1 29 30 package com.caucho.vfs; 31 32 import com.caucho.util.Alarm; 33 import com.caucho.util.ByteBuffer; 34 import com.caucho.util.L10N; 35 36 import java.io.FileNotFoundException ; 37 import java.io.IOException ; 38 import java.util.ArrayList ; 39 import java.util.Map ; 40 41 public class MemoryPath extends FilesystemPath { 42 private static L10N L = new L10N(MemoryPath.class); 43 44 private Node _rootNode; 45 46 protected MemoryPath(FilesystemPath root, 47 String userPath, Map <String ,Object > attributes, 48 String path) 49 { 50 super(root, userPath, path); 51 52 if (root instanceof MemoryPath) 53 _rootNode = ((MemoryPath) root)._rootNode; 54 else 55 _root = this; 56 } 57 58 public MemoryPath() 59 { 60 this(null, "/", null, "/"); 61 62 _root = this; 63 _rootNode = new Node("", null, Node.DIR); 64 } 65 66 public Path fsWalk(String userPath, 67 Map <String ,Object > attributes, 68 String path) 69 { 70 return new MemoryPath(_root, userPath, attributes, path); 71 } 72 73 public String getScheme() 74 { 75 return "memory"; 76 } 77 78 public String getURL() 79 { 80 return getScheme() + ":" + getFullPath(); 81 } 82 83 public boolean exists() 84 { 85 synchronized (_rootNode) { 86 return lookupAll() != null; 87 } 88 } 89 90 private Node lookupAll() 91 { 92 String fullPath = getFullPath(); 93 94 int head = 0; 95 Node node = _rootNode; 96 97 while (node != null && head < fullPath.length()) { 98 int tail = fullPath.indexOf('/', head); 99 100 if (tail == -1) { 101 if (head < fullPath.length()) 102 return node.lookup(fullPath.substring(head)); 103 else 104 return node; 105 } 106 107 if (head != tail) 108 node = node.lookup(fullPath.substring(head, tail)); 109 110 head = tail + 1; 111 } 112 113 return node; 114 } 115 116 private Node lookupAllButTail() 117 { 118 String fullPath = getFullPath(); 119 120 int head = 0; 121 Node node = this._rootNode; 122 123 while (node != null && head < fullPath.length()) { 124 int tail = fullPath.indexOf('/', head); 125 126 if (tail == -1 || tail == fullPath.length() - 1) 127 return node; 128 129 if (head != tail) 130 node = node.lookup(fullPath.substring(head, tail)); 131 132 head = tail + 1; 133 } 134 135 return node; 136 } 137 138 public boolean isDirectory() 139 { 140 synchronized (_rootNode) { 141 Node node = lookupAll(); 142 143 return node != null && node.type == node.DIR; 144 } 145 } 146 147 public boolean isFile() 148 { 149 synchronized (_rootNode) { 150 Node node = lookupAll(); 151 152 return node != null && node.type == node.FILE; 153 } 154 } 155 156 public boolean isObject() 157 { 158 synchronized (_rootNode) { 159 Node node = lookupAll(); 160 161 return node != null && node.type == node.OBJECT; 162 } 163 } 164 165 public boolean setExecutable(boolean isExecutable) 166 { 167 synchronized (_rootNode) { 168 Node node = lookupAll(); 169 170 if (node != null && (node.type == node.FILE || node.type == node.DIR)) { 171 node.isExecutable = isExecutable; 172 return true; 173 } 174 else 175 return false; 176 } 177 } 178 179 public boolean isExecutable() 180 { 181 synchronized (_rootNode) { 182 Node node = lookupAll(); 183 184 if (node != null && (node.type == node.FILE || node.type == node.DIR)) 185 return node.isExecutable; 186 else 187 return false; 188 } 189 } 190 191 public long getLength() 192 { 193 synchronized (_rootNode) { 194 Node node = lookupAll(); 195 196 if (node != null && node.type == node.FILE) 197 return ((ByteBuffer) node.data).length(); 198 else 199 return 0; 200 } 201 } 202 203 public long getLastModified() 204 { 205 synchronized (_rootNode) { 206 Node node = lookupAll(); 207 208 return node == null ? 0 : node.lastModified; 209 } 210 } 211 212 public boolean canRead() 213 { 214 synchronized (_rootNode) { 215 Node node = lookupAll(); 216 217 return node != null; 218 } 219 } 220 221 public boolean canWrite() 222 { 223 synchronized (_rootNode) { 224 Node node = lookupAll(); 225 226 return node != null; 227 } 228 } 229 230 public String []list() 231 { 232 synchronized (_rootNode) { 233 Node node = lookupAll(); 234 235 if (node == null || node.data != null) 236 return new String [0]; 237 238 ArrayList <String > a = new ArrayList <String >(); 239 for (Node child = node.firstChild; child != null; child = child.next) { 240 a.add(child.name); 241 } 242 243 return (String []) a.toArray(new String [a.size()]); 244 } 245 } 246 247 249 private boolean mkdir(boolean parent) 250 { 251 synchronized (_rootNode) { 252 String fullPath = getFullPath(); 253 254 int head = 0; 255 Node node = this._rootNode; 256 257 while (node != null && head < fullPath.length()) { 258 int tail = fullPath.indexOf('/', head); 259 String name; 260 261 if (tail == head) { 262 head = tail + 1; 263 continue; 264 } 265 if (tail == -1) { 266 name = fullPath.substring(head); 267 if (node.lookup(name) != null) 268 return false; 269 node.createDir(name); 270 return true; 271 } 272 273 name = fullPath.substring(head, tail); 274 Node next = node.lookup(name); 275 276 if (next == null && parent) 277 next = node.createDir(name); 278 279 if (next == null || next.type != next.DIR) 280 return false; 281 282 node = next; 283 head = tail + 1; 284 } 285 286 return false; 287 } 288 } 289 290 public boolean mkdir() 291 { 292 return mkdir(false); 293 } 294 295 public boolean mkdirs() 296 { 297 return mkdir(true); 298 } 299 300 public boolean remove() 301 { 302 synchronized (_rootNode) { 303 Node node = lookupAllButTail(); 304 String tail = getTail(); 305 306 if (node == null) 307 return false; 308 309 Node child = node.lookup(tail); 310 if (child == null || child.firstChild != null) 311 return false; 312 313 node.remove(tail); 314 315 return true; 316 } 317 } 318 319 public boolean renameTo(Path path) 320 { 321 synchronized (_rootNode) { 322 if (! (path instanceof MemoryPath)) 323 return false; 324 325 MemoryPath file = (MemoryPath) path; 326 if (_rootNode != file._rootNode) 327 return false; 328 329 Node oldParent = lookupAllButTail(); 330 if (oldParent == null) 331 return false; 332 333 Node child = oldParent.lookup(getTail()); 334 if (child == null) 335 return false; 336 337 Node newParent = file.lookupAllButTail(); 338 if (newParent == null || newParent.type != Node.DIR) 339 return false; 340 341 if (newParent.lookup(file.getTail()) != null) 342 return false; 343 344 oldParent.remove(getTail()); 345 child.name = file.getTail(); 346 newParent.create(child); 347 348 return true; 349 } 350 } 351 352 public StreamImpl openReadImpl() throws IOException 353 { 354 synchronized (_rootNode) { 355 Node node = lookupAll(); 356 357 if (node == null) 358 throw new FileNotFoundException (getPath()); 359 else if (node.type != node.FILE) 360 throw new IOException ("is directory: " + getPath()); 361 362 return new MemoryStream(node, (ByteBuffer) node.data, false); 363 } 364 } 365 366 public StreamImpl openWriteImpl() throws IOException 367 { 368 return openWriteImpl(false); 369 } 370 371 public StreamImpl openAppendImpl() throws IOException 372 { 373 return openWriteImpl(true); 374 } 375 376 private StreamImpl openWriteImpl(boolean append) 377 throws IOException 378 { 379 synchronized (_rootNode) { 380 Node node = lookupAllButTail(); 381 String tail = getTail(); 382 383 if (node == null || node.type != Node.DIR) 384 throw new IOException (L.l("can't create file {0}", getFullPath())); 385 386 Node child = node.lookup(tail); 387 if (child == null) 388 child = node.createFile(tail, new ByteBuffer(256)); 389 else if (! append) { 390 node.remove(tail); 391 child = node.createFile(tail, new ByteBuffer(256)); 392 } 393 else if (child.type != child.FILE) 394 throw new IOException (L.l("can't create file {0}", getFullPath())); 395 return new MemoryStream(child, (ByteBuffer) child.data, true); 396 } 397 } 398 399 public Object getValue() throws IOException 400 { 401 synchronized (_rootNode) { 402 Node node = lookupAll(); 403 404 if (node == null || node.type != node.OBJECT) 405 throw new IOException ("no such object: " + getFullPath().toString()); 406 407 return node.data; 408 } 409 } 410 411 synchronized public void setValue(Object object) throws IOException 412 { 413 synchronized (_rootNode) { 414 Node node = lookupAllButTail(); 415 String tail = getTail(); 416 417 if (node == null || node.type != Node.DIR) 418 throw new IOException (L.l("can't set object {0}", getFullPath())); 419 420 Node child = node.lookup(tail); 421 if (child == null) 422 child = node.createObject(tail, object); 423 else if (child.type == child.OBJECT) 424 child.data = object; 425 else 426 throw new IOException (L.l("can't set object {0}", getFullPath())); 427 } 428 } 429 430 public Path copyCache() 431 { 432 return null; 433 } 434 435 public MemoryPath copyDeep() 436 { 437 MemoryPath path = new MemoryPath(); 438 439 path._rootNode = _rootNode.copy(); 440 441 return path; 442 } 443 444 public boolean equals(Object o) 445 { 446 if (o == null || ! getClass().equals(o.getClass())) 447 return false; 448 449 MemoryPath mp = (MemoryPath) o; 450 451 return getURL().equals(mp.getURL()) && _rootNode == mp._rootNode; 452 } 453 454 private static class Node { 455 static final int DIR = 0; 456 static final int FILE = DIR + 1; 457 static final int OBJECT = FILE + 1; 458 459 String name; 460 Node next; 461 Node firstChild; 462 long lastModified; 463 int type; 464 Object data; 465 boolean isExecutable; 466 467 Node(String name, Object data, int type) 468 { 469 if (name == null) 470 throw new NullPointerException (); 471 this.name = name; 472 this.data = data; 473 this.type = type; 474 this.lastModified = Alarm.getCurrentTime(); 475 } 476 477 Node lookup(String name) 478 { 479 for (Node node = firstChild; node != null; node = node.next) { 480 if (node.name.equals(name)) { 481 return node; 482 } 483 } 484 485 return null; 486 } 487 488 private Node create(String name, Object data, int type) 489 { 490 for (Node node = firstChild; node != null; node = node.next) { 491 if (node.name.equals(name)) 492 return null; 493 } 494 495 Node newNode = new Node(name, data, type); 496 newNode.next = firstChild; 497 firstChild = newNode; 498 lastModified = Alarm.getCurrentTime(); 499 500 return newNode; 501 } 502 503 Node createDir(String name) 504 { 505 return create(name, null, DIR); 506 } 507 508 Node createFile(String name, ByteBuffer data) 509 { 510 return create(name, data, FILE); 511 } 512 513 Node createObject(String name, Object data) 514 { 515 return create(name, data, OBJECT); 516 } 517 518 Node create(Node newNode) 519 { 520 newNode.next = firstChild; 521 firstChild = newNode; 522 523 return newNode; 524 } 525 526 boolean remove(String name) 527 { 528 Node last = null; 529 for (Node node = firstChild; node != null; node = node.next) { 530 if (node.name.equals(name)) { 531 if (node.firstChild != null) 532 return false; 533 534 if (last != null) 535 last.next = node.next; 536 else 537 firstChild = node.next; 538 539 return true; 540 } 541 542 last = node; 543 } 544 545 return false; 546 } 547 548 Node copy() 549 { 550 Node newNode = new Node(name, data, type); 551 552 if (type == DIR) { 553 for (Node child = firstChild; child != null; child = child.next) { 554 Node newChild = child.copy(); 555 556 newChild.next = newNode.firstChild; 557 newNode.firstChild = newChild; 558 } 559 } 560 561 return newNode; 562 } 563 }; 564 565 public class MemoryStream extends StreamImpl { 566 Node _node; 567 ByteBuffer _bb; 568 int _offset; 569 boolean _write; 570 571 MemoryStream(Node node, ByteBuffer bb, boolean write) 572 { 573 setPath(MemoryPath.this); 574 575 _node = node; 576 if (write) 577 node.lastModified = Alarm.getCurrentTime(); 578 _write = write; 579 580 _bb = bb; 581 } 582 583 public int getAvailable() 584 { 585 return _bb.length() - _offset; 586 } 587 588 public boolean canRead() { return true; } 589 590 public int read(byte []buf, int bufOffset, int length) throws IOException 591 { 592 synchronized (_bb) { 593 int sublen = _bb.length() - _offset; 594 if (length < sublen) 595 sublen = length; 596 597 if (sublen <= 0) 598 return -1; 599 600 System.arraycopy(_bb.getBuffer(), _offset, buf, bufOffset, sublen); 601 _offset += sublen; 602 603 return sublen; 604 } 605 } 606 607 public int getPosition() 608 { 609 return _offset; 610 } 611 612 public void seekStart(long pos) 613 { 614 _offset = (int) pos; 615 if (_offset < 0) 616 _offset = 0; 617 if (_offset > _bb.length()) 618 _offset = _bb.length(); 619 } 620 621 public boolean canWrite() { return true; } 622 623 631 public void write(byte []buf, int offset, int length, boolean isEnd) 632 throws IOException 633 { 634 synchronized (_bb) { 635 _bb.add(buf, offset, length); 636 } 637 638 _node.lastModified = Alarm.getCurrentTime(); 639 } 640 } 641 } 642 | Popular Tags |