// Load returns the data stored in the backend for h at the given offset // and saves it in p. Load has the same semantics as io.ReaderAt. func (b *restBackend) Load(h backend.Handle, p []byte, off int64) (n int, err error) { if err := h.Valid(); err != nil { return 0, err } req, err := http.NewRequest("GET", restPath(b.url, h), nil) if err != nil { return 0, err } req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", off, off+int64(len(p)))) client := *b.client <-b.connChan resp, err := client.Do(req) b.connChan <- struct{}{} if resp != nil { defer func() { e := resp.Body.Close() if err == nil { err = e } }() } if err != nil { return 0, err } if resp.StatusCode != 200 && resp.StatusCode != 206 { return 0, fmt.Errorf("unexpected HTTP response code %v", resp.StatusCode) } return io.ReadFull(resp.Body, p) }
// Remove removes the blob with the given name and type. func (b *restBackend) Remove(t backend.Type, name string) error { h := backend.Handle{Type: t, Name: name} if err := h.Valid(); err != nil { return err } req, err := http.NewRequest("DELETE", restPath(b.url, h), nil) if err != nil { return err } client := *b.client <-b.connChan resp, err := client.Do(req) b.connChan <- struct{}{} if err != nil { return err } if resp.StatusCode != 200 { return errors.New("blob not removed") } return resp.Body.Close() }
// Save stores data in the backend at the handle. func (b *restBackend) Save(h backend.Handle, p []byte) (err error) { if err := h.Valid(); err != nil { return err } client := *b.client <-b.connChan resp, err := client.Post(restPath(b.url, h), "binary/octet-stream", bytes.NewReader(p)) b.connChan <- struct{}{} if resp != nil { defer func() { e := resp.Body.Close() if err == nil { err = e } }() } if err != nil { return err } if resp.StatusCode != 200 { return fmt.Errorf("unexpected HTTP response code %v", resp.StatusCode) } return nil }
// Stat returns information about a blob. func (b *restBackend) Stat(h backend.Handle) (backend.BlobInfo, error) { if err := h.Valid(); err != nil { return backend.BlobInfo{}, err } client := *b.client <-b.connChan resp, err := client.Head(restPath(b.url, h)) b.connChan <- struct{}{} if err != nil { return backend.BlobInfo{}, err } if err = resp.Body.Close(); err != nil { return backend.BlobInfo{}, err } if resp.StatusCode != 200 { return backend.BlobInfo{}, fmt.Errorf("unexpected HTTP response code %v", resp.StatusCode) } if resp.ContentLength < 0 { return backend.BlobInfo{}, errors.New("negative content length") } bi := backend.BlobInfo{ Size: resp.ContentLength, } return bi, nil }
// Load returns the data stored in the backend for h at the given offset // and saves it in p. Load has the same semantics as io.ReaderAt. func (b *Local) Load(h backend.Handle, p []byte, off int64) (n int, err error) { if err := h.Valid(); err != nil { return 0, err } f, err := os.Open(filename(b.p, h.Type, h.Name)) if err != nil { return 0, err } defer func() { e := f.Close() if err == nil && e != nil { err = e } }() if off > 0 { _, err = f.Seek(off, 0) if err != nil { return 0, err } } return io.ReadFull(f, p) }
// Save stores data in the backend at the handle. func (be s3) Save(h backend.Handle, p []byte) (err error) { if err := h.Valid(); err != nil { return err } debug.Log("s3.Save", "%v bytes at %d", len(p), h) path := be.s3path(h.Type, h.Name) // Check key does not already exist _, err = be.client.StatObject(be.bucketname, path) if err == nil { debug.Log("s3.blob.Finalize()", "%v already exists", h) return errors.New("key already exists") } <-be.connChan defer func() { be.connChan <- struct{}{} }() debug.Log("s3.Save", "PutObject(%v, %v, %v, %v)", be.bucketname, path, int64(len(p)), "binary/octet-stream") n, err := be.client.PutObject(be.bucketname, path, bytes.NewReader(p), "binary/octet-stream") debug.Log("s3.Save", "%v -> %v bytes, err %#v", path, n, err) return err }
func memLoad(be *MemoryBackend, h backend.Handle, p []byte, off int64) (int, error) { if err := h.Valid(); err != nil { return 0, err } be.m.Lock() defer be.m.Unlock() if h.Type == backend.Config { h.Name = "" } debug.Log("MemoryBackend.Load", "get %v offset %v len %v", h, off, len(p)) if _, ok := be.data[entry{h.Type, h.Name}]; !ok { return 0, errors.New("no such data") } buf := be.data[entry{h.Type, h.Name}] if off > int64(len(buf)) { return 0, errors.New("offset beyond end of file") } buf = buf[off:] n := copy(p, buf) if len(p) > len(buf) { return n, io.ErrUnexpectedEOF } return n, nil }
// Save stores data in the backend at the handle. func (r *SFTP) Save(h backend.Handle, p []byte) (err error) { if err := h.Valid(); err != nil { return err } filename, tmpfile, err := r.tempFile() debug.Log("sftp.Save", "save %v (%d bytes) to %v", h, len(p), filename) n, err := tmpfile.Write(p) if err != nil { return err } if n != len(p) { return errors.New("not all bytes writen") } err = tmpfile.Close() if err != nil { return err } err = r.renameFile(filename, h.Type, h.Name) debug.Log("sftp.Save", "save %v: rename %v: %v", h, filepath.Base(filename), err) if err != nil { return fmt.Errorf("sftp: renameFile: %v", err) } return nil }
// Stat returns information about a blob. func (b *Local) Stat(h backend.Handle) (backend.BlobInfo, error) { if err := h.Valid(); err != nil { return backend.BlobInfo{}, err } fi, err := os.Stat(filename(b.p, h.Type, h.Name)) if err != nil { return backend.BlobInfo{}, err } return backend.BlobInfo{Size: fi.Size()}, nil }
// Stat returns information about a blob. func (r *SFTP) Stat(h backend.Handle) (backend.BlobInfo, error) { if err := h.Valid(); err != nil { return backend.BlobInfo{}, err } fi, err := r.c.Lstat(r.filename(h.Type, h.Name)) if err != nil { return backend.BlobInfo{}, err } return backend.BlobInfo{Size: fi.Size()}, nil }
// restPath returns the path to the given resource. func restPath(url *url.URL, h backend.Handle) string { u := *url var dir string switch h.Type { case backend.Config: dir = "" h.Name = "config" case backend.Data: dir = backend.Paths.Data case backend.Snapshot: dir = backend.Paths.Snapshots case backend.Index: dir = backend.Paths.Index case backend.Lock: dir = backend.Paths.Locks case backend.Key: dir = backend.Paths.Keys default: dir = string(h.Type) } u.Path = path.Join(url.Path, dir, h.Name) return u.String() }
func memStat(be *MemoryBackend, h backend.Handle) (backend.BlobInfo, error) { be.m.Lock() defer be.m.Unlock() if err := h.Valid(); err != nil { return backend.BlobInfo{}, err } if h.Type == backend.Config { h.Name = "" } debug.Log("MemoryBackend.Stat", "stat %v", h) e, ok := be.data[entry{h.Type, h.Name}] if !ok { return backend.BlobInfo{}, errors.New("no such data") } return backend.BlobInfo{Size: int64(len(e))}, nil }
// Save stores data in the backend at the handle. func (b *Local) Save(h backend.Handle, p []byte) (err error) { if err := h.Valid(); err != nil { return err } tmpfile, err := writeToTempfile(filepath.Join(b.p, backend.Paths.Temp), p) debug.Log("local.Save", "saved %v (%d bytes) to %v", h, len(p), tmpfile) filename := filename(b.p, h.Type, h.Name) // test if new path already exists if _, err := os.Stat(filename); err == nil { return fmt.Errorf("Rename(): file %v already exists", filename) } // create directories if necessary, ignore errors if h.Type == backend.Data { err = os.MkdirAll(filepath.Dir(filename), backend.Modes.Dir) if err != nil { return err } } err = os.Rename(tmpfile, filename) debug.Log("local.Save", "save %v: rename %v -> %v: %v", h, filepath.Base(tmpfile), filepath.Base(filename), err) if err != nil { return err } // set mode to read-only fi, err := os.Stat(filename) if err != nil { return err } return setNewFileMode(filename, fi) }
func memSave(be *MemoryBackend, h backend.Handle, p []byte) error { if err := h.Valid(); err != nil { return err } be.m.Lock() defer be.m.Unlock() if h.Type == backend.Config { h.Name = "" } if _, ok := be.data[entry{h.Type, h.Name}]; ok { return errors.New("file already exists") } debug.Log("MemoryBackend.Save", "save %v bytes at %v", len(p), h) buf := make([]byte, len(p)) copy(buf, p) be.data[entry{h.Type, h.Name}] = buf return nil }