1# ------------------------------------------------------------------------- 2# Copyright (c) Microsoft Corporation. All rights reserved. 3# Licensed under the MIT License. See License.txt in the project root for 4# license information. 5# -------------------------------------------------------------------------- 6# pylint: disable=too-many-lines 7import functools 8import time 9from io import BytesIO 10from typing import Optional, Union, IO, List, Dict, Any, Iterable, TYPE_CHECKING # pylint: disable=unused-import 11 12import six 13from azure.core.async_paging import AsyncItemPaged 14 15from azure.core.tracing.decorator import distributed_trace 16from azure.core.tracing.decorator_async import distributed_trace_async 17from .._parser import _datetime_to_str, _get_file_permission 18from .._shared.parser import _str 19 20from .._generated.aio import AzureFileStorage 21from .._generated.version import VERSION 22from .._generated.models import StorageErrorException, FileHTTPHeaders 23from .._shared.policies_async import ExponentialRetry 24from .._shared.uploads_async import upload_data_chunks, FileChunkUploader, IterStreamer 25from .._shared.base_client_async import AsyncStorageAccountHostsMixin 26from .._shared.request_handlers import add_metadata_headers, get_length 27from .._shared.response_handlers import return_response_headers, process_storage_error 28from .._deserialize import deserialize_file_properties, deserialize_file_stream 29from .._serialize import get_access_conditions, get_smb_properties, get_api_version 30from .._file_client import ShareFileClient as ShareFileClientBase 31from ._models import HandlesPaged 32from ._lease_async import ShareLeaseClient 33from ._download_async import StorageStreamDownloader 34 35if TYPE_CHECKING: 36 from datetime import datetime 37 from .._models import ShareProperties, ContentSettings, FileProperties, NTFSAttributes 38 from .._generated.models import HandleItem 39 40 41async def _upload_file_helper( 42 client, 43 stream, 44 size, 45 metadata, 46 content_settings, 47 validate_content, 48 timeout, 49 max_concurrency, 50 file_settings, 51 file_attributes="none", 52 file_creation_time="now", 53 file_last_write_time="now", 54 file_permission=None, 55 file_permission_key=None, 56 **kwargs 57): 58 try: 59 if size is None or size < 0: 60 raise ValueError("A content size must be specified for a File.") 61 response = await client.create_file( 62 size, content_settings=content_settings, metadata=metadata, 63 file_attributes=file_attributes, 64 file_creation_time=file_creation_time, 65 file_last_write_time=file_last_write_time, 66 file_permission=file_permission, 67 permission_key=file_permission_key, 68 timeout=timeout, 69 **kwargs 70 ) 71 if size == 0: 72 return response 73 74 responses = await upload_data_chunks( 75 service=client, 76 uploader_class=FileChunkUploader, 77 total_size=size, 78 chunk_size=file_settings.max_range_size, 79 stream=stream, 80 max_concurrency=max_concurrency, 81 validate_content=validate_content, 82 timeout=timeout, 83 **kwargs 84 ) 85 return sorted(responses, key=lambda r: r.get('last_modified'))[-1] 86 except StorageErrorException as error: 87 process_storage_error(error) 88 89 90class ShareFileClient(AsyncStorageAccountHostsMixin, ShareFileClientBase): 91 """A client to interact with a specific file, although that file may not yet exist. 92 93 :param str account_url: 94 The URI to the storage account. In order to create a client given the full URI to the 95 file, use the :func:`from_file_url` classmethod. 96 :param share_name: 97 The name of the share for the file. 98 :type share_name: str 99 :param str file_path: 100 The file path to the file with which to interact. If specified, this value will override 101 a file value specified in the file URL. 102 :param str snapshot: 103 An optional file snapshot on which to operate. This can be the snapshot ID string 104 or the response returned from :func:`ShareClient.create_snapshot`. 105 :param credential: 106 The credential with which to authenticate. This is optional if the 107 account URL already has a SAS token. The value can be a SAS token string or an account 108 shared access key. 109 :keyword str api_version: 110 The Storage API version to use for requests. Default value is '2019-07-07'. 111 Setting to an older version may result in reduced feature compatibility. 112 113 .. versionadded:: 12.1.0 114 115 :keyword str secondary_hostname: 116 The hostname of the secondary endpoint. 117 :keyword loop: 118 The event loop to run the asynchronous tasks. 119 :keyword int max_range_size: The maximum range size used for a file upload. Defaults to 4*1024*1024. 120 """ 121 122 def __init__( # type: ignore 123 self, 124 account_url, # type: str 125 share_name, # type: str 126 file_path, # type: str 127 snapshot=None, # type: Optional[Union[str, Dict[str, Any]]] 128 credential=None, # type: Optional[Any] 129 **kwargs # type: Any 130 ): 131 # type: (...) -> None 132 kwargs["retry_policy"] = kwargs.get("retry_policy") or ExponentialRetry(**kwargs) 133 loop = kwargs.pop('loop', None) 134 super(ShareFileClient, self).__init__( 135 account_url, share_name=share_name, file_path=file_path, snapshot=snapshot, 136 credential=credential, loop=loop, **kwargs 137 ) 138 self._client = AzureFileStorage(version=VERSION, url=self.url, pipeline=self._pipeline, loop=loop) 139 self._client._config.version = get_api_version(kwargs, VERSION) # pylint: disable=protected-access 140 self._loop = loop 141 142 @distributed_trace_async 143 async def acquire_lease(self, lease_id=None, **kwargs): 144 # type: (int, Optional[str], **Any) -> BlobLeaseClient 145 """Requests a new lease. 146 147 If the file does not have an active lease, the File 148 Service creates a lease on the blob and returns a new lease. 149 150 :param str lease_id: 151 Proposed lease ID, in a GUID string format. The File Service 152 returns 400 (Invalid request) if the proposed lease ID is not 153 in the correct format. 154 :keyword int timeout: 155 The timeout parameter is expressed in seconds. 156 :returns: A ShareLeaseClient object. 157 :rtype: ~azure.storage.fileshare.aio.ShareLeaseClient 158 159 .. admonition:: Example: 160 161 .. literalinclude:: ../samples/blob_samples_common.py 162 :start-after: [START acquire_lease_on_blob] 163 :end-before: [END acquire_lease_on_blob] 164 :language: python 165 :dedent: 8 166 :caption: Acquiring a lease on a blob. 167 """ 168 lease = ShareLeaseClient(self, lease_id=lease_id) # type: ignore 169 await lease.acquire(**kwargs) 170 return lease 171 172 @distributed_trace_async 173 async def create_file( # type: ignore 174 self, 175 size, # type: int 176 file_attributes="none", # type: Union[str, NTFSAttributes] 177 file_creation_time="now", # type: Union[str, datetime] 178 file_last_write_time="now", # type: Union[str, datetime] 179 file_permission=None, # type: Optional[str] 180 permission_key=None, # type: Optional[str] 181 **kwargs # type: Any 182 ): 183 # type: (...) -> Dict[str, Any] 184 """Creates a new file. 185 186 Note that it only initializes the file with no content. 187 188 :param int size: Specifies the maximum size for the file, 189 up to 1 TB. 190 :param file_attributes: 191 The file system attributes for files and directories. 192 If not set, the default value would be "None" and the attributes will be set to "Archive". 193 Here is an example for when the var type is str: 'Temporary|Archive'. 194 file_attributes value is not case sensitive. 195 :type file_attributes: str or :class:`~azure.storage.fileshare.NTFSAttributes` 196 :param file_creation_time: Creation time for the file 197 Default value: Now. 198 :type file_creation_time: str or ~datetime.datetime 199 :param file_last_write_time: Last write time for the file 200 Default value: Now. 201 :type file_last_write_time: str or ~datetime.datetime 202 :param file_permission: If specified the permission (security 203 descriptor) shall be set for the directory/file. This header can be 204 used if Permission size is <= 8KB, else x-ms-file-permission-key 205 header shall be used. Default value: Inherit. If SDDL is specified as 206 input, it must have owner, group and dacl. Note: Only one of the 207 x-ms-file-permission or x-ms-file-permission-key should be specified. 208 :type file_permission: str 209 :param permission_key: Key of the permission to be set for the 210 directory/file. Note: Only one of the x-ms-file-permission or 211 x-ms-file-permission-key should be specified. 212 :type permission_key: str 213 :keyword ~azure.storage.fileshare.ContentSettings content_settings: 214 ContentSettings object used to set file properties. Used to set content type, encoding, 215 language, disposition, md5, and cache control. 216 :keyword dict(str,str) metadata: 217 Name-value pairs associated with the file as metadata. 218 :keyword lease: 219 Required if the file has an active lease. Value can be a ShareLeaseClient object 220 or the lease ID as a string. 221 222 .. versionadded:: 12.1.0 223 224 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 225 :keyword int timeout: 226 The timeout parameter is expressed in seconds. 227 :returns: File-updated property dict (Etag and last modified). 228 :rtype: dict(str, Any) 229 230 .. admonition:: Example: 231 232 .. literalinclude:: ../samples/file_samples_client_async.py 233 :start-after: [START create_file] 234 :end-before: [END create_file] 235 :language: python 236 :dedent: 16 237 :caption: Create a file. 238 """ 239 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 240 content_settings = kwargs.pop('content_settings', None) 241 metadata = kwargs.pop('metadata', None) 242 timeout = kwargs.pop('timeout', None) 243 if self.require_encryption and not self.key_encryption_key: 244 raise ValueError("Encryption required but no key was provided.") 245 246 headers = kwargs.pop("headers", {}) 247 headers.update(add_metadata_headers(metadata)) 248 file_http_headers = None 249 if content_settings: 250 file_http_headers = FileHTTPHeaders( 251 file_cache_control=content_settings.cache_control, 252 file_content_type=content_settings.content_type, 253 file_content_md5=bytearray(content_settings.content_md5) if content_settings.content_md5 else None, 254 file_content_encoding=content_settings.content_encoding, 255 file_content_language=content_settings.content_language, 256 file_content_disposition=content_settings.content_disposition, 257 ) 258 file_permission = _get_file_permission(file_permission, permission_key, 'Inherit') 259 try: 260 return await self._client.file.create( # type: ignore 261 file_content_length=size, 262 metadata=metadata, 263 file_attributes=_str(file_attributes), 264 file_creation_time=_datetime_to_str(file_creation_time), 265 file_last_write_time=_datetime_to_str(file_last_write_time), 266 file_permission=file_permission, 267 file_permission_key=permission_key, 268 file_http_headers=file_http_headers, 269 lease_access_conditions=access_conditions, 270 headers=headers, 271 timeout=timeout, 272 cls=return_response_headers, 273 **kwargs 274 ) 275 except StorageErrorException as error: 276 process_storage_error(error) 277 278 @distributed_trace_async 279 async def upload_file( 280 self, data, # type: Any 281 length=None, # type: Optional[int] 282 file_attributes="none", # type: Union[str, NTFSAttributes] 283 file_creation_time="now", # type: Union[str, datetime] 284 file_last_write_time="now", # type: Union[str, datetime] 285 file_permission=None, # type: Optional[str] 286 permission_key=None, # type: Optional[str] 287 **kwargs # type: Any 288 ): 289 # type: (...) -> Dict[str, Any] 290 """Uploads a new file. 291 292 :param Any data: 293 Content of the file. 294 :param int length: 295 Length of the file in bytes. Specify its maximum size, up to 1 TiB. 296 :param file_attributes: 297 The file system attributes for files and directories. 298 If not set, the default value would be "None" and the attributes will be set to "Archive". 299 Here is an example for when the var type is str: 'Temporary|Archive'. 300 file_attributes value is not case sensitive. 301 :type file_attributes: str or ~azure.storage.fileshare.NTFSAttributes 302 :param file_creation_time: Creation time for the file 303 Default value: Now. 304 :type file_creation_time: str or ~datetime.datetime 305 :param file_last_write_time: Last write time for the file 306 Default value: Now. 307 :type file_last_write_time: str or ~datetime.datetime 308 :param file_permission: If specified the permission (security 309 descriptor) shall be set for the directory/file. This header can be 310 used if Permission size is <= 8KB, else x-ms-file-permission-key 311 header shall be used. Default value: Inherit. If SDDL is specified as 312 input, it must have owner, group and dacl. Note: Only one of the 313 x-ms-file-permission or x-ms-file-permission-key should be specified. 314 :type file_permission: str 315 :param permission_key: Key of the permission to be set for the 316 directory/file. Note: Only one of the x-ms-file-permission or 317 x-ms-file-permission-key should be specified. 318 :type permission_key: str 319 :keyword dict(str,str) metadata: 320 Name-value pairs associated with the file as metadata. 321 :keyword ~azure.storage.fileshare.ContentSettings content_settings: 322 ContentSettings object used to set file properties. Used to set content type, encoding, 323 language, disposition, md5, and cache control. 324 :keyword bool validate_content: 325 If true, calculates an MD5 hash for each range of the file. The storage 326 service checks the hash of the content that has arrived with the hash 327 that was sent. This is primarily valuable for detecting bitflips on 328 the wire if using http instead of https as https (the default) will 329 already validate. Note that this MD5 hash is not stored with the 330 file. 331 :keyword int max_concurrency: 332 Maximum number of parallel connections to use. 333 :keyword str encoding: 334 Defaults to UTF-8. 335 :keyword lease: 336 Required if the file has an active lease. Value can be a ShareLeaseClient object 337 or the lease ID as a string. 338 339 .. versionadded:: 12.1.0 340 341 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 342 :keyword int timeout: 343 The timeout parameter is expressed in seconds. 344 :returns: File-updated property dict (Etag and last modified). 345 :rtype: dict(str, Any) 346 347 .. admonition:: Example: 348 349 .. literalinclude:: ../samples/file_samples_client_async.py 350 :start-after: [START upload_file] 351 :end-before: [END upload_file] 352 :language: python 353 :dedent: 16 354 :caption: Upload a file. 355 """ 356 metadata = kwargs.pop('metadata', None) 357 content_settings = kwargs.pop('content_settings', None) 358 max_concurrency = kwargs.pop('max_concurrency', 1) 359 validate_content = kwargs.pop('validate_content', False) 360 timeout = kwargs.pop('timeout', None) 361 encoding = kwargs.pop('encoding', 'UTF-8') 362 if self.require_encryption or (self.key_encryption_key is not None): 363 raise ValueError("Encryption not supported.") 364 365 if isinstance(data, six.text_type): 366 data = data.encode(encoding) 367 if length is None: 368 length = get_length(data) 369 if isinstance(data, bytes): 370 data = data[:length] 371 372 if isinstance(data, bytes): 373 stream = BytesIO(data) 374 elif hasattr(data, "read"): 375 stream = data 376 elif hasattr(data, "__iter__"): 377 stream = IterStreamer(data, encoding=encoding) # type: ignore 378 else: 379 raise TypeError("Unsupported data type: {}".format(type(data))) 380 return await _upload_file_helper( # type: ignore 381 self, 382 stream, 383 length, 384 metadata, 385 content_settings, 386 validate_content, 387 timeout, 388 max_concurrency, 389 self._config, 390 file_attributes=file_attributes, 391 file_creation_time=file_creation_time, 392 file_last_write_time=file_last_write_time, 393 file_permission=file_permission, 394 file_permission_key=permission_key, 395 **kwargs 396 ) 397 398 @distributed_trace_async 399 async def start_copy_from_url(self, source_url, **kwargs): 400 # type: (str, Any) -> Any 401 """Initiates the copying of data from a source URL into the file 402 referenced by the client. 403 404 The status of this copy operation can be found using the `get_properties` 405 method. 406 407 :param str source_url: 408 Specifies the URL of the source file. 409 :keyword str file_permission: 410 If specified the permission (security descriptor) shall be set for the directory/file. 411 This value can be set to "source" to copy the security descriptor from the source file. 412 Otherwise if set, this value will be used to override the source value. If not set, permission value 413 is inherited from the parent directory of the target file. This setting can be 414 used if Permission size is <= 8KB, otherwise permission_key shall be used. 415 If SDDL is specified as input, it must have owner, group and dacl. 416 Note: Only one of the file_permission or permission_key should be specified. 417 418 .. versionadded:: 12.1.0 419 This parameter was introduced in API version '2019-07-07'. 420 421 :keyword str permission_key: 422 Key of the permission to be set for the directory/file. 423 This value can be set to "source" to copy the security descriptor from the source file. 424 Otherwise if set, this value will be used to override the source value. If not set, permission value 425 is inherited from the parent directory of the target file. 426 Note: Only one of the file_permission or permission_key should be specified. 427 428 .. versionadded:: 12.1.0 429 This parameter was introduced in API version '2019-07-07'. 430 431 :keyword file_attributes: 432 This value can be set to "source" to copy file attributes from the source file to the target file, 433 or to clear all attributes, it can be set to "None". Otherwise it can be set to a list of attributes 434 to set on the target file. If this is not set, the default value is "Archive". 435 436 .. versionadded:: 12.1.0 437 This parameter was introduced in API version '2019-07-07'. 438 439 :paramtype file_attributes: str or :class:`~azure.storage.fileshare.NTFSAttributes` 440 :keyword file_creation_time: 441 This value can be set to "source" to copy the creation time from the source file to the target file, 442 or a datetime to set as creation time on the target file. This could also be a string in ISO 8601 format. 443 If this is not set, creation time will be set to the date time value of the creation 444 (or when it was overwritten) of the target file by copy engine. 445 446 .. versionadded:: 12.1.0 447 This parameter was introduced in API version '2019-07-07'. 448 449 :paramtype file_creation_time: str or ~datetime.datetime 450 :keyword file_last_write_time: 451 This value can be set to "source" to copy the last write time from the source file to the target file, or 452 a datetime to set as the last write time on the target file. This could also be a string in ISO 8601 format. 453 If this is not set, value will be the last write time to the file by the copy engine. 454 455 .. versionadded:: 12.1.0 456 This parameter was introduced in API version '2019-07-07'. 457 458 :paramtype file_last_write_time: str or ~datetime.datetime 459 :keyword bool ignore_read_only: 460 Specifies the option to overwrite the target file if it already exists and has read-only attribute set. 461 462 .. versionadded:: 12.1.0 463 This parameter was introduced in API version '2019-07-07'. 464 465 :keyword bool set_archive_attribute: 466 Specifies the option to set the archive attribute on the target file. 467 True means the archive attribute will be set on the target file despite attribute 468 overrides or the source file state. 469 470 .. versionadded:: 12.1.0 471 This parameter was introduced in API version '2019-07-07'. 472 473 :keyword metadata: 474 Name-value pairs associated with the file as metadata. 475 :type metadata: dict(str, str) 476 :keyword lease: 477 Required if the file has an active lease. Value can be a ShareLeaseClient object 478 or the lease ID as a string. 479 480 .. versionadded:: 12.1.0 481 482 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 483 :keyword int timeout: 484 The timeout parameter is expressed in seconds. 485 :rtype: dict(str, Any) 486 487 .. admonition:: Example: 488 489 .. literalinclude:: ../samples/file_samples_client_async.py 490 :start-after: [START copy_file_from_url] 491 :end-before: [END copy_file_from_url] 492 :language: python 493 :dedent: 16 494 :caption: Copy a file from a URL 495 """ 496 metadata = kwargs.pop('metadata', None) 497 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 498 timeout = kwargs.pop('timeout', None) 499 headers = kwargs.pop("headers", {}) 500 headers.update(add_metadata_headers(metadata)) 501 kwargs.update(get_smb_properties(kwargs)) 502 try: 503 return await self._client.file.start_copy( 504 source_url, 505 metadata=metadata, 506 lease_access_conditions=access_conditions, 507 headers=headers, 508 cls=return_response_headers, 509 timeout=timeout, 510 **kwargs 511 ) 512 except StorageErrorException as error: 513 process_storage_error(error) 514 515 @distributed_trace_async 516 async def abort_copy(self, copy_id, **kwargs): 517 # type: (Union[str, FileProperties], Any) -> None 518 """Abort an ongoing copy operation. 519 520 This will leave a destination file with zero length and full metadata. 521 This will raise an error if the copy operation has already ended. 522 523 :param copy_id: 524 The copy operation to abort. This can be either an ID, or an 525 instance of FileProperties. 526 :type copy_id: str or ~azure.storage.fileshare.FileProperties 527 :keyword lease: 528 Required if the file has an active lease. Value can be a ShareLeaseClient object 529 or the lease ID as a string. 530 531 .. versionadded:: 12.1.0 532 533 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 534 :keyword int timeout: 535 The timeout parameter is expressed in seconds. 536 :rtype: None 537 """ 538 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 539 timeout = kwargs.pop('timeout', None) 540 try: 541 copy_id = copy_id.copy.id 542 except AttributeError: 543 try: 544 copy_id = copy_id["copy_id"] 545 except TypeError: 546 pass 547 try: 548 await self._client.file.abort_copy(copy_id=copy_id, 549 lease_access_conditions=access_conditions, 550 timeout=timeout, **kwargs) 551 except StorageErrorException as error: 552 process_storage_error(error) 553 554 @distributed_trace_async 555 async def download_file( 556 self, 557 offset=None, # type: Optional[int] 558 length=None, # type: Optional[int] 559 **kwargs 560 ): 561 # type: (...) -> Iterable[bytes] 562 """Downloads a file to a stream with automatic chunking. 563 564 :param int offset: 565 Start of byte range to use for downloading a section of the file. 566 Must be set if length is provided. 567 :param int length: 568 Number of bytes to read from the stream. This is optional, but 569 should be supplied for optimal performance. 570 :keyword int max_concurrency: 571 Maximum number of parallel connections to use. 572 :keyword bool validate_content: 573 If true, calculates an MD5 hash for each chunk of the file. The storage 574 service checks the hash of the content that has arrived with the hash 575 that was sent. This is primarily valuable for detecting bitflips on 576 the wire if using http instead of https as https (the default) will 577 already validate. Note that this MD5 hash is not stored with the 578 file. Also note that if enabled, the memory-efficient upload algorithm 579 will not be used, because computing the MD5 hash requires buffering 580 entire blocks, and doing so defeats the purpose of the memory-efficient algorithm. 581 :keyword lease: 582 Required if the file has an active lease. Value can be a ShareLeaseClient object 583 or the lease ID as a string. 584 585 .. versionadded:: 12.1.0 586 587 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 588 :keyword int timeout: 589 The timeout parameter is expressed in seconds. 590 :returns: A iterable data generator (stream) 591 592 .. admonition:: Example: 593 594 .. literalinclude:: ../samples/file_samples_client_async.py 595 :start-after: [START download_file] 596 :end-before: [END download_file] 597 :language: python 598 :dedent: 16 599 :caption: Download a file. 600 """ 601 if self.require_encryption or (self.key_encryption_key is not None): 602 raise ValueError("Encryption not supported.") 603 if length is not None and offset is None: 604 raise ValueError("Offset value must not be None if length is set.") 605 606 range_end = None 607 if length is not None: 608 range_end = offset + length - 1 # Service actually uses an end-range inclusive index 609 610 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 611 612 downloader = StorageStreamDownloader( 613 client=self._client.file, 614 config=self._config, 615 start_range=offset, 616 end_range=range_end, 617 encryption_options=None, 618 name=self.file_name, 619 path='/'.join(self.file_path), 620 share=self.share_name, 621 lease_access_conditions=access_conditions, 622 cls=deserialize_file_stream, 623 **kwargs 624 ) 625 await downloader._setup() # pylint: disable=protected-access 626 return downloader 627 628 @distributed_trace_async 629 async def delete_file(self, **kwargs): 630 # type: (Any) -> None 631 """Marks the specified file for deletion. The file is 632 later deleted during garbage collection. 633 634 :keyword lease: 635 Required if the file has an active lease. Value can be a ShareLeaseClient object 636 or the lease ID as a string. 637 638 .. versionadded:: 12.1.0 639 640 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 641 :keyword int timeout: 642 The timeout parameter is expressed in seconds. 643 :rtype: None 644 645 .. admonition:: Example: 646 647 .. literalinclude:: ../samples/file_samples_client_async.py 648 :start-after: [START delete_file] 649 :end-before: [END delete_file] 650 :language: python 651 :dedent: 16 652 :caption: Delete a file. 653 """ 654 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 655 timeout = kwargs.pop('timeout', None) 656 try: 657 await self._client.file.delete(lease_access_conditions=access_conditions, timeout=timeout, **kwargs) 658 except StorageErrorException as error: 659 process_storage_error(error) 660 661 @distributed_trace_async 662 async def get_file_properties(self, **kwargs): 663 # type: (Any) -> FileProperties 664 """Returns all user-defined metadata, standard HTTP properties, and 665 system properties for the file. 666 667 :keyword lease: 668 Required if the file has an active lease. Value can be a ShareLeaseClient object 669 or the lease ID as a string. 670 671 .. versionadded:: 12.1.0 672 673 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 674 :keyword int timeout: 675 The timeout parameter is expressed in seconds. 676 :returns: FileProperties 677 :rtype: ~azure.storage.fileshare.FileProperties 678 """ 679 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 680 timeout = kwargs.pop('timeout', None) 681 try: 682 file_props = await self._client.file.get_properties( 683 sharesnapshot=self.snapshot, 684 lease_access_conditions=access_conditions, 685 timeout=timeout, 686 cls=deserialize_file_properties, 687 **kwargs 688 ) 689 except StorageErrorException as error: 690 process_storage_error(error) 691 file_props.name = self.file_name 692 file_props.share = self.share_name 693 file_props.snapshot = self.snapshot 694 file_props.path = "/".join(self.file_path) 695 return file_props # type: ignore 696 697 @distributed_trace_async 698 async def set_http_headers(self, content_settings, # type: ContentSettings 699 file_attributes="preserve", # type: Union[str, NTFSAttributes] 700 file_creation_time="preserve", # type: Union[str, datetime] 701 file_last_write_time="preserve", # type: Union[str, datetime] 702 file_permission=None, # type: Optional[str] 703 permission_key=None, # type: Optional[str] 704 **kwargs # type: Any 705 ): 706 # type: (...) -> Dict[str, Any] 707 """Sets HTTP headers on the file. 708 709 :param ~azure.storage.fileshare.ContentSettings content_settings: 710 ContentSettings object used to set file properties. Used to set content type, encoding, 711 language, disposition, md5, and cache control. 712 :param file_attributes: 713 The file system attributes for files and directories. 714 If not set, indicates preservation of existing values. 715 Here is an example for when the var type is str: 'Temporary|Archive' 716 :type file_attributes: str or :class:`~azure.storage.fileshare.NTFSAttributes` 717 :param file_creation_time: Creation time for the file 718 Default value: Preserve. 719 :type file_creation_time: str or ~datetime.datetime 720 :param file_last_write_time: Last write time for the file 721 Default value: Preserve. 722 :type file_last_write_time: str or ~datetime.datetime 723 :param file_permission: If specified the permission (security 724 descriptor) shall be set for the directory/file. This header can be 725 used if Permission size is <= 8KB, else x-ms-file-permission-key 726 header shall be used. Default value: Inherit. If SDDL is specified as 727 input, it must have owner, group and dacl. Note: Only one of the 728 x-ms-file-permission or x-ms-file-permission-key should be specified. 729 :type file_permission: str 730 :param permission_key: Key of the permission to be set for the 731 directory/file. Note: Only one of the x-ms-file-permission or 732 x-ms-file-permission-key should be specified. 733 :type permission_key: str 734 :keyword lease: 735 Required if the file has an active lease. Value can be a ShareLeaseClient object 736 or the lease ID as a string. 737 738 .. versionadded:: 12.1.0 739 740 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 741 :keyword int timeout: 742 The timeout parameter is expressed in seconds. 743 :returns: File-updated property dict (Etag and last modified). 744 :rtype: dict(str, Any) 745 """ 746 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 747 timeout = kwargs.pop('timeout', None) 748 file_content_length = kwargs.pop("size", None) 749 file_http_headers = FileHTTPHeaders( 750 file_cache_control=content_settings.cache_control, 751 file_content_type=content_settings.content_type, 752 file_content_md5=bytearray(content_settings.content_md5) if content_settings.content_md5 else None, 753 file_content_encoding=content_settings.content_encoding, 754 file_content_language=content_settings.content_language, 755 file_content_disposition=content_settings.content_disposition, 756 ) 757 file_permission = _get_file_permission(file_permission, permission_key, 'preserve') 758 try: 759 return await self._client.file.set_http_headers( # type: ignore 760 file_content_length=file_content_length, 761 file_http_headers=file_http_headers, 762 file_attributes=_str(file_attributes), 763 file_creation_time=_datetime_to_str(file_creation_time), 764 file_last_write_time=_datetime_to_str(file_last_write_time), 765 file_permission=file_permission, 766 file_permission_key=permission_key, 767 lease_access_conditions=access_conditions, 768 timeout=timeout, 769 cls=return_response_headers, 770 **kwargs 771 ) 772 except StorageErrorException as error: 773 process_storage_error(error) 774 775 @distributed_trace_async 776 async def set_file_metadata(self, metadata=None, **kwargs): # type: ignore 777 # type: (Optional[Dict[str, Any]], Any) -> Dict[str, Any] 778 """Sets user-defined metadata for the specified file as one or more 779 name-value pairs. 780 781 Each call to this operation replaces all existing metadata 782 attached to the file. To remove all metadata from the file, 783 call this operation with no metadata dict. 784 785 :param metadata: 786 Name-value pairs associated with the file as metadata. 787 :type metadata: dict(str, str) 788 :keyword lease: 789 Required if the file has an active lease. Value can be a ShareLeaseClient object 790 or the lease ID as a string. 791 792 .. versionadded:: 12.1.0 793 794 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 795 :keyword int timeout: 796 The timeout parameter is expressed in seconds. 797 :returns: File-updated property dict (Etag and last modified). 798 :rtype: dict(str, Any) 799 """ 800 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 801 timeout = kwargs.pop('timeout', None) 802 headers = kwargs.pop("headers", {}) 803 headers.update(add_metadata_headers(metadata)) # type: ignore 804 try: 805 return await self._client.file.set_metadata( # type: ignore 806 metadata=metadata, lease_access_conditions=access_conditions, 807 timeout=timeout, cls=return_response_headers, headers=headers, **kwargs 808 ) 809 except StorageErrorException as error: 810 process_storage_error(error) 811 812 @distributed_trace_async 813 async def upload_range( # type: ignore 814 self, 815 data, # type: bytes 816 offset, # type: int 817 length, # type: int 818 **kwargs 819 ): 820 # type: (...) -> Dict[str, Any] 821 """Upload a range of bytes to a file. 822 823 :param bytes data: 824 The data to upload. 825 :param int offset: 826 Start of byte range to use for uploading a section of the file. 827 The range can be up to 4 MB in size. 828 :param int length: 829 Number of bytes to use for uploading a section of the file. 830 The range can be up to 4 MB in size. 831 :keyword bool validate_content: 832 If true, calculates an MD5 hash of the page content. The storage 833 service checks the hash of the content that has arrived 834 with the hash that was sent. This is primarily valuable for detecting 835 bitflips on the wire if using http instead of https as https (the default) 836 will already validate. Note that this MD5 hash is not stored with the 837 file. 838 :keyword lease: 839 Required if the file has an active lease. Value can be a ShareLeaseClient object 840 or the lease ID as a string. 841 842 .. versionadded:: 12.1.0 843 844 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 845 :keyword int timeout: 846 The timeout parameter is expressed in seconds. 847 :keyword str encoding: 848 Defaults to UTF-8. 849 :returns: File-updated property dict (Etag and last modified). 850 :rtype: Dict[str, Any] 851 """ 852 validate_content = kwargs.pop('validate_content', False) 853 timeout = kwargs.pop('timeout', None) 854 encoding = kwargs.pop('encoding', 'UTF-8') 855 if self.require_encryption or (self.key_encryption_key is not None): 856 raise ValueError("Encryption not supported.") 857 if isinstance(data, six.text_type): 858 data = data.encode(encoding) 859 end_range = offset + length - 1 # Reformat to an inclusive range index 860 content_range = 'bytes={0}-{1}'.format(offset, end_range) 861 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 862 try: 863 return await self._client.file.upload_range( # type: ignore 864 range=content_range, 865 content_length=length, 866 optionalbody=data, 867 timeout=timeout, 868 validate_content=validate_content, 869 lease_access_conditions=access_conditions, 870 cls=return_response_headers, 871 **kwargs 872 ) 873 except StorageErrorException as error: 874 process_storage_error(error) 875 876 @distributed_trace_async 877 async def upload_range_from_url(self, source_url, 878 offset, 879 length, 880 source_offset, 881 **kwargs 882 ): 883 # type: (str, int, int, int, **Any) -> Dict[str, Any] 884 """ 885 Writes the bytes from one Azure File endpoint into the specified range of another Azure File endpoint. 886 887 :param int offset: 888 Start of byte range to use for updating a section of the file. 889 The range can be up to 4 MB in size. 890 :param int length: 891 Number of bytes to use for updating a section of the file. 892 The range can be up to 4 MB in size. 893 :param str source_url: 894 A URL of up to 2 KB in length that specifies an Azure file or blob. 895 The value should be URL-encoded as it would appear in a request URI. 896 If the source is in another account, the source must either be public 897 or must be authenticated via a shared access signature. If the source 898 is public, no authentication is required. 899 Examples: 900 https://myaccount.file.core.windows.net/myshare/mydir/myfile 901 https://otheraccount.file.core.windows.net/myshare/mydir/myfile?sastoken 902 :param int source_offset: 903 This indicates the start of the range of bytes(inclusive) that has to be taken from the copy source. 904 The service will read the same number of bytes as the destination range (length-offset). 905 :keyword lease: 906 Required if the file has an active lease. Value can be a ShareLeaseClient object 907 or the lease ID as a string. 908 909 .. versionadded:: 12.1.0 910 911 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 912 :keyword int timeout: 913 The timeout parameter is expressed in seconds. 914 """ 915 options = self._upload_range_from_url_options( 916 source_url=source_url, 917 offset=offset, 918 length=length, 919 source_offset=source_offset, 920 **kwargs 921 ) 922 try: 923 return await self._client.file.upload_range_from_url(**options) # type: ignore 924 except StorageErrorException as error: 925 process_storage_error(error) 926 927 @distributed_trace_async 928 async def get_ranges( # type: ignore 929 self, 930 offset=None, # type: Optional[int] 931 length=None, # type: Optional[int] 932 **kwargs 933 ): 934 # type: (...) -> List[Dict[str, int]] 935 """Returns the list of valid ranges of a file. 936 937 :param int offset: 938 Specifies the start offset of bytes over which to get ranges. 939 :param int length: 940 Number of bytes to use over which to get ranges. 941 :keyword lease: 942 Required if the file has an active lease. Value can be a ShareLeaseClient object 943 or the lease ID as a string. 944 945 .. versionadded:: 12.1.0 946 947 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 948 :keyword int timeout: 949 The timeout parameter is expressed in seconds. 950 :returns: A list of valid ranges. 951 :rtype: List[dict[str, int]] 952 """ 953 timeout = kwargs.pop('timeout', None) 954 if self.require_encryption or (self.key_encryption_key is not None): 955 raise ValueError("Unsupported method for encryption.") 956 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 957 958 content_range = None 959 if offset is not None: 960 if length is not None: 961 end_range = offset + length - 1 # Reformat to an inclusive range index 962 content_range = "bytes={0}-{1}".format(offset, end_range) 963 else: 964 content_range = "bytes={0}-".format(offset) 965 try: 966 ranges = await self._client.file.get_range_list( 967 range=content_range, 968 sharesnapshot=self.snapshot, 969 lease_access_conditions=access_conditions, 970 timeout=timeout, 971 **kwargs 972 ) 973 except StorageErrorException as error: 974 process_storage_error(error) 975 return [{"start": b.start, "end": b.end} for b in ranges] 976 977 @distributed_trace_async 978 async def clear_range( # type: ignore 979 self, 980 offset, # type: int 981 length, # type: int 982 **kwargs 983 ): 984 # type: (...) -> Dict[str, Any] 985 """Clears the specified range and releases the space used in storage for 986 that range. 987 988 :param int offset: 989 Start of byte range to use for clearing a section of the file. 990 The range can be up to 4 MB in size. 991 :param int length: 992 Number of bytes to use for clearing a section of the file. 993 The range can be up to 4 MB in size. 994 :keyword lease: 995 Required if the file has an active lease. Value can be a ShareLeaseClient object 996 or the lease ID as a string. 997 998 .. versionadded:: 12.1.0 999 1000 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 1001 :keyword int timeout: 1002 The timeout parameter is expressed in seconds. 1003 :returns: File-updated property dict (Etag and last modified). 1004 :rtype: Dict[str, Any] 1005 """ 1006 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 1007 timeout = kwargs.pop('timeout', None) 1008 if self.require_encryption or (self.key_encryption_key is not None): 1009 raise ValueError("Unsupported method for encryption.") 1010 1011 if offset is None or offset % 512 != 0: 1012 raise ValueError("offset must be an integer that aligns with 512 bytes file size") 1013 if length is None or length % 512 != 0: 1014 raise ValueError("length must be an integer that aligns with 512 bytes file size") 1015 end_range = length + offset - 1 # Reformat to an inclusive range index 1016 content_range = "bytes={0}-{1}".format(offset, end_range) 1017 try: 1018 return await self._client.file.upload_range( # type: ignore 1019 timeout=timeout, 1020 cls=return_response_headers, 1021 content_length=0, 1022 file_range_write="clear", 1023 range=content_range, 1024 lease_access_conditions=access_conditions, 1025 **kwargs 1026 ) 1027 except StorageErrorException as error: 1028 process_storage_error(error) 1029 1030 @distributed_trace_async 1031 async def resize_file(self, size, **kwargs): 1032 # type: (int, Any) -> Dict[str, Any] 1033 """Resizes a file to the specified size. 1034 1035 :param int size: 1036 Size to resize file to (in bytes) 1037 :keyword lease: 1038 Required if the file has an active lease. Value can be a ShareLeaseClient object 1039 or the lease ID as a string. 1040 1041 .. versionadded:: 12.1.0 1042 1043 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 1044 :keyword int timeout: 1045 The timeout parameter is expressed in seconds. 1046 :returns: File-updated property dict (Etag and last modified). 1047 :rtype: Dict[str, Any] 1048 """ 1049 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 1050 timeout = kwargs.pop('timeout', None) 1051 try: 1052 return await self._client.file.set_http_headers( # type: ignore 1053 file_content_length=size, 1054 file_attributes="preserve", 1055 file_creation_time="preserve", 1056 file_last_write_time="preserve", 1057 file_permission="preserve", 1058 lease_access_conditions=access_conditions, 1059 cls=return_response_headers, 1060 timeout=timeout, 1061 **kwargs 1062 ) 1063 except StorageErrorException as error: 1064 process_storage_error(error) 1065 1066 @distributed_trace 1067 def list_handles(self, **kwargs): 1068 # type: (Any) -> AsyncItemPaged 1069 """Lists handles for file. 1070 1071 :keyword int timeout: 1072 The timeout parameter is expressed in seconds. 1073 :returns: An auto-paging iterable of HandleItem 1074 :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.storage.fileshare.HandleItem] 1075 """ 1076 timeout = kwargs.pop('timeout', None) 1077 results_per_page = kwargs.pop("results_per_page", None) 1078 command = functools.partial( 1079 self._client.file.list_handles, 1080 sharesnapshot=self.snapshot, 1081 timeout=timeout, 1082 **kwargs) 1083 return AsyncItemPaged( 1084 command, results_per_page=results_per_page, 1085 page_iterator_class=HandlesPaged) 1086 1087 @distributed_trace_async 1088 async def close_handle(self, handle, **kwargs): 1089 # type: (Union[str, HandleItem], Any) -> Dict[str, int] 1090 """Close an open file handle. 1091 1092 :param handle: 1093 A specific handle to close. 1094 :type handle: str or ~azure.storage.fileshare.Handle 1095 :keyword int timeout: 1096 The timeout parameter is expressed in seconds. 1097 :returns: 1098 The number of handles closed (this may be 0 if the specified handle was not found) 1099 and the number of handles failed to close in a dict. 1100 :rtype: dict[str, int] 1101 """ 1102 try: 1103 handle_id = handle.id # type: ignore 1104 except AttributeError: 1105 handle_id = handle 1106 if handle_id == '*': 1107 raise ValueError("Handle ID '*' is not supported. Use 'close_all_handles' instead.") 1108 try: 1109 response = await self._client.file.force_close_handles( 1110 handle_id, 1111 marker=None, 1112 sharesnapshot=self.snapshot, 1113 cls=return_response_headers, 1114 **kwargs 1115 ) 1116 return { 1117 'closed_handles_count': response.get('number_of_handles_closed', 0), 1118 'failed_handles_count': response.get('number_of_handles_failed', 0) 1119 } 1120 except StorageErrorException as error: 1121 process_storage_error(error) 1122 1123 @distributed_trace_async 1124 async def close_all_handles(self, **kwargs): 1125 # type: (Any) -> Dict[str, int] 1126 """Close any open file handles. 1127 1128 This operation will block until the service has closed all open handles. 1129 1130 :keyword int timeout: 1131 The timeout parameter is expressed in seconds. 1132 :returns: 1133 The number of handles closed (this may be 0 if the specified handle was not found) 1134 and the number of handles failed to close in a dict. 1135 :rtype: dict[str, int] 1136 """ 1137 timeout = kwargs.pop('timeout', None) 1138 start_time = time.time() 1139 1140 try_close = True 1141 continuation_token = None 1142 total_closed = 0 1143 total_failed = 0 1144 while try_close: 1145 try: 1146 response = await self._client.file.force_close_handles( 1147 handle_id='*', 1148 timeout=timeout, 1149 marker=continuation_token, 1150 sharesnapshot=self.snapshot, 1151 cls=return_response_headers, 1152 **kwargs 1153 ) 1154 except StorageErrorException as error: 1155 process_storage_error(error) 1156 continuation_token = response.get('marker') 1157 try_close = bool(continuation_token) 1158 total_closed += response.get('number_of_handles_closed', 0) 1159 total_failed += response.get('number_of_handles_failed', 0) 1160 if timeout: 1161 timeout = max(0, timeout - (time.time() - start_time)) 1162 return { 1163 'closed_handles_count': total_closed, 1164 'failed_handles_count': total_failed 1165 } 1166