Skip to content

Commit

Permalink
cgofuse: refactor Gettattr
Browse files Browse the repository at this point in the history
- Splits up the logic.
- Adds the new interfaces for time value getters.
- Accounts for active file handles.
  • Loading branch information
djdv committed Dec 2, 2022
1 parent f1e481f commit f71036e
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 70 deletions.
96 changes: 26 additions & 70 deletions internal/filesystem/cgofuse/stat.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,84 +16,40 @@ func (gw *goWrapper) Statfs(path string, stat *fuse.Statfs_t) int {

func (gw *goWrapper) Getattr(path string, stat *fuse.Stat_t, fh uint64) int {
defer gw.systemLock.Access(path)()
goPath, err := fuseToGo(path)
if err != nil {
gw.log.Print(err)
// TODO: review; should we return the value raw or send err to a converter?
// ^ send a stacked err to a converter*
// (so that the trace contains both ops, parent-op+path-lexer+reason)
// TODO: re-read spec. This is the closest value that seemed appropriate
// but maybe ACCESS or NOENT makes more sense.
return -fuse.EINVAL
}

var (
info fs.FileInfo
err error
)
if fh != errorHandle {
// TODO: fh lookup
info, err = gw.infoFromHandle(fh)
} else {
info, err = gw.infoFromPath(path)
}

// TODO: review
goStat, err := fs.Stat(gw.FS, goPath)
if err != nil {
errNo := interpretError(err)
// Don't flood the logs with "not found" errors.
if errNo != -fuse.ENOENT {
// TODO: [DBG] reduce this format
gw.log.Printf("path: %s\ngoPath: %s\nerr:%s", path, goPath, err)
}
return errNo
return interpretError(err)
}

// fsys.log.Printf("stat for %s\n%#v", path, goStat)

// TODO: don't change stat on the fuse object
// push changes back to fs.FS via extension
// fs.SetAttr, fs.SetAttrFuse(path, someOverlappingAttrType)

mTime := fuse.NewTimespec(goStat.ModTime())

// TODO: The fallback should be (optionally) set within the wrapper's constructor.
// Which itself should have a read-only default like this if not provided.
const fallbackPermissions = readAll | executeAll
var (
goMode = goStat.Mode()
fuseType = goToFuseFileType(goMode)
fusePermissions uint32
uid, gid, _ = fuse.Getcontext()
fctx = fuseContext{uid: uid, gid: gid}
)
if goPermissions := goMode.Perm(); goPermissions != 0 {
fusePermissions = goToFusePermissions(goPermissions)
} else {
fusePermissions = fallbackPermissions
}
stat.Uid, stat.Gid, _ = fuse.Getcontext()
stat.Mode = fuseType | fusePermissions
stat.Size = goStat.Size()
// TODO: block size

// TODO: [devel] `File` needs extensions for these times and we should use them conditionally
// something like `if aTimer ok; stat.Atim = aTimer.Time()`
// For now we cheat and use the same value for all
stat.Atim, // XXX: This shouldn't even be legal syntax.
stat.Mtim,
stat.Ctim,
stat.Birthtim = mTime,
mTime,
mTime,
mTime
goToFuseStat(info, fctx, stat)
return operationSuccess
}

/*
if path != "/" {
log.Printf("%s - mode pre conversion: %d, %s",
path,
goStat.Mode(), goStat.Mode())
log.Printf("%s - mode post conversion (masked): %d %d|%d",
path,
stat.Mode,
stat.Mode&fuselib.S_IFMT, stat.Mode&^fuselib.S_IFMT,
)
}
*/
func (gw *goWrapper) infoFromHandle(fh uint64) (fs.FileInfo, error) {
file, err := gw.fileTable.get(fh)
if err != nil {
return nil, err
}
return file.goFile.Stat()
}

return operationSuccess
func (gw *goWrapper) infoFromPath(path string) (fs.FileInfo, error) {
goPath, err := fuseToGo(path)
if err != nil {
return nil, err
}
return fs.Stat(gw.FS, goPath)
}

func (gw *goWrapper) Utimens(path string, tmsp []fuse.Timespec) int {
Expand Down
33 changes: 33 additions & 0 deletions internal/filesystem/cgofuse/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,39 @@ func fuseToGo(path string) (string, error) {
return path[1:], nil
}

func goToFuseStat(info fs.FileInfo, fctx fuseContext, stat *fuse.Stat_t) {
var (
goMode = info.Mode()
fuseType = goToFuseFileType(goMode)
fusePermissions uint32
)
if goPermissions := goMode.Perm(); goPermissions != 0 {
fusePermissions = goToFusePermissions(goPermissions)
} else {
// TODO: The fallback should be (optionally) set within the wrapper's constructor.
// Which itself should have a read-only default like this if not provided.
const fallbackPermissions = readAll | executeAll
fusePermissions = fallbackPermissions
}

stat.Mode = fuseType | fusePermissions
stat.Uid = fctx.uid
stat.Gid = fctx.gid
stat.Size = info.Size()

if atimer, ok := info.(filesystem.AccessTimer); ok {
stat.Atim = fuse.NewTimespec(atimer.AccessTime())
}
stat.Mtim = fuse.NewTimespec(info.ModTime())
if ctimer, ok := info.(filesystem.ChangeTimer); ok {
stat.Ctim = fuse.NewTimespec(ctimer.ChangeTime())
}
// TODO: Block size + others.
if crtimer, ok := info.(filesystem.CreationTimer); ok {
stat.Birthtim = fuse.NewTimespec(crtimer.CreationTime())
}
}

// [FileMode] to FUSE mode bits.
func goToFuseFileType(m fs.FileMode) fileType {
switch m.Type() {
Expand Down

0 comments on commit f71036e

Please sign in to comment.