github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/cmd/mount/file.go (about) 1 //go:build linux 2 3 package mount 4 5 import ( 6 "context" 7 "syscall" 8 "time" 9 10 "bazil.org/fuse" 11 fusefs "bazil.org/fuse/fs" 12 "github.com/rclone/rclone/fs/log" 13 "github.com/rclone/rclone/vfs" 14 ) 15 16 // File represents a file 17 type File struct { 18 *vfs.File 19 fsys *FS 20 } 21 22 // Check interface satisfied 23 var _ fusefs.Node = (*File)(nil) 24 25 // Attr fills out the attributes for the file 26 func (f *File) Attr(ctx context.Context, a *fuse.Attr) (err error) { 27 defer log.Trace(f, "")("a=%+v, err=%v", a, &err) 28 a.Valid = f.fsys.opt.AttrTimeout 29 modTime := f.File.ModTime() 30 Size := uint64(f.File.Size()) 31 Blocks := (Size + 511) / 512 32 a.Gid = f.VFS().Opt.GID 33 a.Uid = f.VFS().Opt.UID 34 a.Mode = f.VFS().Opt.FilePerms 35 a.Size = Size 36 a.Atime = modTime 37 a.Mtime = modTime 38 a.Ctime = modTime 39 a.Blocks = Blocks 40 return nil 41 } 42 43 // Check interface satisfied 44 var _ fusefs.NodeSetattrer = (*File)(nil) 45 46 // Setattr handles attribute changes from FUSE. Currently supports ModTime and Size only 47 func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) (err error) { 48 defer log.Trace(f, "a=%+v", req)("err=%v", &err) 49 if !f.VFS().Opt.NoModTime { 50 if req.Valid.Mtime() { 51 err = f.File.SetModTime(req.Mtime) 52 } else if req.Valid.MtimeNow() { 53 err = f.File.SetModTime(time.Now()) 54 } 55 } 56 if req.Valid.Size() { 57 err = f.File.Truncate(int64(req.Size)) 58 } 59 return translateError(err) 60 } 61 62 // Check interface satisfied 63 var _ fusefs.NodeOpener = (*File)(nil) 64 65 // Open the file for read or write 66 func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fh fusefs.Handle, err error) { 67 defer log.Trace(f, "flags=%v", req.Flags)("fh=%v, err=%v", &fh, &err) 68 69 // fuse flags are based off syscall flags as are os flags, so 70 // should be compatible 71 handle, err := f.File.Open(int(req.Flags)) 72 if err != nil { 73 return nil, translateError(err) 74 } 75 76 // If size unknown then use direct io to read 77 if entry := handle.Node().DirEntry(); entry != nil && entry.Size() < 0 { 78 resp.Flags |= fuse.OpenDirectIO 79 } 80 if f.fsys.opt.DirectIO { 81 resp.Flags |= fuse.OpenDirectIO 82 } 83 84 return &FileHandle{handle}, nil 85 } 86 87 // Check interface satisfied 88 var _ fusefs.NodeFsyncer = (*File)(nil) 89 90 // Fsync the file 91 // 92 // Note that we don't do anything except return OK 93 func (f *File) Fsync(ctx context.Context, req *fuse.FsyncRequest) (err error) { 94 defer log.Trace(f, "")("err=%v", &err) 95 return nil 96 } 97 98 // Getxattr gets an extended attribute by the given name from the 99 // node. 100 // 101 // If there is no xattr by that name, returns fuse.ErrNoXattr. 102 func (f *File) Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error { 103 return syscall.ENOSYS // we never implement this 104 } 105 106 var _ fusefs.NodeGetxattrer = (*File)(nil) 107 108 // Listxattr lists the extended attributes recorded for the node. 109 func (f *File) Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error { 110 return syscall.ENOSYS // we never implement this 111 } 112 113 var _ fusefs.NodeListxattrer = (*File)(nil) 114 115 // Setxattr sets an extended attribute with the given name and 116 // value for the node. 117 func (f *File) Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error { 118 return syscall.ENOSYS // we never implement this 119 } 120 121 var _ fusefs.NodeSetxattrer = (*File)(nil) 122 123 // Removexattr removes an extended attribute for the name. 124 // 125 // If there is no xattr by that name, returns fuse.ErrNoXattr. 126 func (f *File) Removexattr(ctx context.Context, req *fuse.RemovexattrRequest) error { 127 return syscall.ENOSYS // we never implement this 128 } 129 130 var _ fusefs.NodeRemovexattrer = (*File)(nil)