github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/cmd/mount/dir.go (about) 1 // +build linux darwin freebsd 2 3 package mount 4 5 import ( 6 "context" 7 "os" 8 "time" 9 10 "bazil.org/fuse" 11 fusefs "bazil.org/fuse/fs" 12 "github.com/ncw/rclone/cmd/mountlib" 13 "github.com/ncw/rclone/fs/log" 14 "github.com/ncw/rclone/vfs" 15 "github.com/pkg/errors" 16 ) 17 18 // Dir represents a directory entry 19 type Dir struct { 20 *vfs.Dir 21 } 22 23 // Check interface satisfied 24 var _ fusefs.Node = (*Dir)(nil) 25 26 // Attr updates the attributes of a directory 27 func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) (err error) { 28 defer log.Trace(d, "")("attr=%+v, err=%v", a, &err) 29 a.Valid = mountlib.AttrTimeout 30 a.Gid = d.VFS().Opt.GID 31 a.Uid = d.VFS().Opt.UID 32 a.Mode = os.ModeDir | d.VFS().Opt.DirPerms 33 modTime := d.ModTime() 34 a.Atime = modTime 35 a.Mtime = modTime 36 a.Ctime = modTime 37 a.Crtime = modTime 38 // FIXME include Valid so get some caching? 39 // FIXME fs.Debugf(d.path, "Dir.Attr %+v", a) 40 return nil 41 } 42 43 // Check interface satisfied 44 var _ fusefs.NodeSetattrer = (*Dir)(nil) 45 46 // Setattr handles attribute changes from FUSE. Currently supports ModTime only. 47 func (d *Dir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) (err error) { 48 defer log.Trace(d, "stat=%+v", req)("err=%v", &err) 49 if d.VFS().Opt.NoModTime { 50 return nil 51 } 52 53 if req.Valid.MtimeNow() { 54 err = d.SetModTime(time.Now()) 55 } else if req.Valid.Mtime() { 56 err = d.SetModTime(req.Mtime) 57 } 58 59 return translateError(err) 60 } 61 62 // Check interface satisfied 63 var _ fusefs.NodeRequestLookuper = (*Dir)(nil) 64 65 // Lookup looks up a specific entry in the receiver. 66 // 67 // Lookup should return a Node corresponding to the entry. If the 68 // name does not exist in the directory, Lookup should return ENOENT. 69 // 70 // Lookup need not to handle the names "." and "..". 71 func (d *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (node fusefs.Node, err error) { 72 defer log.Trace(d, "name=%q", req.Name)("node=%+v, err=%v", &node, &err) 73 mnode, err := d.Dir.Stat(req.Name) 74 if err != nil { 75 return nil, translateError(err) 76 } 77 resp.EntryValid = mountlib.AttrTimeout 78 switch x := mnode.(type) { 79 case *vfs.File: 80 return &File{x}, nil 81 case *vfs.Dir: 82 return &Dir{x}, nil 83 } 84 panic("bad type") 85 } 86 87 // Check interface satisfied 88 var _ fusefs.HandleReadDirAller = (*Dir)(nil) 89 90 // ReadDirAll reads the contents of the directory 91 func (d *Dir) ReadDirAll(ctx context.Context) (dirents []fuse.Dirent, err error) { 92 itemsRead := -1 93 defer log.Trace(d, "")("item=%d, err=%v", &itemsRead, &err) 94 items, err := d.Dir.ReadDirAll() 95 if err != nil { 96 return nil, translateError(err) 97 } 98 for _, node := range items { 99 var dirent = fuse.Dirent{ 100 // Inode FIXME ??? 101 Type: fuse.DT_File, 102 Name: node.Name(), 103 } 104 if node.IsDir() { 105 dirent.Type = fuse.DT_Dir 106 } 107 dirents = append(dirents, dirent) 108 } 109 itemsRead = len(dirents) 110 return dirents, nil 111 } 112 113 var _ fusefs.NodeCreater = (*Dir)(nil) 114 115 // Create makes a new file 116 func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (node fusefs.Node, handle fusefs.Handle, err error) { 117 defer log.Trace(d, "name=%q", req.Name)("node=%v, handle=%v, err=%v", &node, &handle, &err) 118 file, err := d.Dir.Create(req.Name, int(req.Flags)) 119 if err != nil { 120 return nil, nil, translateError(err) 121 } 122 fh, err := file.Open(int(req.Flags) | os.O_CREATE) 123 if err != nil { 124 return nil, nil, translateError(err) 125 } 126 return &File{file}, &FileHandle{fh}, err 127 } 128 129 var _ fusefs.NodeMkdirer = (*Dir)(nil) 130 131 // Mkdir creates a new directory 132 func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (node fusefs.Node, err error) { 133 defer log.Trace(d, "name=%q", req.Name)("node=%+v, err=%v", &node, &err) 134 dir, err := d.Dir.Mkdir(req.Name) 135 if err != nil { 136 return nil, translateError(err) 137 } 138 return &Dir{dir}, nil 139 } 140 141 var _ fusefs.NodeRemover = (*Dir)(nil) 142 143 // Remove removes the entry with the given name from 144 // the receiver, which must be a directory. The entry to be removed 145 // may correspond to a file (unlink) or to a directory (rmdir). 146 func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) (err error) { 147 defer log.Trace(d, "name=%q", req.Name)("err=%v", &err) 148 err = d.Dir.RemoveName(req.Name) 149 if err != nil { 150 return translateError(err) 151 } 152 return nil 153 } 154 155 // Check interface satisfied 156 var _ fusefs.NodeRenamer = (*Dir)(nil) 157 158 // Rename the file 159 func (d *Dir) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fusefs.Node) (err error) { 160 defer log.Trace(d, "oldName=%q, newName=%q, newDir=%+v", req.OldName, req.NewName, newDir)("err=%v", &err) 161 destDir, ok := newDir.(*Dir) 162 if !ok { 163 return errors.Errorf("Unknown Dir type %T", newDir) 164 } 165 166 err = d.Dir.Rename(req.OldName, req.NewName, destDir.Dir) 167 if err != nil { 168 return translateError(err) 169 } 170 171 return nil 172 } 173 174 // Check interface satisfied 175 var _ fusefs.NodeFsyncer = (*Dir)(nil) 176 177 // Fsync the directory 178 func (d *Dir) Fsync(ctx context.Context, req *fuse.FsyncRequest) (err error) { 179 defer log.Trace(d, "")("err=%v", &err) 180 err = d.Dir.Sync() 181 if err != nil { 182 return translateError(err) 183 } 184 return nil 185 } 186 187 // Check interface satisfied 188 var _ fusefs.NodeLinker = (*Dir)(nil) 189 190 // Link creates a new directory entry in the receiver based on an 191 // existing Node. Receiver must be a directory. 192 func (d *Dir) Link(ctx context.Context, req *fuse.LinkRequest, old fusefs.Node) (newNode fusefs.Node, err error) { 193 defer log.Trace(d, "req=%v, old=%v", req, old)("new=%v, err=%v", &newNode, &err) 194 return nil, fuse.ENOSYS 195 }