
    O|b                        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ddl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ddlZdgZej"                  j$                  r G d dej&                        Znej&                  Z G d d      Zy)z]
`FTPHost` is the central class of the `ftputil` library.

See `__init__.py` for an example.
    NFTPHostc                        e Zd Z fdZ xZS )default_session_factoryc                 f    d|vrt         j                  j                  |d<   t        |   |i | y )Nencoding)ftputilpath_encodingDEFAULT_ENCODINGsuper__init__)selfargskwargs	__class__s      ,lib/python3.12/site-packages/ftputil/host.pyr   z default_session_factory.__init__,   s5     '%,%:%:%K%Kz"Gd-f-    )__name__
__module____qualname__r   __classcell__)r   s   @r   r   r   +   s    	. 	.r   r   c                   h   e Zd ZdZd Zd Zd Zd Zd Z	 	 	 	 	 d+ddd	Z	d
 Z
d Zed        Zd Zd Zd Zd Zeej&                  j(                  dfd       Zd Zd,dZd,dZd Zd,dZd,dZd Zd-dZd Zd Zd,dZ d.dZ!d Z"d Z#e#Z$d/d Z%d! Z&d" Z'd# Z(d0d$Z)d0d%Z*d1d&Z+d' Z,d( Z-d) Z.d* Z/y)2r   z
    FTP host class.
    c                    || _         || _        | j                         | _        t        j
                  j                  |       | _        t        j                  j                  |       | _	        | j                  j                  | _        | j                  j                          t        j                  j                  5  | j                  j                         }| j
                  j!                  t        j"                  j%                  || j&                              | _        ddd       g | _        d| _        d| _        d\  | _        | _        | _        d| _        d| _        y# 1 sw Y   BxY w)z>
        Abstract initialization of `FTPHost` object.
        r   NF).z../        )_args_kwargs_make_session_sessionr   path_Pathstat_Stat_stat_lstat_cache
stat_cacheenableerrorftplib_error_to_ftp_os_errorpwdnormpathtoolas_str_path	_encoding_cached_current_dir	_children_fileclosedcurdirpardirsep_time_shiftuse_list_a_option)r   r   r   current_dirs       r   r   zFTPHost.__init__V   s   
 
 **,LL&&t,	\\''-
**11 ]]77 	--++-K'+yy'9'9((t~~(N(D$	  
 .<*T[$(  "'-	 	s   ;A$E  E)c                     t         j                  j                  5  | j                  j	                          ddd       y# 1 sw Y   yxY w)aX  
        Try to keep the connection alive in order to avoid server timeouts.

        Note that this won't help if the connection has already timed out! In
        this case, `keep_alive` will raise an `TemporaryError`. (Actually, if
        you get a server timeout, the error - for a specific connection - will
        be permanent.)
        N)r   r)   r*   r    r+   r   s    r   
keep_alivezFTPHost.keep_alive   s6     ]]77 	 MM	  	  	 s	   ?Ac                 t   | j                   dd }| j                  j                         }|j                  dt              }t
        j                  j                  5   ||i |}t        |d      s#t
        j                  j                  d|d      |j                  | _        ddd       |S # 1 sw Y   S xY w)zp
        Return a new session object according to the current state of this
        `FTPHost` instance.
        Nsession_factoryr   zsession instance z" must have an `encoding` attribute)r   r   copypopr   r   r)   r*   hasattrNoEncodingErrorr   r/   )r   r   r   factorysessions        r   r   zFTPHost._make_session   s     zz!}""$ **.0GH]]77 	.t.v.G7J/mm33'{2TU  %--DN	. 	. s   A	B--B7c                 N     | j                   | j                  i | j                  S )z9
        Return a copy of this `FTPHost` object.
        )r   r   r   r;   s    r   _copyzFTPHost._copy   s"     t~~tzz:T\\::r   c                    | j                   D ]7  }|j                  j                  s	 |j                  j	                          |c S  y# t
        j                  $ r Y Pt
        j                  $ r Y dt        $ r Y nt        $ r Y xw xY w)z
        Return an available (i. e. one whose `_file` object is closed and
        doesn't have a timed-out server connection) child (`FTPHost` object)
        from the pool of children or `None` if there aren't any.
        N)
r1   r2   r3   r    r+   ftpliberror_reply
error_tempEOFErrorOSErrorr   hosts     r   _available_childzFTPHost._available_child   s     NN !	 D zz   MM%%'0  KC!	 F ) )) ((    
  s#   ABB1B;BBN)restc          	      F   t         j                  j                  || j                        }| j	                         }|O| j                         }| j                  j                  |       t         j                  j                  |      |_
        | j                         }	|j                  j                  |      r|}
n|j                  j                  |	|      }
|j                  j                  |
      \  }}	 |j!                  |       |j                  j+                  |||||||       d|v r| j,                  j/                  |
       |j                  S # t         j"                  j$                  $ r/ t         j"                  j'                  dj)                  |            w xY w)a   
        Return an open file(-like) object which is associated with this
        `FTPHost` object.

        The arguments `path`, `mode`, `buffering`, `encoding`, `errors` and
        `newlines` have the same meaning as for `open`. If `rest` is given as
        an integer,

        - reading will start at the byte (zero-based) `rest`
        - writing will overwrite the remote file from byte `rest`

        This method tries to reuse a child but will generate a new one if none
        is available.
        r   zEremote directory '{}' doesn't exist or has insufficient access rights)mode	bufferingr   errorsnewlinerP   w)r   r-   r.   r/   rO   rF   r1   appendfileFTPFiler2   getcwdr!   isabsjoinsplitchdirr)   PermanentError
FTPIOErrorformat_openr'   
invalidate)r   r!   rR   rS   r   rT   rU   rP   rN   basedireffective_patheffective_direffective_files                r   openzFTPHost.open   s[   6 ||''t~~'F$$&<::<DNN!!$' --d3DJ++- 99??4 !N!YY^^GT:N(,		(G%~		JJ}% 	

 	 	
 $;OO&&~6zz' }}++ 	 --**::@&:O 	s   6E AF c                    | j                   ry| j                  D ],  }|j                  j                          |j                          . 	 t        j
                  j                  5  | j                  j                          ddd       | j                  j                          g | _        d| _         y# 1 sw Y   2xY w# | j                  j                          g | _        d| _         w xY w)z(
        Close host connection.
        NT)
r3   r1   r2   closer   r)   r*   r    r'   clearrM   s     r   rj   zFTPHost.close  s     ;;NN 	DJJJJL	
		;; &##%& OO!!#DNDK& & OO!!#DNDKs$   
B< $B0?B< 0B95B< <*C&c                 |    | j                   j                          || j                  _        d| j                  _        y)a,  
        Set the parser for extracting stat results from directory listings.

        The parser interface is described in the documentation, but here are
        the most important things:

        - A parser should derive from `ftputil.stat.Parser`.

        - The parser has to implement two methods, `parse_line` and
          `ignores_line`. For the latter, there's a probably useful default
          in the class `ftputil.stat.Parser`.

        - `parse_line` should try to parse a line of a directory listing and
          return a `ftputil.stat.StatResult` instance. If parsing isn't
          possible, raise `ftputil.error.ParserError` with a useful error
          message.

        - `ignores_line` should return a true value if the line isn't assumed
          to contain stat information.
        FN)r'   rk   r%   _parser_allow_parser_switching)r   parsers     r   
set_parserzFTPHost.set_parser8  s,    , 	#

-2

*r   c                 v    d}| dk(  ryt        |       }| |z  }t        |d|z  z   d|z  z        d|z  z  }||z  S )z
        Return the given time shift in seconds, but rounded to 15-minute units.
        The argument is also assumed to be given in seconds.
              N@r   r   g      @g      .@)absint)
time_shiftminuteabsolute_time_shiftsignumabsolute_rounded_time_shifts        r   __rounded_time_shiftzFTPHost.__rounded_time_shiftV  sb     ?!*o11&) C&L1dVmD'
F]'# 333r   c                 l   d}d|z  }t        | j                  |            }|d|z  kD  r.t        j                  j	                  dj                  |            d|z  }t        || j                  |      z
        |kD  r8t        j                  j	                  dj                  |t        |                  y)z
        Perform sanity checks on the time shift value (given in seconds). If
        the value is invalid, raise a `TimeShiftError`, else simply return
        `None`.
        rr      z!time shift abs({0:.2f} s) > 1 day   zFtime shift ({0:.2f} s) deviates more than {1:d} s from 15-minute unitsN)rs   _FTPHost__rounded_time_shiftr   r)   TimeShiftErrorra   rt   )r   ru   rv   hourry   maximum_deviations         r   __assert_valid_time_shiftz!FTPHost.__assert_valid_time_shiftj  s     f}&)$*C*CJ*O&P# 'd2--..3:::F 
 JzD55jAABEVV--..''-vj#>O:P'Q  Wr   c                     | j                  |       | j                         }||k7  r1| j                  j                          | j	                  |      | _        yy)a\  
        Set the time shift value.

        By (my) definition, the time shift value is the difference of
        the time zone used in server listings and UTC, i. e.

            time_shift =def= t_server - utc
        <=> t_server = utc + time_shift
        <=> utc = t_server - time_shift

        The time shift is measured in seconds.
        N)!_FTPHost__assert_valid_time_shiftru   r'   rk   r~   r7   )r   ru   old_time_shifts      r   set_time_shiftzFTPHost.set_time_shift  sP     	&&z2*' OO!!##88DD (r   c                     | j                   S )z
        Return the time shift between FTP server and client. See the
        docstring of `set_time_shift` for more on this value.
        )r7   r;   s    r   ru   zFTPHost.time_shift  s    
 r   c                    d}	 | j                  |d      }|j                          	 | j                  j                  |      }| j                  |       t        j                         }||z
  }|dk  rkt        j                  j                  |t        j                  j                         }|j#                  |j$                  dz         }|j'                         |z
  }| j)                  |       y	# t        j                  j                  $ r= t        j                  j                  dj                  | j                                     w xY w# t        j                  j                  $ r  t        j                  j                  d      w xY w)
ai  
        Synchronize the local times of FTP client and server. This is necessary
        to let `upload_if_newer` and `download_if_newer` work correctly. If
        `synchronize_times` isn't applicable (see below), the time shift can
        still be set explicitly with `set_time_shift`.

        This implementation of `synchronize_times` requires _all_ of the
        following:

        - The connection between server and client is established.
        - The client has write access to the directory that is current when
          `synchronize_times` is called.

        The common usage pattern of `synchronize_times` is to call it directly
        after the connection is established. (As can be concluded from the
        points above, this requires write access to the login directory.)

        If `synchronize_times` fails, it raises a `TimeShiftError`.
        _ftputil_sync_rV   z,couldn't write helper file in directory '{}'z)could write helper file but not unlink iti d%)tz   )yearN)rh   rj   r   r)   r`   r   ra   rZ   r!   getmtimeunlink
FTPOSErrortimedatetimefromtimestamptimezoneutcreplacer   	timestampr   )r   helper_file_namefile_server_timenowru   server_datetimes          r   synchronize_timeszFTPHost.synchronize_times  s_   ( ,	II.4EKKM	)),,-=>KKK() iik 3&

 ++ '//== 1 1 5 5 > O .55?;O;ORS;S5TO(224s:JJ'G }}'' 	--..BII$++-X 	 }}'' 		 --..; 		s   "C. ,E .AE=Fc                 H    t         j                  j                  | |||       y)zX
        Copy data from file-like object `source` to file-like object `target`.
        N)r   file_transfercopyfileobj)sourcetargetmax_chunk_sizecallbacks       r   r   zFTPHost.copyfileobj  s     	))&&.(Sr   c                     t         j                  j                  |d      }t         j                  j                  | |d      }||fS )z
        Return a `LocalFile` and `RemoteFile` as source and target,
        respectively.

        The strings `source_path` and `target_path` are the (absolute or
        relative) paths of the local and the remote file, respectively.
        rbwb)r   r   	LocalFile
RemoteFiler   source_pathtarget_pathsource_filetarget_files        r   _upload_fileszFTPHost._upload_files  sA     ++55k4H++66t[$OK''r   c                 *   |dv rt        d      t        j                  j                  |d       t        j                  j	                  || j
                        }| j                  ||      \  }}t        j                  j                  ||d|       y)	a  
        Upload a file from the local source (name) to the remote target (name).

        If a callable `callback` is given, it's called after every chunk of
        transferred data. The chunk size is a constant defined in
        `file_transfer`. The callback will be called with a single argument,
        the data chunk that was transferred before the callback was called.
         r   path argument `source` is emptyr   path_argument_namer   Fconditionalr   N)	IOErrorr   r-   raise_for_empty_pathr.   r/   r   r   	copy_filer   r   r   r   r   r   s         r   uploadzFTPHost.upload   s     Y;<<))&X)N))&4>>)J#'#5#5ff#E [''%( 	( 	
r   c                 (   t         j                  j                  |d       |dv rt        d      t         j                  j	                  || j
                        }| j                  ||      \  }}t         j                  j                  ||d|      S )a7  
        Upload a file only if it's newer than the target on the remote host or
        if the target file does not exist. See the method `upload` for the
        meaning of the parameters.

        If an upload was necessary, return `True`, else return `False`.

        If a callable `callback` is given, it's called after every chunk of
        transferred data. The chunk size is a constant defined in
        `file_transfer`. The callback will be called with a single argument,
        the data chunk that was transferred before the callback was called.
        r   r   r   path argument `target` is emptyr   Tr   )	r   r-   r   r   r.   r/   r   r   r   r   s         r   upload_if_newerzFTPHost.upload_if_newer  s     	))&X)NY;<<))&4>>)J#'#5#5ff#E [$$..$ / 
 	
r   c                     t         j                  j                  | |d      }t         j                  j                  |d      }||fS )z
        Return a `RemoteFile` and `LocalFile` as source and target,
        respectively.

        The strings `source_path` and `target_path` are the (absolute or
        relative) paths of the remote and the local file, respectively.
        r   r   )r   r   r   r   r   s        r   _download_fileszFTPHost._download_files(  sA     ++66t[$O++55k4HK''r   c                 *   t         j                  j                  |d       |dv rt        d      t         j                  j	                  || j
                        }| j                  ||      \  }}t         j                  j                  ||d|       y)	a  
        Download a file from the remote source (name) to the local target
        (name).

        If a callable `callback` is given, it's called after every chunk of
        transferred data. The chunk size is a constant defined in
        `file_transfer`. The callback will be called with a single argument,
        the data chunk that was transferred before the callback was called.
        r   r   r   r   r   Fr   N)	r   r-   r   r   r.   r/   r   r   r   r   s         r   downloadzFTPHost.download4  s     	))&X)NY;<<))&4>>)J#'#7#7#G [''%( 	( 	
r   c                 (   |dv rt        d      t        j                  j                  |d       t        j                  j	                  || j
                        }| j                  ||      \  }}t        j                  j                  ||d|      S )a;  
        Download a file only if it's newer than the target on the local host or
        if the target file does not exist. See the method `download` for the
        meaning of the parameters.

        If a download was necessary, return `True`, else return `False`.

        If a callable `callback` is given, it's called after every chunk of
        transferred data. The chunk size is a constant defined in
        `file_transfer`. The callback will be called with a single argument,
        the data chunk that was transferred before the callback was called.
        r   r   r   r   r   Tr   )	r   r   r-   r   r.   r/   r   r   r   r   s         r   download_if_newerzFTPHost.download_if_newerG  s     Y;<<))&X)N))&4>>)J#'#7#7#G [$$..$ / 
 	
r   c                     | j                         }	 | j                  |       y# t        j                  j                  $ r/ t        j                  j                  dj                  |            w xY w)z
        Raise an `InaccessibleLoginDirError` exception if we can't change to
        the login directory. This test is only reliable if the current
        directory is the login directory.
        z directory '{}' is not accessibleN)rZ   r^   r   r)   r_   InaccessibleLoginDirErrorra   )r   presumable_login_dirs     r   #_check_inaccessible_login_directoryz+FTPHost._check_inaccessible_login_directory`  sa      ${{}	JJ+,}}++ 	--99299:NO 	s
   $ AA0c                 \   | j                          | j                         }	 |r+| j                  |        || d      | j                  |       S | j                  j	                  |      \  }}| j                  |        || |      | j                  |       S # | j                  |       w xY w)a  
        Run an FTP command on a path. The return value of the method is the
        return value of the command.

        If `descend_deeply` is true (the default is false), descend deeply,
        i. e. change the directory to the end of the path.
        r   )r   rZ   r^   r!   r]   )r   commandr!   descend_deeplyold_dirheadtails          r   _robust_ftp_commandzFTPHost._robust_ftp_commandp  s     	002 ++-	 

4  tR( JJw	 "YY__T2
d

4 tT*JJwDJJws   B 7B B+c                     | j                   S )z4
        Return the current directory path.
        )r0   r;   s    r   rZ   zFTPHost.getcwd  s     '''r   c                 v   t         j                  j                  || j                        }t         j                  j
                  5  | j                  j                  |       ddd       | j                  j                  | j                  j                  | j                  |            | _        y# 1 sw Y   NxY w)z=
        Change the directory on the host to `path`.
        r   N)r   r-   r.   r/   r)   r*   r    cwdr!   r,   r\   r0   r   r!   s     r   r^   zFTPHost.chdir  s     ||''t~~'F]]77 	$MMd#	$ $(99#5#5IINN433T:$
 		$ 	$s   B//B8c                     t         j                  j                  |       t         j                  j                  || j                        }d }| j                  ||       y)z
        Make the directory path on the remote host. The argument `mode` is
        ignored and only "supported" for similarity with `os.mkdir`.
        r   c                     t         j                  j                  5  | j                  j	                  |       ddd       y# 1 sw Y   yxY wCallback function.N)r   r)   r*   r    mkdr   s     r   r   zFTPHost.mkdir.<locals>.command  6    ;; (!!$'( ( (   A  A	N)r   r-   r   r.   r/   r   r   r!   rR   r   s       r   mkdirzFTPHost.mkdir  sJ    
 	))$/||''t~~'F	(
 	  $/r   c                    t         j                  j                  |       t         j                  j                  || j                        }| j
                  j                  |      }|j                  | j                        }| j                         }	 t        dt        |            D ]  }| j                   | j
                  j                  |d|dz     z   }	 | j                  |       |t        |      dz
  k(  sS|rVt         j                  j                  dj!                  |            }t"        j$                  |_        | 	 | j                  |       y# t         j                  j                  $ rV 	 | j'                  |       n?# t         j                  j                  $ r | j
                  j)                  |      s Y nw xY wY !w xY w# | j                  |       w xY w)at  
        Make the directory `path`, but also make not yet existing intermediate
        directories, like `os.makedirs`.

        The value of `mode` is only accepted for compatibility with
        `os.makedirs` but otherwise ignored.

        If `exist_ok` is `False` (the default) and the leaf directory exists,
        raise a `PermanentError` with `errno` 17.
        r   r   Nzpath {!r} exists)r   r-   r   r.   r/   r!   abspathr]   r6   rZ   rangelenr\   r^   r)   r_   ra   errnoEEXISTr   isdir)	r   r!   rR   exist_okdirectoriesr   indexnext_directoryftp_os_errors	            r   makedirszFTPHost.makedirs  s    	))$/||''t~~'Fyy  &jj*++-$	  q#k"23 +!%NDIINNK%RS)<T,U!U+JJ~. [!1A!55
 (/}}'C'C.55d;( .3\\***?+B JJw3 }}33 
""

>2"==77 "
  $yy~>!  ?"	
"2 JJwsb   AG E(G :G =AG G	4FG	9G?G	GG	G G		G Gc                    t         j                  j                  |       t         j                  j                  || j                        }| j
                  j                  |      }| j                  |      r.t         j                  j                  dj                  |            d }	 | j                  ||       | j                  j                  |       y# | j                  j                  |       w xY w)a
  
        Remove the _empty_ directory `path` on the remote host.

        Compatibility note:

        Previous versions of ftputil could possibly delete non-empty
        directories as well, - if the server allowed it. This is no longer
        supported.
        r   zdirectory '{}' not emptyc                     t         j                  j                  5  | j                  j	                  |       ddd       y# 1 sw Y   yxY wr   )r   r)   r*   r    rmdr   s     r   r   zFTPHost.rmdir.<locals>.command  r   r   N)r   r-   r   r.   r/   r!   r   listdirr)   r_   ra   r   r'   rc   r   r!   r   s      r   rmdirzFTPHost.rmdir  s     	))$/||''t~~'Fyy  &<<--../I/P/PQU/VWW	(	-$$Wd3OO&&t,DOO&&t,s   )C C4c                 P   t         j                  j                  |       t         j                  j                  || j                        }| j
                  j                  |      }| j
                  j                  |      s6| j
                  j                  |      s| j
                  j                  |      s2d }	 | j                  ||       | j                  j                  |       yt         j                  j                  d      # | j                  j                  |       w xY w)z
        Remove the file or link given by `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).
        r   c                     t         j                  j                  5  | j                  j	                  |       ddd       y# 1 sw Y   yxY wr   )r   r)   r*   r    deleter   s     r   r   zFTPHost.remove.<locals>.command(  s6    ]]?? /MM((./ / /r   z>remove/unlink can only delete files and links, not directoriesN)r   r-   r   r.   r/   r!   r   isfileislinkexistsr   r'   rc   r)   r_   r   s      r   removezFTPHost.remove  s     	))$/||''t~~'Fyy  & IIT"yy%99##D)/1(($7**40--..S  **40s   ;D D%c                    t         j                  j                  |       t         j                  j                  || j                        }|rd }n|d }n|}g }	 | j                  |      }|D ]u  }| j                  j                  ||      }	 | j                  |      j                  }t        j                  |      r| j!                  |||       d	 | j#                  |       w 	 | j%                  |       y# t         j                  j                  $ r)  || j
                  |t        j                                Y w xY w# t         j                  j                  $ r d}Y w xY w# t         j                  j                  $ r*  || j"                  |t        j                                Y ?w xY w# t         j                  j&                  $ r)  || j$                  |t        j                                Y yw xY w)a  
        Remove the given remote, possibly non-empty, directory tree. The
        interface of this method is rather complex, in favor of compatibility
        with `shutil.rmtree`.

        If `ignore_errors` is set to a true value, errors are ignored. If
        `ignore_errors` is a false value _and_ `onerror` isn't set, all
        exceptions occurring during the tree iteration and processing are
        raised. These exceptions are all of type `PermanentError`.

        To distinguish between error situations, pass in a callable for
        `onerror`. This callable must accept three arguments: `func`, `path`
        and `exc_info`. `func` is a bound method object, _for example_
        `your_host_object.listdir`. `path` is the path that was the recent
        argument of the respective method (`listdir`, `remove`, `rmdir`).
        `exc_info` is the exception info as it's got from `sys.exc_info`.

        Implementation note: The code is copied from `shutil.rmtree` in
        Python 2.4 and adapted to ftputil.
        r   c                       y)zDo nothing.N r   s    r   new_onerrorz#FTPHost.rmtree.<locals>.new_onerrorV  s     r   Nc                        )zRe-raise exception.r   r   s    r   r   z#FTPHost.rmtree.<locals>.new_onerror]  s     r   r   )r   r-   r   r.   r/   r   r)   r_   sysexc_infor!   r\   lstatst_moder#   S_ISDIRrmtreer   r   r   )	r   r!   ignore_errorsonerrorr   namesname	full_namerR   s	            r   r  zFTPHost.rmtree;  s   * 	))$/||''t~~'F 
 _ "K	<LL&E  	HD		tT2Izz),44 ||D!I}kBHKK	*	H	:JJt! }}++ 	<dCLLN;	< ==//  }}33 HYGH }}'' 	:

D#,,.9	:sK   C: EE((F2 :AE ?E E%$E%(AF/.F/2AG87G8c                     t         j                  j                  |d       t         j                  j                  |d       t         j                  j                  | j                        }t         j                  j                  | j                        } j
                  j                  |      \  }} j
                  j                  |      \  }} fd} j                          d|v xs d|v }|rB||k(  r= j                         }		  j                  |        |||        j                  |	       y |||       y#  j                  |	       w xY w)zB
        Rename the `source` on the FTP host to `target`.
        r   r   r   r   c                 X   	 t         j                  j                  5  j                  j	                  | |       d d d        j
                  j                  |       }j
                  j                  |      }j                  j                  |       j                  j                  |       y # 1 sw Y   vxY w# j
                  j                  |       }j
                  j                  |      }j                  j                  |       j                  j                  |       w xY wN)	r   r)   r*   r    renamer!   r   r'   rc   )
source_arg
target_argsource_absolute_pathtarget_absolute_pathr   s       r   rename_with_cleanupz+FTPHost.rename.<locals>.rename_with_cleanup  s    	A]]?? AMM((Z@A
 (,yy'8'8'D$'+yy'8'8'D$**+?@**+?@A A
 (,yy'8'8'D$'+yy'8'8'D$**+?@**+?@s"   B; B/B; /B84B; ;A.D) N)
r   r-   r   r.   r/   r!   r]   r   rZ   r^   )
r   r   r   source_headsource_tailtarget_headtarget_tailr  paths_contain_whitespacer   s
   `         r   r  zFTPHost.rename{  s    	))&X)N))&X)N))&4>>)J))&4>>)J#'99??6#: [#'99??6#: [
	A 	002$';$6#OC;<N #{(BkkmG$

;'#K=

7#  / 

7#s   E Ec                 4    d }| j                  ||d      }|S )zj
        Return a directory listing as made by FTP's `LIST` command as a list of
        strings.
        c                     g  fd}t         j                  j                  5   j                  r j                  j                  d||       n j                  j                  ||       ddd       S # 1 sw Y   S xY w)r   c                 z    j                  t        j                  j                  | j                               y)r   r   N)rW   r   r-   as_strr/   )linelinesr   s    r   r   z<FTPHost._dir.<locals>._FTPHost_dir_command.<locals>.callback  s'    W\\000OPr   z-aN)r   r)   r*   r8   r    dir)r   r!   r   r  s   `  @r   _FTPHost_dir_commandz*FTPHost._dir.<locals>._FTPHost_dir_command  sn    EQ ;; 6))MM%%dD(;MM%%dH5	6
 L6
 Ls   AA66B T)r   )r   )r   r!   r  r  s       r   _dirzFTPHost._dir  s,    	 (( $t ) 
 r   c                 L   t         j                  j                  |       |}t         j                  j                  || j                        }| j
                  j                  |      }|D cg c]-  }t         j                  j                  ||| j                        / c}S c c}w )z
        Return a list of directories, files etc. in the directory named `path`.

        If the directory listing from the server can't be parsed with any of
        the available parsers raise a `ParserError`.
        r   )r   r-   r   r.   r/   r%   _listdirsame_string_type_as)r   r!   original_pathitemsitems        r   r   zFTPHost.listdir  s     	))$/||''t~~'F

##D) 
 LL,,]D$..Q
 	
 
s   ,2B!c                     t         j                  j                  |       t         j                  j                  || j                        }| j
                  j                  ||      S )a  
        Return an object similar to that returned by `os.lstat`.

        If the directory listing from the server can't be parsed with any of
        the available parsers, raise a `ParserError`. If the directory _can_ be
        parsed and the `path` is _not_ found, raise a `PermanentError`.

        (`_exception_for_missing_path` is an implementation aid and _not_
        intended for use by ftputil clients.)
        r   )r   r-   r   r.   r/   r%   _lstatr   r!   _exception_for_missing_paths      r   r   zFTPHost.lstat  sK     	))$/||''t~~'Fzz  'BCCr   c                     t         j                  j                  |       t         j                  j                  || j                        }| j
                  j                  ||      S )a  
        Return info from a "stat" call on `path`.

        If the directory containing `path` can't be parsed, raise a
        `ParserError`. If the directory containing `path` 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.)
        r   )r   r-   r   r.   r/   r%   r(  s      r   r#   zFTPHost.stat  sK     	))$/||''t~~'Fzz&ABBr   c              #     K   t         j                  j                  |d       t         j                  j                  || j                        }	 | j                  |      }g g }}|D ]Z  }	| j                  j                  | j                  j                  ||	            r|j                  |	       J|j                  |	       \ |r|||f |D ]X  }	| j                  j                  ||	      }
|s| j                  j                  |
      r=| j                  |
|||      E d{    Z |s|||f yy# t         j                  j                  $ r}| ||       Y d}~yd}~ww xY w7 Ew)z
        Iterate over directory tree and return a tuple (dirpath, dirnames,
        filenames) on each iteration, like the `os.walk` function (see
        https://docs.python.org/library/os.html#os.walk ).
        topr   r   N)r   r-   r   r.   r/   r   r)   r   r!   r   r\   rW   r   walk)r   r,  topdownr  followlinksr  errdirsnondirsr  r!   s              r   r-  zFTPHost.walk  sL     	))#%)Hll&&sT^^&D	LL%E
 Bg 	%Dyytyy~~c489D!t$		%
 tW$$ 	JD99>>#t,D$))"2"24"899T7G[III	J tW$$ ! }}'' 	"	 JsC   AE+D5 !B*E+E+#E)$E+5E&
E!E+!E&&E+c                 4   t         j                  j                  |       t         j                  j                  || j                        }| j
                  j                  |      }fd}| j                  ||       | j                  j                  |       y)a  
        Change the mode of a remote `path` (a string) to the integer `mode`.
        This integer uses the same bits as the mode value returned by the
        `stat` and `lstat` commands.

        If something goes wrong, raise a `TemporaryError` or a
        `PermanentError`, according to the status code returned by the server.
        In particular, a non-existent path usually causes a `PermanentError`.
        r   c                     t         j                  j                  5  | j                  j	                  dj                  |             ddd       y# 1 sw Y   yxY w)r   zSITE CHMOD 0{0:o} {1}N)r   r)   r*   r    voidcmdra   )r   r!   rR   s     r   r   zFTPHost.chmod.<locals>.command(  sI    ;; R%%&=&D&DT4&PQR R Rs   ,AAN)
r   r-   r   r.   r/   r!   r   r   r'   rc   r   s     ` r   chmodzFTPHost.chmod  sr     	))$/||''t~~'Fyy  &	R
 	  $/""4(r   c                     t        d      )Nzcannot serialize FTPHost object)	TypeErrorr;   s    r   __getstate__zFTPHost.__getstate__0  s    9::r   c                     | S r
  r   r;   s    r   	__enter__zFTPHost.__enter__6  s	     r   c                 $    | j                          yNF)rj   )r   exc_typeexc_valexc_tbs       r   __exit__zFTPHost.__exit__;  s     	

r   )rNNNNr
  )Fr=  )FN)T)TNF)0r   r   r   __doc__r   r<   r   rF   rO   rh   rj   rp   staticmethodr~   r   r   ru   r   r   r   MAX_COPY_CHUNK_SIZEr   r   r   r   r   r   r   r   r   rZ   r^   r   r   r   r   r   r  r  r  r   r   r#   r-  r6  r9  r;  rA  r   r   r   r   r   >   s-   .''R $*;-d ? ?B43< 4 4&0E, >(P  ,,@@		T 	T(
$
,
(
&
2 " N(
0,4 l-:"H F>:@*0`@
 DC"%>),;
r   )rC  r   r   rH   r#   r   r   ftputil.errorr   ftputil.fileftputil.file_transferftputil.pathftputil.path_encodingftputil.sessionftputil.statftputil.tool__all__r	   RUNNING_UNDER_PY39_AND_UPFTPr   r   r   r   r   <module>rQ     sx   
     
          + 22	.&** 	. %jjB Br   