1 | #include <assert.h> |
---|
2 | #include <errno.h> |
---|
3 | #include <stdio.h> /* remove() */ |
---|
4 | #include <string.h> /* strcmp() */ |
---|
5 | #include <stdio.h> |
---|
6 | |
---|
7 | #include <sys/types.h> /* stat() */ |
---|
8 | #include <sys/stat.h> /* stat() */ |
---|
9 | #include <unistd.h> /* stat(), sync() */ |
---|
10 | |
---|
11 | #include "transmission.h" |
---|
12 | #include "resume.h" |
---|
13 | #include "torrent.h" /* tr_isTorrent() */ |
---|
14 | #include "utils.h" /* tr_mkdirp() */ |
---|
15 | #include "variant.h" |
---|
16 | |
---|
17 | #include "libtransmission-test.h" |
---|
18 | |
---|
19 | /*** |
---|
20 | **** |
---|
21 | ***/ |
---|
22 | |
---|
23 | #define verify_and_block_until_done(tor) \ |
---|
24 | do { \ |
---|
25 | tr_torrentVerify (tor); \ |
---|
26 | do { \ |
---|
27 | tr_wait_msec (10); \ |
---|
28 | } while (tor->verifyState != TR_VERIFY_NONE); \ |
---|
29 | } while (0) |
---|
30 | |
---|
31 | #define check_have_none(tor, totalSize) \ |
---|
32 | do { \ |
---|
33 | const tr_stat * st = tr_torrentStat(tor); \ |
---|
34 | check_int_eq (TR_STATUS_STOPPED, st->activity); \ |
---|
35 | check_int_eq (TR_STAT_OK, st->error); \ |
---|
36 | check_int_eq (totalSize, st->sizeWhenDone); \ |
---|
37 | check_int_eq (totalSize, st->leftUntilDone); \ |
---|
38 | check_int_eq (totalSize, tor->info.totalSize); \ |
---|
39 | check_int_eq (0, st->haveValid); \ |
---|
40 | } while (0) |
---|
41 | |
---|
42 | #define check_have_all(tor, totalSize) \ |
---|
43 | do { \ |
---|
44 | const tr_stat * st = tr_torrentStat(tor); \ |
---|
45 | check_int_eq (TR_STATUS_STOPPED, st->activity); \ |
---|
46 | check_int_eq (TR_STAT_OK, st->error); \ |
---|
47 | check_int_eq (0, st->leftUntilDone); \ |
---|
48 | check_int_eq (0, st->haveUnchecked); \ |
---|
49 | check_int_eq (0, st->desiredAvailable); \ |
---|
50 | check_int_eq (totalSize, st->sizeWhenDone); \ |
---|
51 | check_int_eq (totalSize, st->haveValid); \ |
---|
52 | } while (0) |
---|
53 | |
---|
54 | static bool |
---|
55 | testFileExistsAndConsistsOfThisString (const tr_torrent * tor, tr_file_index_t fileIndex, const char * str) |
---|
56 | { |
---|
57 | char * path; |
---|
58 | const size_t str_len = strlen (str); |
---|
59 | bool success = false; |
---|
60 | |
---|
61 | path = tr_torrentFindFile (tor, fileIndex); |
---|
62 | if (path != NULL) |
---|
63 | { |
---|
64 | uint8_t * contents; |
---|
65 | size_t contents_len; |
---|
66 | |
---|
67 | assert (tr_fileExists (path, NULL)); |
---|
68 | |
---|
69 | contents = tr_loadFile (path, &contents_len); |
---|
70 | |
---|
71 | success = (str_len == contents_len) |
---|
72 | && (!memcmp (contents, str, contents_len)); |
---|
73 | |
---|
74 | tr_free (contents); |
---|
75 | tr_free (path); |
---|
76 | } |
---|
77 | |
---|
78 | return success; |
---|
79 | } |
---|
80 | |
---|
81 | static void |
---|
82 | onRenameDone (tr_torrent * tor UNUSED, const char * oldpath UNUSED, const char * newname UNUSED, int error, void * user_data) |
---|
83 | { |
---|
84 | *(int*)user_data = error; |
---|
85 | } |
---|
86 | |
---|
87 | static int |
---|
88 | torrentRenameAndWait (tr_torrent * tor, |
---|
89 | const char * oldpath, |
---|
90 | const char * newname) |
---|
91 | { |
---|
92 | int error = -1; |
---|
93 | tr_torrentRenamePath (tor, oldpath, newname, onRenameDone, &error); |
---|
94 | do { |
---|
95 | tr_wait_msec (10); |
---|
96 | } while (error == -1); |
---|
97 | return error; |
---|
98 | } |
---|
99 | |
---|
100 | /*** |
---|
101 | **** |
---|
102 | ***/ |
---|
103 | |
---|
104 | static void |
---|
105 | create_file_with_contents (const char * path, const char * str) |
---|
106 | { |
---|
107 | int rv; |
---|
108 | FILE * fp; |
---|
109 | char * dir; |
---|
110 | const int tmperr = errno; |
---|
111 | |
---|
112 | dir = tr_dirname (path); |
---|
113 | errno = 0; |
---|
114 | rv = tr_mkdirp (dir, 0700); |
---|
115 | assert (errno == 0); |
---|
116 | assert (rv == 0); |
---|
117 | tr_free (dir); |
---|
118 | |
---|
119 | remove (path); |
---|
120 | fp = fopen (path, "wb"); |
---|
121 | fprintf (fp, "%s", str); |
---|
122 | fclose (fp); |
---|
123 | |
---|
124 | sync (); |
---|
125 | |
---|
126 | errno = tmperr; |
---|
127 | } |
---|
128 | |
---|
129 | static void |
---|
130 | create_single_file_torrent_contents (const char * top) |
---|
131 | { |
---|
132 | char * path = tr_buildPath (top, "hello-world.txt", NULL); |
---|
133 | create_file_with_contents (path, "hello, world!\n"); |
---|
134 | tr_free (path); |
---|
135 | } |
---|
136 | |
---|
137 | static tr_torrent * |
---|
138 | create_torrent_from_base64_metainfo (tr_ctor * ctor, const char * metainfo_base64) |
---|
139 | { |
---|
140 | int err; |
---|
141 | int metainfo_len; |
---|
142 | char * metainfo; |
---|
143 | tr_torrent * tor; |
---|
144 | |
---|
145 | /* create the torrent ctor */ |
---|
146 | metainfo = tr_base64_decode (metainfo_base64, -1, &metainfo_len); |
---|
147 | assert (metainfo != NULL); |
---|
148 | assert (metainfo_len > 0); |
---|
149 | assert (session != NULL); |
---|
150 | tr_ctorSetMetainfo (ctor, (uint8_t*)metainfo, metainfo_len); |
---|
151 | tr_ctorSetPaused (ctor, TR_FORCE, true); |
---|
152 | |
---|
153 | /* create the torrent */ |
---|
154 | err = 0; |
---|
155 | tor = tr_torrentNew (ctor, &err); |
---|
156 | assert (!err); |
---|
157 | |
---|
158 | /* cleanup */ |
---|
159 | tr_free (metainfo); |
---|
160 | return tor; |
---|
161 | } |
---|
162 | |
---|
163 | static int |
---|
164 | test_single_filename_torrent (void) |
---|
165 | { |
---|
166 | uint64_t loaded; |
---|
167 | tr_torrent * tor; |
---|
168 | char * tmpstr; |
---|
169 | const size_t totalSize = 14; |
---|
170 | tr_ctor * ctor; |
---|
171 | |
---|
172 | /* this is a single-file torrent whose file is hello-world.txt, holding the string "hello, world!" */ |
---|
173 | ctor = tr_ctorNew (session); |
---|
174 | tor = create_torrent_from_base64_metainfo (ctor, |
---|
175 | "ZDEwOmNyZWF0ZWQgYnkyNTpUcmFuc21pc3Npb24vMi42MSAoMTM0MDcpMTM6Y3JlYXRpb24gZGF0" |
---|
176 | "ZWkxMzU4NTQ5MDk4ZTg6ZW5jb2Rpbmc1OlVURi04NDppbmZvZDY6bGVuZ3RoaTE0ZTQ6bmFtZTE1" |
---|
177 | "OmhlbGxvLXdvcmxkLnR4dDEyOnBpZWNlIGxlbmd0aGkzMjc2OGU2OnBpZWNlczIwOukboJcrkFUY" |
---|
178 | "f6LvqLXBVvSHqCk6Nzpwcml2YXRlaTBlZWU="); |
---|
179 | check (tr_isTorrent (tor)); |
---|
180 | |
---|
181 | /* sanity check the info */ |
---|
182 | check_int_eq (1, tor->info.fileCount); |
---|
183 | check_streq ("hello-world.txt", tor->info.files[0].name); |
---|
184 | check (!tor->info.files[0].is_renamed); |
---|
185 | |
---|
186 | /* sanity check the (empty) stats */ |
---|
187 | verify_and_block_until_done (tor); |
---|
188 | check_have_none (tor, totalSize); |
---|
189 | |
---|
190 | create_single_file_torrent_contents (tor->downloadDir); |
---|
191 | |
---|
192 | /* sanity check the stats again, now that we've added the file */ |
---|
193 | verify_and_block_until_done (tor); |
---|
194 | check_have_all (tor, totalSize); |
---|
195 | |
---|
196 | /** |
---|
197 | *** okay! we've finally put together all the scaffolding to test |
---|
198 | *** renaming a single-file torrent |
---|
199 | **/ |
---|
200 | |
---|
201 | /* confirm that bad inputs get caught */ |
---|
202 | |
---|
203 | check_int_eq (EINVAL, torrentRenameAndWait (tor, "hello-world.txt", NULL)); |
---|
204 | check_int_eq (EINVAL, torrentRenameAndWait (tor, "hello-world.txt", "")); |
---|
205 | check_int_eq (EINVAL, torrentRenameAndWait (tor, "hello-world.txt", ".")); |
---|
206 | check_int_eq (EINVAL, torrentRenameAndWait (tor, "hello-world.txt", "..")); |
---|
207 | check_int_eq (0, torrentRenameAndWait (tor, "hello-world.txt", "hello-world.txt")); |
---|
208 | check_int_eq (EINVAL, torrentRenameAndWait (tor, "hello-world.txt", "hello/world.txt")); |
---|
209 | |
---|
210 | check (!tor->info.files[0].is_renamed); |
---|
211 | check_streq ("hello-world.txt", tor->info.files[0].name); |
---|
212 | |
---|
213 | /*** |
---|
214 | **** Now try a rename that should succeed |
---|
215 | ***/ |
---|
216 | |
---|
217 | tmpstr = tr_buildPath (tor->downloadDir, "hello-world.txt", NULL); |
---|
218 | check (tr_fileExists (tmpstr, NULL)); |
---|
219 | check_streq ("hello-world.txt", tr_torrentName(tor)); |
---|
220 | check_int_eq (0, torrentRenameAndWait (tor, tor->info.name, "foobar")); |
---|
221 | check (!tr_fileExists (tmpstr, NULL)); /* confirm the old filename can't be found */ |
---|
222 | check (tor->info.files[0].is_renamed); /* confirm the file's 'renamed' flag is set */ |
---|
223 | check_streq ("foobar", tr_torrentName(tor)); /* confirm the torrent's name is now 'foobar' */ |
---|
224 | check_streq ("foobar", tor->info.files[0].name); /* confirm the file's name is now 'foobar' */ |
---|
225 | check (strstr (tor->info.torrent, "foobar") == NULL); /* confirm the name in the .torrent file hasn't changed */ |
---|
226 | check (testFileExistsAndConsistsOfThisString (tor, 0, "hello, world!\n")); /* confirm the contents are right */ |
---|
227 | tr_free (tmpstr); |
---|
228 | |
---|
229 | /* (while it's renamed: confirm that the .resume file remembers the changes) */ |
---|
230 | tr_torrentSaveResume (tor); |
---|
231 | sync (); |
---|
232 | loaded = tr_torrentLoadResume (tor, ~0, ctor); |
---|
233 | check_streq ("foobar", tr_torrentName(tor)); |
---|
234 | check ((loaded & TR_FR_NAME) != 0); |
---|
235 | |
---|
236 | /*** |
---|
237 | **** ...and rename it back again |
---|
238 | ***/ |
---|
239 | |
---|
240 | tmpstr = tr_buildPath (tor->downloadDir, "foobar", NULL); |
---|
241 | check (tr_fileExists (tmpstr, NULL)); |
---|
242 | check_int_eq (0, torrentRenameAndWait (tor, "foobar", "hello-world.txt")); |
---|
243 | check (!tr_fileExists (tmpstr, NULL)); |
---|
244 | check (tor->info.files[0].is_renamed); |
---|
245 | check_streq ("hello-world.txt", tor->info.files[0].name); |
---|
246 | check_streq ("hello-world.txt", tr_torrentName(tor)); |
---|
247 | tr_free (tmpstr); |
---|
248 | check (testFileExistsAndConsistsOfThisString (tor, 0, "hello, world!\n")); |
---|
249 | |
---|
250 | /* cleanup */ |
---|
251 | tr_ctorFree (ctor); |
---|
252 | tr_torrentRemove (tor, false, NULL); |
---|
253 | return 0; |
---|
254 | } |
---|
255 | |
---|
256 | /*** |
---|
257 | **** |
---|
258 | **** |
---|
259 | **** |
---|
260 | ***/ |
---|
261 | |
---|
262 | static void |
---|
263 | create_multifile_torrent_contents (const char * top) |
---|
264 | { |
---|
265 | char * path; |
---|
266 | |
---|
267 | path = tr_buildPath (top, "Felidae", "Felinae", "Acinonyx", "Cheetah", "Chester", NULL); |
---|
268 | create_file_with_contents (path, "It ain't easy bein' cheesy.\n"); |
---|
269 | tr_free (path); |
---|
270 | |
---|
271 | path = tr_buildPath (top, "Felidae", "Pantherinae", "Panthera", "Tiger", "Tony", NULL); |
---|
272 | create_file_with_contents (path, "Theyâre Grrrrreat!\n"); |
---|
273 | tr_free (path); |
---|
274 | |
---|
275 | path = tr_buildPath (top, "Felidae", "Felinae", "Felis", "catus", "Kyphi", NULL); |
---|
276 | create_file_with_contents (path, "Inquisitive\n"); |
---|
277 | tr_free (path); |
---|
278 | |
---|
279 | path = tr_buildPath (top, "Felidae", "Felinae", "Felis", "catus", "Saffron", NULL); |
---|
280 | create_file_with_contents (path, "Tough\n"); |
---|
281 | tr_free (path); |
---|
282 | |
---|
283 | sync (); |
---|
284 | } |
---|
285 | |
---|
286 | static int |
---|
287 | test_multifile_torrent (void) |
---|
288 | { |
---|
289 | tr_file_index_t i; |
---|
290 | uint64_t loaded; |
---|
291 | tr_torrent * tor; |
---|
292 | tr_ctor * ctor; |
---|
293 | char * str; |
---|
294 | char * tmp; |
---|
295 | static const size_t totalSize = 67; |
---|
296 | const tr_file * files; |
---|
297 | const char * strings[4]; |
---|
298 | const char * expected_files[4] = { |
---|
299 | "Felidae/Felinae/Acinonyx/Cheetah/Chester", |
---|
300 | "Felidae/Felinae/Felis/catus/Kyphi", |
---|
301 | "Felidae/Felinae/Felis/catus/Saffron", |
---|
302 | "Felidae/Pantherinae/Panthera/Tiger/Tony" |
---|
303 | }; |
---|
304 | const char * expected_contents[4] = { |
---|
305 | "It ain't easy bein' cheesy.\n", |
---|
306 | "Inquisitive\n", |
---|
307 | "Tough\n", |
---|
308 | "Theyâre Grrrrreat!\n" |
---|
309 | }; |
---|
310 | |
---|
311 | ctor = tr_ctorNew (session); |
---|
312 | tor = create_torrent_from_base64_metainfo (ctor, |
---|
313 | "ZDEwOmNyZWF0ZWQgYnkyNTpUcmFuc21pc3Npb24vMi42MSAoMTM0MDcpMTM6Y3JlYXRpb24gZGF0" |
---|
314 | "ZWkxMzU4NTU1NDIwZTg6ZW5jb2Rpbmc1OlVURi04NDppbmZvZDU6ZmlsZXNsZDY6bGVuZ3RoaTI4" |
---|
315 | "ZTQ6cGF0aGw3OkZlbGluYWU4OkFjaW5vbnl4NzpDaGVldGFoNzpDaGVzdGVyZWVkNjpsZW5ndGhp" |
---|
316 | "MTJlNDpwYXRobDc6RmVsaW5hZTU6RmVsaXM1OmNhdHVzNTpLeXBoaWVlZDY6bGVuZ3RoaTZlNDpw" |
---|
317 | "YXRobDc6RmVsaW5hZTU6RmVsaXM1OmNhdHVzNzpTYWZmcm9uZWVkNjpsZW5ndGhpMjFlNDpwYXRo" |
---|
318 | "bDExOlBhbnRoZXJpbmFlODpQYW50aGVyYTU6VGlnZXI0OlRvbnllZWU0Om5hbWU3OkZlbGlkYWUx" |
---|
319 | "MjpwaWVjZSBsZW5ndGhpMzI3NjhlNjpwaWVjZXMyMDp27buFkmy8ICfNX4nsJmt0Ckm2Ljc6cHJp" |
---|
320 | "dmF0ZWkwZWVl"); |
---|
321 | check (tr_isTorrent (tor)); |
---|
322 | files = tor->info.files; |
---|
323 | |
---|
324 | /* sanity check the info */ |
---|
325 | check_streq (tor->info.name, "Felidae"); |
---|
326 | check_int_eq (totalSize, tor->info.totalSize); |
---|
327 | check_int_eq (4, tor->info.fileCount); |
---|
328 | for (i=0; i<4; ++i) |
---|
329 | check_streq (expected_files[i], files[i].name); |
---|
330 | |
---|
331 | /* sanity check the (empty) stats */ |
---|
332 | verify_and_block_until_done (tor); |
---|
333 | check_have_none (tor, totalSize); |
---|
334 | |
---|
335 | /* build the local data */ |
---|
336 | create_multifile_torrent_contents (tor->downloadDir); |
---|
337 | |
---|
338 | /* sanity check the (full) stats */ |
---|
339 | verify_and_block_until_done (tor); |
---|
340 | check_have_all (tor, totalSize); |
---|
341 | |
---|
342 | /** |
---|
343 | *** okay! let's test renaming. |
---|
344 | **/ |
---|
345 | |
---|
346 | /* rename a leaf... */ |
---|
347 | check_int_eq (0, torrentRenameAndWait (tor, "Felidae/Felinae/Felis/catus/Kyphi", "placeholder")); |
---|
348 | check_streq (files[1].name, "Felidae/Felinae/Felis/catus/placeholder"); |
---|
349 | check (testFileExistsAndConsistsOfThisString (tor, 1, "Inquisitive\n")); |
---|
350 | |
---|
351 | /* ...and back again */ |
---|
352 | check_int_eq (0, torrentRenameAndWait (tor, "Felidae/Felinae/Felis/catus/placeholder", "Kyphi")); |
---|
353 | check_streq (files[1].name, "Felidae/Felinae/Felis/catus/Kyphi"); |
---|
354 | testFileExistsAndConsistsOfThisString (tor, 1, "Inquisitive\n"); |
---|
355 | |
---|
356 | /* rename a branch... */ |
---|
357 | check_int_eq (0, torrentRenameAndWait (tor, "Felidae/Felinae/Felis/catus", "placeholder")); |
---|
358 | check_streq (expected_files[0], files[0].name); |
---|
359 | check_streq ("Felidae/Felinae/Felis/placeholder/Kyphi", files[1].name); |
---|
360 | check_streq ("Felidae/Felinae/Felis/placeholder/Saffron", files[2].name); |
---|
361 | check_streq (expected_files[3], files[3].name); |
---|
362 | check (testFileExistsAndConsistsOfThisString (tor, 1, expected_contents[1])); |
---|
363 | check (testFileExistsAndConsistsOfThisString (tor, 2, expected_contents[2])); |
---|
364 | check (files[0].is_renamed == false); |
---|
365 | check (files[1].is_renamed == true); |
---|
366 | check (files[2].is_renamed == true); |
---|
367 | check (files[3].is_renamed == false); |
---|
368 | |
---|
369 | /* (while the branch is renamed: confirm that the .resume file remembers the changes) */ |
---|
370 | tr_torrentSaveResume (tor); |
---|
371 | /* this is a bit dodgy code-wise, but let's make sure the .resume file got the name */ |
---|
372 | tr_free (files[1].name); |
---|
373 | tor->info.files[1].name = tr_strdup ("gabba gabba hey"); |
---|
374 | loaded = tr_torrentLoadResume (tor, ~0, ctor); |
---|
375 | check ((loaded & TR_FR_FILENAMES) != 0); |
---|
376 | check_streq (expected_files[0], files[0].name); |
---|
377 | check_streq ("Felidae/Felinae/Felis/placeholder/Kyphi", files[1].name); |
---|
378 | check_streq ("Felidae/Felinae/Felis/placeholder/Saffron", files[2].name); |
---|
379 | check_streq (expected_files[3], files[3].name); |
---|
380 | |
---|
381 | /* ...and back again */ |
---|
382 | check_int_eq (0, torrentRenameAndWait (tor, "Felidae/Felinae/Felis/placeholder", "catus")); |
---|
383 | for (i=0; i<4; ++i) |
---|
384 | { |
---|
385 | check_streq (expected_files[i], files[i].name); |
---|
386 | check (testFileExistsAndConsistsOfThisString (tor, 1, expected_contents[1])); |
---|
387 | } |
---|
388 | check (files[0].is_renamed == false); |
---|
389 | check (files[1].is_renamed == true); |
---|
390 | check (files[2].is_renamed == true); |
---|
391 | check (files[3].is_renamed == false); |
---|
392 | |
---|
393 | /*** |
---|
394 | **** Test it an incomplete torrent... |
---|
395 | ***/ |
---|
396 | |
---|
397 | /* remove the directory Felidae/Felinae/Felis/catus */ |
---|
398 | str = tr_buildPath (tor->downloadDir, files[1].name, NULL); |
---|
399 | remove (str); |
---|
400 | tr_free (str); |
---|
401 | str = tr_buildPath (tor->downloadDir, files[2].name, NULL); |
---|
402 | remove (str); |
---|
403 | tmp = tr_dirname (str); |
---|
404 | remove (tmp); |
---|
405 | tr_free (tmp); |
---|
406 | tr_free (str); |
---|
407 | verify_and_block_until_done (tor); |
---|
408 | testFileExistsAndConsistsOfThisString (tor, 0, expected_contents[0]); |
---|
409 | check (tr_torrentFindFile (tor, 1) == NULL); |
---|
410 | check (tr_torrentFindFile (tor, 2) == NULL); |
---|
411 | testFileExistsAndConsistsOfThisString (tor, 3, expected_contents[3]); |
---|
412 | |
---|
413 | /* rename a branch... */ |
---|
414 | check_int_eq (0, torrentRenameAndWait (tor, "Felidae/Felinae/Felis/catus", "foo")); |
---|
415 | check_streq (expected_files[0], files[0].name); |
---|
416 | check_streq ("Felidae/Felinae/Felis/foo/Kyphi", files[1].name); |
---|
417 | check_streq ("Felidae/Felinae/Felis/foo/Saffron", files[2].name); |
---|
418 | check_streq (expected_files[3], files[3].name); |
---|
419 | |
---|
420 | /* ...and back again */ |
---|
421 | check_int_eq (0, torrentRenameAndWait (tor, "Felidae/Felinae/Felis/foo", "catus")); |
---|
422 | for (i=0; i<4; ++i) |
---|
423 | check_streq (expected_files[i], files[i].name); |
---|
424 | |
---|
425 | check_int_eq (0, torrentRenameAndWait (tor, "Felidae", "gabba")); |
---|
426 | strings[0] = "gabba/Felinae/Acinonyx/Cheetah/Chester"; |
---|
427 | strings[1] = "gabba/Felinae/Felis/catus/Kyphi"; |
---|
428 | strings[2] = "gabba/Felinae/Felis/catus/Saffron"; |
---|
429 | strings[3] = "gabba/Pantherinae/Panthera/Tiger/Tony"; |
---|
430 | for (i=0; i<4; ++i) |
---|
431 | { |
---|
432 | check_streq (strings[i], files[i].name); |
---|
433 | testFileExistsAndConsistsOfThisString (tor, i, expected_contents[i]); |
---|
434 | } |
---|
435 | |
---|
436 | /* rename the root, then a branch, and then a leaf... */ |
---|
437 | check_int_eq (0, torrentRenameAndWait (tor, "gabba", "Felidae")); |
---|
438 | check_int_eq (0, torrentRenameAndWait (tor, "Felidae/Pantherinae/Panthera/Tiger", "Snow Leopard")); |
---|
439 | check_int_eq (0, torrentRenameAndWait (tor, "Felidae/Pantherinae/Panthera/Snow Leopard/Tony", "10.6")); |
---|
440 | strings[0] = "Felidae/Felinae/Acinonyx/Cheetah/Chester"; |
---|
441 | strings[1] = "Felidae/Felinae/Felis/catus/Kyphi"; |
---|
442 | strings[2] = "Felidae/Felinae/Felis/catus/Saffron"; |
---|
443 | strings[3] = "Felidae/Pantherinae/Panthera/Snow Leopard/10.6"; |
---|
444 | for (i=0; i<4; ++i) |
---|
445 | { |
---|
446 | check_streq (strings[i], files[i].name); |
---|
447 | testFileExistsAndConsistsOfThisString (tor, i, expected_contents[i]); |
---|
448 | } |
---|
449 | |
---|
450 | /*** |
---|
451 | **** |
---|
452 | ***/ |
---|
453 | |
---|
454 | /* cleanup */ |
---|
455 | tr_ctorFree (ctor); |
---|
456 | tr_torrentRemove (tor, false, NULL); |
---|
457 | return 0; |
---|
458 | } |
---|
459 | |
---|
460 | /*** |
---|
461 | **** |
---|
462 | ***/ |
---|
463 | |
---|
464 | static void |
---|
465 | create_zero_torrent_partial_contents (tr_torrent * tor, bool incomplete) |
---|
466 | { |
---|
467 | tr_file_index_t i; |
---|
468 | const tr_stat * st; |
---|
469 | tr_file_stat * fst; |
---|
470 | |
---|
471 | for (i=0; i<tor->info.fileCount; ++i) |
---|
472 | { |
---|
473 | int rv; |
---|
474 | uint64_t j; |
---|
475 | FILE * fp; |
---|
476 | char * path; |
---|
477 | char * dirname; |
---|
478 | const tr_file * file = &tor->info.files[i]; |
---|
479 | struct stat sb; |
---|
480 | |
---|
481 | path = tr_buildPath (tor->downloadDir, file->name, NULL); |
---|
482 | dirname = tr_dirname (path); |
---|
483 | tr_mkdirp (dirname, 0700); |
---|
484 | fp = fopen (path, "wb+"); |
---|
485 | for (j=0; j<file->length; ++j) |
---|
486 | fputc ('\0', fp); |
---|
487 | fclose (fp); |
---|
488 | |
---|
489 | tr_free (dirname); |
---|
490 | tr_free (path); |
---|
491 | |
---|
492 | path = tr_torrentFindFile (tor, i); |
---|
493 | assert (path != NULL); |
---|
494 | rv = stat (path, &sb); |
---|
495 | assert (rv == 0); |
---|
496 | fprintf (stderr, "%s:%d file %s size is %zu\n", __FILE__, __LINE__, path, (size_t)sb.st_size); |
---|
497 | tr_free (path); |
---|
498 | } |
---|
499 | |
---|
500 | sync (); |
---|
501 | verify_and_block_until_done (tor); |
---|
502 | st = tr_torrentStat (tor); |
---|
503 | fprintf (stderr, "%s:%d leftUntilDone %zu\n", __FILE__, __LINE__, (size_t)st->leftUntilDone); |
---|
504 | fst = tr_torrentFiles (tor, NULL); |
---|
505 | for (i=0; i<3; ++i) |
---|
506 | fprintf (stderr, "%s:%d %d %zu\n", __FILE__, __LINE__, (int)i, (size_t)fst[i].bytesCompleted); |
---|
507 | assert (st->leftUntilDone == 0); |
---|
508 | |
---|
509 | if (incomplete) |
---|
510 | { |
---|
511 | FILE * fp; |
---|
512 | char * oldpath = tr_torrentFindFile (tor, 0); |
---|
513 | char * newpath = tr_strdup_printf ("%s.part", oldpath); |
---|
514 | |
---|
515 | rename (oldpath, newpath); |
---|
516 | |
---|
517 | /* invalidate one piece */ |
---|
518 | fp = fopen (newpath, "rb+"); |
---|
519 | fputc ('\1', fp); |
---|
520 | fclose (fp); |
---|
521 | |
---|
522 | tr_free (newpath); |
---|
523 | tr_free (oldpath); |
---|
524 | |
---|
525 | sync (); |
---|
526 | verify_and_block_until_done (tor); |
---|
527 | st = tr_torrentStat (tor); |
---|
528 | assert (st->leftUntilDone == tor->info.pieceSize); |
---|
529 | fprintf (stderr, "%s:%d leftUntilDone %zu\n", __FILE__, __LINE__, (size_t)st->leftUntilDone); |
---|
530 | } |
---|
531 | } |
---|
532 | |
---|
533 | static int |
---|
534 | test_partial_file (void) |
---|
535 | { |
---|
536 | tr_file_index_t i; |
---|
537 | tr_torrent * tor; |
---|
538 | const tr_stat * st; |
---|
539 | tr_file_stat * fst; |
---|
540 | const uint32_t pieceCount = 33; |
---|
541 | const uint32_t pieceSize = 32768; |
---|
542 | const uint32_t length[] = { 1048576, 4096, 512 }; |
---|
543 | const uint64_t totalSize = length[0] + length[1] + length[2]; |
---|
544 | const char * strings[3]; |
---|
545 | |
---|
546 | /*** |
---|
547 | **** create our test torrent with an incomplete .part file |
---|
548 | ***/ |
---|
549 | |
---|
550 | tor = libtransmission_test_zero_torrent_init (); |
---|
551 | check_int_eq (totalSize, tor->info.totalSize); |
---|
552 | check_int_eq (pieceSize, tor->info.pieceSize); |
---|
553 | check_int_eq (pieceCount, tor->info.pieceCount); |
---|
554 | check_streq ("files-filled-with-zeroes/1048576", tor->info.files[0].name); |
---|
555 | check_streq ("files-filled-with-zeroes/4096", tor->info.files[1].name); |
---|
556 | check_streq ("files-filled-with-zeroes/512", tor->info.files[2].name); |
---|
557 | |
---|
558 | create_zero_torrent_partial_contents (tor, true); |
---|
559 | fst = tr_torrentFiles (tor, NULL); |
---|
560 | check_int_eq (length[0] - pieceSize, fst[0].bytesCompleted); |
---|
561 | check_int_eq (length[1], fst[1].bytesCompleted); |
---|
562 | check_int_eq (length[2], fst[2].bytesCompleted); |
---|
563 | tr_torrentFilesFree (fst, tor->info.fileCount); |
---|
564 | st = tr_torrentStat (tor); |
---|
565 | check_int_eq (totalSize, st->sizeWhenDone); |
---|
566 | check_int_eq (pieceSize, st->leftUntilDone); |
---|
567 | |
---|
568 | /*** |
---|
569 | **** |
---|
570 | ***/ |
---|
571 | |
---|
572 | check_int_eq (0, torrentRenameAndWait (tor, "files-filled-with-zeroes", "foo")); |
---|
573 | check_int_eq (0, torrentRenameAndWait (tor, "foo/1048576", "bar")); |
---|
574 | strings[0] = "foo/bar"; |
---|
575 | strings[1] = "foo/4096"; |
---|
576 | strings[2] = "foo/512"; |
---|
577 | for (i=0; i<3; ++i) |
---|
578 | { |
---|
579 | check_streq (strings[i], tor->info.files[i].name); |
---|
580 | } |
---|
581 | |
---|
582 | strings[0] = "foo/bar.part"; |
---|
583 | for (i=0; i<3; ++i) |
---|
584 | { |
---|
585 | char * expected = tr_buildPath (tor->downloadDir, strings[i], NULL); |
---|
586 | char * path = tr_torrentFindFile (tor, i); |
---|
587 | check_streq (expected, path); |
---|
588 | tr_free (path); |
---|
589 | tr_free (expected); |
---|
590 | } |
---|
591 | |
---|
592 | tr_torrentRemove (tor, false, NULL); |
---|
593 | return 0; |
---|
594 | } |
---|
595 | |
---|
596 | /*** |
---|
597 | **** |
---|
598 | ***/ |
---|
599 | |
---|
600 | int |
---|
601 | main (void) |
---|
602 | { |
---|
603 | int ret; |
---|
604 | const testFunc tests[] = { //test_single_filename_torrent, |
---|
605 | //test_multifile_torrent, |
---|
606 | test_partial_file }; |
---|
607 | |
---|
608 | verbose = 1; |
---|
609 | |
---|
610 | libtransmission_test_session_init (); |
---|
611 | ret = runTests (tests, NUM_TESTS (tests)); |
---|
612 | libtransmission_test_session_close (); |
---|
613 | |
---|
614 | return ret; |
---|
615 | } |
---|