github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/inode_operations.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package fs 16 17 import ( 18 "errors" 19 20 "github.com/SagerNet/gvisor/pkg/context" 21 ktime "github.com/SagerNet/gvisor/pkg/sentry/kernel/time" 22 "github.com/SagerNet/gvisor/pkg/sentry/memmap" 23 "github.com/SagerNet/gvisor/pkg/sentry/socket/unix/transport" 24 ) 25 26 var ( 27 // ErrResolveViaReadlink is a special error value returned by 28 // InodeOperations.Getlink() to indicate that a link should be 29 // resolved automatically by walking to the path returned by 30 // InodeOperations.Readlink(). 31 ErrResolveViaReadlink = errors.New("link should be resolved via Readlink()") 32 ) 33 34 // TimeSpec contains access and modification timestamps. If either ATimeOmit or 35 // MTimeOmit is true, then the corresponding timestamp should not be updated. 36 // If either ATimeSetSystemTime or MTimeSetSystemTime are set then the 37 // corresponding timestamp should be ignored and the time will be set to the 38 // current system time. 39 type TimeSpec struct { 40 ATime ktime.Time 41 ATimeOmit bool 42 ATimeSetSystemTime bool 43 MTime ktime.Time 44 MTimeOmit bool 45 MTimeSetSystemTime bool 46 } 47 48 // InodeOperations are operations on an Inode that diverge per file system. 49 // 50 // Objects that implement InodeOperations may cache file system "private" 51 // data that is useful for implementing these methods. In contrast, Inode 52 // contains state that is common to all Inodes; this state may be optionally 53 // used by InodeOperations. An object that implements InodeOperations may 54 // not take a reference on an Inode. 55 type InodeOperations interface { 56 // Release releases all private file system data held by this object. 57 // Once Release is called, this object is dead (no other methods will 58 // ever be called). 59 Release(context.Context) 60 61 // Lookup loads an Inode at name under dir into a Dirent. The name 62 // is a valid component path: it contains no "/"s nor is the empty 63 // string. 64 // 65 // Lookup may return one of: 66 // 67 // * A nil Dirent and a non-nil error. If the reason that Lookup failed 68 // was because the name does not exist under Inode, then must return 69 // syserror.ENOENT. 70 // 71 // * If name does not exist under dir and the file system wishes this 72 // fact to be cached, a non-nil Dirent containing a nil Inode and a 73 // nil error. This is a negative Dirent and must have exactly one 74 // reference (at-construction reference). 75 // 76 // * If name does exist under this dir, a non-nil Dirent containing a 77 // non-nil Inode, and a nil error. File systems that take extra 78 // references on this Dirent should implement DirentOperations. 79 Lookup(ctx context.Context, dir *Inode, name string) (*Dirent, error) 80 81 // Create creates an Inode at name under dir and returns a new File 82 // whose Dirent backs the new Inode. Implementations must ensure that 83 // name does not already exist. Create may return one of: 84 // 85 // * A nil File and a non-nil error. 86 // 87 // * A non-nil File and a nil error. File.Dirent will be a new Dirent, 88 // with a single reference held by File. File systems that take extra 89 // references on this Dirent should implement DirentOperations. 90 // 91 // The caller must ensure that this operation is permitted. 92 Create(ctx context.Context, dir *Inode, name string, flags FileFlags, perm FilePermissions) (*File, error) 93 94 // CreateDirectory creates a new directory under this dir. 95 // CreateDirectory should otherwise do the same as Create. 96 // 97 // The caller must ensure that this operation is permitted. 98 CreateDirectory(ctx context.Context, dir *Inode, name string, perm FilePermissions) error 99 100 // CreateLink creates a symbolic link under dir between newname 101 // and oldname. CreateLink should otherwise do the same as Create. 102 // 103 // The caller must ensure that this operation is permitted. 104 CreateLink(ctx context.Context, dir *Inode, oldname string, newname string) error 105 106 // CreateHardLink creates a hard link under dir between the target 107 // Inode and name. 108 // 109 // The caller must ensure this operation is permitted. 110 CreateHardLink(ctx context.Context, dir *Inode, target *Inode, name string) error 111 112 // CreateFifo creates a new named pipe under dir at name. 113 // 114 // The caller must ensure that this operation is permitted. 115 CreateFifo(ctx context.Context, dir *Inode, name string, perm FilePermissions) error 116 117 // Remove removes the given named non-directory under dir. 118 // 119 // The caller must ensure that this operation is permitted. 120 Remove(ctx context.Context, dir *Inode, name string) error 121 122 // RemoveDirectory removes the given named directory under dir. 123 // 124 // The caller must ensure that this operation is permitted. 125 // 126 // RemoveDirectory should check that the directory to be 127 // removed is empty. 128 RemoveDirectory(ctx context.Context, dir *Inode, name string) error 129 130 // Rename atomically renames oldName under oldParent to newName under 131 // newParent where oldParent and newParent are directories. inode is 132 // the Inode of this InodeOperations. 133 // 134 // If replacement is true, then newName already exists and this call 135 // will replace it with oldName. 136 // 137 // Implementations are responsible for rejecting renames that replace 138 // non-empty directories. 139 Rename(ctx context.Context, inode *Inode, oldParent *Inode, oldName string, newParent *Inode, newName string, replacement bool) error 140 141 // Bind binds a new socket under dir at the given name. 142 // 143 // The caller must ensure that this operation is permitted. 144 Bind(ctx context.Context, dir *Inode, name string, data transport.BoundEndpoint, perm FilePermissions) (*Dirent, error) 145 146 // BoundEndpoint returns the socket endpoint at path stored in 147 // or generated by an Inode. 148 // 149 // The path is only relevant for generated endpoint because stored 150 // endpoints already know their path. It is ok for the endpoint to 151 // hold onto their path because the only way to change a bind 152 // address is to rebind the socket. 153 // 154 // This is valid iff the type of the Inode is a Socket, which 155 // generally implies that this Inode was created via CreateSocket. 156 // 157 // If there is no socket endpoint available, nil will be returned. 158 BoundEndpoint(inode *Inode, path string) transport.BoundEndpoint 159 160 // GetFile returns a new open File backed by a Dirent and FileFlags. 161 // 162 // Special Inode types may block using ctx.Sleeper. RegularFiles, 163 // Directories, and Symlinks must not block (see doCopyUp). 164 // 165 // The returned File will uniquely back an application fd. 166 GetFile(ctx context.Context, d *Dirent, flags FileFlags) (*File, error) 167 168 // UnstableAttr returns the most up-to-date "unstable" attributes of 169 // an Inode, where "unstable" means that they change in response to 170 // file system events. 171 UnstableAttr(ctx context.Context, inode *Inode) (UnstableAttr, error) 172 173 // GetXattr retrieves the value of extended attribute specified by name. 174 // Inodes that do not support extended attributes return EOPNOTSUPP. Inodes 175 // that support extended attributes but don't have a value at name return 176 // ENODATA. 177 // 178 // If this is called through the getxattr(2) syscall, size indicates the 179 // size of the buffer that the application has allocated to hold the 180 // attribute value. If the value is larger than size, implementations may 181 // return ERANGE to indicate that the buffer is too small, but they are also 182 // free to ignore the hint entirely (i.e. the value returned may be larger 183 // than size). All size checking is done independently at the syscall layer. 184 GetXattr(ctx context.Context, inode *Inode, name string, size uint64) (string, error) 185 186 // SetXattr sets the value of extended attribute specified by name. Inodes 187 // that do not support extended attributes return EOPNOTSUPP. 188 SetXattr(ctx context.Context, inode *Inode, name, value string, flags uint32) error 189 190 // ListXattr returns the set of all extended attributes names that 191 // have values. Inodes that do not support extended attributes return 192 // EOPNOTSUPP. 193 // 194 // If this is called through the listxattr(2) syscall, size indicates the 195 // size of the buffer that the application has allocated to hold the 196 // attribute list. If the list would be larger than size, implementations may 197 // return ERANGE to indicate that the buffer is too small, but they are also 198 // free to ignore the hint entirely. All size checking is done independently 199 // at the syscall layer. 200 ListXattr(ctx context.Context, inode *Inode, size uint64) (map[string]struct{}, error) 201 202 // RemoveXattr removes an extended attribute specified by name. Inodes that 203 // do not support extended attributes return EOPNOTSUPP. 204 RemoveXattr(ctx context.Context, inode *Inode, name string) error 205 206 // Check determines whether an Inode can be accessed with the 207 // requested permission mask using the context (which gives access 208 // to Credentials and UserNamespace). 209 Check(ctx context.Context, inode *Inode, p PermMask) bool 210 211 // SetPermissions sets new permissions for an Inode. Returns false 212 // if it was not possible to set the new permissions. 213 // 214 // The caller must ensure that this operation is permitted. 215 SetPermissions(ctx context.Context, inode *Inode, f FilePermissions) bool 216 217 // SetOwner sets the ownership for this file. 218 // 219 // If either UID or GID are set to auth.NoID, its value will not be 220 // changed. 221 // 222 // The caller must ensure that this operation is permitted. 223 SetOwner(ctx context.Context, inode *Inode, owner FileOwner) error 224 225 // SetTimestamps sets the access and modification timestamps of an 226 // Inode according to the access and modification times in the TimeSpec. 227 // 228 // If either ATimeOmit or MTimeOmit is set, then the corresponding 229 // timestamp is not updated. 230 // 231 // If either ATimeSetSystemTime or MTimeSetSystemTime is true, that 232 // timestamp is set to the current time instead. 233 // 234 // The caller must ensure that this operation is permitted. 235 SetTimestamps(ctx context.Context, inode *Inode, ts TimeSpec) error 236 237 // Truncate changes the size of an Inode. Truncate should not check 238 // permissions internally, as it is used for both sys_truncate and 239 // sys_ftruncate. 240 // 241 // Implementations need not check that length >= 0. 242 Truncate(ctx context.Context, inode *Inode, size int64) error 243 244 // Allocate allows the caller to reserve disk space for the inode. 245 // It's equivalent to fallocate(2) with 'mode=0'. 246 Allocate(ctx context.Context, inode *Inode, offset int64, length int64) error 247 248 // WriteOut writes cached Inode state to a backing filesystem in a 249 // synchronous manner. 250 // 251 // File systems that do not cache metadata or data via an Inode 252 // implement WriteOut as a no-op. File systems that are entirely in 253 // memory also implement WriteOut as a no-op. Otherwise file systems 254 // call Inode.Sync to write back page cached data and cached metadata 255 // followed by syncing writeback handles. 256 // 257 // It derives from include/linux/fs.h:super_operations->write_inode. 258 WriteOut(ctx context.Context, inode *Inode) error 259 260 // Readlink reads the symlink path of an Inode. 261 // 262 // Readlink is permitted to return a different path depending on ctx, 263 // the request originator. 264 // 265 // The caller must ensure that this operation is permitted. 266 // 267 // Readlink should check that Inode is a symlink and its content is 268 // at least readable. 269 Readlink(ctx context.Context, inode *Inode) (string, error) 270 271 // Getlink resolves a symlink to a target *Dirent. 272 // 273 // Filesystems that can resolve the link by walking to the path returned 274 // by Readlink should return (nil, ErrResolveViaReadlink), which 275 // triggers link resolution via Realink and Lookup. 276 // 277 // Some links cannot be followed by Lookup. In this case, Getlink can 278 // return the Dirent of the link target. The caller holds a reference 279 // to the Dirent. Filesystems that return a non-nil *Dirent from Getlink 280 // cannot participate in an overlay because it is impossible for the 281 // overlay to ascertain whether or not the *Dirent should contain an 282 // overlayEntry. 283 // 284 // Any error returned from Getlink other than ErrResolveViaReadlink 285 // indicates the caller's inability to traverse this Inode as a link 286 // (e.g. linuxerr.ENOLINK indicates that the Inode is not a link, 287 // syscall.EPERM indicates that traversing the link is not allowed, etc). 288 Getlink(context.Context, *Inode) (*Dirent, error) 289 290 // Mappable returns a memmap.Mappable that provides memory mappings of the 291 // Inode's data. Mappable may return nil if this is not supported. The 292 // returned Mappable must remain valid until InodeOperations.Release is 293 // called. 294 Mappable(*Inode) memmap.Mappable 295 296 // The below methods require cleanup. 297 298 // AddLink increments the hard link count of an Inode. 299 // 300 // Remove in favor of Inode.IncLink. 301 AddLink() 302 303 // DropLink decrements the hard link count of an Inode. 304 // 305 // Remove in favor of Inode.DecLink. 306 DropLink() 307 308 // NotifyStatusChange sets the status change time to the current time. 309 // 310 // Remove in favor of updating the Inode's cached status change time. 311 NotifyStatusChange(ctx context.Context) 312 313 // IsVirtual indicates whether or not this corresponds to a virtual 314 // resource. 315 // 316 // If IsVirtual returns true, then caching will be disabled for this 317 // node, and fs.Dirent.Freeze() will not stop operations on the node. 318 // 319 // Remove in favor of freezing specific mounts. 320 IsVirtual() bool 321 322 // StatFS returns a filesystem Info implementation or an error. If 323 // the filesystem does not support this operation (maybe in the future 324 // it will), then ENOSYS should be returned. 325 StatFS(context.Context) (Info, error) 326 }