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 (i *archiverItem) calcDigest() error { defer i.wgHashed.Done() var d isolated.DigestItem if i.path != "" { // Open and hash the file. var err error if d, err = isolated.HashFile(i.path); err != nil { i.setErr(err) return fmt.Errorf("hash(%s) failed: %s\n", i.DisplayName(), err) } } else { // Use src instead. h := isolated.GetHash() size, err := io.Copy(h, i.src) if err != nil { i.setErr(err) return fmt.Errorf("read(%s) failed: %s\n", i.DisplayName(), err) } if pos, err := i.src.Seek(0, os.SEEK_SET); err != nil || pos != 0 { err = fmt.Errorf("seek(%s) failed: %s\n", i.DisplayName(), err) i.setErr(err) return err } d = isolated.DigestItem{isolated.Sum(h), true, size} } i.lock.Lock() defer i.lock.Unlock() i.digestItem = d for _, child := range i.linked { child.lock.Lock() child.digestItem = d child.lock.Unlock() child.wgHashed.Done() } return nil }