copyparty 1.19.6__py3-none-any.whl → 1.19.8__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/__init__.py +2 -0
- copyparty/__main__.py +48 -19
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +96 -8
- copyparty/bos/bos.py +38 -2
- copyparty/cfg.py +4 -0
- copyparty/ftpd.py +4 -25
- copyparty/httpcli.py +62 -24
- copyparty/httpsrv.py +1 -1
- copyparty/smbd.py +1 -1
- copyparty/svchub.py +27 -1
- copyparty/tcpsrv.py +4 -0
- copyparty/up2k.py +49 -25
- copyparty/util.py +8 -5
- copyparty/web/a/partyfuse.py +19 -11
- copyparty/web/a/u2c.py +6 -4
- copyparty/web/baguettebox.js.gz +0 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.html +1 -1
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/idp.html +5 -5
- copyparty/web/md.html +1 -1
- copyparty/web/md.js.gz +0 -0
- copyparty/web/md2.js.gz +0 -0
- copyparty/web/mde.html +1 -1
- copyparty/web/msg.html +1 -1
- copyparty/web/rups.html +1 -1
- copyparty/web/shares.html +5 -5
- copyparty/web/splash.css.gz +0 -0
- copyparty/web/splash.html +54 -38
- copyparty/web/splash.js.gz +0 -0
- copyparty/web/svcs.html +80 -39
- copyparty/web/svcs.js.gz +0 -0
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.19.6.dist-info → copyparty-1.19.8.dist-info}/METADATA +8 -1
- {copyparty-1.19.6.dist-info → copyparty-1.19.8.dist-info}/RECORD +41 -41
- {copyparty-1.19.6.dist-info → copyparty-1.19.8.dist-info}/WHEEL +0 -0
- {copyparty-1.19.6.dist-info → copyparty-1.19.8.dist-info}/entry_points.txt +0 -0
- {copyparty-1.19.6.dist-info → copyparty-1.19.8.dist-info}/licenses/LICENSE +0 -0
- {copyparty-1.19.6.dist-info → copyparty-1.19.8.dist-info}/top_level.txt +0 -0
copyparty/httpcli.py
CHANGED
@@ -562,7 +562,7 @@ class HttpCli(object):
|
|
562
562
|
return False
|
563
563
|
zsll = [x.split("=", 1) for x in zso.split(";") if "=" in x]
|
564
564
|
cookies = {k.strip(): unescape_cookie(zs) for k, zs in zsll}
|
565
|
-
cookie_pw = cookies.get("cppws"
|
565
|
+
cookie_pw = cookies.get("cppws" if self.is_https else "cppwd") or ""
|
566
566
|
if "b" in cookies and "b" not in uparam:
|
567
567
|
uparam["b"] = cookies["b"]
|
568
568
|
if len(cookies) > self.args.cookie_nmax:
|
@@ -685,7 +685,7 @@ class HttpCli(object):
|
|
685
685
|
if idp_usr in self.asrv.vfs.aread:
|
686
686
|
self.pw = ""
|
687
687
|
self.uname = idp_usr
|
688
|
-
if self.args.ao_have_pw:
|
688
|
+
if self.args.ao_have_pw or self.args.idp_logout:
|
689
689
|
self.html_head += "<script>var is_idp=1</script>\n"
|
690
690
|
else:
|
691
691
|
self.html_head += "<script>var is_idp=2</script>\n"
|
@@ -1250,7 +1250,7 @@ class HttpCli(object):
|
|
1250
1250
|
|
1251
1251
|
res_path = "web/" + self.vpath[5:]
|
1252
1252
|
if res_path in RES:
|
1253
|
-
ap =
|
1253
|
+
ap = self.E.mod_ + res_path
|
1254
1254
|
if bos.path.exists(ap) or bos.path.exists(ap + ".gz"):
|
1255
1255
|
return self.tx_file(ap)
|
1256
1256
|
else:
|
@@ -1627,7 +1627,14 @@ class HttpCli(object):
|
|
1627
1627
|
self.log("inaccessible: %r" % ("/" + self.vpath,))
|
1628
1628
|
raise Pebkac(401, "authenticate")
|
1629
1629
|
|
1630
|
-
if "quota-available-bytes" in props
|
1630
|
+
zi = vn.flags["du_iwho"] if "quota-available-bytes" in props else 0
|
1631
|
+
if zi and (
|
1632
|
+
zi == 9
|
1633
|
+
or (zi == 7 and self.uname != "*")
|
1634
|
+
or (zi == 5 and self.can_write)
|
1635
|
+
or (zi == 4 and self.can_write and self.can_read)
|
1636
|
+
or (zi == 3 and self.can_admin)
|
1637
|
+
):
|
1631
1638
|
bfree, btot, _ = get_df(vn.realpath, False)
|
1632
1639
|
if btot:
|
1633
1640
|
df = {
|
@@ -2319,12 +2326,7 @@ class HttpCli(object):
|
|
2319
2326
|
at = mt = time.time() - lifetime
|
2320
2327
|
cli_mt = self.headers.get("x-oc-mtime")
|
2321
2328
|
if cli_mt:
|
2322
|
-
|
2323
|
-
mt = int(cli_mt)
|
2324
|
-
times = (int(time.time()), mt)
|
2325
|
-
bos.utime(path, times, False)
|
2326
|
-
except:
|
2327
|
-
pass
|
2329
|
+
bos.utime_c(self.log, path, int(cli_mt), False)
|
2328
2330
|
|
2329
2331
|
if nameless and "magic" in vfs.flags:
|
2330
2332
|
try:
|
@@ -3042,7 +3044,7 @@ class HttpCli(object):
|
|
3042
3044
|
self.asrv.forget_session(self.conn.hsrv.broker, self.uname)
|
3043
3045
|
self.get_pwd_cookie("x")
|
3044
3046
|
|
3045
|
-
dst = self.args.SRS + "?h"
|
3047
|
+
dst = self.args.idp_logout or (self.args.SRS + "?h")
|
3046
3048
|
h2 = '<a href="' + dst + '">continue</a>'
|
3047
3049
|
html = self.j2s("msg", h1="ok bye", h2=h2, redir=dst)
|
3048
3050
|
self.reply(html.encode("utf-8"))
|
@@ -3055,6 +3057,11 @@ class HttpCli(object):
|
|
3055
3057
|
uname = self.asrv.iacct.get(hpwd)
|
3056
3058
|
if uname:
|
3057
3059
|
pwd = self.asrv.ases.get(uname) or pwd
|
3060
|
+
if uname and self.conn.hsrv.ipr:
|
3061
|
+
znm = self.conn.hsrv.ipr.get(uname)
|
3062
|
+
if znm and not znm.map(self.ip):
|
3063
|
+
self.log("username [%s] rejected by --ipr" % (self.uname,), 3)
|
3064
|
+
uname = ""
|
3058
3065
|
if uname:
|
3059
3066
|
msg = "hi " + uname
|
3060
3067
|
dur = int(60 * 60 * self.args.logout)
|
@@ -4995,10 +5002,20 @@ class HttpCli(object):
|
|
4995
5002
|
else:
|
4996
5003
|
rip = host
|
4997
5004
|
|
5005
|
+
defpw = "dave:hunter2" if self.args.usernames else "hunter2"
|
5006
|
+
|
4998
5007
|
vp = (self.uparam["hc"] or "").lstrip("/")
|
4999
|
-
pw = self.ouparam.get("pw") or
|
5008
|
+
pw = self.ouparam.get("pw") or defpw
|
5000
5009
|
if pw in self.asrv.sesa:
|
5001
|
-
pw =
|
5010
|
+
pw = defpw
|
5011
|
+
|
5012
|
+
unpw = pw
|
5013
|
+
try:
|
5014
|
+
un, pw = unpw.split(":")
|
5015
|
+
except:
|
5016
|
+
un = ""
|
5017
|
+
if self.args.usernames:
|
5018
|
+
un = "dave"
|
5002
5019
|
|
5003
5020
|
html = self.j2s(
|
5004
5021
|
"svcs",
|
@@ -5012,7 +5029,10 @@ class HttpCli(object):
|
|
5012
5029
|
host=html_sh_esc(host),
|
5013
5030
|
hport=html_sh_esc(hport),
|
5014
5031
|
aname=aname,
|
5032
|
+
b_un=("<b>%s</b>" % (html_sh_esc(un),)) if un else "k",
|
5033
|
+
un=html_sh_esc(un),
|
5015
5034
|
pw=html_sh_esc(pw),
|
5035
|
+
unpw=html_sh_esc(unpw),
|
5016
5036
|
)
|
5017
5037
|
self.reply(html.encode("utf-8"))
|
5018
5038
|
return True
|
@@ -5136,6 +5156,11 @@ class HttpCli(object):
|
|
5136
5156
|
elif nre:
|
5137
5157
|
re_btn = "&re=%s" % (nre,)
|
5138
5158
|
|
5159
|
+
zi = self.args.ver_iwho
|
5160
|
+
show_ver = zi and (
|
5161
|
+
zi == 9 or (zi == 6 and self.uname != "*") or (zi == 3 and avol)
|
5162
|
+
)
|
5163
|
+
|
5139
5164
|
html = self.j2s(
|
5140
5165
|
"splash",
|
5141
5166
|
this=self,
|
@@ -5158,7 +5183,7 @@ class HttpCli(object):
|
|
5158
5183
|
no304=self.no304(),
|
5159
5184
|
k304vis=self.args.k304 > 0,
|
5160
5185
|
no304vis=self.args.no304 > 0,
|
5161
|
-
ver=S_VERSION if
|
5186
|
+
ver=S_VERSION if show_ver else "",
|
5162
5187
|
chpw=self.args.chpw and self.uname != "*",
|
5163
5188
|
ahttps="" if self.is_https else "https://" + self.host + self.req,
|
5164
5189
|
)
|
@@ -5373,8 +5398,9 @@ class HttpCli(object):
|
|
5373
5398
|
|
5374
5399
|
if dk_sz and fsroot:
|
5375
5400
|
kdirs = []
|
5401
|
+
fsroot_ = os.path.join(fsroot, "")
|
5376
5402
|
for dn in dirs:
|
5377
|
-
ap =
|
5403
|
+
ap = fsroot_ + dn
|
5378
5404
|
zs = self.gen_fk(2, self.args.dk_salt, ap, 0, 0)[:dk_sz]
|
5379
5405
|
kdirs.append(dn + "?k=" + zs)
|
5380
5406
|
dirs = kdirs
|
@@ -5905,6 +5931,14 @@ class HttpCli(object):
|
|
5905
5931
|
except:
|
5906
5932
|
raise Pebkac(400, "you dont have all the perms you tried to grant")
|
5907
5933
|
|
5934
|
+
zs = vfs.flags["shr_who"]
|
5935
|
+
if zs == "auth" and self.uname != "*":
|
5936
|
+
pass
|
5937
|
+
elif zs == "a" and self.uname in vfs.axs.uadmin:
|
5938
|
+
pass
|
5939
|
+
else:
|
5940
|
+
raise Pebkac(400, "you dont have perms to create shares from this volume")
|
5941
|
+
|
5908
5942
|
ap, reals, _ = vfs.ls(
|
5909
5943
|
rem, self.uname, not self.args.no_scandir, [[s_rd, s_wr, s_mv, s_del]]
|
5910
5944
|
)
|
@@ -6166,16 +6200,13 @@ class HttpCli(object):
|
|
6166
6200
|
add_og = "og" in vn.flags
|
6167
6201
|
if add_og:
|
6168
6202
|
if "th" in self.uparam or "raw" in self.uparam:
|
6169
|
-
|
6170
|
-
elif
|
6171
|
-
|
6172
|
-
else:
|
6173
|
-
og_ua = False
|
6174
|
-
add_og = True
|
6203
|
+
add_og = False
|
6204
|
+
elif vn.flags["og_ua"]:
|
6205
|
+
add_og = vn.flags["og_ua"].search(self.ua)
|
6175
6206
|
og_fn = ""
|
6176
6207
|
|
6177
6208
|
if "v" in self.uparam:
|
6178
|
-
add_og =
|
6209
|
+
add_og = True
|
6179
6210
|
|
6180
6211
|
if "b" in self.uparam:
|
6181
6212
|
self.out_headers["X-Robots-Tag"] = "noindex, nofollow"
|
@@ -6296,7 +6327,7 @@ class HttpCli(object):
|
|
6296
6327
|
|
6297
6328
|
is_md = abspath.lower().endswith(".md")
|
6298
6329
|
if add_og and not is_md:
|
6299
|
-
if
|
6330
|
+
if self.host not in self.headers.get("referer", ""):
|
6300
6331
|
self.vpath, og_fn = vsplit(self.vpath)
|
6301
6332
|
vpath = self.vpath
|
6302
6333
|
vn, rem = self.asrv.vfs.get(self.vpath, self.uname, False, False)
|
@@ -6336,7 +6367,14 @@ class HttpCli(object):
|
|
6336
6367
|
except:
|
6337
6368
|
self.log("#wow #whoa")
|
6338
6369
|
|
6339
|
-
|
6370
|
+
zi = vn.flags["du_iwho"]
|
6371
|
+
if zi and (
|
6372
|
+
zi == 9
|
6373
|
+
or (zi == 7 and self.uname != "*")
|
6374
|
+
or (zi == 5 and self.can_write)
|
6375
|
+
or (zi == 4 and self.can_write and self.can_read)
|
6376
|
+
or (zi == 3 and self.can_admin)
|
6377
|
+
):
|
6340
6378
|
free, total, zs = get_df(abspath, False)
|
6341
6379
|
if total:
|
6342
6380
|
h1 = humansize(free or 0)
|
copyparty/httpsrv.py
CHANGED
copyparty/smbd.py
CHANGED
copyparty/svchub.py
CHANGED
@@ -21,7 +21,7 @@ from datetime import datetime
|
|
21
21
|
|
22
22
|
|
23
23
|
from .__init__ import ANYWIN, EXE, MACOS, PY2, TYPE_CHECKING, E, EnvParams, unicode
|
24
|
-
from .authsrv import BAD_CFG, AuthSrv
|
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
27
|
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, HAVE_MUTAGEN
|
@@ -283,6 +283,14 @@ class SvcHub(object):
|
|
283
283
|
ch = "abcdefghijklmnopqrstuvwx"[int(args.theme / 2)]
|
284
284
|
args.theme = "{0}{1} {0} {1}".format(ch, bri)
|
285
285
|
|
286
|
+
if args.nid:
|
287
|
+
args.du_who = "no"
|
288
|
+
args.du_iwho = n_du_who(args.du_who)
|
289
|
+
|
290
|
+
if args.ver and args.ver_who == "no":
|
291
|
+
args.ver_who = "all"
|
292
|
+
args.ver_iwho = n_ver_who(args.ver_who)
|
293
|
+
|
286
294
|
if args.nih:
|
287
295
|
args.vname = ""
|
288
296
|
args.doctitle = args.doctitle.replace(" @ --name", "")
|
@@ -966,6 +974,24 @@ class SvcHub(object):
|
|
966
974
|
t = "WARNING:\nDisabling WebDAV support because dxml selftest failed. Please report this bug;\n%s\n...and include the following information in the bug-report:\n%s | expat %s\n"
|
967
975
|
self.log("root", t % (URL_BUG, VERSIONS, expat_ver()), 1)
|
968
976
|
|
977
|
+
if not E.scfg and not al.unsafe_state and not os.getenv("PRTY_UNSAFE_STATE"):
|
978
|
+
t = "because runtime config is currently being stored in an untrusted emergency-fallback location. Please fix your environment so either XDG_CONFIG_HOME or ~/.config can be used instead, or disable this safeguard with --unsafe-state or env-var PRTY_UNSAFE_STATE=1."
|
979
|
+
if not al.no_ses:
|
980
|
+
al.no_ses = True
|
981
|
+
t2 = "A consequence of this misconfiguration is that passwords will now be sent in the HTTP-header of every request!"
|
982
|
+
self.log("root", "WARNING:\nWill disable sessions %s %s" % (t, t2), 1)
|
983
|
+
if al.idp_store == 1:
|
984
|
+
al.idp_store = 0
|
985
|
+
self.log("root", "WARNING:\nDisabling --idp-store %s" % (t,), 3)
|
986
|
+
if al.idp_store:
|
987
|
+
t2 = "ERROR: Cannot enable --idp-store %s" % (t,)
|
988
|
+
self.log("root", t2, 1)
|
989
|
+
raise Exception(t2)
|
990
|
+
if al.shr:
|
991
|
+
t2 = "ERROR: Cannot enable shares %s" % (t,)
|
992
|
+
self.log("root", t2, 1)
|
993
|
+
raise Exception(t2)
|
994
|
+
|
969
995
|
def _process_config(self) :
|
970
996
|
al = self.args
|
971
997
|
|
copyparty/tcpsrv.py
CHANGED
@@ -302,6 +302,10 @@ class TcpSrv(object):
|
|
302
302
|
if os.path.exists(ip):
|
303
303
|
os.unlink(ip)
|
304
304
|
srv.bind(ip)
|
305
|
+
if uds_gid != -1:
|
306
|
+
os.chown(ip, -1, uds_gid)
|
307
|
+
if uds_perm != -1:
|
308
|
+
os.chmod(ip, uds_perm)
|
305
309
|
else:
|
306
310
|
tf = "%s.%d" % (ip, os.getpid())
|
307
311
|
if os.path.exists(tf):
|
copyparty/up2k.py
CHANGED
@@ -410,10 +410,11 @@ class Up2k(object):
|
|
410
410
|
|
411
411
|
ret = []
|
412
412
|
userset = set([(uname or "\n"), "*"])
|
413
|
+
e_d = {}
|
413
414
|
n = 1000
|
414
415
|
try:
|
415
416
|
for ptop, tab2 in self.registry.items():
|
416
|
-
cfg = self.flags.get(ptop,
|
417
|
+
cfg = self.flags.get(ptop, e_d).get("u2abort", 1)
|
417
418
|
if not cfg:
|
418
419
|
continue
|
419
420
|
addr = (ip or "\n") if cfg in (1, 2) else ""
|
@@ -1131,7 +1132,7 @@ class Up2k(object):
|
|
1131
1132
|
ft = "\033[0;32m{}{:.0}"
|
1132
1133
|
ff = "\033[0;35m{}{:.0}"
|
1133
1134
|
fv = "\033[0;36m{}:\033[90m{}"
|
1134
|
-
zs = "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"
|
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"
|
1135
1136
|
fx = set(zs.split())
|
1136
1137
|
fd = vf_bmap()
|
1137
1138
|
fd.update(vf_cmap())
|
@@ -1485,6 +1486,7 @@ class Up2k(object):
|
|
1485
1486
|
files = []
|
1486
1487
|
fat32 = True
|
1487
1488
|
cv = vcv = acv = ""
|
1489
|
+
e_d = {}
|
1488
1490
|
|
1489
1491
|
th_cvd = self.args.th_coversd
|
1490
1492
|
th_cvds = self.args.th_coversd_set
|
@@ -1684,7 +1686,7 @@ class Up2k(object):
|
|
1684
1686
|
|
1685
1687
|
t = "reindex %r => %r mtime(%s/%s) size(%s/%s)"
|
1686
1688
|
self.log(t % (top, rp, dts, lmod, dsz, sz))
|
1687
|
-
self.db_rm(db.c, rd, fn, 0)
|
1689
|
+
self.db_rm(db.c, e_d, rd, fn, 0)
|
1688
1690
|
tfa += 1
|
1689
1691
|
db.n += 1
|
1690
1692
|
in_db = []
|
@@ -1721,7 +1723,7 @@ class Up2k(object):
|
|
1721
1723
|
un = ""
|
1722
1724
|
|
1723
1725
|
# skip upload hooks by not providing vflags
|
1724
|
-
self.db_add(db.c,
|
1726
|
+
self.db_add(db.c, e_d, rd, fn, lmod, sz, "", "", wark, wark, "", un, ip, at)
|
1725
1727
|
db.n += 1
|
1726
1728
|
db.nf += 1
|
1727
1729
|
tfa += 1
|
@@ -1780,7 +1782,7 @@ class Up2k(object):
|
|
1780
1782
|
rm_files = [x for x in hits if x not in seen_files]
|
1781
1783
|
n_rm = len(rm_files)
|
1782
1784
|
for fn in rm_files:
|
1783
|
-
self.db_rm(db.c, rd, fn, 0)
|
1785
|
+
self.db_rm(db.c, e_d, rd, fn, 0)
|
1784
1786
|
|
1785
1787
|
if n_rm:
|
1786
1788
|
self.log("forgot {} deleted files".format(n_rm))
|
@@ -3126,7 +3128,7 @@ class Up2k(object):
|
|
3126
3128
|
for cur, dp_dir, dp_fn in lost:
|
3127
3129
|
t = "forgetting desynced db entry: %r"
|
3128
3130
|
self.log(t % ("/" + vjoin(vjoin(vfs.vpath, dp_dir), dp_fn)))
|
3129
|
-
self.db_rm(cur, dp_dir, dp_fn, cj["size"])
|
3131
|
+
self.db_rm(cur, vfs.flags, dp_dir, dp_fn, cj["size"])
|
3130
3132
|
if c2 and c2 != cur:
|
3131
3133
|
c2.connection.commit()
|
3132
3134
|
|
@@ -3419,10 +3421,9 @@ class Up2k(object):
|
|
3419
3421
|
cur.connection.commit()
|
3420
3422
|
|
3421
3423
|
ap = djoin(job["ptop"], job["prel"], job["name"])
|
3422
|
-
|
3423
|
-
bos.utime(ap, times, False)
|
3424
|
+
mt = bos.utime_c(self.log, ap, int(cj["lmod"]), False, True)
|
3424
3425
|
|
3425
|
-
self.log("touched %r from %d to %d" % (ap, job["lmod"],
|
3426
|
+
self.log("touched %r from %d to %d" % (ap, job["lmod"], mt))
|
3426
3427
|
except Exception as ex:
|
3427
3428
|
self.log("umod failed, %r" % (ex,), 3)
|
3428
3429
|
|
@@ -3456,7 +3457,7 @@ class Up2k(object):
|
|
3456
3457
|
vrel = vjoin(job["prel"], fname)
|
3457
3458
|
xlink = bool(vf.get("xlink"))
|
3458
3459
|
cur, wark, _, _, _, _, _ = self._find_from_vpath(ptop, vrel)
|
3459
|
-
self._forget_file(ptop, vrel, cur, wark, True, st.st_size, xlink)
|
3460
|
+
self._forget_file(ptop, vrel, vf, cur, wark, True, st.st_size, xlink)
|
3460
3461
|
except Exception as ex:
|
3461
3462
|
self.log("skipping replace-relink: %r" % (ex,))
|
3462
3463
|
finally:
|
@@ -3577,8 +3578,7 @@ class Up2k(object):
|
|
3577
3578
|
shutil.copy2(fsenc(csrc), fsenc(dst))
|
3578
3579
|
|
3579
3580
|
if lmod and (not linked or SYMTIME):
|
3580
|
-
|
3581
|
-
bos.utime(dst, times, False)
|
3581
|
+
bos.utime_c(self.log, dst, int(lmod), False)
|
3582
3582
|
|
3583
3583
|
def handle_chunks(
|
3584
3584
|
self, ptop , wark , chashes
|
@@ -3750,10 +3750,8 @@ class Up2k(object):
|
|
3750
3750
|
times = (int(time.time()), int(job["lmod"]))
|
3751
3751
|
t = "no more chunks, setting times %s (%d) on %r"
|
3752
3752
|
self.log(t % (times, bos.path.getsize(dst), dst))
|
3753
|
-
|
3754
|
-
|
3755
|
-
except:
|
3756
|
-
self.log("failed to utime (%r, %s)" % (dst, times))
|
3753
|
+
bos.utime_c(self.log, dst, times[1], False)
|
3754
|
+
# the above logmsg (and associated logic) is retained due to unforget.py
|
3757
3755
|
|
3758
3756
|
zs = "prel name lmod size ptop vtop wark dwrk host user addr"
|
3759
3757
|
z2 = [job[x] for x in zs.split()]
|
@@ -3871,16 +3869,31 @@ class Up2k(object):
|
|
3871
3869
|
|
3872
3870
|
return True
|
3873
3871
|
|
3874
|
-
def db_rm(
|
3872
|
+
def db_rm(
|
3873
|
+
self, db , vflags , rd , fn , sz
|
3874
|
+
) :
|
3875
3875
|
sql = "delete from up where rd = ? and fn = ?"
|
3876
3876
|
try:
|
3877
3877
|
r = db.execute(sql, (rd, fn))
|
3878
3878
|
except:
|
3879
3879
|
r = db.execute(sql, s3enc(self.mem_cur, rd, fn))
|
3880
3880
|
|
3881
|
-
if r.rowcount:
|
3882
|
-
|
3883
|
-
|
3881
|
+
if not r.rowcount:
|
3882
|
+
return
|
3883
|
+
|
3884
|
+
self.volsize[db] -= sz
|
3885
|
+
self.volnfiles[db] -= 1
|
3886
|
+
|
3887
|
+
if "nodirsz" not in vflags:
|
3888
|
+
try:
|
3889
|
+
q = "update ds set nf=nf-1, sz=sz-? where rd=?"
|
3890
|
+
while True:
|
3891
|
+
db.execute(q, (sz, rd))
|
3892
|
+
if not rd:
|
3893
|
+
break
|
3894
|
+
rd = rd.rsplit("/", 1)[0] if "/" in rd else ""
|
3895
|
+
except:
|
3896
|
+
pass
|
3884
3897
|
|
3885
3898
|
def db_add(
|
3886
3899
|
self,
|
@@ -3901,7 +3914,7 @@ class Up2k(object):
|
|
3901
3914
|
skip_xau = False,
|
3902
3915
|
) :
|
3903
3916
|
"""mutex(main) me"""
|
3904
|
-
self.db_rm(db, rd, fn, sz)
|
3917
|
+
self.db_rm(db, vflags, rd, fn, sz)
|
3905
3918
|
|
3906
3919
|
if not ip:
|
3907
3920
|
db_ip = ""
|
@@ -4182,7 +4195,7 @@ class Up2k(object):
|
|
4182
4195
|
xlink = bool(dbv.flags.get("xlink"))
|
4183
4196
|
cur, wark, _, _, _, _, _ = self._find_from_vpath(ptop, volpath)
|
4184
4197
|
self._forget_file(
|
4185
|
-
ptop, volpath, cur, wark, True, st.st_size, xlink
|
4198
|
+
ptop, volpath, dbv.flags, cur, wark, True, st.st_size, xlink
|
4186
4199
|
)
|
4187
4200
|
finally:
|
4188
4201
|
if cur:
|
@@ -4638,7 +4651,14 @@ class Up2k(object):
|
|
4638
4651
|
|
4639
4652
|
with self.reg_mutex:
|
4640
4653
|
has_dupes = self._forget_file(
|
4641
|
-
svn.realpath,
|
4654
|
+
svn.realpath,
|
4655
|
+
srem,
|
4656
|
+
svn.flags,
|
4657
|
+
c1,
|
4658
|
+
w,
|
4659
|
+
is_xvol,
|
4660
|
+
fsize_ or fsize,
|
4661
|
+
xlink,
|
4642
4662
|
)
|
4643
4663
|
|
4644
4664
|
if not is_xvol:
|
@@ -4782,6 +4802,7 @@ class Up2k(object):
|
|
4782
4802
|
self,
|
4783
4803
|
ptop ,
|
4784
4804
|
vrem ,
|
4805
|
+
vflags ,
|
4785
4806
|
cur ,
|
4786
4807
|
wark ,
|
4787
4808
|
drop_tags ,
|
@@ -4806,7 +4827,7 @@ class Up2k(object):
|
|
4806
4827
|
q = "delete from mt where w=?"
|
4807
4828
|
cur.execute(q, (wark[:16],))
|
4808
4829
|
|
4809
|
-
self.db_rm(cur, srd, sfn, sz)
|
4830
|
+
self.db_rm(cur, vflags, srd, sfn, sz)
|
4810
4831
|
|
4811
4832
|
reg = self.registry.get(ptop)
|
4812
4833
|
if reg:
|
@@ -4895,7 +4916,10 @@ class Up2k(object):
|
|
4895
4916
|
mt = bos.path.getmtime(slabs, False)
|
4896
4917
|
flags = self.flags.get(ptop) or {}
|
4897
4918
|
atomic_move(self.log, sabs, slabs, flags)
|
4898
|
-
|
4919
|
+
try:
|
4920
|
+
bos.utime(slabs, (int(time.time()), int(mt)), False)
|
4921
|
+
except:
|
4922
|
+
self.log("relink: failed to utime(%r, %s)" % (slabs, mt), 3)
|
4899
4923
|
self._symlink(slabs, sabs, flags, False, is_mv=True)
|
4900
4924
|
full[slabs] = (ptop, rem)
|
4901
4925
|
sabs = slabs
|
copyparty/util.py
CHANGED
@@ -3102,8 +3102,9 @@ def statdir(
|
|
3102
3102
|
else:
|
3103
3103
|
src = "listdir"
|
3104
3104
|
fun = os.lstat if lstat else os.stat
|
3105
|
+
btop_ = os.path.join(btop, b"")
|
3105
3106
|
for name in os.listdir(btop):
|
3106
|
-
abspath =
|
3107
|
+
abspath = btop_ + name
|
3107
3108
|
try:
|
3108
3109
|
yield (fsdec(name), fun(abspath))
|
3109
3110
|
except Exception as ex:
|
@@ -3142,7 +3143,9 @@ def rmdirs(
|
|
3142
3143
|
|
3143
3144
|
stats = statdir(logger, scandir, lstat, top, False)
|
3144
3145
|
dirs = [x[0] for x in stats if stat.S_ISDIR(x[1].st_mode)]
|
3145
|
-
|
3146
|
+
if dirs:
|
3147
|
+
top_ = os.path.join(top, "")
|
3148
|
+
dirs = [top_ + x for x in dirs]
|
3146
3149
|
ok = []
|
3147
3150
|
ng = []
|
3148
3151
|
for d in reversed(dirs):
|
@@ -4113,7 +4116,7 @@ def _pkg_resource_exists(pkg , name ) :
|
|
4113
4116
|
|
4114
4117
|
|
4115
4118
|
def stat_resource(E , name ):
|
4116
|
-
path =
|
4119
|
+
path = E.mod_ + name
|
4117
4120
|
if os.path.exists(path):
|
4118
4121
|
return os.stat(fsenc(path))
|
4119
4122
|
return None
|
@@ -4158,7 +4161,7 @@ def _has_resource(name ):
|
|
4158
4161
|
|
4159
4162
|
|
4160
4163
|
def has_resource(E , name ):
|
4161
|
-
return _has_resource(name) or os.path.exists(
|
4164
|
+
return _has_resource(name) or os.path.exists(E.mod_ + name)
|
4162
4165
|
|
4163
4166
|
|
4164
4167
|
def load_resource(E , name , mode="rb") :
|
@@ -4181,7 +4184,7 @@ def load_resource(E , name , mode="rb") :
|
|
4181
4184
|
stream = codecs.getreader(enc)(stream)
|
4182
4185
|
return stream
|
4183
4186
|
|
4184
|
-
ap =
|
4187
|
+
ap = E.mod_ + name
|
4185
4188
|
|
4186
4189
|
if PY2:
|
4187
4190
|
return codecs.open(ap, "r", encoding=enc) # type: ignore
|
copyparty/web/a/partyfuse.py
CHANGED
@@ -6,8 +6,8 @@ __copyright__ = 2019
|
|
6
6
|
__license__ = "MIT"
|
7
7
|
__url__ = "https://github.com/9001/copyparty/"
|
8
8
|
|
9
|
-
S_VERSION = "2.
|
10
|
-
S_BUILD_DT = "
|
9
|
+
S_VERSION = "2.1"
|
10
|
+
S_BUILD_DT = "2025-09-06"
|
11
11
|
|
12
12
|
"""
|
13
13
|
mount a copyparty server (local or remote) as a filesystem
|
@@ -95,7 +95,7 @@ except:
|
|
95
95
|
elif MACOS:
|
96
96
|
libfuse = "install https://osxfuse.github.io/"
|
97
97
|
else:
|
98
|
-
libfuse = "apt install
|
98
|
+
libfuse = "apt install libfuse2\n modprobe fuse"
|
99
99
|
|
100
100
|
m = """\033[33m
|
101
101
|
could not import fuse; these may help:
|
@@ -324,7 +324,7 @@ class Gateway(object):
|
|
324
324
|
def sendreq(self, meth, path, headers, **kwargs):
|
325
325
|
tid = get_tid()
|
326
326
|
if self.password:
|
327
|
-
headers["
|
327
|
+
headers["PW"] = self.password
|
328
328
|
|
329
329
|
try:
|
330
330
|
c = self.getconn(tid)
|
@@ -682,9 +682,7 @@ class CPPF(Operations):
|
|
682
682
|
return ret
|
683
683
|
|
684
684
|
def _readdir(self, path, fh=None):
|
685
|
-
|
686
|
-
dbg("readdir %r [%s]", path, fh)
|
687
|
-
|
685
|
+
dbg("dircache miss")
|
688
686
|
ret = self.gw.listdir(path)
|
689
687
|
if not self.n_dircache:
|
690
688
|
return ret
|
@@ -694,11 +692,17 @@ class CPPF(Operations):
|
|
694
692
|
self.dircache.append(cn)
|
695
693
|
self.clean_dircache()
|
696
694
|
|
697
|
-
# import pprint; pprint.pprint(ret)
|
698
695
|
return ret
|
699
696
|
|
700
697
|
def readdir(self, path, fh=None):
|
701
|
-
|
698
|
+
dbg("readdir %r [%s]", path, fh)
|
699
|
+
path = path.strip("/")
|
700
|
+
cn = self.get_cached_dir(path)
|
701
|
+
if cn:
|
702
|
+
ret = cn.data
|
703
|
+
else:
|
704
|
+
ret = self._readdir(path, fh)
|
705
|
+
return [".", ".."] + list(ret)
|
702
706
|
|
703
707
|
def read(self, path, length, offset, fh=None):
|
704
708
|
req_max = 1024 * 1024 * 8
|
@@ -749,7 +753,6 @@ class CPPF(Operations):
|
|
749
753
|
if cn:
|
750
754
|
dents = cn.data
|
751
755
|
else:
|
752
|
-
dbg("cache miss")
|
753
756
|
dents = self._readdir(dirpath)
|
754
757
|
|
755
758
|
try:
|
@@ -857,10 +860,15 @@ def main():
|
|
857
860
|
if WINDOWS:
|
858
861
|
examples.append("http://192.168.1.69:3923/music/ M:")
|
859
862
|
|
863
|
+
epi = "example:" + ex_pre + ex_pre.join(examples)
|
864
|
+
epi += """\n
|
865
|
+
NOTE: if server has --usernames enabled, then password is "username:password"
|
866
|
+
"""
|
867
|
+
|
860
868
|
ap = argparse.ArgumentParser(
|
861
869
|
formatter_class=TheArgparseFormatter,
|
862
870
|
description="mount a copyparty server as a local filesystem -- " + ver,
|
863
|
-
epilog=
|
871
|
+
epilog=epi,
|
864
872
|
)
|
865
873
|
# fmt: off
|
866
874
|
ap.add_argument("base_url", type=str, help="remote copyparty URL to mount")
|
copyparty/web/a/u2c.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
|
-
S_VERSION = "2.
|
5
|
-
S_BUILD_DT = "2025-
|
4
|
+
S_VERSION = "2.13"
|
5
|
+
S_BUILD_DT = "2025-09-05"
|
6
6
|
|
7
7
|
"""
|
8
8
|
u2c.py: upload to copyparty
|
@@ -588,9 +588,10 @@ def undns(url):
|
|
588
588
|
|
589
589
|
def _scd(err, top):
|
590
590
|
"""non-recursive listing of directory contents, along with stat() info"""
|
591
|
+
top_ = os.path.join(top, b"")
|
591
592
|
with os.scandir(top) as dh:
|
592
593
|
for fh in dh:
|
593
|
-
abspath =
|
594
|
+
abspath = top_ + fh.name
|
594
595
|
try:
|
595
596
|
yield [abspath, fh.stat()]
|
596
597
|
except Exception as ex:
|
@@ -599,8 +600,9 @@ def _scd(err, top):
|
|
599
600
|
|
600
601
|
def _lsd(err, top):
|
601
602
|
"""non-recursive listing of directory contents, along with stat() info"""
|
603
|
+
top_ = os.path.join(top, b"")
|
602
604
|
for name in os.listdir(top):
|
603
|
-
abspath =
|
605
|
+
abspath = top_ + name
|
604
606
|
try:
|
605
607
|
yield [abspath, os.stat(abspath)]
|
606
608
|
except Exception as ex:
|
copyparty/web/baguettebox.js.gz
CHANGED
Binary file
|
copyparty/web/browser.css.gz
CHANGED
Binary file
|
copyparty/web/browser.html
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
<meta name="theme-color" content="#{{ tcolor }}">
|
10
10
|
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
|
11
11
|
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/browser.css?_={{ ts }}">
|
12
|
-
{{ html_head }}
|
12
|
+
{{- html_head }}
|
13
13
|
{%- if css %}
|
14
14
|
<link rel="stylesheet" media="screen" href="{{ css }}_={{ ts }}">
|
15
15
|
{%- endif %}
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|