diff --git a/source/net/filebot/CacheManager.java b/source/net/filebot/CacheManager.java index c292de9e..08501919 100644 --- a/source/net/filebot/CacheManager.java +++ b/source/net/filebot/CacheManager.java @@ -58,8 +58,10 @@ public class CacheManager { private void clearDiskStore(File cache) { getChildren(cache).stream().filter(f -> f.isFile() && !f.getName().startsWith(".")).forEach(f -> { - if (!delete(f)) { - debug.warning(format("Failed to delete cache: %s", f.getName())); + try { + delete(f); + } catch (Exception e) { + debug.warning(format("Failed to delete cache: %s => %s", f, e)); } }); } diff --git a/source/net/filebot/Main.java b/source/net/filebot/Main.java index e03e5a72..c5162298 100644 --- a/source/net/filebot/Main.java +++ b/source/net/filebot/Main.java @@ -86,11 +86,8 @@ public class Main { if (args.clearCache()) { System.out.println("Clear cache"); for (File folder : getChildren(ApplicationFolder.Cache.getCanonicalFile(), FOLDERS)) { - if (delete(folder)) { - System.out.println("* Delete " + folder); - } else { - System.out.println("* Failed to delete " + folder); - } + System.out.println("Delete " + folder); + delete(folder); } } diff --git a/source/net/filebot/NativeRenameAction.java b/source/net/filebot/NativeRenameAction.java index 89d6a315..b3b6dcc3 100644 --- a/source/net/filebot/NativeRenameAction.java +++ b/source/net/filebot/NativeRenameAction.java @@ -1,9 +1,11 @@ package net.filebot; import static java.util.Collections.*; +import static net.filebot.Logging.*; import static net.filebot.util.FileUtilities.*; import java.io.File; +import java.io.IOException; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.CancellationException; @@ -64,4 +66,27 @@ public enum NativeRenameAction implements RenameAction { } } + public static void trash(File file) throws IOException { + // use system trash if possible + try { + if (Platform.isMac()) { + // use com.apple.eio package on OS X platform + if (com.apple.eio.FileManager.moveToTrash(file)) { + return; + } + } else if (com.sun.jna.platform.FileUtils.getInstance().hasTrash()) { + // use com.sun.jna.platform package on Windows and Linux + com.sun.jna.platform.FileUtils.getInstance().moveToTrash(new File[] { file }); + return; + } + } catch (Exception e) { + debug.warning(e::toString); + } + + // delete permanently if necessary + if (file.exists()) { + net.filebot.util.FileUtilities.delete(file); + } + } + } diff --git a/source/net/filebot/StandardRenameAction.java b/source/net/filebot/StandardRenameAction.java index 66d31fb7..1efb82b0 100644 --- a/source/net/filebot/StandardRenameAction.java +++ b/source/net/filebot/StandardRenameAction.java @@ -149,29 +149,29 @@ public enum StandardRenameAction implements RenameAction { // reverse symlink if (currentAttr.isSymbolicLink() && !originalAttr.isSymbolicLink()) { - Files.delete(current.toPath()); + NativeRenameAction.trash(current); return original; } // reverse keeplink if (!currentAttr.isSymbolicLink() && originalAttr.isSymbolicLink()) { - Files.delete(original.toPath()); + NativeRenameAction.trash(original); return FileUtilities.moveRename(current, original); } // reverse copy / hardlink if (currentAttr.isRegularFile() && originalAttr.isRegularFile()) { - Files.delete(current.toPath()); + NativeRenameAction.trash(current); return original; } // reverse folder copy if (currentAttr.isDirectory() && originalAttr.isDirectory()) { - FileUtilities.delete(original); + NativeRenameAction.trash(original); return FileUtilities.moveRename(current, original); } - throw new IllegalArgumentException(String.format("Cannot revert files: %s => %s", current, original)); + throw new IllegalArgumentException(String.format("Cannot revert file: %s => %s", current, original)); } } diff --git a/source/net/filebot/ui/rename/RenameAction.java b/source/net/filebot/ui/rename/RenameAction.java index bcd52eaa..bf71ec64 100644 --- a/source/net/filebot/ui/rename/RenameAction.java +++ b/source/net/filebot/ui/rename/RenameAction.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.AbstractList; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -41,8 +40,6 @@ import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JScrollPane; -import com.sun.jna.platform.FileUtils; - import net.filebot.HistorySpooler; import net.filebot.NativeRenameAction; import net.filebot.ResourceManager; @@ -153,7 +150,7 @@ class RenameAction extends AbstractAction { private void deleteEmptyFolders(Map renameMap) { // collect empty folders and files in reverse order - Set empty = new TreeSet(); + Set deleteFiles = new TreeSet(); renameMap.forEach((s, d) -> { File sourceFolder = s.getParentFile(); @@ -170,12 +167,12 @@ class RenameAction extends AbstractAction { for (int i = 0; i < tailSize && !isStructureRoot(sourceFolder); sourceFolder = sourceFolder.getParentFile(), i++) { File[] children = sourceFolder.listFiles(); - if (children == null || !stream(children).allMatch(f -> empty.contains(f) || isThumbnailStore(f))) { + if (children == null || !stream(children).allMatch(f -> deleteFiles.contains(f) || isThumbnailStore(f))) { return; } - stream(children).forEach(empty::add); - empty.add(sourceFolder); + stream(children).forEach(deleteFiles::add); + deleteFiles.add(sourceFolder); } } catch (Exception e) { debug.warning(e::toString); @@ -183,22 +180,10 @@ class RenameAction extends AbstractAction { }); // use system trash to delete left-behind empty folders / hidden files - moveToTrash(empty); - } - - protected void moveToTrash(Collection files) { try { - for (File f : files) { - if (!f.exists()) { - continue; - } - - if (isMacApp()) { - // use com.apple.eio package on OS X platform - MacAppUtilities.moveToTrash(f); - } else { - // use com.sun.jna.platform package on Windows and Linux - FileUtils.getInstance().moveToTrash(new File[] { f }); + for (File file : deleteFiles) { + if (file.exists()) { + NativeRenameAction.trash(file); } } } catch (Throwable e) { diff --git a/source/net/filebot/util/FileUtilities.java b/source/net/filebot/util/FileUtilities.java index 0444d632..57b2c000 100644 --- a/source/net/filebot/util/FileUtilities.java +++ b/source/net/filebot/util/FileUtilities.java @@ -67,7 +67,7 @@ public final class FileUtilities { // on Windows, use ATOMIC_MOVE which allows us to rename files even if only lower/upper-case changes (without ATOMIC_MOVE the operation would be ignored) // but ATOMIC_MOVE can only work for files on the same drive, if that is not the case there is no point trying move with ATOMIC_MOVE - if (File.separator.equals("\\") && source.equals(destination)) { + if (isWindows() && source.equals(destination) && !equalsCaseSensitive(source, destination)) { try { return Files.move(source.toPath(), destination.toPath(), StandardCopyOption.ATOMIC_MOVE).toFile(); } catch (AtomicMoveNotSupportedException e) { @@ -152,9 +152,25 @@ public final class FileUtilities { return destination.toFile(); } - public static boolean delete(File file) { - // delete files or files - return FileUtils.deleteQuietly(file); + public static void delete(File file) throws IOException { + if (file.isDirectory()) { + Files.walkFileTree(file.toPath(), new SimpleFileVisitor() { + + @Override + public FileVisitResult visitFile(Path f, BasicFileAttributes attr) throws IOException { + Files.delete(f); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path f, IOException e) throws IOException { + Files.delete(f); + return FileVisitResult.CONTINUE; + } + }); + } else { + Files.delete(file.toPath()); + } } public static File createFolders(File folder) throws IOException { @@ -225,6 +241,14 @@ public final class FileUtilities { return UTF_8.decode(data).toString(); } + public static boolean isWindows() { + return '\\' == File.separatorChar; + } + + public static boolean equalsCaseSensitive(File a, File b) { + return a.getPath().equals(b.getPath()); + } + /** * Pattern used for matching file extensions. *