Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
964e4d2
Adding share client
souravgupta-msft Feb 27, 2023
69446ae
More share client methods
souravgupta-msft Feb 28, 2023
bf3d82f
Adding tests for share client
souravgupta-msft Mar 3, 2023
0f48bdc
More tests
souravgupta-msft Mar 6, 2023
1456741
lint
souravgupta-msft Mar 6, 2023
dc37bbd
More tests
souravgupta-msft Mar 7, 2023
99256a6
Few changes
souravgupta-msft Mar 9, 2023
ecbd69b
directory client ctors
souravgupta-msft Mar 9, 2023
25aa885
Removing check for shared key
souravgupta-msft Mar 10, 2023
b3785f0
Merge branch 'sourav/shareClient' of https://github.com/Azure/azure-s…
souravgupta-msft Mar 10, 2023
4759643
Adding directory client apis
souravgupta-msft Mar 10, 2023
a72172b
Adding list files and directories api
souravgupta-msft Mar 14, 2023
fe3bfd7
Adding generate SAS method in directory client
souravgupta-msft Mar 14, 2023
a37d5d3
List and force close handles api
souravgupta-msft Mar 14, 2023
4e508c9
Adding tests for directory client
souravgupta-msft Mar 15, 2023
207f205
More tests
souravgupta-msft Mar 15, 2023
72fb334
Format check
souravgupta-msft Mar 16, 2023
03de239
Merge branch 'feature/azfile' of https://github.com/Azure/azure-sdk-f…
souravgupta-msft Mar 17, 2023
5dadfaf
FileSignatureValues to SignatureValues
souravgupta-msft Mar 17, 2023
c4f769a
Merge branch 'sourav/shareClient' of https://github.com/Azure/azure-s…
souravgupta-msft Mar 17, 2023
560e382
updating GetSASURL()
souravgupta-msft Mar 17, 2023
6df4890
Merge from feature branch
souravgupta-msft Mar 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 142 additions & 11 deletions sdk/storage/azfile/directory/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,19 @@ package directory
import (
"context"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/file"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/fileerror"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/internal/base"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/internal/exported"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/internal/generated"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/internal/shared"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/sas"
"net/http"
"net/url"
"strings"
"time"
)

// ClientOptions contains the optional parameters when creating a Client.
Expand All @@ -28,15 +37,23 @@ type Client base.Client[generated.DirectoryClient]
// - directoryURL - the URL of the directory e.g. https://<account>.file.core.windows.net/share/directory?<sas token>
// - options - client options; pass nil to accept the default values
func NewClientWithNoCredential(directoryURL string, options *ClientOptions) (*Client, error) {
return nil, nil
conOptions := shared.GetClientOptions(options)
pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)

return (*Client)(base.NewDirectoryClient(directoryURL, pl, nil)), nil
}

// NewClientWithSharedKeyCredential creates an instance of Client with the specified values.
// - directoryURL - the URL of the directory e.g. https://<account>.file.core.windows.net/share/directory
// - cred - a SharedKeyCredential created with the matching directory's storage account and access key
// - options - client options; pass nil to accept the default values
func NewClientWithSharedKeyCredential(directoryURL string, cred *SharedKeyCredential, options *ClientOptions) (*Client, error) {
return nil, nil
authPolicy := exported.NewSharedKeyCredPolicy(cred)
conOptions := shared.GetClientOptions(options)
conOptions.PerRetryPolicies = append(conOptions.PerRetryPolicies, authPolicy)
pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)

return (*Client)(base.NewDirectoryClient(directoryURL, pl, cred)), nil
}

// NewClientFromConnectionString creates an instance of Client with the specified values.
Expand All @@ -45,7 +62,23 @@ func NewClientWithSharedKeyCredential(directoryURL string, cred *SharedKeyCreden
// - directoryPath - the path of the directory within the share
// - options - client options; pass nil to accept the default values
func NewClientFromConnectionString(connectionString string, shareName string, directoryPath string, options *ClientOptions) (*Client, error) {
return nil, nil
parsed, err := shared.ParseConnectionString(connectionString)
if err != nil {
return nil, err
}

directoryPath = strings.ReplaceAll(directoryPath, "\\", "/")
parsed.ServiceURL = runtime.JoinPaths(parsed.ServiceURL, shareName, directoryPath)

if parsed.AccountKey != "" && parsed.AccountName != "" {
credential, err := exported.NewSharedKeyCredential(parsed.AccountName, parsed.AccountKey)
if err != nil {
return nil, err
}
return NewClientWithSharedKeyCredential(parsed.ServiceURL, credential, options)
}

return NewClientWithNoCredential(parsed.ServiceURL, options)
}

func (d *Client) generated() *generated.DirectoryClient {
Expand All @@ -64,48 +97,146 @@ func (d *Client) URL() string {
// NewSubdirectoryClient creates a new Client object by concatenating subDirectoryName to the end of this Client's URL.
// The new subdirectory Client uses the same request policy pipeline as the parent directory Client.
func (d *Client) NewSubdirectoryClient(subDirectoryName string) *Client {
return nil
subDirectoryName = url.PathEscape(subDirectoryName)
subDirectoryURL := runtime.JoinPaths(d.URL(), subDirectoryName)
return (*Client)(base.NewDirectoryClient(subDirectoryURL, d.generated().Pipeline(), d.sharedKey()))
}

// NewFileClient creates a new file.Client object by concatenating fileName to the end of this Client's URL.
// The new file.Client uses the same request policy pipeline as the Client.
func (d *Client) NewFileClient(fileName string) *file.Client {
return nil
fileName = url.PathEscape(fileName)
fileURL := runtime.JoinPaths(d.URL(), fileName)
return (*file.Client)(base.NewFileClient(fileURL, d.generated().Pipeline(), d.sharedKey()))
}

// Create operation creates a new directory under the specified share or parent directory.
// For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/create-directory.
func (d *Client) Create(ctx context.Context, options *CreateOptions) (CreateResponse, error) {
return CreateResponse{}, nil
fileAttributes, fileCreationTime, fileLastWriteTime, opts := options.format()
resp, err := d.generated().Create(ctx, fileAttributes, fileCreationTime, fileLastWriteTime, opts)
return resp, err
}

// Delete operation removes the specified empty directory. Note that the directory must be empty before it can be deleted.
// Deleting directories that aren't empty returns error 409 (Directory Not Empty).
// For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/delete-directory.
func (d *Client) Delete(ctx context.Context, options *DeleteOptions) (DeleteResponse, error) {
return DeleteResponse{}, nil
opts := options.format()
resp, err := d.generated().Delete(ctx, opts)
return resp, err
}

// GetProperties operation returns all system properties for the specified directory, and it can also be used to check the existence of a directory.
// For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/get-directory-properties.
func (d *Client) GetProperties(ctx context.Context, options *GetPropertiesOptions) (GetPropertiesResponse, error) {
return GetPropertiesResponse{}, nil
opts := options.format()
resp, err := d.generated().GetProperties(ctx, opts)
return resp, err
}

// SetProperties operation sets system properties for the specified directory.
// For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/set-directory-properties.
func (d *Client) SetProperties(ctx context.Context, options *SetPropertiesOptions) (SetPropertiesResponse, error) {
return SetPropertiesResponse{}, nil
fileAttributes, fileCreationTime, fileLastWriteTime, opts := options.format()
resp, err := d.generated().SetProperties(ctx, fileAttributes, fileCreationTime, fileLastWriteTime, opts)
return resp, err
}

// SetMetadata operation sets user-defined metadata for the specified directory.
// For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/set-directory-metadata.
func (d *Client) SetMetadata(ctx context.Context, options *SetMetadataOptions) (SetMetadataResponse, error) {
return SetMetadataResponse{}, nil
opts := options.format()
resp, err := d.generated().SetMetadata(ctx, opts)
return resp, err
}

// ForceCloseHandles operation closes a handle or handles opened on a directory.
// - handleID - Specifies the handle ID to be closed. Use an asterisk (*) as a wildcard string to specify all handles.
//
// For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/force-close-handles.
func (d *Client) ForceCloseHandles(ctx context.Context, handleID string, options *ForceCloseHandlesOptions) (ForceCloseHandlesResponse, error) {
opts := options.format()
resp, err := d.generated().ForceCloseHandles(ctx, handleID, opts)
return resp, err
}

// ListHandles operation returns a list of open handles on a directory.
// For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/list-handles.
func (d *Client) ListHandles(ctx context.Context, options *ListHandlesOptions) (ListHandlesResponse, error) {
opts := options.format()
resp, err := d.generated().ListHandles(ctx, opts)
return resp, err
}

// NewListFilesAndDirectoriesPager operation returns a pager for the files and directories starting from the specified Marker.
// For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/list-directories-and-files.
func (d *Client) NewListFilesAndDirectoriesPager(options *ListFilesAndDirectoriesOptions) *runtime.Pager[ListFilesAndDirectoriesResponse] {
return nil
listOptions := generated.DirectoryClientListFilesAndDirectoriesSegmentOptions{}
if options != nil {
listOptions.Include = options.Include.format()
listOptions.IncludeExtendedInfo = options.IncludeExtendedInfo
listOptions.Marker = options.Marker
listOptions.Maxresults = options.MaxResults
listOptions.Prefix = options.Prefix
listOptions.Sharesnapshot = options.ShareSnapshot
}

return runtime.NewPager(runtime.PagingHandler[ListFilesAndDirectoriesResponse]{
More: func(page ListFilesAndDirectoriesResponse) bool {
return page.NextMarker != nil && len(*page.NextMarker) > 0
},
Fetcher: func(ctx context.Context, page *ListFilesAndDirectoriesResponse) (ListFilesAndDirectoriesResponse, error) {
var req *policy.Request
var err error
if page == nil {
req, err = d.generated().ListFilesAndDirectoriesSegmentCreateRequest(ctx, &listOptions)
} else {
listOptions.Marker = page.NextMarker
req, err = d.generated().ListFilesAndDirectoriesSegmentCreateRequest(ctx, &listOptions)
}
if err != nil {
return ListFilesAndDirectoriesResponse{}, err
}
resp, err := d.generated().Pipeline().Do(req)
if err != nil {
return ListFilesAndDirectoriesResponse{}, err
}
if !runtime.HasStatusCode(resp, http.StatusOK) {
return ListFilesAndDirectoriesResponse{}, runtime.NewResponseError(resp)
}
return d.generated().ListFilesAndDirectoriesSegmentHandleResponse(resp)
},
})
}

// GetSASURL is a convenience method for generating a SAS token for the currently pointed at directory.
// It can only be used if the credential supplied during creation was a SharedKeyCredential.
func (d *Client) GetSASURL(permissions sas.FilePermissions, expiry time.Time, o *GetSASURLOptions) (string, error) {
if d.sharedKey() == nil {
return "", fileerror.MissingSharedKeyCredential
}
st := o.format()

urlParts, err := sas.ParseURL(d.URL())
if err != nil {
return "", err
}

qps, err := sas.SignatureValues{
Version: sas.Version,
Protocol: sas.ProtocolHTTPS,
ShareName: urlParts.ShareName,
DirectoryOrFilePath: urlParts.DirectoryOrFilePath,
Permissions: permissions.String(),
StartTime: st,
ExpiryTime: expiry.UTC(),
}.SignWithSharedKey(d.sharedKey())
if err != nil {
return "", err
}

endpoint := d.URL() + "?" + qps.Encode()

return endpoint, nil
}
Loading