
    7T                        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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dZdZdZdZdZdZdZdZdZdZd Zd Z  G d d      Z! ejD                  dddg      Z#d Z$d Z% ejL                  d !      d"        Z'd# Z(	 	 d1d$Z) ejD                  d%g d&      Z*d2d'Z+	 	 	 d3d(Z,d) Z-d* Z.d+ Z/d, Z0d2d-Z1d. Z2d/ Z3d0 Z4y)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    t        |       dd }|dd }ddt        |      z
  z  |z   S )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                     t        | d      S )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                   B    e Zd ZdZd Zed        Zed        Zd Zd Z	y)	PosixModez(Stores POSIX mode in all useful formats.c                      || _         || _        y)z8Initializes class. Prefer the 'from' constructors below.N)r   r   )selfr   r   s      r   __init__zPosixMode.__init__Q   s    $D(Dr   c                 B    t        |      }t        t        |      |      S )z-Initializes class from base ten int. E.g. 73.)r   r   r   )clsr   r   s      r   from_base_ten_intzPosixMode.from_base_ten_intV   s'     8EN.~>P Pr   c                 ,    t        t        |      |      S )z=Initializes class from base eight (octal) string. E.g. '111'.)r   r   )r$   r   s     r   from_base_eight_strzPosixMode.from_base_eight_str^   s     .~>P Pr   c                     t        |t        |             st        S | j                  |j                  k(  xr | j                  |j                  k(  S )N)
isinstancetypeNotImplementedr   r   )r!   others     r   __eq__zPosixMode.__eq__d   sH    eT$Z(!3!33 85#7#779r   c                 N    dj                  | j                  | j                        S )Nz&(base-ten int: {}, base-eight str: {}))formatr   r   )r!   s    r   __repr__zPosixMode.__repr__j   s&    3::4..0 0r   N)
__name__
__module____qualname____doc__r"   classmethodr%   r'   r-   r0    r   r   r   r   N   s@    0)
 P P P P
90r   r   SystemPosixDatadefault_modeuser_groupsc                      d} t        j                  d      }t        j                  |       | |z
  }|dz  }t        j                  |      S )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_moderB   y   sL     / ((5/-((=	=	($  %<		$	$%;	<<r   c                  4   ddl } ddl}t        j                         }|j	                  |      j
                  }t        |j	                  |      j                  g| j                         D cg c]  }||j                  v s|j                   c}z         S c c}w )z-Gets set of POSIX groups the user is part of.r   N)grppwdr<   getuidgetpwuidpw_namesetpw_gidgetgrallgr_memgr_gid)rD   rE   user_id	user_namegs        r   _get_user_groupsrQ      s     IIK'll7#++)	
||G##$AA9+@qxxAB
C C Bs   *B
>B
   )maxsizec                      t         j                  j                         rt        dd      S t	               } t               }t        | |      S )z1Gets POSIX info that should only be fetched once.N)r   OperatingSystem	IsWindowsr7   rB   rQ   )r8   r9   s     r   get_system_posix_datarW      s@     ((*4&&"$, "+	{	33r   c                 4    |rt        j                  |       | )z8Deletes file before raising error if file path provided.)r<   remove)errordelete_paths     r   "_raise_error_and_maybe_delete_filer\      s    IIk+r   c                 D   |xs t        |      \  }}}}}||cxu r|cxu r n t        j                  j                         ryt	        j
                         dk(  ryddl}ddl}	|j                  j                  }
|	 |	j                  |       |	 |j#                  |       || j(                  }n|}|xs t	        j*                         }||t	        j*                         k(  r^|j,                  t.        j0                  z  ryt        j                  t2        j                  |
||j4                              }t!        ||       ||| j6                  v rb|j,                  t.        j8                  z  ryt        j                  t:        j                  |
|dn||j4                              }t!        ||       |j,                  t.        j<                  z  ryt        j                  t>        j                  |
||j4                              }t!        ||       y# t        $ r9 t        j                  t        j                  |
|            }t!        ||       Y w xY w# t        t$        f$ r9 t        j                  t&        j                  |
|            }t!        ||       Y w xY w)a8  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   rU   rV   r<   geteuidrD   rE   r   
url_stringrG   KeyErrorr   SystemPermissionError_MISSING_UID_FORMATr/   r\   getgrgidOverflowError_MISSING_GID_FORMATr8   rF   r   statS_IRUSR%_INSUFFICIENT_USER_READ_ACCESS_FORMATr   r9   S_IRGRP&_INSUFFICIENT_GROUP_READ_ACCESS_FORMATS_IROTH&_INSUFFICIENT_OTHER_READ_ACCESS_FORMAT)system_posix_dataresourcer[   known_posix_uidgidr@   rD   rE   r`   rZ   mode_to_set
uid_to_sets                 r   !raise_if_invalid_file_permissionsrv      s^   : G=hG !QS$ 
S D Y%>%>%H%H%J  ZZ\Q
  ##..*_=	ll3 	_=	ll3 
\#00KK!biik*[C299;& $,,.((-44
K$>$>	
E
 'uk:[C,888 $,,.((.55&)k"s&&	
E 'uk:,


&
&,33
j+"<"<%
 %UK8o  =**

$
$Z
5e )<	= m$ =**

$
$Z
5e )<	=s%   <H I >IIAJJPosixAttributes)atimemtimerr   rs   r@   c           
          | xs  t         j                  t         j                  v}t        j                  | |      \
  }}}}}}}}}}t        ||||t        j                  |            S )z3Takes file path and returns PosixAttributes object.follow_symlinks)r<   rg   supports_follow_symlinksrw   r   r%   )		file_pathpreserve_symlinksr|   r@   rq   rr   rs   rx   ry   s	            r   get_posix_attributes_from_filer   (  sr     Irwwb.I.II  131-$1ac1eUA 
sC"44T:
< <r   c                    |j                   j                  }t        | |||       |xs t        |      }|xs t	        ||      }|j
                  |j
                  }	d}
n%|j
                  }	|j
                  |j
                  k7  }
|j                  |j                  }n)|j                  }|
xs |j                  |j                  k7  }
|
r?| xs  t        j                  t        j                  v}t        j                  ||	|f|       t        j                  j                         ry|j                  |j                  }d}n|j                  }|j                  |j                  k7  }||j                  k7  rPt        j                         dk7  r9t        j                  |       t!        j"                  dj%                  |            |j&                  |j&                  }n)|j&                  }|xs |j&                  |j&                  k7  }|r>| xs  t        j(                  t        j                  v}t        j(                  ||||       |j*                  |j*                  j,                  |j*                  j,                  k7  rR| xs  t        j.                  t        j                  v}t        j.                  ||j*                  j,                  |       yyy)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`.
  )rp   NFr{   r   z(Root permissions required to set UID {}.)r   resource_namerv   r^   r   rx   ry   r<   utimer}   r   rU   rV   rr   r_   rY   r   rb   r/   rs   chownr@   r   chmod)rn   source_resourcedestination_resourceknown_source_posixknown_destination_posixr   destination_pathcustom_posix_attributesexisting_posix_attributesrx   need_utime_callry   r|   rr   need_chown_callrs   s                   r   %set_posix_attributes_on_file_if_validr   4  s   B *55CC#$	  C	1/	B 
  M	'(8:K	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sCI!!-""//	"	'	'	4	45 L1L1L!L  HH$$11'5 .r   c           	         | j                   r| j                   j                  |      y	 t        | j                   |         }|dk  rHt	        j
                  dj                  | j                  j                  || j                   |                y|t        j                  j                  t        j                  j                        j                         t        z   kD  rHt	        j
                  dj                  || j                  j                  | j                   |                y|S # t        $ rJ t	        j
                  dj                  | j                  j                  || j                   |                Y yw xY w)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	   warningr/   r   r`   datetimenowtimezoneutc	timestamp_SECONDS_PER_DAY)ro   keyr   s      r   "_extract_time_from_custom_metadatar     sQ   			8#9#9#=#=c#B#JH**3/0I ]KK9@@  ++S(2H2H2M	

 h//334>>@	 KK	++16%%00(2H2H2M,
 	5 
 KK@GG  ++S(2H2H2M	

 s   D( (AE;:E;c           	         | j                   r| j                   j                  |      y	 t        | j                   |         }|dk  rHt	        j
                  dj                  | j                  j                  || j                   |                y|S # t        $ rJ t	        j
                  dj                  | j                  j                  || j                   |                Y yw xY w)z/Finds, validates, and returns a POSIX ID value.Nr   r   z-Found negative ID value in {} metadata {}: {})	r   r   r   r   r	   r   r/   r   r`   )ro   r   posix_ids      r    _extract_id_from_custom_metadatar     s    			8#9#9#=#=c#B#J8))#./H \KK7>>  ++S(2H2H2M	

 	/ 
 KK@GG  ++S(2H2H2M	

 s   B AC$#C$c           	      d   | j                   r| j                   j                  t              y	 t        j	                  | j                   t                 S # t
        $ rR t        j                  dj                  | j                  j                  t        | j                   t                        Y yw xY w)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   r/   r   r`   )ro   s    r   "_extract_mode_from_custom_metadatar     s     
 
 				#	#$5	6	>((01  
 KK	f  ++""#45
 
s   %A AB/.B/c                     t        | t              }t        | t              }t        | t              }t        | t
              }t        |       }t        |||||      S )ak  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   rw   )ro   rx   ry   rr   rs   r@   s         r   r^   r^     sU     -X7I
J%
,X7I
J%(3CD#(3CD#	+H	5$	sC	66r   c                    t        | t        j                        rt        |       S t        | t        j                        r t        | j                  j                  |      S t        j                  dj                  | j                              )z,Parses unknown resource type for POSIX data.zECan only retrieve POSIX attributes from file or cloud object, not: {})r)   r   ObjectResourcer^   FileObjectResourcer   r   r   r   InvalidUrlErrorr/   TYPE_STRING)ro   r   s     r   "get_posix_attributes_from_resourcer     sx    ,;;<3H==,??@)**,=  	 4 45	 r   c                    |j                   t        |j                         | t        <   |j                  t        |j                        | t        <   |j
                  t        |j
                        | t        <   |j                  t        |j                        | t        <   |j                  |j                  j                  | t        <   yy)z7Updates custom metadata_dict with PosixAttributes data.N)rx   strr   ry   r   rr   r   rs   r   r@   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                    t        | t        j                        r0| j                  r$t	        j
                  dj                  |             t        |t        j                        r0|j                  r$t	        j
                  dj                  |            t        | t        j                        r0t        |t        j                        rt	        j
                  d      yy)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   r/   CloudUrl)
source_urldestination_urls     r   <raise_if_source_and_destination_not_valid_for_preserve_posixr   6  s     
K//0Z5I5I

 
 299*E  ##%)8)B)B

 
 -44_E  
K001j{++7-

 
 > 7-1r   c                 4    | s|r|j                   r ||i |S y)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)5r4   
__future__r   r   r   collectionsr   r<   rg   "googlecloudsdk.command_lib.storager   r   ,googlecloudsdk.command_lib.storage.resourcesr   googlecloudsdk.corer	   googlecloudsdk.core.cacher
   googlecloudsdk.core.utilr   rc   rf   ri   rk   rm   r   r   r   r   r   r   r   r   r   
namedtupler7   rB   rQ   lrurW   r\   rv   rw   r   r   r   r   r   r^   r   r   r   r   r6   r   r   <module>r      s`   , &  '   	  5 : K # ; . B  B A &
K '
@ ' 0 , . / ,  > 0 0N )+(():*8-)HJ=$C  1%4 &4 	j9n )+((?A	<   |~ F..7*L(r   