"git.arvados.org/arvados.git/sdk/go/arvados"
"git.arvados.org/arvados.git/sdk/go/keepclient"
"github.com/arvados/cgofuse/fuse"
+ "github.com/sirupsen/logrus"
)
// sharedFile wraps arvados.File with a sync.Mutex, so fuse can safely
ReadOnly bool
Uid int
Gid int
+ Logger logrus.FieldLogger
root arvados.CustomFileSystem
open map[uint64]*sharedFile
func (fs *keepFS) Create(path string, flags int, mode uint32) (errc int, fh uint64) {
defer fs.debugPanics()
+ fs.debugOp("Create", path)
if fs.ReadOnly {
return -fuse.EROFS, invalidFH
}
func (fs *keepFS) Open(path string, flags int) (errc int, fh uint64) {
defer fs.debugPanics()
+ fs.debugOp("Open", path)
if fs.ReadOnly && flags&(os.O_RDWR|os.O_WRONLY|os.O_CREATE) != 0 {
return -fuse.EROFS, invalidFH
}
func (fs *keepFS) Utimens(path string, tmsp []fuse.Timespec) int {
defer fs.debugPanics()
+ fs.debugOp("Utimens", path)
if fs.ReadOnly {
return -fuse.EROFS
}
f, err := fs.root.OpenFile(path, 0, 0)
if err != nil {
- return fs.errCode(err)
+ return fs.errCode("Utimens", path, err)
}
f.Close()
return 0
}
-func (fs *keepFS) errCode(err error) int {
+func (fs *keepFS) errCode(op, path string, err error) (errc int) {
if err == nil {
return 0
}
+ defer func() {
+ fs.Logger.WithFields(logrus.Fields{
+ "op": op,
+ "path": path,
+ "errno": errc,
+ "error": err,
+ }).Debug("fuse call returned error")
+ }()
if errors.Is(err, os.ErrNotExist) {
return -fuse.ENOENT
}
func (fs *keepFS) Mkdir(path string, mode uint32) int {
defer fs.debugPanics()
+ fs.debugOp("Mkdir", path)
if fs.ReadOnly {
return -fuse.EROFS
}
f, err := fs.root.OpenFile(path, os.O_CREATE|os.O_EXCL, os.FileMode(mode)|os.ModeDir)
if err != nil {
- return fs.errCode(err)
+ return fs.errCode("Mkdir", path, err)
}
f.Close()
return 0
func (fs *keepFS) Opendir(path string) (errc int, fh uint64) {
defer fs.debugPanics()
+ fs.debugOp("Opendir", path)
f, err := fs.root.OpenFile(path, 0, 0)
if err != nil {
- return fs.errCode(err), invalidFH
+ return fs.errCode("Opendir", path, err), invalidFH
} else if fi, err := f.Stat(); err != nil {
- return fs.errCode(err), invalidFH
+ return fs.errCode("Opendir", path, err), invalidFH
} else if !fi.IsDir() {
f.Close()
return -fuse.ENOTDIR, invalidFH
func (fs *keepFS) Releasedir(path string, fh uint64) (errc int) {
defer fs.debugPanics()
+ fs.debugOp("Releasedir", path)
return fs.Release(path, fh)
}
func (fs *keepFS) Rmdir(path string) int {
defer fs.debugPanics()
- return fs.errCode(fs.root.Remove(path))
+ fs.debugOp("Rmdir", path)
+ return fs.errCode("Rmdir", path, fs.root.Remove(path))
}
func (fs *keepFS) Release(path string, fh uint64) (errc int) {
defer fs.debugPanics()
+ fs.debugOp("Release", path)
fs.Lock()
defer fs.Unlock()
defer delete(fs.open, fh)
func (fs *keepFS) Rename(oldname, newname string) (errc int) {
defer fs.debugPanics()
+ fs.debugOp("Rename", oldname+" -> "+newname)
if fs.ReadOnly {
return -fuse.EROFS
}
- return fs.errCode(fs.root.Rename(oldname, newname))
+ return fs.errCode("Rename", oldname+" -> "+newname, fs.root.Rename(oldname, newname))
}
func (fs *keepFS) Unlink(path string) (errc int) {
defer fs.debugPanics()
+ fs.debugOp("Unlink", path)
if fs.ReadOnly {
return -fuse.EROFS
}
- return fs.errCode(fs.root.Remove(path))
+ return fs.errCode("Unlink", path, fs.root.Remove(path))
}
func (fs *keepFS) Truncate(path string, size int64, fh uint64) (errc int) {
defer fs.debugPanics()
+ fs.debugOp("Truncate", path)
if fs.ReadOnly {
return -fuse.EROFS
}
// Sometimes fh is a valid filehandle and we don't need to
// waste a name lookup.
if f := fs.lookupFH(fh); f != nil {
- return fs.errCode(f.Truncate(size))
+ return fs.errCode("Truncate", path, f.Truncate(size))
}
// Other times, fh is invalid and we need to lookup path.
f, err := fs.root.OpenFile(path, os.O_RDWR, 0)
if err != nil {
- return fs.errCode(err)
+ return fs.errCode("Truncate", path, err)
}
defer f.Close()
- return fs.errCode(f.Truncate(size))
+ return fs.errCode("Truncate", path, f.Truncate(size))
}
func (fs *keepFS) Getattr(path string, stat *fuse.Stat_t, fh uint64) (errc int) {
defer fs.debugPanics()
+ fs.debugOp("Getattr", path)
var fi os.FileInfo
var err error
if f := fs.lookupFH(fh); f != nil {
fi, err = fs.root.Stat(path)
}
if err != nil {
- return fs.errCode(err)
+ return fs.errCode("Getattr", path, err)
}
fs.fillStat(stat, fi)
return 0
}
func (fs *keepFS) Chmod(path string, mode uint32) (errc int) {
+ defer fs.debugPanics()
+ fs.debugOp("Chmod", path)
if fs.ReadOnly {
return -fuse.EROFS
}
if fi, err := fs.root.Stat(path); err != nil {
- return fs.errCode(err)
+ return fs.errCode("Chmod", path, err)
} else if mode & ^uint32(fuse.S_IFREG|fuse.S_IFDIR|0777) != 0 {
// Refuse to set mode bits other than
// regfile/dir/perms
func (fs *keepFS) Write(path string, buf []byte, ofst int64, fh uint64) (n int) {
defer fs.debugPanics()
+ fs.debugOp("Write", path)
if fs.ReadOnly {
return -fuse.EROFS
}
f.Lock()
defer f.Unlock()
if _, err := f.Seek(ofst, io.SeekStart); err != nil {
- return fs.errCode(err)
+ return fs.errCode("Write", path, err)
}
n, err := f.Write(buf)
if err != nil {
- log.Printf("error writing %q: %s", path, err)
- return fs.errCode(err)
+ return fs.errCode("Write", path, err)
}
return n
}
func (fs *keepFS) Read(path string, buf []byte, ofst int64, fh uint64) (n int) {
defer fs.debugPanics()
+ fs.debugOp("Read", path)
f := fs.lookupFH(fh)
if f == nil {
return -fuse.EBADF
f.Lock()
defer f.Unlock()
if _, err := f.Seek(ofst, io.SeekStart); err != nil {
- return fs.errCode(err)
+ return fs.errCode("Read", path, err)
}
n, err := f.Read(buf)
for err == nil && n < len(buf) {
n += done
}
if err != nil && err != io.EOF {
- log.Printf("error reading %q: %s", path, err)
- return fs.errCode(err)
+ return fs.errCode("Read", path, err)
}
return n
}
ofst int64,
fh uint64) (errc int) {
defer fs.debugPanics()
+ fs.debugOp("Readdir", path)
f := fs.lookupFH(fh)
if f == nil {
return -fuse.EBADF
var stat fuse.Stat_t
fis, err := f.Readdir(-1)
if err != nil {
- return fs.errCode(err)
+ return fs.errCode("Readdir", path, err)
}
for _, fi := range fis {
fs.fillStat(&stat, fi)
func (fs *keepFS) Fsync(path string, datasync bool, fh uint64) int {
defer fs.debugPanics()
+ fs.debugOp("Fsync", path)
f := fs.lookupFH(fh)
if f == nil {
return -fuse.EBADF
}
- return fs.errCode(f.Sync())
+ return fs.errCode("Fsync", path, f.Sync())
}
func (fs *keepFS) Fsyncdir(path string, datasync bool, fh uint64) int {
+ fs.debugOp("Fsyncdir", path)
return fs.Fsync(path, datasync, fh)
}
panic(err)
}
}
+
+func (fs *keepFS) debugOp(op, path string) {
+ fs.Logger.WithFields(nil).Tracef("fuse call %s %s", op, path)
+}