예제 #1
0
  /**
   * Copies a source file to a destination file, optionally preserving the source's last
   * modification time. We already have an input stream to read the source file and the destination
   * appears to be an entry in an archive file. Note that this method <em>never</em> closes the
   * given input stream!
   *
   * <p>Note that this method synchronizes on the class object in order to prevent dead locks by two
   * threads copying archive entries to the other's source archive concurrently!
   *
   * @throws FalsePositiveException If the destination is a false positive and the exception cannot
   *     get resolved within this method.
   * @throws InputIOException If copying the data fails because of an IOException in the source.
   * @throws IOException If copying the data fails because of an IOException in the destination.
   */
  static final void cp0(
      final boolean preserve,
      final java.io.File src,
      final InputStream in,
      final ArchiveController dstController,
      final String dstEntryName)
      throws IOException {
    // Do not assume anything about the lock status of the controller:
    // This method may be called from a subclass while a lock is acquired!
    // assert !dstController.readLock().isLocked();
    // assert !dstController.writeLock().isLocked();

    try {
      class OStreamCreator implements IORunnable {
        OutputStream out; // = null;

        public void run() throws IOException {
          // Update controller.
          // This may invalidate the file system object, so it must be
          // done first in case srcController and dstController are the
          // same!
          dstController.autoUmount(dstEntryName);

          final boolean lenient = File.isLenient();

          // Get source archive entry.
          final ArchiveEntry srcEntry = new RfsEntry(src);

          // Get destination archive entry.
          final ArchiveFileSystem dstFileSystem = dstController.autoMount(lenient);
          final Delta delta = dstFileSystem.link(dstEntryName, lenient, preserve ? srcEntry : null);
          final ArchiveEntry dstEntry = delta.getEntry();

          // Create output stream.
          out = dstController.createOutputStream(dstEntry, srcEntry);

          // Now link the destination entry into the file system.
          delta.commit();
        }
      }

      // Create the output stream while the destination controller is
      // write locked.
      final OStreamCreator stream = new OStreamCreator();
      dstController.runWriteLocked(stream);
      final OutputStream out = stream.out;

      // Finally copy the entry data.
      try {
        Streams.cat(in, out);
      } finally {
        out.close();
      }
    } catch (ArchiveEntryFalsePositiveException ex) {
      assert dstController == ex.getController();
      // Reroute call to the destination's enclosing ArchiveController.
      cp0(
          preserve,
          src,
          in,
          dstController.getEnclController(),
          dstController.enclEntryName(dstEntryName));
    }
  }
예제 #2
0
  /**
   * Copies a source file to a destination file, optionally preserving the source's last
   * modification time. We know that the source and destination files both appear to be entries in
   * an archive file.
   *
   * @throws FalsePositiveException If the source or the destination is a false positive and the
   *     exception for the destination cannot get resolved within this method.
   * @throws InputIOException If copying the data fails because of an IOException in the source.
   * @throws IOException If copying the data fails because of an IOException in the destination.
   */
  private static void cp0(
      final boolean preserve,
      final ArchiveController srcController,
      final String srcEntryName,
      final ArchiveController dstController,
      final String dstEntryName)
      throws IOException {
    // Do not assume anything about the lock status of the controller:
    // This method may be called from a subclass while a lock is acquired!
    // assert !srcController.readLock().isLocked();
    // assert !srcController.writeLock().isLocked();
    // assert !dstController.readLock().isLocked();
    // assert !dstController.writeLock().isLocked();

    try {
      class IOStreamCreator implements IORunnable {
        InputStream in;
        OutputStream out;

        public void run() throws IOException {
          // Update controllers.
          // This may invalidate the file system object, so it must be
          // done first in case srcController and dstController are the
          // same!
          class SrcControllerUpdater implements IORunnable {
            public void run() throws IOException {
              srcController.autoUmount(srcEntryName);
              srcController.readLock().lock(); // downgrade to read lock upon return
            }
          } // class SrcControllerUpdater

          final ArchiveEntry srcEntry, dstEntry;
          final Delta delta;
          srcController.runWriteLocked(new SrcControllerUpdater());
          try {
            dstController.autoUmount(dstEntryName);

            // Get source archive entry.
            final ArchiveFileSystem srcFileSystem = srcController.autoMount(false);
            srcEntry = srcFileSystem.get(srcEntryName);

            // Get destination archive entry.
            final boolean lenient = File.isLenient();
            final ArchiveFileSystem dstFileSystem = dstController.autoMount(lenient);
            delta = dstFileSystem.link(dstEntryName, lenient, preserve ? srcEntry : null);
            dstEntry = delta.getEntry();

            // Create input stream.
            in = srcController.createInputStream(srcEntry, dstEntry);
          } finally {
            srcController.readLock().unlock();
          }

          try {
            // Create output stream.
            out = dstController.createOutputStream(dstEntry, srcEntry);

            try {
              // Now link the destination entry into the file system.
              delta.commit();
            } catch (IOException ex) {
              out.close();
              throw ex;
            }
          } catch (IOException ex) {
            try {
              in.close();
            } catch (IOException inFailure) {
              throw new InputIOException(inFailure);
            }
            throw ex;
          }
        }
      } // class IOStreamCreator

      final IOStreamCreator streams = new IOStreamCreator();
      synchronized (copyLock) {
        dstController.runWriteLocked(streams);
      }

      // Finally copy the entry data.
      cp(streams.in, streams.out);
    } catch (ArchiveEntryFalsePositiveException ex) {
      // Both the source and/or the destination may be false positives,
      // so we need to use the exception's additional information to
      // find out which controller actually detected the false positive.
      if (dstController != ex.getController()) throw ex; // not my job - pass on!

      // Reroute call to the destination's enclosing archive controller.
      cp0(
          preserve,
          srcController,
          srcEntryName,
          dstController.getEnclController(),
          dstController.enclEntryName(dstEntryName));
    }
  }