ren_open was too fancy

This commit is contained in:
ed 2024-09-15 14:39:35 +00:00
parent d67e9cc507
commit bb715704b7
3 changed files with 32 additions and 28 deletions

View file

@ -1865,10 +1865,12 @@ class HttpCli(object):
# small toctou, but better than clobbering a hardlink # small toctou, but better than clobbering a hardlink
wunlink(self.log, path, vfs.flags) wunlink(self.log, path, vfs.flags)
with ren_open(fn, *open_a, **params) as zfw: f, fn = ren_open(fn, *open_a, **params)
f, fn = zfw["orz"] try:
path = os.path.join(fdir, fn) path = os.path.join(fdir, fn)
post_sz, sha_hex, sha_b64 = hashcopy(reader, f, self.args.s_wr_slp) post_sz, sha_hex, sha_b64 = hashcopy(reader, f, self.args.s_wr_slp)
finally:
f.close()
if lim: if lim:
lim.nup(self.ip) lim.nup(self.ip)
@ -1907,8 +1909,8 @@ class HttpCli(object):
fn2 = fn.rsplit(".", 1)[0] + "." + ext fn2 = fn.rsplit(".", 1)[0] + "." + ext
params["suffix"] = suffix[:-4] params["suffix"] = suffix[:-4]
with ren_open(fn, *open_a, **params) as zfw: f, fn2 = ren_open(fn2, *open_a, **params)
f, fn = zfw["orz"] f.close()
path2 = os.path.join(fdir, fn2) path2 = os.path.join(fdir, fn2)
atomic_move(self.log, path, path2, vfs.flags) atomic_move(self.log, path, path2, vfs.flags)
@ -2741,8 +2743,8 @@ class HttpCli(object):
bos.makedirs(fdir) bos.makedirs(fdir)
# reserve destination filename # reserve destination filename
with ren_open(fname, "wb", fdir=fdir, suffix=suffix) as zfw: f, fname = ren_open(fname, "wb", fdir=fdir, suffix=suffix)
fname = zfw["orz"][1] f.close()
tnam = fname + ".PARTIAL" tnam = fname + ".PARTIAL"
if self.args.dotpart: if self.args.dotpart:
@ -2765,8 +2767,8 @@ class HttpCli(object):
v2 = lim.dfv - lim.dfl v2 = lim.dfv - lim.dfl
max_sz = min(v1, v2) if v1 and v2 else v1 or v2 max_sz = min(v1, v2) if v1 and v2 else v1 or v2
with ren_open(tnam, "wb", self.args.iobuf, **open_args) as zfw: f, tnam = ren_open(tnam, "wb", self.args.iobuf, **open_args)
f, tnam = zfw["orz"] try:
tabspath = os.path.join(fdir, tnam) tabspath = os.path.join(fdir, tnam)
self.log("writing to {}".format(tabspath)) self.log("writing to {}".format(tabspath))
sz, sha_hex, sha_b64 = hashcopy( sz, sha_hex, sha_b64 = hashcopy(
@ -2774,6 +2776,8 @@ class HttpCli(object):
) )
if sz == 0: if sz == 0:
raise Pebkac(400, "empty files in post") raise Pebkac(400, "empty files in post")
finally:
f.close()
if lim: if lim:
lim.nup(self.ip) lim.nup(self.ip)

View file

@ -3186,8 +3186,9 @@ class Up2k(object):
dip = self.hub.iphash.s(ip) dip = self.hub.iphash.s(ip)
suffix = "-%.6f-%s" % (ts, dip) suffix = "-%.6f-%s" % (ts, dip)
with ren_open(fname, "wb", fdir=fdir, suffix=suffix) as zfw: f, ret = ren_open(fname, "wb", fdir=fdir, suffix=suffix)
return zfw["orz"][1] f.close()
return ret
def _symlink( def _symlink(
self, self,
@ -4530,8 +4531,8 @@ class Up2k(object):
dip = self.hub.iphash.s(job["addr"]) dip = self.hub.iphash.s(job["addr"])
suffix = "-%.6f-%s" % (job["t0"], dip) suffix = "-%.6f-%s" % (job["t0"], dip)
with ren_open(tnam, "wb", fdir=pdir, suffix=suffix) as zfw: f, job["tnam"] = ren_open(tnam, "wb", fdir=pdir, suffix=suffix)
f, job["tnam"] = zfw["orz"] try:
abspath = djoin(pdir, job["tnam"]) abspath = djoin(pdir, job["tnam"])
sprs = job["sprs"] sprs = job["sprs"]
sz = job["size"] sz = job["size"]
@ -4578,6 +4579,8 @@ class Up2k(object):
if job["hash"] and sprs: if job["hash"] and sprs:
f.seek(sz - 1) f.seek(sz - 1)
f.write(b"e") f.write(b"e")
finally:
f.close()
if not job["hash"]: if not job["hash"]:
self._finish_upload(job["ptop"], job["wark"]) self._finish_upload(job["ptop"], job["wark"])

View file

@ -1385,18 +1385,13 @@ def min_ex(max_lines: int = 8, reverse: bool = False) -> str:
return "\n".join(ex[-max_lines:][:: -1 if reverse else 1]) return "\n".join(ex[-max_lines:][:: -1 if reverse else 1])
@contextlib.contextmanager def ren_open(fname: str, *args: Any, **kwargs: Any) -> tuple[typing.IO[Any], str]:
def ren_open(
fname: str, *args: Any, **kwargs: Any
) -> Generator[dict[str, tuple[typing.IO[Any], str]], None, None]:
fun = kwargs.pop("fun", open) fun = kwargs.pop("fun", open)
fdir = kwargs.pop("fdir", None) fdir = kwargs.pop("fdir", None)
suffix = kwargs.pop("suffix", None) suffix = kwargs.pop("suffix", None)
if fname == os.devnull: if fname == os.devnull:
with fun(fname, *args, **kwargs) as f: return fun(fname, *args, **kwargs), fname
yield {"orz": (f, fname)}
return
if suffix: if suffix:
ext = fname.split(".")[-1] ext = fname.split(".")[-1]
@ -1418,6 +1413,7 @@ def ren_open(
asciified = False asciified = False
b64 = "" b64 = ""
while True: while True:
f = None
try: try:
if fdir: if fdir:
fpath = os.path.join(fdir, fname) fpath = os.path.join(fdir, fname)
@ -1429,19 +1425,20 @@ def ren_open(
fname += suffix fname += suffix
ext += suffix ext += suffix
with fun(fsenc(fpath), *args, **kwargs) as f: f = fun(fsenc(fpath), *args, **kwargs)
if b64: if b64:
assert fdir # !rm assert fdir # !rm
fp2 = "fn-trunc.%s.txt" % (b64,) fp2 = "fn-trunc.%s.txt" % (b64,)
fp2 = os.path.join(fdir, fp2) fp2 = os.path.join(fdir, fp2)
with open(fsenc(fp2), "wb") as f2: with open(fsenc(fp2), "wb") as f2:
f2.write(orig_name.encode("utf-8")) f2.write(orig_name.encode("utf-8"))
yield {"orz": (f, fname)} return f, fname
return
except OSError as ex_: except OSError as ex_:
ex = ex_ ex = ex_
if f:
f.close()
# EPERM: android13 # EPERM: android13
if ex.errno in (errno.EINVAL, errno.EPERM) and not asciified: if ex.errno in (errno.EINVAL, errno.EPERM) and not asciified: