@@ -28,10 +28,13 @@ package libfuse
2828import (
2929 "errors"
3030 "fmt"
31+ "hash/fnv"
3132 "io"
3233 "io/fs"
3334 "os"
35+ "path"
3436 "runtime"
37+ "strings"
3538 "syscall"
3639 "time"
3740
@@ -200,6 +203,7 @@ func (lf *Libfuse) fillStat(attr *internal.ObjAttr, stbuf *fuse.Stat_t) {
200203 stbuf .Gid = lf .ownerGID
201204 stbuf .Nlink = 1
202205 stbuf .Size = attr .Size
206+ stbuf .Ino = inodeForAttr (attr )
203207
204208 // Populate mode
205209 // Backing storage implementation has support for mode.
@@ -264,7 +268,7 @@ func (cf *CgofuseFS) Getattr(path string, stat *fuse.Stat_t, fh uint64) int {
264268 // log.Trace("Libfuse::Getattr : %s", name)
265269
266270 // Return the default configuration for the root
267- if name == "" {
271+ if name == "" || name == "." || name == ".." {
268272 stat .Mode = fuse .S_IFDIR | 0777
269273 stat .Uid = cf .uid
270274 stat .Gid = cf .gid
@@ -273,6 +277,7 @@ func (cf *CgofuseFS) Getattr(path string, stat *fuse.Stat_t, fh uint64) int {
273277 stat .Mtim = fuse .NewTimespec (time .Now ())
274278 stat .Atim = stat .Mtim
275279 stat .Ctim = stat .Mtim
280+ stat .Ino = inodeForPath (name )
276281 return 0
277282 }
278283
@@ -462,7 +467,7 @@ func (cf *CgofuseFS) Readdir(
462467 newRequest := offset == 0
463468 if newRequest {
464469 // cache the first two entries ('.' & '..')
465- cacheDots (cacheInfo )
470+ cacheDots (cacheInfo , handle . Path )
466471 }
467472 startOffset := offset
468473 // fetch and serve directory contents back to the OS in a loop until their buffer is full
@@ -516,11 +521,14 @@ type fillFunc = func(name string, stat *fuse.Stat_t, ofst int64) bool
516521
517522// add the first two entries in any directory listing ('.' and '..') to the cache
518523// this replaces any existing cache
519- func cacheDots (cacheInfo * dirChildCache ) {
520- dotAttrs := []* internal.ObjAttr {
521- {Flags : fuseFS .lsFlags , Name : "." },
522- {Flags : fuseFS .lsFlags , Name : ".." },
523- }
524+ func cacheDots (cacheInfo * dirChildCache , dirPath string ) {
525+ currentDir := internal .CreateObjAttrDir (dirPath )
526+ currentDir .Name = "."
527+ parentPath := strings .TrimSuffix (dirPath , "/" )
528+ parentPath = path .Dir (parentPath )
529+ parentDir := internal .CreateObjAttrDir (parentPath )
530+ parentDir .Name = ".."
531+ dotAttrs := []* internal.ObjAttr {currentDir , parentDir }
524532 cacheInfo .sIndex = 0
525533 cacheInfo .eIndex = 2
526534 cacheInfo .length = 2
@@ -530,6 +538,22 @@ func cacheDots(cacheInfo *dirChildCache) {
530538 cacheInfo .lastPage = false
531539}
532540
541+ func inodeForAttr (attr * internal.ObjAttr ) uint64 {
542+ if attr == nil {
543+ return 0
544+ }
545+ if attr .Path != "" {
546+ return inodeForPath (attr .Path )
547+ }
548+ return inodeForPath (attr .Name )
549+ }
550+
551+ func inodeForPath (p string ) uint64 {
552+ h := fnv .New64a ()
553+ _ , _ = h .Write ([]byte (p ))
554+ return h .Sum64 ()
555+ }
556+
533557// Fill the directory list cache with data from the next component
534558func populateDirChildCache (
535559 handle * handlemap.Handle ,
0 commit comments