github.com/tompao/docker@v1.9.1/daemon/volumes.go (about) 1 package daemon 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strings" 10 11 "github.com/Sirupsen/logrus" 12 "github.com/docker/docker/api/types" 13 derr "github.com/docker/docker/errors" 14 "github.com/docker/docker/pkg/chrootarchive" 15 "github.com/docker/docker/pkg/system" 16 "github.com/docker/docker/volume" 17 ) 18 19 var ( 20 // ErrVolumeReadonly is used to signal an error when trying to copy data into 21 // a volume mount that is not writable. 22 ErrVolumeReadonly = errors.New("mounted volume is marked read-only") 23 ) 24 25 // mountPoint is the intersection point between a volume and a container. It 26 // specifies which volume is to be used and where inside a container it should 27 // be mounted. 28 type mountPoint struct { 29 Name string 30 Destination string 31 Driver string 32 RW bool 33 Volume volume.Volume `json:"-"` 34 Source string 35 Mode string `json:"Relabel"` // Originally field was `Relabel`" 36 } 37 38 // Setup sets up a mount point by either mounting the volume if it is 39 // configured, or creating the source directory if supplied. 40 func (m *mountPoint) Setup() (string, error) { 41 if m.Volume != nil { 42 return m.Volume.Mount() 43 } 44 45 if len(m.Source) > 0 { 46 if _, err := os.Stat(m.Source); err != nil { 47 if !os.IsNotExist(err) { 48 return "", err 49 } 50 logrus.Warnf("Auto-creating non-existant volume host path %s, this is deprecated and will be removed soon", m.Source) 51 if err := system.MkdirAll(m.Source, 0755); err != nil { 52 return "", err 53 } 54 } 55 return m.Source, nil 56 } 57 58 return "", derr.ErrorCodeMountSetup 59 } 60 61 // hasResource checks whether the given absolute path for a container is in 62 // this mount point. If the relative path starts with `../` then the resource 63 // is outside of this mount point, but we can't simply check for this prefix 64 // because it misses `..` which is also outside of the mount, so check both. 65 func (m *mountPoint) hasResource(absolutePath string) bool { 66 relPath, err := filepath.Rel(m.Destination, absolutePath) 67 68 return err == nil && relPath != ".." && !strings.HasPrefix(relPath, fmt.Sprintf("..%c", filepath.Separator)) 69 } 70 71 // Path returns the path of a volume in a mount point. 72 func (m *mountPoint) Path() string { 73 if m.Volume != nil { 74 return m.Volume.Path() 75 } 76 77 return m.Source 78 } 79 80 // copyExistingContents copies from the source to the destination and 81 // ensures the ownership is appropriately set. 82 func copyExistingContents(source, destination string) error { 83 volList, err := ioutil.ReadDir(source) 84 if err != nil { 85 return err 86 } 87 if len(volList) > 0 { 88 srcList, err := ioutil.ReadDir(destination) 89 if err != nil { 90 return err 91 } 92 if len(srcList) == 0 { 93 // If the source volume is empty copy files from the root into the volume 94 if err := chrootarchive.CopyWithTar(source, destination); err != nil { 95 return err 96 } 97 } 98 } 99 return copyOwnership(source, destination) 100 } 101 102 // volumeToAPIType converts a volume.Volume to the type used by the remote API 103 func volumeToAPIType(v volume.Volume) *types.Volume { 104 return &types.Volume{ 105 Name: v.Name(), 106 Driver: v.DriverName(), 107 Mountpoint: v.Path(), 108 } 109 }