Beispiel #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, but we know nothing
   * about the destination file yet. Note that this method <em>never</em> closes the given input
   * stream!
   *
   * @throws FileNotFoundException If either the source or the destination cannot get accessed.
   * @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 java.io.File src, final InputStream in, final java.io.File dst)
      throws IOException {
    try {
      if (dst instanceof File) {
        final File dstFile = (File) dst;
        dstFile.ensureNotVirtualRoot("cannot write");
        final String dstEntryName = dstFile.getEnclEntryName();
        if (dstEntryName != null) {
          cp0(preserve, src, in, dstFile.getEnclArchive().getArchiveController(), dstEntryName);
          return;
        }
      }
    } catch (RfsEntryFalsePositiveException dstIsNotArchive) {
    }

    // Treat the destination like a regular file.
    final OutputStream out = new java.io.FileOutputStream(dst);
    try {
      Streams.cat(in, out);
    } finally {
      out.close();
    }
    if (preserve && !dst.setLastModified(src.lastModified()))
      throw new IOException(dst.getPath() + " (cannot preserve last modification time)");
  }
Beispiel #2
0
 private static boolean mv0(
     final java.io.File src, final java.io.File dst, final ArchiveDetector detector) {
   boolean ok = true;
   if (src.isDirectory()) {
     final long srcLastModified = src.lastModified();
     final boolean srcIsArchived = src instanceof File && ((File) src).getInnerArchive() != null;
     final boolean dstIsArchived = dst instanceof File && ((File) dst).getInnerArchive() != null;
     final boolean srcIsGhost = srcIsArchived && srcLastModified <= 0;
     if (!srcIsGhost || !dstIsArchived || !File.isLenient()) dst.mkdir();
     final String[] members = src.list();
     if (!srcIsArchived && dstIsArchived) {
       // Create sorted entries if writing a new archive file.
       // This is courtesy only, so natural order is sufficient.
       Arrays.sort(members);
     }
     for (int i = 0, l = members.length; i < l; i++) {
       final String member = members[i];
       ok &= mv0(detector.createFile(src, member), detector.createFile(dst, member), detector);
     }
     if (!srcIsGhost) ok &= dst.setLastModified(srcLastModified);
   } else if (src.isFile()) { // !isDirectory()
     try {
       cp(true, src, dst);
     } catch (IOException ex) {
       ok = false;
     }
   } else {
     ok = false; // don't move special files!
   }
   return ok && src.delete(); // only unlink if ok!
 }
Beispiel #3
0
 /** Unchecked parameters version. */
 private static void cp_r0(
     final boolean preserve,
     final java.io.File src,
     final java.io.File dst,
     final ArchiveDetector srcDetector,
     final ArchiveDetector dstDetector)
     throws IOException {
   if (src.isDirectory()) {
     final long srcLastModified = src.lastModified();
     final boolean srcIsArchived = src instanceof File && ((File) src).getInnerArchive() != null;
     final boolean dstIsArchived = dst instanceof File && ((File) dst).getInnerArchive() != null;
     final boolean srcIsGhost = srcIsArchived && srcLastModified <= 0;
     if (!srcIsGhost || !dstIsArchived || !File.isLenient())
       if (!dst.mkdir() && !dst.isDirectory())
         throw new IOException("destination is not a directory");
     final String[] members = src.list();
     if (!srcIsArchived && dstIsArchived) {
       // Create sorted entries if writing a new archive.
       // This is a courtesy only, so natural order is sufficient.
       Arrays.sort(members);
     }
     for (int i = 0, l = members.length; i < l; i++) {
       final String member = members[i];
       cp_r0(
           preserve,
           srcDetector.createFile(src, member),
           dstDetector.createFile(dst, member),
           srcDetector,
           dstDetector);
     }
     if (preserve && !srcIsGhost)
       if (!dst.setLastModified(srcLastModified))
         throw new IOException("cannot set last modification time");
   } else if (src.isFile() && (!dst.exists() || dst.isFile())) {
     cp0(preserve, src, dst);
   } else {
     throw new IOException("cannot copy non-existent or special files");
   }
 }
Beispiel #4
0
  /**
   * Copies a source file to a destination file, optionally preserving the source's last
   * modification time. We know that the source file appears to be an entry in an archive file, but
   * we know nothing about the destination file yet.
   *
   * <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 source or 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.
   */
  private static void cp0(
      final boolean preserve,
      final ArchiveController srcController,
      final String srcEntryName,
      final java.io.File dst)
      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();

    try {
      try {
        if (dst instanceof File) {
          final File dstFile = (File) dst;
          dstFile.ensureNotVirtualRoot("cannot write");
          final String dstEntryName = dstFile.getEnclEntryName();
          if (dstEntryName != null) {
            cp0(
                preserve,
                srcController,
                srcEntryName,
                dstFile.getEnclArchive().getArchiveController(),
                dstEntryName);
            return;
          }
        }
      } catch (RfsEntryFalsePositiveException isNotArchive) {
        // 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 (isNotArchive.getController() == srcController)
          throw isNotArchive; // not my job - pass on!
      }

      final InputStream in;
      final long time;
      srcController.readLock().lock();
      try {
        in = srcController.createInputStream0(srcEntryName); // detects false positives!
        time = srcController.lastModified(srcEntryName);
      } finally {
        srcController.readLock().unlock();
      }

      // Treat the destination like a regular file.
      final OutputStream out;
      try {
        out = new java.io.FileOutputStream(dst);
      } catch (IOException ex) {
        try {
          in.close();
        } catch (IOException inFailure) {
          throw new InputIOException(inFailure);
        }
        throw ex;
      }

      cp(in, out);
      if (preserve && !dst.setLastModified(time))
        throw new IOException(dst.getPath() + " (cannot preserve last modification time)");
    } catch (ArchiveEntryFalsePositiveException ex) {
      assert srcController == ex.getController();
      // Reroute call to the source's enclosing archive controller.
      cp0(
          preserve,
          srcController.getEnclController(),
          srcController.enclEntryName(srcEntryName),
          dst);
    }
  }
Beispiel #5
0
  /**
   * Returns <code>true</code> if the given file exists or can be created and at least one byte can
   * be successfully written to it - the file is restored to its previous state afterwards. This is
   * a much stronger test than {@link File#canWrite()}.
   *
   * <p>Please note that if the file is actually open for reading or other activities this method
   * may not be able to reset the last modification time of the file after testing, in which case
   * <code>false</code> is returned. This is known to apply to the Windows platform, but not on Unix
   * platforms.
   */
  public static boolean isWritableOrCreatable(final java.io.File file) {
    try {
      if (!file.exists()) {
        final boolean created = file.createNewFile();
        boolean ok = isWritableOrCreatable(file);
        if (created && !file.delete()) ok = false; // be conservative!
        return ok;
      } else if (file.canWrite()) {
        // Some operating and file system combinations make File.canWrite()
        // believe that the file is writable although it's not.
        // We are not that gullible, so let's test this...
        final long time = file.lastModified();
        if (!file.setLastModified(time + 1)) {
          // This may happen on Windows and normally means that
          // somebody else has opened this file
          // (regardless of read or write mode).
          // Be conservative: We don't allow writing to this file!
          return false;
        }

        boolean ok;
        try {
          // Open the file for reading and writing, requiring any
          // update to its contents to be written to the filesystem
          // synchronously.
          // As Dr. Simon White from Catalysoft, Cambridge, UK reported,
          // "rws" does NOT work on Mac OS X with Apple's Java 1.5
          // Release 1 (equivalent to Sun's Java 1.5.0_02), however
          // it DOES work with Apple's Java 1.5 Release 3.
          // He also confirmed that "rwd" works on Apple's
          // Java 1.5 Release 1, so we use this instead.
          // Thank you very much for spending the time to fix this
          // issue, Dr. White!
          final RandomAccessFile raf = new RandomAccessFile(file, "rwd");
          try {
            final boolean empty;
            int octet = raf.read();
            if (octet == -1) {
              octet = 0; // assume first byte is 0
              empty = true;
            } else {
              empty = false;
            }

            // Let's test if we can (over)write the first byte.
            raf.seek(0);
            raf.write((octet ^ -1) & 0xFF); // write complement
            try {
              // Rewrite original content and check success.
              raf.seek(0);
              raf.write(octet);
              raf.seek(0);
              final int check = raf.read();
              // This should always return true unless the storage
              // device is faulty.
              ok = octet == check;
            } finally {
              if (empty) raf.setLength(0);
            }
          } finally {
            raf.close();
          }
        } finally {
          if (!file.setLastModified(time)) {
            // This may happen on Windows and normally means that
            // somebody else has opened this file meanwhile
            // (regardless of read or write mode).
            // Be conservative: We don't allow (further) writing to
            // this file!
            ok = false;
          }
        }
        return ok;
      } else { // if (file.exists() && !file.canWrite()) {
        return false;
      }
    } catch (IOException ex) {
      return false; // don't allow writing if anything goes wrong!
    }
  }