From 77100754e60752915af008070e3a951e08a67890 Mon Sep 17 00:00:00 2001 From: Patrick Schmidt Date: Wed, 2 Jun 2021 19:30:55 +0200 Subject: [PATCH] Return artificial . and .. directories --- weed/command/mount_std.go | 29 +++++++++++++++++++-- weed/filesys/dir.go | 55 ++++++++++++++++++++++----------------- weed/filesys/wfs.go | 18 +++++++------ weed/filesys/xattr.go | 15 +++++++++++ 4 files changed, 83 insertions(+), 34 deletions(-) diff --git a/weed/command/mount_std.go b/weed/command/mount_std.go index e72a2f2cf..dce2197d6 100644 --- a/weed/command/mount_std.go +++ b/weed/command/mount_std.go @@ -5,15 +5,18 @@ package command import ( "context" "fmt" - "github.com/chrislusf/seaweedfs/weed/storage/types" "os" "os/user" "path" + "path/filepath" "runtime" "strconv" "strings" + "syscall" "time" + "github.com/chrislusf/seaweedfs/weed/storage/types" + "github.com/chrislusf/seaweedfs/weed/filesys/meta_cache" "github.com/seaweedfs/fuse" @@ -49,6 +52,21 @@ func runMount(cmd *Command, args []string) bool { return RunMount(&mountOptions, os.FileMode(umask)) } +func getParentInode(mountDir string) (uint64, error) { + parentDir := filepath.Clean(filepath.Join(mountDir, "..")) + fi, err := os.Stat(parentDir) + if err != nil { + return 0, err + } + + stat, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + return 0, nil + } + + return stat.Ino, nil +} + func RunMount(option *MountOptions, umask os.FileMode) bool { filers := strings.Split(*option.filer, ",") @@ -85,13 +103,19 @@ func RunMount(option *MountOptions, umask os.FileMode) bool { filerMountRootPath := *option.filerMountRootPath dir := util.ResolvePath(*option.dir) - chunkSizeLimitMB := *mountOptions.chunkSizeLimitMB + parentInode, err := getParentInode(dir) + if err != nil { + glog.Errorf("failed to retrieve inode for parent directory of %s: %v", dir, err) + return true + } fmt.Printf("This is SeaweedFS version %s %s %s\n", util.Version(), runtime.GOOS, runtime.GOARCH) if dir == "" { fmt.Printf("Please specify the mount directory via \"-dir\"") return false } + + chunkSizeLimitMB := *mountOptions.chunkSizeLimitMB if chunkSizeLimitMB <= 0 { fmt.Printf("Please specify a reasonable buffer size.") return false @@ -199,6 +223,7 @@ func RunMount(option *MountOptions, umask os.FileMode) bool { MountMode: mountMode, MountCtime: fileInfo.ModTime(), MountMtime: time.Now(), + MountParentInode: parentInode, Umask: umask, VolumeServerAccess: *mountOptions.volumeServerAccess, Cipher: cipher, diff --git a/weed/filesys/dir.go b/weed/filesys/dir.go index 72e41247f..904999c43 100644 --- a/weed/filesys/dir.go +++ b/weed/filesys/dir.go @@ -54,28 +54,27 @@ func (dir *Dir) Id() uint64 { func (dir *Dir) Attr(ctx context.Context, attr *fuse.Attr) error { - // https://github.com/bazil/fuse/issues/196 - attr.Valid = time.Second - - if dir.FullPath() == dir.wfs.option.FilerMountRootPath { - dir.setRootDirAttributes(attr) - glog.V(3).Infof("root dir Attr %s, attr: %+v", dir.FullPath(), attr) - return nil - } - entry, err := dir.maybeLoadEntry() if err != nil { - glog.V(3).Infof("dir Attr %s,err: %+v", dir.FullPath(), err) + glog.V(3).Infof("dir Attr %s, err: %+v", dir.FullPath(), err) return err } + // https://github.com/bazil/fuse/issues/196 + attr.Valid = time.Second attr.Inode = dir.Id() attr.Mode = os.FileMode(entry.Attributes.FileMode) | os.ModeDir attr.Mtime = time.Unix(entry.Attributes.Mtime, 0) attr.Crtime = time.Unix(entry.Attributes.Crtime, 0) + attr.Ctime = time.Unix(entry.Attributes.Crtime, 0) + attr.Atime = time.Unix(entry.Attributes.Mtime, 0) attr.Gid = entry.Attributes.Gid attr.Uid = entry.Attributes.Uid + if dir.FullPath() == dir.wfs.option.FilerMountRootPath { + attr.BlockSize = blockSize + } + glog.V(4).Infof("dir Attr %s, attr: %+v", dir.FullPath(), attr) return nil @@ -93,20 +92,6 @@ func (dir *Dir) Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *f return getxattr(entry, req, resp) } -func (dir *Dir) setRootDirAttributes(attr *fuse.Attr) { - // attr.Inode = 1 // filer2.FullPath(dir.Path).AsInode() - attr.Valid = time.Second - attr.Inode = dir.Id() - attr.Uid = dir.wfs.option.MountUid - attr.Gid = dir.wfs.option.MountGid - attr.Mode = dir.wfs.option.MountMode - attr.Crtime = dir.wfs.option.MountCtime - attr.Ctime = dir.wfs.option.MountCtime - attr.Mtime = dir.wfs.option.MountMtime - attr.Atime = dir.wfs.option.MountMtime - attr.BlockSize = blockSize -} - func (dir *Dir) Fsync(ctx context.Context, req *fuse.FsyncRequest) error { // fsync works at OS level // write the file chunks to the filerGrpcAddress @@ -375,6 +360,28 @@ func (dir *Dir) ReadDirAll(ctx context.Context) (ret []fuse.Dirent, err error) { glog.Errorf("list meta cache: %v", listErr) return nil, fuse.EIO } + + // create proper . and .. directories + ret = append(ret, fuse.Dirent{ + Inode: dirPath.AsInode(), + Name: ".", + Type: fuse.DT_Dir, + }) + + // return the correct parent inode for the mount root + var inode uint64 + if string(dirPath) == dir.wfs.option.FilerMountRootPath { + inode = dir.wfs.option.MountParentInode + } else { + inode = util.FullPath(dir.parent.FullPath()).AsInode() + } + + ret = append(ret, fuse.Dirent{ + Inode: inode, + Name: "..", + Type: fuse.DT_Dir, + }) + return } diff --git a/weed/filesys/wfs.go b/weed/filesys/wfs.go index 8f864a123..178e4e497 100644 --- a/weed/filesys/wfs.go +++ b/weed/filesys/wfs.go @@ -3,9 +3,6 @@ package filesys import ( "context" "fmt" - "github.com/chrislusf/seaweedfs/weed/filer" - "github.com/chrislusf/seaweedfs/weed/storage/types" - "github.com/chrislusf/seaweedfs/weed/wdclient" "math" "math/rand" "os" @@ -14,6 +11,10 @@ import ( "sync" "time" + "github.com/chrislusf/seaweedfs/weed/filer" + "github.com/chrislusf/seaweedfs/weed/storage/types" + "github.com/chrislusf/seaweedfs/weed/wdclient" + "google.golang.org/grpc" "github.com/chrislusf/seaweedfs/weed/util/grace" @@ -46,11 +47,12 @@ type Option struct { DataCenter string Umask os.FileMode - MountUid uint32 - MountGid uint32 - MountMode os.FileMode - MountCtime time.Time - MountMtime time.Time + MountUid uint32 + MountGid uint32 + MountMode os.FileMode + MountCtime time.Time + MountMtime time.Time + MountParentInode uint64 VolumeServerAccess string // how to access volume servers Cipher bool // whether encrypt data on volume server diff --git a/weed/filesys/xattr.go b/weed/filesys/xattr.go index 92e43b675..473805116 100644 --- a/weed/filesys/xattr.go +++ b/weed/filesys/xattr.go @@ -113,6 +113,21 @@ func (wfs *WFS) maybeLoadEntry(dir, name string) (entry *filer_pb.Entry, err err fullpath := util.NewFullPath(dir, name) // glog.V(3).Infof("read entry cache miss %s", fullpath) + // return a valid entry for the mount root + if string(fullpath) == wfs.option.FilerMountRootPath { + return &filer_pb.Entry{ + Name: wfs.option.FilerMountRootPath, + IsDirectory: true, + Attributes: &filer_pb.FuseAttributes{ + Mtime: wfs.option.MountMtime.Unix(), + FileMode: uint32(wfs.option.MountMode), + Uid: wfs.option.MountUid, + Gid: wfs.option.MountGid, + Crtime: wfs.option.MountCtime.Unix(), + }, + }, nil + } + // read from async meta cache meta_cache.EnsureVisited(wfs.metaCache, wfs, util.FullPath(dir)) cachedEntry, cacheErr := wfs.metaCache.FindEntry(context.Background(), fullpath)