Commit c9ea8ee4 by btimby

Initial implementation of pyftpdlib integration

parent 8b582582
......@@ -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
......
"""
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()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment