swift, b2, gcs, s3: Fix moveto and copyto

We now make sure the container/bucket is created before creating any objects.
This commit is contained in:
Nick Craig-Wood 2017-06-07 14:16:50 +01:00
parent b49821956a
commit 9c1e703777
4 changed files with 79 additions and 17 deletions

View File

@ -86,6 +86,8 @@ type Fs struct {
endpoint string // name of the starting api endpoint endpoint string // name of the starting api endpoint
srv *rest.Client // the connection to the b2 server srv *rest.Client // the connection to the b2 server
bucket string // the bucket we are working on bucket string // the bucket we are working on
bucketOKMu sync.Mutex // mutex to protect bucket OK
bucketOK bool // true if we have created the bucket
bucketIDMutex sync.Mutex // mutex to protect _bucketID bucketIDMutex sync.Mutex // mutex to protect _bucketID
_bucketID string // the ID of the bucket we are working on _bucketID string // the ID of the bucket we are working on
info api.AuthorizeAccountResponse // result of authorize call info api.AuthorizeAccountResponse // result of authorize call
@ -671,8 +673,9 @@ func (f *Fs) Put(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.
// Mkdir creates the bucket if it doesn't exist // Mkdir creates the bucket if it doesn't exist
func (f *Fs) Mkdir(dir string) error { func (f *Fs) Mkdir(dir string) error {
// Can't create subdirs f.bucketOKMu.Lock()
if dir != "" { defer f.bucketOKMu.Unlock()
if f.bucketOK {
return nil return nil
} }
opts := rest.Opts{ opts := rest.Opts{
@ -697,6 +700,7 @@ func (f *Fs) Mkdir(dir string) error {
_, getBucketErr := f.getBucketID() _, getBucketErr := f.getBucketID()
if getBucketErr == nil { if getBucketErr == nil {
// found so it is our bucket // found so it is our bucket
f.bucketOK = true
return nil return nil
} }
if getBucketErr != fs.ErrorDirNotFound { if getBucketErr != fs.ErrorDirNotFound {
@ -707,6 +711,7 @@ func (f *Fs) Mkdir(dir string) error {
return errors.Wrap(err, "failed to create bucket") return errors.Wrap(err, "failed to create bucket")
} }
f.setBucketID(response.ID) f.setBucketID(response.ID)
f.bucketOK = true
return nil return nil
} }
@ -714,6 +719,8 @@ func (f *Fs) Mkdir(dir string) error {
// //
// Returns an error if it isn't empty // Returns an error if it isn't empty
func (f *Fs) Rmdir(dir string) error { func (f *Fs) Rmdir(dir string) error {
f.bucketOKMu.Lock()
defer f.bucketOKMu.Unlock()
if f.root != "" || dir != "" { if f.root != "" || dir != "" {
return nil return nil
} }
@ -737,6 +744,7 @@ func (f *Fs) Rmdir(dir string) error {
if err != nil { if err != nil {
return errors.Wrap(err, "failed to delete bucket") return errors.Wrap(err, "failed to delete bucket")
} }
f.bucketOK = false
f.clearBucketID() f.clearBucketID()
f.clearUploadURL() f.clearUploadURL()
return nil return nil
@ -1165,6 +1173,10 @@ func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOptio
if *b2Versions { if *b2Versions {
return errNotWithVersions return errNotWithVersions
} }
err = o.fs.Mkdir("")
if err != nil {
return err
}
size := src.Size() size := src.Size()
// If a large file upload in chunks - see upload.go // If a large file upload in chunks - see upload.go

View File

@ -24,6 +24,7 @@ import (
"path" "path"
"regexp" "regexp"
"strings" "strings"
"sync"
"time" "time"
"github.com/ncw/rclone/fs" "github.com/ncw/rclone/fs"
@ -135,6 +136,8 @@ type Fs struct {
svc *storage.Service // the connection to the storage server svc *storage.Service // the connection to the storage server
client *http.Client // authorized client client *http.Client // authorized client
bucket string // the bucket we are working on bucket string // the bucket we are working on
bucketOKMu sync.Mutex // mutex to protect bucket OK
bucketOK bool // true if we have created the bucket
projectNumber string // used for finding buckets projectNumber string // used for finding buckets
objectACL string // used when creating new objects objectACL string // used when creating new objects
bucketACL string // used when creating new buckets bucketACL string // used when creating new buckets
@ -456,13 +459,15 @@ func (f *Fs) Put(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.
// Mkdir creates the bucket if it doesn't exist // Mkdir creates the bucket if it doesn't exist
func (f *Fs) Mkdir(dir string) error { func (f *Fs) Mkdir(dir string) error {
// Can't create subdirs f.bucketOKMu.Lock()
if dir != "" { defer f.bucketOKMu.Unlock()
if f.bucketOK {
return nil return nil
} }
_, err := f.svc.Buckets.Get(f.bucket).Do() _, err := f.svc.Buckets.Get(f.bucket).Do()
if err == nil { if err == nil {
// Bucket already exists // Bucket already exists
f.bucketOK = true
return nil return nil
} }
@ -474,6 +479,9 @@ func (f *Fs) Mkdir(dir string) error {
Name: f.bucket, Name: f.bucket,
} }
_, err = f.svc.Buckets.Insert(f.projectNumber, &bucket).PredefinedAcl(f.bucketACL).Do() _, err = f.svc.Buckets.Insert(f.projectNumber, &bucket).PredefinedAcl(f.bucketACL).Do()
if err == nil {
f.bucketOK = true
}
return err return err
} }
@ -482,10 +490,16 @@ func (f *Fs) Mkdir(dir string) error {
// Returns an error if it isn't empty: Error 409: The bucket you tried // Returns an error if it isn't empty: Error 409: The bucket you tried
// to delete was not empty. // to delete was not empty.
func (f *Fs) Rmdir(dir string) error { func (f *Fs) Rmdir(dir string) error {
f.bucketOKMu.Lock()
defer f.bucketOKMu.Unlock()
if f.root != "" || dir != "" { if f.root != "" || dir != "" {
return nil return nil
} }
return f.svc.Buckets.Delete(f.bucket).Do() err := f.svc.Buckets.Delete(f.bucket).Do()
if err == nil {
f.bucketOK = false
}
return err
} }
// Precision returns the precision // Precision returns the precision
@ -684,6 +698,10 @@ func (o *Object) Open(options ...fs.OpenOption) (in io.ReadCloser, err error) {
// //
// The new object may have been created if an error is returned // The new object may have been created if an error is returned
func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error { func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
err := o.fs.Mkdir("")
if err != nil {
return err
}
size := src.Size() size := src.Size()
modTime := src.ModTime() modTime := src.ModTime()

View File

@ -21,6 +21,7 @@ import (
"path" "path"
"regexp" "regexp"
"strings" "strings"
"sync"
"time" "time"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
@ -239,6 +240,8 @@ type Fs struct {
c *s3.S3 // the connection to the s3 server c *s3.S3 // the connection to the s3 server
ses *session.Session // the s3 session ses *session.Session // the s3 session
bucket string // the bucket we are working on bucket string // the bucket we are working on
bucketOKMu sync.Mutex // mutex to protect bucket OK
bucketOK bool // true if we have created the bucket
acl string // ACL for new buckets / objects acl string // ACL for new buckets / objects
locationConstraint string // location constraint of new buckets locationConstraint string // location constraint of new buckets
sse string // the type of server-side encryption sse string // the type of server-side encryption
@ -652,11 +655,15 @@ func (f *Fs) dirExists() (bool, error) {
// Mkdir creates the bucket if it doesn't exist // Mkdir creates the bucket if it doesn't exist
func (f *Fs) Mkdir(dir string) error { func (f *Fs) Mkdir(dir string) error {
// Can't create subdirs f.bucketOKMu.Lock()
if dir != "" { defer f.bucketOKMu.Unlock()
if f.bucketOK {
return nil return nil
} }
exists, err := f.dirExists() exists, err := f.dirExists()
if err == nil {
f.bucketOK = exists
}
if err != nil || exists { if err != nil || exists {
return err return err
} }
@ -672,9 +679,12 @@ func (f *Fs) Mkdir(dir string) error {
_, err = f.c.CreateBucket(&req) _, err = f.c.CreateBucket(&req)
if err, ok := err.(awserr.Error); ok { if err, ok := err.(awserr.Error); ok {
if err.Code() == "BucketAlreadyOwnedByYou" { if err.Code() == "BucketAlreadyOwnedByYou" {
return nil err = nil
} }
} }
if err == nil {
f.bucketOK = true
}
return err return err
} }
@ -682,6 +692,8 @@ func (f *Fs) Mkdir(dir string) error {
// //
// Returns an error if it isn't empty // Returns an error if it isn't empty
func (f *Fs) Rmdir(dir string) error { func (f *Fs) Rmdir(dir string) error {
f.bucketOKMu.Lock()
defer f.bucketOKMu.Unlock()
if f.root != "" || dir != "" { if f.root != "" || dir != "" {
return nil return nil
} }
@ -689,6 +701,9 @@ func (f *Fs) Rmdir(dir string) error {
Bucket: &f.bucket, Bucket: &f.bucket,
} }
_, err := f.c.DeleteBucket(&req) _, err := f.c.DeleteBucket(&req)
if err == nil {
f.bucketOK = false
}
return err return err
} }
@ -903,6 +918,10 @@ func (o *Object) Open(options ...fs.OpenOption) (in io.ReadCloser, err error) {
// Update the Object from in with modTime and size // Update the Object from in with modTime and size
func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error { func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
err := o.fs.Mkdir("")
if err != nil {
return err
}
modTime := src.ModTime() modTime := src.ModTime()
uploader := s3manager.NewUploader(o.fs.ses, func(u *s3manager.Uploader) { uploader := s3manager.NewUploader(o.fs.ses, func(u *s3manager.Uploader) {
@ -943,7 +962,7 @@ func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOptio
if o.fs.storageClass != "" { if o.fs.storageClass != "" {
req.StorageClass = &o.fs.storageClass req.StorageClass = &o.fs.storageClass
} }
_, err := uploader.Upload(&req) _, err = uploader.Upload(&req)
if err != nil { if err != nil {
return err return err
} }

View File

@ -9,6 +9,7 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"github.com/ncw/rclone/fs" "github.com/ncw/rclone/fs"
@ -92,6 +93,8 @@ type Fs struct {
features *fs.Features // optional features features *fs.Features // optional features
c *swift.Connection // the connection to the swift server c *swift.Connection // the connection to the swift server
container string // the container we are working on container string // the container we are working on
containerOKMu sync.Mutex // mutex to protect container OK
containerOK bool // true if we have created the container
segmentsContainer string // container to store the segments (if any) in segmentsContainer string // container to store the segments (if any) in
} }
@ -410,30 +413,36 @@ func (f *Fs) Put(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.
// Mkdir creates the container if it doesn't exist // Mkdir creates the container if it doesn't exist
func (f *Fs) Mkdir(dir string) error { func (f *Fs) Mkdir(dir string) error {
// Can't create subdirs f.containerOKMu.Lock()
if dir != "" { defer f.containerOKMu.Unlock()
if f.containerOK {
return nil return nil
} }
// Check to see if container exists first // Check to see if container exists first
_, _, err := f.c.Container(f.container) _, _, err := f.c.Container(f.container)
if err == nil {
return nil
}
if err == swift.ContainerNotFound { if err == swift.ContainerNotFound {
return f.c.ContainerCreate(f.container, nil) err = f.c.ContainerCreate(f.container, nil)
}
if err == nil {
f.containerOK = true
} }
return err return err
} }
// Rmdir deletes the container if the fs is at the root // Rmdir deletes the container if the fs is at the root
// //
// Returns an error if it isn't empty // Returns an error if it isn't empty
func (f *Fs) Rmdir(dir string) error { func (f *Fs) Rmdir(dir string) error {
f.containerOKMu.Lock()
defer f.containerOKMu.Unlock()
if f.root != "" || dir != "" { if f.root != "" || dir != "" {
return nil return nil
} }
return f.c.ContainerDelete(f.container) err := f.c.ContainerDelete(f.container)
if err == nil {
f.containerOK = false
}
return err
} }
// Precision of the remote // Precision of the remote
@ -738,6 +747,10 @@ func (o *Object) updateChunks(in io.Reader, headers swift.Headers, size int64, c
// //
// The new object may have been created if an error is returned // The new object may have been created if an error is returned
func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error { func (o *Object) Update(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
err := o.fs.Mkdir("")
if err != nil {
return err
}
size := src.Size() size := src.Size()
modTime := src.ModTime() modTime := src.ModTime()