cryptomator / cryptofs

Java Filesystem Provider with integrated encryption
GNU Affero General Public License v3.0
94 stars 35 forks source link

DirectoryNotEmptyException when moving symlink with REPLACE_EXISTING set #177

Open JaniruTEC opened 1 year ago

JaniruTEC commented 1 year ago

Moving a symlink (on top of another symlink) causes a DirectoryNotEmptyException:

var source = fs.getPath("/source");
var target = fs.getPath("/target");
Files.createSymbolicLink(source, fs.getPath("/linkedBySource.txt"));
Files.createSymbolicLink(target, fs.getPath("/linkedByTarget.txt"));

Assertions.assertDoesNotThrow(() -> Files.move(source, target, REPLACE_EXISTING));

Stacktrace:

java.nio.file.DirectoryNotEmptyException: /vault/d/FW/62AD46Y3CLSPBJCAZTO2EQD5TDALWH/y6Yo0PGakzpfU2ZozQWLcHrgiT8=.c9s
    at com.google.common.jimfs.FileSystemView.checkEmpty(FileSystemView.java:493)
    at com.google.common.jimfs.FileSystemView.checkDeletable(FileSystemView.java:477)
    at com.google.common.jimfs.FileSystemView.delete(FileSystemView.java:449)
    at com.google.common.jimfs.FileSystemView.copy(FileSystemView.java:539)
    at com.google.common.jimfs.JimfsFileSystemProvider.copy(JimfsFileSystemProvider.java:268)
    at com.google.common.jimfs.JimfsFileSystemProvider.move(JimfsFileSystemProvider.java:273)
    at java.base/java.nio.file.Files.move(Files.java:1432)
    at org.cryptomator.cryptofs/org.cryptomator.cryptofs.CryptoFileSystemImpl.moveSymlink(CryptoFileSystemImpl.java:585)
    at org.cryptomator.cryptofs/org.cryptomator.cryptofs.CryptoFileSystemImpl.move(CryptoFileSystemImpl.java:573)
    at org.cryptomator.cryptofs/org.cryptomator.cryptofs.MoveOperation.move(MoveOperation.java:37)
    at org.cryptomator.cryptofs/org.cryptomator.cryptofs.CryptoFileSystemProvider.move(CryptoFileSystemProvider.java:255)
    at java.base/java.nio.file.Files.move(Files.java:1432)

The same happens when using a regular filesystem instead of JIMFS.

org.cryptomator.cryptofs/org.cryptomator.cryptofs.CryptoFileSystemImpl.moveSymlink(CryptoFileSystemImpl.java:585):

CiphertextFilePath ciphertextSource = cryptoPathMapper.getCiphertextFilePath(cleartextSource);
CiphertextFilePath ciphertextTarget = cryptoPathMapper.getCiphertextFilePath(cleartextTarget);
try (OpenCryptoFiles.TwoPhaseMove twoPhaseMove = openCryptoFiles.prepareMove(ciphertextSource.getRawPath(), ciphertextTarget.getRawPath())) {
    Files.move(ciphertextSource.getRawPath(), ciphertextTarget.getRawPath(), options); //585
    if (ciphertextTarget.isShortened()) {
        ciphertextTarget.persistLongFileName();
    } else {
        Files.deleteIfExists(ciphertextTarget.getInflatedNamePath()); // no longer needed if not shortened
    }
    twoPhaseMove.commit();
}

Tests showed that both ciphertextSource.getRawPath() and ciphertextTarget.getRawPath() are directories, not regular files. I assume the problem is related to this.