486 } 487 if (!hasCopyAttrs) 488 u.mtime = u.atime= u.ctime = System.currentTimeMillis(); 489 update(u); 490 if (deletesrc) 491 updateDelete(eSrc); 492 } finally { 493 endWrite(); 494 } 495 } 496 497 // Returns an output stream for writing the contents into the specified 498 // entry. 499 OutputStream newOutputStream(byte[] path, OpenOption... options) 500 throws IOException 501 { 502 checkWritable(); 503 boolean hasCreateNew = false; 504 boolean hasCreate = false; 505 boolean hasAppend = false; 506 for (OpenOption opt: options) { 507 if (opt == READ) 508 throw new IllegalArgumentException("READ not allowed"); 509 if (opt == CREATE_NEW) 510 hasCreateNew = true; 511 if (opt == CREATE) 512 hasCreate = true; 513 if (opt == APPEND) 514 hasAppend = true; 515 } 516 beginRead(); // only need a readlock, the "update()" will 517 try { // try to obtain a writelock when the os is 518 ensureOpen(); // being closed. 519 Entry e = getEntry0(path); 520 if (e != null) { 521 if (e.isDir() || hasCreateNew) 522 throw new FileAlreadyExistsException(getString(path)); 523 if (hasAppend) { 524 InputStream is = getInputStream(e); 525 OutputStream os = getOutputStream(new Entry(e, Entry.NEW)); 526 copyStream(is, os); 527 is.close(); 528 return os; 529 } 530 return getOutputStream(new Entry(e, Entry.NEW)); 531 } else { 532 if (!hasCreate && !hasCreateNew) 533 throw new NoSuchFileException(getString(path)); 534 checkParents(path); 535 return getOutputStream(new Entry(path, Entry.NEW)); 547 ensureOpen(); 548 Entry e = getEntry0(path); 549 if (e == null) 550 throw new NoSuchFileException(getString(path)); 551 if (e.isDir()) 552 throw new FileSystemException(getString(path), "is a directory", null); 553 return getInputStream(e); 554 } finally { 555 endRead(); 556 } 557 } 558 559 private void checkOptions(Set<? extends OpenOption> options) { 560 // check for options of null type and option is an intance of StandardOpenOption 561 for (OpenOption option : options) { 562 if (option == null) 563 throw new NullPointerException(); 564 if (!(option instanceof StandardOpenOption)) 565 throw new IllegalArgumentException(); 566 } 567 } 568 569 // Returns a Writable/ReadByteChannel for now. Might consdier to use 570 // newFileChannel() instead, which dump the entry data into a regular 571 // file on the default file system and create a FileChannel on top of 572 // it. 573 SeekableByteChannel newByteChannel(byte[] path, 574 Set<? extends OpenOption> options, 575 FileAttribute<?>... attrs) 576 throws IOException 577 { 578 checkOptions(options); 579 if (options.contains(StandardOpenOption.WRITE) || 580 options.contains(StandardOpenOption.APPEND)) { 581 checkWritable(); 582 beginRead(); 583 try { 584 final WritableByteChannel wbc = Channels.newChannel( 585 newOutputStream(path, options.toArray(new OpenOption[0]))); 586 long leftover = 0; 694 // Returns a FileChannel of the specified entry. 695 // 696 // This implementation creates a temporary file on the default file system, 697 // copy the entry data into it if the entry exists, and then create a 698 // FileChannel on top of it. 699 FileChannel newFileChannel(byte[] path, 700 Set<? extends OpenOption> options, 701 FileAttribute<?>... attrs) 702 throws IOException 703 { 704 checkOptions(options); 705 final boolean forWrite = (options.contains(StandardOpenOption.WRITE) || 706 options.contains(StandardOpenOption.APPEND)); 707 beginRead(); 708 try { 709 ensureOpen(); 710 Entry e = getEntry0(path); 711 if (forWrite) { 712 checkWritable(); 713 if (e == null) { 714 if (!options.contains(StandardOpenOption.CREATE_NEW)) 715 throw new NoSuchFileException(getString(path)); 716 } else { 717 if (options.contains(StandardOpenOption.CREATE_NEW)) 718 throw new FileAlreadyExistsException(getString(path)); 719 if (e.isDir()) 720 throw new FileAlreadyExistsException("directory <" 721 + getString(path) + "> exists"); 722 } 723 options.remove(StandardOpenOption.CREATE_NEW); // for tmpfile 724 } else if (e == null || e.isDir()) { 725 throw new NoSuchFileException(getString(path)); 726 } 727 728 final boolean isFCH = (e != null && e.type == Entry.FILECH); 729 final Path tmpfile = isFCH ? e.file : getTempPathForEntry(path); 730 final FileChannel fch = tmpfile.getFileSystem() 731 .provider() 732 .newFileChannel(tmpfile, options, attrs); 733 final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH); 734 if (forWrite) { 735 u.flag = FLAG_DATADESCR; 736 u.method = METHOD_DEFLATED; 737 } 738 // is there a better way to hook into the FileChannel's close method? 739 return new FileChannel() { 740 public int write(ByteBuffer src) throws IOException { 741 return fch.write(src); 742 } | 486 } 487 if (!hasCopyAttrs) 488 u.mtime = u.atime= u.ctime = System.currentTimeMillis(); 489 update(u); 490 if (deletesrc) 491 updateDelete(eSrc); 492 } finally { 493 endWrite(); 494 } 495 } 496 497 // Returns an output stream for writing the contents into the specified 498 // entry. 499 OutputStream newOutputStream(byte[] path, OpenOption... options) 500 throws IOException 501 { 502 checkWritable(); 503 boolean hasCreateNew = false; 504 boolean hasCreate = false; 505 boolean hasAppend = false; 506 boolean hasTruncate = false; 507 for (OpenOption opt: options) { 508 if (opt == READ) 509 throw new IllegalArgumentException("READ not allowed"); 510 if (opt == CREATE_NEW) 511 hasCreateNew = true; 512 if (opt == CREATE) 513 hasCreate = true; 514 if (opt == APPEND) 515 hasAppend = true; 516 if (opt == TRUNCATE_EXISTING) 517 hasTruncate = true; 518 } 519 if (hasAppend && hasTruncate) 520 throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed"); 521 beginRead(); // only need a readlock, the "update()" will 522 try { // try to obtain a writelock when the os is 523 ensureOpen(); // being closed. 524 Entry e = getEntry0(path); 525 if (e != null) { 526 if (e.isDir() || hasCreateNew) 527 throw new FileAlreadyExistsException(getString(path)); 528 if (hasAppend) { 529 InputStream is = getInputStream(e); 530 OutputStream os = getOutputStream(new Entry(e, Entry.NEW)); 531 copyStream(is, os); 532 is.close(); 533 return os; 534 } 535 return getOutputStream(new Entry(e, Entry.NEW)); 536 } else { 537 if (!hasCreate && !hasCreateNew) 538 throw new NoSuchFileException(getString(path)); 539 checkParents(path); 540 return getOutputStream(new Entry(path, Entry.NEW)); 552 ensureOpen(); 553 Entry e = getEntry0(path); 554 if (e == null) 555 throw new NoSuchFileException(getString(path)); 556 if (e.isDir()) 557 throw new FileSystemException(getString(path), "is a directory", null); 558 return getInputStream(e); 559 } finally { 560 endRead(); 561 } 562 } 563 564 private void checkOptions(Set<? extends OpenOption> options) { 565 // check for options of null type and option is an intance of StandardOpenOption 566 for (OpenOption option : options) { 567 if (option == null) 568 throw new NullPointerException(); 569 if (!(option instanceof StandardOpenOption)) 570 throw new IllegalArgumentException(); 571 } 572 if (options.contains(APPEND) && options.contains(TRUNCATE_EXISTING)) 573 throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed"); 574 } 575 576 // Returns a Writable/ReadByteChannel for now. Might consdier to use 577 // newFileChannel() instead, which dump the entry data into a regular 578 // file on the default file system and create a FileChannel on top of 579 // it. 580 SeekableByteChannel newByteChannel(byte[] path, 581 Set<? extends OpenOption> options, 582 FileAttribute<?>... attrs) 583 throws IOException 584 { 585 checkOptions(options); 586 if (options.contains(StandardOpenOption.WRITE) || 587 options.contains(StandardOpenOption.APPEND)) { 588 checkWritable(); 589 beginRead(); 590 try { 591 final WritableByteChannel wbc = Channels.newChannel( 592 newOutputStream(path, options.toArray(new OpenOption[0]))); 593 long leftover = 0; 701 // Returns a FileChannel of the specified entry. 702 // 703 // This implementation creates a temporary file on the default file system, 704 // copy the entry data into it if the entry exists, and then create a 705 // FileChannel on top of it. 706 FileChannel newFileChannel(byte[] path, 707 Set<? extends OpenOption> options, 708 FileAttribute<?>... attrs) 709 throws IOException 710 { 711 checkOptions(options); 712 final boolean forWrite = (options.contains(StandardOpenOption.WRITE) || 713 options.contains(StandardOpenOption.APPEND)); 714 beginRead(); 715 try { 716 ensureOpen(); 717 Entry e = getEntry0(path); 718 if (forWrite) { 719 checkWritable(); 720 if (e == null) { 721 if (!options.contains(StandardOpenOption.CREATE) && 722 !options.contains(StandardOpenOption.CREATE_NEW)) { 723 throw new NoSuchFileException(getString(path)); 724 } 725 } else { 726 if (options.contains(StandardOpenOption.CREATE_NEW)) { 727 throw new FileAlreadyExistsException(getString(path)); 728 } 729 if (e.isDir()) 730 throw new FileAlreadyExistsException("directory <" 731 + getString(path) + "> exists"); 732 } 733 options = new HashSet<>(options); 734 options.remove(StandardOpenOption.CREATE_NEW); // for tmpfile 735 } else if (e == null || e.isDir()) { 736 throw new NoSuchFileException(getString(path)); 737 } 738 739 final boolean isFCH = (e != null && e.type == Entry.FILECH); 740 final Path tmpfile = isFCH ? e.file : getTempPathForEntry(path); 741 final FileChannel fch = tmpfile.getFileSystem() 742 .provider() 743 .newFileChannel(tmpfile, options, attrs); 744 final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH); 745 if (forWrite) { 746 u.flag = FLAG_DATADESCR; 747 u.method = METHOD_DEFLATED; 748 } 749 // is there a better way to hook into the FileChannel's close method? 750 return new FileChannel() { 751 public int write(ByteBuffer src) throws IOException { 752 return fch.write(src); 753 } |