mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
b6db23cffe
The vfs storage driver currently shells out to the `cp` binary on the host system to perform an 'archive' copy of the base image to a new directory. The archive option preserves the modified time of the files which are created but there was an issue where it was unable to preserve the modified time of copied symbolic links on some host systems with an outdated version of `cp`. This change no longer relies on the host system implementation and instead utilizes the `CopyWithTar` function found in `pkg/archive` which is used to copy from source to destination directory using a Tar archive, which should correctly preserve file attributes. Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
104 lines
2 KiB
Go
104 lines
2 KiB
Go
package vfs
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
|
|
"github.com/docker/docker/daemon/graphdriver"
|
|
"github.com/docker/docker/pkg/archive"
|
|
"github.com/docker/libcontainer/label"
|
|
)
|
|
|
|
func init() {
|
|
graphdriver.Register("vfs", Init)
|
|
}
|
|
|
|
func Init(home string, options []string) (graphdriver.Driver, error) {
|
|
d := &Driver{
|
|
home: home,
|
|
}
|
|
return graphdriver.NaiveDiffDriver(d), nil
|
|
}
|
|
|
|
type Driver struct {
|
|
home string
|
|
}
|
|
|
|
func (d *Driver) String() string {
|
|
return "vfs"
|
|
}
|
|
|
|
func (d *Driver) Status() [][2]string {
|
|
return nil
|
|
}
|
|
|
|
func (d *Driver) Cleanup() error {
|
|
return nil
|
|
}
|
|
|
|
func isGNUcoreutils() bool {
|
|
if stdout, err := exec.Command("cp", "--version").Output(); err == nil {
|
|
return bytes.Contains(stdout, []byte("GNU coreutils"))
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (d *Driver) Create(id, parent string) error {
|
|
dir := d.dir(id)
|
|
if err := os.MkdirAll(path.Dir(dir), 0700); err != nil {
|
|
return err
|
|
}
|
|
if err := os.Mkdir(dir, 0755); err != nil {
|
|
return err
|
|
}
|
|
opts := []string{"level:s0"}
|
|
if _, mountLabel, err := label.InitLabels(opts); err == nil {
|
|
label.Relabel(dir, mountLabel, "")
|
|
}
|
|
if parent == "" {
|
|
return nil
|
|
}
|
|
parentDir, err := d.Get(parent, "")
|
|
if err != nil {
|
|
return fmt.Errorf("%s: %s", parent, err)
|
|
}
|
|
if err := archive.CopyWithTar(parentDir, dir); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *Driver) dir(id string) string {
|
|
return path.Join(d.home, "dir", path.Base(id))
|
|
}
|
|
|
|
func (d *Driver) Remove(id string) error {
|
|
if _, err := os.Stat(d.dir(id)); err != nil {
|
|
return err
|
|
}
|
|
return os.RemoveAll(d.dir(id))
|
|
}
|
|
|
|
func (d *Driver) Get(id, mountLabel string) (string, error) {
|
|
dir := d.dir(id)
|
|
if st, err := os.Stat(dir); err != nil {
|
|
return "", err
|
|
} else if !st.IsDir() {
|
|
return "", fmt.Errorf("%s: not a directory", dir)
|
|
}
|
|
return dir, nil
|
|
}
|
|
|
|
func (d *Driver) Put(id string) {
|
|
// The vfs driver has no runtime resources (e.g. mounts)
|
|
// to clean up, so we don't need anything here
|
|
}
|
|
|
|
func (d *Driver) Exists(id string) bool {
|
|
_, err := os.Stat(d.dir(id))
|
|
return err == nil
|
|
}
|