diff --git a/sdk/core/azure-core-test/src/test_proxy_manager.cpp b/sdk/core/azure-core-test/src/test_proxy_manager.cpp index a9e3283ef..a58e16a0a 100644 --- a/sdk/core/azure-core-test/src/test_proxy_manager.cpp +++ b/sdk/core/azure-core-test/src/test_proxy_manager.cpp @@ -225,6 +225,7 @@ void TestProxyManager::SetProxySanitizer() "x-ms-file-change-time", "x-ms-file-creation-time", "x-ms-file-last-write-time", + "x-ms-link-text", "x-ms-rename-source", "x-ms-immutability-policy-until-date", }; diff --git a/sdk/storage/assets.json b/sdk/storage/assets.json index 1979cddfd..cef6a7452 100644 --- a/sdk/storage/assets.json +++ b/sdk/storage/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "cpp", "TagPrefix": "cpp/storage", - "Tag": "cpp/storage_f9f7bb54df" + "Tag": "cpp/storage_57a579efb6" } diff --git a/sdk/storage/azure-storage-common/src/account_sas_builder.cpp b/sdk/storage/azure-storage-common/src/account_sas_builder.cpp index d774accd3..e7425c8ac 100644 --- a/sdk/storage/azure-storage-common/src/account_sas_builder.cpp +++ b/sdk/storage/azure-storage-common/src/account_sas_builder.cpp @@ -9,7 +9,7 @@ namespace Azure { namespace Storage { namespace Sas { namespace { - constexpr static const char* SasVersion = "2025-01-05"; + constexpr static const char* SasVersion = "2025-05-05"; } void AccountSasBuilder::SetPermissions(AccountSasPermissions permissions) diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp index d22fa7886..d6460416c 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp @@ -32,7 +32,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { /** * The version used for the operations to Azure storage services. */ - constexpr static const char* ApiVersion = "2025-01-05"; + constexpr static const char* ApiVersion = "2025-05-05"; } // namespace _detail namespace Models { /** @@ -1088,62 +1088,115 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string ParentFileId; }; /** - * @brief Response type for #Azure::Storage::Files::Shares::ShareDirectoryClient::Create. + * @brief NFS only. Type of the file or directory. */ - struct CreateDirectoryResult final - { - /** - * Indicates if the directory was successfully created by this operation. - */ - bool Created = true; - /** - * The SMB related properties for the file. - */ - FileSmbProperties SmbProperties; - /** - * The ETag contains a value which represents the version of the directory, in quotes. - */ - Azure::ETag ETag; - /** - * Returns the date and time the share was last modified. Any operation that modifies the - * directory or its properties updates the last modified time. Operations on files do not - * affect the last modified time of the directory. - */ - DateTime LastModified; - /** - * The value of this header is set to true if the contents of the request are successfully - * encrypted using the specified algorithm, and false otherwise. - */ - bool IsServerEncrypted = bool(); + class NfsFileType final : public Core::_internal::ExtendableEnumeration { + public: + /** Constructs a new NfsFileType instance */ + NfsFileType() = default; + /** Constructs a new NfsFileType from a string. */ + explicit NfsFileType(std::string value) : ExtendableEnumeration(std::move(value)) {} + + /** Constant value of type NfsFileType: Regular */ + AZ_STORAGE_FILES_SHARES_DLLEXPORT const static NfsFileType Regular; + /** Constant value of type NfsFileType: Directory */ + AZ_STORAGE_FILES_SHARES_DLLEXPORT const static NfsFileType Directory; + /** Constant value of type NfsFileType: Symlink */ + AZ_STORAGE_FILES_SHARES_DLLEXPORT const static NfsFileType SymLink; }; - /** - * @brief Response type for #Azure::Storage::Files::Shares::ShareDirectoryClient::GetProperties. - */ - struct DirectoryProperties final - { + namespace _detail { /** - * The SMB related properties for the file. + * @brief Response type for #Azure::Storage::Files::Shares::ShareDirectoryClient::Create. */ - FileSmbProperties SmbProperties; + struct CreateDirectoryResult final + { + /** + * Indicates if the directory was successfully created by this operation. + */ + bool Created = true; + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * The ETag contains a value which represents the version of the directory, in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the share was last modified. Any operation that modifies the + * directory or its properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + bool IsServerEncrypted = bool(); + /** + * NFS only. The mode of the file or directory. + */ + Nullable FileMode; + /** + * NFS only. The owner of the file or directory. + */ + Nullable Owner; + /** + * NFS only. The owning group of the file or directory. + */ + Nullable Group; + /** + * NFS only. Type of the file or directory. + */ + Nullable NfsFileType; + }; /** - * A set of name-value pairs that contain metadata for the directory. + * @brief Response type for + * #Azure::Storage::Files::Shares::ShareDirectoryClient::GetProperties. */ - Core::CaseInsensitiveMap Metadata; - /** - * The ETag contains a value that you can use to perform operations conditionally, in quotes. - */ - Azure::ETag ETag; - /** - * Returns the date and time the Directory was last modified. Operations on files within the - * directory do not affect the last modified time of the directory. - */ - DateTime LastModified; - /** - * The value of this header is set to true if the directory metadata is completely encrypted - * using the specified algorithm. Otherwise, the value is set to false. - */ - bool IsServerEncrypted = bool(); - }; + struct DirectoryProperties final + { + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * A set of name-value pairs that contain metadata for the directory. + */ + Core::CaseInsensitiveMap Metadata; + /** + * The ETag contains a value that you can use to perform operations conditionally, in + * quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the Directory was last modified. Operations on files within the + * directory do not affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * The value of this header is set to true if the directory metadata is completely encrypted + * using the specified algorithm. Otherwise, the value is set to false. + */ + bool IsServerEncrypted = bool(); + /** + * NFS only. The mode of the file or directory. + */ + Nullable FileMode; + /** + * NFS only. The owner of the file or directory. + */ + Nullable Owner; + /** + * NFS only. The owning group of the file or directory. + */ + Nullable Group; + /** + * NFS only. Type of the file or directory. + */ + Nullable NfsFileType; + }; + } // namespace _detail /** * @brief Response type for #Azure::Storage::Files::Shares::ShareDirectoryClient::Delete. */ @@ -1154,31 +1207,46 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { */ bool Deleted = true; }; - /** - * @brief Response type for #Azure::Storage::Files::Shares::ShareDirectoryClient::SetProperties. - */ - struct SetDirectoryPropertiesResult final - { + namespace _detail { /** - * The SMB related properties for the file. + * @brief Response type for + * #Azure::Storage::Files::Shares::ShareDirectoryClient::SetProperties. */ - FileSmbProperties SmbProperties; - /** - * The ETag contains a value which represents the version of the file, in quotes. - */ - Azure::ETag ETag; - /** - * Returns the date and time the directory was last modified. Any operation that modifies the - * directory or its properties updates the last modified time. Operations on files do not - * affect the last modified time of the directory. - */ - DateTime LastModified; - /** - * The value of this header is set to true if the contents of the request are successfully - * encrypted using the specified algorithm, and false otherwise. - */ - bool IsServerEncrypted = bool(); - }; + struct SetDirectoryPropertiesResult final + { + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * The ETag contains a value which represents the version of the file, in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the directory was last modified. Any operation that modifies + * the directory or its properties updates the last modified time. Operations on files do + * not affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + bool IsServerEncrypted = bool(); + /** + * NFS only. The mode of the file or directory. + */ + Nullable FileMode; + /** + * NFS only. The owner of the file or directory. + */ + Nullable Owner; + /** + * NFS only. The owning group of the file or directory. + */ + Nullable Group; + }; + } // namespace _detail /** * @brief Response type for #Azure::Storage::Files::Shares::ShareDirectoryClient::SetMetadata. */ @@ -1476,36 +1544,52 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { */ std::string FileParentId; }; + /** + * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::Create. + */ + struct CreateFileResult final + { + /** + * Indicates if the file was successfully created by this operation. + */ + bool Created = true; + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * The ETag contains a value which represents the version of the file, in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the share was last modified. Any operation that modifies the + * directory or its properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + bool IsServerEncrypted = bool(); + /** + * NFS only. The mode of the file or directory. + */ + Nullable FileMode; + /** + * NFS only. The owner of the file or directory. + */ + Nullable Owner; + /** + * NFS only. The owning group of the file or directory. + */ + Nullable Group; + /** + * NFS only. Type of the file or directory. + */ + Nullable NfsFileType; + }; } // namespace _detail - /** - * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::Create. - */ - struct CreateFileResult final - { - /** - * Indicates if the file was successfully created by this operation. - */ - bool Created = true; - /** - * The SMB related properties for the file. - */ - FileSmbProperties SmbProperties; - /** - * The ETag contains a value which represents the version of the file, in quotes. - */ - Azure::ETag ETag; - /** - * Returns the date and time the share was last modified. Any operation that modifies the - * directory or its properties updates the last modified time. Operations on files do not - * affect the last modified time of the directory. - */ - DateTime LastModified; - /** - * The value of this header is set to true if the contents of the request are successfully - * encrypted using the specified algorithm, and false otherwise. - */ - bool IsServerEncrypted = bool(); - }; /** * @brief Standard HTTP properties supported files. */ @@ -1556,202 +1640,229 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { /** Constant value of type CopyStatus: Failed */ AZ_STORAGE_FILES_SHARES_DLLEXPORT const static CopyStatus Failed; }; - /** - * @brief Detailed information of the downloaded file. - */ - struct DownloadFileDetails final - { + namespace _detail { /** - * The ETag contains a value that you can use to perform operations conditionally. If the - * request version is 2011-08-18 or newer, the ETag value will be in quotes. + * @brief Detailed information of the downloaded file. */ - Azure::ETag ETag; + struct DownloadFileDetails final + { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the + * request version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the file was last modified. Any operation that modifies the + * file, including an update of the file's metadata or properties, changes the last-modified + * time of the file. + */ + DateTime LastModified; + /** + * A set of name-value pairs associated with the share or file. + */ + Core::CaseInsensitiveMap Metadata; + /** + * String identifier for this copy operation. Use with Get File Properties to check the + * status of this copy operation, or pass to Abort Copy File to abort a pending copy. + */ + Nullable CopyId; + /** + * URL up to 2 KB in length that specifies the source file or file used in the last + * attempted Copy File operation where this file was the destination file. This header does + * not appear if this file has never been the destination in a Copy File operation, or if + * this file has been modified after a concluded Copy File operation using Set File + * Properties, Put File, or Put Block List. + */ + Nullable CopySource; + /** + * Status of a copy operation. + */ + Nullable CopyStatus; + /** + * Only appears when x-ms-copy-status is failed or pending. Describes the cause of the last + * fatal or non-fatal copy operation failure. This header does not appear if this file has + * never been the destination in a Copy File operation, or if this file has been modified + * after a concluded Copy File operation using Set File Properties, Put File, or Put Block + * List. + */ + Nullable CopyStatusDescription; + /** + * Contains the number of bytes copied and the total bytes in the source in the last + * attempted Copy File operation where this file was the destination file. Can show between + * 0 and Content-Length bytes copied. This header does not appear if this file has never + * been the destination in a Copy File operation, or if this file has been modified after a + * concluded Copy File operation using Set File Properties, Put File, or Put Block List. + */ + Nullable CopyProgress; + /** + * Conclusion time of the last attempted Copy File operation where this file was the + * destination file. This value can specify the time of a completed, aborted, or failed copy + * attempt. This header does not appear if a copy is pending, if this file has never been + * the destination in a Copy File operation, or if this file has been modified after a + * concluded Copy File operation using Set File Properties, Put File, or Put Block List. + */ + Nullable CopyCompletedOn; + /** + * True if the file data and metadata are completely encrypted using the specified + * algorithm. Otherwise, the value is set to false (when the file is unencrypted, or if only + * parts of the file/application metadata are encrypted). + */ + bool IsServerEncrypted = bool(); + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * When a share is leased, specifies whether the lease is of infinite or fixed duration. + */ + Nullable LeaseDuration; + /** + * Lease state of the share. + */ + Nullable LeaseState; + /** + * The current lease status of the share. + */ + Nullable LeaseStatus; + Nullable FileMode; + Nullable Owner; + Nullable Group; + Nullable LinkCount; + }; /** - * Returns the date and time the file was last modified. Any operation that modifies the file, - * including an update of the file's metadata or properties, changes the last-modified time of - * the file. + * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::Download. */ - DateTime LastModified; + struct DownloadFileResult final + { + /** + * Content of the file or file range. + */ + std::unique_ptr BodyStream; + /** + * Indicates the range of bytes returned. + */ + Core::Http::HttpRange ContentRange; + /** + * Size of the file in bytes. + */ + std::int64_t FileSize = std::int64_t(); + /** + * MD5 hash for the downloaded range of data. + */ + Nullable TransactionalContentHash; + /** + * Standard HTTP properties supported files. + */ + FileHttpHeaders HttpHeaders; + /** + * Detailed information of the downloaded file. + */ + DownloadFileDetails Details; + }; /** - * A set of name-value pairs associated with the share or file. + * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::GetProperties. */ - Core::CaseInsensitiveMap Metadata; - /** - * String identifier for this copy operation. Use with Get File Properties to check the status - * of this copy operation, or pass to Abort Copy File to abort a pending copy. - */ - Nullable CopyId; - /** - * URL up to 2 KB in length that specifies the source file or file used in the last attempted - * Copy File operation where this file was the destination file. This header does not appear - * if this file has never been the destination in a Copy File operation, or if this file has - * been modified after a concluded Copy File operation using Set File Properties, Put File, or - * Put Block List. - */ - Nullable CopySource; - /** - * Status of a copy operation. - */ - Nullable CopyStatus; - /** - * Only appears when x-ms-copy-status is failed or pending. Describes the cause of the last - * fatal or non-fatal copy operation failure. This header does not appear if this file has - * never been the destination in a Copy File operation, or if this file has been modified - * after a concluded Copy File operation using Set File Properties, Put File, or Put Block - * List. - */ - Nullable CopyStatusDescription; - /** - * Contains the number of bytes copied and the total bytes in the source in the last attempted - * Copy File operation where this file was the destination file. Can show between 0 and - * Content-Length bytes copied. This header does not appear if this file has never been the - * destination in a Copy File operation, or if this file has been modified after a concluded - * Copy File operation using Set File Properties, Put File, or Put Block List. - */ - Nullable CopyProgress; - /** - * Conclusion time of the last attempted Copy File operation where this file was the - * destination file. This value can specify the time of a completed, aborted, or failed copy - * attempt. This header does not appear if a copy is pending, if this file has never been the - * destination in a Copy File operation, or if this file has been modified after a concluded - * Copy File operation using Set File Properties, Put File, or Put Block List. - */ - Nullable CopyCompletedOn; - /** - * True if the file data and metadata are completely encrypted using the specified algorithm. - * Otherwise, the value is set to false (when the file is unencrypted, or if only parts of the - * file/application metadata are encrypted). - */ - bool IsServerEncrypted = bool(); - /** - * The SMB related properties for the file. - */ - FileSmbProperties SmbProperties; - /** - * When a share is leased, specifies whether the lease is of infinite or fixed duration. - */ - Nullable LeaseDuration; - /** - * Lease state of the share. - */ - Nullable LeaseState; - /** - * The current lease status of the share. - */ - Nullable LeaseStatus; - }; - /** - * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::Download. - */ - struct DownloadFileResult final - { - /** - * Content of the file or file range. - */ - std::unique_ptr BodyStream; - /** - * Indicates the range of bytes returned. - */ - Core::Http::HttpRange ContentRange; - /** - * Size of the file in bytes. - */ - std::int64_t FileSize = std::int64_t(); - /** - * MD5 hash for the downloaded range of data. - */ - Nullable TransactionalContentHash; - /** - * Standard HTTP properties supported files. - */ - FileHttpHeaders HttpHeaders; - /** - * Detailed information of the downloaded file. - */ - DownloadFileDetails Details; - }; - /** - * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::GetProperties. - */ - struct FileProperties final - { - /** - * The SMB related properties for the file. - */ - FileSmbProperties SmbProperties; - /** - * Standard HTTP properties supported files. - */ - FileHttpHeaders HttpHeaders; - /** - * Returns the date and time the file was last modified. The date format follows RFC 1123. Any - * operation that modifies the file or its properties updates the last modified time. - */ - DateTime LastModified; - /** - * A set of name-value pairs associated with this file as user-defined metadata. - */ - Core::CaseInsensitiveMap Metadata; - /** - * The size of the file in bytes. This header returns the value of the 'x-ms-content-length' - * header that is stored with the file. - */ - std::int64_t FileSize = std::int64_t(); - /** - * The ETag contains a value that you can use to perform operations conditionally, in quotes. - */ - Azure::ETag ETag; - /** - * Conclusion time of the last attempted Copy File operation where this file was the - * destination file. This value can specify the time of a completed, aborted, or failed copy - * attempt. - */ - Nullable CopyCompletedOn; - /** - * Only appears when x-ms-copy-status is failed or pending. Describes cause of fatal or - * non-fatal copy operation failure. - */ - Nullable CopyStatusDescription; - /** - * String identifier for the last attempted Copy File operation where this file was the - * destination file. - */ - Nullable CopyId; - /** - * Contains the number of bytes copied and the total bytes in the source in the last attempted - * Copy File operation where this file was the destination file. Can show between 0 and - * Content-Length bytes copied. - */ - Nullable CopyProgress; - /** - * URL up to 2KB in length that specifies the source file used in the last attempted Copy File - * operation where this file was the destination file. - */ - Nullable CopySource; - /** - * State of the copy operation identified by 'x-ms-copy-id'. - */ - Nullable CopyStatus; - /** - * The value of this header is set to true if the file data and application metadata are - * completely encrypted using the specified algorithm. Otherwise, the value is set to false - * (when the file is unencrypted, or if only parts of the file/application metadata are - * encrypted). - */ - bool IsServerEncrypted = bool(); - /** - * When a file is leased, specifies whether the lease is of infinite or fixed duration. - */ - Nullable LeaseDuration; - /** - * Lease state of the file. - */ - Nullable LeaseState; - /** - * The current lease status of the file. - */ - Nullable LeaseStatus; - }; + struct FileProperties final + { + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * Standard HTTP properties supported files. + */ + FileHttpHeaders HttpHeaders; + /** + * Returns the date and time the file was last modified. The date format follows RFC 1123. + * Any operation that modifies the file or its properties updates the last modified time. + */ + DateTime LastModified; + /** + * A set of name-value pairs associated with this file as user-defined metadata. + */ + Core::CaseInsensitiveMap Metadata; + /** + * The size of the file in bytes. This header returns the value of the 'x-ms-content-length' + * header that is stored with the file. + */ + std::int64_t FileSize = std::int64_t(); + /** + * The ETag contains a value that you can use to perform operations conditionally, in + * quotes. + */ + Azure::ETag ETag; + /** + * Conclusion time of the last attempted Copy File operation where this file was the + * destination file. This value can specify the time of a completed, aborted, or failed copy + * attempt. + */ + Nullable CopyCompletedOn; + /** + * Only appears when x-ms-copy-status is failed or pending. Describes cause of fatal or + * non-fatal copy operation failure. + */ + Nullable CopyStatusDescription; + /** + * String identifier for the last attempted Copy File operation where this file was the + * destination file. + */ + Nullable CopyId; + /** + * Contains the number of bytes copied and the total bytes in the source in the last + * attempted Copy File operation where this file was the destination file. Can show between + * 0 and Content-Length bytes copied. + */ + Nullable CopyProgress; + /** + * URL up to 2KB in length that specifies the source file used in the last attempted Copy + * File operation where this file was the destination file. + */ + Nullable CopySource; + /** + * State of the copy operation identified by 'x-ms-copy-id'. + */ + Nullable CopyStatus; + /** + * The value of this header is set to true if the file data and application metadata are + * completely encrypted using the specified algorithm. Otherwise, the value is set to false + * (when the file is unencrypted, or if only parts of the file/application metadata are + * encrypted). + */ + bool IsServerEncrypted = bool(); + /** + * When a file is leased, specifies whether the lease is of infinite or fixed duration. + */ + Nullable LeaseDuration; + /** + * Lease state of the file. + */ + Nullable LeaseState; + /** + * The current lease status of the file. + */ + Nullable LeaseStatus; + /** + * NFS only. The mode of the file or directory. + */ + Nullable FileMode; + /** + * NFS only. The owner of the file or directory. + */ + Nullable Owner; + /** + * NFS only. The owning group of the file or directory. + */ + Nullable Group; + /** + * NFS only. The link count of the file or directory. + */ + Nullable LinkCount; + /** + * NFS only. Type of the file or directory. + */ + Nullable NfsFileType; + }; + } // namespace _detail /** * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::Delete. */ @@ -1761,32 +1872,54 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { * Indicates if the file was successfully deleted by this operation. */ bool Deleted = true; + /** + * NFS only. The link count of the file or directory. + */ + Nullable LinkCount; }; - /** - * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::SetProperties. - */ - struct SetFilePropertiesResult final - { + namespace _detail { /** - * The SMB related properties for the file. + * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::SetProperties. */ - FileSmbProperties SmbProperties; - /** - * The ETag contains a value which represents the version of the file, in quotes. - */ - Azure::ETag ETag; - /** - * Returns the date and time the directory was last modified. Any operation that modifies the - * directory or its properties updates the last modified time. Operations on files do not - * affect the last modified time of the directory. - */ - DateTime LastModified; - /** - * The value of this header is set to true if the contents of the request are successfully - * encrypted using the specified algorithm, and false otherwise. - */ - bool IsServerEncrypted = bool(); - }; + struct SetFilePropertiesResult final + { + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * The ETag contains a value which represents the version of the file, in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the directory was last modified. Any operation that modifies + * the directory or its properties updates the last modified time. Operations on files do + * not affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + bool IsServerEncrypted = bool(); + /** + * NFS only. The mode of the file or directory. + */ + Nullable FileMode; + /** + * NFS only. The owner of the file or directory. + */ + Nullable Owner; + /** + * NFS only. The owning group of the file or directory. + */ + Nullable Group; + /** + * NFS only. The link count of the file or directory. + */ + Nullable LinkCount; + }; + } // namespace _detail /** * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::SetMetadata. */ @@ -1996,6 +2129,43 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { /** Constant value of type PermissionCopyMode: Override */ AZ_STORAGE_FILES_SHARES_DLLEXPORT const static PermissionCopyMode Override; }; + /** + * @brief NFS only. Applicable only when the copy source is a File. Determines the copy behavior + * of the mode bits of the file. source: The mode on the destination file is copied from the + * source file. override: The mode on the destination file is determined via the x-ms-mode + * header. + */ + class ModeCopyMode final : public Core::_internal::ExtendableEnumeration { + public: + /** Constructs a new ModeCopyMode instance */ + ModeCopyMode() = default; + /** Constructs a new ModeCopyMode from a string. */ + explicit ModeCopyMode(std::string value) : ExtendableEnumeration(std::move(value)) {} + + /** Constant value of type ModeCopyMode: Source */ + AZ_STORAGE_FILES_SHARES_DLLEXPORT const static ModeCopyMode Source; + /** Constant value of type ModeCopyMode: Override */ + AZ_STORAGE_FILES_SHARES_DLLEXPORT const static ModeCopyMode Override; + }; + /** + * @brief NFS only. Determines the copy behavior of the owner user identifier (UID) and group + * identifier (GID) of the file. source: The owner user identifier (UID) and group identifier + * (GID) on the destination file is copied from the source file. override: The owner user + * identifier (UID) and group identifier (GID) on the destination file is determined via the + * x-ms-owner and x-ms-group headers. + */ + class OwnerCopyMode final : public Core::_internal::ExtendableEnumeration { + public: + /** Constructs a new OwnerCopyMode instance */ + OwnerCopyMode() = default; + /** Constructs a new OwnerCopyMode from a string. */ + explicit OwnerCopyMode(std::string value) : ExtendableEnumeration(std::move(value)) {} + + /** Constant value of type OwnerCopyMode: Source */ + AZ_STORAGE_FILES_SHARES_DLLEXPORT const static OwnerCopyMode Source; + /** Constant value of type OwnerCopyMode: Override */ + AZ_STORAGE_FILES_SHARES_DLLEXPORT const static OwnerCopyMode Override; + }; namespace _detail { /** * @brief Response type for #Azure::Storage::Files::Shares::FileClient::StartCopy. @@ -2109,6 +2279,106 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { */ std::string FileParentId; }; + /** + * @brief Response type for #Azure::Storage::Files::Shares::FileClient::CreateSymbolicLink. + */ + struct CreateFileSymbolicLinkResult final + { + bool Created = true; + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * The ETag contains a value which represents the version of the file, in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the share was last modified. Any operation that modifies the + * directory or its properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * NFS only. The mode of the file or directory. + */ + std::string FileMode; + /** + * NFS only. The owner of the file or directory. + */ + std::string Owner; + /** + * NFS only. The owning group of the file or directory. + */ + std::string Group; + /** + * NFS only. Type of the file or directory. + */ + Models::NfsFileType NfsFileType; + }; + /** + * @brief Response type for #Azure::Storage::Files::Shares::FileClient::GetSymbolicLink. + */ + struct GetFileSymbolicLinkResult final + { + /** + * The ETag contains a value which represents the version of the file, in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the share was last modified. Any operation that modifies the + * directory or its properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * The path to the original file, the symbolic link is pointing to. The path is of type + * string which is not resolved and is stored as is. The path can be absolute path or the + * relative path depending on the content stored in the symbolic link file. + */ + std::string LinkText; + }; + /** + * @brief Response type for #Azure::Storage::Files::Shares::FileClient::CreateHardLink. + */ + struct CreateFileHardLinkResult final + { + bool Created = true; + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * The ETag contains a value which represents the version of the file, in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the share was last modified. Any operation that modifies the + * directory or its properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * NFS only. The link count of the file or directory. + */ + std::int64_t LinkCount = std::int64_t(); + /** + * NFS only. The mode of the file or directory. + */ + std::string FileMode; + /** + * NFS only. The owner of the file or directory. + */ + std::string Owner; + /** + * NFS only. The owning group of the file or directory. + */ + std::string Group; + /** + * NFS only. Type of the file or directory. + */ + Models::NfsFileType NfsFileType; + }; } // namespace _detail } // namespace Models namespace _detail { @@ -2357,8 +2627,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Nullable FileLastWriteTime; Nullable FileChangeTime; Nullable FileRequestIntent; + Nullable Owner; + Nullable Group; + Nullable FileMode; }; - static Response Create( + static Response Create( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const CreateDirectoryOptions& options, @@ -2369,7 +2642,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Nullable Sharesnapshot; Nullable FileRequestIntent; }; - static Response GetProperties( + static Response GetProperties( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const GetDirectoryPropertiesOptions& options, @@ -2395,8 +2668,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Nullable FileChangeTime; Nullable AllowTrailingDot; Nullable FileRequestIntent; + Nullable Owner; + Nullable Group; + Nullable FileMode; }; - static Response SetProperties( + static Response SetProperties( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const SetDirectoryPropertiesOptions& options, @@ -2504,8 +2780,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Nullable FileChangeTime; Nullable LeaseId; Nullable FileRequestIntent; + Nullable Owner; + Nullable Group; + Nullable FileMode; + Nullable NfsFileType; }; - static Response Create( + static Response Create( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const CreateFileOptions& options, @@ -2518,7 +2798,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Nullable LeaseId; Nullable FileRequestIntent; }; - static Response Download( + static Response Download( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const DownloadFileOptions& options, @@ -2530,7 +2810,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Nullable LeaseId; Nullable FileRequestIntent; }; - static Response GetProperties( + static Response GetProperties( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const GetFilePropertiesOptions& options, @@ -2565,8 +2845,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Nullable LeaseId; Nullable AllowTrailingDot; Nullable FileRequestIntent; + Nullable Owner; + Nullable Group; + Nullable FileMode; }; - static Response SetHttpHeaders( + static Response SetHttpHeaders( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const SetFileHttpHeadersOptions& options, @@ -2698,6 +2981,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Nullable AllowTrailingDot; Nullable AllowSourceTrailingDot; Nullable FileRequestIntent; + Nullable Owner; + Nullable Group; + Nullable FileMode; + Nullable FileModeCopyMode; + Nullable FileOwnerCopyMode; }; static Response StartCopy( Core::Http::_internal::HttpPipeline& pipeline, @@ -2767,6 +3055,43 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { const Core::Url& url, const RenameFileOptions& options, const Core::Context& context); + struct CreateFileSymbolicLinkOptions final + { + std::map Metadata; + Nullable FileCreationTime; + Nullable FileLastWriteTime; + Nullable LeaseId; + Nullable Owner; + Nullable Group; + std::string LinkText; + Nullable FileRequestIntent; + }; + static Response CreateSymbolicLink( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + const CreateFileSymbolicLinkOptions& options, + const Core::Context& context); + struct GetFileSymbolicLinkOptions final + { + Nullable Sharesnapshot; + Nullable FileRequestIntent; + }; + static Response GetSymbolicLink( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + const GetFileSymbolicLinkOptions& options, + const Core::Context& context); + struct CreateFileHardLinkOptions final + { + Nullable LeaseId; + std::string TargetFile; + Nullable FileRequestIntent; + }; + static Response CreateHardLink( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + const CreateFileHardLinkOptions& options, + const Core::Context& context); }; } // namespace _detail }}}} // namespace Azure::Storage::Files::Shares \ No newline at end of file diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_file_client.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_file_client.hpp index 3d84ecb47..893fc7385 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_file_client.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_file_client.hpp @@ -379,6 +379,19 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { const UploadFileRangeFromUriOptions& options = UploadFileRangeFromUriOptions(), const Azure::Core::Context& context = Azure::Core::Context()) const; + /** + * @brief NFS only. Creates a hard link to the file specified by path. + * @param targetFile Path of the file to create the hard link to, not including the share. + * @param options Optional parameters to create this file's symbolic link. + * @param context Context for cancelling long running operations. + * @return Azure::Response containing the returned + * information. + */ + Azure::Response CreateHardLink( + const std::string& targetFile, + const CreateHardLinkOptions& options = CreateHardLinkOptions(), + const Azure::Core::Context& context = Azure::Core::Context()) const; + private: Azure::Core::Url m_shareFileUrl; 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 d3fe917f0..40b134de4 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 @@ -18,6 +18,208 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { + namespace Models { + enum class RolePermissions + { + /* + * @brief No permissions. + */ + None = 0, + + /* + * @brief The execute permission. + */ + Execute = 1, + + /* + * @brief The write permission. + */ + Write = 2, + + /* + * @brief The read permission. + */ + Read = 4, + }; + + inline RolePermissions operator|(const RolePermissions& lhs, const RolePermissions& rhs) + { + using type = std::underlying_type_t; + return static_cast(static_cast(lhs) | static_cast(rhs)); + } + + inline RolePermissions operator&(const RolePermissions& lhs, const RolePermissions& rhs) + { + using type = std::underlying_type_t; + return static_cast(static_cast(lhs) & static_cast(rhs)); + } + + /** + * @brief The mode permissions of the file or directory. + */ + struct NfsFileMode final + { + /** + * @brief Permissions the owner has over the file or directory. + */ + RolePermissions Owner; + + /** + * @brief Permissions the group has over the file or directory. + */ + RolePermissions Group; + + /** + * @brief Permissions other have over the file or directory. + */ + RolePermissions Other; + + /** + * @brief Set effective user ID (setuid) on the file or directory. + */ + bool EffectiveUserIdentity = false; + + /** + * @brief Set effective group ID (setgid) on the file or directory. + */ + bool EffectiveGroupIdentity = false; + + /** + * @brief The sticky bit may be set on directories. The files in that directory may only be + * renamed or deleted by the file's owner, the directory's owner, or the root user. + */ + bool StickyBit = false; + + /** + * @brief Returns the octal representation of NfsFileMode as a string. + */ + std::string ToOctalFileMode() const; + + /** + * @brief Returns NfsFileMode as a string in symbolic notation. + */ + std::string ToSymbolicFileMode() const; + + /** + * @brief Returns a NfsFileMode from the octal string representation. + * + * @param modeString A 4-digit octal string representation of a File Mode. + */ + static NfsFileMode ParseOctalFileMode(const std::string& modeString); + + /** + * @brief Returns a NfsFileMode from the symbolic string representation. + * + * @param modeString A 9-character symbolic string representation of a File Mode. + */ + static NfsFileMode ParseSymbolicFileMode(const std::string& modeString); + }; + + /** + * @brief NFS properties. Note that these properties only apply to files or directories in + * premium NFS file accounts. + */ + struct FilePosixProperties final + { + /** + * NFS only. The mode of the file or directory. + */ + Nullable FileMode; + + /** + * NFS only. The owner of the file or directory. + */ + Nullable Owner; + + /** + * NFS only. The owning group of the file or directory. + */ + Nullable Group; + + /** + * NFS only. Type of the file or directory. + */ + Nullable NfsFileType; + + /** + * NFS only. The link count of the file or directory. + */ + Nullable LinkCount; + }; + } // namespace Models + + /** + * Smb Properties to copy from the source file. + */ + enum class CopyableFileSmbPropertyFlags + { + /** + * None. + */ + None = 0, + + /** + * File Attributes. + */ + FileAttributes = 1, + + /** + * Created On. + */ + CreatedOn = 2, + + /** + * Last Written On. + */ + LastWrittenOn = 4, + + /** + * Changed On. + */ + ChangedOn = 8, + + /** + * Permission + */ + Permission = 16, + + /** + * All. + */ + All = ~None + }; + + inline CopyableFileSmbPropertyFlags operator|( + CopyableFileSmbPropertyFlags lhs, + CopyableFileSmbPropertyFlags rhs) + { + using type = std::underlying_type_t; + return static_cast( + static_cast(lhs) | static_cast(rhs)); + } + inline CopyableFileSmbPropertyFlags& operator|=( + CopyableFileSmbPropertyFlags& lhs, + CopyableFileSmbPropertyFlags rhs) + { + lhs = lhs | rhs; + return lhs; + } + inline CopyableFileSmbPropertyFlags operator&( + CopyableFileSmbPropertyFlags lhs, + CopyableFileSmbPropertyFlags rhs) + { + using type = std::underlying_type_t; + return static_cast( + static_cast(lhs) & static_cast(rhs)); + } + inline CopyableFileSmbPropertyFlags& operator&=( + CopyableFileSmbPropertyFlags& lhs, + CopyableFileSmbPropertyFlags rhs) + { + lhs = lhs & rhs; + return lhs; + } + /** * @brief Audiences available for share service * @@ -389,6 +591,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { * SMB properties to set for the directory. */ Models::FileSmbProperties SmbProperties; + + /** + * The NFS related properties for the file. + */ + Models::FilePosixProperties PosixProperties; }; /** @@ -550,6 +757,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { * returned in SDDL format. */ Nullable FilePermissionFormat; + + /** + * The NFS related properties for the file. + */ + Models::FilePosixProperties PosixProperties; }; /** @@ -695,6 +907,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { * The operation will only succeed if the access condition is met. */ LeaseAccessConditions AccessConditions; + + /** + * The NFS related properties for the file. + */ + Models::FilePosixProperties PosixProperties; }; /** @@ -766,6 +983,17 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { */ Azure::Nullable PermissionCopyMode; + /** + * Smb Properties to copy from the source file. + * If this flag is nullable, it will use the value of source file(except ChangedOn, it will be + * default value) if the property is not set. + * If this flag is disabled, it will use the default + * value of destination file if the property is not set. + * If this flag is enabled, it will use the value of source file no + * matter the property is set or not. + */ + Azure::Nullable SmbPropertiesToCopy; + /** * Specifies the option to overwrite the target file if it already exists and has * read-only attribute set. @@ -782,6 +1010,23 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { * The operation will only succeed if the access condition is met. */ LeaseAccessConditions AccessConditions; + + /** + * The NFS related properties for the file. + */ + Models::FilePosixProperties PosixProperties; + + /** + * Optional, only applicable to NFS Files. If not populated, the destination file will have the + * default File Mode. + */ + Azure::Nullable ModeCopyMode; + + /** + * Optional, only applicable to NFS Files. If not populated, the destination file will have the + * default Owner and Group. + */ + Azure::Nullable OwnerCopyMode; }; /** @@ -835,6 +1080,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { * The operation will only succeed if the access condition is met. */ LeaseAccessConditions AccessConditions; + + /** + * The NFS related properties for the file. + */ + Models::FilePosixProperties PosixProperties; }; /** @@ -1066,6 +1316,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { */ Nullable FilePermissionFormat; + /** + * The NFS related properties for the file. + */ + Models::FilePosixProperties PosixProperties; + /** * @brief Options for parallel transfer. */ @@ -1131,4 +1386,16 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { struct RenewLeaseOptions final { }; + + /** + * @brief Optional parameters for + * #Azure::Storage::Files::Shares::ShareFileClient::CreateHardLink. + */ + struct CreateHardLinkOptions final + { + /** + * Specify the access condition for the path. + */ + LeaseAccessConditions AccessConditions; + }; }}}} // namespace Azure::Storage::Files::Shares 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 ae875ca94..79bcfde4d 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 @@ -48,6 +48,127 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { bool IsServerEncrypted = bool(); }; + /** + * @brief Detailed information of the downloaded file. + */ + struct DownloadFileDetails final + { + /** + * The ETag contains a value that you can use to perform operations conditionally. If the + * request version is 2011-08-18 or newer, the ETag value will be in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the file was last modified. Any operation that modifies the + * file, including an update of the file's metadata or properties, changes the last-modified + * time of the file. + */ + DateTime LastModified; + /** + * A set of name-value pairs associated with the share or file. + */ + Core::CaseInsensitiveMap Metadata; + /** + * String identifier for this copy operation. Use with Get File Properties to check the + * status of this copy operation, or pass to Abort Copy File to abort a pending copy. + */ + Nullable CopyId; + /** + * URL up to 2 KB in length that specifies the source file or file used in the last + * attempted Copy File operation where this file was the destination file. This header does + * not appear if this file has never been the destination in a Copy File operation, or if + * this file has been modified after a concluded Copy File operation using Set File + * Properties, Put File, or Put Block List. + */ + Nullable CopySource; + /** + * Status of a copy operation. + */ + Nullable CopyStatus; + /** + * Only appears when x-ms-copy-status is failed or pending. Describes the cause of the last + * fatal or non-fatal copy operation failure. This header does not appear if this file has + * never been the destination in a Copy File operation, or if this file has been modified + * after a concluded Copy File operation using Set File Properties, Put File, or Put Block + * List. + */ + Nullable CopyStatusDescription; + /** + * Contains the number of bytes copied and the total bytes in the source in the last + * attempted Copy File operation where this file was the destination file. Can show between + * 0 and Content-Length bytes copied. This header does not appear if this file has never + * been the destination in a Copy File operation, or if this file has been modified after a + * concluded Copy File operation using Set File Properties, Put File, or Put Block List. + */ + Nullable CopyProgress; + /** + * Conclusion time of the last attempted Copy File operation where this file was the + * destination file. This value can specify the time of a completed, aborted, or failed copy + * attempt. This header does not appear if a copy is pending, if this file has never been + * the destination in a Copy File operation, or if this file has been modified after a + * concluded Copy File operation using Set File Properties, Put File, or Put Block List. + */ + Nullable CopyCompletedOn; + /** + * True if the file data and metadata are completely encrypted using the specified + * algorithm. Otherwise, the value is set to false (when the file is unencrypted, or if only + * parts of the file/application metadata are encrypted). + */ + bool IsServerEncrypted = bool(); + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * When a share is leased, specifies whether the lease is of infinite or fixed duration. + */ + Nullable LeaseDuration; + /** + * Lease state of the share. + */ + Nullable LeaseState; + /** + * The current lease status of the share. + */ + Nullable LeaseStatus; + + /** + * The NFS related properties for the file. + */ + FilePosixProperties PosixProperties; + }; + + /** + * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::Download. + */ + struct DownloadFileResult final + { + /** + * Content of the file or file range. + */ + std::unique_ptr BodyStream; + /** + * Indicates the range of bytes returned. + */ + Core::Http::HttpRange ContentRange; + /** + * Size of the file in bytes. + */ + std::int64_t FileSize = std::int64_t(); + /** + * MD5 hash for the downloaded range of data. + */ + Nullable TransactionalContentHash; + /** + * Standard HTTP properties supported files. + */ + FileHttpHeaders HttpHeaders; + /** + * Detailed information of the downloaded file. + */ + DownloadFileDetails Details; + }; + /** * @brief The information returned when downloading a file to a destination. */ @@ -317,6 +438,285 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { */ Azure::Nullable AccessRights; }; + + /** + * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::GetProperties. + */ + struct FileProperties final + { + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * Standard HTTP properties supported files. + */ + FileHttpHeaders HttpHeaders; + /** + * Returns the date and time the file was last modified. The date format follows RFC 1123. + * Any operation that modifies the file or its properties updates the last modified time. + */ + DateTime LastModified; + /** + * A set of name-value pairs associated with this file as user-defined metadata. + */ + Core::CaseInsensitiveMap Metadata; + /** + * The size of the file in bytes. This header returns the value of the 'x-ms-content-length' + * header that is stored with the file. + */ + std::int64_t FileSize = std::int64_t(); + /** + * The ETag contains a value that you can use to perform operations conditionally, in + * quotes. + */ + Azure::ETag ETag; + /** + * Conclusion time of the last attempted Copy File operation where this file was the + * destination file. This value can specify the time of a completed, aborted, or failed copy + * attempt. + */ + Nullable CopyCompletedOn; + /** + * Only appears when x-ms-copy-status is failed or pending. Describes cause of fatal or + * non-fatal copy operation failure. + */ + Nullable CopyStatusDescription; + /** + * String identifier for the last attempted Copy File operation where this file was the + * destination file. + */ + Nullable CopyId; + /** + * Contains the number of bytes copied and the total bytes in the source in the last + * attempted Copy File operation where this file was the destination file. Can show between + * 0 and Content-Length bytes copied. + */ + Nullable CopyProgress; + /** + * URL up to 2KB in length that specifies the source file used in the last attempted Copy + * File operation where this file was the destination file. + */ + Nullable CopySource; + /** + * State of the copy operation identified by 'x-ms-copy-id'. + */ + Nullable CopyStatus; + /** + * The value of this header is set to true if the file data and application metadata are + * completely encrypted using the specified algorithm. Otherwise, the value is set to false + * (when the file is unencrypted, or if only parts of the file/application metadata are + * encrypted). + */ + bool IsServerEncrypted = bool(); + /** + * When a file is leased, specifies whether the lease is of infinite or fixed duration. + */ + Nullable LeaseDuration; + /** + * Lease state of the file. + */ + Nullable LeaseState; + /** + * The current lease status of the file. + */ + Nullable LeaseStatus; + /** + * The NFS related properties for the file. + */ + FilePosixProperties PosixProperties; + }; + + /** + * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::Create. + */ + struct CreateFileResult final + { + /** + * Indicates if the file was successfully created by this operation. + */ + bool Created = true; + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * The ETag contains a value which represents the version of the file, in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the share was last modified. Any operation that modifies the + * directory or its properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + bool IsServerEncrypted = bool(); + /** + * The NFS related properties for the file. + */ + FilePosixProperties PosixProperties; + }; + + /** + * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::SetProperties. + */ + struct SetFilePropertiesResult final + { + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * The ETag contains a value which represents the version of the file, in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the directory was last modified. Any operation that modifies + * the directory or its properties updates the last modified time. Operations on files do + * not affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + bool IsServerEncrypted = bool(); + /** + * The NFS related properties for the file. + */ + FilePosixProperties PosixProperties; + }; + + /** + * @brief Response type for #Azure::Storage::Files::Shares::ShareFileClient::CreateHardLink. + */ + struct CreateFileHardLinkResult final + { + /** + * The ETag contains a value which represents the version of the file, in quotes. + */ + Azure::ETag ETag; + + /** + * Returns the date and time the share was last modified. Any operation that modifies the + * directory or its properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + */ + DateTime LastModified; + + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + + /** + * The NFS related properties for the file. + */ + FilePosixProperties PosixProperties; + }; + + /** + * @brief Response type for #Azure::Storage::Files::Shares::ShareDirectoryClient::Create. + */ + struct CreateDirectoryResult final + { + /** + * Indicates if the directory was successfully created by this operation. + */ + bool Created = true; + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * The ETag contains a value which represents the version of the directory, in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the share was last modified. Any operation that modifies the + * directory or its properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + bool IsServerEncrypted = bool(); + /** + * The NFS related properties for the file. + */ + FilePosixProperties PosixProperties; + }; + /** + * @brief Response type for + * #Azure::Storage::Files::Shares::ShareDirectoryClient::GetProperties. + */ + struct DirectoryProperties final + { + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * A set of name-value pairs that contain metadata for the directory. + */ + Core::CaseInsensitiveMap Metadata; + /** + * The ETag contains a value that you can use to perform operations conditionally, in + * quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the Directory was last modified. Operations on files within the + * directory do not affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * The value of this header is set to true if the directory metadata is completely encrypted + * using the specified algorithm. Otherwise, the value is set to false. + */ + bool IsServerEncrypted = bool(); + /** + * The NFS related properties for the file. + */ + FilePosixProperties PosixProperties; + }; + + /** + * @brief Response type for + * #Azure::Storage::Files::Shares::ShareDirectoryClient::SetProperties. + */ + struct SetDirectoryPropertiesResult final + { + /** + * The SMB related properties for the file. + */ + FileSmbProperties SmbProperties; + /** + * The ETag contains a value which represents the version of the file, in quotes. + */ + Azure::ETag ETag; + /** + * Returns the date and time the directory was last modified. Any operation that modifies + * the directory or its properties updates the last modified time. Operations on files do + * not affect the last modified time of the directory. + */ + DateTime LastModified; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + bool IsServerEncrypted = bool(); + /** + * The NFS related properties for the file. + */ + FilePosixProperties PosixProperties; + }; } // namespace Models /** diff --git a/sdk/storage/azure-storage-files-shares/src/rest_client.cpp b/sdk/storage/azure-storage-files-shares/src/rest_client.cpp index adeea96d0..ad5494e48 100644 --- a/sdk/storage/azure-storage-files-shares/src/rest_client.cpp +++ b/sdk/storage/azure-storage-files-shares/src/rest_client.cpp @@ -185,6 +185,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { const FileAttributes FileAttributes::Offline("Offline"); const FileAttributes FileAttributes::NotContentIndexed("NotContentIndexed"); const FileAttributes FileAttributes::NoScrubData("NoScrubData"); + const NfsFileType NfsFileType::Regular("Regular"); + const NfsFileType NfsFileType::Directory("Directory"); + const NfsFileType NfsFileType::SymLink("SymLink"); namespace _detail { const AccessRight AccessRight::Read("Read"); const AccessRight AccessRight::Write("Write"); @@ -198,6 +201,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { const FileLastWrittenMode FileLastWrittenMode::Preserve("preserve"); const PermissionCopyMode PermissionCopyMode::Source("source"); const PermissionCopyMode PermissionCopyMode::Override("override"); + const ModeCopyMode ModeCopyMode::Source("source"); + const ModeCopyMode ModeCopyMode::Override("override"); + const OwnerCopyMode OwnerCopyMode::Source("source"); + const OwnerCopyMode OwnerCopyMode::Override("override"); } // namespace Models namespace _detail { Response ServiceClient::SetProperties( @@ -319,7 +326,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader("Content-Length", std::to_string(requestBody.Length())); request.GetUrl().AppendQueryParameter("restype", "service"); request.GetUrl().AppendQueryParameter("comp", "properties"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -344,7 +351,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Get, url); request.GetUrl().AppendQueryParameter("restype", "service"); request.GetUrl().AppendQueryParameter("comp", "properties"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -580,7 +587,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { _internal::UrlEncodeQueryParameter( ListSharesIncludeFlagsToString(options.Include.Value()))); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -1024,7 +1031,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-access-tier", options.AccessTier.Value().ToString()); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.EnabledProtocols.HasValue() && !options.EnabledProtocols.Value().ToString().empty()) { @@ -1123,7 +1130,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "sharesnapshot", _internal::UrlEncodeQueryParameter(options.Sharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -1280,7 +1287,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "sharesnapshot", _internal::UrlEncodeQueryParameter(options.Sharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.DeleteSnapshots.HasValue() && !options.DeleteSnapshots.Value().ToString().empty()) { request.SetHeader("x-ms-delete-snapshots", options.DeleteSnapshots.Value().ToString()); @@ -1331,7 +1338,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-proposed-lease-id", options.ProposedLeaseId.Value()); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.Sharesnapshot.HasValue() && !options.Sharesnapshot.Value().empty()) { request.GetUrl().AppendQueryParameter( @@ -1370,7 +1377,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-lease-id", options.LeaseId); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.Sharesnapshot.HasValue() && !options.Sharesnapshot.Value().empty()) { request.GetUrl().AppendQueryParameter( @@ -1412,7 +1419,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-proposed-lease-id", options.ProposedLeaseId.Value()); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.Sharesnapshot.HasValue() && !options.Sharesnapshot.Value().empty()) { request.GetUrl().AppendQueryParameter( @@ -1451,7 +1458,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-lease-id", options.LeaseId); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.Sharesnapshot.HasValue() && !options.Sharesnapshot.Value().empty()) { request.GetUrl().AppendQueryParameter( @@ -1494,7 +1501,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.Sharesnapshot.HasValue() && !options.Sharesnapshot.Value().empty()) { request.GetUrl().AppendQueryParameter( @@ -1532,7 +1539,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-meta-" + p.first, p.second); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -1575,7 +1582,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader("Content-Length", std::to_string(requestBody.Length())); request.GetUrl().AppendQueryParameter("restype", "share"); request.GetUrl().AppendQueryParameter("comp", "filepermission"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -1611,7 +1618,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader( "x-ms-file-permission-format", options.FilePermissionFormat.Value().ToString()); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -1646,7 +1653,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); request.GetUrl().AppendQueryParameter("restype", "share"); request.GetUrl().AppendQueryParameter("comp", "properties"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.Quota.HasValue()) { request.SetHeader("x-ms-share-quota", std::to_string(options.Quota.Value())); @@ -1777,7 +1784,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-meta-" + p.first, p.second); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -1808,7 +1815,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Get, url); request.GetUrl().AppendQueryParameter("restype", "share"); request.GetUrl().AppendQueryParameter("comp", "acl"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -1960,7 +1967,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader("Content-Length", std::to_string(requestBody.Length())); request.GetUrl().AppendQueryParameter("restype", "share"); request.GetUrl().AppendQueryParameter("comp", "acl"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -1992,7 +1999,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Get, url); request.GetUrl().AppendQueryParameter("restype", "share"); request.GetUrl().AppendQueryParameter("comp", "stats"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -2066,7 +2073,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } return Response(std::move(response), std::move(pRawResponse)); } - Response DirectoryClient::Create( + Response DirectoryClient::Create( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const CreateDirectoryOptions& options, @@ -2083,7 +2090,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-meta-" + p.first, p.second); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.FilePermission.HasValue() && !options.FilePermission.Value().empty()) { request.SetHeader("x-ms-file-permission", options.FilePermission.Value()); @@ -2119,13 +2126,25 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-file-request-intent", options.FileRequestIntent.Value().ToString()); } + if (options.Owner.HasValue() && !options.Owner.Value().empty()) + { + request.SetHeader("x-ms-owner", options.Owner.Value()); + } + if (options.Group.HasValue() && !options.Group.Value().empty()) + { + request.SetHeader("x-ms-group", options.Group.Value()); + } + if (options.FileMode.HasValue() && !options.FileMode.Value().empty()) + { + request.SetHeader("x-ms-mode", options.FileMode.Value()); + } auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Created) { throw StorageException::CreateFromResponse(std::move(pRawResponse)); } - Models::CreateDirectoryResult response; + Models::_detail::CreateDirectoryResult response; response.ETag = ETag(pRawResponse->GetHeaders().at("ETag")); response.LastModified = DateTime::Parse( pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); @@ -2136,8 +2155,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { response.SmbProperties.PermissionKey = pRawResponse->GetHeaders().at("x-ms-file-permission-key"); } - response.SmbProperties.Attributes - = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + if (pRawResponse->GetHeaders().count("x-ms-file-attributes") != 0) + { + response.SmbProperties.Attributes + = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + } if (pRawResponse->GetHeaders().count("x-ms-file-creation-time") != 0) { response.SmbProperties.CreatedOn = DateTime::Parse( @@ -2158,9 +2180,27 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } response.SmbProperties.FileId = pRawResponse->GetHeaders().at("x-ms-file-id"); response.SmbProperties.ParentFileId = pRawResponse->GetHeaders().at("x-ms-file-parent-id"); - return Response(std::move(response), std::move(pRawResponse)); + if (pRawResponse->GetHeaders().count("x-ms-mode") != 0) + { + response.FileMode = pRawResponse->GetHeaders().at("x-ms-mode"); + } + if (pRawResponse->GetHeaders().count("x-ms-owner") != 0) + { + response.Owner = pRawResponse->GetHeaders().at("x-ms-owner"); + } + if (pRawResponse->GetHeaders().count("x-ms-group") != 0) + { + response.Group = pRawResponse->GetHeaders().at("x-ms-group"); + } + if (pRawResponse->GetHeaders().count("x-ms-file-file-type") != 0) + { + response.NfsFileType + = Models::NfsFileType(pRawResponse->GetHeaders().at("x-ms-file-file-type")); + } + return Response( + std::move(response), std::move(pRawResponse)); } - Response DirectoryClient::GetProperties( + Response DirectoryClient::GetProperties( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const GetDirectoryPropertiesOptions& options, @@ -2178,7 +2218,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "sharesnapshot", _internal::UrlEncodeQueryParameter(options.Sharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -2190,7 +2230,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { throw StorageException::CreateFromResponse(std::move(pRawResponse)); } - Models::DirectoryProperties response; + Models::_detail::DirectoryProperties response; for (auto i = pRawResponse->GetHeaders().lower_bound("x-ms-meta-"); i != pRawResponse->GetHeaders().end() && i->first.substr(0, 10) == "x-ms-meta-"; ++i) @@ -2202,8 +2242,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); response.IsServerEncrypted = pRawResponse->GetHeaders().at("x-ms-server-encrypted") == std::string("true"); - response.SmbProperties.Attributes - = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + if (pRawResponse->GetHeaders().count("x-ms-file-attributes") != 0) + { + response.SmbProperties.Attributes + = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + } if (pRawResponse->GetHeaders().count("x-ms-file-creation-time") != 0) { response.SmbProperties.CreatedOn = DateTime::Parse( @@ -2229,7 +2272,25 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } response.SmbProperties.FileId = pRawResponse->GetHeaders().at("x-ms-file-id"); response.SmbProperties.ParentFileId = pRawResponse->GetHeaders().at("x-ms-file-parent-id"); - return Response(std::move(response), std::move(pRawResponse)); + if (pRawResponse->GetHeaders().count("x-ms-mode") != 0) + { + response.FileMode = pRawResponse->GetHeaders().at("x-ms-mode"); + } + if (pRawResponse->GetHeaders().count("x-ms-owner") != 0) + { + response.Owner = pRawResponse->GetHeaders().at("x-ms-owner"); + } + if (pRawResponse->GetHeaders().count("x-ms-group") != 0) + { + response.Group = pRawResponse->GetHeaders().at("x-ms-group"); + } + if (pRawResponse->GetHeaders().count("x-ms-file-file-type") != 0) + { + response.NfsFileType + = Models::NfsFileType(pRawResponse->GetHeaders().at("x-ms-file-file-type")); + } + return Response( + std::move(response), std::move(pRawResponse)); } Response DirectoryClient::Delete( Core::Http::_internal::HttpPipeline& pipeline, @@ -2244,7 +2305,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader( "x-ms-allow-trailing-dot", options.AllowTrailingDot.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -2259,7 +2320,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Models::DeleteDirectoryResult response; return Response(std::move(response), std::move(pRawResponse)); } - Response DirectoryClient::SetProperties( + Response DirectoryClient::SetProperties( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const SetDirectoryPropertiesOptions& options, @@ -2268,7 +2329,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); request.GetUrl().AppendQueryParameter("restype", "directory"); request.GetUrl().AppendQueryParameter("comp", "properties"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.FilePermission.HasValue() && !options.FilePermission.Value().empty()) { request.SetHeader("x-ms-file-permission", options.FilePermission.Value()); @@ -2309,13 +2370,25 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-file-request-intent", options.FileRequestIntent.Value().ToString()); } + if (options.Owner.HasValue() && !options.Owner.Value().empty()) + { + request.SetHeader("x-ms-owner", options.Owner.Value()); + } + if (options.Group.HasValue() && !options.Group.Value().empty()) + { + request.SetHeader("x-ms-group", options.Group.Value()); + } + if (options.FileMode.HasValue() && !options.FileMode.Value().empty()) + { + request.SetHeader("x-ms-mode", options.FileMode.Value()); + } auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Ok) { throw StorageException::CreateFromResponse(std::move(pRawResponse)); } - Models::SetDirectoryPropertiesResult response; + Models::_detail::SetDirectoryPropertiesResult response; response.ETag = ETag(pRawResponse->GetHeaders().at("ETag")); response.LastModified = DateTime::Parse( pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); @@ -2326,8 +2399,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { response.SmbProperties.PermissionKey = pRawResponse->GetHeaders().at("x-ms-file-permission-key"); } - response.SmbProperties.Attributes - = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + if (pRawResponse->GetHeaders().count("x-ms-file-attributes") != 0) + { + response.SmbProperties.Attributes + = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + } if (pRawResponse->GetHeaders().count("x-ms-file-creation-time") != 0) { response.SmbProperties.CreatedOn = DateTime::Parse( @@ -2348,7 +2424,19 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } response.SmbProperties.FileId = pRawResponse->GetHeaders().at("x-ms-file-id"); response.SmbProperties.ParentFileId = pRawResponse->GetHeaders().at("x-ms-file-parent-id"); - return Response( + if (pRawResponse->GetHeaders().count("x-ms-mode") != 0) + { + response.FileMode = pRawResponse->GetHeaders().at("x-ms-mode"); + } + if (pRawResponse->GetHeaders().count("x-ms-owner") != 0) + { + response.Owner = pRawResponse->GetHeaders().at("x-ms-owner"); + } + if (pRawResponse->GetHeaders().count("x-ms-group") != 0) + { + response.Group = pRawResponse->GetHeaders().at("x-ms-group"); + } + return Response( std::move(response), std::move(pRawResponse)); } Response DirectoryClient::SetMetadata( @@ -2364,7 +2452,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-meta-" + p.first, p.second); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -2418,7 +2506,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "maxresults", std::to_string(options.MaxResults.Value())); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.Include.HasValue() && !ListFilesIncludeFlagsToString(options.Include.Value()).empty()) { @@ -2811,7 +2899,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-recursive", options.Recursive.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -3024,7 +3112,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-recursive", options.Recursive.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -3062,7 +3150,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); request.GetUrl().AppendQueryParameter("restype", "directory"); request.GetUrl().AppendQueryParameter("comp", "rename"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (!options.RenameSource.empty()) { request.SetHeader("x-ms-file-rename-source", options.RenameSource); @@ -3164,7 +3252,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { return Response( std::move(response), std::move(pRawResponse)); } - Response FileClient::Create( + Response FileClient::Create( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const CreateFileOptions& options, @@ -3176,7 +3264,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader( "x-ms-allow-trailing-dot", options.AllowTrailingDot.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); request.SetHeader("x-ms-content-length", std::to_string(options.FileContentLength)); request.SetHeader("x-ms-type", "file"); if (options.FileContentType.HasValue() && !options.FileContentType.Value().empty()) @@ -3249,13 +3337,29 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-file-request-intent", options.FileRequestIntent.Value().ToString()); } + if (options.Owner.HasValue() && !options.Owner.Value().empty()) + { + request.SetHeader("x-ms-owner", options.Owner.Value()); + } + if (options.Group.HasValue() && !options.Group.Value().empty()) + { + request.SetHeader("x-ms-group", options.Group.Value()); + } + if (options.FileMode.HasValue() && !options.FileMode.Value().empty()) + { + request.SetHeader("x-ms-mode", options.FileMode.Value()); + } + if (options.NfsFileType.HasValue() && !options.NfsFileType.Value().ToString().empty()) + { + request.SetHeader("x-ms-file-file-type", options.NfsFileType.Value().ToString()); + } auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Created) { throw StorageException::CreateFromResponse(std::move(pRawResponse)); } - Models::CreateFileResult response; + Models::_detail::CreateFileResult response; response.ETag = ETag(pRawResponse->GetHeaders().at("ETag")); response.LastModified = DateTime::Parse( pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); @@ -3266,8 +3370,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { response.SmbProperties.PermissionKey = pRawResponse->GetHeaders().at("x-ms-file-permission-key"); } - response.SmbProperties.Attributes - = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + if (pRawResponse->GetHeaders().count("x-ms-file-attributes") != 0) + { + response.SmbProperties.Attributes + = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + } if (pRawResponse->GetHeaders().count("x-ms-file-creation-time") != 0) { response.SmbProperties.CreatedOn = DateTime::Parse( @@ -3288,9 +3395,27 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } response.SmbProperties.FileId = pRawResponse->GetHeaders().at("x-ms-file-id"); response.SmbProperties.ParentFileId = pRawResponse->GetHeaders().at("x-ms-file-parent-id"); - return Response(std::move(response), std::move(pRawResponse)); + if (pRawResponse->GetHeaders().count("x-ms-mode") != 0) + { + response.FileMode = pRawResponse->GetHeaders().at("x-ms-mode"); + } + if (pRawResponse->GetHeaders().count("x-ms-owner") != 0) + { + response.Owner = pRawResponse->GetHeaders().at("x-ms-owner"); + } + if (pRawResponse->GetHeaders().count("x-ms-group") != 0) + { + response.Group = pRawResponse->GetHeaders().at("x-ms-group"); + } + if (pRawResponse->GetHeaders().count("x-ms-file-file-type") != 0) + { + response.NfsFileType + = Models::NfsFileType(pRawResponse->GetHeaders().at("x-ms-file-file-type")); + } + return Response( + std::move(response), std::move(pRawResponse)); } - Response FileClient::Download( + Response FileClient::Download( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const DownloadFileOptions& options, @@ -3302,7 +3427,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader( "x-ms-allow-trailing-dot", options.AllowTrailingDot.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.Range.HasValue() && !options.Range.Value().empty()) { request.SetHeader("x-ms-range", options.Range.Value()); @@ -3328,7 +3453,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { throw StorageException::CreateFromResponse(std::move(pRawResponse)); } - Models::DownloadFileResult response; + Models::_detail::DownloadFileResult response; response.BodyStream = pRawResponse->ExtractBodyStream(); response.Details.LastModified = DateTime::Parse( pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); @@ -3415,8 +3540,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } response.Details.IsServerEncrypted = pRawResponse->GetHeaders().at("x-ms-server-encrypted") == std::string("true"); - response.Details.SmbProperties.Attributes - = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + if (pRawResponse->GetHeaders().count("x-ms-file-attributes") != 0) + { + response.Details.SmbProperties.Attributes + = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + } if (pRawResponse->GetHeaders().count("x-ms-file-creation-time") != 0) { response.Details.SmbProperties.CreatedOn = DateTime::Parse( @@ -3458,6 +3586,22 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { response.Details.LeaseStatus = Models::LeaseStatus(pRawResponse->GetHeaders().at("x-ms-lease-status")); } + if (pRawResponse->GetHeaders().count("x-ms-mode") != 0) + { + response.Details.FileMode = pRawResponse->GetHeaders().at("x-ms-mode"); + } + if (pRawResponse->GetHeaders().count("x-ms-owner") != 0) + { + response.Details.Owner = pRawResponse->GetHeaders().at("x-ms-owner"); + } + if (pRawResponse->GetHeaders().count("x-ms-group") != 0) + { + response.Details.Group = pRawResponse->GetHeaders().at("x-ms-group"); + } + if (pRawResponse->GetHeaders().count("x-ms-link-count") != 0) + { + response.Details.LinkCount = std::stoll(pRawResponse->GetHeaders().at("x-ms-link-count")); + } if (httpStatusCode == Core::Http::HttpStatusCode::PartialContent) { if (pRawResponse->GetHeaders().count("Content-MD5") != 0) @@ -3468,9 +3612,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { response.TransactionalContentHash.Value().Algorithm = HashAlgorithm::Md5; } } - return Response(std::move(response), std::move(pRawResponse)); + return Response( + std::move(response), std::move(pRawResponse)); } - Response FileClient::GetProperties( + Response FileClient::GetProperties( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const GetFilePropertiesOptions& options, @@ -3487,7 +3632,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "sharesnapshot", _internal::UrlEncodeQueryParameter(options.Sharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -3503,7 +3648,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { throw StorageException::CreateFromResponse(std::move(pRawResponse)); } - Models::FileProperties response; + Models::_detail::FileProperties response; response.LastModified = DateTime::Parse( pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); for (auto i = pRawResponse->GetHeaders().lower_bound("x-ms-meta-"); @@ -3570,8 +3715,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } response.IsServerEncrypted = pRawResponse->GetHeaders().at("x-ms-server-encrypted") == std::string("true"); - response.SmbProperties.Attributes - = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + if (pRawResponse->GetHeaders().count("x-ms-file-attributes") != 0) + { + response.SmbProperties.Attributes + = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + } if (pRawResponse->GetHeaders().count("x-ms-file-creation-time") != 0) { response.SmbProperties.CreatedOn = DateTime::Parse( @@ -3611,7 +3759,29 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { response.LeaseStatus = Models::LeaseStatus(pRawResponse->GetHeaders().at("x-ms-lease-status")); } - return Response(std::move(response), std::move(pRawResponse)); + if (pRawResponse->GetHeaders().count("x-ms-mode") != 0) + { + response.FileMode = pRawResponse->GetHeaders().at("x-ms-mode"); + } + if (pRawResponse->GetHeaders().count("x-ms-owner") != 0) + { + response.Owner = pRawResponse->GetHeaders().at("x-ms-owner"); + } + if (pRawResponse->GetHeaders().count("x-ms-group") != 0) + { + response.Group = pRawResponse->GetHeaders().at("x-ms-group"); + } + if (pRawResponse->GetHeaders().count("x-ms-link-count") != 0) + { + response.LinkCount = std::stoll(pRawResponse->GetHeaders().at("x-ms-link-count")); + } + if (pRawResponse->GetHeaders().count("x-ms-file-file-type") != 0) + { + response.NfsFileType + = Models::NfsFileType(pRawResponse->GetHeaders().at("x-ms-file-file-type")); + } + return Response( + std::move(response), std::move(pRawResponse)); } Response FileClient::Delete( Core::Http::_internal::HttpPipeline& pipeline, @@ -3625,7 +3795,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader( "x-ms-allow-trailing-dot", options.AllowTrailingDot.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -3642,9 +3812,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { throw StorageException::CreateFromResponse(std::move(pRawResponse)); } Models::DeleteFileResult response; + if (pRawResponse->GetHeaders().count("x-ms-link-count") != 0) + { + response.LinkCount = std::stoll(pRawResponse->GetHeaders().at("x-ms-link-count")); + } return Response(std::move(response), std::move(pRawResponse)); } - Response FileClient::SetHttpHeaders( + Response FileClient::SetHttpHeaders( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, const SetFileHttpHeadersOptions& options, @@ -3652,7 +3826,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); request.GetUrl().AppendQueryParameter("comp", "properties"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.FileContentLength.HasValue()) { request.SetHeader("x-ms-content-length", std::to_string(options.FileContentLength.Value())); @@ -3728,13 +3902,25 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-file-request-intent", options.FileRequestIntent.Value().ToString()); } + if (options.Owner.HasValue() && !options.Owner.Value().empty()) + { + request.SetHeader("x-ms-owner", options.Owner.Value()); + } + if (options.Group.HasValue() && !options.Group.Value().empty()) + { + request.SetHeader("x-ms-group", options.Group.Value()); + } + if (options.FileMode.HasValue() && !options.FileMode.Value().empty()) + { + request.SetHeader("x-ms-mode", options.FileMode.Value()); + } auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Ok) { throw StorageException::CreateFromResponse(std::move(pRawResponse)); } - Models::SetFilePropertiesResult response; + Models::_detail::SetFilePropertiesResult response; response.ETag = ETag(pRawResponse->GetHeaders().at("ETag")); response.LastModified = DateTime::Parse( pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); @@ -3745,8 +3931,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { response.SmbProperties.PermissionKey = pRawResponse->GetHeaders().at("x-ms-file-permission-key"); } - response.SmbProperties.Attributes - = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + if (pRawResponse->GetHeaders().count("x-ms-file-attributes") != 0) + { + response.SmbProperties.Attributes + = Models::FileAttributes(pRawResponse->GetHeaders().at("x-ms-file-attributes")); + } if (pRawResponse->GetHeaders().count("x-ms-file-creation-time") != 0) { response.SmbProperties.CreatedOn = DateTime::Parse( @@ -3767,7 +3956,23 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } response.SmbProperties.FileId = pRawResponse->GetHeaders().at("x-ms-file-id"); response.SmbProperties.ParentFileId = pRawResponse->GetHeaders().at("x-ms-file-parent-id"); - return Response( + if (pRawResponse->GetHeaders().count("x-ms-mode") != 0) + { + response.FileMode = pRawResponse->GetHeaders().at("x-ms-mode"); + } + if (pRawResponse->GetHeaders().count("x-ms-owner") != 0) + { + response.Owner = pRawResponse->GetHeaders().at("x-ms-owner"); + } + if (pRawResponse->GetHeaders().count("x-ms-group") != 0) + { + response.Group = pRawResponse->GetHeaders().at("x-ms-group"); + } + if (pRawResponse->GetHeaders().count("x-ms-link-count") != 0) + { + response.LinkCount = std::stoll(pRawResponse->GetHeaders().at("x-ms-link-count")); + } + return Response( std::move(response), std::move(pRawResponse)); } Response FileClient::SetMetadata( @@ -3782,7 +3987,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-meta-" + p.first, p.second); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -3826,7 +4031,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-proposed-lease-id", options.ProposedLeaseId.Value()); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -3864,7 +4069,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-lease-id", options.LeaseId); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -3905,7 +4110,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-proposed-lease-id", options.ProposedLeaseId.Value()); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -3943,7 +4148,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -3990,7 +4195,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("Content-MD5", Core::Convert::Base64Encode(options.ContentMD5.Value())); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -4077,7 +4282,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { "x-ms-source-if-none-match-crc64", Core::Convert::Base64Encode(options.SourceIfNoneMatchCrc64.Value())); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -4153,7 +4358,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { "prevsharesnapshot", _internal::UrlEncodeQueryParameter(options.Prevsharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.Range.HasValue() && !options.Range.Value().empty()) { request.SetHeader("x-ms-range", options.Range.Value()); @@ -4282,7 +4487,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { const Core::Context& context) { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); for (const auto& p : options.Metadata) { request.SetHeader("x-ms-meta-" + p.first, p.second); @@ -4357,6 +4562,29 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-file-request-intent", options.FileRequestIntent.Value().ToString()); } + if (options.Owner.HasValue() && !options.Owner.Value().empty()) + { + request.SetHeader("x-ms-owner", options.Owner.Value()); + } + if (options.Group.HasValue() && !options.Group.Value().empty()) + { + request.SetHeader("x-ms-group", options.Group.Value()); + } + if (options.FileMode.HasValue() && !options.FileMode.Value().empty()) + { + request.SetHeader("x-ms-mode", options.FileMode.Value()); + } + if (options.FileModeCopyMode.HasValue() + && !options.FileModeCopyMode.Value().ToString().empty()) + { + request.SetHeader("x-ms-file-mode-copy-mode", options.FileModeCopyMode.Value().ToString()); + } + if (options.FileOwnerCopyMode.HasValue() + && !options.FileOwnerCopyMode.Value().ToString().empty()) + { + request.SetHeader( + "x-ms-file-owner-copy-mode", options.FileOwnerCopyMode.Value().ToString()); + } auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Accepted) @@ -4386,7 +4614,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { "copyid", _internal::UrlEncodeQueryParameter(options.CopyId)); } request.SetHeader("x-ms-copy-action", "abort"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -4433,7 +4661,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "sharesnapshot", _internal::UrlEncodeQueryParameter(options.Sharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -4642,7 +4870,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-handle-id", options.HandleId); } - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -4679,7 +4907,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); request.GetUrl().AppendQueryParameter("comp", "rename"); - request.SetHeader("x-ms-version", "2025-01-05"); + request.SetHeader("x-ms-version", "2025-05-05"); if (!options.RenameSource.empty()) { request.SetHeader("x-ms-file-rename-source", options.RenameSource); @@ -4785,5 +5013,180 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { return Response( std::move(response), std::move(pRawResponse)); } + Response FileClient::CreateSymbolicLink( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + const CreateFileSymbolicLinkOptions& options, + const Core::Context& context) + { + auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); + request.GetUrl().AppendQueryParameter("restype", "symboliclink"); + request.SetHeader("x-ms-version", "2025-05-05"); + for (const auto& p : options.Metadata) + { + request.SetHeader("x-ms-meta-" + p.first, p.second); + } + if (options.FileCreationTime.HasValue() && !options.FileCreationTime.Value().empty()) + { + request.SetHeader("x-ms-file-creation-time", options.FileCreationTime.Value()); + } + if (options.FileLastWriteTime.HasValue() && !options.FileLastWriteTime.Value().empty()) + { + request.SetHeader("x-ms-file-last-write-time", options.FileLastWriteTime.Value()); + } + if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) + { + request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); + } + if (options.Owner.HasValue() && !options.Owner.Value().empty()) + { + request.SetHeader("x-ms-owner", options.Owner.Value()); + } + if (options.Group.HasValue() && !options.Group.Value().empty()) + { + request.SetHeader("x-ms-group", options.Group.Value()); + } + if (!options.LinkText.empty()) + { + request.SetHeader("x-ms-link-text", options.LinkText); + } + if (options.FileRequestIntent.HasValue() + && !options.FileRequestIntent.Value().ToString().empty()) + { + request.SetHeader("x-ms-file-request-intent", options.FileRequestIntent.Value().ToString()); + } + auto pRawResponse = pipeline.Send(request, context); + auto httpStatusCode = pRawResponse->GetStatusCode(); + if (httpStatusCode != Core::Http::HttpStatusCode::Created) + { + throw StorageException::CreateFromResponse(std::move(pRawResponse)); + } + Models::_detail::CreateFileSymbolicLinkResult response; + response.ETag = ETag(pRawResponse->GetHeaders().at("ETag")); + response.LastModified = DateTime::Parse( + pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); + if (pRawResponse->GetHeaders().count("x-ms-file-creation-time") != 0) + { + response.SmbProperties.CreatedOn = DateTime::Parse( + pRawResponse->GetHeaders().at("x-ms-file-creation-time"), + Azure::DateTime::DateFormat::Rfc3339); + } + if (pRawResponse->GetHeaders().count("x-ms-file-last-write-time") != 0) + { + response.SmbProperties.LastWrittenOn = DateTime::Parse( + pRawResponse->GetHeaders().at("x-ms-file-last-write-time"), + Azure::DateTime::DateFormat::Rfc3339); + } + if (pRawResponse->GetHeaders().count("x-ms-file-change-time") != 0) + { + response.SmbProperties.ChangedOn = DateTime::Parse( + pRawResponse->GetHeaders().at("x-ms-file-change-time"), + Azure::DateTime::DateFormat::Rfc3339); + } + response.SmbProperties.FileId = pRawResponse->GetHeaders().at("x-ms-file-id"); + response.SmbProperties.ParentFileId = pRawResponse->GetHeaders().at("x-ms-file-parent-id"); + response.FileMode = pRawResponse->GetHeaders().at("x-ms-mode"); + response.Owner = pRawResponse->GetHeaders().at("x-ms-owner"); + response.Group = pRawResponse->GetHeaders().at("x-ms-group"); + response.NfsFileType + = Models::NfsFileType(pRawResponse->GetHeaders().at("x-ms-file-file-type")); + return Response( + std::move(response), std::move(pRawResponse)); + } + Response FileClient::GetSymbolicLink( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + const GetFileSymbolicLinkOptions& options, + const Core::Context& context) + { + auto request = Core::Http::Request(Core::Http::HttpMethod::Get, url); + request.GetUrl().AppendQueryParameter("restype", "symboliclink"); + if (options.Sharesnapshot.HasValue() && !options.Sharesnapshot.Value().empty()) + { + request.GetUrl().AppendQueryParameter( + "sharesnapshot", _internal::UrlEncodeQueryParameter(options.Sharesnapshot.Value())); + } + request.SetHeader("x-ms-version", "2025-05-05"); + if (options.FileRequestIntent.HasValue() + && !options.FileRequestIntent.Value().ToString().empty()) + { + request.SetHeader("x-ms-file-request-intent", options.FileRequestIntent.Value().ToString()); + } + auto pRawResponse = pipeline.Send(request, context); + auto httpStatusCode = pRawResponse->GetStatusCode(); + if (httpStatusCode != Core::Http::HttpStatusCode::Ok) + { + throw StorageException::CreateFromResponse(std::move(pRawResponse)); + } + Models::_detail::GetFileSymbolicLinkResult response; + response.ETag = ETag(pRawResponse->GetHeaders().at("ETag")); + response.LastModified = DateTime::Parse( + pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); + response.LinkText = pRawResponse->GetHeaders().at("x-ms-link-text"); + return Response( + std::move(response), std::move(pRawResponse)); + } + Response FileClient::CreateHardLink( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + const CreateFileHardLinkOptions& options, + const Core::Context& context) + { + auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); + request.GetUrl().AppendQueryParameter("restype", "hardlink"); + request.SetHeader("x-ms-version", "2025-05-05"); + request.SetHeader("x-ms-type", "file"); + if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) + { + request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); + } + if (!options.TargetFile.empty()) + { + request.SetHeader("x-ms-file-target-file", options.TargetFile); + } + if (options.FileRequestIntent.HasValue() + && !options.FileRequestIntent.Value().ToString().empty()) + { + request.SetHeader("x-ms-file-request-intent", options.FileRequestIntent.Value().ToString()); + } + auto pRawResponse = pipeline.Send(request, context); + auto httpStatusCode = pRawResponse->GetStatusCode(); + if (httpStatusCode != Core::Http::HttpStatusCode::Created) + { + throw StorageException::CreateFromResponse(std::move(pRawResponse)); + } + Models::_detail::CreateFileHardLinkResult response; + response.ETag = ETag(pRawResponse->GetHeaders().at("ETag")); + response.LastModified = DateTime::Parse( + pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); + if (pRawResponse->GetHeaders().count("x-ms-file-creation-time") != 0) + { + response.SmbProperties.CreatedOn = DateTime::Parse( + pRawResponse->GetHeaders().at("x-ms-file-creation-time"), + Azure::DateTime::DateFormat::Rfc3339); + } + if (pRawResponse->GetHeaders().count("x-ms-file-last-write-time") != 0) + { + response.SmbProperties.LastWrittenOn = DateTime::Parse( + pRawResponse->GetHeaders().at("x-ms-file-last-write-time"), + Azure::DateTime::DateFormat::Rfc3339); + } + if (pRawResponse->GetHeaders().count("x-ms-file-change-time") != 0) + { + response.SmbProperties.ChangedOn = DateTime::Parse( + pRawResponse->GetHeaders().at("x-ms-file-change-time"), + Azure::DateTime::DateFormat::Rfc3339); + } + response.SmbProperties.FileId = pRawResponse->GetHeaders().at("x-ms-file-id"); + response.SmbProperties.ParentFileId = pRawResponse->GetHeaders().at("x-ms-file-parent-id"); + response.LinkCount = std::stoll(pRawResponse->GetHeaders().at("x-ms-link-count")); + response.FileMode = pRawResponse->GetHeaders().at("x-ms-mode"); + response.Owner = pRawResponse->GetHeaders().at("x-ms-owner"); + response.Group = pRawResponse->GetHeaders().at("x-ms-group"); + response.NfsFileType + = Models::NfsFileType(pRawResponse->GetHeaders().at("x-ms-file-file-type")); + return Response( + std::move(response), std::move(pRawResponse)); + } } // namespace _detail }}}} // namespace Azure::Storage::Files::Shares \ No newline at end of file diff --git a/sdk/storage/azure-storage-files-shares/src/share_directory_client.cpp b/sdk/storage/azure-storage-files-shares/src/share_directory_client.cpp index 462dd3429..e556ea0a4 100644 --- a/sdk/storage/azure-storage-files-shares/src/share_directory_client.cpp +++ b/sdk/storage/azure-storage-files-shares/src/share_directory_client.cpp @@ -164,32 +164,20 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto protocolLayerOptions = _detail::DirectoryClient::CreateDirectoryOptions(); protocolLayerOptions.Metadata = std::map(options.Metadata.begin(), options.Metadata.end()); - if (options.SmbProperties.Attributes.GetValues().empty()) - { - protocolLayerOptions.FileAttributes = Models::FileAttributes::Directory.ToString(); - } - else - { - protocolLayerOptions.FileAttributes = options.SmbProperties.Attributes.ToString(); - } + protocolLayerOptions.FileAttributes = options.SmbProperties.Attributes.ToString(); + if (options.SmbProperties.CreatedOn.HasValue()) { protocolLayerOptions.FileCreationTime = options.SmbProperties.CreatedOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileCreationTime = std::string(FileDefaultTimeValue); - } + if (options.SmbProperties.LastWrittenOn.HasValue()) { protocolLayerOptions.FileLastWriteTime = options.SmbProperties.LastWrittenOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileLastWriteTime = std::string(FileDefaultTimeValue); - } + if (options.SmbProperties.ChangedOn.HasValue()) { protocolLayerOptions.FileChangeTime = options.SmbProperties.ChangedOn.Value().ToString( @@ -203,13 +191,16 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { protocolLayerOptions.FilePermissionKey = options.SmbProperties.PermissionKey; } - else - { - protocolLayerOptions.FilePermission = std::string(FileInheritPermission); - } + protocolLayerOptions.AllowTrailingDot = m_allowTrailingDot; protocolLayerOptions.FileRequestIntent = m_shareTokenIntent; protocolLayerOptions.FilePermissionFormat = options.DirectoryPermissionFormat; + if (options.PosixProperties.FileMode.HasValue()) + { + protocolLayerOptions.FileMode = options.PosixProperties.FileMode.Value().ToOctalFileMode(); + } + protocolLayerOptions.Owner = options.PosixProperties.Owner; + protocolLayerOptions.Group = options.PosixProperties.Group; auto result = _detail::DirectoryClient::Create( *m_pipeline, m_shareDirectoryUrl, protocolLayerOptions, context); Models::CreateDirectoryResult ret; @@ -218,7 +209,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { ret.IsServerEncrypted = result.Value.IsServerEncrypted; ret.LastModified = std::move(result.Value.LastModified); ret.SmbProperties = std::move(result.Value.SmbProperties); - + if (result.Value.FileMode.HasValue()) + { + ret.PosixProperties.FileMode + = Models::NfsFileMode::ParseOctalFileMode(result.Value.FileMode.Value()); + } + ret.PosixProperties.Owner = std::move(result.Value.Owner); + ret.PosixProperties.Group = std::move(result.Value.Group); + ret.PosixProperties.NfsFileType = std::move(result.Value.NfsFileType); return Azure::Response( std::move(ret), std::move(result.RawResponse)); } @@ -417,8 +415,24 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto protocolLayerOptions = _detail::DirectoryClient::GetDirectoryPropertiesOptions(); protocolLayerOptions.AllowTrailingDot = m_allowTrailingDot; protocolLayerOptions.FileRequestIntent = m_shareTokenIntent; - return _detail::DirectoryClient::GetProperties( + auto response = _detail::DirectoryClient::GetProperties( *m_pipeline, m_shareDirectoryUrl, protocolLayerOptions, context); + Models::DirectoryProperties ret; + ret.ETag = std::move(response.Value.ETag); + ret.IsServerEncrypted = response.Value.IsServerEncrypted; + ret.LastModified = std::move(response.Value.LastModified); + ret.Metadata = std::move(response.Value.Metadata); + ret.SmbProperties = std::move(response.Value.SmbProperties); + if (response.Value.FileMode.HasValue()) + { + ret.PosixProperties.FileMode + = Models::NfsFileMode::ParseOctalFileMode(response.Value.FileMode.Value()); + } + ret.PosixProperties.Owner = std::move(response.Value.Owner); + ret.PosixProperties.Group = std::move(response.Value.Group); + ret.PosixProperties.NfsFileType = std::move(response.Value.NfsFileType); + return Azure::Response( + std::move(ret), std::move(response.RawResponse)); } Azure::Response ShareDirectoryClient::SetProperties( @@ -428,28 +442,16 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { auto protocolLayerOptions = _detail::DirectoryClient::SetDirectoryPropertiesOptions(); protocolLayerOptions.FileAttributes = smbProperties.Attributes.ToString(); - if (protocolLayerOptions.FileAttributes.empty()) - { - protocolLayerOptions.FileAttributes = FilePreserveSmbProperties; - } if (smbProperties.CreatedOn.HasValue()) { protocolLayerOptions.FileCreationTime = smbProperties.CreatedOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileCreationTime = FilePreserveSmbProperties; - } if (smbProperties.LastWrittenOn.HasValue()) { protocolLayerOptions.FileLastWriteTime = smbProperties.LastWrittenOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileLastWriteTime = FilePreserveSmbProperties; - } if (smbProperties.ChangedOn.HasValue()) { protocolLayerOptions.FileChangeTime = smbProperties.ChangedOn.Value().ToString( @@ -463,15 +465,31 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { protocolLayerOptions.FilePermissionKey = smbProperties.PermissionKey; } - else - { - protocolLayerOptions.FilePermission = FilePreserveSmbProperties; - } protocolLayerOptions.AllowTrailingDot = m_allowTrailingDot; protocolLayerOptions.FileRequestIntent = m_shareTokenIntent; protocolLayerOptions.FilePermissionFormat = options.FilePermissionFormat; - return _detail::DirectoryClient::SetProperties( + if (options.PosixProperties.FileMode.HasValue()) + { + protocolLayerOptions.FileMode = options.PosixProperties.FileMode.Value().ToOctalFileMode(); + } + protocolLayerOptions.Owner = options.PosixProperties.Owner; + protocolLayerOptions.Group = options.PosixProperties.Group; + auto response = _detail::DirectoryClient::SetProperties( *m_pipeline, m_shareDirectoryUrl, protocolLayerOptions, context); + Models::SetDirectoryPropertiesResult ret; + ret.ETag = std::move(response.Value.ETag); + ret.IsServerEncrypted = response.Value.IsServerEncrypted; + ret.LastModified = std::move(response.Value.LastModified); + ret.SmbProperties = std::move(response.Value.SmbProperties); + if (response.Value.FileMode.HasValue()) + { + ret.PosixProperties.FileMode + = Models::NfsFileMode::ParseOctalFileMode(response.Value.FileMode.Value()); + } + ret.PosixProperties.Owner = std::move(response.Value.Owner); + ret.PosixProperties.Group = std::move(response.Value.Group); + return Azure::Response( + std::move(ret), std::move(response.RawResponse)); } Azure::Response ShareDirectoryClient::SetMetadata( 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 b1ac59a99..aec93dc8f 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 @@ -147,28 +147,17 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { protocolLayerOptions.Metadata = std::map(options.Metadata.begin(), options.Metadata.end()); protocolLayerOptions.FileAttributes = options.SmbProperties.Attributes.ToString(); - if (protocolLayerOptions.FileAttributes.empty()) - { - protocolLayerOptions.FileAttributes = Models::FileAttributes::None.ToString(); - } + if (options.SmbProperties.CreatedOn.HasValue()) { protocolLayerOptions.FileCreationTime = options.SmbProperties.CreatedOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileCreationTime = std::string(FileDefaultTimeValue); - } if (options.SmbProperties.LastWrittenOn.HasValue()) { protocolLayerOptions.FileLastWriteTime = options.SmbProperties.LastWrittenOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileLastWriteTime = std::string(FileDefaultTimeValue); - } if (options.SmbProperties.ChangedOn.HasValue()) { protocolLayerOptions.FileChangeTime = options.SmbProperties.ChangedOn.Value().ToString( @@ -182,10 +171,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { protocolLayerOptions.FilePermissionKey = options.SmbProperties.PermissionKey; } - else - { - protocolLayerOptions.FilePermission = std::string(FileInheritPermission); - } protocolLayerOptions.FileContentLength = fileSize; if (!options.HttpHeaders.ContentType.empty()) { @@ -218,6 +203,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { protocolLayerOptions.AllowTrailingDot = m_allowTrailingDot; protocolLayerOptions.FileRequestIntent = m_shareTokenIntent; protocolLayerOptions.FilePermissionFormat = options.FilePermissionFormat; + if (options.PosixProperties.FileMode.HasValue()) + { + protocolLayerOptions.FileMode = options.PosixProperties.FileMode.Value().ToOctalFileMode(); + } + protocolLayerOptions.Owner = options.PosixProperties.Owner; + protocolLayerOptions.Group = options.PosixProperties.Group; + protocolLayerOptions.NfsFileType = options.PosixProperties.NfsFileType; auto result = _detail::FileClient::Create(*m_pipeline, m_shareFileUrl, protocolLayerOptions, context); Models::CreateFileResult ret; @@ -226,6 +218,14 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { ret.SmbProperties = std::move(result.Value.SmbProperties); ret.IsServerEncrypted = result.Value.IsServerEncrypted; ret.LastModified = std::move(result.Value.LastModified); + if (result.Value.FileMode.HasValue()) + { + ret.PosixProperties.FileMode + = Models::NfsFileMode::ParseOctalFileMode(result.Value.FileMode.Value()); + } + ret.PosixProperties.Owner = std::move(result.Value.Owner); + ret.PosixProperties.Group = std::move(result.Value.Group); + ret.PosixProperties.NfsFileType = std::move(result.Value.NfsFileType); return Azure::Response(std::move(ret), std::move(result.RawResponse)); } @@ -242,6 +242,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { = _detail::FileClient::Delete(*m_pipeline, m_shareFileUrl, protocolLayerOptions, context); Models::DeleteFileResult ret; ret.Deleted = true; + ret.LinkCount = result.Value.LinkCount; return Azure::Response(std::move(ret), std::move(result.RawResponse)); } @@ -363,7 +364,37 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { = Azure::Core::Http::HttpRange{rangeStartOffset, rangeEndOffset - rangeStartOffset + 1}; downloadResponse.Value.FileSize = std::stoll(contentRange.substr(slash_pos + 1)); } - return downloadResponse; + Models::DownloadFileResult result; + result.BodyStream = std::move(downloadResponse.Value.BodyStream); + result.ContentRange = std::move(downloadResponse.Value.ContentRange); + result.FileSize = downloadResponse.Value.FileSize; + result.HttpHeaders = std::move(downloadResponse.Value.HttpHeaders); + result.TransactionalContentHash = std::move(downloadResponse.Value.TransactionalContentHash); + result.Details.CopyCompletedOn = std::move(downloadResponse.Value.Details.CopyCompletedOn); + result.Details.CopyId = std::move(downloadResponse.Value.Details.CopyId); + result.Details.CopyProgress = std::move(downloadResponse.Value.Details.CopyProgress); + result.Details.CopySource = std::move(downloadResponse.Value.Details.CopySource); + result.Details.CopyStatus = std::move(downloadResponse.Value.Details.CopyStatus); + result.Details.CopyStatusDescription + = std::move(downloadResponse.Value.Details.CopyStatusDescription); + result.Details.ETag = std::move(downloadResponse.Value.Details.ETag); + result.Details.IsServerEncrypted = downloadResponse.Value.Details.IsServerEncrypted; + result.Details.LastModified = std::move(downloadResponse.Value.Details.LastModified); + result.Details.LeaseDuration = std::move(downloadResponse.Value.Details.LeaseDuration); + result.Details.LeaseState = std::move(downloadResponse.Value.Details.LeaseState); + result.Details.LeaseStatus = std::move(downloadResponse.Value.Details.LeaseStatus); + result.Details.Metadata = std::move(downloadResponse.Value.Details.Metadata); + result.Details.SmbProperties = std::move(downloadResponse.Value.Details.SmbProperties); + if (downloadResponse.Value.Details.FileMode.HasValue()) + { + result.Details.PosixProperties.FileMode = Models::NfsFileMode::ParseOctalFileMode( + downloadResponse.Value.Details.FileMode.Value()); + } + result.Details.PosixProperties.Owner = std::move(downloadResponse.Value.Details.Owner); + result.Details.PosixProperties.Group = std::move(downloadResponse.Value.Details.Group); + result.Details.PosixProperties.LinkCount = std::move(downloadResponse.Value.Details.LinkCount); + return Azure::Response( + std::move(result), std::move(downloadResponse.RawResponse)); } StartFileCopyOperation ShareFileClient::StartCopy( @@ -375,67 +406,154 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { protocolLayerOptions.Metadata = std::map(options.Metadata.begin(), options.Metadata.end()); protocolLayerOptions.CopySource = std::move(copySource); - if (options.SmbProperties.Attributes.GetValues().empty()) + + if (options.SmbPropertiesToCopy.HasValue()) { - protocolLayerOptions.FileAttributes = FileCopySourceTime; - } - else - { - protocolLayerOptions.FileAttributes = options.SmbProperties.Attributes.ToString(); - } - if (options.SmbProperties.CreatedOn.HasValue()) - { - protocolLayerOptions.FileCreationTime = options.SmbProperties.CreatedOn.Value().ToString( - Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); - } - else - { - protocolLayerOptions.FileCreationTime = std::string(FileCopySourceTime); - } - if (options.SmbProperties.LastWrittenOn.HasValue()) - { - protocolLayerOptions.FileLastWriteTime = options.SmbProperties.LastWrittenOn.Value().ToString( - Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); - } - else - { - protocolLayerOptions.FileLastWriteTime = std::string(FileCopySourceTime); - } - if (options.SmbProperties.ChangedOn.HasValue()) - { - protocolLayerOptions.FileChangeTime = options.SmbProperties.ChangedOn.Value().ToString( - Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); - } - if (options.PermissionCopyMode.HasValue()) - { - protocolLayerOptions.FilePermissionCopyMode = options.PermissionCopyMode.Value(); - if (options.PermissionCopyMode.Value() == Models::PermissionCopyMode::Override) + if ((options.SmbPropertiesToCopy.Value() & CopyableFileSmbPropertyFlags::FileAttributes) + == CopyableFileSmbPropertyFlags::FileAttributes) { - if (options.Permission.HasValue()) + protocolLayerOptions.FileAttributes = FileCopySourceTime; + } + else if (!options.SmbProperties.Attributes.GetValues().empty()) + { + protocolLayerOptions.FileAttributes = options.SmbProperties.Attributes.ToString(); + } + + if ((options.SmbPropertiesToCopy.Value() & CopyableFileSmbPropertyFlags::CreatedOn) + == CopyableFileSmbPropertyFlags::CreatedOn) + { + protocolLayerOptions.FileCreationTime = std::string(FileCopySourceTime); + } + else if (options.SmbProperties.CreatedOn.HasValue()) + { + protocolLayerOptions.FileCreationTime = options.SmbProperties.CreatedOn.Value().ToString( + Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); + } + + if ((options.SmbPropertiesToCopy.Value() & CopyableFileSmbPropertyFlags::LastWrittenOn) + == CopyableFileSmbPropertyFlags::LastWrittenOn) + { + protocolLayerOptions.FileLastWriteTime = std::string(FileCopySourceTime); + } + else if (options.SmbProperties.LastWrittenOn.HasValue()) + { + protocolLayerOptions.FileLastWriteTime + = options.SmbProperties.LastWrittenOn.Value().ToString( + Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); + } + + if ((options.SmbPropertiesToCopy.Value() & CopyableFileSmbPropertyFlags::ChangedOn) + == CopyableFileSmbPropertyFlags::ChangedOn) + { + protocolLayerOptions.FileChangeTime = std::string(FileCopySourceTime); + } + else if (options.SmbProperties.ChangedOn.HasValue()) + { + protocolLayerOptions.FileChangeTime = options.SmbProperties.ChangedOn.Value().ToString( + Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); + } + + if ((options.SmbPropertiesToCopy.Value() & CopyableFileSmbPropertyFlags::Permission) + == CopyableFileSmbPropertyFlags::Permission) + { + protocolLayerOptions.FilePermissionCopyMode = Models::PermissionCopyMode::Source; + } + else if (options.PermissionCopyMode.HasValue()) + { + protocolLayerOptions.FilePermissionCopyMode = options.PermissionCopyMode.Value(); + if (options.PermissionCopyMode.Value() == Models::PermissionCopyMode::Override) { - protocolLayerOptions.FilePermission = options.Permission; - protocolLayerOptions.FilePermissionFormat = options.FilePermissionFormat; - } - else if (options.SmbProperties.PermissionKey.HasValue()) - { - protocolLayerOptions.FilePermissionKey = options.SmbProperties.PermissionKey; - } - else - { - AZURE_ASSERT_MSG(false, "Either FilePermission or FilePermissionKey must be set."); + if (options.Permission.HasValue()) + { + protocolLayerOptions.FilePermission = options.Permission; + protocolLayerOptions.FilePermissionFormat = options.FilePermissionFormat; + } + else if (options.SmbProperties.PermissionKey.HasValue()) + { + protocolLayerOptions.FilePermissionKey = options.SmbProperties.PermissionKey; + } + else + { + AZURE_ASSERT_MSG(false, "Either FilePermission or FilePermissionKey must be set."); + } } } } else { - protocolLayerOptions.FilePermissionCopyMode = Models::PermissionCopyMode::Source; + if (options.SmbProperties.Attributes.GetValues().empty()) + { + protocolLayerOptions.FileAttributes = FileCopySourceTime; + } + else + { + protocolLayerOptions.FileAttributes = options.SmbProperties.Attributes.ToString(); + } + if (options.SmbProperties.CreatedOn.HasValue()) + { + protocolLayerOptions.FileCreationTime = options.SmbProperties.CreatedOn.Value().ToString( + Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); + } + else + { + protocolLayerOptions.FileCreationTime = std::string(FileCopySourceTime); + } + if (options.SmbProperties.LastWrittenOn.HasValue()) + { + protocolLayerOptions.FileLastWriteTime + = options.SmbProperties.LastWrittenOn.Value().ToString( + Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); + } + else + { + protocolLayerOptions.FileLastWriteTime = std::string(FileCopySourceTime); + } + if (options.SmbProperties.ChangedOn.HasValue()) + { + protocolLayerOptions.FileChangeTime = options.SmbProperties.ChangedOn.Value().ToString( + Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); + } + if (options.PermissionCopyMode.HasValue()) + { + protocolLayerOptions.FilePermissionCopyMode = options.PermissionCopyMode.Value(); + if (options.PermissionCopyMode.Value() == Models::PermissionCopyMode::Override) + { + if (options.Permission.HasValue()) + { + protocolLayerOptions.FilePermission = options.Permission; + protocolLayerOptions.FilePermissionFormat = options.FilePermissionFormat; + } + else if (options.SmbProperties.PermissionKey.HasValue()) + { + protocolLayerOptions.FilePermissionKey = options.SmbProperties.PermissionKey; + } + else + { + AZURE_ASSERT_MSG(false, "Either FilePermission or FilePermissionKey must be set."); + } + } + } + else + { + protocolLayerOptions.FilePermissionCopyMode = Models::PermissionCopyMode::Source; + } } + protocolLayerOptions.IgnoreReadOnly = options.IgnoreReadOnly; protocolLayerOptions.SetArchiveAttribute = options.SetArchiveAttribute; protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId; protocolLayerOptions.AllowTrailingDot = m_allowTrailingDot; protocolLayerOptions.AllowSourceTrailingDot = m_allowSourceTrailingDot; protocolLayerOptions.FileRequestIntent = m_shareTokenIntent; + if (options.PosixProperties.FileMode.HasValue()) + { + protocolLayerOptions.FileMode = options.PosixProperties.FileMode.Value().ToOctalFileMode(); + } + protocolLayerOptions.FileModeCopyMode = options.ModeCopyMode; + protocolLayerOptions.Owner = options.PosixProperties.Owner; + protocolLayerOptions.Group = options.PosixProperties.Group; + protocolLayerOptions.FileOwnerCopyMode = options.OwnerCopyMode; + auto response = _detail::FileClient::StartCopy( *m_pipeline, m_shareFileUrl, protocolLayerOptions, context); @@ -467,8 +585,35 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId; protocolLayerOptions.AllowTrailingDot = m_allowTrailingDot; protocolLayerOptions.FileRequestIntent = m_shareTokenIntent; - return _detail::FileClient::GetProperties( + auto response = _detail::FileClient::GetProperties( *m_pipeline, m_shareFileUrl, protocolLayerOptions, context); + Models::FileProperties ret; + ret.CopyCompletedOn = std::move(response.Value.CopyCompletedOn); + ret.CopyId = std::move(response.Value.CopyId); + ret.CopyProgress = std::move(response.Value.CopyProgress); + ret.CopySource = std::move(response.Value.CopySource); + ret.CopyStatus = std::move(response.Value.CopyStatus); + ret.CopyStatusDescription = std::move(response.Value.CopyStatusDescription); + ret.ETag = std::move(response.Value.ETag); + ret.FileSize = response.Value.FileSize; + ret.HttpHeaders = std::move(response.Value.HttpHeaders); + ret.IsServerEncrypted = response.Value.IsServerEncrypted; + ret.LastModified = std::move(response.Value.LastModified); + ret.LeaseDuration = std::move(response.Value.LeaseDuration); + ret.LeaseState = std::move(response.Value.LeaseState); + ret.LeaseStatus = std::move(response.Value.LeaseStatus); + ret.Metadata = std::move(response.Value.Metadata); + ret.SmbProperties = std::move(response.Value.SmbProperties); + if (response.Value.FileMode.HasValue()) + { + ret.PosixProperties.FileMode + = Models::NfsFileMode::ParseOctalFileMode(response.Value.FileMode.Value()); + } + ret.PosixProperties.Owner = std::move(response.Value.Owner); + ret.PosixProperties.Group = std::move(response.Value.Group); + ret.PosixProperties.NfsFileType = std::move(response.Value.NfsFileType); + ret.PosixProperties.LinkCount = std::move(response.Value.LinkCount); + return Azure::Response(std::move(ret), std::move(response.RawResponse)); } Azure::Response ShareFileClient::SetProperties( @@ -479,28 +624,16 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { auto protocolLayerOptions = _detail::FileClient::SetFileHttpHeadersOptions(); protocolLayerOptions.FileAttributes = smbProperties.Attributes.ToString(); - if (protocolLayerOptions.FileAttributes.empty()) - { - protocolLayerOptions.FileAttributes = FilePreserveSmbProperties; - } if (smbProperties.CreatedOn.HasValue()) { protocolLayerOptions.FileCreationTime = smbProperties.CreatedOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileCreationTime = FilePreserveSmbProperties; - } if (smbProperties.LastWrittenOn.HasValue()) { protocolLayerOptions.FileLastWriteTime = smbProperties.LastWrittenOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileLastWriteTime = FilePreserveSmbProperties; - } if (smbProperties.ChangedOn.HasValue()) { protocolLayerOptions.FileChangeTime = smbProperties.ChangedOn.Value().ToString( @@ -516,10 +649,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { protocolLayerOptions.FilePermissionKey = smbProperties.PermissionKey; } - else - { - protocolLayerOptions.FilePermission = FilePreserveSmbProperties; - } if (!httpHeaders.ContentType.empty()) { @@ -544,9 +673,31 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { protocolLayerOptions.AllowTrailingDot = m_allowTrailingDot; protocolLayerOptions.FileRequestIntent = m_shareTokenIntent; protocolLayerOptions.FilePermissionFormat = options.FilePermissionFormat; + if (options.PosixProperties.FileMode.HasValue()) + { + protocolLayerOptions.FileMode = options.PosixProperties.FileMode.Value().ToOctalFileMode(); + } + protocolLayerOptions.Owner = options.PosixProperties.Owner; + protocolLayerOptions.Group = options.PosixProperties.Group; - return _detail::FileClient::SetHttpHeaders( + auto response = _detail::FileClient::SetHttpHeaders( *m_pipeline, m_shareFileUrl, protocolLayerOptions, context); + + Models::SetFilePropertiesResult ret; + ret.ETag = std::move(response.Value.ETag); + ret.IsServerEncrypted = response.Value.IsServerEncrypted; + ret.LastModified = std::move(response.Value.LastModified); + ret.SmbProperties = std::move(response.Value.SmbProperties); + if (response.Value.FileMode.HasValue()) + { + ret.PosixProperties.FileMode + = Models::NfsFileMode::ParseOctalFileMode(response.Value.FileMode.Value()); + } + ret.PosixProperties.Owner = std::move(response.Value.Owner); + ret.PosixProperties.Group = std::move(response.Value.Group); + ret.PosixProperties.LinkCount = std::move(response.Value.LinkCount); + return Azure::Response( + std::move(ret), std::move(response.RawResponse)); } Azure::Response ShareFileClient::SetMetadata( @@ -1014,28 +1165,19 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { _detail::FileClient::CreateFileOptions protocolLayerOptions; protocolLayerOptions.FileContentLength = bufferSize; protocolLayerOptions.FileAttributes = options.SmbProperties.Attributes.ToString(); - if (protocolLayerOptions.FileAttributes.empty()) - { - protocolLayerOptions.FileAttributes = Models::FileAttributes::None.ToString(); - } + if (options.SmbProperties.CreatedOn.HasValue()) { protocolLayerOptions.FileCreationTime = options.SmbProperties.CreatedOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileCreationTime = std::string(FileDefaultTimeValue); - } + if (options.SmbProperties.LastWrittenOn.HasValue()) { protocolLayerOptions.FileLastWriteTime = options.SmbProperties.LastWrittenOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileLastWriteTime = std::string(FileDefaultTimeValue); - } + if (options.SmbProperties.ChangedOn.HasValue()) { protocolLayerOptions.FileChangeTime = options.SmbProperties.ChangedOn.Value().ToString( @@ -1049,10 +1191,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { protocolLayerOptions.FilePermissionKey = options.SmbProperties.PermissionKey; } - else - { - protocolLayerOptions.FilePermission = std::string(FileInheritPermission); - } if (!options.HttpHeaders.ContentType.empty()) { @@ -1086,6 +1224,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { protocolLayerOptions.AllowTrailingDot = m_allowTrailingDot; protocolLayerOptions.FileRequestIntent = m_shareTokenIntent; protocolLayerOptions.FilePermissionFormat = options.FilePermissionFormat; + if (options.PosixProperties.FileMode.HasValue()) + { + protocolLayerOptions.FileMode = options.PosixProperties.FileMode.Value().ToOctalFileMode(); + } + protocolLayerOptions.Owner = options.PosixProperties.Owner; + protocolLayerOptions.Group = options.PosixProperties.Group; + protocolLayerOptions.NfsFileType = options.PosixProperties.NfsFileType; auto createResult = _detail::FileClient::Create(*m_pipeline, m_shareFileUrl, protocolLayerOptions, context); @@ -1132,28 +1277,19 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { _detail::FileClient::CreateFileOptions protocolLayerOptions; protocolLayerOptions.FileContentLength = fileReader.GetFileSize(); protocolLayerOptions.FileAttributes = options.SmbProperties.Attributes.ToString(); - if (protocolLayerOptions.FileAttributes.empty()) - { - protocolLayerOptions.FileAttributes = Models::FileAttributes::None.ToString(); - } + if (options.SmbProperties.CreatedOn.HasValue()) { protocolLayerOptions.FileCreationTime = options.SmbProperties.CreatedOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileCreationTime = std::string(FileDefaultTimeValue); - } + if (options.SmbProperties.LastWrittenOn.HasValue()) { protocolLayerOptions.FileLastWriteTime = options.SmbProperties.LastWrittenOn.Value().ToString( Azure::DateTime::DateFormat::Rfc3339, DateTime::TimeFractionFormat::AllDigits); } - else - { - protocolLayerOptions.FileLastWriteTime = std::string(FileDefaultTimeValue); - } + if (options.SmbProperties.ChangedOn.HasValue()) { protocolLayerOptions.FileChangeTime = options.SmbProperties.ChangedOn.Value().ToString( @@ -1167,10 +1303,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { protocolLayerOptions.FilePermissionKey = options.SmbProperties.PermissionKey; } - else - { - protocolLayerOptions.FilePermission = std::string(FileInheritPermission); - } if (!options.HttpHeaders.ContentType.empty()) { @@ -1204,6 +1336,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { protocolLayerOptions.AllowTrailingDot = m_allowTrailingDot; protocolLayerOptions.FileRequestIntent = m_shareTokenIntent; protocolLayerOptions.FilePermissionFormat = options.FilePermissionFormat; + if (options.PosixProperties.FileMode.HasValue()) + { + protocolLayerOptions.FileMode = options.PosixProperties.FileMode.Value().ToOctalFileMode(); + } + protocolLayerOptions.Owner = options.PosixProperties.Owner; + protocolLayerOptions.Group = options.PosixProperties.Group; + protocolLayerOptions.NfsFileType = options.PosixProperties.NfsFileType; auto createResult = _detail::FileClient::Create(*m_pipeline, m_shareFileUrl, protocolLayerOptions, context); @@ -1294,4 +1433,30 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { return _detail::FileClient::UploadRangeFromUri( *m_pipeline, m_shareFileUrl, protocolLayerOptions, context); } + + Azure::Response ShareFileClient::CreateHardLink( + const std::string& targetFile, + const CreateHardLinkOptions& options, + const Azure::Core::Context& context) const + { + _detail::FileClient::CreateFileHardLinkOptions protocolLayerOptions; + protocolLayerOptions.TargetFile = targetFile; + protocolLayerOptions.FileRequestIntent = m_shareTokenIntent; + protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId; + + auto response = _detail::FileClient::CreateHardLink( + *m_pipeline, m_shareFileUrl, protocolLayerOptions, context); + + Models::CreateFileHardLinkResult ret; + ret.ETag = std::move(response.Value.ETag); + ret.SmbProperties = std::move(response.Value.SmbProperties); + ret.LastModified = std::move(response.Value.LastModified); + ret.PosixProperties.FileMode = Models::NfsFileMode::ParseOctalFileMode(response.Value.FileMode); + ret.PosixProperties.Owner = std::move(response.Value.Owner); + ret.PosixProperties.Group = std::move(response.Value.Group); + ret.PosixProperties.NfsFileType = std::move(response.Value.NfsFileType); + ret.PosixProperties.LinkCount = response.Value.LinkCount; + return Azure::Response( + std::move(ret), std::move(response.RawResponse)); + } }}}} // namespace Azure::Storage::Files::Shares diff --git a/sdk/storage/azure-storage-files-shares/src/share_options.cpp b/sdk/storage/azure-storage-files-shares/src/share_options.cpp index 59b1a352a..345d5ba23 100644 --- a/sdk/storage/azure-storage-files-shares/src/share_options.cpp +++ b/sdk/storage/azure-storage-files-shares/src/share_options.cpp @@ -7,4 +7,223 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { const ShareAudience ShareAudience::DefaultAudience(_internal::StorageDefaultAudience); + namespace Models { + namespace { + RolePermissions ParseOctal(char c) + { + RolePermissions permissions = RolePermissions::None; + int permissionValue = c - '0'; + if (permissionValue < 0 || permissionValue > 7) + { + throw std::invalid_argument("Permission value must be >0 and <7."); + } + if ((permissionValue & 4) == 4) + { + permissions = permissions | RolePermissions::Read; + } + if ((permissionValue & 2) == 2) + { + permissions = permissions | RolePermissions::Write; + } + if ((permissionValue & 1) == 1) + { + permissions = permissions | RolePermissions::Execute; + } + return permissions; + } + + char ToOctal(RolePermissions permissions) + { + char c = '0'; + if ((permissions & RolePermissions::Read) == RolePermissions::Read) + { + c += 4; + } + if ((permissions & RolePermissions::Write) == RolePermissions::Write) + { + c += 2; + } + if ((permissions & RolePermissions::Execute) == RolePermissions::Execute) + { + c += 1; + } + return c; + } + + RolePermissions ParseSymbolic(std::string s, bool& setSticky) + { + if (s.length() != 3) + { + throw std::invalid_argument("Symbolic role permission format is invalid."); + } + + RolePermissions permissions = RolePermissions::None; + setSticky = false; + // Read character + if (s[0] == 'r') + { + permissions = permissions | RolePermissions ::Read; + } + else if (s[0] != '-') + { + throw std::invalid_argument( + "Invalid character in symbolic role permission: " + std::string(1, s[0])); + } + + // Write character + if (s[1] == 'w') + { + permissions = permissions | RolePermissions ::Write; + } + else if (s[1] != '-') + { + throw std::invalid_argument( + "Invalid character in symbolic role permission: " + std::string(1, s[1])); + } + + // Execute character + if (s[2] == 'x' || s[2] == 's' || s[2] == 't') + { + permissions = permissions | RolePermissions ::Execute; + if (s[2] == 's' || s[2] == 't') + { + setSticky = true; + } + } + if (s[2] == 'S' || s[2] == 'T') + { + setSticky = true; + } + + if (s[2] != 'x' && s[2] != 's' && s[2] != 'S' && s[2] != 't' && s[2] != 'T' && s[2] != '-') + { + throw std::invalid_argument( + "Invalid character in symbolic role permission: " + std::string(1, s[2])); + } + + return permissions; + } + + std::string ToSymbolic(RolePermissions permissions) + { + std::string s; + s.push_back((permissions & RolePermissions::Read) == RolePermissions::Read ? 'r' : '-'); + s.push_back((permissions & RolePermissions::Write) == RolePermissions::Write ? 'w' : '-'); + s.push_back( + (permissions & RolePermissions::Execute) == RolePermissions::Execute ? 'x' : '-'); + return s; + } + } // namespace + + std::string NfsFileMode::ToOctalFileMode() const + { + int higherOrderDigit = 0; + if (EffectiveUserIdentity) + { + higherOrderDigit |= 4; + } + if (EffectiveGroupIdentity) + { + higherOrderDigit |= 2; + } + if (StickyBit) + { + higherOrderDigit |= 1; + } + + std::string modeString = ""; + modeString.push_back(static_cast(higherOrderDigit + '0')); + modeString.push_back(ToOctal(Owner)); + modeString.push_back(ToOctal(Group)); + modeString.push_back(ToOctal(Other)); + return modeString; + } + + std::string NfsFileMode::ToSymbolicFileMode() const + { + std::string modeString = ""; + modeString.append(ToSymbolic(Owner)); + modeString.append(ToSymbolic(Group)); + modeString.append(ToSymbolic(Other)); + if (EffectiveUserIdentity) + { + if (modeString[2] == 'x') + { + modeString[2] = 's'; + } + else + { + modeString[2] = 'S'; + } + } + + if (EffectiveGroupIdentity) + { + if (modeString[5] == 'x') + { + modeString[5] = 's'; + } + else + { + modeString[5] = 'S'; + } + } + + if (StickyBit) + { + if (modeString[8] == 'x') + { + modeString[8] = 't'; + } + else + { + modeString[8] = 'T'; + } + } + return modeString; + } + + NfsFileMode NfsFileMode::ParseOctalFileMode(const std::string& modeString) + { + if (modeString.length() != 4) + { + throw std::invalid_argument("modeString must be a 4-digit octal number."); + } + NfsFileMode mode; + mode.Owner = ParseOctal(modeString[1]); + mode.Group = ParseOctal(modeString[2]); + mode.Other = ParseOctal(modeString[3]); + + int value = modeString[0] - '0'; + if ((value & 4) == 4) + { + mode.EffectiveUserIdentity = true; + } + + if ((value & 2) == 2) + { + mode.EffectiveGroupIdentity = true; + } + + if ((value & 1) == 1) + { + mode.StickyBit = true; + } + return mode; + } + + NfsFileMode NfsFileMode::ParseSymbolicFileMode(const std::string& modeString) + { + if (modeString.length() != 9) + { + throw std::invalid_argument("modeString must be a 9-character octal number."); + } + NfsFileMode mode; + mode.Owner = ParseSymbolic(modeString.substr(0, 3), mode.EffectiveUserIdentity); + mode.Group = ParseSymbolic(modeString.substr(3, 3), mode.EffectiveGroupIdentity); + mode.Other = ParseSymbolic(modeString.substr(6, 3), mode.StickyBit); + return mode; + } + } // namespace Models + }}}} // namespace Azure::Storage::Files::Shares diff --git a/sdk/storage/azure-storage-files-shares/src/share_responses.cpp b/sdk/storage/azure-storage-files-shares/src/share_responses.cpp index ac7f28f5f..23e064bd1 100644 --- a/sdk/storage/azure-storage-files-shares/src/share_responses.cpp +++ b/sdk/storage/azure-storage-files-shares/src/share_responses.cpp @@ -10,6 +10,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { namespace Models { + ShareFileHandleAccessRights::ShareFileHandleAccessRights(const std::string& value) { if (!value.empty()) diff --git a/sdk/storage/azure-storage-files-shares/swagger/README.md b/sdk/storage/azure-storage-files-shares/swagger/README.md index 699ed5d1a..df7211e58 100644 --- a/sdk/storage/azure-storage-files-shares/swagger/README.md +++ b/sdk/storage/azure-storage-files-shares/swagger/README.md @@ -9,7 +9,7 @@ package-name: azure-storage-files-shares namespace: Azure::Storage::Files::Shares output-folder: generated clear-output-folder: true -input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/storage/data-plane/Microsoft.FileStorage/stable/2025-01-05/file.json +input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/refs/heads/feature/storage/stg97base/specification/storage/data-plane/Microsoft.FileStorage/stable/2025-05-05/file.json ``` ## ModelFour Options @@ -36,19 +36,20 @@ directive: delete $["x-ms-code-generation-settings"]; ``` -### Delete Unused Query Parameters and Headers +### Delete Unused Query Parameters and Headers and global changes for Parameters and Headers ```yaml directive: - from: swagger-document where: $["x-ms-paths"].*.*.parameters transform: > - $ = $.filter(p => !(p["$ref"] && (p["$ref"].endsWith("#/parameters/Timeout") || p["$ref"].endsWith("#/parameters/ClientRequestId")))); + $ = $.filter(p => !(p["$ref"] && (p["$ref"].endsWith("#/parameters/Timeout") || p["$ref"].endsWith("#/parameters/ClientRequestId") + || p["$ref"].endsWith("#/parameters/StructuredBodyGet") || p["$ref"].endsWith("#/parameters/StructuredBodyPut") || p["$ref"].endsWith("#/parameters/StructuredContentLength")))); - from: swagger-document where: $["x-ms-paths"].*.*.responses.*.headers transform: > for (const h in $) { - if (["x-ms-client-request-id", "x-ms-request-id", "x-ms-version", "Date"].includes(h)) { + if (["x-ms-client-request-id", "x-ms-request-id", "x-ms-version", "Date", "x-ms-structured-body", "x-ms-structured-content-length"].includes(h)) { delete $[h]; } } @@ -79,12 +80,12 @@ directive: "name": "ApiVersion", "modelAsString": false }, - "enum": ["2025-01-05"] + "enum": ["2025-05-05"] }; - from: swagger-document where: $.parameters transform: > - $.ApiVersionParameter.enum[0] = "2025-01-05"; + $.ApiVersionParameter.enum[0] = "2025-05-05"; ``` ### Rename Operations @@ -167,6 +168,9 @@ directive: "File_ForceCloseHandles", "Directory_Rename", "File_Rename", + "File_CreateSymbolicLink", + "File_GetSymbolicLink", + "File_CreateHardLink", ]; for (const url in $["x-ms-paths"]) { for (const verb in $["x-ms-paths"][url]) { @@ -229,6 +233,7 @@ directive: $.FileLastWriteTimeMode["x-ms-enum"]["values"] = [{"value": "now", "name": "Now"},{"value": "preserve", "name": "Preserve"}]; $.FileRequestIntent["x-ms-enum"]["values"] = [{"value": "__placeHolder", "name": "__placeHolder"}, {"value": "backup", "name": "Backup"}]; $.FilePermissionFormat["enum"] = ["sddl", "binary"]; + $.FileAttributes["required"] = true; - from: swagger-document where: $.definitions transform: > @@ -658,11 +663,17 @@ directive: transform: > $.headers["x-ms-file-permission-key"]["x-ms-client-path"] = "SmbProperties.PermissionKey"; $.headers["x-ms-file-attributes"]["x-ms-client-path"] = "SmbProperties.Attributes"; + $.headers["x-ms-file-attributes"]["x-nullable"] = true; + $.headers["x-ms-file-attributes"]["x-ms-client-default"] = "None"; $.headers["x-ms-file-creation-time"]["x-ms-client-path"] = "SmbProperties.CreatedOn"; $.headers["x-ms-file-last-write-time"]["x-ms-client-path"] = "SmbProperties.LastWrittenOn"; $.headers["x-ms-file-change-time"]["x-ms-client-path"] = "SmbProperties.ChangedOn"; $.headers["x-ms-file-id"]["x-ms-client-path"] = "SmbProperties.FileId"; $.headers["x-ms-file-parent-id"]["x-ms-client-path"] = "SmbProperties.ParentFileId"; + $.headers["x-ms-mode"]["x-nullable"] = true; + $.headers["x-ms-owner"]["x-nullable"] = true; + $.headers["x-ms-group"]["x-nullable"] = true; + $.headers["x-ms-file-file-type"]["x-nullable"] = true; $.schema = { "type": "object", "x-ms-client-name": "CreateDirectoryResult", @@ -670,7 +681,8 @@ directive: "properties": { "Created": {"type": "boolean", "x-ms-client-default": true, "x-ms-xml": {"name": ""}}, "SmbProperties": {"$ref": "#/definitions/FileSmbProperties", "x-ms-xml": {"name": ""}} - } + }, + "x-namespace" : "_detail" }; ``` @@ -700,18 +712,25 @@ directive: transform: > $.headers["x-ms-file-permission-key"]["x-ms-client-path"] = "SmbProperties.PermissionKey"; $.headers["x-ms-file-attributes"]["x-ms-client-path"] = "SmbProperties.Attributes"; + $.headers["x-ms-file-attributes"]["x-nullable"] = true; + $.headers["x-ms-file-attributes"]["x-ms-client-default"] = "None"; $.headers["x-ms-file-creation-time"]["x-ms-client-path"] = "SmbProperties.CreatedOn"; $.headers["x-ms-file-last-write-time"]["x-ms-client-path"] = "SmbProperties.LastWrittenOn"; $.headers["x-ms-file-change-time"]["x-ms-client-path"] = "SmbProperties.ChangedOn"; $.headers["x-ms-file-id"]["x-ms-client-path"] = "SmbProperties.FileId"; $.headers["x-ms-file-parent-id"]["x-ms-client-path"] = "SmbProperties.ParentFileId"; + $.headers["x-ms-mode"]["x-nullable"] = true; + $.headers["x-ms-owner"]["x-nullable"] = true; + $.headers["x-ms-group"]["x-nullable"] = true; + $.headers["x-ms-file-file-type"]["x-nullable"] = true; $.schema = { "type": "object", "x-ms-client-name": "DirectoryProperties", "x-ms-sealed": false, "properties": { "SmbProperties": {"$ref": "#/definitions/FileSmbProperties", "x-ms-xml": {"name": ""}} - } + }, + "x-namespace" : "_detail" }; ``` @@ -724,18 +743,24 @@ directive: transform: > $.headers["x-ms-file-permission-key"]["x-ms-client-path"] = "SmbProperties.PermissionKey"; $.headers["x-ms-file-attributes"]["x-ms-client-path"] = "SmbProperties.Attributes"; + $.headers["x-ms-file-attributes"]["x-nullable"] = true; + $.headers["x-ms-file-attributes"]["x-ms-client-default"] = "None"; $.headers["x-ms-file-creation-time"]["x-ms-client-path"] = "SmbProperties.CreatedOn"; $.headers["x-ms-file-last-write-time"]["x-ms-client-path"] = "SmbProperties.LastWrittenOn"; $.headers["x-ms-file-change-time"]["x-ms-client-path"] = "SmbProperties.ChangedOn"; $.headers["x-ms-file-id"]["x-ms-client-path"] = "SmbProperties.FileId"; $.headers["x-ms-file-parent-id"]["x-ms-client-path"] = "SmbProperties.ParentFileId"; + $.headers["x-ms-mode"]["x-nullable"] = true; + $.headers["x-ms-owner"]["x-nullable"] = true; + $.headers["x-ms-group"]["x-nullable"] = true; $.schema = { "type": "object", "x-ms-client-name": "SetDirectoryPropertiesResult", "x-ms-sealed": false, "properties": { "SmbProperties": {"$ref": "#/definitions/FileSmbProperties", "x-ms-xml": {"name": ""}} - } + }, + "x-namespace" : "_detail" }; ``` @@ -748,11 +773,17 @@ directive: transform: > $.headers["x-ms-file-permission-key"]["x-ms-client-path"] = "SmbProperties.PermissionKey"; $.headers["x-ms-file-attributes"]["x-ms-client-path"] = "SmbProperties.Attributes"; + $.headers["x-ms-file-attributes"]["x-nullable"] = true; + $.headers["x-ms-file-attributes"]["x-ms-client-default"] = "None"; $.headers["x-ms-file-creation-time"]["x-ms-client-path"] = "SmbProperties.CreatedOn"; $.headers["x-ms-file-last-write-time"]["x-ms-client-path"] = "SmbProperties.LastWrittenOn"; $.headers["x-ms-file-change-time"]["x-ms-client-path"] = "SmbProperties.ChangedOn"; $.headers["x-ms-file-id"]["x-ms-client-path"] = "SmbProperties.FileId"; $.headers["x-ms-file-parent-id"]["x-ms-client-path"] = "SmbProperties.ParentFileId"; + $.headers["x-ms-mode"]["x-nullable"] = true; + $.headers["x-ms-owner"]["x-nullable"] = true; + $.headers["x-ms-group"]["x-nullable"] = true; + $.headers["x-ms-file-file-type"]["x-nullable"] = true; $.schema = { "type": "object", "x-ms-client-name": "CreateFileResult", @@ -760,7 +791,8 @@ directive: "properties": { "Created": {"type": "boolean", "x-ms-client-default": true, "x-ms-xml": {"name": ""}}, "SmbProperties": {"$ref": "#/definitions/FileSmbProperties", "x-ms-xml": {"name": ""}} - } + }, + "x-namespace" : "_detail" }; ``` @@ -773,6 +805,8 @@ directive: transform: > $.headers["x-ms-file-permission-key"]["x-ms-client-path"] = "SmbProperties.PermissionKey"; $.headers["x-ms-file-attributes"]["x-ms-client-path"] = "SmbProperties.Attributes"; + $.headers["x-ms-file-attributes"]["x-nullable"] = true; + $.headers["x-ms-file-attributes"]["x-ms-client-default"] = "None"; $.headers["x-ms-file-creation-time"]["x-ms-client-path"] = "SmbProperties.CreatedOn"; $.headers["x-ms-file-last-write-time"]["x-ms-client-path"] = "SmbProperties.LastWrittenOn"; $.headers["x-ms-file-change-time"]["x-ms-client-path"] = "SmbProperties.ChangedOn"; @@ -801,6 +835,11 @@ directive: $.headers["x-ms-lease-duration"]["x-nullable"] = true; $.headers["x-ms-lease-state"]["x-nullable"] = true; $.headers["x-ms-lease-status"]["x-nullable"] = true; + $.headers["x-ms-mode"]["x-nullable"] = true; + $.headers["x-ms-owner"]["x-nullable"] = true; + $.headers["x-ms-group"]["x-nullable"] = true; + $.headers["x-ms-file-file-type"]["x-nullable"] = true; + $.headers["x-ms-link-count"]["x-nullable"] = true; delete $.headers["x-ms-type"]; $.schema = { "type": "object", @@ -809,7 +848,8 @@ directive: "properties": { "SmbProperties": {"$ref": "#/definitions/FileSmbProperties", "x-ms-xml": {"name": ""}}, "HttpHeaders": {"$ref": "#/definitions/FileHttpHeaders", "x-ms-xml": {"name": ""}} - } + }, + "x-namespace" : "_detail" }; ``` @@ -822,18 +862,25 @@ directive: transform: > $.headers["x-ms-file-permission-key"]["x-ms-client-path"] = "SmbProperties.PermissionKey"; $.headers["x-ms-file-attributes"]["x-ms-client-path"] = "SmbProperties.Attributes"; + $.headers["x-ms-file-attributes"]["x-nullable"] = true; + $.headers["x-ms-file-attributes"]["x-ms-client-default"] = "None"; $.headers["x-ms-file-creation-time"]["x-ms-client-path"] = "SmbProperties.CreatedOn"; $.headers["x-ms-file-last-write-time"]["x-ms-client-path"] = "SmbProperties.LastWrittenOn"; $.headers["x-ms-file-change-time"]["x-ms-client-path"] = "SmbProperties.ChangedOn"; $.headers["x-ms-file-id"]["x-ms-client-path"] = "SmbProperties.FileId"; $.headers["x-ms-file-parent-id"]["x-ms-client-path"] = "SmbProperties.ParentFileId"; + $.headers["x-ms-mode"]["x-nullable"] = true; + $.headers["x-ms-owner"]["x-nullable"] = true; + $.headers["x-ms-group"]["x-nullable"] = true; + $.headers["x-ms-link-count"]["x-nullable"] = true; $.schema = { "type": "object", "x-ms-client-name": "SetFilePropertiesResult", "x-ms-sealed": false, "properties": { "SmbProperties": {"$ref": "#/definitions/FileSmbProperties", "x-ms-xml": {"name": ""}} - } + }, + "x-namespace" : "_detail" }; ``` @@ -861,8 +908,13 @@ directive: "SmbProperties": {"$ref": "#/definitions/FileSmbProperties", "x-ms-xml": {"name": ""}}, "LeaseDuration": {"$ref": "#/definitions/LeaseDuration"}, "LeaseState": {"$ref": "#/definitions/LeaseState"}, - "LeaseStatus": {"$ref": "#/definitions/LeaseStatus"} - } + "LeaseStatus": {"$ref": "#/definitions/LeaseStatus"}, + "FileMode": {"type": "string", "x-nullable": true}, + "Owner": {"type": "string", "x-nullable": true}, + "Group": {"type": "string", "x-nullable": true}, + "LinkCount": {"type": "integer", "format": "int64", "x-nullable": true}, + }, + "x-namespace" : "_detail" }; $.DownloadFileResult = { "type": "object", @@ -874,7 +926,8 @@ directive: "TransactionalContentHash": {"$ref": "#/definitions/ContentHash", "x-nullable": true, "x-ms-xml": {"name": ""}}, "HttpHeaders": {"$ref": "#/definitions/FileHttpHeaders", "x-ms-xml": {"name": ""}}, "Details": {"$ref": "#/definitions/DownloadFileDetails", "x-ms-xml": {"name": ""}} - } + }, + "x-namespace" : "_detail" }; - from: swagger-document where: $["x-ms-paths"]["/{shareName}/{directory}/{fileName}"].get.responses @@ -905,11 +958,17 @@ directive: $[status_code].headers["x-ms-server-encrypted"]["x-ms-client-path"] = "Details.IsServerEncrypted"; $[status_code].headers["x-ms-file-permission-key"]["x-ms-client-path"] = "Details.SmbProperties.PermissionKey"; $[status_code].headers["x-ms-file-attributes"]["x-ms-client-path"] = "Details.SmbProperties.Attributes"; + $[status_code].headers["x-ms-file-attributes"]["x-nullable"] = true; + $[status_code].headers["x-ms-file-attributes"]["x-ms-client-default"] = "None"; $[status_code].headers["x-ms-file-creation-time"]["x-ms-client-path"] = "Details.SmbProperties.CreatedOn"; $[status_code].headers["x-ms-file-last-write-time"]["x-ms-client-path"] = "Details.SmbProperties.LastWrittenOn"; $[status_code].headers["x-ms-file-change-time"]["x-ms-client-path"] = "Details.SmbProperties.ChangedOn"; $[status_code].headers["x-ms-file-id"]["x-ms-client-path"] = "Details.SmbProperties.FileId"; $[status_code].headers["x-ms-file-parent-id"]["x-ms-client-path"] = "Details.SmbProperties.ParentFileId"; + $[status_code].headers["x-ms-mode"]["x-ms-client-path"] = "Details.FileMode"; + $[status_code].headers["x-ms-owner"]["x-ms-client-path"] = "Details.Owner"; + $[status_code].headers["x-ms-group"]["x-ms-client-path"] = "Details.Group"; + $[status_code].headers["x-ms-link-count"]["x-ms-client-path"] = "Details.LinkCount"; delete $[status_code].headers["Accept-Ranges"]; delete $[status_code].headers["Content-Length"]; delete $[status_code].headers["Content-Range"]; @@ -928,6 +987,7 @@ directive: - from: swagger-document where: $["x-ms-paths"]["/{shareName}/{directory}/{fileName}"].delete.responses["202"] transform: > + $.headers["x-ms-link-count"]["x-nullable"] = true; $.schema = { "type": "object", "x-ms-client-name": "DeleteFileResult", @@ -1046,6 +1106,54 @@ directive: $["x-ms-file-change-time"].format = "date-time"; ``` +### CreateFileSymbolicLink + +```yaml +directive: + - from: swagger-document + where: $["x-ms-paths"]["/{shareName}/{directory}/{fileName}?restype=symboliclink"].put.responses["201"] + transform: > + $.headers["x-ms-file-creation-time"]["x-ms-client-path"] = "SmbProperties.CreatedOn"; + $.headers["x-ms-file-last-write-time"]["x-ms-client-path"] = "SmbProperties.LastWrittenOn"; + $.headers["x-ms-file-change-time"]["x-ms-client-path"] = "SmbProperties.ChangedOn"; + $.headers["x-ms-file-id"]["x-ms-client-path"] = "SmbProperties.FileId"; + $.headers["x-ms-file-parent-id"]["x-ms-client-path"] = "SmbProperties.ParentFileId"; + $.schema = { + "type": "object", + "x-ms-client-name": "CreateFileSymbolicLinkResult", + "x-ms-sealed": false, + "properties": { + "Created": {"type": "boolean", "x-ms-client-default": true, "x-ms-xml": {"name": ""}}, + "SmbProperties": {"$ref": "#/definitions/FileSmbProperties", "x-ms-xml": {"name": ""}} + }, + "x-namespace" : "_detail" + }; +``` + +### CreateFileHardLink + +```yaml +directive: + - from: swagger-document + where: $["x-ms-paths"]["/{shareName}/{directory}/{fileName}?restype=hardlink"].put.responses["201"] + transform: > + $.headers["x-ms-file-creation-time"]["x-ms-client-path"] = "SmbProperties.CreatedOn"; + $.headers["x-ms-file-last-write-time"]["x-ms-client-path"] = "SmbProperties.LastWrittenOn"; + $.headers["x-ms-file-change-time"]["x-ms-client-path"] = "SmbProperties.ChangedOn"; + $.headers["x-ms-file-id"]["x-ms-client-path"] = "SmbProperties.FileId"; + $.headers["x-ms-file-parent-id"]["x-ms-client-path"] = "SmbProperties.ParentFileId"; + $.schema = { + "type": "object", + "x-ms-client-name": "CreateFileHardLinkResult", + "x-ms-sealed": false, + "properties": { + "Created": {"type": "boolean", "x-ms-client-default": true, "x-ms-xml": {"name": ""}}, + "SmbProperties": {"$ref": "#/definitions/FileSmbProperties", "x-ms-xml": {"name": ""}} + }, + "x-namespace" : "_detail" + }; +``` + ### Description ```yaml diff --git a/sdk/storage/azure-storage-files-shares/test/ut/CMakeLists.txt b/sdk/storage/azure-storage-files-shares/test/ut/CMakeLists.txt index 81bb8c0d9..2b5dab237 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/CMakeLists.txt +++ b/sdk/storage/azure-storage-files-shares/test/ut/CMakeLists.txt @@ -27,6 +27,7 @@ add_executable ( share_sas_test.cpp share_service_client_test.cpp share_service_client_test.hpp + share_utility_test.cpp simplified_header_test.cpp # Include shared test source code ${CMAKE_CURRENT_SOURCE_DIR}/../../../azure-storage-common/test/ut/test_base.cpp diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_directory_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/ut/share_directory_client_test.cpp index ad49b34d8..7ceb05820 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/share_directory_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_directory_client_test.cpp @@ -1377,4 +1377,75 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_EQ(binaryPermission, permission); } } + + TEST_F(FileShareDirectoryClientTest, PremiumNfsProperties_PLAYBACKONLY_) + { + auto shareServiceClient = *m_premiumShareServiceClient; + + auto shareName = LowercaseRandomString(); + auto shareClient = GetPremiumShareClientForTest(shareName); + Files::Shares::CreateShareOptions shareOptions; + shareOptions.EnabledProtocols = Files::Shares::Models::ShareProtocols::Nfs; + EXPECT_NO_THROW(shareClient.Create(shareOptions)); + + auto directoryName = LowercaseRandomString(); + auto directoryClient + = shareClient.GetRootDirectoryClient().GetSubdirectoryClient(directoryName); + + std::string octalMode = "0777"; + + // Create a file + Files::Shares::CreateDirectoryOptions createOptions; + createOptions.PosixProperties.FileMode + = Files::Shares::Models::NfsFileMode::ParseOctalFileMode(octalMode); + createOptions.PosixProperties.Group = "123"; + createOptions.PosixProperties.Owner = "456"; + createOptions.PosixProperties.NfsFileType = Files::Shares::Models::NfsFileType::Regular; + Files::Shares::Models::CreateDirectoryResult createResult; + EXPECT_NO_THROW(createResult = directoryClient.Create(createOptions).Value); + EXPECT_TRUE(createResult.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(createResult.PosixProperties.FileMode.Value().ToOctalFileMode(), octalMode); + EXPECT_TRUE(createResult.PosixProperties.Group.HasValue()); + EXPECT_EQ( + createResult.PosixProperties.Group.Value(), createOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(createResult.PosixProperties.FileMode.HasValue()); + EXPECT_EQ( + createResult.PosixProperties.Owner.Value(), createOptions.PosixProperties.Owner.Value()); + EXPECT_TRUE(createResult.PosixProperties.NfsFileType.HasValue()); + EXPECT_EQ( + createResult.PosixProperties.NfsFileType.Value(), + Files::Shares::Models::NfsFileType::Directory); + + // Set Properties + Files::Shares::SetDirectoryPropertiesOptions setOptions; + setOptions.PosixProperties.FileMode + = Files::Shares::Models::NfsFileMode::ParseOctalFileMode("0707"); + setOptions.PosixProperties.Group = "123"; + setOptions.PosixProperties.Owner = "456"; + Files::Shares::Models::SetDirectoryPropertiesResult setResult; + EXPECT_NO_THROW( + setResult + = directoryClient.SetProperties(Files::Shares::Models::FileSmbProperties(), setOptions) + .Value); + EXPECT_TRUE(setResult.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(setResult.PosixProperties.FileMode.Value().ToOctalFileMode(), "0707"); + EXPECT_TRUE(setResult.PosixProperties.Group.HasValue()); + EXPECT_EQ(setResult.PosixProperties.Group.Value(), setOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(setResult.PosixProperties.Owner.HasValue()); + EXPECT_EQ(setResult.PosixProperties.Owner.Value(), setOptions.PosixProperties.Owner.Value()); + + // Get Properties + Files::Shares::Models::DirectoryProperties properties; + EXPECT_NO_THROW(properties = directoryClient.GetProperties().Value); + EXPECT_TRUE(properties.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(properties.PosixProperties.FileMode.Value().ToOctalFileMode(), "0707"); + EXPECT_TRUE(properties.PosixProperties.Group.HasValue()); + EXPECT_EQ(properties.PosixProperties.Group.Value(), setOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(properties.PosixProperties.Owner.HasValue()); + EXPECT_EQ(properties.PosixProperties.Owner.Value(), setOptions.PosixProperties.Owner.Value()); + EXPECT_TRUE(properties.PosixProperties.NfsFileType.HasValue()); + EXPECT_EQ( + properties.PosixProperties.NfsFileType.Value(), + Files::Shares::Models::NfsFileType::Directory); + } }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_file_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/ut/share_file_client_test.cpp index 85f994fcc..00e250010 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/share_file_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_file_client_test.cpp @@ -817,6 +817,128 @@ namespace Azure { namespace Storage { namespace Test { } } + TEST_F(FileShareFileClientTest, CopyWithSmbPropertyFlags) + { + auto sddlPermission + = "O:S-1-5-21-2127521184-1604012920-1887927527-21560751G:S-1-5-21-2127521184-1604012920-" + "1887927527-513D:(A;;FA;;;SY)(A;;FA;;;BA)(A;;0x1200a9;;;S-1-5-21-397955417-626881126-" + "188441444-3053964)"; + + Files::Shares::CreateFileOptions createOptions; + createOptions.SmbProperties.Attributes = Files::Shares::Models::FileAttributes::System + | Files::Shares::Models::FileAttributes::NotContentIndexed; + auto fileClient = m_shareClient->GetRootDirectoryClient().GetFileClient(RandomString() + "1"); + fileClient.Create(128, createOptions); + auto sourceProperties = fileClient.GetProperties().Value; + + auto fileProperties = m_fileClient->GetProperties().Value; + + // None scenario + { + Files::Shares::StartFileCopyOptions options; + options.SmbPropertiesToCopy = Files::Shares::CopyableFileSmbPropertyFlags::None; + options.SmbProperties.Attributes = Files::Shares::Models::FileAttributes::ReadOnly; + options.SmbProperties.CreatedOn = fileProperties.SmbProperties.CreatedOn; + options.SmbProperties.ChangedOn = fileProperties.SmbProperties.ChangedOn; + options.SmbProperties.LastWrittenOn = fileProperties.SmbProperties.LastWrittenOn; + options.PermissionCopyMode = Files::Shares::Models::PermissionCopyMode::Override; + options.Permission = sddlPermission; + + auto destFileClient + = m_shareClient->GetRootDirectoryClient().GetFileClient(RandomString() + "2"); + auto copyOperation = destFileClient.StartCopy(fileClient.GetUrl(), options); + EXPECT_EQ( + copyOperation.GetRawResponse().GetStatusCode(), + Azure::Core::Http::HttpStatusCode::Accepted); + auto destProperties = copyOperation.PollUntilDone(std::chrono::milliseconds(1000)).Value; + EXPECT_EQ(destProperties.CopyStatus.Value(), Files::Shares::Models::CopyStatus::Success); + destProperties = destFileClient.GetProperties().Value; + EXPECT_EQ( + destProperties.SmbProperties.Attributes, + options.SmbProperties.Attributes | Files::Shares::Models::FileAttributes::Archive); + EXPECT_EQ( + destProperties.SmbProperties.CreatedOn.Value(), options.SmbProperties.CreatedOn.Value()); + EXPECT_EQ( + destProperties.SmbProperties.ChangedOn.Value(), options.SmbProperties.ChangedOn.Value()); + EXPECT_EQ( + destProperties.SmbProperties.LastWrittenOn.Value(), + options.SmbProperties.LastWrittenOn.Value()); + auto destPermissionKey = destProperties.SmbProperties.PermissionKey.Value(); + std::string destPermission = m_shareClient->GetPermission(destPermissionKey).Value; + EXPECT_EQ(destPermission, sddlPermission); + } + + // Source scenario + { + Files::Shares::StartFileCopyOptions options; + options.SmbPropertiesToCopy = Files::Shares::CopyableFileSmbPropertyFlags::All; + options.SmbProperties.Attributes = Files::Shares::Models::FileAttributes::ReadOnly; + options.SmbProperties.CreatedOn = fileProperties.SmbProperties.CreatedOn; + options.SmbProperties.ChangedOn = fileProperties.SmbProperties.ChangedOn; + options.SmbProperties.LastWrittenOn = fileProperties.SmbProperties.LastWrittenOn; + options.PermissionCopyMode = Files::Shares::Models::PermissionCopyMode::Override; + options.SmbProperties.PermissionKey = ""; + + auto destFileClient + = m_shareClient->GetRootDirectoryClient().GetFileClient(RandomString() + "2"); + auto copyOperation = destFileClient.StartCopy(fileClient.GetUrl(), options); + EXPECT_EQ( + copyOperation.GetRawResponse().GetStatusCode(), + Azure::Core::Http::HttpStatusCode::Accepted); + auto destProperties = copyOperation.PollUntilDone(std::chrono::milliseconds(1000)).Value; + EXPECT_EQ(destProperties.CopyStatus.Value(), Files::Shares::Models::CopyStatus::Success); + destProperties = destFileClient.GetProperties().Value; + EXPECT_EQ(destProperties.SmbProperties.Attributes, sourceProperties.SmbProperties.Attributes); + EXPECT_EQ( + destProperties.SmbProperties.CreatedOn.Value(), + sourceProperties.SmbProperties.CreatedOn.Value()); + EXPECT_EQ( + destProperties.SmbProperties.ChangedOn.Value(), + sourceProperties.SmbProperties.ChangedOn.Value()); + EXPECT_EQ( + destProperties.SmbProperties.LastWrittenOn.Value(), + sourceProperties.SmbProperties.LastWrittenOn.Value()); + EXPECT_EQ( + destProperties.SmbProperties.PermissionKey.Value(), + sourceProperties.SmbProperties.PermissionKey.Value()); + } + + // Part Source Scenario + { + + Files::Shares::StartFileCopyOptions options; + options.SmbPropertiesToCopy = Files::Shares::CopyableFileSmbPropertyFlags::FileAttributes + | Files::Shares::CopyableFileSmbPropertyFlags::Permission; + options.SmbProperties.Attributes = Files::Shares::Models::FileAttributes::ReadOnly; + options.SmbProperties.CreatedOn = fileProperties.SmbProperties.CreatedOn; + options.SmbProperties.ChangedOn = fileProperties.SmbProperties.ChangedOn; + options.SmbProperties.LastWrittenOn = fileProperties.SmbProperties.LastWrittenOn; + options.PermissionCopyMode = Files::Shares::Models::PermissionCopyMode::Override; + options.SmbProperties.PermissionKey = ""; + + auto destFileClient + = m_shareClient->GetRootDirectoryClient().GetFileClient(RandomString() + "2"); + auto copyOperation = destFileClient.StartCopy(fileClient.GetUrl(), options); + EXPECT_EQ( + copyOperation.GetRawResponse().GetStatusCode(), + Azure::Core::Http::HttpStatusCode::Accepted); + auto destProperties = copyOperation.PollUntilDone(std::chrono::milliseconds(1000)).Value; + EXPECT_EQ(destProperties.CopyStatus.Value(), Files::Shares::Models::CopyStatus::Success); + destProperties = destFileClient.GetProperties().Value; + EXPECT_EQ(destProperties.SmbProperties.Attributes, sourceProperties.SmbProperties.Attributes); + EXPECT_EQ( + destProperties.SmbProperties.CreatedOn.Value(), options.SmbProperties.CreatedOn.Value()); + EXPECT_EQ( + destProperties.SmbProperties.ChangedOn.Value(), options.SmbProperties.ChangedOn.Value()); + EXPECT_EQ( + destProperties.SmbProperties.LastWrittenOn.Value(), + options.SmbProperties.LastWrittenOn.Value()); + EXPECT_EQ( + destProperties.SmbProperties.PermissionKey.Value(), + sourceProperties.SmbProperties.PermissionKey.Value()); + } + } + TEST_F(FileShareFileClientTest, RangeRelated) { size_t fileSize = 1024 * 3; @@ -2089,4 +2211,352 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_EQ(binaryPermission, permission); } } + + TEST_F(FileShareFileClientTest, PremiumNfsProperties_PLAYBACKONLY_) + { + auto shareServiceClient = *m_premiumShareServiceClient; + + auto shareName = LowercaseRandomString(); + auto shareClient = GetPremiumShareClientForTest(shareName); + Files::Shares::CreateShareOptions shareOptions; + shareOptions.EnabledProtocols = Files::Shares::Models::ShareProtocols::Nfs; + EXPECT_NO_THROW(shareClient.Create(shareOptions)); + auto otherProperties = m_fileClient->GetProperties().Value; + + auto fileName = LowercaseRandomString(); + auto fileClient = shareClient.GetRootDirectoryClient().GetFileClient(fileName); + + std::string octalMode = "0777"; + + // Create a file + Files::Shares::CreateFileOptions createOptions; + createOptions.PosixProperties.FileMode + = Files::Shares::Models::NfsFileMode::ParseOctalFileMode(octalMode); + createOptions.PosixProperties.Group = "123"; + createOptions.PosixProperties.Owner = "456"; + createOptions.PosixProperties.NfsFileType = Files::Shares::Models::NfsFileType::Regular; + Files::Shares::Models::CreateFileResult createResult; + EXPECT_NO_THROW(createResult = fileClient.Create(256, createOptions).Value); + EXPECT_TRUE(createResult.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(createResult.PosixProperties.FileMode.Value().ToOctalFileMode(), octalMode); + EXPECT_TRUE(createResult.PosixProperties.Group.HasValue()); + EXPECT_EQ( + createResult.PosixProperties.Group.Value(), createOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(createResult.PosixProperties.FileMode.HasValue()); + EXPECT_EQ( + createResult.PosixProperties.Owner.Value(), createOptions.PosixProperties.Owner.Value()); + EXPECT_TRUE(createResult.PosixProperties.NfsFileType.HasValue()); + EXPECT_EQ( + createResult.PosixProperties.NfsFileType.Value(), + Files::Shares::Models::NfsFileType::Regular); + + // Set Properties + Files::Shares::SetFilePropertiesOptions setOptions; + setOptions.PosixProperties.FileMode + = Files::Shares::Models::NfsFileMode::ParseOctalFileMode("0707"); + setOptions.PosixProperties.Group = "123"; + setOptions.PosixProperties.Owner = "456"; + Files::Shares::Models::SetFilePropertiesResult setResult; + EXPECT_NO_THROW( + setResult = fileClient + .SetProperties( + Files::Shares::Models::FileHttpHeaders(), + Files::Shares::Models::FileSmbProperties(), + setOptions) + .Value); + EXPECT_TRUE(setResult.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(setResult.PosixProperties.FileMode.Value().ToOctalFileMode(), "0707"); + EXPECT_TRUE(setResult.PosixProperties.Group.HasValue()); + EXPECT_EQ(setResult.PosixProperties.Group.Value(), setOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(setResult.PosixProperties.Owner.HasValue()); + EXPECT_EQ(setResult.PosixProperties.Owner.Value(), setOptions.PosixProperties.Owner.Value()); + EXPECT_TRUE(setResult.PosixProperties.LinkCount.HasValue()); + + // Get Properties + Files::Shares::Models::FileProperties properties; + EXPECT_NO_THROW(properties = fileClient.GetProperties().Value); + EXPECT_TRUE(properties.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(properties.PosixProperties.FileMode.Value().ToOctalFileMode(), "0707"); + EXPECT_TRUE(properties.PosixProperties.Group.HasValue()); + EXPECT_EQ(properties.PosixProperties.Group.Value(), setOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(properties.PosixProperties.Owner.HasValue()); + EXPECT_EQ(properties.PosixProperties.Owner.Value(), setOptions.PosixProperties.Owner.Value()); + EXPECT_TRUE(properties.PosixProperties.LinkCount.HasValue()); + EXPECT_TRUE(properties.PosixProperties.NfsFileType.HasValue()); + EXPECT_EQ( + properties.PosixProperties.NfsFileType.Value(), + Files::Shares::Models::NfsFileType::Regular); + + // Download + Files::Shares::Models::DownloadFileResult downloadResult; + EXPECT_NO_THROW(downloadResult = fileClient.Download().Value); + EXPECT_TRUE(downloadResult.Details.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(downloadResult.Details.PosixProperties.FileMode.Value().ToOctalFileMode(), "0707"); + EXPECT_TRUE(downloadResult.Details.PosixProperties.Group.HasValue()); + EXPECT_EQ( + downloadResult.Details.PosixProperties.Group.Value(), + setOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(downloadResult.Details.PosixProperties.Owner.HasValue()); + EXPECT_EQ( + downloadResult.Details.PosixProperties.Owner.Value(), + setOptions.PosixProperties.Owner.Value()); + EXPECT_TRUE(downloadResult.Details.PosixProperties.LinkCount.HasValue()); + + // DownloadTo + Files::Shares::Models::DownloadFileToResult downloadToResult; + std::string tempFilename = RandomString() + "1"; + EXPECT_NO_THROW(downloadToResult = fileClient.DownloadTo(tempFilename).Value); + EXPECT_TRUE(downloadToResult.Details.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(downloadToResult.Details.PosixProperties.FileMode.Value().ToOctalFileMode(), "0707"); + EXPECT_TRUE(downloadToResult.Details.PosixProperties.Group.HasValue()); + EXPECT_EQ( + downloadToResult.Details.PosixProperties.Group.Value(), + setOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(downloadToResult.Details.PosixProperties.Owner.HasValue()); + EXPECT_EQ( + downloadToResult.Details.PosixProperties.Owner.Value(), + setOptions.PosixProperties.Owner.Value()); + EXPECT_TRUE(downloadToResult.Details.PosixProperties.LinkCount.HasValue()); + DeleteFile(tempFilename); + + std::vector buff(256); + EXPECT_NO_THROW(downloadToResult = fileClient.DownloadTo(buff.data(), 256).Value); + EXPECT_TRUE(downloadToResult.Details.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(downloadToResult.Details.PosixProperties.FileMode.Value().ToOctalFileMode(), "0707"); + EXPECT_TRUE(downloadToResult.Details.PosixProperties.Group.HasValue()); + EXPECT_EQ( + downloadToResult.Details.PosixProperties.Group.Value(), + setOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(downloadToResult.Details.PosixProperties.Owner.HasValue()); + EXPECT_EQ( + downloadToResult.Details.PosixProperties.Owner.Value(), + setOptions.PosixProperties.Owner.Value()); + EXPECT_TRUE(downloadToResult.Details.PosixProperties.LinkCount.HasValue()); + + // Create HardLink + auto hardLinkClient + = shareClient.GetRootDirectoryClient().GetFileClient(LowercaseRandomString()); + Files::Shares::CreateHardLinkOptions createHardLinkOptions; + Files::Shares::Models::CreateFileHardLinkResult createFileHardLinkResult; + EXPECT_NO_THROW( + createFileHardLinkResult + = hardLinkClient.CreateHardLink(fileName, createHardLinkOptions).Value); + EXPECT_TRUE(createFileHardLinkResult.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(createFileHardLinkResult.PosixProperties.FileMode.Value().ToOctalFileMode(), "0707"); + EXPECT_TRUE(createFileHardLinkResult.PosixProperties.Group.HasValue()); + EXPECT_EQ( + createFileHardLinkResult.PosixProperties.Group.Value(), + createOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(createFileHardLinkResult.PosixProperties.FileMode.HasValue()); + EXPECT_EQ( + createFileHardLinkResult.PosixProperties.Owner.Value(), + createOptions.PosixProperties.Owner.Value()); + EXPECT_TRUE(createFileHardLinkResult.PosixProperties.NfsFileType.HasValue()); + EXPECT_EQ( + createFileHardLinkResult.PosixProperties.NfsFileType.Value(), + Files::Shares::Models::NfsFileType::Regular); + EXPECT_TRUE(createFileHardLinkResult.SmbProperties.CreatedOn.HasValue()); + EXPECT_TRUE(createFileHardLinkResult.SmbProperties.LastWrittenOn.HasValue()); + EXPECT_TRUE(createFileHardLinkResult.SmbProperties.ChangedOn.HasValue()); + EXPECT_TRUE(!createFileHardLinkResult.SmbProperties.FileId.empty()); + EXPECT_TRUE(!createFileHardLinkResult.SmbProperties.ParentFileId.empty()); + EXPECT_TRUE(createFileHardLinkResult.ETag.HasValue()); + + // Delete + Files::Shares::Models::DeleteFileResult deleteResult; + EXPECT_NO_THROW(deleteResult = fileClient.Delete().Value); + EXPECT_TRUE(deleteResult.LinkCount.HasValue()); + + // Upload + size_t fileSize = 512; + std::vector content(RandomBuffer(fileSize)); + auto memBodyStream = Core::IO::MemoryBodyStream(content); + tempFilename = "file" + RandomString(); + WriteFile(tempFilename, content); + + Files::Shares::UploadFileFromOptions uploadOptions; + uploadOptions.PosixProperties.FileMode + = Files::Shares::Models::NfsFileMode::ParseOctalFileMode(octalMode); + uploadOptions.PosixProperties.Group = "123"; + uploadOptions.PosixProperties.Owner = "456"; + uploadOptions.PosixProperties.NfsFileType = Files::Shares::Models::NfsFileType::Regular; + + // From buffer + fileClient = shareClient.GetRootDirectoryClient().GetFileClient(LowercaseRandomString()); + EXPECT_NO_THROW(fileClient.UploadFrom(content.data(), fileSize, uploadOptions)); + properties = fileClient.GetProperties().Value; + EXPECT_TRUE(properties.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(properties.PosixProperties.FileMode.Value().ToOctalFileMode(), octalMode); + EXPECT_TRUE(properties.PosixProperties.Group.HasValue()); + EXPECT_EQ( + properties.PosixProperties.Group.Value(), uploadOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(properties.PosixProperties.Owner.HasValue()); + EXPECT_EQ( + properties.PosixProperties.Owner.Value(), uploadOptions.PosixProperties.Owner.Value()); + EXPECT_TRUE(properties.PosixProperties.LinkCount.HasValue()); + EXPECT_TRUE(properties.PosixProperties.NfsFileType.HasValue()); + EXPECT_EQ( + properties.PosixProperties.NfsFileType.Value(), + Files::Shares::Models::NfsFileType::Regular); + + // From file + fileClient = shareClient.GetRootDirectoryClient().GetFileClient(LowercaseRandomString()); + EXPECT_NO_THROW(fileClient.UploadFrom(tempFilename, uploadOptions)); + properties = fileClient.GetProperties().Value; + EXPECT_TRUE(properties.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(properties.PosixProperties.FileMode.Value().ToOctalFileMode(), octalMode); + EXPECT_TRUE(properties.PosixProperties.Group.HasValue()); + EXPECT_EQ( + properties.PosixProperties.Group.Value(), uploadOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(properties.PosixProperties.Owner.HasValue()); + EXPECT_EQ( + properties.PosixProperties.Owner.Value(), uploadOptions.PosixProperties.Owner.Value()); + EXPECT_TRUE(properties.PosixProperties.LinkCount.HasValue()); + EXPECT_TRUE(properties.PosixProperties.NfsFileType.HasValue()); + EXPECT_EQ( + properties.PosixProperties.NfsFileType.Value(), + Files::Shares::Models::NfsFileType::Regular); + } + + TEST_F(FileShareFileClientTest, PremiumNfsPropertiesForCopy_PLAYBACKONLY_) + { + auto shareServiceClient = *m_premiumShareServiceClient; + + auto shareName = LowercaseRandomString(); + auto shareClient = GetPremiumShareClientForTest(shareName); + Files::Shares::CreateShareOptions shareOptions; + shareOptions.EnabledProtocols = Files::Shares::Models::ShareProtocols::Nfs; + EXPECT_NO_THROW(shareClient.Create(shareOptions)); + + auto sourceName = LowercaseRandomString(); + auto sourceClient = shareClient.GetRootDirectoryClient().GetFileClient(sourceName); + + std::string sourceMode = "0777"; + + // Create a file + Files::Shares::CreateFileOptions createOptions; + createOptions.PosixProperties.FileMode + = Files::Shares::Models::NfsFileMode::ParseOctalFileMode(sourceMode); + createOptions.PosixProperties.Group = "123"; + createOptions.PosixProperties.Owner = "456"; + createOptions.PosixProperties.NfsFileType = Files::Shares::Models::NfsFileType::Regular; + EXPECT_NO_THROW(sourceClient.Create(256, createOptions)); + + // Copy with override + auto destFileClient + = shareClient.GetRootDirectoryClient().GetFileClient(LowercaseRandomString()); + Files::Shares::StartFileCopyOptions copyOptions; + copyOptions.SmbPropertiesToCopy = Files::Shares::CopyableFileSmbPropertyFlags::None; + copyOptions.PosixProperties.FileMode + = Files::Shares::Models::NfsFileMode::ParseOctalFileMode("0757"); + copyOptions.ModeCopyMode = Files::Shares::Models::ModeCopyMode::Override; + copyOptions.PosixProperties.Group = "888"; + copyOptions.PosixProperties.Owner = "999"; + copyOptions.OwnerCopyMode = Files::Shares::Models::OwnerCopyMode::Override; + auto copyOperation = destFileClient.StartCopy(sourceClient.GetUrl(), copyOptions); + EXPECT_EQ( + copyOperation.GetRawResponse().GetStatusCode(), + Azure::Core::Http::HttpStatusCode::Accepted); + auto properties = copyOperation.PollUntilDone(std::chrono::milliseconds(1000)).Value; + EXPECT_EQ(properties.CopyStatus.Value(), Files::Shares::Models::CopyStatus::Success); + EXPECT_TRUE(properties.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(properties.PosixProperties.FileMode.Value().ToOctalFileMode(), "0757"); + EXPECT_TRUE(properties.PosixProperties.Group.HasValue()); + EXPECT_EQ(properties.PosixProperties.Group.Value(), copyOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(properties.PosixProperties.Owner.HasValue()); + EXPECT_EQ(properties.PosixProperties.Owner.Value(), copyOptions.PosixProperties.Owner.Value()); + + // Copy with source + copyOptions = Files::Shares::StartFileCopyOptions(); + copyOptions.SmbPropertiesToCopy = Files::Shares::CopyableFileSmbPropertyFlags::None; + copyOptions.ModeCopyMode = Files::Shares::Models::ModeCopyMode::Source; + copyOptions.OwnerCopyMode = Files::Shares::Models::OwnerCopyMode::Source; + destFileClient = shareClient.GetRootDirectoryClient().GetFileClient(LowercaseRandomString()); + copyOperation = destFileClient.StartCopy(sourceClient.GetUrl(), copyOptions); + EXPECT_EQ( + copyOperation.GetRawResponse().GetStatusCode(), + Azure::Core::Http::HttpStatusCode::Accepted); + properties = copyOperation.PollUntilDone(std::chrono::milliseconds(1000)).Value; + EXPECT_EQ(properties.CopyStatus.Value(), Files::Shares::Models::CopyStatus::Success); + EXPECT_TRUE(properties.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(properties.PosixProperties.FileMode.Value().ToOctalFileMode(), sourceMode); + EXPECT_TRUE(properties.PosixProperties.Group.HasValue()); + EXPECT_EQ( + properties.PosixProperties.Group.Value(), createOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(properties.PosixProperties.Owner.HasValue()); + EXPECT_EQ( + properties.PosixProperties.Owner.Value(), createOptions.PosixProperties.Owner.Value()); + + // Copy with source/override + copyOptions = Files::Shares::StartFileCopyOptions(); + copyOptions.SmbPropertiesToCopy = Files::Shares::CopyableFileSmbPropertyFlags::None; + copyOptions.ModeCopyMode = Files::Shares::Models::ModeCopyMode::Override; + copyOptions.PosixProperties.FileMode + = Files::Shares::Models::NfsFileMode::ParseOctalFileMode("0767"); + copyOptions.OwnerCopyMode = Files::Shares::Models::OwnerCopyMode::Source; + destFileClient = shareClient.GetRootDirectoryClient().GetFileClient(LowercaseRandomString()); + copyOperation = destFileClient.StartCopy(sourceClient.GetUrl(), copyOptions); + EXPECT_EQ( + copyOperation.GetRawResponse().GetStatusCode(), + Azure::Core::Http::HttpStatusCode::Accepted); + properties = copyOperation.PollUntilDone(std::chrono::milliseconds(1000)).Value; + EXPECT_EQ(properties.CopyStatus.Value(), Files::Shares::Models::CopyStatus::Success); + EXPECT_TRUE(properties.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(properties.PosixProperties.FileMode.Value().ToOctalFileMode(), "0767"); + EXPECT_TRUE(properties.PosixProperties.Group.HasValue()); + EXPECT_EQ( + properties.PosixProperties.Group.Value(), createOptions.PosixProperties.Group.Value()); + EXPECT_TRUE(properties.PosixProperties.Owner.HasValue()); + EXPECT_EQ( + properties.PosixProperties.Owner.Value(), createOptions.PosixProperties.Owner.Value()); + + // Copy without NfsProperties + copyOptions = Files::Shares::StartFileCopyOptions(); + copyOptions.SmbPropertiesToCopy = Files::Shares::CopyableFileSmbPropertyFlags::None; + destFileClient = shareClient.GetRootDirectoryClient().GetFileClient(LowercaseRandomString()); + copyOperation = destFileClient.StartCopy(sourceClient.GetUrl(), copyOptions); + EXPECT_EQ( + copyOperation.GetRawResponse().GetStatusCode(), + Azure::Core::Http::HttpStatusCode::Accepted); + properties = copyOperation.PollUntilDone(std::chrono::milliseconds(1000)).Value; + EXPECT_EQ(properties.CopyStatus.Value(), Files::Shares::Models::CopyStatus::Success); + EXPECT_TRUE(properties.PosixProperties.FileMode.HasValue()); + EXPECT_EQ(properties.PosixProperties.FileMode.Value().ToOctalFileMode(), "0664"); + EXPECT_TRUE(properties.PosixProperties.Group.HasValue()); + EXPECT_EQ(properties.PosixProperties.Group.Value(), "0"); + EXPECT_TRUE(properties.PosixProperties.Owner.HasValue()); + EXPECT_EQ(properties.PosixProperties.Owner.Value(), "0"); + + // Copy with invalid input + copyOptions = Files::Shares::StartFileCopyOptions(); + copyOptions.SmbPropertiesToCopy = Files::Shares::CopyableFileSmbPropertyFlags::None; + copyOptions.ModeCopyMode = Files::Shares::Models::ModeCopyMode::Source; + copyOptions.PosixProperties.FileMode + = Files::Shares::Models::NfsFileMode::ParseOctalFileMode("0767"); + copyOptions.OwnerCopyMode = Files::Shares::Models::OwnerCopyMode::Source; + destFileClient = shareClient.GetRootDirectoryClient().GetFileClient(LowercaseRandomString()); + EXPECT_THROW(destFileClient.StartCopy(sourceClient.GetUrl(), copyOptions), StorageException); + + copyOptions = Files::Shares::StartFileCopyOptions(); + copyOptions.SmbPropertiesToCopy = Files::Shares::CopyableFileSmbPropertyFlags::None; + copyOptions.ModeCopyMode = Files::Shares::Models::ModeCopyMode::Override; + copyOptions.OwnerCopyMode = Files::Shares::Models::OwnerCopyMode::Source; + destFileClient = shareClient.GetRootDirectoryClient().GetFileClient(LowercaseRandomString()); + EXPECT_THROW(destFileClient.StartCopy(sourceClient.GetUrl(), copyOptions), StorageException); + + copyOptions = Files::Shares::StartFileCopyOptions(); + copyOptions.SmbPropertiesToCopy = Files::Shares::CopyableFileSmbPropertyFlags::None; + copyOptions.ModeCopyMode = Files::Shares::Models::ModeCopyMode::Source; + copyOptions.OwnerCopyMode = Files::Shares::Models::OwnerCopyMode::Override; + destFileClient = shareClient.GetRootDirectoryClient().GetFileClient(LowercaseRandomString()); + EXPECT_THROW(destFileClient.StartCopy(sourceClient.GetUrl(), copyOptions), StorageException); + + copyOptions = Files::Shares::StartFileCopyOptions(); + copyOptions.SmbPropertiesToCopy = Files::Shares::CopyableFileSmbPropertyFlags::None; + copyOptions.ModeCopyMode = Files::Shares::Models::ModeCopyMode::Source; + copyOptions.OwnerCopyMode = Files::Shares::Models::OwnerCopyMode::Source; + copyOptions.PosixProperties.Group = "888"; + destFileClient = shareClient.GetRootDirectoryClient().GetFileClient(LowercaseRandomString()); + EXPECT_THROW(destFileClient.StartCopy(sourceClient.GetUrl(), copyOptions), StorageException); + } }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_utility_test.cpp b/sdk/storage/azure-storage-files-shares/test/ut/share_utility_test.cpp new file mode 100644 index 000000000..e0721f9c1 --- /dev/null +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_utility_test.cpp @@ -0,0 +1,161 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include + +#include + +/* cSpell:ignore rwsrwsrwt, rwxrwxrwx, rwSrwSrwT, xrwt, rwSr*/ + +namespace Azure { namespace Storage { namespace Test { + + TEST(ShareUtilityTest, NfsFileMode) + { + auto testOctal = [&](const std::string& modeString) { + auto mode = Files::Shares::Models::NfsFileMode::ParseOctalFileMode(modeString); + EXPECT_EQ(mode.ToOctalFileMode(), modeString); + }; + auto testSymbolic = [&](const std::string& modeString) { + auto mode = Files::Shares::Models::NfsFileMode::ParseSymbolicFileMode(modeString); + EXPECT_EQ(mode.ToSymbolicFileMode(), modeString); + }; + auto testOctalToSymbolic = [&](const std::string& octal, const std::string& symbolic) { + auto mode = Files::Shares::Models::NfsFileMode::ParseOctalFileMode(octal); + EXPECT_EQ(mode.ToSymbolicFileMode(), symbolic); + }; + auto testSymbolicToOctal = [&](const std::string& symbolic, const std::string& octal) { + auto mode = Files::Shares::Models::NfsFileMode::ParseSymbolicFileMode(symbolic); + EXPECT_EQ(mode.ToOctalFileMode(), octal); + }; + + // 0000 + testOctal("0000"); + testSymbolic("---------"); + testOctalToSymbolic("0000", "---------"); + testSymbolicToOctal("---------", "0000"); + + // 1111 + testOctal("1111"); + testSymbolic("--x--x--x"); + testOctalToSymbolic("1111", "--x--x--t"); + testSymbolicToOctal("--x--x--t", "1111"); + + // 2222 + testOctal("2222"); + testSymbolic("-w--wS-w-"); + testOctalToSymbolic("2222", "-w--wS-w-"); + testSymbolicToOctal("-w--wS-w-", "2222"); + + // 3333 + testOctal("3333"); + testSymbolic("-wx-ws-wt"); + testOctalToSymbolic("3333", "-wx-ws-wt"); + testSymbolicToOctal("-wx-ws-wt", "3333"); + + // 4444 + testOctal("4444"); + testSymbolic("r-Sr--r--"); + testOctalToSymbolic("4444", "r-Sr--r--"); + testSymbolicToOctal("r-Sr--r--", "4444"); + + // 5555 + testOctal("5555"); + testSymbolic("r-sr-xr-t"); + testOctalToSymbolic("5555", "r-sr-xr-t"); + testSymbolicToOctal("r-sr-xr-t", "5555"); + + // 6666 + testOctal("6666"); + testSymbolic("rwSrwSrw-"); + testOctalToSymbolic("6666", "rwSrwSrw-"); + testSymbolicToOctal("rwSrwSrw-", "6666"); + + // 7777 + testOctal("7777"); + testSymbolic("rwsrwsrwt"); + testOctalToSymbolic("7777", "rwsrwsrwt"); + testSymbolicToOctal("rwsrwsrwt", "7777"); + + // 0001 + testOctal("0001"); + testSymbolic("--------x"); + testOctalToSymbolic("0001", "--------x"); + testSymbolicToOctal("--------x", "0001"); + + // 0010 + testOctal("0010"); + testSymbolic("-----x---"); + testOctalToSymbolic("0010", "-----x---"); + testSymbolicToOctal("-----x---", "0010"); + + // 0100 + testOctal("0100"); + testSymbolic("--x------"); + testOctalToSymbolic("0100", "--x------"); + testSymbolicToOctal("--x------", "0100"); + + // 0124 + testOctal("0124"); + testSymbolic("--x-w-r--"); + testOctalToSymbolic("0124", "--x-w-r--"); + testSymbolicToOctal("--x-w-r--", "0124"); + + // 0777 + testOctal("0777"); + testSymbolic("rwxrwxrwx"); + testOctalToSymbolic("0777", "rwxrwxrwx"); + testSymbolicToOctal("rwxrwxrwx", "0777"); + + // 4210 + testOctal("4210"); + testSymbolic("-wS--x---"); + testOctalToSymbolic("4210", "-wS--x---"); + testSymbolicToOctal("-wS--x---", "4210"); + + // 1357 + testOctal("1357"); + testSymbolic("-wxr-xrwt"); + testOctalToSymbolic("1357", "-wxr-xrwt"); + testSymbolicToOctal("-wxr-xrwt", "1357"); + + // 7654 + testOctal("7654"); + testSymbolic("rwSr-sr-T"); + testOctalToSymbolic("7654", "rwSr-sr-T"); + testSymbolicToOctal("rwSr-sr-T", "7654"); + + // 7666 + testOctal("7666"); + testSymbolic("rwSrwSrwT"); + testOctalToSymbolic("7666", "rwSrwSrwT"); + testSymbolicToOctal("rwSrwSrwT", "7666"); + + // Invalid + EXPECT_THROW( + Files::Shares::Models::NfsFileMode::ParseOctalFileMode("1239"), std::invalid_argument); + EXPECT_THROW( + Files::Shares::Models::NfsFileMode::ParseOctalFileMode("9786"), std::invalid_argument); + EXPECT_THROW( + Files::Shares::Models::NfsFileMode::ParseOctalFileMode("12344"), std::invalid_argument); + EXPECT_THROW( + Files::Shares::Models::NfsFileMode::ParseOctalFileMode("12"), std::invalid_argument); + EXPECT_THROW( + Files::Shares::Models::NfsFileMode::ParseOctalFileMode("test"), std::invalid_argument); + EXPECT_THROW( + Files::Shares::Models::NfsFileMode::ParseOctalFileMode("rwSrwSrwT"), std::invalid_argument); + EXPECT_THROW( + Files::Shares::Models::NfsFileMode::ParseSymbolicFileMode("1234"), std::invalid_argument); + EXPECT_THROW( + Files::Shares::Models::NfsFileMode::ParseSymbolicFileMode("raSrwSrwT"), + std::invalid_argument); + EXPECT_THROW( + Files::Shares::Models::NfsFileMode::ParseSymbolicFileMode("---rwxrwxrwx"), + std::invalid_argument); + EXPECT_THROW( + Files::Shares::Models::NfsFileMode::ParseSymbolicFileMode("---rwx"), std::invalid_argument); + EXPECT_THROW( + Files::Shares::Models::NfsFileMode::ParseSymbolicFileMode("---test"), + std::invalid_argument); + } + +}}} // namespace Azure::Storage::Test