diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_directory_client.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_directory_client.hpp index 6e98e9d91..abc59b48a 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_directory_client.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_directory_client.hpp @@ -137,6 +137,27 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { bool Recursive, const DeleteDirectoryOptions& options = DeleteDirectoryOptions()) const; + /** + * @brief Sets POSIX access control rights on files and directories under given directory + * recursively. + * @param mode Mode PathSetAccessControlRecursiveMode::Set sets POSIX access control rights on + * files and directories, PathSetAccessControlRecursiveMode::Modify modifies one or more POSIX + * access control rights that pre-exist on files and directories, + * PathSetAccessControlRecursiveMode::Remove removes one or more POSIX access control rights + * that were present earlier on files and directories + * @param acls Sets POSIX access control rights on files and directories. Each access control + * entry (ACE) consists of a scope, a type, a user or group identifier, and permissions. + * @param options Optional parameters to set an access control recursively to the resource the + * directory points to. + * @return Azure::Core::Response + * @remark This request is sent to dfs endpoint. + */ + Azure::Core::Response SetAccessControlRecursive( + PathSetAccessControlRecursiveMode mode, + std::vector acls, + const SetDirectoryAccessControlRecursiveOptions& options + = SetDirectoryAccessControlRecursiveOptions()) const; + private: explicit DirectoryClient( Azure::Core::Http::Url dfsUri, diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp index d123b055c..750c2abe3 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp @@ -647,6 +647,43 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { PathAccessConditions AccessConditions; }; + /** + * @brief Optional parameters for PathClient::SetAccessControlRecursive + */ + struct SetDirectoryAccessControlRecursiveOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + + /** + * @brief When performing setAccessControlRecursive on a directory, the number of paths that + * are processed with each invocation is limited. If the number of paths to be processed + * exceeds this limit, a continuation token is returned in this response header. When a + * continuation token is returned in the response, it must be specified in a subsequent + * invocation of the setAccessControlRecursive operation to continue the + * setAccessControlRecursive operation on the directory. + */ + Azure::Core::Nullable Continuation; + + /** + * @brief It specifies the maximum number of files or directories on which the acl change will + * be applied. If omitted or greater than 2,000, the request will process up to 2,000 + * items. + */ + Azure::Core::Nullable MaxRecords; + + /** + * @brief Optional. Valid for "SetAccessControlRecursive" operation. If set to false, the + * operation will terminate quickly on encountering user errors (4XX). If true, the operation + * will ignore user errors and proceed with the operation on other sub-entities of the + * directory. Continuation token will only be returned when forceFlag is true in case of user + * errors. If not set the default value is false for this. + */ + Azure::Core::Nullable ForceFlag; + }; + using CreateFileOptions = CreatePathOptions; using CreateDirectoryOptions = CreatePathOptions; diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp index 40353a5ff..bed64df95 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp @@ -183,7 +183,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { Azure::Core::Nullable Continuation; }; - using DirectorySetAccessControlRecursiveInfo = PathSetAccessControlRecursiveResult; + using SetDirectoryAccessControlRecursiveResult = PathSetAccessControlRecursiveResult; using CreateDirectoryResult = CreatePathResult; using DeleteDirectoryResult = PathDeleteResult; diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp index 19d86ad32..a45bb31ff 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp @@ -23,7 +23,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { namespace Details { - constexpr static const char* c_DefaultServiceApiVersion = "2019-12-12"; + constexpr static const char* c_DefaultServiceApiVersion = "2020-02-10"; constexpr static const char* c_PathDnsSuffixDefault = "dfs.core.windows.net"; constexpr static const char* c_QueryFileSystemResource = "resource"; constexpr static const char* c_QueryTimeout = "timeout"; @@ -31,6 +31,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { constexpr static const char* c_QueryRecursiveRequired = "recursive"; constexpr static const char* c_QueryContinuation = "continuation"; constexpr static const char* c_QueryPathSetAccessControlRecursiveMode = "mode"; + constexpr static const char* c_QueryForceFlag = "forceflag"; constexpr static const char* c_QueryDirectory = "directory"; constexpr static const char* c_QueryPrefix = "prefix"; constexpr static const char* c_QueryMaxResults = "maxresults"; @@ -45,6 +46,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { constexpr static const char* c_QueryMaxRecords = "maxrecords"; constexpr static const char* c_QueryPathGetPropertiesAction = "action"; constexpr static const char* c_QueryAction = "action"; + constexpr static const char* c_QueryComp = "comp"; constexpr static const char* c_HeaderApiVersionParameter = "x-ms-version"; constexpr static const char* c_HeaderClientRequestId = "x-ms-client-request-id"; constexpr static const char* c_HeaderIfMatch = "if-match"; @@ -68,6 +70,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { constexpr static const char* c_HeaderContentType = "x-ms-content-type"; constexpr static const char* c_HeaderTransactionalContentMd5 = "content-md5"; constexpr static const char* c_HeaderContentMd5 = "x-ms-content-md5"; + constexpr static const char* c_HeaderContentCrc64 = "x-ms-content-crc64"; constexpr static const char* c_HeaderUmask = "x-ms-umask"; constexpr static const char* c_HeaderPermissions = "x-ms-permissions"; constexpr static const char* c_HeaderRenameSource = "x-ms-rename-source"; @@ -75,6 +78,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { constexpr static const char* c_HeaderGroup = "x-ms-group"; constexpr static const char* c_HeaderAcl = "x-ms-acl"; constexpr static const char* c_HeaderContentLength = "content-length"; + constexpr static const char* c_HeaderPathExpiryOptions = "x-ms-expiry-option"; + constexpr static const char* c_HeaderPathExpiryTime = "x-ms-expiry-time"; constexpr static const char* c_HeaderDate = "date"; constexpr static const char* c_HeaderXMsRequestId = "x-ms-request-id"; constexpr static const char* c_HeaderXMsClientRequestId = "x-ms-client-request-id"; @@ -103,6 +108,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { constexpr static const char* c_HeaderXMsGroup = "x-ms-group"; constexpr static const char* c_HeaderXMsPermissions = "x-ms-permissions"; constexpr static const char* c_HeaderXMsAcl = "x-ms-acl"; + constexpr static const char* c_HeaderXMsContentCrc64 = "x-ms-content-crc64"; + constexpr static const char* c_HeaderXMsRequestServerEncrypted + = "x-ms-request-server-encrypted"; } // namespace Details struct DataLakeHttpHeaders { @@ -159,6 +167,54 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { + " to PathSetAccessControlRecursiveMode"); } + // Required. Indicates mode of the expiry time + enum class PathExpiryOptions + { + NeverExpire, + RelativeToCreation, + RelativeToNow, + Absolute, + Unknown + }; + + inline std::string PathExpiryOptionsToString(const PathExpiryOptions& pathExpiryOptions) + { + switch (pathExpiryOptions) + { + case PathExpiryOptions::NeverExpire: + return "NeverExpire"; + case PathExpiryOptions::RelativeToCreation: + return "RelativeToCreation"; + case PathExpiryOptions::RelativeToNow: + return "RelativeToNow"; + case PathExpiryOptions::Absolute: + return "Absolute"; + default: + return std::string(); + } + } + + inline PathExpiryOptions PathExpiryOptionsFromString(const std::string& pathExpiryOptions) + { + if (pathExpiryOptions == "NeverExpire") + { + return PathExpiryOptions::NeverExpire; + } + if (pathExpiryOptions == "RelativeToCreation") + { + return PathExpiryOptions::RelativeToCreation; + } + if (pathExpiryOptions == "RelativeToNow") + { + return PathExpiryOptions::RelativeToNow; + } + if (pathExpiryOptions == "Absolute") + { + return PathExpiryOptions::Absolute; + } + throw std::runtime_error("Cannot convert " + pathExpiryOptions + " to PathExpiryOptions"); + } + struct AclFailedEntry { std::string Name; @@ -185,9 +241,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { static SetAccessControlRecursiveResponse CreateFromJson(const nlohmann::json& node) { SetAccessControlRecursiveResponse result; - result.DirectoriesSuccessful = std::stoi(node["directoriesSuccessful"].get()); - result.FilesSuccessful = std::stoi(node["filesSuccessful"].get()); - result.FailureCount = std::stoi(node["failureCount"].get()); + result.DirectoriesSuccessful = node["directoriesSuccessful"].get(); + result.FilesSuccessful = node["filesSuccessful"].get(); + result.FailureCount = node["failureCount"].get(); for (const auto& element : node["failedEntries"]) { result.FailedEntries.emplace_back(AclFailedEntry::CreateFromJson(element)); @@ -481,7 +537,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { throw std::runtime_error("Cannot convert " + pathLeaseAction + " to PathLeaseAction"); } - // Lease state of the blob. + // Lease state of the resource. enum class LeaseStateType { Available, @@ -536,7 +592,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { throw std::runtime_error("Cannot convert " + leaseStateType + " to LeaseStateType"); } - // The current lease status of the blob. + // The lease status of the resource. enum class LeaseStatusType { Locked, @@ -652,6 +708,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { struct FileSystemListPathsResult { + Azure::Core::Nullable ETag; + Azure::Core::Nullable LastModified; Azure::Core::Nullable Continuation; std::vector Paths; @@ -674,8 +732,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { struct PathUpdateResult { - std::string ETag; - std::string LastModified; + Azure::Core::Nullable ETag; + Azure::Core::Nullable LastModified; Azure::Core::Nullable AcceptRanges; DataLakeHttpHeaders HttpHeaders; int64_t ContentLength = int64_t(); @@ -789,6 +847,16 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { struct PathAppendDataResult { + Azure::Core::Nullable ETag; + Azure::Core::Nullable ContentMD5; + Azure::Core::Nullable XMsContentCrc64; + bool IsServerEncrypted = bool(); + }; + + struct PathSetExpiryResult + { + std::string ETag; + std::string LastModified; }; class DataLakeRestClient { @@ -1290,6 +1358,15 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { ? FileSystemListPathsResult() : FileSystemListPathsResult::FileSystemListPathsResultFromPathList( PathList::CreateFromJson(nlohmann::json::parse(bodyBuffer))); + if (response.GetHeaders().find(Details::c_HeaderETag) != response.GetHeaders().end()) + { + result.ETag = response.GetHeaders().at(Details::c_HeaderETag); + } + if (response.GetHeaders().find(Details::c_HeaderLastModified) + != response.GetHeaders().end()) + { + result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); + } if (response.GetHeaders().find(Details::c_HeaderXMsContinuation) != response.GetHeaders().end()) { @@ -1361,7 +1438,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { // active and matches this ID. Azure::Core::Nullable SourceLeaseId; // A lease ID for the source path. If specified, the source path must - // have an active lease and the leaase ID must match. + // have an active lease and the lease ID must match. Azure::Core::Nullable Properties; // Optional. User-defined properties to be stored with the filesystem, in // the format of a comma-separated list of name and value pairs "n1=v1, @@ -1576,6 +1653,13 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { // modifies one or more POSIX access control rights that pre-exist on files and // directories, "remove" removes one or more POSIX access control rights that // were present earlier on files and directories + Azure::Core::Nullable + ForceFlag; // Optional. Valid for "SetAccessControlRecursive" operation. If set to + // false, the operation will terminate quickly on encountering user errors + // (4XX). If true, the operation will ignore user errors and proceed with the + // operation on other sub-entities of the directory. Continuation token will + // only be returned when forceFlag is true in case of user errors. If not set + // the default value is false for this. Azure::Core::Nullable Position; // This parameter allows the caller to upload data in parallel and control the // order in which it is appended to the file. It is required when uploading @@ -1701,6 +1785,11 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { request.GetUrl().AppendQuery( Details::c_QueryPathSetAccessControlRecursiveMode, PathSetAccessControlRecursiveModeToString(updateOptions.Mode)); + if (updateOptions.ForceFlag.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryForceFlag, (updateOptions.ForceFlag.GetValue() ? "true" : "false")); + } if (updateOptions.Position.HasValue()) { request.GetUrl().AppendQuery( @@ -2324,6 +2413,13 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { // modifies one or more POSIX access control rights that pre-exist on files and // directories, "remove" removes one or more POSIX access control rights that // were present earlier on files and directories + Azure::Core::Nullable + ForceFlag; // Optional. Valid for "SetAccessControlRecursive" operation. If set to + // false, the operation will terminate quickly on encountering user errors + // (4XX). If true, the operation will ignore user errors and proceed with the + // operation on other sub-entities of the directory. Continuation token will + // only be returned when forceFlag is true in case of user errors. If not set + // the default value is false for this. Azure::Core::Nullable MaxRecords; // Optional. It specifies the maximum number of files or directories on // which the acl change will be applied. If omitted or greater than 2,000, @@ -2365,6 +2461,12 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { request.GetUrl().AppendQuery( Details::c_QueryPathSetAccessControlRecursiveMode, PathSetAccessControlRecursiveModeToString(setAccessControlRecursiveOptions.Mode)); + if (setAccessControlRecursiveOptions.ForceFlag.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryForceFlag, + (setAccessControlRecursiveOptions.ForceFlag.GetValue() ? "true" : "false")); + } if (setAccessControlRecursiveOptions.MaxRecords.HasValue()) { request.GetUrl().AppendQuery( @@ -2585,6 +2687,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { Azure::Core::Nullable TransactionalContentMd5; // Specify the transactional md5 for the body, to be validated // by the service. + Azure::Core::Nullable ContentCrc64; // Specify the transactional crc64 for the + // body, to be validated by the service. Azure::Core::Nullable LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease is // active and matches this ID. @@ -2629,6 +2733,11 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { Details::c_HeaderTransactionalContentMd5, appendDataOptions.TransactionalContentMd5.GetValue()); } + if (appendDataOptions.ContentCrc64.HasValue()) + { + request.AddHeader( + Details::c_HeaderContentCrc64, appendDataOptions.ContentCrc64.GetValue()); + } if (appendDataOptions.LeaseIdOptional.HasValue()) { request.AddHeader( @@ -2644,6 +2753,55 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { return AppendDataParseResult(context, pipeline.Send(context, request)); } + struct SetExpiryOptions + { + Azure::Core::Nullable + Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting + // Timeouts for Blob Service Operations. + std::string ApiVersionParameter + = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use + // for this request. + Azure::Core::Nullable + ClientRequestId; // Provides a client-generated, opaque value with a 1 KB character + // limit that is recorded in the analytics logs when storage analytics + // logging is enabled. + PathExpiryOptions XMsExpiryOption; // Required. Indicates mode of the expiry time + Azure::Core::Nullable PathExpiryTime; // The time to set the blob to expiry + }; + + static Azure::Core::Response SetExpiry( + const Azure::Core::Http::Url& url, + Azure::Core::Http::HttpPipeline& pipeline, + const Azure::Core::Context& context, + const SetExpiryOptions& setExpiryOptions) + { + Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Put, url); + request.AddHeader(Details::c_HeaderContentLength, "0"); + request.GetUrl().AppendQuery(Details::c_QueryComp, "expiry"); + if (setExpiryOptions.Timeout.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryTimeout, std::to_string(setExpiryOptions.Timeout.GetValue())); + } + request.AddHeader( + Details::c_HeaderApiVersionParameter, setExpiryOptions.ApiVersionParameter); + if (setExpiryOptions.ClientRequestId.HasValue()) + { + request.AddHeader( + Details::c_HeaderClientRequestId, setExpiryOptions.ClientRequestId.GetValue()); + } + request.AddHeader( + Details::c_HeaderPathExpiryOptions, + PathExpiryOptionsToString(setExpiryOptions.XMsExpiryOption)); + if (setExpiryOptions.PathExpiryTime.HasValue()) + { + request.AddHeader( + Details::c_HeaderPathExpiryTime, setExpiryOptions.PathExpiryTime.GetValue()); + } + return SetExpiryParseResult(context, pipeline.Send(context, request)); + } + private: static Azure::Core::Response CreateParseResult( const Azure::Core::Context& context, @@ -2698,8 +2856,15 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { : PathUpdateResult::PathUpdateResultFromSetAccessControlRecursiveResponse( SetAccessControlRecursiveResponse::CreateFromJson( nlohmann::json::parse(bodyBuffer))); - result.ETag = response.GetHeaders().at(Details::c_HeaderETag); - result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); + if (response.GetHeaders().find(Details::c_HeaderETag) != response.GetHeaders().end()) + { + result.ETag = response.GetHeaders().at(Details::c_HeaderETag); + } + if (response.GetHeaders().find(Details::c_HeaderLastModified) + != response.GetHeaders().end()) + { + result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); + } if (response.GetHeaders().find(Details::c_HeaderAcceptRanges) != response.GetHeaders().end()) { @@ -3182,6 +3347,22 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { { // Append data to file control response. PathAppendDataResult result; + if (response.GetHeaders().find(Details::c_HeaderETag) != response.GetHeaders().end()) + { + result.ETag = response.GetHeaders().at(Details::c_HeaderETag); + } + if (response.GetHeaders().find(Details::c_HeaderContentMD5) + != response.GetHeaders().end()) + { + result.ContentMD5 = response.GetHeaders().at(Details::c_HeaderContentMD5); + } + if (response.GetHeaders().find(Details::c_HeaderXMsContentCrc64) + != response.GetHeaders().end()) + { + result.XMsContentCrc64 = response.GetHeaders().at(Details::c_HeaderXMsContentCrc64); + } + result.IsServerEncrypted + = response.GetHeaders().at(Details::c_HeaderXMsRequestServerEncrypted) == "true"; return Azure::Core::Response( std::move(result), std::move(responsePtr)); } @@ -3191,6 +3372,27 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { throw Azure::Storage::StorageError::CreateFromResponse(std::move(responsePtr)); } } + + static Azure::Core::Response SetExpiryParseResult( + const Azure::Core::Context& context, + std::unique_ptr responsePtr) + { + /* const */ auto& response = *responsePtr; + if (response.GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok) + { + // The blob expiry was set successfully. + PathSetExpiryResult result; + result.ETag = response.GetHeaders().at(Details::c_HeaderETag); + result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); + return Azure::Core::Response( + std::move(result), std::move(responsePtr)); + } + else + { + unused(context); + throw Azure::Storage::StorageError::CreateFromResponse(std::move(responsePtr)); + } + } }; }; // class DataLakeRestClient diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_directory_client.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_directory_client.cpp index 48d03dd43..5130574cb 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_directory_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_directory_client.cpp @@ -196,4 +196,21 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { return DataLakeRestClient::Path::Delete( m_dfsUri, *m_pipeline, options.Context, protocolLayerOptions); } + + Azure::Core::Response + DirectoryClient::SetAccessControlRecursive( + PathSetAccessControlRecursiveMode mode, + std::vector acls, + const SetDirectoryAccessControlRecursiveOptions& options) const + { + DataLakeRestClient::Path::SetAccessControlRecursiveOptions protocolLayerOptions; + protocolLayerOptions.Mode = mode; + protocolLayerOptions.Continuation = options.Continuation; + protocolLayerOptions.MaxRecords = options.MaxRecords; + protocolLayerOptions.ForceFlag = options.ForceFlag; + protocolLayerOptions.Acl = Acl::SerializeAcls(acls); + return DataLakeRestClient::Path::SetAccessControlRecursive( + m_dfsUri, *m_pipeline, options.Context, protocolLayerOptions); + } + }}}} // namespace Azure::Storage::Files::DataLake diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp index 0f15619f6..7d0e37002 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp @@ -105,8 +105,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { { auto parsedConnectionString = Azure::Storage::Details::ParseConnectionString(connectionString); auto fileUri = std::move(parsedConnectionString.DataLakeServiceUri); - fileUri.AppendPath(fileSystemName, true); - fileUri.AppendPath(filePath, true); + fileUri.AppendPath(fileSystemName); + fileUri.AppendPath(filePath); if (parsedConnectionString.KeyCredential) { diff --git a/sdk/storage/azure-storage-files-datalake/test/datalake_directory_client_test.cpp b/sdk/storage/azure-storage-files-datalake/test/datalake_directory_client_test.cpp index d01997554..c9ccc8a02 100644 --- a/sdk/storage/azure-storage-files-datalake/test/datalake_directory_client_test.cpp +++ b/sdk/storage/azure-storage-files-datalake/test/datalake_directory_client_test.cpp @@ -295,4 +295,42 @@ namespace Azure { namespace Storage { namespace Test { } } + TEST_F(DataLakeDirectoryClientTest, DirectorySetAccessControlRecursive) + { + // Setup directories. + auto rootDirectoryName = LowercaseRandomString(); + auto directoryName1 = LowercaseRandomString(); + auto directoryName2 = LowercaseRandomString(); + auto rootDirectoryClient = m_fileSystemClient->GetDirectoryClient(rootDirectoryName); + rootDirectoryClient.Create(); + auto directoryClient1 + = m_fileSystemClient->GetDirectoryClient(rootDirectoryName + "/" + directoryName1); + directoryClient1.Create(); + auto directoryClient2 + = m_fileSystemClient->GetDirectoryClient(rootDirectoryName + "/" + directoryName2); + directoryClient2.Create(); + + { + // Set/Get Acls recursive works. + std::vector acls = GetValidAcls(); + EXPECT_NO_THROW(directoryClient1.SetAccessControl(acls)); + EXPECT_NO_THROW(rootDirectoryClient.SetAccessControlRecursive( + Files::DataLake::PathSetAccessControlRecursiveMode::Modify, acls)); + std::vector resultAcls1; + std::vector resultAcls2; + EXPECT_NO_THROW(resultAcls1 = directoryClient1.GetAccessControls()->Acls); + EXPECT_NO_THROW(resultAcls2 = directoryClient2.GetAccessControls()->Acls); + for (const auto& acl : resultAcls2) + { + auto iter = std::find_if( + resultAcls1.begin(), resultAcls1.end(), [&acl](const Files::DataLake::Acl& targetAcl) { + return (targetAcl.Type == acl.Type) && (targetAcl.Id == acl.Id) + && (targetAcl.Scope == acl.Scope); + }); + EXPECT_TRUE(iter != resultAcls1.end()); + EXPECT_EQ(iter->Permissions, acl.Permissions); + } + } + } + }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/protocol/share_rest_client.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/protocol/share_rest_client.hpp index 58961158b..223adb8e2 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/protocol/share_rest_client.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/protocol/share_rest_client.hpp @@ -24,12 +24,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { namespace Details { - constexpr static const char* c_DefaultServiceApiVersion = "2019-12-12"; + constexpr static const char* c_DefaultServiceApiVersion = "2020-02-10"; constexpr static const char* c_QueryCopyId = "copyid"; constexpr static const char* c_QueryListSharesInclude = "include"; constexpr static const char* c_QueryMarker = "marker"; constexpr static const char* c_QueryMaxResults = "maxresults"; constexpr static const char* c_QueryPrefix = "prefix"; + constexpr static const char* c_QueryPrevShareSnapshot = "prevsharesnapshot"; constexpr static const char* c_QueryShareSnapshot = "sharesnapshot"; constexpr static const char* c_QueryTimeout = "timeout"; constexpr static const char* c_QueryRestype = "restype"; @@ -61,6 +62,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { constexpr static const char* c_HeaderFileTypeConstant = "x-ms-type"; constexpr static const char* c_HeaderRangeGetContentMd5 = "x-ms-range-get-content-md5"; constexpr static const char* c_HeaderHandleId = "x-ms-handle-id"; + constexpr static const char* c_HeaderBreakPeriod = "x-ms-lease-break-period"; constexpr static const char* c_HeaderDuration = "x-ms-lease-duration"; constexpr static const char* c_HeaderLeaseId = "x-ms-lease-id"; constexpr static const char* c_HeaderMetadata = "x-ms-meta"; @@ -83,8 +85,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { = "x-ms-share-provisioned-egress-mbps"; constexpr static const char* c_HeaderNextAllowedQuotaDowngradeTime = "x-ms-share-next-allowed-quota-downgrade-time"; - constexpr static const char* c_HeaderSnapshot = "x-ms-snapshot"; + constexpr static const char* c_HeaderLeaseDuration = "x-ms-lease-duration"; + constexpr static const char* c_HeaderLeaseState = "x-ms-lease-state"; + constexpr static const char* c_HeaderLeaseStatus = "x-ms-lease-status"; + constexpr static const char* c_HeaderLeaseTime = "x-ms-lease-time"; constexpr static const char* c_HeaderClientRequestId = "x-ms-client-request-id"; + constexpr static const char* c_HeaderAction = "x-ms-lease-action"; + constexpr static const char* c_HeaderSnapshot = "x-ms-snapshot"; constexpr static const char* c_HeaderRequestIsServerEncrypted = "x-ms-request-server-encrypted"; constexpr static const char* c_HeaderFileChangeTime = "x-ms-file-change-time"; constexpr static const char* c_HeaderFileId = "x-ms-file-id"; @@ -108,11 +115,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { constexpr static const char* c_HeaderCopyId = "x-ms-copy-id"; constexpr static const char* c_HeaderCopyProgress = "x-ms-copy-progress"; constexpr static const char* c_HeaderCopyStatus = "x-ms-copy-status"; - constexpr static const char* c_HeaderLeaseDuration = "x-ms-lease-duration"; - constexpr static const char* c_HeaderLeaseState = "x-ms-lease-state"; - constexpr static const char* c_HeaderLeaseStatus = "x-ms-lease-status"; constexpr static const char* c_HeaderFileType = "x-ms-type"; - constexpr static const char* c_HeaderAction = "x-ms-lease-action"; constexpr static const char* c_HeaderFileRangeWrite = "x-ms-write"; constexpr static const char* c_HeaderFileRangeWriteTypeDefault = "update"; constexpr static const char* c_HeaderXMsContentCrc64 = "x-ms-content-crc64"; @@ -359,173 +362,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string LastReconnectTime; // Time handle was last connected to (UTC) }; - // An enumeration of directories and files. - struct ListFilesAndDirectoriesSegmentResponse - { - std::string ServiceEndpoint; - std::string ShareName; - std::string ShareSnapshot; - std::string DirectoryPath; - std::string Prefix; - std::string Marker; - int32_t MaxResults = int32_t(); - FilesAndDirectoriesListSegment Segment; - std::string NextMarker; - }; - - // An enumeration of handles. - struct ListHandlesResponse - { - std::vector HandleList; - std::string NextMarker; - }; - - // Properties of a share. - struct ShareProperties - { - std::string LastModified; - std::string Etag; - int32_t Quota = int32_t(); - Azure::Core::Nullable ProvisionedIops; - Azure::Core::Nullable ProvisionedIngressMBps; - Azure::Core::Nullable ProvisionedEgressMBps; - Azure::Core::Nullable NextAllowedQuotaDowngradeTime; - std::string DeletedTime; - int32_t RemainingRetentionDays = int32_t(); - }; - - typedef std::map Metadata; - - // A listed Azure Storage share item. - struct ShareItem - { - std::string Name; - std::string Snapshot; - bool Deleted = bool(); - std::string Version; - ShareProperties Properties; - Metadata ShareMetadata; - }; - - // An enumeration of shares. - struct ListSharesResponse - { - std::string ServiceEndpoint; - std::string Prefix; - std::string Marker; - int32_t MaxResults = int32_t(); - std::vector ShareItems; - std::string NextMarker; - }; - - // The retention policy. - struct ShareRetentionPolicy - { - bool Enabled - = bool(); // Indicates whether a retention policy is enabled for the File service. If false, - // metrics data is retained, and the user is responsible for deleting it. - int32_t Days = int32_t(); // Indicates the number of days that metrics data should be retained. - // All data older than this value will be deleted. Metrics data is - // deleted on a best-effort basis after the retention period expires. - }; - - // Storage Analytics metrics for file service. - struct Metrics - { - std::string Version; // The version of Storage Analytics to configure. - bool Enabled = bool(); // Indicates whether metrics are enabled for the File service. - bool IncludeAPIs = bool(); // Indicates whether metrics should generate summary statistics for - // called API operations. - ShareRetentionPolicy RetentionPolicy; - }; - - // An Azure Storage file range. - struct Range - { - int64_t Start = int64_t(); // Start of the range. - int64_t End = int64_t(); // End of the range. - }; - - // Stats for the share. - struct ShareStats - { - int64_t ShareUsageBytes - = int64_t(); // The approximate size of the data stored in bytes. Note that this value may - // not include all recently created or recently resized files. - }; - - // Signed identifier. - struct SignedIdentifier - { - std::string Id; // A unique id. - AccessPolicy Policy; // The access policy. - }; - - // Storage service properties. - struct StorageServiceProperties - { - Metrics HourMetrics; // A summary of request statistics grouped by API in hourly aggregates for - // files. - Metrics MinuteMetrics; // A summary of request statistics grouped by API in minute aggregates - // for files. - std::vector Cors; // The set of CORS rules. - }; - - // A permission (a security descriptor) at the share level. - struct SharePermission - { - std::string Permission; // The permission in the Security Descriptor Definition Language (SDDL). - }; - - // State of the copy operation identified by 'x-ms-copy-id'. - enum class CopyStatusType - { - Pending, - Success, - Aborted, - Failed, - Unknown - }; - - inline std::string CopyStatusTypeToString(const CopyStatusType& copyStatusType) - { - switch (copyStatusType) - { - case CopyStatusType::Pending: - return "pending"; - case CopyStatusType::Success: - return "success"; - case CopyStatusType::Aborted: - return "aborted"; - case CopyStatusType::Failed: - return "failed"; - default: - return std::string(); - } - } - - inline CopyStatusType CopyStatusTypeFromString(const std::string& copyStatusType) - { - if (copyStatusType == "pending") - { - return CopyStatusType::Pending; - } - if (copyStatusType == "success") - { - return CopyStatusType::Success; - } - if (copyStatusType == "aborted") - { - return CopyStatusType::Aborted; - } - if (copyStatusType == "failed") - { - return CopyStatusType::Failed; - } - throw std::runtime_error("Cannot convert " + copyStatusType + " to CopyStatusType"); - } - - // When a file is leased, specifies whether the lease is of infinite or fixed duration. + // When a file or share is leased, specifies whether the lease is of infinite or fixed duration. enum class LeaseDurationType { Infinite, @@ -559,7 +396,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { throw std::runtime_error("Cannot convert " + leaseDurationType + " to LeaseDurationType"); } - // Lease state of the file. + // Lease state of the file or share. enum class LeaseStateType { Available, @@ -614,7 +451,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { throw std::runtime_error("Cannot convert " + leaseStateType + " to LeaseStateType"); } - // The current lease status of the file. + // The current lease status of the file or share. enum class LeaseStatusType { Locked, @@ -648,12 +485,168 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { throw std::runtime_error("Cannot convert " + leaseStatusType + " to LeaseStatusType"); } + // An enumeration of directories and files. + struct ListFilesAndDirectoriesSegmentResponse + { + std::string ServiceEndpoint; + std::string ShareName; + std::string ShareSnapshot; + std::string DirectoryPath; + std::string Prefix; + std::string Marker; + int32_t MaxResults = int32_t(); + FilesAndDirectoriesListSegment Segment; + std::string NextMarker; + }; + + // An enumeration of handles. + struct ListHandlesResponse + { + std::vector HandleList; + std::string NextMarker; + }; + + // Properties of a share. + struct ShareProperties + { + std::string LastModified; + std::string Etag; + int32_t Quota = int32_t(); + Azure::Core::Nullable ProvisionedIops; + Azure::Core::Nullable ProvisionedIngressMBps; + Azure::Core::Nullable ProvisionedEgressMBps; + Azure::Core::Nullable NextAllowedQuotaDowngradeTime; + std::string DeletedTime; + int32_t RemainingRetentionDays = int32_t(); + LeaseStatusType LeaseStatus; + LeaseStateType LeaseState; + LeaseDurationType LeaseDuration; + }; + + typedef std::map Metadata; + + // A listed Azure Storage share item. + struct ShareItem + { + std::string Name; + std::string Snapshot; + bool Deleted = bool(); + std::string Version; + ShareProperties Properties; + Metadata ShareMetadata; + }; + + // An enumeration of shares. + struct ListSharesResponse + { + std::string ServiceEndpoint; + std::string Prefix; + std::string Marker; + int32_t MaxResults = int32_t(); + std::vector ShareItems; + std::string NextMarker; + }; + + // The retention policy. + struct ShareRetentionPolicy + { + bool Enabled + = bool(); // Indicates whether a retention policy is enabled for the File service. If false, + // metrics data is retained, and the user is responsible for deleting it. + Azure::Core::Nullable + Days; // Indicates the number of days that metrics data should be retained. All data older + // than this value will be deleted. Metrics data is deleted on a best-effort basis + // after the retention period expires. + }; + + // Storage Analytics metrics for file service. + struct Metrics + { + std::string Version; // The version of Storage Analytics to configure. + bool Enabled = bool(); // Indicates whether metrics are enabled for the File service. + bool IncludeAPIs = bool(); // Indicates whether metrics should generate summary statistics for + // called API operations. + ShareRetentionPolicy RetentionPolicy; + }; + + // Settings for SMB multichannel + struct SmbMultichannel + { + bool Enabled = bool(); // If SMB multichannel is enabled. + }; + + // An Azure Storage file range. + struct FileRange + { + int64_t Start = int64_t(); // Start of the range. + int64_t End = int64_t(); // End of the range. + }; + + // An Azure Storage file clear range. + struct ClearRange + { + int64_t Start = int64_t(); // Start of the range. + int64_t End = int64_t(); // End of the range. + }; + + // Settings for SMB protocol. + struct SmbSettings + { + SmbMultichannel Multichannel; // Settings for SMB Multichannel. + }; + + // Protocol settings + struct ShareProtocolSettings + { + SmbSettings Settings; // Settings for SMB protocol. + }; + + // The list of file ranges + struct ShareFileRangeList + { + std::vector Ranges; + std::vector ClearRanges; + }; + + // Stats for the share. + struct ShareStats + { + int64_t ShareUsageBytes + = int64_t(); // The approximate size of the data stored in bytes. Note that this value may + // not include all recently created or recently resized files. + }; + + // Signed identifier. + struct SignedIdentifier + { + std::string Id; // A unique id. + AccessPolicy Policy; // The access policy. + }; + + // Storage service properties. + struct StorageServiceProperties + { + Metrics HourMetrics; // A summary of request statistics grouped by API in hourly aggregates for + // files. + Metrics MinuteMetrics; // A summary of request statistics grouped by API in minute aggregates + // for files. + std::vector Cors; // The set of CORS rules. + Azure::Core::Nullable Protocol; // Protocol settings + }; + + // A permission (a security descriptor) at the share level. + struct SharePermission + { + std::string Permission; // The permission in the Security Descriptor Definition Language (SDDL). + }; + // Describes what lease action to take. enum class LeaseAction { Acquire, Release, Change, + Renew, Break, Unknown }; @@ -668,6 +661,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { return "release"; case LeaseAction::Change: return "change"; + case LeaseAction::Renew: + return "renew"; case LeaseAction::Break: return "break"; default: @@ -689,6 +684,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { return LeaseAction::Change; } + if (leaseAction == "renew") + { + return LeaseAction::Renew; + } if (leaseAction == "break") { return LeaseAction::Break; @@ -696,6 +695,54 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { throw std::runtime_error("Cannot convert " + leaseAction + " to LeaseAction"); } + // State of the copy operation identified by 'x-ms-copy-id'. + enum class CopyStatusType + { + Pending, + Success, + Aborted, + Failed, + Unknown + }; + + inline std::string CopyStatusTypeToString(const CopyStatusType& copyStatusType) + { + switch (copyStatusType) + { + case CopyStatusType::Pending: + return "pending"; + case CopyStatusType::Success: + return "success"; + case CopyStatusType::Aborted: + return "aborted"; + case CopyStatusType::Failed: + return "failed"; + default: + return std::string(); + } + } + + inline CopyStatusType CopyStatusTypeFromString(const std::string& copyStatusType) + { + if (copyStatusType == "pending") + { + return CopyStatusType::Pending; + } + if (copyStatusType == "success") + { + return CopyStatusType::Success; + } + if (copyStatusType == "aborted") + { + return CopyStatusType::Aborted; + } + if (copyStatusType == "failed") + { + return CopyStatusType::Failed; + } + throw std::runtime_error("Cannot convert " + copyStatusType + " to CopyStatusType"); + } + // Specify one of the following options: - Update: Writes the bytes specified by the request body // into the specified range. The Range and Content-Length headers must match to perform the // update. - Clear: Clears the specified range and releases the space used in storage for that @@ -743,6 +790,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Metrics HourMetrics; Metrics MinuteMetrics; std::vector Cors; + Azure::Core::Nullable Protocol; }; struct ServiceListSharesSegmentResult @@ -771,12 +819,54 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Azure::Core::Nullable ProvisionedIngressMBps; Azure::Core::Nullable ProvisionedEgressMBps; Azure::Core::Nullable NextAllowedQuotaDowngradeTime; + Azure::Core::Nullable LeaseDuration; + Azure::Core::Nullable LeaseState; + Azure::Core::Nullable LeaseStatus; }; struct ShareDeleteResult { }; + struct ShareAcquireLeaseResult + { + std::string ETag; + std::string LastModified; + Azure::Core::Nullable LeaseTime; + std::string LeaseId; + }; + + struct ShareReleaseLeaseResult + { + std::string ETag; + std::string LastModified; + Azure::Core::Nullable LeaseTime; + }; + + struct ShareChangeLeaseResult + { + std::string ETag; + std::string LastModified; + Azure::Core::Nullable LeaseTime; + std::string LeaseId; + }; + + struct ShareRenewLeaseResult + { + std::string ETag; + std::string LastModified; + Azure::Core::Nullable LeaseTime; + std::string LeaseId; + }; + + struct ShareBreakLeaseResult + { + std::string ETag; + std::string LastModified; + int32_t LeaseTime = int32_t(); + Azure::Core::Nullable LeaseId; + }; + struct ShareCreateSnapshotResult { std::string Snapshot; @@ -1053,7 +1143,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { struct FileGetRangeListResult { - std::vector RangeList; + std::vector Ranges; + std::vector ClearRanges; std::string LastModified; std::string ETag; int64_t FileContentLength = int64_t(); @@ -1249,9 +1340,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { writer.Write(XmlNode{XmlNodeType::StartTag, "Enabled"}); writer.Write(XmlNode{XmlNodeType::Text, nullptr, object.Enabled == 0 ? "false" : "true"}); writer.Write(XmlNode{XmlNodeType::EndTag}); - writer.Write(XmlNode{XmlNodeType::StartTag, "Days"}); - writer.Write(XmlNode{XmlNodeType::Text, nullptr, std::to_string(object.Days).data()}); - writer.Write(XmlNode{XmlNodeType::EndTag}); + if (object.Days.HasValue()) + { + writer.Write(XmlNode{XmlNodeType::StartTag, "Days"}); + writer.Write( + XmlNode{XmlNodeType::Text, nullptr, std::to_string(object.Days.GetValue()).data()}); + writer.Write(XmlNode{XmlNodeType::EndTag}); + } }; static void MetricsToXml(XmlWriter& writer, const Metrics& object) @@ -1293,6 +1388,27 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { writer.Write(XmlNode{XmlNodeType::EndTag}); }; + static void SmbMultichannelToXml(XmlWriter& writer, const SmbMultichannel& object) + { + writer.Write(XmlNode{XmlNodeType::StartTag, "Multichannel"}); + writer.Write(XmlNode{XmlNodeType::StartTag, "Enabled"}); + writer.Write(XmlNode{XmlNodeType::Text, nullptr, object.Enabled == 0 ? "false" : "true"}); + writer.Write(XmlNode{XmlNodeType::EndTag}); + writer.Write(XmlNode{XmlNodeType::EndTag}); + }; + + static void SmbSettingsToXml(XmlWriter& writer, const SmbSettings& object) + { + writer.Write(XmlNode{XmlNodeType::StartTag, "SMB"}); + SmbMultichannelToXml(writer, object.Multichannel); + writer.Write(XmlNode{XmlNodeType::EndTag}); + }; + + static void ShareProtocolSettingsToXml(XmlWriter& writer, const ShareProtocolSettings& object) + { + SmbSettingsToXml(writer, object.Settings); + }; + static void StorageServicePropertiesToXml( XmlWriter& writer, const StorageServiceProperties& object) @@ -1313,6 +1429,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } writer.Write(XmlNode{XmlNodeType::EndTag}); } + if (object.Protocol.HasValue()) + { + writer.Write(XmlNode{XmlNodeType::StartTag, "Protocol"}); + ShareProtocolSettingsToXml(writer, object.Protocol.GetValue()); + writer.Write(XmlNode{XmlNodeType::EndTag}); + } writer.Write(XmlNode{XmlNodeType::EndTag}); }; static Azure::Core::Response GetPropertiesParseResult( @@ -1345,9 +1467,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = ShareRetentionPolicy(); enum class XmlTagName { + c_Days, c_Unknown, c_Enabled, - c_Days, }; std::vector path; @@ -1372,14 +1494,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "Enabled") == 0) - { - path.emplace_back(XmlTagName::c_Enabled); - } - else if (std::strcmp(node.Name, "Days") == 0) + if (std::strcmp(node.Name, "Days") == 0) { path.emplace_back(XmlTagName::c_Days); } + else if (std::strcmp(node.Name, "Enabled") == 0) + { + path.emplace_back(XmlTagName::c_Enabled); + } else { path.emplace_back(XmlTagName::c_Unknown); @@ -1405,11 +1527,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = Metrics(); enum class XmlTagName { - c_Unknown, c_Version, - c_Enabled, + c_Unknown, c_IncludeAPIs, c_RetentionPolicy, + c_Enabled, }; std::vector path; @@ -1438,10 +1560,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { path.emplace_back(XmlTagName::c_Version); } - else if (std::strcmp(node.Name, "Enabled") == 0) - { - path.emplace_back(XmlTagName::c_Enabled); - } else if (std::strcmp(node.Name, "IncludeAPIs") == 0) { path.emplace_back(XmlTagName::c_IncludeAPIs); @@ -1450,6 +1568,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { path.emplace_back(XmlTagName::c_RetentionPolicy); } + else if (std::strcmp(node.Name, "Enabled") == 0) + { + path.emplace_back(XmlTagName::c_Enabled); + } else { path.emplace_back(XmlTagName::c_Unknown); @@ -1485,12 +1607,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = CorsRule(); enum class XmlTagName { - c_Unknown, - c_AllowedOrigins, - c_AllowedMethods, c_AllowedHeaders, c_ExposedHeaders, c_MaxAgeInSeconds, + c_AllowedOrigins, + c_AllowedMethods, + c_Unknown, }; std::vector path; @@ -1515,15 +1637,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "AllowedOrigins") == 0) - { - path.emplace_back(XmlTagName::c_AllowedOrigins); - } - else if (std::strcmp(node.Name, "AllowedMethods") == 0) - { - path.emplace_back(XmlTagName::c_AllowedMethods); - } - else if (std::strcmp(node.Name, "AllowedHeaders") == 0) + if (std::strcmp(node.Name, "AllowedHeaders") == 0) { path.emplace_back(XmlTagName::c_AllowedHeaders); } @@ -1535,6 +1649,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { path.emplace_back(XmlTagName::c_MaxAgeInSeconds); } + else if (std::strcmp(node.Name, "AllowedOrigins") == 0) + { + path.emplace_back(XmlTagName::c_AllowedOrigins); + } + else if (std::strcmp(node.Name, "AllowedMethods") == 0) + { + path.emplace_back(XmlTagName::c_AllowedMethods); + } else { path.emplace_back(XmlTagName::c_Unknown); @@ -1567,17 +1689,187 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { return result; } + static SmbMultichannel SmbMultichannelFromXml(XmlReader& reader) + { + auto result = SmbMultichannel(); + enum class XmlTagName + { + c_Unknown, + c_Enabled, + }; + std::vector path; + + while (true) + { + auto node = reader.Read(); + if (node.Type == XmlNodeType::End) + { + break; + } + else if (node.Type == XmlNodeType::EndTag) + { + if (path.size() > 0) + { + path.pop_back(); + } + else + { + break; + } + } + else if (node.Type == XmlNodeType::StartTag) + { + + if (std::strcmp(node.Name, "Enabled") == 0) + { + path.emplace_back(XmlTagName::c_Enabled); + } + else + { + path.emplace_back(XmlTagName::c_Unknown); + } + } + else if (node.Type == XmlNodeType::Text) + { + if (path.size() == 1 && path[0] == XmlTagName::c_Enabled) + { + result.Enabled = node.Value; + } + } + } + return result; + } + + static SmbSettings SmbSettingsFromXml(XmlReader& reader) + { + auto result = SmbSettings(); + enum class XmlTagName + { + c_Unknown, + c_SMB, + c_Multichannel, + }; + std::vector path; + + while (true) + { + auto node = reader.Read(); + if (node.Type == XmlNodeType::End) + { + break; + } + else if (node.Type == XmlNodeType::EndTag) + { + if (path.size() > 0) + { + path.pop_back(); + } + else + { + break; + } + } + else if (node.Type == XmlNodeType::StartTag) + { + + if (std::strcmp(node.Name, "SMB") == 0) + { + path.emplace_back(XmlTagName::c_SMB); + } + else if (std::strcmp(node.Name, "Multichannel") == 0) + { + path.emplace_back(XmlTagName::c_Multichannel); + } + else + { + path.emplace_back(XmlTagName::c_Unknown); + } + + if (path.size() == 2 && path[0] == XmlTagName::c_SMB + && path[1] == XmlTagName::c_Multichannel) + { + result.Multichannel = SmbMultichannelFromXml(reader); + path.pop_back(); + } + } + else if (node.Type == XmlNodeType::Text) + { + } + } + return result; + } + + static ShareProtocolSettings ShareProtocolSettingsFromXml(XmlReader& reader) + { + auto result = ShareProtocolSettings(); + enum class XmlTagName + { + c_ShareProtocolSettings, + c_Unknown, + c_SMB, + }; + std::vector path; + + while (true) + { + auto node = reader.Read(); + if (node.Type == XmlNodeType::End) + { + break; + } + else if (node.Type == XmlNodeType::EndTag) + { + if (path.size() > 0) + { + path.pop_back(); + } + else + { + break; + } + } + else if (node.Type == XmlNodeType::StartTag) + { + + if (std::strcmp(node.Name, "ShareProtocolSettings") == 0) + { + path.emplace_back(XmlTagName::c_ShareProtocolSettings); + } + else if (std::strcmp(node.Name, "SMB") == 0) + { + path.emplace_back(XmlTagName::c_SMB); + } + else + { + path.emplace_back(XmlTagName::c_Unknown); + } + + if (path.size() == 2 && path[0] == XmlTagName::c_ShareProtocolSettings + && path[1] == XmlTagName::c_SMB) + { + result.Settings = SmbSettingsFromXml(reader); + path.pop_back(); + } + } + else if (node.Type == XmlNodeType::Text) + { + } + } + return result; + } + static StorageServiceProperties StorageServicePropertiesFromXml(XmlReader& reader) { auto result = StorageServiceProperties(); enum class XmlTagName { - c_Unknown, c_StorageServiceProperties, - c_HourMetrics, - c_MinuteMetrics, - c_CorsRule, + c_Protocol, c_Cors, + c_HourMetrics, + c_CorsRule, + c_Unknown, + c_MinuteMetrics, }; std::vector path; @@ -1606,21 +1898,25 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { path.emplace_back(XmlTagName::c_StorageServiceProperties); } + else if (std::strcmp(node.Name, "Protocol") == 0) + { + path.emplace_back(XmlTagName::c_Protocol); + } + else if (std::strcmp(node.Name, "Cors") == 0) + { + path.emplace_back(XmlTagName::c_Cors); + } else if (std::strcmp(node.Name, "HourMetrics") == 0) { path.emplace_back(XmlTagName::c_HourMetrics); } - else if (std::strcmp(node.Name, "MinuteMetrics") == 0) - { - path.emplace_back(XmlTagName::c_MinuteMetrics); - } else if (std::strcmp(node.Name, "CorsRule") == 0) { path.emplace_back(XmlTagName::c_CorsRule); } - else if (std::strcmp(node.Name, "Cors") == 0) + else if (std::strcmp(node.Name, "MinuteMetrics") == 0) { - path.emplace_back(XmlTagName::c_Cors); + path.emplace_back(XmlTagName::c_MinuteMetrics); } else { @@ -1640,6 +1936,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { result.MinuteMetrics = MetricsFromXml(reader); path.pop_back(); } + else if ( + path.size() == 2 && path[0] == XmlTagName::c_StorageServiceProperties + && path[1] == XmlTagName::c_Protocol) + { + result.Protocol = ShareProtocolSettingsFromXml(reader); + path.pop_back(); + } else if ( path.size() == 3 && path[0] == XmlTagName::c_StorageServiceProperties && path[1] == XmlTagName::c_Cors && path[2] == XmlTagName::c_CorsRule) @@ -1662,6 +1965,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { result.HourMetrics = std::move(object.HourMetrics); result.MinuteMetrics = std::move(object.MinuteMetrics); result.Cors = std::move(object.Cors); + result.Protocol = std::move(object.Protocol); return result; } @@ -1690,21 +1994,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } } - static ShareProperties SharePropertiesFromXml(XmlReader& reader) + static LeaseStatusType LeaseStatusTypeFromXml(XmlReader& reader) { - auto result = ShareProperties(); + auto result = LeaseStatusType::Unknown; enum class XmlTagName { c_Unknown, - c_LastModified, - c_Etag, - c_Quota, - c_ProvisionedIops, - c_ProvisionedIngressMBps, - c_ProvisionedEgressMBps, - c_NextAllowedQuotaDowngradeTime, - c_DeletedTime, - c_RemainingRetentionDays, + c_LeaseStatus, }; std::vector path; @@ -1729,9 +2025,177 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "Last-Modified") == 0) + if (std::strcmp(node.Name, "LeaseStatus") == 0) { - path.emplace_back(XmlTagName::c_LastModified); + path.emplace_back(XmlTagName::c_LeaseStatus); + } + else + { + path.emplace_back(XmlTagName::c_Unknown); + } + } + else if (node.Type == XmlNodeType::Text) + { + if (path.size() == 1 && path[0] == XmlTagName::c_LeaseStatus) + { + result = LeaseStatusTypeFromString(node.Value); + } + } + } + return result; + } + + static LeaseStateType LeaseStateTypeFromXml(XmlReader& reader) + { + auto result = LeaseStateType::Unknown; + enum class XmlTagName + { + c_LeaseState, + c_Unknown, + }; + std::vector path; + + while (true) + { + auto node = reader.Read(); + if (node.Type == XmlNodeType::End) + { + break; + } + else if (node.Type == XmlNodeType::EndTag) + { + if (path.size() > 0) + { + path.pop_back(); + } + else + { + break; + } + } + else if (node.Type == XmlNodeType::StartTag) + { + + if (std::strcmp(node.Name, "LeaseState") == 0) + { + path.emplace_back(XmlTagName::c_LeaseState); + } + else + { + path.emplace_back(XmlTagName::c_Unknown); + } + } + else if (node.Type == XmlNodeType::Text) + { + if (path.size() == 1 && path[0] == XmlTagName::c_LeaseState) + { + result = LeaseStateTypeFromString(node.Value); + } + } + } + return result; + } + + static LeaseDurationType LeaseDurationTypeFromXml(XmlReader& reader) + { + auto result = LeaseDurationType::Unknown; + enum class XmlTagName + { + c_LeaseDuration, + c_Unknown, + }; + std::vector path; + + while (true) + { + auto node = reader.Read(); + if (node.Type == XmlNodeType::End) + { + break; + } + else if (node.Type == XmlNodeType::EndTag) + { + if (path.size() > 0) + { + path.pop_back(); + } + else + { + break; + } + } + else if (node.Type == XmlNodeType::StartTag) + { + + if (std::strcmp(node.Name, "LeaseDuration") == 0) + { + path.emplace_back(XmlTagName::c_LeaseDuration); + } + else + { + path.emplace_back(XmlTagName::c_Unknown); + } + } + else if (node.Type == XmlNodeType::Text) + { + if (path.size() == 1 && path[0] == XmlTagName::c_LeaseDuration) + { + result = LeaseDurationTypeFromString(node.Value); + } + } + } + return result; + } + + static ShareProperties SharePropertiesFromXml(XmlReader& reader) + { + auto result = ShareProperties(); + enum class XmlTagName + { + c_LeaseState, + c_DeletedTime, + c_Etag, + c_Quota, + c_Unknown, + c_RemainingRetentionDays, + c_ProvisionedIngressMBps, + c_LastModified, + c_ProvisionedIops, + c_ProvisionedEgressMBps, + c_LeaseDuration, + c_NextAllowedQuotaDowngradeTime, + c_LeaseStatus, + }; + std::vector path; + + while (true) + { + auto node = reader.Read(); + if (node.Type == XmlNodeType::End) + { + break; + } + else if (node.Type == XmlNodeType::EndTag) + { + if (path.size() > 0) + { + path.pop_back(); + } + else + { + break; + } + } + else if (node.Type == XmlNodeType::StartTag) + { + + if (std::strcmp(node.Name, "LeaseState") == 0) + { + path.emplace_back(XmlTagName::c_LeaseState); + } + else if (std::strcmp(node.Name, "DeletedTime") == 0) + { + path.emplace_back(XmlTagName::c_DeletedTime); } else if (std::strcmp(node.Name, "Etag") == 0) { @@ -1741,34 +2205,58 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { path.emplace_back(XmlTagName::c_Quota); } - else if (std::strcmp(node.Name, "ProvisionedIops") == 0) + else if (std::strcmp(node.Name, "RemainingRetentionDays") == 0) { - path.emplace_back(XmlTagName::c_ProvisionedIops); + path.emplace_back(XmlTagName::c_RemainingRetentionDays); } else if (std::strcmp(node.Name, "ProvisionedIngressMBps") == 0) { path.emplace_back(XmlTagName::c_ProvisionedIngressMBps); } + else if (std::strcmp(node.Name, "Last-Modified") == 0) + { + path.emplace_back(XmlTagName::c_LastModified); + } + else if (std::strcmp(node.Name, "ProvisionedIops") == 0) + { + path.emplace_back(XmlTagName::c_ProvisionedIops); + } else if (std::strcmp(node.Name, "ProvisionedEgressMBps") == 0) { path.emplace_back(XmlTagName::c_ProvisionedEgressMBps); } + else if (std::strcmp(node.Name, "LeaseDuration") == 0) + { + path.emplace_back(XmlTagName::c_LeaseDuration); + } else if (std::strcmp(node.Name, "NextAllowedQuotaDowngradeTime") == 0) { path.emplace_back(XmlTagName::c_NextAllowedQuotaDowngradeTime); } - else if (std::strcmp(node.Name, "DeletedTime") == 0) + else if (std::strcmp(node.Name, "LeaseStatus") == 0) { - path.emplace_back(XmlTagName::c_DeletedTime); - } - else if (std::strcmp(node.Name, "RemainingRetentionDays") == 0) - { - path.emplace_back(XmlTagName::c_RemainingRetentionDays); + path.emplace_back(XmlTagName::c_LeaseStatus); } else { path.emplace_back(XmlTagName::c_Unknown); } + + if (path.size() == 1 && path[0] == XmlTagName::c_LeaseStatus) + { + result.LeaseStatus = LeaseStatusTypeFromXml(reader); + path.pop_back(); + } + else if (path.size() == 1 && path[0] == XmlTagName::c_LeaseState) + { + result.LeaseState = LeaseStateTypeFromXml(reader); + path.pop_back(); + } + else if (path.size() == 1 && path[0] == XmlTagName::c_LeaseDuration) + { + result.LeaseDuration = LeaseDurationTypeFromXml(reader); + path.pop_back(); + } } else if (node.Type == XmlNodeType::Text) { @@ -1852,13 +2340,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = ShareItem(); enum class XmlTagName { - c_Unknown, c_Name, - c_Snapshot, - c_Deleted, c_Version, + c_Deleted, c_Properties, c_Metadata, + c_Unknown, + c_Snapshot, }; std::vector path; @@ -1887,18 +2375,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { path.emplace_back(XmlTagName::c_Name); } - else if (std::strcmp(node.Name, "Snapshot") == 0) + else if (std::strcmp(node.Name, "Version") == 0) { - path.emplace_back(XmlTagName::c_Snapshot); + path.emplace_back(XmlTagName::c_Version); } else if (std::strcmp(node.Name, "Deleted") == 0) { path.emplace_back(XmlTagName::c_Deleted); } - else if (std::strcmp(node.Name, "Version") == 0) - { - path.emplace_back(XmlTagName::c_Version); - } else if (std::strcmp(node.Name, "Properties") == 0) { path.emplace_back(XmlTagName::c_Properties); @@ -1907,6 +2391,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { path.emplace_back(XmlTagName::c_Metadata); } + else if (std::strcmp(node.Name, "Snapshot") == 0) + { + path.emplace_back(XmlTagName::c_Snapshot); + } else { path.emplace_back(XmlTagName::c_Unknown); @@ -1951,14 +2439,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = ListSharesResponse(); enum class XmlTagName { - c_Unknown, - c_EnumerationResults, - c_Prefix, - c_Marker, - c_MaxResults, - c_Shares, - c_Share, c_NextMarker, + c_Marker, + c_EnumerationResults, + c_MaxResults, + c_Share, + c_Unknown, + c_Prefix, + c_Shares, }; std::vector path; @@ -1983,33 +2471,33 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "EnumerationResults") == 0) + if (std::strcmp(node.Name, "NextMarker") == 0) { - path.emplace_back(XmlTagName::c_EnumerationResults); - } - else if (std::strcmp(node.Name, "Prefix") == 0) - { - path.emplace_back(XmlTagName::c_Prefix); + path.emplace_back(XmlTagName::c_NextMarker); } else if (std::strcmp(node.Name, "Marker") == 0) { path.emplace_back(XmlTagName::c_Marker); } + else if (std::strcmp(node.Name, "EnumerationResults") == 0) + { + path.emplace_back(XmlTagName::c_EnumerationResults); + } else if (std::strcmp(node.Name, "MaxResults") == 0) { path.emplace_back(XmlTagName::c_MaxResults); } - else if (std::strcmp(node.Name, "Shares") == 0) - { - path.emplace_back(XmlTagName::c_Shares); - } else if (std::strcmp(node.Name, "Share") == 0) { path.emplace_back(XmlTagName::c_Share); } - else if (std::strcmp(node.Name, "NextMarker") == 0) + else if (std::strcmp(node.Name, "Prefix") == 0) { - path.emplace_back(XmlTagName::c_NextMarker); + path.emplace_back(XmlTagName::c_Prefix); + } + else if (std::strcmp(node.Name, "Shares") == 0) + { + path.emplace_back(XmlTagName::c_Shares); } else { @@ -2141,6 +2629,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. + Azure::Core::Nullable + LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease is + // active and matches this ID. }; static Azure::Core::Response GetProperties( @@ -2162,6 +2653,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Details::c_QueryTimeout, std::to_string(getPropertiesOptions.Timeout.GetValue())); } request.AddHeader(Details::c_HeaderVersion, getPropertiesOptions.ApiVersionParameter); + if (getPropertiesOptions.LeaseIdOptional.HasValue()) + { + request.AddHeader( + Details::c_HeaderLeaseId, getPropertiesOptions.LeaseIdOptional.GetValue()); + } return GetPropertiesParseResult(context, pipeline.Send(context, request)); } @@ -2180,6 +2676,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Azure::Core::Nullable XMsDeleteSnapshots; // Specifies the option include to delete the base share and all of // its snapshots. + Azure::Core::Nullable + LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease is + // active and matches this ID. }; static Azure::Core::Response Delete( @@ -2207,9 +2706,311 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Details::c_HeaderDeleteSnapshots, DeleteSnapshotsOptionTypeToString(deleteOptions.XMsDeleteSnapshots.GetValue())); } + if (deleteOptions.LeaseIdOptional.HasValue()) + { + request.AddHeader(Details::c_HeaderLeaseId, deleteOptions.LeaseIdOptional.GetValue()); + } return DeleteParseResult(context, pipeline.Send(context, request)); } + struct AcquireLeaseOptions + { + Azure::Core::Nullable + Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting + // Timeouts for File Service Operations. + int32_t LeaseDuration + = int32_t(); // 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. + Azure::Core::Nullable + ProposedLeaseIdOptional; // Proposed lease ID, in a GUID string format. The File service + // returns 400 (Invalid request) if the proposed lease ID is + // not in the correct format. See Guid Constructor (String) for + // a list of valid GUID string formats. + std::string ApiVersionParameter + = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use + // for this request. + Azure::Core::Nullable + ShareSnapshot; // The snapshot parameter is an opaque DateTime value that, when present, + // specifies the share snapshot to query. + Azure::Core::Nullable + ClientRequestId; // Provides a client-generated, opaque value with a 1 KB character + // limit that is recorded in the analytics logs when storage analytics + // logging is enabled. + }; + + static Azure::Core::Response AcquireLease( + const Azure::Core::Http::Url& url, + Azure::Core::Http::HttpPipeline& pipeline, + Azure::Core::Context context, + const AcquireLeaseOptions& acquireLeaseOptions) + { + Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Put, url); + request.AddHeader(Details::c_HeaderContentLength, "0"); + request.GetUrl().AppendQuery(Details::c_QueryComp, "lease"); + request.AddHeader(Details::c_HeaderAction, "acquire"); + request.GetUrl().AppendQuery(Details::c_QueryRestype, "share"); + if (acquireLeaseOptions.Timeout.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryTimeout, std::to_string(acquireLeaseOptions.Timeout.GetValue())); + } + request.AddHeader( + Details::c_HeaderDuration, std::to_string(acquireLeaseOptions.LeaseDuration)); + if (acquireLeaseOptions.ProposedLeaseIdOptional.HasValue()) + { + request.AddHeader( + Details::c_HeaderProposedLeaseId, + acquireLeaseOptions.ProposedLeaseIdOptional.GetValue()); + } + request.AddHeader(Details::c_HeaderVersion, acquireLeaseOptions.ApiVersionParameter); + if (acquireLeaseOptions.ShareSnapshot.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryShareSnapshot, acquireLeaseOptions.ShareSnapshot.GetValue()); + } + if (acquireLeaseOptions.ClientRequestId.HasValue()) + { + request.AddHeader( + Details::c_HeaderRequestId, acquireLeaseOptions.ClientRequestId.GetValue()); + } + return AcquireLeaseParseResult(context, pipeline.Send(context, request)); + } + + struct ReleaseLeaseOptions + { + Azure::Core::Nullable + Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting + // Timeouts for File Service Operations. + std::string LeaseIdRequired; // Specifies the current lease ID on the resource. + std::string ApiVersionParameter + = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use + // for this request. + Azure::Core::Nullable + ShareSnapshot; // The snapshot parameter is an opaque DateTime value that, when present, + // specifies the share snapshot to query. + Azure::Core::Nullable + ClientRequestId; // Provides a client-generated, opaque value with a 1 KB character + // limit that is recorded in the analytics logs when storage analytics + // logging is enabled. + }; + + static Azure::Core::Response ReleaseLease( + const Azure::Core::Http::Url& url, + Azure::Core::Http::HttpPipeline& pipeline, + Azure::Core::Context context, + const ReleaseLeaseOptions& releaseLeaseOptions) + { + Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Put, url); + request.AddHeader(Details::c_HeaderContentLength, "0"); + request.GetUrl().AppendQuery(Details::c_QueryComp, "lease"); + request.AddHeader(Details::c_HeaderAction, "release"); + request.GetUrl().AppendQuery(Details::c_QueryRestype, "share"); + if (releaseLeaseOptions.Timeout.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryTimeout, std::to_string(releaseLeaseOptions.Timeout.GetValue())); + } + request.AddHeader(Details::c_HeaderLeaseId, releaseLeaseOptions.LeaseIdRequired); + request.AddHeader(Details::c_HeaderVersion, releaseLeaseOptions.ApiVersionParameter); + if (releaseLeaseOptions.ShareSnapshot.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryShareSnapshot, releaseLeaseOptions.ShareSnapshot.GetValue()); + } + if (releaseLeaseOptions.ClientRequestId.HasValue()) + { + request.AddHeader( + Details::c_HeaderRequestId, releaseLeaseOptions.ClientRequestId.GetValue()); + } + return ReleaseLeaseParseResult(context, pipeline.Send(context, request)); + } + + struct ChangeLeaseOptions + { + Azure::Core::Nullable + Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting + // Timeouts for File Service Operations. + std::string LeaseIdRequired; // Specifies the current lease ID on the resource. + Azure::Core::Nullable + ProposedLeaseIdOptional; // Proposed lease ID, in a GUID string format. The File service + // returns 400 (Invalid request) if the proposed lease ID is + // not in the correct format. See Guid Constructor (String) for + // a list of valid GUID string formats. + std::string ApiVersionParameter + = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use + // for this request. + Azure::Core::Nullable + ShareSnapshot; // The snapshot parameter is an opaque DateTime value that, when present, + // specifies the share snapshot to query. + Azure::Core::Nullable + ClientRequestId; // Provides a client-generated, opaque value with a 1 KB character + // limit that is recorded in the analytics logs when storage analytics + // logging is enabled. + }; + + static Azure::Core::Response ChangeLease( + const Azure::Core::Http::Url& url, + Azure::Core::Http::HttpPipeline& pipeline, + Azure::Core::Context context, + const ChangeLeaseOptions& changeLeaseOptions) + { + Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Put, url); + request.AddHeader(Details::c_HeaderContentLength, "0"); + request.GetUrl().AppendQuery(Details::c_QueryComp, "lease"); + request.AddHeader(Details::c_HeaderAction, "change"); + request.GetUrl().AppendQuery(Details::c_QueryRestype, "share"); + if (changeLeaseOptions.Timeout.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryTimeout, std::to_string(changeLeaseOptions.Timeout.GetValue())); + } + request.AddHeader(Details::c_HeaderLeaseId, changeLeaseOptions.LeaseIdRequired); + if (changeLeaseOptions.ProposedLeaseIdOptional.HasValue()) + { + request.AddHeader( + Details::c_HeaderProposedLeaseId, + changeLeaseOptions.ProposedLeaseIdOptional.GetValue()); + } + request.AddHeader(Details::c_HeaderVersion, changeLeaseOptions.ApiVersionParameter); + if (changeLeaseOptions.ShareSnapshot.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryShareSnapshot, changeLeaseOptions.ShareSnapshot.GetValue()); + } + if (changeLeaseOptions.ClientRequestId.HasValue()) + { + request.AddHeader( + Details::c_HeaderRequestId, changeLeaseOptions.ClientRequestId.GetValue()); + } + return ChangeLeaseParseResult(context, pipeline.Send(context, request)); + } + + struct RenewLeaseOptions + { + Azure::Core::Nullable + Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting + // Timeouts for File Service Operations. + std::string LeaseIdRequired; // Specifies the current lease ID on the resource. + std::string ApiVersionParameter + = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use + // for this request. + Azure::Core::Nullable + ShareSnapshot; // The snapshot parameter is an opaque DateTime value that, when present, + // specifies the share snapshot to query. + Azure::Core::Nullable + ClientRequestId; // Provides a client-generated, opaque value with a 1 KB character + // limit that is recorded in the analytics logs when storage analytics + // logging is enabled. + }; + + static Azure::Core::Response RenewLease( + const Azure::Core::Http::Url& url, + Azure::Core::Http::HttpPipeline& pipeline, + Azure::Core::Context context, + const RenewLeaseOptions& renewLeaseOptions) + { + Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Put, url); + request.AddHeader(Details::c_HeaderContentLength, "0"); + request.GetUrl().AppendQuery(Details::c_QueryComp, "lease"); + request.AddHeader(Details::c_HeaderAction, "renew"); + request.GetUrl().AppendQuery(Details::c_QueryRestype, "share"); + if (renewLeaseOptions.Timeout.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryTimeout, std::to_string(renewLeaseOptions.Timeout.GetValue())); + } + request.AddHeader(Details::c_HeaderLeaseId, renewLeaseOptions.LeaseIdRequired); + request.AddHeader(Details::c_HeaderVersion, renewLeaseOptions.ApiVersionParameter); + if (renewLeaseOptions.ShareSnapshot.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryShareSnapshot, renewLeaseOptions.ShareSnapshot.GetValue()); + } + if (renewLeaseOptions.ClientRequestId.HasValue()) + { + request.AddHeader( + Details::c_HeaderRequestId, renewLeaseOptions.ClientRequestId.GetValue()); + } + return RenewLeaseParseResult(context, pipeline.Send(context, request)); + } + + struct BreakLeaseOptions + { + Azure::Core::Nullable + Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting + // Timeouts for File Service Operations. + Azure::Core::Nullable + LeaseBreakPeriod; // For a break operation, proposed duration the lease should continue + // before it is broken, in seconds, between 0 and 60. This break + // period is only used if it is shorter than the time remaining on the + // lease. If longer, the time remaining on the lease is used. A new + // lease will not be available before the break period has expired, + // but the lease may be held for longer than the break period. If this + // header does not appear with a break operation, a fixed-duration + // lease breaks after the remaining lease period elapses, and an + // infinite lease breaks immediately. + Azure::Core::Nullable + LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease is + // active and matches this ID. + std::string ApiVersionParameter + = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use + // for this request. + Azure::Core::Nullable + ClientRequestId; // Provides a client-generated, opaque value with a 1 KB character + // limit that is recorded in the analytics logs when storage analytics + // logging is enabled. + Azure::Core::Nullable + ShareSnapshot; // The snapshot parameter is an opaque DateTime value that, when present, + // specifies the share snapshot to query. + }; + + static Azure::Core::Response BreakLease( + const Azure::Core::Http::Url& url, + Azure::Core::Http::HttpPipeline& pipeline, + Azure::Core::Context context, + const BreakLeaseOptions& breakLeaseOptions) + { + Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Put, url); + request.AddHeader(Details::c_HeaderContentLength, "0"); + request.GetUrl().AppendQuery(Details::c_QueryComp, "lease"); + request.AddHeader(Details::c_HeaderAction, "break"); + request.GetUrl().AppendQuery(Details::c_QueryRestype, "share"); + if (breakLeaseOptions.Timeout.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryTimeout, std::to_string(breakLeaseOptions.Timeout.GetValue())); + } + if (breakLeaseOptions.LeaseBreakPeriod.HasValue()) + { + request.AddHeader( + Details::c_HeaderBreakPeriod, + std::to_string(breakLeaseOptions.LeaseBreakPeriod.GetValue())); + } + if (breakLeaseOptions.LeaseIdOptional.HasValue()) + { + request.AddHeader(Details::c_HeaderLeaseId, breakLeaseOptions.LeaseIdOptional.GetValue()); + } + request.AddHeader(Details::c_HeaderVersion, breakLeaseOptions.ApiVersionParameter); + if (breakLeaseOptions.ClientRequestId.HasValue()) + { + request.AddHeader( + Details::c_HeaderRequestId, breakLeaseOptions.ClientRequestId.GetValue()); + } + if (breakLeaseOptions.ShareSnapshot.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryShareSnapshot, breakLeaseOptions.ShareSnapshot.GetValue()); + } + return BreakLeaseParseResult(context, pipeline.Send(context, request)); + } + struct CreateSnapshotOptions { Azure::Core::Nullable @@ -2340,6 +3141,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { // for this request. Azure::Core::Nullable ShareQuota; // Specifies the maximum size of the share, in gigabytes. + Azure::Core::Nullable + LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease is + // active and matches this ID. }; static Azure::Core::Response SetQuota( @@ -2363,6 +3167,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.AddHeader( Details::c_HeaderQuota, std::to_string(setQuotaOptions.ShareQuota.GetValue())); } + if (setQuotaOptions.LeaseIdOptional.HasValue()) + { + request.AddHeader(Details::c_HeaderLeaseId, setQuotaOptions.LeaseIdOptional.GetValue()); + } return SetQuotaParseResult(context, pipeline.Send(context, request)); } @@ -2377,6 +3185,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. + Azure::Core::Nullable + LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease is + // active and matches this ID. }; static Azure::Core::Response SetMetadata( @@ -2409,6 +3220,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } metadataKeys.clear(); request.AddHeader(Details::c_HeaderVersion, setMetadataOptions.ApiVersionParameter); + if (setMetadataOptions.LeaseIdOptional.HasValue()) + { + request.AddHeader( + Details::c_HeaderLeaseId, setMetadataOptions.LeaseIdOptional.GetValue()); + } return SetMetadataParseResult(context, pipeline.Send(context, request)); } @@ -2421,6 +3237,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. + Azure::Core::Nullable + LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease is + // active and matches this ID. }; static Azure::Core::Response GetAccessPolicy( @@ -2438,6 +3257,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Details::c_QueryTimeout, std::to_string(getAccessPolicyOptions.Timeout.GetValue())); } request.AddHeader(Details::c_HeaderVersion, getAccessPolicyOptions.ApiVersionParameter); + if (getAccessPolicyOptions.LeaseIdOptional.HasValue()) + { + request.AddHeader( + Details::c_HeaderLeaseId, getAccessPolicyOptions.LeaseIdOptional.GetValue()); + } return GetAccessPolicyParseResult(context, pipeline.Send(context, request)); } @@ -2451,6 +3275,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. + Azure::Core::Nullable + LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease is + // active and matches this ID. }; static Azure::Core::Response SetAccessPolicy( @@ -2479,6 +3306,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Details::c_QueryTimeout, std::to_string(setAccessPolicyOptions.Timeout.GetValue())); } request.AddHeader(Details::c_HeaderVersion, setAccessPolicyOptions.ApiVersionParameter); + if (setAccessPolicyOptions.LeaseIdOptional.HasValue()) + { + request.AddHeader( + Details::c_HeaderLeaseId, setAccessPolicyOptions.LeaseIdOptional.GetValue()); + } return SetAccessPolicyParseResult(context, pipeline.Send(context, request)); } @@ -2491,6 +3323,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. + Azure::Core::Nullable + LeaseIdOptional; // If specified, the operation only succeeds if the resource's lease is + // active and matches this ID. }; static Azure::Core::Response GetStatistics( @@ -2508,6 +3343,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Details::c_QueryTimeout, std::to_string(getStatisticsOptions.Timeout.GetValue())); } request.AddHeader(Details::c_HeaderVersion, getStatisticsOptions.ApiVersionParameter); + if (getStatisticsOptions.LeaseIdOptional.HasValue()) + { + request.AddHeader( + Details::c_HeaderLeaseId, getStatisticsOptions.LeaseIdOptional.GetValue()); + } return GetStatisticsParseResult(context, pipeline.Send(context, request)); } @@ -2629,6 +3469,24 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { result.NextAllowedQuotaDowngradeTime = response.GetHeaders().at(Details::c_HeaderNextAllowedQuotaDowngradeTime); } + if (response.GetHeaders().find(Details::c_HeaderLeaseDuration) + != response.GetHeaders().end()) + { + result.LeaseDuration = LeaseDurationTypeFromString( + response.GetHeaders().at(Details::c_HeaderLeaseDuration)); + } + if (response.GetHeaders().find(Details::c_HeaderLeaseState) + != response.GetHeaders().end()) + { + result.LeaseState + = LeaseStateTypeFromString(response.GetHeaders().at(Details::c_HeaderLeaseState)); + } + if (response.GetHeaders().find(Details::c_HeaderLeaseStatus) + != response.GetHeaders().end()) + { + result.LeaseStatus + = LeaseStatusTypeFromString(response.GetHeaders().at(Details::c_HeaderLeaseStatus)); + } return Azure::Core::Response( std::move(result), std::move(responsePtr)); } @@ -2658,6 +3516,138 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } } + static Azure::Core::Response AcquireLeaseParseResult( + Azure::Core::Context context, + std::unique_ptr responsePtr) + { + auto& response = *responsePtr; + if (response.GetStatusCode() == Azure::Core::Http::HttpStatusCode::Created) + { + // The Acquire operation completed successfully. + ShareAcquireLeaseResult result; + result.ETag = response.GetHeaders().at(Details::c_HeaderETag); + result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); + if (response.GetHeaders().find(Details::c_HeaderLeaseTime) != response.GetHeaders().end()) + { + result.LeaseTime = std::stoi(response.GetHeaders().at(Details::c_HeaderLeaseTime)); + } + result.LeaseId = response.GetHeaders().at(Details::c_HeaderLeaseId); + return Azure::Core::Response( + std::move(result), std::move(responsePtr)); + } + else + { + unused(context); + throw Azure::Storage::StorageError::CreateFromResponse(std::move(responsePtr)); + } + } + + static Azure::Core::Response ReleaseLeaseParseResult( + Azure::Core::Context context, + std::unique_ptr responsePtr) + { + auto& response = *responsePtr; + if (response.GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok) + { + // The Release operation completed successfully. + ShareReleaseLeaseResult result; + result.ETag = response.GetHeaders().at(Details::c_HeaderETag); + result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); + if (response.GetHeaders().find(Details::c_HeaderLeaseTime) != response.GetHeaders().end()) + { + result.LeaseTime = std::stoi(response.GetHeaders().at(Details::c_HeaderLeaseTime)); + } + return Azure::Core::Response( + std::move(result), std::move(responsePtr)); + } + else + { + unused(context); + throw Azure::Storage::StorageError::CreateFromResponse(std::move(responsePtr)); + } + } + + static Azure::Core::Response ChangeLeaseParseResult( + Azure::Core::Context context, + std::unique_ptr responsePtr) + { + auto& response = *responsePtr; + if (response.GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok) + { + // The Change operation completed successfully. + ShareChangeLeaseResult result; + result.ETag = response.GetHeaders().at(Details::c_HeaderETag); + result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); + if (response.GetHeaders().find(Details::c_HeaderLeaseTime) != response.GetHeaders().end()) + { + result.LeaseTime = std::stoi(response.GetHeaders().at(Details::c_HeaderLeaseTime)); + } + result.LeaseId = response.GetHeaders().at(Details::c_HeaderLeaseId); + return Azure::Core::Response( + std::move(result), std::move(responsePtr)); + } + else + { + unused(context); + throw Azure::Storage::StorageError::CreateFromResponse(std::move(responsePtr)); + } + } + + static Azure::Core::Response RenewLeaseParseResult( + Azure::Core::Context context, + std::unique_ptr responsePtr) + { + auto& response = *responsePtr; + if (response.GetStatusCode() == Azure::Core::Http::HttpStatusCode::Ok) + { + // The Renew operation completed successfully. + ShareRenewLeaseResult result; + result.ETag = response.GetHeaders().at(Details::c_HeaderETag); + result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); + if (response.GetHeaders().find(Details::c_HeaderLeaseTime) != response.GetHeaders().end()) + { + result.LeaseTime = std::stoi(response.GetHeaders().at(Details::c_HeaderLeaseTime)); + } + result.LeaseId = response.GetHeaders().at(Details::c_HeaderLeaseId); + return Azure::Core::Response( + std::move(result), std::move(responsePtr)); + } + else + { + unused(context); + throw Azure::Storage::StorageError::CreateFromResponse(std::move(responsePtr)); + } + } + + static Azure::Core::Response BreakLeaseParseResult( + Azure::Core::Context context, + std::unique_ptr responsePtr) + { + auto& response = *responsePtr; + if (response.GetStatusCode() == Azure::Core::Http::HttpStatusCode::Accepted) + { + // The Break operation completed successfully. + ShareBreakLeaseResult result; + result.ETag = response.GetHeaders().at(Details::c_HeaderETag); + result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); + if (response.GetHeaders().find(Details::c_HeaderLeaseTime) != response.GetHeaders().end()) + { + result.LeaseTime = std::stoi(response.GetHeaders().at(Details::c_HeaderLeaseTime)); + } + if (response.GetHeaders().find(Details::c_HeaderLeaseId) != response.GetHeaders().end()) + { + result.LeaseId = response.GetHeaders().at(Details::c_HeaderLeaseId); + } + return Azure::Core::Response( + std::move(result), std::move(responsePtr)); + } + else + { + unused(context); + throw Azure::Storage::StorageError::CreateFromResponse(std::move(responsePtr)); + } + } + static Azure::Core::Response CreateSnapshotParseResult( Azure::Core::Context context, std::unique_ptr responsePtr) @@ -2816,8 +3806,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = AccessPolicy(); enum class XmlTagName { - c_Unknown, c_Start, + c_Unknown, c_Expiry, c_Permission, }; @@ -2947,9 +3937,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = std::vector(); enum class XmlTagName { + c_SignedIdentifier, c_Unknown, c_SignedIdentifiers, - c_SignedIdentifier, }; std::vector path; @@ -2974,14 +3964,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "SignedIdentifiers") == 0) - { - path.emplace_back(XmlTagName::c_SignedIdentifiers); - } - else if (std::strcmp(node.Name, "SignedIdentifier") == 0) + if (std::strcmp(node.Name, "SignedIdentifier") == 0) { path.emplace_back(XmlTagName::c_SignedIdentifier); } + else if (std::strcmp(node.Name, "SignedIdentifiers") == 0) + { + path.emplace_back(XmlTagName::c_SignedIdentifiers); + } else { path.emplace_back(XmlTagName::c_Unknown); @@ -3097,9 +4087,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = ShareStats(); enum class XmlTagName { + c_ShareUsageBytes, c_Unknown, c_ShareStats, - c_ShareUsageBytes, }; std::vector path; @@ -3124,14 +4114,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "ShareStats") == 0) - { - path.emplace_back(XmlTagName::c_ShareStats); - } - else if (std::strcmp(node.Name, "ShareUsageBytes") == 0) + if (std::strcmp(node.Name, "ShareUsageBytes") == 0) { path.emplace_back(XmlTagName::c_ShareUsageBytes); } + else if (std::strcmp(node.Name, "ShareStats") == 0) + { + path.emplace_back(XmlTagName::c_ShareStats); + } else { path.emplace_back(XmlTagName::c_Unknown); @@ -3793,8 +4783,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = DirectoryItem(); enum class XmlTagName { - c_Unknown, c_Name, + c_Unknown, }; std::vector path; @@ -3844,8 +4834,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = FileProperty(); enum class XmlTagName { - c_Unknown, c_ContentLength, + c_Unknown, }; std::vector path; @@ -3895,8 +4885,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = FileItem(); enum class XmlTagName { - c_Unknown, c_Name, + c_Unknown, c_Properties, }; std::vector path; @@ -3957,9 +4947,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = FilesAndDirectoriesListSegment(); enum class XmlTagName { + c_File, c_Unknown, c_Directory, - c_File, }; std::vector path; @@ -3984,14 +4974,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "Directory") == 0) - { - path.emplace_back(XmlTagName::c_Directory); - } - else if (std::strcmp(node.Name, "File") == 0) + if (std::strcmp(node.Name, "File") == 0) { path.emplace_back(XmlTagName::c_File); } + else if (std::strcmp(node.Name, "Directory") == 0) + { + path.emplace_back(XmlTagName::c_Directory); + } else { path.emplace_back(XmlTagName::c_Unknown); @@ -4020,13 +5010,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = ListFilesAndDirectoriesSegmentResponse(); enum class XmlTagName { - c_Unknown, - c_EnumerationResults, - c_Prefix, - c_Marker, - c_MaxResults, - c_Entries, c_NextMarker, + c_Marker, + c_EnumerationResults, + c_MaxResults, + c_Unknown, + c_Prefix, + c_Entries, }; std::vector path; @@ -4051,30 +5041,30 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "EnumerationResults") == 0) + if (std::strcmp(node.Name, "NextMarker") == 0) { - path.emplace_back(XmlTagName::c_EnumerationResults); - } - else if (std::strcmp(node.Name, "Prefix") == 0) - { - path.emplace_back(XmlTagName::c_Prefix); + path.emplace_back(XmlTagName::c_NextMarker); } else if (std::strcmp(node.Name, "Marker") == 0) { path.emplace_back(XmlTagName::c_Marker); } + else if (std::strcmp(node.Name, "EnumerationResults") == 0) + { + path.emplace_back(XmlTagName::c_EnumerationResults); + } else if (std::strcmp(node.Name, "MaxResults") == 0) { path.emplace_back(XmlTagName::c_MaxResults); } + else if (std::strcmp(node.Name, "Prefix") == 0) + { + path.emplace_back(XmlTagName::c_Prefix); + } else if (std::strcmp(node.Name, "Entries") == 0) { path.emplace_back(XmlTagName::c_Entries); } - else if (std::strcmp(node.Name, "NextMarker") == 0) - { - path.emplace_back(XmlTagName::c_NextMarker); - } else { path.emplace_back(XmlTagName::c_Unknown); @@ -4191,15 +5181,15 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = HandleItem(); enum class XmlTagName { - c_Unknown, - c_HandleId, - c_Path, - c_FileId, - c_ParentId, - c_SessionId, - c_ClientIp, c_OpenTime, + c_HandleId, + c_SessionId, + c_ParentId, + c_FileId, + c_Unknown, c_LastReconnectTime, + c_Path, + c_ClientIp, }; std::vector path; @@ -4224,38 +5214,38 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "HandleId") == 0) + if (std::strcmp(node.Name, "OpenTime") == 0) + { + path.emplace_back(XmlTagName::c_OpenTime); + } + else if (std::strcmp(node.Name, "HandleId") == 0) { path.emplace_back(XmlTagName::c_HandleId); } - else if (std::strcmp(node.Name, "Path") == 0) - { - path.emplace_back(XmlTagName::c_Path); - } - else if (std::strcmp(node.Name, "FileId") == 0) - { - path.emplace_back(XmlTagName::c_FileId); - } - else if (std::strcmp(node.Name, "ParentId") == 0) - { - path.emplace_back(XmlTagName::c_ParentId); - } else if (std::strcmp(node.Name, "SessionId") == 0) { path.emplace_back(XmlTagName::c_SessionId); } - else if (std::strcmp(node.Name, "ClientIp") == 0) + else if (std::strcmp(node.Name, "ParentId") == 0) { - path.emplace_back(XmlTagName::c_ClientIp); + path.emplace_back(XmlTagName::c_ParentId); } - else if (std::strcmp(node.Name, "OpenTime") == 0) + else if (std::strcmp(node.Name, "FileId") == 0) { - path.emplace_back(XmlTagName::c_OpenTime); + path.emplace_back(XmlTagName::c_FileId); } else if (std::strcmp(node.Name, "LastReconnectTime") == 0) { path.emplace_back(XmlTagName::c_LastReconnectTime); } + else if (std::strcmp(node.Name, "Path") == 0) + { + path.emplace_back(XmlTagName::c_Path); + } + else if (std::strcmp(node.Name, "ClientIp") == 0) + { + path.emplace_back(XmlTagName::c_ClientIp); + } else { path.emplace_back(XmlTagName::c_Unknown); @@ -4305,11 +5295,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = ListHandlesResponse(); enum class XmlTagName { - c_Unknown, - c_EnumerationResults, - c_Entries, - c_Handle, c_NextMarker, + c_EnumerationResults, + c_Handle, + c_Unknown, + c_Entries, }; std::vector path; @@ -4334,21 +5324,21 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "EnumerationResults") == 0) + if (std::strcmp(node.Name, "NextMarker") == 0) + { + path.emplace_back(XmlTagName::c_NextMarker); + } + else if (std::strcmp(node.Name, "EnumerationResults") == 0) { path.emplace_back(XmlTagName::c_EnumerationResults); } - else if (std::strcmp(node.Name, "Entries") == 0) - { - path.emplace_back(XmlTagName::c_Entries); - } else if (std::strcmp(node.Name, "Handle") == 0) { path.emplace_back(XmlTagName::c_Handle); } - else if (std::strcmp(node.Name, "NextMarker") == 0) + else if (std::strcmp(node.Name, "Entries") == 0) { - path.emplace_back(XmlTagName::c_NextMarker); + path.emplace_back(XmlTagName::c_Entries); } else { @@ -4421,7 +5411,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. - int64_t XMsContentLength; // Specifies the maximum size for the file, up to 1 TB. + int64_t XMsContentLength; // Specifies the maximum size for the file, up to 4 TB. Azure::Core::Nullable FileContentType; // Sets the MIME content type of the file. The default type is // 'application/octet-stream'. @@ -4852,11 +5842,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting // Timeouts for File Service Operations. - Azure::Core::Nullable - LeaseDuration; // 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. + int32_t LeaseDuration + = int32_t(); // 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. Azure::Core::Nullable ProposedLeaseIdOptional; // Proposed lease ID, in a GUID string format. The File service // returns 400 (Invalid request) if the proposed lease ID is @@ -4886,12 +5876,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQuery( Details::c_QueryTimeout, std::to_string(acquireLeaseOptions.Timeout.GetValue())); } - if (acquireLeaseOptions.LeaseDuration.HasValue()) - { - request.AddHeader( - Details::c_HeaderDuration, - std::to_string(acquireLeaseOptions.LeaseDuration.GetValue())); - } + request.AddHeader( + Details::c_HeaderDuration, std::to_string(acquireLeaseOptions.LeaseDuration)); if (acquireLeaseOptions.ProposedLeaseIdOptional.HasValue()) { request.AddHeader( @@ -5219,6 +6205,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Azure::Core::Nullable ShareSnapshot; // The snapshot parameter is an opaque DateTime value that, when present, // specifies the share snapshot to query. + Azure::Core::Nullable + PrevShareSnapshot; // The previous snapshot parameter is an opaque DateTime value that, + // when present, specifies the previous snapshot. Azure::Core::Nullable Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting @@ -5246,6 +6235,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQuery( Details::c_QueryShareSnapshot, getRangeListOptions.ShareSnapshot.GetValue()); } + if (getRangeListOptions.PrevShareSnapshot.HasValue()) + { + request.GetUrl().AppendQuery( + Details::c_QueryPrevShareSnapshot, getRangeListOptions.PrevShareSnapshot.GetValue()); + } if (getRangeListOptions.Timeout.HasValue()) { request.GetUrl().AppendQuery( @@ -6208,7 +7202,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { = XmlReader(reinterpret_cast(bodyBuffer.data()), bodyBuffer.size()); FileGetRangeListResult result = bodyBuffer.empty() ? FileGetRangeListResult() - : FileGetRangeListResultFromRangeList(RangeListFromXml(reader)); + : FileGetRangeListResultFromShareFileRangeList(ShareFileRangeListFromXml(reader)); result.LastModified = response.GetHeaders().at(Details::c_HeaderLastModified); result.ETag = response.GetHeaders().at(Details::c_HeaderETag); result.FileContentLength @@ -6223,13 +7217,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } } - static Range RangeFromXml(XmlReader& reader) + static FileRange FileRangeFromXml(XmlReader& reader) { - auto result = Range(); + auto result = FileRange(); enum class XmlTagName { - c_Unknown, c_Start, + c_Unknown, c_End, }; std::vector path; @@ -6283,13 +7277,74 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { return result; } - static std::vector RangeListFromXml(XmlReader& reader) + static ClearRange ClearRangeFromXml(XmlReader& reader) { - auto result = std::vector(); + auto result = ClearRange(); enum class XmlTagName { + c_Start, c_Unknown, + c_End, + }; + std::vector path; + + while (true) + { + auto node = reader.Read(); + if (node.Type == XmlNodeType::End) + { + break; + } + else if (node.Type == XmlNodeType::EndTag) + { + if (path.size() > 0) + { + path.pop_back(); + } + else + { + break; + } + } + else if (node.Type == XmlNodeType::StartTag) + { + + if (std::strcmp(node.Name, "Start") == 0) + { + path.emplace_back(XmlTagName::c_Start); + } + else if (std::strcmp(node.Name, "End") == 0) + { + path.emplace_back(XmlTagName::c_End); + } + else + { + path.emplace_back(XmlTagName::c_Unknown); + } + } + else if (node.Type == XmlNodeType::Text) + { + if (path.size() == 1 && path[0] == XmlTagName::c_Start) + { + result.Start = std::stoll(node.Value); + } + else if (path.size() == 1 && path[0] == XmlTagName::c_End) + { + result.End = std::stoll(node.Value); + } + } + } + return result; + } + + static ShareFileRangeList ShareFileRangeListFromXml(XmlReader& reader) + { + auto result = ShareFileRangeList(); + enum class XmlTagName + { c_Ranges, + c_Unknown, + c_ClearRange, c_Range, }; std::vector path; @@ -6319,6 +7374,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { path.emplace_back(XmlTagName::c_Ranges); } + else if (std::strcmp(node.Name, "ClearRange") == 0) + { + path.emplace_back(XmlTagName::c_ClearRange); + } else if (std::strcmp(node.Name, "Range") == 0) { path.emplace_back(XmlTagName::c_Range); @@ -6327,11 +7386,17 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { path.emplace_back(XmlTagName::c_Unknown); } - if (path.size() == 2 && path[0] == XmlTagName::c_Ranges && path[1] == XmlTagName::c_Range) { - result.emplace_back(RangeFromXml(reader)); + result.Ranges.emplace_back(FileRangeFromXml(reader)); + path.pop_back(); + } + else if ( + path.size() == 2 && path[0] == XmlTagName::c_Ranges + && path[1] == XmlTagName::c_ClearRange) + { + result.ClearRanges.emplace_back(ClearRangeFromXml(reader)); path.pop_back(); } } @@ -6342,10 +7407,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { return result; } - static FileGetRangeListResult FileGetRangeListResultFromRangeList(std::vector object) + static FileGetRangeListResult FileGetRangeListResultFromShareFileRangeList( + ShareFileRangeList object) { FileGetRangeListResult result; - result.RangeList = std::move(object); + result.Ranges = std::move(object.Ranges); + result.ClearRanges = std::move(object.ClearRanges); return result; } @@ -6429,15 +7496,15 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = HandleItem(); enum class XmlTagName { - c_Unknown, - c_HandleId, - c_Path, - c_FileId, - c_ParentId, - c_SessionId, - c_ClientIp, c_OpenTime, + c_HandleId, + c_SessionId, + c_ParentId, + c_FileId, + c_Unknown, c_LastReconnectTime, + c_Path, + c_ClientIp, }; std::vector path; @@ -6462,38 +7529,38 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "HandleId") == 0) + if (std::strcmp(node.Name, "OpenTime") == 0) + { + path.emplace_back(XmlTagName::c_OpenTime); + } + else if (std::strcmp(node.Name, "HandleId") == 0) { path.emplace_back(XmlTagName::c_HandleId); } - else if (std::strcmp(node.Name, "Path") == 0) - { - path.emplace_back(XmlTagName::c_Path); - } - else if (std::strcmp(node.Name, "FileId") == 0) - { - path.emplace_back(XmlTagName::c_FileId); - } - else if (std::strcmp(node.Name, "ParentId") == 0) - { - path.emplace_back(XmlTagName::c_ParentId); - } else if (std::strcmp(node.Name, "SessionId") == 0) { path.emplace_back(XmlTagName::c_SessionId); } - else if (std::strcmp(node.Name, "ClientIp") == 0) + else if (std::strcmp(node.Name, "ParentId") == 0) { - path.emplace_back(XmlTagName::c_ClientIp); + path.emplace_back(XmlTagName::c_ParentId); } - else if (std::strcmp(node.Name, "OpenTime") == 0) + else if (std::strcmp(node.Name, "FileId") == 0) { - path.emplace_back(XmlTagName::c_OpenTime); + path.emplace_back(XmlTagName::c_FileId); } else if (std::strcmp(node.Name, "LastReconnectTime") == 0) { path.emplace_back(XmlTagName::c_LastReconnectTime); } + else if (std::strcmp(node.Name, "Path") == 0) + { + path.emplace_back(XmlTagName::c_Path); + } + else if (std::strcmp(node.Name, "ClientIp") == 0) + { + path.emplace_back(XmlTagName::c_ClientIp); + } else { path.emplace_back(XmlTagName::c_Unknown); @@ -6543,11 +7610,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto result = ListHandlesResponse(); enum class XmlTagName { - c_Unknown, - c_EnumerationResults, - c_Entries, - c_Handle, c_NextMarker, + c_EnumerationResults, + c_Handle, + c_Unknown, + c_Entries, }; std::vector path; @@ -6572,21 +7639,21 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "EnumerationResults") == 0) + if (std::strcmp(node.Name, "NextMarker") == 0) + { + path.emplace_back(XmlTagName::c_NextMarker); + } + else if (std::strcmp(node.Name, "EnumerationResults") == 0) { path.emplace_back(XmlTagName::c_EnumerationResults); } - else if (std::strcmp(node.Name, "Entries") == 0) - { - path.emplace_back(XmlTagName::c_Entries); - } else if (std::strcmp(node.Name, "Handle") == 0) { path.emplace_back(XmlTagName::c_Handle); } - else if (std::strcmp(node.Name, "NextMarker") == 0) + else if (std::strcmp(node.Name, "Entries") == 0) { - path.emplace_back(XmlTagName::c_NextMarker); + path.emplace_back(XmlTagName::c_Entries); } else { diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_client.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_client.hpp index 0626d63b2..dd6231d3e 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_client.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_client.hpp @@ -218,6 +218,65 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { const ListFilesAndDirectoriesSegmentOptions& options = ListFilesAndDirectoriesSegmentOptions()) const; + /** + * @brief Acquires a lease on the share. + * + * @param proposedLeaseId Proposed lease ID, in a GUID string format. + * @param duration Specifies the duration of the lease, in seconds, or + * Azure::Storage::c_InfiniteLeaseDuration 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. + * @param options Optional parameters to execute this function. + * @return Azure::Core::Response describing the lease. + */ + Azure::Core::Response AcquireLease( + const std::string& proposedLeaseId, + int32_t duration, + const AcquireShareLeaseOptions& options = AcquireShareLeaseOptions()) const; + + /** + * @brief Releases the share's previously-acquired lease. + * + * @param leaseId ID of the previously-acquired lease. + * @param options Optional parameters to execute this function. + * @return Azure::Core::Response describing the updated lease status. + */ + Azure::Core::Response ReleaseLease( + const std::string& leaseId, + const ReleaseShareLeaseOptions& options = ReleaseShareLeaseOptions()) const; + + /** + * @brief Changes the lease of an active lease. + * + * @param leaseId ID of the previously-acquired lease. + * @param proposedLeaseId Proposed lease ID, in a GUID string format. + * @param options Optional parameters to execute this function. + * @return Azure::Core::Response describing the changed lease. + */ + Azure::Core::Response ChangeLease( + const std::string& leaseId, + const std::string& proposedLeaseId, + const ChangeShareLeaseOptions& options = ChangeShareLeaseOptions()) const; + + /** + * @brief Breaks the previously-acquired lease. + * + * @param options Optional parameters to execute this function. + * @return Azure::Core::Response describing the broken lease. + */ + Azure::Core::Response BreakLease( + const BreakShareLeaseOptions& options = BreakShareLeaseOptions()) const; + + /** + * @brief Renew the previously-acquired lease. + * + * @param leaseId ID of the previously-acquired lease. + * @param options Optional parameters to execute this function. + * @return Azure::Core::Response describing the renewed lease. + */ + Azure::Core::Response RenewLease( + const std::string& leaseId, + const RenewShareLeaseOptions& options = RenewShareLeaseOptions()) const; + private: Azure::Core::Http::Url m_shareUri; std::shared_ptr m_pipeline; diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp index 8ebc2954c..e23373b20 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp @@ -209,6 +209,70 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Azure::Core::Context Context; }; + /** + * @brief Optional parameters for ShareClient::AcquireLease. + */ + struct AcquireShareLeaseOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + }; + + /** + * @brief Optional parameters for ShareClient::ChangeLease. + */ + struct ChangeShareLeaseOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + }; + + /** + * @brief Optional parameters for ShareClient::ReleaseLease. + */ + struct ReleaseShareLeaseOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + }; + + /** + * @brief Optional parameters for ShareClient::BreakLease. + */ + struct BreakShareLeaseOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + + /** + * @brief Proposed duration the lease should continue before it is broken, in seconds, + * between 0 and 60. This break period is only used if it is shorter than the time remaining on + * the lease. If longer, the time remaining on the lease is used. A new lease will not be + * available before the break period has expired, but the lease may be held for longer than the + * break period. + */ + Azure::Core::Nullable BreakPeriod; + }; + + /** + * @brief Optional parameters for ShareClient::BreakLease. + */ + struct RenewShareLeaseOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + }; + struct CreateDirectoryOptions { /** @@ -640,6 +704,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { */ Azure::Core::Nullable Length; + /** + * @brief The previous snapshot parameter is an opaque DateTime value that, when present, + * specifies the previous snapshot. + */ + Azure::Core::Nullable PrevShareSnapshot; + /** * @brief The operation will only succeed if the access condition is met. */ diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_responses.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_responses.hpp index 9abcff40c..afad42dd4 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_responses.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_responses.hpp @@ -27,6 +27,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { using CreateSharePermissionResult = ShareCreatePermissionResult; using GetShareAccessPolicyResult = ShareGetAccessPolicyResult; using GetSharePermissionResult = ShareGetPermissionResult; + using AcquireShareLeaseResult = ShareAcquireLeaseResult; + using RenewShareLeaseResult = ShareRenewLeaseResult; + using ReleaseShareLeaseResult = ShareReleaseLeaseResult; + using BreakShareLeaseResult = ShareBreakLeaseResult; + using ChangeShareLeaseResult = ShareChangeLeaseResult; // DirectoryClient models: using CreateDirectoryResult = DirectoryCreateResult; diff --git a/sdk/storage/azure-storage-files-shares/src/share_client.cpp b/sdk/storage/azure-storage-files-shares/src/share_client.cpp index ed5cb0ea6..d8989b9cb 100644 --- a/sdk/storage/azure-storage-files-shares/src/share_client.cpp +++ b/sdk/storage/azure-storage-files-shares/src/share_client.cpp @@ -274,4 +274,57 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::move(ret), result.ExtractRawResponse()); } + Azure::Core::Response ShareClient::AcquireLease( + const std::string& proposedLeaseId, + int32_t duration, + const AcquireShareLeaseOptions& options) const + { + ShareRestClient::Share::AcquireLeaseOptions protocolLayerOptions; + protocolLayerOptions.ProposedLeaseIdOptional = proposedLeaseId; + protocolLayerOptions.LeaseDuration = duration; + return ShareRestClient::Share::AcquireLease( + m_shareUri, *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::ChangeLease( + const std::string& leaseId, + const std::string& proposedLeaseId, + const ChangeShareLeaseOptions& options) const + { + ShareRestClient::Share::ChangeLeaseOptions protocolLayerOptions; + protocolLayerOptions.LeaseIdRequired = leaseId; + protocolLayerOptions.ProposedLeaseIdOptional = proposedLeaseId; + return ShareRestClient::Share::ChangeLease( + m_shareUri, *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::ReleaseLease( + const std::string& leaseId, + const ReleaseShareLeaseOptions& options) const + { + ShareRestClient::Share::ReleaseLeaseOptions protocolLayerOptions; + protocolLayerOptions.LeaseIdRequired = leaseId; + return ShareRestClient::Share::ReleaseLease( + m_shareUri, *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::BreakLease( + const BreakShareLeaseOptions& options) const + { + ShareRestClient::Share::BreakLeaseOptions protocolLayerOptions; + protocolLayerOptions.LeaseBreakPeriod = options.BreakPeriod; + return ShareRestClient::Share::BreakLease( + m_shareUri, *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::RenewLease( + const std::string& leaseId, + const RenewShareLeaseOptions& options) const + { + ShareRestClient::Share::RenewLeaseOptions protocolLayerOptions; + protocolLayerOptions.LeaseIdRequired = leaseId; + return ShareRestClient::Share::RenewLease( + m_shareUri, *m_pipeline, options.Context, protocolLayerOptions); + } + }}}} // namespace Azure::Storage::Files::Shares diff --git a/sdk/storage/azure-storage-files-shares/src/share_file_client.cpp b/sdk/storage/azure-storage-files-shares/src/share_file_client.cpp index 69567a6e6..81bbd3503 100644 --- a/sdk/storage/azure-storage-files-shares/src/share_file_client.cpp +++ b/sdk/storage/azure-storage-files-shares/src/share_file_client.cpp @@ -476,6 +476,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } } + protocolLayerOptions.PrevShareSnapshot = options.PrevShareSnapshot; protocolLayerOptions.LeaseIdOptional = options.AccessConditions.LeaseId; return ShareRestClient::File::GetRangeList( m_shareFileUri, *m_pipeline, options.Context, protocolLayerOptions); diff --git a/sdk/storage/azure-storage-files-shares/test/share_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/share_client_test.cpp index b1e1db27d..c74ea1433 100644 --- a/sdk/storage/azure-storage-files-shares/test/share_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/share_client_test.cpp @@ -31,7 +31,12 @@ namespace Azure { namespace Storage { namespace Test { m_shareClient->Create(); } - void FileShareClientTest::TearDownTestSuite() { m_shareClient->Delete(); } + void FileShareClientTest::TearDownTestSuite() + { + auto deleteOptions = Files::Shares::DeleteShareOptions(); + deleteOptions.IncludeSnapshots = true; + m_shareClient->Delete(deleteOptions); + } Files::Shares::FileShareHttpHeaders FileShareClientTest::GetInterestingHttpHeaders() { @@ -182,4 +187,115 @@ namespace Azure { namespace Storage { namespace Test { auto ret2 = m_shareClient->GetPermission(ret->FilePermissionKey); EXPECT_EQ(expectedPermission, ret2->Permission); } + + TEST_F(FileShareClientTest, Lease) + { + std::string leaseId1 = CreateUniqueLeaseId(); + int32_t leaseDuration = 20; + auto aLease = *m_shareClient->AcquireLease(leaseId1, leaseDuration); + EXPECT_FALSE(aLease.ETag.empty()); + EXPECT_FALSE(aLease.LastModified.empty()); + EXPECT_EQ(aLease.LeaseId, leaseId1); + aLease = *m_shareClient->AcquireLease(leaseId1, leaseDuration); + EXPECT_FALSE(aLease.ETag.empty()); + EXPECT_FALSE(aLease.LastModified.empty()); + EXPECT_EQ(aLease.LeaseId, leaseId1); + + auto properties = *m_shareClient->GetProperties(); + EXPECT_EQ(properties.LeaseState.GetValue(), Files::Shares::LeaseStateType::Leased); + EXPECT_EQ(properties.LeaseStatus.GetValue(), Files::Shares::LeaseStatusType::Locked); + EXPECT_EQ(Files::Shares::LeaseDurationType::Fixed, properties.LeaseDuration.GetValue()); + + auto rLease = *m_shareClient->RenewLease(leaseId1); + EXPECT_FALSE(rLease.ETag.empty()); + EXPECT_FALSE(rLease.LastModified.empty()); + EXPECT_EQ(rLease.LeaseId, leaseId1); + + std::string leaseId2 = CreateUniqueLeaseId(); + EXPECT_NE(leaseId1, leaseId2); + auto cLease = *m_shareClient->ChangeLease(leaseId1, leaseId2); + EXPECT_FALSE(cLease.ETag.empty()); + EXPECT_FALSE(cLease.LastModified.empty()); + EXPECT_EQ(cLease.LeaseId, leaseId2); + + auto blobInfo = *m_shareClient->ReleaseLease(leaseId2); + EXPECT_FALSE(blobInfo.ETag.empty()); + EXPECT_FALSE(blobInfo.LastModified.empty()); + + aLease = *m_shareClient->AcquireLease(CreateUniqueLeaseId(), c_InfiniteLeaseDuration); + properties = *m_shareClient->GetProperties(); + EXPECT_EQ(Files::Shares::LeaseDurationType::Infinite, properties.LeaseDuration.GetValue()); + auto brokenLease = *m_shareClient->BreakLease(); + EXPECT_FALSE(brokenLease.ETag.empty()); + EXPECT_FALSE(brokenLease.LastModified.empty()); + EXPECT_EQ(brokenLease.LeaseTime, 0); + + aLease = *m_shareClient->AcquireLease(CreateUniqueLeaseId(), leaseDuration); + brokenLease = *m_shareClient->BreakLease(); + EXPECT_FALSE(brokenLease.ETag.empty()); + EXPECT_FALSE(brokenLease.LastModified.empty()); + EXPECT_NE(brokenLease.LeaseTime, 0); + + Files::Shares::BreakShareLeaseOptions options; + options.BreakPeriod = 0; + m_shareClient->BreakLease(options); + } + + TEST_F(FileShareClientTest, SnapshotLease) + { + std::string leaseId1 = CreateUniqueLeaseId(); + int32_t leaseDuration = 20; + auto snapshotResult = m_shareClient->CreateSnapshot(); + auto shareSnapshot = m_shareClient->WithSnapshot(snapshotResult->Snapshot); + auto aLease = *shareSnapshot.AcquireLease(leaseId1, leaseDuration); + EXPECT_FALSE(aLease.ETag.empty()); + EXPECT_FALSE(aLease.LastModified.empty()); + EXPECT_EQ(aLease.LeaseId, leaseId1); + aLease = *shareSnapshot.AcquireLease(leaseId1, leaseDuration); + EXPECT_FALSE(aLease.ETag.empty()); + EXPECT_FALSE(aLease.LastModified.empty()); + EXPECT_EQ(aLease.LeaseId, leaseId1); + + auto properties = *shareSnapshot.GetProperties(); + EXPECT_EQ(properties.LeaseState.GetValue(), Files::Shares::LeaseStateType::Leased); + EXPECT_EQ(properties.LeaseStatus.GetValue(), Files::Shares::LeaseStatusType::Locked); + EXPECT_EQ(Files::Shares::LeaseDurationType::Fixed, properties.LeaseDuration.GetValue()); + + auto rLease = *shareSnapshot.RenewLease(leaseId1); + EXPECT_FALSE(rLease.ETag.empty()); + EXPECT_FALSE(rLease.LastModified.empty()); + EXPECT_EQ(rLease.LeaseId, leaseId1); + + std::string leaseId2 = CreateUniqueLeaseId(); + EXPECT_NE(leaseId1, leaseId2); + auto cLease = *shareSnapshot.ChangeLease(leaseId1, leaseId2); + EXPECT_FALSE(cLease.ETag.empty()); + EXPECT_FALSE(cLease.LastModified.empty()); + EXPECT_EQ(cLease.LeaseId, leaseId2); + + auto blobInfo = *shareSnapshot.ReleaseLease(leaseId2); + EXPECT_FALSE(blobInfo.ETag.empty()); + EXPECT_FALSE(blobInfo.LastModified.empty()); + + aLease = *shareSnapshot.AcquireLease(CreateUniqueLeaseId(), c_InfiniteLeaseDuration); + properties = *shareSnapshot.GetProperties(); + EXPECT_EQ(Files::Shares::LeaseDurationType::Infinite, properties.LeaseDuration.GetValue()); + auto brokenLease = *shareSnapshot.BreakLease(); + EXPECT_FALSE(brokenLease.ETag.empty()); + EXPECT_FALSE(brokenLease.LastModified.empty()); + EXPECT_EQ(brokenLease.LeaseTime, 0); + + aLease = *shareSnapshot.AcquireLease(CreateUniqueLeaseId(), leaseDuration); + brokenLease = *shareSnapshot.BreakLease(); + EXPECT_FALSE(brokenLease.ETag.empty()); + EXPECT_FALSE(brokenLease.LastModified.empty()); + EXPECT_NE(brokenLease.LeaseTime, 0); + + Files::Shares::BreakShareLeaseOptions options; + options.BreakPeriod = 0; + shareSnapshot.BreakLease(options); + + EXPECT_THROW(m_shareClient->Delete(), StorageError); + } + }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/azure-storage-files-shares/test/share_file_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/share_file_client_test.cpp index db26816e5..9e8ed1f8e 100644 --- a/sdk/storage/azure-storage-files-shares/test/share_file_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/share_file_client_test.cpp @@ -615,11 +615,51 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_NO_THROW(fileClient.ClearRange(512, 512)); Files::Shares::GetFileRangeListResult result; EXPECT_NO_THROW(result = fileClient.GetRangeList().ExtractValue()); - EXPECT_EQ(2U, result.RangeList.size()); - result.RangeList[0].Start = 0; - result.RangeList[0].End = 511; - result.RangeList[1].Start = 1024; - result.RangeList[1].End = fileSize / 2; + EXPECT_EQ(2U, result.Ranges.size()); + EXPECT_EQ(0, result.Ranges[0].Start); + EXPECT_EQ(511, result.Ranges[0].End); + EXPECT_EQ(1024, result.Ranges[1].Start); + EXPECT_EQ(static_cast(fileSize / 2) - 1, result.Ranges[1].End); + } + + TEST_F(FileShareFileClientTest, DISABLED_PreviousRangeWithSnapshot) + { + size_t fileSize = 1 * 1024 * 1024; + auto fileContent = RandomBuffer(fileSize); + auto memBodyStream = Core::Http::MemoryBodyStream(fileContent); + auto halfContent + = std::vector(fileContent.begin(), fileContent.begin() + fileSize / 2); + halfContent.resize(fileSize); + auto fileClient = m_shareClient->GetFileClient(LowercaseRandomString(10)); + fileClient.Create(fileSize); + EXPECT_NO_THROW(fileClient.UploadRange(0, &memBodyStream)); + EXPECT_NO_THROW(fileClient.ClearRange(fileSize / 2, fileSize / 2)); + std::vector downloadContent(static_cast(fileSize), '\x00'); + EXPECT_NO_THROW( + fileClient.DownloadTo(downloadContent.data(), static_cast(fileSize))); + EXPECT_EQ(halfContent, downloadContent); + + auto snapshot1 = m_shareClient->CreateSnapshot()->Snapshot; + EXPECT_NO_THROW(fileClient.ClearRange(500, 2048)); + auto snapshot2 = m_shareClient->CreateSnapshot()->Snapshot; + Files::Shares::GetFileRangeListResult result; + Files::Shares::GetFileRangeListOptions options; + options.PrevShareSnapshot = snapshot1; + EXPECT_NO_THROW(result = fileClient.GetRangeList(options).ExtractValue()); + EXPECT_EQ(2U, result.Ranges.size()); + EXPECT_EQ(0, result.Ranges[0].Start); + EXPECT_EQ(511, result.Ranges[0].End); + EXPECT_EQ(1024, result.Ranges[1].Start); + EXPECT_EQ(static_cast(fileSize / 2) - 1, result.Ranges[1].End); + EXPECT_NO_THROW(fileClient.ClearRange(3096, 2048)); + auto snapshot3 = m_shareClient->CreateSnapshot()->Snapshot; + options.PrevShareSnapshot = snapshot1; + EXPECT_NO_THROW(result = fileClient.GetRangeList(options).ExtractValue()); + EXPECT_EQ(2U, result.Ranges.size()); + EXPECT_EQ(0, result.Ranges[0].Start); + EXPECT_EQ(511, result.Ranges[0].End); + EXPECT_EQ(1024, result.Ranges[1].Start); + EXPECT_EQ(static_cast(fileSize / 2) - 1, result.Ranges[1].End); } }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/azure-storage-files-shares/test/share_service_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/share_service_client_test.cpp index d96f56b42..fae88d895 100644 --- a/sdk/storage/azure-storage-files-shares/test/share_service_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/share_service_client_test.cpp @@ -186,8 +186,14 @@ namespace Azure { namespace Storage { namespace Test { downloadedProperties.HourMetrics.RetentionPolicy.Enabled, properties.HourMetrics.RetentionPolicy.Enabled); EXPECT_EQ( - downloadedProperties.HourMetrics.RetentionPolicy.Days, - properties.HourMetrics.RetentionPolicy.Days); + downloadedProperties.HourMetrics.RetentionPolicy.Days.HasValue(), + properties.HourMetrics.RetentionPolicy.Days.HasValue()); + if (properties.HourMetrics.RetentionPolicy.Days.HasValue()) + { + EXPECT_EQ( + downloadedProperties.HourMetrics.RetentionPolicy.Days.GetValue(), + properties.HourMetrics.RetentionPolicy.Days.GetValue()); + } EXPECT_EQ(downloadedProperties.MinuteMetrics.Version, properties.MinuteMetrics.Version); EXPECT_EQ(downloadedProperties.MinuteMetrics.Enabled, properties.MinuteMetrics.Enabled); @@ -196,8 +202,14 @@ namespace Azure { namespace Storage { namespace Test { downloadedProperties.MinuteMetrics.RetentionPolicy.Enabled, properties.MinuteMetrics.RetentionPolicy.Enabled); EXPECT_EQ( - downloadedProperties.MinuteMetrics.RetentionPolicy.Days, - properties.MinuteMetrics.RetentionPolicy.Days); + downloadedProperties.MinuteMetrics.RetentionPolicy.Days.HasValue(), + properties.MinuteMetrics.RetentionPolicy.Days.HasValue()); + if (properties.MinuteMetrics.RetentionPolicy.Days.HasValue()) + { + EXPECT_EQ( + downloadedProperties.MinuteMetrics.RetentionPolicy.Days.GetValue(), + properties.MinuteMetrics.RetentionPolicy.Days.GetValue()); + } EXPECT_EQ(downloadedProperties.Cors.size(), properties.Cors.size()); for (const auto& cors : downloadedProperties.Cors) @@ -218,4 +230,99 @@ namespace Azure { namespace Storage { namespace Test { m_fileShareServiceClient->SetProperties(originalProperties); } + TEST_F(FileShareServiceClientTest, DISABLED_SetPremiumFileProperties) + { + auto premiumFileShareServiceClient = std::make_shared( + Files::Shares::ServiceClient::CreateFromConnectionString(PremiumFileConnectionString())); + auto properties = *premiumFileShareServiceClient->GetProperties(); + auto originalProperties = properties; + + properties.HourMetrics.Enabled = true; + properties.HourMetrics.RetentionPolicy.Enabled = true; + properties.HourMetrics.RetentionPolicy.Days = 4; + properties.HourMetrics.IncludeAPIs = true; + + properties.MinuteMetrics.Enabled = true; + properties.MinuteMetrics.RetentionPolicy.Enabled = true; + properties.MinuteMetrics.RetentionPolicy.Days = 3; + properties.MinuteMetrics.IncludeAPIs = true; + + Files::Shares::CorsRule corsRule; + corsRule.AllowedOrigins = "http://www.example1.com"; + corsRule.AllowedMethods = "GET,PUT"; + corsRule.AllowedHeaders = "x-ms-header1,x-ms-header2"; + corsRule.ExposedHeaders = "x-ms-header3"; + corsRule.MaxAgeInSeconds = 10; + properties.Cors.emplace_back(corsRule); + + corsRule.AllowedOrigins = "http://www.example2.com"; + corsRule.AllowedMethods = "DELETE"; + corsRule.AllowedHeaders = "x-ms-header1"; + corsRule.ExposedHeaders = "x-ms-header2,x-ms-header3"; + corsRule.MaxAgeInSeconds = 20; + properties.Cors.emplace_back(corsRule); + + auto protocolSettings = Files::Shares::ShareProtocolSettings(); + protocolSettings.Settings.Multichannel.Enabled = true; + properties.Protocol = protocolSettings; + + EXPECT_NO_THROW(premiumFileShareServiceClient->SetProperties(properties)); + // It takes some time before the new properties comes into effect. + using namespace std::chrono_literals; + std::this_thread::sleep_for(10s); + auto downloadedProperties = *premiumFileShareServiceClient->GetProperties(); + + EXPECT_EQ(downloadedProperties.HourMetrics.Version, properties.HourMetrics.Version); + EXPECT_EQ(downloadedProperties.HourMetrics.Enabled, properties.HourMetrics.Enabled); + EXPECT_EQ(downloadedProperties.HourMetrics.IncludeAPIs, properties.HourMetrics.IncludeAPIs); + EXPECT_EQ( + downloadedProperties.HourMetrics.RetentionPolicy.Enabled, + properties.HourMetrics.RetentionPolicy.Enabled); + EXPECT_EQ( + downloadedProperties.HourMetrics.RetentionPolicy.Days.HasValue(), + properties.HourMetrics.RetentionPolicy.Days.HasValue()); + if (properties.HourMetrics.RetentionPolicy.Days.HasValue()) + { + EXPECT_EQ( + downloadedProperties.HourMetrics.RetentionPolicy.Days.GetValue(), + properties.HourMetrics.RetentionPolicy.Days.GetValue()); + } + + EXPECT_EQ(downloadedProperties.MinuteMetrics.Version, properties.MinuteMetrics.Version); + EXPECT_EQ(downloadedProperties.MinuteMetrics.Enabled, properties.MinuteMetrics.Enabled); + EXPECT_EQ(downloadedProperties.MinuteMetrics.IncludeAPIs, properties.MinuteMetrics.IncludeAPIs); + EXPECT_EQ( + downloadedProperties.MinuteMetrics.RetentionPolicy.Enabled, + properties.MinuteMetrics.RetentionPolicy.Enabled); + EXPECT_EQ( + downloadedProperties.MinuteMetrics.RetentionPolicy.Days.HasValue(), + properties.MinuteMetrics.RetentionPolicy.Days.HasValue()); + if (properties.MinuteMetrics.RetentionPolicy.Days.HasValue()) + { + EXPECT_EQ( + downloadedProperties.MinuteMetrics.RetentionPolicy.Days.GetValue(), + properties.MinuteMetrics.RetentionPolicy.Days.GetValue()); + } + + EXPECT_EQ(downloadedProperties.Cors.size(), properties.Cors.size()); + for (const auto& cors : downloadedProperties.Cors) + { + auto iter = std::find_if( + properties.Cors.begin(), + properties.Cors.end(), + [&cors](const Files::Shares::CorsRule& rule) { + return rule.AllowedOrigins == cors.AllowedOrigins; + }); + EXPECT_EQ(iter->AllowedMethods, cors.AllowedMethods); + EXPECT_EQ(iter->AllowedHeaders, cors.AllowedHeaders); + EXPECT_EQ(iter->ExposedHeaders, cors.ExposedHeaders); + EXPECT_EQ(iter->MaxAgeInSeconds, cors.MaxAgeInSeconds); + EXPECT_NE(properties.Cors.end(), iter); + } + + EXPECT_EQ(true, properties.Protocol.GetValue().Settings.Multichannel.Enabled); + + premiumFileShareServiceClient->SetProperties(originalProperties); + } + }}} // namespace Azure::Storage::Test