copyparty 1.19.8__py3-none-any.whl → 1.19.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- copyparty/__main__.py +22 -14
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +102 -9
- copyparty/cfg.py +2 -0
- copyparty/ftpd.py +3 -0
- copyparty/httpcli.py +23 -11
- copyparty/mdns.py +3 -1
- copyparty/mtag.py +0 -1
- copyparty/svchub.py +11 -2
- copyparty/u2idx.py +29 -4
- copyparty/up2k.py +15 -5
- copyparty/util.py +41 -19
- copyparty/web/baguettebox.js.gz +0 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/dbg-audio.js.gz +0 -0
- copyparty/web/deps/busy.mp3.gz +0 -0
- copyparty/web/deps/easymde.css.gz +0 -0
- copyparty/web/deps/easymde.js.gz +0 -0
- copyparty/web/deps/marked.js.gz +0 -0
- copyparty/web/deps/mini-fa.css.gz +0 -0
- copyparty/web/deps/prism.css.gz +0 -0
- copyparty/web/deps/prism.js.gz +0 -0
- copyparty/web/deps/prismd.css.gz +0 -0
- copyparty/web/deps/scp.woff2 +0 -0
- copyparty/web/deps/sha512.ac.js.gz +0 -0
- copyparty/web/md.css.gz +0 -0
- copyparty/web/md.js.gz +0 -0
- copyparty/web/md2.css.gz +0 -0
- copyparty/web/md2.js.gz +0 -0
- copyparty/web/mde.css.gz +0 -0
- copyparty/web/mde.js.gz +0 -0
- copyparty/web/msg.css.gz +0 -0
- copyparty/web/rups.css.gz +0 -0
- copyparty/web/rups.js.gz +0 -0
- copyparty/web/shares.css.gz +0 -0
- copyparty/web/shares.js.gz +0 -0
- copyparty/web/splash.css.gz +0 -0
- copyparty/web/splash.js.gz +0 -0
- copyparty/web/svcs.js.gz +0 -0
- copyparty/web/ui.css.gz +0 -0
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.19.8.dist-info → copyparty-1.19.9.dist-info}/METADATA +5 -1
- {copyparty-1.19.8.dist-info → copyparty-1.19.9.dist-info}/RECORD +50 -50
- {copyparty-1.19.8.dist-info → copyparty-1.19.9.dist-info}/WHEEL +0 -0
- {copyparty-1.19.8.dist-info → copyparty-1.19.9.dist-info}/entry_points.txt +0 -0
- {copyparty-1.19.8.dist-info → copyparty-1.19.9.dist-info}/licenses/LICENSE +0 -0
- {copyparty-1.19.8.dist-info → copyparty-1.19.9.dist-info}/top_level.txt +0 -0
copyparty/__main__.py
CHANGED
|
@@ -1169,11 +1169,14 @@ def add_qr(ap, tty):
|
|
|
1169
1169
|
ap2.add_argument("--qr-every", metavar="SEC", type=float, default=0, help="print the qr-code every \033[33mSEC\033[0m (try this with/without --qr-pin in case of issues)")
|
|
1170
1170
|
ap2.add_argument("--qr-winch", metavar="SEC", type=float, default=0, help="when --qr-pin is enabled, check for terminal size change every \033[33mSEC\033[0m")
|
|
1171
1171
|
ap2.add_argument("--qr-file", metavar="TXT", type=u, action="append", help="\033[34mREPEATABLE:\033[0m write qr-code to file.\n └─To create txt or svg, \033[33mTXT\033[0m is Filepath:Zoom:Pad, for example [\033[32mqr.txt:1:2\033[0m]\n └─To create png or gif, \033[33mTXT\033[0m is Filepath:Zoom:Pad:Foreground:Background, for example [\033[32mqr.png:8:2:333333:ffcc55\033[0m], or [\033[32mqr.png:8:2::ffcc55\033[0m] for transparent")
|
|
1172
|
+
ap2.add_argument("--qr-stdout", action="store_true", help="always display the QR-code on STDOUT in the terminal, even if \033[33m-q\033[0m")
|
|
1173
|
+
ap2.add_argument("--qr-stderr", action="store_true", help="always display the QR-code on STDERR in the terminal, even if \033[33m-q\033[0m")
|
|
1172
1174
|
|
|
1173
1175
|
|
|
1174
1176
|
def add_fs(ap):
|
|
1175
1177
|
ap2 = ap.add_argument_group("filesystem options")
|
|
1176
1178
|
rm_re_def = "15/0.1" if ANYWIN else "0/0"
|
|
1179
|
+
ap2.add_argument("--casechk", metavar="N", type=u, default="auto", help="detect and prevent CI (case-insensitive) behavior if the underlying filesystem is CI? [\033[32my\033[0m] = detect and prevent, [\033[32mn\033[0m] = ignore and allow, [\033[32mauto\033[0m] = \033[32my\033[0m if CI fs detected. NOTE: \033[32my\033[0m is very slow but necessary for correct WebDAV behavior on Windows/Macos (volflag=casechk)")
|
|
1177
1180
|
ap2.add_argument("--rm-retry", metavar="T/R", type=u, default=rm_re_def, help="if a file cannot be deleted because it is busy, continue trying for \033[33mT\033[0m seconds, retry every \033[33mR\033[0m seconds; disable with 0/0 (volflag=rm_retry)")
|
|
1178
1181
|
ap2.add_argument("--mv-retry", metavar="T/R", type=u, default=rm_re_def, help="if a file cannot be renamed because it is busy, continue trying for \033[33mT\033[0m seconds, retry every \033[33mR\033[0m seconds; disable with 0/0 (volflag=mv_retry)")
|
|
1179
1182
|
ap2.add_argument("--iobuf", metavar="BYTES", type=int, default=256*1024, help="file I/O buffer-size; if your volumes are on a network drive, try increasing to \033[32m524288\033[0m or even \033[32m4194304\033[0m (and let me know if that improves your performance)")
|
|
@@ -1673,6 +1676,7 @@ def add_db_general(ap, hcores):
|
|
|
1673
1676
|
ap2.add_argument("--hash-mt", metavar="CORES", type=int, default=hcores, help="num cpu cores to use for file hashing; set 0 or 1 for single-core hashing")
|
|
1674
1677
|
ap2.add_argument("--re-maxage", metavar="SEC", type=int, default=0, help="rescan filesystem for changes every \033[33mSEC\033[0m seconds; 0=off (volflag=scan)")
|
|
1675
1678
|
ap2.add_argument("--db-act", metavar="SEC", type=float, default=10.0, help="defer any scheduled volume reindexing until \033[33mSEC\033[0m seconds after last db write (uploads, renames, ...)")
|
|
1679
|
+
ap2.add_argument("--srch-icase", action="store_true", help="case-insensitive search for all unicode characters (the default is icase for just ascii). NOTE: will make searches much slower (around 4x), and NOTE: only applies to filenames/paths, not tags")
|
|
1676
1680
|
ap2.add_argument("--srch-time", metavar="SEC", type=int, default=45, help="search deadline -- terminate searches running for more than \033[33mSEC\033[0m seconds")
|
|
1677
1681
|
ap2.add_argument("--srch-hits", metavar="N", type=int, default=7999, help="max search results to allow clients to fetch; 125 results will be shown initially")
|
|
1678
1682
|
ap2.add_argument("--srch-excl", metavar="PTN", type=u, default="", help="regex: exclude files from search results if the file-URL matches \033[33mPTN\033[0m (case-sensitive). Example: [\033[32mpassword|logs/[0-9]\033[0m] any URL containing 'password' or 'logs/DIGIT' (volflag=srch_excl)")
|
|
@@ -1727,7 +1731,7 @@ def add_og(ap):
|
|
|
1727
1731
|
ap2.add_argument("--uqe", action="store_true", help="query-string parceling; translate a request for \033[33m/foo/.uqe/BASE64\033[0m into \033[33m/foo?TEXT\033[0m, or \033[33m/foo/?TEXT\033[0m if the first character in \033[33mTEXT\033[0m is a slash. Automatically enabled for \033[33m--og\033[0m")
|
|
1728
1732
|
|
|
1729
1733
|
|
|
1730
|
-
def add_ui(ap, retry):
|
|
1734
|
+
def add_ui(ap, retry ):
|
|
1731
1735
|
THEMES = 10
|
|
1732
1736
|
ap2 = ap.add_argument_group("ui options")
|
|
1733
1737
|
ap2.add_argument("--grid", action="store_true", help="show grid/thumbnails by default (volflag=grid)")
|
|
@@ -1869,18 +1873,21 @@ def run_argparse(
|
|
|
1869
1873
|
for k, h, _ in sects:
|
|
1870
1874
|
ap2.add_argument("--help-" + k, action="store_true", help=h)
|
|
1871
1875
|
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
raise Exception()
|
|
1875
|
-
|
|
1876
|
+
if retry:
|
|
1877
|
+
a = ["ascii", "replace"]
|
|
1876
1878
|
for x in ap._actions:
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
+
try:
|
|
1880
|
+
x.default = x.default.encode(*a).decode(*a)
|
|
1881
|
+
except:
|
|
1882
|
+
pass
|
|
1879
1883
|
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
+
try:
|
|
1885
|
+
if x.help and x.help is not argparse.SUPPRESS:
|
|
1886
|
+
x.help = x.help.replace("└─", "`-").encode(*a).decode(*a)
|
|
1887
|
+
if retry > 2:
|
|
1888
|
+
x.help = RE_ANSI.sub("", x.help)
|
|
1889
|
+
except:
|
|
1890
|
+
pass
|
|
1884
1891
|
|
|
1885
1892
|
ret = ap.parse_args(args=argv[1:])
|
|
1886
1893
|
for k, h, t in sects:
|
|
@@ -1990,7 +1997,7 @@ def main(argv = None) :
|
|
|
1990
1997
|
except:
|
|
1991
1998
|
nc = 486 # mdns/ssdp restart headroom; select() maxfd is 512 on windows
|
|
1992
1999
|
|
|
1993
|
-
retry =
|
|
2000
|
+
retry = 0
|
|
1994
2001
|
for fmtr in [RiceFormatter, RiceFormatter, Dodge11874, BasicDodge11874]:
|
|
1995
2002
|
try:
|
|
1996
2003
|
al = run_argparse(argv, fmtr, retry, nc)
|
|
@@ -1999,8 +2006,9 @@ def main(argv = None) :
|
|
|
1999
2006
|
except SystemExit:
|
|
2000
2007
|
raise
|
|
2001
2008
|
except:
|
|
2002
|
-
retry
|
|
2003
|
-
|
|
2009
|
+
retry += 1
|
|
2010
|
+
t = "WARNING: due to limitations in your terminal and/or OS, the helptext cannot be displayed correctly. Will show a simplified version due to the following error:\n[ %s ]:\n%s\n"
|
|
2011
|
+
lprint(t % (fmtr, min_ex()))
|
|
2004
2012
|
|
|
2005
2013
|
try:
|
|
2006
2014
|
assert al # type: ignore
|
copyparty/__version__.py
CHANGED
copyparty/authsrv.py
CHANGED
|
@@ -13,7 +13,7 @@ import threading
|
|
|
13
13
|
import time
|
|
14
14
|
from datetime import datetime
|
|
15
15
|
|
|
16
|
-
from .__init__ import ANYWIN, PY2, TYPE_CHECKING, WINDOWS, E
|
|
16
|
+
from .__init__ import ANYWIN, MACOS, PY2, TYPE_CHECKING, WINDOWS, E
|
|
17
17
|
from .bos import bos
|
|
18
18
|
from .cfg import flagdescs, permdescs, vf_bmap, vf_cmap, vf_vmap
|
|
19
19
|
from .pwhash import PWHash
|
|
@@ -92,6 +92,8 @@ SBADCFG = " ({})".format(BAD_CFG)
|
|
|
92
92
|
|
|
93
93
|
PTN_U_GRP = re.compile(r"\$\{u(%[+-][^}]+)\}")
|
|
94
94
|
PTN_G_GRP = re.compile(r"\$\{g(%[+-][^}]+)\}")
|
|
95
|
+
PTN_U_ANY = re.compile(r"(\${[u][}%])")
|
|
96
|
+
PTN_G_ANY = re.compile(r"(\${[g][}%])")
|
|
95
97
|
PTN_SIGIL = re.compile(r"(\${[ug][}%])")
|
|
96
98
|
|
|
97
99
|
|
|
@@ -417,15 +419,17 @@ class VFS(object):
|
|
|
417
419
|
self.all_nodes[vpath] = self
|
|
418
420
|
self.all_aps = [(rp, [self])]
|
|
419
421
|
self.all_vps = [(vp, self)]
|
|
422
|
+
self.canonical = self._canonical
|
|
423
|
+
self.dcanonical = self._dcanonical
|
|
420
424
|
else:
|
|
421
425
|
self.histpath = self.dbpath = ""
|
|
422
426
|
self.all_aps = []
|
|
423
427
|
self.all_vps = []
|
|
428
|
+
self.canonical = self._canonical_null
|
|
429
|
+
self.dcanonical = self._dcanonical_null
|
|
424
430
|
|
|
425
431
|
self.get_dbv = self._get_dbv
|
|
426
432
|
self.ls = self._ls
|
|
427
|
-
self.canonical = self._canonical
|
|
428
|
-
self.dcanonical = self._dcanonical
|
|
429
433
|
|
|
430
434
|
def __repr__(self) :
|
|
431
435
|
return "VFS(%s)" % (
|
|
@@ -619,6 +623,34 @@ class VFS(object):
|
|
|
619
623
|
vrem = vjoin(self.vpath[len(dbv.vpath) :].lstrip("/"), vrem)
|
|
620
624
|
return dbv, vrem
|
|
621
625
|
|
|
626
|
+
def casechk(self, rem , do_stat ) :
|
|
627
|
+
ap = self.canonical(rem, False)
|
|
628
|
+
if do_stat and not bos.path.exists(ap):
|
|
629
|
+
return True # doesn't exist at all; good to go
|
|
630
|
+
dp, fn = os.path.split(ap)
|
|
631
|
+
try:
|
|
632
|
+
fns = os.listdir(dp)
|
|
633
|
+
except:
|
|
634
|
+
return True # maybe chmod 111; assume ok
|
|
635
|
+
if fn in fns:
|
|
636
|
+
return True
|
|
637
|
+
hit = "<?>"
|
|
638
|
+
lfn = fn.lower()
|
|
639
|
+
for zs in fns:
|
|
640
|
+
if lfn == zs.lower():
|
|
641
|
+
hit = zs
|
|
642
|
+
break
|
|
643
|
+
if self.log:
|
|
644
|
+
t = "returning 404 due to underlying case-insensitive filesystem:\n http-req: %r\n local-fs: %r"
|
|
645
|
+
self.log("vfs", t % (fn, hit))
|
|
646
|
+
return False
|
|
647
|
+
|
|
648
|
+
def _canonical_null(self, rem , resolve = True) :
|
|
649
|
+
return ""
|
|
650
|
+
|
|
651
|
+
def _dcanonical_null(self, rem ) :
|
|
652
|
+
return ""
|
|
653
|
+
|
|
622
654
|
def _canonical(self, rem , resolve = True) :
|
|
623
655
|
"""returns the canonical path (fully-resolved absolute fs path)"""
|
|
624
656
|
ap = self.realpath
|
|
@@ -704,8 +736,12 @@ class VFS(object):
|
|
|
704
736
|
"""return user-readable [fsdir,real,virt] items at vpath"""
|
|
705
737
|
virt_vis = {} # nodes readable by user
|
|
706
738
|
abspath = self.canonical(rem)
|
|
707
|
-
|
|
708
|
-
|
|
739
|
+
if abspath:
|
|
740
|
+
real = list(statdir(self.log, scandir, lstat, abspath, throw))
|
|
741
|
+
real.sort()
|
|
742
|
+
else:
|
|
743
|
+
real = []
|
|
744
|
+
|
|
709
745
|
if not rem:
|
|
710
746
|
# no vfs nodes in the list of real inodes
|
|
711
747
|
real = [x for x in real if x[0] not in self.nodes]
|
|
@@ -1121,6 +1157,16 @@ class AuthSrv(object):
|
|
|
1121
1157
|
src0 = src # abspath
|
|
1122
1158
|
dst0 = dst # vpath
|
|
1123
1159
|
|
|
1160
|
+
zsl = []
|
|
1161
|
+
for ptn, sigil in ((PTN_U_ANY, "${u}"), (PTN_G_ANY, "${g}")):
|
|
1162
|
+
if bool(ptn.search(src)) != bool(ptn.search(dst)):
|
|
1163
|
+
zsl.append(sigil)
|
|
1164
|
+
if zsl:
|
|
1165
|
+
t = "ERROR: if %s is mentioned in a volume definition, it must be included in both the filesystem-path [%s] and the volume-url [/%s]"
|
|
1166
|
+
t = "\n".join([t % (x, src, dst) for x in zsl])
|
|
1167
|
+
self.log(t, 1)
|
|
1168
|
+
raise Exception(t)
|
|
1169
|
+
|
|
1124
1170
|
un_gn = [(un, gn) for un, gns in un_gns.items() for gn in gns]
|
|
1125
1171
|
if not un_gn:
|
|
1126
1172
|
# ensure volume creation if there's no users
|
|
@@ -1213,8 +1259,8 @@ class AuthSrv(object):
|
|
|
1213
1259
|
self.log(t, c=3)
|
|
1214
1260
|
raise Exception(BAD_CFG)
|
|
1215
1261
|
|
|
1216
|
-
if not bos.path.
|
|
1217
|
-
self.log("warning: filesystem-path
|
|
1262
|
+
if not bos.path.exists(src):
|
|
1263
|
+
self.log("warning: filesystem-path did not exist: %r" % (src,), 3)
|
|
1218
1264
|
|
|
1219
1265
|
mount[dst] = (src, dst0)
|
|
1220
1266
|
daxs[dst] = AXS()
|
|
@@ -1836,7 +1882,7 @@ class AuthSrv(object):
|
|
|
1836
1882
|
vol.all_vps.sort(key=lambda x: len(x[0]), reverse=True)
|
|
1837
1883
|
vol.root = vfs
|
|
1838
1884
|
|
|
1839
|
-
zs = "neversymlink"
|
|
1885
|
+
zs = "neversymlink du_iwho"
|
|
1840
1886
|
k_ign = set(zs.split())
|
|
1841
1887
|
for vol in vfs.all_vols.values():
|
|
1842
1888
|
unknown_flags = set()
|
|
@@ -1987,6 +2033,8 @@ class AuthSrv(object):
|
|
|
1987
2033
|
promote = []
|
|
1988
2034
|
demote = []
|
|
1989
2035
|
for vol in vfs.all_vols.values():
|
|
2036
|
+
if not vol.realpath:
|
|
2037
|
+
continue
|
|
1990
2038
|
hid = self.hid_cache.get(vol.realpath)
|
|
1991
2039
|
if not hid:
|
|
1992
2040
|
zb = hashlib.sha512(afsenc(vol.realpath)).digest()
|
|
@@ -2025,6 +2073,8 @@ class AuthSrv(object):
|
|
|
2025
2073
|
vol.histpath = absreal(vol.histpath)
|
|
2026
2074
|
|
|
2027
2075
|
for vol in vfs.all_vols.values():
|
|
2076
|
+
if not vol.realpath:
|
|
2077
|
+
continue
|
|
2028
2078
|
hid = self.hid_cache[vol.realpath]
|
|
2029
2079
|
vflag = vol.flags.get("dbpath")
|
|
2030
2080
|
if vflag == "-":
|
|
@@ -2336,7 +2386,7 @@ class AuthSrv(object):
|
|
|
2336
2386
|
vol.flags["du_iwho"] = n_du_who(vol.flags["du_who"])
|
|
2337
2387
|
|
|
2338
2388
|
if not enshare:
|
|
2339
|
-
vol.flags["shr_who"] = "no"
|
|
2389
|
+
vol.flags["shr_who"] = self.args.shr_who = "no"
|
|
2340
2390
|
|
|
2341
2391
|
if vol.flags.get("og"):
|
|
2342
2392
|
self.args.uqe = True
|
|
@@ -2513,6 +2563,47 @@ class AuthSrv(object):
|
|
|
2513
2563
|
self.log(t.format(vol.vpath, mtp), 1)
|
|
2514
2564
|
errors = True
|
|
2515
2565
|
|
|
2566
|
+
for vol in vfs.all_nodes.values():
|
|
2567
|
+
if not vol.realpath or os.path.isfile(vol.realpath):
|
|
2568
|
+
continue
|
|
2569
|
+
ccs = vol.flags["casechk"][:1].lower()
|
|
2570
|
+
if ccs in ("y", "n"):
|
|
2571
|
+
if ccs == "y":
|
|
2572
|
+
vol.flags["bcasechk"] = True
|
|
2573
|
+
continue
|
|
2574
|
+
try:
|
|
2575
|
+
bos.makedirs(vol.realpath, vf=vol.flags)
|
|
2576
|
+
files = os.listdir(vol.realpath)
|
|
2577
|
+
for fn in files:
|
|
2578
|
+
fn2 = fn.lower()
|
|
2579
|
+
if fn == fn2:
|
|
2580
|
+
fn2 = fn.upper()
|
|
2581
|
+
if fn == fn2 or fn2 in files:
|
|
2582
|
+
continue
|
|
2583
|
+
is_ci = os.path.exists(os.path.join(vol.realpath, fn2))
|
|
2584
|
+
ccs = "y" if is_ci else "n"
|
|
2585
|
+
break
|
|
2586
|
+
if ccs not in ("y", "n"):
|
|
2587
|
+
ap = os.path.join(vol.realpath, "casechk")
|
|
2588
|
+
open(ap, "wb").close()
|
|
2589
|
+
ccs = "y" if os.path.exists(ap[:-1] + "K") else "n"
|
|
2590
|
+
os.unlink(ap)
|
|
2591
|
+
except Exception as ex:
|
|
2592
|
+
if ANYWIN:
|
|
2593
|
+
zs = "Windows"
|
|
2594
|
+
ccs = "y"
|
|
2595
|
+
elif MACOS:
|
|
2596
|
+
zs = "Macos"
|
|
2597
|
+
ccs = "y"
|
|
2598
|
+
else:
|
|
2599
|
+
zs = "Linux"
|
|
2600
|
+
ccs = "n"
|
|
2601
|
+
t = "unable to determine if filesystem at %r is case-insensitive due to %r; assuming casechk=%s due to %s"
|
|
2602
|
+
self.log(t % (vol.realpath, ex, ccs, zs), 3)
|
|
2603
|
+
vol.flags["casechk"] = ccs
|
|
2604
|
+
if ccs == "y":
|
|
2605
|
+
vol.flags["bcasechk"] = True
|
|
2606
|
+
|
|
2516
2607
|
tags = self.args.mtp or []
|
|
2517
2608
|
tags = [x.split("=")[0] for x in tags]
|
|
2518
2609
|
tags = [y for x in tags for y in x.split(",")]
|
|
@@ -2784,6 +2875,8 @@ class AuthSrv(object):
|
|
|
2784
2875
|
shn.dcanonical = shn._dcanonical_shr
|
|
2785
2876
|
else:
|
|
2786
2877
|
shn.ls = shn._ls
|
|
2878
|
+
shn.canonical = shn._canonical
|
|
2879
|
+
shn.dcanonical = shn._dcanonical
|
|
2787
2880
|
|
|
2788
2881
|
shn.shr_owner = s_un
|
|
2789
2882
|
shn.shr_src = (s_vfs, s_rem)
|
copyparty/cfg.py
CHANGED
|
@@ -81,6 +81,7 @@ def vf_vmap() :
|
|
|
81
81
|
}
|
|
82
82
|
for k in (
|
|
83
83
|
"bup_ck",
|
|
84
|
+
"casechk",
|
|
84
85
|
"chmod_d",
|
|
85
86
|
"chmod_f",
|
|
86
87
|
"dbd",
|
|
@@ -244,6 +245,7 @@ flagcats = {
|
|
|
244
245
|
"no_db_ip": "never store uploader-IP in the db; disables unpost",
|
|
245
246
|
"fat32": "avoid excessive reindexing on android sdcardfs",
|
|
246
247
|
"dbd=[acid|swal|wal|yolo]": "database speed-durability tradeoff",
|
|
248
|
+
"casechk=auto": "actively prevent case-insensitive filesystem? y/n",
|
|
247
249
|
"xlink": "cross-volume dupe detection / linking (dangerous)",
|
|
248
250
|
"xdev": "do not descend into other filesystems",
|
|
249
251
|
"xvol": "do not follow symlinks leaving the volume root",
|
copyparty/ftpd.py
CHANGED
|
@@ -198,6 +198,9 @@ class FtpFs(AbstractedFS):
|
|
|
198
198
|
if r and not cr or w and not cw or m and not cm or d and not cd:
|
|
199
199
|
raise FSE(t.format(vpath), 1)
|
|
200
200
|
|
|
201
|
+
if "bcasechk" in vfs.flags and not vfs.casechk(rem, True):
|
|
202
|
+
raise FSE("No such file or directory", 1)
|
|
203
|
+
|
|
201
204
|
return os.path.join(vfs.realpath, rem), vfs, rem
|
|
202
205
|
except Pebkac as ex:
|
|
203
206
|
raise FSE(str(ex))
|
copyparty/httpcli.py
CHANGED
|
@@ -730,6 +730,9 @@ class HttpCli(object):
|
|
|
730
730
|
else:
|
|
731
731
|
avn = vn
|
|
732
732
|
|
|
733
|
+
if "bcasechk" in vn.flags and not vn.casechk(rem, True):
|
|
734
|
+
return self.tx_404() and False
|
|
735
|
+
|
|
733
736
|
(
|
|
734
737
|
self.can_read,
|
|
735
738
|
self.can_write,
|
|
@@ -1546,6 +1549,7 @@ class HttpCli(object):
|
|
|
1546
1549
|
if xtag is not None:
|
|
1547
1550
|
props = set([y.tag.split("}")[-1] for y in xtag])
|
|
1548
1551
|
# assume <allprop/> otherwise; nobody ever gonna <propname/>
|
|
1552
|
+
self.hint = ""
|
|
1549
1553
|
|
|
1550
1554
|
zi = int(time.time())
|
|
1551
1555
|
vst = os.stat_result((16877, -1, -1, 1, 1000, 1000, 8, zi, zi, zi))
|
|
@@ -1555,7 +1559,9 @@ class HttpCli(object):
|
|
|
1555
1559
|
except OSError as ex:
|
|
1556
1560
|
if ex.errno not in (errno.ENOENT, errno.ENOTDIR):
|
|
1557
1561
|
raise
|
|
1558
|
-
|
|
1562
|
+
if tap:
|
|
1563
|
+
raise Pebkac(404)
|
|
1564
|
+
st = vst
|
|
1559
1565
|
|
|
1560
1566
|
topdir = {"vp": "", "st": st}
|
|
1561
1567
|
fgen = []
|
|
@@ -1595,6 +1601,9 @@ class HttpCli(object):
|
|
|
1595
1601
|
)
|
|
1596
1602
|
|
|
1597
1603
|
elif depth == "0" or not stat.S_ISDIR(st.st_mode):
|
|
1604
|
+
if depth == "0" and not self.vpath and not vn.realpath:
|
|
1605
|
+
# rootless server; give dummy listing
|
|
1606
|
+
self.can_read = True
|
|
1598
1607
|
# propfind on a file; return as topdir
|
|
1599
1608
|
if not self.can_read and not self.can_get:
|
|
1600
1609
|
self.log("inaccessible: %r" % ("/" + self.vpath,))
|
|
@@ -1627,7 +1636,11 @@ class HttpCli(object):
|
|
|
1627
1636
|
self.log("inaccessible: %r" % ("/" + self.vpath,))
|
|
1628
1637
|
raise Pebkac(401, "authenticate")
|
|
1629
1638
|
|
|
1630
|
-
zi =
|
|
1639
|
+
zi = (
|
|
1640
|
+
vn.flags["du_iwho"]
|
|
1641
|
+
if vn.realpath and "quota-available-bytes" in props
|
|
1642
|
+
else 0
|
|
1643
|
+
)
|
|
1631
1644
|
if zi and (
|
|
1632
1645
|
zi == 9
|
|
1633
1646
|
or (zi == 7 and self.uname != "*")
|
|
@@ -1761,6 +1774,7 @@ class HttpCli(object):
|
|
|
1761
1774
|
xprop = xroot.find(r"./{DAV:}propertyupdate/{DAV:}set/{DAV:}prop")
|
|
1762
1775
|
for ze in xprop:
|
|
1763
1776
|
ze.clear()
|
|
1777
|
+
self.hint = ""
|
|
1764
1778
|
|
|
1765
1779
|
txt = """<multistatus xmlns="DAV:"><response><propstat><status>HTTP/1.1 403 Forbidden</status></propstat></response></multistatus>"""
|
|
1766
1780
|
xroot = parse_xml(txt)
|
|
@@ -1816,6 +1830,7 @@ class HttpCli(object):
|
|
|
1816
1830
|
ET.register_namespace("D", "DAV:")
|
|
1817
1831
|
lk = parse_xml(txt)
|
|
1818
1832
|
assert lk.tag == "{DAV:}lockinfo"
|
|
1833
|
+
self.hint = ""
|
|
1819
1834
|
|
|
1820
1835
|
token = str(uuid.uuid4())
|
|
1821
1836
|
|
|
@@ -3403,8 +3418,6 @@ class HttpCli(object):
|
|
|
3403
3418
|
sz, sha_hex, sha_b64 = copier(
|
|
3404
3419
|
p_data, f, hasher, max_sz, self.args.s_wr_slp
|
|
3405
3420
|
)
|
|
3406
|
-
if sz == 0:
|
|
3407
|
-
raise Pebkac(400, "empty files in post")
|
|
3408
3421
|
finally:
|
|
3409
3422
|
f.close()
|
|
3410
3423
|
|
|
@@ -4711,11 +4724,9 @@ class HttpCli(object):
|
|
|
4711
4724
|
packer = StreamZip
|
|
4712
4725
|
ext = "zip"
|
|
4713
4726
|
|
|
4714
|
-
fn =
|
|
4715
|
-
if
|
|
4716
|
-
fn =
|
|
4717
|
-
else:
|
|
4718
|
-
fn = self.host.split(":")[0]
|
|
4727
|
+
fn = self.vpath.split("/")[-1] or self.host.split(":")[0]
|
|
4728
|
+
if items:
|
|
4729
|
+
fn = "sel-" + fn
|
|
4719
4730
|
|
|
4720
4731
|
if vn.flags.get("zipmax") and not (
|
|
4721
4732
|
vn.flags.get("zipmaxu") and self.uname != "*"
|
|
@@ -4891,8 +4902,8 @@ class HttpCli(object):
|
|
|
4891
4902
|
else:
|
|
4892
4903
|
fullfile = b""
|
|
4893
4904
|
|
|
4894
|
-
if not sz_md and b"\n"
|
|
4895
|
-
lead =
|
|
4905
|
+
if not sz_md and buf.startswith((b"\n", b"\r\n")):
|
|
4906
|
+
lead = b"\n" if buf.startswith(b"\n") else b"\r\n"
|
|
4896
4907
|
sz_md += len(lead)
|
|
4897
4908
|
|
|
4898
4909
|
sz_md += len(buf)
|
|
@@ -6207,6 +6218,7 @@ class HttpCli(object):
|
|
|
6207
6218
|
|
|
6208
6219
|
if "v" in self.uparam:
|
|
6209
6220
|
add_og = True
|
|
6221
|
+
og_fn = ""
|
|
6210
6222
|
|
|
6211
6223
|
if "b" in self.uparam:
|
|
6212
6224
|
self.out_headers["X-Robots-Tag"] = "noindex, nofollow"
|
copyparty/mdns.py
CHANGED
|
@@ -12,7 +12,9 @@ from ipaddress import IPv4Network, IPv6Network
|
|
|
12
12
|
from .__init__ import TYPE_CHECKING
|
|
13
13
|
from .__init__ import unicode as U
|
|
14
14
|
from .multicast import MC_Sck, MCast
|
|
15
|
-
from .stolen.dnslib import
|
|
15
|
+
from .stolen.dnslib import (
|
|
16
|
+
AAAA,
|
|
17
|
+
)
|
|
16
18
|
from .stolen.dnslib import CLASS as DC
|
|
17
19
|
from .stolen.dnslib import (
|
|
18
20
|
NSEC,
|
copyparty/mtag.py
CHANGED
copyparty/svchub.py
CHANGED
|
@@ -842,6 +842,10 @@ class SvcHub(object):
|
|
|
842
842
|
if w8:
|
|
843
843
|
time.sleep(w8)
|
|
844
844
|
self.log("qr-code", qr)
|
|
845
|
+
if self.args.qr_stdout:
|
|
846
|
+
self.pr(self.tcpsrv.qr)
|
|
847
|
+
if self.args.qr_stderr:
|
|
848
|
+
self.pr(self.tcpsrv.qr, file=sys.stderr)
|
|
845
849
|
w8 = self.args.qr_every
|
|
846
850
|
msg = "%s\033[%dA" % (qr, len(qr.split("\n")))
|
|
847
851
|
while w8:
|
|
@@ -875,8 +879,13 @@ class SvcHub(object):
|
|
|
875
879
|
self.sticky_qr()
|
|
876
880
|
if self.args.qr_wait or self.args.qr_every or self.args.qr_winch:
|
|
877
881
|
Daemon(self._qr_thr, "qr")
|
|
878
|
-
|
|
879
|
-
|
|
882
|
+
else:
|
|
883
|
+
if not self.args.qr_pin:
|
|
884
|
+
self.log("qr-code", self.tcpsrv.qr)
|
|
885
|
+
if self.args.qr_stdout:
|
|
886
|
+
self.pr(self.tcpsrv.qr)
|
|
887
|
+
if self.args.qr_stderr:
|
|
888
|
+
self.pr(self.tcpsrv.qr, file=sys.stderr)
|
|
880
889
|
else:
|
|
881
890
|
self.log("root", "workers OK\n")
|
|
882
891
|
|
copyparty/u2idx.py
CHANGED
|
@@ -50,6 +50,11 @@ class U2idx(object):
|
|
|
50
50
|
self.log("your python does not have sqlite3; searching will be disabled")
|
|
51
51
|
return
|
|
52
52
|
|
|
53
|
+
if self.args.srch_icase:
|
|
54
|
+
self._open_db = self._open_db_icase
|
|
55
|
+
else:
|
|
56
|
+
self._open_db = self._open_db_std
|
|
57
|
+
|
|
53
58
|
|
|
54
59
|
self.active_id = ""
|
|
55
60
|
self.active_cur = None
|
|
@@ -65,6 +70,15 @@ class U2idx(object):
|
|
|
65
70
|
def log(self, msg , c = 0) :
|
|
66
71
|
self.log_func("u2idx", msg, c)
|
|
67
72
|
|
|
73
|
+
def _open_db_std(self, *args, **kwargs):
|
|
74
|
+
kwargs["check_same_thread"] = False
|
|
75
|
+
return sqlite3.connect(*args, **kwargs)
|
|
76
|
+
|
|
77
|
+
def _open_db_icase(self, *args, **kwargs):
|
|
78
|
+
db = self._open_db_std(*args, **kwargs)
|
|
79
|
+
db.create_function("casefold", 1, lambda x: x.casefold() if x else x)
|
|
80
|
+
return db
|
|
81
|
+
|
|
68
82
|
def shutdown(self) :
|
|
69
83
|
if not HAVE_SQLITE3:
|
|
70
84
|
return
|
|
@@ -142,8 +156,7 @@ class U2idx(object):
|
|
|
142
156
|
uri = ""
|
|
143
157
|
try:
|
|
144
158
|
uri = "{}?mode=ro&nolock=1".format(Path(db_path).as_uri())
|
|
145
|
-
|
|
146
|
-
cur = db.cursor()
|
|
159
|
+
cur = self._open_db(uri, timeout=2, uri=True).cursor()
|
|
147
160
|
cur.execute('pragma table_info("up")').fetchone()
|
|
148
161
|
self.log("ro: %r" % (db_path,))
|
|
149
162
|
except:
|
|
@@ -154,7 +167,7 @@ class U2idx(object):
|
|
|
154
167
|
if not cur:
|
|
155
168
|
# on windows, this steals the write-lock from up2k.deferred_init --
|
|
156
169
|
# seen on win 10.0.17763.2686, py 3.10.4, sqlite 3.37.2
|
|
157
|
-
cur =
|
|
170
|
+
cur = self._open_db(db_path, timeout=2).cursor()
|
|
158
171
|
self.log("opened %r" % (db_path,))
|
|
159
172
|
|
|
160
173
|
self.cur[ptop] = cur
|
|
@@ -167,6 +180,8 @@ class U2idx(object):
|
|
|
167
180
|
if not HAVE_SQLITE3:
|
|
168
181
|
return [], [], False
|
|
169
182
|
|
|
183
|
+
icase = self.args.srch_icase
|
|
184
|
+
|
|
170
185
|
q = ""
|
|
171
186
|
v = ""
|
|
172
187
|
va = []
|
|
@@ -226,9 +241,13 @@ class U2idx(object):
|
|
|
226
241
|
elif v == "path":
|
|
227
242
|
v = "trim(?||up.rd,'/')"
|
|
228
243
|
va.append("\nrd")
|
|
244
|
+
if icase:
|
|
245
|
+
v = "casefold(%s)" % (v,)
|
|
229
246
|
|
|
230
247
|
elif v == "name":
|
|
231
248
|
v = "up.fn"
|
|
249
|
+
if icase:
|
|
250
|
+
v = "casefold(%s)" % (v,)
|
|
232
251
|
|
|
233
252
|
elif v == "tags" or ptn_mt.match(v):
|
|
234
253
|
have_mt = True
|
|
@@ -279,6 +298,12 @@ class U2idx(object):
|
|
|
279
298
|
tail = "||'%'"
|
|
280
299
|
v = v[:-1]
|
|
281
300
|
|
|
301
|
+
if icase and "casefold(" in q:
|
|
302
|
+
try:
|
|
303
|
+
v = unicode(v).casefold()
|
|
304
|
+
except:
|
|
305
|
+
v = unicode(v).lower()
|
|
306
|
+
|
|
282
307
|
q += " {}?{} ".format(head, tail)
|
|
283
308
|
va.append(v)
|
|
284
309
|
is_key = True
|
|
@@ -313,7 +338,7 @@ class U2idx(object):
|
|
|
313
338
|
uname ,
|
|
314
339
|
vols ,
|
|
315
340
|
uq ,
|
|
316
|
-
uv
|
|
341
|
+
uv ,
|
|
317
342
|
have_mt ,
|
|
318
343
|
sort ,
|
|
319
344
|
lim ,
|
copyparty/up2k.py
CHANGED
|
@@ -60,6 +60,7 @@ from .util import (
|
|
|
60
60
|
sfsenc,
|
|
61
61
|
spack,
|
|
62
62
|
statdir,
|
|
63
|
+
trystat_shutil_copy2,
|
|
63
64
|
ub64enc,
|
|
64
65
|
unhumanize,
|
|
65
66
|
vjoin,
|
|
@@ -1132,7 +1133,7 @@ class Up2k(object):
|
|
|
1132
1133
|
ft = "\033[0;32m{}{:.0}"
|
|
1133
1134
|
ff = "\033[0;35m{}{:.0}"
|
|
1134
1135
|
fv = "\033[0;36m{}:\033[90m{}"
|
|
1135
|
-
zs = "du_iwho ext_th_d html_head put_name2 mv_re_r mv_re_t rm_re_r rm_re_t srch_re_dots srch_re_nodot zipmax zipmaxn_v zipmaxs_v"
|
|
1136
|
+
zs = "bcasechk du_iwho ext_th_d html_head put_name2 mv_re_r mv_re_t rm_re_r rm_re_t srch_re_dots srch_re_nodot zipmax zipmaxn_v zipmaxs_v"
|
|
1136
1137
|
fx = set(zs.split())
|
|
1137
1138
|
fd = vf_bmap()
|
|
1138
1139
|
fd.update(vf_cmap())
|
|
@@ -2753,7 +2754,7 @@ class Up2k(object):
|
|
|
2753
2754
|
cur.close()
|
|
2754
2755
|
db.close()
|
|
2755
2756
|
|
|
2756
|
-
|
|
2757
|
+
trystat_shutil_copy2(self.log, fsenc(db_path), fsenc(bak))
|
|
2757
2758
|
return self._orz(db_path)
|
|
2758
2759
|
|
|
2759
2760
|
def _read_ver(self, cur ) :
|
|
@@ -3575,7 +3576,7 @@ class Up2k(object):
|
|
|
3575
3576
|
t = "BUG: no valid sources to link from! orig(%r) fsrc(%r) link(%r)"
|
|
3576
3577
|
self.log(t, 1)
|
|
3577
3578
|
raise Exception(t % (src, fsrc, dst))
|
|
3578
|
-
|
|
3579
|
+
trystat_shutil_copy2(self.log, fsenc(csrc), fsenc(dst))
|
|
3579
3580
|
|
|
3580
3581
|
if lmod and (not linked or SYMTIME):
|
|
3581
3582
|
bos.utime_c(self.log, dst, int(lmod), False)
|
|
@@ -4124,6 +4125,9 @@ class Up2k(object):
|
|
|
4124
4125
|
except:
|
|
4125
4126
|
raise Pebkac(400, "file not found on disk (already deleted?)")
|
|
4126
4127
|
|
|
4128
|
+
if "bcasechk" in vn.flags and not vn.casechk(rem, False):
|
|
4129
|
+
raise Pebkac(400, "file does not exist case-sensitively")
|
|
4130
|
+
|
|
4127
4131
|
scandir = not self.args.no_scandir
|
|
4128
4132
|
if is_dir:
|
|
4129
4133
|
# note: deletion inside shares would require a rewrite here;
|
|
@@ -4248,6 +4252,9 @@ class Up2k(object):
|
|
|
4248
4252
|
self.db_act = self.vol_act[svn_dbv.realpath] = time.time()
|
|
4249
4253
|
|
|
4250
4254
|
st = bos.stat(sabs)
|
|
4255
|
+
if "bcasechk" in svn.flags and not svn.casechk(srem, False):
|
|
4256
|
+
raise Pebkac(400, "file does not exist case-sensitively")
|
|
4257
|
+
|
|
4251
4258
|
if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
|
|
4252
4259
|
with self.mutex:
|
|
4253
4260
|
try:
|
|
@@ -4405,7 +4412,7 @@ class Up2k(object):
|
|
|
4405
4412
|
b1, b2 = fsenc(sabs), fsenc(dabs)
|
|
4406
4413
|
is_link = os.path.islink(b1) # due to _relink
|
|
4407
4414
|
try:
|
|
4408
|
-
|
|
4415
|
+
trystat_shutil_copy2(self.log, b1, b2)
|
|
4409
4416
|
except:
|
|
4410
4417
|
try:
|
|
4411
4418
|
wunlink(self.log, dabs, dvn.flags)
|
|
@@ -4465,6 +4472,9 @@ class Up2k(object):
|
|
|
4465
4472
|
raise Pebkac(400, "mv: cannot move a mountpoint")
|
|
4466
4473
|
|
|
4467
4474
|
st = bos.lstat(sabs)
|
|
4475
|
+
if "bcasechk" in svn.flags and not svn.casechk(srem, False):
|
|
4476
|
+
raise Pebkac(400, "file does not exist case-sensitively")
|
|
4477
|
+
|
|
4468
4478
|
if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
|
|
4469
4479
|
with self.mutex:
|
|
4470
4480
|
try:
|
|
@@ -4710,7 +4720,7 @@ class Up2k(object):
|
|
|
4710
4720
|
b1, b2 = fsenc(sabs), fsenc(dabs)
|
|
4711
4721
|
is_link = os.path.islink(b1) # due to _relink
|
|
4712
4722
|
try:
|
|
4713
|
-
|
|
4723
|
+
trystat_shutil_copy2(self.log, b1, b2)
|
|
4714
4724
|
except:
|
|
4715
4725
|
try:
|
|
4716
4726
|
wunlink(self.log, dabs, dvn.flags)
|
copyparty/util.py
CHANGED
|
@@ -1495,10 +1495,12 @@ def vol_san(vols , txt ) :
|
|
|
1495
1495
|
bvp = vol.vpath.encode("utf-8")
|
|
1496
1496
|
bvph = b"$hist(/" + bvp + b")"
|
|
1497
1497
|
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1498
|
+
if bap:
|
|
1499
|
+
txt = txt.replace(bap, bvp)
|
|
1500
|
+
txt = txt.replace(bap.replace(b"\\", b"\\\\"), bvp)
|
|
1501
|
+
if bhp:
|
|
1502
|
+
txt = txt.replace(bhp, bvph)
|
|
1503
|
+
txt = txt.replace(bhp.replace(b"\\", b"\\\\"), bvph)
|
|
1502
1504
|
|
|
1503
1505
|
if vol.histpath != vol.dbpath:
|
|
1504
1506
|
bdp = vol.dbpath.encode("utf-8")
|
|
@@ -2174,14 +2176,14 @@ def odfusion(
|
|
|
2174
2176
|
ret = base.copy()
|
|
2175
2177
|
if oth.startswith("+"):
|
|
2176
2178
|
for k in words1:
|
|
2177
|
-
ret[k] = True
|
|
2179
|
+
ret[k] = True # type: ignore
|
|
2178
2180
|
elif oth[:1] in ("-", "/"):
|
|
2179
2181
|
for k in words1:
|
|
2180
|
-
ret.pop(k, None)
|
|
2182
|
+
ret.pop(k, None) # type: ignore
|
|
2181
2183
|
else:
|
|
2182
2184
|
ret = ODict.fromkeys(words0, True)
|
|
2183
2185
|
|
|
2184
|
-
return ret
|
|
2186
|
+
return ret # type: ignore
|
|
2185
2187
|
|
|
2186
2188
|
|
|
2187
2189
|
def ipnorm(ip ) :
|
|
@@ -2553,6 +2555,24 @@ def set_fperms(f , vf ) :
|
|
|
2553
2555
|
os.fchown(fno, vf["uid"], vf["gid"])
|
|
2554
2556
|
|
|
2555
2557
|
|
|
2558
|
+
def trystat_shutil_copy2(log , src , dst ) :
|
|
2559
|
+
try:
|
|
2560
|
+
return shutil.copy2(src, dst)
|
|
2561
|
+
except:
|
|
2562
|
+
# ignore failed mtime on linux+ntfs; for example:
|
|
2563
|
+
# shutil.py:437 <copy2>: copystat(src, dst, follow_symlinks=follow_symlinks)
|
|
2564
|
+
# shutil.py:376 <copystat>: lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
|
|
2565
|
+
# [PermissionError] [Errno 1] Operation not permitted, '/windows/_videos'
|
|
2566
|
+
_, _, tb = sys.exc_info()
|
|
2567
|
+
for _, _, fun, _ in traceback.extract_tb(tb):
|
|
2568
|
+
if fun == "copystat":
|
|
2569
|
+
if log:
|
|
2570
|
+
t = "warning: failed to retain some file attributes (timestamp and/or permissions) during copy from %r to %r:\n%s"
|
|
2571
|
+
log(t % (src, dst, min_ex()), 3)
|
|
2572
|
+
return dst # close enough
|
|
2573
|
+
raise
|
|
2574
|
+
|
|
2575
|
+
|
|
2556
2576
|
def _fs_mvrm(
|
|
2557
2577
|
log , src , dst , atomic , flags
|
|
2558
2578
|
) :
|
|
@@ -2591,7 +2611,7 @@ def _fs_mvrm(
|
|
|
2591
2611
|
t = "something appeared at dst; aborting rename %r ==> %r"
|
|
2592
2612
|
log(t % (src, dst), 1)
|
|
2593
2613
|
return False
|
|
2594
|
-
osfun(*args)
|
|
2614
|
+
osfun(*args) # type: ignore
|
|
2595
2615
|
if attempt:
|
|
2596
2616
|
now = time.time()
|
|
2597
2617
|
t = "%sd in %.2f sec, attempt %d: %r"
|
|
@@ -2641,7 +2661,7 @@ def atomic_move(log , src , dst , flags ) :
|
|
|
2641
2661
|
os.unlink(bdst)
|
|
2642
2662
|
except:
|
|
2643
2663
|
pass
|
|
2644
|
-
shutil.move(bsrc, bdst)
|
|
2664
|
+
shutil.move(bsrc, bdst) # type: ignore
|
|
2645
2665
|
|
|
2646
2666
|
|
|
2647
2667
|
def wunlink(log , abspath , flags ) :
|
|
@@ -3046,7 +3066,7 @@ def sendfile_kern(
|
|
|
3046
3066
|
try:
|
|
3047
3067
|
req = min(0x2000000, upper - ofs) # 32 MiB
|
|
3048
3068
|
if use_poll:
|
|
3049
|
-
poll.poll(10000)
|
|
3069
|
+
poll.poll(10000) # type: ignore
|
|
3050
3070
|
else:
|
|
3051
3071
|
select.select([], [out_fd], [], 10)
|
|
3052
3072
|
n = os.sendfile(out_fd, in_fd, ofs, req)
|
|
@@ -3334,7 +3354,9 @@ NICEB = NICES.encode("utf-8")
|
|
|
3334
3354
|
|
|
3335
3355
|
|
|
3336
3356
|
def runcmd(
|
|
3337
|
-
argv
|
|
3357
|
+
argv ,
|
|
3358
|
+
timeout = None,
|
|
3359
|
+
**ka
|
|
3338
3360
|
) :
|
|
3339
3361
|
isbytes = isinstance(argv[0], (bytes, bytearray))
|
|
3340
3362
|
oom = ka.pop("oom", 0) # 0..1000
|
|
@@ -3353,19 +3375,19 @@ def runcmd(
|
|
|
3353
3375
|
if ANYWIN:
|
|
3354
3376
|
if isbytes:
|
|
3355
3377
|
if argv[0] in CMD_EXEB:
|
|
3356
|
-
argv[0] += b".exe"
|
|
3378
|
+
argv[0] += b".exe" # type: ignore
|
|
3357
3379
|
else:
|
|
3358
3380
|
if argv[0] in CMD_EXES:
|
|
3359
|
-
argv[0] += ".exe"
|
|
3381
|
+
argv[0] += ".exe" # type: ignore
|
|
3360
3382
|
|
|
3361
3383
|
if ka.pop("nice", None):
|
|
3362
3384
|
if WINDOWS:
|
|
3363
3385
|
ka["creationflags"] = 0x4000
|
|
3364
3386
|
elif NICEB:
|
|
3365
3387
|
if isbytes:
|
|
3366
|
-
argv = [NICEB] + argv
|
|
3388
|
+
argv = [NICEB] + argv # type: ignore
|
|
3367
3389
|
else:
|
|
3368
|
-
argv = [NICES] + argv
|
|
3390
|
+
argv = [NICES] + argv # type: ignore
|
|
3369
3391
|
|
|
3370
3392
|
p = sp.Popen(argv, stdout=cout, stderr=cerr, **ka)
|
|
3371
3393
|
|
|
@@ -3377,10 +3399,10 @@ def runcmd(
|
|
|
3377
3399
|
pass
|
|
3378
3400
|
|
|
3379
3401
|
if not timeout or PY2:
|
|
3380
|
-
bout, berr = p.communicate(sin)
|
|
3402
|
+
bout, berr = p.communicate(sin) # type: ignore
|
|
3381
3403
|
else:
|
|
3382
3404
|
try:
|
|
3383
|
-
bout, berr = p.communicate(sin, timeout=timeout)
|
|
3405
|
+
bout, berr = p.communicate(sin, timeout=timeout) # type: ignore
|
|
3384
3406
|
except sp.TimeoutExpired:
|
|
3385
3407
|
if kill == "n":
|
|
3386
3408
|
return -18, "", "" # SIGCONT; leave it be
|
|
@@ -3390,7 +3412,7 @@ def runcmd(
|
|
|
3390
3412
|
killtree(p.pid)
|
|
3391
3413
|
|
|
3392
3414
|
try:
|
|
3393
|
-
bout, berr = p.communicate(timeout=1)
|
|
3415
|
+
bout, berr = p.communicate(timeout=1) # type: ignore
|
|
3394
3416
|
except:
|
|
3395
3417
|
bout = b""
|
|
3396
3418
|
berr = b""
|
|
@@ -3812,7 +3834,7 @@ def runhook(
|
|
|
3812
3834
|
at ,
|
|
3813
3835
|
txt ,
|
|
3814
3836
|
) :
|
|
3815
|
-
args = (broker or up2k).args
|
|
3837
|
+
args = (broker or up2k).args # type: ignore
|
|
3816
3838
|
verbose = args.hook_v
|
|
3817
3839
|
vp = vp.replace("\\", "/")
|
|
3818
3840
|
ret = {"rc": 0}
|
copyparty/web/baguettebox.js.gz
CHANGED
|
Binary file
|
copyparty/web/browser.css.gz
CHANGED
|
Binary file
|
copyparty/web/browser.js.gz
CHANGED
|
Binary file
|
copyparty/web/dbg-audio.js.gz
CHANGED
|
Binary file
|
copyparty/web/deps/busy.mp3.gz
CHANGED
|
Binary file
|
|
Binary file
|
copyparty/web/deps/easymde.js.gz
CHANGED
|
Binary file
|
copyparty/web/deps/marked.js.gz
CHANGED
|
Binary file
|
|
Binary file
|
copyparty/web/deps/prism.css.gz
CHANGED
|
Binary file
|
copyparty/web/deps/prism.js.gz
CHANGED
|
Binary file
|
copyparty/web/deps/prismd.css.gz
CHANGED
|
Binary file
|
copyparty/web/deps/scp.woff2
CHANGED
|
Binary file
|
|
Binary file
|
copyparty/web/md.css.gz
CHANGED
|
Binary file
|
copyparty/web/md.js.gz
CHANGED
|
Binary file
|
copyparty/web/md2.css.gz
CHANGED
|
Binary file
|
copyparty/web/md2.js.gz
CHANGED
|
Binary file
|
copyparty/web/mde.css.gz
CHANGED
|
Binary file
|
copyparty/web/mde.js.gz
CHANGED
|
Binary file
|
copyparty/web/msg.css.gz
CHANGED
|
Binary file
|
copyparty/web/rups.css.gz
CHANGED
|
Binary file
|
copyparty/web/rups.js.gz
CHANGED
|
Binary file
|
copyparty/web/shares.css.gz
CHANGED
|
Binary file
|
copyparty/web/shares.js.gz
CHANGED
|
Binary file
|
copyparty/web/splash.css.gz
CHANGED
|
Binary file
|
copyparty/web/splash.js.gz
CHANGED
|
Binary file
|
copyparty/web/svcs.js.gz
CHANGED
|
Binary file
|
copyparty/web/ui.css.gz
CHANGED
|
Binary file
|
copyparty/web/up2k.js.gz
CHANGED
|
Binary file
|
copyparty/web/util.js.gz
CHANGED
|
Binary file
|
copyparty/web/w.hash.js.gz
CHANGED
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: copyparty
|
|
3
|
-
Version: 1.19.
|
|
3
|
+
Version: 1.19.9
|
|
4
4
|
Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
|
|
5
5
|
Author-email: ed <copyparty@ocv.me>
|
|
6
6
|
License: MIT
|
|
@@ -2770,6 +2770,10 @@ below are some tweaks roughly ordered by usefulness:
|
|
|
2770
2770
|
* using [pypy](https://www.pypy.org/) instead of [cpython](https://www.python.org/) *can* be 70% faster for some workloads, but slower for many others
|
|
2771
2771
|
* and pypy can sometimes crash on startup with `-j0` (TODO make issue)
|
|
2772
2772
|
|
|
2773
|
+
* if you are running the copyparty server **on Windows or Macos:**
|
|
2774
|
+
* `--casechk=y` makes it much faster, but also awakens [the usual surprises](https://github.com/9001/copyparty/issues/781) you expect from a case-insensitive filesystem
|
|
2775
|
+
* this is the same as `casechk: n` in a config-file
|
|
2776
|
+
|
|
2773
2777
|
|
|
2774
2778
|
## client-side
|
|
2775
2779
|
|
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
copyparty/__init__.py,sha256=8nHuSqcIwZvExA-66pV6slJnDEunE8LwlmGzYnGnDBU,2647
|
|
2
|
-
copyparty/__main__.py,sha256=
|
|
3
|
-
copyparty/__version__.py,sha256=
|
|
4
|
-
copyparty/authsrv.py,sha256=
|
|
2
|
+
copyparty/__main__.py,sha256=b0eURrybXQRskCWSK4Y0wR2Su6tRHgFd2CAbNWLqvK4,144217
|
|
3
|
+
copyparty/__version__.py,sha256=x0kGBgJD-lVB_8ZPEnHxRPxds_whwQbXlPRKJh2kCKk,251
|
|
4
|
+
copyparty/authsrv.py,sha256=ccWyDpc4Pk07iRd7Zjs7GA8FDU1BXTsNQ6yj4DvXIV0,132201
|
|
5
5
|
copyparty/broker_mp.py,sha256=QdOXXvV2Xn6J0CysEqyY3GZbqxQMyWnTpnba-a5lMc0,4987
|
|
6
6
|
copyparty/broker_mpw.py,sha256=PpSS4SK3pItlpfD8OwVr3QmJEPKlUgaf2nuMOozixgU,3347
|
|
7
7
|
copyparty/broker_thr.py,sha256=fjoYtpSscUA7-nMl4r1n2R7UK3J9lrvLS3rUZ-iJzKQ,1721
|
|
8
8
|
copyparty/broker_util.py,sha256=oZ3dGdJXLYvmdV4KSFdUv_PGErkgU-7kgr1SIglkjCU,1663
|
|
9
9
|
copyparty/cert.py,sha256=OGTUBxhqPbseG0Bd4cHD6e5T5T8JdGqp3q0KAYqX0Cc,8031
|
|
10
|
-
copyparty/cfg.py,sha256=
|
|
10
|
+
copyparty/cfg.py,sha256=xIZH90TbOb9AnTOfx_v-cx6ONQce_TL9tKp9srNxx2g,16455
|
|
11
11
|
copyparty/dxml.py,sha256=VZADJS9z18LalENSvVfjk29ddnpaDQ-v8AVm_THwS1c,2607
|
|
12
12
|
copyparty/fsutil.py,sha256=NC_CJC4TDag399vVDH9_uQfdfpTMwRFLNxERSWhlVvs,4594
|
|
13
|
-
copyparty/ftpd.py,sha256=
|
|
14
|
-
copyparty/httpcli.py,sha256=
|
|
13
|
+
copyparty/ftpd.py,sha256=XtHvgtZPSMm0YMTCeKrElb8ZeIceHWskM16B3HyRXjQ,18264
|
|
14
|
+
copyparty/httpcli.py,sha256=K-qyKwk9QChYTwqHcGFqugbCRni4YfswWT4yopk0Yf4,240218
|
|
15
15
|
copyparty/httpconn.py,sha256=IA9fdCjigawZ4kWhgvVN3nSiy5pb3W2qaE6rFqUYdq0,6943
|
|
16
16
|
copyparty/httpsrv.py,sha256=tza1m3Ob8A_iPjJBRoh9O_8ruAM7l3bJ905GsHsVf2A,19039
|
|
17
17
|
copyparty/ico.py,sha256=-7QjF_jIxnPo4Vr0oUPksQ_U_Ef0HRsSPm3s71idOz8,3879
|
|
18
|
-
copyparty/mdns.py,sha256=
|
|
18
|
+
copyparty/mdns.py,sha256=u0G1ho1Pqks5dtgsyn3qctgRhGHk3ufQ3Y8HJ2l4Nhk,18422
|
|
19
19
|
copyparty/metrics.py,sha256=1dim0ShnsD5cfspRbeN9Mt14wOIxPRtxCZY2IScikKw,8974
|
|
20
|
-
copyparty/mtag.py,sha256=
|
|
20
|
+
copyparty/mtag.py,sha256=fz0QXGc4F63iormFLkFCDtpSNmo6aDX5DmtkHBbovow,22803
|
|
21
21
|
copyparty/multicast.py,sha256=xjCBHbbFI7XEohXxgBCAeExkzXJede6TLc5oR7ov5vM,12322
|
|
22
22
|
copyparty/pwhash.py,sha256=58txP8GXIHOtWd__Tni8qkilHEGpOFsKIPuzjdFLc6M,4426
|
|
23
23
|
copyparty/smbd.py,sha256=1iLbJMwG84EswYOe2irTc-CSJkzkM3Tq4cuqRFJDHII,14671
|
|
24
24
|
copyparty/ssdp.py,sha256=R1Z61GZOxBMF2Sk4RTxKWMOemogmcjEWG-CvLihd45k,7023
|
|
25
25
|
copyparty/star.py,sha256=tV5BbX6AiQ7N4UU8DYtSTckNYeoeey4DBqq4LjfymbY,3818
|
|
26
26
|
copyparty/sutil.py,sha256=E65jAaOzHlJYnqsOKDMPVT8kALPUVexpkSStWBdItkY,3231
|
|
27
|
-
copyparty/svchub.py,sha256=
|
|
27
|
+
copyparty/svchub.py,sha256=PTExaPzyztOHsMamPp-HNH8JKLdd4QSORNEov5KuPrA,54171
|
|
28
28
|
copyparty/szip.py,sha256=9srQzjsTBrBadf6QMh4YRAL70rkZLevAOHqXWK5jvr8,8846
|
|
29
29
|
copyparty/tcpsrv.py,sha256=v3L4vpNwLC-gZjXEdeyS2QyCujYjnGz8FnGfnRKIZzI,22099
|
|
30
30
|
copyparty/tftpd.py,sha256=fXW0w2_fSbzKVQGTLgr4DbtxaIEfwB591bl0pYhwy6k,14272
|
|
31
31
|
copyparty/th_cli.py,sha256=n3MMbnN7HTVSBHkTI2qLIjgwVvHkGsfTW7-aPJ-2o4s,5545
|
|
32
32
|
copyparty/th_srv.py,sha256=iAWBHgtAaYAshXdCFrUx7IWq4y3NXrH79yzHChsy2dc,38335
|
|
33
|
-
copyparty/u2idx.py,sha256=
|
|
34
|
-
copyparty/up2k.py,sha256=
|
|
35
|
-
copyparty/util.py,sha256=
|
|
33
|
+
copyparty/u2idx.py,sha256=YiacETpyncxHcyzhu3ltujovdLV7PPC7pZ3Tkwtwoj8,14437
|
|
34
|
+
copyparty/up2k.py,sha256=__FwjSxXh1r8IywPqHU4118FCqZ_BQMuHGtuaZ_UnlQ,182779
|
|
35
|
+
copyparty/util.py,sha256=g4eCa23uoz7rVPEOj6dAyuYZ3xwVIHv7AUUmYvtqvW4,109002
|
|
36
36
|
copyparty/bos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
37
|
copyparty/bos/bos.py,sha256=aGnph4sLIXe7-SFLo5qo1V67Ab1ZtgiUNbAN8EnHvkA,3371
|
|
38
38
|
copyparty/bos/path.py,sha256=yEjCq2ki9CvxA5sCT8pS0keEXwugs0ZeUyUhdBziOCI,777
|
|
@@ -54,60 +54,60 @@ copyparty/stolen/ifaddr/__init__.py,sha256=vpREjAyPubr5s1NJi91icXV3q1o4DrKAvHABw
|
|
|
54
54
|
copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUuTOrU,2626
|
|
55
55
|
copyparty/stolen/ifaddr/_shared.py,sha256=uNC4SdEIgdSLKvuUzsf1aM-H1Xrc_9mpLoOT43YukGs,6206
|
|
56
56
|
copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
|
|
57
|
-
copyparty/web/baguettebox.js.gz,sha256=
|
|
58
|
-
copyparty/web/browser.css.gz,sha256=
|
|
57
|
+
copyparty/web/baguettebox.js.gz,sha256=IXzu3LvbDUX1XXxtN88YHPaxIoJQEN6fo3Mx9T1mgdI,8365
|
|
58
|
+
copyparty/web/browser.css.gz,sha256=NQJZWuyE2umXFakMrqE0Q0sVq55rORGdw_wA5PRz67o,15703
|
|
59
59
|
copyparty/web/browser.html,sha256=DrhMtj-FUjDM0jYhQnsOkVMc8U0bFY_6uGMIY1HB9po,4791
|
|
60
|
-
copyparty/web/browser.js.gz,sha256=
|
|
60
|
+
copyparty/web/browser.js.gz,sha256=tmGsp1xEJwM6o9ajSeIaZjQxc9FaLZUikAzM-HFe_Jk,315342
|
|
61
61
|
copyparty/web/browser2.html,sha256=NRUZ08GH-e2YcGXcoz0UjYg6JIVF42u4IMX4HHwWTmg,1587
|
|
62
62
|
copyparty/web/cf.html,sha256=lJThtNFNAQT1ClCHHlivAkDGE0LutedwopXD62Z8Nys,589
|
|
63
|
-
copyparty/web/dbg-audio.js.gz,sha256=
|
|
63
|
+
copyparty/web/dbg-audio.js.gz,sha256=fNf4wGVGdz5fDtn-97ks3XPIglTKnTKiYo4Dk2m-NoA,688
|
|
64
64
|
copyparty/web/idp.html,sha256=z7nHFqfhOVYKRpST6o7IRp1Jt_xnImKYCYCub5IMmiM,1486
|
|
65
|
-
copyparty/web/md.css.gz,sha256=
|
|
65
|
+
copyparty/web/md.css.gz,sha256=z6S4rOq2ImiSOBW43MrBXEuy-4FpkE2MFDGvbn-P-y0,2032
|
|
66
66
|
copyparty/web/md.html,sha256=idHQhV8TYB0bWi9aBVoXGsySaQPlXZSvyFW6OSw-n18,4206
|
|
67
|
-
copyparty/web/md.js.gz,sha256=
|
|
68
|
-
copyparty/web/md2.css.gz,sha256=
|
|
69
|
-
copyparty/web/md2.js.gz,sha256=
|
|
70
|
-
copyparty/web/mde.css.gz,sha256=
|
|
67
|
+
copyparty/web/md.js.gz,sha256=ZCFPnMU0dOerxO0ccUzTtDjL5_1u9jRIGZ7NoLC3q4E,4180
|
|
68
|
+
copyparty/web/md2.css.gz,sha256=KycVC-vV0hAOaq1OD2YiS7y8mXYgucT8tCtynW0SfIA,699
|
|
69
|
+
copyparty/web/md2.js.gz,sha256=SfusONhUhLmSX7LSFZIyQag4H3_LhxqiyoVLwqmEqAE,8465
|
|
70
|
+
copyparty/web/mde.css.gz,sha256=cXTemEFV2boL6xhRQuVVV39CaNdIynDDJTtEDzfkOXE,942
|
|
71
71
|
copyparty/web/mde.html,sha256=o9iRxSSxFlwHsei8zeG9hDGY0GAol-F6Hx575MyOuzI,1776
|
|
72
|
-
copyparty/web/mde.js.gz,sha256=
|
|
73
|
-
copyparty/web/msg.css.gz,sha256=
|
|
72
|
+
copyparty/web/mde.js.gz,sha256=nlDivV2PgbXjsJe_GCtknpb5nVfFjzv7gMd700v9dxE,2220
|
|
73
|
+
copyparty/web/msg.css.gz,sha256=lBx8YdzLqbqbFW8h-3gw6Daadsy83Z7EsK8TP_6oK8M,300
|
|
74
74
|
copyparty/web/msg.html,sha256=aS47IjsxXFTZZCNck2ip3IwYKrHoYNZstnNND2WweCA,978
|
|
75
|
-
copyparty/web/rups.css.gz,sha256=
|
|
75
|
+
copyparty/web/rups.css.gz,sha256=XV1nExg_g82bf-B6hiKxjQCYVr5_-YOPVSxkPR4bcCc,647
|
|
76
76
|
copyparty/web/rups.html,sha256=t7aofu0JFH2zPcYhInNytxgNJNEVycUG0QaSw0TJDZQ,1299
|
|
77
|
-
copyparty/web/rups.js.gz,sha256=
|
|
78
|
-
copyparty/web/shares.css.gz,sha256=
|
|
77
|
+
copyparty/web/rups.js.gz,sha256=oVAp1fCrnE6HERAAXvP9kDTkrBHQIMiJmQEtVY-TXM0,929
|
|
78
|
+
copyparty/web/shares.css.gz,sha256=ChgHt-2dPgvPCpwClNeijX39OWJIbwj7NBIZXLLvaT0,547
|
|
79
79
|
copyparty/web/shares.html,sha256=FDFMP5G7DL9B7g2SPBfbHtm83z-VXDMSnSWMsBhVLzk,2583
|
|
80
|
-
copyparty/web/shares.js.gz,sha256=
|
|
81
|
-
copyparty/web/splash.css.gz,sha256=
|
|
80
|
+
copyparty/web/shares.js.gz,sha256=LGgFdYhtTwBp96x6CtWZpMWrGaZW7vn5LYvIhPQqm8g,942
|
|
81
|
+
copyparty/web/splash.css.gz,sha256=NCtj8oXbSRIn5tL9RaswvzBSTzmCpAAqDtcgmgf3gXE,1100
|
|
82
82
|
copyparty/web/splash.html,sha256=6FQedU-mVZ5UEiwm-9Wq_A_UatbTf29IqN4lWtS_6n0,7463
|
|
83
|
-
copyparty/web/splash.js.gz,sha256=
|
|
83
|
+
copyparty/web/splash.js.gz,sha256=35fsbq9PAN4p67BcXzJhkupDnM6W7qn48AUGYeaFPKI,15893
|
|
84
84
|
copyparty/web/svcs.html,sha256=jILgJ2WZ9gWHFqOla1tXTPPrR7XI5vENctz4UWTx0Go,17577
|
|
85
|
-
copyparty/web/svcs.js.gz,sha256=
|
|
86
|
-
copyparty/web/ui.css.gz,sha256=
|
|
87
|
-
copyparty/web/up2k.js.gz,sha256=
|
|
88
|
-
copyparty/web/util.js.gz,sha256=
|
|
89
|
-
copyparty/web/w.hash.js.gz,sha256=
|
|
85
|
+
copyparty/web/svcs.js.gz,sha256=DapO-UcJYln4VPyZ6Pwi0Lzhlyx0Hul7y7E2ephu34c,971
|
|
86
|
+
copyparty/web/ui.css.gz,sha256=Txx36dDbFI7_9I2LPUO40nCFnxLFKVpdkBsHFwI7JoE,2848
|
|
87
|
+
copyparty/web/up2k.js.gz,sha256=PzZR6mqB796ETr_EZVob0XZOrNZLo8GN3E8TYW3q7TY,25033
|
|
88
|
+
copyparty/web/util.js.gz,sha256=CWy_7OGcsMo4RvQE21A4UF3BIP9hRJFXPAYTGjZOX2k,15571
|
|
89
|
+
copyparty/web/w.hash.js.gz,sha256=rI-78PyXCdVjOpULbD9raBRyxxaPls5OjR7wonzXZPE,1193
|
|
90
90
|
copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
91
91
|
copyparty/web/a/partyfuse.py,sha256=QxBoe0iu4LTedmxWdIsuBUlwdxQ7zQh9LAFtjAFcPpo,28206
|
|
92
92
|
copyparty/web/a/u2c.py,sha256=F78m5b7EPODJd1LgsAxWrwj3v_4z1hGsU53UKy-wCYA,53378
|
|
93
93
|
copyparty/web/a/webdav-cfg.bat,sha256=Y4NoGZlksAIg4cBMb7KdJrpKC6Nx97onaTl6yMjaimk,1449
|
|
94
94
|
copyparty/web/deps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
95
|
-
copyparty/web/deps/busy.mp3.gz,sha256=
|
|
96
|
-
copyparty/web/deps/easymde.css.gz,sha256=
|
|
97
|
-
copyparty/web/deps/easymde.js.gz,sha256=
|
|
95
|
+
copyparty/web/deps/busy.mp3.gz,sha256=ySTZiSMbGLJLioVUzUR2eEVemZQ-ACSgawJmw7lFvms,106
|
|
96
|
+
copyparty/web/deps/easymde.css.gz,sha256=s4eN1eVggiAyuK_LZjvHPTBFizw7TRuMU8DvMwB9_aA,3053
|
|
97
|
+
copyparty/web/deps/easymde.js.gz,sha256=CDSEpsMEmYXSjRTqsWmRlcZ27pTh5GvhomvKWtiNoaM,77014
|
|
98
98
|
copyparty/web/deps/fuse.py,sha256=6j4Zy3VpQg629pwwIW77v2LJ1hy-qlyrxwhXfKl9B7I,33426
|
|
99
|
-
copyparty/web/deps/marked.js.gz,sha256=
|
|
100
|
-
copyparty/web/deps/mini-fa.css.gz,sha256=
|
|
99
|
+
copyparty/web/deps/marked.js.gz,sha256=_Wkf2QWv3ooEAx5xUhyHvMQHPnzevQ1Fy84OFFdVgt0,22704
|
|
100
|
+
copyparty/web/deps/mini-fa.css.gz,sha256=iYbmyD75m_gFaUhJBT2tk0FfMsLWZ_BArESc4nXd4tg,584
|
|
101
101
|
copyparty/web/deps/mini-fa.woff,sha256=L9DNncV2TIyvsrspMbJouvnnt7F068Hbn7YZYvN76AU,2784
|
|
102
|
-
copyparty/web/deps/prism.css.gz,sha256=
|
|
103
|
-
copyparty/web/deps/prism.js.gz,sha256=
|
|
104
|
-
copyparty/web/deps/prismd.css.gz,sha256=
|
|
105
|
-
copyparty/web/deps/scp.woff2,sha256=
|
|
106
|
-
copyparty/web/deps/sha512.ac.js.gz,sha256=
|
|
102
|
+
copyparty/web/deps/prism.css.gz,sha256=XQqg2Ii9aX391H9-ozl-UdEdj0-aGsuk7cHa6Hz6Ceo,1478
|
|
103
|
+
copyparty/web/deps/prism.js.gz,sha256=TjgEbUZ7iLayORYkmi1LMklNJ7NIZdkQWAmPuIR7EJo,41438
|
|
104
|
+
copyparty/web/deps/prismd.css.gz,sha256=VPKuZhPmVyhTKHo2xN6IBX-C2A8Eo313vIPxQ2HxoI8,1648
|
|
105
|
+
copyparty/web/deps/scp.woff2,sha256=mmjmsoLDBPKa5VHcEdxZiJcDR1S1TOvCjIg5Cf1iL0s,8684
|
|
106
|
+
copyparty/web/deps/sha512.ac.js.gz,sha256=OLk7EjA5e-DtJGlV0IQbvokpmoyE5v7djezx9kZBabE,7046
|
|
107
107
|
copyparty/web/deps/sha512.hw.js.gz,sha256=UAed2_ocklZCnIzcSYz2h4P1ycztlCLj-ewsRTud2lU,7939
|
|
108
|
-
copyparty-1.19.
|
|
109
|
-
copyparty-1.19.
|
|
110
|
-
copyparty-1.19.
|
|
111
|
-
copyparty-1.19.
|
|
112
|
-
copyparty-1.19.
|
|
113
|
-
copyparty-1.19.
|
|
108
|
+
copyparty-1.19.9.dist-info/licenses/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
|
|
109
|
+
copyparty-1.19.9.dist-info/METADATA,sha256=35gSIe2RmfYMrNXpmjA2wt-Irvbi01lJZhpg_vpJAlo,177645
|
|
110
|
+
copyparty-1.19.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
111
|
+
copyparty-1.19.9.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
|
|
112
|
+
copyparty-1.19.9.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
|
|
113
|
+
copyparty-1.19.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|