diff options
author | btimby <btimby@67cdc799-7952-0410-af00-57a81ceafa0f> | 2012-04-17 15:47:48 +0000 |
---|---|---|
committer | btimby <btimby@67cdc799-7952-0410-af00-57a81ceafa0f> | 2012-04-17 15:47:48 +0000 |
commit | fd93dcc55e5218ba57ee418faf1e08f2a2bd6f97 (patch) | |
tree | 5f1e4b7b6f8f40bfe5d1bfc603b62aa9f025f49d | |
parent | 831618e29f1033b4fe8db14058ab635643273c62 (diff) | |
download | pyfilesystem-fd93dcc55e5218ba57ee418faf1e08f2a2bd6f97.tar.gz |
Initial implementation of pyftpdlib integration
git-svn-id: http://pyfilesystem.googlecode.com/svn/trunk@765 67cdc799-7952-0410-af00-57a81ceafa0f
-rw-r--r-- | fs/commands/fsserve.py | 7 | ||||
-rw-r--r-- | fs/expose/ftp.py | 136 |
2 files changed, 143 insertions, 0 deletions
diff --git a/fs/commands/fsserve.py b/fs/commands/fsserve.py index 5a05dd8..4595c15 100644 --- a/fs/commands/fsserve.py +++ b/fs/commands/fsserve.py @@ -56,6 +56,13 @@ Serves the contents of PATH with one of a number of methods""" self.output("Starting rpc server on %s:%i\n" % (options.addr, port), verbose=True) s.serve_forever() + elif options.type == 'ftp': + from fs.expose.ftp import serve_fs + if port is None: + port = 21 + self.output("Starting ftp server on %s:%i\n" % (options.addr, port), verbose=True) + serve_fs(fs, options.addr, port) + elif options.type == 'sftp': from fs.expose.sftp import BaseSFTPServer import logging diff --git a/fs/expose/ftp.py b/fs/expose/ftp.py new file mode 100644 index 0000000..2bdaf1d --- /dev/null +++ b/fs/expose/ftp.py @@ -0,0 +1,136 @@ +""" +fs.expose.ftp +============== + +Expose an FS object over FTP (via pyftpdlib). + +This module provides the necessary interfaces to expose an FS object over +FTP, plugging into the infrastructure provided by the 'pyftpdlib' module. +""" + +from __future__ import with_statement + +import os +import stat as statinfo +import time +import threading + +from pyftpdlib import ftpserver + +from fs.base import flags_to_mode +from fs.path import * +from fs.errors import * +from fs.local_functools import wraps +from fs.filelike import StringIO +from fs.utils import isdir +from fs.osfs import OSFS + +class FTPFS(ftpserver.AbstractedFS): + def __init__(self, fs, root, cmd_channel): + self.fs = fs + super(FTPFS, self).__init__(root, cmd_channel) + + def validpath(self, path): + return True + + def open(self, path, mode): + return self.fs.open(path, mode) + + def chdir(self, path): + self.cwd = path + + def mkdir(self, path): + if isinstance(path, str): + path = unicode(path, sys.getfilesystemencoding()) + self.fs.createdir(path) + + def listdir(self, path): + return map(lambda x: x.encode('utf8'), self.fs.listdir(path)) + + def rmdir(self, path): + self.fs.removedir(path) + + def remove(self, path): + self.fs.remove(path) + + def rename(self, src, dst): + self.fs.rename(src, dst) + + def chmod(self, path, mode): + raise NotImplementedError() + + def stat(self, path): + # TODO: stat needs to be handled using fs.getinfo() method. + return super(FTPFS, self).stat(self.fs.getsyspath(path)) + + def lstat(self, path): + return self.stat(path) + + def isfile(self, path): + return self.fs.isfile(path) + + def isdir(self, path): + return self.fs.isdir(path) + + def getsize(self, path): + return self.fs.getsize(path) + + def getmtime(self, path): + return self.fs.getinfo(path).time + + def realpath(self, path): + return path + + def lexists(self, path): + return True + + +class FTPFSFactory(object): + """ + A factory class which can hold a reference to a file system object and + later pass it along to an FTPFS instance. An instance of this object allows + multiple FTPFS instances to be created by pyftpdlib and share the same fs. + """ + def __init__(self, fs): + """ + Initializes the factory with an fs instance. + """ + self.fs = fs + + def __call__(self, root, cmd_channel): + """ + This is the entry point of pyftpdlib. We will pass along the two parameters + as well as the previously provided fs instance. + """ + return FTPFS(self.fs, root, cmd_channel) + + +class HomeFTPFS(FTPFS): + """ + A file system which serves a user's home directory. + """ + def __init__(self, root, cmd_channel): + """ + Use the provided user's home directory to create an FTPFS that serves an OSFS + rooted at the home directory. + """ + super(DemoFS, self).__init__(OSFS(root_path=root), '/', cmd_channel) + + +def serve_fs(fs, addr, port): + from pyftpdlib.contrib.authorizers import UnixAuthorizer + ftp_handler = ftpserver.FTPHandler + ftp_handler.authorizer = ftpserver.DummyAuthorizer() + ftp_handler.authorizer.add_anonymous('/') + ftp_handler.abstracted_fs = FTPFSFactory(fs) + s = ftpserver.FTPServer((addr, port), ftp_handler) + s.serve_forever() + + +def main(): + serve_fs(HomeFTPFS, '127.0.0.1', 21) + + +# When called from the command-line, expose a DemoFS for testing purposes +if __name__ == "__main__": + main() |