diff options
| author | Jakob Unterwurzacher | 2017-09-05 22:47:15 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2017-09-05 22:47:15 +0200 | 
| commit | 604b0779d47d39fc5390a67167a8090748843cc1 (patch) | |
| tree | 8e5fbac917a8de6cdb6a185fc49608b07b3af4da /internal | |
| parent | 6f3b65d924d8ab0827516ee274935b2c18979e10 (diff) | |
macos: automatically remove .DS_Store on Rmdir
MacOS sprinkles .DS_Store files everywhere. This is hard to avoid for
users, so handle it transparently in Rmdir().
Mitigates https://github.com/rfjakob/gocryptfs/issues/140
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/fusefrontend/fs_dir.go | 28 | 
1 files changed, 27 insertions, 1 deletions
| diff --git a/internal/fusefrontend/fs_dir.go b/internal/fusefrontend/fs_dir.go index c1bf9bf..b144ea4 100644 --- a/internal/fusefrontend/fs_dir.go +++ b/internal/fusefrontend/fs_dir.go @@ -20,6 +20,8 @@ import (  	"github.com/rfjakob/gocryptfs/internal/tlog"  ) +const dsStoreName = ".DS_Store" +  func (fs *FS) mkdirWithIv(cPath string, mode uint32) error {  	// Between the creation of the directory and the creation of gocryptfs.diriv  	// the directory is inconsistent. Take the lock to prevent other readers @@ -117,6 +119,16 @@ func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fu  	return fuse.OK  } +// haveDsstore return true if one of the entries in "names" is ".DS_Store". +func haveDsstore(names []string) bool { +	for _, n := range names { +		if n == dsStoreName { +			return true +		} +	} +	return false +} +  // Rmdir implements pathfs.FileSystem  func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {  	cPath, err := fs.getBackingPath(path) @@ -175,6 +187,7 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {  	}  	dirfd := os.NewFile(uintptr(dirfdRaw), cName)  	defer dirfd.Close() +retry:  	// Check directory contents  	children, err := dirfd.Readdirnames(10)  	if err == io.EOF { @@ -189,6 +202,18 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {  		tlog.Warn.Printf("Rmdir: Readdirnames: %v", err)  		return fuse.ToStatus(err)  	} +	// MacOS sprinkles .DS_Store files everywhere. This is hard to avoid for +	// users, so handle it transparently here. +	if runtime.GOOS == "darwin" && len(children) <= 2 && haveDsstore(children) { +		ds := filepath.Join(cPath, dsStoreName) +		err = syscall.Unlink(ds) +		if err != nil { +			tlog.Warn.Printf("Rmdir: failed to delete blocking file %q: %v", ds, err) +			return fuse.ToStatus(err) +		} +		tlog.Warn.Printf("Rmdir: had to delete blocking file %q", ds) +		goto retry +	}  	// If the directory is not empty besides gocryptfs.diriv, do not even  	// attempt the dance around gocryptfs.diriv.  	if len(children) > 1 { @@ -236,6 +261,7 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {  	return fuse.OK  } +// If syscallcompat.HaveGetdents is false we will warn once about it  var haveGetdentsWarnOnce sync.Once  // OpenDir implements pathfs.FileSystem @@ -325,7 +351,7 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f  		if err != nil {  			tlog.Warn.Printf("OpenDir %q: invalid entry %q: %v",  				cDirName, cName, err) -			if runtime.GOOS == "darwin" && cName == ".DS_Store" { +			if runtime.GOOS == "darwin" && cName == dsStoreName {  				// MacOS creates lots of these files. Log the warning but don't  				// increment errorCount - does not warrant returning EIO.  				continue | 
