diff --git a/Microsoft.WindowsAzure.Storage/includes/was/blob.h b/Microsoft.WindowsAzure.Storage/includes/was/blob.h index 72cfb5f2..4d0636ab 100644 --- a/Microsoft.WindowsAzure.Storage/includes/was/blob.h +++ b/Microsoft.WindowsAzure.Storage/includes/was/blob.h @@ -830,236 +830,6 @@ namespace azure { namespace storage { int64_t m_append_position; }; - /// - /// The lease state of a resource. - /// - enum class lease_state - { - /// - /// The lease state is not specified. - /// - unspecified, - - /// - /// The lease is in the Available state. - /// - available, - - /// - /// The lease is in the Leased state. - /// - leased, - - /// - /// The lease is in the Expired state. - /// - expired, - - /// - /// The lease is in the Breaking state. - /// - breaking, - - /// - /// The lease is in the Broken state. - /// - broken, - }; - - /// - /// The lease status of a resource. - /// - enum class lease_status - { - /// - /// The lease status is not specified. - /// - unspecified, - - /// - /// The resource is locked. - /// - locked, - - /// - /// The resource is available to be locked. - /// - unlocked - }; - - /// - /// Specifies the proposed duration of seconds that the lease should continue before it is broken. - /// - class lease_break_period - { - public: - /// - /// Initializes a new instance of the class that breaks - /// a fixed-duration lease after the remaining lease period elapses, or breaks an infinite lease immediately. - /// - lease_break_period() - : m_seconds(std::chrono::seconds::max()) - { - } - - /// - /// Initializes a new instance of the class that breaks - /// a lease after the proposed duration. - /// - /// The proposed duration, in seconds, for the lease before it is broken. Value may - /// be between 0 and 60 seconds. - lease_break_period(const std::chrono::seconds& seconds) - : m_seconds(seconds) - { - if (seconds != std::chrono::seconds::max()) - { - utility::assert_in_bounds(_XPLATSTR("seconds"), seconds, protocol::minimum_lease_break_period, protocol::maximum_lease_break_period); - } - } - -#if defined(_MSC_VER) && _MSC_VER < 1900 - // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, - // have implicitly-declared move constructor and move assignment operator. - - /// - /// Initializes a new instance of the class based on an existing instance. - /// - /// An existing object. - lease_break_period(lease_break_period&& other) - { - *this = std::move(other); - } - - /// - /// Returns a reference to an object. - /// - /// An existing object to use to set properties. - /// An object with properties set. - lease_break_period& operator=(lease_break_period&& other) - { - if (this != &other) - { - m_seconds = std::move(other.m_seconds); - } - return *this; - } -#endif - - /// - /// Indicates whether the object is valid. - /// - /// true if the object is valid; otherwise, false. - bool is_valid() const - { - return m_seconds < std::chrono::seconds::max(); - } - - /// - /// Gets the proposed duration for the lease before it is broken. - /// - /// The proposed proposed duration for the lease before it is broken, in seconds. - const std::chrono::seconds& seconds() const - { - return m_seconds; - } - - private: - - std::chrono::seconds m_seconds; - }; - - /// - /// The lease duration for a Blob service resource. - /// - enum class lease_duration - { - /// - /// The lease duration is not specified. - /// - unspecified, - - /// - /// The lease duration is finite. - /// - fixed, - - /// - /// The lease duration is infinite. - /// - infinite, - }; - - /// - /// Specifies the duration of the lease. - /// - class lease_time - { - public: - /// - /// Initializes a new instance of the class that never expires. - /// - lease_time() - : m_seconds(-1) - { - } - - /// - /// Initializes a new instance of the class that expires after the - /// specified duration. - /// - /// The duration of the lease in seconds. For a non-infinite lease, this value can be - /// between 15 and 60 seconds. - lease_time(const std::chrono::seconds& seconds) - : m_seconds(seconds) - { - if (seconds.count() != -1) - { - utility::assert_in_bounds(_XPLATSTR("seconds"), seconds, protocol::minimum_fixed_lease_duration, protocol::maximum_fixed_lease_duration); - } - } - -#if defined(_MSC_VER) && _MSC_VER < 1900 - // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, - // have implicitly-declared move constructor and move assignment operator. - - /// - /// Initializes a new instance of the class based on an existing instance. - /// - /// An existing object. - lease_time(lease_time&& other) - { - *this = std::move(other); - } - - /// - /// Returns a reference to an object. - /// - /// An existing object to use to set properties. - /// An object with properties set. - lease_time& operator=(lease_time&& other) - { - if (this != &other) - { - m_seconds = std::move(other.m_seconds); - } - return *this; - } -#endif - - /// - /// Gets the duration of the lease in seconds for a non-infinite lease. - /// - /// The duration of the lease. - const std::chrono::seconds& seconds() const - { - return m_seconds; - } - - private: - - std::chrono::seconds m_seconds; - }; - /// /// The tier of the block blob on a standard storage account. /// diff --git a/Microsoft.WindowsAzure.Storage/includes/was/core.h b/Microsoft.WindowsAzure.Storage/includes/was/core.h index 7e7aefb3..7e4d446a 100644 --- a/Microsoft.WindowsAzure.Storage/includes/was/core.h +++ b/Microsoft.WindowsAzure.Storage/includes/was/core.h @@ -118,7 +118,7 @@ namespace azure { namespace storage { WASTORAGE_API storage_uri(web::http::uri primary_uri, web::http::uri secondary_uri); #if defined(_MSC_VER) && _MSC_VER < 1900 - // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, + // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, // have implicitly-declared move constructor and move assignment operator. /// @@ -289,7 +289,7 @@ namespace azure { namespace storage { public: utility::string_t m_bearer_token; - + private: pplx::extensibility::reader_writer_lock_t m_mutex; @@ -733,7 +733,7 @@ namespace azure { namespace storage { } #if defined(_MSC_VER) && _MSC_VER < 1900 - // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, + // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, // have implicitly-declared move constructor and move assignment operator. /// @@ -859,7 +859,7 @@ namespace azure { namespace storage { } #if defined(_MSC_VER) && _MSC_VER < 1900 - // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, + // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, // have implicitly-declared move constructor and move assignment operator. /// @@ -977,7 +977,7 @@ namespace azure { namespace storage { WASTORAGE_API request_result(utility::datetime start_time, storage_location target_location, const web::http::http_response& response, web::http::status_code http_status_code, storage_extended_error extended_error); #if defined(_MSC_VER) && _MSC_VER < 1900 - // Compilers that fully support C++ 11 r-value reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, + // Compilers that fully support C++ 11 r-value reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, // have implicitly-declared move constructor and move assignment operator. /// @@ -1271,7 +1271,7 @@ namespace azure { namespace storage { } #if defined(_MSC_VER) && _MSC_VER < 1900 - // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, + // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, // have implicitly-declared move constructor and move assignment operator. /// @@ -1382,7 +1382,7 @@ namespace azure { namespace storage { } #if defined(_MSC_VER) && _MSC_VER < 1900 - // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, + // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, // have implicitly-declared move constructor and move assignment operator. /// @@ -1556,6 +1556,236 @@ namespace azure { namespace storage { std::shared_ptr m_policy; }; + /// + /// The lease state of a resource. + /// + enum class lease_state + { + /// + /// The lease state is not specified. + /// + unspecified, + + /// + /// The lease is in the Available state. + /// + available, + + /// + /// The lease is in the Leased state. + /// + leased, + + /// + /// The lease is in the Expired state. + /// + expired, + + /// + /// The lease is in the Breaking state. + /// + breaking, + + /// + /// The lease is in the Broken state. + /// + broken, + }; + + /// + /// The lease status of a resource. + /// + enum class lease_status + { + /// + /// The lease status is not specified. + /// + unspecified, + + /// + /// The resource is locked. + /// + locked, + + /// + /// The resource is available to be locked. + /// + unlocked + }; + + /// + /// Specifies the proposed duration of seconds that the lease should continue before it is broken. + /// + class lease_break_period + { + public: + /// + /// Initializes a new instance of the class that breaks + /// a fixed-duration lease after the remaining lease period elapses, or breaks an infinite lease immediately. + /// + lease_break_period() + : m_seconds(std::chrono::seconds::max()) + { + } + + /// + /// Initializes a new instance of the class that breaks + /// a lease after the proposed duration. + /// + /// The proposed duration, in seconds, for the lease before it is broken. Value may + /// be between 0 and 60 seconds. + lease_break_period(const std::chrono::seconds& seconds) + : m_seconds(seconds) + { + if (seconds != std::chrono::seconds::max()) + { + utility::assert_in_bounds(_XPLATSTR("seconds"), seconds, protocol::minimum_lease_break_period, protocol::maximum_lease_break_period); + } + } + +#if defined(_MSC_VER) && _MSC_VER < 1900 + // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, + // have implicitly-declared move constructor and move assignment operator. + + /// + /// Initializes a new instance of the class based on an existing instance. + /// + /// An existing object. + lease_break_period(lease_break_period&& other) + { + *this = std::move(other); + } + + /// + /// Returns a reference to an object. + /// + /// An existing object to use to set properties. + /// An object with properties set. + lease_break_period& operator=(lease_break_period&& other) + { + if (this != &other) + { + m_seconds = std::move(other.m_seconds); + } + return *this; + } +#endif + + /// + /// Indicates whether the object is valid. + /// + /// true if the object is valid; otherwise, false. + bool is_valid() const + { + return m_seconds < std::chrono::seconds::max(); + } + + /// + /// Gets the proposed duration for the lease before it is broken. + /// + /// The proposed proposed duration for the lease before it is broken, in seconds. + const std::chrono::seconds& seconds() const + { + return m_seconds; + } + + private: + + std::chrono::seconds m_seconds; + }; + + /// + /// The lease duration for a Blob service resource. + /// + enum class lease_duration + { + /// + /// The lease duration is not specified. + /// + unspecified, + + /// + /// The lease duration is finite. + /// + fixed, + + /// + /// The lease duration is infinite. + /// + infinite, + }; + + /// + /// Specifies the duration of the lease. + /// + class lease_time + { + public: + /// + /// Initializes a new instance of the class that never expires. + /// + lease_time() + : m_seconds(-1) + { + } + + /// + /// Initializes a new instance of the class that expires after the + /// specified duration. + /// + /// The duration of the lease in seconds. For a non-infinite lease, this value can be + /// between 15 and 60 seconds. + lease_time(const std::chrono::seconds& seconds) + : m_seconds(seconds) + { + if (seconds.count() != -1) + { + utility::assert_in_bounds(_XPLATSTR("seconds"), seconds, protocol::minimum_fixed_lease_duration, protocol::maximum_fixed_lease_duration); + } + } + +#if defined(_MSC_VER) && _MSC_VER < 1900 + // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, + // have implicitly-declared move constructor and move assignment operator. + + /// + /// Initializes a new instance of the class based on an existing instance. + /// + /// An existing object. + lease_time(lease_time&& other) + { + *this = std::move(other); + } + + /// + /// Returns a reference to an object. + /// + /// An existing object to use to set properties. + /// An object with properties set. + lease_time& operator=(lease_time&& other) + { + if (this != &other) + { + m_seconds = std::move(other.m_seconds); + } + return *this; + } +#endif + + /// + /// Gets the duration of the lease in seconds for a non-infinite lease. + /// + /// The duration of the lease. + const std::chrono::seconds& seconds() const + { + return m_seconds; + } + + private: + + std::chrono::seconds m_seconds; + }; + #ifdef _WIN32 /// /// Interface for scheduling tasks that start after a provided delay in milliseconds diff --git a/Microsoft.WindowsAzure.Storage/includes/was/file.h b/Microsoft.WindowsAzure.Storage/includes/was/file.h index c892b8bb..26c720f1 100644 --- a/Microsoft.WindowsAzure.Storage/includes/was/file.h +++ b/Microsoft.WindowsAzure.Storage/includes/was/file.h @@ -51,19 +51,83 @@ namespace azure { namespace storage { class file_access_condition { public: + /// + /// Constructs an empty file access condition. + /// file_access_condition() - : m_valid(false) { } +#if defined(_MSC_VER) && _MSC_VER < 1900 + // Compilers that fully support C++ 11 rvalue reference, e.g. g++ 4.8+, clang++ 3.3+ and Visual Studio 2015+, + // have implicitly-declared move constructor and move assignment operator. + + /// + /// Initializes a new instance of the class based on an existing instance. + /// + /// An existing object. + file_access_condition(file_access_condition&& other) + { + *this = std::move(other); + } + + /// + /// Returns a reference to an object. + /// + /// An existing object to use to set properties. + /// An object with properties set. + file_access_condition& operator=(file_access_condition&& other) + { + if (this != &other) + { + m_lease_id = std::move(other.m_lease_id); + } + return *this; + } +#endif + + /// + /// Generates a file access condition such that an operation will be performed only if the lease ID on the + /// resource matches the specified lease ID. + /// + /// The lease ID that must match the lease ID of the resource. + /// An object that represents the lease condition. + static file_access_condition generate_lease_condition(utility::string_t lease_id) + { + file_access_condition condition; + condition.set_lease_id(std::move(lease_id)); + return condition; + } + + /// + /// Returns if this condition is empty. + /// + /// true if this condition is empty, false otherwise. bool is_valid() const { - return m_valid; + return !m_lease_id.empty(); } - private: + /// + /// Gets a lease ID that must match the lease on a resource. + /// + /// A string containing the lease ID. + const utility::string_t& lease_id() const + { + return m_lease_id; + } - bool m_valid; + /// + /// Sets a lease ID that must match the lease on a resource. + /// + /// A string containing the lease ID. + void set_lease_id(utility::string_t value) + { + m_lease_id = std::move(value); + } + + private: + utility::string_t m_lease_id; }; /// @@ -2700,6 +2764,8 @@ namespace azure { namespace storage { /// Initializes a new instance of the class. /// cloud_file_properties() + : m_lease_status(azure::storage::lease_status::unspecified), m_lease_state(azure::storage::lease_state::unspecified), + m_lease_duration(azure::storage::lease_duration::unspecified) { } @@ -2739,8 +2805,11 @@ namespace azure { namespace storage { m_last_write_time_now = std::move(other.m_last_write_time_now); m_last_write_time_preserve = std::move(other.m_last_write_time_preserve); m_change_time = std::move(other.m_change_time); - m_file_id = std::move(m_file_id); - m_parent_id = std::move(m_parent_id); + m_file_id = std::move(other.m_file_id); + m_parent_id = std::move(other.m_parent_id); + m_lease_status = std::move(other.m_lease_status); + m_lease_state = std::move(other.m_lease_state); + m_lease_duration = std::move(other.m_lease_duration); } return *this; } @@ -3118,6 +3187,33 @@ namespace azure { namespace storage { return m_parent_id; } + /// + /// Gets the file's lease status. + /// + /// An object that indicates the file's lease status. + azure::storage::lease_status lease_status() const + { + return m_lease_status; + } + + /// + /// Gets the file's lease state. + /// + /// An object that indicates the file's lease state. + azure::storage::lease_state lease_state() const + { + return m_lease_state; + } + + /// + /// Gets the file's lease duration. + /// + /// An object that indicates the file's lease duration. + azure::storage::lease_duration lease_duration() const + { + return m_lease_duration; + } + private: utility::size64_t m_length{ 0 }; @@ -3146,9 +3242,13 @@ namespace azure { namespace storage { utility::datetime m_change_time; utility::string_t m_file_id; utility::string_t m_parent_id; + azure::storage::lease_status m_lease_status; + azure::storage::lease_state m_lease_state; + azure::storage::lease_duration m_lease_duration; void update_etag_and_last_modified(const cloud_file_properties& other); void update_acl_attributes_filetime_and_fileid(const cloud_file_properties& other); + void update_lease(const cloud_file_properties& other); friend class cloud_file; friend class protocol::file_response_parsers; @@ -4696,6 +4796,224 @@ namespace azure { namespace storage { return *m_copy_state; } + /// + /// Acquires a lease on the file. + /// + /// A string representing the proposed lease ID for the new lease. May be an empty string if no lease ID is proposed. + /// A string containing the lease ID. + utility::string_t acquire_lease(const utility::string_t& proposed_lease_id) const + { + return acquire_lease_async(proposed_lease_id).get(); + } + + /// + /// Acquires a lease on the file. + /// + /// A string representing the proposed lease ID for the new lease. May be an empty string if no lease ID is proposed. + /// An object that represents the access condition for the operation. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + /// A string containing the lease ID. + utility::string_t acquire_lease(const utility::string_t& proposed_lease_id, const file_access_condition& condition, const file_request_options& options, operation_context context) const + { + return acquire_lease_async(proposed_lease_id, condition, options, context).get(); + } + + /// + /// Initiates an asynchronous operation to acquire a lease on the file. + /// + /// A string representing the proposed lease ID for the new lease. May be an empty string if no lease ID is proposed. + /// A object of type that represents the current operation. + pplx::task acquire_lease_async(const utility::string_t& proposed_lease_id) const + { + return acquire_lease_async(proposed_lease_id, file_access_condition(), file_request_options(), operation_context()); + } + + /// + /// Initiates an asynchronous operation to acquire a lease on the file. + /// + /// A string representing the proposed lease ID for the new lease. May be an empty string if no lease ID is proposed. + /// An object that represents the access condition for the operation. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + /// A object of type that represents the current operation. + pplx::task acquire_lease_async(const utility::string_t& proposed_lease_id, const file_access_condition& condition, const file_request_options& options, operation_context context) const + { + return acquire_lease_async(proposed_lease_id, condition, options, context, pplx::cancellation_token::none()); + } + + /// + /// Initiates an asynchronous operation to acquire a lease on the file. + /// + /// A string representing the proposed lease ID for the new lease. May be an empty string if no lease ID is proposed. + /// An object that represents the access condition for the operation. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + /// An object that is used to cancel the current operation. + /// A object of type that represents the current operation. + WASTORAGE_API pplx::task acquire_lease_async(const utility::string_t& proposed_lease_id, const file_access_condition& condition, const file_request_options& options, operation_context context, const pplx::cancellation_token& cancellation_token) const; + + /// + /// Changes the lease ID on the file. + /// + /// A string containing the proposed lease ID for the lease. May not be empty. + /// An object that represents the access conditions for the file, including a required lease ID. + /// The new lease ID. + utility::string_t change_lease(const utility::string_t& proposed_lease_id, const file_access_condition& condition) const + { + return change_lease_async(proposed_lease_id, condition).get(); + } + + /// + /// Changes the lease ID on the file. + /// + /// A string containing the proposed lease ID for the lease. May not be empty. + /// An object that represents the access conditions for the file, including a required lease ID. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + /// The new lease ID. + utility::string_t change_lease(const utility::string_t& proposed_lease_id, const file_access_condition& condition, const file_request_options& options, operation_context context) const + { + return change_lease_async(proposed_lease_id, condition, options, context).get(); + } + + /// + /// Initiates an asynchronous operation to change the lease ID on the file. + /// + /// A string containing the proposed lease ID for the lease. May not be empty. + /// An object that represents the access conditions for the file, including a required lease ID. + /// A object of type that represents the current operation. + pplx::task change_lease_async(const utility::string_t& proposed_lease_id, const file_access_condition& condition) const + { + return change_lease_async(proposed_lease_id, condition, file_request_options(), operation_context()); + } + + /// + /// Initiates an asynchronous operation to change the lease ID on the file. + /// + /// A string containing the proposed lease ID for the lease. May not be empty. + /// An object that represents the access conditions for the file, including a required lease ID. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + /// A object of type that represents the current operation. + pplx::task change_lease_async(const utility::string_t& proposed_lease_id, const file_access_condition& condition, const file_request_options& options, operation_context context) const + { + return change_lease_async(proposed_lease_id, condition, options, context, pplx::cancellation_token::none()); + } + + /// + /// Initiates an asynchronous operation to change the lease ID on the file. + /// + /// A string containing the proposed lease ID for the lease. May not be empty. + /// An object that represents the access conditions for the file, including a required lease ID. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + /// An object that is used to cancel the current operation. + /// A object of type that represents the current operation. + WASTORAGE_API pplx::task change_lease_async(const utility::string_t& proposed_lease_id, const file_access_condition& condition, const file_request_options& options, operation_context context, const pplx::cancellation_token& cancellation_token) const; + + /// + /// Releases the lease on the file. + /// + /// An object that represents the access conditions for the file, including a required lease ID. + void release_lease(const file_access_condition& condition) const + { + release_lease_async(condition).wait(); + } + + /// + /// Releases the lease on the file. + /// + /// An object that represents the access conditions for the file, including a required lease ID. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + void release_lease(const file_access_condition& condition, const file_request_options& options, operation_context context) const + { + release_lease_async(condition, options, context).wait(); + } + + /// + /// Initiates an asynchronous operation to release the lease on the file. + /// + /// An object that represents the access conditions for the file, including a required lease ID. + /// A object that represents the current operation. + pplx::task release_lease_async(const file_access_condition& condition) const + { + return release_lease_async(condition, file_request_options(), operation_context()); + } + + /// + /// Initiates an asynchronous operation to release the lease on the file. + /// + /// An object that represents the access conditions for the file, including a required lease ID. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + /// A object that represents the current operation. + pplx::task release_lease_async(const file_access_condition& condition, const file_request_options& options, operation_context context) const + { + return release_lease_async(condition, options, context, pplx::cancellation_token::none()); + } + + /// + /// Initiates an asynchronous operation to release the lease on the file. + /// + /// An object that represents the access conditions for the file, including a required lease ID. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + /// An object that is used to cancel the current operation. + /// A object that represents the current operation. + WASTORAGE_API pplx::task release_lease_async(const file_access_condition& condition, const file_request_options& options, operation_context context, const pplx::cancellation_token& cancellation_token) const; + + /// + /// Breaks the current lease on the file. + /// + void break_lease() const + { + return break_lease_async().get(); + } + + /// + /// Breaks the current lease on the file. + /// + /// An object that represents the access conditions for the file, including a required lease ID. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + void break_lease(const file_access_condition& condition, const file_request_options& options, operation_context context) const + { + return break_lease_async(condition, options, context).get(); + } + + /// + /// Initiates an asynchronous operation to break the current lease on the file. + /// + /// A object that represents the current operation. + pplx::task break_lease_async() const + { + return break_lease_async(file_access_condition(), file_request_options(), operation_context()); + } + + /// + /// Initiates an asynchronous operation to break the current lease on the file. + /// + /// An object that represents the access conditions for the file, including a required lease ID. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + /// A object that represents the current operation. + pplx::task break_lease_async(const file_access_condition& condition, const file_request_options& options, operation_context context) const + { + return break_lease_async(condition, options, context, pplx::cancellation_token::none()); + } + + /// + /// Initiates an asynchronous operation to break the current lease on the file. + /// + /// An object that represents the access conditions for the file, including a required lease ID. + /// An object that specifies additional options for the request. + /// An object that represents the context for the current operation. + /// An object that is used to cancel the current operation. + /// A object that represents the current operation. + WASTORAGE_API pplx::task break_lease_async(const file_access_condition& condition, const file_request_options& options, operation_context context, const pplx::cancellation_token& cancellation_token) const; + private: void init(storage_credentials credentials); diff --git a/Microsoft.WindowsAzure.Storage/includes/wascore/protocol.h b/Microsoft.WindowsAzure.Storage/includes/wascore/protocol.h index 59849e6f..fdec99db 100644 --- a/Microsoft.WindowsAzure.Storage/includes/wascore/protocol.h +++ b/Microsoft.WindowsAzure.Storage/includes/wascore/protocol.h @@ -130,19 +130,21 @@ namespace azure { namespace storage { namespace protocol { web::http::http_request get_file_directory_properties(web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); web::http::http_request set_file_directory_properties(const cloud_file_directory_properties& properties, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); web::http::http_request set_file_directory_metadata(const cloud_metadata& metadata, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request create_file(const int64_t length, const cloud_metadata& metadata, const cloud_file_properties& properties, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request delete_file(web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request get_file_properties(web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request set_file_properties(const cloud_file_properties& properties, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request resize_with_properties(const cloud_file_properties& properties, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request set_file_metadata(const cloud_metadata& metadata, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request copy_file(const web::http::uri& source, const cloud_metadata& metadata, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request copy_file_from_blob(const web::http::uri& source, const access_condition& condition, const cloud_metadata& metadata, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request abort_copy_file(const utility::string_t& copy_id, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request list_file_ranges(utility::size64_t start_offset, utility::size64_t length, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request put_file_range(file_range range, file_range_write write, utility::string_t content_md5, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - web::http::http_request get_file(utility::size64_t start_offset, utility::size64_t length, bool md5_validation, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); - + web::http::http_request create_file(const int64_t length, const cloud_metadata& metadata, const cloud_file_properties& properties, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request delete_file(const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request get_file_properties(const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request set_file_properties(const cloud_file_properties& properties, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request resize_with_properties(const cloud_file_properties& properties, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request set_file_metadata(const cloud_metadata& metadata, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request copy_file(const web::http::uri& source, const cloud_metadata& metadata, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request copy_file_from_blob(const web::http::uri& source, const access_condition& condition, const cloud_metadata& metadata, const file_access_condition& file_condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request abort_copy_file(const utility::string_t& copy_id, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request list_file_ranges(utility::size64_t start_offset, utility::size64_t length, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request put_file_range(file_range range, file_range_write write, utility::string_t content_md5, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request get_file(utility::size64_t start_offset, utility::size64_t length, bool md5_validation, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context); + web::http::http_request lease_file(const utility::string_t& lease_action, const utility::string_t& proposed_lease_id, const file_access_condition& condition, web::http::uri_builder& uri_builder, const std::chrono::seconds& timeout, operation_context context); + void add_access_condition(web::http::http_request& request, const file_access_condition& condition); + // Common response parsers template diff --git a/Microsoft.WindowsAzure.Storage/src/cloud_file.cpp b/Microsoft.WindowsAzure.Storage/src/cloud_file.cpp index ba56842e..e160d09c 100644 --- a/Microsoft.WindowsAzure.Storage/src/cloud_file.cpp +++ b/Microsoft.WindowsAzure.Storage/src/cloud_file.cpp @@ -52,13 +52,20 @@ namespace azure { namespace storage { m_parent_id = other.m_parent_id; } + void cloud_file_properties::update_lease(const cloud_file_properties& other) + { + m_lease_status = other.m_lease_status; + m_lease_state = other.m_lease_state; + m_lease_duration = other.m_lease_duration; + } + cloud_file::cloud_file(storage_uri uri) : m_uri(std::move(uri)), m_metadata(std::make_shared()), m_properties(std::make_shared()), m_copy_state(std::make_shared()) { init(std::move(storage_credentials())); } - + cloud_file::cloud_file(storage_uri uri, storage_credentials credentials) : m_uri(std::move(uri)), m_metadata(std::make_shared()), m_properties(std::make_shared()), m_copy_state(std::make_shared()) @@ -97,14 +104,13 @@ namespace azure { namespace storage { pplx::task cloud_file::create_async(int64_t length, const file_access_condition& access_condition, const file_request_options& options, operation_context context) { - UNREFERENCED_PARAMETER(access_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); auto properties = m_properties; auto command = std::make_shared>(uri()); - command->set_build_request(std::bind(protocol::create_file, length, metadata(), this->properties(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::create_file, length, metadata(), this->properties(), access_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_preprocess_response([properties, length](const web::http::http_response& response, const request_result& result, operation_context context) { @@ -144,14 +150,13 @@ namespace azure { namespace storage { pplx::task cloud_file::delete_file_async(const file_access_condition& access_condition, const file_request_options& options, operation_context context) { - UNREFERENCED_PARAMETER(access_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); auto properties = m_properties; auto command = std::make_shared>(uri()); - command->set_build_request(std::bind(protocol::delete_file, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::delete_file, access_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_preprocess_response([properties](const web::http::http_response& response, const request_result& result, operation_context context) { @@ -187,7 +192,6 @@ namespace azure { namespace storage { pplx::task cloud_file::download_attributes_async(const file_access_condition& access_condition, const file_request_options& options, operation_context context) { - UNREFERENCED_PARAMETER(access_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); @@ -196,7 +200,7 @@ namespace azure { namespace storage { auto copy_state = m_copy_state; auto command = std::make_shared>(uri()); - command->set_build_request(std::bind(protocol::get_file_properties, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::get_file_properties, access_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_preprocess_response([metadata, properties, copy_state](const web::http::http_response& response, const request_result& result, operation_context context) { @@ -210,14 +214,13 @@ namespace azure { namespace storage { pplx::task cloud_file::upload_properties_async(const file_access_condition& access_condition, const file_request_options& options, operation_context context) const { - UNREFERENCED_PARAMETER(access_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); auto properties = m_properties; auto command = std::make_shared>(uri()); - command->set_build_request(std::bind(protocol::set_file_properties, this->properties(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::set_file_properties, this->properties(), access_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_preprocess_response([properties](const web::http::http_response& response, const request_result& result, operation_context context) { @@ -232,14 +235,13 @@ namespace azure { namespace storage { pplx::task cloud_file::upload_metadata_async(const file_access_condition& access_condition, const file_request_options& options, operation_context context) const { - UNREFERENCED_PARAMETER(access_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); auto properties = m_properties; auto command = std::make_shared>(uri()); - command->set_build_request(std::bind(protocol::set_file_metadata, this->metadata(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::set_file_metadata, this->metadata(), access_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_preprocess_response([properties](const web::http::http_response& response, const request_result& result, operation_context context) { @@ -253,7 +255,6 @@ namespace azure { namespace storage { pplx::task cloud_file::start_copy_async(const web::http::uri& source, const file_access_condition& source_condition, const file_access_condition& dest_condition, const file_request_options& options, operation_context context) const { UNREFERENCED_PARAMETER(source_condition); - UNREFERENCED_PARAMETER(dest_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); @@ -261,7 +262,7 @@ namespace azure { namespace storage { auto copy_state = m_copy_state; auto command = std::make_shared>(uri()); - command->set_build_request(std::bind(protocol::copy_file, source, this->metadata(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::copy_file, source, this->metadata(), dest_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_preprocess_response([properties, copy_state](const web::http::http_response& response, const request_result& result, operation_context context) { @@ -284,7 +285,6 @@ namespace azure { namespace storage { pplx::task cloud_file::start_copy_async(const web::http::uri& source, const access_condition& source_condition, const file_access_condition& dest_condition, const file_request_options& options, operation_context context) const { - UNREFERENCED_PARAMETER(dest_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); @@ -292,7 +292,7 @@ namespace azure { namespace storage { auto copy_state = m_copy_state; auto command = std::make_shared>(uri()); - command->set_build_request(std::bind(protocol::copy_file_from_blob, source, source_condition, this->metadata(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::copy_file_from_blob, source, source_condition, this->metadata(), dest_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_preprocess_response([properties, copy_state](const web::http::http_response& response, const request_result& result, operation_context context) { @@ -321,27 +321,25 @@ namespace azure { namespace storage { pplx::task cloud_file::abort_copy_async(const utility::string_t& copy_id, const file_access_condition& access_condition, const file_request_options& options, operation_context context) const { - UNREFERENCED_PARAMETER(access_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); auto command = std::make_shared>(uri()); - command->set_build_request(std::bind(protocol::abort_copy_file, copy_id, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::abort_copy_file, copy_id, access_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_preprocess_response(std::bind(protocol::preprocess_response_void, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); return core::executor::execute_async(command, modified_options, context); } - + pplx::task> cloud_file::list_ranges_async(utility::size64_t start_offset, utility::size64_t length, const file_access_condition& access_condition, const file_request_options& options, operation_context context) const { - UNREFERENCED_PARAMETER(access_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); auto properties = m_properties; auto command = std::make_shared>>(uri()); - command->set_build_request(std::bind(protocol::list_file_ranges, start_offset, length, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::list_file_ranges, start_offset, length, access_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_preprocess_response([properties](const web::http::http_response& response, const request_result& result, operation_context context) -> std::vector { @@ -364,7 +362,6 @@ namespace azure { namespace storage { pplx::task cloud_file::clear_range_async(utility::size64_t start_offset, utility::size64_t length, const file_access_condition& access_condition, const file_request_options& options, operation_context context) const { - UNREFERENCED_PARAMETER(access_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); @@ -373,7 +370,7 @@ namespace azure { namespace storage { file_range range(start_offset, end_offset); auto command = std::make_shared>(uri()); - command->set_build_request(std::bind(protocol::put_file_range, range, file_range_write::clear, utility::string_t(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::put_file_range, range, file_range_write::clear, utility::string_t(), access_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_preprocess_response([properties](const web::http::http_response& response, const request_result& result, operation_context context) { @@ -384,10 +381,9 @@ namespace azure { namespace storage { }); return core::executor::execute_async(command, modified_options, context); } - + pplx::task cloud_file::write_range_async(Concurrency::streams::istream stream, int64_t start_offset, const utility::string_t& content_md5, const file_access_condition& access_condition, const file_request_options& options, operation_context context) const { - UNREFERENCED_PARAMETER(access_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); @@ -403,12 +399,12 @@ namespace azure { namespace storage { properties->update_etag_and_last_modified(modified_properties); properties->m_content_md5 = modified_properties.content_md5(); }); - return core::istream_descriptor::create(stream, needs_md5 ? checksum_type::md5 : checksum_type::none, std::numeric_limits::max(), protocol::max_range_size).then([command, context, start_offset, content_md5, modified_options](core::istream_descriptor request_body)->pplx::task + return core::istream_descriptor::create(stream, needs_md5 ? checksum_type::md5 : checksum_type::none, std::numeric_limits::max(), protocol::max_range_size).then([command, context, start_offset, content_md5, access_condition, modified_options](core::istream_descriptor request_body)->pplx::task { const utility::string_t& md5 = content_md5.empty() ? request_body.content_checksum().md5() : content_md5; auto end_offset = start_offset + request_body.length() - 1; file_range range(start_offset, end_offset); - command->set_build_request(std::bind(protocol::put_file_range, range, file_range_write::update, md5, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::put_file_range, range, file_range_write::update, md5, access_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_request_body(request_body); return core::executor::execute_async(command, modified_options, context); }); @@ -427,7 +423,6 @@ namespace azure { namespace storage { pplx::task cloud_file::download_single_range_to_stream_async(concurrency::streams::ostream target, utility::size64_t offset, utility::size64_t length, const file_access_condition& condition, const file_request_options& options, operation_context context, bool update_properties, bool validate_last_modify) const { - UNREFERENCED_PARAMETER(condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); @@ -444,7 +439,7 @@ namespace azure { namespace storage { std::shared_ptr> command = std::make_shared>(uri()); std::weak_ptr> weak_command(command); - command->set_build_request([offset, length, modified_options, download_info](web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) -> web::http::http_request + command->set_build_request([offset, length, condition, modified_options, download_info](web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) -> web::http::http_request { utility::size64_t current_offset = offset; utility::size64_t current_length = length; @@ -469,7 +464,7 @@ namespace azure { namespace storage { } } - return protocol::get_file(current_offset, current_length, modified_options.use_transactional_md5() && !download_info->m_are_properties_populated, uri_builder, timeout, context); + return protocol::get_file(current_offset, current_length, modified_options.use_transactional_md5() && !download_info->m_are_properties_populated, condition, uri_builder, timeout, context); }); command->set_authentication_handler(service_client().authentication_handler()); command->set_location_mode(core::command_location_mode::primary_or_secondary); @@ -547,7 +542,7 @@ namespace azure { namespace storage { throw storage_exception(protocol::error_missing_md5, false); } - // Lock to the current storage location when resuming a failed download. This is locked + // Lock to the current storage location when resuming a failed download. This is locked // early before the retry policy has the opportunity to change the storage location. command->set_location_mode(core::command_location_mode::primary_or_secondary, result.target_location()); @@ -797,7 +792,7 @@ namespace azure { namespace storage { return core::cloud_file_ostreambuf(instance, instance->properties().length(), access_condition, modified_options, context).create_ostream(); }); } - + pplx::task cloud_file::open_write_async(utility::size64_t length, const file_access_condition& access_condition, const file_request_options& options, operation_context context) const { file_request_options modified_options(options); @@ -809,7 +804,7 @@ namespace azure { namespace storage { return core::cloud_file_ostreambuf(instance, length, access_condition, modified_options, context).create_ostream(); }); } - + pplx::task cloud_file::upload_from_stream_async(concurrency::streams::istream source, utility::size64_t length, const file_access_condition& access_condition, const file_request_options& options, operation_context context) const { file_request_options modified_options(options); @@ -832,7 +827,7 @@ namespace azure { namespace storage { }); }); } - + pplx::task cloud_file::upload_from_file_async(const utility::string_t& path, const file_access_condition& access_condition, const file_request_options& options, operation_context context) const { auto instance = std::make_shared(*this); @@ -847,7 +842,7 @@ namespace azure { namespace storage { }); }); } - + pplx::task cloud_file::upload_text_async(const utility::string_t& text, const file_access_condition& condition, const file_request_options& options, operation_context context) const { auto utf8_body = utility::conversions::to_utf8string(text); @@ -859,7 +854,6 @@ namespace azure { namespace storage { pplx::task cloud_file::resize_async(int64_t length, const file_access_condition& access_condition, const file_request_options& options, operation_context context) const { - UNREFERENCED_PARAMETER(access_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); @@ -867,7 +861,7 @@ namespace azure { namespace storage { properties->m_length = length; auto command = std::make_shared>(uri()); - command->set_build_request(std::bind(protocol::resize_with_properties, this->properties(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::resize_with_properties, this->properties(), access_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_preprocess_response([properties](const web::http::http_response& response, const request_result& result, operation_context context) { @@ -910,7 +904,6 @@ namespace azure { namespace storage { pplx::task cloud_file::exists_async(bool primary_only, const file_access_condition& access_condition, const file_request_options& options, operation_context context) const { - UNREFERENCED_PARAMETER(access_condition); file_request_options modified_options(options); modified_options.apply_defaults(service_client().default_request_options()); @@ -918,7 +911,7 @@ namespace azure { namespace storage { auto metadata = m_metadata; auto command = std::make_shared>(uri()); - command->set_build_request(std::bind(protocol::get_file_properties, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_build_request(std::bind(protocol::get_file_properties, access_condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); command->set_authentication_handler(service_client().authentication_handler()); command->set_location_mode(primary_only ? core::command_location_mode::primary_only : core::command_location_mode::primary_or_secondary); command->set_preprocess_response([properties, metadata](const web::http::http_response& response, const request_result& result, operation_context context) @@ -935,4 +928,90 @@ namespace azure { namespace storage { return core::executor::execute_async(command, modified_options, context); } -}} \ No newline at end of file + pplx::task cloud_file::acquire_lease_async(const utility::string_t& proposed_lease_id, const file_access_condition& condition, const file_request_options& options, operation_context context, const pplx::cancellation_token& cancellation_token) const + { + file_request_options modified_options(options); + modified_options.apply_defaults(service_client().default_request_options()); + + auto properties = m_properties; + + auto command = std::make_shared>(uri(), cancellation_token, modified_options.is_maximum_execution_time_customized()); + command->set_build_request(std::bind(protocol::lease_file, protocol::header_value_lease_acquire, proposed_lease_id, condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_authentication_handler(service_client().authentication_handler()); + command->set_preprocess_response([properties](const web::http::http_response& response, const request_result& result, operation_context context) -> utility::string_t + { + protocol::preprocess_response_void(response, result, context); + auto response_properties = protocol::file_response_parsers::parse_file_properties(response); + properties->update_etag_and_last_modified(response_properties); + properties->update_lease(response_properties); + return protocol::parse_lease_id(response); + }); + + return core::executor::execute_async(command, modified_options, context); + } + + pplx::task cloud_file::change_lease_async(const utility::string_t& proposed_lease_id, const file_access_condition& condition, const file_request_options& options, operation_context context, const pplx::cancellation_token& cancellation_token) const + { + file_request_options modified_options(options); + modified_options.apply_defaults(service_client().default_request_options()); + + auto properties = m_properties; + + auto command = std::make_shared>(uri(), cancellation_token, modified_options.is_maximum_execution_time_customized()); + command->set_build_request(std::bind(protocol::lease_file, protocol::header_value_lease_change, proposed_lease_id, condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_authentication_handler(service_client().authentication_handler()); + command->set_preprocess_response([properties](const web::http::http_response& response, const request_result& result, operation_context context) -> utility::string_t + { + protocol::preprocess_response_void(response, result, context); + auto response_properties = protocol::file_response_parsers::parse_file_properties(response); + properties->update_etag_and_last_modified(response_properties); + properties->update_lease(response_properties); + return protocol::parse_lease_id(response); + }); + + return core::executor::execute_async(command, modified_options, context); + } + + pplx::task cloud_file::release_lease_async(const file_access_condition& condition, const file_request_options& options, operation_context context, const pplx::cancellation_token& cancellation_token) const + { + file_request_options modified_options(options); + modified_options.apply_defaults(service_client().default_request_options()); + + auto properties = m_properties; + + auto command = std::make_shared>(uri(), cancellation_token, modified_options.is_maximum_execution_time_customized()); + command->set_build_request(std::bind(protocol::lease_file, protocol::header_value_lease_release, utility::string_t(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_authentication_handler(service_client().authentication_handler()); + command->set_preprocess_response([properties](const web::http::http_response& response, const request_result& result, operation_context context) -> void + { + protocol::preprocess_response_void(response, result, context); + auto response_properties = protocol::file_response_parsers::parse_file_properties(response); + properties->update_etag_and_last_modified(response_properties); + properties->update_lease(response_properties); + }); + + return core::executor::execute_async(command, modified_options, context); + } + + pplx::task cloud_file::break_lease_async(const file_access_condition& condition, const file_request_options& options, operation_context context, const pplx::cancellation_token& cancellation_token) const + { + file_request_options modified_options(options); + modified_options.apply_defaults(service_client().default_request_options()); + + auto properties = m_properties; + + auto command = std::make_shared>(uri(), cancellation_token, modified_options.is_maximum_execution_time_customized()); + command->set_build_request(std::bind(protocol::lease_file, protocol::header_value_lease_break, utility::string_t(), condition, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + command->set_authentication_handler(service_client().authentication_handler()); + command->set_preprocess_response([properties](const web::http::http_response& response, const request_result& result, operation_context context) -> void + { + protocol::preprocess_response_void(response, result, context); + auto response_properties = protocol::file_response_parsers::parse_file_properties(response); + properties->update_etag_and_last_modified(response_properties); + properties->update_lease(response_properties); + }); + + return core::executor::execute_async(command, modified_options, context); + } + +}} diff --git a/Microsoft.WindowsAzure.Storage/src/file_request_factory.cpp b/Microsoft.WindowsAzure.Storage/src/file_request_factory.cpp index 068c130c..170e74b3 100644 --- a/Microsoft.WindowsAzure.Storage/src/file_request_factory.cpp +++ b/Microsoft.WindowsAzure.Storage/src/file_request_factory.cpp @@ -218,6 +218,11 @@ namespace azure { namespace storage { namespace protocol { } } + void add_access_condition(web::http::http_request& request, const file_access_condition& condition) + { + add_optional_header(request.headers(), ms_header_lease_id, condition.lease_id()); + } + web::http::http_request list_shares(const utility::string_t& prefix, bool get_metadata, int max_results, const continuation_token& token, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { uri_builder.append_query(core::make_query_parameter(uri_query_component, component_list, /* do_encoding */ false)); @@ -365,7 +370,7 @@ namespace azure { namespace storage { namespace protocol { return request; } - + web::http::http_request set_file_directory_metadata(const cloud_metadata& metadata, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { uri_builder.append_query(core::make_query_parameter(uri_query_resource_type, resource_directory, /* do_encoding */ false)); @@ -384,7 +389,7 @@ namespace azure { namespace storage { namespace protocol { { uri_builder.append_query(core::make_query_parameter(uri_query_prefix, prefix)); } - + if (!token.empty()) { uri_builder.append_query(core::make_query_parameter(uri_query_marker, token.next_marker())); @@ -399,7 +404,7 @@ namespace azure { namespace storage { namespace protocol { return request; } - web::http::http_request create_file(const int64_t length, const cloud_metadata& metadata, const cloud_file_properties& properties, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) + web::http::http_request create_file(const int64_t length, const cloud_metadata& metadata, const cloud_file_properties& properties, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { web::http::http_request request(base_request(web::http::methods::PUT, uri_builder, timeout, context)); @@ -410,22 +415,25 @@ namespace azure { namespace storage { namespace protocol { add_optional_header(request.headers(), _XPLATSTR("x-ms-type"), _XPLATSTR("file")); request.headers()[ms_header_content_length] = core::convert_to_string(length); + add_access_condition(request, condition); return request; } - web::http::http_request delete_file(web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) + web::http::http_request delete_file(const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { web::http::http_request request(base_request(web::http::methods::DEL, uri_builder, timeout, context)); + add_access_condition(request, condition); return request; } - web::http::http_request get_file_properties(web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) + web::http::http_request get_file_properties(const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { web::http::http_request request(base_request(web::http::methods::HEAD, uri_builder, timeout, context)); + add_access_condition(request, condition); return request; } - - web::http::http_request set_file_properties(const cloud_file_properties& properties, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) + + web::http::http_request set_file_properties(const cloud_file_properties& properties, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { uri_builder.append_query(core::make_query_parameter(uri_query_component, component_properties, /* do_encoding */ false)); @@ -434,71 +442,72 @@ namespace azure { namespace storage { namespace protocol { //If resize is needed, user should call azure::storage::cloud_file::resize instead. add_file_properties(request, properties); add_additional_properties(request, properties, file_operation_type::update); + add_access_condition(request, condition); return request; } - web::http::http_request resize_with_properties(const cloud_file_properties & properties, web::http::uri_builder uri_builder, const std::chrono::seconds & timeout, operation_context context) + web::http::http_request resize_with_properties(const cloud_file_properties & properties, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds & timeout, operation_context context) { - auto request = set_file_properties(properties, uri_builder, timeout, context); - + auto request = set_file_properties(properties, condition, uri_builder, timeout, context); request.headers()[ms_header_content_length] = core::convert_to_string(properties.length()); return request; } - - web::http::http_request set_file_metadata(const cloud_metadata& metadata, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) + + web::http::http_request set_file_metadata(const cloud_metadata& metadata, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { uri_builder.append_query(core::make_query_parameter(uri_query_component, component_metadata, /* do_encoding */ false)); web::http::http_request request(base_request(web::http::methods::PUT, uri_builder, timeout, context)); add_metadata(request, metadata); + add_access_condition(request, condition); return request; } - - web::http::http_request copy_file(const web::http::uri& source, const cloud_metadata& metadata, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) + web::http::http_request copy_file(const web::http::uri& source, const cloud_metadata& metadata, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { web::http::http_request request(base_request(web::http::methods::PUT, uri_builder, timeout, context)); request.headers().add(ms_header_copy_source, source.to_string()); add_metadata(request, metadata); - + add_access_condition(request, condition); return request; } - web::http::http_request copy_file_from_blob(const web::http::uri& source, const access_condition& condition, const cloud_metadata& metadata, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) + web::http::http_request copy_file_from_blob(const web::http::uri& source, const access_condition& condition, const cloud_metadata& metadata, const file_access_condition& file_condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { web::http::http_request request(base_request(web::http::methods::PUT, uri_builder, timeout, context)); request.headers().add(ms_header_copy_source, source.to_string()); add_source_access_condition(request, condition); add_metadata(request, metadata); - + add_access_condition(request, file_condition); return request; } - web::http::http_request abort_copy_file(const utility::string_t& copy_id, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) + web::http::http_request abort_copy_file(const utility::string_t& copy_id, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { uri_builder.append_query(core::make_query_parameter(uri_query_component, component_copy, /* do_encoding */ false)); uri_builder.append_query(core::make_query_parameter(uri_query_copy_id, copy_id, /* do_encoding */ false)); web::http::http_request request(base_request(web::http::methods::PUT, uri_builder, timeout, context)); request.headers().add(ms_header_copy_action, header_value_copy_abort); + add_access_condition(request, condition); return request; } - web::http::http_request list_file_ranges(utility::size64_t start_offset, utility::size64_t length, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) + web::http::http_request list_file_ranges(utility::size64_t start_offset, utility::size64_t length, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { uri_builder.append_query(core::make_query_parameter(uri_query_component, component_range_list, /* do_encoding */ false)); - + web::http::http_request request(base_request(web::http::methods::GET, uri_builder, timeout, context)); add_file_range(request, start_offset, length); - + add_access_condition(request, condition); return request; } - web::http::http_request put_file_range(file_range range, file_range_write write, utility::string_t content_md5, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) + web::http::http_request put_file_range(file_range range, file_range_write write, utility::string_t content_md5, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { uri_builder.append_query(core::make_query_parameter(uri_query_component, component_range, /* do_encoding */ false)); web::http::http_request request(base_request(web::http::methods::PUT, uri_builder, timeout, context)); - + web::http::http_headers& headers = request.headers(); headers.add(ms_header_range, range.to_string()); @@ -513,10 +522,11 @@ namespace azure { namespace storage { namespace protocol { headers.add(_XPLATSTR("x-ms-write"), _XPLATSTR("clear")); break; } + add_access_condition(request, condition); return request; } - web::http::http_request get_file(utility::size64_t start_offset, utility::size64_t length, bool md5_validation, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) + web::http::http_request get_file(utility::size64_t start_offset, utility::size64_t length, bool md5_validation, const file_access_condition& condition, web::http::uri_builder uri_builder, const std::chrono::seconds& timeout, operation_context context) { web::http::http_request request(base_request(web::http::methods::GET, uri_builder, timeout, context)); web::http::http_headers& headers = request.headers(); @@ -526,6 +536,29 @@ namespace azure { namespace storage { namespace protocol { { headers.add(ms_header_range_get_content_md5, header_value_true); } + add_access_condition(request, condition); + return request; + } + + web::http::http_request lease_file(const utility::string_t& lease_action, const utility::string_t& proposed_lease_id, const file_access_condition& condition, web::http::uri_builder& uri_builder, const std::chrono::seconds& timeout, operation_context context) + { + uri_builder.append_query(core::make_query_parameter(uri_query_component, component_lease, /* do_encoding */ false)); + web::http::http_request request(base_request(web::http::methods::PUT, uri_builder, timeout, context)); + + web::http::http_headers& headers = request.headers(); + headers.add(ms_header_lease_action, lease_action); + if (lease_action == header_value_lease_acquire) + { + headers.add(ms_header_lease_duration, "-1"); + add_optional_header(headers, ms_header_lease_proposed_id, proposed_lease_id); + } + else if (lease_action == header_value_lease_change) + { + add_optional_header(headers, ms_header_lease_proposed_id, proposed_lease_id); + } + + add_access_condition(request, condition); + return request; } -}}} \ No newline at end of file +}}} diff --git a/Microsoft.WindowsAzure.Storage/src/file_response_parsers.cpp b/Microsoft.WindowsAzure.Storage/src/file_response_parsers.cpp index c8848a4e..b2082126 100644 --- a/Microsoft.WindowsAzure.Storage/src/file_response_parsers.cpp +++ b/Microsoft.WindowsAzure.Storage/src/file_response_parsers.cpp @@ -93,6 +93,10 @@ namespace azure { namespace storage { namespace protocol { properties.m_file_id = get_header_value(headers, ms_header_file_id); properties.m_parent_id = get_header_value(headers, ms_header_file_parent_id); + properties.m_lease_status = parse_lease_status(response); + properties.m_lease_state = parse_lease_state(response); + properties.m_lease_duration = parse_lease_duration(response); + return properties; } diff --git a/Microsoft.WindowsAzure.Storage/tests/cloud_file_directory_test.cpp b/Microsoft.WindowsAzure.Storage/tests/cloud_file_directory_test.cpp index 3d321015..14eaa638 100644 --- a/Microsoft.WindowsAzure.Storage/tests/cloud_file_directory_test.cpp +++ b/Microsoft.WindowsAzure.Storage/tests/cloud_file_directory_test.cpp @@ -322,7 +322,7 @@ SUITE(File) m_directory.get_subdirectory_reference(exclude_prefix + azure::storage::core::convert_to_string(i)).create(); } - int num_items_expected = directories.size() + files.size(); + size_t num_items_expected = directories.size() + files.size(); int num_items_actual = 0; for (auto&& item : m_directory.list_files_and_directories(prefix)) { diff --git a/Microsoft.WindowsAzure.Storage/tests/cloud_file_test.cpp b/Microsoft.WindowsAzure.Storage/tests/cloud_file_test.cpp index 16249adf..5685dc3c 100644 --- a/Microsoft.WindowsAzure.Storage/tests/cloud_file_test.cpp +++ b/Microsoft.WindowsAzure.Storage/tests/cloud_file_test.cpp @@ -48,7 +48,7 @@ SUITE(File) CHECK(!m_file.create_if_not_exists(1024U, azure::storage::file_access_condition(), azure::storage::file_request_options(), m_context)); CHECK_EQUAL(m_file.properties().length(), 1024U); m_file.download_attributes(); - + CHECK_EQUAL(m_file.properties().server_encrypted(), true); CHECK(m_file.exists(azure::storage::file_access_condition(), azure::storage::file_request_options(), m_context)); @@ -159,7 +159,7 @@ SUITE(File) m_file.upload_properties(); CHECK(m_file.properties().permission().empty()); CHECK(m_file.properties().permission_key() == properties.permission_key()); - CHECK_EQUAL(m_file.properties().attributes(), properties.attributes()); + CHECK(m_file.properties().attributes() == properties.attributes()); CHECK(m_file.properties().creation_time() == properties.creation_time()); CHECK(m_file.properties().last_write_time() == properties.last_write_time()); CHECK(m_file.properties().file_id() == properties.file_id()); @@ -179,7 +179,7 @@ SUITE(File) m_file.upload_properties(); CHECK(m_file.properties().permission().empty()); CHECK(!m_file.properties().permission_key().empty()); - CHECK_EQUAL(m_file.properties().attributes(), new_attributes); + CHECK(m_file.properties().attributes() == new_attributes); CHECK(m_file.properties().creation_time() == current_time); CHECK(m_file.properties().last_write_time() == current_time); @@ -211,7 +211,7 @@ SUITE(File) directory.upload_properties(); CHECK(directory.properties().permission().empty()); CHECK(directory.properties().permission_key() == properties.permission_key()); - CHECK_EQUAL(directory.properties().attributes(), properties.attributes()); + CHECK(directory.properties().attributes() == properties.attributes()); CHECK(directory.properties().creation_time() == properties.creation_time()); CHECK(directory.properties().last_write_time() == properties.last_write_time()); CHECK(directory.properties().file_id() == properties.file_id()); @@ -231,7 +231,7 @@ SUITE(File) directory.upload_properties(); CHECK(directory.properties().permission().empty()); CHECK(!directory.properties().permission_key().empty()); - CHECK_EQUAL(directory.properties().attributes(), new_attributes); + CHECK(directory.properties().attributes() == new_attributes); CHECK(directory.properties().creation_time() == current_time); CHECK(directory.properties().last_write_time() == current_time); @@ -405,7 +405,7 @@ SUITE(File) /// create dest files with specified sas credentials, only read access to dest read file and only write access to dest write file. auto dest_file_name = this->get_random_string(); auto dest = m_directory.get_file_reference(dest_file_name); - + /// try to copy from source blob to dest file, use dest_read_file to check copy stats. auto copy_id = dest.start_copy(source_blob, azure::storage::access_condition(), azure::storage::file_access_condition(), azure::storage::file_request_options(), m_context); CHECK(wait_for_copy(dest)); @@ -537,7 +537,7 @@ SUITE(File) { auto range = ranges1.at(0); CHECK(range.start_offset() == 0); - CHECK((range.end_offset() - range.start_offset() + 1) == content.length()); + CHECK(size_t(range.end_offset() - range.start_offset() + 1) == content.length()); } m_file.clear_range(0, content.length()); auto ranges_clear = m_file.list_ranges(0, 2048, azure::storage::file_access_condition(), azure::storage::file_request_options(), m_context); @@ -547,7 +547,7 @@ SUITE(File) { auto range = ranges1.at(0); CHECK(range.start_offset() == 0); - CHECK((range.end_offset() - range.start_offset() + 1) == content.length()); + CHECK(size_t(range.end_offset() - range.start_offset() + 1) == content.length()); } // verify write range with total length larger than the content. @@ -880,4 +880,185 @@ SUITE(File) check_parallelism(context, 1); CHECK(file.properties().size() == target_length); } + + TEST_FIXTURE(file_test_base, file_lease) + { + m_file.create(1024); + CHECK(azure::storage::lease_status::unspecified == m_file.properties().lease_status()); + CHECK(azure::storage::lease_state::unspecified == m_file.properties().lease_state()); + CHECK(azure::storage::lease_duration::unspecified == m_file.properties().lease_duration()); + m_file.download_attributes(); + CHECK(azure::storage::lease_status::unlocked == m_file.properties().lease_status()); + CHECK(azure::storage::lease_state::available == m_file.properties().lease_state()); + CHECK(azure::storage::lease_duration::unspecified == m_file.properties().lease_duration()); + + // Acquire + utility::string_t lease_id = m_file.acquire_lease(utility::string_t()); + CHECK(azure::storage::lease_status::unspecified == m_file.properties().lease_status()); + CHECK(azure::storage::lease_state::unspecified == m_file.properties().lease_state()); + CHECK(azure::storage::lease_duration::unspecified == m_file.properties().lease_duration()); + m_file.download_attributes(); + CHECK(azure::storage::lease_status::locked == m_file.properties().lease_status()); + CHECK(azure::storage::lease_state::leased == m_file.properties().lease_state()); + CHECK(azure::storage::lease_duration::infinite == m_file.properties().lease_duration()); + + // Change + utility::string_t lease_id2 = utility::uuid_to_string(utility::new_uuid()); + azure::storage::file_access_condition condition; + condition.set_lease_id(lease_id); + lease_id = m_file.change_lease(lease_id2, condition); + utility::details::inplace_tolower(lease_id); + utility::details::inplace_tolower(lease_id2); + CHECK(lease_id == lease_id2); + CHECK(azure::storage::lease_status::unspecified == m_file.properties().lease_status()); + CHECK(azure::storage::lease_state::unspecified == m_file.properties().lease_state()); + CHECK(azure::storage::lease_duration::unspecified == m_file.properties().lease_duration()); + + // Break + m_file.break_lease(); + CHECK(azure::storage::lease_status::unspecified == m_file.properties().lease_status()); + CHECK(azure::storage::lease_state::unspecified == m_file.properties().lease_state()); + CHECK(azure::storage::lease_duration::unspecified == m_file.properties().lease_duration()); + m_file.download_attributes(); + CHECK(azure::storage::lease_status::unlocked == m_file.properties().lease_status()); + CHECK(azure::storage::lease_state::broken == m_file.properties().lease_state()); + CHECK(azure::storage::lease_duration::unspecified == m_file.properties().lease_duration()); + + lease_id = m_file.acquire_lease(utility::string_t()); + condition.set_lease_id(lease_id); + m_file.break_lease(condition, azure::storage::file_request_options(), m_context); + + // Acquire with proposed lease id + lease_id2 = utility::uuid_to_string(utility::new_uuid()); + lease_id = m_file.acquire_lease(lease_id2); + utility::details::inplace_tolower(lease_id); + utility::details::inplace_tolower(lease_id2); + CHECK(lease_id == lease_id2); + + // Release + CHECK_THROW(m_file.release_lease(condition), azure::storage::storage_exception); + condition.set_lease_id(lease_id); + m_file.release_lease(condition); + CHECK(azure::storage::lease_status::unspecified == m_file.properties().lease_status()); + CHECK(azure::storage::lease_state::unspecified == m_file.properties().lease_state()); + CHECK(azure::storage::lease_duration::unspecified == m_file.properties().lease_duration()); + m_file.download_attributes(); + CHECK(azure::storage::lease_status::unlocked == m_file.properties().lease_status()); + CHECK(azure::storage::lease_state::available == m_file.properties().lease_state()); + CHECK(azure::storage::lease_duration::unspecified == m_file.properties().lease_duration()); + } + + TEST_FIXTURE(file_test_base, file_operations_with_lease) + { + m_file.create(1024); + utility::string_t lease_id = m_file.acquire_lease(utility::string_t()); + + azure::storage::file_access_condition lease_condition; + lease_condition.set_lease_id(lease_id); + azure::storage::file_access_condition wrong_condition; + wrong_condition.set_lease_id(utility::uuid_to_string(utility::new_uuid())); + azure::storage::file_access_condition empty_condition; + + std::vector conditions = + { + empty_condition, wrong_condition, lease_condition + }; + + utility::string_t upload_content = _XPLATSTR("content"); + concurrency::streams::container_buffer> download_buffer; + auto copy_src = m_directory.get_file_reference(_XPLATSTR("copy_src")); + copy_src.create(1024); + copy_src.upload_text(upload_content); + utility::string_t copy_id; + std::vector> funcs = + { + // Create + [&](azure::storage::file_access_condition condition) { m_file.create(2048, condition, azure::storage::file_request_options(), m_context); }, + // Create if not exists + [&](azure::storage::file_access_condition condition) { m_file.create_if_not_exists(2048, condition, azure::storage::file_request_options(), m_context); }, + // Download attributes + [&](azure::storage::file_access_condition condition) { m_file.download_attributes(condition, azure::storage::file_request_options(), m_context); }, + // Exist + [&](azure::storage::file_access_condition condition) { m_file.exists(condition, azure::storage::file_request_options(), m_context); }, + // Upload properties + [&](azure::storage::file_access_condition condition) { m_file.upload_properties(condition, azure::storage::file_request_options(), m_context); }, + // Upload metadata + [&](azure::storage::file_access_condition condition) { m_file.upload_metadata(condition, azure::storage::file_request_options(), m_context); }, + // Resize + [&](azure::storage::file_access_condition condition) { m_file.resize(4096, condition, azure::storage::file_request_options(), m_context); }, + // Upload from stream + [&](azure::storage::file_access_condition condition) { m_file.upload_from_stream(concurrency::streams::bytestream::open_istream(utility::conversions::to_utf8string(upload_content)), condition, azure::storage::file_request_options(), m_context); }, + // Write range + [&](azure::storage::file_access_condition condition) { m_file.write_range(concurrency::streams::bytestream::open_istream(utility::conversions::to_utf8string(upload_content)), 0, utility::string_t(), condition, azure::storage::file_request_options(), m_context); }, + // List ranges + [&](azure::storage::file_access_condition condition) { m_file.list_ranges(0, 4096, condition, azure::storage::file_request_options(), m_context); }, + // Download range + [&](azure::storage::file_access_condition condition) { m_file.download_to_stream(download_buffer.create_ostream(), condition, azure::storage::file_request_options(), m_context); }, + // Clear range + [&](azure::storage::file_access_condition condition) { m_file.clear_range(0, 1, condition, azure::storage::file_request_options(), m_context); }, + // Start copy + [&](azure::storage::file_access_condition condition) + { + auto id = m_file.start_copy(copy_src.uri().primary_uri(), azure::storage::access_condition(), condition, azure::storage::file_request_options(), m_context); + copy_id = id.empty() ? copy_id : id; + }, + // Abort copy + [&](azure::storage::file_access_condition condition) { m_file.abort_copy(copy_id, condition, azure::storage::file_request_options(), m_context); }, + // Delete if exists + [&](azure::storage::file_access_condition condition) { m_file.delete_file_if_exists(condition, azure::storage::file_request_options(), m_context); }, + }; + + std::vector> expected_results = + { + // Create + {0, 0, 1}, + // Create if not exists + {0, 0, 1}, + // Download Attributes + {1, 0, 1}, + // Exist + {1, 0, 1}, + // Upload properties + {0, 0, 1}, + // Upload metadata + {0, 0, 1}, + // Resize + {0, 0, 1}, + // Upload from stream + {0, 0, 1}, + // Write range + {0, 0, 1}, + // List ranges + {1, 0, 1}, + // Download range + {1, 0, 1}, + // Clear range + {0, 0, 1}, + // Start copy + {0, 0, 1}, + // Abort copy + {0, 0, 1}, + // Delete if exists + {0, 0, 1}, + }; + CHECK_EQUAL(funcs.size(), expected_results.size()); + + for (int i = 0; i < funcs.size(); ++i) + { + for (int j = 0; j < conditions.size(); ++j) + { + try + { + funcs[i](conditions[j]); + } + catch (azure::storage::storage_exception& e) + { + if (expected_results[i][j] == true && e.result().http_status_code() == web::http::status_codes::PreconditionFailed) + { + throw; + } + } + } + } + } }