Commit bb170217 by btimby

Be less heavy-handed, setting the reference to None will do.

Ensure that pyfs file systems are closed when use with ftp and sftp daemons.
parent 33160ed4
......@@ -187,7 +187,7 @@ class ArchiveMountFS(mountfs.MountFS):
def close(self):
# Close and delete references to any other fs instances.
self.rootfs.close()
del self.rootfs
self.rootfs = None
super(ArchiveMountFS, self).close()
def ismount(self, path):
......
......@@ -78,6 +78,12 @@ class FTPFS(ftpserver.AbstractedFS):
self.encoding = encoding
super(FTPFS, self).__init__(root, cmd_channel)
def close(self):
# Close and dereference the pyfs file system.
if self.fs:
self.fs.close()
self.fs = None
def validpath(self, path):
try:
normpath(path)
......@@ -207,6 +213,19 @@ class FTPFS(ftpserver.AbstractedFS):
return True
class FTPFSHandler(ftpserver.FTPHandler):
"""
An FTPHandler class that closes the filesystem when done.
"""
def close(self):
# Close the FTPFS instance, it will close the pyfs file system.
if self.fs:
self.fs.close()
super(FTPFSHandler, self).close()
class FTPFSFactory(object):
"""
A factory class which can hold a reference to a file system object and
......@@ -247,7 +266,7 @@ def serve_fs(fs, addr, port):
combo.
"""
from pyftpdlib.contrib.authorizers import UnixAuthorizer
ftp_handler = ftpserver.FTPHandler
ftp_handler = FTPFSHandler
ftp_handler.authorizer = ftpserver.DummyAuthorizer()
ftp_handler.authorizer.add_anonymous('/')
ftp_handler.abstracted_fs = FTPFSFactory(fs)
......
......@@ -103,6 +103,11 @@ class SFTPServerInterface(paramiko.SFTPServerInterface):
self.encoding = encoding
super(SFTPServerInterface,self).__init__(server, *args, **kwds)
def close(self):
# Close the pyfs file system and dereference it.
self.fs.close()
self.fs = None
@report_sftp_errors
def open(self, path, flags, attr):
return SFTPHandle(self, path, flags)
......@@ -247,6 +252,17 @@ class SFTPHandle(paramiko.SFTPHandle):
return self.owner.chattr(self.path, attr)
class SFTPServer(paramiko.SFTPServer):
"""
An SFTPServer class that closes the filesystem when done.
"""
def finish_subsystem(self):
# Close the SFTPServerInterface, it will close the pyfs file system.
self.server.close()
super(SFTPServer, self).finish_subsystem()
class SFTPRequestHandler(SocketServer.BaseRequestHandler):
"""SocketServer RequestHandler subclass for BaseSFTPServer.
......@@ -254,6 +270,9 @@ class SFTPRequestHandler(SocketServer.BaseRequestHandler):
sftp subsystem, and hands off to the transport's own request handling
thread.
"""
timeout = 60
auth_timeout = 60
def setup(self):
"""
Creates the SSH transport. Sets security options.
......@@ -264,13 +283,26 @@ class SFTPRequestHandler(SocketServer.BaseRequestHandler):
so.digests = ('hmac-sha1', )
so.compression = ('zlib@openssh.com', 'none')
self.transport.add_server_key(self.server.host_key)
self.transport.set_subsystem_handler("sftp", paramiko.SFTPServer, SFTPServerInterface, self.server.fs, encoding=self.server.encoding)
self.transport.set_subsystem_handler("sftp", SFTPServer, SFTPServerInterface, self.server.fs, encoding=self.server.encoding)
def handle(self):
"""
Start the paramiko server, this will start a thread to handle the connection.
"""
self.transport.start_server(server=BaseServerInterface())
# TODO: I like the code below _in theory_ but it does not work as I expected.
# Figure out how to actually time out a new client if they fail to auth in a
# certain amount of time.
#chan = self.transport.accept(self.auth_timeout)
#if chan is None:
# self.transport.close()
def handle_timeout(self):
try:
self.transport.close()
finally:
super(SFTPRequestHandler, self).handle_timeout()
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
......
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