
    `                        S r SSKJ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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r " S S\5      rS r S r!S r"  S&S jr#S r$ S'S jr%S r&S r'        S(S jr(S r)S r* S'S jr+ S'S  jr,S! r-S" r.S# r/S'S$ jr0S% r1g))z0Helper functions for tracker file functionality.    )absolute_import)print_function)division)unicode_literalsN)config)CommandException)GetGsutilStateDir)ResumableThreshold)UTF8)GetMd5)CreateDirIfNeededd   zCouldn't write tracker file (%s): %s. This can happen if gsutil is configured to save tracker files to an unwritable directory)encryption_key_sha256serialization_datac                   ,    \ rS rSrSrSrSrSrSrSr	Sr
g	)
TrackerFileType4   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       %platform/gsutil/gslib/tracker_file.pyr   r   4   s!    &(+%/%/'r&   r   c                    [        U [        R                  5      (       a  U R                  [        5      nU nOU nU R                  [        5      n[        R                  " U5      nSUR                  5       -   S-   USS -   $ )a  Apply a hash function (SHA1) to shorten the passed file name.

The spec for the hashed file name is as follows:

    TRACKER_<hash>_<trailing>

where hash is a SHA1 hash on the original file name and trailing is
the last 16 chars from 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 100 characters.

Args:
  filename: file name to be hashed. May be unicode or bytes.

Returns:
  shorter, hashed version of passed file name
TRACKER_.iN)	
isinstancesix	text_typeencoder   decodehashlibsha1	hexdigest)filenamefilename_bytesfilename_strms       r'   _HashFilenamer7   =   sk    $ #--((__T*NLN??4(Lll>"!	akkm	#c	)L,>	>>r&   c                      [         R                  " SS[        R                  R	                  [        5       S5      5      n [        U 5        U $ )zLooks up or creates the gsutil tracker file directory.

This is the configured directory where gsutil keeps its resumable transfer
tracker files. This function creates it if it doesn't already exist.

Returns:
  The pathname to the tracker directory.
GSUtilresumable_tracker_dirztracker-files)r   getospathjoinr	   r   )tracker_dirs    r'   CreateTrackerDirIfNeededr@   Y   s<     

8%<77<<(9(;_MO+K 	r&   c                     [         R                  " SSSU < SU< SU< SU< SU< S35      n[        U[        R                  5      $ )aC  Gets the tracker file name described by the arguments.

Args:
  src_bucket_name: Source bucket (string).
  src_obj_name: Source object (string).
  dst_bucket_name: Destination bucket (string).
  dst_obj_name: Destination object (string)
  api_selector: API to use for this operation.

Returns:
  File path to tracker file.
[/\\]_	rewrite____z.token)resub_HashAndReturnPathr   r$   )src_bucket_namesrc_obj_namedst_bucket_namedst_obj_nameapi_selectorres_tracker_file_names         r'   GetRewriteTrackerFilePathrO   h   s?      66o|
 
1?3J3J	KKr&   c                    U[         R                  :X  a;  [        R                  " SSSU R                  < SU R
                  < SU< S35      nGOU[         R                  :X  aJ  [        R                  " SSS[        R                  R                  U R
                  5      < SU< S35      nGO&U[         R                  :X  aE  [        R                  " SSS[        R                  R                  U R
                  5      X$4-  5      nOU[         R                  :X  a>  [        R                  " SSS	U R                  < SU R
                  < SU< SU< S3	5      nO{U[         R                  :X  aI  [        R                  " SSS
[        R                  R                  U R
                  5      < SU< S35      nOU[         R                  :X  a
  [        5       e[        WU5      $ )a  Gets the tracker file name described by the arguments.

Args:
  dst_url: Destination URL for tracker file.
  tracker_file_type: TrackerFileType for this operation.
  api_selector: API to use for this operation.
  src_url: Source URL for the source file name for parallel uploads.
  component_num: Component number if this is a download component, else None.

Returns:
  File path to tracker file.
rB   rC   resumable_upload__rE   z.urlresumable_download__z.etagz#resumable_download__%s__%s__%d.etagparallel_upload__sliced_download__)r   r   rF   rG   bucket_nameobject_namer    r<   r=   realpathr!   r"   r#   r$   NotImplementedErrorrH   )dst_urltracker_file_typerM   src_urlcomponent_numrN   s         r'   GetTrackerFilePathr]      s}   " /000VV3			g11<AB O444VV3			'--	.>? O>>>  VV3=			'--	.LMN O;;;  VV3			g117LJK O;;;VV3			'--	.>? O333

	13D	EEr&   c                     [        [        U [        R                  U5      5        [	        X5      nU H  n[        U5        M     g)zDeletes all tracker files corresponding to an object download.

Args:
  dst_url: StorageUrl describing the destination file.
  api_selector: The Cloud API implementation used.
N)DeleteTrackerFiler]   r   r    !GetSlicedDownloadTrackerFilePaths)rY   rM   tracker_filestracker_files       r'   DeleteDownloadTrackerFilesrc      s=     /":":LIK 4GJ-#ll# $r&   c           
         [        U [        R                  U5      nU/nUc@  Sn [        US5      n[        R
                  " U5      S   n U(       a  UR                  5         [        U5       H,  nUR                  [        U [        R                  UUS95        M.     U$ ! [        [        4 a    Us U(       a  UR                  5         $ $ f = f! U(       a  UR                  5         f f = f)a  Gets a list of sliced download tracker file paths.

The list consists of the parent tracker file path in index 0, and then
any existing component tracker files in [1:].

Args:
  dst_url: Destination URL for tracker file.
  api_selector: API to use for this operation.
  num_components: The number of component tracker files, if already known.
                  If not known, the number will be retrieved from the parent
                  tracker file on disk.
Returns:
  File path to tracker file.
Nrnum_componentsr\   )r]   r   r#   openjsonloadIOError
ValueErrorcloserangeappendr!   )rY   rM   rf   parallel_tracker_file_pathtracker_file_pathsrb   is          r'   r`   r`      s    "  2.. >23 L4c:lyy./?@n 
 a7*==')*	,- ! 
 Z   	 
  
 
s#   %B C1C CC C)c                     [        5       n[        U 5      n[        U5      R                  5       < SU< 3nU< [        R
                  < U< 3n[        U5      [        :  d   eU$ )zHashes and returns a tracker file path.

Args:
  res_tracker_file_name: The tracker file name prior to it being hashed.
  tracker_file_type: The TrackerFileType of res_tracker_file_name.

Returns:
  Final (hashed) tracker file path.
rC   )r@   r7   strlowerr<   seplenMAX_TRACKER_FILE_NAME_LENGTH)rN   rZ   r:   hashed_tracker_file_nametracker_file_nametracker_file_paths         r'   rH   rH      se     34*+@A!$%6!7!=!=!?!9;"7"35		">	>>	>	r&   c                     U (       a<  [         R                  R                  U 5      (       a  [         R                  " U 5        g g g N)r<   r=   existsunlink)rz   s    r'   r_   r_     s-    277>>*;<<II  =r&   c                    U (       ac  U R                   (       aR  U R                  (       aA  U R                  (       a0  U(       a)  UR                   (       a  UR                  (       a  U(       d  g[        5       nU UUUUUUU
UUU	4 H<  nUc  M  UR	                  [
        R                  " U5      R                  S5      5        M>     UR                  5       $ )a,  Creates an MD5 hex digest of the parameters for a rewrite call.

Resuming rewrites requires that the input parameters are identical. Thus,
the rewrite tracker file needs to represent the input parameters. For
easy comparison, hash the input values. If a user does a performs a
same-source/same-destination rewrite via a different command (for example,
with a changed ACL), the hashes will not match and we will restart the
rewrite from the beginning.

Args:
  src_obj_metadata: apitools Object describing source object. Must include
    bucket, name, and etag.
  dst_obj_metadata: apitools Object describing destination object. Must
    include bucket and object name
  projection: Projection used for the API call.
  src_generation: Optional source generation.
  gen_match: Optional generation precondition.
  meta_gen_match: Optional metageneration precondition.
  canned_acl: Optional canned ACL string.
  max_bytes_per_call: Optional maximum bytes rewritten per call.
  src_dec_key_sha256: Optional SHA256 hash string of decryption key for
      source object.
  dst_enc_key_sha256: Optional SHA256 hash string of encryption key for
      destination object.
  fields: Optional fields to include in response to call.

Returns:
  MD5 hex digest Hash of the input parameters, or None if required parameters
  are missing.
Nr   )	bucketnameetagr   updater,   r-   r.   r2   )src_obj_metadatadst_obj_metadata
projectionsrc_generation	gen_matchmeta_gen_match
canned_aclmax_bytes_per_callsrc_dec_key_sha256dst_enc_key_sha256fieldsmd5_hashinput_params                r'   HashRewriteParametersr     s    R "2"9"9


'7'<'<
"2"9"9


z
X(k oocmmK077?@!" 
			r&   c                 "   SnU(       d  g [        U S5      nUR                  5       R                  S5      nX1:X  a7  UR                  5       R                  S5      U(       a  UR                  5         $ $  U(       a  UR                  5         gg! [         aZ  nUR
                  [
        R                  :w  a2  [        R                  R                  SU < SUR                  < S35         SnANxSnAff = f! U(       a  UR                  5         f f = f)an  Attempts to read a rewrite tracker file.

Args:
  tracker_file_name: Tracker file path string.
  rewrite_params_hash: MD5 hex digest of rewrite call parameters constructed
      by HashRewriteParameters.

Returns:
  String rewrite_token for resuming rewrite requests if a matching tracker
  file exists, None otherwise (which will result in starting a new rewrite).
Nre   
z!Couldn't read Copy tracker file (): z. Restarting copy from scratch.)rh   readlinerstriprm   rk   errnoENOENTsysstderrwritestrerror)rz   rewrite_params_hashrb   existing_hashes        r'   ReadRewriteTrackerFiler   K  s     ,	
)3/L ))+2248M+""$++D1   ,   
 ?ww%,,	jj/=??  s1   AB 3C4 
C1AC,'C4 ,C11C4 4Dc                 ,    [        U U< SU< S35        g)a  Writes a rewrite tracker file.

Args:
  tracker_file_name: Tracker file path string.
  rewrite_params_hash: MD5 hex digest of rewrite call parameters constructed
      by HashRewriteParameters.
  rewrite_token: Rewrite token string returned by the service.
r   N)_WriteTrackerFile)rz   r   rewrite_tokens      r'   WriteRewriteTrackerFiler   l  s     %"5}EGr&   c           	         U R                   (       d   eSnU R                  [        5       :  a  Xt4$ UR                  nUc  [        R
                  n	O[        R                  n	USU-  -  n[        UU	UUS9nSn
 [        US5      n
U	[        R
                  L aJ  U
R                  5       R                  S5      nXR                   :X  a  Xu4U
(       a  U
R                  5         $ $ O{U	[        R                  L ah  [        R                  " U
R                  5       5      nUS   U R                   :X  a1  US   U R                  :X  a  X|S   4U
(       a  U
R                  5         $ $ UR!                  S	U-  5        U
(       a  U
R                  5         U	[        R
                  L a  [/        USU R                   -  5        Xt4$ U	[        R                  L a  [1        XpU5        Xt4$ ! ["        [$        4 a`  n['        U[$        5      (       d  UR(                  [(        R*                  :w  a#  UR!                  S
U< S[-        U5      < S35         SnANSnAff = f! U
(       a  U
R                  5         f f = f)a  Checks for a download tracker file and creates one if it does not exist.

The methodology for determining the download start point differs between
normal and sliced downloads. For normal downloads, the existing bytes in
the file are presumed to be correct and have been previously downloaded from
the server (if a tracker file exists). In this case, the existing file size
is used to determine the download start point. For sliced downloads, the
number of bytes previously retrieved from the server cannot be determined
from the existing file size, and so the number of bytes known to have been
previously downloaded is retrieved from the tracker file.

Args:
  src_obj_metadata: Metadata for the source object. Must include etag and
                    generation.
  dst_url: Destination URL for tracker file.
  logger: For outputting log messages.
  api_selector: API to use for this operation.
  start_byte: The start byte of the byte range for this download.
  existing_file_size: Size of existing file for this download on disk.
  component_num: The component number, if this is a component of a parallel
                 download, else None.

Returns:
  tracker_file_name: The name of the tracker file, if one was used.
  download_start_byte: The first byte that still needs to be downloaded.
Nz component %drg   re   r   r   
generationdownload_start_bytezPTracker file doesn't match for download of %s. Restarting download from scratch.z%Couldn't read download tracker file (r   z#. Restarting download from scratch.z%s
)r   sizer
   rV   r   r    r!   r]   rh   r   r   rm   ri   loadsreadr   warnrk   rl   r+   r   r   rt   r   !WriteDownloadComponentTrackerFile)r   rY   loggerrM   
start_byteexisting_file_sizer\   rz   download_namerZ   rb   
etag_valuecomponent_datar   s                 r'   ReadOrCreateDownloadTrackerFiler   z  sR   B 
			/11 ((%%-'00'::_}44M():)57DF ,)3/LO444((*11$7j	,,	, 4"  % 
-	o@@	@zz,"3"3"56n

 $4$9$9
9

&*:*E*E
E 1F"GG   KK )+89 :  /222'2B2G2G)GH 
	&& O>>>%&7&02		&&# :	 J !Z  AGGu||$;kk.?QI J	J  s9   8AG  A#G G I(AI>I II I%c                 "   U R                   (       d   eSnU R                  [        5       :  a  U$ Uc  [        R                  nO[        R
                  n[        UUUUS9nSn [        US5      nU[        R                  L aI  UR                  5       R                  S5      n	XR                   :X  a  UU(       a  UR                  5         $ $ OzU[        R
                  L ag  [        R                  " UR                  5       5      n
U
S   U R                   :X  a0  U
S   U R                  :X  a  U
S   U(       a  UR                  5         $ $ U(       a  UR                  5         U$ ! [        [         4 a     N+f = f! U(       a  UR                  5         f f = f)aF  Returns the download starting point.

The methodology of this function is the same as in
ReadOrCreateDownloadTrackerFile, with the difference that we are not
interested here in possibly creating a tracker file. In case there is no
tracker file, this means the download starting point is start_byte.

Args:
  src_obj_metadata: Metadata for the source object. Must include etag and
                    generation.
  dst_url: Destination URL for tracker file.
  api_selector: API to use for this operation.
  start_byte: The start byte of the byte range for this download.
  existing_file_size: Size of existing file for this download on disk.
  component_num: The component number, if this is a component of a parallel
                 download, else None.

Returns:
  download_start_byte: The first byte that still needs to be downloaded.
Nrg   re   r   r   r   r   )r   r   r
   r   r    r!   r]   rh   r   r   rm   ri   r   r   r   rk   rl   )r   rY   rM   r   r   r\   rz   rZ   rb   r   r   s              r'   GetDownloadStartByter     s   4 
			/11 '00'::():)57DF ,)3/LO444((*11$7j	,,	,!   
-	o@@	@zz,"3"3"56n

 $4$9$9
9

&*:*E*E
E34   
 :	 		
  s2   #AE 
E4 A!E E1.E4 0E11E4 4Fc                 x    UR                   UR                  US.n[        U [        R                  " U5      5        g)zUpdates or creates a download component tracker file on disk.

Args:
  tracker_file_name: The name of the tracker file.
  src_obj_metadata: Metadata for the source object. Must include etag.
  current_file_pos: The current position in the file.
)r   r   r   N)r   r   r   ri   dumps)rz   r   current_file_posr   s       r'   r   r     s6     ##$//-. %tzz.'ABr&   c                 t    [         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! [        [        4 a  n[        XR                  5      eSnAff = f)z/Creates a tracker file, storing the input data.i  wNF)r<   rh   O_WRONLYO_CREATO_TRUNCfdopenr   rk   OSError#RaiseUnwritableTrackerFileExceptionr   )rz   datafdtfr   s        r'   r   r   +  s    M	"BKK"**$<rzz$I
B	2s	rhhtn 
 
	
7	 M
-.?
LLMs6   AB !A<3B <
B
B 
B B7B22B7c                      [         R                  " U5      n[        X5        g! [         a  n[        XR                  5      eSnAff = f)zlCreate a tracker file and write json data to it.

Raises:
  TypeError: If the data is not JSON serializable
N)ri   r   	TypeErrorr   r   r   )rz   r   json_strerrs       r'   WriteJsonDataToTrackerFiler   7  sE    Ozz$H %0 
 O
-.?
NNOs   $ 
AAAc                    SnSnSn [        U S5      nUR                  5       n[        R                  " U5      nU[           U:w  a  SnSnOLU[
           U(       a  UR                  5         U(       a  UR                  SU 5        U(       a  [        U 5        $ $ U(       a  UR                  5         U(       a  UR                  SU 5        U(       a  [        U 5        gg! [         aD  nUR                  [        R                  :w  a  UR                  SXR                  5         SnANSnAf[        [        4 a[  nSnUb  Sn SnANWs SnAU(       a  UR                  5         U(       a  UR                  SU 5        U(       a  [        U 5        $ $ SnAff = f! U(       a  UR                  5         U(       a  UR                  SU 5        U(       a  [        U 5        f f = f)a  Reads tracker data from an upload tracker file if it exists.

Deletes the tracker file if it uses an old format or the desired
encryption key has changed.

Args:
  tracker_file_name: Tracker file name for this upload.
  logger: logging.Logger for outputting log messages.
  encryption_key_sha256: Encryption key SHA256 for use in this upload, if any.

Returns:
  Serialization data if the tracker file already exists (resume existing
  upload), None otherwise.
NFre   TzUpload tracker file (%s) does not match current encryption key. Restarting upload from scratch with a new tracker file that uses the current encryption key.zKCouldn't read upload tracker file (%s): %s. Restarting upload from scratch.)rh   r   ri   r   ENCRYPTION_UPLOAD_TRACKER_ENTRY"SERIALIZATION_UPLOAD_TRACKER_ENTRYrm   r   r_   rk   r   r   r   KeyErrorrl   )	rz   r   r   rb   remove_tracker_fileencryption_restarttracker_datatracker_jsonr   s	            r'   GetUploadTrackerDatar   D  s    ,#+)3/L$$&L::l+L348MM <=& kk78IK )*  kk78IK )* 3 
 A 	ww%,,kk!"3ZZA J	  ( kk78IK )* # kk78IK )* s[   AC F C 
F&:D% F %F8F?F FFF FF AGc                 (    [        [        X4-  5      e)z:Raises an exception when unable to write the tracker file.)r   &TRACKER_FILE_UNWRITABLE_EXCEPTION_TEXT)rz   	error_strs     r'   r   r     s    ?+78 	9 9r&   )NNr}   )NNNNNNNN)2__doc__
__future__r   r   r   r   r   r0   ri   r<   rF   r   r,   botor   gslib.exceptionr   gslib.utils.boto_utilr	   r
   gslib.utils.constantsr   gslib.utils.hashing_helperr   gslib.utils.system_utilr   rx   r   r   r   objectr   r7   r@   rO   r]   rc   r`   rH   r_   r   r   r   r   r   r   r   r   r   r   r   r&   r'   <module>r      s   7 & %  '    	 	 
 
  , 3 4 & - 5
  # C '
 #: %9 "f ?8L6  $%)	0Ff$& 6:(V(! *.$()-%)-1-1-1!%@FBG( 37V'| (,CLC$	M
18+v9r&   