123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- package mount
- import (
- "context"
- "syscall"
- "time"
- "github.com/hanwen/go-fuse/v2/fuse"
- "github.com/seaweedfs/seaweedfs/weed/filer"
- "github.com/seaweedfs/seaweedfs/weed/glog"
- "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
- )
- /*
- What is an inode?
- If the file is an hardlinked file:
- use the hardlink id as inode
- Otherwise:
- use the file path as inode
- When creating a link:
- use the original file inode
- */
- /** Create a hard link to a file */
- func (wfs *WFS) Link(cancel <-chan struct{}, in *fuse.LinkIn, name string, out *fuse.EntryOut) (code fuse.Status) {
- if wfs.IsOverQuota {
- return fuse.Status(syscall.ENOSPC)
- }
- if s := checkName(name); s != fuse.OK {
- return s
- }
- newParentPath, code := wfs.inodeToPath.GetPath(in.NodeId)
- if code != fuse.OK {
- return
- }
- oldEntryPath, code := wfs.inodeToPath.GetPath(in.Oldnodeid)
- if code != fuse.OK {
- return
- }
- oldParentPath, _ := oldEntryPath.DirAndName()
- oldEntry, status := wfs.maybeLoadEntry(oldEntryPath)
- if status != fuse.OK {
- return status
- }
- // hardlink is not allowed in WORM mode
- if wfs.wormEnabledForEntry(oldEntryPath, oldEntry) {
- return fuse.EPERM
- }
- // update old file to hardlink mode
- if len(oldEntry.HardLinkId) == 0 {
- oldEntry.HardLinkId = filer.NewHardLinkId()
- oldEntry.HardLinkCounter = 1
- }
- oldEntry.HardLinkCounter++
- updateOldEntryRequest := &filer_pb.UpdateEntryRequest{
- Directory: oldParentPath,
- Entry: oldEntry,
- Signatures: []int32{wfs.signature},
- }
- // CreateLink 1.2 : update new file to hardlink mode
- oldEntry.Attributes.Mtime = time.Now().Unix()
- request := &filer_pb.CreateEntryRequest{
- Directory: string(newParentPath),
- Entry: &filer_pb.Entry{
- Name: name,
- IsDirectory: false,
- Attributes: oldEntry.Attributes,
- Chunks: oldEntry.GetChunks(),
- Extended: oldEntry.Extended,
- HardLinkId: oldEntry.HardLinkId,
- HardLinkCounter: oldEntry.HardLinkCounter,
- },
- Signatures: []int32{wfs.signature},
- SkipCheckParentDirectory: true,
- }
- // apply changes to the filer, and also apply to local metaCache
- err := wfs.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
- wfs.mapPbIdFromLocalToFiler(request.Entry)
- defer wfs.mapPbIdFromFilerToLocal(request.Entry)
- if err := filer_pb.UpdateEntry(client, updateOldEntryRequest); err != nil {
- return err
- }
- wfs.metaCache.UpdateEntry(context.Background(), filer.FromPbEntry(updateOldEntryRequest.Directory, updateOldEntryRequest.Entry))
- if err := filer_pb.CreateEntry(client, request); err != nil {
- return err
- }
- wfs.metaCache.InsertEntry(context.Background(), filer.FromPbEntry(request.Directory, request.Entry))
- return nil
- })
- newEntryPath := newParentPath.Child(name)
- if err != nil {
- glog.V(0).Infof("Link %v -> %s: %v", oldEntryPath, newEntryPath, err)
- return fuse.EIO
- }
- wfs.inodeToPath.AddPath(oldEntry.Attributes.Inode, newEntryPath)
- wfs.outputPbEntry(out, oldEntry.Attributes.Inode, request.Entry)
- return fuse.OK
- }
|