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! }
/** * Removes the entire directory tree represented by the parameter, regardless whether it's a file * or directory, whether the directory is empty or not or whether the file or directory is * actually an archive file, an entry in an archive file or not enclosed in an archive file at * all. * * <p>The name of this method is inspired by the Unix command line utility <code>rm</code> with * the <code>-r</code> option to operate recursively. * * <p>This file system operation is <em>not</em> atomic. * * @return Whether or not the entire directory tree was successfully removed. */ public static boolean rm_r(final java.io.File file) { boolean ok = true; if (file.isDirectory()) { // Note that listing the directory this way will cause a recursive // deletion if the directory is actually an archive file. // Although this does not provide best performance (the archive // file could simply be removed like an ordinary file), it ensures // that the state cached by the ArchiveController is not bypassed // and hence prevents a potential bug. java.io.File[] members = file.listFiles(); for (int i = members.length; --i >= 0; ) ok &= rm_r(members[i]); } return ok && file.delete(); }
/** Unchecked parameters version. */ private static void cp0(final boolean preserve, final java.io.File src, final java.io.File dst) throws IOException { assert src != null; assert dst != null; try { try { if (src instanceof File) { final File srcFile = (File) src; srcFile.ensureNotVirtualRoot("cannot read"); final String srcEntryName = srcFile.getEnclEntryName(); if (srcEntryName != null) { cp0(preserve, srcFile.getEnclArchive().getArchiveController(), srcEntryName, dst); return; } } } catch (RfsEntryFalsePositiveException srcIsNotArchive) { } // Treat the source like a regular file. final InputStream in = new java.io.FileInputStream(src); try { cp0(preserve, src, in, dst); } finally { try { in.close(); } catch (IOException ex) { throw new InputIOException(ex); } } } catch (FileNotFoundException ex) { throw ex; } catch (ArchiveBusyException ex) { throw new FileBusyException(ex); } catch (ArchiveFileSystemException afse) { final FileNotFoundException fnfe = new FileNotFoundException(afse.toString()); fnfe.initCause(afse); throw fnfe; } catch (IOException ex) { dst.delete(); throw ex; } }
/** * 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! } }