fusefrontend: relay Utimens to go-fuse
Commit af5441dcd9
has caused a
regression ( https://github.com/rfjakob/gocryptfs/issues/35 )
that is fixed by this commit.
The go-fuse library by now has all the syscall wrappers in
place to correctly handle Utimens, also for symlinks.
Instead of duplicating the effort here just call into go-fuse.
Closes #35
This commit is contained in:
parent
8f1e51789d
commit
fca1b82417
|
@ -33,18 +33,16 @@ type file struct {
|
||||||
// Every FUSE entrypoint should RLock(). The only user of Lock() is
|
// Every FUSE entrypoint should RLock(). The only user of Lock() is
|
||||||
// Release(), which closes the fd and sets "released" to true.
|
// Release(), which closes the fd and sets "released" to true.
|
||||||
fdLock sync.RWMutex
|
fdLock sync.RWMutex
|
||||||
|
|
||||||
// Was the file opened O_WRONLY?
|
// Was the file opened O_WRONLY?
|
||||||
writeOnly bool
|
writeOnly bool
|
||||||
|
|
||||||
// Content encryption helper
|
// Content encryption helper
|
||||||
contentEnc *contentenc.ContentEnc
|
contentEnc *contentenc.ContentEnc
|
||||||
|
|
||||||
// Inode number
|
// Inode number
|
||||||
ino uint64
|
ino uint64
|
||||||
|
|
||||||
// File header
|
// File header
|
||||||
header *contentenc.FileHeader
|
header *contentenc.FileHeader
|
||||||
|
// go-fuse nodefs.loopbackFile
|
||||||
|
loopbackFile nodefs.File
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFile(fd *os.File, writeOnly bool, contentEnc *contentenc.ContentEnc) (nodefs.File, fuse.Status) {
|
func NewFile(fd *os.File, writeOnly bool, contentEnc *contentenc.ContentEnc) (nodefs.File, fuse.Status) {
|
||||||
|
@ -57,10 +55,11 @@ func NewFile(fd *os.File, writeOnly bool, contentEnc *contentenc.ContentEnc) (no
|
||||||
wlock.register(st.Ino)
|
wlock.register(st.Ino)
|
||||||
|
|
||||||
return &file{
|
return &file{
|
||||||
fd: fd,
|
fd: fd,
|
||||||
writeOnly: writeOnly,
|
writeOnly: writeOnly,
|
||||||
contentEnc: contentEnc,
|
contentEnc: contentEnc,
|
||||||
ino: st.Ino,
|
ino: st.Ino,
|
||||||
|
loopbackFile: nodefs.NewLoopbackFile(fd),
|
||||||
}, fuse.OK
|
}, fuse.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,41 +385,8 @@ func (f *file) GetAttr(a *fuse.Attr) fuse.Status {
|
||||||
return fuse.OK
|
return fuse.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
const _UTIME_OMIT = ((1 << 30) - 2)
|
|
||||||
|
|
||||||
// utimeToTimespec converts a "time.Time" pointer as passed to Utimens to a
|
|
||||||
// Timespec that can be passed to the utimensat syscall.
|
|
||||||
func utimeToTimespec(t *time.Time) (ts syscall.Timespec) {
|
|
||||||
if t == nil {
|
|
||||||
ts.Nsec = _UTIME_OMIT
|
|
||||||
} else {
|
|
||||||
ts = syscall.NsecToTimespec(t.UnixNano())
|
|
||||||
// For dates before 1970, NsecToTimespec incorrectly returns negative
|
|
||||||
// nanoseconds. Ticket: https://github.com/golang/go/issues/12777
|
|
||||||
if ts.Nsec < 0 {
|
|
||||||
ts.Nsec = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ts
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *file) Utimens(a *time.Time, m *time.Time) fuse.Status {
|
func (f *file) Utimens(a *time.Time, m *time.Time) fuse.Status {
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
|
return f.loopbackFile.Utimens(a, m)
|
||||||
ts := make([]syscall.Timespec, 2)
|
|
||||||
ts[0] = utimeToTimespec(a)
|
|
||||||
ts[1] = utimeToTimespec(m)
|
|
||||||
|
|
||||||
fn := fmt.Sprintf("/proc/self/fd/%d", f.fd.Fd())
|
|
||||||
err := syscall.UtimesNano(fn, ts)
|
|
||||||
if err != nil {
|
|
||||||
tlog.Debug.Printf("UtimesNano on %q failed: %v", fn, err)
|
|
||||||
}
|
|
||||||
if err == syscall.ENOENT {
|
|
||||||
// If /proc/self/fd/X did not exist, the actual error is that the file
|
|
||||||
// descriptor was invalid.
|
|
||||||
return fuse.EBADF
|
|
||||||
}
|
|
||||||
return fuse.ToStatus(err)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,14 +234,11 @@ func (fs *FS) Utimens(path string, a *time.Time, m *time.Time, context *fuse.Con
|
||||||
if fs.isFiltered(path) {
|
if fs.isFiltered(path) {
|
||||||
return fuse.EPERM
|
return fuse.EPERM
|
||||||
}
|
}
|
||||||
cPath, err := fs.getBackingPath(path)
|
cPath, err := fs.encryptPath(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
ts := make([]syscall.Timespec, 2)
|
return fs.FileSystem.Utimens(cPath, a, m, context)
|
||||||
ts[0] = utimeToTimespec(a)
|
|
||||||
ts[1] = utimeToTimespec(m)
|
|
||||||
return fuse.ToStatus(syscall.UtimesNano(cPath, ts))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) StatFs(path string) *fuse.StatfsOut {
|
func (fs *FS) StatFs(path string) *fuse.StatfsOut {
|
||||||
|
|
Loading…
Reference in New Issue