summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwillmcgugan@gmail.com <willmcgugan@gmail.com@67cdc799-7952-0410-af00-57a81ceafa0f>2013-09-09 21:04:18 +0000
committerwillmcgugan@gmail.com <willmcgugan@gmail.com@67cdc799-7952-0410-af00-57a81ceafa0f>2013-09-09 21:04:18 +0000
commit5cb5166aa8e4a5296bd2e2029d5e804aa99f6ec2 (patch)
tree15514e12fb03c5eb17dc09251fd3e1bea6fd93e6
parentc2ba6ee6aaabce323fc8c7bd087f30287e5cb54b (diff)
downloadpyfilesystem-5cb5166aa8e4a5296bd2e2029d5e804aa99f6ec2.tar.gz
Added option to folllow symlinks to ftpfs, patch from Andrew
git-svn-id: http://pyfilesystem.googlecode.com/svn/trunk@873 67cdc799-7952-0410-af00-57a81ceafa0f
-rw-r--r--fs/ftpfs.py28
-rw-r--r--fs/opener.py2
-rw-r--r--fs/tests/test_ftpfs.py30
3 files changed, 44 insertions, 16 deletions
diff --git a/fs/ftpfs.py b/fs/ftpfs.py
index 2527285..4c3f8b9 100644
--- a/fs/ftpfs.py
+++ b/fs/ftpfs.py
@@ -337,6 +337,7 @@ class FTPListDataParser(object):
i = 0
while (i + 3) < len(result.name):
if result.name[i:i+4] == ' -> ':
+ result.target = result.name[i+4:]
result.name = result.name[:i]
break
i += 1
@@ -891,7 +892,7 @@ class FTPFS(FS):
'file.read_and_write' : False,
}
- def __init__(self, host='', user='', passwd='', acct='', timeout=_GLOBAL_DEFAULT_TIMEOUT, port=21, dircache=True):
+ def __init__(self, host='', user='', passwd='', acct='', timeout=_GLOBAL_DEFAULT_TIMEOUT, port=21, dircache=True, follow_symlinks=False):
"""Connect to a FTP server.
:param host: Host to connect to
@@ -917,6 +918,7 @@ class FTPFS(FS):
self.timeout = timeout
self.default_timeout = timeout is _GLOBAL_DEFAULT_TIMEOUT
self.use_dircache = dircache
+ self.follow_symlinks = follow_symlinks
self.use_mlst = False
self._lock = threading.RLock()
@@ -1018,6 +1020,30 @@ class FTPFS(FS):
pass
self.dircache[path] = dirlist
+ def is_symlink(info):
+ return info['try_retr'] and info['try_cwd'] and info.has_key('target')
+
+ def resolve_symlink(linkpath):
+ linkinfo = self.getinfo(linkpath)
+ if not linkinfo.has_key('resolved'):
+ linkinfo['resolved'] = linkpath
+ if is_symlink(linkinfo):
+ target = linkinfo['target']
+ base, fname = pathsplit(linkpath)
+ return resolve_symlink(pathjoin(base, target))
+ else:
+ return linkinfo
+
+ if self.follow_symlinks:
+ for name in dirlist:
+ if is_symlink(dirlist[name]):
+ target = dirlist[name]['target']
+ linkinfo = resolve_symlink(pathjoin(path, target))
+ for key in linkinfo:
+ if key != 'name':
+ dirlist[name][key] = linkinfo[key]
+ del dirlist[name]['target']
+
return dirlist
@synchronize
diff --git a/fs/opener.py b/fs/opener.py
index 83e9ce1..49fef9b 100644
--- a/fs/opener.py
+++ b/fs/opener.py
@@ -434,7 +434,7 @@ examples:
dirpath, resourcepath = pathsplit(path)
url = netloc
- ftpfs = FTPFS(url, user=username or '', passwd=password or '')
+ ftpfs = FTPFS(url, user=username or '', passwd=password or '', follow_symlinks=(fs_name_params == "symlinks"))
ftpfs.cache_hint(True)
if create_dir and path:
diff --git a/fs/tests/test_ftpfs.py b/fs/tests/test_ftpfs.py
index 588367f..d37e5df 100644
--- a/fs/tests/test_ftpfs.py
+++ b/fs/tests/test_ftpfs.py
@@ -16,7 +16,9 @@ from six import PY3
try:
- from pyftpdlib import ftpserver
+ from pyftpdlib.authorizers import DummyAuthorizer
+ from pyftpdlib.handlers import FTPHandler
+ from pyftpdlib.servers import FTPServer
except ImportError:
if not PY3:
raise ImportError("Requires pyftpdlib <http://code.google.com/p/pyftpdlib/>")
@@ -27,7 +29,7 @@ from fs import ftpfs
ftp_port = 30000
class TestFTPFS(unittest.TestCase, FSTestCases, ThreadingTestCases):
-
+
__test__ = not PY3
def setUp(self):
@@ -47,11 +49,11 @@ class TestFTPFS(unittest.TestCase, FSTestCases, ThreadingTestCases):
file_path,
self.temp_dir,
use_port],
- stdout=subprocess.PIPE,
+ stdout=subprocess.PIPE,
env=env)
# Block until the server writes a line to stdout
self.ftp_server.stdout.readline()
-
+
# Poll until a connection can be made
start_time = time.time()
while time.time() - start_time < 5:
@@ -66,14 +68,14 @@ class TestFTPFS(unittest.TestCase, FSTestCases, ThreadingTestCases):
else:
# Avoid a possible infinite loop
raise Exception("Unable to connect to ftp server")
-
+
self.fs = ftpfs.FTPFS('127.0.0.1', 'user', '12345', dircache=True, port=use_port, timeout=5.0)
self.fs.cache_hint(True)
def tearDown(self):
- #self.ftp_server.terminate()
- if sys.platform == 'win32':
+ #self.ftp_server.terminate()
+ if sys.platform == 'win32':
os.popen('TASKKILL /PID '+str(self.ftp_server.pid)+' /F')
else:
os.system('kill '+str(self.ftp_server.pid))
@@ -89,21 +91,21 @@ if __name__ == "__main__":
# Run an ftp server that exposes a given directory
import sys
- authorizer = ftpserver.DummyAuthorizer()
+ authorizer = DummyAuthorizer()
authorizer.add_user("user", "12345", sys.argv[1], perm="elradfmw")
authorizer.add_anonymous(sys.argv[1])
- def nolog(*args):
- pass
- ftpserver.log = nolog
- ftpserver.logline = nolog
+ #def nolog(*args):
+ # pass
+ #ftpserver.log = nolog
+ #ftpserver.logline = nolog
- handler = ftpserver.FTPHandler
+ handler = FTPHandler
handler.authorizer = authorizer
address = ("127.0.0.1", int(sys.argv[2]))
#print address
- ftpd = ftpserver.FTPServer(address, handler)
+ ftpd = FTPServer(address, handler)
sys.stdout.write('serving\n')
sys.stdout.flush()