mirror of
https://github.com/mitb-archive/filebot
synced 2024-12-23 16:28:51 -05:00
225 lines
5.3 KiB
Java
225 lines
5.3 KiB
Java
package net.filebot;
|
|
|
|
import static java.util.Arrays.*;
|
|
import static java.util.stream.Collectors.*;
|
|
import static net.filebot.UserFiles.*;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.LinkOption;
|
|
import java.nio.file.attribute.BasicFileAttributes;
|
|
import java.util.List;
|
|
|
|
import net.filebot.util.FileUtilities;
|
|
|
|
public enum StandardRenameAction implements RenameAction {
|
|
|
|
MOVE {
|
|
|
|
@Override
|
|
public File rename(File from, File to) throws Exception {
|
|
return FileUtilities.moveRename(from, to);
|
|
}
|
|
},
|
|
|
|
COPY {
|
|
|
|
@Override
|
|
public File rename(File from, File to) throws Exception {
|
|
return FileUtilities.copyAs(from, to);
|
|
}
|
|
},
|
|
|
|
KEEPLINK {
|
|
|
|
@Override
|
|
public File rename(File from, File to) throws Exception {
|
|
File dest = FileUtilities.resolveDestination(from, to);
|
|
|
|
// move file and the create a symlink to the new location via NIO.2
|
|
try {
|
|
Files.move(from.toPath(), dest.toPath());
|
|
FileUtilities.createRelativeSymlink(from, dest, true);
|
|
} catch (LinkageError e) {
|
|
throw new Exception("Unsupported Operation: move, createSymbolicLink");
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
},
|
|
|
|
SYMLINK {
|
|
|
|
@Override
|
|
public File rename(File from, File to) throws Exception {
|
|
File dest = FileUtilities.resolveDestination(from, to);
|
|
|
|
// create symlink via NIO.2
|
|
try {
|
|
return FileUtilities.createRelativeSymlink(dest, from, true);
|
|
} catch (LinkageError e) {
|
|
throw new Exception("Unsupported Operation: createSymbolicLink");
|
|
}
|
|
}
|
|
},
|
|
|
|
HARDLINK {
|
|
|
|
@Override
|
|
public File rename(File from, File to) throws Exception {
|
|
File dest = FileUtilities.resolveDestination(from, to);
|
|
|
|
// create hardlink via NIO.2
|
|
try {
|
|
return FileUtilities.createHardLinkStructure(dest, from);
|
|
} catch (LinkageError e) {
|
|
throw new Exception("Unsupported Operation: createLink");
|
|
}
|
|
}
|
|
},
|
|
|
|
DUPLICATE {
|
|
|
|
@Override
|
|
public File rename(File from, File to) throws Exception {
|
|
try {
|
|
return HARDLINK.rename(from, to);
|
|
} catch (Exception e) {
|
|
return COPY.rename(from, to);
|
|
}
|
|
}
|
|
},
|
|
|
|
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
|
|
public File rename(File from, File to) throws IOException {
|
|
return FileUtilities.resolve(from, to);
|
|
}
|
|
|
|
@Override
|
|
public boolean canRevert() {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
public String getDisplayName() {
|
|
switch (this) {
|
|
case MOVE:
|
|
return "Rename";
|
|
case COPY:
|
|
return "Copy";
|
|
case KEEPLINK:
|
|
return "Keeplink";
|
|
case SYMLINK:
|
|
return "Symlink";
|
|
case HARDLINK:
|
|
return "Hardlink";
|
|
case DUPLICATE:
|
|
return "Hardlink or Copy";
|
|
case REFLINK:
|
|
return "Lightweight Copy";
|
|
default:
|
|
return "Test";
|
|
}
|
|
}
|
|
|
|
public String getDisplayVerb() {
|
|
switch (this) {
|
|
case MOVE:
|
|
return "Moving";
|
|
case COPY:
|
|
return "Copying";
|
|
case KEEPLINK:
|
|
return "Moving and symlinking";
|
|
case SYMLINK:
|
|
return "Symlinking";
|
|
case HARDLINK:
|
|
return "Hardlinking";
|
|
case DUPLICATE:
|
|
return "Duplicating";
|
|
case REFLINK:
|
|
return "Reflinking";
|
|
default:
|
|
return "Testing";
|
|
}
|
|
}
|
|
|
|
public static List<String> names() {
|
|
return stream(values()).map(Enum::name).collect(toList());
|
|
}
|
|
|
|
public static StandardRenameAction forName(String name) {
|
|
for (StandardRenameAction action : values()) {
|
|
if (action.name().equalsIgnoreCase(name)) {
|
|
return action;
|
|
}
|
|
}
|
|
|
|
throw new IllegalArgumentException(String.format("%s not in %s", name, names()));
|
|
}
|
|
|
|
public static File revert(File current, File original) throws IOException {
|
|
// do nothing if current and original path is exactly the same
|
|
if (current.equals(original)) {
|
|
return original;
|
|
}
|
|
|
|
// reverse move
|
|
if (current.exists() && !original.exists()) {
|
|
return FileUtilities.moveRename(current, original);
|
|
}
|
|
|
|
BasicFileAttributes currentAttr = Files.readAttributes(current.toPath(), BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
|
|
BasicFileAttributes originalAttr = Files.readAttributes(original.toPath(), BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
|
|
|
|
// reverse symlink
|
|
if (currentAttr.isSymbolicLink() && !originalAttr.isSymbolicLink()) {
|
|
trash(current);
|
|
return original;
|
|
}
|
|
|
|
// reverse keeplink
|
|
if (!currentAttr.isSymbolicLink() && originalAttr.isSymbolicLink()) {
|
|
trash(original);
|
|
return FileUtilities.moveRename(current, original);
|
|
}
|
|
|
|
// reverse copy / hardlink
|
|
if (currentAttr.isRegularFile() && originalAttr.isRegularFile()) {
|
|
trash(current);
|
|
return original;
|
|
}
|
|
|
|
// reverse folder copy
|
|
if (currentAttr.isDirectory() && originalAttr.isDirectory()) {
|
|
trash(original);
|
|
return FileUtilities.moveRename(current, original);
|
|
}
|
|
|
|
throw new IllegalArgumentException(String.format("Cannot revert file: %s => %s", current, original));
|
|
}
|
|
|
|
}
|