github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/layer/filestore.go (about) 1 package layer 2 3 import ( 4 "compress/gzip" 5 "errors" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "regexp" 12 "strconv" 13 14 "github.com/Sirupsen/logrus" 15 "github.com/docker/distribution/digest" 16 "github.com/docker/docker/pkg/ioutils" 17 ) 18 19 var ( 20 stringIDRegexp = regexp.MustCompile(`^[a-f0-9]{64}(-init)?$`) 21 supportedAlgorithms = []digest.Algorithm{ 22 digest.SHA256, 23 // digest.SHA384, // Currently not used 24 // digest.SHA512, // Currently not used 25 } 26 ) 27 28 type fileMetadataStore struct { 29 root string 30 } 31 32 type fileMetadataTransaction struct { 33 store *fileMetadataStore 34 root string 35 } 36 37 // NewFSMetadataStore returns an instance of a metadata store 38 // which is backed by files on disk using the provided root 39 // as the root of metadata files. 40 func NewFSMetadataStore(root string) (MetadataStore, error) { 41 if err := os.MkdirAll(root, 0700); err != nil { 42 return nil, err 43 } 44 return &fileMetadataStore{ 45 root: root, 46 }, nil 47 } 48 49 func (fms *fileMetadataStore) getLayerDirectory(layer ChainID) string { 50 dgst := digest.Digest(layer) 51 return filepath.Join(fms.root, string(dgst.Algorithm()), dgst.Hex()) 52 } 53 54 func (fms *fileMetadataStore) getLayerFilename(layer ChainID, filename string) string { 55 return filepath.Join(fms.getLayerDirectory(layer), filename) 56 } 57 58 func (fms *fileMetadataStore) getMountDirectory(mount string) string { 59 return filepath.Join(fms.root, "mounts", mount) 60 } 61 62 func (fms *fileMetadataStore) getMountFilename(mount, filename string) string { 63 return filepath.Join(fms.getMountDirectory(mount), filename) 64 } 65 66 func (fms *fileMetadataStore) StartTransaction() (MetadataTransaction, error) { 67 tmpDir := filepath.Join(fms.root, "tmp") 68 if err := os.MkdirAll(tmpDir, 0755); err != nil { 69 return nil, err 70 } 71 72 td, err := ioutil.TempDir(tmpDir, "layer-") 73 if err != nil { 74 return nil, err 75 } 76 // Create a new tempdir 77 return &fileMetadataTransaction{ 78 store: fms, 79 root: td, 80 }, nil 81 } 82 83 func (fm *fileMetadataTransaction) SetSize(size int64) error { 84 content := fmt.Sprintf("%d", size) 85 return ioutil.WriteFile(filepath.Join(fm.root, "size"), []byte(content), 0644) 86 } 87 88 func (fm *fileMetadataTransaction) SetParent(parent ChainID) error { 89 return ioutil.WriteFile(filepath.Join(fm.root, "parent"), []byte(digest.Digest(parent).String()), 0644) 90 } 91 92 func (fm *fileMetadataTransaction) SetDiffID(diff DiffID) error { 93 return ioutil.WriteFile(filepath.Join(fm.root, "diff"), []byte(digest.Digest(diff).String()), 0644) 94 } 95 96 func (fm *fileMetadataTransaction) SetCacheID(cacheID string) error { 97 return ioutil.WriteFile(filepath.Join(fm.root, "cache-id"), []byte(cacheID), 0644) 98 } 99 100 func (fm *fileMetadataTransaction) TarSplitWriter(compressInput bool) (io.WriteCloser, error) { 101 f, err := os.OpenFile(filepath.Join(fm.root, "tar-split.json.gz"), os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) 102 if err != nil { 103 return nil, err 104 } 105 var wc io.WriteCloser 106 if compressInput { 107 wc = gzip.NewWriter(f) 108 } else { 109 wc = f 110 } 111 112 return ioutils.NewWriteCloserWrapper(wc, func() error { 113 wc.Close() 114 return f.Close() 115 }), nil 116 } 117 118 func (fm *fileMetadataTransaction) Commit(layer ChainID) error { 119 finalDir := fm.store.getLayerDirectory(layer) 120 if err := os.MkdirAll(filepath.Dir(finalDir), 0755); err != nil { 121 return err 122 } 123 return os.Rename(fm.root, finalDir) 124 } 125 126 func (fm *fileMetadataTransaction) Cancel() error { 127 return os.RemoveAll(fm.root) 128 } 129 130 func (fm *fileMetadataTransaction) String() string { 131 return fm.root 132 } 133 134 func (fms *fileMetadataStore) GetSize(layer ChainID) (int64, error) { 135 content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "size")) 136 if err != nil { 137 return 0, err 138 } 139 140 size, err := strconv.ParseInt(string(content), 10, 64) 141 if err != nil { 142 return 0, err 143 } 144 145 return size, nil 146 } 147 148 func (fms *fileMetadataStore) GetParent(layer ChainID) (ChainID, error) { 149 content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "parent")) 150 if err != nil { 151 if os.IsNotExist(err) { 152 return "", nil 153 } 154 return "", err 155 } 156 157 dgst, err := digest.ParseDigest(string(content)) 158 if err != nil { 159 return "", err 160 } 161 162 return ChainID(dgst), nil 163 } 164 165 func (fms *fileMetadataStore) GetDiffID(layer ChainID) (DiffID, error) { 166 content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "diff")) 167 if err != nil { 168 return "", err 169 } 170 171 dgst, err := digest.ParseDigest(string(content)) 172 if err != nil { 173 return "", err 174 } 175 176 return DiffID(dgst), nil 177 } 178 179 func (fms *fileMetadataStore) GetCacheID(layer ChainID) (string, error) { 180 content, err := ioutil.ReadFile(fms.getLayerFilename(layer, "cache-id")) 181 if err != nil { 182 return "", err 183 } 184 185 if !stringIDRegexp.MatchString(string(content)) { 186 return "", errors.New("invalid cache id value") 187 } 188 189 return string(content), nil 190 } 191 192 func (fms *fileMetadataStore) TarSplitReader(layer ChainID) (io.ReadCloser, error) { 193 fz, err := os.Open(fms.getLayerFilename(layer, "tar-split.json.gz")) 194 if err != nil { 195 return nil, err 196 } 197 f, err := gzip.NewReader(fz) 198 if err != nil { 199 return nil, err 200 } 201 202 return ioutils.NewReadCloserWrapper(f, func() error { 203 f.Close() 204 return fz.Close() 205 }), nil 206 } 207 208 func (fms *fileMetadataStore) SetMountID(mount string, mountID string) error { 209 if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil { 210 return err 211 } 212 return ioutil.WriteFile(fms.getMountFilename(mount, "mount-id"), []byte(mountID), 0644) 213 } 214 215 func (fms *fileMetadataStore) SetInitID(mount string, init string) error { 216 if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil { 217 return err 218 } 219 return ioutil.WriteFile(fms.getMountFilename(mount, "init-id"), []byte(init), 0644) 220 } 221 222 func (fms *fileMetadataStore) SetMountParent(mount string, parent ChainID) error { 223 if err := os.MkdirAll(fms.getMountDirectory(mount), 0755); err != nil { 224 return err 225 } 226 return ioutil.WriteFile(fms.getMountFilename(mount, "parent"), []byte(digest.Digest(parent).String()), 0644) 227 } 228 229 func (fms *fileMetadataStore) GetMountID(mount string) (string, error) { 230 content, err := ioutil.ReadFile(fms.getMountFilename(mount, "mount-id")) 231 if err != nil { 232 return "", err 233 } 234 235 if !stringIDRegexp.MatchString(string(content)) { 236 return "", errors.New("invalid mount id value") 237 } 238 239 return string(content), nil 240 } 241 242 func (fms *fileMetadataStore) GetInitID(mount string) (string, error) { 243 content, err := ioutil.ReadFile(fms.getMountFilename(mount, "init-id")) 244 if err != nil { 245 if os.IsNotExist(err) { 246 return "", nil 247 } 248 return "", err 249 } 250 251 if !stringIDRegexp.MatchString(string(content)) { 252 return "", errors.New("invalid init id value") 253 } 254 255 return string(content), nil 256 } 257 258 func (fms *fileMetadataStore) GetMountParent(mount string) (ChainID, error) { 259 content, err := ioutil.ReadFile(fms.getMountFilename(mount, "parent")) 260 if err != nil { 261 if os.IsNotExist(err) { 262 return "", nil 263 } 264 return "", err 265 } 266 267 dgst, err := digest.ParseDigest(string(content)) 268 if err != nil { 269 return "", err 270 } 271 272 return ChainID(dgst), nil 273 } 274 275 func (fms *fileMetadataStore) List() ([]ChainID, []string, error) { 276 var ids []ChainID 277 for _, algorithm := range supportedAlgorithms { 278 fileInfos, err := ioutil.ReadDir(filepath.Join(fms.root, string(algorithm))) 279 if err != nil { 280 if os.IsNotExist(err) { 281 continue 282 } 283 return nil, nil, err 284 } 285 286 for _, fi := range fileInfos { 287 if fi.IsDir() && fi.Name() != "mounts" { 288 dgst := digest.NewDigestFromHex(string(algorithm), fi.Name()) 289 if err := dgst.Validate(); err != nil { 290 logrus.Debugf("Ignoring invalid digest %s:%s", algorithm, fi.Name()) 291 } else { 292 ids = append(ids, ChainID(dgst)) 293 } 294 } 295 } 296 } 297 298 fileInfos, err := ioutil.ReadDir(filepath.Join(fms.root, "mounts")) 299 if err != nil { 300 if os.IsNotExist(err) { 301 return ids, []string{}, nil 302 } 303 return nil, nil, err 304 } 305 306 var mounts []string 307 for _, fi := range fileInfos { 308 if fi.IsDir() { 309 mounts = append(mounts, fi.Name()) 310 } 311 } 312 313 return ids, mounts, nil 314 } 315 316 func (fms *fileMetadataStore) Remove(layer ChainID) error { 317 return os.RemoveAll(fms.getLayerDirectory(layer)) 318 } 319 320 func (fms *fileMetadataStore) RemoveMount(mount string) error { 321 return os.RemoveAll(fms.getMountDirectory(mount)) 322 }