1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package driver 18 19 import ( 20 "fmt" 21 "io" 22 "os" 23 ) 24 25 var ErrNotSupported = fmt.Errorf("not supported") 26 27 // Driver provides all of the system-level functions in a common interface. 28 // The context should call these with full paths and should never use the `os` 29 // package or any other package to access resources on the filesystem. This 30 // mechanism let's us carefully control access to the context and maintain 31 // path and resource integrity. It also gives us an interface to reason about 32 // direct resource access. 33 // 34 // Implementations don't need to do much other than meet the interface. For 35 // example, it is not required to wrap os.FileInfo to return correct paths for 36 // the call to Name(). 37 type Driver interface { 38 // Note that Open() returns a File interface instead of *os.File. This 39 // is because os.File is a struct, so if Open was to return *os.File, 40 // the only way to fulfill the interface would be to call os.Open() 41 Open(path string) (File, error) 42 OpenFile(path string, flag int, perm os.FileMode) (File, error) 43 44 Stat(path string) (os.FileInfo, error) 45 Lstat(path string) (os.FileInfo, error) 46 Readlink(p string) (string, error) 47 Mkdir(path string, mode os.FileMode) error 48 Remove(path string) error 49 50 Link(oldname, newname string) error 51 Lchmod(path string, mode os.FileMode) error 52 Lchown(path string, uid, gid int64) error 53 Symlink(oldname, newname string) error 54 55 MkdirAll(path string, perm os.FileMode) error 56 RemoveAll(path string) error 57 58 // TODO(aaronl): These methods might move outside the main Driver 59 // interface in the future as more platforms are added. 60 Mknod(path string, mode os.FileMode, major int, minor int) error 61 Mkfifo(path string, mode os.FileMode) error 62 } 63 64 // File is the interface for interacting with files returned by continuity's Open 65 // This is needed since os.File is a struct, instead of an interface, so it can't 66 // be used. 67 type File interface { 68 io.ReadWriteCloser 69 io.Seeker 70 Readdir(n int) ([]os.FileInfo, error) 71 } 72 73 func NewSystemDriver() (Driver, error) { 74 // TODO(stevvooe): Consider having this take a "hint" path argument, which 75 // would be the context root. The hint could be used to resolve required 76 // filesystem support when assembling the driver to use. 77 return &driver{}, nil 78 } 79 80 // XAttrDriver should be implemented on operation systems and filesystems that 81 // have xattr support for regular files and directories. 82 type XAttrDriver interface { 83 // Getxattr returns all of the extended attributes for the file at path. 84 // Typically, this takes a syscall call to Listxattr and Getxattr. 85 Getxattr(path string) (map[string][]byte, error) 86 87 // Setxattr sets all of the extended attributes on file at path, following 88 // any symbolic links, if necessary. All attributes on the target are 89 // replaced by the values from attr. If the operation fails to set any 90 // attribute, those already applied will not be rolled back. 91 Setxattr(path string, attr map[string][]byte) error 92 } 93 94 // LXAttrDriver should be implemented by drivers on operating systems and 95 // filesystems that support setting and getting extended attributes on 96 // symbolic links. If this is not implemented, extended attributes will be 97 // ignored on symbolic links. 98 type LXAttrDriver interface { 99 // LGetxattr returns all of the extended attributes for the file at path 100 // and does not follow symlinks. Typically, this takes a syscall call to 101 // Llistxattr and Lgetxattr. 102 LGetxattr(path string) (map[string][]byte, error) 103 104 // LSetxattr sets all of the extended attributes on file at path, without 105 // following symbolic links. All attributes on the target are replaced by 106 // the values from attr. If the operation fails to set any attribute, 107 // those already applied will not be rolled back. 108 LSetxattr(path string, attr map[string][]byte) error 109 } 110 111 type DeviceInfoDriver interface { 112 DeviceInfo(fi os.FileInfo) (maj uint64, min uint64, err error) 113 } 114 115 // driver is a simple default implementation that sends calls out to the "os" 116 // package. Extend the "driver" type in system-specific files to add support, 117 // such as xattrs, which can add support at compile time. 118 type driver struct{} 119 120 var _ File = &os.File{} 121 122 // LocalDriver is the exported Driver struct for convenience. 123 var LocalDriver Driver = &driver{} 124 125 func (d *driver) Open(p string) (File, error) { 126 return os.Open(p) 127 } 128 129 func (d *driver) OpenFile(path string, flag int, perm os.FileMode) (File, error) { 130 return os.OpenFile(path, flag, perm) 131 } 132 133 func (d *driver) Stat(p string) (os.FileInfo, error) { 134 return os.Stat(p) 135 } 136 137 func (d *driver) Lstat(p string) (os.FileInfo, error) { 138 return os.Lstat(p) 139 } 140 141 func (d *driver) Readlink(p string) (string, error) { 142 return os.Readlink(p) 143 } 144 145 func (d *driver) Mkdir(p string, mode os.FileMode) error { 146 return os.Mkdir(p, mode) 147 } 148 149 // Remove is used to unlink files and remove directories. 150 // This is following the golang os package api which 151 // combines the operations into a higher level Remove 152 // function. If explicit unlinking or directory removal 153 // to mirror system call is required, they should be 154 // split up at that time. 155 func (d *driver) Remove(path string) error { 156 return os.Remove(path) 157 } 158 159 func (d *driver) Link(oldname, newname string) error { 160 return os.Link(oldname, newname) 161 } 162 163 func (d *driver) Lchown(name string, uid, gid int64) error { 164 // TODO: error out if uid excesses int bit width? 165 return os.Lchown(name, int(uid), int(gid)) 166 } 167 168 func (d *driver) Symlink(oldname, newname string) error { 169 return os.Symlink(oldname, newname) 170 } 171 172 func (d *driver) MkdirAll(path string, perm os.FileMode) error { 173 return os.MkdirAll(path, perm) 174 } 175 176 func (d *driver) RemoveAll(path string) error { 177 return os.RemoveAll(path) 178 } 179