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
This commit is contained in:
parent
6f3b65d924
commit
604b0779d4
@ -20,6 +20,8 @@ import (
|
|||||||
"github.com/rfjakob/gocryptfs/internal/tlog"
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const dsStoreName = ".DS_Store"
|
||||||
|
|
||||||
func (fs *FS) mkdirWithIv(cPath string, mode uint32) error {
|
func (fs *FS) mkdirWithIv(cPath string, mode uint32) error {
|
||||||
// Between the creation of the directory and the creation of gocryptfs.diriv
|
// Between the creation of the directory and the creation of gocryptfs.diriv
|
||||||
// the directory is inconsistent. Take the lock to prevent other readers
|
// 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
|
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
|
// Rmdir implements pathfs.FileSystem
|
||||||
func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
|
func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
|
||||||
cPath, err := fs.getBackingPath(path)
|
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)
|
dirfd := os.NewFile(uintptr(dirfdRaw), cName)
|
||||||
defer dirfd.Close()
|
defer dirfd.Close()
|
||||||
|
retry:
|
||||||
// Check directory contents
|
// Check directory contents
|
||||||
children, err := dirfd.Readdirnames(10)
|
children, err := dirfd.Readdirnames(10)
|
||||||
if err == io.EOF {
|
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)
|
tlog.Warn.Printf("Rmdir: Readdirnames: %v", err)
|
||||||
return fuse.ToStatus(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
|
// If the directory is not empty besides gocryptfs.diriv, do not even
|
||||||
// attempt the dance around gocryptfs.diriv.
|
// attempt the dance around gocryptfs.diriv.
|
||||||
if len(children) > 1 {
|
if len(children) > 1 {
|
||||||
@ -236,6 +261,7 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
|
|||||||
return fuse.OK
|
return fuse.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If syscallcompat.HaveGetdents is false we will warn once about it
|
||||||
var haveGetdentsWarnOnce sync.Once
|
var haveGetdentsWarnOnce sync.Once
|
||||||
|
|
||||||
// OpenDir implements pathfs.FileSystem
|
// OpenDir implements pathfs.FileSystem
|
||||||
@ -325,7 +351,7 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("OpenDir %q: invalid entry %q: %v",
|
tlog.Warn.Printf("OpenDir %q: invalid entry %q: %v",
|
||||||
cDirName, cName, err)
|
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
|
// MacOS creates lots of these files. Log the warning but don't
|
||||||
// increment errorCount - does not warrant returning EIO.
|
// increment errorCount - does not warrant returning EIO.
|
||||||
continue
|
continue
|
||||||
|
Loading…
Reference in New Issue
Block a user