Skip to content

Commit 6eee601

Browse files
committed
fix u2c --ow (overwrite/replace)
the u2c flag to overwrite files on the server became no-op in v1.13.8
1 parent 2fac2be commit 6eee601

File tree

2 files changed

+91
-23
lines changed

2 files changed

+91
-23
lines changed

copyparty/up2k.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2846,7 +2846,7 @@ def _handle_json(self, cj: dict[str, Any], depth: int = 1) -> dict[str, Any]:
28462846
self.log(t)
28472847
del reg[wark]
28482848

2849-
elif inc_ap != orig_ap and not data_ok:
2849+
elif inc_ap != orig_ap and not data_ok and "done" in reg[wark]:
28502850
self.log("asserting contents of %s" % (orig_ap,))
28512851
dhashes, _ = self._hashlist_from_file(orig_ap)
28522852
dwark = up2k_wark_from_hashlist(self.salt, st.st_size, dhashes)
@@ -3107,7 +3107,22 @@ def _untaken(self, fdir: str, job: dict[str, Any], ts: float) -> str:
31073107
fp = djoin(fdir, fname)
31083108
if job.get("replace") and bos.path.exists(fp):
31093109
self.log("replacing existing file at {}".format(fp))
3110-
wunlink(self.log, fp, self.flags.get(job["ptop"]) or {})
3110+
cur = None
3111+
ptop = job["ptop"]
3112+
vf = self.flags.get(ptop) or {}
3113+
st = bos.stat(fp)
3114+
try:
3115+
vrel = vjoin(job["prel"], fname)
3116+
xlink = bool(vf.get("xlink"))
3117+
cur, wark, _, _, _, _ = self._find_from_vpath(ptop, vrel)
3118+
self._forget_file(ptop, vrel, cur, wark, True, st.st_size, xlink)
3119+
except Exception as ex:
3120+
self.log("skipping replace-relink: %r" % (ex,))
3121+
finally:
3122+
if cur:
3123+
cur.connection.commit()
3124+
3125+
wunlink(self.log, fp, vf)
31113126

31123127
if self.args.plain_ip:
31133128
dip = ip.replace(":", ".")

tests/test_dedup.py

Lines changed: 74 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ class TestDedup(unittest.TestCase):
1919
def setUp(self):
2020
self.td = tu.get_ramdisk()
2121

22+
# (data, chash, wark)
23+
self.files = [
24+
(
25+
"one",
26+
"BfcDQQeKz2oG1CPSFyD5ZD1flTYm2IoCY23DqeeVgq6w",
27+
"XMbpLRqVdtGmgggqjUI6uSoNMTqZVX4K6zr74XA1BRKc",
28+
),
29+
(
30+
"two",
31+
"ko1Q0eJNq3zKYs_oT83Pn8aVFgonj5G1wK8itwnYL4qj",
32+
"fxvihWlnQIbVbUPr--TxyV41913kPLhXPD1ngXYxDfou",
33+
),
34+
]
35+
2236
def tearDown(self):
2337
os.chdir(tempfile.gettempdir())
2438
shutil.rmtree(self.td)
@@ -40,25 +54,54 @@ def cinit(self):
4054
if self.fstab:
4155
self.conn.hsrv.hub.up2k.fstab = self.fstab
4256

57+
def test_a(self):
58+
file404 = "\nJ2EOT"
59+
f1, f2 = self.files
60+
fns = ("f1", "f2", "f3")
61+
dn = "d"
62+
63+
self.conn = None
64+
self.fstab = None
65+
for e2d in [True, False]:
66+
self.args = Cfg(v=[".::A"], a=[], e2d=e2d)
67+
self.reset()
68+
self.cinit()
69+
70+
# dupes in parallel
71+
sfn, hs = self.do_post_hs(dn, fns[0], f1, True)
72+
for fn in fns[1:]:
73+
h, b = self.handshake(dn, fn, f1)
74+
self.assertIn(" 422 Unpro", h)
75+
self.assertIn("a different location;", b)
76+
self.do_post_data(dn, fns[0], f1, True, sfn, hs)
77+
if not e2d:
78+
# dupesched is e2d only; hs into existence
79+
for fn, data in zip(fns, (f1[0], file404, file404)):
80+
h, b = self.curl("%s/%s" % ("d", fn))
81+
self.assertEqual(b, data)
82+
for fn in fns[1:]:
83+
h, b = self.do_post_hs(dn, fn, f1, False)
84+
for fn in fns:
85+
h, b = self.curl("%s/%s" % ("d", fn))
86+
self.assertEqual(b, f1[0])
87+
88+
if not e2d:
89+
continue
90+
91+
# overwrite file
92+
sfn, hs = self.do_post_hs(dn, fns[0], f2, True, replace=True)
93+
self.do_post_data(dn, fns[0], f2, True, sfn, hs)
94+
for fn, f in zip(fns, (f2, f1, f1)):
95+
h, b = self.curl("%s/%s" % ("d", fn))
96+
self.assertEqual(b, f[0])
97+
4398
def test(self):
4499
quick = True # sufficient for regular smoketests
45100
# quick = False
46101

47102
dirnames = ["d1", "d2"]
48103
filenames = ["f1", "f2"]
49-
files = [
50-
(
51-
"one",
52-
"BfcDQQeKz2oG1CPSFyD5ZD1flTYm2IoCY23DqeeVgq6w",
53-
"XMbpLRqVdtGmgggqjUI6uSoNMTqZVX4K6zr74XA1BRKc",
54-
),
55-
(
56-
"two",
57-
"ko1Q0eJNq3zKYs_oT83Pn8aVFgonj5G1wK8itwnYL4qj",
58-
"fxvihWlnQIbVbUPr--TxyV41913kPLhXPD1ngXYxDfou",
59-
),
60-
]
61-
# (data, chash, wark)
104+
files = self.files
62105

63106
self.ctr = 336 if quick else 2016 # estimated total num uploads
64107
self.conn = None
@@ -127,10 +170,13 @@ def do_tc(self, cm1, cm2, cm3, irm):
127170
def do_post(self, dn, fn, fi, first):
128171
print("\n\n# do_post", self.ctr, repr((dn, fn, fi, first)))
129172
self.ctr -= 1
173+
sfn, hs = self.do_post_hs(dn, fn, fi, first)
174+
return self.do_post_data(dn, fn, fi, first, sfn, hs)
130175

131-
data, chash, wark = fi
132-
hs = self.handshake(dn, fn, fi)
133-
self.assertEqual(hs["wark"], wark)
176+
def do_post_hs(self, dn, fn, fi, first, replace=False):
177+
h, b = self.handshake(dn, fn, fi, replace=replace)
178+
hs = json.loads(b)
179+
self.assertEqual(hs["wark"], fi[2])
134180

135181
sfn = hs["name"]
136182
if sfn == fn:
@@ -140,6 +186,10 @@ def do_post(self, dn, fn, fi, first):
140186
if first:
141187
raise Exception("wait what")
142188

189+
return sfn, hs
190+
191+
def do_post_data(self, dn, fn, fi, first, sfn, hs):
192+
data, chash, wark = fi
143193
if hs["hash"]:
144194
self.assertEqual(hs["hash"][0], chash)
145195
self.put_chunk(dn, wark, chash, data)
@@ -150,16 +200,18 @@ def do_post(self, dn, fn, fi, first):
150200
self.assertEqual(b, data)
151201
return sfn
152202

153-
def handshake(self, dn, fn, fi):
203+
def handshake(self, dn, fn, fi, replace=False):
154204
hdr = "POST /%s/ HTTP/1.1\r\nConnection: close\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n"
155205
msg = {"name": fn, "size": 3, "lmod": 1234567890, "life": 0, "hash": [fi[1]]}
206+
if replace:
207+
msg["replace"] = True
156208
buf = json.dumps(msg).encode("utf-8")
157209
buf = (hdr % (dn, len(buf))).encode("utf-8") + buf
158-
print("HS -->", buf)
210+
# print("HS -->", buf)
159211
HttpCli(self.conn.setbuf(buf)).run()
160212
ret = self.conn.s._reply.decode("utf-8").split("\r\n\r\n", 1)
161-
print("HS <--", ret)
162-
return json.loads(ret[1])
213+
# print("HS <--", ret)
214+
return ret
163215

164216
def put_chunk(self, dn, wark, chash, data):
165217
msg = [
@@ -173,14 +225,15 @@ def put_chunk(self, dn, wark, chash, data):
173225
data,
174226
]
175227
buf = "\r\n".join(msg).encode("utf-8")
176-
print("PUT -->", buf)
228+
# print("PUT -->", buf)
177229
HttpCli(self.conn.setbuf(buf)).run()
178230
ret = self.conn.s._reply.decode("utf-8").split("\r\n\r\n", 1)
179231
self.assertEqual(ret[1], "thank")
180232

181233
def curl(self, url, binary=False, meth=None):
182234
h = "%s /%s HTTP/1.1\r\nConnection: close\r\n\r\n"
183235
h = h % (meth or "GET", url)
236+
# print("CURL -->", url)
184237
HttpCli(self.conn.setbuf(h.encode("utf-8"))).run()
185238
if binary:
186239
h, b = self.conn.s._reply.split(b"\r\n\r\n", 1)

0 commit comments

Comments
 (0)