@@ -541,24 +541,27 @@ type Options struct {
541541
542542// Fs represents a remote azure server
543543type Fs struct {
544- name string // name of this remote
545- root string // the path we are working on if any
546- opt Options // parsed config options
547- ci * fs.ConfigInfo // global config
548- features * fs.Features // optional features
549- cntSVCcacheMu sync.Mutex // mutex to protect cntSVCcache
550- cntSVCcache map [string ]* container.Client // reference to containerClient per container
551- svc * service.Client // client to access azblob
552- cred azcore.TokenCredential // how to generate tokens (may be nil)
553- sharedKeyCred * service.SharedKeyCredential // shared key credentials (may be nil)
554- anonymous bool // if this is anonymous access
555- rootContainer string // container part of root (if any)
556- rootDirectory string // directory part of root (if any)
557- isLimited bool // if limited to one container
558- cache * bucket.Cache // cache for container creation status
559- pacer * fs.Pacer // To pace and retry the API calls
560- uploadToken * pacer.TokenDispenser // control concurrency
561- publicAccess container.PublicAccessType // Container Public Access Level
544+ name string // name of this remote
545+ root string // the path we are working on if any
546+ opt Options // parsed config options
547+ ci * fs.ConfigInfo // global config
548+ features * fs.Features // optional features
549+ cntSVCcacheMu sync.Mutex // mutex to protect cntSVCcache
550+ cntSVCcache map [string ]* container.Client // reference to containerClient per container
551+ svc * service.Client // client to access azblob
552+ containerName string // container Name
553+ blobClient * blob.Client // reference to blob Client
554+ blobBlockClient * blockblob.Client // reference to block blob client
555+ cred azcore.TokenCredential // how to generate tokens (may be nil)
556+ sharedKeyCred * service.SharedKeyCredential // shared key credentials (may be nil)
557+ anonymous bool // if this is anonymous access
558+ rootContainer string // container part of root (if any)
559+ rootDirectory string // directory part of root (if any)
560+ isLimited bool // if limited to one container
561+ cache * bucket.Cache // cache for container creation status
562+ pacer * fs.Pacer // To pace and retry the API calls
563+ uploadToken * pacer.TokenDispenser // control concurrency
564+ publicAccess container.PublicAccessType // Container Public Access Level
562565}
563566
564567// Object describes an azure object
@@ -865,8 +868,18 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
865868 }
866869 endpoint := opt .SASURL
867870 containerName := parts .ContainerName
868- // Check if we have container level SAS or account level SAS
869- if containerName != "" {
871+ if parts .BlobName != "" {
872+ // Blob level SAS
873+ f .containerName = parts .ContainerName
874+ f .blobClient , err = blob .NewClientWithNoCredential (endpoint , nil )
875+ if err != nil {
876+ return nil , fmt .Errorf ("unable to create SAS URL for blob client: %w" , err )
877+ }
878+ f .blobBlockClient , err = blockblob .NewClientWithNoCredential (endpoint , nil )
879+ if err != nil {
880+ return nil , fmt .Errorf ("unable to create SAS URL for blob block client: %w" , err )
881+ }
882+ } else if containerName != "" { // Check if we have container level SAS or account level SAS
870883 // Container level SAS
871884 if f .rootContainer != "" && containerName != f .rootContainer {
872885 return nil , fmt .Errorf ("container name in SAS URL (%q) and container provided in command (%q) do not match" , containerName , f .rootContainer )
@@ -1106,6 +1119,9 @@ func (f *Fs) newObjectWithInfo(ctx context.Context, remote string, info *contain
11061119 fs : f ,
11071120 remote : remote ,
11081121 }
1122+ if f .containerName != "" {
1123+ o .remote = f .containerName
1124+ }
11091125 if info != nil {
11101126 err := o .decodeMetaDataFromBlob (info )
11111127 if err != nil {
@@ -1128,12 +1144,20 @@ func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) {
11281144
11291145// getBlobSVC creates a blob client
11301146func (f * Fs ) getBlobSVC (container , containerPath string ) * blob.Client {
1131- return f .cntSVC (container ).NewBlobClient (containerPath )
1147+ if f .containerName == "" {
1148+ return f .cntSVC (container ).NewBlobClient (containerPath )
1149+ } else {
1150+ return f .blobClient
1151+ }
11321152}
11331153
11341154// getBlockBlobSVC creates a block blob client
11351155func (f * Fs ) getBlockBlobSVC (container , containerPath string ) * blockblob.Client {
1136- return f .cntSVC (container ).NewBlockBlobClient (containerPath )
1156+ if f .containerName == "" {
1157+ return f .cntSVC (container ).NewBlockBlobClient (containerPath )
1158+ } else {
1159+ return f .blobBlockClient
1160+ }
11371161}
11381162
11391163// updateMetadataWithModTime adds the modTime passed in to o.meta.
@@ -1503,6 +1527,9 @@ func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options .
15031527 fs : f ,
15041528 remote : src .Remote (),
15051529 }
1530+ if f .containerName != "" {
1531+ fs .remote = f .containerName
1532+ }
15061533 return fs , fs .Update (ctx , in , src , options ... )
15071534}
15081535
@@ -1949,9 +1976,11 @@ func (f *Fs) copySinglepart(ctx context.Context, remote, dstContainer, dstPath s
19491976// If it isn't possible then return fs.ErrorCantCopy
19501977func (f * Fs ) Copy (ctx context.Context , src fs.Object , remote string ) (fs.Object , error ) {
19511978 dstContainer , dstPath := f .split (remote )
1952- err := f .mkdirParent (ctx , remote )
1953- if err != nil {
1954- return nil , err
1979+ if f .containerName == "" {
1980+ err := f .mkdirParent (ctx , remote )
1981+ if err != nil {
1982+ return nil , err
1983+ }
19551984 }
19561985 srcObj , ok := src .(* Object )
19571986 if ! ok {
@@ -2881,8 +2910,10 @@ type uploadInfo struct {
28812910// Prepare the object for upload
28822911func (o * Object ) prepareUpload (ctx context.Context , src fs.ObjectInfo , options []fs.OpenOption ) (ui uploadInfo , err error ) {
28832912 container , containerPath := o .split ()
2884- if container == "" || containerPath == "" {
2885- return ui , fmt .Errorf ("can't upload to root - need a container" )
2913+ if o .fs .containerName == "" {
2914+ if container == "" || containerPath == "" {
2915+ return ui , fmt .Errorf ("can't upload to root - need a container" )
2916+ }
28862917 }
28872918 // Create parent dir/bucket if not saving directory marker
28882919 metadataMu .Lock ()
0 commit comments