2013-02-18 18:25:43 -05:00
|
|
|
package fs
|
2013-01-25 14:32:37 -05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2013-03-11 08:42:36 -04:00
|
|
|
"fmt"
|
2013-03-12 14:59:27 -04:00
|
|
|
"github.com/dotcloud/docker/future"
|
2013-01-27 18:42:42 -05:00
|
|
|
"io/ioutil"
|
2013-01-25 14:32:37 -05:00
|
|
|
"os"
|
2013-02-26 20:26:46 -05:00
|
|
|
"path"
|
|
|
|
"path/filepath"
|
2013-01-25 14:32:37 -05:00
|
|
|
)
|
|
|
|
|
2013-01-27 18:42:42 -05:00
|
|
|
type LayerStore struct {
|
2013-02-26 20:26:46 -05:00
|
|
|
Root string
|
2013-01-25 14:32:37 -05:00
|
|
|
}
|
|
|
|
|
2013-01-27 18:42:42 -05:00
|
|
|
func NewLayerStore(root string) (*LayerStore, error) {
|
2013-01-25 14:32:37 -05:00
|
|
|
abspath, err := filepath.Abs(root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2013-02-18 18:25:43 -05:00
|
|
|
// Create the root directory if it doesn't exists
|
|
|
|
if err := os.Mkdir(root, 0700); err != nil && !os.IsExist(err) {
|
|
|
|
return nil, err
|
|
|
|
}
|
2013-01-27 18:42:42 -05:00
|
|
|
return &LayerStore{
|
2013-01-25 14:32:37 -05:00
|
|
|
Root: abspath,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2013-01-27 18:42:42 -05:00
|
|
|
func (store *LayerStore) List() []string {
|
|
|
|
files, err := ioutil.ReadDir(store.Root)
|
|
|
|
if err != nil {
|
|
|
|
return []string{}
|
|
|
|
}
|
|
|
|
var layers []string
|
|
|
|
for _, st := range files {
|
|
|
|
if st.IsDir() {
|
|
|
|
layers = append(layers, path.Join(store.Root, st.Name()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return layers
|
|
|
|
}
|
|
|
|
|
|
|
|
func (store *LayerStore) Get(id string) string {
|
|
|
|
if !store.Exists(id) {
|
|
|
|
return ""
|
2013-01-25 14:32:37 -05:00
|
|
|
}
|
2013-01-27 18:42:42 -05:00
|
|
|
return store.layerPath(id)
|
2013-01-25 14:32:37 -05:00
|
|
|
}
|
|
|
|
|
2013-01-27 18:42:42 -05:00
|
|
|
func (store *LayerStore) rootExists() (bool, error) {
|
2013-01-25 14:32:37 -05:00
|
|
|
if stat, err := os.Stat(store.Root); err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
return false, err
|
|
|
|
} else if !stat.IsDir() {
|
|
|
|
return false, errors.New("Not a directory: " + store.Root)
|
|
|
|
}
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2013-01-27 18:42:42 -05:00
|
|
|
func (store *LayerStore) Init() error {
|
|
|
|
if exists, err := store.rootExists(); err != nil {
|
2013-01-25 14:32:37 -05:00
|
|
|
return err
|
|
|
|
} else if exists {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return os.Mkdir(store.Root, 0700)
|
|
|
|
}
|
|
|
|
|
2013-01-27 18:42:42 -05:00
|
|
|
func (store *LayerStore) Mktemp() (string, error) {
|
|
|
|
tmpName := future.RandomId()
|
2013-02-26 20:26:46 -05:00
|
|
|
tmpPath := path.Join(store.Root, "tmp-"+tmpName)
|
2013-01-25 14:32:37 -05:00
|
|
|
if err := os.Mkdir(tmpPath, 0700); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return tmpPath, nil
|
|
|
|
}
|
|
|
|
|
2013-01-27 18:42:42 -05:00
|
|
|
func (store *LayerStore) layerPath(id string) string {
|
2013-01-25 14:32:37 -05:00
|
|
|
return path.Join(store.Root, id)
|
|
|
|
}
|
|
|
|
|
2013-03-11 08:42:36 -04:00
|
|
|
func (store *LayerStore) AddLayer(id string, archive Archive) (string, error) {
|
2013-02-18 18:25:43 -05:00
|
|
|
if _, err := os.Stat(store.layerPath(id)); err == nil {
|
2013-03-11 08:42:36 -04:00
|
|
|
return "", fmt.Errorf("Layer already exists: %v", id)
|
2013-02-18 18:25:43 -05:00
|
|
|
}
|
2013-01-25 14:32:37 -05:00
|
|
|
tmp, err := store.Mktemp()
|
|
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err != nil {
|
2013-03-11 08:42:36 -04:00
|
|
|
return "", fmt.Errorf("Mktemp failed: %s", err)
|
2013-01-25 14:32:37 -05:00
|
|
|
}
|
2013-03-13 17:20:07 -04:00
|
|
|
if err := Untar(archive, tmp); err != nil {
|
2013-03-14 00:50:15 -04:00
|
|
|
return "", err
|
2013-01-25 14:32:37 -05:00
|
|
|
}
|
2013-01-27 18:42:42 -05:00
|
|
|
layer := store.layerPath(id)
|
|
|
|
if !store.Exists(id) {
|
|
|
|
if err := os.Rename(tmp, layer); err != nil {
|
2013-03-11 08:42:36 -04:00
|
|
|
return "", fmt.Errorf("Could not rename temp dir to layer %s: %s", layer, err)
|
2013-01-25 14:32:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return layer, nil
|
|
|
|
}
|
|
|
|
|
2013-01-27 18:42:42 -05:00
|
|
|
func (store *LayerStore) Exists(id string) bool {
|
|
|
|
st, err := os.Stat(store.layerPath(id))
|
2013-01-25 14:32:37 -05:00
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return st.IsDir()
|
|
|
|
}
|