< prev index next >

src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java

Print this page
rev 13714 : 8028480: (zipfs) NoSuchFileException on creating a file in ZipFileSystem with CREATE and WRITE
8034773: (zipfs) newOutputstream uses CREATE_NEW when no options specified
Summary: to open the new steram with appropricate open options
Reviewed-by:
   1 /*
   2  * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  *
   8  *   - Redistributions of source code must retain the above copyright
   9  *     notice, this list of conditions and the following disclaimer.
  10  *
  11  *   - Redistributions in binary form must reproduce the above copyright
  12  *     notice, this list of conditions and the following disclaimer in the
  13  *     documentation and/or other materials provided with the distribution.
  14  *
  15  *   - Neither the name of Oracle nor the names of its
  16  *     contributors may be used to endorse or promote products derived
  17  *     from this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR


 480             }
 481             if (!hasCopyAttrs)
 482                 u.mtime = u.atime= u.ctime = System.currentTimeMillis();
 483             update(u);
 484             if (deletesrc)
 485                 updateDelete(eSrc);
 486         } finally {
 487             endWrite();
 488         }
 489     }
 490 
 491     // Returns an output stream for writing the contents into the specified
 492     // entry.
 493     OutputStream newOutputStream(byte[] path, OpenOption... options)
 494         throws IOException
 495     {
 496         checkWritable();
 497         boolean hasCreateNew = false;
 498         boolean hasCreate = false;
 499         boolean hasAppend = false;

 500         for (OpenOption opt: options) {
 501             if (opt == READ)
 502                 throw new IllegalArgumentException("READ not allowed");
 503             if (opt == CREATE_NEW)
 504                 hasCreateNew = true;
 505             if (opt == CREATE)
 506                 hasCreate = true;
 507             if (opt == APPEND)
 508                 hasAppend = true;


 509         }


 510         beginRead();                 // only need a readlock, the "update()" will
 511         try {                        // try to obtain a writelock when the os is
 512             ensureOpen();            // being closed.
 513             Entry e = getEntry0(path);
 514             if (e != null) {
 515                 if (e.isDir() || hasCreateNew)
 516                     throw new FileAlreadyExistsException(getString(path));
 517                 if (hasAppend) {
 518                     InputStream is = getInputStream(e);
 519                     OutputStream os = getOutputStream(new Entry(e, Entry.NEW));
 520                     copyStream(is, os);
 521                     is.close();
 522                     return os;
 523                 }
 524                 return getOutputStream(new Entry(e, Entry.NEW));
 525             } else {
 526                 if (!hasCreate && !hasCreateNew)
 527                     throw new NoSuchFileException(getString(path));
 528                 checkParents(path);
 529                 return getOutputStream(new Entry(path, Entry.NEW));


 541             ensureOpen();
 542             Entry e = getEntry0(path);
 543             if (e == null)
 544                 throw new NoSuchFileException(getString(path));
 545             if (e.isDir())
 546                 throw new FileSystemException(getString(path), "is a directory", null);
 547             return getInputStream(e);
 548         } finally {
 549             endRead();
 550         }
 551     }
 552 
 553     private void checkOptions(Set<? extends OpenOption> options) {
 554         // check for options of null type and option is an intance of StandardOpenOption
 555         for (OpenOption option : options) {
 556             if (option == null)
 557                 throw new NullPointerException();
 558             if (!(option instanceof StandardOpenOption))
 559                 throw new IllegalArgumentException();
 560         }


 561     }
 562 
 563     // Returns a Writable/ReadByteChannel for now. Might consdier to use
 564     // newFileChannel() instead, which dump the entry data into a regular
 565     // file on the default file system and create a FileChannel on top of
 566     // it.
 567     SeekableByteChannel newByteChannel(byte[] path,
 568                                        Set<? extends OpenOption> options,
 569                                        FileAttribute<?>... attrs)
 570         throws IOException
 571     {
 572         checkOptions(options);
 573         if (options.contains(StandardOpenOption.WRITE) ||
 574             options.contains(StandardOpenOption.APPEND)) {
 575             checkWritable();
 576             beginRead();
 577             try {
 578                 final WritableByteChannel wbc = Channels.newChannel(
 579                     newOutputStream(path, options.toArray(new OpenOption[0])));
 580                 long leftover = 0;


 688     // Returns a FileChannel of the specified entry.
 689     //
 690     // This implementation creates a temporary file on the default file system,
 691     // copy the entry data into it if the entry exists, and then create a
 692     // FileChannel on top of it.
 693     FileChannel newFileChannel(byte[] path,
 694                                Set<? extends OpenOption> options,
 695                                FileAttribute<?>... attrs)
 696         throws IOException
 697     {
 698         checkOptions(options);
 699         final  boolean forWrite = (options.contains(StandardOpenOption.WRITE) ||
 700                                    options.contains(StandardOpenOption.APPEND));
 701         beginRead();
 702         try {
 703             ensureOpen();
 704             Entry e = getEntry0(path);
 705             if (forWrite) {
 706                 checkWritable();
 707                 if (e == null) {
 708                 if (!options.contains(StandardOpenOption.CREATE_NEW))

 709                     throw new NoSuchFileException(getString(path));

 710                 } else {
 711                     if (options.contains(StandardOpenOption.CREATE_NEW))
 712                         throw new FileAlreadyExistsException(getString(path));

 713                     if (e.isDir())
 714                         throw new FileAlreadyExistsException("directory <"
 715                             + getString(path) + "> exists");
 716                 }

 717                 options.remove(StandardOpenOption.CREATE_NEW); // for tmpfile
 718             } else if (e == null || e.isDir()) {
 719                 throw new NoSuchFileException(getString(path));
 720             }
 721 
 722             final boolean isFCH = (e != null && e.type == Entry.FILECH);
 723             final Path tmpfile = isFCH ? e.file : getTempPathForEntry(path);
 724             final FileChannel fch = tmpfile.getFileSystem()
 725                                            .provider()
 726                                            .newFileChannel(tmpfile, options, attrs);
 727             final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH);
 728             if (forWrite) {
 729                 u.flag = FLAG_DATADESCR;
 730                 u.method = METHOD_DEFLATED;
 731             }
 732             // is there a better way to hook into the FileChannel's close method?
 733             return new FileChannel() {
 734                 public int write(ByteBuffer src) throws IOException {
 735                     return fch.write(src);
 736                 }


   1 /*
   2  * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  *
   8  *   - Redistributions of source code must retain the above copyright
   9  *     notice, this list of conditions and the following disclaimer.
  10  *
  11  *   - Redistributions in binary form must reproduce the above copyright
  12  *     notice, this list of conditions and the following disclaimer in the
  13  *     documentation and/or other materials provided with the distribution.
  14  *
  15  *   - Neither the name of Oracle nor the names of its
  16  *     contributors may be used to endorse or promote products derived
  17  *     from this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR


 480             }
 481             if (!hasCopyAttrs)
 482                 u.mtime = u.atime= u.ctime = System.currentTimeMillis();
 483             update(u);
 484             if (deletesrc)
 485                 updateDelete(eSrc);
 486         } finally {
 487             endWrite();
 488         }
 489     }
 490 
 491     // Returns an output stream for writing the contents into the specified
 492     // entry.
 493     OutputStream newOutputStream(byte[] path, OpenOption... options)
 494         throws IOException
 495     {
 496         checkWritable();
 497         boolean hasCreateNew = false;
 498         boolean hasCreate = false;
 499         boolean hasAppend = false;
 500         boolean hasTruncate = false;
 501         for (OpenOption opt: options) {
 502             if (opt == READ)
 503                 throw new IllegalArgumentException("READ not allowed");
 504             if (opt == CREATE_NEW)
 505                 hasCreateNew = true;
 506             if (opt == CREATE)
 507                 hasCreate = true;
 508             if (opt == APPEND)
 509                 hasAppend = true;
 510             if (opt == TRUNCATE_EXISTING)
 511                 hasTruncate = true;
 512         }
 513         if (hasAppend && hasTruncate)
 514             throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
 515         beginRead();                 // only need a readlock, the "update()" will
 516         try {                        // try to obtain a writelock when the os is
 517             ensureOpen();            // being closed.
 518             Entry e = getEntry0(path);
 519             if (e != null) {
 520                 if (e.isDir() || hasCreateNew)
 521                     throw new FileAlreadyExistsException(getString(path));
 522                 if (hasAppend) {
 523                     InputStream is = getInputStream(e);
 524                     OutputStream os = getOutputStream(new Entry(e, Entry.NEW));
 525                     copyStream(is, os);
 526                     is.close();
 527                     return os;
 528                 }
 529                 return getOutputStream(new Entry(e, Entry.NEW));
 530             } else {
 531                 if (!hasCreate && !hasCreateNew)
 532                     throw new NoSuchFileException(getString(path));
 533                 checkParents(path);
 534                 return getOutputStream(new Entry(path, Entry.NEW));


 546             ensureOpen();
 547             Entry e = getEntry0(path);
 548             if (e == null)
 549                 throw new NoSuchFileException(getString(path));
 550             if (e.isDir())
 551                 throw new FileSystemException(getString(path), "is a directory", null);
 552             return getInputStream(e);
 553         } finally {
 554             endRead();
 555         }
 556     }
 557 
 558     private void checkOptions(Set<? extends OpenOption> options) {
 559         // check for options of null type and option is an intance of StandardOpenOption
 560         for (OpenOption option : options) {
 561             if (option == null)
 562                 throw new NullPointerException();
 563             if (!(option instanceof StandardOpenOption))
 564                 throw new IllegalArgumentException();
 565         }
 566         if (options.contains(APPEND) && options.contains(TRUNCATE_EXISTING))
 567             throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
 568     }
 569 
 570     // Returns a Writable/ReadByteChannel for now. Might consdier to use
 571     // newFileChannel() instead, which dump the entry data into a regular
 572     // file on the default file system and create a FileChannel on top of
 573     // it.
 574     SeekableByteChannel newByteChannel(byte[] path,
 575                                        Set<? extends OpenOption> options,
 576                                        FileAttribute<?>... attrs)
 577         throws IOException
 578     {
 579         checkOptions(options);
 580         if (options.contains(StandardOpenOption.WRITE) ||
 581             options.contains(StandardOpenOption.APPEND)) {
 582             checkWritable();
 583             beginRead();
 584             try {
 585                 final WritableByteChannel wbc = Channels.newChannel(
 586                     newOutputStream(path, options.toArray(new OpenOption[0])));
 587                 long leftover = 0;


 695     // Returns a FileChannel of the specified entry.
 696     //
 697     // This implementation creates a temporary file on the default file system,
 698     // copy the entry data into it if the entry exists, and then create a
 699     // FileChannel on top of it.
 700     FileChannel newFileChannel(byte[] path,
 701                                Set<? extends OpenOption> options,
 702                                FileAttribute<?>... attrs)
 703         throws IOException
 704     {
 705         checkOptions(options);
 706         final  boolean forWrite = (options.contains(StandardOpenOption.WRITE) ||
 707                                    options.contains(StandardOpenOption.APPEND));
 708         beginRead();
 709         try {
 710             ensureOpen();
 711             Entry e = getEntry0(path);
 712             if (forWrite) {
 713                 checkWritable();
 714                 if (e == null) {
 715                     if (!options.contains(StandardOpenOption.CREATE) &&
 716                         !options.contains(StandardOpenOption.CREATE_NEW)) {
 717                         throw new NoSuchFileException(getString(path));
 718                     }
 719                 } else {
 720                     if (options.contains(StandardOpenOption.CREATE_NEW)) {
 721                         throw new FileAlreadyExistsException(getString(path));
 722                     }
 723                     if (e.isDir())
 724                         throw new FileAlreadyExistsException("directory <"
 725                             + getString(path) + "> exists");
 726                 }
 727                 options = new HashSet<>(options);
 728                 options.remove(StandardOpenOption.CREATE_NEW); // for tmpfile
 729             } else if (e == null || e.isDir()) {
 730                 throw new NoSuchFileException(getString(path));
 731             }
 732 
 733             final boolean isFCH = (e != null && e.type == Entry.FILECH);
 734             final Path tmpfile = isFCH ? e.file : getTempPathForEntry(path);
 735             final FileChannel fch = tmpfile.getFileSystem()
 736                                            .provider()
 737                                            .newFileChannel(tmpfile, options, attrs);
 738             final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH);
 739             if (forWrite) {
 740                 u.flag = FLAG_DATADESCR;
 741                 u.method = METHOD_DEFLATED;
 742             }
 743             // is there a better way to hook into the FileChannel's close method?
 744             return new FileChannel() {
 745                 public int write(ByteBuffer src) throws IOException {
 746                     return fch.write(src);
 747                 }


< prev index next >