| 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 && os.IsNotExist(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) |
| } |