From a6935b029324046821dca72ff8de96b02705034d Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 2 Oct 2021 23:34:12 +0200 Subject: [PATCH] allow uploading empty files --- copyparty/up2k.py | 89 +++++++++++++++++++++++++------------------ copyparty/web/up2k.js | 71 ++++++++++++++++++++-------------- copyparty/web/util.js | 2 +- 3 files changed, 96 insertions(+), 66 deletions(-) diff --git a/copyparty/up2k.py b/copyparty/up2k.py index bee9f333..13386b62 100644 --- a/copyparty/up2k.py +++ b/copyparty/up2k.py @@ -1362,53 +1362,56 @@ class Up2k(object): # del self.registry[ptop][wark] return ret, dst - # windows cant rename open files - if not ANYWIN or src == dst: - self.finish_upload(ptop, wark) + # windows cant rename open files + if not ANYWIN or src == dst: + self._finish_upload(ptop, wark) return ret, dst def finish_upload(self, ptop, wark): with self.mutex: - try: - job = self.registry[ptop][wark] - pdir = os.path.join(job["ptop"], job["prel"]) - src = os.path.join(pdir, job["tnam"]) - dst = os.path.join(pdir, job["name"]) - except Exception as ex: - return "finish_upload, wark, " + repr(ex) + self._finish_upload(ptop, wark) - # self.log("--- " + wark + " " + dst + " finish_upload atomic " + dst, 4) - atomic_move(src, dst) + def _finish_upload(self, ptop, wark): + try: + job = self.registry[ptop][wark] + pdir = os.path.join(job["ptop"], job["prel"]) + src = os.path.join(pdir, job["tnam"]) + dst = os.path.join(pdir, job["name"]) + except Exception as ex: + return "finish_upload, wark, " + repr(ex) - if ANYWIN: - a = [dst, job["size"], (int(time.time()), int(job["lmod"]))] - self.lastmod_q.put(a) + # self.log("--- " + wark + " " + dst + " finish_upload atomic " + dst, 4) + atomic_move(src, dst) - a = [job[x] for x in "ptop wark prel name lmod size addr".split()] - a += [job.get("at") or time.time()] - if self.idx_wark(*a): - # self.log("pop " + wark + " " + dst + " finish_upload idx_wark", 4) - del self.registry[ptop][wark] - # in-memory registry is reserved for unfinished uploads + if ANYWIN: + a = [dst, job["size"], (int(time.time()), int(job["lmod"]))] + self.lastmod_q.put(a) - dupes = self.dupesched.pop(dst, []) - if not dupes: - return + a = [job[x] for x in "ptop wark prel name lmod size addr".split()] + a += [job.get("at") or time.time()] + if self.idx_wark(*a): + # self.log("pop " + wark + " " + dst + " finish_upload idx_wark", 4) + del self.registry[ptop][wark] + # in-memory registry is reserved for unfinished uploads - cur = self.cur.get(ptop) - for rd, fn in dupes: - d2 = os.path.join(ptop, rd, fn) - if os.path.exists(d2): - continue + dupes = self.dupesched.pop(dst, []) + if not dupes: + return - self._symlink(dst, d2) - if cur: - self.db_rm(cur, rd, fn) - self.db_add(cur, wark, rd, fn, *a[-4:]) + cur = self.cur.get(ptop) + for rd, fn in dupes: + d2 = os.path.join(ptop, rd, fn) + if os.path.exists(d2): + continue + self._symlink(dst, d2) if cur: - cur.connection.commit() + self.db_rm(cur, rd, fn) + self.db_add(cur, wark, rd, fn, *a[-4:]) + + if cur: + cur.connection.commit() def idx_wark(self, ptop, wark, rd, fn, lmod, sz, ip, at): cur = self.cur.get(ptop) @@ -1768,7 +1771,13 @@ class Up2k(object): except: cj["lmod"] = int(time.time()) - wark = up2k_wark_from_hashlist(self.salt, cj["size"], cj["hash"]) + if cj["hash"]: + wark = up2k_wark_from_hashlist(self.salt, cj["size"], cj["hash"]) + else: + wark = up2k_wark_from_metadata( + self.salt, cj["size"], cj["lmod"], cj["prel"], cj["name"] + ) + return wark def _hashlist_from_file(self, path): @@ -1811,6 +1820,8 @@ class Up2k(object): if self.args.nw: job["tnam"] = tnam + if not job["hash"]: + del self.registry[job["ptop"]][job["wark"]] return suffix = ".{:.6f}-{}".format(job["t0"], job["addr"]) @@ -1827,8 +1838,12 @@ class Up2k(object): except: self.log("could not sparse [{}]".format(fp), 3) - f.seek(job["size"] - 1) - f.write(b"e") + if job["hash"]: + f.seek(job["size"] - 1) + f.write(b"e") + + if not job["hash"]: + self._finish_upload(job["ptop"], job["wark"]) def _lastmodder(self): while True: diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js index 1d159df9..6411c67f 100644 --- a/copyparty/web/up2k.js +++ b/copyparty/web/up2k.js @@ -744,11 +744,14 @@ function up2k_init(subtle) { more_one_file(); var bad_files = [], + nil_files = [], good_files = [], dirs = []; for (var a = 0; a < files.length; a++) { - var fobj = files[a]; + var fobj = files[a], + dst = good_files; + if (is_itemlist) { if (fobj.kind !== 'file') continue; @@ -765,16 +768,15 @@ function up2k_init(subtle) { } try { if (fobj.size < 1) - throw 1; + dst = nil_files; } catch (ex) { - bad_files.push(fobj.name); - continue; + dst = bad_files; } - good_files.push([fobj, fobj.name]); + dst.push([fobj, fobj.name]); } if (dirs) { - return read_dirs(null, [], dirs, good_files, bad_files); + return read_dirs(null, [], dirs, good_files, nil_files, bad_files); } } @@ -788,7 +790,7 @@ function up2k_init(subtle) { } var rd_missing_ref = []; - function read_dirs(rd, pf, dirs, good, bad, spins) { + function read_dirs(rd, pf, dirs, good, nil, bad, spins) { spins = spins || 0; if (++spins == 5) rd_missing_ref = rd_flatten(pf, dirs); @@ -809,7 +811,7 @@ function up2k_init(subtle) { msg.push('
  • ' + esc(missing[a]) + '
  • '); return modal.alert(msg.join('') + '', function () { - read_dirs(rd, [], [], good, bad, spins); + read_dirs(rd, [], [], good, nil, bad, spins); }); } spins = 0; @@ -817,11 +819,11 @@ function up2k_init(subtle) { if (!dirs.length) { if (!pf.length) - return gotallfiles(good, bad); + return gotallfiles(good, nil, bad); console.log("retry pf, " + pf.length); setTimeout(function () { - read_dirs(rd, pf, dirs, good, bad, spins); + read_dirs(rd, pf, dirs, good, nil, bad, spins); }, 50); return; } @@ -843,14 +845,15 @@ function up2k_init(subtle) { pf.push(name); dn.file(function (fobj) { apop(pf, name); + var dst = good; try { - if (fobj.size > 0) { - good.push([fobj, name]); - return; - } + if (fobj.size < 1) + dst = nil; } - catch (ex) { } - bad.push(name); + catch (ex) { + dst = bad; + } + dst.push([fobj, name]); }); } ngot += 1; @@ -859,23 +862,33 @@ function up2k_init(subtle) { dirs.shift(); rd = null; } - return read_dirs(rd, pf, dirs, good, bad, spins); + return read_dirs(rd, pf, dirs, good, nil, bad, spins); }); } - function gotallfiles(good_files, bad_files) { + function gotallfiles(good_files, nil_files, bad_files) { + var ntot = good_files.concat(nil_files, bad_files).length; if (bad_files.length) { - var ntot = bad_files.length + good_files.length, - msg = 'These {0} files (of {1} total) were skipped because they are empty:\n'.format(bad_files.length, ntot); - + var msg = 'These {0} files (of {1} total) were skipped, possibly due to filesystem permissions:\n'.format(bad_files.length, ntot); for (var a = 0, aa = Math.min(20, bad_files.length); a < aa; a++) - msg += '-- ' + bad_files[a] + '\n'; - - if (good_files.length - bad_files.length <= 1 && ANDROID) - msg += '\nFirefox-Android has a bug which prevents selecting multiple files. Try selecting one file at a time. For more info, see firefox bug 1456557'; + msg += '-- ' + bad_files[a][1] + '\n'; + msg += '\nMaybe it works better if you select just one file'; return modal.alert(msg, function () { - gotallfiles(good_files, []); + gotallfiles(good_files, nil_files, []); + }); + } + + if (nil_files.length) { + var msg = 'These {0} files (of {1} total) are blank/empty; upload them anyways?\n'.format(nil_files.length, ntot); + for (var a = 0, aa = Math.min(20, nil_files.length); a < aa; a++) + msg += '-- ' + nil_files[a][1] + '\n'; + + msg += '\nMaybe it works better if you select just one file'; + return modal.confirm(msg, function () { + gotallfiles(good_files.concat(nil_files), [], []); + }, function () { + gotallfiles(good_files, [], []); }); } @@ -921,7 +934,7 @@ function up2k_init(subtle) { "t0": now, "fobj": fobj, "name": name, - "size": fobj.size, + "size": fobj.size || 0, "lmod": lmod / 1000, "purl": fdir, "done": false, @@ -946,7 +959,9 @@ function up2k_init(subtle) { st.bytes.total += fobj.size; st.files.push(entry); - if (uc.turbo) + if (!entry.size) + push_t(st.todo.handshake, entry); + else if (uc.turbo) push_t(st.todo.head, entry); else push_t(st.todo.hash, entry); diff --git a/copyparty/web/util.js b/copyparty/web/util.js index a0b89fe2..95e1c694 100644 --- a/copyparty/web/util.js +++ b/copyparty/web/util.js @@ -1049,7 +1049,7 @@ var modal = (function () { } function _confirm(html, cok, cng, fun) { cb_ok = cok; - cb_ng = cng === undefined ? cok : null; + cb_ng = cng === undefined ? cok : cng; cb_up = fun; html += '
    ' + ok_cancel + '
    '; r.show(html);