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  }