ftpfs.py :  » Web-Server » SkunkWEB » skunkweb-3.4.4 » pylibs » vfs » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Web Server » SkunkWEB 
SkunkWEB » skunkweb 3.4.4 » pylibs » vfs » ftpfs.py
# Time-stamp: <02/11/05 12:47:02 smulloni>

########################################################################
#  
#  Copyright (C) 2002 Jacob Smullyan <smulloni@smullyan.org>
#  
#      You may distribute under the terms of either the GNU General
#      Public License or the SkunkWeb License, as specified in the
#      README file.
########################################################################

"""
The ftp vfs requires that Doobee R. Tzeck's python wrapper to Dan
Bernstein's ftpparse, available at http://c0re.jp/c0de/ftpparsemodule/,
be installed; Fredrik Lundh's similarly named module is not the
same one and won't work.

More information about ftpparse itself is available on Dan
Bernstein's website at http://cr.yp.to/ftpparse.html.
"""

import sys
import os
import cStringIO
import ftplib
import types
import socket

try:
    import ftpparse
except ImportError:
    import sys
    print >> sys.stderr, __doc__
    print >> sys.stderr, "\n\nThis module will self-destruct in five seconds.\n"
    import time
    time.sleep(5)
    raise

import vfs

_have22=(2, 2)<=sys.version_info[:2]
if not _have22:
    # 2.1
    from UserList import UserList
    _isstring=lambda x: isinstance(x, (str, unicode))
else:
    list_=list
    _isstring=lambda x: type(x) in (types.StringType, types.UnicodeType)

try:
    from skunklib import normpath2
except ImportError:
    from os.path import normpath
    
    
class FtpListResult(list_):

    def __init__(self, thing=None):
        self._fname_dict={}
        if thing:
            for t in thing:
                self.append(t)
        
    def append(self, item):
        res=ftpparse.ftpparse([item])[0]
        if res:
            list_.append(self, res)
            self._fname_dict[res[ftpparse.NAME]]=res

    def __getitem__(self, key):
        if _isstring(key):
            if self._fname_dict.has_key(key):
                return self._fname_dict[key]
            raise KeyError, key
        return list_.__getitem__(self, key)

    def keys(self):
        return self._fname_dict.keys()

    def get(self, key, default=None):
        return self._fname_dict.get(key, default)


class FTPFile:
    def __init__(self, ftpconn, name, mode='r'):
        self.mode=mode
        self.name=name
        self.closed=0
        self._conn=ftpconn
        self._buff=cStringIO.StringIO()
        self.__initmode()

    def __readall(self, binary=0):
        sio=cStringIO.StringIO()
        if binary:
            self._conn.retrbinary('RETR %s' % self.name,
                                  sio.write)
        else:
            self._conn.retrlines('RETR %s' %self.name,
                                 lambda x: sio.write("%s\n" % x))
        self._buff.truncate()
        self._buff.write(sio.getvalue())
        self._buff.reset()


    def write(self, bytes):
        if self.closed:
            raise ValueError, "file closed"
        if self.mode not in ('w', 'wb'):
            raise vfs.NotWriteableException, self.name
        self._buff.write(bytes)

    def read(self, size=-99):
        if size and size >-1:
            return self._buff.read(size)
        return self._buff.read()

    def seek(self, offset, whence=0):
        self._buff.seek(offset, whence)

    def tell(self):
        return self._buff.tell()

    def flush(self):
        if self.closed:
            raise ValueError, "file closed"        
        if self.mode=='w':
            self._buff.reset()
            self._conn.storlines('STOR %s' % self.name,
                                 self._buff)
        elif self.mode=='wb':
            self._buff.reset()
            self._conn.storbinary('STOR %s' % self.name,
                                  self._buff)
        else:
            raise vfs.NotWriteableException, self.name

    def close(self):
        if not self.closed:
            self.flush()
            self._buff.truncate()
            self.closed=1

    def __initmode(self):
        if self.mode.startswith('r'):
            self.__readall('b' in self.mode)

if _have22:


    def _robustify(func):
        def robuster(*args, **kwargs):
            try:
                func(*args, **kwargs)
            except ftplib.error_temp:
                self=args[0]
                try:
                    self.login(self.user,
                               self.passwd,
                               self.acct)
                except (ftplib.Error, socket.error, IOError, EOFError):
                    self.connect(self.host, self.port)
                    self.login(self.user,
                               self.passwd,
                               self.acct)
                return func(*args, **kwargs)
        return robuster
        
    class _robustmeta(type):
        def __new__(self, classname, bases, classdict):
            robustlist=classdict.get('robust', [])
            
            for mname in robustlist:
                m=classdict.get(mname)
                if not m:
                    for b in bases:
                        if hasattr(b, mname):
                            m=getattr(b, mname)
                            break
                    
                if m:
                    classdict[mname]=_robustify(m)
                else:
                    print type(m)
            return type.__new__(self, classname, bases, classdict)

    class FtpConnection(ftplib.FTP, object):
        """
        a wrapper around ftplib.FTP
        that provides error recovery
        in case the connection goes south due to
        timeout
        """
        __metaclass__=_robustmeta

        def connect(self, host='', port=ftplib.FTP_PORT):
            self.host=host
            self.port=port
            ftplib.FTP.connect(self, host, port)
        
        def login(self, user='', passwd='', acct=''):
            self.user=user
            self.passwd=passwd
            self.acct=acct
            ftplib.FTP.login(self, user, passwd, acct)

        robust=['retrbinary',
                'retrlines',
                'storbinary',
                'storlines',
                'delete',
                'rename',
                'mkd',
                'rmd',
                'dir']
else:
    # I haven't implemented any error-recovery for Python 2.1.
    # Sorry.  Anyone want to do it?
    FtpConnection=ftplib.FTP
        
class FtpFS(vfs.FS):
    writeable=1
    def __init__(self,
                 host,
                 username='',
                 password='',
                 acct='',
                 passive=1,
                 port=ftplib.FTP_PORT):
        self._host=host
        self._port=port
        self._username=username
        self._password=password
        self._acct=acct
        self._passive=passive
        self._conn=FtpConnection()
        self._initconn()

    def _initconn(self):
        self._conn.connect(self._host, self._port)
        self._conn.login(self._username,
                         self._password,
                         self._acct)
        self._conn.set_pasv(self._passive)

    def _get_parsed_record(self, path, all=0):
        path=normpath(path)
        fname=os.path.basename(path)
        res=FtpListResult()
        self._conn.dir(path, res.append)
        if all:
            return res
        record=res.get(os.path.basename(path), res.get(path))
        if not record:
            # in the case of a directory, try again with the parent directory
            parent=os.path.dirname(path)
            res=FtpListResult()
            self._conn.dir(parent, res.append)
            record=res.get(os.path.basename(path), res.get(path))
        return record

    def ministat(self, path):
        # we don't try to get anything for '/'
        if path=='/':
            return [-1]*4
        record=self._get_parsed_record(path)
        if record:
            return [record[ftpparse.SIZE]] +[record[ftpparse.MTIME]]*3            
        raise vfs.FileNotFoundException, path

    def mkdir(self, dirname):
        self._conn.mkd(dirname)

    mkdirs=mkdir

    def isdir(self, path):
        if path=='/':
            return 1
        record=self._get_parsed_record(path)
        if record:
            return record[ftpparse.CWD]
        

    def isfile(self, path):
        if path=='/':
            return 0
        record=self._get_parsed_record(path)
        if record:
            return record[ftpparse.RETR]
        return 0

    def remove(self, path):
        record=self._get_parsed_record(path)
        if not record:
            raise vfs.FileNotFoundException, path
        if record[ftpparse.RETR]:
            self._conn.delete(path)
        elif record[ftpparse.CWD]:
            self._conn.rmd(path)

    def rename(self, path, newpath):
        self._conn.rename(path, newpath)
        
    def listdir(self, path):
        record=self._get_parsed_record(path, 1)
        if record:
            return [x[ftpparse.NAME] for x in record]

    def open(self, path, mode='r'):
        return FTPFile(self._conn, path, mode)

    # this requires a different walk implementation 
    # that will make fewer ftp requests.
    def walk(self, dir, visitfunc, arg):
        try:
            res=self._get_parsed_record(dir, 1)
            realnames = [x[ftpparse.NAME] for x in res]
        except:
            return
        names=realnames[:]
        visitfunc(arg, dir, names)
        for name in names:
            if name not in realnames:
                # does not exist
                continue
            if res[name][ftpparse.CWD]:
                fullname = os.path.join(dir, name)
                self.walk(fullname, visitfunc, arg)
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.