// Upload uploads a file to a B2 bucket. If mimeType is "", "b2/x-auto" will be used. // // Concurrent calls to Upload will use separate upload URLs, but consequent ones // will attempt to reuse previously obtained ones to save b2_get_upload_url calls. // Upload URL failures are handled transparently. // // Since the B2 API requires a SHA1 header, normally the file will first be read // entirely into a memory buffer. Two cases avoid the memory copy: if r is a // bytes.Buffer, the SHA1 will be computed in place; otherwise, if r implements io.Seeker // (like *os.File and *bytes.Reader), the file will be read twice, once to compute // the SHA1 and once to upload. // // If a file by this name already exist, a new version will be created. func (b *Bucket) Upload(r io.Reader, name, mimeType string) (*FileInfo, error) { var body io.ReadSeeker switch r := r.(type) { case *bytes.Buffer: defer r.Reset() // we are expected to consume it body = bytes.NewReader(r.Bytes()) case io.ReadSeeker: body = r default: b, err := ioutil.ReadAll(r) if err != nil { return nil, err } body = bytes.NewReader(b) } h := sha1.New() length, err := io.Copy(h, body) if err != nil { return nil, err } sha1Sum := hex.EncodeToString(h.Sum(nil)) var fi *FileInfo for i := 0; i < 5; i++ { if _, err = body.Seek(0, io.SeekStart); err != nil { return nil, err } fi, err = b.UploadWithSHA1(body, name, mimeType, sha1Sum, length) if err == nil { break } } return fi, err }