From 4d5dc557664b9bdf377c0fb560f9a13bc717d13f Mon Sep 17 00:00:00 2001 From: chrislu Date: Sat, 23 Jul 2022 12:57:00 -0700 Subject: [PATCH] mount: better support hard links --- weed/mount/inode_to_path.go | 59 ++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/weed/mount/inode_to_path.go b/weed/mount/inode_to_path.go index 29635efca..79c016a15 100644 --- a/weed/mount/inode_to_path.go +++ b/weed/mount/inode_to_path.go @@ -14,18 +14,39 @@ type InodeToPath struct { path2inode map[util.FullPath]uint64 } type InodeEntry struct { - util.FullPath + paths []util.FullPath nlookup uint64 isDirectory bool isChildrenCached bool } +func (ie *InodeEntry) removeOnePath(p util.FullPath) bool { + if len(ie.paths) == 0 { + return false + } + idx := -1 + for i, x := range ie.paths { + if x == p { + idx = i + break + } + } + if idx < 0 { + return false + } + for x := len(ie.paths) - 2; x > idx; x-- { + ie.paths[x-1] = ie.paths[x] + } + ie.paths = ie.paths[0 : len(ie.paths)-1] + return true +} + func NewInodeToPath(root util.FullPath) *InodeToPath { t := &InodeToPath{ inode2path: make(map[uint64]*InodeEntry), path2inode: make(map[util.FullPath]uint64), } - t.inode2path[1] = &InodeEntry{root, 1, true, false} + t.inode2path[1] = &InodeEntry{[]util.FullPath{root}, 1, true, false} t.path2inode[root] = 1 return t } @@ -54,9 +75,9 @@ func (i *InodeToPath) Lookup(path util.FullPath, unixTime int64, isDirectory boo } } else { if !isLookup { - i.inode2path[inode] = &InodeEntry{path, 0, isDirectory, false} + i.inode2path[inode] = &InodeEntry{[]util.FullPath{path}, 0, isDirectory, false} } else { - i.inode2path[inode] = &InodeEntry{path, 1, isDirectory, false} + i.inode2path[inode] = &InodeEntry{[]util.FullPath{path}, 1, isDirectory, false} } } @@ -94,10 +115,10 @@ func (i *InodeToPath) GetPath(inode uint64) (util.FullPath, fuse.Status) { i.RLock() defer i.RUnlock() path, found := i.inode2path[inode] - if !found { + if !found || len(path.paths) == 0 { return "", fuse.ENOENT } - return path.FullPath, fuse.OK + return path.paths[0], fuse.OK } func (i *InodeToPath) HasPath(path util.FullPath) bool { @@ -148,7 +169,15 @@ func (i *InodeToPath) RemovePath(path util.FullPath) { inode, found := i.path2inode[path] if found { delete(i.path2inode, path) - delete(i.inode2path, inode) + i.removePathFromInode2Path(inode, path) + } +} + +func (i *InodeToPath) removePathFromInode2Path(inode uint64, path util.FullPath) { + if ie, found := i.inode2path[inode]; found { + if ie.removeOnePath(path) && len(ie.paths) == 0 { + delete(i.inode2path, inode) + } } } @@ -158,7 +187,7 @@ func (i *InodeToPath) MovePath(sourcePath, targetPath util.FullPath) (sourceInod sourceInode, sourceFound := i.path2inode[sourcePath] targetInode, targetFound := i.path2inode[targetPath] if targetFound { - delete(i.inode2path, targetInode) + i.removePathFromInode2Path(targetInode, targetPath) delete(i.path2inode, targetPath) } if sourceFound { @@ -170,7 +199,11 @@ func (i *InodeToPath) MovePath(sourcePath, targetPath util.FullPath) (sourceInod return } if entry, entryFound := i.inode2path[sourceInode]; entryFound { - entry.FullPath = targetPath + for i, p := range entry.paths { + if p == sourcePath { + entry.paths[i] = targetPath + } + } entry.isChildrenCached = false if !targetFound { entry.nlookup++ @@ -187,7 +220,9 @@ func (i *InodeToPath) Forget(inode, nlookup uint64, onForgetDir func(dir util.Fu if found { path.nlookup -= nlookup if path.nlookup <= 0 { - delete(i.path2inode, path.FullPath) + for _, p := range path.paths { + delete(i.path2inode, p) + } delete(i.inode2path, inode) } } @@ -195,7 +230,9 @@ func (i *InodeToPath) Forget(inode, nlookup uint64, onForgetDir func(dir util.Fu if found { if path.isDirectory && path.nlookup <= 0 && onForgetDir != nil { path.isChildrenCached = false - onForgetDir(path.FullPath) + for _, p := range path.paths { + onForgetDir(p) + } } } }