diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index a3f4b7f4..f67b6870 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -165,8 +165,11 @@ class Lim(object): self.chk_rem(rem) if sz != -1: self.chk_sz(sz) - self.chk_vsz(broker, ptop, sz, volgetter) - self.chk_df(abspath, sz) # side effects; keep last-ish + else: + sz = 0 + + self.chk_vsz(broker, ptop, sz, volgetter) + self.chk_df(abspath, sz) # side effects; keep last-ish ap2, vp2 = self.rot(abspath) if abspath == ap2: @@ -206,7 +209,15 @@ class Lim(object): if self.dft < time.time(): self.dft = int(time.time()) + 300 - self.dfv = get_df(abspath)[0] or 0 + + df, du, err = get_df(abspath, True) + if err: + t = "failed to read disk space usage for [%s]: %s" + self.log(t % (abspath, err), 3) + self.dfv = 0xAAAAAAAAA # 42.6 GiB + else: + self.dfv = df or 0 + for j in list(self.reg.values()) if self.reg else []: self.dfv -= int(j["size"] / (len(j["hash"]) or 999) * len(j["need"])) diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 926b09b3..d00da5ce 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -5105,7 +5105,7 @@ class HttpCli(object): self.log("#wow #whoa") if not self.args.nid: - free, total = get_df(abspath) + free, total, _ = get_df(abspath, False) if total is not None: h1 = humansize(free or 0) h2 = humansize(total) diff --git a/copyparty/metrics.py b/copyparty/metrics.py index 2539a5e1..af54c93f 100644 --- a/copyparty/metrics.py +++ b/copyparty/metrics.py @@ -128,7 +128,7 @@ class Metrics(object): addbh("cpp_disk_size_bytes", "total HDD size of volume") addbh("cpp_disk_free_bytes", "free HDD space in volume") for vpath, vol in allvols: - free, total = get_df(vol.realpath) + free, total, _ = get_df(vol.realpath, False) if free is None or total is None: continue diff --git a/copyparty/util.py b/copyparty/util.py index 21f50b84..61264e7d 100644 --- a/copyparty/util.py +++ b/copyparty/util.py @@ -213,6 +213,9 @@ except: ansi_re = re.compile("\033\\[[^mK]*[mK]") +BOS_SEP = ("%s" % (os.sep,)).encode("ascii") + + surrogateescape.register_surrogateescape() if WINDOWS and PY2: FS_ENCODING = "utf-8" @@ -2492,23 +2495,28 @@ def wunlink(log: "NamedLogger", abspath: str, flags: dict[str, Any]) -> bool: return _fs_mvrm(log, abspath, "", False, flags) -def get_df(abspath: str) -> tuple[Optional[int], Optional[int]]: +def get_df(abspath: str, prune: bool) -> tuple[Optional[int], Optional[int], str]: try: - # some fuses misbehave - assert ctypes # type: ignore # !rm + ap = fsenc(abspath) + while prune and not os.path.isdir(ap) and BOS_SEP in ap: + # strip leafs until it hits an existing folder + ap = ap.rsplit(BOS_SEP, 1)[0] + if ANYWIN: + assert ctypes # type: ignore # !rm + abspath = fsdec(ap) bfree = ctypes.c_ulonglong(0) ctypes.windll.kernel32.GetDiskFreeSpaceExW( # type: ignore ctypes.c_wchar_p(abspath), None, None, ctypes.pointer(bfree) ) - return (bfree.value, None) + return (bfree.value, None, "") else: - sv = os.statvfs(fsenc(abspath)) + sv = os.statvfs(ap) free = sv.f_frsize * sv.f_bfree total = sv.f_frsize * sv.f_blocks - return (free, total) - except: - return (None, None) + return (free, total, "") + except Exception as ex: + return (None, None, repr(ex)) if not ANYWIN and not MACOS: