From b8453c3b4f61033c3132c91d4b33e593e0ce334e Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 13 Feb 2022 16:38:24 +0100 Subject: [PATCH] ftpd: support rootless filesystems --- README.md | 1 + copyparty/ftpd.py | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3179d232..8b58e49d 100644 --- a/README.md +++ b/README.md @@ -634,6 +634,7 @@ an FTP server can be started using `--ftp 3921`, and/or `--ftps` for explicit T * uploads are not resumable -- delete and restart if necessary * runs in active mode by default, you probably want `--ftp-pr 12000-13000` * if you enable both `ftp` and `ftps`, the port-range will be divided in half + * some older software (filezilla on debian-stable) cannot passive-mode with TLS ## file indexing diff --git a/copyparty/ftpd.py b/copyparty/ftpd.py index 8b5b654e..f4ad9af1 100644 --- a/copyparty/ftpd.py +++ b/copyparty/ftpd.py @@ -18,11 +18,9 @@ from pyftpdlib.log import config_logging from .__init__ import E from .util import Pebkac, fsenc, exclude_dotfiles from .bos import bos -from .authsrv import AuthSrv if TYPE_CHECKING: from .svchub import SvcHub - from .authsrv import AuthSrv class FtpAuth(DummyAuthorizer): @@ -82,6 +80,9 @@ class FtpFs(AbstractedFS): try: vpath = vpath.replace("\\", "/").lstrip("/") vfs, rem = self.hub.asrv.vfs.get(vpath, self.uname, r, w, m, d) + if not vfs.realpath: + raise FilesystemError("no filesystem mounted at this path") + return os.path.join(vfs.realpath, rem) except Pebkac as ex: raise FilesystemError(str(ex)) @@ -125,8 +126,8 @@ class FtpFs(AbstractedFS): bos.mkdir(ap) def listdir(self, path): + vpath = join(self.cwd, path).lstrip("/") try: - vpath = join(self.cwd, path).lstrip("/") vfs, rem = self.hub.asrv.vfs.get(vpath, self.uname, True, False) fsroot, vfs_ls, vfs_virt = vfs.ls( @@ -141,8 +142,12 @@ class FtpFs(AbstractedFS): vfs_ls.sort() return vfs_ls except Exception as ex: - # display write-only folders as empty - return [] + if vpath: + # display write-only folders as empty + return [] + + # return list of volumes + return [x.split("/")[0] for x in self.hub.asrv.vfs.all_vols.keys()] def rmdir(self, path): ap = self.rv2a(path, d=True) @@ -210,8 +215,11 @@ class FtpFs(AbstractedFS): return bos.path.islink(ap) def isdir(self, path): - st = self.stat(path) - return stat.S_ISDIR(st.st_mode) + try: + st = self.stat(path) + return stat.S_ISDIR(st.st_mode) + except: + return True def getsize(self, path): ap = self.rv2a(path)