Skip to content

Commit

Permalink
bubble OS-filesystem errors to client
Browse files Browse the repository at this point in the history
send a 500 or 404 if a folder is inaccessible or does not exist

previously it would return an empty directory listing instead
  • Loading branch information
9001 committed Nov 2, 2024
1 parent 71d9e01 commit 119e88d
Show file tree
Hide file tree
Showing 9 changed files with 27 additions and 9 deletions.
3 changes: 2 additions & 1 deletion bin/partyfuse.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,8 @@ def listdir(self, path):
if r.status != 200:
self.closeconn()
info("http error %s reading dir %r", r.status, web_path)
raise FuseOSError(errno.ENOENT)
err = errno.ENOENT if r.status == 404 else errno.EIO
raise FuseOSError(err)

ctype = r.getheader("Content-Type", "")
if ctype == "application/json":
Expand Down
5 changes: 4 additions & 1 deletion bin/u2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,10 @@ def hasher(self):

if self.ar.drd:
dp = os.path.join(top, rd)
lnodes = set(os.listdir(dp))
try:
lnodes = set(os.listdir(dp))
except:
lnodes = list(ls) # fs eio; don't delete
if ptn:
zs = dp.replace(sep, b"/").rstrip(b"/") + b"/"
zls = [zs + x for x in lnodes]
Expand Down
6 changes: 4 additions & 2 deletions copyparty/authsrv.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,10 +591,11 @@ def _ls_shr(
scandir: bool,
permsets: list[list[bool]],
lstat: bool = False,
throw: bool = False,
) -> tuple[str, list[tuple[str, os.stat_result]], dict[str, "VFS"]]:
"""replaces _ls for certain shares (single-file, or file selection)"""
vn, rem = self.shr_src # type: ignore
abspath, real, _ = vn.ls(rem, "\n", scandir, permsets, lstat)
abspath, real, _ = vn.ls(rem, "\n", scandir, permsets, lstat, throw)
real = [x for x in real if os.path.basename(x[0]) in self.shr_files]
return abspath, real, {}

Expand All @@ -605,11 +606,12 @@ def _ls(
scandir: bool,
permsets: list[list[bool]],
lstat: bool = False,
throw: bool = False,
) -> tuple[str, list[tuple[str, os.stat_result]], dict[str, "VFS"]]:
"""return user-readable [fsdir,real,virt] items at vpath"""
virt_vis = {} # nodes readable by user
abspath = self.canonical(rem)
real = list(statdir(self.log, scandir, lstat, abspath))
real = list(statdir(self.log, scandir, lstat, abspath, throw))
real.sort()
if not rem:
# no vfs nodes in the list of real inodes
Expand Down
1 change: 1 addition & 0 deletions copyparty/ftpd.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ def listdir(self, path: str) -> list[str]:
self.uname,
not self.args.no_scandir,
[[True, False], [False, True]],
throw=True,
)
vfs_ls = [x[0] for x in vfs_ls1]
vfs_ls.extend(vfs_virt.keys())
Expand Down
2 changes: 2 additions & 0 deletions copyparty/httpcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1450,6 +1450,7 @@ def handle_propfind(self) -> bool:
not self.args.no_scandir,
[[True, False]],
lstat="davrt" not in vn.flags,
throw=True,
)
if not self.can_read:
vfs_ls = []
Expand Down Expand Up @@ -5459,6 +5460,7 @@ def tx_browser(self) -> bool:
not self.args.no_scandir,
[[True, False], [False, True]],
lstat="lt" in self.uparam,
throw=True,
)
stats = {k: v for k, v in vfs_ls}
ls_names = [x[0] for x in vfs_ls]
Expand Down
1 change: 1 addition & 0 deletions copyparty/tftpd.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ def _ls(self, vpath: str, raddress: str, rport: int, force=False) -> Any:
"*",
not self.args.no_scandir,
[[True, False]],
throw=True,
)
dnames = set([x[0] for x in vfs_ls if stat.S_ISDIR(x[1].st_mode)])
dirs1 = [(v.st_mtime, v.st_size, k + "/") for k, v in vfs_ls if k in dnames]
Expand Down
4 changes: 3 additions & 1 deletion copyparty/th_srv.py
Original file line number Diff line number Diff line change
Expand Up @@ -896,7 +896,9 @@ def _clean(self, cat: str, thumbpath: str) -> int:
prev_b64 = None
prev_fp = ""
try:
t1 = statdir(self.log_func, not self.args.no_scandir, False, thumbpath)
t1 = statdir(
self.log_func, not self.args.no_scandir, False, thumbpath, False
)
ents = sorted(list(t1))
except:
return 0
Expand Down
2 changes: 1 addition & 1 deletion copyparty/up2k.py
Original file line number Diff line number Diff line change
Expand Up @@ -1347,7 +1347,7 @@ def _build_dir(
rds = rd + "/" if rd else ""
cdirs = cdir + os.sep

g = statdir(self.log_func, not self.args.no_scandir, True, cdir)
g = statdir(self.log_func, not self.args.no_scandir, True, cdir, False)
gl = sorted(g)
partials = set([x[0] for x in gl if "PARTIAL" in x[0]])
for iname, inf in gl:
Expand Down
12 changes: 9 additions & 3 deletions copyparty/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2862,7 +2862,7 @@ def sendfile_kern(


def statdir(
logger: Optional["RootLogger"], scandir: bool, lstat: bool, top: str
logger: Optional["RootLogger"], scandir: bool, lstat: bool, top: str, throw: bool
) -> Generator[tuple[str, os.stat_result], None, None]:
if lstat and ANYWIN:
lstat = False
Expand Down Expand Up @@ -2898,6 +2898,12 @@ def statdir(
logger(src, "[s] {} @ {}".format(repr(ex), fsdec(abspath)), 6)

except Exception as ex:
if throw:
zi = getattr(ex, "errno", 0)
if zi == errno.ENOENT:
raise Pebkac(404, str(ex))
raise

t = "{} @ {}".format(repr(ex), top)
if logger:
logger(src, t, 1)
Expand All @@ -2906,7 +2912,7 @@ def statdir(


def dir_is_empty(logger: "RootLogger", scandir: bool, top: str):
for _ in statdir(logger, scandir, False, top):
for _ in statdir(logger, scandir, False, top, False):
return False
return True

Expand All @@ -2919,7 +2925,7 @@ def rmdirs(
top = os.path.dirname(top)
depth -= 1

stats = statdir(logger, scandir, lstat, top)
stats = statdir(logger, scandir, lstat, top, False)
dirs = [x[0] for x in stats if stat.S_ISDIR(x[1].st_mode)]
dirs = [os.path.join(top, x) for x in dirs]
ok = []
Expand Down

0 comments on commit 119e88d

Please sign in to comment.