
    ]&                     ~   d Z ddlmZ ddlmZ ddlmZ ddlZddlZddlZddlm	Z	 ddl
mZ ddlmZ dd	lmZ dd
lmZ ddlmZ dZ G d dej(                        Z G d de      Zd ZddZddZddZddZd Zd Z e       ZejA                  d      Z!ejA                  d      Z"ejA                  d      Z#ddZ$y)a  Utilities that augment the core CRC32C functionality for storage commands.

The core CRC32C utility provides a hashlib-like functionality for CRC32C
calculation but will at times fall back to a slow, all-Python implementation.
This utility provides several mitigation strategies to avoid relying on the slow
implementation of CRC32C, including adding a "deferred" strategy that uses the
component gcloud-crc32c on files after they are downloaded.
    )absolute_import)division)unicode_literalsN)info_holder)errors)crc32c)binary_operations)log)
propertieszgcloud-crc32cc                   *     e Zd ZdZ fdZddZ xZS )GcloudCrc32cOperationz1Operation for hashing a file using gcloud-crc32c.c                 8    t        t        | 
  ddt        i| y )Nbinary )superr   __init__BINARY_NAME)selfkwargs	__class__s     :lib/googlecloudsdk/command_lib/storage/fast_crc32c_util.pyr   zGcloudCrc32cOperation.__init__/   s    	
/M{MfM    c                 4    dt        |      dt        |      |gS )Nz-oz-l)str)r   	file_pathoffsetlengthr   s        r   _ParseArgsForCommandz*GcloudCrc32cOperation._ParseArgsForCommand2   s    #f+tS[)<<r   )r   r   )__name__
__module____qualname____doc__r   r   __classcell__)r   s   @r   r   r   ,   s    9N=r   r   c                   6    e Zd ZdZd	dZd Zd Zd Zd Zd Z	y)
DeferredCrc32czHashlib-like helper for deferring hash calculations to gcloud-crc32c.

  NOTE: Given this class relies on analyzing data on disk, it is not appropriate
  for hashing streaming downloads and will fail to work as expected.
  c                     || _         y)zSets up the internal checksum variable and allows an initial value.

    Args:
      crc (int): The initial checksum to be stored.
    N)_crc)r   crcs     r   r   zDeferredCrc32c.__init__=   s     DIr   c                 .    t        | j                        S )N)r(   )r%   r'   r   s    r   copyzDeferredCrc32c.copyE   s    dii((r   c                      ~y )Nr   )r   datas     r   updatezDeferredCrc32c.updateH   s    
r   c                     ||t        j                  d      t               } ||||      }|j                  rd| _        yt	        |j
                        | _        y)aq  Calculates checksum on a provided file path.

    Args:
      file_path (str): A string representing a path to a file.
      offset (int): The number of bytes to offset from the beginning of the
        file. Defaults to 0.
      length (int): The number of bytes to read into the file. If not specified
        will calculate until the end of file is encountered.
    NzIgcloud_crc32c binary uses 0 (not `None`) to indicate "no argument given.")r   r   r   r   )r   Errorr   failedintstdoutr'   )r   r   r   r   crc32c_operationresults         r   sum_filezDeferredCrc32c.sum_fileM   sX     ~LL"  -.	&PF]]DIFMM(:DIr   c                 B    t        j                  d| j                        S )zReturns the checksum in big-endian order, per RFC 4960.

    See: https://cloud.google.com/storage/docs/json_api/v1/objects#crc32c

    Returns:
      An eight-byte digest string.
    z>L)structpackr'   r*   s    r   digestzDeferredCrc32c.digest`   s     ;;tTYY''r   c                 V    dj                  | j                        j                  d      S )zReturns a checksum like `digest` except as a bytestring of double length.

    Returns:
      A sixteen byte digest string, containing only hex digits.
    z{:08x}ascii)formatr'   encoder*   s    r   	hexdigestzDeferredCrc32c.hexdigestj   s"     ??499%,,W55r   N)r   )
r   r    r!   r"   r   r+   r.   r6   r:   r?   r   r   r   r%   r%   6   s%    )
;&(6r   r%   c                  t    	 t         t        j                  t               v S # t        j                  $ r Y yw xY w)zCReturns if gcloud-crc32c is installed and does not attempt install.F)r   r	   CheckForInstalledBinaryMissingExecutableExceptionr   r   r   _is_gcloud_crc32c_installedrC   s   s6    +CCKPPP		5	5 s   ! 77c                 6   	 t         t        j                  t         |       v S # t        j                  $ rK t	        j
                  d       t        j                  j                  j                  j                  d       Y y t	        j
                  d       Y yxY w)zCReturns True if gcloud-crc32c is installed and optionally installs.install_if_missingzygcloud-crc32c can not be found on the path. The user may have opted out of installation or lack component manager access.Fz.Failed to check if gcloud-crc32c is available.)r   r	   rA   rB   r
   debugr   VALUESstorageuse_gcloud_crc32cSetrE   s    r   !_check_if_gcloud_crc32c_availablerL   {   s    @+CC(:   
	5	5 	;
 II	A //33E: 
@II>?	s    # AB Bc                     t         j                  xsA t        j                  j                  j
                  j                         duxr t        |       S )NF)r   IS_FAST_GOOGLE_CRC32C_AVAILABLEr   rH   rI   rJ   GetBoolrL   rE   s    r   check_if_will_use_fast_crc32crP      sG    		/	/ 
1199;5H @
+,>
?	r   c                     t         j                  j                  j                  j	                         }|du ry|t
        j                  ry| rt        d      S t               S )zReturns True if gcloud-crc32c should be used and installs if needed.

  Args:
    install_if_missing (bool): Install gcloud-crc32c if not already present.

  Returns:
    True if the Go binary gcloud-crc32c should be used.
  FTrE   )	r   rH   rI   rJ   rO   r   rN   rL   rC   )rF   user_wants_gcloud_crc32cs     r   should_use_gcloud_crc32crS      s]     1199;  &&,,,EE	$	&&r   c                 \    t        d      }|r
t               S t        j                  |       S )aZ  Wraps the crc32c.get_crc32c() method to allow fallback to gcloud-crc32c.

  DO NOT USE for streaming downloads, as this relies on file-based hashing and
  does not take whether or not streaming is enabled into account.

  Args:
    initial_data (bytes): The CRC32C object will be initialized with the
      checksum of the data.

  Returns:
    A DeferredCrc32c instance if hashing can be deferred. Otherwise it returns a
    google_crc32c.Checksum instance if google-crc32c
    (https://github.com/googleapis/python-crc32c) is available and a
    predefined.Crc instance from crcmod library if not.
  TrE   )rS   r%   r   
get_crc32c)initial_datashould_defers     r   rU   rU      s)      *TB,)	Nv/@/@/NNr   c                      t        j                         } | j                  j                  }|rGt        j
                  j                  |dd      }dj                  | j                  j                  |      S y)zReturns the command to install google-crc32c library.

  This will typically only be called if gcloud-crc32c is missing and can't be
  installed for some reason. It requires user intervention which is why it's
  not a preferred option.
  libthird_partyz5{} -m pip install google-crc32c --upgrade --target {}N)
r   
InfoHolderinstallationsdk_rootospathjoinr=   basicpython_location)sdk_infor]   third_party_paths      r   !get_google_crc32c_install_commandre      sc     ##%(""++(ww||He]CBII&&(8: :	r   c                  ~    t               } d}t        j                  dj                  | r|             S |            S )z CRC32C warnings share this text.z'gcloud components install gcloud-crc32cz      This copy {{}} since fast hash calculation tools
      are not installed. You can change this by running:
      	$ {crc32c_step}
      You can also modify the "storage/check_hashes" config setting.)crc32c_step)re   textwrapdedentr=   )google_crc32c_install_stepgcloud_crc32c_install_steps     r   _get_hash_check_warning_baserl      se      ABH	H IO' 1 IO I

 
 * IO I

 
r   zwill not be validatedzmay be slowzwas skippedc                 
   t        d      ryt        j                  j                  j                  j                         }|t        j                  j                  j                  k(  r| rt        j                  t               y|t        j                  j                  j                  k(  rt        j                  t               y|t        j                  j                  j                  k(  rt        j                   t"              y)a  Informs user about slow hashing if requested.

  Args:
    warn_for_always (bool): User may not want to see a warning about slow hashes
      if they have the "always check hashes" property set because (1) they
      intentionally set a property and (2) it could duplicate a warning in
      FileDownloadTask.

  Raises:
    errors.Error: IF_FAST_ELSE_FAIL set, and CRC32C binary not present. See
      error message for more details.
  TrE   N)rP   r   rH   rI   check_hashesGetCheckHashesALWAYSvaluer
   warning_SLOW_HASH_CHECK_WARNINGIF_FAST_ELSE_SKIP_NO_HASH_CHECK_WARNINGIF_FAST_ELSE_FAILr   r0   _NO_HASH_CHECK_ERROR)warn_for_alwaysrn   s     r   log_or_raise_crc32c_issuesrz      s     #d;
""**77;;=,Z++22888_KK()z--??EEEKK&'z--??EEE
,,+
,, Fr   )F)r   )T)%r"   
__future__r   r   r   r^   r8   rh   googlecloudsdk.command_libr   "googlecloudsdk.command_lib.storager   googlecloudsdk.command_lib.utilr   &googlecloudsdk.command_lib.util.anthosr	   googlecloudsdk.corer
   r   r   BinaryBackedOperationr   objectr%   rC   rL   rP   rS   rU   re   rl   _HASH_CHECK_WARNING_BASEr=   rv   rt   rx   rz   r   r   r   <module>r      s    '  ' 	   2 5 2 D # * =-CC =:6V :6z,'0O( $ 89 188  4::=I /66}E -r   