weedfs_symlink.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. package mount
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "syscall"
  7. "time"
  8. "github.com/hanwen/go-fuse/v2/fuse"
  9. "github.com/seaweedfs/seaweedfs/weed/filer"
  10. "github.com/seaweedfs/seaweedfs/weed/glog"
  11. "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  12. )
  13. /** Create a symbolic link */
  14. func (wfs *WFS) Symlink(cancel <-chan struct{}, header *fuse.InHeader, target string, name string, out *fuse.EntryOut) (code fuse.Status) {
  15. if wfs.IsOverQuota {
  16. return fuse.Status(syscall.ENOSPC)
  17. }
  18. if s := checkName(name); s != fuse.OK {
  19. return s
  20. }
  21. dirPath, code := wfs.inodeToPath.GetPath(header.NodeId)
  22. if code != fuse.OK {
  23. return
  24. }
  25. entryFullPath := dirPath.Child(name)
  26. request := &filer_pb.CreateEntryRequest{
  27. Directory: string(dirPath),
  28. Entry: &filer_pb.Entry{
  29. Name: name,
  30. IsDirectory: false,
  31. Attributes: &filer_pb.FuseAttributes{
  32. Mtime: time.Now().Unix(),
  33. Crtime: time.Now().Unix(),
  34. FileMode: uint32(os.FileMode(0777) | os.ModeSymlink),
  35. Uid: header.Uid,
  36. Gid: header.Gid,
  37. SymlinkTarget: target,
  38. },
  39. },
  40. Signatures: []int32{wfs.signature},
  41. SkipCheckParentDirectory: true,
  42. }
  43. err := wfs.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
  44. wfs.mapPbIdFromLocalToFiler(request.Entry)
  45. defer wfs.mapPbIdFromFilerToLocal(request.Entry)
  46. if err := filer_pb.CreateEntry(client, request); err != nil {
  47. return fmt.Errorf("symlink %s: %v", entryFullPath, err)
  48. }
  49. wfs.metaCache.InsertEntry(context.Background(), filer.FromPbEntry(request.Directory, request.Entry))
  50. return nil
  51. })
  52. if err != nil {
  53. glog.V(0).Infof("Symlink %s => %s: %v", entryFullPath, target, err)
  54. return fuse.EIO
  55. }
  56. inode := wfs.inodeToPath.Lookup(entryFullPath, request.Entry.Attributes.Crtime, false, false, 0, true)
  57. wfs.outputPbEntry(out, inode, request.Entry)
  58. return fuse.OK
  59. }
  60. func (wfs *WFS) Readlink(cancel <-chan struct{}, header *fuse.InHeader) (out []byte, code fuse.Status) {
  61. entryFullPath, code := wfs.inodeToPath.GetPath(header.NodeId)
  62. if code != fuse.OK {
  63. return
  64. }
  65. entry, status := wfs.maybeLoadEntry(entryFullPath)
  66. if status != fuse.OK {
  67. return nil, status
  68. }
  69. if os.FileMode(entry.Attributes.FileMode)&os.ModeSymlink == 0 {
  70. return nil, fuse.EINVAL
  71. }
  72. return []byte(entry.Attributes.SymlinkTarget), fuse.OK
  73. }