From 2fc095cd3ed1e992c72a5684b7dc3ecdc4fae8bd Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Sun, 20 Jan 2019 08:37:46 +0000 Subject: [PATCH] azureblob: Stop Mkdir attempting to create existing containers Before this change azureblob would attempt to create already existing containers. This causes problems with limited permissions keys. This change checks the container exists before trying to create it in the same way the s3 backend does. This uses no more requests in the usual case of the container existing. See: https://forum.rclone.org/t/copying-individual-files-to-azure-blob-storage/8397 --- backend/azureblob/azureblob.go | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/backend/azureblob/azureblob.go b/backend/azureblob/azureblob.go index c26f9a6d4..520b03aca 100644 --- a/backend/azureblob/azureblob.go +++ b/backend/azureblob/azureblob.go @@ -754,6 +754,35 @@ func (f *Fs) Put(in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs. return fs, fs.Update(in, src, options...) } +// Check if the container exists +// +// NB this can return incorrect results if called immediately after container deletion +func (f *Fs) dirExists() (bool, error) { + options := azblob.ListBlobsSegmentOptions{ + Details: azblob.BlobListingDetails{ + Copy: false, + Metadata: false, + Snapshots: false, + UncommittedBlobs: false, + Deleted: false, + }, + MaxResults: 1, + } + err := f.pacer.Call(func() (bool, error) { + ctx := context.Background() + _, err := f.cntURL.ListBlobsHierarchySegment(ctx, azblob.Marker{}, "", options) + return f.shouldRetry(err) + }) + if err == nil { + return true, nil + } + // Check http error code along with service code, current SDK doesn't populate service code correctly sometimes + if storageErr, ok := err.(azblob.StorageError); ok && (storageErr.ServiceCode() == azblob.ServiceCodeContainerNotFound || storageErr.Response().StatusCode == http.StatusNotFound) { + return false, nil + } + return false, err +} + // Mkdir creates the container if it doesn't exist func (f *Fs) Mkdir(dir string) error { f.containerOKMu.Lock() @@ -761,6 +790,15 @@ func (f *Fs) Mkdir(dir string) error { if f.containerOK { return nil } + if !f.containerDeleted { + exists, err := f.dirExists() + if err == nil { + f.containerOK = exists + } + if err != nil || exists { + return err + } + } // now try to create the container err := f.pacer.Call(func() (bool, error) {