
    ~c                        S r SSKJr  SSKJr  SSKJr  SSKrSSKrSSKrSSKrSSK	r	SSK
r
SSKJr  SSKJr  SSKJr  SS	KJr  SS
KJr  SSKJr  SSKJr  SSKJr  SrSrSr " S S\R2                  5      r\R6                  " SSS/5      r\R6                  " S/ SQ5      rS rS rS r S r!S r"S r#  S/S jr$S r%S  r&S! r'S" r(  S/S# jr)S$ r*S% r+ S0S& jr,S' r-  S/S( jr.S) r/S* r0S+ r1S, r2   S1S- jr3S. r4g)2zUtilities for tracker files.    )absolute_import)division)unicode_literalsN)encryption_util)errors)log)
properties)files)hashing)	platforms)scaled_integerd      z[/\\]c                   ,    \ rS rSrSrSrSrSrSrSr	Sr
g	)
TrackerFileType-   uploaddownloaddownload_componentparallel_uploadsliced_downloadrewrite N)__name__
__module____qualname____firstlineno__UPLOADDOWNLOADDOWNLOAD_COMPONENTPARALLEL_UPLOADSLICED_DOWNLOADREWRITE__static_attributes__r       ;lib/googlecloudsdk/command_lib/storage/tracker_file_util.pyr   r   -   s!    &(+%/%/'r%   r   CompositeUploadTrackerDataencryption_key_sha256random_prefixResumableUploadTrackerDatacompleter(   serialization_datac                 l    [        U S5      nU(       d  Sn[        U 5      " SR                  X5      5      $ )zEdits error to use custom unwritable message.

Args:
  error (Exception): Python error to modify message of.
  tracker_file_path (str): Tracker file path there were issues writing to.

Returns:
  Exception argument with altered error message.
strerrorz[No strerror]zCould not write tracker file ({}): {}. This can happen if gcloud storage is configured to save tracker files to an unwritable directory.)getattrtypeformat)errortracker_file_pathoriginal_error_texts      r&   "_get_unwritable_tracker_file_errorr6   @   s<      z2	)	eQ 6
8 8r%   c                      [         R                  R                  R                  R	                  5       n [
        R                  " U 5        U $ )zLooks up or creates the gcloud storage tracker file directory.

Resumable transfer tracker files will be kept here.

Returns:
  The path string to the tracker directory.
)r	   VALUESstoragetracker_files_directoryGetr
   MakeDir)tracker_directorys    r&   #_create_tracker_directory_if_neededr>   S   s8     !''//GGKKM--!"	r%   c                    [         R                  R                  5       [         R                  R                  :X  aM  [        R
                  R                  R                  R                  5       (       a  [         R                  " U 5      $ U $ )z7Converts colons and characters that make Windows upset.)
r   OperatingSystemCurrentWINDOWSr	   r8   r9   ,convert_incompatible_windows_path_charactersGetBoolMakePathWindowsCompatible	file_names    r&   _windows_sanitize_file_namerH   a   s_     '')Y-F-F-N-NN



#
#
P
P
X
X
Z
Z..y99	r%   c                 ~    [        U 5      [        :  a*  [        R                  " SR	                  [        U 5      5      eg )Nz/File name is over max character limit of {}: {})len_MAX_FILE_NAME_LENGTHr   Errorr2   rF   s    r&   raise_exceeds_max_length_errorrM   k   s8    ^++
,,9@@!9	
  ,r%   c                     [         R                  " U R                  S5      5      n[        SR	                  UR                  5       U S[        -  S 5      5      $ )a  Applies a hash function (SHA1) to shorten the passed file name.

The spec for the hashed file name is as follows:
    TRACKER_<hash>_<trailing>
'hash' is a SHA1 hash on the original file name, and 'trailing' is
the last chars of the original file name. Max file name lengths
vary by operating system, so the goal of this function is to ensure
the hashed version takes fewer than _MAX_FILE_NAME_LENGTH  characters.

Args:
  file_name (str): File name to be hashed. May be unicode or bytes.

Returns:
  String of shorter, hashed file_name.
zutf-8z{}.{}N)hashlibsha1encoderH   r2   	hexdigest*_TRAILING_FILE_NAME_CHARACTERS_FOR_DISPLAY)rG   name_hash_objects     r&   get_hashed_file_namerV   t   sT      \\)"2"27";<	$nn

$
$
&
BCCE
F
 r%   c                     [        U 5      nSR                  UR                  R                  5       U5      nUc  UnOUSR                  U5      -   n[	        U5        [
        R                  R                  X&5      nU$ )a  Hashes and returns a tracker file path.

Args:
  tracker_file_name (str): The tracker file name prior to it being hashed.
  tracker_file_type (TrackerFileType): The TrackerFileType of
    res_tracker_file_name.
  resumable_tracker_directory (str): Path to directory of tracker files.
  component_number (int|None): The number of the component is being tracked
    for a sliced download or composite upload.

Returns:
  Final (hashed) tracker file path.

Raises:
  Error: Hashed file path is too long.
z{}_TRACKER_{}z_{})rV   r2   valuelowerrM   ospathjoin)tracker_file_nametracker_file_typeresumable_tracker_directorycomponent_numberhashed_tracker_file_nametracker_file_name_with_typefinal_tracker_file_namer4   s           r&   _get_hashed_tracker_file_pathrd      s    , 22CD / 6 6##%'?! 99ELL=  !!89ggll! 
r%   c                    U[         R                  L aa  Ub   U R                  R                  S5      u  n  nOU R                  nSR	                  U R
                  X@R                  R                  5      nGOU[         R                  L aO  SR	                  [        R                  R                  U R                  5      U R                  R                  5      nGOxU[         R                  L aP  SR	                  [        R                  R                  U R                  5      U R                  R                  U5      nGOU[         R                  L a=  SR	                  U R
                  U R                  UU R                  R                  5      nOU[         R                  L aN  SR	                  [        R                  R                  U R                  5      U R                  R                  5      nOdU[         R                  L aQ  SR	                  UR
                  UR                  U R
                  U R                  U R                  R                  5      n[!        W5      n[#        5       n[%        UUUU5      $ )a  Retrieves path string to tracker file.

Args:
  destination_url (storage_url.StorageUrl): Describes the destination file.
  tracker_file_type (TrackerFileType): Type of tracker file to retrieve.
  source_url (storage_url.StorageUrl): Describes the source file.
  component_number (int): The number of the component is being tracked for a
    sliced download or composite upload.

Returns:
  String file path to tracker file.
_z resumable_upload__{}__{}__{}.urlzresumable_download__{}__{}.etagz#resumable_download__{}__{}__{}.etagz#parallel_upload__{}__{}__{}__{}.urlzsliced_download__{}__{}.etagz!rewrite__{}__{}__{}__{}__{}.token)r   r   resource_name
rpartitionr2   bucket_nameschemerX   r   rZ   r[   realpathr    r!   r"   r#   get_delimiterless_file_pathr>   rd   )	destination_urlr^   
source_urlr`   object_namerf   raw_result_tracker_file_nameresult_tracker_file_namer_   s	            r&   get_tracker_file_pathrr      s     /000 # *77BB3Gk1a#11k $F#L#L##[2H2H2N2N$P O444#D#K#K
667$$$&  O>>> $I#O#O
667$$&6$8  O;;; $I#O#O##_%B%BJ$$$&  O;;;#A#H#H
667$$$&  O333#F#M#M
 8 8##_%B%B$$$& 
 9" !D E	&!	
 r%   c                 :    [         R                  " [        SU 5      $ )zReturns a string representation of the given path without any delimiters.

Args:
  file_path (str): Path from which delimiters should be removed.

Returns:
  A copy of file_path without any delimiters.
rf   )resubRE_DELIMITER_PATTERN)	file_paths    r&   rl   rl      s     
$c9	55r%   c           	         [        U [        R                  5      nU/nSn [        R                  " U5      n[
        R                  " U5      S   n U(       a  UR                  5         [        U5       H+  nUR                  [        U [        R                  US95        M-     U$ ! [        R                   a    Us U(       a  UR                  5         $ $ f = f! U(       a  UR                  5         f f = f)a'  Gets a list of tracker file paths for each slice of a sliced download.

The returned list consists of the parent tracker file path in index 0
followed by component tracker files.

Args:
  destination_url: Destination URL for tracker file.

Returns:
  List of string file paths to tracker files.
Ntotal_componentsr`   )rr   r   r"   r
   
FileReaderjsonloadMissingFileErrorcloserangeappendr    )rm   parallel_tracker_file_pathtracker_file_pathstracker_filery   is         r&   '_get_sliced_download_tracker_file_pathsr     s      566 823,##$>?Lyy./AB !"a..	 ! # 
 
		    s#   /B$ $C:C CC C2c                     U (       a<  [         R                  R                  U 5      (       a  [         R                  " U 5        ggg)z"Deletes tracker file if it exists.N)rZ   r[   existsremover4   s    r&   delete_tracker_filer   +  s-    277>>*;<<II  =r%   c                     [        U 5      nU H  n[        U5        M     [        [        U [        R                  5      5        g)a  Deletes all tracker files for an object download.

Deletes files for different strategies in case download was interrupted and
resumed with a different strategy. Prevents orphaned tracker files.

Args:
  destination_url (storage_url.StorageUrl): Describes the destination file.
N)r   r   rr   r   r   )rm   sliced_download_tracker_filesr   s      r&   delete_download_tracker_filesr   1  s@     #J#3l% 4 O_-E-EFHr%   c           	         U R                   R                  U R                   R                  U R                  UR                   R                  UR                   R                  4n[	        U5      (       d  [
        R                  " S5      eU R                  =(       d    U R                  nSnU(       a  UR                  (       a  [        UR                  R                  [        R                  5      (       a}  UR                  R                  nUR                  [        R                  R                   L a  UR"                  nO3UR                  [        R                  R$                  L a  UR&                  nU[(        R*                  " [,        R.                  R0                  R2                  R5                  5       5      [7        USS5      [7        USS5      [7        USS5      UU4nXH-   n	SR9                  U	 V
s/ s H  n
[;        U
5      PM     sn
5      R=                  S5      n[>        R@                  " U5      nURC                  5       $ s  sn
f )a  Creates an MD5 hex digest of the parameters for GCS rewrite call.

Resuming rewrites requires that the input parameters are identical, so the
tracker file needs to represent the input parameters. This is done by hashing
the API call parameters. For example, if a user performs a rewrite with a
changed ACL, the hashes will not match, and we will restart the rewrite.

Args:
  source_object_resource (ObjectResource): Must include bucket, name, etag,
    and metadata.
  destination_object_resource (ObjectResource|UnknownResource): Must include
    bucket, name, and metadata.
  destination_metadata (messages.Object|None): Separated from
    destination_object_resource since UnknownResource does not have metadata.
  request_config (request_config_factory._RequestConfig|None): Contains a
    variety of API arguments.

Returns:
  MD5 hex digest (string) of the input parameters.

Raises:
  Error if argument is missing required property.
z"Missing required parameter values.Nprecondition_generation_match!precondition_metageneration_matchpredefined_acl_string UTF8)"storage_urlri   rg   etagallr   rL   decryption_key_hash_sha256kms_keyresource_args
isinstanceencryption_keyr   EncryptionKeyr1   KeyTypeCSEKsha256CMEKkeyr   ParseIntegerr	   r8   r9   copy_chunk_sizer;   r0   r\   strrR   r   get_md5rS   )source_object_resourcedestination_object_resourcedestination_metadatarequest_configmandatory_parameterssource_encryptiondestination_encryptionr   optional_parametersall_parameters	parameterparameters_bytesparameters_hashs                r&   ,hash_gcs_rewrite_parameters_for_tracker_filer   D  s   6 1<<HH0<<JJ0555AAMM5AAOO	Q
 
!	"	"
,,;
<< 77 %$$   55--<< ..0 0

&
&
5
5C
xx?**///"zz	_,,11	1"ww !!



#
#
3
3
7
7
9;n=tDnA4Hn5t<	 (=.WWn nc)nn    &v OO$45/		"	"	$$s   2Ic                    [         R                  " SR                  U 5      5         [        R                  " U [        R
                  [        R                  -  [        R                  -  S5      n[        R                  " US5       nUR                  U5        SSS5        g! , (       d  f       g= f! [         a  n[        X@5      eSnAff = f)z/Creates a tracker file, storing the input data.zWriting tracker file to {}.i  wN)r   debugr2   rZ   openO_WRONLYO_CREATO_TRUNCfdopenwriteOSErrorr6   )r4   datafile_descriptorwrite_streames        r&   _write_tracker_filer     s    )))001BCDCgg/ kkBJJ6CULO	?C	(L 
)	(	(	 C
,Q
BBCs6   AB2 B!B2 !
B/+B2 /B2 2
C<CCc                 F    [         R                  " U5      n[        X5        g)zCreates a tracker file and writes JSON to it.

Args:
  tracker_file_path (str): The path to the tracker file.
  data (object): JSON-serializable data to write to file.
N)r|   dumpsr   )r4   r   json_strings      r&   _write_json_to_tracker_filer     s     

4 +'5r%   c                 J    [        UUS9n[        XR                  5       5        g)a  Updates or creates a tracker file for a composite upload.

Args:
  tracker_file_path (str): The path to the tracker file.
  random_prefix (str): A prefix used to ensure temporary component names are
      unique across multiple running instances of the CLI.
  encryption_key_sha256 (str|None): The encryption key used for the
      upload.

Returns:
  None, but writes data passed as arguments at tracker_file_path.
)r(   r)   N)r'   r   _asdict)r4   r)   r(   r   s       r&   #write_composite_upload_tracker_filer     s%     
$1!
#$ /@r%   c                 L    [        UUUS9n[        XR                  5       5        g)a  Updates or creates a tracker file for a resumable upload.

Args:
  tracker_file_path (str): The path to the tracker file.
  complete (bool): True if the upload is complete.
  encryption_key_sha256 (Optional[str]): The encryption key used for the
      upload.
  serialization_data (dict): Data used by API libraries to resume uploads.

Returns:
  None, but writes data passed as arguments at tracker_file_path.
r+   N)r*   r   r   )r4   r,   r(   r-   r   s        r&   #write_resumable_upload_tracker_filer     s(     
$1+
-$ /@r%   c                     UR                   UR                  S.nUb  Ub  [        R                  " S5      eX$S'   Ub  X4S'   [	        X5        g)a  Updates or creates a tracker file for component or multipart download.

Args:
  tracker_file_path (str): The path to the tracker file.
  source_object_resource (resource_reference.ObjectResource): Needed for
    object etag and optionally generation.
  slice_start_byte (int|None): Where to resume downloading from. Signals
    this is the tracker file of a component.
  total_components (int|None): Total number of components in download. Signals
    this is the parent tracker file of a sliced download.
)r   
generationNzCannot have a tracker file with slice_start_byte and total_components. slice_start_byte signals a component within a larger operation. total_components signals the parent tracker for a multi-component operation.slice_start_bytery   )r   r   r   rL   r   )r4   r   r   ry   component_datas        r&   &write_tracker_file_with_component_datar     sd      %))*55. !#LL*  *:%&!)9%&/@r%   c                 :    [        U SR                  X5      5        g)a  Writes rewrite operation information to a tracker file.

Args:
  tracker_file_name (str): The path to the tracker file.
  rewrite_parameters_hash (str): MD5 hex digest of rewrite call parameters.
  rewrite_token (str): Returned by API, so rewrites can resume where they left
    off.
z{}
{}N)r   r2   )r]   rewrite_parameters_hashrewrite_tokens      r&   write_rewrite_tracker_filer     s     'oo&=MOr%   c                     [         R                  R                  U5      (       d  g[        R                  " U5       n[
        R                  " U5      nU " S0 UD6sSSS5        $ ! , (       d  f       g= f)zHReturns an instance of named_tuple_class with data at tracker_file_path.Nr   )rZ   r[   r   r
   r{   r|   r}   )named_tuple_classr4   r   tracker_dicts       r&   _read_namedtuple_from_json_filer     sO    	)	*	*)*l99\*L,|, +**s   A$$
A2c                 "    [        [        U 5      $ )zReads a composite upload tracker file.

Args:
  tracker_file_path (str): The path to the tracker file.

Returns:
  A CompositeUploadTrackerData instance with data at tracker_file_path, or
  None if no file exists at tracker_file_path.
)r   r'   r   s    r&   "read_composite_upload_tracker_filer           
) "3
5 5r%   c                 "    [        [        U 5      $ )zReads a resumable upload tracker file.

Args:
  tracker_file_path (str): The path to the tracker file.

Returns:
  A ResumableUploadTrackerData instance with data at tracker_file_path, or
  None if no file exists at tracker_file_path.
)r   r*   r   s    r&   "read_resumable_upload_tracker_filer     r   r%   c                    U R                   (       d  [        R                  " S5      eU(       a  Uc  Ub  [        R                  " S5      eUb-  SR	                  UR
                  U5      n[        R                  nO0UR
                  nUb  [        R                  nO[        R                  n[        XUS9n[        R                  " SR	                  U5      5        SnSn	 [        R                  " U5      nU[        R                  L a1  UR                  5       R!                  S5      n
XR                   :X  a  S	n	O["        R$                  " UR'                  5       5      nUS
   U R                   :X  aP  US   U R(                  :X  a=  U[        R                  L a  US   U:X  a  S	n	OU[        R                  L a  US   U:X  a  S	n	U	(       aA  [        R                  " SR	                  U5      5        US	4U(       a  UR+                  5         $ $  U(       a  UR+                  5         U(       a  [/        U5        [        R                  " SR	                  U5      5        U[        R                  L a  [1        XpR                   S-   5        US4$ U[        R                  L a  [3        UU US9  US4$ U[        R                  L a  [3        UU US9  US4$ ! [        R,                   a     Nf = f! U(       a  UR+                  5         f f = f)a  Checks for a download tracker file and creates one if it does not exist.

Args:
  source_object_resource (resource_reference.ObjectResource): Needed for
    object etag and generation.
  destination_url (storage_url.StorageUrl): Destination URL for tracker file.
  slice_start_byte (int|None): Start byte to use if we cannot find a
    matching tracker file for a download slice.
  component_number (int|None): The download component number to find the start
    point for. Indicates part of a multi-component download.
  total_components (int|None): The number of components in a sliced download.
    Indicates this is the parent tracker for a multi-component operation.

Returns:
  tracker_file_path (str): The path to the tracker file (found or created).
  found_tracker_file (bool): False if tracker file had to be created.

Raises:
  ValueCannotBeDeterminedError: Source object resource does not have
    necessary metadata to decide on download start byte.
z'Source object resource is missing etag.Nztotal_components indicates this is the parent tracker file for a multi-component operation. slice_start_byte and component_number cannot be present since this is not for an individual component.z{} component {}rz   z!Searching for tracker file at {}.F
Tr   r   ry   r   zFound tracker file for {}.z No matching tracker file for {}.)r   )ry   )r   r   ValueCannotBeDeterminedErrorrL   r2   rg   r   r    r"   r   rr   r   r   r
   r{   readlinerstripr|   loadsreadr   r   r~   r   r   r   )r   rm   r   r`   ry   download_name_for_loggerr^   r4   r   does_tracker_file_match
etag_valuer   s               r&   $read_or_create_download_tracker_filer     s   4 
 	$	$

-
-13 3+7+7
,,	L  !077%%'7 9'::.<<#)99)22+;KM))/667HIJ,!##$56LO444((*11$7j	22	2"&zz,"3"3"56n

 $:$?$?
?

&*@*K*K
K!@!@@-.2BB$(
!/"D"DDJ #3J4$(
!	ii,334LMN$    !/2)).556NOP/222)+F+F+MN 
E	!! O>>>*)+ 
E	!! O;;;*)+ 
E	!!3 
		 		
  s+   DK
 K$ 
K!K$  K!!K$ $K>c                 <   [         R                  R                  U 5      (       d  g[        R                  " U 5       nUR                  5        Vs/ s H  o3R                  S5      PM     snu  pEXA:X  a  UsSSS5        $  SSS5        gs  snf ! , (       d  f       g= f)aG  Attempts to read a rewrite tracker file.

Args:
  tracker_file_path (str): The path to the tracker file.
  rewrite_parameters_hash (str): MD5 hex digest of rewrite call parameters
    constructed by hash_gcs_rewrite_parameters_for_tracker_file.

Returns:
  String token for resuming rewrites if a matching tracker file exists.
Nr   )rZ   r[   r   r
   r{   	readlinesr   )r4   r   r   lineexisting_hashr   s         r&   #get_rewrite_token_from_tracker_filer     s     
)	*	*)*l&2&<&<&>$&>dD&>$ M / +* 0	 + 
$ +* 
s   BB)BB
B)NN)N)NNN)5__doc__
__future__r   r   r   collectionsenumrP   r|   rZ   rt   "googlecloudsdk.command_lib.storager   r   googlecloudsdk.corer   r	   googlecloudsdk.core.utilr
   r   r   r   rK   rT   rv   Enumr   
namedtupler'   r*   r6   r>   rH   rM   rV   rd   rr   rl   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r%   r&   <module>r      sF   # &  '     	 	 > 5 # * * , . 3
  -/ * dii  )33 o.0 
 )33 ?A 
8&2&V &*+/BJ	6!H!H* GK@D>%B	C6 ?CA*A0 =A<@ADO-55  ;?:>:>	d"Nr%   