mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-01-19 02:48:24 +00:00
2dcb8cb93b
this is just an in memory representation. POSIX wants different inode numbers for the same named file or directory.
142 lines
4.3 KiB
Go
142 lines
4.3 KiB
Go
package filesys
|
|
|
|
import (
|
|
"context"
|
|
"github.com/chrislusf/seaweedfs/weed/filer"
|
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
|
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
|
"github.com/chrislusf/seaweedfs/weed/util"
|
|
"github.com/seaweedfs/fuse"
|
|
"github.com/seaweedfs/fuse/fs"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
func (dir *Dir) Rename(ctx context.Context, req *fuse.RenameRequest, newDirectory fs.Node) error {
|
|
|
|
newDir := newDirectory.(*Dir)
|
|
|
|
newPath := util.NewFullPath(newDir.FullPath(), req.NewName)
|
|
oldPath := util.NewFullPath(dir.FullPath(), req.OldName)
|
|
|
|
glog.V(4).Infof("dir Rename %s => %s", oldPath, newPath)
|
|
|
|
// update remote filer
|
|
err := dir.wfs.WithFilerClient(true, func(client filer_pb.SeaweedFilerClient) error {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
request := &filer_pb.StreamRenameEntryRequest{
|
|
OldDirectory: dir.FullPath(),
|
|
OldName: req.OldName,
|
|
NewDirectory: newDir.FullPath(),
|
|
NewName: req.NewName,
|
|
Signatures: []int32{dir.wfs.signature},
|
|
}
|
|
|
|
stream, err := client.StreamRenameEntry(ctx, request)
|
|
if err != nil {
|
|
glog.Errorf("dir AtomicRenameEntry %s => %s : %v", oldPath, newPath, err)
|
|
return fuse.EIO
|
|
}
|
|
|
|
for {
|
|
resp, recvErr := stream.Recv()
|
|
if recvErr != nil {
|
|
if recvErr == io.EOF {
|
|
break
|
|
} else {
|
|
glog.V(0).Infof("dir Rename %s => %s receive: %v", oldPath, newPath, recvErr)
|
|
if strings.Contains(recvErr.Error(), "not empty") {
|
|
return fuse.EEXIST
|
|
}
|
|
if strings.Contains(recvErr.Error(), "not directory") {
|
|
return fuse.ENOTDIR
|
|
}
|
|
return recvErr
|
|
}
|
|
}
|
|
|
|
if err = dir.handleRenameResponse(ctx, resp); err != nil {
|
|
glog.V(0).Infof("dir Rename %s => %s : %v", oldPath, newPath, err)
|
|
return err
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func (dir *Dir) handleRenameResponse(ctx context.Context, resp *filer_pb.StreamRenameEntryResponse) error {
|
|
// comes from filer StreamRenameEntry, can only be create or delete entry
|
|
|
|
if resp.EventNotification.NewEntry != nil {
|
|
// with new entry, the old entry name also exists. This is the first step to create new entry
|
|
newEntry := filer.FromPbEntry(resp.EventNotification.NewParentPath, resp.EventNotification.NewEntry)
|
|
if err := dir.wfs.metaCache.AtomicUpdateEntryFromFiler(ctx, "", newEntry); err != nil {
|
|
return err
|
|
}
|
|
|
|
oldParent, newParent := util.FullPath(resp.Directory), util.FullPath(resp.EventNotification.NewParentPath)
|
|
oldName, newName := resp.EventNotification.OldEntry.Name, resp.EventNotification.NewEntry.Name
|
|
|
|
isDirectory := newEntry.IsDirectory()
|
|
|
|
oldPath := oldParent.Child(oldName)
|
|
newPath := newParent.Child(newName)
|
|
oldFsNode := NodeWithId(oldPath.AsInode(isDirectory))
|
|
newFsNode := NodeWithId(newPath.AsInode(isDirectory))
|
|
newDirNode, found := dir.wfs.Server.FindInternalNode(NodeWithId(newParent.AsInode(true)))
|
|
var newDir *Dir
|
|
if found {
|
|
newDir = newDirNode.(*Dir)
|
|
}
|
|
dir.wfs.Server.InvalidateInternalNode(oldFsNode, newFsNode, func(internalNode fs.Node) {
|
|
if file, ok := internalNode.(*File); ok {
|
|
glog.V(4).Infof("internal file node %s", oldParent.Child(oldName))
|
|
file.Name = newName
|
|
file.id = uint64(newFsNode)
|
|
if found {
|
|
file.dir = newDir
|
|
}
|
|
}
|
|
if dir, ok := internalNode.(*Dir); ok {
|
|
glog.V(4).Infof("internal dir node %s", oldParent.Child(oldName))
|
|
dir.name = newName
|
|
dir.id = uint64(newFsNode)
|
|
if found {
|
|
dir.parent = newDir
|
|
}
|
|
}
|
|
})
|
|
|
|
// change file handle
|
|
if !isDirectory {
|
|
inodeId := oldPath.AsInode(isDirectory)
|
|
dir.wfs.handlesLock.Lock()
|
|
if existingHandle, found := dir.wfs.handles[inodeId]; found && existingHandle != nil {
|
|
glog.V(4).Infof("opened file handle %s => %s", oldPath, newPath)
|
|
delete(dir.wfs.handles, inodeId)
|
|
existingHandle.handle = newPath.AsInode(isDirectory)
|
|
existingHandle.f.entry.Name = newName
|
|
existingHandle.f.id = newPath.AsInode(isDirectory)
|
|
dir.wfs.handles[newPath.AsInode(isDirectory)] = existingHandle
|
|
}
|
|
dir.wfs.handlesLock.Unlock()
|
|
}
|
|
|
|
} else if resp.EventNotification.OldEntry != nil {
|
|
// without new entry, only old entry name exists. This is the second step to delete old entry
|
|
if err := dir.wfs.metaCache.AtomicUpdateEntryFromFiler(ctx, util.NewFullPath(resp.Directory, resp.EventNotification.OldEntry.Name), nil); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|