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