func (d *disk) Add(digest isolated.HexDigest, src io.Reader) error { if !digest.Validate() { return os.ErrInvalid } p := d.itemPath(digest) dst, err := os.Create(p) if err != nil { return err } h := isolated.GetHash() // TODO(maruel): Use a LimitedReader flavor that fails when reaching limit. size, err := io.Copy(dst, io.TeeReader(src, h)) if err2 := dst.Close(); err == nil { err = err2 } if err != nil { _ = os.Remove(p) return err } if isolated.Sum(h) != digest { _ = os.Remove(p) return errors.New("invalid hash") } if common.Size(size) > d.policies.MaxSize { _ = os.Remove(p) return errors.New("item too large") } d.lock.Lock() defer d.lock.Unlock() d.lru.pushFront(digest, common.Size(size)) d.respectPolicies() return nil }
func (m *memory) Evict(digest isolated.HexDigest) { if !digest.Validate() { return } m.lock.Lock() defer m.lock.Unlock() delete(m.data, digest) m.lru.pop(digest) }
func (d *disk) Evict(digest isolated.HexDigest) { if !digest.Validate() { return } d.lock.Lock() defer d.lock.Unlock() d.lru.pop(digest) _ = os.Remove(d.itemPath(digest)) }
func (d *disk) Read(digest isolated.HexDigest) (io.ReadCloser, error) { if !digest.Validate() { return nil, os.ErrInvalid } f, err := os.Open(d.itemPath(digest)) if err != nil { return nil, err } return f, nil }
func (m *memory) Hardlink(digest isolated.HexDigest, dest string, perm os.FileMode) error { if !digest.Validate() { return os.ErrInvalid } m.lock.Lock() content, ok := m.data[digest] m.lock.Unlock() if !ok { return os.ErrNotExist } return ioutil.WriteFile(dest, content, perm) }
func (m *memory) Read(digest isolated.HexDigest) (io.ReadCloser, error) { if !digest.Validate() { return nil, os.ErrInvalid } m.lock.Lock() defer m.lock.Unlock() content, ok := m.data[digest] if !ok { return nil, os.ErrNotExist } return ioutil.NopCloser(bytes.NewBuffer(content)), nil }
func (m *memory) Touch(digest isolated.HexDigest) bool { if !digest.Validate() { return false } m.lock.Lock() defer m.lock.Unlock() if _, ok := m.data[digest]; !ok { return false } m.lru.touch(digest) return true }
func (d *disk) Touch(digest isolated.HexDigest) bool { if !digest.Validate() { return false } d.lock.Lock() defer d.lock.Unlock() mtime := time.Now() if err := os.Chtimes(d.itemPath(digest), mtime, mtime); err != nil { return false } d.lru.touch(digest) return true }
func (d *disk) Hardlink(digest isolated.HexDigest, dest string, perm os.FileMode) error { if !digest.Validate() { return os.ErrInvalid } src := d.itemPath(digest) // - Windows, if dest exists, the call fails. In particular, trying to // os.Remove() will fail if the file's ReadOnly bit is set. What's worse is // that the ReadOnly bit is set on the file inode, shared on all hardlinks // to this inode. This means that in the case of a file with the ReadOnly // bit set, it would have to do: // - If dest exists: // - If dest has ReadOnly bit: // - If file has any other inode: // - Remove the ReadOnly bit. // - Remove dest. // - Set the ReadOnly bit on one of the inode found. // - Call os.Link() // In short, nobody ain't got time for that. // // - On any other (sane) OS, if dest exists, it is silently overwritten. return os.Link(src, dest) }
func (m *memory) Add(digest isolated.HexDigest, src io.Reader) error { if !digest.Validate() { return os.ErrInvalid } // TODO(maruel): Use a LimitedReader flavor that fails when reaching limit. content, err := ioutil.ReadAll(src) if err != nil { return err } if isolated.HashBytes(content) != digest { return errors.New("invalid hash") } if common.Size(len(content)) > m.policies.MaxSize { return errors.New("item too large") } m.lock.Lock() defer m.lock.Unlock() m.data[digest] = content m.lru.pushFront(digest, common.Size(len(content))) m.respectPolicies() return nil }