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