aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Lackner2017-11-25 01:56:56 +0100
committerrfjakob2017-11-25 16:19:09 +0100
commit9f56b33e0c8701085189aa77463f1b471b70a705 (patch)
tree924753e68c55dec84048c58678eb90f9361f3ea6
parentd257bb34c1dd478cdb62c0d19c3e280d4f8649b4 (diff)
fusefrontend: Fix longname handling for renames with existing target
Fixes https://github.com/rfjakob/gocryptfs/issues/170 Steps to reproduce the problem: * Create a regular forward mount point * Create a file with a shortname and one with a long filename * Try to run 'mv <shortname> <longname>' This should actually work and replace the existing file, but instead it fails with: mv: cannot move '<shortname>' to '<longname>': File exists The problem is the creation of the .name file. If the target already exists we can safely ignore the EEXIST error and just keep the existing .name file.
-rw-r--r--internal/fusefrontend/fs.go8
-rw-r--r--internal/nametransform/longnames.go6
-rw-r--r--tests/matrix/matrix_test.go45
3 files changed, 54 insertions, 5 deletions
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go
index 3c442a5..b4819fd 100644
--- a/internal/fusefrontend/fs.go
+++ b/internal/fusefrontend/fs.go
@@ -517,7 +517,13 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod
finalNewPath = cNewName
// Create destination .name file
err = fs.nameTransform.WriteLongName(newDirFd, cNewName, newPath)
- if err != nil {
+ // Failure to write the .name file is expected when the target path already
+ // exists. Since hashes are pretty unique, there is no need to modify the
+ // file anyway. We still set newDirFd to nil to ensure that we do not delete
+ // the file on error.
+ if err == syscall.EEXIST {
+ newDirFd = nil
+ } else if err != nil {
return fuse.ToStatus(err)
}
}
diff --git a/internal/nametransform/longnames.go b/internal/nametransform/longnames.go
index 8af191d..7cd904e 100644
--- a/internal/nametransform/longnames.go
+++ b/internal/nametransform/longnames.go
@@ -114,7 +114,11 @@ func (n *NameTransform) WriteLongName(dirfd *os.File, hashName string, plainName
fdRaw, err := syscallcompat.Openat(int(dirfd.Fd()), hashName+LongNameSuffix,
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL, 0600)
if err != nil {
- tlog.Warn.Printf("WriteLongName: Openat: %v", err)
+ // Don't warn if the file already exists - this is allowed for renames
+ // and should be handled by the caller.
+ if err != syscall.EEXIST {
+ tlog.Warn.Printf("WriteLongName: Openat: %v", err)
+ }
return err
}
fd := os.NewFile(uintptr(fdRaw), hashName+LongNameSuffix)
diff --git a/tests/matrix/matrix_test.go b/tests/matrix/matrix_test.go
index 88c255e..9b9cb1b 100644
--- a/tests/matrix/matrix_test.go
+++ b/tests/matrix/matrix_test.go
@@ -544,7 +544,7 @@ func TestLongNames(t *testing.T) {
if !test_helpers.VerifyExistence(wd + n255x) {
t.Errorf("n255x is not in directory listing")
}
- // Rename long to long
+ // Rename long to long (target does not exist)
n255y := string(bytes.Repeat([]byte("y"), 255))
err = os.Rename(wd+n255x, wd+n255y)
if err != nil {
@@ -553,7 +553,20 @@ func TestLongNames(t *testing.T) {
if !test_helpers.VerifyExistence(wd + n255y) {
t.Errorf("n255y is not in directory listing")
}
- // Rename long to short
+ // Rename long to long (target exists)
+ f, err = os.Create(wd + n255x)
+ if err != nil {
+ t.Fatalf("Could not create n255x: %v", err)
+ }
+ f.Close()
+ err = os.Rename(wd+n255x, wd+n255y)
+ if err != nil {
+ t.Fatalf("Could not rename n255x to n255y: %v", err)
+ }
+ if !test_helpers.VerifyExistence(wd + n255y) {
+ t.Errorf("n255y is not in directory listing")
+ }
+ // Rename long to short (target does not exist)
err = os.Rename(wd+n255y, wd+"short")
if err != nil {
t.Fatalf("Could not rename n255y to short: %v", err)
@@ -561,7 +574,20 @@ func TestLongNames(t *testing.T) {
if !test_helpers.VerifyExistence(wd + "short") {
t.Errorf("short is not in directory listing")
}
- // Rename short to long
+ // Rename long to short (target exists)
+ f, err = os.Create(wd + n255y)
+ if err != nil {
+ t.Fatalf("Could not create n255y: %v", err)
+ }
+ f.Close()
+ err = os.Rename(wd+n255y, wd+"short")
+ if err != nil {
+ t.Fatalf("Could not rename n255y to short: %v", err)
+ }
+ if !test_helpers.VerifyExistence(wd + "short") {
+ t.Errorf("short is not in directory listing")
+ }
+ // Rename short to long (target does not exist)
err = os.Rename(wd+"short", wd+n255x)
if err != nil {
t.Fatalf("Could not rename short to n255x: %v", err)
@@ -569,6 +595,19 @@ func TestLongNames(t *testing.T) {
if !test_helpers.VerifyExistence(wd + n255x) {
t.Errorf("255x is not in directory listing II")
}
+ // Rename short to long (target exists)
+ f, err = os.Create(wd + "short")
+ if err != nil {
+ t.Fatalf("Could not create short: %v", err)
+ }
+ f.Close()
+ err = os.Rename(wd+"short", wd+n255x)
+ if err != nil {
+ t.Fatalf("Could not rename short to n255x: %v", err)
+ }
+ if !test_helpers.VerifyExistence(wd + n255x) {
+ t.Errorf("n255x is not in directory listing")
+ }
// Unlink
err = syscall.Unlink(wd + n255x)
if err != nil {