1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/volumes/volume.go

153 lines
3.6 KiB
Go
Raw Normal View History

package volumes
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"github.com/docker/docker/pkg/symlink"
)
type Volume struct {
ID string
Path string
IsBindMount bool
Writable bool
containers map[string]struct{}
configPath string
repository *Repository
lock sync.Mutex
}
func (v *Volume) IsDir() (bool, error) {
stat, err := os.Stat(v.Path)
if err != nil {
return false, err
}
return stat.IsDir(), nil
}
func (v *Volume) Containers() []string {
v.lock.Lock()
var containers []string
for c := range v.containers {
containers = append(containers, c)
}
v.lock.Unlock()
return containers
}
func (v *Volume) RemoveContainer(containerId string) {
v.lock.Lock()
delete(v.containers, containerId)
v.lock.Unlock()
}
func (v *Volume) AddContainer(containerId string) {
v.lock.Lock()
v.containers[containerId] = struct{}{}
v.lock.Unlock()
}
func (v *Volume) initialize() error {
v.lock.Lock()
defer v.lock.Unlock()
if _, err := os.Stat(v.Path); err != nil {
if !os.IsNotExist(err) {
return err
}
if err := os.MkdirAll(v.Path, 0755); err != nil {
return err
}
}
if err := os.MkdirAll(v.configPath, 0755); err != nil {
return err
}
return v.toDisk()
}
func (v *Volume) ToDisk() error {
v.lock.Lock()
defer v.lock.Unlock()
return v.toDisk()
}
func (v *Volume) toDisk() error {
jsonPath, err := v.jsonPath()
if err != nil {
return err
}
f, err := os.OpenFile(jsonPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
if err := json.NewEncoder(f).Encode(v); err != nil {
f.Close()
return err
}
return f.Close()
}
func (v *Volume) FromDisk() error {
v.lock.Lock()
defer v.lock.Unlock()
pth, err := v.jsonPath()
if err != nil {
return err
}
jsonSource, err := os.Open(pth)
if err != nil {
return err
}
defer jsonSource.Close()
dec := json.NewDecoder(jsonSource)
return dec.Decode(v)
}
func (v *Volume) jsonPath() (string, error) {
return v.GetRootResourcePath("config.json")
}
// Evalutes `path` in the scope of the volume's root path, with proper path
// sanitisation. Symlinks are all scoped to the root of the volume, as
// though the volume's root was `/`.
//
// The volume's root path is the host-facing path of the root of the volume's
// mountpoint inside a container.
//
// NOTE: The returned path is *only* safely scoped inside the volume's root
// if no component of the returned path changes (such as a component
// symlinking to a different path) between using this method and using the
// path. See symlink.FollowSymlinkInScope for more details.
func (v *Volume) GetResourcePath(path string) (string, error) {
cleanPath := filepath.Join("/", path)
return symlink.FollowSymlinkInScope(filepath.Join(v.Path, cleanPath), v.Path)
}
// Evalutes `path` in the scope of the volume's config path, with proper path
// sanitisation. Symlinks are all scoped to the root of the config path, as
// though the config path was `/`.
//
// The config path of a volume is not exposed to the container and is just used
// to store volume configuration options and other internal information. If in
// doubt, you probably want to just use v.GetResourcePath.
//
// NOTE: The returned path is *only* safely scoped inside the volume's config
// path if no component of the returned path changes (such as a component
// symlinking to a different path) between using this method and using the
// path. See symlink.FollowSymlinkInScope for more details.
func (v *Volume) GetRootResourcePath(path string) (string, error) {
cleanPath := filepath.Join("/", path)
return symlink.FollowSymlinkInScope(filepath.Join(v.configPath, cleanPath), v.configPath)
}