package volumes import ( "encoding/json" "io" "io/ioutil" "os" "path" "path/filepath" "sync" "github.com/docker/docker/pkg/archive" "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) Export(resource, name string) (io.ReadCloser, error) { if v.IsBindMount && filepath.Base(resource) == name { name = "" } basePath, err := v.getResourcePath(resource) if err != nil { return nil, err } stat, err := os.Stat(basePath) if err != nil { return nil, err } var filter []string if !stat.IsDir() { d, f := path.Split(basePath) basePath = d filter = []string{f} } else { filter = []string{path.Base(basePath)} basePath = path.Dir(basePath) } return archive.TarWithOptions(basePath, &archive.TarOptions{ Compression: archive.Uncompressed, Name: name, IncludeFiles: filter, }) } 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 } jsonPath, err := v.jsonPath() if err != nil { return err } f, err := os.Create(jsonPath) if err != nil { return err } defer f.Close() return v.toDisk() } func (v *Volume) ToDisk() error { v.lock.Lock() defer v.lock.Unlock() return v.toDisk() } func (v *Volume) toDisk() error { data, err := json.Marshal(v) if err != nil { return err } pth, err := v.jsonPath() if err != nil { return err } return ioutil.WriteFile(pth, data, 0666) } 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") } func (v *Volume) getRootResourcePath(path string) (string, error) { cleanPath := filepath.Join("/", path) return symlink.FollowSymlinkInScope(filepath.Join(v.configPath, cleanPath), v.configPath) } func (v *Volume) getResourcePath(path string) (string, error) { cleanPath := filepath.Join("/", path) return symlink.FollowSymlinkInScope(filepath.Join(v.Path, cleanPath), v.Path) }