copyparty 1.19.8__py3-none-any.whl → 1.19.10__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 +26 -14
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +102 -9
- copyparty/broker_mpw.py +3 -0
- copyparty/cfg.py +4 -0
- copyparty/fsutil.py +66 -23
- copyparty/ftpd.py +3 -0
- copyparty/httpcli.py +23 -11
- copyparty/mdns.py +3 -1
- copyparty/mtag.py +2 -4
- copyparty/svchub.py +14 -2
- copyparty/u2idx.py +29 -4
- copyparty/up2k.py +20 -9
- copyparty/util.py +48 -22
- 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.10.dist-info}/METADATA +7 -3
- {copyparty-1.19.8.dist-info → copyparty-1.19.10.dist-info}/RECORD +52 -52
- {copyparty-1.19.8.dist-info → copyparty-1.19.10.dist-info}/WHEEL +0 -0
- {copyparty-1.19.8.dist-info → copyparty-1.19.10.dist-info}/entry_points.txt +0 -0
- {copyparty-1.19.8.dist-info → copyparty-1.19.10.dist-info}/licenses/LICENSE +0 -0
- {copyparty-1.19.8.dist-info → copyparty-1.19.10.dist-info}/top_level.txt +0 -0
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
|
@@ -426,9 +426,8 @@ def _get_cover_from_epub2(
|
|
|
426
426
|
) :
|
|
427
427
|
# <meta name="cover" content="id-to-cover-image"> in <metadata>, then
|
|
428
428
|
# <item> in <manifest>
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
)
|
|
429
|
+
xn = package_root.find("./metadata/meta[@name='cover']", package_ns)
|
|
430
|
+
cover_id = xn.get("content") if xn is not None else None
|
|
432
431
|
|
|
433
432
|
if not cover_id:
|
|
434
433
|
return None
|
|
@@ -504,7 +503,6 @@ class MTag(object):
|
|
|
504
503
|
"album-artist",
|
|
505
504
|
"tpe2",
|
|
506
505
|
"aart",
|
|
507
|
-
"conductor",
|
|
508
506
|
"organization",
|
|
509
507
|
"band",
|
|
510
508
|
],
|
copyparty/svchub.py
CHANGED
|
@@ -24,6 +24,7 @@ from .__init__ import ANYWIN, EXE, MACOS, PY2, TYPE_CHECKING, E, EnvParams, unic
|
|
|
24
24
|
from .authsrv import BAD_CFG, AuthSrv, n_du_who, n_ver_who
|
|
25
25
|
from .bos import bos
|
|
26
26
|
from .cert import ensure_cert
|
|
27
|
+
from .fsutil import ramdisk_chk
|
|
27
28
|
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, HAVE_MUTAGEN
|
|
28
29
|
from .pwhash import HAVE_ARGON2
|
|
29
30
|
from .tcpsrv import TcpSrv
|
|
@@ -304,6 +305,7 @@ class SvcHub(object):
|
|
|
304
305
|
|
|
305
306
|
# initiate all services to manage
|
|
306
307
|
self.asrv = AuthSrv(self.args, self.log, dargs=self.dargs)
|
|
308
|
+
ramdisk_chk(self.asrv)
|
|
307
309
|
|
|
308
310
|
if args.cgen:
|
|
309
311
|
self.asrv.cgen()
|
|
@@ -842,6 +844,10 @@ class SvcHub(object):
|
|
|
842
844
|
if w8:
|
|
843
845
|
time.sleep(w8)
|
|
844
846
|
self.log("qr-code", qr)
|
|
847
|
+
if self.args.qr_stdout:
|
|
848
|
+
self.pr(self.tcpsrv.qr)
|
|
849
|
+
if self.args.qr_stderr:
|
|
850
|
+
self.pr(self.tcpsrv.qr, file=sys.stderr)
|
|
845
851
|
w8 = self.args.qr_every
|
|
846
852
|
msg = "%s\033[%dA" % (qr, len(qr.split("\n")))
|
|
847
853
|
while w8:
|
|
@@ -875,8 +881,13 @@ class SvcHub(object):
|
|
|
875
881
|
self.sticky_qr()
|
|
876
882
|
if self.args.qr_wait or self.args.qr_every or self.args.qr_winch:
|
|
877
883
|
Daemon(self._qr_thr, "qr")
|
|
878
|
-
|
|
879
|
-
|
|
884
|
+
else:
|
|
885
|
+
if not self.args.qr_pin:
|
|
886
|
+
self.log("qr-code", self.tcpsrv.qr)
|
|
887
|
+
if self.args.qr_stdout:
|
|
888
|
+
self.pr(self.tcpsrv.qr)
|
|
889
|
+
if self.args.qr_stderr:
|
|
890
|
+
self.pr(self.tcpsrv.qr, file=sys.stderr)
|
|
880
891
|
else:
|
|
881
892
|
self.log("root", "workers OK\n")
|
|
882
893
|
|
|
@@ -1340,6 +1351,7 @@ class SvcHub(object):
|
|
|
1340
1351
|
with self.reload_mutex:
|
|
1341
1352
|
self.log("root", "reloading config")
|
|
1342
1353
|
self.asrv.reload(9 if up2k else 4)
|
|
1354
|
+
ramdisk_chk(self.asrv)
|
|
1343
1355
|
if up2k:
|
|
1344
1356
|
self.up2k.reload(rescan_all_vols)
|
|
1345
1357
|
t += "; volumes are now reinitializing"
|
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,
|
|
@@ -208,7 +209,7 @@ class Up2k(object):
|
|
|
208
209
|
t = "could not initialize sqlite3, will use in-memory registry only"
|
|
209
210
|
self.log(t, 3)
|
|
210
211
|
|
|
211
|
-
self.fstab = Fstab(self.log_func, self.args)
|
|
212
|
+
self.fstab = Fstab(self.log_func, self.args, True)
|
|
212
213
|
self.gen_fk = self._gen_fk if self.args.log_fk else gen_filekey
|
|
213
214
|
|
|
214
215
|
if self.args.hash_mt < 2:
|
|
@@ -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())
|
|
@@ -1490,6 +1491,7 @@ class Up2k(object):
|
|
|
1490
1491
|
|
|
1491
1492
|
th_cvd = self.args.th_coversd
|
|
1492
1493
|
th_cvds = self.args.th_coversd_set
|
|
1494
|
+
scan_pr_s = self.args.scan_pr_s
|
|
1493
1495
|
|
|
1494
1496
|
self.pp.msg = "a%d %s" % (self.pp.n, cdir)
|
|
1495
1497
|
|
|
@@ -1701,7 +1703,7 @@ class Up2k(object):
|
|
|
1701
1703
|
if nohash or not sz:
|
|
1702
1704
|
wark = up2k_wark_from_metadata(self.salt, sz, lmod, rd, fn)
|
|
1703
1705
|
else:
|
|
1704
|
-
if sz > 1024 * 1024:
|
|
1706
|
+
if sz > 1024 * 1024 * scan_pr_s:
|
|
1705
1707
|
self.log("file: %r" % (abspath,))
|
|
1706
1708
|
|
|
1707
1709
|
try:
|
|
@@ -2753,7 +2755,7 @@ class Up2k(object):
|
|
|
2753
2755
|
cur.close()
|
|
2754
2756
|
db.close()
|
|
2755
2757
|
|
|
2756
|
-
|
|
2758
|
+
trystat_shutil_copy2(self.log, fsenc(db_path), fsenc(bak))
|
|
2757
2759
|
return self._orz(db_path)
|
|
2758
2760
|
|
|
2759
2761
|
def _read_ver(self, cur ) :
|
|
@@ -2990,7 +2992,7 @@ class Up2k(object):
|
|
|
2990
2992
|
|
|
2991
2993
|
# check if filesystem supports sparse files;
|
|
2992
2994
|
# refuse out-of-order / multithreaded uploading if sprs False
|
|
2993
|
-
sprs = self.fstab.get(pdir) != "ng"
|
|
2995
|
+
sprs = self.fstab.get(pdir)[0] != "ng"
|
|
2994
2996
|
|
|
2995
2997
|
if True:
|
|
2996
2998
|
jcur = self.cur.get(ptop)
|
|
@@ -3575,7 +3577,7 @@ class Up2k(object):
|
|
|
3575
3577
|
t = "BUG: no valid sources to link from! orig(%r) fsrc(%r) link(%r)"
|
|
3576
3578
|
self.log(t, 1)
|
|
3577
3579
|
raise Exception(t % (src, fsrc, dst))
|
|
3578
|
-
|
|
3580
|
+
trystat_shutil_copy2(self.log, fsenc(csrc), fsenc(dst))
|
|
3579
3581
|
|
|
3580
3582
|
if lmod and (not linked or SYMTIME):
|
|
3581
3583
|
bos.utime_c(self.log, dst, int(lmod), False)
|
|
@@ -4124,6 +4126,9 @@ class Up2k(object):
|
|
|
4124
4126
|
except:
|
|
4125
4127
|
raise Pebkac(400, "file not found on disk (already deleted?)")
|
|
4126
4128
|
|
|
4129
|
+
if "bcasechk" in vn.flags and not vn.casechk(rem, False):
|
|
4130
|
+
raise Pebkac(400, "file does not exist case-sensitively")
|
|
4131
|
+
|
|
4127
4132
|
scandir = not self.args.no_scandir
|
|
4128
4133
|
if is_dir:
|
|
4129
4134
|
# note: deletion inside shares would require a rewrite here;
|
|
@@ -4248,6 +4253,9 @@ class Up2k(object):
|
|
|
4248
4253
|
self.db_act = self.vol_act[svn_dbv.realpath] = time.time()
|
|
4249
4254
|
|
|
4250
4255
|
st = bos.stat(sabs)
|
|
4256
|
+
if "bcasechk" in svn.flags and not svn.casechk(srem, False):
|
|
4257
|
+
raise Pebkac(400, "file does not exist case-sensitively")
|
|
4258
|
+
|
|
4251
4259
|
if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
|
|
4252
4260
|
with self.mutex:
|
|
4253
4261
|
try:
|
|
@@ -4405,7 +4413,7 @@ class Up2k(object):
|
|
|
4405
4413
|
b1, b2 = fsenc(sabs), fsenc(dabs)
|
|
4406
4414
|
is_link = os.path.islink(b1) # due to _relink
|
|
4407
4415
|
try:
|
|
4408
|
-
|
|
4416
|
+
trystat_shutil_copy2(self.log, b1, b2)
|
|
4409
4417
|
except:
|
|
4410
4418
|
try:
|
|
4411
4419
|
wunlink(self.log, dabs, dvn.flags)
|
|
@@ -4465,6 +4473,9 @@ class Up2k(object):
|
|
|
4465
4473
|
raise Pebkac(400, "mv: cannot move a mountpoint")
|
|
4466
4474
|
|
|
4467
4475
|
st = bos.lstat(sabs)
|
|
4476
|
+
if "bcasechk" in svn.flags and not svn.casechk(srem, False):
|
|
4477
|
+
raise Pebkac(400, "file does not exist case-sensitively")
|
|
4478
|
+
|
|
4468
4479
|
if stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode):
|
|
4469
4480
|
with self.mutex:
|
|
4470
4481
|
try:
|
|
@@ -4710,7 +4721,7 @@ class Up2k(object):
|
|
|
4710
4721
|
b1, b2 = fsenc(sabs), fsenc(dabs)
|
|
4711
4722
|
is_link = os.path.islink(b1) # due to _relink
|
|
4712
4723
|
try:
|
|
4713
|
-
|
|
4724
|
+
trystat_shutil_copy2(self.log, b1, b2)
|
|
4714
4725
|
except:
|
|
4715
4726
|
try:
|
|
4716
4727
|
wunlink(self.log, dabs, dvn.flags)
|
|
@@ -5145,7 +5156,7 @@ class Up2k(object):
|
|
|
5145
5156
|
sprs = False
|
|
5146
5157
|
|
|
5147
5158
|
if not ANYWIN and sprs and sz > 1024 * 1024:
|
|
5148
|
-
fs = self.fstab.get(pdir)
|
|
5159
|
+
fs, mnt = self.fstab.get(pdir)
|
|
5149
5160
|
if fs == "ok":
|
|
5150
5161
|
pass
|
|
5151
5162
|
elif "nosparse" in vf:
|
copyparty/util.py
CHANGED
|
@@ -525,6 +525,8 @@ def py_desc() :
|
|
|
525
525
|
ofs = py_ver.find(".final.")
|
|
526
526
|
if ofs > 0:
|
|
527
527
|
py_ver = py_ver[:ofs]
|
|
528
|
+
if "free-threading" in sys.version:
|
|
529
|
+
py_ver += "t"
|
|
528
530
|
|
|
529
531
|
host_os = platform.system()
|
|
530
532
|
compiler = platform.python_compiler().split("http")[0]
|
|
@@ -1040,16 +1042,18 @@ class ProgressPrinter(threading.Thread):
|
|
|
1040
1042
|
sigblock()
|
|
1041
1043
|
tp = 0
|
|
1042
1044
|
msg = None
|
|
1043
|
-
|
|
1045
|
+
slp_pr = self.args.scan_pr_r
|
|
1046
|
+
slp_ps = min(slp_pr, self.args.scan_st_r)
|
|
1047
|
+
no_stdout = self.args.q or slp_pr == slp_ps
|
|
1044
1048
|
fmt = " {}\033[K\r" if VT100 else " {} $\r"
|
|
1045
1049
|
while not self.end:
|
|
1046
|
-
time.sleep(
|
|
1050
|
+
time.sleep(slp_ps)
|
|
1047
1051
|
if msg == self.msg or self.end:
|
|
1048
1052
|
continue
|
|
1049
1053
|
|
|
1050
1054
|
msg = self.msg
|
|
1051
1055
|
now = time.time()
|
|
1052
|
-
if msg and now - tp
|
|
1056
|
+
if msg and now - tp >= slp_pr:
|
|
1053
1057
|
tp = now
|
|
1054
1058
|
self.log("progress: %r" % (msg,), 6)
|
|
1055
1059
|
|
|
@@ -1495,10 +1499,12 @@ def vol_san(vols , txt ) :
|
|
|
1495
1499
|
bvp = vol.vpath.encode("utf-8")
|
|
1496
1500
|
bvph = b"$hist(/" + bvp + b")"
|
|
1497
1501
|
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
+
if bap:
|
|
1503
|
+
txt = txt.replace(bap, bvp)
|
|
1504
|
+
txt = txt.replace(bap.replace(b"\\", b"\\\\"), bvp)
|
|
1505
|
+
if bhp:
|
|
1506
|
+
txt = txt.replace(bhp, bvph)
|
|
1507
|
+
txt = txt.replace(bhp.replace(b"\\", b"\\\\"), bvph)
|
|
1502
1508
|
|
|
1503
1509
|
if vol.histpath != vol.dbpath:
|
|
1504
1510
|
bdp = vol.dbpath.encode("utf-8")
|
|
@@ -2174,14 +2180,14 @@ def odfusion(
|
|
|
2174
2180
|
ret = base.copy()
|
|
2175
2181
|
if oth.startswith("+"):
|
|
2176
2182
|
for k in words1:
|
|
2177
|
-
ret[k] = True
|
|
2183
|
+
ret[k] = True # type: ignore
|
|
2178
2184
|
elif oth[:1] in ("-", "/"):
|
|
2179
2185
|
for k in words1:
|
|
2180
|
-
ret.pop(k, None)
|
|
2186
|
+
ret.pop(k, None) # type: ignore
|
|
2181
2187
|
else:
|
|
2182
2188
|
ret = ODict.fromkeys(words0, True)
|
|
2183
2189
|
|
|
2184
|
-
return ret
|
|
2190
|
+
return ret # type: ignore
|
|
2185
2191
|
|
|
2186
2192
|
|
|
2187
2193
|
def ipnorm(ip ) :
|
|
@@ -2553,6 +2559,24 @@ def set_fperms(f , vf ) :
|
|
|
2553
2559
|
os.fchown(fno, vf["uid"], vf["gid"])
|
|
2554
2560
|
|
|
2555
2561
|
|
|
2562
|
+
def trystat_shutil_copy2(log , src , dst ) :
|
|
2563
|
+
try:
|
|
2564
|
+
return shutil.copy2(src, dst)
|
|
2565
|
+
except:
|
|
2566
|
+
# ignore failed mtime on linux+ntfs; for example:
|
|
2567
|
+
# shutil.py:437 <copy2>: copystat(src, dst, follow_symlinks=follow_symlinks)
|
|
2568
|
+
# shutil.py:376 <copystat>: lookup("utime")(dst, ns=(st.st_atime_ns, st.st_mtime_ns),
|
|
2569
|
+
# [PermissionError] [Errno 1] Operation not permitted, '/windows/_videos'
|
|
2570
|
+
_, _, tb = sys.exc_info()
|
|
2571
|
+
for _, _, fun, _ in traceback.extract_tb(tb):
|
|
2572
|
+
if fun == "copystat":
|
|
2573
|
+
if log:
|
|
2574
|
+
t = "warning: failed to retain some file attributes (timestamp and/or permissions) during copy from %r to %r:\n%s"
|
|
2575
|
+
log(t % (src, dst, min_ex()), 3)
|
|
2576
|
+
return dst # close enough
|
|
2577
|
+
raise
|
|
2578
|
+
|
|
2579
|
+
|
|
2556
2580
|
def _fs_mvrm(
|
|
2557
2581
|
log , src , dst , atomic , flags
|
|
2558
2582
|
) :
|
|
@@ -2591,7 +2615,7 @@ def _fs_mvrm(
|
|
|
2591
2615
|
t = "something appeared at dst; aborting rename %r ==> %r"
|
|
2592
2616
|
log(t % (src, dst), 1)
|
|
2593
2617
|
return False
|
|
2594
|
-
osfun(*args)
|
|
2618
|
+
osfun(*args) # type: ignore
|
|
2595
2619
|
if attempt:
|
|
2596
2620
|
now = time.time()
|
|
2597
2621
|
t = "%sd in %.2f sec, attempt %d: %r"
|
|
@@ -2641,7 +2665,7 @@ def atomic_move(log , src , dst , flags ) :
|
|
|
2641
2665
|
os.unlink(bdst)
|
|
2642
2666
|
except:
|
|
2643
2667
|
pass
|
|
2644
|
-
shutil.move(bsrc, bdst)
|
|
2668
|
+
shutil.move(bsrc, bdst) # type: ignore
|
|
2645
2669
|
|
|
2646
2670
|
|
|
2647
2671
|
def wunlink(log , abspath , flags ) :
|
|
@@ -3046,7 +3070,7 @@ def sendfile_kern(
|
|
|
3046
3070
|
try:
|
|
3047
3071
|
req = min(0x2000000, upper - ofs) # 32 MiB
|
|
3048
3072
|
if use_poll:
|
|
3049
|
-
poll.poll(10000)
|
|
3073
|
+
poll.poll(10000) # type: ignore
|
|
3050
3074
|
else:
|
|
3051
3075
|
select.select([], [out_fd], [], 10)
|
|
3052
3076
|
n = os.sendfile(out_fd, in_fd, ofs, req)
|
|
@@ -3334,7 +3358,9 @@ NICEB = NICES.encode("utf-8")
|
|
|
3334
3358
|
|
|
3335
3359
|
|
|
3336
3360
|
def runcmd(
|
|
3337
|
-
argv
|
|
3361
|
+
argv ,
|
|
3362
|
+
timeout = None,
|
|
3363
|
+
**ka
|
|
3338
3364
|
) :
|
|
3339
3365
|
isbytes = isinstance(argv[0], (bytes, bytearray))
|
|
3340
3366
|
oom = ka.pop("oom", 0) # 0..1000
|
|
@@ -3353,19 +3379,19 @@ def runcmd(
|
|
|
3353
3379
|
if ANYWIN:
|
|
3354
3380
|
if isbytes:
|
|
3355
3381
|
if argv[0] in CMD_EXEB:
|
|
3356
|
-
argv[0] += b".exe"
|
|
3382
|
+
argv[0] += b".exe" # type: ignore
|
|
3357
3383
|
else:
|
|
3358
3384
|
if argv[0] in CMD_EXES:
|
|
3359
|
-
argv[0] += ".exe"
|
|
3385
|
+
argv[0] += ".exe" # type: ignore
|
|
3360
3386
|
|
|
3361
3387
|
if ka.pop("nice", None):
|
|
3362
3388
|
if WINDOWS:
|
|
3363
3389
|
ka["creationflags"] = 0x4000
|
|
3364
3390
|
elif NICEB:
|
|
3365
3391
|
if isbytes:
|
|
3366
|
-
argv = [NICEB] + argv
|
|
3392
|
+
argv = [NICEB] + argv # type: ignore
|
|
3367
3393
|
else:
|
|
3368
|
-
argv = [NICES] + argv
|
|
3394
|
+
argv = [NICES] + argv # type: ignore
|
|
3369
3395
|
|
|
3370
3396
|
p = sp.Popen(argv, stdout=cout, stderr=cerr, **ka)
|
|
3371
3397
|
|
|
@@ -3377,10 +3403,10 @@ def runcmd(
|
|
|
3377
3403
|
pass
|
|
3378
3404
|
|
|
3379
3405
|
if not timeout or PY2:
|
|
3380
|
-
bout, berr = p.communicate(sin)
|
|
3406
|
+
bout, berr = p.communicate(sin) # type: ignore
|
|
3381
3407
|
else:
|
|
3382
3408
|
try:
|
|
3383
|
-
bout, berr = p.communicate(sin, timeout=timeout)
|
|
3409
|
+
bout, berr = p.communicate(sin, timeout=timeout) # type: ignore
|
|
3384
3410
|
except sp.TimeoutExpired:
|
|
3385
3411
|
if kill == "n":
|
|
3386
3412
|
return -18, "", "" # SIGCONT; leave it be
|
|
@@ -3390,7 +3416,7 @@ def runcmd(
|
|
|
3390
3416
|
killtree(p.pid)
|
|
3391
3417
|
|
|
3392
3418
|
try:
|
|
3393
|
-
bout, berr = p.communicate(timeout=1)
|
|
3419
|
+
bout, berr = p.communicate(timeout=1) # type: ignore
|
|
3394
3420
|
except:
|
|
3395
3421
|
bout = b""
|
|
3396
3422
|
berr = b""
|
|
@@ -3812,7 +3838,7 @@ def runhook(
|
|
|
3812
3838
|
at ,
|
|
3813
3839
|
txt ,
|
|
3814
3840
|
) :
|
|
3815
|
-
args = (broker or up2k).args
|
|
3841
|
+
args = (broker or up2k).args # type: ignore
|
|
3816
3842
|
verbose = args.hook_v
|
|
3817
3843
|
vp = vp.replace("\\", "/")
|
|
3818
3844
|
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
|