
    O|bh                         d Z ddlZddlZddlZddlZddlZddlZg dZdZ	dZ
dZ G d de      Z G d d	      Z G d
 de      Z G d de      Z G d d      Zy)zE
ftputil.stat - stat result, parsers, and FTP stat'ing for `ftputil`
    N)
StatResultParser
UnixParserMSParser<   iQ c                   @    e Zd ZdZdddddddd	d
ddddZd Zd Zd Zy)r   zP
    Support class resembling a tuple like that returned from `os.(l)stat`.
    r                           	   
      )st_modest_inost_devst_nlinkst_uidst_gidst_sizest_atimest_mtimest_ctime_st_name
_st_targetc                 6    d| _         d | _        t        | _        y )N )r   r   UNKNOWN_PRECISION_st_mtime_precision)selfsequences     ,lib/python3.12/site-packages/ftputil/stat.py__init__zStatResult.__init__0   s     #4     c                 v    || j                   v r| | j                   |      S t        dj                  |            )Nz)'StatResult' object has no attribute '{}')_index_mappingAttributeErrorformat)r$   	attr_names     r&   __getattr__zStatResult.__getattr__=   sA    +++++I677 ;BB9M r(   c                 0   t        d | j                  j                         D              }g }t        |       D ])  \  }}|j	                  dj                  ||   |             + dj                  t        |       j                  dj                  |            S )Nc              3   *   K   | ]  \  }}||f  y w)N ).0kvs      r&   	<genexpr>z&StatResult.__repr__.<locals>.<genexpr>H   s     L1aVLs   z{}={!r}z{}({})z, )	dictr*   items	enumerateappendr,   type__name__join)r$   index_to_nameargument_stringsindexitems        r&   __repr__zStatResult.__repr__E   s     L0C0C0I0I0KLL$T? 	RKE4##I$4$4]55I4$PQ	RtDz22DII>N4OPPr(   N)r;   
__module____qualname____doc__r*   r'   r.   rA   r1   r(   r&   r   r      sD    
 N5Qr(   r   c                       e Zd ZdZdddddddd	d
ddddZ ej                  d      Zd ZddZ	d Z
d Zed        Z	 ddZddZy)r   zu
    Represent a parser for directory lines. Parsers for specific directory
    formats inherit from this class.
    r	   r
   r   r   r   r   r   r   r   r   r      )janfebmaraprmayjunjulaugsepoctnovdecz^total\s+\d+c                 p    |j                         sy| j                  j                  |      }t        |      S )aR  
        Return a true value if the line should be ignored, i. e. is assumed to
        _not_ contain actual directory/file/link data. A typical example are
        summary lines like "total 23" which are emitted by some FTP servers.

        If the line should be used to extract stat data from it, return a false
        value.
        T)strip_total_regexsearchbool)r$   linematchs      r&   ignores_linezParser.ignores_linej   s0     zz|!!((.E{r(   c                     t        d      )a  
        Return a `StatResult` object as derived from the string `line`. The
        parser code to use depends on the directory format the FTP server
        delivers (also see examples at end of file).

        If the given text line can't be parsed, raise a `ParserError`.

        For the definition of `time_shift` see the docstring of
        `FTPHost.set_time_shift` in `ftputil.py`. Not all parsers use the
        `time_shift` parameter.
        zmust be defined by subclass)NotImplementedError)r$   rX   
time_shifts      r&   
parse_linezParser.parse_line{   s     ""?@@r(   c           	      t   t        |      dk7  r.t        j                  j                  dj	                  |            d}|dd D ]  }|dk7  }|dz  |z   } |d   dk(  r|t
        j                  z  }|d   dk(  r|t
        j                  z  }t
        j                  t
        j                  t
        j                  t
        j                  t
        j                  t
        j                  t
        j                  dd	}|d   }||v r
|||   z  }|S t        j                  j                  d
j	                  |            )a  
        Return an integer from the `mode_string`, compatible with the `st_mode`
        value in stat results. Such a mode string may look like "drwxr-xr-x".

        If the mode string can't be parsed, raise an
        `ftputil.error.ParserError`.
        r   zinvalid mode string '{}'r   r	   -r   sr   )bcdlpra   r`   ?z unknown file type character '{}')lenftputilerrorParserErrorr,   statS_ISUIDS_ISGIDS_IFBLKS_IFCHRS_IFDIRS_IFLNKS_IFIFOS_IFSOCKS_IFREG)r$   mode_stringr   bitfile_type_to_mode	file_types         r&   parse_unix_modezParser.parse_unix_mode   s0    {r!--++*11+>  q$ 	+C*C!|s*G	+ q>S ,Gq>S ,G 
  N	)) 1) <<G
  --++299)D r(   c                     	 t        |      S # t        $ r0 t        j                  j	                  dj                  ||            w xY w)a  
        Return `int_string` converted to an integer.

        If it can't be converted, raise a `ParserError`, using
        `int_description` in the error message. For example, if the integer
        value is a day, pass "day" for `int_description`.
        znon-integer {} value {!r})int
ValueErrorri   rj   rk   r,   )r$   
int_stringint_descriptions      r&   _as_intzParser._as_int   sG    	z?" 	--+++22?JO 	s	   
 9Ac                    	 t        j                   | |||||t         j                  j                        S # t        $ rH | dd|dd|dd|dd|dd|d}t        j
                  j                  dj                  |            w xY w)z
        Return UTC `datetime.datetime` object for the given year, month, day,
        hour, minute and second.

        If there are invalid values, for example minute > 59, raise a
        `ParserError`.
        tzinfo04dr`   02d :zinvalid datetime {0!r})datetimetimezoneutcr}   ri   rj   rk   r,   )yearmonthdayhourminutesecondinvalid_datetimes          r&   	_datetimezParser._datetime   s    	$$eS$x?P?P?T?T   	*AeC[#c!*AfS\6#,8  --++(//0@A 	s
   36 ABc                    	 | j                   |j                            }| j                  |d      }d|v}|rt        }| j                  |d      dd}}
}	nt        }|j                  d      \  }
}d| j                  |
d      | j                  |d      }}
}t        j                  j                         j                  t        j                  j                  	      t        j                   |
      z   }|j"                  }	| j%                  |	|||
|d      |j                  d      t        j                   d
      z   kD  r|	dz  }	| j%                  |	|||
|d      t        j                   |
      z
  }|j'                         }|dk  rt(        }d}|r||fS |S # t        $ r/ t        j                  j                  dj                  |            w xY w)a  
        Return a floating point number, like from `time.mktime`, by parsing the
        string arguments `month_abbreviation`, `day` and `year_or_time`. The
        parameter `time_shift` is the difference "time on server" - "time on
        client" and is available as the `time_shift` parameter in the
        `parse_line` interface.

        If `with_precision` is true return a two-element tuple consisting of
        the floating point number as described in the previous paragraph and
        the precision of the time in seconds. The default is `False` for
        backward compatibility with custom parsers.

        The precision value takes into account that, for example, a time string
        like "May 26  2005" has only a precision of one day. This information
        is important for the `upload_if_newer` and `download_if_newer` methods
        in the `FTPHost` class.

        Times in Unix-style directory listings typically have one of these
        formats:

        - "Nov 23 02:33" (month name, day of month, time)

        - "May 26  2005" (month name, day of month, year)

        If this method can't make sense of the given arguments, it raises an
        `ftputil.error.ParserError`.
        z invalid month abbreviation {0!r}r   r   r   r   Nr   r   r   seconds)r   x   r	           )_month_numberslowerKeyErrorri   rj   rk   r,   r   DAY_PRECISIONMINUTE_PRECISIONsplitr   utcnowreplacer   r   	timedeltar   r   	timestampr"   )r$   month_abbreviationr   year_or_timer]   with_precisionr   year_is_knownst_mtime_precisionserver_yearr   r   r   
server_nowserver_utc_datetimer   s                   r&   parse_unix_timezParser.parse_unix_time   s   <	''(:(@(@(BCE
 ll3&</!.(,\6(JAqvK "2'--c2LD&T6*VX. $D "**113;;((,, < "":67J %//K, ~~UCvq""!",x/A/A#/NNO q  #nnT61
z23 '002 c>!2H///OG  	--++299:LM 	s   F 8Gc                 h   |j                  d      D cg c]  }| j                  |d       c}\  }}}|dk\  rn|dk\  rd|z   }nd|z   }	 |dd |d	d
 |d
   }}
}	| j                  |	d      | j                  |
d      }
}	|	dk(  r|dk(  rd}	|	dk7  r
|dk(  r|	dz  }	| j                  ||||	|
d      }|t        j                  |      z
  }|j                         }|dk  r	t        }d}nt        }|r||fS |S c c}w # t        $ r/ t        j                  j                  dj                  |            w xY w)am  
        Return a floating point number, like from `time.mktime`, by parsing the
        string arguments `date` and `time_`. The parameter `time_shift` is the
        difference

            "time on server" - "time on client"

        and can be set as the `time_shift` parameter in the `parse_line`
        interface.

        If `with_precision` is true return a two-element tuple consisting of
        the floating point number as described in the previous paragraph and
        the precision of the time in seconds. The default is `False` for
        backward compatibility with custom parsers.

        The precision value takes into account that, for example, a time string
        like "10-23-2001 03:25PM" has only a precision of one minute. This
        information is important for the `upload_if_newer` and
        `download_if_newer` methods in the `FTPHost` class.

        Usually, the returned precision is `MINUTE_PRECISION`, except when the
        date is before the epoch, in which case the returned `st_mtime` value
        is set to 0.0 and the precision to `UNKNOWN_PRECISION`.

        Times in MS-style directory listings typically have the format
        "10-23-01 03:25PM" (month-day_of_month-two_digit_year, hour:minute,
        am/pm).

        If this method can't make sense of the given arguments, it raises an
        `ftputil.error.ParserError`.
        r`   zyear/month/dayi  F   il  i  r   r
   r   r   zinvalid time string '{}'r   r   rF   APr   r   )r   r   
IndexErrorri   rj   rk   r,   r   r   r   r   r"   r   )r$   datetime_r]   r   partr   r   r   r   r   am_pmserver_datetimeclient_datetimer   r   s                   r&   parse_ms_timezParser.parse_ms_timeC  sg   X >BZZ_
59DLL/0
sD 4<RZ$;D$;D	V"'!*eAaj%(%&D T62DLL4Rf2:%3,D2:%3,BJD..uc4K)H,>,>z,RR",,.c>!2H!1///O=
  	V--++,F,M,Me,TUU	Vs   C4C9 98D1Nr   )F)r;   rB   rC   rD   r   recompilerU   rZ   r^   rz   r   staticmethodr   r   r   r1   r(   r&   r   r   R   s     N 2::o.L"A"*Z  , QVcJIr(   r   c                   (    e Zd ZdZed        ZddZy)r   z<
    `Parser` class for Unix-specific directory format.
    c                 f   | j                         }d}|dz   }t        |      |k  r.t        j                  j	                  dj                  |             	 t        |d          | j                  d|dz
        }d}|j                  |d       |S # t        $ r | j                  d|dz
        }Y |S w xY w)a  
        Split a line in metadata, nlink, user, group, size, month, day,
        year_or_time and name and return the result as an nine-element list of
        these values. If the name is a link, it will be encoded as a string
        "link_name -> link_target".
        r   r	   line '{}' can't be parsedr   Nr
   )	r   rh   ri   rj   rk   r,   r|   insertr}   )rX   
line_partsFIELD_COUNT_WITHOUT_USERIDFIELD_COUNT_WITH_USERIDUSER_FIELD_INDEXs        r&   _split_linezUnixParser._split_line  s     ZZ\
%&""<q"@z?77--++,G,N,Nt,TUU		6
1 D*Dq*HIJ .5  	GD*AA*EFJ 	Gs   B B0/B0c                 z   	 | j                  |      \	  }}}}}}}	}
}| j                  |      }d}d}t        |      }|}|}t        |      }d}| j                  ||	|
|d      \  }}d}|j                  d      dkD  r.t        j                  j	                  dj                  |            |j                  d      dk(  r|j                  d      \  }}n|d}}t        ||||||||||f
      }||_        ||_        ||_        |S # t        $ r-}t        j                  j	                  t        |            d}~ww xY w)a  
        Return a `StatResult` instance corresponding to the given text line.
        The `time_shift` value is needed to determine to which year a datetime
        without an explicit year belongs.

        If the line can't be parsed, raise a `ParserError`.
        NTr   z -> r	   z%name '{}' contains more than one "->")r   r}   ri   rj   rk   strrz   r|   r   countr,   r   r   r#   r   r   )r$   rX   r]   rv   nlinkusergroupsizer   r   r   nameexcr   r   r   r   r   r   r   r   r   r   r   st_name	st_targetstat_results                              r&   r^   zUnixParser.parse_line  s   	6   &
 &&{3u:d)'+';';3j (< (
$$ ::f! --++;BB4H  ZZ1$!%F!3GY!%tYG 
" +='&!*c  	6--++CH55	6s   D 	D:(D55D:Nr   )r;   rB   rC   rD   r   r   r^   r1   r(   r&   r   r     s!      :Jr(   r   c                       e Zd ZdZddZy)r   z:
    `Parser` class for MS-specific directory format.
    c                 F   	 |j                  dd      \  }}}}d}|dk(  r|t        j                  z  }n|t        j                  z  }d}d}	d}
d}d}|dk7  r	 t        |      }nd}d}| j                  |||d      \  }}d}t        |||	|
||||||f
      }||_        d|_        ||_        |S # t        $ r/ t        j                  j	                  dj                  |            w xY w# t        $ r/ t        j                  j	                  dj                  |            w xY w)	aY  
        Return a `StatResult` instance corresponding to the given text line
        from a FTP server which emits "Microsoft format" (see end of file).

        If the line can't be parsed, raise a `ParserError`.

        The parameter `time_shift` isn't used in this method but is listed for
        compatibility with the base class.
        Nr   r      z<DIR>zinvalid size {}Tr   )r   r}   ri   rj   rk   r,   rl   rq   ru   r|   r   r   r   r   r#   )r$   rX   r]   r   r   dir_or_sizer   r   r   r   r   r   r   r   r   r   r   r   r   s                      r&   r^   zMSParser.parse_line  si   	V-1ZZa-@*D%d '!,G,G'!Wk* G'+'9'9%D (: (
$$  
$  $!%*<'m  	V--++,G,N,Nt,TUU	V(  Wmm//0A0H0H0UVVWs   B- C( -8C%(8D Nr   )r;   rB   rC   rD   r^   r1   r(   r&   r   r     s    Dr(   r   c                   T    e Zd ZdZd Zd Zd Zd ZddZddZ	d Z
d	 Zdd
ZddZy)_StatzD
    Methods for stat'ing directories, links and regular files.
    c                     || _         |j                  | _        t               | _        d| _        t        j                  j                         | _	        y )NT)
_hostpath_pathr   _parser_allow_parser_switchingri   
stat_cache	StatCache_lstat_cache)r$   hosts     r&   r'   z_Stat.__init__U  s>    
YY
!| (,$#..88:r(   c                 8    | j                   j                  |      S )zm
        Return a list of lines, as fetched by FTP's `LIST` command, when
        applied to `path`.
        )r   _dirr$   r   s     r&   	_host_dirz_Stat._host_dir`  s    
 zzt$$r(   c              #     K   | j                  |      }| j                  }|j                  r]t        |      |j                  j
                  k\  r;t        t        j                  dt        |      z              }|j                  |       |D ]  }| j                  j                  |      r| j                  j                  || j                  j                               }|j                  | j                  j                   | j                  j"                  fv r| j$                  j'                  ||j                        }|||<   |  yw)z
        Yield stat results extracted from the directory listing `path`. Omit
        the special entries for the directory itself and its parent directory.
        g?N)r   r   _enabledrh   _cacher   r|   mathceilresizer   rZ   r^   r   r]   r   curdirpardirr   r<   )r$   r   linescachenew_sizerX   r   	loop_paths           r&   _stat_results_from_dirz_Stat._stat_results_from_dirg  s    
 t$ !! >>c%jELL,=,==499S3u:%567HLL" 	D||((. ,,11$

8M8M8OPK##

(9(94::;L;L'MM

k.B.BCI*E)	s   EE	c                 8   | j                   j                  |      }| j                   j                  |      s.t        j                  j                  dj                  |            g }| j                  |      D ]  }|j                  }|j                  |       ! |S )a  
        Return a list of directories, files etc. in the directory named `path`.

        Like `os.listdir` the returned list elements have the type of the path
        argument.

        If the directory listing from the server can't be parsed, raise a
        `ParserError`.
        z8550 {}: no such directory or wrong directory parser used)
r   abspathisdirri   rj   PermanentErrorr,   r   r   r9   )r$   r   namesr   r   s        r&   _real_listdirz_Stat._real_listdir  s     zz!!$'zz%--..JQQRVW  66t< 	"K!**GLL!	" r(   c                    | j                   j                  |      }|| j                  v r| j                  |   S |dk(  rt        j                  j                  d      | j                   j                  |      \  }}| j                   j                  |      s|syd}| j                  |      D ]  }|j                  |k(  s|} ||S |r.t        j                  j                  dj                  |            y)a#  
        Return an object similar to that returned by `os.lstat`.

        If the directory listing from the server can't be parsed, raise a
        `ParserError`. If the directory can be parsed and the `path` is not
        found, raise a `PermanentError`. That means that if the directory
        containing `path` can't be parsed we get a `ParserError`, independent
        on the presence of `path` on the server.

        (`_exception_for_missing_path` is an implementation aid and _not_
        intended for use by ftputil clients.)
        /z can't stat remote root directoryNz!550 {}: no such file or directory)r   r   r   ri   rj   RootDirErrorr   r   r   r   r   r,   )r$   r   _exception_for_missing_pathdirnamebasenamelstat_result_for_pathr   s          r&   _real_lstatz_Stat._real_lstat  s     zz!!$'4$$$$$T** 3;--,,-OPP JJ,,T2 zz(1L !%
  66w? 	4K##x/(3%	4 !,((& --..3::4@  r(   c                     |}t               }	 | j                  ||      }|yt        j                  |j                        s|S | j
                  j                  |      \  }}| j
                  j                  ||j                        }| j
                  j                  | j
                  j                  |            }||v r.t        j                  j                  dj                  |            |j                  |       )a  
        Return info from a "stat" call on `path`.

        If the directory containing `path` can't be parsed, raise a
        `ParserError`. If the listing can be parsed but the `path` can't be
        found, raise a `PermanentError`. Also raise a `PermanentError` if
        there's an endless (cyclic) chain of symbolic links "behind" the
        `path`.

        (`_exception_for_missing_path` is an implementation aid and _not_
        intended for use by ftputil clients.)
        Nz6recursive link structure detected for remote path '{}')setr   rl   S_ISLNKr   r   r   r<   r   r   normpathri   rj   RecursiveLinksErrorr,   add)r$   r   r   original_pathvisited_pathslstat_resultr   _s           r&   
_real_statz_Stat._real_stat  s     ++D2MNL# << 4 45## ))$/JGQ::??7L,C,CDD::%%djj&9&9$&?@D}$mm77LSS%  d#/ r(   c                     	  ||i |}|| j                   ur	|rd| _        |S # t        j                  j                  $ r. | j                  r d| _        t               | _         ||i |cY S  w xY w)z
        Call `method` with the `args` and `kwargs` once. If that results in a
        `ParserError` and only one parser has been used yet, try the other
        parser. If that still fails, propagate the `ParserError`.
        F)r   r   ri   rj   rk   r   r   )r$   methodargskwargsresults        r&   __call_with_parser_retryz_Stat.__call_with_parser_retry  s{    	T,V,F d000f/4,M}}(( 	++/4,'zt.v..	s    # AA.,A.c                 :    | j                  | j                  |      S )z
        Return a list of items in `path`.

        Raise a `PermanentError` if the path doesn't exist, but maybe raise
        other exceptions depending on the state of the server (e. g. timeout).
        )_Stat__call_with_parser_retryr   r   s     r&   _listdirz_Stat._listdir2  s     ,,T-?-?FFr(   c                 <    | j                  | j                  ||      S )z
        Return a `StatResult` without following links.

        Raise a `PermanentError` if the path doesn't exist, but maybe raise
        other exceptions depending on the state of the server (e. g. timeout).
        )r  r   r$   r   r   s      r&   _lstatz_Stat._lstat;  s%     ,,d$?
 	
r(   c                 <    | j                  | j                  ||      S )z
        Return a `StatResult` with following links.

        Raise a `PermanentError` if the path doesn't exist, but maybe raise
        other exceptions depending on the state of the server (e. g. timeout).
        )r  r
  r  s      r&   _statz_Stat._statF  s#     ,,OOT#>
 	
r(   N)T)r;   rB   rC   rD   r'   r   r   r   r   r
  r  r  r  r  r1   r(   r&   r   r   N  s=    	;%h08t($T6G	
	
r(   r   )rD   r   r   r   rl   ftputil.errorri   ftputil.stat_cache__all__r   r   r"   tupler   r   r   r   r   r1   r(   r&   <module>r     s~   
   	    =   0Q 0Qlz zz	m m`Iv I^A
 A
r(   