Support CoW clones on both macOS (with APFS) and Linux (with BTRFS) and enable those actions in the GUI

This commit is contained in:
Reinhard Pointner 2017-11-27 18:18:37 +01:00
parent 8ac28f25e4
commit d3c7028710
8 changed files with 46 additions and 28 deletions

View File

@ -11,6 +11,8 @@ import java.nio.file.LinkOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import com.sun.jna.Platform;
import net.filebot.util.FileUtilities;
public enum StandardRenameAction implements RenameAction {
@ -79,6 +81,35 @@ public enum StandardRenameAction implements RenameAction {
}
},
CLONE {
@Override
public File rename(File from, File to) throws Exception {
File dest = FileUtilities.resolveDestination(from, to);
// clonefile or reflink requires filesystem that supports copy-on-write (e.g. apfs or btrfs)
ProcessBuilder process = new ProcessBuilder();
if (Platform.isMac()) {
// -c copy files using clonefile
process.command("cp", "-c", "-f", from.getPath(), dest.getPath());
} else {
// --reflink copy files using reflink
process.command("cp", "--reflink", "--force", from.isDirectory() ? "--recursive" : "--no-target-directory", from.getPath(), dest.getPath());
}
process.directory(from.getParentFile());
process.inheritIO();
int exitCode = process.start().waitFor();
if (exitCode != 0) {
throw new IOException(String.format("%s failed with exit code %d", process.command(), exitCode));
}
return dest;
}
},
DUPLICATE {
@Override
@ -91,26 +122,6 @@ public enum StandardRenameAction implements RenameAction {
}
},
REFLINK {
@Override
public File rename(File from, File to) throws Exception {
File dest = FileUtilities.resolveDestination(from, to);
// reflink requires Linux and a filesystem that supports copy-on-write (e.g. btrfs)
ProcessBuilder process = new ProcessBuilder("cp", "--reflink", "--force", from.isDirectory() ? "--recursive" : "--no-target-directory", from.getPath(), dest.getPath());
process.directory(from.getParentFile());
process.inheritIO();
int exitCode = process.start().waitFor();
if (exitCode != 0) {
throw new IOException(String.format("reflink: %s failed with exit code %d", process.command(), exitCode));
}
return dest;
}
},
TEST {
@Override
@ -136,10 +147,10 @@ public enum StandardRenameAction implements RenameAction {
return "Symlink";
case HARDLINK:
return "Hardlink";
case CLONE:
return "Clone";
case DUPLICATE:
return "Hardlink or Copy";
case REFLINK:
return "Lightweight Copy";
default:
return "Test";
}
@ -157,10 +168,10 @@ public enum StandardRenameAction implements RenameAction {
return "Symlinking";
case HARDLINK:
return "Hardlinking";
case CLONE:
return "Cloning";
case DUPLICATE:
return "Duplicating";
case REFLINK:
return "Reflinking";
default:
return "Testing";
}

View File

@ -60,7 +60,7 @@ public class ArgumentBean {
@Option(name = "--order", usage = "Episode order", metaVar = "[Airdate, Absolute, DVD]")
public String order = "Airdate";
@Option(name = "--action", usage = "Rename action", metaVar = "[move, copy, keeplink, symlink, hardlink, reflink, test]")
@Option(name = "--action", usage = "Rename action", metaVar = "[move, copy, keeplink, symlink, hardlink, clone, test]")
public String action = "move";
@Option(name = "--conflict", usage = "Conflict resolution", metaVar = "[skip, override, auto, index, fail]")

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -2,6 +2,7 @@ package net.filebot.ui.rename;
import static java.util.Collections.*;
import static net.filebot.Logging.*;
import static net.filebot.Settings.*;
import static net.filebot.WebServices.*;
import static net.filebot.util.FileUtilities.*;
@ -147,7 +148,14 @@ public class Preset {
}
public static StandardRenameAction[] getSupportedActions() {
return new StandardRenameAction[] { StandardRenameAction.MOVE, StandardRenameAction.COPY, StandardRenameAction.KEEPLINK, StandardRenameAction.SYMLINK, StandardRenameAction.HARDLINK };
if (isWindowsApp()) {
// CoW clones not supported on Windows
return new StandardRenameAction[] { StandardRenameAction.MOVE, StandardRenameAction.COPY, StandardRenameAction.KEEPLINK, StandardRenameAction.SYMLINK, StandardRenameAction.HARDLINK };
} else {
// CoW clones / reflinks supported on macOS and Linux
return new StandardRenameAction[] { StandardRenameAction.MOVE, StandardRenameAction.COPY, StandardRenameAction.KEEPLINK, StandardRenameAction.SYMLINK, StandardRenameAction.HARDLINK, StandardRenameAction.CLONE };
}
}
public static Language[] getSupportedLanguages() {

View File

@ -22,7 +22,6 @@ import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@ -547,7 +546,7 @@ public class RenamePanel extends JComponent {
actionPopup.addSeparator();
actionPopup.addDescription(new JLabel("Action:"));
for (StandardRenameAction action : EnumSet.of(StandardRenameAction.MOVE, StandardRenameAction.COPY, StandardRenameAction.KEEPLINK, StandardRenameAction.SYMLINK, StandardRenameAction.HARDLINK)) {
for (StandardRenameAction action : Preset.getSupportedActions()) {
actionPopup.add(new SetRenameAction(action));
}