diff --git a/sdk/storage/azfile/CHANGELOG.md b/sdk/storage/azfile/CHANGELOG.md index 79470a10c599..5f903f4285bd 100644 --- a/sdk/storage/azfile/CHANGELOG.md +++ b/sdk/storage/azfile/CHANGELOG.md @@ -1,16 +1,29 @@ # Release History -## 1.0.1 (Unreleased) +## 1.1.0-beta.1 (Unreleased) ### Features Added -### Breaking Changes +* Updated service version to `2022-11-02`. +* Added OAuth support. +* Added [Rename Directory API](https://learn.microsoft.com/rest/api/storageservices/rename-directory). +* Added [Rename File API](https://learn.microsoft.com/rest/api/storageservices/rename-file). +* Added `x-ms-file-change-time` request header in + * Create File/Directory + * Set File/Directory Properties + * Copy File +* Added `x-ms-file-last-write-time` request header in Put Range and Put Range from URL. +* Updated the SAS Version to `2022-11-02` and added `Encryption Scope` to Account SAS. +* Trailing dot support for files and directories. ### Bugs Fixed + +* Fixed service SAS creation where expiry time or permissions can be omitted when stored access policy is used. * Fixed issue where some requests fail with mismatch in string to sign. ### Other Changes +* Updated version of azcore to 1.7.1 and azidentity to 1.3.1. * Added `dragonfly` and `aix` to build constraints in `mmf_unix.go`. ## 1.0.0 (2023-07-12) diff --git a/sdk/storage/azfile/README.md b/sdk/storage/azfile/README.md index 2b6ba2b9a02e..9d543493bf30 100644 --- a/sdk/storage/azfile/README.md +++ b/sdk/storage/azfile/README.md @@ -1,6 +1,6 @@ # Azure File Storage SDK for Go -> Service Version: 2020-10-02 +> Service Version: 2022-11-02 Azure File Shares offers fully managed file shares in the cloud that are accessible via the industry standard [Server Message Block (SMB) protocol](https://docs.microsoft.com/windows/desktop/FileIO/microsoft-smb-protocol-and-cifs-protocol-overview). @@ -19,6 +19,12 @@ Install the Azure File Storage SDK for Go with [go get][goget]: go get github.com/Azure/azure-sdk-for-go/sdk/storage/azfile ``` +If you plan to authenticate with Azure Active Directory (recommended), also install the [azidentity][azidentity] module. + +```Powershell +go get github.com/Azure/azure-sdk-for-go/sdk/azidentity +``` + ### Prerequisites A supported [Go][godevdl] version (the Azure SDK supports the two most recent Go releases). @@ -39,18 +45,24 @@ az storage account create --name MyStorageAccount --resource-group MyResourceGro The Azure File Storage SDK for Go allows you to interact with four types of resources: the storage account itself, file shares, directories, and files. Interaction with these resources starts with an instance of a client. To create a client object, you will need the storage account's file service URL and a -credential that allows you to access the storage account: +credential that allows you to access the storage account. The [azidentity][azidentity] module makes it easy to add +Azure Active Directory support for authenticating Azure SDK clients with their corresponding Azure services. ```go -// create a credential for authenticating using shared key -cred, err := service.NewSharedKeyCredential("", "") +// create a credential for authenticating with Azure Active Directory +cred, err := azidentity.NewDefaultAzureCredential(nil) // TODO: handle err // create service.Client for the specified storage account that uses the above credential -client, err := service.NewClientWithSharedKeyCredential("https://.file.core.windows.net/", cred, nil) +client, err := service.NewClient("https://.file.core.windows.net/", cred, &service.ClientOptions{FileRequestIntent: to.Ptr(service.ShareTokenIntentBackup)}) // TODO: handle err ``` +Learn more about enabling Azure Active Directory for authentication with Azure Storage: [Authorize access to blobs using Azure Active Directory][storage_ad] + +Other options for authentication include connection strings, shared key, and shared access signatures (SAS). +Use the appropriate client constructor function for the authentication mechanism you wish to use. + ## Key concepts Azure file shares can be used to: @@ -264,3 +276,5 @@ additional questions or comments. [coc]: https://opensource.microsoft.com/codeofconduct/ [coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ [coc_contact]: mailto:opencode@microsoft.com +[azidentity]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity +[storage_ad]: https://learn.microsoft.com/azure/storage/common/storage-auth-aad diff --git a/sdk/storage/azfile/assets.json b/sdk/storage/azfile/assets.json index 297645fadc04..fd83f762dd7e 100644 --- a/sdk/storage/azfile/assets.json +++ b/sdk/storage/azfile/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "go", "TagPrefix": "go/storage/azfile", - "Tag": "go/storage/azfile_600a15563c" + "Tag": "go/storage/azfile_66b915bf67" } diff --git a/sdk/storage/azfile/directory/client.go b/sdk/storage/azfile/directory/client.go index 3a0182e9b9b4..34af659ddcc5 100644 --- a/sdk/storage/azfile/directory/client.go +++ b/sdk/storage/azfile/directory/client.go @@ -8,6 +8,8 @@ package directory import ( "context" + "errors" + "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" @@ -15,6 +17,7 @@ import ( "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" @@ -26,15 +29,43 @@ type ClientOptions base.ClientOptions // Client represents a URL to the Azure Storage directory allowing you to manipulate its directories and files. type Client base.Client[generated.DirectoryClient] +// NewClient creates an instance of Client with the specified values. +// - directoryURL - the URL of the directory e.g. https://.file.core.windows.net/share/directory +// - cred - an Azure AD credential, typically obtained via the azidentity module +// - options - client options; pass nil to accept the default values +// +// Note that ClientOptions.FileRequestIntent is currently required for token authentication. +func NewClient(directoryURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) { + authPolicy := runtime.NewBearerTokenPolicy(cred, []string{shared.TokenScope}, nil) + conOptions := shared.GetClientOptions(options) + plOpts := runtime.PipelineOptions{ + PerRetry: []policy.Policy{authPolicy}, + } + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) + + azClient, err := azcore.NewClient(shared.DirectoryClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewDirectoryClient(directoryURL, azClient, nil, (*base.ClientOptions)(conOptions))), nil +} + // NewClientWithNoCredential creates an instance of Client with the specified values. // This is used to anonymously access a directory or with a shared access signature (SAS) token. // - directoryURL - the URL of the directory e.g. https://.file.core.windows.net/share/directory? // - options - client options; pass nil to accept the default values func NewClientWithNoCredential(directoryURL string, options *ClientOptions) (*Client, error) { conOptions := shared.GetClientOptions(options) - pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions) + plOpts := runtime.PipelineOptions{} + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) + + azClient, err := azcore.NewClient(shared.DirectoryClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } - return (*Client)(base.NewDirectoryClient(directoryURL, pl, nil)), nil + return (*Client)(base.NewDirectoryClient(directoryURL, azClient, nil, (*base.ClientOptions)(conOptions))), nil } // NewClientWithSharedKeyCredential creates an instance of Client with the specified values. @@ -44,10 +75,17 @@ func NewClientWithNoCredential(directoryURL string, options *ClientOptions) (*Cl func NewClientWithSharedKeyCredential(directoryURL string, cred *SharedKeyCredential, options *ClientOptions) (*Client, error) { 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) + plOpts := runtime.PipelineOptions{ + PerRetry: []policy.Policy{authPolicy}, + } + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) - return (*Client)(base.NewDirectoryClient(directoryURL, pl, cred)), nil + azClient, err := azcore.NewClient(shared.DirectoryClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewDirectoryClient(directoryURL, azClient, cred, (*base.ClientOptions)(conOptions))), nil } // NewClientFromConnectionString creates an instance of Client with the specified values. @@ -83,6 +121,10 @@ func (d *Client) sharedKey() *SharedKeyCredential { return base.SharedKey((*base.Client[generated.DirectoryClient])(d)) } +func (d *Client) getClientOptions() *base.ClientOptions { + return base.GetClientOptions((*base.Client[generated.DirectoryClient])(d)) +} + // URL returns the URL endpoint used by the Client object. func (d *Client) URL() string { return d.generated().Endpoint() @@ -93,7 +135,7 @@ func (d *Client) URL() string { func (d *Client) NewSubdirectoryClient(subDirectoryName string) *Client { subDirectoryName = url.PathEscape(strings.TrimRight(subDirectoryName, "/")) subDirectoryURL := runtime.JoinPaths(d.URL(), subDirectoryName) - return (*Client)(base.NewDirectoryClient(subDirectoryURL, d.generated().Pipeline(), d.sharedKey())) + return (*Client)(base.NewDirectoryClient(subDirectoryURL, d.generated().InternalClient(), d.sharedKey(), d.getClientOptions())) } // NewFileClient creates a new file.Client object by concatenating fileName to the end of this Client's URL. @@ -101,15 +143,15 @@ func (d *Client) NewSubdirectoryClient(subDirectoryName string) *Client { func (d *Client) NewFileClient(fileName string) *file.Client { fileName = url.PathEscape(fileName) fileURL := runtime.JoinPaths(d.URL(), fileName) - return (*file.Client)(base.NewFileClient(fileURL, d.generated().Pipeline(), d.sharedKey())) + return (*file.Client)(base.NewFileClient(fileURL, d.generated().InternalClient().WithClientName(shared.FileClient), d.sharedKey(), d.getClientOptions())) } // Create operation creates a new directory under the specified share or parent directory. // file.ParseNTFSFileAttributes method can be used to convert the file attributes returned in response to NTFSFileAttributes. // 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) { - fileAttributes, fileCreationTime, fileLastWriteTime, opts := options.format() - resp, err := d.generated().Create(ctx, fileAttributes, fileCreationTime, fileLastWriteTime, opts) + opts := options.format() + resp, err := d.generated().Create(ctx, opts) return resp, err } @@ -122,6 +164,45 @@ func (d *Client) Delete(ctx context.Context, options *DeleteOptions) (DeleteResp return resp, err } +// Rename operation renames a directory, and can optionally set system properties for the directory. +// - destinationPath: the destination path to rename the directory to. +// +// For more information, see https://learn.microsoft.com/rest/api/storageservices/rename-directory. +func (d *Client) Rename(ctx context.Context, destinationPath string, options *RenameOptions) (RenameResponse, error) { + destinationPath = strings.Trim(strings.TrimSpace(destinationPath), "/") + if len(destinationPath) == 0 { + return RenameResponse{}, errors.New("destination path must not be empty") + } + + opts, destLease, smbInfo := options.format() + + urlParts, err := sas.ParseURL(d.URL()) + if err != nil { + return RenameResponse{}, err + } + + destParts := strings.Split(destinationPath, "?") + newDestPath := destParts[0] + newDestQuery := "" + if len(destParts) == 2 { + newDestQuery = destParts[1] + } + + urlParts.DirectoryOrFilePath = newDestPath + destURL := urlParts.String() + // replace the query part if it is present in destination path + if len(newDestQuery) > 0 { + destURL = strings.Split(destURL, "?")[0] + "?" + newDestQuery + } + + destDirClient := (*Client)(base.NewDirectoryClient(destURL, d.generated().InternalClient(), d.sharedKey(), d.getClientOptions())) + + resp, err := destDirClient.generated().Rename(ctx, d.URL(), opts, nil, destLease, smbInfo) + return RenameResponse{ + DirectoryClientRenameResponse: 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. // file.ParseNTFSFileAttributes method can be used to convert the file attributes returned in response to NTFSFileAttributes. // For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/get-directory-properties. @@ -135,8 +216,8 @@ func (d *Client) GetProperties(ctx context.Context, options *GetPropertiesOption // file.ParseNTFSFileAttributes method can be used to convert the file attributes returned in response to NTFSFileAttributes. // 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) { - fileAttributes, fileCreationTime, fileLastWriteTime, opts := options.format() - resp, err := d.generated().SetProperties(ctx, fileAttributes, fileCreationTime, fileLastWriteTime, opts) + opts := options.format() + resp, err := d.generated().SetProperties(ctx, opts) return resp, err } @@ -195,7 +276,7 @@ func (d *Client) NewListFilesAndDirectoriesPager(options *ListFilesAndDirectorie if err != nil { return ListFilesAndDirectoriesResponse{}, err } - resp, err := d.generated().Pipeline().Do(req) + resp, err := d.generated().InternalClient().Pipeline().Do(req) if err != nil { return ListFilesAndDirectoriesResponse{}, err } diff --git a/sdk/storage/azfile/directory/client_test.go b/sdk/storage/azfile/directory/client_test.go index c1d6a372b1cb..0e665932da46 100644 --- a/sdk/storage/azfile/directory/client_test.go +++ b/sdk/storage/azfile/directory/client_test.go @@ -15,9 +15,13 @@ import ( "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/testcommon" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/lease" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/sas" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/service" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/share" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "strings" "testing" "time" ) @@ -313,6 +317,7 @@ func (d *DirectoryRecordedTestsSuite) TestDirSetPropertiesNonDefault() { _require.NoError(err) creationTime := currTime.Add(5 * time.Minute).Round(time.Microsecond) lastWriteTime := currTime.Add(10 * time.Minute).Round(time.Millisecond) + changeTime := currTime.Add(15 * time.Minute).Round(time.Millisecond) // Set the custom permissions sResp, err := dirClient.SetProperties(context.Background(), &directory.SetPropertiesOptions{ @@ -323,6 +328,7 @@ func (d *DirectoryRecordedTestsSuite) TestDirSetPropertiesNonDefault() { }, CreationTime: &creationTime, LastWriteTime: &lastWriteTime, + ChangeTime: &changeTime, }, FilePermissions: &file.Permissions{ Permission: &testcommon.SampleSDDL, @@ -335,6 +341,7 @@ func (d *DirectoryRecordedTestsSuite) TestDirSetPropertiesNonDefault() { _require.NotEqual(*sResp.FilePermissionKey, *cResp.FilePermissionKey) _require.Equal(*sResp.FileCreationTime, creationTime.UTC()) _require.Equal(*sResp.FileLastWriteTime, lastWriteTime.UTC()) + _require.Equal(*sResp.FileChangeTime, changeTime.UTC()) fileAttributes, err := file.ParseNTFSFileAttributes(sResp.FileAttributes) _require.NoError(err) @@ -351,6 +358,7 @@ func (d *DirectoryRecordedTestsSuite) TestDirSetPropertiesNonDefault() { _require.Equal(*gResp.FilePermissionKey, *sResp.FilePermissionKey) _require.Equal(*gResp.FileCreationTime, *sResp.FileCreationTime) _require.Equal(*gResp.FileLastWriteTime, *sResp.FileLastWriteTime) + _require.Equal(*gResp.FileChangeTime, *sResp.FileChangeTime) _require.Equal(*gResp.FileAttributes, *sResp.FileAttributes) fileAttributes2, err := file.ParseNTFSFileAttributes(gResp.FileAttributes) @@ -386,6 +394,7 @@ func (d *DirectoryUnrecordedTestsSuite) TestDirCreateDeleteNonDefault() { Attributes: &file.NTFSFileAttributes{None: true}, CreationTime: to.Ptr(time.Now().Add(5 * time.Minute)), LastWriteTime: to.Ptr(time.Now().Add(10 * time.Minute)), + ChangeTime: to.Ptr(time.Now().Add(10 * time.Minute)), }, FilePermissions: &file.Permissions{ Permission: &testcommon.SampleSDDL, @@ -778,6 +787,7 @@ func (d *DirectoryRecordedTestsSuite) TestDirListFilesAndDirsDefault() { fileCtr += len(resp.Segment.Files) for _, dir := range resp.Segment.Directories { _require.NotNil(dir.Name) + _require.Greater(len(*dir.Name), 0) _require.NotNil(dir.ID) _require.Nil(dir.Attributes) _require.Nil(dir.PermissionKey) @@ -788,6 +798,7 @@ func (d *DirectoryRecordedTestsSuite) TestDirListFilesAndDirsDefault() { } for _, f := range resp.Segment.Files { _require.NotNil(f.Name) + _require.Greater(len(*f.Name), 0) _require.NotNil(f.ID) _require.Nil(f.Attributes) _require.Nil(f.PermissionKey) @@ -934,12 +945,16 @@ func (d *DirectoryRecordedTestsSuite) TestDirListFilesAndDirsWithPrefix() { _require.NoError(err) dirCtr += len(resp.Segment.Directories) fileCtr += len(resp.Segment.Files) + _require.NotNil(resp.Prefix) + _require.Equal(*resp.Prefix, "1") if len(resp.Segment.Directories) > 0 { _require.NotNil(resp.Segment.Directories[0].Name) + _require.Greater(len(*resp.Segment.Directories[0].Name), 0) _require.Equal(*resp.Segment.Directories[0].Name, "1"+dirName) } if len(resp.Segment.Files) > 0 { _require.NotNil(resp.Segment.Files[0].Name) + _require.Greater(len(*resp.Segment.Files[0].Name), 0) _require.Equal(*resp.Segment.Files[0].Name, "1"+fileName) } } @@ -1166,3 +1181,1038 @@ func (d *DirectoryRecordedTestsSuite) TestDirectoryCreateWithTrailingSlash() { _, err = subDirClient.Create(context.Background(), nil) _require.NoError(err) } + +func (d *DirectoryRecordedTestsSuite) TestDirectoryCreateDeleteUsingOAuth() { + _require := require.New(d.T()) + testName := d.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := testcommon.GenerateDirectoryName(testName) + dirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + dirName + + options := &directory.ClientOptions{FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup)} + testcommon.SetClientOptions(d.T(), &options.ClientOptions) + dirClient, err := directory.NewClient(dirURL, cred, options) + _require.NoError(err) + + resp, err := dirClient.Create(context.Background(), nil) + _require.NoError(err) + _require.NotNil(resp.ETag) + _require.NotNil(resp.RequestID) + _require.Equal(resp.LastModified.IsZero(), false) + _require.Equal(resp.FileCreationTime.IsZero(), false) + _require.Equal(resp.FileLastWriteTime.IsZero(), false) + _require.Equal(resp.FileChangeTime.IsZero(), false) + + gResp, err := dirClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.NotNil(gResp.FileCreationTime) + _require.NotNil(gResp.FileLastWriteTime) + _require.NotNil(gResp.FilePermissionKey) + + dResp, err := dirClient.Delete(context.Background(), nil) + _require.NoError(err) + _require.Equal(dResp.Date.IsZero(), false) + _require.NotNil(dResp.RequestID) + _require.NotNil(dResp.Version) + + _, err = dirClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectorySetPropertiesUsingOAuth() { + _require := require.New(d.T()) + testName := d.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := testcommon.GenerateDirectoryName(testName) + dirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + dirName + + options := &directory.ClientOptions{FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup)} + testcommon.SetClientOptions(d.T(), &options.ClientOptions) + dirClient, err := directory.NewClient(dirURL, cred, options) + _require.NoError(err) + + cResp, err := dirClient.Create(context.Background(), nil) + _require.NoError(err) + _require.NotNil(cResp.FilePermissionKey) + + currTime, err := time.Parse(time.UnixDate, "Fri Mar 31 21:00:00 GMT 2023") + _require.NoError(err) + creationTime := currTime.Add(5 * time.Minute).Round(time.Microsecond) + lastWriteTime := currTime.Add(10 * time.Minute).Round(time.Millisecond) + changeTime := currTime.Add(15 * time.Minute).Round(time.Millisecond) + + // Set the custom permissions + sResp, err := dirClient.SetProperties(context.Background(), &directory.SetPropertiesOptions{ + FileSMBProperties: &file.SMBProperties{ + Attributes: &file.NTFSFileAttributes{ + ReadOnly: true, + System: true, + }, + CreationTime: &creationTime, + LastWriteTime: &lastWriteTime, + ChangeTime: &changeTime, + }, + FilePermissions: &file.Permissions{ + Permission: &testcommon.SampleSDDL, + }, + }) + _require.NoError(err) + _require.NotNil(sResp.FileCreationTime) + _require.NotNil(sResp.FileLastWriteTime) + _require.NotNil(sResp.FileChangeTime) + _require.NotNil(sResp.FilePermissionKey) + _require.NotEqual(*sResp.FilePermissionKey, *cResp.FilePermissionKey) + _require.Equal(*sResp.FileCreationTime, creationTime.UTC()) + _require.Equal(*sResp.FileLastWriteTime, lastWriteTime.UTC()) + _require.Equal(*sResp.FileChangeTime, changeTime.UTC()) + + fileAttributes, err := file.ParseNTFSFileAttributes(sResp.FileAttributes) + _require.NoError(err) + _require.NotNil(fileAttributes) + _require.True(fileAttributes.ReadOnly) + _require.True(fileAttributes.System) + _require.True(fileAttributes.Directory) + + gResp, err := dirClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.NotNil(gResp.FileCreationTime) + _require.NotNil(gResp.FileLastWriteTime) + _require.NotNil(gResp.FileChangeTime) + _require.NotNil(gResp.FilePermissionKey) + _require.Equal(*gResp.FilePermissionKey, *sResp.FilePermissionKey) + _require.Equal(*gResp.FileCreationTime, *sResp.FileCreationTime) + _require.Equal(*gResp.FileLastWriteTime, *sResp.FileLastWriteTime) + _require.Equal(*gResp.FileChangeTime, *sResp.FileChangeTime) + _require.Equal(*gResp.FileAttributes, *sResp.FileAttributes) + + fileAttributes2, err := file.ParseNTFSFileAttributes(gResp.FileAttributes) + _require.NoError(err) + _require.NotNil(fileAttributes2) + _require.True(fileAttributes2.ReadOnly) + _require.True(fileAttributes2.System) + _require.True(fileAttributes2.Directory) + _require.EqualValues(fileAttributes2, fileAttributes) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectorySetMetadataUsingOAuth() { + _require := require.New(d.T()) + testName := d.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := testcommon.GenerateDirectoryName(testName) + dirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + dirName + + options := &directory.ClientOptions{FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup)} + testcommon.SetClientOptions(d.T(), &options.ClientOptions) + dirClient, err := directory.NewClient(dirURL, cred, options) + _require.NoError(err) + + _, err = dirClient.Create(context.Background(), nil) + _require.NoError(err) + + md := map[string]*string{ + "Foo": to.Ptr("FooValuE"), + "Bar": to.Ptr("bArvaLue"), + } + + sResp, err := dirClient.SetMetadata(context.Background(), &directory.SetMetadataOptions{ + Metadata: md, + }) + _require.NoError(err) + _require.Equal(sResp.Date.IsZero(), false) + _require.NotNil(sResp.ETag) + _require.NotNil(sResp.RequestID) + _require.NotNil(sResp.Version) + _require.NotNil(sResp.IsServerEncrypted) + + gResp, err := dirClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.Equal(gResp.Date.IsZero(), false) + _require.NotNil(gResp.ETag) + _require.Equal(gResp.LastModified.IsZero(), false) + _require.NotNil(gResp.RequestID) + _require.NotNil(gResp.Version) + _require.NotNil(gResp.IsServerEncrypted) + _require.EqualValues(gResp.Metadata, md) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryListHandlesUsingOAuth() { + _require := require.New(d.T()) + testName := d.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := testcommon.GenerateDirectoryName(testName) + dirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + dirName + + options := &directory.ClientOptions{FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup)} + testcommon.SetClientOptions(d.T(), &options.ClientOptions) + dirClient, err := directory.NewClient(dirURL, cred, options) + _require.NoError(err) + + _, err = dirClient.Create(context.Background(), nil) + _require.NoError(err) + + resp, err := dirClient.ListHandles(context.Background(), nil) + _require.NoError(err) + _require.Len(resp.Handles, 0) + _require.NotNil(resp.NextMarker) + _require.Equal(*resp.NextMarker, "") +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryForceCloseHandlesUsingOAuth() { + _require := require.New(d.T()) + testName := d.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := testcommon.GenerateDirectoryName(testName) + dirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + dirName + + options := &directory.ClientOptions{FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup)} + testcommon.SetClientOptions(d.T(), &options.ClientOptions) + dirClient, err := directory.NewClient(dirURL, cred, options) + _require.NoError(err) + + _, err = dirClient.Create(context.Background(), nil) + _require.NoError(err) + + resp, err := dirClient.ForceCloseHandles(context.Background(), "*", nil) + _require.NoError(err) + _require.EqualValues(*resp.NumberOfHandlesClosed, 0) + _require.EqualValues(*resp.NumberOfHandlesFailedToClose, 0) + _require.Nil(resp.Marker) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryListUsingOAuth() { + _require := require.New(d.T()) + testName := d.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := testcommon.GenerateDirectoryName(testName) + dirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + dirName + + options := &directory.ClientOptions{FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup)} + testcommon.SetClientOptions(d.T(), &options.ClientOptions) + dirClient, err := directory.NewClient(dirURL, cred, options) + _require.NoError(err) + + _, err = dirClient.Create(context.Background(), nil) + _require.NoError(err) + + fileName := testcommon.GenerateFileName(testName) + + // create directories + for i := 0; i < 10; i++ { + subDirClient := dirClient.NewSubdirectoryClient(dirName + fmt.Sprintf("%v", i)) + _, err = subDirClient.Create(context.Background(), nil) + _require.NoError(err) + } + + // create files + for i := 0; i < 5; i++ { + fileClient := dirClient.NewFileClient(fileName + fmt.Sprintf("%v", i)) + _, err = fileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + } + + subDirCtr, fileCtr := 0, 0 + pager := dirClient.NewListFilesAndDirectoriesPager(nil) + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.NoError(err) + subDirCtr += len(resp.Segment.Directories) + fileCtr += len(resp.Segment.Files) + for _, dir := range resp.Segment.Directories { + _require.NotNil(dir.Name) + _require.Greater(len(*dir.Name), 0) + _require.NotNil(dir.ID) + _require.Nil(dir.Attributes) + _require.Nil(dir.PermissionKey) + _require.Nil(dir.Properties.ETag) + _require.Nil(dir.Properties.ChangeTime) + _require.Nil(dir.Properties.CreationTime) + _require.Nil(dir.Properties.ContentLength) + } + for _, f := range resp.Segment.Files { + _require.NotNil(f.Name) + _require.Greater(len(*f.Name), 0) + _require.NotNil(f.ID) + _require.Nil(f.Attributes) + _require.Nil(f.PermissionKey) + _require.Nil(f.Properties.ETag) + _require.Nil(f.Properties.ChangeTime) + _require.Nil(f.Properties.CreationTime) + _require.NotNil(f.Properties.ContentLength) + _require.Equal(*f.Properties.ContentLength, int64(2048)) + } + } + _require.Equal(subDirCtr, 10) + _require.Equal(fileCtr, 5) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryRenameDefault() { + _require := require.New(d.T()) + testName := d.T().Name() + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirClient := testcommon.CreateNewDirectory(context.Background(), _require, testcommon.GenerateDirectoryName(testName), shareClient) + + fileName := testcommon.GenerateFileName(testName) + fClient := dirClient.NewFileClient(fileName) + _, err = fClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + resp, err := dirClient.Rename(context.Background(), "newDirName", nil) + _require.NoError(err) + _require.NotNil(resp.ETag) + _require.NotNil(resp.RequestID) + _require.Equal(resp.LastModified.IsZero(), false) + _require.Equal(resp.FileCreationTime.IsZero(), false) + _require.Equal(resp.FileLastWriteTime.IsZero(), false) + _require.Equal(resp.FileChangeTime.IsZero(), false) + + _, err = dirClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) + + _, err = fClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ParentNotFound) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryRenameUsingOAuth() { + _require := require.New(d.T()) + testName := d.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := testcommon.GenerateDirectoryName(testName) + dirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + dirName + + options := &directory.ClientOptions{FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup)} + testcommon.SetClientOptions(d.T(), &options.ClientOptions) + dirClient, err := directory.NewClient(dirURL, cred, options) + _require.NoError(err) + _, err = dirClient.Create(context.Background(), nil) + _require.NoError(err) + + fileName := testcommon.GenerateFileName(testName) + fClient := dirClient.NewFileClient(fileName) + _, err = fClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + resp, err := dirClient.Rename(context.Background(), "dir1", nil) + _require.NoError(err) + _require.NotNil(resp.ETag) + _require.NotNil(resp.RequestID) + _require.Equal(resp.LastModified.IsZero(), false) + _require.Equal(resp.FileCreationTime.IsZero(), false) + _require.Equal(resp.FileLastWriteTime.IsZero(), false) + _require.Equal(resp.FileChangeTime.IsZero(), false) + + _, err = dirClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) + + _, err = fClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ParentNotFound) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryRenameParentNotFound() { + _require := require.New(d.T()) + testName := d.T().Name() + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirClient := testcommon.CreateNewDirectory(context.Background(), _require, testcommon.GenerateDirectoryName(testName), shareClient) + + _, err = dirClient.Rename(context.Background(), "dir1/dir2/", nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ParentNotFound) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryRenameDifferentDir() { + _require := require.New(d.T()) + testName := d.T().Name() + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + srcParentDirCl := testcommon.CreateNewDirectory(context.Background(), _require, testcommon.GenerateDirectoryName(testName), shareClient) + srcDirCl := srcParentDirCl.NewSubdirectoryClient("subDir1") + + _, err = srcDirCl.Create(context.Background(), nil) + _require.NoError(err) + + _ = testcommon.CreateNewDirectory(context.Background(), _require, "destDir", shareClient) + + _, err = srcDirCl.Rename(context.Background(), "destDir/subDir2", nil) + _require.NoError(err) + + _, err = srcDirCl.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryRenameIgnoreReadOnly() { + _require := require.New(d.T()) + testName := d.T().Name() + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + srcDirCl := testcommon.CreateNewDirectory(context.Background(), _require, testcommon.GenerateDirectoryName(testName), shareClient) + + destParentDirCl := testcommon.CreateNewDirectory(context.Background(), _require, "destDir", shareClient) + + _, err = destParentDirCl.NewFileClient("testFile").Create(context.Background(), 2048, &file.CreateOptions{ + SMBProperties: &file.SMBProperties{ + Attributes: &file.NTFSFileAttributes{ReadOnly: true}, + }, + }) + _require.NoError(err) + + _, err = srcDirCl.Rename(context.Background(), "destDir/testFile", nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceAlreadyExists) + + _, err = srcDirCl.Rename(context.Background(), "destDir/testFile", &directory.RenameOptions{ + ReplaceIfExists: to.Ptr(true), + }) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ReadOnlyAttribute) + + _, err = srcDirCl.Rename(context.Background(), "destDir/testFile", &directory.RenameOptions{ + ReplaceIfExists: to.Ptr(true), + IgnoreReadOnly: to.Ptr(true), + }) + _require.NoError(err) + + _, err = srcDirCl.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryRenameNonDefault() { + _require := require.New(d.T()) + testName := d.T().Name() + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + srcDirCl := testcommon.CreateNewDirectory(context.Background(), _require, "dir1", shareClient) + + currTime, err := time.Parse(time.UnixDate, "Fri Mar 31 21:00:00 GMT 2023") + _require.NoError(err) + creationTime := currTime.Add(5 * time.Minute).Round(time.Microsecond) + lastWriteTime := currTime.Add(8 * time.Minute).Round(time.Millisecond) + changeTime := currTime.Add(10 * time.Minute).Round(time.Millisecond) + + md := map[string]*string{ + "Foo": to.Ptr("FooValuE"), + "Bar": to.Ptr("bArvaLue"), + } + + resp, err := srcDirCl.Rename(context.Background(), "dir2", &directory.RenameOptions{ + FileSMBProperties: &file.SMBProperties{ + Attributes: &file.NTFSFileAttributes{ + ReadOnly: true, + System: true, + }, + CreationTime: &creationTime, + LastWriteTime: &lastWriteTime, + ChangeTime: &changeTime, + }, + FilePermissions: &file.Permissions{ + Permission: &testcommon.SampleSDDL, + }, + Metadata: md, + }) + _require.NoError(err) + _require.NotNil(resp.FileCreationTime) + _require.Equal(*resp.FileCreationTime, creationTime.UTC()) + _require.NotNil(resp.FileLastWriteTime) + _require.Equal(*resp.FileLastWriteTime, lastWriteTime.UTC()) + _require.NotNil(resp.FileChangeTime) + _require.Equal(*resp.FileChangeTime, changeTime.UTC()) + _require.NotNil(resp.FilePermissionKey) + + fileAttributes, err := file.ParseNTFSFileAttributes(resp.FileAttributes) + _require.NoError(err) + _require.NotNil(fileAttributes) + _require.True(fileAttributes.ReadOnly) + _require.True(fileAttributes.System) + _require.True(fileAttributes.Directory) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryRenameDestLease() { + _require := require.New(d.T()) + testName := d.T().Name() + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + srcDirCl := testcommon.CreateNewDirectory(context.Background(), _require, "dir1", shareClient) + + destParentDirCl := testcommon.CreateNewDirectory(context.Background(), _require, "dir2", shareClient) + + destFileClient := destParentDirCl.NewFileClient("testFile") + _, err = destFileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + proposedLeaseID := "c820a799-76d7-4ee2-6e15-546f19325c2c" + + // acquire lease on destFile + fileLeaseClient, err := lease.NewFileClient(destFileClient, &lease.FileClientOptions{ + LeaseID: &proposedLeaseID, + }) + _require.NoError(err) + acqResp, err := fileLeaseClient.Acquire(context.Background(), nil) + _require.NoError(err) + _require.NotNil(acqResp.LeaseID) + _require.Equal(*acqResp.LeaseID, proposedLeaseID) + + destPath := "dir2/testFile" + _, err = srcDirCl.Rename(context.Background(), destPath, &directory.RenameOptions{ + ReplaceIfExists: to.Ptr(true), + }) + _require.Error(err) + + _, err = srcDirCl.Rename(context.Background(), destPath, &directory.RenameOptions{ + ReplaceIfExists: to.Ptr(true), + DestinationLeaseAccessConditions: &directory.DestinationLeaseAccessConditions{ + DestinationLeaseID: acqResp.LeaseID, + }, + }) + _require.NoError(err) + + _, err = srcDirCl.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (d *DirectoryUnrecordedTestsSuite) TestDirectoryRenameUsingSAS() { + _require := require.New(d.T()) + testName := d.T().Name() + + cred, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + perms := sas.FilePermissions{Read: true, Create: true, Write: true} + sasQueryParams, err := sas.SignatureValues{ + Protocol: sas.ProtocolHTTPS, // Users MUST use HTTPS (not HTTP) + ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration + ShareName: shareName, + Permissions: perms.String(), + }.SignWithSharedKey(cred) + _require.NoError(err) + + sasToken := sasQueryParams.Encode() + + srcDirCl, err := directory.NewClientWithNoCredential(shareClient.URL()+"/dir1?"+sasToken, nil) + _require.NoError(err) + _, err = srcDirCl.Create(context.Background(), nil) + _require.NoError(err) + + destPathWithSAS := "dir2?" + sasToken + _, err = srcDirCl.Rename(context.Background(), destPathWithSAS, nil) + _require.NoError(err) + + _, err = srcDirCl.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryCreateDeleteTrailingDot() { + _require := require.New(d.T()) + testName := d.T().Name() + + options := &service.ClientOptions{AllowTrailingDot: to.Ptr(true)} + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, options) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := "dir...." + dirClient := testcommon.CreateNewDirectory(context.Background(), _require, dirName, shareClient) + + _, err = dirClient.GetProperties(context.Background(), nil) + _require.NoError(err) + + _, err = dirClient.Delete(context.Background(), nil) + _require.NoError(err) + + _, err = dirClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectorySetPropertiesTrailingDotAndOAuth() { + _require := require.New(d.T()) + testName := d.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := "dir.." + dirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + dirName + + options := &directory.ClientOptions{ + FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup), + AllowTrailingDot: to.Ptr(true), + } + testcommon.SetClientOptions(d.T(), &options.ClientOptions) + dirClient, err := directory.NewClient(dirURL, cred, options) + _require.NoError(err) + + cResp, err := dirClient.Create(context.Background(), nil) + _require.NoError(err) + _require.NotNil(cResp.FilePermissionKey) + + currTime, err := time.Parse(time.UnixDate, "Fri Mar 31 21:00:00 GMT 2023") + _require.NoError(err) + creationTime := currTime.Add(5 * time.Minute).Round(time.Microsecond) + lastWriteTime := currTime.Add(10 * time.Minute).Round(time.Millisecond) + changeTime := currTime.Add(15 * time.Minute).Round(time.Millisecond) + + // Set the custom permissions + sResp, err := dirClient.SetProperties(context.Background(), &directory.SetPropertiesOptions{ + FileSMBProperties: &file.SMBProperties{ + Attributes: &file.NTFSFileAttributes{ + ReadOnly: true, + System: true, + }, + CreationTime: &creationTime, + LastWriteTime: &lastWriteTime, + ChangeTime: &changeTime, + }, + FilePermissions: &file.Permissions{ + Permission: &testcommon.SampleSDDL, + }, + }) + _require.NoError(err) + _require.NotNil(sResp.FileCreationTime) + _require.NotNil(sResp.FileLastWriteTime) + _require.NotNil(sResp.FileChangeTime) + _require.NotNil(sResp.FilePermissionKey) + _require.NotEqual(*sResp.FilePermissionKey, *cResp.FilePermissionKey) + _require.Equal(*sResp.FileCreationTime, creationTime.UTC()) + _require.Equal(*sResp.FileLastWriteTime, lastWriteTime.UTC()) + _require.Equal(*sResp.FileChangeTime, changeTime.UTC()) + + fileAttributes, err := file.ParseNTFSFileAttributes(sResp.FileAttributes) + _require.NoError(err) + _require.NotNil(fileAttributes) + _require.True(fileAttributes.ReadOnly) + _require.True(fileAttributes.System) + _require.True(fileAttributes.Directory) + + gResp, err := dirClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.NotNil(gResp.FileCreationTime) + _require.NotNil(gResp.FileLastWriteTime) + _require.NotNil(gResp.FileChangeTime) + _require.NotNil(gResp.FilePermissionKey) + _require.Equal(*gResp.FilePermissionKey, *sResp.FilePermissionKey) + _require.Equal(*gResp.FileCreationTime, *sResp.FileCreationTime) + _require.Equal(*gResp.FileLastWriteTime, *sResp.FileLastWriteTime) + _require.Equal(*gResp.FileChangeTime, *sResp.FileChangeTime) + _require.Equal(*gResp.FileAttributes, *sResp.FileAttributes) + + fileAttributes2, err := file.ParseNTFSFileAttributes(gResp.FileAttributes) + _require.NoError(err) + _require.NotNil(fileAttributes2) + _require.True(fileAttributes2.ReadOnly) + _require.True(fileAttributes2.System) + _require.True(fileAttributes2.Directory) + _require.EqualValues(fileAttributes2, fileAttributes) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectorySetMetadataTrailingDot() { + _require := require.New(d.T()) + testName := d.T().Name() + + options := &service.ClientOptions{AllowTrailingDot: to.Ptr(true)} + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, options) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := "dir.." + dirClient := testcommon.CreateNewDirectory(context.Background(), _require, dirName, shareClient) + + md := map[string]*string{ + "Foo": to.Ptr("FooValuE"), + "Bar": to.Ptr("bArvaLue"), + } + + _, err = dirClient.SetMetadata(context.Background(), &directory.SetMetadataOptions{ + Metadata: md, + }) + _require.NoError(err) + + gResp, err := dirClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.EqualValues(gResp.Metadata, md) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryListTrailingDot() { + _require := require.New(d.T()) + testName := d.T().Name() + + options := &service.ClientOptions{AllowTrailingDot: to.Ptr(true)} + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, options) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := testcommon.GenerateDirectoryName(testName) + "." + dirClient := testcommon.CreateNewDirectory(context.Background(), _require, dirName, shareClient) + _require.NoError(err) + + // create directories + for i := 0; i < 10; i++ { + subDirName := fmt.Sprintf("dir %v", i) + if i%2 == 0 { + subDirName += ".." + } + subDirClient := dirClient.NewSubdirectoryClient(subDirName) + _, err = subDirClient.Create(context.Background(), nil) + _require.NoError(err) + } + + // create files + for i := 0; i < 5; i++ { + fName := fmt.Sprintf("file %v", i) + if i%2 == 0 { + fName += ".." + } + fileClient := dirClient.NewFileClient(fName) + _, err = fileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + } + + subDirCtr, subDirDotCtr, fileCtr, fileDotCtr := 0, 0, 0, 0 + pager := dirClient.NewListFilesAndDirectoriesPager(nil) + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.NoError(err) + subDirCtr += len(resp.Segment.Directories) + fileCtr += len(resp.Segment.Files) + for _, dir := range resp.Segment.Directories { + _require.NotNil(dir.Name) + _require.Greater(len(*dir.Name), 0) + if strings.HasSuffix(*dir.Name, "..") { + subDirDotCtr++ + } + } + for _, f := range resp.Segment.Files { + _require.NotNil(f.Name) + _require.Greater(len(*f.Name), 0) + if strings.HasSuffix(*f.Name, "..") { + fileDotCtr++ + } + } + } + _require.Equal(subDirCtr, 10) + _require.Equal(subDirDotCtr, 5) + _require.Equal(fileCtr, 5) + _require.Equal(fileDotCtr, 3) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryRenameNegativeSourceTrailingDot() { + _require := require.New(d.T()) + testName := d.T().Name() + + options := &service.ClientOptions{ + AllowTrailingDot: to.Ptr(true), + } + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, options) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := testcommon.GenerateDirectoryName(testName) + ".." + dirClient := testcommon.CreateNewDirectory(context.Background(), _require, dirName, shareClient) + + _, err = dirClient.Rename(context.Background(), "dir1..", nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (d *DirectoryRecordedTestsSuite) TestDirectoryRenameSourceTrailingDotAndOAuth() { + _require := require.New(d.T()) + testName := d.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := testcommon.GenerateDirectoryName(testName) + ".." + dirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + dirName + + options := &directory.ClientOptions{ + FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup), + AllowTrailingDot: to.Ptr(true), + AllowSourceTrailingDot: to.Ptr(true), + } + testcommon.SetClientOptions(d.T(), &options.ClientOptions) + dirClient, err := directory.NewClient(dirURL, cred, options) + _require.NoError(err) + _, err = dirClient.Create(context.Background(), nil) + _require.NoError(err) + + fileName := "file.." + fClient := dirClient.NewFileClient(fileName) + _, err = fClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + resp, err := dirClient.Rename(context.Background(), "dir1..", nil) + _require.NoError(err) + _require.Equal(resp.LastModified.IsZero(), false) + _require.Equal(resp.FileCreationTime.IsZero(), false) + _require.Equal(resp.FileLastWriteTime.IsZero(), false) + _require.Equal(resp.FileChangeTime.IsZero(), false) + + _, err = dirClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) + + _, err = fClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ParentNotFound) +} + +func (d *DirectoryRecordedTestsSuite) TestListFileDirEncoded() { + _require := require.New(d.T()) + testName := d.T().Name() + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := "directory\uFFFF" + dirClient := testcommon.CreateNewDirectory(context.Background(), _require, dirName, shareClient) + + fileName := "file\uFFFE" + fileClient := testcommon.CreateNewFileFromShare(context.Background(), _require, fileName, 2048, shareClient) + + _, err = dirClient.GetProperties(context.Background(), nil) + _require.NoError(err) + + _, err = fileClient.GetProperties(context.Background(), nil) + _require.NoError(err) + + pager := shareClient.NewRootDirectoryClient().NewListFilesAndDirectoriesPager(nil) + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.NoError(err) + _require.Len(resp.Segment.Directories, 1) + _require.NotNil(resp.Segment.Directories[0]) + _require.Equal(*resp.Segment.Directories[0].Name, dirName) + _require.Len(resp.Segment.Files, 1) + _require.NotNil(resp.Segment.Files[0]) + _require.Equal(*resp.Segment.Files[0].Name, fileName) + } +} + +func (d *DirectoryRecordedTestsSuite) TestListFileDirEncodedContinuationToken() { + _require := require.New(d.T()) + testName := d.T().Name() + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName0 := "file0\uFFFE" + _ = testcommon.CreateNewFileFromShare(context.Background(), _require, fileName0, 2048, shareClient) + + fileName1 := "file1\uFFFE" + _ = testcommon.CreateNewFileFromShare(context.Background(), _require, fileName1, 2048, shareClient) + + var files []string + pager := shareClient.NewRootDirectoryClient().NewListFilesAndDirectoriesPager(&directory.ListFilesAndDirectoriesOptions{ + MaxResults: to.Ptr(int32(1)), + }) + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.NoError(err) + _require.Len(resp.Segment.Files, 1) + _require.NotNil(resp.Segment.Files[0].Name) + files = append(files, *resp.Segment.Files[0].Name) + } + + _require.Len(files, 2) + _require.Equal(files[0], fileName0) + _require.Equal(files[1], fileName1) +} + +func (d *DirectoryRecordedTestsSuite) TestListFileDirEncodedPrefix() { + _require := require.New(d.T()) + testName := d.T().Name() + + svcClient, err := testcommon.GetServiceClient(d.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + dirName := "directory\uFFFF" + _ = testcommon.CreateNewDirectory(context.Background(), _require, dirName, shareClient) + + pager := shareClient.NewRootDirectoryClient().NewListFilesAndDirectoriesPager(&directory.ListFilesAndDirectoriesOptions{ + Prefix: &dirName, + }) + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.NoError(err) + _require.Len(resp.Segment.Directories, 1) + _require.Len(resp.Segment.Files, 0) + _require.NotNil(resp.Segment.Directories[0]) + _require.Equal(*resp.Segment.Directories[0].Name, dirName) + _require.NotNil(resp.Prefix) + _require.Equal(*resp.Prefix, dirName) + } +} diff --git a/sdk/storage/azfile/directory/constants.go b/sdk/storage/azfile/directory/constants.go index 2b16931bbc56..8db08a4e1971 100644 --- a/sdk/storage/azfile/directory/constants.go +++ b/sdk/storage/azfile/directory/constants.go @@ -22,3 +22,15 @@ const ( func PossibleListFilesIncludeTypeValues() []ListFilesIncludeType { return generated.PossibleListFilesIncludeTypeValues() } + +// ShareTokenIntent is required if authorization header specifies an OAuth token. +type ShareTokenIntent = generated.ShareTokenIntent + +const ( + ShareTokenIntentBackup ShareTokenIntent = generated.ShareTokenIntentBackup +) + +// PossibleShareTokenIntentValues returns the possible values for the ShareTokenIntent const type. +func PossibleShareTokenIntentValues() []ShareTokenIntent { + return generated.PossibleShareTokenIntentValues() +} diff --git a/sdk/storage/azfile/directory/examples_test.go b/sdk/storage/azfile/directory/examples_test.go index 0d355ff82191..6663a5c0b3ba 100644 --- a/sdk/storage/azfile/directory/examples_test.go +++ b/sdk/storage/azfile/directory/examples_test.go @@ -10,9 +10,9 @@ import ( "context" "fmt" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/directory" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/file" - "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/internal/testcommon" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/service" "log" "os" @@ -98,6 +98,7 @@ func Example_directoryClient_SetProperties() { creationTime := time.Now().Add(5 * time.Minute).Round(time.Microsecond) lastWriteTime := time.Now().Add(10 * time.Minute).Round(time.Millisecond) + testSDDL := `O:S-1-5-32-548G:S-1-5-21-397955417-626881126-188441444-512D:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)` // Set the custom permissions _, err = dirClient.SetProperties(context.Background(), &directory.SetPropertiesOptions{ @@ -110,7 +111,7 @@ func Example_directoryClient_SetProperties() { LastWriteTime: &lastWriteTime, }, FilePermissions: &file.Permissions{ - Permission: &testcommon.SampleSDDL, + Permission: &testSDDL, }, }) handleError(err) @@ -191,3 +192,88 @@ func Example_directoryClient_SetMetadata() { handleError(err) fmt.Println("Directory deleted") } + +func Example_directoryClient_OAuth() { + accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME") + if !ok { + panic("AZURE_STORAGE_ACCOUNT_NAME could not be found") + } + + cred, err := azidentity.NewDefaultAzureCredential(nil) + handleError(err) + + shareName := "testShare" + dirName := "testDirectory" + dirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + dirName + + dirClient, err := directory.NewClient(dirURL, cred, &directory.ClientOptions{FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup)}) + handleError(err) + + _, err = dirClient.Create(context.TODO(), nil) + handleError(err) + fmt.Println("Directory created") + + _, err = dirClient.GetProperties(context.TODO(), nil) + handleError(err) + fmt.Println("Directory properties retrieved") + + _, err = dirClient.Delete(context.TODO(), nil) + handleError(err) + fmt.Println("Directory deleted") +} + +func Example_directoryClient_TrailingDot() { + accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME") + if !ok { + panic("AZURE_STORAGE_ACCOUNT_NAME could not be found") + } + + cred, err := azidentity.NewDefaultAzureCredential(nil) + handleError(err) + + shareName := "testShare" + dirName := "testDirectory.." // directory name with trailing dot + dirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + dirName + + dirClient, err := directory.NewClient(dirURL, cred, &directory.ClientOptions{ + FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup), + AllowTrailingDot: to.Ptr(true), + }) + handleError(err) + + fmt.Println(dirClient.URL()) + + _, err = dirClient.Create(context.TODO(), nil) + handleError(err) + fmt.Println("Directory created") + + _, err = dirClient.GetProperties(context.TODO(), nil) + handleError(err) + fmt.Println("Directory properties retrieved") + + _, err = dirClient.Delete(context.TODO(), nil) + handleError(err) + fmt.Println("Directory deleted") +} + +func Example_directoryClient_Rename() { + accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME") + if !ok { + panic("AZURE_STORAGE_ACCOUNT_NAME could not be found") + } + + cred, err := azidentity.NewDefaultAzureCredential(nil) + handleError(err) + + shareName := "testShare" + srcDirName := "testDirectory" + destDirName := "newDirectory" + srcDirURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + srcDirName + + srcDirClient, err := directory.NewClient(srcDirURL, cred, &directory.ClientOptions{FileRequestIntent: to.Ptr(directory.ShareTokenIntentBackup)}) + handleError(err) + + _, err = srcDirClient.Rename(context.TODO(), destDirName, nil) + handleError(err) + fmt.Println("Directory renamed") +} diff --git a/sdk/storage/azfile/directory/models.go b/sdk/storage/azfile/directory/models.go index 950cf1a91d63..d26dacc46aac 100644 --- a/sdk/storage/azfile/directory/models.go +++ b/sdk/storage/azfile/directory/models.go @@ -7,11 +7,9 @@ package directory import ( - "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/file" "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" "reflect" ) @@ -24,6 +22,9 @@ func NewSharedKeyCredential(accountName, accountKey string) (*SharedKeyCredentia return exported.NewSharedKeyCredential(accountName, accountKey) } +// DestinationLeaseAccessConditions contains optional parameters to access the destination directory. +type DestinationLeaseAccessConditions = generated.DestinationLeaseAccessConditions + // --------------------------------------------------------------------------------------------------------------------- // CreateOptions contains the optional parameters for the Client.Create method. @@ -36,24 +37,26 @@ type CreateOptions struct { Metadata map[string]*string } -func (o *CreateOptions) format() (fileAttributes string, fileCreationTime string, fileLastWriteTime string, createOptions *generated.DirectoryClientCreateOptions) { +func (o *CreateOptions) format() *generated.DirectoryClientCreateOptions { if o == nil { - return shared.FileAttributesDirectory, shared.DefaultCurrentTimeString, shared.DefaultCurrentTimeString, &generated.DirectoryClientCreateOptions{ - FilePermission: to.Ptr(shared.DefaultFilePermissionString), - } + return nil } - fileAttributes, fileCreationTime, fileLastWriteTime = o.FileSMBProperties.Format(true, shared.FileAttributesDirectory, shared.DefaultCurrentTimeString) + fileAttributes, fileCreationTime, fileLastWriteTime, fileChangeTime := exported.FormatSMBProperties(o.FileSMBProperties, true) - permission, permissionKey := o.FilePermissions.Format(shared.DefaultFilePermissionString) + permission, permissionKey := exported.FormatPermissions(o.FilePermissions) - createOptions = &generated.DirectoryClientCreateOptions{ + createOptions := &generated.DirectoryClientCreateOptions{ + FileAttributes: fileAttributes, + FileChangeTime: fileChangeTime, + FileCreationTime: fileCreationTime, + FileLastWriteTime: fileLastWriteTime, FilePermission: permission, FilePermissionKey: permissionKey, Metadata: o.Metadata, } - return + return createOptions } // --------------------------------------------------------------------------------------------------------------------- @@ -69,6 +72,55 @@ func (o *DeleteOptions) format() *generated.DirectoryClientDeleteOptions { // --------------------------------------------------------------------------------------------------------------------- +// RenameOptions contains the optional parameters for the Client.Rename method. +type RenameOptions struct { + // FileSMBProperties contains the optional parameters regarding the SMB/NTFS properties for a file. + FileSMBProperties *file.SMBProperties + // FilePermissions contains the optional parameters for the permissions on the file. + FilePermissions *file.Permissions + // IgnoreReadOnly specifies whether the ReadOnly attribute on a pre-existing destination file should be respected. + // If true, rename will succeed, otherwise, a previous file at the destination with the ReadOnly attribute set will cause rename to fail. + IgnoreReadOnly *bool + // A name-value pair to associate with a file storage object. + Metadata map[string]*string + // ReplaceIfExists specifies that if the destination file already exists, whether this request will overwrite the file or not. + // If true, rename will succeed and will overwrite the destination file. If not provided or if false and the destination file does exist, + // the request will not overwrite the destination file. + // If provided and the destination file does not exist, rename will succeed. + ReplaceIfExists *bool + // DestinationLeaseAccessConditions contains optional parameters to access the destination directory. + DestinationLeaseAccessConditions *DestinationLeaseAccessConditions +} + +func (o *RenameOptions) format() (*generated.DirectoryClientRenameOptions, *generated.DestinationLeaseAccessConditions, *generated.CopyFileSMBInfo) { + if o == nil { + return nil, nil, nil + } + + fileAttributes, fileCreationTime, fileLastWriteTime, fileChangeTime := exported.FormatSMBProperties(o.FileSMBProperties, true) + + permission, permissionKey := exported.FormatPermissions(o.FilePermissions) + + renameOpts := &generated.DirectoryClientRenameOptions{ + FilePermission: permission, + FilePermissionKey: permissionKey, + IgnoreReadOnly: o.IgnoreReadOnly, + Metadata: o.Metadata, + ReplaceIfExists: o.ReplaceIfExists, + } + + smbInfo := &generated.CopyFileSMBInfo{ + FileAttributes: fileAttributes, + FileChangeTime: fileChangeTime, + FileCreationTime: fileCreationTime, + FileLastWriteTime: fileLastWriteTime, + } + + return renameOpts, o.DestinationLeaseAccessConditions, smbInfo +} + +// --------------------------------------------------------------------------------------------------------------------- + // GetPropertiesOptions contains the optional parameters for the Client.GetProperties method. type GetPropertiesOptions struct { // ShareSnapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query for the directory properties. @@ -95,22 +147,24 @@ type SetPropertiesOptions struct { FilePermissions *file.Permissions } -func (o *SetPropertiesOptions) format() (fileAttributes string, fileCreationTime string, fileLastWriteTime string, setPropertiesOptions *generated.DirectoryClientSetPropertiesOptions) { +func (o *SetPropertiesOptions) format() *generated.DirectoryClientSetPropertiesOptions { if o == nil { - return shared.DefaultPreserveString, shared.DefaultPreserveString, shared.DefaultPreserveString, &generated.DirectoryClientSetPropertiesOptions{ - FilePermission: to.Ptr(shared.DefaultPreserveString), - } + return nil } - fileAttributes, fileCreationTime, fileLastWriteTime = o.FileSMBProperties.Format(true, shared.DefaultPreserveString, shared.DefaultPreserveString) + fileAttributes, fileCreationTime, fileLastWriteTime, fileChangeTime := exported.FormatSMBProperties(o.FileSMBProperties, true) - permission, permissionKey := o.FilePermissions.Format(shared.DefaultPreserveString) + permission, permissionKey := exported.FormatPermissions(o.FilePermissions) - setPropertiesOptions = &generated.DirectoryClientSetPropertiesOptions{ + setPropertiesOptions := &generated.DirectoryClientSetPropertiesOptions{ + FileAttributes: fileAttributes, + FileChangeTime: fileChangeTime, + FileCreationTime: fileCreationTime, + FileLastWriteTime: fileLastWriteTime, FilePermission: permission, FilePermissionKey: permissionKey, } - return + return setPropertiesOptions } // --------------------------------------------------------------------------------------------------------------------- diff --git a/sdk/storage/azfile/directory/responses.go b/sdk/storage/azfile/directory/responses.go index 28f2470b10ba..92bc742323cc 100644 --- a/sdk/storage/azfile/directory/responses.go +++ b/sdk/storage/azfile/directory/responses.go @@ -14,6 +14,11 @@ type CreateResponse = generated.DirectoryClientCreateResponse // DeleteResponse contains the response from method Client.Delete. type DeleteResponse = generated.DirectoryClientDeleteResponse +// RenameResponse contains the response from method Client.Rename. +type RenameResponse struct { + generated.DirectoryClientRenameResponse +} + // GetPropertiesResponse contains the response from method Client.GetProperties. type GetPropertiesResponse = generated.DirectoryClientGetPropertiesResponse diff --git a/sdk/storage/azfile/file/client.go b/sdk/storage/azfile/file/client.go index ad91fea6255a..f1d0d3232af8 100644 --- a/sdk/storage/azfile/file/client.go +++ b/sdk/storage/azfile/file/client.go @@ -10,6 +10,8 @@ import ( "bytes" "context" "errors" + "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/azcore/streaming" "github.com/Azure/azure-sdk-for-go/sdk/internal/log" @@ -32,6 +34,28 @@ type ClientOptions base.ClientOptions // Client represents a URL to the Azure Storage file. type Client base.Client[generated.FileClient] +// NewClient creates an instance of Client with the specified values. +// - fileURL - the URL of the file e.g. https://.file.core.windows.net/share/directoryPath/file +// - cred - an Azure AD credential, typically obtained via the azidentity module +// - options - client options; pass nil to accept the default values +// +// Note that ClientOptions.FileRequestIntent is currently required for token authentication. +func NewClient(fileURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) { + authPolicy := runtime.NewBearerTokenPolicy(cred, []string{shared.TokenScope}, nil) + conOptions := shared.GetClientOptions(options) + plOpts := runtime.PipelineOptions{ + PerRetry: []policy.Policy{authPolicy}, + } + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) + + azClient, err := azcore.NewClient(shared.FileClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewFileClient(fileURL, azClient, nil, (*base.ClientOptions)(conOptions))), nil +} + // NewClientWithNoCredential creates an instance of Client with the specified values. // This is used to anonymously access a file or with a shared access signature (SAS) token. // - fileURL - the URL of the file e.g. https://.file.core.windows.net/share/directoryPath/file? @@ -40,9 +64,15 @@ type Client base.Client[generated.FileClient] // The directoryPath is optional in the fileURL. If omitted, it points to file within the specified share. func NewClientWithNoCredential(fileURL string, options *ClientOptions) (*Client, error) { conOptions := shared.GetClientOptions(options) - pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions) + plOpts := runtime.PipelineOptions{} + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) - return (*Client)(base.NewFileClient(fileURL, pl, nil)), nil + azClient, err := azcore.NewClient(shared.FileClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewFileClient(fileURL, azClient, nil, (*base.ClientOptions)(conOptions))), nil } // NewClientWithSharedKeyCredential creates an instance of Client with the specified values. @@ -54,10 +84,17 @@ func NewClientWithNoCredential(fileURL string, options *ClientOptions) (*Client, func NewClientWithSharedKeyCredential(fileURL string, cred *SharedKeyCredential, options *ClientOptions) (*Client, error) { 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) + plOpts := runtime.PipelineOptions{ + PerRetry: []policy.Policy{authPolicy}, + } + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) + + azClient, err := azcore.NewClient(shared.FileClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } - return (*Client)(base.NewFileClient(fileURL, pl, cred)), nil + return (*Client)(base.NewFileClient(fileURL, azClient, cred, (*base.ClientOptions)(conOptions))), nil } // NewClientFromConnectionString creates an instance of Client with the specified values. @@ -93,6 +130,10 @@ func (f *Client) sharedKey() *SharedKeyCredential { return base.SharedKey((*base.Client[generated.FileClient])(f)) } +func (f *Client) getClientOptions() *base.ClientOptions { + return base.GetClientOptions((*base.Client[generated.FileClient])(f)) +} + // URL returns the URL endpoint used by the Client object. func (f *Client) URL() string { return f.generated().Endpoint() @@ -104,8 +145,8 @@ func (f *Client) URL() string { // ParseNTFSFileAttributes method can be used to convert the file attributes returned in response to NTFSFileAttributes. // For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/create-file. func (f *Client) Create(ctx context.Context, fileContentLength int64, options *CreateOptions) (CreateResponse, error) { - fileAttributes, fileCreationTime, fileLastWriteTime, fileCreateOptions, fileHTTPHeaders, leaseAccessConditions := options.format() - resp, err := f.generated().Create(ctx, fileContentLength, fileAttributes, fileCreationTime, fileLastWriteTime, fileCreateOptions, fileHTTPHeaders, leaseAccessConditions) + fileCreateOptions, fileHTTPHeaders, leaseAccessConditions := options.format() + resp, err := f.generated().Create(ctx, fileContentLength, fileCreateOptions, fileHTTPHeaders, leaseAccessConditions) return resp, err } @@ -117,6 +158,45 @@ func (f *Client) Delete(ctx context.Context, options *DeleteOptions) (DeleteResp return resp, err } +// Rename operation renames a file, and can optionally set system properties for the file. +// - destinationPath: the destination path to rename the file to. +// +// For more information, see https://learn.microsoft.com/rest/api/storageservices/rename-file. +func (f *Client) Rename(ctx context.Context, destinationPath string, options *RenameOptions) (RenameResponse, error) { + destinationPath = strings.Trim(strings.TrimSpace(destinationPath), "/") + if len(destinationPath) == 0 { + return RenameResponse{}, errors.New("destination path must not be empty") + } + + opts, srcLease, destLease, smbInfo, fileHTTPHeaders := options.format() + + urlParts, err := sas.ParseURL(f.URL()) + if err != nil { + return RenameResponse{}, err + } + + destParts := strings.Split(destinationPath, "?") + newDestPath := destParts[0] + newDestQuery := "" + if len(destParts) == 2 { + newDestQuery = destParts[1] + } + + urlParts.DirectoryOrFilePath = newDestPath + destURL := urlParts.String() + // replace the query part if it is present in destination path + if len(newDestQuery) > 0 { + destURL = strings.Split(destURL, "?")[0] + "?" + newDestQuery + } + + destFileClient := (*Client)(base.NewFileClient(destURL, f.generated().InternalClient(), f.sharedKey(), f.getClientOptions())) + + resp, err := destFileClient.generated().Rename(ctx, f.URL(), opts, srcLease, destLease, smbInfo, fileHTTPHeaders) + return RenameResponse{ + FileClientRenameResponse: resp, + }, err +} + // GetProperties operation returns all user-defined metadata, standard HTTP properties, and system properties for the file. // ParseNTFSFileAttributes method can be used to convert the file attributes returned in response to NTFSFileAttributes. // For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/get-file-properties. @@ -130,8 +210,8 @@ func (f *Client) GetProperties(ctx context.Context, options *GetPropertiesOption // ParseNTFSFileAttributes method can be used to convert the file attributes returned in response to NTFSFileAttributes. // For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/set-file-properties. func (f *Client) SetHTTPHeaders(ctx context.Context, options *SetHTTPHeadersOptions) (SetHTTPHeadersResponse, error) { - fileAttributes, fileCreationTime, fileLastWriteTime, opts, fileHTTPHeaders, leaseAccessConditions := options.format() - resp, err := f.generated().SetHTTPHeaders(ctx, fileAttributes, fileCreationTime, fileLastWriteTime, opts, fileHTTPHeaders, leaseAccessConditions) + opts, fileHTTPHeaders, leaseAccessConditions := options.format() + resp, err := f.generated().SetHTTPHeaders(ctx, opts, fileHTTPHeaders, leaseAccessConditions) return resp, err } @@ -166,8 +246,8 @@ func (f *Client) AbortCopy(ctx context.Context, copyID string, options *AbortCop // Resize operation resizes the file to the specified size. // For more information, see https://learn.microsoft.com/en-us/rest/api/storageservices/set-file-properties. func (f *Client) Resize(ctx context.Context, size int64, options *ResizeOptions) (ResizeResponse, error) { - fileAttributes, fileCreationTime, fileLastWriteTime, opts, leaseAccessConditions := options.format(size) - resp, err := f.generated().SetHTTPHeaders(ctx, fileAttributes, fileCreationTime, fileLastWriteTime, opts, nil, leaseAccessConditions) + opts, leaseAccessConditions := options.format(size) + resp, err := f.generated().SetHTTPHeaders(ctx, opts, nil, leaseAccessConditions) return resp, err } diff --git a/sdk/storage/azfile/file/client_test.go b/sdk/storage/azfile/file/client_test.go index 6b86ae745325..33911f4099f0 100644 --- a/sdk/storage/azfile/file/client_test.go +++ b/sdk/storage/azfile/file/client_test.go @@ -22,7 +22,9 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/fileerror" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/internal/testcommon" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/lease" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/sas" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/service" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/share" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -395,6 +397,7 @@ func (f *FileUnrecordedTestsSuite) TestFileGetSetPropertiesNonDefault() { creationTime := time.Now().Add(-time.Hour) lastWriteTime := time.Now().Add(-time.Minute * 15) + changeTime := time.Now().Add(-time.Minute * 30) options := &file.SetHTTPHeadersOptions{ Permissions: &file.Permissions{Permission: &testcommon.SampleSDDL}, @@ -402,6 +405,7 @@ func (f *FileUnrecordedTestsSuite) TestFileGetSetPropertiesNonDefault() { Attributes: &file.NTFSFileAttributes{Hidden: true}, CreationTime: &creationTime, LastWriteTime: &lastWriteTime, + ChangeTime: &changeTime, }, HTTPHeaders: &file.HTTPHeaders{ ContentType: to.Ptr("text/html"), @@ -450,6 +454,7 @@ func (f *FileUnrecordedTestsSuite) TestFileGetSetPropertiesNonDefault() { _require.EqualValues((*getResp.FileCreationTime).Format(testcommon.ISO8601), creationTime.UTC().Format(testcommon.ISO8601)) _require.EqualValues((*getResp.FileLastWriteTime).Format(testcommon.ISO8601), lastWriteTime.UTC().Format(testcommon.ISO8601)) + _require.EqualValues((*getResp.FileChangeTime).Format(testcommon.ISO8601), changeTime.UTC().Format(testcommon.ISO8601)) _require.NotNil(getResp.ETag) _require.NotNil(getResp.RequestID) @@ -488,7 +493,6 @@ func (f *FileRecordedTestsSuite) TestFileGetSetPropertiesDefault() { }) _require.NoError(err) - // get properties on the share snapshot getResp, err := fClient.GetProperties(context.Background(), nil) _require.NoError(err) _require.Equal(setResp.LastModified.IsZero(), false) @@ -535,6 +539,7 @@ func (f *FileRecordedTestsSuite) TestFilePreservePermissions() { pKey := getResp.FilePermissionKey cTime := getResp.FileCreationTime lwTime := getResp.FileLastWriteTime + changeTime := getResp.FileChangeTime attribs := getResp.FileAttributes md5Str := "MDAwMDAwMDA=" @@ -579,6 +584,7 @@ func (f *FileRecordedTestsSuite) TestFilePreservePermissions() { _require.EqualValues(getResp.FilePermissionKey, pKey) _require.EqualValues(cTime, getResp.FileCreationTime) _require.EqualValues(lwTime, getResp.FileLastWriteTime) + _require.NotEqualValues(changeTime, getResp.FileChangeTime) // default value is "now" for file change time _require.EqualValues(attribs, getResp.FileAttributes) _require.NotNil(getResp.ETag) @@ -1037,11 +1043,13 @@ func (f *FileRecordedTestsSuite) TestFileStartCopySourceCreationTime() { Attributes: &file.NTFSFileAttributes{ReadOnly: true, Hidden: true}, CreationTime: to.Ptr(currTime.Add(5 * time.Minute)), LastWriteTime: to.Ptr(currTime.Add(2 * time.Minute)), + ChangeTime: to.Ptr(currTime.Add(8 * time.Minute)), }, }) _require.NoError(err) _require.NotNil(cResp.FileCreationTime) _require.NotNil(cResp.FileLastWriteTime) + _require.NotNil(cResp.FileChangeTime) _require.NotNil(cResp.FileAttributes) _require.NotNil(cResp.FilePermissionKey) @@ -1064,6 +1072,7 @@ func (f *FileRecordedTestsSuite) TestFileStartCopySourceCreationTime() { _require.NoError(err) _require.EqualValues(resp2.FileCreationTime, cResp.FileCreationTime) _require.NotEqualValues(resp2.FileLastWriteTime, cResp.FileLastWriteTime) + _require.NotEqualValues(resp2.FileChangeTime, cResp.FileChangeTime) _require.NotEqualValues(resp2.FileAttributes, cResp.FileAttributes) } @@ -1088,11 +1097,13 @@ func (f *FileRecordedTestsSuite) TestFileStartCopySourceProperties() { Attributes: &file.NTFSFileAttributes{System: true}, CreationTime: to.Ptr(currTime.Add(1 * time.Minute)), LastWriteTime: to.Ptr(currTime.Add(2 * time.Minute)), + ChangeTime: to.Ptr(currTime.Add(5 * time.Minute)), }, }) _require.NoError(err) _require.NotNil(cResp.FileCreationTime) _require.NotNil(cResp.FileLastWriteTime) + _require.NotNil(cResp.FileChangeTime) _require.NotNil(cResp.FileAttributes) _require.NotNil(cResp.FilePermissionKey) @@ -1105,6 +1116,7 @@ func (f *FileRecordedTestsSuite) TestFileStartCopySourceProperties() { CopyFileSMBInfo: &file.CopyFileSMBInfo{ CreationTime: file.SourceCopyFileCreationTime{}, LastWriteTime: file.SourceCopyFileLastWriteTime{}, + ChangeTime: file.SourceCopyFileChangeTime{}, Attributes: file.SourceCopyFileAttributes{}, PermissionCopyMode: to.Ptr(file.PermissionCopyModeTypeSource), }, @@ -1117,6 +1129,7 @@ func (f *FileRecordedTestsSuite) TestFileStartCopySourceProperties() { _require.NoError(err) _require.EqualValues(resp2.FileCreationTime, cResp.FileCreationTime) _require.EqualValues(resp2.FileLastWriteTime, cResp.FileLastWriteTime) + _require.EqualValues(resp2.FileChangeTime, cResp.FileChangeTime) _require.EqualValues(resp2.FileAttributes, cResp.FileAttributes) _require.EqualValues(resp2.FilePermissionKey, cResp.FilePermissionKey) @@ -1148,20 +1161,24 @@ func (f *FileRecordedTestsSuite) TestFileStartCopyDifferentProperties() { Attributes: &file.NTFSFileAttributes{System: true}, CreationTime: to.Ptr(currTime.Add(1 * time.Minute)), LastWriteTime: to.Ptr(currTime.Add(2 * time.Minute)), + ChangeTime: to.Ptr(currTime.Add(3 * time.Minute)), }, }) _require.NoError(err) _require.NotNil(cResp.FileCreationTime) _require.NotNil(cResp.FileLastWriteTime) + _require.NotNil(cResp.FileChangeTime) _require.NotNil(cResp.FileAttributes) _require.NotNil(cResp.FilePermissionKey) destCreationTime := currTime.Add(5 * time.Minute) destLastWriteTIme := currTime.Add(6 * time.Minute) + destChangeTime := currTime.Add(7 * time.Minute) _, err = copyFClient.StartCopyFromURL(context.Background(), fClient.URL(), &file.StartCopyFromURLOptions{ CopyFileSMBInfo: &file.CopyFileSMBInfo{ CreationTime: file.DestinationCopyFileCreationTime(destCreationTime), LastWriteTime: file.DestinationCopyFileLastWriteTime(destLastWriteTIme), + ChangeTime: file.DestinationCopyFileChangeTime(destChangeTime), Attributes: file.DestinationCopyFileAttributes{ReadOnly: true}, }, }) @@ -1175,6 +1192,8 @@ func (f *FileRecordedTestsSuite) TestFileStartCopyDifferentProperties() { _require.EqualValues(*resp2.FileCreationTime, destCreationTime.UTC()) _require.NotEqualValues(resp2.FileLastWriteTime, cResp.FileLastWriteTime) _require.EqualValues(*resp2.FileLastWriteTime, destLastWriteTIme.UTC()) + _require.NotEqualValues(resp2.FileChangeTime, cResp.FileChangeTime) + _require.EqualValues(*resp2.FileChangeTime, destChangeTime.UTC()) _require.NotEqualValues(resp2.FileAttributes, cResp.FileAttributes) _require.EqualValues(resp2.FilePermissionKey, cResp.FilePermissionKey) } @@ -1196,6 +1215,7 @@ func (f *FileRecordedTestsSuite) TestFileStartCopyOverrideMode() { _require.NoError(err) _require.NotNil(cResp.FileCreationTime) _require.NotNil(cResp.FileLastWriteTime) + _require.NotNil(cResp.FileChangeTime) _require.NotNil(cResp.FileAttributes) _require.NotNil(cResp.FilePermissionKey) @@ -1215,6 +1235,7 @@ func (f *FileRecordedTestsSuite) TestFileStartCopyOverrideMode() { _require.NoError(err) _require.NotEqualValues(resp2.FileCreationTime, cResp.FileCreationTime) _require.NotEqualValues(resp2.FileLastWriteTime, cResp.FileLastWriteTime) + _require.NotEqualValues(resp2.FileChangeTime, cResp.FileChangeTime) _require.NotEqualValues(resp2.FilePermissionKey, cResp.FilePermissionKey) } @@ -1235,6 +1256,7 @@ func (f *FileRecordedTestsSuite) TestNegativeFileStartCopyOverrideMode() { _require.NoError(err) _require.NotNil(cResp.FileCreationTime) _require.NotNil(cResp.FileLastWriteTime) + _require.NotNil(cResp.FileChangeTime) _require.NotNil(cResp.FileAttributes) _require.NotNil(cResp.FilePermissionKey) @@ -1269,6 +1291,7 @@ func (f *FileRecordedTestsSuite) TestFileStartCopySetArchiveAttributeTrue() { _require.NoError(err) _require.NotNil(cResp.FileCreationTime) _require.NotNil(cResp.FileLastWriteTime) + _require.NotNil(cResp.FileChangeTime) _require.NotNil(cResp.FileAttributes) _require.NotNil(cResp.FilePermissionKey) @@ -1286,6 +1309,7 @@ func (f *FileRecordedTestsSuite) TestFileStartCopySetArchiveAttributeTrue() { _require.NoError(err) _require.NotEqualValues(resp2.FileCreationTime, cResp.FileCreationTime) _require.NotEqualValues(resp2.FileLastWriteTime, cResp.FileLastWriteTime) + _require.NotEqualValues(resp2.FileChangeTime, cResp.FileChangeTime) _require.Contains(*resp2.FileAttributes, "Archive") } @@ -1310,6 +1334,7 @@ func (f *FileRecordedTestsSuite) TestFileStartCopySetArchiveAttributeFalse() { _require.NoError(err) _require.NotNil(cResp.FileCreationTime) _require.NotNil(cResp.FileLastWriteTime) + _require.NotNil(cResp.FileChangeTime) _require.NotNil(cResp.FileAttributes) _require.NotNil(cResp.FilePermissionKey) @@ -1327,6 +1352,7 @@ func (f *FileRecordedTestsSuite) TestFileStartCopySetArchiveAttributeFalse() { _require.NoError(err) _require.NotEqualValues(resp2.FileCreationTime, cResp.FileCreationTime) _require.NotEqualValues(resp2.FileLastWriteTime, cResp.FileLastWriteTime) + _require.NotEqualValues(resp2.FileChangeTime, cResp.FileChangeTime) _require.NotContains(*resp2.FileAttributes, "Archive") } @@ -1347,6 +1373,7 @@ func (f *FileRecordedTestsSuite) TestFileStartCopyDestReadOnly() { _require.NoError(err) _require.NotNil(cResp.FileCreationTime) _require.NotNil(cResp.FileLastWriteTime) + _require.NotNil(cResp.FileChangeTime) _require.NotNil(cResp.FileAttributes) _require.NotNil(cResp.FilePermissionKey) @@ -1370,6 +1397,7 @@ func (f *FileRecordedTestsSuite) TestFileStartCopyDestReadOnly() { _require.NoError(err) _require.NotEqualValues(resp2.FileCreationTime, cResp.FileCreationTime) _require.NotEqualValues(resp2.FileLastWriteTime, cResp.FileLastWriteTime) + _require.NotEqualValues(resp2.FileChangeTime, cResp.FileChangeTime) } func (f *FileRecordedTestsSuite) TestNegativeFileStartCopyDestReadOnly() { @@ -1389,6 +1417,7 @@ func (f *FileRecordedTestsSuite) TestNegativeFileStartCopyDestReadOnly() { _require.NoError(err) _require.NotNil(cResp.FileCreationTime) _require.NotNil(cResp.FileLastWriteTime) + _require.NotNil(cResp.FileChangeTime) _require.NotNil(cResp.FileAttributes) _require.NotNil(cResp.FilePermissionKey) @@ -2537,6 +2566,58 @@ func (f *FileRecordedTestsSuite) TestFileUploadRangeIncorrectTransactionalMD5() testcommon.ValidateFileErrorCode(_require, err, fileerror.MD5Mismatch) } +func (f *FileRecordedTestsSuite) TestFileUploadRangeLastWrittenModePreserve() { + _require := require.New(f.T()) + testName := f.T().Name() + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fClient := testcommon.GetFileClientFromShare(testcommon.GenerateFileName(testName), shareClient) + cResp, err := fClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + _require.NotNil(cResp.FileLastWriteTime) + + contentR, _ := testcommon.GenerateData(2048) + + // Upload range with correct transactional MD5 + pResp, err := fClient.UploadRange(context.Background(), 0, contentR, &file.UploadRangeOptions{ + LastWrittenMode: to.Ptr(file.LastWrittenModePreserve), + }) + _require.NoError(err) + _require.NotNil(pResp.FileLastWriteTime) + _require.EqualValues(*pResp.FileLastWriteTime, *cResp.FileLastWriteTime) +} + +func (f *FileRecordedTestsSuite) TestFileUploadRangeLastWrittenModeNow() { + _require := require.New(f.T()) + testName := f.T().Name() + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fClient := testcommon.GetFileClientFromShare(testcommon.GenerateFileName(testName), shareClient) + cResp, err := fClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + _require.NotNil(cResp.FileLastWriteTime) + + contentR, _ := testcommon.GenerateData(2048) + + // Upload range with correct transactional MD5 + pResp, err := fClient.UploadRange(context.Background(), 0, contentR, &file.UploadRangeOptions{ + LastWrittenMode: to.Ptr(file.LastWrittenModeNow), + }) + _require.NoError(err) + _require.NotNil(pResp.FileLastWriteTime) + _require.NotEqualValues(*pResp.FileLastWriteTime, *cResp.FileLastWriteTime) +} + // Testings for GetRangeList and ClearRange func (f *FileRecordedTestsSuite) TestGetRangeListNonDefaultExact() { _require := require.New(f.T()) @@ -2850,7 +2931,8 @@ func (f *FileRecordedTestsSuite) TestFileGetRangeListSnapshot() { fileSize := int64(512) fClient := setupGetRangeListTest(_require, testName, fileSize, shareClient) - resp, _ := shareClient.CreateSnapshot(context.Background(), nil) + resp, err := shareClient.CreateSnapshot(context.Background(), nil) + _require.NoError(err) _require.NotNil(resp.Snapshot) resp2, err := fClient.GetRangeList(context.Background(), &file.GetRangeListOptions{ @@ -3152,4 +3234,1036 @@ func (f *FileRecordedTestsSuite) TestFileForceCloseHandlesDefault() { _require.Nil(resp.Marker) } +func (f *FileRecordedTestsSuite) TestFileCreateDeleteUsingOAuth() { + _require := require.New(f.T()) + testName := f.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName := testcommon.GenerateFileName(testName) + fileURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + fileName + + options := &file.ClientOptions{FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup)} + testcommon.SetClientOptions(f.T(), &options.ClientOptions) + fileClient, err := file.NewClient(fileURL, cred, options) + _require.NoError(err) + + resp, err := fileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + _require.NotNil(resp.ETag) + _require.NotNil(resp.RequestID) + _require.Equal(resp.LastModified.IsZero(), false) + _require.Equal(resp.FileCreationTime.IsZero(), false) + _require.Equal(resp.FileLastWriteTime.IsZero(), false) + _require.Equal(resp.FileChangeTime.IsZero(), false) + + gResp, err := fileClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.NotNil(gResp.FileCreationTime) + _require.NotNil(gResp.FileLastWriteTime) + _require.NotNil(gResp.FilePermissionKey) + _require.Equal(*gResp.ContentLength, int64(2048)) + + dResp, err := fileClient.Delete(context.Background(), nil) + _require.NoError(err) + _require.Equal(dResp.Date.IsZero(), false) + _require.NotNil(dResp.RequestID) + _require.NotNil(dResp.Version) + + _, err = fileClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (f *FileRecordedTestsSuite) TestFileGetSetPropertiesUsingOAuth() { + _require := require.New(f.T()) + testName := f.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName := testcommon.GenerateFileName(testName) + fileURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + fileName + + clOptions := &file.ClientOptions{FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup)} + testcommon.SetClientOptions(f.T(), &clOptions.ClientOptions) + fClient, err := file.NewClient(fileURL, cred, clOptions) + _require.NoError(err) + + _, err = fClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + md5Str := "MDAwMDAwMDA=" + testMd5 := []byte(md5Str) + + options := &file.SetHTTPHeadersOptions{ + Permissions: &file.Permissions{Permission: &testcommon.SampleSDDL}, + SMBProperties: &file.SMBProperties{ + Attributes: &file.NTFSFileAttributes{Hidden: true, ReadOnly: true}, + }, + HTTPHeaders: &file.HTTPHeaders{ + ContentType: to.Ptr("text/html"), + ContentEncoding: to.Ptr("gzip"), + ContentLanguage: to.Ptr("en"), + ContentMD5: testMd5, + CacheControl: to.Ptr("no-transform"), + ContentDisposition: to.Ptr("attachment"), + }, + } + setResp, err := fClient.SetHTTPHeaders(context.Background(), options) + _require.NoError(err) + _require.NotNil(setResp.ETag) + _require.Equal(setResp.LastModified.IsZero(), false) + _require.NotNil(setResp.RequestID) + _require.NotNil(setResp.Version) + _require.Equal(setResp.Date.IsZero(), false) + _require.NotNil(setResp.IsServerEncrypted) + + fileAttributes, err := file.ParseNTFSFileAttributes(setResp.FileAttributes) + _require.NoError(err) + _require.NotNil(fileAttributes) + _require.True(fileAttributes.Hidden) + _require.True(fileAttributes.ReadOnly) + + getResp, err := fClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.Equal(getResp.LastModified.IsZero(), false) + _require.Equal(*getResp.FileType, "File") + + _require.EqualValues(getResp.ContentType, options.HTTPHeaders.ContentType) + _require.EqualValues(getResp.ContentEncoding, options.HTTPHeaders.ContentEncoding) + _require.EqualValues(getResp.ContentLanguage, options.HTTPHeaders.ContentLanguage) + _require.EqualValues(getResp.ContentMD5, options.HTTPHeaders.ContentMD5) + _require.EqualValues(getResp.CacheControl, options.HTTPHeaders.CacheControl) + _require.EqualValues(getResp.ContentDisposition, options.HTTPHeaders.ContentDisposition) + _require.Equal(*getResp.ContentLength, int64(2048)) + _require.NotEqual(getResp.FilePermissionKey, "") + + fileAttributes2, err := file.ParseNTFSFileAttributes(getResp.FileAttributes) + _require.NoError(err) + _require.NotNil(fileAttributes2) + _require.True(fileAttributes2.Hidden) + _require.True(fileAttributes2.ReadOnly) + _require.EqualValues(fileAttributes, fileAttributes2) + _require.NotNil(getResp.ETag) + _require.NotNil(getResp.RequestID) + _require.NotNil(getResp.Version) + _require.Equal(getResp.Date.IsZero(), false) + _require.NotNil(getResp.IsServerEncrypted) +} + +func (f *FileRecordedTestsSuite) TestFileSetMetadataUsingOAuth() { + _require := require.New(f.T()) + testName := f.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName := testcommon.GenerateFileName(testName) + fileURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + fileName + + options := &file.ClientOptions{FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup)} + testcommon.SetClientOptions(f.T(), &options.ClientOptions) + fileClient, err := file.NewClient(fileURL, cred, options) + _require.NoError(err) + + _, err = fileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + metadata := map[string]*string{ + "Foo": to.Ptr("Foovalue"), + "Bar": to.Ptr("Barvalue"), + } + _, err = fileClient.SetMetadata(context.Background(), &file.SetMetadataOptions{ + Metadata: metadata, + }) + _require.NoError(err) + + getResp, err := fileClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.Equal(*getResp.ContentLength, int64(2048)) + _require.EqualValues(getResp.Metadata, metadata) +} + +func (f *FileRecordedTestsSuite) TestFileUploadClearListRangeUsingOAuth() { + _require := require.New(f.T()) + testName := f.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName := testcommon.GenerateFileName(testName) + fileURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + fileName + + options := &file.ClientOptions{FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup)} + testcommon.SetClientOptions(f.T(), &options.ClientOptions) + fileClient, err := file.NewClient(fileURL, cred, options) + _require.NoError(err) + + _, err = fileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + contentSize := 1024 * 2 // 2KB + contentR, contentD := testcommon.GenerateData(contentSize) + md5Value := md5.Sum(contentD) + contentMD5 := md5Value[:] + + uResp, err := fileClient.UploadRange(context.Background(), 0, contentR, &file.UploadRangeOptions{ + TransactionalValidation: file.TransferValidationTypeMD5(contentMD5), + }) + _require.NoError(err) + _require.NotNil(uResp.ContentMD5) + _require.EqualValues(uResp.ContentMD5, contentMD5) + + rangeList, err := fileClient.GetRangeList(context.Background(), nil) + _require.NoError(err) + _require.Len(rangeList.Ranges, 1) + _require.EqualValues(*rangeList.Ranges[0], file.ShareFileRange{Start: to.Ptr(int64(0)), End: to.Ptr(int64(contentSize - 1))}) + + cResp, err := fileClient.ClearRange(context.Background(), file.HTTPRange{Offset: 0, Count: int64(contentSize)}, nil) + _require.NoError(err) + _require.Nil(cResp.ContentMD5) + + rangeList2, err := fileClient.GetRangeList(context.Background(), nil) + _require.NoError(err) + _require.Len(rangeList2.Ranges, 0) +} + +func (f *FileRecordedTestsSuite) TestFileRenameDefault() { + _require := require.New(f.T()) + testName := f.T().Name() + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + srcFileClient := testcommon.CreateNewFileFromShare(context.Background(), _require, testcommon.GenerateFileName(testName), 2048, shareClient) + + resp, err := srcFileClient.Rename(context.Background(), "testFile", nil) + _require.NoError(err) + _require.NotNil(resp.ETag) + _require.NotNil(resp.RequestID) + _require.Equal(resp.LastModified.IsZero(), false) + _require.Equal(resp.FileCreationTime.IsZero(), false) + _require.Equal(resp.FileLastWriteTime.IsZero(), false) + _require.Equal(resp.FileChangeTime.IsZero(), false) + + _, err = srcFileClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (f *FileRecordedTestsSuite) TestFileRenameUsingOAuth() { + _require := require.New(f.T()) + testName := f.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName := testcommon.GenerateFileName(testName) + fileURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + fileName + + options := &file.ClientOptions{FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup)} + testcommon.SetClientOptions(f.T(), &options.ClientOptions) + srcFileClient, err := file.NewClient(fileURL, cred, options) + _require.NoError(err) + + _, err = srcFileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + resp, err := srcFileClient.Rename(context.Background(), "testFile", nil) + _require.NoError(err) + _require.NotNil(resp.ETag) + _require.NotNil(resp.RequestID) + _require.Equal(resp.LastModified.IsZero(), false) + _require.Equal(resp.FileCreationTime.IsZero(), false) + _require.Equal(resp.FileLastWriteTime.IsZero(), false) + _require.Equal(resp.FileChangeTime.IsZero(), false) + + _, err = srcFileClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (f *FileRecordedTestsSuite) TestFileRenameDifferentDir() { + _require := require.New(f.T()) + testName := f.T().Name() + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + srcDirCl := testcommon.CreateNewDirectory(context.Background(), _require, "dir1", shareClient) + + srcFileClient := srcDirCl.NewFileClient("file1") + _, err = srcFileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + _ = testcommon.CreateNewDirectory(context.Background(), _require, "dir2", shareClient) + + _, err = srcFileClient.Rename(context.Background(), "dir2/file2/", nil) + _require.NoError(err) + + _, err = srcFileClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (f *FileRecordedTestsSuite) TestFileRenameIgnoreReadOnly() { + _require := require.New(f.T()) + testName := f.T().Name() + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + srcFileClient := testcommon.CreateNewFileFromShare(context.Background(), _require, "file1", 2048, shareClient) + + _, err = shareClient.NewRootDirectoryClient().NewFileClient("file2").Create(context.Background(), 1024, &file.CreateOptions{ + SMBProperties: &file.SMBProperties{ + Attributes: &file.NTFSFileAttributes{ReadOnly: true}, + }, + }) + _require.NoError(err) + + _, err = srcFileClient.Rename(context.Background(), "file2", nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceAlreadyExists) + + _, err = srcFileClient.Rename(context.Background(), "file2", &file.RenameOptions{ + ReplaceIfExists: to.Ptr(true), + }) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ReadOnlyAttribute) + + _, err = srcFileClient.Rename(context.Background(), "file2", &file.RenameOptions{ + ReplaceIfExists: to.Ptr(true), + IgnoreReadOnly: to.Ptr(true), + }) + _require.NoError(err) + + _, err = srcFileClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (f *FileRecordedTestsSuite) TestFileRenameNonDefault() { + _require := require.New(f.T()) + testName := f.T().Name() + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + srcFileClient := testcommon.CreateNewFileFromShare(context.Background(), _require, "file1", 2048, shareClient) + + currTime, err := time.Parse(time.UnixDate, "Fri Mar 31 21:00:00 GMT 2023") + _require.NoError(err) + creationTime := currTime.Add(5 * time.Minute).Round(time.Microsecond) + lastWriteTime := currTime.Add(8 * time.Minute).Round(time.Millisecond) + changeTime := currTime.Add(10 * time.Minute).Round(time.Millisecond) + + md := map[string]*string{ + "Foo": to.Ptr("FooValuE"), + "Bar": to.Ptr("bArvaLue"), + } + + renameOptions := file.RenameOptions{ + SMBProperties: &file.SMBProperties{ + Attributes: &file.NTFSFileAttributes{ + ReadOnly: true, + System: true, + }, + CreationTime: &creationTime, + LastWriteTime: &lastWriteTime, + ChangeTime: &changeTime, + }, + Permissions: &file.Permissions{ + Permission: &testcommon.SampleSDDL, + }, + Metadata: md, + ContentType: to.Ptr("my_type"), + } + + resp, err := srcFileClient.Rename(context.Background(), "file2", &renameOptions) + _require.NoError(err) + _require.NotNil(resp.FileCreationTime) + _require.Equal(*resp.FileCreationTime, creationTime.UTC()) + _require.NotNil(resp.FileLastWriteTime) + _require.Equal(*resp.FileLastWriteTime, lastWriteTime.UTC()) + _require.NotNil(resp.FileChangeTime) + _require.Equal(*resp.FileChangeTime, changeTime.UTC()) + _require.NotNil(resp.FilePermissionKey) + + fileAttributes, err := file.ParseNTFSFileAttributes(resp.FileAttributes) + _require.NoError(err) + _require.NotNil(fileAttributes) + _require.True(fileAttributes.ReadOnly) + _require.True(fileAttributes.System) +} + +func (f *FileRecordedTestsSuite) TestFileRenameSrcDestLease() { + _require := require.New(f.T()) + testName := f.T().Name() + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareClient := testcommon.CreateNewShare(context.Background(), _require, testcommon.GenerateShareName(testName), svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + srcFileClient := testcommon.CreateNewFileFromShare(context.Background(), _require, "file1", 2048, shareClient) + destFileClient := testcommon.CreateNewFileFromShare(context.Background(), _require, "file2", 2048, shareClient) + + var proposedLeaseIDs = []*string{to.Ptr("c820a799-76d7-4ee2-6e15-546f19325c2c"), to.Ptr("326cc5e1-746e-4af8-4811-a50e6629a8ca")} + + // acquire lease on source file + srcFileLeaseClient, err := lease.NewFileClient(srcFileClient, &lease.FileClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + _require.NoError(err) + srcAcqResp, err := srcFileLeaseClient.Acquire(context.Background(), nil) + _require.NoError(err) + _require.NotNil(srcAcqResp.LeaseID) + _require.Equal(*srcAcqResp.LeaseID, *proposedLeaseIDs[0]) + + // acquire lease on destination file + destFileLeaseClient, err := lease.NewFileClient(destFileClient, &lease.FileClientOptions{ + LeaseID: proposedLeaseIDs[1], + }) + _require.NoError(err) + destAcqResp, err := destFileLeaseClient.Acquire(context.Background(), nil) + _require.NoError(err) + _require.NotNil(destAcqResp.LeaseID) + _require.Equal(*destAcqResp.LeaseID, *proposedLeaseIDs[1]) + + _, err = srcFileClient.Rename(context.Background(), "file2", &file.RenameOptions{ + ReplaceIfExists: to.Ptr(true), + }) + _require.Error(err) + + _, err = srcFileClient.Rename(context.Background(), "file2", &file.RenameOptions{ + ReplaceIfExists: to.Ptr(true), + SourceLeaseAccessConditions: &file.SourceLeaseAccessConditions{ + SourceLeaseID: srcAcqResp.LeaseID, + }, + DestinationLeaseAccessConditions: &file.DestinationLeaseAccessConditions{ + DestinationLeaseID: destAcqResp.LeaseID, + }, + }) + _require.NoError(err) + + _, err = srcFileClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (f *FileUnrecordedTestsSuite) TestFileRenameUsingSAS() { + _require := require.New(f.T()) + testName := f.T().Name() + + cred, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + perms := sas.FilePermissions{Read: true, Create: true, Write: true} + sasQueryParams, err := sas.SignatureValues{ + Protocol: sas.ProtocolHTTPS, // Users MUST use HTTPS (not HTTP) + ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration + ShareName: shareName, + Permissions: perms.String(), + }.SignWithSharedKey(cred) + _require.NoError(err) + + sasToken := sasQueryParams.Encode() + + srcFileClient, err := file.NewClientWithNoCredential(shareClient.URL()+"/file1?"+sasToken, nil) + _require.NoError(err) + + _, err = srcFileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + destPathWithSAS := "file2?" + sasToken + _, err = srcFileClient.Rename(context.Background(), destPathWithSAS, nil) + _require.NoError(err) + + _, err = srcFileClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (f *FileRecordedTestsSuite) TestFileCreateDeleteTrailingDot() { + _require := require.New(f.T()) + testName := f.T().Name() + + options := &service.ClientOptions{AllowTrailingDot: to.Ptr(true)} + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, options) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName := "file.." + fileClient := testcommon.CreateNewFileFromShare(context.Background(), _require, fileName, 2048, shareClient) + + _, err = fileClient.GetProperties(context.Background(), nil) + _require.NoError(err) + + _, err = fileClient.Delete(context.Background(), nil) + _require.NoError(err) + + _, err = fileClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (f *FileRecordedTestsSuite) TestFileGetSetPropertiesTrailingDotOAuth() { + _require := require.New(f.T()) + testName := f.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName := "file.." + fileURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + fileName + + clOptions := &file.ClientOptions{ + FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup), + AllowTrailingDot: to.Ptr(true), + } + testcommon.SetClientOptions(f.T(), &clOptions.ClientOptions) + fClient, err := file.NewClient(fileURL, cred, clOptions) + _require.NoError(err) + + _, err = fClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + md5Str := "MDAwMDAwMDA=" + testMd5 := []byte(md5Str) + + options := &file.SetHTTPHeadersOptions{ + Permissions: &file.Permissions{Permission: &testcommon.SampleSDDL}, + SMBProperties: &file.SMBProperties{ + Attributes: &file.NTFSFileAttributes{Hidden: true, ReadOnly: true}, + }, + HTTPHeaders: &file.HTTPHeaders{ + ContentType: to.Ptr("text/html"), + ContentEncoding: to.Ptr("gzip"), + ContentLanguage: to.Ptr("en"), + ContentMD5: testMd5, + CacheControl: to.Ptr("no-transform"), + ContentDisposition: to.Ptr("attachment"), + }, + } + setResp, err := fClient.SetHTTPHeaders(context.Background(), options) + _require.NoError(err) + _require.NotNil(setResp.ETag) + _require.Equal(setResp.LastModified.IsZero(), false) + _require.NotNil(setResp.RequestID) + _require.NotNil(setResp.Version) + _require.Equal(setResp.Date.IsZero(), false) + _require.NotNil(setResp.IsServerEncrypted) + + fileAttributes, err := file.ParseNTFSFileAttributes(setResp.FileAttributes) + _require.NoError(err) + _require.NotNil(fileAttributes) + _require.True(fileAttributes.Hidden) + _require.True(fileAttributes.ReadOnly) + + getResp, err := fClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.Equal(getResp.LastModified.IsZero(), false) + _require.Equal(*getResp.FileType, "File") + + _require.EqualValues(getResp.ContentType, options.HTTPHeaders.ContentType) + _require.EqualValues(getResp.ContentEncoding, options.HTTPHeaders.ContentEncoding) + _require.EqualValues(getResp.ContentLanguage, options.HTTPHeaders.ContentLanguage) + _require.EqualValues(getResp.ContentMD5, options.HTTPHeaders.ContentMD5) + _require.EqualValues(getResp.CacheControl, options.HTTPHeaders.CacheControl) + _require.EqualValues(getResp.ContentDisposition, options.HTTPHeaders.ContentDisposition) + _require.Equal(*getResp.ContentLength, int64(2048)) + _require.NotEqual(getResp.FilePermissionKey, "") + + fileAttributes2, err := file.ParseNTFSFileAttributes(getResp.FileAttributes) + _require.NoError(err) + _require.NotNil(fileAttributes2) + _require.True(fileAttributes2.Hidden) + _require.True(fileAttributes2.ReadOnly) + _require.EqualValues(fileAttributes, fileAttributes2) + _require.NotNil(getResp.ETag) + _require.NotNil(getResp.RequestID) + _require.NotNil(getResp.Version) + _require.Equal(getResp.Date.IsZero(), false) + _require.NotNil(getResp.IsServerEncrypted) +} + +func (f *FileRecordedTestsSuite) TestFileSetMetadataTrailingDot() { + _require := require.New(f.T()) + testName := f.T().Name() + + options := &service.ClientOptions{AllowTrailingDot: to.Ptr(true)} + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, options) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName := "file.." + fileClient := testcommon.CreateNewFileFromShare(context.Background(), _require, fileName, 2048, shareClient) + + metadata := map[string]*string{ + "Foo": to.Ptr("Foovalue"), + "Bar": to.Ptr("Barvalue"), + } + _, err = fileClient.SetMetadata(context.Background(), &file.SetMetadataOptions{ + Metadata: metadata, + }) + _require.NoError(err) + + getResp, err := fileClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.Equal(*getResp.ContentLength, int64(2048)) + _require.EqualValues(getResp.Metadata, metadata) +} + +func (f *FileRecordedTestsSuite) TestFileUploadClearListRangeTrailingDotOAuth() { + _require := require.New(f.T()) + testName := f.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName := testcommon.GenerateFileName(testName) + ".." + fileURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + fileName + + options := &file.ClientOptions{ + FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup), + AllowTrailingDot: to.Ptr(true), + } + testcommon.SetClientOptions(f.T(), &options.ClientOptions) + fileClient, err := file.NewClient(fileURL, cred, options) + _require.NoError(err) + + _, err = fileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + contentSize := 1024 * 2 // 2KB + contentR, contentD := testcommon.GenerateData(contentSize) + md5Value := md5.Sum(contentD) + contentMD5 := md5Value[:] + + uResp, err := fileClient.UploadRange(context.Background(), 0, contentR, &file.UploadRangeOptions{ + TransactionalValidation: file.TransferValidationTypeMD5(contentMD5), + }) + _require.NoError(err) + _require.NotNil(uResp.ContentMD5) + _require.EqualValues(uResp.ContentMD5, contentMD5) + + rangeList, err := fileClient.GetRangeList(context.Background(), nil) + _require.NoError(err) + _require.Len(rangeList.Ranges, 1) + _require.EqualValues(*rangeList.Ranges[0], file.ShareFileRange{Start: to.Ptr(int64(0)), End: to.Ptr(int64(contentSize - 1))}) + + cResp, err := fileClient.ClearRange(context.Background(), file.HTTPRange{Offset: 0, Count: int64(contentSize)}, nil) + _require.NoError(err) + _require.Nil(cResp.ContentMD5) + + rangeList2, err := fileClient.GetRangeList(context.Background(), nil) + _require.NoError(err) + _require.Len(rangeList2.Ranges, 0) +} + +func (f *FileRecordedTestsSuite) TestFileRenameTrailingDotOAuth() { + _require := require.New(f.T()) + testName := f.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName := testcommon.GenerateFileName(testName) + ".." + fileURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + fileName + + options := &file.ClientOptions{ + FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup), + AllowTrailingDot: to.Ptr(true), + AllowSourceTrailingDot: to.Ptr(true), + } + testcommon.SetClientOptions(f.T(), &options.ClientOptions) + srcFileClient, err := file.NewClient(fileURL, cred, options) + _require.NoError(err) + + _, err = srcFileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + _, err = srcFileClient.Rename(context.Background(), "file..", nil) + _require.NoError(err) + + _, err = srcFileClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (f *FileRecordedTestsSuite) TestFileRenameNegativeSourceTrailingDot() { + _require := require.New(f.T()) + testName := f.T().Name() + + options := &service.ClientOptions{ + AllowTrailingDot: to.Ptr(true), + } + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, options) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + fileName := testcommon.GenerateFileName(testName) + ".." + srcFileClient := testcommon.CreateNewFileFromShare(context.Background(), _require, fileName, 2048, shareClient) + + _, err = srcFileClient.Rename(context.Background(), "file..", nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.ResourceNotFound) +} + +func (f *FileUnrecordedTestsSuite) TestFileUploadRangeFromURLTrailingDot() { + _require := require.New(f.T()) + testName := f.T().Name() + + cred, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.NoError(err) + + options := &service.ClientOptions{ + AllowTrailingDot: to.Ptr(true), + AllowSourceTrailingDot: to.Ptr(true), + } + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, options) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + var fileSize int64 = 1024 * 10 + contentSize := 1024 * 8 // 8KB + rsc, content := testcommon.GenerateData(contentSize) + contentCRC64 := crc64.Checksum(content, shared.CRC64Table) + + srcFileName := "srcFile.." + srcFClient := testcommon.CreateNewFileFromShare(context.Background(), _require, srcFileName, fileSize, shareClient) + _, err = srcFClient.UploadRange(context.Background(), 0, rsc, nil) + _require.NoError(err) + + perms := sas.FilePermissions{Read: true, Write: true} + sasQueryParams, err := sas.SignatureValues{ + //Protocol: sas.ProtocolHTTPS, + ExpiryTime: time.Now().UTC().Add(1 * time.Hour), + ShareName: shareName, + FilePath: srcFileName, + Permissions: perms.String(), + }.SignWithSharedKey(cred) + _require.NoError(err) + + srcFileSAS := srcFClient.URL() + "?" + sasQueryParams.Encode() + + destFClient := testcommon.CreateNewFileFromShare(context.Background(), _require, "destFile..", fileSize, shareClient) + + uResp, err := destFClient.UploadRangeFromURL(context.Background(), srcFileSAS, 0, 0, int64(contentSize), &file.UploadRangeFromURLOptions{ + SourceContentCRC64: contentCRC64, + }) + _require.NoError(err) + _require.NotNil(uResp.XMSContentCRC64) + _require.EqualValues(binary.LittleEndian.Uint64(uResp.XMSContentCRC64), contentCRC64) + + // validate the content uploaded + dResp, err := destFClient.DownloadStream(context.Background(), &file.DownloadStreamOptions{ + Range: file.HTTPRange{Offset: 0, Count: int64(contentSize)}, + }) + _require.NoError(err) + + data, err := ioutil.ReadAll(dResp.Body) + defer func() { + err = dResp.Body.Close() + _require.NoError(err) + }() + + _require.EqualValues(data, content) +} + +func (f *FileRecordedTestsSuite) TestStartCopyTrailingDotOAuth() { + _require := require.New(f.T()) + testName := f.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + clOptions := &file.ClientOptions{ + FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup), + AllowTrailingDot: to.Ptr(true), + AllowSourceTrailingDot: to.Ptr(true), + } + testcommon.SetClientOptions(f.T(), &clOptions.ClientOptions) + + srcFileName, destFileName := "srcFile..", "destFile.." + srcFileClient, err := file.NewClient(fmt.Sprintf("https://%s.file.core.windows.net/%s/%s", accountName, shareName, srcFileName), cred, clOptions) + _require.NoError(err) + destFileClient, err := file.NewClient(fmt.Sprintf("https://%s.file.core.windows.net/%s/%s", accountName, shareName, destFileName), cred, clOptions) + _require.NoError(err) + + fileSize := int64(2048) + _, err = srcFileClient.Create(context.Background(), fileSize, nil) + _require.NoError(err) + + contentR, srcContent := testcommon.GenerateData(int(fileSize)) + srcContentMD5 := md5.Sum(srcContent) + + _, err = srcFileClient.UploadRange(context.Background(), 0, contentR, nil) + _require.NoError(err) + + copyResp, err := destFileClient.StartCopyFromURL(context.Background(), srcFileClient.URL(), nil) + _require.NoError(err) + _require.NotEqual(copyResp.CopyStatus, "") + + time.Sleep(time.Duration(5) * time.Second) + + getResp, err := destFileClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.EqualValues(getResp.CopyID, copyResp.CopyID) + _require.NotEqual(*getResp.CopyStatus, "") + _require.Equal(*getResp.CopySource, srcFileClient.URL()) + _require.Equal(*getResp.CopyStatus, file.CopyStatusTypeSuccess) + + // validate data copied + dResp, err := destFileClient.DownloadStream(context.Background(), &file.DownloadStreamOptions{ + Range: file.HTTPRange{Offset: 0, Count: fileSize}, + RangeGetContentMD5: to.Ptr(true), + }) + _require.NoError(err) + + destContent, err := io.ReadAll(dResp.Body) + _require.NoError(err) + _require.EqualValues(srcContent, destContent) + _require.Equal(dResp.ContentMD5, srcContentMD5[:]) + + fileAttributes, err := file.ParseNTFSFileAttributes(dResp.FileAttributes) + _require.NoError(err) + _require.NotNil(fileAttributes) +} + +func (f *FileUnrecordedTestsSuite) TestFileUploadRangeFromURLPreserve() { + _require := require.New(f.T()) + testName := f.T().Name() + + cred, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + var fileSize int64 = 1024 * 20 + srcFileName := "src" + testcommon.GenerateFileName(testName) + srcFClient := testcommon.CreateNewFileFromShare(context.Background(), _require, srcFileName, fileSize, shareClient) + + contentSize := 1024 * 8 // 8KB + content := make([]byte, contentSize) + body := bytes.NewReader(content) + rsc := streaming.NopCloser(body) + contentCRC64 := crc64.Checksum(content, shared.CRC64Table) + + _, err = srcFClient.UploadRange(context.Background(), 0, rsc, nil) + _require.NoError(err) + + perms := sas.FilePermissions{Read: true, Write: true} + sasQueryParams, err := sas.SignatureValues{ + Protocol: sas.ProtocolHTTPS, + ExpiryTime: time.Now().UTC().Add(1 * time.Hour), + ShareName: shareName, + FilePath: srcFileName, + Permissions: perms.String(), + }.SignWithSharedKey(cred) + _require.NoError(err) + + srcFileSAS := srcFClient.URL() + "?" + sasQueryParams.Encode() + + destFClient := testcommon.GetFileClientFromShare("dest"+testcommon.GenerateFileName(testName), shareClient) + cResp, err := destFClient.Create(context.Background(), fileSize, nil) + _require.NoError(err) + _require.NotNil(cResp.FileLastWriteTime) + + uResp, err := destFClient.UploadRangeFromURL(context.Background(), srcFileSAS, 0, 0, int64(contentSize), &file.UploadRangeFromURLOptions{ + SourceContentCRC64: contentCRC64, + LastWrittenMode: to.Ptr(file.LastWrittenModePreserve), + }) + _require.NoError(err) + _require.NotNil(uResp.XMSContentCRC64) + _require.EqualValues(binary.LittleEndian.Uint64(uResp.XMSContentCRC64), contentCRC64) + _require.NotNil(uResp.FileLastWriteTime) + _require.EqualValues(*uResp.FileLastWriteTime, *cResp.FileLastWriteTime) +} + +func (f *FileUnrecordedTestsSuite) TestFileUploadRangeFromURLNow() { + _require := require.New(f.T()) + testName := f.T().Name() + + cred, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(f.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + var fileSize int64 = 1024 * 20 + srcFileName := "src" + testcommon.GenerateFileName(testName) + srcFClient := testcommon.CreateNewFileFromShare(context.Background(), _require, srcFileName, fileSize, shareClient) + + contentSize := 1024 * 8 // 8KB + content := make([]byte, contentSize) + body := bytes.NewReader(content) + rsc := streaming.NopCloser(body) + contentCRC64 := crc64.Checksum(content, shared.CRC64Table) + + _, err = srcFClient.UploadRange(context.Background(), 0, rsc, nil) + _require.NoError(err) + + perms := sas.FilePermissions{Read: true, Write: true} + sasQueryParams, err := sas.SignatureValues{ + Protocol: sas.ProtocolHTTPS, + ExpiryTime: time.Now().UTC().Add(1 * time.Hour), + ShareName: shareName, + FilePath: srcFileName, + Permissions: perms.String(), + }.SignWithSharedKey(cred) + _require.NoError(err) + + srcFileSAS := srcFClient.URL() + "?" + sasQueryParams.Encode() + + destFClient := testcommon.GetFileClientFromShare("dest"+testcommon.GenerateFileName(testName), shareClient) + cResp, err := destFClient.Create(context.Background(), fileSize, nil) + _require.NoError(err) + _require.NotNil(cResp.FileLastWriteTime) + + uResp, err := destFClient.UploadRangeFromURL(context.Background(), srcFileSAS, 0, 0, int64(contentSize), &file.UploadRangeFromURLOptions{ + SourceContentCRC64: contentCRC64, + LastWrittenMode: to.Ptr(file.LastWrittenModeNow), + }) + _require.NoError(err) + _require.NotNil(uResp.XMSContentCRC64) + _require.EqualValues(binary.LittleEndian.Uint64(uResp.XMSContentCRC64), contentCRC64) + _require.NotNil(uResp.FileLastWriteTime) + _require.NotEqualValues(*uResp.FileLastWriteTime, *cResp.FileLastWriteTime) +} + // TODO: Add tests for retry header options diff --git a/sdk/storage/azfile/file/constants.go b/sdk/storage/azfile/file/constants.go index c5687bd1b3b5..6738fe709fba 100644 --- a/sdk/storage/azfile/file/constants.go +++ b/sdk/storage/azfile/file/constants.go @@ -76,3 +76,28 @@ type TransferValidationType = exported.TransferValidationType // TransferValidationTypeMD5 is a TransferValidationType used to provide a precomputed MD5. type TransferValidationTypeMD5 = exported.TransferValidationTypeMD5 + +// ShareTokenIntent is required if authorization header specifies an OAuth token. +type ShareTokenIntent = generated.ShareTokenIntent + +const ( + ShareTokenIntentBackup ShareTokenIntent = generated.ShareTokenIntentBackup +) + +// PossibleShareTokenIntentValues returns the possible values for the ShareTokenIntent const type. +func PossibleShareTokenIntentValues() []ShareTokenIntent { + return generated.PossibleShareTokenIntentValues() +} + +// LastWrittenMode specifies if the file last write time should be preserved or overwritten +type LastWrittenMode = generated.FileLastWrittenMode + +const ( + LastWrittenModeNow LastWrittenMode = generated.FileLastWrittenModeNow + LastWrittenModePreserve LastWrittenMode = generated.FileLastWrittenModePreserve +) + +// PossibleLastWrittenModeValues returns the possible values for the LastWrittenMode const type. +func PossibleLastWrittenModeValues() []LastWrittenMode { + return generated.PossibleFileLastWrittenModeValues() +} diff --git a/sdk/storage/azfile/file/examples_test.go b/sdk/storage/azfile/file/examples_test.go index b54aa5aab215..fe9556abbda3 100644 --- a/sdk/storage/azfile/file/examples_test.go +++ b/sdk/storage/azfile/file/examples_test.go @@ -13,6 +13,7 @@ import ( "fmt" "github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/file" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/sas" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/service" @@ -648,3 +649,170 @@ func Example_fileClient_UploadRangeFromURL() { _, err = destFClient.UploadRangeFromURL(context.Background(), srcFileSAS, 0, 0, int64(contentSize), nil) handleError(err) } + +func Example_fileClient_OAuth() { + accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME") + if !ok { + panic("AZURE_STORAGE_ACCOUNT_NAME could not be found") + } + + cred, err := azidentity.NewDefaultAzureCredential(nil) + handleError(err) + + shareName := "testShare" + fileName := "testFile" + fileURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + fileName + + fileClient, err := file.NewClient(fileURL, cred, &file.ClientOptions{FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup)}) + handleError(err) + + _, err = fileClient.Create(context.TODO(), 2048, nil) + handleError(err) + fmt.Println("File created") + + _, err = fileClient.GetProperties(context.TODO(), nil) + handleError(err) + fmt.Println("File properties retrieved") + + _, err = fileClient.Delete(context.TODO(), nil) + handleError(err) + fmt.Println("File deleted") +} + +func Example_fileClient_TrailingDot() { + accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME") + if !ok { + panic("AZURE_STORAGE_ACCOUNT_NAME could not be found") + } + + cred, err := azidentity.NewDefaultAzureCredential(nil) + handleError(err) + + shareName := "testShare" + fileName := "testFile.." // file name with trailing dot + fileURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + fileName + + fileClient, err := file.NewClient(fileURL, cred, &file.ClientOptions{ + FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup), + AllowTrailingDot: to.Ptr(true), + }) + handleError(err) + + _, err = fileClient.Create(context.TODO(), 2048, nil) + handleError(err) + fmt.Println("File created") + + _, err = fileClient.GetProperties(context.TODO(), nil) + handleError(err) + fmt.Println("File properties retrieved") + + _, err = fileClient.Delete(context.TODO(), nil) + handleError(err) + fmt.Println("File deleted") +} + +func Example_fileClient_Rename() { + accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME") + if !ok { + panic("AZURE_STORAGE_ACCOUNT_NAME could not be found") + } + + cred, err := azidentity.NewDefaultAzureCredential(nil) + handleError(err) + + shareName := "testShare" + srcFileName := "testFile" + destFileName := "newFile" + srcFileURL := "https://" + accountName + ".file.core.windows.net/" + shareName + "/" + srcFileName + + srcFileClient, err := file.NewClient(srcFileURL, cred, &file.ClientOptions{FileRequestIntent: to.Ptr(file.ShareTokenIntentBackup)}) + handleError(err) + + _, err = srcFileClient.Rename(context.TODO(), destFileName, nil) + handleError(err) + fmt.Println("File renamed") +} + +func Example_fileClient_CopyFileUsingSourceProperties() { + // Your connection string can be obtained from the Azure Portal. + connectionString, ok := os.LookupEnv("AZURE_STORAGE_CONNECTION_STRING") + if !ok { + log.Fatal("the environment variable 'AZURE_STORAGE_CONNECTION_STRING' could not be found") + } + shareName := "testShare" + srcFileName := "testFile" + dstFileName := "testFile2" + fileSize := int64(5) + + shareClient, err := share.NewClientFromConnectionString(connectionString, shareName, nil) + handleError(err) + + _, err = shareClient.Create(context.Background(), nil) + handleError(err) + + srcFileClient := shareClient.NewRootDirectoryClient().NewFileClient(srcFileName) + _, err = srcFileClient.Create(context.Background(), fileSize, nil) + handleError(err) + + dstFileClient := shareClient.NewRootDirectoryClient().NewFileClient(dstFileName) + + contentR, _ := generateData(int(fileSize)) + + _, err = srcFileClient.UploadRange(context.Background(), 0, contentR, nil) + handleError(err) + + _, err = dstFileClient.StartCopyFromURL(context.Background(), srcFileClient.URL(), &file.StartCopyFromURLOptions{ + CopyFileSMBInfo: &file.CopyFileSMBInfo{ + CreationTime: file.SourceCopyFileCreationTime{}, + LastWriteTime: file.SourceCopyFileLastWriteTime{}, + ChangeTime: file.SourceCopyFileChangeTime{}, + Attributes: file.SourceCopyFileAttributes{}, + PermissionCopyMode: to.Ptr(file.PermissionCopyModeTypeSource), + }, + }) + handleError(err) + fmt.Println("File copied") +} + +func Example_fileClient_CopyFileUsingDestinationProperties() { + // Your connection string can be obtained from the Azure Portal. + connectionString, ok := os.LookupEnv("AZURE_STORAGE_CONNECTION_STRING") + if !ok { + log.Fatal("the environment variable 'AZURE_STORAGE_CONNECTION_STRING' could not be found") + } + shareName := "testShare" + srcFileName := "testFile" + dstFileName := "testFile2" + fileSize := int64(5) + + shareClient, err := share.NewClientFromConnectionString(connectionString, shareName, nil) + handleError(err) + + _, err = shareClient.Create(context.Background(), nil) + handleError(err) + + srcFileClient := shareClient.NewRootDirectoryClient().NewFileClient(srcFileName) + _, err = srcFileClient.Create(context.Background(), fileSize, nil) + handleError(err) + + dstFileClient := shareClient.NewRootDirectoryClient().NewFileClient(dstFileName) + + contentR, _ := generateData(int(fileSize)) + + _, err = srcFileClient.UploadRange(context.Background(), 0, contentR, nil) + handleError(err) + + destCreationTime := time.Now().Add(5 * time.Minute) + destLastWriteTIme := time.Now().Add(6 * time.Minute) + destChangeTime := time.Now().Add(7 * time.Minute) + _, err = dstFileClient.StartCopyFromURL(context.Background(), srcFileClient.URL(), &file.StartCopyFromURLOptions{ + CopyFileSMBInfo: &file.CopyFileSMBInfo{ + CreationTime: file.DestinationCopyFileCreationTime(destCreationTime), + LastWriteTime: file.DestinationCopyFileLastWriteTime(destLastWriteTIme), + ChangeTime: file.DestinationCopyFileChangeTime(destChangeTime), + Attributes: file.DestinationCopyFileAttributes{ReadOnly: true}, + }, + }) + handleError(err) + fmt.Println("File copied") +} diff --git a/sdk/storage/azfile/file/models.go b/sdk/storage/azfile/file/models.go index 22f9f814fee5..df5216910fbd 100644 --- a/sdk/storage/azfile/file/models.go +++ b/sdk/storage/azfile/file/models.go @@ -9,7 +9,6 @@ package file import ( "encoding/binary" "errors" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "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" @@ -67,6 +66,12 @@ type ClearRange = generated.ClearRange // ShareFileRange - An Azure Storage file range. type ShareFileRange = generated.FileRange +// SourceLeaseAccessConditions contains optional parameters to access the source directory. +type SourceLeaseAccessConditions = generated.SourceLeaseAccessConditions + +// DestinationLeaseAccessConditions contains optional parameters to access the destination directory. +type DestinationLeaseAccessConditions = generated.DestinationLeaseAccessConditions + // --------------------------------------------------------------------------------------------------------------------- // CreateOptions contains the optional parameters for the Client.Create method. @@ -81,28 +86,26 @@ type CreateOptions struct { Metadata map[string]*string } -func (o *CreateOptions) format() (fileAttributes string, fileCreationTime string, fileLastWriteTime string, - createOptions *generated.FileClientCreateOptions, fileHTTPHeaders *generated.ShareFileHTTPHeaders, leaseAccessConditions *LeaseAccessConditions) { +func (o *CreateOptions) format() (*generated.FileClientCreateOptions, *generated.ShareFileHTTPHeaders, *LeaseAccessConditions) { if o == nil { - return shared.FileAttributesNone, shared.DefaultCurrentTimeString, shared.DefaultCurrentTimeString, &generated.FileClientCreateOptions{ - FilePermission: to.Ptr(shared.DefaultFilePermissionString), - }, nil, nil + return nil, nil, nil } - fileAttributes, fileCreationTime, fileLastWriteTime = o.SMBProperties.Format(false, shared.FileAttributesNone, shared.DefaultCurrentTimeString) + fileAttributes, fileCreationTime, fileLastWriteTime, fileChangeTime := exported.FormatSMBProperties(o.SMBProperties, false) - permission, permissionKey := o.Permissions.Format(shared.DefaultFilePermissionString) + permission, permissionKey := exported.FormatPermissions(o.Permissions) - createOptions = &generated.FileClientCreateOptions{ + createOptions := &generated.FileClientCreateOptions{ + FileAttributes: fileAttributes, + FileChangeTime: fileChangeTime, + FileCreationTime: fileCreationTime, + FileLastWriteTime: fileLastWriteTime, FilePermission: permission, FilePermissionKey: permissionKey, Metadata: o.Metadata, } - fileHTTPHeaders = o.HTTPHeaders - leaseAccessConditions = o.LeaseAccessConditions - - return + return createOptions, o.HTTPHeaders, o.LeaseAccessConditions } // --------------------------------------------------------------------------------------------------------------------- @@ -122,6 +125,63 @@ func (o *DeleteOptions) format() (*generated.FileClientDeleteOptions, *generated // --------------------------------------------------------------------------------------------------------------------- +// RenameOptions contains the optional parameters for the Client.Rename method. +type RenameOptions struct { + // SMBProperties contains the optional parameters regarding the SMB/NTFS properties for a file. + SMBProperties *SMBProperties + // Permissions contains the optional parameters for the permissions on the file. + Permissions *Permissions + // ContentType sets the content type of the file. + ContentType *string + // IgnoreReadOnly specifies whether the ReadOnly attribute on a pre-existing destination file should be respected. + // If true, rename will succeed, otherwise, a previous file at the destination with the ReadOnly attribute set will cause rename to fail. + IgnoreReadOnly *bool + // A name-value pair to associate with a file storage object. + Metadata map[string]*string + // ReplaceIfExists specifies that if the destination file already exists, whether this request will overwrite the file or not. + // If true, rename will succeed and will overwrite the destination file. If not provided or if false and the destination file does exist, + // the request will not overwrite the destination file. + // If provided and the destination file does not exist, rename will succeed. + ReplaceIfExists *bool + // SourceLeaseAccessConditions contains optional parameters to access the source directory. + SourceLeaseAccessConditions *SourceLeaseAccessConditions + // DestinationLeaseAccessConditions contains optional parameters to access the destination directory. + DestinationLeaseAccessConditions *DestinationLeaseAccessConditions +} + +func (o *RenameOptions) format() (*generated.FileClientRenameOptions, *generated.SourceLeaseAccessConditions, *generated.DestinationLeaseAccessConditions, *generated.CopyFileSMBInfo, *generated.ShareFileHTTPHeaders) { + if o == nil { + return nil, nil, nil, nil, nil + } + + fileAttributes, fileCreationTime, fileLastWriteTime, fileChangeTime := exported.FormatSMBProperties(o.SMBProperties, false) + + permission, permissionKey := exported.FormatPermissions(o.Permissions) + + renameOpts := &generated.FileClientRenameOptions{ + FilePermission: permission, + FilePermissionKey: permissionKey, + IgnoreReadOnly: o.IgnoreReadOnly, + Metadata: o.Metadata, + ReplaceIfExists: o.ReplaceIfExists, + } + + smbInfo := &generated.CopyFileSMBInfo{ + FileAttributes: fileAttributes, + FileChangeTime: fileChangeTime, + FileCreationTime: fileCreationTime, + FileLastWriteTime: fileLastWriteTime, + } + + fileHTTPHeaders := &generated.ShareFileHTTPHeaders{ + ContentType: o.ContentType, + } + + return renameOpts, o.SourceLeaseAccessConditions, o.DestinationLeaseAccessConditions, smbInfo, fileHTTPHeaders +} + +// --------------------------------------------------------------------------------------------------------------------- + // GetPropertiesOptions contains the optional parameters for the Client.GetProperties method. type GetPropertiesOptions struct { // ShareSnapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query for the file properties. @@ -156,28 +216,26 @@ type SetHTTPHeadersOptions struct { LeaseAccessConditions *LeaseAccessConditions } -func (o *SetHTTPHeadersOptions) format() (fileAttributes string, fileCreationTime string, fileLastWriteTime string, - opts *generated.FileClientSetHTTPHeadersOptions, fileHTTPHeaders *generated.ShareFileHTTPHeaders, leaseAccessConditions *LeaseAccessConditions) { +func (o *SetHTTPHeadersOptions) format() (*generated.FileClientSetHTTPHeadersOptions, *generated.ShareFileHTTPHeaders, *LeaseAccessConditions) { if o == nil { - return shared.DefaultPreserveString, shared.DefaultPreserveString, shared.DefaultPreserveString, &generated.FileClientSetHTTPHeadersOptions{ - FilePermission: to.Ptr(shared.DefaultPreserveString), - }, nil, nil + return nil, nil, nil } - fileAttributes, fileCreationTime, fileLastWriteTime = o.SMBProperties.Format(false, shared.DefaultPreserveString, shared.DefaultPreserveString) + fileAttributes, fileCreationTime, fileLastWriteTime, fileChangeTime := exported.FormatSMBProperties(o.SMBProperties, false) - permission, permissionKey := o.Permissions.Format(shared.DefaultPreserveString) + permission, permissionKey := exported.FormatPermissions(o.Permissions) - opts = &generated.FileClientSetHTTPHeadersOptions{ + opts := &generated.FileClientSetHTTPHeadersOptions{ + FileAttributes: fileAttributes, + FileChangeTime: fileChangeTime, + FileCreationTime: fileCreationTime, + FileLastWriteTime: fileLastWriteTime, FileContentLength: o.FileContentLength, FilePermission: permission, FilePermissionKey: permissionKey, } - fileHTTPHeaders = o.HTTPHeaders - leaseAccessConditions = o.LeaseAccessConditions - - return + return opts, o.HTTPHeaders, o.LeaseAccessConditions } // --------------------------------------------------------------------------------------------------------------------- @@ -234,14 +292,28 @@ func (o *StartCopyFromURLOptions) format() (*generated.FileClientStartCopyOption // CopyFileSMBInfo contains a group of parameters for the FileClient.StartCopy method. type CopyFileSMBInfo struct { - // Specifies either the option to copy file attributes from a source file(source) to a target file or a list of attributes - // to set on a target file. + // Specifies either the option to copy file attributes from a source file(source) to a target file or a list of attributes to set on a target file. + // CopyFileAttributes is an interface and its underlying implementation are: + // - SourceCopyFileAttributes - specifies to copy file attributes from a source file to a target file. + // - DestinationCopyFileAttributes - specifies a list of attributes to set on a target file. Attributes CopyFileAttributes + // Specifies either the option to copy file change time from a source file(source) to a target file or a time value in + // ISO 8601 format to set as change time on a target file. + // CopyFileChangeTime is an interface and its underlying implementation are: + // - SourceCopyFileChangeTime - specifies to copy file change time from a source file to a target file. + // - DestinationCopyFileChangeTime - specifies a time value in ISO 8601 format to set as change time on a target file. + ChangeTime CopyFileChangeTime // Specifies either the option to copy file creation time from a source file(source) to a target file or a time value in ISO // 8601 format to set as creation time on a target file. + // CopyFileCreationTime is an interface and its underlying implementation are: + // - SourceCopyFileCreationTime - specifies to copy file creation time from a source file to a target file. + // - DestinationCopyFileCreationTime - specifies a time value in ISO 8601 format to set as creation time on a target file. CreationTime CopyFileCreationTime // Specifies either the option to copy file last write time from a source file(source) to a target file or a time value in // ISO 8601 format to set as last write time on a target file. + // CopyFileLastWriteTime is an interface and its underlying implementation are: + // - SourceCopyFileLastWriteTime - specifies to copy file last write time from a source file to a target file. + // - DestinationCopyFileLastWriteTime - specifies a time value in ISO 8601 format to set as last write time on a target file. LastWriteTime CopyFileLastWriteTime // Specifies the option to copy file security descriptor from source file or to set it using the value which is defined by // the header value of x-ms-file-permission or x-ms-file-permission-key. @@ -273,6 +345,9 @@ func (c *CopyFileSMBInfo) format() *generated.CopyFileSMBInfo { if c.LastWriteTime != nil { opts.FileLastWriteTime = c.LastWriteTime.FormatLastWriteTime() } + if c.ChangeTime != nil { + opts.FileChangeTime = c.ChangeTime.FormatChangeTime() + } return opts } @@ -287,6 +362,16 @@ type SourceCopyFileAttributes = exported.SourceCopyFileAttributes // DestinationCopyFileAttributes specifies a list of attributes to set on a target file. type DestinationCopyFileAttributes = exported.DestinationCopyFileAttributes +// CopyFileChangeTime specifies either the option to copy file change time from a source file(source) to a target file or +// a time value in ISO 8601 format to set as change time on a target file. +type CopyFileChangeTime = exported.CopyFileChangeTime + +// SourceCopyFileChangeTime specifies to copy file change time from a source file(source) to a target file. +type SourceCopyFileChangeTime = exported.SourceCopyFileChangeTime + +// DestinationCopyFileChangeTime specifies a time value in ISO 8601 format to set as change time on a target file. +type DestinationCopyFileChangeTime = exported.DestinationCopyFileChangeTime + // CopyFileCreationTime specifies either the option to copy file creation time from a source file(source) to a target file or // a time value in ISO 8601 format to set as creation time on a target file. type CopyFileCreationTime = exported.CopyFileCreationTime @@ -444,20 +529,17 @@ type ResizeOptions struct { LeaseAccessConditions *LeaseAccessConditions } -func (o *ResizeOptions) format(contentLength int64) (fileAttributes string, fileCreationTime string, fileLastWriteTime string, - opts *generated.FileClientSetHTTPHeadersOptions, leaseAccessConditions *LeaseAccessConditions) { - fileAttributes, fileCreationTime, fileLastWriteTime = shared.DefaultPreserveString, shared.DefaultPreserveString, shared.DefaultPreserveString - - opts = &generated.FileClientSetHTTPHeadersOptions{ +func (o *ResizeOptions) format(contentLength int64) (*generated.FileClientSetHTTPHeadersOptions, *LeaseAccessConditions) { + opts := &generated.FileClientSetHTTPHeadersOptions{ FileContentLength: &contentLength, - FilePermission: to.Ptr(shared.DefaultPreserveString), } + var leaseAccessConditions *LeaseAccessConditions = nil if o != nil { leaseAccessConditions = o.LeaseAccessConditions } - return + return opts, leaseAccessConditions } // --------------------------------------------------------------------------------------------------------------------- @@ -469,6 +551,8 @@ type UploadRangeOptions struct { TransactionalValidation TransferValidationType // LeaseAccessConditions contains optional parameters to access leased entity. LeaseAccessConditions *LeaseAccessConditions + // LastWrittenMode specifies if the file last write time should be preserved or overwritten. + LastWrittenMode *LastWrittenMode } func (o *UploadRangeOptions) format(offset int64, body io.ReadSeekCloser) (string, int64, *generated.FileClientUploadRangeOptions, *generated.LeaseAccessConditions, error) { @@ -499,6 +583,7 @@ func (o *UploadRangeOptions) format(offset int64, body io.ReadSeekCloser) (strin if o != nil { leaseAccessConditions = o.LeaseAccessConditions + uploadRangeOptions.FileLastWrittenMode = o.LastWrittenMode } if o != nil && o.TransactionalValidation != nil { _, err = o.TransactionalValidation.Apply(body, uploadRangeOptions) @@ -541,6 +626,8 @@ type UploadRangeFromURLOptions struct { SourceContentCRC64 uint64 SourceModifiedAccessConditions *SourceModifiedAccessConditions LeaseAccessConditions *LeaseAccessConditions + // LastWrittenMode specifies if the file last write time should be preserved or overwritten. + LastWrittenMode *LastWrittenMode } func (o *UploadRangeFromURLOptions) format(sourceOffset int64, destinationOffset int64, count int64) (string, *generated.FileClientUploadRangeFromURLOptions, *generated.SourceModifiedAccessConditions, *generated.LeaseAccessConditions, error) { @@ -564,6 +651,7 @@ func (o *UploadRangeFromURLOptions) format(sourceOffset int64, destinationOffset if o != nil { opts.CopySourceAuthorization = o.CopySourceAuthorization + opts.FileLastWrittenMode = o.LastWrittenMode sourceModifiedAccessConditions = o.SourceModifiedAccessConditions leaseAccessConditions = o.LeaseAccessConditions diff --git a/sdk/storage/azfile/file/responses.go b/sdk/storage/azfile/file/responses.go index e47d87741861..5d77e6e24a1b 100644 --- a/sdk/storage/azfile/file/responses.go +++ b/sdk/storage/azfile/file/responses.go @@ -18,6 +18,11 @@ type CreateResponse = generated.FileClientCreateResponse // DeleteResponse contains the response from method Client.Delete. type DeleteResponse = generated.FileClientDeleteResponse +// RenameResponse contains the response from method Client.Rename. +type RenameResponse struct { + generated.FileClientRenameResponse +} + // GetPropertiesResponse contains the response from method Client.GetProperties. type GetPropertiesResponse = generated.FileClientGetPropertiesResponse diff --git a/sdk/storage/azfile/fileerror/error_codes.go b/sdk/storage/azfile/fileerror/error_codes.go index c897c0953828..c8c12f76912e 100644 --- a/sdk/storage/azfile/fileerror/error_codes.go +++ b/sdk/storage/azfile/fileerror/error_codes.go @@ -34,71 +34,72 @@ func HasCode(err error, codes ...Code) bool { type Code = generated.StorageErrorCode const ( - AccountAlreadyExists Code = "AccountAlreadyExists" - AccountBeingCreated Code = "AccountBeingCreated" - AccountIsDisabled Code = "AccountIsDisabled" - AuthenticationFailed Code = "AuthenticationFailed" - AuthorizationFailure Code = "AuthorizationFailure" - AuthorizationPermissionMismatch Code = "AuthorizationPermissionMismatch" - AuthorizationProtocolMismatch Code = "AuthorizationProtocolMismatch" - AuthorizationResourceTypeMismatch Code = "AuthorizationResourceTypeMismatch" - AuthorizationServiceMismatch Code = "AuthorizationServiceMismatch" - AuthorizationSourceIPMismatch Code = "AuthorizationSourceIPMismatch" - CannotDeleteFileOrDirectory Code = "CannotDeleteFileOrDirectory" - ClientCacheFlushDelay Code = "ClientCacheFlushDelay" - ConditionHeadersNotSupported Code = "ConditionHeadersNotSupported" - ConditionNotMet Code = "ConditionNotMet" - DeletePending Code = "DeletePending" - DirectoryNotEmpty Code = "DirectoryNotEmpty" - EmptyMetadataKey Code = "EmptyMetadataKey" - FeatureVersionMismatch Code = "FeatureVersionMismatch" - FileLockConflict Code = "FileLockConflict" - InsufficientAccountPermissions Code = "InsufficientAccountPermissions" - InternalError Code = "InternalError" - InvalidAuthenticationInfo Code = "InvalidAuthenticationInfo" - InvalidFileOrDirectoryPathName Code = "InvalidFileOrDirectoryPathName" - InvalidHTTPVerb Code = "InvalidHttpVerb" - InvalidHeaderValue Code = "InvalidHeaderValue" - InvalidInput Code = "InvalidInput" - InvalidMD5 Code = "InvalidMd5" - InvalidMetadata Code = "InvalidMetadata" - InvalidQueryParameterValue Code = "InvalidQueryParameterValue" - InvalidRange Code = "InvalidRange" - InvalidResourceName Code = "InvalidResourceName" - InvalidURI Code = "InvalidUri" - InvalidXMLDocument Code = "InvalidXmlDocument" - InvalidXMLNodeValue Code = "InvalidXmlNodeValue" - MD5Mismatch Code = "Md5Mismatch" - MetadataTooLarge Code = "MetadataTooLarge" - MissingContentLengthHeader Code = "MissingContentLengthHeader" - MissingRequiredHeader Code = "MissingRequiredHeader" - MissingRequiredQueryParameter Code = "MissingRequiredQueryParameter" - MissingRequiredXMLNode Code = "MissingRequiredXmlNode" - MultipleConditionHeadersNotSupported Code = "MultipleConditionHeadersNotSupported" - OperationTimedOut Code = "OperationTimedOut" - OutOfRangeInput Code = "OutOfRangeInput" - OutOfRangeQueryParameterValue Code = "OutOfRangeQueryParameterValue" - ParentNotFound Code = "ParentNotFound" - ReadOnlyAttribute Code = "ReadOnlyAttribute" - RequestBodyTooLarge Code = "RequestBodyTooLarge" - RequestURLFailedToParse Code = "RequestUrlFailedToParse" - ResourceAlreadyExists Code = "ResourceAlreadyExists" - ResourceNotFound Code = "ResourceNotFound" - ResourceTypeMismatch Code = "ResourceTypeMismatch" - ServerBusy Code = "ServerBusy" - ShareAlreadyExists Code = "ShareAlreadyExists" - ShareBeingDeleted Code = "ShareBeingDeleted" - ShareDisabled Code = "ShareDisabled" - ShareHasSnapshots Code = "ShareHasSnapshots" - ShareNotFound Code = "ShareNotFound" - ShareSnapshotCountExceeded Code = "ShareSnapshotCountExceeded" - ShareSnapshotInProgress Code = "ShareSnapshotInProgress" - ShareSnapshotOperationNotSupported Code = "ShareSnapshotOperationNotSupported" - SharingViolation Code = "SharingViolation" - UnsupportedHTTPVerb Code = "UnsupportedHttpVerb" - UnsupportedHeader Code = "UnsupportedHeader" - UnsupportedQueryParameter Code = "UnsupportedQueryParameter" - UnsupportedXMLNode Code = "UnsupportedXmlNode" + AccountAlreadyExists Code = "AccountAlreadyExists" + AccountBeingCreated Code = "AccountBeingCreated" + AccountIsDisabled Code = "AccountIsDisabled" + AuthenticationFailed Code = "AuthenticationFailed" + AuthorizationFailure Code = "AuthorizationFailure" + AuthorizationPermissionMismatch Code = "AuthorizationPermissionMismatch" + AuthorizationProtocolMismatch Code = "AuthorizationProtocolMismatch" + AuthorizationResourceTypeMismatch Code = "AuthorizationResourceTypeMismatch" + AuthorizationServiceMismatch Code = "AuthorizationServiceMismatch" + AuthorizationSourceIPMismatch Code = "AuthorizationSourceIPMismatch" + CannotDeleteFileOrDirectory Code = "CannotDeleteFileOrDirectory" + ClientCacheFlushDelay Code = "ClientCacheFlushDelay" + ConditionHeadersNotSupported Code = "ConditionHeadersNotSupported" + ConditionNotMet Code = "ConditionNotMet" + DeletePending Code = "DeletePending" + DirectoryNotEmpty Code = "DirectoryNotEmpty" + EmptyMetadataKey Code = "EmptyMetadataKey" + FeatureVersionMismatch Code = "FeatureVersionMismatch" + FileLockConflict Code = "FileLockConflict" + InsufficientAccountPermissions Code = "InsufficientAccountPermissions" + InternalError Code = "InternalError" + InvalidAuthenticationInfo Code = "InvalidAuthenticationInfo" + InvalidFileOrDirectoryPathName Code = "InvalidFileOrDirectoryPathName" + InvalidHTTPVerb Code = "InvalidHttpVerb" + InvalidHeaderValue Code = "InvalidHeaderValue" + InvalidInput Code = "InvalidInput" + InvalidMD5 Code = "InvalidMd5" + InvalidMetadata Code = "InvalidMetadata" + InvalidQueryParameterValue Code = "InvalidQueryParameterValue" + InvalidRange Code = "InvalidRange" + InvalidResourceName Code = "InvalidResourceName" + InvalidURI Code = "InvalidUri" + InvalidXMLDocument Code = "InvalidXmlDocument" + InvalidXMLNodeValue Code = "InvalidXmlNodeValue" + MD5Mismatch Code = "Md5Mismatch" + MetadataTooLarge Code = "MetadataTooLarge" + MissingContentLengthHeader Code = "MissingContentLengthHeader" + MissingRequiredHeader Code = "MissingRequiredHeader" + MissingRequiredQueryParameter Code = "MissingRequiredQueryParameter" + MissingRequiredXMLNode Code = "MissingRequiredXmlNode" + MultipleConditionHeadersNotSupported Code = "MultipleConditionHeadersNotSupported" + OperationTimedOut Code = "OperationTimedOut" + OutOfRangeInput Code = "OutOfRangeInput" + OutOfRangeQueryParameterValue Code = "OutOfRangeQueryParameterValue" + ParentNotFound Code = "ParentNotFound" + ReadOnlyAttribute Code = "ReadOnlyAttribute" + RequestBodyTooLarge Code = "RequestBodyTooLarge" + RequestURLFailedToParse Code = "RequestUrlFailedToParse" + ResourceAlreadyExists Code = "ResourceAlreadyExists" + ResourceNotFound Code = "ResourceNotFound" + ResourceTypeMismatch Code = "ResourceTypeMismatch" + ServerBusy Code = "ServerBusy" + ShareAlreadyExists Code = "ShareAlreadyExists" + ShareBeingDeleted Code = "ShareBeingDeleted" + ShareDisabled Code = "ShareDisabled" + ShareHasSnapshots Code = "ShareHasSnapshots" + ShareNotFound Code = "ShareNotFound" + ShareSnapshotCountExceeded Code = "ShareSnapshotCountExceeded" + ShareSnapshotInProgress Code = "ShareSnapshotInProgress" + ShareSnapshotOperationNotSupported Code = "ShareSnapshotOperationNotSupported" + SharingViolation Code = "SharingViolation" + UnsupportedHTTPVerb Code = "UnsupportedHttpVerb" + UnsupportedHeader Code = "UnsupportedHeader" + UnsupportedQueryParameter Code = "UnsupportedQueryParameter" + UnsupportedXMLNode Code = "UnsupportedXmlNode" + FileOAuthManagementAPIRestrictedToSRP Code = "FileOAuthManagementApiRestrictedToSrp" ) var ( diff --git a/sdk/storage/azfile/go.mod b/sdk/storage/azfile/go.mod index cbd96fa64efc..6ca511e61728 100644 --- a/sdk/storage/azfile/go.mod +++ b/sdk/storage/azfile/go.mod @@ -3,26 +3,26 @@ module github.com/Azure/azure-sdk-for-go/sdk/storage/azfile go 1.18 require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 github.com/stretchr/testify v1.7.1 ) require ( - github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dnaeon/go-vcr v1.1.0 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/dnaeon/go-vcr v1.2.0 // indirect + github.com/golang-jwt/jwt/v5 v5.0.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.7.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/sdk/storage/azfile/go.sum b/sdk/storage/azfile/go.sum index 8f03fb9639d6..4f9e2448901a 100644 --- a/sdk/storage/azfile/go.sum +++ b/sdk/storage/azfile/go.sum @@ -1,20 +1,21 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0 h1:rTnT/Jrcm+figWlYz4Ixzt0SJVR2cMC8lvZcimipiEY= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2 h1:uqM+VoHjVH6zdlkLF2b6O0ZANcHoj3rO0PoQ3jglUJA= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.2/go.mod h1:twTKAa1E6hLmSDjLhaCkbTMQKc7p/rNLU40rLxGEOCI= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 h1:LNHhpdK7hzUcx/k1LIcuh5k7k1LGIWLQfCjaneSj7Fc= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag= -github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0 h1:UE9n9rkJF62ArLb1F3DEjRt8O3jLwMWdSoypKV4f3MU= -github.com/AzureAD/microsoft-authentication-library-for-go v0.9.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 h1:Ma67P/GGprNwsslzEH6+Kb8nybI8jpDTm4Wmzu2ReK8= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 h1:nVocQV40OQne5613EeLayJiRAJuKlBGy+m22qWG+WRg= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0/go.mod h1:7QJP7dr2wznCMeqIrhMgWGf7XpAQnVrJqDm9nvV3Cu4= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= -github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -27,20 +28,20 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/sdk/storage/azfile/internal/base/clients.go b/sdk/storage/azfile/internal/base/clients.go index 93317d4dc29b..101a58a5f85e 100644 --- a/sdk/storage/azfile/internal/base/clients.go +++ b/sdk/storage/azfile/internal/base/clients.go @@ -16,11 +16,16 @@ import ( // ClientOptions contains the optional parameters when creating a Client. type ClientOptions struct { azcore.ClientOptions + AllowTrailingDot *bool + FileRequestIntent *generated.ShareTokenIntent + AllowSourceTrailingDot *bool + pipelineOptions *runtime.PipelineOptions } type Client[T any] struct { inner *T sharedKey *exported.SharedKeyCredential + options *ClientOptions } func InnerClient[T any](client *Client[T]) *T { @@ -31,30 +36,46 @@ func SharedKey[T any](client *Client[T]) *exported.SharedKeyCredential { return client.sharedKey } -func NewServiceClient(serviceURL string, pipeline runtime.Pipeline, sharedKey *exported.SharedKeyCredential) *Client[generated.ServiceClient] { +func GetClientOptions[T any](client *Client[T]) *ClientOptions { + return client.options +} + +func GetPipelineOptions(clOpts *ClientOptions) *runtime.PipelineOptions { + return clOpts.pipelineOptions +} + +func SetPipelineOptions(clOpts *ClientOptions, plOpts *runtime.PipelineOptions) { + clOpts.pipelineOptions = plOpts +} + +func NewServiceClient(serviceURL string, azClient *azcore.Client, sharedKey *exported.SharedKeyCredential, options *ClientOptions) *Client[generated.ServiceClient] { return &Client[generated.ServiceClient]{ - inner: generated.NewServiceClient(serviceURL, pipeline), + inner: generated.NewServiceClient(serviceURL, azClient), sharedKey: sharedKey, + options: options, } } -func NewShareClient(shareURL string, pipeline runtime.Pipeline, sharedKey *exported.SharedKeyCredential) *Client[generated.ShareClient] { +func NewShareClient(shareURL string, azClient *azcore.Client, sharedKey *exported.SharedKeyCredential, options *ClientOptions) *Client[generated.ShareClient] { return &Client[generated.ShareClient]{ - inner: generated.NewShareClient(shareURL, pipeline), + inner: generated.NewShareClient(shareURL, options.FileRequestIntent, azClient), sharedKey: sharedKey, + options: options, } } -func NewDirectoryClient(directoryURL string, pipeline runtime.Pipeline, sharedKey *exported.SharedKeyCredential) *Client[generated.DirectoryClient] { +func NewDirectoryClient(directoryURL string, azClient *azcore.Client, sharedKey *exported.SharedKeyCredential, options *ClientOptions) *Client[generated.DirectoryClient] { return &Client[generated.DirectoryClient]{ - inner: generated.NewDirectoryClient(directoryURL, pipeline), + inner: generated.NewDirectoryClient(directoryURL, options.AllowTrailingDot, options.FileRequestIntent, options.AllowSourceTrailingDot, azClient), sharedKey: sharedKey, + options: options, } } -func NewFileClient(fileURL string, pipeline runtime.Pipeline, sharedKey *exported.SharedKeyCredential) *Client[generated.FileClient] { +func NewFileClient(fileURL string, azClient *azcore.Client, sharedKey *exported.SharedKeyCredential, options *ClientOptions) *Client[generated.FileClient] { return &Client[generated.FileClient]{ - inner: generated.NewFileClient(fileURL, pipeline), + inner: generated.NewFileClient(fileURL, options.AllowTrailingDot, options.FileRequestIntent, options.AllowSourceTrailingDot, azClient), sharedKey: sharedKey, + options: options, } } diff --git a/sdk/storage/azfile/internal/exported/copy_file_smb_options.go b/sdk/storage/azfile/internal/exported/copy_file_smb_options.go index 9f0da40bba4d..4dc9d91d954d 100644 --- a/sdk/storage/azfile/internal/exported/copy_file_smb_options.go +++ b/sdk/storage/azfile/internal/exported/copy_file_smb_options.go @@ -68,6 +68,34 @@ func (d DestinationCopyFileLastWriteTime) notPubliclyImplementable() {} // --------------------------------------------------------------------------------------------------------------------- +// CopyFileChangeTime specifies either the option to copy file change time from a source file(source) to a target file or +// a time value in ISO 8601 format to set as change time on a target file. +type CopyFileChangeTime interface { + FormatChangeTime() *string + notPubliclyImplementable() +} + +// SourceCopyFileChangeTime specifies to copy file change time from a source file(source) to a target file. +type SourceCopyFileChangeTime struct { +} + +func (s SourceCopyFileChangeTime) FormatChangeTime() *string { + return to.Ptr("source") +} + +func (s SourceCopyFileChangeTime) notPubliclyImplementable() {} + +// DestinationCopyFileChangeTime specifies a time value in ISO 8601 format to set as change time on a target file. +type DestinationCopyFileChangeTime time.Time + +func (d DestinationCopyFileChangeTime) FormatChangeTime() *string { + return to.Ptr(time.Time(d).UTC().Format(generated.ISO8601)) +} + +func (d DestinationCopyFileChangeTime) notPubliclyImplementable() {} + +// --------------------------------------------------------------------------------------------------------------------- + // CopyFileAttributes specifies either the option to copy file attributes from a source file(source) to a target file or // a list of attributes to set on a target file. type CopyFileAttributes interface { diff --git a/sdk/storage/azfile/internal/exported/file_permissions.go b/sdk/storage/azfile/internal/exported/file_permissions.go index 73fce6afb27c..6ba95bb67bb5 100644 --- a/sdk/storage/azfile/internal/exported/file_permissions.go +++ b/sdk/storage/azfile/internal/exported/file_permissions.go @@ -18,14 +18,20 @@ type Permissions struct { PermissionKey *string } +// Deprecated: Internal implementation; use FormatPermissions instead. // Format returns file permission string and permission key. func (p *Permissions) Format(defaultFilePermissionStr string) (*string, *string) { + return nil, nil +} + +// FormatPermissions returns file permission string and permission key. +func FormatPermissions(p *Permissions) (*string, *string) { if p == nil { - return &defaultFilePermissionStr, nil + return nil, nil } if p.Permission == nil && p.PermissionKey == nil { - return &defaultFilePermissionStr, nil + return nil, nil } else { return p.Permission, p.PermissionKey } diff --git a/sdk/storage/azfile/internal/exported/smb_property.go b/sdk/storage/azfile/internal/exported/smb_property.go index d5957561963b..2ada941cb0a0 100644 --- a/sdk/storage/azfile/internal/exported/smb_property.go +++ b/sdk/storage/azfile/internal/exported/smb_property.go @@ -8,6 +8,7 @@ package exported import ( "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/internal/generated" "strings" "time" @@ -22,33 +23,44 @@ type SMBProperties struct { CreationTime *time.Time // The Coordinated Universal Time (UTC) last write time for the file/directory. Default value is 'now'. LastWriteTime *time.Time + // The Coordinated Universal Time (UTC) change time for the file/directory. Default value is 'now'. + ChangeTime *time.Time } +// Deprecated: Internal implementation; use FormatSMBProperties instead. // Format returns file attributes, creation time and last write time. func (sp *SMBProperties) Format(isDir bool, defaultFileAttributes string, defaultCurrentTimeString string) (fileAttributes string, creationTime string, lastWriteTime string) { + return +} + +// FormatSMBProperties returns file attributes, creation time, last write time and change time. +func FormatSMBProperties(sp *SMBProperties, isDir bool) (fileAttributes *string, creationTime *string, lastWriteTime *string, changeTime *string) { if sp == nil { - return defaultFileAttributes, defaultCurrentTimeString, defaultCurrentTimeString + return nil, nil, nil, nil } - fileAttributes = defaultFileAttributes + fileAttributes = nil if sp.Attributes != nil { - fileAttributes = sp.Attributes.String() - if fileAttributes == "" { - fileAttributes = defaultFileAttributes - } else if isDir && strings.ToLower(fileAttributes) != "none" { + fileAttributes = to.Ptr(sp.Attributes.String()) + if isDir && fileAttributes != nil && strings.ToLower(*fileAttributes) != "none" { // Directories need to have this attribute included, if setting any attributes. - fileAttributes += "|Directory" + *fileAttributes += "|Directory" } } - creationTime = defaultCurrentTimeString + creationTime = nil if sp.CreationTime != nil { - creationTime = sp.CreationTime.UTC().Format(generated.ISO8601) + creationTime = to.Ptr(sp.CreationTime.UTC().Format(generated.ISO8601)) } - lastWriteTime = defaultCurrentTimeString + lastWriteTime = nil if sp.LastWriteTime != nil { - lastWriteTime = sp.LastWriteTime.UTC().Format(generated.ISO8601) + lastWriteTime = to.Ptr(sp.LastWriteTime.UTC().Format(generated.ISO8601)) + } + + changeTime = nil + if sp.ChangeTime != nil { + changeTime = to.Ptr(sp.ChangeTime.UTC().Format(generated.ISO8601)) } return diff --git a/sdk/storage/azfile/internal/exported/version.go b/sdk/storage/azfile/internal/exported/version.go index 940441e6704f..72634b3aa648 100644 --- a/sdk/storage/azfile/internal/exported/version.go +++ b/sdk/storage/azfile/internal/exported/version.go @@ -8,5 +8,5 @@ package exported const ( ModuleName = "azfile" - ModuleVersion = "v1.0.1" + ModuleVersion = "v1.1.0-beta.1" ) diff --git a/sdk/storage/azfile/internal/generated/autorest.md b/sdk/storage/azfile/internal/generated/autorest.md index 634ccff33f46..921ad0ca976c 100644 --- a/sdk/storage/azfile/internal/generated/autorest.md +++ b/sdk/storage/azfile/internal/generated/autorest.md @@ -7,7 +7,7 @@ go: true clear-output-folder: false version: "^3.0.0" license-header: MICROSOFT_MIT_NO_VERSION -input-file: "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/bbea558ac43d6ebec72455233c84b0158c89fcda/specification/storage/data-plane/Microsoft.FileStorage/preview/2020-10-02/file.json" +input-file: "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/7dcd41cd28d46eb256bac034760a7e2f0a036238/specification/storage/data-plane/Microsoft.FileStorage/preview/2022-11-02/file.json" credential-scope: "https://storage.azure.com/.default" output-folder: ../generated file-prefix: "zz_" @@ -19,7 +19,7 @@ modelerfour: seal-single-value-enum-by-default: true lenient-model-deduplication: true export-clients: true -use: "@autorest/go@4.0.0-preview.45" +use: "@autorest/go@4.0.0-preview.49" ``` ### Don't include share name, directory, or file name in path - we have direct URIs @@ -141,6 +141,7 @@ directive: ``` yaml directive: - from: + - zz_directory_client.go - zz_file_client.go - zz_models.go where: $ @@ -257,6 +258,10 @@ directive: where: $.parameters.FileLastWriteTime transform: > $.format = "str"; +- from: swagger-document + where: $.parameters.FileChangeTime + transform: > + $.format = "str"; ``` ### Remove pager methods and export various generated methods in directory client @@ -307,3 +312,44 @@ directive: return $. replace(/ShareUsageBytes\s+\*int32/g, `ShareUsageBytes *int64`); ``` + +### Convert StringEncoded to string type + +``` yaml +directive: + - from: zz_models.go + where: $ + transform: >- + return $. + replace(/\*StringEncoded/g, `*string`); +``` + +### Removing UnmarshalXML for Handle to create custom UnmarshalXML function + +``` yaml +directive: +- from: swagger-document + where: $.definitions + transform: > + $.Handle["x-ms-go-omit-serde-methods"] = true; +``` + +### Convert FileAttributes to an optional parameter + +``` yaml +directive: +- from: swagger-document + where: $.parameters.FileAttributes + transform: > + $.required = false; +``` + +### Rename ProvisionedBandwidthMiBps response field + +``` yaml +directive: +- from: swagger-document + where: $["x-ms-paths"]["/{shareName}?restype=share"] + transform: > + $.get.responses["200"].headers["x-ms-share-provisioned-bandwidth-mibps"]["x-ms-client-name"] = "ProvisionedBandwidthMiBps" +``` \ No newline at end of file diff --git a/sdk/storage/azfile/internal/generated/directory_client.go b/sdk/storage/azfile/internal/generated/directory_client.go index 11a75a9f50c8..cd81b4db8272 100644 --- a/sdk/storage/azfile/internal/generated/directory_client.go +++ b/sdk/storage/azfile/internal/generated/directory_client.go @@ -6,7 +6,9 @@ package generated -import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) const ( // ISO8601 is used for formatting file creation, last write and change time. @@ -17,6 +19,23 @@ func (client *DirectoryClient) Endpoint() string { return client.endpoint } -func (client *DirectoryClient) Pipeline() runtime.Pipeline { - return client.pl +func (client *DirectoryClient) InternalClient() *azcore.Client { + return client.internal +} + +// NewDirectoryClient creates a new instance of DirectoryClient with the specified values. +// - endpoint - The URL of the service account, share, directory or file that is the target of the desired operation. +// - allowTrailingDot - If true, the trailing dot will not be trimmed from the target URI. +// - fileRequestIntent - Valid value is backup +// - allowSourceTrailingDot - If true, the trailing dot will not be trimmed from the source URI. +// - azClient - azcore.Client is a basic HTTP client. It consists of a pipeline and tracing provider. +func NewDirectoryClient(endpoint string, allowTrailingDot *bool, fileRequestIntent *ShareTokenIntent, allowSourceTrailingDot *bool, azClient *azcore.Client) *DirectoryClient { + client := &DirectoryClient{ + internal: azClient, + endpoint: endpoint, + allowTrailingDot: allowTrailingDot, + fileRequestIntent: fileRequestIntent, + allowSourceTrailingDot: allowSourceTrailingDot, + } + return client } diff --git a/sdk/storage/azfile/internal/generated/file_client.go b/sdk/storage/azfile/internal/generated/file_client.go index f4a01a783938..e3c415e7529d 100644 --- a/sdk/storage/azfile/internal/generated/file_client.go +++ b/sdk/storage/azfile/internal/generated/file_client.go @@ -6,12 +6,31 @@ package generated -import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) func (client *FileClient) Endpoint() string { return client.endpoint } -func (client *FileClient) Pipeline() runtime.Pipeline { - return client.pl +func (client *FileClient) InternalClient() *azcore.Client { + return client.internal +} + +// NewFileClient creates a new instance of FileClient with the specified values. +// - endpoint - The URL of the service account, share, directory or file that is the target of the desired operation. +// - allowTrailingDot - If true, the trailing dot will not be trimmed from the target URI. +// - fileRequestIntent - Valid value is backup +// - allowSourceTrailingDot - If true, the trailing dot will not be trimmed from the source URI. +// - azClient - azcore.Client is a basic HTTP client. It consists of a pipeline and tracing provider. +func NewFileClient(endpoint string, allowTrailingDot *bool, fileRequestIntent *ShareTokenIntent, allowSourceTrailingDot *bool, azClient *azcore.Client) *FileClient { + client := &FileClient{ + internal: azClient, + endpoint: endpoint, + allowTrailingDot: allowTrailingDot, + fileRequestIntent: fileRequestIntent, + allowSourceTrailingDot: allowSourceTrailingDot, + } + return client } diff --git a/sdk/storage/azfile/internal/generated/models.go b/sdk/storage/azfile/internal/generated/models.go index 6450b7de2e82..3aeb9ae89d49 100644 --- a/sdk/storage/azfile/internal/generated/models.go +++ b/sdk/storage/azfile/internal/generated/models.go @@ -6,6 +6,13 @@ package generated +import ( + "encoding/xml" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "net/url" + "time" +) + type TransactionalContentSetter interface { SetMD5([]byte) // add SetCRC64() when Azure File service starts supporting it. @@ -23,3 +30,128 @@ type SourceContentSetter interface { func (f *FileClientUploadRangeFromURLOptions) SetSourceContentCRC64(v []byte) { f.SourceContentCRC64 = v } + +// Custom MarshalXML/UnmarshalXML functions for types that need special handling. + +// MarshalXML implements the xml.Marshaller interface for type Handle. +func (h Handle) MarshalXML(enc *xml.Encoder, start xml.StartElement) error { + type alias Handle + aux := &struct { + *alias + LastReconnectTime *timeRFC1123 `xml:"LastReconnectTime"` + OpenTime *timeRFC1123 `xml:"OpenTime"` + }{ + alias: (*alias)(&h), + LastReconnectTime: (*timeRFC1123)(h.LastReconnectTime), + OpenTime: (*timeRFC1123)(h.OpenTime), + } + return enc.EncodeElement(aux, start) +} + +// UnmarshalXML implements the xml.Unmarshaller interface for type Handle. +func (h *Handle) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { + type alias Handle + aux := &struct { + *alias + Path *StringEncoded `xml:"Path"` + LastReconnectTime *timeRFC1123 `xml:"LastReconnectTime"` + OpenTime *timeRFC1123 `xml:"OpenTime"` + }{ + alias: (*alias)(h), + } + if err := dec.DecodeElement(aux, &start); err != nil { + return err + } + h.LastReconnectTime = (*time.Time)(aux.LastReconnectTime) + h.OpenTime = (*time.Time)(aux.OpenTime) + if aux.Path != nil { + if aux.Path.Encoded != nil && *aux.Path.Encoded { + name, err := url.QueryUnescape(*aux.Path.Content) + if err != nil { + return err + } + h.Path = to.Ptr(string(name)) + } else { + h.Path = aux.Path.Content + } + } + return nil +} + +// UnmarshalXML implements the xml.Unmarshaller interface for type Directory. +func (d *Directory) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { + type alias Directory + aux := &struct { + *alias + Name *StringEncoded `xml:"Name"` + }{ + alias: (*alias)(d), + } + if err := dec.DecodeElement(aux, &start); err != nil { + return err + } + if aux.Name != nil { + if aux.Name.Encoded != nil && *aux.Name.Encoded { + name, err := url.QueryUnescape(*aux.Name.Content) + if err != nil { + return err + } + d.Name = to.Ptr(string(name)) + } else { + d.Name = aux.Name.Content + } + } + return nil +} + +// UnmarshalXML implements the xml.Unmarshaller interface for type File. +func (f *File) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { + type alias File + aux := &struct { + *alias + Name *StringEncoded `xml:"Name"` + }{ + alias: (*alias)(f), + } + if err := dec.DecodeElement(aux, &start); err != nil { + return err + } + if aux.Name != nil { + if aux.Name.Encoded != nil && *aux.Name.Encoded { + name, err := url.QueryUnescape(*aux.Name.Content) + if err != nil { + return err + } + f.Name = to.Ptr(string(name)) + } else { + f.Name = aux.Name.Content + } + } + return nil +} + +// UnmarshalXML implements the xml.Unmarshaller interface for type ListFilesAndDirectoriesSegmentResponse. +func (l *ListFilesAndDirectoriesSegmentResponse) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { + type alias ListFilesAndDirectoriesSegmentResponse + aux := &struct { + *alias + Prefix *StringEncoded `xml:"Prefix"` + }{ + alias: (*alias)(l), + } + if err := dec.DecodeElement(aux, &start); err != nil { + return err + } + if aux.Prefix != nil { + if aux.Prefix.Encoded != nil && *aux.Prefix.Encoded { + name, err := url.QueryUnescape(*aux.Prefix.Content) + if err != nil { + return err + } + l.Prefix = to.Ptr(string(name)) + } else { + l.Prefix = aux.Prefix.Content + } + } + return nil +} diff --git a/sdk/storage/azfile/internal/generated/service_client.go b/sdk/storage/azfile/internal/generated/service_client.go index 1f449b955e82..8c99594b7dbd 100644 --- a/sdk/storage/azfile/internal/generated/service_client.go +++ b/sdk/storage/azfile/internal/generated/service_client.go @@ -6,12 +6,25 @@ package generated -import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) func (client *ServiceClient) Endpoint() string { return client.endpoint } -func (client *ServiceClient) Pipeline() runtime.Pipeline { - return client.pl +func (client *ServiceClient) InternalClient() *azcore.Client { + return client.internal +} + +// NewServiceClient creates a new instance of ServiceClient with the specified values. +// - endpoint - The URL of the service account, share, directory or file that is the target of the desired operation. +// - azClient - azcore.Client is a basic HTTP client. It consists of a pipeline and tracing provider. +func NewServiceClient(endpoint string, azClient *azcore.Client) *ServiceClient { + client := &ServiceClient{ + internal: azClient, + endpoint: endpoint, + } + return client } diff --git a/sdk/storage/azfile/internal/generated/share_client.go b/sdk/storage/azfile/internal/generated/share_client.go index 040785814606..14f4d5bdefa2 100644 --- a/sdk/storage/azfile/internal/generated/share_client.go +++ b/sdk/storage/azfile/internal/generated/share_client.go @@ -6,12 +6,27 @@ package generated -import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) func (client *ShareClient) Endpoint() string { return client.endpoint } -func (client *ShareClient) Pipeline() runtime.Pipeline { - return client.pl +func (client *ShareClient) InternalClient() *azcore.Client { + return client.internal +} + +// NewShareClient creates a new instance of ShareClient with the specified values. +// - endpoint - The URL of the service account, share, directory or file that is the target of the desired operation. +// - fileRequestIntent - Valid value is backup +// - azClient - azcore.Client is a basic HTTP client. It consists of a pipeline and tracing provider. +func NewShareClient(endpoint string, fileRequestIntent *ShareTokenIntent, azClient *azcore.Client) *ShareClient { + client := &ShareClient{ + internal: azClient, + endpoint: endpoint, + fileRequestIntent: fileRequestIntent, + } + return client } diff --git a/sdk/storage/azfile/internal/generated/zz_constants.go b/sdk/storage/azfile/internal/generated/zz_constants.go index 13ee55aa841e..2f356c7c3f63 100644 --- a/sdk/storage/azfile/internal/generated/zz_constants.go +++ b/sdk/storage/azfile/internal/generated/zz_constants.go @@ -12,19 +12,19 @@ package generated type CopyStatusType string const ( - CopyStatusTypePending CopyStatusType = "pending" - CopyStatusTypeSuccess CopyStatusType = "success" CopyStatusTypeAborted CopyStatusType = "aborted" CopyStatusTypeFailed CopyStatusType = "failed" + CopyStatusTypePending CopyStatusType = "pending" + CopyStatusTypeSuccess CopyStatusType = "success" ) // PossibleCopyStatusTypeValues returns the possible values for the CopyStatusType const type. func PossibleCopyStatusTypeValues() []CopyStatusType { return []CopyStatusType{ - CopyStatusTypePending, - CopyStatusTypeSuccess, CopyStatusTypeAborted, CopyStatusTypeFailed, + CopyStatusTypePending, + CopyStatusTypeSuccess, } } @@ -43,18 +43,33 @@ func PossibleDeleteSnapshotsOptionTypeValues() []DeleteSnapshotsOptionType { } } +type FileLastWrittenMode string + +const ( + FileLastWrittenModeNow FileLastWrittenMode = "Now" + FileLastWrittenModePreserve FileLastWrittenMode = "Preserve" +) + +// PossibleFileLastWrittenModeValues returns the possible values for the FileLastWrittenMode const type. +func PossibleFileLastWrittenModeValues() []FileLastWrittenMode { + return []FileLastWrittenMode{ + FileLastWrittenModeNow, + FileLastWrittenModePreserve, + } +} + type FileRangeWriteType string const ( - FileRangeWriteTypeUpdate FileRangeWriteType = "update" FileRangeWriteTypeClear FileRangeWriteType = "clear" + FileRangeWriteTypeUpdate FileRangeWriteType = "update" ) // PossibleFileRangeWriteTypeValues returns the possible values for the FileRangeWriteType const type. func PossibleFileRangeWriteTypeValues() []FileRangeWriteType { return []FileRangeWriteType{ - FileRangeWriteTypeUpdate, FileRangeWriteTypeClear, + FileRangeWriteTypeUpdate, } } @@ -62,15 +77,15 @@ func PossibleFileRangeWriteTypeValues() []FileRangeWriteType { type LeaseDurationType string const ( - LeaseDurationTypeInfinite LeaseDurationType = "infinite" LeaseDurationTypeFixed LeaseDurationType = "fixed" + LeaseDurationTypeInfinite LeaseDurationType = "infinite" ) // PossibleLeaseDurationTypeValues returns the possible values for the LeaseDurationType const type. func PossibleLeaseDurationTypeValues() []LeaseDurationType { return []LeaseDurationType{ - LeaseDurationTypeInfinite, LeaseDurationTypeFixed, + LeaseDurationTypeInfinite, } } @@ -79,20 +94,20 @@ type LeaseStateType string const ( LeaseStateTypeAvailable LeaseStateType = "available" - LeaseStateTypeLeased LeaseStateType = "leased" - LeaseStateTypeExpired LeaseStateType = "expired" LeaseStateTypeBreaking LeaseStateType = "breaking" LeaseStateTypeBroken LeaseStateType = "broken" + LeaseStateTypeExpired LeaseStateType = "expired" + LeaseStateTypeLeased LeaseStateType = "leased" ) // PossibleLeaseStateTypeValues returns the possible values for the LeaseStateType const type. func PossibleLeaseStateTypeValues() []LeaseStateType { return []LeaseStateType{ LeaseStateTypeAvailable, - LeaseStateTypeLeased, - LeaseStateTypeExpired, LeaseStateTypeBreaking, LeaseStateTypeBroken, + LeaseStateTypeExpired, + LeaseStateTypeLeased, } } @@ -115,51 +130,51 @@ func PossibleLeaseStatusTypeValues() []LeaseStatusType { type ListFilesIncludeType string const ( - ListFilesIncludeTypeTimestamps ListFilesIncludeType = "Timestamps" - ListFilesIncludeTypeEtag ListFilesIncludeType = "Etag" ListFilesIncludeTypeAttributes ListFilesIncludeType = "Attributes" + ListFilesIncludeTypeEtag ListFilesIncludeType = "Etag" ListFilesIncludeTypePermissionKey ListFilesIncludeType = "PermissionKey" + ListFilesIncludeTypeTimestamps ListFilesIncludeType = "Timestamps" ) // PossibleListFilesIncludeTypeValues returns the possible values for the ListFilesIncludeType const type. func PossibleListFilesIncludeTypeValues() []ListFilesIncludeType { return []ListFilesIncludeType{ - ListFilesIncludeTypeTimestamps, - ListFilesIncludeTypeEtag, ListFilesIncludeTypeAttributes, + ListFilesIncludeTypeEtag, ListFilesIncludeTypePermissionKey, + ListFilesIncludeTypeTimestamps, } } type ListSharesIncludeType string const ( - ListSharesIncludeTypeSnapshots ListSharesIncludeType = "snapshots" - ListSharesIncludeTypeMetadata ListSharesIncludeType = "metadata" ListSharesIncludeTypeDeleted ListSharesIncludeType = "deleted" + ListSharesIncludeTypeMetadata ListSharesIncludeType = "metadata" + ListSharesIncludeTypeSnapshots ListSharesIncludeType = "snapshots" ) // PossibleListSharesIncludeTypeValues returns the possible values for the ListSharesIncludeType const type. func PossibleListSharesIncludeTypeValues() []ListSharesIncludeType { return []ListSharesIncludeType{ - ListSharesIncludeTypeSnapshots, - ListSharesIncludeTypeMetadata, ListSharesIncludeTypeDeleted, + ListSharesIncludeTypeMetadata, + ListSharesIncludeTypeSnapshots, } } type PermissionCopyModeType string const ( - PermissionCopyModeTypeSource PermissionCopyModeType = "source" PermissionCopyModeTypeOverride PermissionCopyModeType = "override" + PermissionCopyModeTypeSource PermissionCopyModeType = "source" ) // PossiblePermissionCopyModeTypeValues returns the possible values for the PermissionCopyModeType const type. func PossiblePermissionCopyModeTypeValues() []PermissionCopyModeType { return []PermissionCopyModeType{ - PermissionCopyModeTypeSource, PermissionCopyModeTypeOverride, + PermissionCopyModeTypeSource, } } @@ -183,17 +198,30 @@ func PossibleShareAccessTierValues() []ShareAccessTier { type ShareRootSquash string const ( + ShareRootSquashAllSquash ShareRootSquash = "AllSquash" ShareRootSquashNoRootSquash ShareRootSquash = "NoRootSquash" ShareRootSquashRootSquash ShareRootSquash = "RootSquash" - ShareRootSquashAllSquash ShareRootSquash = "AllSquash" ) // PossibleShareRootSquashValues returns the possible values for the ShareRootSquash const type. func PossibleShareRootSquashValues() []ShareRootSquash { return []ShareRootSquash{ + ShareRootSquashAllSquash, ShareRootSquashNoRootSquash, ShareRootSquashRootSquash, - ShareRootSquashAllSquash, + } +} + +type ShareTokenIntent string + +const ( + ShareTokenIntentBackup ShareTokenIntent = "backup" +) + +// PossibleShareTokenIntentValues returns the possible values for the ShareTokenIntent const type. +func PossibleShareTokenIntentValues() []ShareTokenIntent { + return []ShareTokenIntent{ + ShareTokenIntentBackup, } } diff --git a/sdk/storage/azfile/internal/generated/zz_directory_client.go b/sdk/storage/azfile/internal/generated/zz_directory_client.go index 1b1eed71d03f..4e05f2f7d860 100644 --- a/sdk/storage/azfile/internal/generated/zz_directory_client.go +++ b/sdk/storage/azfile/internal/generated/zz_directory_client.go @@ -23,38 +23,26 @@ import ( ) // DirectoryClient contains the methods for the Directory group. -// Don't use this type directly, use NewDirectoryClient() instead. +// Don't use this type directly, use a constructor function instead. type DirectoryClient struct { - endpoint string - pl runtime.Pipeline -} - -// NewDirectoryClient creates a new instance of DirectoryClient with the specified values. -// - endpoint - The URL of the service account, share, directory or file that is the target of the desired operation. -// - pl - the pipeline used for sending requests and handling responses. -func NewDirectoryClient(endpoint string, pl runtime.Pipeline) *DirectoryClient { - client := &DirectoryClient{ - endpoint: endpoint, - pl: pl, - } - return client + internal *azcore.Client + endpoint string + allowTrailingDot *bool + fileRequestIntent *ShareTokenIntent + allowSourceTrailingDot *bool } // Create - Creates a new directory under the specified share or parent directory. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 -// - fileAttributes - If specified, the provided file attributes shall be set. Default value: ‘Archive’ for file and ‘Directory’ -// for directory. ‘None’ can also be specified as default. -// - fileCreationTime - Creation time for the file/directory. Default value: Now. -// - fileLastWriteTime - Last write time for the file/directory. Default value: Now. +// Generated from API version 2022-11-02 // - options - DirectoryClientCreateOptions contains the optional parameters for the DirectoryClient.Create method. -func (client *DirectoryClient) Create(ctx context.Context, fileAttributes string, fileCreationTime string, fileLastWriteTime string, options *DirectoryClientCreateOptions) (DirectoryClientCreateResponse, error) { - req, err := client.createCreateRequest(ctx, fileAttributes, fileCreationTime, fileLastWriteTime, options) +func (client *DirectoryClient) Create(ctx context.Context, options *DirectoryClientCreateOptions) (DirectoryClientCreateResponse, error) { + req, err := client.createCreateRequest(ctx, options) if err != nil { return DirectoryClientCreateResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return DirectoryClientCreateResponse{}, err } @@ -65,7 +53,7 @@ func (client *DirectoryClient) Create(ctx context.Context, fileAttributes string } // createCreateRequest creates the Create request. -func (client *DirectoryClient) createCreateRequest(ctx context.Context, fileAttributes string, fileCreationTime string, fileLastWriteTime string, options *DirectoryClientCreateOptions) (*policy.Request, error) { +func (client *DirectoryClient) createCreateRequest(ctx context.Context, options *DirectoryClientCreateOptions) (*policy.Request, error) { req, err := runtime.NewRequest(ctx, http.MethodPut, client.endpoint) if err != nil { return nil, err @@ -76,6 +64,9 @@ func (client *DirectoryClient) createCreateRequest(ctx context.Context, fileAttr reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } if options != nil && options.Metadata != nil { for k, v := range options.Metadata { if v != nil { @@ -83,16 +74,28 @@ func (client *DirectoryClient) createCreateRequest(ctx context.Context, fileAttr } } } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.FilePermission != nil { req.Raw().Header["x-ms-file-permission"] = []string{*options.FilePermission} } if options != nil && options.FilePermissionKey != nil { req.Raw().Header["x-ms-file-permission-key"] = []string{*options.FilePermissionKey} } - req.Raw().Header["x-ms-file-attributes"] = []string{fileAttributes} - req.Raw().Header["x-ms-file-creation-time"] = []string{fileCreationTime} - req.Raw().Header["x-ms-file-last-write-time"] = []string{fileLastWriteTime} + if options != nil && options.FileAttributes != nil { + req.Raw().Header["x-ms-file-attributes"] = []string{*options.FileAttributes} + } + if options != nil && options.FileCreationTime != nil { + req.Raw().Header["x-ms-file-creation-time"] = []string{*options.FileCreationTime} + } + if options != nil && options.FileLastWriteTime != nil { + req.Raw().Header["x-ms-file-last-write-time"] = []string{*options.FileLastWriteTime} + } + if options != nil && options.FileChangeTime != nil { + req.Raw().Header["x-ms-file-change-time"] = []string{*options.FileChangeTime} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -169,14 +172,14 @@ func (client *DirectoryClient) createHandleResponse(resp *http.Response) (Direct // Delete - Removes the specified empty directory. Note that the directory must be empty before it can be deleted. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - DirectoryClientDeleteOptions contains the optional parameters for the DirectoryClient.Delete method. func (client *DirectoryClient) Delete(ctx context.Context, options *DirectoryClientDeleteOptions) (DirectoryClientDeleteResponse, error) { req, err := client.deleteCreateRequest(ctx, options) if err != nil { return DirectoryClientDeleteResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return DirectoryClientDeleteResponse{}, err } @@ -198,7 +201,13 @@ func (client *DirectoryClient) deleteCreateRequest(ctx context.Context, options reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -225,7 +234,7 @@ func (client *DirectoryClient) deleteHandleResponse(resp *http.Response) (Direct // ForceCloseHandles - Closes all handles open for given directory. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - handleID - Specifies handle ID opened on the file or directory to be closed. Asterisk (‘*’) is a wildcard that specifies // all handles. // - options - DirectoryClientForceCloseHandlesOptions contains the optional parameters for the DirectoryClient.ForceCloseHandles @@ -235,7 +244,7 @@ func (client *DirectoryClient) ForceCloseHandles(ctx context.Context, handleID s if err != nil { return DirectoryClientForceCloseHandlesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return DirectoryClientForceCloseHandlesResponse{}, err } @@ -267,7 +276,13 @@ func (client *DirectoryClient) forceCloseHandlesCreateRequest(ctx context.Contex if options != nil && options.Recursive != nil { req.Raw().Header["x-ms-recursive"] = []string{strconv.FormatBool(*options.Recursive)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -315,14 +330,14 @@ func (client *DirectoryClient) forceCloseHandlesHandleResponse(resp *http.Respon // subdirectories. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - DirectoryClientGetPropertiesOptions contains the optional parameters for the DirectoryClient.GetProperties method. func (client *DirectoryClient) GetProperties(ctx context.Context, options *DirectoryClientGetPropertiesOptions) (DirectoryClientGetPropertiesResponse, error) { req, err := client.getPropertiesCreateRequest(ctx, options) if err != nil { return DirectoryClientGetPropertiesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return DirectoryClientGetPropertiesResponse{}, err } @@ -347,7 +362,13 @@ func (client *DirectoryClient) getPropertiesCreateRequest(ctx context.Context, o reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -432,7 +453,7 @@ func (client *DirectoryClient) getPropertiesHandleResponse(resp *http.Response) // NewListFilesAndDirectoriesSegmentPager - Returns a list of files or directories under the specified share or directory. // It lists the contents only for a single level of the directory hierarchy. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - DirectoryClientListFilesAndDirectoriesSegmentOptions contains the optional parameters for the DirectoryClient.NewListFilesAndDirectoriesSegmentPager // method. // @@ -464,10 +485,16 @@ func (client *DirectoryClient) ListFilesAndDirectoriesSegmentCreateRequest(ctx c reqQP.Set("include", strings.Join(strings.Fields(strings.Trim(fmt.Sprint(options.Include), "[]")), ",")) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.IncludeExtendedInfo != nil { req.Raw().Header["x-ms-file-extended-info"] = []string{strconv.FormatBool(*options.IncludeExtendedInfo)} } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -500,14 +527,14 @@ func (client *DirectoryClient) ListFilesAndDirectoriesSegmentHandleResponse(resp // ListHandles - Lists handles for directory. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - DirectoryClientListHandlesOptions contains the optional parameters for the DirectoryClient.ListHandles method. func (client *DirectoryClient) ListHandles(ctx context.Context, options *DirectoryClientListHandlesOptions) (DirectoryClientListHandlesResponse, error) { req, err := client.listHandlesCreateRequest(ctx, options) if err != nil { return DirectoryClientListHandlesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return DirectoryClientListHandlesResponse{}, err } @@ -541,7 +568,13 @@ func (client *DirectoryClient) listHandlesCreateRequest(ctx context.Context, opt if options != nil && options.Recursive != nil { req.Raw().Header["x-ms-recursive"] = []string{strconv.FormatBool(*options.Recursive)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -571,17 +604,177 @@ func (client *DirectoryClient) listHandlesHandleResponse(resp *http.Response) (D return result, nil } +// Rename - Renames a directory +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2022-11-02 +// - renameSource - Required. Specifies the URI-style path of the source file, up to 2 KB in length. +// - options - DirectoryClientRenameOptions contains the optional parameters for the DirectoryClient.Rename method. +// - SourceLeaseAccessConditions - SourceLeaseAccessConditions contains a group of parameters for the DirectoryClient.Rename +// method. +// - DestinationLeaseAccessConditions - DestinationLeaseAccessConditions contains a group of parameters for the DirectoryClient.Rename +// method. +// - CopyFileSMBInfo - CopyFileSMBInfo contains a group of parameters for the DirectoryClient.Rename method. +func (client *DirectoryClient) Rename(ctx context.Context, renameSource string, options *DirectoryClientRenameOptions, sourceLeaseAccessConditions *SourceLeaseAccessConditions, destinationLeaseAccessConditions *DestinationLeaseAccessConditions, copyFileSMBInfo *CopyFileSMBInfo) (DirectoryClientRenameResponse, error) { + req, err := client.renameCreateRequest(ctx, renameSource, options, sourceLeaseAccessConditions, destinationLeaseAccessConditions, copyFileSMBInfo) + if err != nil { + return DirectoryClientRenameResponse{}, err + } + resp, err := client.internal.Pipeline().Do(req) + if err != nil { + return DirectoryClientRenameResponse{}, err + } + if !runtime.HasStatusCode(resp, http.StatusOK) { + return DirectoryClientRenameResponse{}, runtime.NewResponseError(resp) + } + return client.renameHandleResponse(resp) +} + +// renameCreateRequest creates the Rename request. +func (client *DirectoryClient) renameCreateRequest(ctx context.Context, renameSource string, options *DirectoryClientRenameOptions, sourceLeaseAccessConditions *SourceLeaseAccessConditions, destinationLeaseAccessConditions *DestinationLeaseAccessConditions, copyFileSMBInfo *CopyFileSMBInfo) (*policy.Request, error) { + req, err := runtime.NewRequest(ctx, http.MethodPut, client.endpoint) + if err != nil { + return nil, err + } + reqQP := req.Raw().URL.Query() + reqQP.Set("restype", "directory") + reqQP.Set("comp", "rename") + if options != nil && options.Timeout != nil { + reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) + } + req.Raw().URL.RawQuery = reqQP.Encode() + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} + req.Raw().Header["x-ms-file-rename-source"] = []string{renameSource} + if options != nil && options.ReplaceIfExists != nil { + req.Raw().Header["x-ms-file-rename-replace-if-exists"] = []string{strconv.FormatBool(*options.ReplaceIfExists)} + } + if options != nil && options.IgnoreReadOnly != nil { + req.Raw().Header["x-ms-file-rename-ignore-readonly"] = []string{strconv.FormatBool(*options.IgnoreReadOnly)} + } + if sourceLeaseAccessConditions != nil && sourceLeaseAccessConditions.SourceLeaseID != nil { + req.Raw().Header["x-ms-source-lease-id"] = []string{*sourceLeaseAccessConditions.SourceLeaseID} + } + if destinationLeaseAccessConditions != nil && destinationLeaseAccessConditions.DestinationLeaseID != nil { + req.Raw().Header["x-ms-destination-lease-id"] = []string{*destinationLeaseAccessConditions.DestinationLeaseID} + } + if copyFileSMBInfo != nil && copyFileSMBInfo.FileAttributes != nil { + req.Raw().Header["x-ms-file-attributes"] = []string{*copyFileSMBInfo.FileAttributes} + } + if copyFileSMBInfo != nil && copyFileSMBInfo.FileCreationTime != nil { + req.Raw().Header["x-ms-file-creation-time"] = []string{*copyFileSMBInfo.FileCreationTime} + } + if copyFileSMBInfo != nil && copyFileSMBInfo.FileLastWriteTime != nil { + req.Raw().Header["x-ms-file-last-write-time"] = []string{*copyFileSMBInfo.FileLastWriteTime} + } + if copyFileSMBInfo != nil && copyFileSMBInfo.FileChangeTime != nil { + req.Raw().Header["x-ms-file-change-time"] = []string{*copyFileSMBInfo.FileChangeTime} + } + if options != nil && options.FilePermission != nil { + req.Raw().Header["x-ms-file-permission"] = []string{*options.FilePermission} + } + if options != nil && options.FilePermissionKey != nil { + req.Raw().Header["x-ms-file-permission-key"] = []string{*options.FilePermissionKey} + } + if options != nil && options.Metadata != nil { + for k, v := range options.Metadata { + if v != nil { + req.Raw().Header["x-ms-meta-"+k] = []string{*v} + } + } + } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.allowSourceTrailingDot != nil { + req.Raw().Header["x-ms-source-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowSourceTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } + req.Raw().Header["Accept"] = []string{"application/xml"} + return req, nil +} + +// renameHandleResponse handles the Rename response. +func (client *DirectoryClient) renameHandleResponse(resp *http.Response) (DirectoryClientRenameResponse, error) { + result := DirectoryClientRenameResponse{} + if val := resp.Header.Get("ETag"); val != "" { + result.ETag = (*azcore.ETag)(&val) + } + if val := resp.Header.Get("Last-Modified"); val != "" { + lastModified, err := time.Parse(time.RFC1123, val) + if err != nil { + return DirectoryClientRenameResponse{}, err + } + result.LastModified = &lastModified + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return DirectoryClientRenameResponse{}, err + } + result.Date = &date + } + if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" { + isServerEncrypted, err := strconv.ParseBool(val) + if err != nil { + return DirectoryClientRenameResponse{}, err + } + result.IsServerEncrypted = &isServerEncrypted + } + if val := resp.Header.Get("x-ms-file-permission-key"); val != "" { + result.FilePermissionKey = &val + } + if val := resp.Header.Get("x-ms-file-attributes"); val != "" { + result.FileAttributes = &val + } + if val := resp.Header.Get("x-ms-file-creation-time"); val != "" { + fileCreationTime, err := time.Parse(ISO8601, val) + if err != nil { + return DirectoryClientRenameResponse{}, err + } + result.FileCreationTime = &fileCreationTime + } + if val := resp.Header.Get("x-ms-file-last-write-time"); val != "" { + fileLastWriteTime, err := time.Parse(ISO8601, val) + if err != nil { + return DirectoryClientRenameResponse{}, err + } + result.FileLastWriteTime = &fileLastWriteTime + } + if val := resp.Header.Get("x-ms-file-change-time"); val != "" { + fileChangeTime, err := time.Parse(ISO8601, val) + if err != nil { + return DirectoryClientRenameResponse{}, err + } + result.FileChangeTime = &fileChangeTime + } + if val := resp.Header.Get("x-ms-file-id"); val != "" { + result.ID = &val + } + if val := resp.Header.Get("x-ms-file-parent-id"); val != "" { + result.ParentID = &val + } + return result, nil +} + // SetMetadata - Updates user defined metadata for the specified directory. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - DirectoryClientSetMetadataOptions contains the optional parameters for the DirectoryClient.SetMetadata method. func (client *DirectoryClient) SetMetadata(ctx context.Context, options *DirectoryClientSetMetadataOptions) (DirectoryClientSetMetadataResponse, error) { req, err := client.setMetadataCreateRequest(ctx, options) if err != nil { return DirectoryClientSetMetadataResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return DirectoryClientSetMetadataResponse{}, err } @@ -611,7 +804,13 @@ func (client *DirectoryClient) setMetadataCreateRequest(ctx context.Context, opt } } } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -648,18 +847,14 @@ func (client *DirectoryClient) setMetadataHandleResponse(resp *http.Response) (D // SetProperties - Sets properties on the directory. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 -// - fileAttributes - If specified, the provided file attributes shall be set. Default value: ‘Archive’ for file and ‘Directory’ -// for directory. ‘None’ can also be specified as default. -// - fileCreationTime - Creation time for the file/directory. Default value: Now. -// - fileLastWriteTime - Last write time for the file/directory. Default value: Now. +// Generated from API version 2022-11-02 // - options - DirectoryClientSetPropertiesOptions contains the optional parameters for the DirectoryClient.SetProperties method. -func (client *DirectoryClient) SetProperties(ctx context.Context, fileAttributes string, fileCreationTime string, fileLastWriteTime string, options *DirectoryClientSetPropertiesOptions) (DirectoryClientSetPropertiesResponse, error) { - req, err := client.setPropertiesCreateRequest(ctx, fileAttributes, fileCreationTime, fileLastWriteTime, options) +func (client *DirectoryClient) SetProperties(ctx context.Context, options *DirectoryClientSetPropertiesOptions) (DirectoryClientSetPropertiesResponse, error) { + req, err := client.setPropertiesCreateRequest(ctx, options) if err != nil { return DirectoryClientSetPropertiesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return DirectoryClientSetPropertiesResponse{}, err } @@ -670,7 +865,7 @@ func (client *DirectoryClient) SetProperties(ctx context.Context, fileAttributes } // setPropertiesCreateRequest creates the SetProperties request. -func (client *DirectoryClient) setPropertiesCreateRequest(ctx context.Context, fileAttributes string, fileCreationTime string, fileLastWriteTime string, options *DirectoryClientSetPropertiesOptions) (*policy.Request, error) { +func (client *DirectoryClient) setPropertiesCreateRequest(ctx context.Context, options *DirectoryClientSetPropertiesOptions) (*policy.Request, error) { req, err := runtime.NewRequest(ctx, http.MethodPut, client.endpoint) if err != nil { return nil, err @@ -682,16 +877,31 @@ func (client *DirectoryClient) setPropertiesCreateRequest(ctx context.Context, f reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.FilePermission != nil { req.Raw().Header["x-ms-file-permission"] = []string{*options.FilePermission} } if options != nil && options.FilePermissionKey != nil { req.Raw().Header["x-ms-file-permission-key"] = []string{*options.FilePermissionKey} } - req.Raw().Header["x-ms-file-attributes"] = []string{fileAttributes} - req.Raw().Header["x-ms-file-creation-time"] = []string{fileCreationTime} - req.Raw().Header["x-ms-file-last-write-time"] = []string{fileLastWriteTime} + if options != nil && options.FileAttributes != nil { + req.Raw().Header["x-ms-file-attributes"] = []string{*options.FileAttributes} + } + if options != nil && options.FileCreationTime != nil { + req.Raw().Header["x-ms-file-creation-time"] = []string{*options.FileCreationTime} + } + if options != nil && options.FileLastWriteTime != nil { + req.Raw().Header["x-ms-file-last-write-time"] = []string{*options.FileLastWriteTime} + } + if options != nil && options.FileChangeTime != nil { + req.Raw().Header["x-ms-file-change-time"] = []string{*options.FileChangeTime} + } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } diff --git a/sdk/storage/azfile/internal/generated/zz_file_client.go b/sdk/storage/azfile/internal/generated/zz_file_client.go index cfe2ea780a3b..fda41c5f79a3 100644 --- a/sdk/storage/azfile/internal/generated/zz_file_client.go +++ b/sdk/storage/azfile/internal/generated/zz_file_client.go @@ -24,27 +24,19 @@ import ( ) // FileClient contains the methods for the File group. -// Don't use this type directly, use NewFileClient() instead. +// Don't use this type directly, use a constructor function instead. type FileClient struct { - endpoint string - pl runtime.Pipeline -} - -// NewFileClient creates a new instance of FileClient with the specified values. -// - endpoint - The URL of the service account, share, directory or file that is the target of the desired operation. -// - pl - the pipeline used for sending requests and handling responses. -func NewFileClient(endpoint string, pl runtime.Pipeline) *FileClient { - client := &FileClient{ - endpoint: endpoint, - pl: pl, - } - return client + internal *azcore.Client + endpoint string + allowTrailingDot *bool + fileRequestIntent *ShareTokenIntent + allowSourceTrailingDot *bool } // AbortCopy - Aborts a pending Copy File operation, and leaves a destination file with zero length and full metadata. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - copyID - The copy identifier provided in the x-ms-copy-id header of the original Copy File operation. // - options - FileClientAbortCopyOptions contains the optional parameters for the FileClient.AbortCopy method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. @@ -53,7 +45,7 @@ func (client *FileClient) AbortCopy(ctx context.Context, copyID string, options if err != nil { return FileClientAbortCopyResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientAbortCopyResponse{}, err } @@ -77,10 +69,16 @@ func (client *FileClient) abortCopyCreateRequest(ctx context.Context, copyID str } req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["x-ms-copy-action"] = []string{"abort"} - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -107,7 +105,7 @@ func (client *FileClient) abortCopyHandleResponse(resp *http.Response) (FileClie // AcquireLease - [Update] The Lease File operation establishes and manages a lock on a file for write and delete operations // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - duration - Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite // lease can be between 15 and 60 seconds. A lease duration cannot be changed using // renew or change. @@ -117,7 +115,7 @@ func (client *FileClient) AcquireLease(ctx context.Context, duration int32, opti if err != nil { return FileClientAcquireLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientAcquireLeaseResponse{}, err } @@ -144,10 +142,16 @@ func (client *FileClient) acquireLeaseCreateRequest(ctx context.Context, duratio if options != nil && options.ProposedLeaseID != nil { req.Raw().Header["x-ms-proposed-lease-id"] = []string{*options.ProposedLeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -190,7 +194,7 @@ func (client *FileClient) acquireLeaseHandleResponse(resp *http.Response) (FileC // BreakLease - [Update] The Lease File operation establishes and manages a lock on a file for write and delete operations // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - FileClientBreakLeaseOptions contains the optional parameters for the FileClient.BreakLease method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *FileClient) BreakLease(ctx context.Context, options *FileClientBreakLeaseOptions, leaseAccessConditions *LeaseAccessConditions) (FileClientBreakLeaseResponse, error) { @@ -198,7 +202,7 @@ func (client *FileClient) BreakLease(ctx context.Context, options *FileClientBre if err != nil { return FileClientBreakLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientBreakLeaseResponse{}, err } @@ -224,10 +228,16 @@ func (client *FileClient) breakLeaseCreateRequest(ctx context.Context, options * if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -270,7 +280,7 @@ func (client *FileClient) breakLeaseHandleResponse(resp *http.Response) (FileCli // ChangeLease - [Update] The Lease File operation establishes and manages a lock on a file for write and delete operations // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - leaseID - Specifies the current lease ID on the resource. // - options - FileClientChangeLeaseOptions contains the optional parameters for the FileClient.ChangeLease method. func (client *FileClient) ChangeLease(ctx context.Context, leaseID string, options *FileClientChangeLeaseOptions) (FileClientChangeLeaseResponse, error) { @@ -278,7 +288,7 @@ func (client *FileClient) ChangeLease(ctx context.Context, leaseID string, optio if err != nil { return FileClientChangeLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientChangeLeaseResponse{}, err } @@ -305,10 +315,16 @@ func (client *FileClient) changeLeaseCreateRequest(ctx context.Context, leaseID if options != nil && options.ProposedLeaseID != nil { req.Raw().Header["x-ms-proposed-lease-id"] = []string{*options.ProposedLeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -351,21 +367,17 @@ func (client *FileClient) changeLeaseHandleResponse(resp *http.Response) (FileCl // Create - Creates a new file or replaces a file. Note it only initializes the file with no content. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - fileContentLength - Specifies the maximum size for the file, up to 4 TB. -// - fileAttributes - If specified, the provided file attributes shall be set. Default value: ‘Archive’ for file and ‘Directory’ -// for directory. ‘None’ can also be specified as default. -// - fileCreationTime - Creation time for the file/directory. Default value: Now. -// - fileLastWriteTime - Last write time for the file/directory. Default value: Now. // - options - FileClientCreateOptions contains the optional parameters for the FileClient.Create method. // - ShareFileHTTPHeaders - ShareFileHTTPHeaders contains a group of parameters for the FileClient.Create method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. -func (client *FileClient) Create(ctx context.Context, fileContentLength int64, fileAttributes string, fileCreationTime string, fileLastWriteTime string, options *FileClientCreateOptions, shareFileHTTPHeaders *ShareFileHTTPHeaders, leaseAccessConditions *LeaseAccessConditions) (FileClientCreateResponse, error) { - req, err := client.createCreateRequest(ctx, fileContentLength, fileAttributes, fileCreationTime, fileLastWriteTime, options, shareFileHTTPHeaders, leaseAccessConditions) +func (client *FileClient) Create(ctx context.Context, fileContentLength int64, options *FileClientCreateOptions, shareFileHTTPHeaders *ShareFileHTTPHeaders, leaseAccessConditions *LeaseAccessConditions) (FileClientCreateResponse, error) { + req, err := client.createCreateRequest(ctx, fileContentLength, options, shareFileHTTPHeaders, leaseAccessConditions) if err != nil { return FileClientCreateResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientCreateResponse{}, err } @@ -376,7 +388,7 @@ func (client *FileClient) Create(ctx context.Context, fileContentLength int64, f } // createCreateRequest creates the Create request. -func (client *FileClient) createCreateRequest(ctx context.Context, fileContentLength int64, fileAttributes string, fileCreationTime string, fileLastWriteTime string, options *FileClientCreateOptions, shareFileHTTPHeaders *ShareFileHTTPHeaders, leaseAccessConditions *LeaseAccessConditions) (*policy.Request, error) { +func (client *FileClient) createCreateRequest(ctx context.Context, fileContentLength int64, options *FileClientCreateOptions, shareFileHTTPHeaders *ShareFileHTTPHeaders, leaseAccessConditions *LeaseAccessConditions) (*policy.Request, error) { req, err := runtime.NewRequest(ctx, http.MethodPut, client.endpoint) if err != nil { return nil, err @@ -386,7 +398,10 @@ func (client *FileClient) createCreateRequest(ctx context.Context, fileContentLe reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} req.Raw().Header["x-ms-content-length"] = []string{strconv.FormatInt(fileContentLength, 10)} req.Raw().Header["x-ms-type"] = []string{"file"} if shareFileHTTPHeaders != nil && shareFileHTTPHeaders.ContentType != nil { @@ -420,12 +435,24 @@ func (client *FileClient) createCreateRequest(ctx context.Context, fileContentLe if options != nil && options.FilePermissionKey != nil { req.Raw().Header["x-ms-file-permission-key"] = []string{*options.FilePermissionKey} } - req.Raw().Header["x-ms-file-attributes"] = []string{fileAttributes} - req.Raw().Header["x-ms-file-creation-time"] = []string{fileCreationTime} - req.Raw().Header["x-ms-file-last-write-time"] = []string{fileLastWriteTime} + if options != nil && options.FileAttributes != nil { + req.Raw().Header["x-ms-file-attributes"] = []string{*options.FileAttributes} + } + if options != nil && options.FileCreationTime != nil { + req.Raw().Header["x-ms-file-creation-time"] = []string{*options.FileCreationTime} + } + if options != nil && options.FileLastWriteTime != nil { + req.Raw().Header["x-ms-file-last-write-time"] = []string{*options.FileLastWriteTime} + } + if options != nil && options.FileChangeTime != nil { + req.Raw().Header["x-ms-file-change-time"] = []string{*options.FileChangeTime} + } if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -502,7 +529,7 @@ func (client *FileClient) createHandleResponse(resp *http.Response) (FileClientC // Delete - removes the file from the storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - FileClientDeleteOptions contains the optional parameters for the FileClient.Delete method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *FileClient) Delete(ctx context.Context, options *FileClientDeleteOptions, leaseAccessConditions *LeaseAccessConditions) (FileClientDeleteResponse, error) { @@ -510,7 +537,7 @@ func (client *FileClient) Delete(ctx context.Context, options *FileClientDeleteO if err != nil { return FileClientDeleteResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientDeleteResponse{}, err } @@ -531,10 +558,16 @@ func (client *FileClient) deleteCreateRequest(ctx context.Context, options *File reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -561,7 +594,7 @@ func (client *FileClient) deleteHandleResponse(resp *http.Response) (FileClientD // Download - Reads or downloads a file from the system, including its metadata and properties. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - FileClientDownloadOptions contains the optional parameters for the FileClient.Download method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *FileClient) Download(ctx context.Context, options *FileClientDownloadOptions, leaseAccessConditions *LeaseAccessConditions) (FileClientDownloadResponse, error) { @@ -569,7 +602,7 @@ func (client *FileClient) Download(ctx context.Context, options *FileClientDownl if err != nil { return FileClientDownloadResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientDownloadResponse{}, err } @@ -591,7 +624,10 @@ func (client *FileClient) downloadCreateRequest(ctx context.Context, options *Fi } req.Raw().URL.RawQuery = reqQP.Encode() runtime.SkipBodyDownload(req) - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.Range != nil { req.Raw().Header["x-ms-range"] = []string{*options.Range} } @@ -601,6 +637,9 @@ func (client *FileClient) downloadCreateRequest(ctx context.Context, options *Fi if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -758,7 +797,7 @@ func (client *FileClient) downloadHandleResponse(resp *http.Response) (FileClien // ForceCloseHandles - Closes all handles open for given file // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - handleID - Specifies handle ID opened on the file or directory to be closed. Asterisk (‘*’) is a wildcard that specifies // all handles. // - options - FileClientForceCloseHandlesOptions contains the optional parameters for the FileClient.ForceCloseHandles method. @@ -767,7 +806,7 @@ func (client *FileClient) ForceCloseHandles(ctx context.Context, handleID string if err != nil { return FileClientForceCloseHandlesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientForceCloseHandlesResponse{}, err } @@ -796,7 +835,13 @@ func (client *FileClient) forceCloseHandlesCreateRequest(ctx context.Context, ha } req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["x-ms-handle-id"] = []string{handleID} - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -843,7 +888,7 @@ func (client *FileClient) forceCloseHandlesHandleResponse(resp *http.Response) ( // not return the content of the file. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - FileClientGetPropertiesOptions contains the optional parameters for the FileClient.GetProperties method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *FileClient) GetProperties(ctx context.Context, options *FileClientGetPropertiesOptions, leaseAccessConditions *LeaseAccessConditions) (FileClientGetPropertiesResponse, error) { @@ -851,7 +896,7 @@ func (client *FileClient) GetProperties(ctx context.Context, options *FileClient if err != nil { return FileClientGetPropertiesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientGetPropertiesResponse{}, err } @@ -875,10 +920,16 @@ func (client *FileClient) getPropertiesCreateRequest(ctx context.Context, option reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -1026,7 +1077,7 @@ func (client *FileClient) getPropertiesHandleResponse(resp *http.Response) (File // GetRangeList - Returns the list of valid ranges for a file. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - FileClientGetRangeListOptions contains the optional parameters for the FileClient.GetRangeList method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *FileClient) GetRangeList(ctx context.Context, options *FileClientGetRangeListOptions, leaseAccessConditions *LeaseAccessConditions) (FileClientGetRangeListResponse, error) { @@ -1034,7 +1085,7 @@ func (client *FileClient) GetRangeList(ctx context.Context, options *FileClientG if err != nil { return FileClientGetRangeListResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientGetRangeListResponse{}, err } @@ -1062,13 +1113,19 @@ func (client *FileClient) getRangeListCreateRequest(ctx context.Context, options reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.Range != nil { req.Raw().Header["x-ms-range"] = []string{*options.Range} } if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -1115,14 +1172,14 @@ func (client *FileClient) getRangeListHandleResponse(resp *http.Response) (FileC // ListHandles - Lists handles for file // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - FileClientListHandlesOptions contains the optional parameters for the FileClient.ListHandles method. func (client *FileClient) ListHandles(ctx context.Context, options *FileClientListHandlesOptions) (FileClientListHandlesResponse, error) { req, err := client.listHandlesCreateRequest(ctx, options) if err != nil { return FileClientListHandlesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientListHandlesResponse{}, err } @@ -1153,7 +1210,13 @@ func (client *FileClient) listHandlesCreateRequest(ctx context.Context, options reqQP.Set("sharesnapshot", *options.Sharesnapshot) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -1186,7 +1249,7 @@ func (client *FileClient) listHandlesHandleResponse(resp *http.Response) (FileCl // ReleaseLease - [Update] The Lease File operation establishes and manages a lock on a file for write and delete operations // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - leaseID - Specifies the current lease ID on the resource. // - options - FileClientReleaseLeaseOptions contains the optional parameters for the FileClient.ReleaseLease method. func (client *FileClient) ReleaseLease(ctx context.Context, leaseID string, options *FileClientReleaseLeaseOptions) (FileClientReleaseLeaseResponse, error) { @@ -1194,7 +1257,7 @@ func (client *FileClient) ReleaseLease(ctx context.Context, leaseID string, opti if err != nil { return FileClientReleaseLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientReleaseLeaseResponse{}, err } @@ -1218,10 +1281,16 @@ func (client *FileClient) releaseLeaseCreateRequest(ctx context.Context, leaseID req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["x-ms-lease-action"] = []string{"release"} req.Raw().Header["x-ms-lease-id"] = []string{leaseID} - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -1258,23 +1327,182 @@ func (client *FileClient) releaseLeaseHandleResponse(resp *http.Response) (FileC return result, nil } +// Rename - Renames a file +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2022-11-02 +// - renameSource - Required. Specifies the URI-style path of the source file, up to 2 KB in length. +// - options - FileClientRenameOptions contains the optional parameters for the FileClient.Rename method. +// - SourceLeaseAccessConditions - SourceLeaseAccessConditions contains a group of parameters for the DirectoryClient.Rename +// method. +// - DestinationLeaseAccessConditions - DestinationLeaseAccessConditions contains a group of parameters for the DirectoryClient.Rename +// method. +// - CopyFileSMBInfo - CopyFileSMBInfo contains a group of parameters for the DirectoryClient.Rename method. +// - ShareFileHTTPHeaders - ShareFileHTTPHeaders contains a group of parameters for the FileClient.Create method. +func (client *FileClient) Rename(ctx context.Context, renameSource string, options *FileClientRenameOptions, sourceLeaseAccessConditions *SourceLeaseAccessConditions, destinationLeaseAccessConditions *DestinationLeaseAccessConditions, copyFileSMBInfo *CopyFileSMBInfo, shareFileHTTPHeaders *ShareFileHTTPHeaders) (FileClientRenameResponse, error) { + req, err := client.renameCreateRequest(ctx, renameSource, options, sourceLeaseAccessConditions, destinationLeaseAccessConditions, copyFileSMBInfo, shareFileHTTPHeaders) + if err != nil { + return FileClientRenameResponse{}, err + } + resp, err := client.internal.Pipeline().Do(req) + if err != nil { + return FileClientRenameResponse{}, err + } + if !runtime.HasStatusCode(resp, http.StatusOK) { + return FileClientRenameResponse{}, runtime.NewResponseError(resp) + } + return client.renameHandleResponse(resp) +} + +// renameCreateRequest creates the Rename request. +func (client *FileClient) renameCreateRequest(ctx context.Context, renameSource string, options *FileClientRenameOptions, sourceLeaseAccessConditions *SourceLeaseAccessConditions, destinationLeaseAccessConditions *DestinationLeaseAccessConditions, copyFileSMBInfo *CopyFileSMBInfo, shareFileHTTPHeaders *ShareFileHTTPHeaders) (*policy.Request, error) { + req, err := runtime.NewRequest(ctx, http.MethodPut, client.endpoint) + if err != nil { + return nil, err + } + reqQP := req.Raw().URL.Query() + reqQP.Set("comp", "rename") + if options != nil && options.Timeout != nil { + reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) + } + req.Raw().URL.RawQuery = reqQP.Encode() + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} + req.Raw().Header["x-ms-file-rename-source"] = []string{renameSource} + if options != nil && options.ReplaceIfExists != nil { + req.Raw().Header["x-ms-file-rename-replace-if-exists"] = []string{strconv.FormatBool(*options.ReplaceIfExists)} + } + if options != nil && options.IgnoreReadOnly != nil { + req.Raw().Header["x-ms-file-rename-ignore-readonly"] = []string{strconv.FormatBool(*options.IgnoreReadOnly)} + } + if sourceLeaseAccessConditions != nil && sourceLeaseAccessConditions.SourceLeaseID != nil { + req.Raw().Header["x-ms-source-lease-id"] = []string{*sourceLeaseAccessConditions.SourceLeaseID} + } + if destinationLeaseAccessConditions != nil && destinationLeaseAccessConditions.DestinationLeaseID != nil { + req.Raw().Header["x-ms-destination-lease-id"] = []string{*destinationLeaseAccessConditions.DestinationLeaseID} + } + if copyFileSMBInfo != nil && copyFileSMBInfo.FileAttributes != nil { + req.Raw().Header["x-ms-file-attributes"] = []string{*copyFileSMBInfo.FileAttributes} + } + if copyFileSMBInfo != nil && copyFileSMBInfo.FileCreationTime != nil { + req.Raw().Header["x-ms-file-creation-time"] = []string{*copyFileSMBInfo.FileCreationTime} + } + if copyFileSMBInfo != nil && copyFileSMBInfo.FileLastWriteTime != nil { + req.Raw().Header["x-ms-file-last-write-time"] = []string{*copyFileSMBInfo.FileLastWriteTime} + } + if copyFileSMBInfo != nil && copyFileSMBInfo.FileChangeTime != nil { + req.Raw().Header["x-ms-file-change-time"] = []string{*copyFileSMBInfo.FileChangeTime} + } + if options != nil && options.FilePermission != nil { + req.Raw().Header["x-ms-file-permission"] = []string{*options.FilePermission} + } + if options != nil && options.FilePermissionKey != nil { + req.Raw().Header["x-ms-file-permission-key"] = []string{*options.FilePermissionKey} + } + if options != nil && options.Metadata != nil { + for k, v := range options.Metadata { + if v != nil { + req.Raw().Header["x-ms-meta-"+k] = []string{*v} + } + } + } + if shareFileHTTPHeaders != nil && shareFileHTTPHeaders.ContentType != nil { + req.Raw().Header["x-ms-content-type"] = []string{*shareFileHTTPHeaders.ContentType} + } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.allowSourceTrailingDot != nil { + req.Raw().Header["x-ms-source-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowSourceTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } + req.Raw().Header["Accept"] = []string{"application/xml"} + return req, nil +} + +// renameHandleResponse handles the Rename response. +func (client *FileClient) renameHandleResponse(resp *http.Response) (FileClientRenameResponse, error) { + result := FileClientRenameResponse{} + if val := resp.Header.Get("ETag"); val != "" { + result.ETag = (*azcore.ETag)(&val) + } + if val := resp.Header.Get("Last-Modified"); val != "" { + lastModified, err := time.Parse(time.RFC1123, val) + if err != nil { + return FileClientRenameResponse{}, err + } + result.LastModified = &lastModified + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return FileClientRenameResponse{}, err + } + result.Date = &date + } + if val := resp.Header.Get("x-ms-request-server-encrypted"); val != "" { + isServerEncrypted, err := strconv.ParseBool(val) + if err != nil { + return FileClientRenameResponse{}, err + } + result.IsServerEncrypted = &isServerEncrypted + } + if val := resp.Header.Get("x-ms-file-permission-key"); val != "" { + result.FilePermissionKey = &val + } + if val := resp.Header.Get("x-ms-file-attributes"); val != "" { + result.FileAttributes = &val + } + if val := resp.Header.Get("x-ms-file-creation-time"); val != "" { + fileCreationTime, err := time.Parse(ISO8601, val) + if err != nil { + return FileClientRenameResponse{}, err + } + result.FileCreationTime = &fileCreationTime + } + if val := resp.Header.Get("x-ms-file-last-write-time"); val != "" { + fileLastWriteTime, err := time.Parse(ISO8601, val) + if err != nil { + return FileClientRenameResponse{}, err + } + result.FileLastWriteTime = &fileLastWriteTime + } + if val := resp.Header.Get("x-ms-file-change-time"); val != "" { + fileChangeTime, err := time.Parse(ISO8601, val) + if err != nil { + return FileClientRenameResponse{}, err + } + result.FileChangeTime = &fileChangeTime + } + if val := resp.Header.Get("x-ms-file-id"); val != "" { + result.ID = &val + } + if val := resp.Header.Get("x-ms-file-parent-id"); val != "" { + result.ParentID = &val + } + return result, nil +} + // SetHTTPHeaders - Sets HTTP headers on the file. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 -// - fileAttributes - If specified, the provided file attributes shall be set. Default value: ‘Archive’ for file and ‘Directory’ -// for directory. ‘None’ can also be specified as default. -// - fileCreationTime - Creation time for the file/directory. Default value: Now. -// - fileLastWriteTime - Last write time for the file/directory. Default value: Now. +// Generated from API version 2022-11-02 // - options - FileClientSetHTTPHeadersOptions contains the optional parameters for the FileClient.SetHTTPHeaders method. // - ShareFileHTTPHeaders - ShareFileHTTPHeaders contains a group of parameters for the FileClient.Create method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. -func (client *FileClient) SetHTTPHeaders(ctx context.Context, fileAttributes string, fileCreationTime string, fileLastWriteTime string, options *FileClientSetHTTPHeadersOptions, shareFileHTTPHeaders *ShareFileHTTPHeaders, leaseAccessConditions *LeaseAccessConditions) (FileClientSetHTTPHeadersResponse, error) { - req, err := client.setHTTPHeadersCreateRequest(ctx, fileAttributes, fileCreationTime, fileLastWriteTime, options, shareFileHTTPHeaders, leaseAccessConditions) +func (client *FileClient) SetHTTPHeaders(ctx context.Context, options *FileClientSetHTTPHeadersOptions, shareFileHTTPHeaders *ShareFileHTTPHeaders, leaseAccessConditions *LeaseAccessConditions) (FileClientSetHTTPHeadersResponse, error) { + req, err := client.setHTTPHeadersCreateRequest(ctx, options, shareFileHTTPHeaders, leaseAccessConditions) if err != nil { return FileClientSetHTTPHeadersResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientSetHTTPHeadersResponse{}, err } @@ -1285,7 +1513,7 @@ func (client *FileClient) SetHTTPHeaders(ctx context.Context, fileAttributes str } // setHTTPHeadersCreateRequest creates the SetHTTPHeaders request. -func (client *FileClient) setHTTPHeadersCreateRequest(ctx context.Context, fileAttributes string, fileCreationTime string, fileLastWriteTime string, options *FileClientSetHTTPHeadersOptions, shareFileHTTPHeaders *ShareFileHTTPHeaders, leaseAccessConditions *LeaseAccessConditions) (*policy.Request, error) { +func (client *FileClient) setHTTPHeadersCreateRequest(ctx context.Context, options *FileClientSetHTTPHeadersOptions, shareFileHTTPHeaders *ShareFileHTTPHeaders, leaseAccessConditions *LeaseAccessConditions) (*policy.Request, error) { req, err := runtime.NewRequest(ctx, http.MethodPut, client.endpoint) if err != nil { return nil, err @@ -1296,7 +1524,7 @@ func (client *FileClient) setHTTPHeadersCreateRequest(ctx context.Context, fileA reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.FileContentLength != nil { req.Raw().Header["x-ms-content-length"] = []string{strconv.FormatInt(*options.FileContentLength, 10)} } @@ -1324,12 +1552,27 @@ func (client *FileClient) setHTTPHeadersCreateRequest(ctx context.Context, fileA if options != nil && options.FilePermissionKey != nil { req.Raw().Header["x-ms-file-permission-key"] = []string{*options.FilePermissionKey} } - req.Raw().Header["x-ms-file-attributes"] = []string{fileAttributes} - req.Raw().Header["x-ms-file-creation-time"] = []string{fileCreationTime} - req.Raw().Header["x-ms-file-last-write-time"] = []string{fileLastWriteTime} + if options != nil && options.FileAttributes != nil { + req.Raw().Header["x-ms-file-attributes"] = []string{*options.FileAttributes} + } + if options != nil && options.FileCreationTime != nil { + req.Raw().Header["x-ms-file-creation-time"] = []string{*options.FileCreationTime} + } + if options != nil && options.FileLastWriteTime != nil { + req.Raw().Header["x-ms-file-last-write-time"] = []string{*options.FileLastWriteTime} + } + if options != nil && options.FileChangeTime != nil { + req.Raw().Header["x-ms-file-change-time"] = []string{*options.FileChangeTime} + } if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -1406,7 +1649,7 @@ func (client *FileClient) setHTTPHeadersHandleResponse(resp *http.Response) (Fil // SetMetadata - Updates user-defined metadata for the specified file. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - FileClientSetMetadataOptions contains the optional parameters for the FileClient.SetMetadata method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *FileClient) SetMetadata(ctx context.Context, options *FileClientSetMetadataOptions, leaseAccessConditions *LeaseAccessConditions) (FileClientSetMetadataResponse, error) { @@ -1414,7 +1657,7 @@ func (client *FileClient) SetMetadata(ctx context.Context, options *FileClientSe if err != nil { return FileClientSetMetadataResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientSetMetadataResponse{}, err } @@ -1443,10 +1686,16 @@ func (client *FileClient) setMetadataCreateRequest(ctx context.Context, options } } } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -1490,7 +1739,7 @@ func (client *FileClient) setMetadataHandleResponse(resp *http.Response) (FileCl // StartCopy - Copies a blob or file to a destination file within the storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - copySource - Specifies the URL of the source file or blob, up to 2 KB in length. To copy a file to another file within // the same storage account, you may use Shared Key to authenticate the source file. If you are // copying a file from another storage account, or if you are copying a blob from the same storage account or another storage @@ -1498,14 +1747,14 @@ func (client *FileClient) setMetadataHandleResponse(resp *http.Response) (FileCl // access signature. If the source is a public blob, no authentication is required to perform the copy operation. A file in // a share snapshot can also be specified as a copy source. // - options - FileClientStartCopyOptions contains the optional parameters for the FileClient.StartCopy method. -// - CopyFileSMBInfo - CopyFileSMBInfo contains a group of parameters for the FileClient.StartCopy method. +// - CopyFileSMBInfo - CopyFileSMBInfo contains a group of parameters for the DirectoryClient.Rename method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *FileClient) StartCopy(ctx context.Context, copySource string, options *FileClientStartCopyOptions, copyFileSMBInfo *CopyFileSMBInfo, leaseAccessConditions *LeaseAccessConditions) (FileClientStartCopyResponse, error) { req, err := client.startCopyCreateRequest(ctx, copySource, options, copyFileSMBInfo, leaseAccessConditions) if err != nil { return FileClientStartCopyResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientStartCopyResponse{}, err } @@ -1526,7 +1775,7 @@ func (client *FileClient) startCopyCreateRequest(ctx context.Context, copySource reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.Metadata != nil { for k, v := range options.Metadata { if v != nil { @@ -1556,12 +1805,24 @@ func (client *FileClient) startCopyCreateRequest(ctx context.Context, copySource if copyFileSMBInfo != nil && copyFileSMBInfo.FileLastWriteTime != nil { req.Raw().Header["x-ms-file-last-write-time"] = []string{*copyFileSMBInfo.FileLastWriteTime} } + if copyFileSMBInfo != nil && copyFileSMBInfo.FileChangeTime != nil { + req.Raw().Header["x-ms-file-change-time"] = []string{*copyFileSMBInfo.FileChangeTime} + } if copyFileSMBInfo != nil && copyFileSMBInfo.SetArchiveAttribute != nil { req.Raw().Header["x-ms-file-copy-set-archive"] = []string{strconv.FormatBool(*copyFileSMBInfo.SetArchiveAttribute)} } if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.allowSourceTrailingDot != nil { + req.Raw().Header["x-ms-source-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowSourceTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -1604,7 +1865,7 @@ func (client *FileClient) startCopyHandleResponse(resp *http.Response) (FileClie // UploadRange - Upload a range of bytes to a file. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - rangeParam - Specifies the range of bytes to be written. Both the start and end of the range must be specified. For an // update operation, the range can be up to 4 MB in size. For a clear operation, the range can be // up to the value of the file's full size. The File service accepts only a single byte range for the Range and 'x-ms-range' @@ -1625,7 +1886,7 @@ func (client *FileClient) UploadRange(ctx context.Context, rangeParam string, fi if err != nil { return FileClientUploadRangeResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientUploadRangeResponse{}, err } @@ -1653,12 +1914,24 @@ func (client *FileClient) uploadRangeCreateRequest(ctx context.Context, rangePar if options != nil && options.ContentMD5 != nil { req.Raw().Header["Content-MD5"] = []string{base64.StdEncoding.EncodeToString(options.ContentMD5)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } + if options != nil && options.FileLastWrittenMode != nil { + req.Raw().Header["x-ms-file-last-write-time"] = []string{string(*options.FileLastWrittenMode)} + } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, req.SetBody(optionalbody, "application/octet-stream") + if err := req.SetBody(optionalbody, "application/octet-stream"); err != nil { + return nil, err + } + return req, nil } // uploadRangeHandleResponse handles the UploadRange response. @@ -1701,13 +1974,20 @@ func (client *FileClient) uploadRangeHandleResponse(resp *http.Response) (FileCl } result.IsServerEncrypted = &isServerEncrypted } + if val := resp.Header.Get("x-ms-file-last-write-time"); val != "" { + fileLastWriteTime, err := time.Parse(ISO8601, val) + if err != nil { + return FileClientUploadRangeResponse{}, err + } + result.FileLastWriteTime = &fileLastWriteTime + } return result, nil } // UploadRangeFromURL - Upload a range of bytes to a file where the contents are read from a URL. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - rangeParam - Writes data to the specified byte range in the file. // - copySource - Specifies the URL of the source file or blob, up to 2 KB in length. To copy a file to another file within // the same storage account, you may use Shared Key to authenticate the source file. If you are @@ -1726,7 +2006,7 @@ func (client *FileClient) UploadRangeFromURL(ctx context.Context, rangeParam str if err != nil { return FileClientUploadRangeFromURLResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return FileClientUploadRangeFromURLResponse{}, err } @@ -1764,13 +2044,22 @@ func (client *FileClient) uploadRangeFromURLCreateRequest(ctx context.Context, r if sourceModifiedAccessConditions != nil && sourceModifiedAccessConditions.SourceIfNoneMatchCRC64 != nil { req.Raw().Header["x-ms-source-if-none-match-crc64"] = []string{base64.StdEncoding.EncodeToString(sourceModifiedAccessConditions.SourceIfNoneMatchCRC64)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } if options != nil && options.CopySourceAuthorization != nil { req.Raw().Header["x-ms-copy-source-authorization"] = []string{*options.CopySourceAuthorization} } + if options != nil && options.FileLastWrittenMode != nil { + req.Raw().Header["x-ms-file-last-write-time"] = []string{string(*options.FileLastWrittenMode)} + } + if client.allowTrailingDot != nil { + req.Raw().Header["x-ms-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowTrailingDot)} + } + if client.allowSourceTrailingDot != nil { + req.Raw().Header["x-ms-source-allow-trailing-dot"] = []string{strconv.FormatBool(*client.allowSourceTrailingDot)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -1815,6 +2104,13 @@ func (client *FileClient) uploadRangeFromURLHandleResponse(resp *http.Response) } result.IsServerEncrypted = &isServerEncrypted } + if val := resp.Header.Get("x-ms-file-last-write-time"); val != "" { + fileLastWriteTime, err := time.Parse(ISO8601, val) + if err != nil { + return FileClientUploadRangeFromURLResponse{}, err + } + result.FileLastWriteTime = &fileLastWriteTime + } if val := resp.Header.Get("Content-MD5"); val != "" { contentMD5, err := base64.StdEncoding.DecodeString(val) if err != nil { diff --git a/sdk/storage/azfile/internal/generated/zz_models.go b/sdk/storage/azfile/internal/generated/zz_models.go index 95443aea430f..a27b53f42cea 100644 --- a/sdk/storage/azfile/internal/generated/zz_models.go +++ b/sdk/storage/azfile/internal/generated/zz_models.go @@ -34,11 +34,14 @@ type ClearRange struct { Start *int64 `xml:"Start"` } -// CopyFileSMBInfo contains a group of parameters for the FileClient.StartCopy method. +// CopyFileSMBInfo contains a group of parameters for the DirectoryClient.Rename method. type CopyFileSMBInfo struct { // Specifies either the option to copy file attributes from a source file(source) to a target file or a list of attributes // to set on a target file. FileAttributes *string + // Specifies either the option to copy file last write time from a source file(source) to a target file or a time value in + // ISO 8601 format to set as last write time on a target file. + FileChangeTime *string // Specifies either the option to copy file creation time from a source file(source) to a target file or a time value in ISO // 8601 format to set as creation time on a target file. FileCreationTime *string @@ -80,6 +83,16 @@ type CORSRule struct { MaxAgeInSeconds *int32 `xml:"MaxAgeInSeconds"` } +// DestinationLeaseAccessConditions contains a group of parameters for the DirectoryClient.Rename method. +type DestinationLeaseAccessConditions struct { + // Required if the destination file has an active infinite lease. The lease ID specified for this header must match the lease + // ID of the destination file. If the request does not include the lease ID or + // it is not valid, the operation fails with status code 412 (Precondition Failed). If this header is specified and the destination + // file does not currently have an active lease, the operation will also + // fail with status code 412 (Precondition Failed). + DestinationLeaseID *string +} + // Directory - A listed directory item. type Directory struct { // REQUIRED @@ -94,6 +107,15 @@ type Directory struct { // DirectoryClientCreateOptions contains the optional parameters for the DirectoryClient.Create method. type DirectoryClientCreateOptions struct { + // If specified, the provided file attributes shall be set. Default value: ‘Archive’ for file and ‘Directory’ for directory. + // ‘None’ can also be specified as default. + FileAttributes *string + // Change time for the file/directory. Default value: Now. + FileChangeTime *string + // Creation time for the file/directory. Default value: Now. + FileCreationTime *string + // Last write time for the file/directory. Default value: Now. + FileLastWriteTime *string // If specified the permission (security descriptor) shall be set for the directory/file. This header can be used if Permission // size is <= 8KB, else x-ms-file-permission-key header shall be used. Default // value: Inherit. If SDDL is specified as input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission @@ -184,6 +206,33 @@ type DirectoryClientListHandlesOptions struct { Timeout *int32 } +// DirectoryClientRenameOptions contains the optional parameters for the DirectoryClient.Rename method. +type DirectoryClientRenameOptions struct { + // If specified the permission (security descriptor) shall be set for the directory/file. This header can be used if Permission + // size is <= 8KB, else x-ms-file-permission-key header shall be used. Default + // value: Inherit. If SDDL is specified as input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission + // or x-ms-file-permission-key should be specified. + FilePermission *string + // Key of the permission to be set for the directory/file. Note: Only one of the x-ms-file-permission or x-ms-file-permission-key + // should be specified. + FilePermissionKey *string + // Optional. A boolean value that specifies whether the ReadOnly attribute on a preexisting destination file should be respected. + // If true, the rename will succeed, otherwise, a previous file at the + // destination with the ReadOnly attribute set will cause the rename to fail. + IgnoreReadOnly *bool + // A name-value pair to associate with a file storage object. + Metadata map[string]*string + // Optional. A boolean value for if the destination file already exists, whether this request will overwrite the file or not. + // If true, the rename will succeed and will overwrite the destination file. If + // not provided or if false and the destination file does exist, the request will not overwrite the destination file. If provided + // and the destination file doesn’t exist, the rename will succeed. Note: + // This value does not override the x-ms-file-copy-ignore-read-only header value. + ReplaceIfExists *bool + // The timeout parameter is expressed in seconds. For more information, see Setting Timeouts for File Service Operations. + // [https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN] + Timeout *int32 +} + // DirectoryClientSetMetadataOptions contains the optional parameters for the DirectoryClient.SetMetadata method. type DirectoryClientSetMetadataOptions struct { // A name-value pair to associate with a file storage object. @@ -195,6 +244,15 @@ type DirectoryClientSetMetadataOptions struct { // DirectoryClientSetPropertiesOptions contains the optional parameters for the DirectoryClient.SetProperties method. type DirectoryClientSetPropertiesOptions struct { + // If specified, the provided file attributes shall be set. Default value: ‘Archive’ for file and ‘Directory’ for directory. + // ‘None’ can also be specified as default. + FileAttributes *string + // Change time for the file/directory. Default value: Now. + FileChangeTime *string + // Creation time for the file/directory. Default value: Now. + FileCreationTime *string + // Last write time for the file/directory. Default value: Now. + FileLastWriteTime *string // If specified the permission (security descriptor) shall be set for the directory/file. This header can be used if Permission // size is <= 8KB, else x-ms-file-permission-key header shall be used. Default // value: Inherit. If SDDL is specified as input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission @@ -267,6 +325,15 @@ type FileClientChangeLeaseOptions struct { // FileClientCreateOptions contains the optional parameters for the FileClient.Create method. type FileClientCreateOptions struct { + // If specified, the provided file attributes shall be set. Default value: ‘Archive’ for file and ‘Directory’ for directory. + // ‘None’ can also be specified as default. + FileAttributes *string + // Change time for the file/directory. Default value: Now. + FileChangeTime *string + // Creation time for the file/directory. Default value: Now. + FileCreationTime *string + // Last write time for the file/directory. Default value: Now. + FileLastWriteTime *string // If specified the permission (security descriptor) shall be set for the directory/file. This header can be used if Permission // size is <= 8KB, else x-ms-file-permission-key header shall be used. Default // value: Inherit. If SDDL is specified as input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission @@ -364,11 +431,47 @@ type FileClientReleaseLeaseOptions struct { Timeout *int32 } +// FileClientRenameOptions contains the optional parameters for the FileClient.Rename method. +type FileClientRenameOptions struct { + // If specified the permission (security descriptor) shall be set for the directory/file. This header can be used if Permission + // size is <= 8KB, else x-ms-file-permission-key header shall be used. Default + // value: Inherit. If SDDL is specified as input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission + // or x-ms-file-permission-key should be specified. + FilePermission *string + // Key of the permission to be set for the directory/file. Note: Only one of the x-ms-file-permission or x-ms-file-permission-key + // should be specified. + FilePermissionKey *string + // Optional. A boolean value that specifies whether the ReadOnly attribute on a preexisting destination file should be respected. + // If true, the rename will succeed, otherwise, a previous file at the + // destination with the ReadOnly attribute set will cause the rename to fail. + IgnoreReadOnly *bool + // A name-value pair to associate with a file storage object. + Metadata map[string]*string + // Optional. A boolean value for if the destination file already exists, whether this request will overwrite the file or not. + // If true, the rename will succeed and will overwrite the destination file. If + // not provided or if false and the destination file does exist, the request will not overwrite the destination file. If provided + // and the destination file doesn’t exist, the rename will succeed. Note: + // This value does not override the x-ms-file-copy-ignore-read-only header value. + ReplaceIfExists *bool + // The timeout parameter is expressed in seconds. For more information, see Setting Timeouts for File Service Operations. + // [https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN] + Timeout *int32 +} + // FileClientSetHTTPHeadersOptions contains the optional parameters for the FileClient.SetHTTPHeaders method. type FileClientSetHTTPHeadersOptions struct { + // If specified, the provided file attributes shall be set. Default value: ‘Archive’ for file and ‘Directory’ for directory. + // ‘None’ can also be specified as default. + FileAttributes *string + // Change time for the file/directory. Default value: Now. + FileChangeTime *string // Resizes a file to the specified size. If the specified byte value is less than the current size of the file, then all ranges // above the specified byte value are cleared. FileContentLength *int64 + // Creation time for the file/directory. Default value: Now. + FileCreationTime *string + // Last write time for the file/directory. Default value: Now. + FileLastWriteTime *string // If specified the permission (security descriptor) shall be set for the directory/file. This header can be used if Permission // size is <= 8KB, else x-ms-file-permission-key header shall be used. Default // value: Inherit. If SDDL is specified as input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission @@ -412,6 +515,8 @@ type FileClientStartCopyOptions struct { type FileClientUploadRangeFromURLOptions struct { // Only Bearer type is supported. Credentials should be a valid OAuth access token to copy source. CopySourceAuthorization *string + // If the file last write time should be preserved or overwritten + FileLastWrittenMode *FileLastWrittenMode // Specify the crc64 calculated for the range of bytes that must be read from the copy source. SourceContentCRC64 []byte // Bytes of source data in the specified range. @@ -428,6 +533,8 @@ type FileClientUploadRangeOptions struct { // arrived with the header value that was sent. If the two hashes do not match, the operation will fail with error code 400 // (Bad Request). ContentMD5 []byte + // If the file last write time should be preserved or overwritten + FileLastWrittenMode *FileLastWrittenMode // The timeout parameter is expressed in seconds. For more information, see Setting Timeouts for File Service Operations. // [https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN] Timeout *int32 @@ -479,7 +586,7 @@ type Handle struct { // REQUIRED; Time when the session that previously opened the handle has last been reconnected. (UTC) OpenTime *time.Time `xml:"OpenTime"` - // REQUIRED; File or directory name including full path starting from share root + // REQUIRED Path *string `xml:"Path"` // REQUIRED; SMB session ID in context of which the file handle was opened @@ -518,6 +625,7 @@ type ListFilesAndDirectoriesSegmentResponse struct { // REQUIRED ShareName *string `xml:"ShareName,attr"` DirectoryID *string `xml:"DirectoryId"` + Encoded *bool `xml:"Encoded,attr"` Marker *string `xml:"Marker"` MaxResults *int32 `xml:"MaxResults"` ShareSnapshot *string `xml:"ShareSnapshot,attr"` @@ -847,7 +955,7 @@ type ShareFileRangeList struct { // SharePermission - A permission (a security descriptor) at the share level. type SharePermission struct { // REQUIRED; The permission in the Security Descriptor Definition Language (SDDL). - Permission *string `json:"permission,omitempty"` + Permission *string } // ShareProperties - Properties of a share. @@ -875,6 +983,7 @@ type ShareProperties struct { // The current lease status of the share. LeaseStatus *LeaseStatusType `xml:"LeaseStatus"` NextAllowedQuotaDowngradeTime *time.Time `xml:"NextAllowedQuotaDowngradeTime"` + ProvisionedBandwidthMiBps *int32 `xml:"ProvisionedBandwidthMiBps"` ProvisionedEgressMBps *int32 `xml:"ProvisionedEgressMBps"` ProvisionedIngressMBps *int32 `xml:"ProvisionedIngressMBps"` ProvisionedIops *int32 `xml:"ProvisionedIops"` @@ -904,6 +1013,12 @@ type SMBMultichannel struct { Enabled *bool `xml:"Enabled"` } +// SourceLeaseAccessConditions contains a group of parameters for the DirectoryClient.Rename method. +type SourceLeaseAccessConditions struct { + // Required if the source file has an active infinite lease. + SourceLeaseID *string +} + // SourceModifiedAccessConditions contains a group of parameters for the FileClient.UploadRangeFromURL method. type SourceModifiedAccessConditions struct { // Specify the crc64 value to operate only on range with a matching crc64 checksum. @@ -913,7 +1028,7 @@ type SourceModifiedAccessConditions struct { } type StorageError struct { - Message *string `json:"Message,omitempty"` + Message *string } // StorageServiceProperties - Storage service properties. @@ -930,3 +1045,8 @@ type StorageServiceProperties struct { // Protocol settings Protocol *ProtocolSettings `xml:"ProtocolSettings"` } + +type StringEncoded struct { + Content *string `xml:",chardata"` + Encoded *bool `xml:"Encoded,attr"` +} diff --git a/sdk/storage/azfile/internal/generated/zz_models_serde.go b/sdk/storage/azfile/internal/generated/zz_models_serde.go index 7f837baac65c..94664adc2280 100644 --- a/sdk/storage/azfile/internal/generated/zz_models_serde.go +++ b/sdk/storage/azfile/internal/generated/zz_models_serde.go @@ -115,39 +115,6 @@ func (f FilesAndDirectoriesListSegment) MarshalXML(enc *xml.Encoder, start xml.S return enc.EncodeElement(aux, start) } -// MarshalXML implements the xml.Marshaller interface for type Handle. -func (h Handle) MarshalXML(enc *xml.Encoder, start xml.StartElement) error { - type alias Handle - aux := &struct { - *alias - LastReconnectTime *timeRFC1123 `xml:"LastReconnectTime"` - OpenTime *timeRFC1123 `xml:"OpenTime"` - }{ - alias: (*alias)(&h), - LastReconnectTime: (*timeRFC1123)(h.LastReconnectTime), - OpenTime: (*timeRFC1123)(h.OpenTime), - } - return enc.EncodeElement(aux, start) -} - -// UnmarshalXML implements the xml.Unmarshaller interface for type Handle. -func (h *Handle) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { - type alias Handle - aux := &struct { - *alias - LastReconnectTime *timeRFC1123 `xml:"LastReconnectTime"` - OpenTime *timeRFC1123 `xml:"OpenTime"` - }{ - alias: (*alias)(h), - } - if err := dec.DecodeElement(aux, &start); err != nil { - return err - } - h.LastReconnectTime = (*time.Time)(aux.LastReconnectTime) - h.OpenTime = (*time.Time)(aux.OpenTime) - return nil -} - // MarshalXML implements the xml.Marshaller interface for type ListHandlesResponse. func (l ListHandlesResponse) MarshalXML(enc *xml.Encoder, start xml.StartElement) error { type alias ListHandlesResponse diff --git a/sdk/storage/azfile/internal/generated/zz_response_types.go b/sdk/storage/azfile/internal/generated/zz_response_types.go index be6bf1f60562..b94bd5e6fae4 100644 --- a/sdk/storage/azfile/internal/generated/zz_response_types.go +++ b/sdk/storage/azfile/internal/generated/zz_response_types.go @@ -167,6 +167,48 @@ type DirectoryClientListHandlesResponse struct { Version *string `xml:"Version"` } +// DirectoryClientRenameResponse contains the response from method DirectoryClient.Rename. +type DirectoryClientRenameResponse struct { + // Date contains the information returned from the Date header response. + Date *time.Time + + // ETag contains the information returned from the ETag header response. + ETag *azcore.ETag + + // FileAttributes contains the information returned from the x-ms-file-attributes header response. + FileAttributes *string + + // FileChangeTime contains the information returned from the x-ms-file-change-time header response. + FileChangeTime *time.Time + + // FileCreationTime contains the information returned from the x-ms-file-creation-time header response. + FileCreationTime *time.Time + + // ID contains the information returned from the x-ms-file-id header response. + ID *string + + // FileLastWriteTime contains the information returned from the x-ms-file-last-write-time header response. + FileLastWriteTime *time.Time + + // ParentID contains the information returned from the x-ms-file-parent-id header response. + ParentID *string + + // FilePermissionKey contains the information returned from the x-ms-file-permission-key header response. + FilePermissionKey *string + + // IsServerEncrypted contains the information returned from the x-ms-request-server-encrypted header response. + IsServerEncrypted *bool + + // LastModified contains the information returned from the Last-Modified header response. + LastModified *time.Time + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // Version contains the information returned from the x-ms-version header response. + Version *string +} + // DirectoryClientSetMetadataResponse contains the response from method DirectoryClient.SetMetadata. type DirectoryClientSetMetadataResponse struct { // Date contains the information returned from the Date header response. @@ -646,6 +688,48 @@ type FileClientReleaseLeaseResponse struct { Version *string } +// FileClientRenameResponse contains the response from method FileClient.Rename. +type FileClientRenameResponse struct { + // Date contains the information returned from the Date header response. + Date *time.Time + + // ETag contains the information returned from the ETag header response. + ETag *azcore.ETag + + // FileAttributes contains the information returned from the x-ms-file-attributes header response. + FileAttributes *string + + // FileChangeTime contains the information returned from the x-ms-file-change-time header response. + FileChangeTime *time.Time + + // FileCreationTime contains the information returned from the x-ms-file-creation-time header response. + FileCreationTime *time.Time + + // ID contains the information returned from the x-ms-file-id header response. + ID *string + + // FileLastWriteTime contains the information returned from the x-ms-file-last-write-time header response. + FileLastWriteTime *time.Time + + // ParentID contains the information returned from the x-ms-file-parent-id header response. + ParentID *string + + // FilePermissionKey contains the information returned from the x-ms-file-permission-key header response. + FilePermissionKey *string + + // IsServerEncrypted contains the information returned from the x-ms-request-server-encrypted header response. + IsServerEncrypted *bool + + // LastModified contains the information returned from the Last-Modified header response. + LastModified *time.Time + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string + + // Version contains the information returned from the x-ms-version header response. + Version *string +} + // FileClientSetHTTPHeadersResponse contains the response from method FileClient.SetHTTPHeaders. type FileClientSetHTTPHeadersResponse struct { // Date contains the information returned from the Date header response. @@ -744,6 +828,9 @@ type FileClientUploadRangeFromURLResponse struct { // ETag contains the information returned from the ETag header response. ETag *azcore.ETag + // FileLastWriteTime contains the information returned from the x-ms-file-last-write-time header response. + FileLastWriteTime *time.Time + // IsServerEncrypted contains the information returned from the x-ms-request-server-encrypted header response. IsServerEncrypted *bool @@ -771,6 +858,9 @@ type FileClientUploadRangeResponse struct { // ETag contains the information returned from the ETag header response. ETag *azcore.ETag + // FileLastWriteTime contains the information returned from the x-ms-file-last-write-time header response. + FileLastWriteTime *time.Time + // IsServerEncrypted contains the information returned from the x-ms-request-server-encrypted header response. IsServerEncrypted *bool @@ -1027,6 +1117,9 @@ type ShareClientGetPropertiesResponse struct { // response. NextAllowedQuotaDowngradeTime *time.Time + // ProvisionedBandwidthMiBps contains the information returned from the x-ms-share-provisioned-bandwidth-mibps header response. + ProvisionedBandwidthMiBps *int32 + // ProvisionedEgressMBps contains the information returned from the x-ms-share-provisioned-egress-mbps header response. ProvisionedEgressMBps *int32 diff --git a/sdk/storage/azfile/internal/generated/zz_service_client.go b/sdk/storage/azfile/internal/generated/zz_service_client.go index efd5f4708912..847b97903bae 100644 --- a/sdk/storage/azfile/internal/generated/zz_service_client.go +++ b/sdk/storage/azfile/internal/generated/zz_service_client.go @@ -12,6 +12,7 @@ package generated import ( "context" "fmt" + "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" "net/http" @@ -20,35 +21,24 @@ import ( ) // ServiceClient contains the methods for the Service group. -// Don't use this type directly, use NewServiceClient() instead. +// Don't use this type directly, use a constructor function instead. type ServiceClient struct { + internal *azcore.Client endpoint string - pl runtime.Pipeline -} - -// NewServiceClient creates a new instance of ServiceClient with the specified values. -// - endpoint - The URL of the service account, share, directory or file that is the target of the desired operation. -// - pl - the pipeline used for sending requests and handling responses. -func NewServiceClient(endpoint string, pl runtime.Pipeline) *ServiceClient { - client := &ServiceClient{ - endpoint: endpoint, - pl: pl, - } - return client } // GetProperties - Gets the properties of a storage account's File service, including properties for Storage Analytics metrics // and CORS (Cross-Origin Resource Sharing) rules. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ServiceClientGetPropertiesOptions contains the optional parameters for the ServiceClient.GetProperties method. func (client *ServiceClient) GetProperties(ctx context.Context, options *ServiceClientGetPropertiesOptions) (ServiceClientGetPropertiesResponse, error) { req, err := client.getPropertiesCreateRequest(ctx, options) if err != nil { return ServiceClientGetPropertiesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ServiceClientGetPropertiesResponse{}, err } @@ -71,7 +61,7 @@ func (client *ServiceClient) getPropertiesCreateRequest(ctx context.Context, opt reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -94,7 +84,7 @@ func (client *ServiceClient) getPropertiesHandleResponse(resp *http.Response) (S // NewListSharesSegmentPager - The List Shares Segment operation returns a list of the shares and share snapshots under the // specified account. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ServiceClientListSharesSegmentOptions contains the optional parameters for the ServiceClient.NewListSharesSegmentPager // method. // @@ -122,7 +112,7 @@ func (client *ServiceClient) ListSharesSegmentCreateRequest(ctx context.Context, reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -146,7 +136,7 @@ func (client *ServiceClient) ListSharesSegmentHandleResponse(resp *http.Response // metrics and CORS (Cross-Origin Resource Sharing) rules. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - storageServiceProperties - The StorageService properties. // - options - ServiceClientSetPropertiesOptions contains the optional parameters for the ServiceClient.SetProperties method. func (client *ServiceClient) SetProperties(ctx context.Context, storageServiceProperties StorageServiceProperties, options *ServiceClientSetPropertiesOptions) (ServiceClientSetPropertiesResponse, error) { @@ -154,7 +144,7 @@ func (client *ServiceClient) SetProperties(ctx context.Context, storageServicePr if err != nil { return ServiceClientSetPropertiesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ServiceClientSetPropertiesResponse{}, err } @@ -177,9 +167,12 @@ func (client *ServiceClient) setPropertiesCreateRequest(ctx context.Context, sto reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} req.Raw().Header["Accept"] = []string{"application/xml"} - return req, runtime.MarshalAsXML(req, storageServiceProperties) + if err := runtime.MarshalAsXML(req, storageServiceProperties); err != nil { + return nil, err + } + return req, nil } // setPropertiesHandleResponse handles the SetProperties response. diff --git a/sdk/storage/azfile/internal/generated/zz_share_client.go b/sdk/storage/azfile/internal/generated/zz_share_client.go index 1ba2fda44963..3c83f97775df 100644 --- a/sdk/storage/azfile/internal/generated/zz_share_client.go +++ b/sdk/storage/azfile/internal/generated/zz_share_client.go @@ -23,28 +23,18 @@ import ( ) // ShareClient contains the methods for the Share group. -// Don't use this type directly, use NewShareClient() instead. +// Don't use this type directly, use a constructor function instead. type ShareClient struct { - endpoint string - pl runtime.Pipeline -} - -// NewShareClient creates a new instance of ShareClient with the specified values. -// - endpoint - The URL of the service account, share, directory or file that is the target of the desired operation. -// - pl - the pipeline used for sending requests and handling responses. -func NewShareClient(endpoint string, pl runtime.Pipeline) *ShareClient { - client := &ShareClient{ - endpoint: endpoint, - pl: pl, - } - return client + internal *azcore.Client + endpoint string + fileRequestIntent *ShareTokenIntent } // AcquireLease - The Lease Share operation establishes and manages a lock on a share, or the specified snapshot for set and // delete share operations. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - duration - Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite // lease can be between 15 and 60 seconds. A lease duration cannot be changed using // renew or change. @@ -54,7 +44,7 @@ func (client *ShareClient) AcquireLease(ctx context.Context, duration int32, opt if err != nil { return ShareClientAcquireLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientAcquireLeaseResponse{}, err } @@ -85,7 +75,7 @@ func (client *ShareClient) acquireLeaseCreateRequest(ctx context.Context, durati if options != nil && options.ProposedLeaseID != nil { req.Raw().Header["x-ms-proposed-lease-id"] = []string{*options.ProposedLeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -132,7 +122,7 @@ func (client *ShareClient) acquireLeaseHandleResponse(resp *http.Response) (Shar // delete share operations. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ShareClientBreakLeaseOptions contains the optional parameters for the ShareClient.BreakLease method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *ShareClient) BreakLease(ctx context.Context, options *ShareClientBreakLeaseOptions, leaseAccessConditions *LeaseAccessConditions) (ShareClientBreakLeaseResponse, error) { @@ -140,7 +130,7 @@ func (client *ShareClient) BreakLease(ctx context.Context, options *ShareClientB if err != nil { return ShareClientBreakLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientBreakLeaseResponse{}, err } @@ -173,7 +163,7 @@ func (client *ShareClient) breakLeaseCreateRequest(ctx context.Context, options if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -228,7 +218,7 @@ func (client *ShareClient) breakLeaseHandleResponse(resp *http.Response) (ShareC // delete share operations. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - leaseID - Specifies the current lease ID on the resource. // - options - ShareClientChangeLeaseOptions contains the optional parameters for the ShareClient.ChangeLease method. func (client *ShareClient) ChangeLease(ctx context.Context, leaseID string, options *ShareClientChangeLeaseOptions) (ShareClientChangeLeaseResponse, error) { @@ -236,7 +226,7 @@ func (client *ShareClient) ChangeLease(ctx context.Context, leaseID string, opti if err != nil { return ShareClientChangeLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientChangeLeaseResponse{}, err } @@ -267,7 +257,7 @@ func (client *ShareClient) changeLeaseCreateRequest(ctx context.Context, leaseID if options != nil && options.ProposedLeaseID != nil { req.Raw().Header["x-ms-proposed-lease-id"] = []string{*options.ProposedLeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -314,14 +304,14 @@ func (client *ShareClient) changeLeaseHandleResponse(resp *http.Response) (Share // fails. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ShareClientCreateOptions contains the optional parameters for the ShareClient.Create method. func (client *ShareClient) Create(ctx context.Context, options *ShareClientCreateOptions) (ShareClientCreateResponse, error) { req, err := client.createCreateRequest(ctx, options) if err != nil { return ShareClientCreateResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientCreateResponse{}, err } @@ -356,7 +346,7 @@ func (client *ShareClient) createCreateRequest(ctx context.Context, options *Sha if options != nil && options.AccessTier != nil { req.Raw().Header["x-ms-access-tier"] = []string{string(*options.AccessTier)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.EnabledProtocols != nil { req.Raw().Header["x-ms-enabled-protocols"] = []string{*options.EnabledProtocols} } @@ -399,7 +389,7 @@ func (client *ShareClient) createHandleResponse(resp *http.Response) (ShareClien // CreatePermission - Create a permission (a security descriptor). // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - sharePermission - A permission (a security descriptor) at the share level. // - options - ShareClientCreatePermissionOptions contains the optional parameters for the ShareClient.CreatePermission method. func (client *ShareClient) CreatePermission(ctx context.Context, sharePermission SharePermission, options *ShareClientCreatePermissionOptions) (ShareClientCreatePermissionResponse, error) { @@ -407,7 +397,7 @@ func (client *ShareClient) CreatePermission(ctx context.Context, sharePermission if err != nil { return ShareClientCreatePermissionResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientCreatePermissionResponse{}, err } @@ -430,9 +420,15 @@ func (client *ShareClient) createPermissionCreateRequest(ctx context.Context, sh reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, runtime.MarshalAsJSON(req, sharePermission) + if err := runtime.MarshalAsJSON(req, sharePermission); err != nil { + return nil, err + } + return req, nil } // createPermissionHandleResponse handles the CreatePermission response. @@ -460,14 +456,14 @@ func (client *ShareClient) createPermissionHandleResponse(resp *http.Response) ( // CreateSnapshot - Creates a read-only snapshot of a share. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ShareClientCreateSnapshotOptions contains the optional parameters for the ShareClient.CreateSnapshot method. func (client *ShareClient) CreateSnapshot(ctx context.Context, options *ShareClientCreateSnapshotOptions) (ShareClientCreateSnapshotResponse, error) { req, err := client.createSnapshotCreateRequest(ctx, options) if err != nil { return ShareClientCreateSnapshotResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientCreateSnapshotResponse{}, err } @@ -497,7 +493,7 @@ func (client *ShareClient) createSnapshotCreateRequest(ctx context.Context, opti } } } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -538,7 +534,7 @@ func (client *ShareClient) createSnapshotHandleResponse(resp *http.Response) (Sh // contained within it are later deleted during garbage collection. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ShareClientDeleteOptions contains the optional parameters for the ShareClient.Delete method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *ShareClient) Delete(ctx context.Context, options *ShareClientDeleteOptions, leaseAccessConditions *LeaseAccessConditions) (ShareClientDeleteResponse, error) { @@ -546,7 +542,7 @@ func (client *ShareClient) Delete(ctx context.Context, options *ShareClientDelet if err != nil { return ShareClientDeleteResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientDeleteResponse{}, err } @@ -571,7 +567,7 @@ func (client *ShareClient) deleteCreateRequest(ctx context.Context, options *Sha reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.DeleteSnapshots != nil { req.Raw().Header["x-ms-delete-snapshots"] = []string{string(*options.DeleteSnapshots)} } @@ -604,7 +600,7 @@ func (client *ShareClient) deleteHandleResponse(resp *http.Response) (ShareClien // GetAccessPolicy - Returns information about stored access policies specified on the share. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ShareClientGetAccessPolicyOptions contains the optional parameters for the ShareClient.GetAccessPolicy method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *ShareClient) GetAccessPolicy(ctx context.Context, options *ShareClientGetAccessPolicyOptions, leaseAccessConditions *LeaseAccessConditions) (ShareClientGetAccessPolicyResponse, error) { @@ -612,7 +608,7 @@ func (client *ShareClient) GetAccessPolicy(ctx context.Context, options *ShareCl if err != nil { return ShareClientGetAccessPolicyResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientGetAccessPolicyResponse{}, err } @@ -635,7 +631,7 @@ func (client *ShareClient) getAccessPolicyCreateRequest(ctx context.Context, opt reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } @@ -678,7 +674,7 @@ func (client *ShareClient) getAccessPolicyHandleResponse(resp *http.Response) (S // GetPermission - Returns the permission (security descriptor) for a given key // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - filePermissionKey - Key of the permission to be set for the directory/file. // - options - ShareClientGetPermissionOptions contains the optional parameters for the ShareClient.GetPermission method. func (client *ShareClient) GetPermission(ctx context.Context, filePermissionKey string, options *ShareClientGetPermissionOptions) (ShareClientGetPermissionResponse, error) { @@ -686,7 +682,7 @@ func (client *ShareClient) GetPermission(ctx context.Context, filePermissionKey if err != nil { return ShareClientGetPermissionResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientGetPermissionResponse{}, err } @@ -710,7 +706,10 @@ func (client *ShareClient) getPermissionCreateRequest(ctx context.Context, fileP } req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["x-ms-file-permission-key"] = []string{filePermissionKey} - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} + if client.fileRequestIntent != nil { + req.Raw().Header["x-ms-file-request-intent"] = []string{string(*client.fileRequestIntent)} + } req.Raw().Header["Accept"] = []string{"application/json"} return req, nil } @@ -741,7 +740,7 @@ func (client *ShareClient) getPermissionHandleResponse(resp *http.Response) (Sha // data returned does not include the share's list of files. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ShareClientGetPropertiesOptions contains the optional parameters for the ShareClient.GetProperties method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *ShareClient) GetProperties(ctx context.Context, options *ShareClientGetPropertiesOptions, leaseAccessConditions *LeaseAccessConditions) (ShareClientGetPropertiesResponse, error) { @@ -749,7 +748,7 @@ func (client *ShareClient) GetProperties(ctx context.Context, options *ShareClie if err != nil { return ShareClientGetPropertiesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientGetPropertiesResponse{}, err } @@ -774,7 +773,7 @@ func (client *ShareClient) getPropertiesCreateRequest(ctx context.Context, optio reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } @@ -855,6 +854,14 @@ func (client *ShareClient) getPropertiesHandleResponse(resp *http.Response) (Sha } result.NextAllowedQuotaDowngradeTime = &nextAllowedQuotaDowngradeTime } + if val := resp.Header.Get("x-ms-share-provisioned-bandwidth-mibps"); val != "" { + provisionedBandwidthMiBps32, err := strconv.ParseInt(val, 10, 32) + provisionedBandwidthMiBps := int32(provisionedBandwidthMiBps32) + if err != nil { + return ShareClientGetPropertiesResponse{}, err + } + result.ProvisionedBandwidthMiBps = &provisionedBandwidthMiBps + } if val := resp.Header.Get("x-ms-lease-duration"); val != "" { result.LeaseDuration = (*LeaseDurationType)(&val) } @@ -889,7 +896,7 @@ func (client *ShareClient) getPropertiesHandleResponse(resp *http.Response) (Sha // GetStatistics - Retrieves statistics related to the share. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ShareClientGetStatisticsOptions contains the optional parameters for the ShareClient.GetStatistics method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *ShareClient) GetStatistics(ctx context.Context, options *ShareClientGetStatisticsOptions, leaseAccessConditions *LeaseAccessConditions) (ShareClientGetStatisticsResponse, error) { @@ -897,7 +904,7 @@ func (client *ShareClient) GetStatistics(ctx context.Context, options *ShareClie if err != nil { return ShareClientGetStatisticsResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientGetStatisticsResponse{}, err } @@ -920,7 +927,7 @@ func (client *ShareClient) getStatisticsCreateRequest(ctx context.Context, optio reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } @@ -964,7 +971,7 @@ func (client *ShareClient) getStatisticsHandleResponse(resp *http.Response) (Sha // delete share operations. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - leaseID - Specifies the current lease ID on the resource. // - options - ShareClientReleaseLeaseOptions contains the optional parameters for the ShareClient.ReleaseLease method. func (client *ShareClient) ReleaseLease(ctx context.Context, leaseID string, options *ShareClientReleaseLeaseOptions) (ShareClientReleaseLeaseResponse, error) { @@ -972,7 +979,7 @@ func (client *ShareClient) ReleaseLease(ctx context.Context, leaseID string, opt if err != nil { return ShareClientReleaseLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientReleaseLeaseResponse{}, err } @@ -1000,7 +1007,7 @@ func (client *ShareClient) releaseLeaseCreateRequest(ctx context.Context, leaseI req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["x-ms-lease-action"] = []string{"release"} req.Raw().Header["x-ms-lease-id"] = []string{leaseID} - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1044,7 +1051,7 @@ func (client *ShareClient) releaseLeaseHandleResponse(resp *http.Response) (Shar // delete share operations. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - leaseID - Specifies the current lease ID on the resource. // - options - ShareClientRenewLeaseOptions contains the optional parameters for the ShareClient.RenewLease method. func (client *ShareClient) RenewLease(ctx context.Context, leaseID string, options *ShareClientRenewLeaseOptions) (ShareClientRenewLeaseResponse, error) { @@ -1052,7 +1059,7 @@ func (client *ShareClient) RenewLease(ctx context.Context, leaseID string, optio if err != nil { return ShareClientRenewLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientRenewLeaseResponse{}, err } @@ -1080,7 +1087,7 @@ func (client *ShareClient) renewLeaseCreateRequest(ctx context.Context, leaseID req.Raw().URL.RawQuery = reqQP.Encode() req.Raw().Header["x-ms-lease-action"] = []string{"renew"} req.Raw().Header["x-ms-lease-id"] = []string{leaseID} - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1126,14 +1133,14 @@ func (client *ShareClient) renewLeaseHandleResponse(resp *http.Response) (ShareC // Restore - Restores a previously deleted Share. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ShareClientRestoreOptions contains the optional parameters for the ShareClient.Restore method. func (client *ShareClient) Restore(ctx context.Context, options *ShareClientRestoreOptions) (ShareClientRestoreResponse, error) { req, err := client.restoreCreateRequest(ctx, options) if err != nil { return ShareClientRestoreResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientRestoreResponse{}, err } @@ -1156,7 +1163,7 @@ func (client *ShareClient) restoreCreateRequest(ctx context.Context, options *Sh reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1205,7 +1212,7 @@ func (client *ShareClient) restoreHandleResponse(resp *http.Response) (ShareClie // SetAccessPolicy - Sets a stored access policy for use with shared access signatures. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - shareACL - The ACL for the share. // - options - ShareClientSetAccessPolicyOptions contains the optional parameters for the ShareClient.SetAccessPolicy method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. @@ -1214,7 +1221,7 @@ func (client *ShareClient) SetAccessPolicy(ctx context.Context, shareACL []*Sign if err != nil { return ShareClientSetAccessPolicyResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientSetAccessPolicyResponse{}, err } @@ -1237,7 +1244,7 @@ func (client *ShareClient) setAccessPolicyCreateRequest(ctx context.Context, sha reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } @@ -1246,7 +1253,10 @@ func (client *ShareClient) setAccessPolicyCreateRequest(ctx context.Context, sha XMLName xml.Name `xml:"SignedIdentifiers"` ShareACL *[]*SignedIdentifier `xml:"SignedIdentifier"` } - return req, runtime.MarshalAsXML(req, wrapper{ShareACL: &shareACL}) + if err := runtime.MarshalAsXML(req, wrapper{ShareACL: &shareACL}); err != nil { + return nil, err + } + return req, nil } // setAccessPolicyHandleResponse handles the SetAccessPolicy response. @@ -1281,7 +1291,7 @@ func (client *ShareClient) setAccessPolicyHandleResponse(resp *http.Response) (S // SetMetadata - Sets one or more user-defined name-value pairs for the specified share. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ShareClientSetMetadataOptions contains the optional parameters for the ShareClient.SetMetadata method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *ShareClient) SetMetadata(ctx context.Context, options *ShareClientSetMetadataOptions, leaseAccessConditions *LeaseAccessConditions) (ShareClientSetMetadataResponse, error) { @@ -1289,7 +1299,7 @@ func (client *ShareClient) SetMetadata(ctx context.Context, options *ShareClient if err != nil { return ShareClientSetMetadataResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientSetMetadataResponse{}, err } @@ -1319,7 +1329,7 @@ func (client *ShareClient) setMetadataCreateRequest(ctx context.Context, options } } } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } @@ -1359,7 +1369,7 @@ func (client *ShareClient) setMetadataHandleResponse(resp *http.Response) (Share // SetProperties - Sets properties for the specified share. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2022-11-02 // - options - ShareClientSetPropertiesOptions contains the optional parameters for the ShareClient.SetProperties method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ShareClient.GetProperties method. func (client *ShareClient) SetProperties(ctx context.Context, options *ShareClientSetPropertiesOptions, leaseAccessConditions *LeaseAccessConditions) (ShareClientSetPropertiesResponse, error) { @@ -1367,7 +1377,7 @@ func (client *ShareClient) SetProperties(ctx context.Context, options *ShareClie if err != nil { return ShareClientSetPropertiesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ShareClientSetPropertiesResponse{}, err } @@ -1390,7 +1400,7 @@ func (client *ShareClient) setPropertiesCreateRequest(ctx context.Context, optio reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2022-11-02"} if options != nil && options.Quota != nil { req.Raw().Header["x-ms-share-quota"] = []string{strconv.FormatInt(int64(*options.Quota), 10)} } diff --git a/sdk/storage/azfile/internal/shared/shared.go b/sdk/storage/azfile/internal/shared/shared.go index 0b819c28ea5a..4b8140f68556 100644 --- a/sdk/storage/azfile/internal/shared/shared.go +++ b/sdk/storage/azfile/internal/shared/shared.go @@ -62,6 +62,13 @@ const ( FileAttributesDirectory = "Directory" ) +const ( + ServiceClient = "azfile/service.Client" + ShareClient = "azfile/share.Client" + DirectoryClient = "azfile/directory.Client" + FileClient = "azfile/file.Client" +) + func GetClientOptions[T any](o *T) *T { if o == nil { return new(T) diff --git a/sdk/storage/azfile/internal/testcommon/clients_auth.go b/sdk/storage/azfile/internal/testcommon/clients_auth.go index 8e2e562116f0..8e7b14931105 100644 --- a/sdk/storage/azfile/internal/testcommon/clients_auth.go +++ b/sdk/storage/azfile/internal/testcommon/clients_auth.go @@ -42,6 +42,9 @@ const ( AccountNameEnvVar = "AZURE_STORAGE_ACCOUNT_NAME" AccountKeyEnvVar = "AZURE_STORAGE_ACCOUNT_KEY" DefaultEndpointSuffixEnvVar = "AZURE_STORAGE_ENDPOINT_SUFFIX" + EncryptionScopeEnvVar = "AZURE_STORAGE_ENCRYPTION_SCOPE" + PremiumAccountNameEnvVar = "FILE_STORAGE_ACCOUNT_NAME" + PremiumAccountKeyEnvVar = "FILE_STORAGE_ACCOUNT_KEY" ) const ( @@ -106,6 +109,10 @@ func GetGenericAccountInfo(accountType TestAccountType) (string, string) { } accountNameEnvVar := string(accountType) + AccountNameEnvVar accountKeyEnvVar := string(accountType) + AccountKeyEnvVar + if accountType == TestAccountPremium { + accountNameEnvVar = string(accountType) + PremiumAccountNameEnvVar + accountKeyEnvVar = string(accountType) + PremiumAccountKeyEnvVar + } accountName, _ := GetRequiredEnv(accountNameEnvVar) accountKey, _ := GetRequiredEnv(accountKeyEnvVar) return accountName, accountKey @@ -114,7 +121,11 @@ func GetGenericAccountInfo(accountType TestAccountType) (string, string) { func GetGenericSharedKeyCredential(accountType TestAccountType) (*service.SharedKeyCredential, error) { accountName, accountKey := GetGenericAccountInfo(accountType) if accountName == "" || accountKey == "" { - return nil, errors.New(string(accountType) + AccountNameEnvVar + " and/or " + string(accountType) + AccountKeyEnvVar + " environment variables not specified.") + if accountType == TestAccountPremium { + return nil, errors.New(string(accountType) + PremiumAccountNameEnvVar + " and/or " + string(accountType) + PremiumAccountKeyEnvVar + " environment variables not specified.") + } else { + return nil, errors.New(string(accountType) + AccountNameEnvVar + " and/or " + string(accountType) + AccountKeyEnvVar + " environment variables not specified.") + } } return service.NewSharedKeyCredential(accountName, accountKey) } @@ -122,7 +133,11 @@ func GetGenericSharedKeyCredential(accountType TestAccountType) (*service.Shared func GetGenericConnectionString(accountType TestAccountType) (*string, error) { accountName, accountKey := GetGenericAccountInfo(accountType) if accountName == "" || accountKey == "" { - return nil, errors.New(string(accountType) + AccountNameEnvVar + " and/or " + string(accountType) + AccountKeyEnvVar + " environment variables not specified.") + if accountType == TestAccountPremium { + return nil, errors.New(string(accountType) + PremiumAccountNameEnvVar + " and/or " + string(accountType) + PremiumAccountKeyEnvVar + " environment variables not specified.") + } else { + return nil, errors.New(string(accountType) + AccountNameEnvVar + " and/or " + string(accountType) + AccountKeyEnvVar + " environment variables not specified.") + } } connectionString := fmt.Sprintf("DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s;EndpointSuffix=core.windows.net/", accountName, accountKey) diff --git a/sdk/storage/azfile/internal/testcommon/common.go b/sdk/storage/azfile/internal/testcommon/common.go index 11e61800da79..c706fd6d4557 100644 --- a/sdk/storage/azfile/internal/testcommon/common.go +++ b/sdk/storage/azfile/internal/testcommon/common.go @@ -101,6 +101,7 @@ func BeforeTest(t *testing.T, suite string, test string) { require.NoError(t, recording.AddURISanitizer(FakeStorageURL, urlRegex, nil)) require.NoError(t, recording.AddHeaderRegexSanitizer("x-ms-copy-source", FakeStorageURL, urlRegex, nil)) require.NoError(t, recording.AddHeaderRegexSanitizer("x-ms-copy-source-authorization", FakeToken, tokenRegex, nil)) + require.NoError(t, recording.AddHeaderRegexSanitizer("x-ms-file-rename-source", FakeStorageURL, urlRegex, nil)) // we freeze request IDs and timestamps to avoid creating noisy diffs // NOTE: we can't freeze time stamps as that breaks some tests that use if-modified-since etc (maybe it can be fixed?) //testframework.AddHeaderRegexSanitizer("X-Ms-Date", "Wed, 10 Aug 2022 23:34:14 GMT", "", nil) diff --git a/sdk/storage/azfile/lease/client_test.go b/sdk/storage/azfile/lease/client_test.go index 7b90fbfa9f7f..8ea8587e16ac 100644 --- a/sdk/storage/azfile/lease/client_test.go +++ b/sdk/storage/azfile/lease/client_test.go @@ -70,9 +70,10 @@ func (l *LeaseRecordedTestsSuite) TestShareAcquireLease() { shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) defer testcommon.DeleteShare(context.Background(), _require, shareClient) - shareLeaseClient, _ := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ + shareLeaseClient, err := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ LeaseID: proposedLeaseIDs[0], }) + _require.NoError(err) ctx := context.Background() acquireLeaseResponse, err := shareLeaseClient.Acquire(ctx, int32(60), nil) @@ -98,13 +99,15 @@ func (l *LeaseRecordedTestsSuite) TestNegativeShareAcquireMultipleLease() { shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) defer testcommon.DeleteShare(context.Background(), _require, shareClient) - shareLeaseClient0, _ := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ + shareLeaseClient0, err := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ LeaseID: proposedLeaseIDs[0], }) + _require.NoError(err) - shareLeaseClient1, _ := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ + shareLeaseClient1, err := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ LeaseID: proposedLeaseIDs[1], }) + _require.NoError(err) ctx := context.Background() acquireLeaseResponse0, err := shareLeaseClient0.Acquire(ctx, int32(60), nil) @@ -131,9 +134,10 @@ func (l *LeaseRecordedTestsSuite) TestShareDeleteShareWithoutLeaseId() { shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) defer testcommon.DeleteShare(context.Background(), _require, shareClient) - shareLeaseClient, _ := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ + shareLeaseClient, err := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ LeaseID: proposedLeaseIDs[0], }) + _require.NoError(err) ctx := context.Background() acquireLeaseResponse, err := shareLeaseClient.Acquire(ctx, int32(60), nil) @@ -162,9 +166,10 @@ func (l *LeaseRecordedTestsSuite) TestShareReleaseLease() { shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) defer testcommon.DeleteShare(context.Background(), _require, shareClient) - shareLeaseClient, _ := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ + shareLeaseClient, err := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ LeaseID: proposedLeaseIDs[0], }) + _require.NoError(err) ctx := context.Background() acquireLeaseResponse, err := shareLeaseClient.Acquire(ctx, int32(60), nil) @@ -193,9 +198,10 @@ func (l *LeaseRecordedTestsSuite) TestShareRenewLease() { shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) defer testcommon.DeleteShare(context.Background(), _require, shareClient) - shareLeaseClient, _ := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ + shareLeaseClient, err := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ LeaseID: proposedLeaseIDs[0], }) + _require.NoError(err) ctx := context.Background() acquireLeaseResponse, err := shareLeaseClient.Acquire(ctx, int32(15), nil) @@ -221,9 +227,10 @@ func (l *LeaseRecordedTestsSuite) TestShareBreakLeaseDefault() { shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) defer testcommon.DeleteShare(context.Background(), _require, shareClient) - shareLeaseClient, _ := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ + shareLeaseClient, err := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ LeaseID: proposedLeaseIDs[0], }) + _require.NoError(err) ctx := context.Background() acquireLeaseResponse, err := shareLeaseClient.Acquire(ctx, int32(60), nil) @@ -253,9 +260,10 @@ func (l *LeaseRecordedTestsSuite) TestShareBreakLeaseNonDefault() { shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) defer testcommon.DeleteShare(context.Background(), _require, shareClient) - shareLeaseClient, _ := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ + shareLeaseClient, err := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ LeaseID: proposedLeaseIDs[0], }) + _require.NoError(err) ctx := context.Background() acquireLeaseResponse, err := shareLeaseClient.Acquire(ctx, int32(60), nil) @@ -290,9 +298,10 @@ func (l *LeaseRecordedTestsSuite) TestNegativeShareBreakRenewLease() { shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) defer testcommon.DeleteShare(context.Background(), _require, shareClient) - shareLeaseClient, _ := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ + shareLeaseClient, err := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ LeaseID: proposedLeaseIDs[0], }) + _require.NoError(err) ctx := context.Background() acquireLeaseResponse, err := shareLeaseClient.Acquire(ctx, int32(60), nil) @@ -325,9 +334,10 @@ func (l *LeaseRecordedTestsSuite) TestShareChangeLease() { shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) defer testcommon.DeleteShare(context.Background(), _require, shareClient) - shareLeaseClient, _ := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ + shareLeaseClient, err := lease.NewShareClient(shareClient, &lease.ShareClientOptions{ LeaseID: proposedLeaseIDs[0], }) + _require.NoError(err) ctx := context.Background() acquireLeaseResponse, err := shareLeaseClient.Acquire(ctx, int32(60), nil) diff --git a/sdk/storage/azfile/sas/account.go b/sdk/storage/azfile/sas/account.go index 6b0c0067e811..6facc516ef75 100644 --- a/sdk/storage/azfile/sas/account.go +++ b/sdk/storage/azfile/sas/account.go @@ -22,13 +22,14 @@ type SharedKeyCredential = exported.SharedKeyCredential // AccountSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage account. // For more information, see https://docs.microsoft.com/rest/api/storageservices/constructing-an-account-sas type AccountSignatureValues struct { - Version string `param:"sv"` // If not specified, this format to SASVersion - Protocol Protocol `param:"spr"` // See the SASProtocol* constants - StartTime time.Time `param:"st"` // Not specified if IsZero - ExpiryTime time.Time `param:"se"` // Not specified if IsZero - Permissions string `param:"sp"` // Create by initializing AccountPermissions and then call String() - IPRange IPRange `param:"sip"` - ResourceTypes string `param:"srt"` // Create by initializing AccountResourceTypes and then call String() + Version string `param:"sv"` // If not specified, this format to SASVersion + Protocol Protocol `param:"spr"` // See the SASProtocol* constants + StartTime time.Time `param:"st"` // Not specified if IsZero + ExpiryTime time.Time `param:"se"` // Not specified if IsZero + Permissions string `param:"sp"` // Create by initializing AccountPermissions and then call String() + IPRange IPRange `param:"sip"` + ResourceTypes string `param:"srt"` // Create by initializing AccountResourceTypes and then call String() + EncryptionScope string `param:"ses"` } // SignWithSharedKey uses an account's shared key credential to sign this signature values to produce @@ -65,6 +66,7 @@ func (v AccountSignatureValues) SignWithSharedKey(sharedKeyCredential *SharedKey v.IPRange.String(), string(v.Protocol), v.Version, + v.EncryptionScope, ""}, // That is right, the account SAS requires a terminating extra newline "\n") @@ -74,12 +76,13 @@ func (v AccountSignatureValues) SignWithSharedKey(sharedKeyCredential *SharedKey } p := QueryParameters{ // Common SAS parameters - version: v.Version, - protocol: v.Protocol, - startTime: v.StartTime, - expiryTime: v.ExpiryTime, - permissions: v.Permissions, - ipRange: v.IPRange, + version: v.Version, + protocol: v.Protocol, + startTime: v.StartTime, + expiryTime: v.ExpiryTime, + permissions: v.Permissions, + ipRange: v.IPRange, + encryptionScope: v.EncryptionScope, // Account-specific SAS parameters services: "f", // will always be "f" for Azure File diff --git a/sdk/storage/azfile/sas/query_params.go b/sdk/storage/azfile/sas/query_params.go index 5bf5422d6082..09c799088cbb 100644 --- a/sdk/storage/azfile/sas/query_params.go +++ b/sdk/storage/azfile/sas/query_params.go @@ -22,7 +22,7 @@ const ( var ( // Version is the default version encoded in the SAS token. - Version = "2020-02-10" + Version = "2022-11-02" ) // TimeFormats ISO 8601 format. @@ -127,6 +127,7 @@ type QueryParameters struct { resource string `param:"sr"` permissions string `param:"sp"` signature string `param:"sig"` + encryptionScope string `param:"ses"` cacheControl string `param:"rscc"` contentDisposition string `param:"rscd"` contentEncoding string `param:"rsce"` @@ -197,6 +198,11 @@ func (p *QueryParameters) Signature() string { return p.signature } +// EncryptionScope returns encryption scope. +func (p *QueryParameters) EncryptionScope() string { + return p.encryptionScope +} + // CacheControl returns cacheControl. func (p *QueryParameters) CacheControl() string { return p.cacheControl @@ -259,6 +265,9 @@ func (p *QueryParameters) Encode() string { if p.signature != "" { v.Add("sig", p.signature) } + if p.encryptionScope != "" { + v.Add("ses", p.encryptionScope) + } if p.cacheControl != "" { v.Add("rscc", p.cacheControl) } @@ -318,6 +327,8 @@ func NewQueryParameters(values url.Values, deleteSASParametersFromValues bool) Q p.permissions = val case "sig": p.signature = val + case "ses": + p.encryptionScope = val case "rscc": p.cacheControl = val case "rscd": diff --git a/sdk/storage/azfile/sas/query_params_test.go b/sdk/storage/azfile/sas/query_params_test.go index 7d699f9c3396..e9215bbc9624 100644 --- a/sdk/storage/azfile/sas/query_params_test.go +++ b/sdk/storage/azfile/sas/query_params_test.go @@ -132,7 +132,7 @@ func TestIPRange_String(t *testing.T) { func TestSAS(t *testing.T) { // Note: This is a totally invalid fake SAS, this is just testing our ability to parse different query parameters on a SAS - const sas = "sv=2019-12-12&sr=b&st=2111-01-09T01:42:34.936Z&se=2222-03-09T01:42:34.936Z&sp=rw&sip=168.1.5.60-168.1.5.70&spr=https,http&si=myIdentifier&ss=bf&srt=s&rscc=cc&rscd=cd&rsce=ce&rscl=cl&rsct=ct&sig=clNxbtnkKSHw7f3KMEVVc4agaszoRFdbZr%2FWBmPNsrw%3D" + const sas = "sv=2019-12-12&sr=b&st=2111-01-09T01:42:34.936Z&se=2222-03-09T01:42:34.936Z&sp=rw&sip=168.1.5.60-168.1.5.70&spr=https,http&si=myIdentifier&ss=bf&srt=s&rscc=cc&rscd=cd&rsce=ce&rscl=cl&rsct=ct&ses=test&sig=clNxbtnkKSHw7f3KMEVVc4agaszoRFdbZr%2FWBmPNsrw%3D" _url := fmt.Sprintf("https://teststorageaccount.file.core.windows.net/testshare/testpath?%s", sas) _uri, err := url.Parse(_url) require.NoError(t, err) @@ -177,6 +177,7 @@ func validateSAS(t *testing.T, sas string, parameters QueryParameters) { require.NoError(t, err) require.Equal(t, parameters.Signature(), sign) + require.Equal(t, parameters.EncryptionScope(), sasCompMap["ses"]) require.Equal(t, parameters.CacheControl(), sasCompMap["rscc"]) require.Equal(t, parameters.ContentDisposition(), sasCompMap["rscd"]) require.Equal(t, parameters.ContentEncoding(), sasCompMap["rsce"]) diff --git a/sdk/storage/azfile/sas/service.go b/sdk/storage/azfile/sas/service.go index 50192f9ef58b..88bdb6a779cd 100644 --- a/sdk/storage/azfile/sas/service.go +++ b/sdk/storage/azfile/sas/service.go @@ -39,7 +39,7 @@ type SignatureValues struct { // SignWithSharedKey uses an account's SharedKeyCredential to sign this signature values to produce the proper SAS query parameters. func (v SignatureValues) SignWithSharedKey(sharedKeyCredential *SharedKeyCredential) (QueryParameters, error) { - if v.ExpiryTime.IsZero() || v.Permissions == "" { + if v.Identifier == "" && (v.ExpiryTime.IsZero() || v.Permissions == "") { return QueryParameters{}, errors.New("service SAS is missing at least one of these: ExpiryTime or Permissions") } diff --git a/sdk/storage/azfile/sas/service_test.go b/sdk/storage/azfile/sas/service_test.go index dd640be0e4fc..2e235e656a5e 100644 --- a/sdk/storage/azfile/sas/service_test.go +++ b/sdk/storage/azfile/sas/service_test.go @@ -7,8 +7,11 @@ package sas import ( + "errors" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/internal/exported" "github.com/stretchr/testify/require" "testing" + "time" ) func TestSharePermissions_String(t *testing.T) { @@ -145,3 +148,45 @@ func TestGetCanonicalName(t *testing.T) { require.Equal(t, c.expected, getCanonicalName(c.inputAccount, c.inputShare, c.inputFilePath)) } } + +func TestFileSignatureValues_SignWithSharedKey(t *testing.T) { + cred, err := exported.NewSharedKeyCredential("fakeaccountname", "AKIAIOSFODNN7EXAMPLE") + require.Nil(t, err, "error creating valid shared key credentials.") + + expiryDate, err := time.Parse("2006-01-02", "2023-07-20") + require.Nil(t, err, "error creating valid expiry date.") + + testdata := []struct { + object SignatureValues + expected QueryParameters + expectedError error + }{ + { + object: SignatureValues{ShareName: "fakestorageshare", Permissions: "r", ExpiryTime: expiryDate}, + expected: QueryParameters{version: Version, permissions: "r", expiryTime: expiryDate, resource: "s"}, + expectedError: nil, + }, + { + object: SignatureValues{ShareName: "fakestorageshare", Permissions: "", ExpiryTime: expiryDate}, + expected: QueryParameters{}, + expectedError: errors.New("service SAS is missing at least one of these: ExpiryTime or Permissions"), + }, + { + object: SignatureValues{ShareName: "fakestorageshare", Permissions: "r", ExpiryTime: *new(time.Time)}, + expected: QueryParameters{}, + expectedError: errors.New("service SAS is missing at least one of these: ExpiryTime or Permissions"), + }, + { + object: SignatureValues{ShareName: "fakestorageshare", Permissions: "", ExpiryTime: *new(time.Time), Identifier: "fakepolicyname"}, + expected: QueryParameters{version: Version, resource: "s", identifier: "fakepolicyname"}, + expectedError: nil, + }, + } + for _, c := range testdata { + act, err := c.object.SignWithSharedKey(cred) + require.Equal(t, c.expectedError, err) + // ignore signature value + act.signature = "" + require.Equal(t, c.expected, act) + } +} diff --git a/sdk/storage/azfile/service/client.go b/sdk/storage/azfile/service/client.go index 89bf5f02c5a3..aec7d058169c 100644 --- a/sdk/storage/azfile/service/client.go +++ b/sdk/storage/azfile/service/client.go @@ -8,6 +8,7 @@ package service 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/fileerror" @@ -28,15 +29,45 @@ type ClientOptions base.ClientOptions // Client represents a URL to the Azure File Storage service allowing you to manipulate file shares. type Client base.Client[generated.ServiceClient] +// NewClient creates an instance of Client with the specified values. +// - serviceURL - the URL of the storage account e.g. https://.file.core.windows.net/ +// - cred - an Azure AD credential, typically obtained via the azidentity module +// - options - client options; pass nil to accept the default values +// +// Note that service-level operations do not support token credential authentication. +// This constructor exists to allow the construction of a share.Client that has token credential authentication. +// Also note that ClientOptions.FileRequestIntent is currently required for token authentication. +func NewClient(serviceURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) { + authPolicy := runtime.NewBearerTokenPolicy(cred, []string{shared.TokenScope}, nil) + conOptions := shared.GetClientOptions(options) + plOpts := runtime.PipelineOptions{ + PerRetry: []policy.Policy{authPolicy}, + } + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) + + azClient, err := azcore.NewClient(shared.ServiceClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewServiceClient(serviceURL, azClient, nil, (*base.ClientOptions)(conOptions))), nil +} + // NewClientWithNoCredential creates an instance of Client with the specified values. // This is used to anonymously access a storage account or with a shared access signature (SAS) token. // - serviceURL - the URL of the storage account e.g. https://.file.core.windows.net/? // - options - client options; pass nil to accept the default values func NewClientWithNoCredential(serviceURL string, options *ClientOptions) (*Client, error) { conOptions := shared.GetClientOptions(options) - pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions) + plOpts := runtime.PipelineOptions{} + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) - return (*Client)(base.NewServiceClient(serviceURL, pl, nil)), nil + azClient, err := azcore.NewClient(shared.ServiceClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewServiceClient(serviceURL, azClient, nil, (*base.ClientOptions)(conOptions))), nil } // NewClientWithSharedKeyCredential creates an instance of Client with the specified values. @@ -46,10 +77,17 @@ func NewClientWithNoCredential(serviceURL string, options *ClientOptions) (*Clie func NewClientWithSharedKeyCredential(serviceURL string, cred *SharedKeyCredential, options *ClientOptions) (*Client, error) { 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) + plOpts := runtime.PipelineOptions{ + PerRetry: []policy.Policy{authPolicy}, + } + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) - return (*Client)(base.NewServiceClient(serviceURL, pl, cred)), nil + azClient, err := azcore.NewClient(shared.ServiceClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewServiceClient(serviceURL, azClient, cred, (*base.ClientOptions)(conOptions))), nil } // NewClientFromConnectionString creates an instance of Client with the specified values. @@ -80,6 +118,10 @@ func (s *Client) sharedKey() *SharedKeyCredential { return base.SharedKey((*base.Client[generated.ServiceClient])(s)) } +func (s *Client) getClientOptions() *base.ClientOptions { + return base.GetClientOptions((*base.Client[generated.ServiceClient])(s)) +} + // URL returns the URL endpoint used by the Client object. func (s *Client) URL() string { return s.generated().Endpoint() @@ -89,7 +131,7 @@ func (s *Client) URL() string { // The new share.Client uses the same request policy pipeline as the Client. func (s *Client) NewShareClient(shareName string) *share.Client { shareURL := runtime.JoinPaths(s.generated().Endpoint(), shareName) - return (*share.Client)(base.NewShareClient(shareURL, s.generated().Pipeline(), s.sharedKey())) + return (*share.Client)(base.NewShareClient(shareURL, s.generated().InternalClient().WithClientName(shared.ShareClient), s.sharedKey(), s.getClientOptions())) } // CreateShare is a lifecycle method to creates a new share under the specified account. @@ -172,7 +214,7 @@ func (s *Client) NewListSharesPager(options *ListSharesOptions) *runtime.Pager[L if err != nil { return ListSharesSegmentResponse{}, err } - resp, err := s.generated().Pipeline().Do(req) + resp, err := s.generated().InternalClient().Pipeline().Do(req) if err != nil { return ListSharesSegmentResponse{}, err } diff --git a/sdk/storage/azfile/service/client_test.go b/sdk/storage/azfile/service/client_test.go index d9c3642c4628..2aac3b0791ed 100644 --- a/sdk/storage/azfile/service/client_test.go +++ b/sdk/storage/azfile/service/client_test.go @@ -229,7 +229,8 @@ func (s *ServiceRecordedTestsSuite) TestAccountListSharesNonDefault() { func (s *ServiceUnrecordedTestsSuite) TestSASServiceClientRestoreShare() { _require := require.New(s.T()) testName := s.T().Name() - cred, _ := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + cred, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.NoError(err) serviceClient, err := service.NewClientWithSharedKeyCredential(fmt.Sprintf("https://%s.file.core.windows.net/", cred.AccountName()), cred, nil) _require.NoError(err) @@ -452,3 +453,170 @@ func (s *ServiceRecordedTestsSuite) TestServiceCreateDeleteRestoreShare() { } _require.Equal(sharesCnt, 1) } + +func (s *ServiceRecordedTestsSuite) TestServiceOAuthNegative() { + _require := require.New(s.T()) + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + options := &service.ClientOptions{FileRequestIntent: to.Ptr(service.ShareTokenIntentBackup)} + testcommon.SetClientOptions(s.T(), &options.ClientOptions) + svcClient, err := service.NewClient("https://"+accountName+".file.core.windows.net/", cred, options) + _require.NoError(err) + + // service-level operations are not supported using token credential authentication. + _, err = svcClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.FileOAuthManagementAPIRestrictedToSRP) + + _, err = svcClient.SetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.FileOAuthManagementAPIRestrictedToSRP) + + pager := svcClient.NewListSharesPager(nil) + _, err = pager.NextPage(context.Background()) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.FileOAuthManagementAPIRestrictedToSRP) +} + +func (s *ServiceRecordedTestsSuite) TestServiceCreateDeleteDirOAuth() { + _require := require.New(s.T()) + testName := s.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + // create service client using token credential + options := &service.ClientOptions{FileRequestIntent: to.Ptr(service.ShareTokenIntentBackup)} + testcommon.SetClientOptions(s.T(), &options.ClientOptions) + svcClientOAuth, err := service.NewClient("https://"+accountName+".file.core.windows.net/", cred, options) + _require.NoError(err) + + dirClient := svcClientOAuth.NewShareClient(shareName).NewDirectoryClient(testcommon.GenerateDirectoryName(testName)) + + _, err = dirClient.Create(context.Background(), nil) + _require.NoError(err) + + _, err = dirClient.GetProperties(context.Background(), nil) + _require.NoError(err) + + _, err = dirClient.Delete(context.Background(), nil) + _require.NoError(err) +} + +func (s *ServiceUnrecordedTestsSuite) TestAccountSASEncryptionScope() { + _require := require.New(s.T()) + testName := s.T().Name() + cred, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.NoError(err) + + encryptionScope, err := testcommon.GetRequiredEnv(testcommon.EncryptionScopeEnvVar) + _require.NoError(err) + + resources := sas.AccountResourceTypes{ + Object: true, + Service: true, + Container: true, + } + permissions := sas.AccountPermissions{ + Read: true, + Write: true, + Delete: true, + List: true, + Create: true, + } + expiry := time.Now().Add(1 * time.Hour) + + qps, err := sas.AccountSignatureValues{ + Permissions: permissions.String(), + ResourceTypes: resources.String(), + ExpiryTime: expiry.UTC(), + EncryptionScope: encryptionScope, + }.SignWithSharedKey(cred) + _require.NoError(err) + + svcSAS := fmt.Sprintf("https://%s.file.core.windows.net/?%s", cred.AccountName(), qps.Encode()) + svcClient, err := service.NewClientWithNoCredential(svcSAS, nil) + _require.NoError(err) + + _, err = svcClient.GetProperties(context.Background(), nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + _, err = svcClient.CreateShare(context.Background(), shareName, nil) + _require.NoError(err) + defer func() { + _, err = svcClient.DeleteShare(context.Background(), shareName, nil) + _require.NoError(err) + }() + + pager := svcClient.NewListSharesPager(&service.ListSharesOptions{ + Prefix: &shareName, + }) + + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.NoError(err) + _require.Len(resp.Shares, 1) + _require.NotNil(resp.Shares[0].Name) + _require.Equal(*resp.Shares[0].Name, shareName) + } + + shareClient := svcClient.NewShareClient(shareName) + fileClient := shareClient.NewRootDirectoryClient().NewFileClient(testcommon.GenerateFileName(testName)) + + _, err = fileClient.Create(context.Background(), 2048, nil) + _require.NoError(err) + + _, err = fileClient.GetProperties(context.Background(), nil) + _require.NoError(err) +} + +func (s *ServiceRecordedTestsSuite) TestPremiumAccountListShares() { + _require := require.New(s.T()) + testName := s.T().Name() + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountPremium, nil) + _require.NoError(err) + + mySharePrefix := testcommon.GenerateEntityName(testName) + shareClients := map[string]*share.Client{} + for i := 0; i < 4; i++ { + shareName := mySharePrefix + "share" + strconv.Itoa(i) + shareClients[shareName] = testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClients[shareName]) + } + + pager := svcClient.NewListSharesPager(&service.ListSharesOptions{ + Prefix: to.Ptr(mySharePrefix), + }) + + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.NoError(err) + _require.Len(resp.Shares, 4) + for _, shareItem := range resp.Shares { + _require.NotNil(shareItem.Properties) + _require.NotNil(shareItem.Properties.ProvisionedBandwidthMiBps) + _require.NotNil(shareItem.Properties.ProvisionedIngressMBps) + _require.NotNil(shareItem.Properties.ProvisionedEgressMBps) + _require.NotNil(shareItem.Properties.ProvisionedIops) + _require.NotNil(shareItem.Properties.NextAllowedQuotaDowngradeTime) + _require.Greater(*shareItem.Properties.ProvisionedBandwidthMiBps, (int32)(0)) + } + } +} diff --git a/sdk/storage/azfile/service/constants.go b/sdk/storage/azfile/service/constants.go index a936067376b4..4908f031110a 100644 --- a/sdk/storage/azfile/service/constants.go +++ b/sdk/storage/azfile/service/constants.go @@ -35,3 +35,15 @@ const ( func PossibleShareRootSquashValues() []ShareRootSquash { return generated.PossibleShareRootSquashValues() } + +// ShareTokenIntent is required if authorization header specifies an OAuth token. +type ShareTokenIntent = generated.ShareTokenIntent + +const ( + ShareTokenIntentBackup ShareTokenIntent = generated.ShareTokenIntentBackup +) + +// PossibleShareTokenIntentValues returns the possible values for the ShareTokenIntent const type. +func PossibleShareTokenIntentValues() []ShareTokenIntent { + return generated.PossibleShareTokenIntentValues() +} diff --git a/sdk/storage/azfile/share/client.go b/sdk/storage/azfile/share/client.go index 5e557edd4f3d..466774c548dc 100644 --- a/sdk/storage/azfile/share/client.go +++ b/sdk/storage/azfile/share/client.go @@ -8,6 +8,8 @@ package share 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/directory" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/fileerror" @@ -27,15 +29,44 @@ type ClientOptions base.ClientOptions // Client represents a URL to the Azure Storage share allowing you to manipulate its directories and files. type Client base.Client[generated.ShareClient] +// NewClient creates an instance of Client with the specified values. +// - shareURL - the URL of the share e.g. https://.file.core.windows.net/share +// - cred - an Azure AD credential, typically obtained via the azidentity module +// - options - client options; pass nil to accept the default values +// +// Note that the only share-level operations that support token credential authentication are CreatePermission and GetPermission. +// Also note that ClientOptions.FileRequestIntent is currently required for token authentication. +func NewClient(shareURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) { + authPolicy := runtime.NewBearerTokenPolicy(cred, []string{shared.TokenScope}, nil) + conOptions := shared.GetClientOptions(options) + plOpts := runtime.PipelineOptions{ + PerRetry: []policy.Policy{authPolicy}, + } + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) + + azClient, err := azcore.NewClient(shared.ShareClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewShareClient(shareURL, azClient, nil, (*base.ClientOptions)(conOptions))), nil +} + // NewClientWithNoCredential creates an instance of Client with the specified values. // This is used to anonymously access a share or with a shared access signature (SAS) token. // - shareURL - the URL of the share e.g. https://.file.core.windows.net/share? // - options - client options; pass nil to accept the default values func NewClientWithNoCredential(shareURL string, options *ClientOptions) (*Client, error) { conOptions := shared.GetClientOptions(options) - pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions) + plOpts := runtime.PipelineOptions{} + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) - return (*Client)(base.NewShareClient(shareURL, pl, nil)), nil + azClient, err := azcore.NewClient(shared.ShareClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewShareClient(shareURL, azClient, nil, (*base.ClientOptions)(conOptions))), nil } // NewClientWithSharedKeyCredential creates an instance of Client with the specified values. @@ -45,10 +76,17 @@ func NewClientWithNoCredential(shareURL string, options *ClientOptions) (*Client func NewClientWithSharedKeyCredential(shareURL string, cred *SharedKeyCredential, options *ClientOptions) (*Client, error) { 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) + plOpts := runtime.PipelineOptions{ + PerRetry: []policy.Policy{authPolicy}, + } + base.SetPipelineOptions((*base.ClientOptions)(conOptions), &plOpts) - return (*Client)(base.NewShareClient(shareURL, pl, cred)), nil + azClient, err := azcore.NewClient(shared.ShareClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewShareClient(shareURL, azClient, cred, (*base.ClientOptions)(conOptions))), nil } // NewClientFromConnectionString creates an instance of Client with the specified values. @@ -81,6 +119,10 @@ func (s *Client) sharedKey() *SharedKeyCredential { return base.SharedKey((*base.Client[generated.ShareClient])(s)) } +func (s *Client) getClientOptions() *base.ClientOptions { + return base.GetClientOptions((*base.Client[generated.ShareClient])(s)) +} + // URL returns the URL endpoint used by the Client object. func (s *Client) URL() string { return s.generated().Endpoint() @@ -91,14 +133,14 @@ func (s *Client) URL() string { func (s *Client) NewDirectoryClient(directoryName string) *directory.Client { directoryName = url.PathEscape(strings.TrimRight(directoryName, "/")) directoryURL := runtime.JoinPaths(s.URL(), directoryName) - return (*directory.Client)(base.NewDirectoryClient(directoryURL, s.generated().Pipeline(), s.sharedKey())) + return (*directory.Client)(base.NewDirectoryClient(directoryURL, s.generated().InternalClient().WithClientName(shared.DirectoryClient), s.sharedKey(), s.getClientOptions())) } // NewRootDirectoryClient creates a new directory.Client object for the root of the share using the Client's URL. // The new directory.Client uses the same request policy pipeline as the Client. func (s *Client) NewRootDirectoryClient() *directory.Client { rootDirURL := s.URL() - return (*directory.Client)(base.NewDirectoryClient(rootDirURL, s.generated().Pipeline(), s.sharedKey())) + return (*directory.Client)(base.NewDirectoryClient(rootDirURL, s.generated().InternalClient().WithClientName(shared.DirectoryClient), s.sharedKey(), s.getClientOptions())) } // WithSnapshot creates a new Client object identical to the source but with the specified share snapshot timestamp. @@ -109,8 +151,9 @@ func (s *Client) WithSnapshot(shareSnapshot string) (*Client, error) { return nil, err } p.ShareSnapshot = shareSnapshot + clientOptions := base.GetClientOptions((*base.Client[generated.ShareClient])(s)) - return (*Client)(base.NewShareClient(p.String(), s.generated().Pipeline(), s.sharedKey())), nil + return (*Client)(base.NewShareClient(p.String(), s.generated().InternalClient(), s.sharedKey(), clientOptions)), nil } // Create operation creates a new share within a storage account. If a share with the same name already exists, the operation fails. diff --git a/sdk/storage/azfile/share/client_test.go b/sdk/storage/azfile/share/client_test.go index 44940a537d27..1639450d18af 100644 --- a/sdk/storage/azfile/share/client_test.go +++ b/sdk/storage/azfile/share/client_test.go @@ -1458,3 +1458,163 @@ func (s *ShareRecordedTestsSuite) TestSASShareClientSignNegative() { _, err = shareClient.GetSASURL(sas.SharePermissions{}, expiry, nil) _require.Equal(err.Error(), "service SAS is missing at least one of these: ExpiryTime or Permissions") } + +func (s *ShareRecordedTestsSuite) TestShareOAuthNegative() { + _require := require.New(s.T()) + testName := s.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + options := &share.ClientOptions{FileRequestIntent: to.Ptr(share.TokenIntentBackup)} + testcommon.SetClientOptions(s.T(), &options.ClientOptions) + shareClient, err := share.NewClient("https://"+accountName+".file.core.windows.net/"+shareName, cred, options) + _require.NoError(err) + + _, err = shareClient.Create(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.FileOAuthManagementAPIRestrictedToSRP) + + _, err = shareClient.GetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.FileOAuthManagementAPIRestrictedToSRP) + + _, err = shareClient.SetProperties(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.FileOAuthManagementAPIRestrictedToSRP) + + _, err = shareClient.Delete(context.Background(), nil) + _require.Error(err) + testcommon.ValidateFileErrorCode(_require, err, fileerror.FileOAuthManagementAPIRestrictedToSRP) +} + +func (s *ShareRecordedTestsSuite) TestShareCreateAndGetPermissionOAuth() { + _require := require.New(s.T()) + testName := s.T().Name() + + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + options := &share.ClientOptions{FileRequestIntent: to.Ptr(share.TokenIntentBackup)} + testcommon.SetClientOptions(s.T(), &options.ClientOptions) + shareClientOAuth, err := share.NewClient("https://"+accountName+".file.core.windows.net/"+shareName, cred, options) + _require.NoError(err) + + // Create a permission and check that it's not empty. + createResp, err := shareClientOAuth.CreatePermission(context.Background(), testcommon.SampleSDDL, nil) + _require.NoError(err) + _require.NotNil(createResp.FilePermissionKey) + _require.NotEmpty(*createResp.FilePermissionKey) + + getResp, err := shareClientOAuth.GetPermission(context.Background(), *createResp.FilePermissionKey, nil) + _require.NoError(err) + _require.NotNil(getResp.Permission) + _require.NotEmpty(*getResp.Permission) +} + +func (s *ShareUnrecordedTestsSuite) TestShareSASUsingAccessPolicy() { + _require := require.New(s.T()) + testName := s.T().Name() + + cred, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.NoError(err) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := testcommon.CreateNewShare(context.Background(), _require, shareName, svcClient) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + + id := "testAccessPolicy" + ps := share.AccessPolicyPermission{ + Read: true, + Write: true, + Create: true, + Delete: true, + List: true, + } + signedIdentifiers := make([]*share.SignedIdentifier, 0) + signedIdentifiers = append(signedIdentifiers, &share.SignedIdentifier{ + AccessPolicy: &share.AccessPolicy{ + Expiry: to.Ptr(time.Now().Add(1 * time.Hour)), + Start: to.Ptr(time.Now()), + Permission: to.Ptr(ps.String()), + }, + ID: &id, + }) + + _, err = shareClient.SetAccessPolicy(context.Background(), &share.SetAccessPolicyOptions{ + ShareACL: signedIdentifiers, + }) + _require.NoError(err) + + gResp, err := shareClient.GetAccessPolicy(context.Background(), nil) + _require.NoError(err) + _require.Len(gResp.SignedIdentifiers, 1) + + time.Sleep(30 * time.Second) + + sasQueryParams, err := sas.SignatureValues{ + Protocol: sas.ProtocolHTTPS, + Identifier: id, + ShareName: shareName, + }.SignWithSharedKey(cred) + _require.NoError(err) + + shareSAS := shareClient.URL() + "?" + sasQueryParams.Encode() + shareClientSAS, err := share.NewClientWithNoCredential(shareSAS, nil) + _require.NoError(err) + + dirClient := testcommon.CreateNewDirectory(context.Background(), _require, testcommon.GenerateDirectoryName(testName), shareClientSAS) + fileClient := testcommon.CreateNewFileFromShare(context.Background(), _require, testcommon.GenerateFileName(testName), 2048, shareClientSAS) + + _, err = dirClient.GetProperties(context.Background(), nil) + _require.NoError(err) + + _, err = fileClient.GetProperties(context.Background(), nil) + _require.NoError(err) + + _, err = dirClient.Delete(context.Background(), nil) + _require.NoError(err) + + _, err = fileClient.Delete(context.Background(), nil) + _require.NoError(err) +} + +func (s *ShareRecordedTestsSuite) TestPremiumShareBandwidth() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountPremium, nil) + _require.NoError(err) + + shareName := testcommon.GenerateShareName(testName) + shareClient := svcClient.NewShareClient(shareName) + + _, err = shareClient.Create(context.Background(), nil) + defer testcommon.DeleteShare(context.Background(), _require, shareClient) + _require.NoError(err) + + response, err := shareClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.NotNil(response.ProvisionedBandwidthMiBps) + _require.NotNil(response.ProvisionedIngressMBps) + _require.NotNil(response.ProvisionedEgressMBps) + _require.NotNil(response.ProvisionedIops) + _require.NotNil(response.NextAllowedQuotaDowngradeTime) + _require.Greater(*response.ProvisionedBandwidthMiBps, (int32)(0)) +} diff --git a/sdk/storage/azfile/share/constants.go b/sdk/storage/azfile/share/constants.go index 231ab9e27e09..26dd5df8c984 100644 --- a/sdk/storage/azfile/share/constants.go +++ b/sdk/storage/azfile/share/constants.go @@ -48,3 +48,15 @@ const ( func PossibleDeleteSnapshotsOptionTypeValues() []DeleteSnapshotsOptionType { return generated.PossibleDeleteSnapshotsOptionTypeValues() } + +// TokenIntent is required if authorization header specifies an OAuth token. +type TokenIntent = generated.ShareTokenIntent + +const ( + TokenIntentBackup TokenIntent = generated.ShareTokenIntentBackup +) + +// PossibleTokenIntentValues returns the possible values for the TokenIntent const type. +func PossibleTokenIntentValues() []TokenIntent { + return generated.PossibleShareTokenIntentValues() +} diff --git a/sdk/storage/azfile/share/examples_test.go b/sdk/storage/azfile/share/examples_test.go index bb4739e9b151..bd67ce31daf1 100644 --- a/sdk/storage/azfile/share/examples_test.go +++ b/sdk/storage/azfile/share/examples_test.go @@ -10,6 +10,7 @@ import ( "context" "fmt" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/sas" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/service" "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/share" @@ -462,3 +463,35 @@ func Example_share_Client_GetSASURL() { fmt.Println(f) } } + +func Example_share_Client_CreateAndGetPermissionOAuth() { + accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME") + if !ok { + panic("AZURE_STORAGE_ACCOUNT_NAME could not be found") + } + + shareName := "testshare" + shareURL := fmt.Sprintf("https://%s.file.core.windows.net/%s", accountName, shareName) + + cred, err := azidentity.NewDefaultAzureCredential(nil) + handleError(err) + + // FileRequestintent is required if authorization header specifies an OAuth token. + options := &share.ClientOptions{FileRequestIntent: to.Ptr(share.TokenIntentBackup)} + shareClient, err := share.NewClient(shareURL, cred, options) + handleError(err) + + // Create, Delete, GetProperties, SetProperties, etc. operations does not work when share client is created using OAuth credentials + // Operations supported are: CreatePermission and GetPermission + // Below GetProperties operation results in an error + _, err = shareClient.GetProperties(context.TODO(), nil) + fmt.Println(err.Error()) + + testSDDL := `O:S-1-5-32-548G:S-1-5-21-397955417-626881126-188441444-512D:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)` + createResp, err := shareClient.CreatePermission(context.TODO(), testSDDL, nil) + handleError(err) + + getResp, err := shareClient.GetPermission(context.TODO(), *createResp.FilePermissionKey, nil) + handleError(err) + fmt.Println(*getResp.Permission) +} diff --git a/sdk/storage/azfile/test-resources.json b/sdk/storage/azfile/test-resources.json index c6259f7ab02f..912321ecd276 100644 --- a/sdk/storage/azfile/test-resources.json +++ b/sdk/storage/azfile/test-resources.json @@ -25,6 +25,7 @@ "blobDataContributorRoleId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", "contributorRoleId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c')]", "blobDataOwnerRoleId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/b7e6dc6d-f1e8-4753-8033-0f276bb0955b')]", + "fileElevatedContributorCustomRoleId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/9276e164-dbbe-4f3f-b4db-cfdd87eebbe9')]", "primaryAccountName": "[concat(parameters('baseName'), 'prim')]", "immutableAccountName": "[concat(parameters('baseName'), 'imm')]", "primaryEncryptionScopeName": "encryptionScope", @@ -85,6 +86,15 @@ "principalId": "[parameters('testApplicationOid')]" } }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "[variables('authorizationApiVersion')]", + "name": "[guid(concat('fileElevatedContributorCustomRoleId', resourceGroup().id))]", + "properties": { + "roleDefinitionId": "[variables('fileElevatedContributorCustomRoleId')]", + "principalId": "[parameters('testApplicationOid')]" + } + }, { "type": "Microsoft.Storage/storageAccounts", "apiVersion": "[variables('mgmtApiVersion')]",