@Override public void copyFrom(Directory from, String srcFile, String destFile, IOContext context) throws IOException { final Directory fromUnwrapped = FilterDirectory.unwrap(from); final Directory toUnwrapped = FilterDirectory.unwrap(this); // try to unwrap to FSDirectory - we might be able to just create hard-links of these files and // save copying // the entire file. Exception suppressedException = null; boolean tryCopy = true; if (fromUnwrapped instanceof FSDirectory && toUnwrapped instanceof FSDirectory) { final Path fromPath = ((FSDirectory) fromUnwrapped).getDirectory(); final Path toPath = ((FSDirectory) toUnwrapped).getDirectory(); if (Files.isReadable(fromPath.resolve(srcFile)) && Files.isWritable(toPath)) { // only try hardlinks if we have permission to access the files // if not super.copyFrom() will give us the right exceptions suppressedException = AccessController.doPrivileged( (PrivilegedAction<Exception>) () -> { try { Files.createLink(toPath.resolve(destFile), fromPath.resolve(srcFile)); } catch (FileNotFoundException | NoSuchFileException | FileAlreadyExistsException ex) { return ex; // in these cases we bubble up since it's a true error condition. } catch (IOException | UnsupportedOperationException // if the FS doesn't support hard-links | SecurityException ex // we don't have permission to use hard-links just fall back to // byte copy ) { // hard-links are not supported or the files are on different filesystems // we could go deeper and check if their filesstores are the same and opt // out earlier but for now we just fall back to normal file-copy return ex; } return null; }); tryCopy = suppressedException != null; } } if (tryCopy) { try { super.copyFrom(from, srcFile, destFile, context); } catch (Exception ex) { if (suppressedException != null) { ex.addSuppressed(suppressedException); } throw ex; } } }
public void createSymLink(Path symLink, Path realFile, boolean force) throws IOException { symLink = resolve(symLink); if (force) { Files.deleteIfExists(symLink); } if (Platform.detect() == Platform.WINDOWS) { if (isDirectory(realFile)) { // Creating symlinks to directories on Windows requires escalated privileges. We're just // going to have to copy things recursively. MoreFiles.copyRecursively(realFile, symLink); } else { // When sourcePath is relative, resolve it from the targetPath. We're creating a hard link // anyway. realFile = symLink.getParent().resolve(realFile).normalize(); Files.createLink(symLink, realFile); } } else { Files.createSymbolicLink(symLink, realFile); } }
public static void copyFile(File source, File destination, boolean hardLinks) { if (!source.exists()) { return; } if (hardLinks && !Config.getBooleanProperty("CONTENT_VERSION_HARD_LINK", true)) { hardLinks = false; } if ((destination.getParentFile() != null) && (!destination.getParentFile().exists())) { destination.getParentFile().mkdirs(); } if (hardLinks) { // I think we need to be sure to unlink first if (destination.exists()) { Path destinationPath = Paths.get(destination.getAbsolutePath()); try { // "If the file is a symbolic link then the symbolic link itself, not the final target of // the link, is deleted." Files.delete(destinationPath); } catch (IOException e) { Logger.error( FileUtil.class, "Error removing hardLink: " + destination.getAbsolutePath(), e); } } try { Path newLink = Paths.get(destination.getAbsolutePath()); Path existingFile = Paths.get(source.getAbsolutePath()); Files.createLink(newLink, existingFile); // setting this means we will try again if we cannot hard link if (!destination.exists()) { hardLinks = false; } } catch (IOException e) { Logger.error( FileUtil.class, "Can't create hardLink. source: " + source.getAbsolutePath() + ", destination: " + destination.getAbsolutePath()); // setting this means we will try again if we cannot hard link hardLinks = false; } } if (!hardLinks) { FileChannel srcChannel = null; FileChannel dstChannel = null; try { srcChannel = new FileInputStream(source).getChannel(); dstChannel = new FileOutputStream(destination).getChannel(); dstChannel.transferFrom(srcChannel, 0, srcChannel.size()); } catch (IOException ioe) { Logger.error(FileUtil.class, ioe.getMessage(), ioe); } finally { try { srcChannel.close(); dstChannel.close(); } catch (IOException ioe) { Logger.error(FileUtil.class, ioe.getMessage(), ioe); } } } }