fix --df for webdav; closes #107

PUT uploads, as used by webdav, would stat the absolute
path of the file to be created, which would throw ENOENT

strip components until the path is an existing directory

and also try to enforce disk space / volume size limits
even when the incoming file is of unknown size
This commit is contained in:
ed 2024-10-18 18:14:35 +00:00
parent 5ca8f0706d
commit 2a570bb4ca
4 changed files with 32 additions and 13 deletions

View file

@ -165,8 +165,11 @@ class Lim(object):
self.chk_rem(rem) self.chk_rem(rem)
if sz != -1: if sz != -1:
self.chk_sz(sz) self.chk_sz(sz)
self.chk_vsz(broker, ptop, sz, volgetter) else:
self.chk_df(abspath, sz) # side effects; keep last-ish sz = 0
self.chk_vsz(broker, ptop, sz, volgetter)
self.chk_df(abspath, sz) # side effects; keep last-ish
ap2, vp2 = self.rot(abspath) ap2, vp2 = self.rot(abspath)
if abspath == ap2: if abspath == ap2:
@ -206,7 +209,15 @@ class Lim(object):
if self.dft < time.time(): if self.dft < time.time():
self.dft = int(time.time()) + 300 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 []: for j in list(self.reg.values()) if self.reg else []:
self.dfv -= int(j["size"] / (len(j["hash"]) or 999) * len(j["need"])) self.dfv -= int(j["size"] / (len(j["hash"]) or 999) * len(j["need"]))

View file

@ -5105,7 +5105,7 @@ class HttpCli(object):
self.log("#wow #whoa") self.log("#wow #whoa")
if not self.args.nid: if not self.args.nid:
free, total = get_df(abspath) free, total, _ = get_df(abspath, False)
if total is not None: if total is not None:
h1 = humansize(free or 0) h1 = humansize(free or 0)
h2 = humansize(total) h2 = humansize(total)

View file

@ -128,7 +128,7 @@ class Metrics(object):
addbh("cpp_disk_size_bytes", "total HDD size of volume") addbh("cpp_disk_size_bytes", "total HDD size of volume")
addbh("cpp_disk_free_bytes", "free HDD space in volume") addbh("cpp_disk_free_bytes", "free HDD space in volume")
for vpath, vol in allvols: 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: if free is None or total is None:
continue continue

View file

@ -213,6 +213,9 @@ except:
ansi_re = re.compile("\033\\[[^mK]*[mK]") ansi_re = re.compile("\033\\[[^mK]*[mK]")
BOS_SEP = ("%s" % (os.sep,)).encode("ascii")
surrogateescape.register_surrogateescape() surrogateescape.register_surrogateescape()
if WINDOWS and PY2: if WINDOWS and PY2:
FS_ENCODING = "utf-8" 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) 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: try:
# some fuses misbehave ap = fsenc(abspath)
assert ctypes # type: ignore # !rm 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: if ANYWIN:
assert ctypes # type: ignore # !rm
abspath = fsdec(ap)
bfree = ctypes.c_ulonglong(0) bfree = ctypes.c_ulonglong(0)
ctypes.windll.kernel32.GetDiskFreeSpaceExW( # type: ignore ctypes.windll.kernel32.GetDiskFreeSpaceExW( # type: ignore
ctypes.c_wchar_p(abspath), None, None, ctypes.pointer(bfree) ctypes.c_wchar_p(abspath), None, None, ctypes.pointer(bfree)
) )
return (bfree.value, None) return (bfree.value, None, "")
else: else:
sv = os.statvfs(fsenc(abspath)) sv = os.statvfs(ap)
free = sv.f_frsize * sv.f_bfree free = sv.f_frsize * sv.f_bfree
total = sv.f_frsize * sv.f_blocks total = sv.f_frsize * sv.f_blocks
return (free, total) return (free, total, "")
except: except Exception as ex:
return (None, None) return (None, None, repr(ex))
if not ANYWIN and not MACOS: if not ANYWIN and not MACOS: