From 0ebbc3a53317bf3b587c0254c1ed35ab047fd653 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys <hanwen@google.com> Date: Thu, 18 Aug 2011 00:56:08 -0300 Subject: [PATCH] Handle setattr and getattr on open files too. --- fuse/fsetattr_test.go | 16 ++++++---------- fuse/pathfilesystem.go | 12 ++++++++++-- fuse/pathops.go | 18 +++++++++++++----- unionfs/unionfs_test.go | 20 ++++++++++++++++++++ 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/fuse/fsetattr_test.go b/fuse/fsetattr_test.go index 63a3355..8d5ada1 100644 --- a/fuse/fsetattr_test.go +++ b/fuse/fsetattr_test.go @@ -3,7 +3,6 @@ package fuse import ( "fmt" "log" - "json" "os" "syscall" "testing" @@ -152,28 +151,25 @@ func TestFSetAttr(t *testing.T) { if state.KernelSettings().Flags&CAP_FILE_OPS == 0 { log.Println("Mount does not support file operations") - m, _ := json.Marshal(state.KernelSettings()) - log.Println("Kernel settings: ", string(m)) - return } - - _, err = os.Lstat(fn) + + _, err = f.Stat() CheckSuccess(err) if !fs.file.GetAttrCalled { t.Error("Should have called File.GetAttr") } - err = os.Chmod(fn, 024) + err = f.Chmod(024) CheckSuccess(err) if fs.file.FileInfo.Mode&07777 != 024 { t.Error("chmod") } - err = os.Chtimes(fn, 100, 101) + err = os.Chtimes(fn, 100e3, 101e3) CheckSuccess(err) - if fs.file.FileInfo.Atime_ns != 100 || fs.file.FileInfo.Atime_ns != 101 { - t.Error("Utimens") + if fs.file.FileInfo.Atime_ns != 100e3 || fs.file.FileInfo.Mtime_ns != 101e3 { + t.Error("Utimens", fs.file.FileInfo) } // TODO - test chown if run as root. diff --git a/fuse/pathfilesystem.go b/fuse/pathfilesystem.go index 1a0f5d9..9995555 100644 --- a/fuse/pathfilesystem.go +++ b/fuse/pathfilesystem.go @@ -648,8 +648,8 @@ func (me *FileSystemConnector) unsafeUnmountNode(node *inode) { unmounted.fs.Unmount() } -func (me *FileSystemConnector) getOpenFileData(nodeid uint64, fh uint64) (f File, m *fileSystemMount, p string) { - node := me.getInodeData(nodeid) +func (me *FileSystemConnector) getOpenFileData(nodeid uint64, fh uint64) (f File, m *fileSystemMount, p string, node *inode) { + node = me.getInodeData(nodeid) node.treeLock.RLock() defer node.treeLock.RUnlock() @@ -666,6 +666,14 @@ func (me *FileSystemConnector) getOpenFileData(nodeid uint64, fh uint64) (f File m = mount p = path } + if f == nil { + node.OpenFilesMutex.Lock() + defer node.OpenFilesMutex.Unlock() + + if len(node.OpenFiles) > 0 { + f = node.OpenFiles[0].file + } + } return } diff --git a/fuse/pathops.go b/fuse/pathops.go index 71aa5a0..a7b8a6b 100644 --- a/fuse/pathops.go +++ b/fuse/pathops.go @@ -98,9 +98,18 @@ func (me *FileSystemConnector) Forget(h *InHeader, input *ForgetIn) { } func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out *AttrOut, code Status) { + fh := uint64(0) if input.Flags&FUSE_GETATTR_FH != 0 { - opened := me.getOpenedFile(input.Fh) - fi, err := opened.file.GetAttr() + fh = input.Fh + } + + f, mount, fullPath, node := me.getOpenFileData(header.NodeId, fh) + if mount == nil && f == nil { + return nil, ENOENT + } + + if f != nil { + fi, err := f.GetAttr() if err != OK && err != ENOSYS { return nil, err } @@ -109,13 +118,12 @@ func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out out = &AttrOut{} CopyFileInfo(fi, &out.Attr) out.Attr.Ino = header.NodeId - SplitNs(opened.fileSystemMount.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec) + SplitNs(node.mount.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec) return out, OK } } - fullPath, mount, _ := me.GetPath(header.NodeId) if mount == nil { return nil, ENOENT } @@ -192,7 +200,7 @@ func (me *FileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) (out getAttrIn.Flags |= FUSE_GETATTR_FH } - f, mount, fullPath := me.getOpenFileData(header.NodeId, fh) + f, mount, fullPath, _ := me.getOpenFileData(header.NodeId, fh) if mount == nil { return nil, ENOENT } diff --git a/unionfs/unionfs_test.go b/unionfs/unionfs_test.go index 3635758..625ef36 100644 --- a/unionfs/unionfs_test.go +++ b/unionfs/unionfs_test.go @@ -807,3 +807,23 @@ func TestDisappearing(t *testing.T) { t.Fatal("write should succeed", err) } } + +func TestDeletedGetAttr(t *testing.T) { + t.Log("TestDeletedGetAttr") + wd, clean := setupUfs(t) + defer clean() + + err := ioutil.WriteFile(wd+"/ro/file", []byte("blabla"), 0644) + CheckSuccess(err) + + f, err := os.Open(wd + "/mount/file") + CheckSuccess(err) + defer f.Close() + + err = os.Remove(wd+"/mount/file") + CheckSuccess(err) + + if fi, err := f.Stat(); err != nil || !fi.IsRegular() { + t.Fatalf("stat returned error or non-file: %v %v", err, fi) + } +} -- 2.30.9