
    7T                        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	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rSrSrSrSrSrSrS rS r  " S S5      r!\RD                  " SSS/5      r#S r$S r%\RL                  " S S!9S" 5       r'S# r(  S1S$ jr)\RD                  " S%/ S&Q5      r*S2S' jr+   S3S( jr,S) r-S* r.S+ r/S, r0S2S- jr1S. r2S/ r3S0 r4g)4z%POSIX utilities for storage commands.    )absolute_import)division)unicode_literalsN)errors)storage_url)resource_reference)log)function_result_cache)	platformsz;UID in {} metadata doesn't exist on current system. UID: {}z;GID in {} metadata doesn't exist on current system. GID: {}z|Insufficient access to local destination to apply {}. User {} owns file, but owner does not have read permission in mode {}.zInsufficient access to local destination to apply {}. Group {} would own file, but group does not have read permission in mode {}.zInsufficient access to local destination to apply {}. UID {} is not owner of file, and user is not in a group that owns the file. Users in "other" category do not have read permission in mode {}.zgoog-reserved-file-atimezgoog-reserved-posix-gidzgoog-reserved-posix-modezgoog-reserved-file-mtimezgoog-reserved-posix-uidiQ c                 P    [        U 5      SS nUSS nSS[        U5      -
  -  U-   $ )zCTakes base ten integer, converts to octal, and removes extra chars.   N0   )octlen)base_ten_int
oct_stringpermission_bytess      4lib/googlecloudsdk/command_lib/storage/posix_util.py"convert_base_ten_to_base_eight_strr   =   s=     < $*_	C())	*-=	==    c                     [        U S5      $ )zHTakes string representing integer in octal and converts to base ten int.   )int)base_eight_strs    r   &convert_base_eight_str_to_base_ten_intr   H   s     
^Q	r   c                   J    \ rS rSrSrS r\S 5       r\S 5       rS r	S r
Srg	)
	PosixModeN   z(Stores POSIX mode in all useful formats.c                     Xl         X l        g)z8Initializes class. Prefer the 'from' constructors below.N)r   r   )selfr   r   s      r   __init__PosixMode.__init__Q   s    $(r   c                 B    [        U5      n[        [        U5      U5      $ )z-Initializes class from base ten int. E.g. 73.)r   r   r   )clsr   r   s      r   from_base_ten_intPosixMode.from_base_ten_intV   s'     8EN.~>P Pr   c                 ,    [        [        U5      U5      $ )z=Initializes class from base eight (octal) string. E.g. '111'.)r   r   )r&   r   s     r   from_base_eight_strPosixMode.from_base_eight_str^   s     .~>P Pr   c                     [        U[        U 5      5      (       d  [        $ U R                  UR                  :H  =(       a    U R                  UR                  :H  $ )N)
isinstancetypeNotImplementedr   r   )r"   others     r   __eq__PosixMode.__eq__d   sK    eT$Z((!3!33 85#7#779r   c                 N    SR                  U R                  U R                  5      $ )Nz&(base-ten int: {}, base-eight str: {}))formatr   r   )r"   s    r   __repr__PosixMode.__repr__j   s&    3::4..0 0r   )r   r   N)__name__
__module____qualname____firstlineno____doc__r#   classmethodr'   r*   r1   r5   __static_attributes__ r   r   r   r   N   s@    0)
 P P P P
90r   r   SystemPosixDatadefault_modeuser_groupsc                      Sn [         R                  " S5      n[         R                  " U5        X-
  nUS-  n[        R                  U5      $ )zDGets default permissions files are created with as PosixMode object.i     i  )osumaskr   r'   )max_permissionscurrent_umaskmodemode_without_executions       r   _get_default_moderJ   y   sJ     / ((5/-((=		($  %<		$	$%;	<<r   c                  @   SSK n SSKn[        R                  " 5       nUR	                  U5      R
                  n[        UR	                  U5      R                  /U R                  5        Vs/ s H   oCUR                  ;   d  M  UR                  PM"     sn-   5      $ s  snf )z-Gets set of POSIX groups the user is part of.r   N)grppwdrD   getuidgetpwuidpw_namesetpw_gidgetgrallgr_memgr_gid)rL   rM   user_id	user_namegs        r   _get_user_groupsrY      s     IIK'll7#++)	
||G##$AA+@xqxxAB
C C Bs   +B
B
   )maxsizec                      [         R                  R                  5       (       a  [        SS5      $ [	        5       n [        5       n[        X5      $ )z1Gets POSIX info that should only be fetched once.N)r   OperatingSystem	IsWindowsr?   rJ   rY   )r@   rA   s     r   get_system_posix_datar_      sA     ((**4&&"$, "+		33r   c                 @    U(       a  [         R                  " U5        U e)z8Deletes file before raising error if file path provided.)rD   remove)errordelete_paths     r   "_raise_error_and_maybe_delete_filerd      s    IIk+r   c                    U=(       d    [        U5      u    pEpgXVs=L a	  Us=L a  b%  O  [        R                  R                  5       (       a  g[        R
                  " 5       S:X  a  gSSKnSSKn	UR                  R                  n
Ub   U	R                  U5        Ub   UR#                  U5        Uc  U R(                  nOUnU=(       d    [        R*                  " 5       nUb  U[        R*                  " 5       :X  ab  UR,                  [.        R0                  -  (       a  g[        R                  " [2        R                  XUR4                  5      5      n[!        X5        Ub  X`R6                  ;   ah  UR,                  [.        R8                  -  (       a  g[        R                  " [:        R                  U
Uc  SOUUR4                  5      5      n[!        X5        UR,                  [.        R<                  -  (       a  g[        R                  " [>        R                  XUR4                  5      5      n[!        X5        g! [         a8    [        R                  " [        R                  X5      5      n[!        X5         GNf = f! [        [$        4 a8    [        R                  " [&        R                  X5      5      n[!        X5         GNf = f)a  Detects permissions causing inaccessibility.

Can delete invalid file.

Args:
  system_posix_data (SystemPosixData): Helps determine if file will be made
    inaccessible in local environment.
  resource (ObjectResource): Contains URL used for messages and custom POSIX
    metadata used to determine if setting invalid file permissions.
  delete_path (str|None): If present, will delete file before raising error.
    Useful if file has been downloaded and needs to be cleaned up.
  known_posix (PosixAttributes|None): Use pre-parsed POSIX data instead of
    extracting from source. Not super important here because the source is a
    cloud object and doesn't require an `os.stat` call to harvest metadata,
    but it would be strange if we used `known_posix` for callers and only
    `resource` here, especially if the values were different (which they
    shouldn't be). Be careful using this because, if the data is wrong, it
    could mess with these safety checks.

Raises:
  SystemPermissionError: Has explanatory message about issue.
Nr   z[user primary group]) (get_posix_attributes_from_cloud_resourcer   r]   r^   rD   geteuidrL   rM   r   
url_stringrO   KeyErrorr   SystemPermissionError_MISSING_UID_FORMATr4   rd   getgrgidOverflowError_MISSING_GID_FORMATr@   rN   r   statS_IRUSR%_INSUFFICIENT_USER_READ_ACCESS_FORMATr   rA   S_IRGRP&_INSUFFICIENT_GROUP_READ_ACCESS_FORMATS_IROTH&_INSUFFICIENT_OTHER_READ_ACCESS_FORMAT)system_posix_dataresourcerc   known_posix_uidgidrH   rL   rM   rh   rb   mode_to_set
uid_to_sets                 r   !raise_if_invalid_file_permissionsr~      sI   : G=hG !QS 
 D  Y%>%>%H%H%J%J  ZZ\Q
  ##..*_=	ll3 	_=	ll3 
\#00KK!biik*[C299;& $,,.((-44K$>$>	
E
 'u:[C888 $,,.((.55&)k"s&&	
E 'u:,


&
&,33
+"<"<%
 %U8o  =**

$
$Z
5e )<	= m$ =**

$
$Z
5e )<	=s%   	H: I? :>I<;I<?AKKPosixAttributes)atimemtimerz   r{   rH   c           
          U(       + =(       d!    [         R                  [         R                  ;  n[         R                  " XS9u
  n    pEpdpxn[        XxXV[        R                  U5      5      $ )z3Takes file path and returns PosixAttributes object.follow_symlinks)rD   ro   supports_follow_symlinksr   r   r'   )		file_pathpreserve_symlinksr   rH   ry   rz   r{   r   r   s	            r   get_posix_attributes_from_filer   (  sf     Irwwb.I.II  131-$1aceA 
s"44T:
< <r   c                 &   UR                   R                  n[        U UUUS9  U=(       d    [        U5      nU=(       d    [	        Xe5      nUR
                  c  UR
                  n	Sn
O%UR
                  n	UR
                  UR
                  :g  n
UR                  c  UR                  nO.UR                  nU
=(       d    UR                  UR                  :g  n
U
(       aF  U(       + =(       d!    [        R                  [        R                  ;  n[        R                  " XiU4US9  [        R                  R                  5       (       a  gUR                  c  UR                  nSnOUR                  nUR                  UR                  :g  nXR                  :w  aT  [        R                  " 5       S:w  a;  [        R                  " U5        [         R"                  " SR%                  U5      5      eUR&                  c  UR&                  nO.UR&                  nU=(       d    UR&                  UR&                  :g  nU(       aD  U(       + =(       d!    [        R(                  [        R                  ;  n[        R(                  " XmXS9  UR*                  b  UR*                  R,                  UR*                  R,                  :w  aZ  U(       + =(       d!    [        R.                  [        R                  ;  n[        R.                  " UUR*                  R,                  US9  ggg)a  Sets custom POSIX attributes on file if the final metadata will be valid.

This function is typically called after downloads.
`raise_if_invalid_file_permissions` should have been called before initiating
a download, but we call it again here to be safe.

Args:
  system_posix_data (SystemPosixData): System-wide POSIX. Helps fill in
    missing data and determine validity of result.
  source_resource (resource_reference.ObjectResource): Source resource with
    POSIX attributes to apply.
  destination_resource (resource_reference.FileObjectResource): Destination
    resource to apply POSIX attributes to.
  known_source_posix (PosixAttributes|None): Use pre-parsed POSIX data instead
    of extracting from source.
  known_destination_posix (PosixAttributes|None): Use pre-parsed POSIX data
    instead of extracting from destination.
  preserve_symlinks (bool): Whether symlinks should be preserved rather than
    followed.

Raises:
  SystemPermissionError: Custom metadata asked for file ownership change that
    user did not have permission to perform. Other permission errors from
    OS functions are possible. Also see `raise_if_invalid_file_permissions`.
)rx   NFr   r   z(Root permissions required to set UID {}.)r   resource_namer~   rf   r   r   r   rD   utimer   r   r]   r^   rz   rg   ra   r   rj   r4   r{   chownrH   r   chmod)rv   source_resourcedestination_resourceknown_source_posixknown_destination_posixr   destination_pathcustom_posix_attributesexisting_posix_attributesr   need_utime_callr   r   rz   need_chown_callr{   s                   r   %set_posix_attributes_on_file_if_validr   4  s   B *55CC#$	  C	1/	B 
  M	'(8	L 
 ""*%++EO#))E%%)B)H)HH  ""*%++E#))E 	L"((,E,K,KK  L1L1L!L  HHu~O((**
  (
#
'
'CO
!
%
%C##'@'D'DD  +++

0Aii ! ((
4
;
;C
@    (
#
'
'C
!
%
%C 	H"&&*C*G*GG 
  L1L1L!L  HHCI!!-""//	"	'	'	4	45 L1L1L!L  HH$$11'5 .r   c           	         U R                   (       a  U R                   R                  U5      c  g [        U R                   U   5      nUS:  aH  [        R
                  " SR                  U R                  R                  XR                   U   5      5        gU[        R                  R                  [        R                  R                  5      R                  5       [        -   :  aH  [        R
                  " SR                  XR                  R                  U R                   U   5      5        gU$ ! [         aJ    [        R
                  " SR                  U R                  R                  XR                   U   5      5         gf = f)z1Finds, validates, and returns a POSIX time value.N6{} metadata did not contain a numeric value for {}: {}r   z/Found negative time value in {} metadata {}: {}z^Found {} value in {} metadata that is more than one day in the future from the system time: {})custom_fieldsgetr   
ValueErrorr	   warningr4   r   rh   datetimenowtimezoneutc	timestamp_SECONDS_PER_DAY)rw   keyr   s      r   "_extract_time_from_custom_metadatar     sK   			8#9#9#=#=c#B#JH**3/0I ]KK9@@  ++S2H2H2M	

 h//334>>@	 KK	++16%%00(2H2H2M,
 	5 
 KK@GG  ++S2H2H2M	

 s   D0 0AFFc           	         U R                   (       a  U R                   R                  U5      c  g [        U R                   U   5      nUS:  aH  [        R
                  " SR                  U R                  R                  XR                   U   5      5        gU$ ! [         aJ    [        R
                  " SR                  U R                  R                  XR                   U   5      5         gf = f)z/Finds, validates, and returns a POSIX ID value.Nr   r   z-Found negative ID value in {} metadata {}: {})	r   r   r   r   r	   r   r4   r   rh   )rw   r   posix_ids      r    _extract_id_from_custom_metadatar     s    			8#9#9#=#=c#B#J8))#./H \KK7>>  ++S2H2H2M	

 	/ 
 KK@GG  ++S2H2H2M	

 s   B AC,+C,c           	      t   U R                   (       a   U R                   R                  [        5      c  g [        R	                  U R                   [           5      $ ! [
         aS    [        R                  " SR                  U R                  R                  [        U R                   [           5      5         gf = f)z1Finds, validates, and returns a POSIX mode value.NzG{} metadata did not contain a valid permissions octal string for {}: {})r   r   MODE_METADATA_KEYr   r*   r   r	   r   r4   r   rh   )rw   s    r   "_extract_mode_from_custom_metadatar     s     
 
 				#	#$5	6	>((01  
 KK	f  ++""#45
 
s   %A AB76B7c                     [        U [        5      n[        U [        5      n[        U [        5      n[        U [
        5      n[        U 5      n[        XX4U5      $ )a[  Parses metadata_dict and returns PosixAttributes.

Note: This parses an object's *custom* metadata with user-set fields,
not the full metadata with provider-set fields.

Args:
  resource (ObjectResource): Contains URL to include in logged warnings and
    custom metadata to parse.

Returns:
  PosixAttributes object populated from metadata_dict.
)r   ATIME_METADATA_KEYMTIME_METADATA_KEYr   UID_METADATA_KEYGID_METADATA_KEYr   r   )rw   r   r   rz   r{   rH   s         r   rf   rf     sQ     -X7I
J%
,X7I
J%(3CD#(3CD#	+H	5$	s	66r   c                 2   [        U [        R                  5      (       a  [        U 5      $ [        U [        R                  5      (       a   [        U R                  R                  U5      $ [        R                  " SR                  U R                  5      5      e)z,Parses unknown resource type for POSIX data.zECan only retrieve POSIX attributes from file or cloud object, not: {})r-   r   ObjectResourcerf   FileObjectResourcer   r   r   r   InvalidUrlErrorr4   TYPE_STRING)rw   r   s     r   "get_posix_attributes_from_resourcer     s~    ,;;<<3H==,??@@)**,=  	 4 45	 r   c                    UR                   b  [        UR                   5      U [        '   UR                  b  [        UR                  5      U [        '   UR
                  b  [        UR
                  5      U [        '   UR                  b  [        UR                  5      U [        '   UR                  b  UR                  R                  U [        '   gg)z7Updates custom metadata_dict with PosixAttributes data.N)r   strr   r   r   rz   r   r{   r   rH   r   r   )metadata_dictposix_attributess     r   1update_custom_metadata_dict_with_posix_attributesr   '  s     '(+,<,B,B(CM$%'(+,<,B,B(CM$%%&)*:*>*>&?M"#%&)*:*>*>&?M"#&'7'<'<'K'KM#$ 'r   c                    [        U [        R                  5      (       a6  U R                  (       a%  [        R
                  " SR                  U 5      5      e[        U[        R                  5      (       a6  UR                  (       a%  [        R
                  " SR                  U5      5      e[        U [        R                  5      (       a6  [        U[        R                  5      (       a  [        R
                  " S5      egg)zGLogs errors and returns bool indicating if transfer is valid for POSIX.z(Cannot preserve POSIX data from pipe: {}z#Cannot write POSIX data to pipe: {}z4Cannot preserve POSIX data for cloud-to-cloud copiesN)r-   r   FileUrl	is_streamr   r   r4   CloudUrl)
source_urldestination_urls     r   <raise_if_source_and_destination_not_valid_for_preserve_posixr   6  s     
K//00Z5I5I

 
 299*E  ##% %)8)B)B

 
 -44_E  
K0011j{++7- 7-

 
 > 7-1r   c                 R    U (       d  U(       a  UR                   (       a  U" U0 UD6$ g)zEUseful for gating functions without repeating the below if statement.N)preserve_posix)posix_to_setuser_request_argsfunctionargskwargss        r   run_if_setting_posixr   J  s&     ',=,L,LT$V$$	r   )NN)F)NNF)5r;   
__future__r   r   r   collectionsr   rD   ro   "googlecloudsdk.command_lib.storager   r   ,googlecloudsdk.command_lib.storage.resourcesr   googlecloudsdk.corer	   googlecloudsdk.core.cacher
   googlecloudsdk.core.utilr   rk   rn   rq   rs   ru   r   r   r   r   r   r   r   r   r   
namedtupler?   rJ   rY   lrur_   rd   r~   r   r   r   r   r   r   rf   r   r   r   r   r>   r   r   <module>r      sY   , &  '   	  5 : K # ; . B  B A &
K '
@ ' 0 , . / ,  > 0 0N (():*8-)HJ=$C  1%4 &4 	j9n ((?A	<   |~ F..7*L(r   