diff --git a/README.md b/README.md index af058940..8a3b668d 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ turn almost any device into a file server with resumable uploads/downloads using * [custom mimetypes](#custom-mimetypes) - change the association of a file extension * [GDPR compliance](#GDPR-compliance) - imagine using copyparty professionally... * [feature chickenbits](#feature-chickenbits) - buggy feature? rip it out + * [feature beefybits](#feature-beefybits) - force-enable incompatible features * [packages](#packages) - the party might be closer than you think * [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes) * [fedora package](#fedora-package) - does not exist yet @@ -2137,6 +2138,15 @@ buggy feature? rip it out by setting any of the following environment variables example: `PRTY_NO_IFADDR=1 python3 copyparty-sfx.py` +### feature beefybits + +force-enable features with known issues on your OS/env by setting any of the following environment variables, also affectionately knnown as `fuckitbits` or `hail-mary-bits` + +| env-var | what it does | +| ------------------------ | ------------ | +| `PRTY_FORCE_MP` | force-enable multiprocessing (real multithreading) on MacOS and other broken platforms | + + # packages the party might be closer than you think diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index db9c1cdd..bfabd128 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -359,6 +359,7 @@ class VFS(object): self.lim: Optional[Lim] = None # upload limits; only set for dbv self.shr_src: Optional[tuple[VFS, str]] = None # source vfs+rem of a share self.shr_files: set[str] = set() # filenames to include from shr_src + self.shr_owner: str = "" # uname self.aread: dict[str, list[str]] = {} self.awrite: dict[str, list[str]] = {} self.amove: dict[str, list[str]] = {} @@ -376,7 +377,7 @@ class VFS(object): vp = vpath + ("/" if vpath else "") self.histpath = os.path.join(realpath, ".hist") # db / thumbcache self.all_vols = {vpath: self} # flattened recursive - self.all_nodes = {vpath: self} # also jumpvols + self.all_nodes = {vpath: self} # also jumpvols/shares self.all_aps = [(rp, self)] self.all_vps = [(vp, self)] else: @@ -2327,11 +2328,6 @@ class AuthSrv(object): for x, y in vfs.all_vols.items() if x != shr and not x.startswith(shrs) } - vfs.all_nodes = { - x: y - for x, y in vfs.all_nodes.items() - if x != shr and not x.startswith(shrs) - } assert db and cur and cur2 and shv # type: ignore for row in cur.execute("select * from sh"): @@ -2361,6 +2357,7 @@ class AuthSrv(object): else: shn.ls = shn._ls + shn.shr_owner = s_un shn.shr_src = (s_vfs, s_rem) shn.realpath = s_vfs.canonical(s_rem) @@ -2386,7 +2383,9 @@ class AuthSrv(object): self.js_ls = {} self.js_htm = {} - for vn in self.vfs.all_nodes.values(): + for vp, vn in self.vfs.all_nodes.items(): + if enshare and vp.startswith(shrs): + continue # propagates later in this func vf = vn.flags vn.js_ls = { "idx": "e2d" in vf, @@ -2444,8 +2443,12 @@ class AuthSrv(object): vols = list(vfs.all_nodes.values()) if enshare: assert shv # type: ignore # !rm - vols.append(shv) - vols.extend(list(shv.nodes.values())) + for vol in shv.nodes.values(): + if vol.vpath not in vfs.all_nodes: + self.log("BUG: /%s not in all_nodes" % (vol.vpath,), 1) + vols.append(vol) + if shr in vfs.all_nodes: + self.log("BUG: %s found in all_nodes" % (shr,), 1) for vol in vols: dbv = vol.get_dbv("")[0] diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index f439d6c1..886d7cb9 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -5012,6 +5012,8 @@ class HttpCli(object): def get_dls(self) -> list[list[Any]]: ret = [] dls = self.conn.hsrv.tdls + enshare = self.args.shr + shrs = enshare[1:] for dl_id, (t0, sz, vn, vp, uname) in self.conn.hsrv.tdli.items(): t1, sent = dls[dl_id] if sent > 0x100000: # 1m; buffers 2~4 @@ -5020,6 +5022,15 @@ class HttpCli(object): vp = "" elif self.uname not in vn.axs.udot and (vp.startswith(".") or "/." in vp): vp = "" + elif ( + enshare + and vp.startswith(shrs) + and self.uname != vn.shr_owner + and self.uname not in vn.axs.uadmin + and self.uname not in self.args.shr_adm + and not dl_id.startswith(self.ip + ":") + ): + vp = "" if self.uname not in vn.axs.uadmin: dl_id = uname = "" diff --git a/copyparty/svchub.py b/copyparty/svchub.py index 560355f2..7213a7d2 100644 --- a/copyparty/svchub.py +++ b/copyparty/svchub.py @@ -1260,7 +1260,7 @@ class SvcHub(object): raise def check_mp_support(self) -> str: - if MACOS: + if MACOS and not os.environ.get("PRTY_FORCE_MP"): return "multiprocessing is wonky on mac osx;" elif sys.version_info < (3, 3): return "need python 3.3 or newer for multiprocessing;" @@ -1280,7 +1280,7 @@ class SvcHub(object): return False try: - if mp.cpu_count() <= 1: + if mp.cpu_count() <= 1 and not os.environ.get("PRTY_FORCE_MP"): raise Exception() except: self.log("svchub", "only one CPU detected; multiprocessing disabled")