You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
4.4 KiB

5 years ago
5 years ago
4 years ago
3 years ago
  1. package filesys
  2. import (
  3. "context"
  4. "github.com/chrislusf/seaweedfs/weed/filer"
  5. "github.com/chrislusf/seaweedfs/weed/glog"
  6. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  7. "github.com/chrislusf/seaweedfs/weed/util"
  8. "github.com/seaweedfs/fuse"
  9. "github.com/seaweedfs/fuse/fs"
  10. "io"
  11. "strings"
  12. )
  13. func (dir *Dir) Rename(ctx context.Context, req *fuse.RenameRequest, newDirectory fs.Node) error {
  14. if err := checkName(req.NewName); err != nil {
  15. return err
  16. }
  17. if err := checkName(req.OldName); err != nil {
  18. return err
  19. }
  20. newDir := newDirectory.(*Dir)
  21. newPath := util.NewFullPath(newDir.FullPath(), req.NewName)
  22. oldPath := util.NewFullPath(dir.FullPath(), req.OldName)
  23. glog.V(4).Infof("dir Rename %s => %s", oldPath, newPath)
  24. // update remote filer
  25. err := dir.wfs.WithFilerClient(true, func(client filer_pb.SeaweedFilerClient) error {
  26. ctx, cancel := context.WithCancel(context.Background())
  27. defer cancel()
  28. request := &filer_pb.StreamRenameEntryRequest{
  29. OldDirectory: dir.FullPath(),
  30. OldName: req.OldName,
  31. NewDirectory: newDir.FullPath(),
  32. NewName: req.NewName,
  33. Signatures: []int32{dir.wfs.signature},
  34. }
  35. stream, err := client.StreamRenameEntry(ctx, request)
  36. if err != nil {
  37. glog.Errorf("dir AtomicRenameEntry %s => %s : %v", oldPath, newPath, err)
  38. return fuse.EIO
  39. }
  40. for {
  41. resp, recvErr := stream.Recv()
  42. if recvErr != nil {
  43. if recvErr == io.EOF {
  44. break
  45. } else {
  46. glog.V(0).Infof("dir Rename %s => %s receive: %v", oldPath, newPath, recvErr)
  47. if strings.Contains(recvErr.Error(), "not empty") {
  48. return fuse.EEXIST
  49. }
  50. if strings.Contains(recvErr.Error(), "not directory") {
  51. return fuse.ENOTDIR
  52. }
  53. return recvErr
  54. }
  55. }
  56. if err = dir.handleRenameResponse(ctx, resp); err != nil {
  57. glog.V(0).Infof("dir Rename %s => %s : %v", oldPath, newPath, err)
  58. return err
  59. }
  60. }
  61. return nil
  62. })
  63. return err
  64. }
  65. func (dir *Dir) handleRenameResponse(ctx context.Context, resp *filer_pb.StreamRenameEntryResponse) error {
  66. // comes from filer StreamRenameEntry, can only be create or delete entry
  67. if resp.EventNotification.NewEntry != nil {
  68. // with new entry, the old entry name also exists. This is the first step to create new entry
  69. newEntry := filer.FromPbEntry(resp.EventNotification.NewParentPath, resp.EventNotification.NewEntry)
  70. if err := dir.wfs.metaCache.AtomicUpdateEntryFromFiler(ctx, "", newEntry); err != nil {
  71. return err
  72. }
  73. oldParent, newParent := util.FullPath(resp.Directory), util.FullPath(resp.EventNotification.NewParentPath)
  74. oldName, newName := resp.EventNotification.OldEntry.Name, resp.EventNotification.NewEntry.Name
  75. isDirectory := newEntry.IsDirectory()
  76. oldPath := oldParent.Child(oldName)
  77. newPath := newParent.Child(newName)
  78. oldFsNode := NodeWithId(oldPath.AsInode(isDirectory))
  79. newFsNode := NodeWithId(newPath.AsInode(isDirectory))
  80. newDirNode, found := dir.wfs.Server.FindInternalNode(NodeWithId(newParent.AsInode(true)))
  81. var newDir *Dir
  82. if found {
  83. newDir = newDirNode.(*Dir)
  84. }
  85. dir.wfs.Server.InvalidateInternalNode(oldFsNode, newFsNode, func(internalNode fs.Node) {
  86. if file, ok := internalNode.(*File); ok {
  87. glog.V(4).Infof("internal file node %s", oldParent.Child(oldName))
  88. file.Name = newName
  89. file.id = uint64(newFsNode)
  90. if found {
  91. file.dir = newDir
  92. }
  93. }
  94. if dir, ok := internalNode.(*Dir); ok {
  95. glog.V(4).Infof("internal dir node %s", oldParent.Child(oldName))
  96. dir.name = newName
  97. dir.id = uint64(newFsNode)
  98. if found {
  99. dir.parent = newDir
  100. }
  101. }
  102. })
  103. // change file handle
  104. if !isDirectory {
  105. inodeId := oldPath.AsInode(isDirectory)
  106. dir.wfs.handlesLock.Lock()
  107. if existingHandle, found := dir.wfs.handles[inodeId]; found && existingHandle != nil {
  108. glog.V(4).Infof("opened file handle %s => %s", oldPath, newPath)
  109. delete(dir.wfs.handles, inodeId)
  110. existingHandle.handle = newPath.AsInode(isDirectory)
  111. existingHandle.f.entry.Name = newName
  112. existingHandle.f.id = newPath.AsInode(isDirectory)
  113. dir.wfs.handles[newPath.AsInode(isDirectory)] = existingHandle
  114. }
  115. dir.wfs.handlesLock.Unlock()
  116. }
  117. } else if resp.EventNotification.OldEntry != nil {
  118. // without new entry, only old entry name exists. This is the second step to delete old entry
  119. if err := dir.wfs.metaCache.AtomicUpdateEntryFromFiler(ctx, util.NewFullPath(resp.Directory, resp.EventNotification.OldEntry.Name), nil); err != nil {
  120. return err
  121. }
  122. }
  123. return nil
  124. }