
    RSigS                         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Zd dl	Z	n# e
$ r dxZ	ZY nw xY wdgZdddd	d
ddddddddZ G d d          Ze j        dk    redgz  Z G d de          ZdS dS )    N   )FilesystemError)memoizeAbstractedFSJanFebMarAprMayJunJulAugSepOctNovDec)r                        	   
         c                      e Zd ZdZd Zed             Zed             Zej        d             Zej        d             Ze	e
j        dk    fd            Zd	 Zd
 Zd Zd Zd Zd.dZd Zd Zd Zd Zd Zd Zd Zd Zd Zd Z ee
d          rd ZneZ ee
d          rd Zd  Z d! Z!d" Z"d# Z#d$ Z$d% Z%d& Z&e'd' Z(nd( Z(e)d) Z*nd* Z*d/d,Z+d/d-Z,dS )0r   a  A class used to interact with the file system, providing a
    cross-platform interface compatible with both Windows and
    UNIX style filesystems where all paths use "/" separator.

    AbstractedFS distinguishes between "real" filesystem paths and
    "virtual" ftp paths emulating a UNIX chroot jail where the user
    can not escape its home directory (example: real "/home/user"
    path will be seen as "/" by the client)

    It also provides some utility methods and wraps around all os.*
    calls involving operations against the filesystem like creating
    files or removing directories.

    FilesystemError exception can be raised from within any of
    the methods below in order to send a customized error string
    to the client.
    c                 0    d| _         || _        || _        dS )z
        - (str) root: the user "real" home directory (e.g. '/home/user')
        - (instance) cmd_channel: the FTPHandler class instance.
        /N)_cwd_rootcmd_channelselfrootr#   s      I/home/jrussi/.local/lib/python3.11/site-packages/pyftpdlib/filesystems.py__init__zAbstractedFS.__init__?   s      	
&    c                     | j         S )zThe user home directory.r"   r%   s    r'   r&   zAbstractedFS.rootM   s     zr)   c                     | j         S )z#The user current working directory.r!   r,   s    r'   cwdzAbstractedFS.cwdR   s     yr)   c                     || _         d S Nr+   r%   paths     r'   r&   zAbstractedFS.rootW   s    


r)   c                     || _         d S r1   r.   r2   s     r'   r/   zAbstractedFS.cwd[   s    			r)   ntc                 r    |r|                      d          rdS t          j                            |           S )Nr    T)
startswithosr3   isabs)r3   _windowss     r'   _isabszAbstractedFS._isabsa   s8      	,, 	4w}}T"""r)   c                    |                      |          r t          j                            |          }nBt          j                            t          j                            | j        |                    }t          j        dk    r|                    dd          }|dd         dk    r|dd         }|dd         dk    |                      |          sd}|S )am  Normalize a "virtual" ftp pathname (typically the raw string
        coming from client) depending on the current working directory.

        Example (having "/foo" as current working directory):
        >>> ftpnorm('bar')
        '/foo/bar'

        Note: directory separators are system independent ("/").
        Pathname returned is always absolutized.
        \r    Nr   z//r   )r;   r8   r3   normpathjoinr/   sepreplacer%   ftppathps      r'   ftpnormzAbstractedFS.ftpnormk   s     ;;w 	B  ))AA  dh!@!@AAA 6T>>		$$$A etmm!""A etmm
 {{1~~ 	Ar)   c                    t           j                            | j                  t           j        k    r2t           j                            |                     |                    S |                     |          dd         }t           j                            t           j                            | j        |                    S )aE  Translate a "virtual" ftp pathname (typically the raw string
        coming from client) into equivalent absolute "real" filesystem
        pathname.

        Example (having "/home/user" as root directory):
        >>> ftp2fs("foo")
        '/home/user/foo'

        Note: directory separators are system dependent.
        r   N)r8   r3   r>   r&   r@   rE   r?   rB   s      r'   ftp2fszAbstractedFS.ftp2fs   s     7DI&&"&007##DLL$9$9:::W%%abb)A7##BGLLA$>$>???r)   c                    |                      |          r t          j                            |          }nBt          j                            t          j                            | j        |                    }|                     |          sdS |                    t          j        d          }|t          | j                  d         }|
                    d          sd|z   }|S )a  Translate a "real" filesystem pathname into equivalent
        absolute "virtual" ftp pathname depending on the user's
        root directory.

        Example (having "/home/user" as root directory):
        >>> fs2ftp("/home/user/foo")
        '/foo'

        As for ftpnorm, directory separators are system independent
        ("/") and pathname returned is always absolutized.

        On invalid pathnames escaping from user's root directory
        (e.g. "/home" when root is "/home/user") always return "/".
        r    N)r;   r8   r3   r>   r?   r&   	validpathrA   r@   lenr7   )r%   fspathrD   s      r'   fs2ftpzAbstractedFS.fs2ftp   s     ;;v 	B  ((AA  di!@!@AAA~~a   	3IIbfc""c$)nn||C   	aAr)   c                 N   |                      | j                  }|                      |          }|                    t          j                  s|t          j        z  }|                    t          j                  s|t          j        z  }|dt          |                   |k    S )a/  Check whether the path belongs to user's home directory.
        Expected argument is a "real" filesystem pathname.

        If path is a symbolic link it is resolved to check its real
        destination.

        Pathnames escaping from user's root directory are considered
        not valid.
        r   )realpathr&   endswithr8   r@   rJ   )r%   r3   r&   s      r'   rI   zAbstractedFS.validpath   s     }}TY''}}T""}}RV$$ 	BFND}}RV$$ 	BFNDAD		M"d**r)   c                 "    t          ||          S )z"Open a file returning its handler.)open)r%   filenamemodes      r'   rQ   zAbstractedFS.open   s    Hd###r)    Nwbc                      G d d          }d|v}dt           _        t          j        ||||          \  }}t          j        ||          }	 ||	|          S )zA wrap around tempfile.mkstemp creating a file with a unique
        name.  Unlike mkstemp it returns an object with a file-like
        interface.
        c                       e Zd Zd Zd ZdS ))AbstractedFS.mkstemp.<locals>.FileWrapperc                 "    || _         || _        d S r1   )filename)r%   fdr[   s      r'   r(   z2AbstractedFS.mkstemp.<locals>.FileWrapper.__init__   s    	 			r)   c                 ,    t          | j        |          S r1   )getattrrZ   )r%   attrs     r'   __getattr__z5AbstractedFS.mkstemp.<locals>.FileWrapper.__getattr__   s    ty$///r)   N)__name__
__module____qualname__r(   r`    r)   r'   FileWrapperrX      s2        ! ! !0 0 0 0 0r)   re   b2   )text)tempfileTMP_MAXmkstempr8   fdopen)
r%   suffixprefixdirrS   re   rh   r\   r[   rZ   s
             r'   rk   zAbstractedFS.mkstemp   s}    	0 	0 	0 	0 	0 	0 	0 	0 $#FFCdCCCDyT""{4&&&r)   c                 b    t          j        |           |                     |          | _        dS )zvChange the current directory. If this method is overridden
        it is vital that `cwd` attribute gets set.
        N)r8   chdirrL   r/   r2   s     r'   rq   zAbstractedFS.chdir   s(    
 	;;t$$r)   c                 .    t          j        |           dS )zCreate the specified directory.N)r8   mkdirr2   s     r'   rs   zAbstractedFS.mkdir       
r)   c                 *    t          j        |          S z List the content of a directory.r8   listdirr2   s     r'   rx   zAbstractedFS.listdir       z$r)   c                 *    t          j        |          S rv   rw   r2   s     r'   listdirinfozAbstractedFS.listdirinfo   ry   r)   c                 .    t          j        |           dS )zRemove the specified directory.N)r8   rmdirr2   s     r'   r}   zAbstractedFS.rmdir   rt   r)   c                 .    t          j        |           dS )zRemove the specified file.N)r8   remover2   s     r'   r   zAbstractedFS.remove   s    
	$r)   c                 0    t          j        ||           dS )z2Rename the specified src file to the dst filename.N)r8   rename)r%   srcdsts      r'   r   zAbstractedFS.rename  s    
	#sr)   c                 h    t          t          d          st          t          j        ||           dS )zChange file/directory mode.chmodN)hasattrr8   NotImplementedErrorr   )r%   r3   rS   s      r'   r   zAbstractedFS.chmod  s2    r7## 	&%%
tr)   c                 *    t          j        |          S )z/Perform a stat() system call on the given path.)r8   statr2   s     r'   r   zAbstractedFS.stat  s    wt}}r)   c                 0    t          j        |||f          S )z)Perform a utime() call on the given path.)r8   utime)r%   r3   timevals      r'   r   zAbstractedFS.utime  s     xw0111r)   lstatc                 *    t          j        |          S )z-Like stat but does not follow symbolic links.)r8   r   r2   s     r'   r   zAbstractedFS.lstat  s    8D>>!r)   readlinkc                 *    t          j        |          S )z_Return a string representing the path to which a
            symbolic link points.
            )r8   r   r2   s     r'   r   zAbstractedFS.readlink"  s     ;t$$$r)   c                 @    t           j                            |          S )zReturn True if path is a file.)r8   r3   isfiler2   s     r'   r   zAbstractedFS.isfile*      w~~d###r)   c                 @    t           j                            |          S )z'Return True if path is a symbolic link.)r8   r3   islinkr2   s     r'   r   zAbstractedFS.islink.  r   r)   c                 @    t           j                            |          S )z#Return True if path is a directory.)r8   r3   isdirr2   s     r'   r   zAbstractedFS.isdir2  s    w}}T"""r)   c                 @    t           j                            |          S )z/Return the size of the specified file in bytes.)r8   r3   getsizer2   s     r'   r   zAbstractedFS.getsize6  s    wt$$$r)   c                 @    t           j                            |          S )zMReturn the last modified time as a number of seconds since
        the epoch.)r8   r3   getmtimer2   s     r'   r   zAbstractedFS.getmtime:  s     w%%%r)   c                 @    t           j                            |          S )zReturn the canonical version of path eliminating any
        symbolic links encountered in the path (if they are
        supported by the operating system).
        )r8   r3   rN   r2   s     r'   rN   zAbstractedFS.realpath?  s    
 w%%%r)   c                 @    t           j                            |          S )znReturn True if path refers to an existing path, including
        a broken or circular symbolic link.
        )r8   r3   lexistsr2   s     r'   r   zAbstractedFS.lexistsF  s     wt$$$r)   c                 Z    	 t          j        |          j        S # t          $ r |cY S w xY w)zReturn the username associated with user id.
            If this can't be determined return raw uid instead.
            On Windows just return "owner".
            )pwdgetpwuidpw_nameKeyErrorr%   uids     r'   get_user_by_uidzAbstractedFS.get_user_by_uidN  >    
|C((00   


    **c                     dS )Nownerrd   r   s     r'   r   zAbstractedFS.get_user_by_uidZ      7r)   c                 Z    	 t          j        |          j        S # t          $ r |cY S w xY w)zReturn the group name associated with group id.
            If this can't be determined return raw gid instead.
            On Windows just return "group".
            )grpgetgrgidgr_namer   r%   gids     r'   get_group_by_gidzAbstractedFS.get_group_by_gid_  r   r   c                     dS )Ngrouprd   r   s     r'   r   zAbstractedFS.get_group_by_gidk  r   r)   Tc              #   t   K   t            fd            }t            fd            } j        j        rt          j        }nt          j        }d}t           dd          }t          j                    }	|D ]}
t          j        	                    ||
          }	  
                    |          }n# t          t          f$ r |rY O w xY wt          j        |j                  }|j        }|sd}|j        } ||j                  } ||j                  } ||j                  }|	|j        z
  |k    rdnd}	 t*          |j                 d	t          j        ||          }nD# t0          $ r7  |            }t*          |j                 d	t          j        d|          }Y nw xY w|j        d
z  t          j        k    }|r/|-	 |
dz    ||          z   }
n# t          t          f$ r |s Y nw xY w|d	|dd	|dd	|dd	|dd	|d	|
d}|                     j        j         j        j                  V  dS )ax  Return an iterator object that yields the entries of given
        directory emulating the "/bin/ls -lA" UNIX command output.

         - (str) basedir: the absolute dirname.
         - (list) listing: the names of the entries in basedir
         - (bool) ignore_err: when False raise exception if os.lstat()
         call fails.

        On platforms which do not support the pwd and grp modules (such
        as Windows), ownership is printed as "owner" and "group" as a
        default, and number of hard links is always "1". On UNIX
        systems, the actual owner, group, and number of links are
        printed.

        This is how output appears to client:

        -rw-rw-rw-   1 owner   group    7045120 Sep 02  3:47 music.mp3
        drwxrwxrwx   1 owner   group          0 Aug 31 18:50 e-books
        -rw-rw-rw-   1 owner   group        380 Sep 02  3:40 module.py
        c                 .                         |           S r1   )r   )r   r%   s    r'   r   z1AbstractedFS.format_list.<locals>.get_user_by_uid  s    '',,,r)   c                 .                         |           S r1   )r   )r   r%   s    r'   r   z2AbstractedFS.format_list.<locals>.get_group_by_gid  s    ((---r)   i N r   Nr   z%d  %Yz%d %H:%M    z -> z>38z>8
)r   r#   use_gmt_timestimegmtime	localtimer^   r8   r3   r?   r   OSErrorr   r   filemodest_modest_nlinkst_sizest_uidst_gidst_mtime_months_maptm_monstrftime
ValueErrorS_IFLNKencodeencodingunicode_errors)r%   basedirlisting
ignore_errr   r   timefunc
SIX_MONTHSr   nowbasenamerZ   stpermsnlinkssizeunamegnamemtimefmtstrmtimestrr   lines   `                      r'   format_listzAbstractedFS.format_listp  s     , 
	- 	- 	- 	- 
	- 
	. 	. 	. 	. 
	. ) 	&{HH~H'
4T22ikk ;	 ;	H7<<22DZZ%%_-    H
 M"*--E[F :D#OBI..E$$RY//EHR[))E "%r{!2Z!?!?XXZF---M&%000     !

---M*e444 j5(T\9F (.'&088D>>AHH1   %   D ++ )4+;+J     s;	 ;	s6   B//CC7*E"">F#"F#GG,+G,c              #      K   | j         j        rt          j        }nt          j        }d                    d |D                       }d                    d |D                       }d|v sd|v sd|v r|dz  }d|v r|d	z  }d
|v }	d|v }
d|v }d|v }d|v }d|v }d|v }d|v }d|v }|D ]}i t          j                            ||          }	 |                     |          }n# t          t          f$ r |rY Q w xY w|j        dz  t          j        k    }|r'|	r|dk    rdd
<   n|dk    rdd
<   ndd
<   |
r|d<   n|	rdd
<   |
r|d<   |r
|j        d<   |r8	 t          j        d ||j                            d<   n# t           $ r Y nw xY w|r8	 t          j        d ||j                            d<   n# t           $ r Y nw xY w|rt%          |j        dz            d<   |r
|j        d<   |r
|j        d<   |r|j        dd|j        dd<   d                    fdt/                                                    D                       }| d| d }|                    | j         j        | j         j                  V  d!S )"aY  Return an iterator object that yields the entries of a given
        directory or of a single file in a form suitable with MLSD and
        MLST commands.

        Every entry includes a list of "facts" referring the listed
        element.  See RFC-3659, chapter 7, to see what every single
        fact stands for.

         - (str) basedir: the absolute dirname.
         - (list) listing: the names of the entries in basedir
         - (str) perms: the string referencing the user permissions.
         - (str) facts: the list of "facts" to be returned.
         - (bool) ignore_err: when False raise exception if os.stat()
         call fails.

        Note that "facts" returned may change depending on the platform
        and on what user specified by using the OPTS command.

        This is how output could appear to the client issuing
        a MLSD request:

        type=file;size=156;perm=r;modify=20071029155301;unique=8012; music.mp3
        type=dir;size=0;perm=el;modify=20071127230206;unique=801e33; ebooks
        type=file;size=211;perm=r;modify=20071103093626;unique=192; module.py
        rT   c                     g | ]}|d v|	S )arwrd   .0xs     r'   
<listcomp>z,AbstractedFS.format_mlsx.<locals>.<listcomp>  s    >>>q~~1~~~r)   c                     g | ]}|d v|	S )celmprd   r   s     r'   r   z,AbstractedFS.format_mlsx.<locals>.<listcomp>  s"    AAA!0@0@A0@0@0@r)   wafcdrD   typepermr   modifycreatez	unix.modezunix.uidzunix.giduniquer   .cdirz..pdirro   rZ   z%Y%m%d%H%M%Si  r   gc                 ,    g | ]}| d |          dS )=;rd   )r   r   retfactss     r'   r   z,AbstractedFS.format_mlsx.<locals>.<listcomp>F  s.    HHH1A&&&&&HHHr)   r   r   N)r#   r   r   r   r   r?   r8   r3   r   r   r   r   S_IFDIRr   r   r   r   st_ctimeoctr   r   st_devst_inosortedkeysr   r   r   )r%   r   r   r   factsr   r   permdirpermfile	show_type	show_perm	show_sizeshow_modifyshow_create	show_modeshow_uidshow_gidshow_uniquer   rZ   r   r   
factstringr   r   s                           @r'   format_mlsxzAbstractedFS.format_mlsx  s     4 ) 	&{HH~H''>>e>>>??77AAuAAABB5LLcUllusNG%<<sNGeO	eO	eO	%'%'5(	&&%' L	 L	HH7<<22DYYt___-    H Z%'DL8E 0 13+1((!T))+1((+0( /'.HV$ .'-HV$ 0'/HV$ .#%:  )-&(=(=* *HX&&
 "   D )-&(=(=* *HX&& "   D  >(+BJ,<(=(=% 1')y$ 1')y$  D(*	%C%C%Cbi%C%C%C" HHHHx}}0G0GHHH J !118111D++ )4+;+J     UL	 L	s6   C##C:8C:&F
FF&F<<
G	G	)rT   rT   NrU   )T)-ra   rb   rc   __doc__r(   propertyr&   r/   setterstaticmethodr8   r[   r;   rE   rG   rL   rI   rQ   rk   rq   rs   rx   r{   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   rN   r   r   r   r   r   r   r  rd   r)   r'   r   r   ,   s        $' ' '   X   X 
[  [ 	Z  Z
  go # # # \#  >@ @ @$  6+ + +($ $ $' ' ' '0% % %                      2 2 2 wr7 	" 	" 	" 	"
 wr: %	% 	% 	%$ $ $$ $ $# # #% % %& & &
& & &% % % 	 	 	 		 	 	 	 	 	 		 	 	
` ` ` `Dy y y y y yr)   posixUnixFilesystemc                   *    e Zd ZdZd Zd Zd Zd ZdS )r  zRepresents the real UNIX filesystem.

        Differently from AbstractedFS the client will login into
        /home/<username> and will be able to escape its home directory
        and navigate the real filesystem.
        c                 L    t                               | ||           || _        d S r1   )r   r(   r/   r$   s      r'   r(   zUnixFilesystem.__init__]  s%    !!$k:::DHHHr)   c                 ,    |                      |          S r1   )rE   )r%   rC   s     r'   rG   zUnixFilesystem.ftp2fsb  s    <<(((r)   c                     |S r1   rd   )r%   rK   s     r'   rL   zUnixFilesystem.fs2ftpe  s    Mr)   c                     dS )NTrd   r2   s     r'   rI   zUnixFilesystem.validpathh  s	     4r)   N)ra   rb   rc   r  r(   rG   rL   rI   rd   r)   r'   r  r  U  sZ        	 		 	 	
	) 	) 	)	 	 		 	 	 	 	r)   )r8   r   ri   r   
exceptionsr   utilsr   r   r   ImportError__all__r   r   r[   r  rd   r)   r'   <module>r!     sW  
 
			    ' ' ' ' ' '      JJJJJJJ   C### 
  *_ _ _ _ _ _ _ _L 7g !!G          s   ' 	33