github.com/sshnaidm/storage@v1.12.13/drivers/vfs/driver.go (about) 1 package vfs 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "strings" 8 9 "github.com/containers/storage/drivers" 10 "github.com/containers/storage/pkg/idtools" 11 "github.com/containers/storage/pkg/ostree" 12 "github.com/containers/storage/pkg/system" 13 "github.com/opencontainers/selinux/go-selinux/label" 14 ) 15 16 var ( 17 // CopyDir defines the copy method to use. 18 CopyDir = dirCopy 19 ) 20 21 func init() { 22 graphdriver.Register("vfs", Init) 23 } 24 25 // Init returns a new VFS driver. 26 // This sets the home directory for the driver and returns NaiveDiffDriver. 27 func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) { 28 d := &Driver{ 29 homes: []string{home}, 30 idMappings: idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps), 31 } 32 rootIDs := d.idMappings.RootPair() 33 if err := idtools.MkdirAllAndChown(home, 0700, rootIDs); err != nil { 34 return nil, err 35 } 36 for _, option := range options.DriverOptions { 37 if strings.HasPrefix(option, "vfs.imagestore=") { 38 d.homes = append(d.homes, strings.Split(option[15:], ",")...) 39 continue 40 } 41 if strings.HasPrefix(option, ".imagestore=") { 42 d.homes = append(d.homes, strings.Split(option[12:], ",")...) 43 continue 44 } 45 if strings.HasPrefix(option, "vfs.ostree_repo=") { 46 if !ostree.OstreeSupport() { 47 return nil, fmt.Errorf("vfs: ostree_repo specified but support for ostree is missing") 48 } 49 d.ostreeRepo = option[16:] 50 } 51 if strings.HasPrefix(option, ".ostree_repo=") { 52 if !ostree.OstreeSupport() { 53 return nil, fmt.Errorf("vfs: ostree_repo specified but support for ostree is missing") 54 } 55 d.ostreeRepo = option[13:] 56 } 57 if strings.HasPrefix(option, "vfs.mountopt=") { 58 return nil, fmt.Errorf("vfs driver does not support mount options") 59 } 60 } 61 if d.ostreeRepo != "" { 62 rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps) 63 if err != nil { 64 return nil, err 65 } 66 if err := ostree.CreateOSTreeRepository(d.ostreeRepo, rootUID, rootGID); err != nil { 67 return nil, err 68 } 69 } 70 return graphdriver.NewNaiveDiffDriver(d, graphdriver.NewNaiveLayerIDMapUpdater(d)), nil 71 } 72 73 // Driver holds information about the driver, home directory of the driver. 74 // Driver implements graphdriver.ProtoDriver. It uses only basic vfs operations. 75 // In order to support layering, files are copied from the parent layer into the new layer. There is no copy-on-write support. 76 // Driver must be wrapped in NaiveDiffDriver to be used as a graphdriver.Driver 77 type Driver struct { 78 homes []string 79 idMappings *idtools.IDMappings 80 ostreeRepo string 81 } 82 83 func (d *Driver) String() string { 84 return "vfs" 85 } 86 87 // Status is used for implementing the graphdriver.ProtoDriver interface. VFS does not currently have any status information. 88 func (d *Driver) Status() [][2]string { 89 return nil 90 } 91 92 // Metadata is used for implementing the graphdriver.ProtoDriver interface. VFS does not currently have any meta data. 93 func (d *Driver) Metadata(id string) (map[string]string, error) { 94 return nil, nil 95 } 96 97 // Cleanup is used to implement graphdriver.ProtoDriver. There is no cleanup required for this driver. 98 func (d *Driver) Cleanup() error { 99 return nil 100 } 101 102 // CreateFromTemplate creates a layer with the same contents and parent as another layer. 103 func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error { 104 if readWrite { 105 return d.CreateReadWrite(id, template, opts) 106 } 107 return d.Create(id, template, opts) 108 } 109 110 // CreateReadWrite creates a layer that is writable for use as a container 111 // file system. 112 func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { 113 return d.create(id, parent, opts, false) 114 } 115 116 // Create prepares the filesystem for the VFS driver and copies the directory for the given id under the parent. 117 func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error { 118 return d.create(id, parent, opts, true) 119 } 120 121 func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, ro bool) error { 122 if opts != nil && len(opts.StorageOpt) != 0 { 123 return fmt.Errorf("--storage-opt is not supported for vfs") 124 } 125 126 idMappings := d.idMappings 127 if opts != nil && opts.IDMappings != nil { 128 idMappings = opts.IDMappings 129 } 130 131 dir := d.dir(id) 132 rootIDs := idMappings.RootPair() 133 if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0700, rootIDs); err != nil { 134 return err 135 } 136 if parent != "" { 137 st, err := system.Stat(d.dir(parent)) 138 if err != nil { 139 return err 140 } 141 rootIDs.UID = int(st.UID()) 142 rootIDs.GID = int(st.GID()) 143 } 144 if err := idtools.MkdirAndChown(dir, 0755, rootIDs); err != nil { 145 return err 146 } 147 labelOpts := []string{"level:s0"} 148 if _, mountLabel, err := label.InitLabels(labelOpts); err == nil { 149 label.SetFileLabel(dir, mountLabel) 150 } 151 if parent != "" { 152 parentDir, err := d.Get(parent, graphdriver.MountOpts{}) 153 if err != nil { 154 return fmt.Errorf("%s: %s", parent, err) 155 } 156 if err := dirCopy(parentDir, dir); err != nil { 157 return err 158 } 159 } 160 161 if ro && d.ostreeRepo != "" { 162 if err := ostree.ConvertToOSTree(d.ostreeRepo, dir, id); err != nil { 163 return err 164 } 165 } 166 return nil 167 168 } 169 170 func (d *Driver) dir(id string) string { 171 for i, home := range d.homes { 172 if i > 0 { 173 home = filepath.Join(home, d.String()) 174 } 175 candidate := filepath.Join(home, "dir", filepath.Base(id)) 176 fi, err := os.Stat(candidate) 177 if err == nil && fi.IsDir() { 178 return candidate 179 } 180 } 181 return filepath.Join(d.homes[0], "dir", filepath.Base(id)) 182 } 183 184 // Remove deletes the content from the directory for a given id. 185 func (d *Driver) Remove(id string) error { 186 if d.ostreeRepo != "" { 187 // Ignore errors, we don't want to fail if the ostree branch doesn't exist, 188 ostree.DeleteOSTree(d.ostreeRepo, id) 189 } 190 return system.EnsureRemoveAll(d.dir(id)) 191 } 192 193 // Get returns the directory for the given id. 194 func (d *Driver) Get(id string, options graphdriver.MountOpts) (_ string, retErr error) { 195 dir := d.dir(id) 196 if len(options.Options) > 0 { 197 return "", fmt.Errorf("vfs driver does not support mount options") 198 } 199 if st, err := os.Stat(dir); err != nil { 200 return "", err 201 } else if !st.IsDir() { 202 return "", fmt.Errorf("%s: not a directory", dir) 203 } 204 return dir, nil 205 } 206 207 // Put is a noop for vfs that return nil for the error, since this driver has no runtime resources to clean up. 208 func (d *Driver) Put(id string) error { 209 // The vfs driver has no runtime resources (e.g. mounts) 210 // to clean up, so we don't need anything here 211 return nil 212 } 213 214 // Exists checks to see if the directory exists for the given id. 215 func (d *Driver) Exists(id string) bool { 216 _, err := os.Stat(d.dir(id)) 217 return err == nil 218 } 219 220 // AdditionalImageStores returns additional image stores supported by the driver 221 func (d *Driver) AdditionalImageStores() []string { 222 if len(d.homes) > 1 { 223 return d.homes[1:] 224 } 225 return nil 226 }