copyparty 1.15.0__py3-none-any.whl → 1.15.2__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 +1 -0
- copyparty/__main__.py +21 -12
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +84 -8
- copyparty/broker_mp.py +6 -2
- copyparty/broker_mpw.py +6 -2
- copyparty/broker_thr.py +5 -9
- copyparty/broker_util.py +13 -1
- copyparty/cfg.py +1 -0
- copyparty/fsutil.py +0 -3
- copyparty/httpcli.py +145 -70
- copyparty/httpconn.py +0 -1
- copyparty/httpsrv.py +3 -5
- copyparty/svchub.py +67 -5
- copyparty/th_srv.py +15 -7
- copyparty/u2idx.py +0 -3
- copyparty/up2k.py +223 -100
- copyparty/util.py +116 -63
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/splash.css.gz +0 -0
- copyparty/web/splash.html +12 -0
- copyparty/web/splash.js.gz +0 -0
- {copyparty-1.15.0.dist-info → copyparty-1.15.2.dist-info}/METADATA +15 -3
- {copyparty-1.15.0.dist-info → copyparty-1.15.2.dist-info}/RECORD +29 -29
- {copyparty-1.15.0.dist-info → copyparty-1.15.2.dist-info}/WHEEL +1 -1
- {copyparty-1.15.0.dist-info → copyparty-1.15.2.dist-info}/LICENSE +0 -0
- {copyparty-1.15.0.dist-info → copyparty-1.15.2.dist-info}/entry_points.txt +0 -0
- {copyparty-1.15.0.dist-info → copyparty-1.15.2.dist-info}/top_level.txt +0 -0
copyparty/up2k.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
|
-
import base64
|
5
4
|
import errno
|
6
5
|
import gzip
|
7
6
|
import hashlib
|
@@ -61,6 +60,7 @@ from .util import (
|
|
61
60
|
sfsenc,
|
62
61
|
spack,
|
63
62
|
statdir,
|
63
|
+
ub64enc,
|
64
64
|
unhumanize,
|
65
65
|
vjoin,
|
66
66
|
vsplit,
|
@@ -265,19 +265,29 @@ class Up2k(object):
|
|
265
265
|
if not self.stop:
|
266
266
|
self.log("uploads are now possible", 2)
|
267
267
|
|
268
|
-
def get_state(self) :
|
268
|
+
def get_state(self, get_q , uname ) :
|
269
269
|
mtpq = 0
|
270
|
+
ups = []
|
271
|
+
up_en = not self.args.no_up_list
|
270
272
|
q = "select count(w) from mt where k = 't:mtp'"
|
271
273
|
got_lock = False if PY2 else self.mutex.acquire(timeout=0.5)
|
272
274
|
if got_lock:
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
275
|
+
try:
|
276
|
+
for cur in self.cur.values() if get_q else []:
|
277
|
+
try:
|
278
|
+
mtpq += cur.execute(q).fetchone()[0]
|
279
|
+
except:
|
280
|
+
pass
|
281
|
+
if uname and up_en:
|
282
|
+
ups = self._active_uploads(uname)
|
283
|
+
finally:
|
284
|
+
self.mutex.release()
|
279
285
|
else:
|
280
286
|
mtpq = "(?)"
|
287
|
+
if up_en:
|
288
|
+
ups = [(0, 0, time.time(), "cannot show list (server too busy)")]
|
289
|
+
|
290
|
+
ups.sort(reverse=True)
|
281
291
|
|
282
292
|
ret = {
|
283
293
|
"volstate": self.volstate,
|
@@ -285,6 +295,7 @@ class Up2k(object):
|
|
285
295
|
"hashq": self.n_hashq,
|
286
296
|
"tagq": self.n_tagq,
|
287
297
|
"mtpq": mtpq,
|
298
|
+
"ups": ups,
|
288
299
|
"dbwu": "{:.2f}".format(self.db_act),
|
289
300
|
"dbwt": "{:.2f}".format(
|
290
301
|
min(1000 * 24 * 60 * 60 - 1, time.time() - self.db_act)
|
@@ -292,6 +303,32 @@ class Up2k(object):
|
|
292
303
|
}
|
293
304
|
return json.dumps(ret, separators=(",\n", ": "))
|
294
305
|
|
306
|
+
def _active_uploads(self, uname ) :
|
307
|
+
ret = []
|
308
|
+
for vtop in self.asrv.vfs.aread[uname]:
|
309
|
+
vfs = self.asrv.vfs.all_vols.get(vtop)
|
310
|
+
if not vfs: # dbv only
|
311
|
+
continue
|
312
|
+
ptop = vfs.realpath
|
313
|
+
tab = self.registry.get(ptop)
|
314
|
+
if not tab:
|
315
|
+
continue
|
316
|
+
for job in tab.values():
|
317
|
+
ineed = len(job["need"])
|
318
|
+
ihash = len(job["hash"])
|
319
|
+
if ineed == ihash or not ineed:
|
320
|
+
continue
|
321
|
+
|
322
|
+
zt = (
|
323
|
+
ineed / ihash,
|
324
|
+
job["size"],
|
325
|
+
int(job["t0"]),
|
326
|
+
int(job["poke"]),
|
327
|
+
djoin(vtop, job["prel"], job["name"]),
|
328
|
+
)
|
329
|
+
ret.append(zt)
|
330
|
+
return ret
|
331
|
+
|
295
332
|
def find_job_by_ap(self, ptop , ap ) :
|
296
333
|
try:
|
297
334
|
if ANYWIN:
|
@@ -572,7 +609,6 @@ class Up2k(object):
|
|
572
609
|
return timeout
|
573
610
|
|
574
611
|
def _check_shares(self) :
|
575
|
-
assert sqlite3 # type: ignore
|
576
612
|
|
577
613
|
now = time.time()
|
578
614
|
timeout = now + 9001
|
@@ -893,7 +929,6 @@ class Up2k(object):
|
|
893
929
|
with self.mutex, self.reg_mutex:
|
894
930
|
reg = self.register_vpath(vol.realpath, vol.flags)
|
895
931
|
|
896
|
-
assert reg
|
897
932
|
cur, _ = reg
|
898
933
|
with self.mutex:
|
899
934
|
cur.connection.commit()
|
@@ -910,7 +945,6 @@ class Up2k(object):
|
|
910
945
|
reg = self.register_vpath(vol.realpath, vol.flags)
|
911
946
|
|
912
947
|
try:
|
913
|
-
assert reg
|
914
948
|
cur, db_path = reg
|
915
949
|
if bos.path.getsize(db_path + "-wal") < 1024 * 1024 * 5:
|
916
950
|
continue
|
@@ -1116,7 +1150,7 @@ class Up2k(object):
|
|
1116
1150
|
zsl = [x[len(prefix) :] for x in zsl]
|
1117
1151
|
zsl.sort()
|
1118
1152
|
zb = hashlib.sha1("\n".join(zsl).encode("utf-8", "replace")).digest()
|
1119
|
-
vcfg =
|
1153
|
+
vcfg = ub64enc(zb[:18]).decode("ascii")
|
1120
1154
|
|
1121
1155
|
c = cur.execute("select v from kv where k = 'volcfg'")
|
1122
1156
|
try:
|
@@ -1145,7 +1179,6 @@ class Up2k(object):
|
|
1145
1179
|
with self.reg_mutex:
|
1146
1180
|
reg = self.register_vpath(top, vol.flags)
|
1147
1181
|
|
1148
|
-
assert reg and self.pp
|
1149
1182
|
cur, db_path = reg
|
1150
1183
|
|
1151
1184
|
db = Dbw(cur, 0, time.time())
|
@@ -1164,6 +1197,10 @@ class Up2k(object):
|
|
1164
1197
|
# ~/.wine/dosdevices/z:/ and such
|
1165
1198
|
excl.extend(("/dev", "/proc", "/run", "/sys"))
|
1166
1199
|
|
1200
|
+
if self.args.re_dirsz:
|
1201
|
+
db.c.execute("delete from ds")
|
1202
|
+
db.n += 1
|
1203
|
+
|
1167
1204
|
rtop = absreal(top)
|
1168
1205
|
n_add = n_rm = 0
|
1169
1206
|
try:
|
@@ -1172,7 +1209,7 @@ class Up2k(object):
|
|
1172
1209
|
self.log(t % (vol.vpath, rtop), 6)
|
1173
1210
|
return True, False
|
1174
1211
|
|
1175
|
-
n_add = self._build_dir(
|
1212
|
+
n_add, _, _ = self._build_dir(
|
1176
1213
|
db,
|
1177
1214
|
top,
|
1178
1215
|
set(excl),
|
@@ -1246,17 +1283,18 @@ class Up2k(object):
|
|
1246
1283
|
cst ,
|
1247
1284
|
dev ,
|
1248
1285
|
xvol ,
|
1249
|
-
)
|
1286
|
+
) :
|
1250
1287
|
if xvol and not rcdir.startswith(top):
|
1251
1288
|
self.log("skip xvol: [{}] -> [{}]".format(cdir, rcdir), 6)
|
1252
|
-
return 0
|
1289
|
+
return 0, 0, 0
|
1253
1290
|
|
1254
1291
|
if rcdir in seen:
|
1255
1292
|
t = "bailing from symlink loop,\n prev: {}\n curr: {}\n from: {}"
|
1256
1293
|
self.log(t.format(seen[-1], rcdir, cdir), 3)
|
1257
|
-
return 0
|
1294
|
+
return 0, 0, 0
|
1258
1295
|
|
1259
|
-
|
1296
|
+
# total-files-added, total-num-files, recursive-size
|
1297
|
+
tfa = tnf = rsz = 0
|
1260
1298
|
seen = seen + [rcdir]
|
1261
1299
|
unreg = []
|
1262
1300
|
files = []
|
@@ -1266,22 +1304,24 @@ class Up2k(object):
|
|
1266
1304
|
th_cvd = self.args.th_coversd
|
1267
1305
|
th_cvds = self.args.th_coversd_set
|
1268
1306
|
|
1269
|
-
assert self.pp and self.mem_cur
|
1270
1307
|
self.pp.msg = "a%d %s" % (self.pp.n, cdir)
|
1271
1308
|
|
1272
1309
|
rd = cdir[len(top) :].strip("/")
|
1273
1310
|
if WINDOWS:
|
1274
1311
|
rd = rd.replace("\\", "/").strip("/")
|
1275
1312
|
|
1313
|
+
rds = rd + "/" if rd else ""
|
1314
|
+
cdirs = cdir + os.sep
|
1315
|
+
|
1276
1316
|
g = statdir(self.log_func, not self.args.no_scandir, True, cdir)
|
1277
1317
|
gl = sorted(g)
|
1278
1318
|
partials = set([x[0] for x in gl if "PARTIAL" in x[0]])
|
1279
1319
|
for iname, inf in gl:
|
1280
1320
|
if self.stop:
|
1281
|
-
return -1
|
1321
|
+
return -1, 0, 0
|
1282
1322
|
|
1283
|
-
rp =
|
1284
|
-
abspath =
|
1323
|
+
rp = rds + iname
|
1324
|
+
abspath = cdirs + iname
|
1285
1325
|
|
1286
1326
|
if rei and rei.search(abspath):
|
1287
1327
|
unreg.append(rp)
|
@@ -1315,7 +1355,7 @@ class Up2k(object):
|
|
1315
1355
|
continue
|
1316
1356
|
# self.log(" dir: {}".format(abspath))
|
1317
1357
|
try:
|
1318
|
-
|
1358
|
+
i1, i2, i3 = self._build_dir(
|
1319
1359
|
db,
|
1320
1360
|
top,
|
1321
1361
|
excl,
|
@@ -1330,6 +1370,9 @@ class Up2k(object):
|
|
1330
1370
|
dev,
|
1331
1371
|
xvol,
|
1332
1372
|
)
|
1373
|
+
tfa += i1
|
1374
|
+
tnf += i2
|
1375
|
+
rsz += i3
|
1333
1376
|
except:
|
1334
1377
|
t = "failed to index subdir [{}]:\n{}"
|
1335
1378
|
self.log(t.format(abspath, min_ex()), c=1)
|
@@ -1348,6 +1391,7 @@ class Up2k(object):
|
|
1348
1391
|
# placeholder for unfinished upload
|
1349
1392
|
continue
|
1350
1393
|
|
1394
|
+
rsz += sz
|
1351
1395
|
files.append((sz, lmod, iname))
|
1352
1396
|
liname = iname.lower()
|
1353
1397
|
if (
|
@@ -1369,6 +1413,18 @@ class Up2k(object):
|
|
1369
1413
|
):
|
1370
1414
|
cv = iname
|
1371
1415
|
|
1416
|
+
if not self.args.no_dirsz:
|
1417
|
+
tnf += len(files)
|
1418
|
+
q = "select sz, nf from ds where rd=? limit 1"
|
1419
|
+
try:
|
1420
|
+
db_sz, db_nf = db.c.execute(q, (rd,)).fetchone() or (-1, -1)
|
1421
|
+
if rsz != db_sz or tnf != db_nf:
|
1422
|
+
db.c.execute("delete from ds where rd=?", (rd,))
|
1423
|
+
db.c.execute("insert into ds values (?,?,?)", (rd, rsz, tnf))
|
1424
|
+
db.n += 1
|
1425
|
+
except:
|
1426
|
+
pass # mojibake rd
|
1427
|
+
|
1372
1428
|
# folder of 1000 files = ~1 MiB RAM best-case (tiny filenames);
|
1373
1429
|
# free up stuff we're done with before dhashing
|
1374
1430
|
gl = []
|
@@ -1382,7 +1438,7 @@ class Up2k(object):
|
|
1382
1438
|
|
1383
1439
|
zh.update(cv.encode("utf-8", "replace"))
|
1384
1440
|
zh.update(spack(b"<d", cst.st_mtime))
|
1385
|
-
dhash =
|
1441
|
+
dhash = ub64enc(zh.digest()[:12]).decode("ascii")
|
1386
1442
|
sql = "select d from dh where d=? and +h=?"
|
1387
1443
|
try:
|
1388
1444
|
c = db.c.execute(sql, (rd, dhash))
|
@@ -1392,7 +1448,7 @@ class Up2k(object):
|
|
1392
1448
|
c = db.c.execute(sql, (drd, dhash))
|
1393
1449
|
|
1394
1450
|
if c.fetchone():
|
1395
|
-
return
|
1451
|
+
return tfa, tnf, rsz
|
1396
1452
|
|
1397
1453
|
if cv and rd:
|
1398
1454
|
# mojibake not supported (for performance / simplicity):
|
@@ -1409,10 +1465,10 @@ class Up2k(object):
|
|
1409
1465
|
seen_files = set([x[2] for x in files]) # for dropcheck
|
1410
1466
|
for sz, lmod, fn in files:
|
1411
1467
|
if self.stop:
|
1412
|
-
return -1
|
1468
|
+
return -1, 0, 0
|
1413
1469
|
|
1414
|
-
rp =
|
1415
|
-
abspath =
|
1470
|
+
rp = rds + fn
|
1471
|
+
abspath = cdirs + fn
|
1416
1472
|
nohash = reh.search(abspath) if reh else False
|
1417
1473
|
|
1418
1474
|
sql = "select w, mt, sz, ip, at from up where rd = ? and fn = ?"
|
@@ -1442,7 +1498,7 @@ class Up2k(object):
|
|
1442
1498
|
)
|
1443
1499
|
self.log(t)
|
1444
1500
|
self.db_rm(db.c, rd, fn, 0)
|
1445
|
-
|
1501
|
+
tfa += 1
|
1446
1502
|
db.n += 1
|
1447
1503
|
in_db = []
|
1448
1504
|
else:
|
@@ -1467,7 +1523,7 @@ class Up2k(object):
|
|
1467
1523
|
continue
|
1468
1524
|
|
1469
1525
|
if not hashes:
|
1470
|
-
return -1
|
1526
|
+
return -1, 0, 0
|
1471
1527
|
|
1472
1528
|
wark = up2k_wark_from_hashlist(self.salt, sz, hashes)
|
1473
1529
|
|
@@ -1478,7 +1534,7 @@ class Up2k(object):
|
|
1478
1534
|
# skip upload hooks by not providing vflags
|
1479
1535
|
self.db_add(db.c, {}, rd, fn, lmod, sz, "", "", wark, "", "", ip, at)
|
1480
1536
|
db.n += 1
|
1481
|
-
|
1537
|
+
tfa += 1
|
1482
1538
|
td = time.time() - db.t
|
1483
1539
|
if db.n >= 4096 or td >= 60:
|
1484
1540
|
self.log("commit {} new files".format(db.n))
|
@@ -1491,33 +1547,37 @@ class Up2k(object):
|
|
1491
1547
|
db.c.execute("insert into dh values (?,?)", (drd, dhash)) # type: ignore
|
1492
1548
|
|
1493
1549
|
if self.stop:
|
1494
|
-
return -1
|
1550
|
+
return -1, 0, 0
|
1495
1551
|
|
1496
1552
|
# drop shadowed folders
|
1497
1553
|
for sh_rd in unreg:
|
1498
1554
|
n = 0
|
1499
|
-
q = "select count(w) from up where (rd
|
1555
|
+
q = "select count(w) from up where (rd=? or rd like ?||'/%') and +at == 0"
|
1500
1556
|
for sh_erd in [sh_rd, "//" + w8b64enc(sh_rd)]:
|
1501
1557
|
try:
|
1502
|
-
|
1558
|
+
erd_erd = (sh_erd, sh_erd)
|
1559
|
+
n = db.c.execute(q, erd_erd).fetchone()[0]
|
1503
1560
|
break
|
1504
1561
|
except:
|
1505
1562
|
pass
|
1506
1563
|
|
1564
|
+
|
1507
1565
|
if n:
|
1508
1566
|
t = "forgetting {} shadowed autoindexed files in [{}] > [{}]"
|
1509
1567
|
self.log(t.format(n, top, sh_rd))
|
1510
|
-
assert sh_erd # type: ignore
|
1511
1568
|
|
1512
|
-
q = "delete from dh where (d = ? or d like ?||'
|
1513
|
-
db.c.execute(q,
|
1569
|
+
q = "delete from dh where (d = ? or d like ?||'/%')"
|
1570
|
+
db.c.execute(q, erd_erd)
|
1571
|
+
|
1572
|
+
q = "delete from up where (rd=? or rd like ?||'/%') and +at == 0"
|
1573
|
+
db.c.execute(q, erd_erd)
|
1574
|
+
tfa += n
|
1514
1575
|
|
1515
|
-
|
1516
|
-
|
1517
|
-
ret += n
|
1576
|
+
q = "delete from ds where (rd=? or rd like ?||'/%')"
|
1577
|
+
db.c.execute(q, erd_erd)
|
1518
1578
|
|
1519
1579
|
if n4g:
|
1520
|
-
return
|
1580
|
+
return tfa, tnf, rsz
|
1521
1581
|
|
1522
1582
|
# drop missing files
|
1523
1583
|
q = "select fn from up where rd = ?"
|
@@ -1535,7 +1595,7 @@ class Up2k(object):
|
|
1535
1595
|
if n_rm:
|
1536
1596
|
self.log("forgot {} deleted files".format(n_rm))
|
1537
1597
|
|
1538
|
-
return
|
1598
|
+
return tfa, tnf, rsz
|
1539
1599
|
|
1540
1600
|
def _drop_lost(self, cur , top , excl ) :
|
1541
1601
|
rm = []
|
@@ -1610,7 +1670,7 @@ class Up2k(object):
|
|
1610
1670
|
|
1611
1671
|
# then covers
|
1612
1672
|
n_rm3 = 0
|
1613
|
-
qu = "select 1 from up where rd=? and
|
1673
|
+
qu = "select 1 from up where rd=? and fn=? limit 1"
|
1614
1674
|
q = "delete from cv where rd=? and dn=? and +fn=?"
|
1615
1675
|
for crd, cdn, fn in cur.execute("select * from cv"):
|
1616
1676
|
urd = vjoin(crd, cdn)
|
@@ -1753,13 +1813,13 @@ class Up2k(object):
|
|
1753
1813
|
return 0
|
1754
1814
|
|
1755
1815
|
with self.mutex:
|
1816
|
+
q = "update up set w=?, sz=?, mt=? where rd=? and fn=?"
|
1756
1817
|
for rd, fn, w, sz, mt in rewark:
|
1757
|
-
q = "update up set w = ?, sz = ?, mt = ? where rd = ? and fn = ? limit 1"
|
1758
1818
|
cur.execute(q, (w, sz, int(mt), rd, fn))
|
1759
1819
|
|
1760
|
-
|
1761
|
-
q = "delete from up where
|
1762
|
-
cur.
|
1820
|
+
if f404:
|
1821
|
+
q = "delete from up where rd=? and fn=? and +w=?"
|
1822
|
+
cur.executemany(q, f404)
|
1763
1823
|
|
1764
1824
|
cur.connection.commit()
|
1765
1825
|
|
@@ -2226,7 +2286,6 @@ class Up2k(object):
|
|
2226
2286
|
# mp.pool.ThreadPool and concurrent.futures.ThreadPoolExecutor
|
2227
2287
|
# both do crazy runahead so lets reinvent another wheel
|
2228
2288
|
nw = max(1, self.args.mtag_mt)
|
2229
|
-
assert self.mtag
|
2230
2289
|
if not self.mpool_used:
|
2231
2290
|
self.mpool_used = True
|
2232
2291
|
self.log("using {}x {}".format(nw, self.mtag.backend))
|
@@ -2300,7 +2359,6 @@ class Up2k(object):
|
|
2300
2359
|
at ,
|
2301
2360
|
) :
|
2302
2361
|
"""will mutex(main)"""
|
2303
|
-
assert self.mtag
|
2304
2362
|
|
2305
2363
|
try:
|
2306
2364
|
st = bos.stat(abspath)
|
@@ -2332,7 +2390,6 @@ class Up2k(object):
|
|
2332
2390
|
tags ,
|
2333
2391
|
) :
|
2334
2392
|
"""mutex(main) me"""
|
2335
|
-
assert self.mtag
|
2336
2393
|
|
2337
2394
|
if not bos.path.isfile(abspath):
|
2338
2395
|
return 0
|
@@ -2388,7 +2445,7 @@ class Up2k(object):
|
|
2388
2445
|
def _log_sqlite_incompat(self, db_path, t0) :
|
2389
2446
|
txt = t0 or ""
|
2390
2447
|
digest = hashlib.sha512(db_path.encode("utf-8", "replace")).digest()
|
2391
|
-
stackname =
|
2448
|
+
stackname = ub64enc(digest[:9]).decode("ascii")
|
2392
2449
|
stackpath = os.path.join(E.cfg, "stack-%s.txt" % (stackname,))
|
2393
2450
|
|
2394
2451
|
t = " the filesystem at %s may not support locking, or is otherwise incompatible with sqlite\n\n %s\n\n"
|
@@ -2431,12 +2488,11 @@ class Up2k(object):
|
|
2431
2488
|
self.log("WARN: failed to upgrade from v4", 3)
|
2432
2489
|
|
2433
2490
|
if ver == DB_VER:
|
2434
|
-
|
2435
|
-
|
2436
|
-
|
2437
|
-
|
2438
|
-
|
2439
|
-
pass
|
2491
|
+
self._add_dhash_tab(cur)
|
2492
|
+
self._add_xiu_tab(cur)
|
2493
|
+
self._add_cv_tab(cur)
|
2494
|
+
self._add_idx_up_vp(cur, db_path)
|
2495
|
+
self._add_ds_tab(cur)
|
2440
2496
|
|
2441
2497
|
try:
|
2442
2498
|
nfiles = next(cur.execute("select count(w) from up"))[0]
|
@@ -2533,9 +2589,10 @@ class Up2k(object):
|
|
2533
2589
|
|
2534
2590
|
for cmd in [
|
2535
2591
|
r"create table up (w text, mt int, sz int, rd text, fn text, ip text, at int)",
|
2536
|
-
r"create index
|
2592
|
+
r"create index up_vp on up(rd, fn)",
|
2537
2593
|
r"create index up_fn on up(fn)",
|
2538
2594
|
r"create index up_ip on up(ip)",
|
2595
|
+
r"create index up_at on up(at)",
|
2539
2596
|
idx,
|
2540
2597
|
r"create table mt (w text, k text, v int)",
|
2541
2598
|
r"create index mt_w on mt(w)",
|
@@ -2549,6 +2606,7 @@ class Up2k(object):
|
|
2549
2606
|
self._add_dhash_tab(cur)
|
2550
2607
|
self._add_xiu_tab(cur)
|
2551
2608
|
self._add_cv_tab(cur)
|
2609
|
+
self._add_ds_tab(cur)
|
2552
2610
|
self.log("created DB at {}".format(db_path))
|
2553
2611
|
return cur
|
2554
2612
|
|
@@ -2565,6 +2623,12 @@ class Up2k(object):
|
|
2565
2623
|
|
2566
2624
|
def _add_dhash_tab(self, cur ) :
|
2567
2625
|
# v5 -> v5a
|
2626
|
+
try:
|
2627
|
+
cur.execute("select d, h from dh limit 1").fetchone()
|
2628
|
+
return
|
2629
|
+
except:
|
2630
|
+
pass
|
2631
|
+
|
2568
2632
|
for cmd in [
|
2569
2633
|
r"create table dh (d text, h text)",
|
2570
2634
|
r"create index dh_d on dh(d)",
|
@@ -2618,6 +2682,40 @@ class Up2k(object):
|
|
2618
2682
|
|
2619
2683
|
cur.connection.commit()
|
2620
2684
|
|
2685
|
+
def _add_idx_up_vp(self, cur , db_path ) :
|
2686
|
+
# v5c -> v5d
|
2687
|
+
try:
|
2688
|
+
cur.execute("drop index up_rd")
|
2689
|
+
except:
|
2690
|
+
return
|
2691
|
+
|
2692
|
+
for cmd in [
|
2693
|
+
r"create index up_vp on up(rd, fn)",
|
2694
|
+
r"create index up_at on up(at)",
|
2695
|
+
]:
|
2696
|
+
self.log("upgrading db [%s]: %s" % (db_path, cmd[:18]))
|
2697
|
+
cur.execute(cmd)
|
2698
|
+
|
2699
|
+
self.log("upgrading db [%s]: writing to disk..." % (db_path,))
|
2700
|
+
cur.connection.commit()
|
2701
|
+
cur.execute("vacuum")
|
2702
|
+
|
2703
|
+
def _add_ds_tab(self, cur ) :
|
2704
|
+
# v5d -> v5e
|
2705
|
+
try:
|
2706
|
+
cur.execute("select rd, sz from ds limit 1").fetchone()
|
2707
|
+
return
|
2708
|
+
except:
|
2709
|
+
pass
|
2710
|
+
|
2711
|
+
for cmd in [
|
2712
|
+
r"create table ds (rd text, sz int, nf int)",
|
2713
|
+
r"create index ds_rd on ds(rd)",
|
2714
|
+
]:
|
2715
|
+
cur.execute(cmd)
|
2716
|
+
|
2717
|
+
cur.connection.commit()
|
2718
|
+
|
2621
2719
|
def wake_rescanner(self):
|
2622
2720
|
with self.rescan_cond:
|
2623
2721
|
self.rescan_cond.notify_all()
|
@@ -2802,7 +2900,6 @@ class Up2k(object):
|
|
2802
2900
|
|
2803
2901
|
c2 = cur
|
2804
2902
|
|
2805
|
-
assert c2
|
2806
2903
|
c2.connection.commit()
|
2807
2904
|
|
2808
2905
|
cur = jcur
|
@@ -2843,7 +2940,7 @@ class Up2k(object):
|
|
2843
2940
|
self.log(t)
|
2844
2941
|
del reg[wark]
|
2845
2942
|
|
2846
|
-
elif inc_ap != orig_ap and not data_ok:
|
2943
|
+
elif inc_ap != orig_ap and not data_ok and "done" in reg[wark]:
|
2847
2944
|
self.log("asserting contents of %s" % (orig_ap,))
|
2848
2945
|
dhashes, _ = self._hashlist_from_file(orig_ap)
|
2849
2946
|
dwark = up2k_wark_from_hashlist(self.salt, st.st_size, dhashes)
|
@@ -2907,9 +3004,12 @@ class Up2k(object):
|
|
2907
3004
|
job = deepcopy(job)
|
2908
3005
|
job["wark"] = wark
|
2909
3006
|
job["at"] = cj.get("at") or time.time()
|
2910
|
-
zs = "
|
3007
|
+
zs = "vtop ptop prel name lmod host user addr poke"
|
2911
3008
|
for k in zs.split():
|
2912
3009
|
job[k] = cj.get(k) or ""
|
3010
|
+
for k in ("life", "replace"):
|
3011
|
+
if k in cj:
|
3012
|
+
job[k] = cj[k]
|
2913
3013
|
|
2914
3014
|
pdir = djoin(cj["ptop"], cj["prel"])
|
2915
3015
|
if rand:
|
@@ -3010,18 +3110,8 @@ class Up2k(object):
|
|
3010
3110
|
"busy": {},
|
3011
3111
|
}
|
3012
3112
|
# client-provided, sanitized by _get_wark: name, size, lmod
|
3013
|
-
|
3014
|
-
|
3015
|
-
"user",
|
3016
|
-
"addr",
|
3017
|
-
"vtop",
|
3018
|
-
"ptop",
|
3019
|
-
"prel",
|
3020
|
-
"name",
|
3021
|
-
"size",
|
3022
|
-
"lmod",
|
3023
|
-
"poke",
|
3024
|
-
]:
|
3113
|
+
zs = "vtop ptop prel name size lmod host user addr poke"
|
3114
|
+
for k in zs.split():
|
3025
3115
|
job[k] = cj[k]
|
3026
3116
|
|
3027
3117
|
for k in ["life", "replace"]:
|
@@ -3104,7 +3194,22 @@ class Up2k(object):
|
|
3104
3194
|
fp = djoin(fdir, fname)
|
3105
3195
|
if job.get("replace") and bos.path.exists(fp):
|
3106
3196
|
self.log("replacing existing file at {}".format(fp))
|
3107
|
-
|
3197
|
+
cur = None
|
3198
|
+
ptop = job["ptop"]
|
3199
|
+
vf = self.flags.get(ptop) or {}
|
3200
|
+
st = bos.stat(fp)
|
3201
|
+
try:
|
3202
|
+
vrel = vjoin(job["prel"], fname)
|
3203
|
+
xlink = bool(vf.get("xlink"))
|
3204
|
+
cur, wark, _, _, _, _ = self._find_from_vpath(ptop, vrel)
|
3205
|
+
self._forget_file(ptop, vrel, cur, wark, True, st.st_size, xlink)
|
3206
|
+
except Exception as ex:
|
3207
|
+
self.log("skipping replace-relink: %r" % (ex,))
|
3208
|
+
finally:
|
3209
|
+
if cur:
|
3210
|
+
cur.connection.commit()
|
3211
|
+
|
3212
|
+
wunlink(self.log, fp, vf)
|
3108
3213
|
|
3109
3214
|
if self.args.plain_ip:
|
3110
3215
|
dip = ip.replace(":", ".")
|
@@ -3112,8 +3217,9 @@ class Up2k(object):
|
|
3112
3217
|
dip = self.hub.iphash.s(ip)
|
3113
3218
|
|
3114
3219
|
suffix = "-%.6f-%s" % (ts, dip)
|
3115
|
-
|
3116
|
-
|
3220
|
+
f, ret = ren_open(fname, "wb", fdir=fdir, suffix=suffix)
|
3221
|
+
f.close()
|
3222
|
+
return ret
|
3117
3223
|
|
3118
3224
|
def _symlink(
|
3119
3225
|
self,
|
@@ -3260,7 +3366,6 @@ class Up2k(object):
|
|
3260
3366
|
t = "that chunk is already being written to:\n {}\n {} {}/{}\n {}"
|
3261
3367
|
raise Pebkac(400, t.format(wark, chash, idx, nh, job["name"]))
|
3262
3368
|
|
3263
|
-
assert chash # type: ignore
|
3264
3369
|
chunksize = up2k_chunksize(job["size"])
|
3265
3370
|
|
3266
3371
|
coffsets = []
|
@@ -3295,19 +3400,30 @@ class Up2k(object):
|
|
3295
3400
|
|
3296
3401
|
return chashes, chunksize, coffsets, path, job["lmod"], job["sprs"]
|
3297
3402
|
|
3298
|
-
def
|
3299
|
-
|
3300
|
-
|
3301
|
-
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
|
3403
|
+
def fast_confirm_chunks(
|
3404
|
+
self, ptop , wark , chashes
|
3405
|
+
) :
|
3406
|
+
if not self.mutex.acquire(False):
|
3407
|
+
return -1, ""
|
3408
|
+
if not self.reg_mutex.acquire(False):
|
3409
|
+
self.mutex.release()
|
3410
|
+
return -1, ""
|
3411
|
+
try:
|
3412
|
+
return self._confirm_chunks(ptop, wark, chashes)
|
3413
|
+
finally:
|
3414
|
+
self.reg_mutex.release()
|
3415
|
+
self.mutex.release()
|
3306
3416
|
|
3307
3417
|
def confirm_chunks(
|
3308
3418
|
self, ptop , wark , chashes
|
3309
3419
|
) :
|
3310
3420
|
with self.mutex, self.reg_mutex:
|
3421
|
+
return self._confirm_chunks(ptop, wark, chashes)
|
3422
|
+
|
3423
|
+
def _confirm_chunks(
|
3424
|
+
self, ptop , wark , chashes
|
3425
|
+
) :
|
3426
|
+
if True:
|
3311
3427
|
self.db_act = self.vol_act[ptop] = time.time()
|
3312
3428
|
try:
|
3313
3429
|
job = self.registry[ptop][wark]
|
@@ -3315,7 +3431,7 @@ class Up2k(object):
|
|
3315
3431
|
src = djoin(pdir, job["tnam"])
|
3316
3432
|
dst = djoin(pdir, job["name"])
|
3317
3433
|
except Exception as ex:
|
3318
|
-
return "confirm_chunk, wark(%r)" % (ex,) # type: ignore
|
3434
|
+
return -2, "confirm_chunk, wark(%r)" % (ex,) # type: ignore
|
3319
3435
|
|
3320
3436
|
for chash in chashes:
|
3321
3437
|
job["busy"].pop(chash, None)
|
@@ -3324,7 +3440,7 @@ class Up2k(object):
|
|
3324
3440
|
for chash in chashes:
|
3325
3441
|
job["need"].remove(chash)
|
3326
3442
|
except Exception as ex:
|
3327
|
-
return "confirm_chunk, chash(%s) %r" % (chash, ex) # type: ignore
|
3443
|
+
return -2, "confirm_chunk, chash(%s) %r" % (chash, ex) # type: ignore
|
3328
3444
|
|
3329
3445
|
ret = len(job["need"])
|
3330
3446
|
if ret > 0:
|
@@ -3473,7 +3589,6 @@ class Up2k(object):
|
|
3473
3589
|
cur.connection.commit()
|
3474
3590
|
except Exception as ex:
|
3475
3591
|
x = self.register_vpath(ptop, {})
|
3476
|
-
assert x
|
3477
3592
|
db_ex_chk(self.log, ex, x[1])
|
3478
3593
|
raise
|
3479
3594
|
|
@@ -3488,7 +3603,6 @@ class Up2k(object):
|
|
3488
3603
|
try:
|
3489
3604
|
r = db.execute(sql, (rd, fn))
|
3490
3605
|
except:
|
3491
|
-
assert self.mem_cur
|
3492
3606
|
r = db.execute(sql, s3enc(self.mem_cur, rd, fn))
|
3493
3607
|
|
3494
3608
|
if r.rowcount:
|
@@ -3526,7 +3640,6 @@ class Up2k(object):
|
|
3526
3640
|
try:
|
3527
3641
|
db.execute(sql, v)
|
3528
3642
|
except:
|
3529
|
-
assert self.mem_cur
|
3530
3643
|
rd, fn = s3enc(self.mem_cur, rd, fn)
|
3531
3644
|
v = (wark, int(ts), sz, rd, fn, db_ip, int(at or 0))
|
3532
3645
|
db.execute(sql, v)
|
@@ -3574,7 +3687,6 @@ class Up2k(object):
|
|
3574
3687
|
try:
|
3575
3688
|
db.execute(q, (cd, wark[:16], rd, fn))
|
3576
3689
|
except:
|
3577
|
-
assert self.mem_cur
|
3578
3690
|
rd, fn = s3enc(self.mem_cur, rd, fn)
|
3579
3691
|
db.execute(q, (cd, wark[:16], rd, fn))
|
3580
3692
|
|
@@ -3607,6 +3719,19 @@ class Up2k(object):
|
|
3607
3719
|
except:
|
3608
3720
|
pass
|
3609
3721
|
|
3722
|
+
if "nodirsz" not in vflags:
|
3723
|
+
try:
|
3724
|
+
q = "update ds set nf=nf+1, sz=sz+? where rd=?"
|
3725
|
+
q2 = "insert into ds values(?,?,1)"
|
3726
|
+
while True:
|
3727
|
+
if not db.execute(q, (sz, rd)).rowcount:
|
3728
|
+
db.execute(q2, (rd, sz))
|
3729
|
+
if not rd:
|
3730
|
+
break
|
3731
|
+
rd = rd.rsplit("/", 1)[0] if "/" in rd else ""
|
3732
|
+
except:
|
3733
|
+
pass
|
3734
|
+
|
3610
3735
|
def handle_rm(
|
3611
3736
|
self,
|
3612
3737
|
uname ,
|
@@ -3991,7 +4116,6 @@ class Up2k(object):
|
|
3991
4116
|
|
3992
4117
|
has_dupes = False
|
3993
4118
|
if w:
|
3994
|
-
assert c1
|
3995
4119
|
if c2 and c2 != c1:
|
3996
4120
|
self._copy_tags(c1, c2, w)
|
3997
4121
|
|
@@ -4129,7 +4253,6 @@ class Up2k(object):
|
|
4129
4253
|
try:
|
4130
4254
|
c = cur.execute(q, (rd, fn))
|
4131
4255
|
except:
|
4132
|
-
assert self.mem_cur
|
4133
4256
|
c = cur.execute(q, s3enc(self.mem_cur, rd, fn))
|
4134
4257
|
|
4135
4258
|
hit = c.fetchone()
|
@@ -4372,8 +4495,7 @@ class Up2k(object):
|
|
4372
4495
|
rem -= len(buf)
|
4373
4496
|
|
4374
4497
|
digest = hashobj.digest()[:33]
|
4375
|
-
|
4376
|
-
ret.append(digest.decode("utf-8"))
|
4498
|
+
ret.append(ub64enc(digest).decode("ascii"))
|
4377
4499
|
|
4378
4500
|
return ret, st
|
4379
4501
|
|
@@ -4445,8 +4567,8 @@ class Up2k(object):
|
|
4445
4567
|
dip = self.hub.iphash.s(job["addr"])
|
4446
4568
|
|
4447
4569
|
suffix = "-%.6f-%s" % (job["t0"], dip)
|
4448
|
-
|
4449
|
-
|
4570
|
+
f, job["tnam"] = ren_open(tnam, "wb", fdir=pdir, suffix=suffix)
|
4571
|
+
try:
|
4450
4572
|
abspath = djoin(pdir, job["tnam"])
|
4451
4573
|
sprs = job["sprs"]
|
4452
4574
|
sz = job["size"]
|
@@ -4493,6 +4615,8 @@ class Up2k(object):
|
|
4493
4615
|
if job["hash"] and sprs:
|
4494
4616
|
f.seek(sz - 1)
|
4495
4617
|
f.write(b"e")
|
4618
|
+
finally:
|
4619
|
+
f.close()
|
4496
4620
|
|
4497
4621
|
if not job["hash"]:
|
4498
4622
|
self._finish_upload(job["ptop"], job["wark"])
|
@@ -4835,11 +4959,10 @@ def up2k_wark_from_hashlist(salt , filesize , hashes ) :
|
|
4835
4959
|
vstr = "\n".join(values)
|
4836
4960
|
|
4837
4961
|
wark = hashlib.sha512(vstr.encode("utf-8")).digest()[:33]
|
4838
|
-
|
4839
|
-
return wark.decode("ascii")
|
4962
|
+
return ub64enc(wark).decode("ascii")
|
4840
4963
|
|
4841
4964
|
|
4842
4965
|
def up2k_wark_from_metadata(salt , sz , lastmod , rd , fn ) :
|
4843
4966
|
ret = sfsenc("%s\n%d\n%d\n%s\n%s" % (salt, lastmod, sz, rd, fn))
|
4844
|
-
ret =
|
4967
|
+
ret = ub64enc(hashlib.sha512(ret).digest())
|
4845
4968
|
return ("#%s" % (ret.decode("ascii"),))[:44]
|