diff --git a/source/net/filebot/StandardRenameAction.java b/source/net/filebot/StandardRenameAction.java index 296b55a8..0aca077f 100644 --- a/source/net/filebot/StandardRenameAction.java +++ b/source/net/filebot/StandardRenameAction.java @@ -2,6 +2,7 @@ package net.filebot; import java.io.File; import java.io.IOException; +import java.nio.file.Files; import net.filebot.util.FileUtilities; @@ -31,7 +32,7 @@ public enum StandardRenameAction implements RenameAction { // move file and the create a symlink to the new location via NIO.2 try { - java.nio.file.Files.move(from.toPath(), destionation.toPath()); + Files.move(from.toPath(), destionation.toPath()); FileUtilities.createRelativeSymlink(from, destionation, true); } catch (LinkageError e) { throw new Exception("Unsupported Operation: move, createSymbolicLink"); @@ -64,12 +65,10 @@ public enum StandardRenameAction implements RenameAction { // create hardlink via NIO.2 try { - java.nio.file.Files.createLink(destionation.toPath(), from.toPath()); + return FileUtilities.createHardLinkStructure(destionation, from); } catch (LinkageError e) { throw new Exception("Unsupported Operation: createLink"); } - - return destionation; } }, diff --git a/source/net/filebot/util/FileUtilities.java b/source/net/filebot/util/FileUtilities.java index b101914a..e59f05a8 100644 --- a/source/net/filebot/util/FileUtilities.java +++ b/source/net/filebot/util/FileUtilities.java @@ -17,11 +17,17 @@ import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.nio.file.AtomicMoveNotSupportedException; +import java.nio.file.FileVisitOption; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; +import java.util.EnumSet; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -58,9 +64,9 @@ public final class FileUtilities { } else { // on Windows ATOMIC_MOVE allows us to rename files even if only lower/upper-case changes (without ATOMIC_MOVE the operation would be ignored) try { - java.nio.file.Files.move(source.toPath(), destination.toPath(), StandardCopyOption.ATOMIC_MOVE); + Files.move(source.toPath(), destination.toPath(), StandardCopyOption.ATOMIC_MOVE); } catch (AtomicMoveNotSupportedException e) { - java.nio.file.Files.move(source.toPath(), destination.toPath(), StandardCopyOption.REPLACE_EXISTING); + Files.move(source.toPath(), destination.toPath(), StandardCopyOption.REPLACE_EXISTING); } } @@ -76,7 +82,7 @@ public final class FileUtilities { org.apache.commons.io.FileUtils.copyDirectory(source, destination); } else { // copy file - java.nio.file.Files.copy(source.toPath(), destination.toPath(), StandardCopyOption.REPLACE_EXISTING); + Files.copy(source.toPath(), destination.toPath(), StandardCopyOption.REPLACE_EXISTING); } return destination; @@ -114,7 +120,30 @@ public final class FileUtilities { } // create symlink via NIO.2 - return java.nio.file.Files.createSymbolicLink(link.toPath(), target.toPath()).toFile(); + return Files.createSymbolicLink(link.toPath(), target.toPath()).toFile(); + } + + public static File createHardLinkStructure(File link, File target) throws IOException { + if (target.isFile()) { + return Files.createLink(link.toPath(), target.toPath()).toFile(); + } + + // if the target is a directory, recreate the structure and hardlink each file item + final Path source = target.getCanonicalFile().toPath(); + final Path destination = link.getCanonicalFile().toPath(); + + Files.walkFileTree(source, EnumSet.of(FileVisitOption.FOLLOW_LINKS), FILE_WALK_MAX_DEPTH, new SimpleFileVisitor() { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Path linkFile = destination.resolve(source.relativize(file)); + Files.createDirectories(linkFile.getParent()); + Files.createLink(linkFile, file); + return FileVisitResult.CONTINUE; + } + }); + + return destination.toFile(); } public static boolean delete(File file) { @@ -391,16 +420,18 @@ public final class FileUtilities { return asList(files); } + public static final int FILE_WALK_MAX_DEPTH = 32; + public static List listFiles(File... folders) { return listFiles(asList(folders)); } public static List listFiles(Iterable folders) { - return listFiles(folders, 32, false, true, false); + return listFiles(folders, FILE_WALK_MAX_DEPTH, false, true, false); } public static List listFolders(Iterable folders) { - return listFiles(folders, 32, false, false, true); + return listFiles(folders, FILE_WALK_MAX_DEPTH, false, false, true); } public static List listFiles(Iterable folders, int maxDepth, boolean addHidden, boolean addFiles, boolean addFolders) {