2 """Parse output of FTP LIST command.
3 Pure python implementation.
5 See http://cr.yp.to/ftpparse.html, http://effbot.org/downloads#ftpparse,
6 http://c0re.23.nu/c0de/ftpparsemodule/ and http://www.ocgy.ubc.ca/~tang/treeftp
8 Currently covered formats:
9 UNIX ls, with or without gid;
17 Definitely not covered:
18 EPLF (show me an FTP server first...);
19 Long VMS filenames, with information split across two lines;
20 NCSA Telnet FTP server. Has LIST = NLST (and bad NLST for directories).
25 from mx import DateTime
27 _parse_datetime = False
29 _parse_datetime = True
32 class parse_error(Exception): pass
36 def __init__(self, name=None, perm=None, nlink=None, user=None, group=None, \
37 size=None, mtime=None, links_to=None, file_type=None):
40 mtime = ' '.join(mtime)
43 mtime = DateTime.DateTimeFrom(mtime)
44 except DateTime.Error:
54 self.links_to = links_to
55 self.file_type = file_type # f - regular file, d - directory, l - symlink
59 return """<%s: name=%s, perm=%s, nlink=%s, user=%s, group=%s, size=%s, mtime=%s, links-to=%s, type=%s at 0x%x>""" % (
60 self.__class__.__name__, self.name, self.perm, self.nlink,
61 self.user, self.group, self.size, self.mtime,
62 self.links_to, self.file_type, id(self))
65 def _parse_unix(line, parts):
78 if parts[1][0] == '[': # NetWare
85 perm = perm + ' ' + parts[1]
90 parts = line.split(None, 7) # resplit the original line...
91 name = parts[7] # ...in case the filename contains whitespaces
93 elif parts[1] == "folder": # NetPresenz for the Mac
98 parts = line.split(None, 6)
101 elif parts[0][0] == 'l': # symlink
103 nlink = int(parts[1])
109 parts = line.split(None, 8)
111 parts = link.split(" -> ")
122 nlink = int(parts[1])
128 parts = line.split(None, 7)
130 parts = name.split(' ')[1:]
131 name = ' '.join(parts)
134 if parts[2].isdigit(): # NetPresenz
145 nlink = int(parts[1])
150 parts = line.split(None, 7)
153 return entry(name, perm, nlink, user, group, size, mtime, links_to, file_type)
156 def _parse_vms(parts):
160 user = parts[4][1:-1]
168 parts = user.split(',')
172 return entry(name, perm, nlink, user, group, size, mtime, links_to, file_type)
175 def _parse_dos(parts):
185 # Change %m-%d-%y format to %y-%m-%d
187 date_parts = date.split('-')
188 date = "%s-%s-%s" % (date_parts[2], date_parts[0], date_parts[1])
194 if parts[2] == "<DIR>":
200 return entry(name, perm, nlink, user, group, size, mtime, links_to, file_type)
207 if c == '+': # EPLF format is not supported
210 if c in ('b', 'c', 'd', 'l', 'p', 's', '-'): # UNIX-like
211 return _parse_unix(line, parts)
213 if ';' in parts[0]: # VMS
214 return _parse_vms(parts)
216 if '0' <= c <= '9': # DOS
217 return _parse_dos(parts)
220 #Some useless lines, safely ignored:
221 #"Total of 11 Files, 10966 Blocks." (VMS)
222 #"total 14786" (UNIX)
223 #"DISK$ANONFTP:[ANONYMOUS]" (VMS)
224 #"Directory DISK$PCSA:[ANONYM]" (VMS)
230 #UNIX-style listing, without inum and without blocks
231 print ftpparse("-rw-r--r-- 1 root other 531 Jan 29 03:26 README")
232 print ftpparse("dr-xr-xr-x 2 root other 512 Apr 8 1994 etc")
233 print ftpparse("dr-xr-xr-x 2 root 512 Apr 8 1994 etc")
234 print ftpparse("lrwxrwxrwx 1 root other 7 Jan 25 00:17 bin -> usr/bin")
235 #FTP servers for Windoze:
236 print ftpparse("---------- 1 owner group 1803128 Jul 10 10:18 ls-lR.Z")
237 print ftpparse("d--------- 1 owner group 0 May 9 19:45 Softlib")
239 print ftpparse("-rwxrwxrwx 1 noone nogroup 322 Aug 19 1996 message.ftp")
241 print ftpparse("d [R----F--] supervisor 512 Jan 16 18:53 login")
242 print ftpparse("- [R----F--] rhesus 214059 Oct 20 15:27 cx.exe")
243 #NetPresenz for the Mac:
244 print ftpparse("-------r-- 326 1391972 1392298 Nov 22 1995 MegaPhone.sit")
245 print ftpparse("drwxrwxr-x folder 2 May 10 1996 network")
247 #MultiNet (some spaces removed from examples)
248 print ftpparse("00README.TXT;1 2 30-DEC-1996 17:44 [SYSTEM] (RWED,RWED,RE,RE)")
249 print ftpparse("CORE.DIR;1 1 8-SEP-1996 16:09 [SYSTEM] (RWE,RWE,RE,RE)")
251 print ftpparse("CII-MANUAL.TEX;1 213/216 29-JAN-1996 03:33:12 [ANONYMOU,ANONYMOUS] (RWED,RWED,,)")
254 print ftpparse("04-27-00 09:09PM <DIR> licensed")
255 print ftpparse("07-18-00 10:16AM <DIR> pub")
256 print ftpparse("04-14-00 03:47PM 589 readme.htm")
258 print ftpparse("-rw-r--r-- 1 root other 531 Jan 29 03:26 READ ME")
259 print ftpparse("-rw-r--r-- 1 root other 531 Jan 29 03:26 DO NOT READ ME ")
261 if __name__ == "__main__":