Skip to content

Commit

Permalink
Actually fix cross-device moving of folders
Browse files Browse the repository at this point in the history
  • Loading branch information
rushsteve1 committed Mar 8, 2022
1 parent 0e6d7fb commit f4041ab
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 11 deletions.
File renamed without changes.
2 changes: 1 addition & 1 deletion source/run.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/

import cli : OPTS, parseOpts;
import operations;
import ops;
import util : createMissingFolders, err, log;
import ver : COPY_TEXT, VER_TEXT;

Expand Down
36 changes: 36 additions & 0 deletions source/tests.d
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,42 @@ unittest {
test_trash_dir.rmdirRecurse();
}

/**
Trash a directory containing a file from /tmp/
On most systems (including mine) this is a separate tempfs so this test is
for cross-filesystem trashing
*/
unittest {
string testdir = "/tmp/tdir";
testdir.mkdir();
string testfile = testdir ~ "/test.file";
testfile.write("hello");
scope (exit)
testdir.rmdirRecurse();
assert(testdir.exists());
assert(testfile.exists());
auto tinfo = TrashFile(testdir, Clock.currTime());

// Trash the file
assert(mini(["-r", testdir]) == 0);

assert(!testdir.exists());
assert(!testfile.exists());
assert(tinfo.file_path.exists());
assert(tinfo.info_path.exists());

// Restore the file
assert(mini(["--restore", "tdir"]) == 0);
assert(testdir.exists());
assert(testfile.exists());
assert(!tinfo.file_path.exists());
assert(!tinfo.info_path.exists());

// Cleanup
scope (success)
test_trash_dir.rmdirRecurse();
}

/**
Test trashing a file that does not have write permissions
*/
Expand Down
24 changes: 14 additions & 10 deletions source/util.d
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import std.stdio : stderr, stdin, writef;
import std.file;
import std.format : format;
import std.string : strip, toLower;
import std.path : buildNormalizedPath;
import std.path : buildNormalizedPath, relativePath, absolutePath;

/**
Prints a formatted error message to stderr with the program name at the
Expand Down Expand Up @@ -89,7 +89,8 @@ void createMissingFolders() {
/**
Attempts to rename a file `src` to `tgt`, but if that fails with `EXDEV` then
the `src` and `tgt` paths are on different devices and cannot be renamed
across. In that case perform a copy then remove
across. In that case perform a copy then remove, descending recursively if
needed.
*/
void renameOrCopy(in string src, in string tgt) {
try {
Expand All @@ -101,14 +102,17 @@ void renameOrCopy(in string src, in string tgt) {
if (src.isFile) {
src.copy(tgt);
src.remove();
} else if (src.isDir) {
foreach(string name; src.dirEntries(SpanMode.shallow)) {
name.renameOrCopy(buildNormalizedPath(tgt, name));
}
src.rmdir();
} else {
err("path was neither file or directory");
}
} else if (src.isDir) {
tgt.mkdir();
foreach (string name; src.dirEntries(SpanMode.shallow)) {
string rel = name.absolutePath().relativePath(src.absolutePath());
string path = buildNormalizedPath(tgt, rel);
name.renameOrCopy(path);
}
src.rmdir();
} else {
err("path was neither file or directory");
}
}
}

Expand Down

0 comments on commit f4041ab

Please sign in to comment.