Viewing file: Session.py (33.91 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
######################################################################## # $Header: /var/local/cvsroot/4Suite/Ft/Server/Server/Ftp/Session.py,v 1.15 2005/04/11 16:51:12 jkloth Exp $ """ Repository exposed as FTP session
Copyright 2005 Fourthought, Inc. (USA). Detailed license and copyright information: http://4suite.org/COPYRIGHT Project home, documentation, distributions: http://4suite.org/ """
import string, socket, types, sha, time import os, sys, thread, cStringIO, traceback from Ft.Lib import Time from Ft.Server.Common import XmlLib
from Ft.Server.Server import SCore, FtServerServerException, Error from Ft.Server.Common import ResourceTypes, Schema from cStringIO import StringIO
from Ft.Server.ThirdParty.pyftpd import timeout_socket from Ft.Server.ThirdParty.pyftpd.config import * from Ft.Lib import Uri
from Ft.Server import SCHEMA_NSS
from Ft.Server.Common.Util import IMT_MAP
from Ft.Rdf.Parsers import Versa from Ft.Server.Server.Drivers import FtssInputSource
t_socket = timeout_socket.timeout_socket
authmethods = [] permmethods = []
sessions = {}
for i in modules: mod = __import__('Ft.Server.ThirdParty.pyftpd.'+i, {}, {}, ["*"]) methods = dir(mod) if "got_user" in methods: # it is authentification module authmethods.append( (getattr(mod,'got_user'), getattr(mod,'got_pass'))) if "permcheck" in methods: # permission module permmethods.append(getattr(mod,"permcheck")) if "v2fs" in methods: # virtual to real path v2fs = getattr(mod,'v2fs') # this overrides v2fs ftom utils
def permcheck(f, user, group, session, operation): last = 0 for i in permmethods: l, c = i(f, user, group, session, operation) if l == 0: last = 0 elif l == 1: last = 1 if not c: break return last
def got_user(username, session, sessions): # session points to Session class last_deny_rt = 500, "", "", "", 0, 0 # response code, response message, user, group, deny_or_grant, continue last_grant_rt = 200, "", "", "", 0, 0 last_rt = 500, "", "", "", 0, 0 last = -1 for i in authmethods: rt = n, r, u, g, l, c = i[0](username, session, sessions) if l == 0: last_deny_rt = rt last = 0 elif l == 1: last_grant_rt = rt last = 1 else: last_rt = rt if not c: break #now last is 1 for grant access, 0 for deny if last == 1: n, r, u, g, l, c = last_grant_rt elif last == 0: n, r, u, g, l, c = last_deny_rt else: n, r, u, g, l, c = last_rt return n, r, u, g, l
def got_pass(username, password, session, sessions): last_deny_rt = 500, "", 0, 0 last_grant_rt = 200, "", 0, 0 last_rt = 500, "", 0, 0 last = 0 for i in authmethods: rt = n, r, l, c = i[1](username, password, session, sessions) if l == 0: last_deny_rt = rt last = 0 elif l == 1: last_grant_rt = rt last = 1 else: last_rt = rt if not c: break #now last is 1 for grant access, 0 for deny if last == 1: n, r, l, c = last_grant_rt elif last == 0: n, r, l, c = last_deny_rt else: n, r, l, c = last_rt return n, r, l
class Session: threading = 0 def __init__(self, rfile, wfile, client_address, server): self.serverAddy = server.hostname self.user = "" self.group = "" self.curcmd = "just connected" self.exit_immediately = 0 self.pendingconn = 0 # if there is an open data connection - for ABOR self.last_cmd_time = self.session_create_time = time.time() self.rfile = rfile self.wfile = wfile self.restpos = 0 self.passive = 0 self.create_datasock = self.create_nonpasv_datasock #self.create_datasock = self.create_pasv_datasock self.ip = client_address[0] self.dataport = None self.replymessage(220, initial_msg) self.cwd = '/' self.limit_retr_speed = 0. self.limit_stor_speed = 0.
#Additions self._userName = None self._password = None self.logFile = server.errorLog self.properties = server.properties self.extendedMapping = {} for ext, imt in IMT_MAP.items(): self.extendedMapping[ext] = (None, None, imt) if hasattr(server,'extendedMapping'): self.extendedMapping.update(server.extendedMapping) self.cmddict = { # "rnfr": self.cmd_rnfr, # "rnto": self.cmd_rnto, "quit": self.cmd_quit, #done "syst": self.cmd_syst, "user": self.cmd_user, #done "pass": self.cmd_pass, #done "port": self.cmd_port, #done "stor": self.cmd_stor, #done "appe": self.cmd_appe, #done "dele": self.cmd_dele, #done "mkd" : self.cmd_mkd, #done "rmd" : self.cmd_rmd, #done "retr": self.cmd_retr, #done "rest": self.cmd_rest, #done "size": self.cmd_size, #done "list": self.cmd_list, #done "nlst": self.cmd_list, #done "pasv": self.cmd_pasv, "pwd" : self.cmd_pwd, #done "cwd" : self.cmd_cwd, #done "cdup": self.cmd_cdup, #done "site": self.cmd_site, "abor": self.cmd_abor, "type": self.cmd_dummy, "noop": self.cmd_dummy, #done }
def v2fs(self, f): return v2fs(f, self)
def reply(self, x): self.wfile.write(x + "\r\n")
def replymessage(self, n, x): # reply to the client, x is possibly tuple of lines if type(x) == types.StringType: self.reply(`n`+" "+x) else: for i in x[:-1]: self.reply(`n`+"-"+i) self.reply(`n`+" "+x[-1])
def create_nonpasv_datasock(self): if not self.dataport: self.reply("425 what about a PORT command?") return try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock = t_socket(sock=sock, timeout=timeout_data) self.sock.connect((self.ip, self.dataport)) self.reply("150 dataconnection is up!") return 1 except socket.error: self.reply("425 your dataport sucks big time!") return None
def create_pasv_datasock(self): try: self.sock = t_socket(sock=self.sock, timeout=timeout_data) conn, addr = self.sock.accept() self.sock = t_socket(sock=conn, timeout=timeout_data) self.reply("150 dataconnection is up!") self.create_datasock = self.create_nonpasv_datasock return 1 except "socket.error": self.reply("425 cannot create socket") return None
def close_datasock(self): self.sock.close()
def cmd_quit(self,_): self.reply("221 Have a good one!")
def cmd_abor(self,_): if self.pendingconn and self.threading: self.abort_received = 1 while self.pendingconn: time.sleep(0.1) # prevent from taking up 100% CPU self.reply("226 Aborted") return
def cmd_user(self, username): n, r, self.user, self.group, self.logged = got_user(username, self, sessions) self.replymessage(n, r)
def cmd_pass(self, password): n, r, self.logged = got_pass(self.user, password, self, sessions) if self.logged: self._userName = self.user self._password = sha.new(password).hexdigest() self.replymessage(n, r)
def cmd_dummy(self, _): self.reply("200 OK (in other words: ignored)")
def cmd_syst(self, _): self.reply("215 UNIX Type: L8")
def cmd_pwd(self, _): self.reply('257 "%s" is where you are' % self.cwd)
def cmd_cdup(self, _): """ Overriden for 4SS """ self.cmd_cwd("..") return repo = self.repoFactory.getRepo() parcontainer = repo.fetchResource(self.cwd).getParent() if parcontainer: pardir = parcontainer.getUri() else: pardir = self.cwd repo.txRollback() self.cmd_cwd(pardir)
def cmd_cwd(self, path): """ Overriden for 4Suite Server """ if path: repo = self._getRepo() try: curPath = self.cwd if curPath[-1] != '/': curPath = curPath + '/' newPath = FtssInputSource.FTSS_RESOLVER.normalize(path, curPath) print "curr path: %s, rel path: %s , new path: %s"%(curPath,path,newPath) base = repo.fetchResource(self.cwd) next = base.fetchResource(newPath) if not next.isResourceType(ResourceTypes.ResourceType.CONTAINER): self.log_error(550,"the specified path is not a directory/container") self.reply("550 the specified path is not a directory/container") else: self.cwd = next.getAbsolutePath() self.reply("250 Ok, going there") finally: repo.txRollback()
def cmd_site(self, command): """ Overiden to permit 4SS specific commands """ #FIXME implement SITE command self.log_error(502,"This command is not yet implemented") self.reply("502 This command is not yet implemented") return
c = string.split(command) cmd, arg = string.lower(c[0]), c[1:] if cmd == "ps": sl = [] for i in sessions.keys(): cs = sessions[i] sl.append(" %i %s[%s]@%s %% %s" % (i, cs.user, cs.group, cs.ip, cs.curcmd)) sl.append("TOTAL %i" % len(sessions)) self.replymessage(250,sl) return elif cmd == "shutdown": # does not work self.reply("250 Oh dear, shutting down server") sys.exit(0) elif cmd == "kill": try: pid2kill = int(arg[0]) except: self.reply("400 PID error") return if sessions.has_key(pid2kill): sessions[pid2kill].exit_immediately=1 else: self.reply("400 No such PID") return else: self.reply("500 Unknown SITE command") return self.reply("250 Ok, done.")
def cmd_noop(self,_): self.reply("200 NOOPing")
def cmd_pasv(self, _): FTP_DATA_BOTTOM = 40000 FTP_DATA_TOP = 44999
for port in xrange(FTP_DATA_BOTTOM, FTP_DATA_TOP): try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.bind(('', port)) break except socket.error: pass else: self.log_error(425,"Cannot be passive") self.reply("425 Cannot be passive") return self.sock.listen(1) adr, self.dataport = self.sock.getsockname() if not adr or adr == '0.0.0.0': adr = socket.gethostname() adr = socket.gethostbyname(socket.gethostname()) if adr == '127.0.0.1': self.log_ftp_message("Using ServerName to determine ip for passive mode: %s"%(adr)) addr=socket.gethostbyname(self.serverAddy) adr = string.replace(adr, ".", ",") porthi, portlo = self.dataport/256, self.dataport%256 self.passive = 1 self.create_datasock = self.create_pasv_datasock self.log_ftp_message("227 Entering Passive Mode (%s,%i,%i)" % (adr, porthi, portlo)) self.reply("227 Entering Passive Mode (%s,%i,%i)" % (adr, porthi, portlo))
def cmd_port(self, port_id): numstr = filter(lambda x: x in "0123456789,", port_id) parts = string.split(numstr,",")
try: hi = int(parts[-2]) lo = int(parts[-1]) for v in [hi,lo]: if v < 0 or v > 255: raise ValueError except IndexError: self.log_error(501,"Are you a hacker?") self.reply("501 are you a hacker?") return except ValueError: self.log_error(501,"Uninterpretable value") self.reply("501 looks like nonsense to me...") return
self.dataport = (hi << 8) + lo self.reply("230 Port is " + str(self.dataport)+ " (am ignoring specified IP for security)")
def stor_or_appe(self, filename, comm): """ Overriden for 4SS """ path = self.absolutePath(filename) tail = os.path.split(path)[1] ext = os.path.splitext(tail)[1]
try: (dd,rt,imt) = self.extendedMapping[ext] except KeyError: (dd,rt,imt) = None,None,None #self.log_ftp_message("imt is: %s"%(imt)) repo = self._getRepo() r = "226 Phew, upload successfully completed"
if not self.create_datasock(): repo.txRollback() return
self.abort_received = 0 self.pendingconn = 1 stringBuffer=StringIO()
if repo.hasResource(path): resource=repo.fetchResource(path) if comm=='appe': #Appending to existing resource, append buffer w/ current #content stringBuffer.write(resource.getContent()) stringBuffer.seek(self.restpos)
bufferSuccessful=1 try: while 1: if self.abort_received: r = "426 Aborted" self.log_error(426,"Resource transfer aborted")
bufferSuccessful=0 break
if self.limit_stor_speed: timer = time.time() s = self.sock.recv(rbufsize) if len(s) == 0: break dur = time.time()-timer #speed = len(s)/dur #if speed>self.limit_stor_speed: if dur*self.limit_stor_speed<len(s): # to avoid division time.sleep(len(s)/self.limit_stor_speed-dur) else: s = self.sock.recv(rbufsize) if len(s) == 0: break stringBuffer.write(s)
except socket.error: bufferSuccessful=0 r = "425 Socket error" self.log_error(425,"Socket error") except IOError: bufferSuccessful=0 r = "553 Upload error" self.log_error(553,"Upload error") except timeout_socket.Timeout: bufferSuccessful=0 r = "425 Timeout while uploading" self.log_error(425,"Timeout while uploading") try: self.close_datasock() except socket.error: bufferSuccessful=0 r = "425 Socket error" self.log_error(425,"Socket error")
if bufferSuccessful: #write buffer back to 4SS resource if repo.hasResource(path): try: resource.setContent(stringBuffer.getvalue()) except: raise r="553 failed to store or append to resource" self.log_error(553,"Failed to store or append to resource") else: #new resource. Determine imt from content and extension #src= self.log_ftp_message("NOTE: utf-8 encoding is assumed!")
self.log_ftp_message("Storing %s with imt: %s, rt %s, dd %s"%(path,imt,rt,dd)) if rt is None: if imt == 'text/xml' or dd is not None: rt = ResourceTypes.ResourceType.XML_DOCUMENT else: rt = ResourceTypes.ResourceType.RAW_FILE if imt is None: if rt == ResourceTypes.ResourceType.RAW_FILE: imt = 'text/plain' else: imt = 'text/xml' if rt == ResourceTypes.ResourceType.RAW_FILE: repo.createRawFile(path,imt,stringBuffer.getvalue()) else: repo.createDocument(path,stringBuffer.getvalue(),forcedType=rt,docDef=dd) repo.txCommit() else: repo.txRollback()
stringBuffer.close()
try: self.reply(r) except: pass self.pendingconn = 0
def cmd_stor(self, filename): if self.threading: thread.start_new_thread(self.stor_or_appe, (filename, "stor")) else: self.stor_or_appe(filename, "stor")
def cmd_appe(self, filename): if self.threading: thread.start_new_thread(self.stor_or_appe, (filename, "appe")) else: self.stor_or_appe(filename, "appe")
def cmd_dele(self, filename): """ Overriden for 4SS """ path=self.absolutePath(filename) repo = self._getRepo() if not repo.hasResource(path): self.log_error(550,"Server ran into problems deleting %s"%path) self.reply("550 Server ran into problems deleting %s"%path) repo.txRollback() return elif ResourceTypes._IsResourceType(repo.fetchResource(path).getResourceType(),ResourceTypes.ResourceType.CONTAINER): repo.txRollback() self.log_error(550,"DEL command called on a container/directory") self.reply("550 DEL command called on a container/directory") return
try: repo.deleteResource(path) repo.txCommit() self.reply("250 File eliminated") except: self.log_error(550,"Unable to delete") self.reply("550 unable to delete") repo.txRollback()
def cmd_mkd(self, dirname): """ Overidden for 4SS """ repo = repo = self._getRepo() cont = repo.fetchResource(self.cwd)
try: cont.createContainer(dirname,1) except: self.log_error(550,"The server was unable to create the directory %s"%dirname) self.reply("550 The server was unable to create the directory %s"%dirname) else: self.reply('257 "%s" Directory created' % dirname) repo.txCommit()
def cmd_rmd(self, dirname): """ Overidden for 4SS """ path=self.absolutePath(dirname) repo = self._getRepo() if not repo.hasResource(path): self.log_error(550,"Directory '%s' does not exist"%path) self.reply("550 Directory '%s' does not exist"%path) repo.txRollback() return elif not ResourceTypes._IsResourceType(repo.fetchResource(path).getResourceType(),ResourceTypes.ResourceType.CONTAINER): self.log_error(550,"%s is not a directory"%(path)) self.reply("550 %s is not a directory"%(path)) repo.txRollback() return else: try: repo.deleteResource(path) except: repo.txRollback() self.log_error(550,"Server was unable to remove the directory") self.reply("550 Server was unable to remove the directory") return else: self.reply("250 Directory removed") repo.txCommit() return
def cmd_rest(self, pos): try: self.restpos = long(pos) self.reply("350 Restarting. Are you happy?") return except ValueError: self.log_error(530,"Invalid rest value") self.reply("530 Sorry.")
def cmd_retr(self, filename): if self.threading: thread.start_new_thread(self.cmd_retr1, (filename,)) else: self.cmd_retr1(filename)
def cmd_retr1(self, path): """ Overriden for 4SS """ if not path: self.log_error(550,"Resource path doesnt exist") self.reply("550 resource path doesnt exist") repo.txRollback() return
repo = self._getRepo()
stringBuffer=StringIO() try: base = repo.fetchResource(self.cwd) cur = base.fetchResource(path) stringBuffer.write(cur.getContent()) stringBuffer.seek(0) if self.restpos: stringBuffer.seek(self.restpos) finally: repo.txRollback()
self.restpos = 0 r = "226 Enjoy the resource"
try: if not self.create_datasock(): return self.abort_received = 0 self.pendingconn = 1 try: while 1: if self.abort_received: r = "426 Aborted" self.log_error(426,"Resource retrieval aborted") break s = stringBuffer.read(sbufsize) if not s: break if self.limit_retr_speed: timer = time.time() self.sock.send(s) dur = time.time()-timer #speed = len(s)/dur #if speed>self.limit_retr_speed: if dur*self.limit_retr_speed<len(s): # to avoid division time.sleep(len(s)/self.limit_retr_speed-dur)
self.sock.send(s) finally: stringBuffer.close() self.close_datasock() except socket.error: r = "425 Socket error" self.log_error(425,"Socket error") except (IOError, OSError): r = "421 File read error" self.log_error(421,"File read error") except timeout_socket.Timeout: r = "425 Timeout while RETRieving" self.log_error(425,"Timeout while RETRieving") try: self.reply(r) except: pass self.pendingconn = 0
def cmd_size(self, path): """ Overriden for 4SS """ repo = self._getRepo() path = os.path.join(self.cwd, path) if not path or not repo.hasResource(path): repo.txRollback() self.log_error(553,"Resource path does not exist") self.reply("553 File read failed!") return res=repo.fetchResource(path)
#ensure filename is not a container if ResourceTypes._IsResourceType(res.getResourceType(),ResourceTypes.ResourceType.CONTAINER): repo.txRollback() self.log_error(550,"Resource path refers to a container/directory") self.reply("550 resource path refers to a container/directory") return
try: size = repo.fetchResource(path).getSize() except: self.reply("553 resource sizing failed!") self.log_error(553,"Resource sizing failed") repo.txRollback() return self.reply("213 "+`size`) repo.txRollback() return
def cmd_list(self, path): """ Overidden for 4SS """ #Account for some clients that prepend options to the specified path (Emacs - for instance) path = path and path.split()[-1] or path #Account for redundant /. appended to pathname by certain clients (Emacs - for instance) path = path[-2:] == '/.' and path[:-1] or path if not path or path[0] == '-': path = self.cwd else: path = os.path.join(self.cwd, path)
repo = self._getRepo() paths = [] try: if not self.create_datasock(): return if repo.hasResource(path): res = repo.fetchResource(path) resType = res.getResourceType() if res.resourceType == ResourceTypes.ResourceType.CONTAINER: paths = self.unixDirListing(res) #for child in res: # name=child.getName() # if ResourceTypes._IsResourceType(child.getResourceType(),ResourceTypes.ResourceType.CONTAINER): # name=name+'/' # paths.append(name) else: paths = [path] else: self.log_error(550,"Unable to locate %s in the repository"%(path)) return
try: r = map(lambda x: "%s\r\n" % x, paths) try: for i in r: self.sock.send(i) except socket.error: pass try: self.close_datasock() except socket.error: pass
del r # to save memory self.reply("226 Wow, listing done") return finally: try: self.close_datasock() except socket.error: pass self.reply("226 Listing completed") finally: repo.txRollback() return
# parses the command and eventually calls the appropriate routine def docmd(self, cmd): # if the connection has broken... we have to shut down: if cmd == "": raise "session_exit" # filter suspicious chars first cmd2 = filter(lambda x: ord(x) >= 32 and x not in "\377\364\362",cmd) lcmd2 = string.split(cmd2, None, 1) or [""] command = string.lower(lcmd2[0]) if len(lcmd2) > 1: args = string.strip(lcmd2[1]) else: args = "" # was None, but it was breaking some commands print "recieved command %s, with arguments: %s"%(command,args)
u = self.user or "-" ip = self.ip or "-" if command == "pass": c = "PASS ****" else: c = cmd2
if self.cmddict.has_key(command): self.log_ftp_command(command,args) self.curcmd = c if self.threading: while self.pendingconn and command<>"abor": pass try: try: self.cmddict[command](args) except FtServerServerException, e: if e.errorCode == Error.PERMISSION_DENIED: self.log_error(550,"the specified path %s does not exist: "+e.args['path']) self.reply("550 the specified path does %s not exist",e.args['path']) else: raise e except: import cStringIO, traceback st = cStringIO.StringIO() traceback.print_exc(file=st) self.log_error(550,"Unable to complete command: %s\nException Traceback:\n%s"%(command,st.getvalue())) self.reply("550 I cannot:") return else: self.reply("500 I'm gonna ignore this command '%s'... maybe later..." % command) return
def loop(self): while not self.exit_immediately: try: self.last_cmd_time = time.time() l = self.rfile.readline() except timeout_socket.Timeout: if self.pendingconn: # if there is an ongoing connection, do not timeout for commands # there is a subtle race here - if data connection ends while readline() # is near timeout, client will get 421 Timeout as soon as the data # connections finishes, not having a chance to enter control # commands. But there is not much to be done about it. continue # continue because we do not want to do docmd(), when # readline() timeouted, l is an old value else: try: self.reply("421 timeout") break except (socket.error, timeout_socket.Timeout): break try: self.docmd(l) except ("session_exit", socket.error): break
def loop1(self): while not self.exit_immediately: try: self.last_cmd_time = time.time() self.docmd(self.rfile.readline()) except "session_exit": break
################ #Logging Method ################
def log_error(self, code, msg): self.logFile.error("%s[FTP ERROR %s]: %s\n"%(self.log_date_time_string(),code,msg))
def log_serverResponse(self,msg): self.logFile.debug("%s Server Response: %s\n"%(self.log_date_time_string(),msg))
def log_ftp_command(self,cmd, args): self.logFile.info("%s FTP server recieved command : %s %s\n"%(self.log_date_time_string(),string.upper(cmd),args)) def log_ftp_message(self,msg): self.logFile.info("%s FTP server message: %s\n"%(self.log_date_time_string(),msg)) def log_date_time_string(self): """ Create a time string suitable for Common Log Format. [dd/mmm/yyyy:HH:MM:SS ZZZZZ] dd - Day of the month as a decimal number [01,31] mmm - Abbreviated month name yyyy - Year with century as a decimal number HH - Hour (24-hour clock) as a decimal number [00,23] MM - Minute as a decimal number [00,59] SS - Second as a decimal number [00,61] ZZZZZ - The time-zone as hour offset from GMT in (+/-)HHMM format """ localtime = time.localtime(time.time()) # too bad that %z doesn't work in strftime() strtime = time.strftime('[%d/%b/%Y:%T %%+03d%%02d]', localtime) tzoffset = time.daylight and time.altzone or time.timezone (hour, min) = divmod(tzoffset, 3600) return strtime % (-hour, min / 3600)
####################### # Helper ######### def _getRepo(self): return SCore.GetRepository(self._userName, self._password, self.logFile, self.properties)
## appendix = "" ## if child.resourceType == ResourceTypes.ResourceType.ALIAS: ## appendix = ' -> ' + child.referenceUri ## dirflag='l' ## desc = name + ' -> ' + child.referenceUri ## size = '-'
## elif child.isResourceType(ResourceTypes.ResourceType.FILE): ## dirflag='-' ## #size = '%.1fk' % (child.size / 1000.0) ## size = "%10i"%child.size ## desc = child.imt ## else: ## dirflag='d' ## if name == os.path.basename(pathInfo.uri): ## if pathInfo.uri == '/': ## if prevName=='.': ## name = '..' ## else: ## name = '.' ## else: ## name = '.'
## elif name == os.path.basename(repo.fetchContainer(path).fetchResourceInformation('..').uri): ## name = '..'
## size = '%10i'%(4096) ## desc = 'container'
#spacer = ' ' * (32 - len(name)) #r.append('%-*s %-*s %-24s %6s %s%s %s\r\n' % ( # max_read,readAcl, # max_write, writeAcl, # modified, size, name, spacer, desc))
def unixDirListing(self,parent): parent_abs = parent.getAbsolutePath() parent_with_slash = parent_abs != '/' and parent_abs + '/' or "/"
paths = [] repo = self._getRepo() container = repo.fetchResource(parent_abs) for child in container: size = child.getSize() modified = Time.FromISO8601(child.getLastModifiedDate()) minute=str(modified.minute()) hour=str(modified.hour()) if len(minute)<2: minute = '0%s'%(minute) if len(hour)<2: hour = '0%s'%(hour) monthDay = time.strftime('%b %d',modified.asPythonTimeTuple()) hourMinute = '%s:%s'%(hour,minute) unixTimeString = '%s %s'%(monthDay,hourMinute) permBits = '-rwxrwxrwx' if child.isResourceType(ResourceTypes.ResourceType.CONTAINER): permBits = 'drwxrwxrwx' childEntry = '%s 0 ???? ???? %7s %s %s'%(permBits, size, unixTimeString, child.getName()) paths.append(childEntry) return paths def absolutePath(self,path): curPath = self.cwd if curPath[-1] != '/': curPath = curPath + '/' return Uri.BASIC_RESOLVER.normalize(path, curPath)
## ls, cd, get, user, password
|