A clone of btpd with my configuration changes.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

391 lignes
9.7 KiB

  1. #include <errno.h>
  2. #include <inttypes.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <openssl/sha.h>
  6. #include "benc.h"
  7. #include "metainfo.h"
  8. #include "subr.h"
  9. /*
  10. * d
  11. * announce = url
  12. * announce-list = l l url ... e ... e
  13. * info = d
  14. * name = advisory file/dir save name
  15. * piece length = power of two length of each block
  16. * pieces = 20b of sha1-hash * num of pieces
  17. * length = length of file in bytes in single file download
  18. * files = l d
  19. * length = length of file in bytes
  20. * path = l path components
  21. *
  22. */
  23. uint8_t *
  24. mi_hashes(const char *p)
  25. {
  26. return benc_dget_mema(benc_dget_dct(p, "info"), "pieces", NULL);
  27. }
  28. size_t
  29. mi_npieces(const char *p)
  30. {
  31. size_t plen;
  32. benc_dget_mem(benc_dget_dct(p, "info"), "pieces", &plen);
  33. return plen / 20;
  34. }
  35. int
  36. mi_simple(const char *p)
  37. {
  38. return benc_dget_lst(benc_dget_dct(p, "info"), "files") == NULL;
  39. }
  40. void
  41. mi_free_announce(struct mi_announce *ann)
  42. {
  43. if (ann->tiers != NULL) {
  44. for (int ti = 0; ti < ann->ntiers; ti++)
  45. if (ann->tiers[ti].urls != NULL) {
  46. for (int ui = 0; ui < ann->tiers[ti].nurls; ui++)
  47. if (ann->tiers[ti].urls[ui] != NULL)
  48. free(ann->tiers[ti].urls[ui]);
  49. free(ann->tiers[ti].urls);
  50. }
  51. free(ann->tiers);
  52. }
  53. free(ann);
  54. }
  55. static void
  56. mi_shuffle_announce(struct mi_announce *ann)
  57. {
  58. for (int i = 0; i < ann->ntiers; i++) {
  59. for (int j = 0; j < ann->tiers[i].nurls - 1; j++) {
  60. char *tmp = ann->tiers[i].urls[j];
  61. int ri = rand_between(j, ann->tiers[i].nurls - 1);
  62. ann->tiers[i].urls[j] = ann->tiers[i].urls[ri];
  63. ann->tiers[i].urls[ri] = tmp;
  64. }
  65. }
  66. }
  67. struct mi_announce *
  68. mi_announce(const char *p)
  69. {
  70. int ti, ui;
  71. const char *alst, *ulst, *url;
  72. struct mi_announce *res;
  73. if ((res = calloc(1, sizeof(*res))) == NULL)
  74. return NULL;
  75. if ((alst = benc_dget_lst(p, "announce-list")) != NULL) {
  76. res->ntiers = benc_nelems(alst);
  77. if ((res->tiers = calloc(res->ntiers, sizeof(*res->tiers))) == NULL)
  78. goto error;
  79. ti = 0; ulst = benc_first(alst);
  80. while (ulst != NULL) {
  81. res->tiers[ti].nurls = benc_nelems(ulst);
  82. res->tiers[ti].urls =
  83. calloc(res->tiers[ti].nurls, sizeof(*res->tiers[ti].urls));
  84. if (res->tiers[ti].urls == NULL)
  85. goto error;
  86. ui = 0; url = benc_first(ulst);
  87. while (url != NULL) {
  88. if ((res->tiers[ti].urls[ui] =
  89. benc_str(url, NULL, NULL)) == NULL)
  90. goto error;
  91. ui++; url = benc_next(url);
  92. }
  93. ti++; ulst = benc_next(ulst);
  94. }
  95. } else {
  96. res->ntiers = 1;
  97. if ((res->tiers = calloc(1, sizeof(*res->tiers))) == NULL)
  98. goto error;
  99. res->tiers[0].nurls = 1;
  100. if ((res->tiers[0].urls =
  101. calloc(1, sizeof(*res->tiers[0].urls))) == NULL)
  102. goto error;
  103. if ((res->tiers[0].urls[0] =
  104. benc_dget_str(p, "announce", NULL)) == NULL)
  105. goto error;
  106. }
  107. mi_shuffle_announce(res);
  108. return res;
  109. error:
  110. if (res != NULL)
  111. mi_free_announce(res);
  112. return NULL;
  113. }
  114. off_t
  115. mi_piece_length(const char *p)
  116. {
  117. return benc_dget_int(benc_dget_dct(p, "info"), "piece length");
  118. }
  119. off_t
  120. mi_total_length(const char *p)
  121. {
  122. const char *info = benc_dget_dct(p, "info");
  123. const char *files = benc_dget_lst(info, "files");
  124. if (files != NULL) {
  125. off_t length = 0;
  126. const char *fdct = benc_first(files);
  127. while (fdct != NULL) {
  128. length += benc_dget_int(fdct, "length");
  129. fdct = benc_next(fdct);
  130. }
  131. return length;
  132. } else
  133. return benc_dget_int(info, "length");
  134. }
  135. uint8_t *
  136. mi_info_hash(const char *p, uint8_t *hash)
  137. {
  138. const char *info = benc_dget_dct(p, "info");
  139. if (hash == NULL)
  140. if ((hash = malloc(20)) == NULL)
  141. return NULL;
  142. return SHA1(info, benc_length(info), hash);
  143. }
  144. char *
  145. mi_name(const char *p)
  146. {
  147. return benc_dget_str(benc_dget_dct(p, "info"), "name", NULL);
  148. }
  149. size_t
  150. mi_nfiles(const char *p)
  151. {
  152. const char *files = benc_dget_lst(benc_dget_dct(p, "info"), "files");
  153. if (files != NULL)
  154. return benc_nelems(files);
  155. else
  156. return 1;
  157. }
  158. static char *
  159. mi_filepath(const char *plst)
  160. {
  161. char *res = NULL;
  162. const char *str;
  163. size_t npaths = 0, plen = 0, len;
  164. const char *iter = benc_first(plst);
  165. while (iter != NULL) {
  166. benc_mem(iter, &len, &iter);
  167. npaths++;
  168. plen += len;
  169. }
  170. if ((res = malloc(plen + (npaths - 1) + 1)) == NULL)
  171. return NULL;
  172. iter = benc_first(plst);
  173. str = benc_mem(iter, &len, &iter);
  174. bcopy(str, res, len);
  175. plen = len;
  176. npaths--;
  177. while (npaths > 0) {
  178. res[plen] = '/';
  179. plen++;
  180. str = benc_mem(iter, &len, &iter);
  181. bcopy(str, res + plen, len);
  182. plen += len;
  183. npaths--;
  184. }
  185. res[plen] = '\0';
  186. return res;
  187. }
  188. void
  189. mi_free_files(unsigned nfiles, struct mi_file *files)
  190. {
  191. for (unsigned i = 0; i < nfiles; i++)
  192. if (files[i].path != NULL)
  193. free(files[i].path);
  194. free(files);
  195. }
  196. struct mi_file *
  197. mi_files(const char *p)
  198. {
  199. struct mi_file *fi;
  200. const char *info = benc_dget_dct(p, "info");
  201. const char *files = benc_dget_lst(info, "files");
  202. if (files != NULL) {
  203. int i = 0;
  204. unsigned nfiles = benc_nelems(files);
  205. const char *fdct = benc_first(files);
  206. if ((fi = calloc(nfiles, sizeof(*fi))) == NULL)
  207. return NULL;
  208. for (fdct = benc_first(files); fdct != NULL; fdct = benc_next(fdct)) {
  209. fi[i].length = benc_dget_int(fdct, "length");
  210. fi[i].path = mi_filepath(benc_dget_lst(fdct, "path"));
  211. if (fi[i].path == NULL) {
  212. mi_free_files(nfiles, fi);
  213. return NULL;
  214. }
  215. i++;
  216. }
  217. } else {
  218. if ((fi = calloc(1, sizeof(*fi))) == NULL)
  219. return NULL;
  220. fi[0].length = benc_dget_int(info, "length");
  221. fi[0].path = benc_dget_str(info, "name", NULL);
  222. if (fi[0].path == NULL) {
  223. free(fi);
  224. return NULL;
  225. }
  226. }
  227. return fi;
  228. }
  229. static int
  230. mi_test_path(const char *path, size_t len)
  231. {
  232. if (len == 0)
  233. return 0;
  234. else if (len == 1 && path[0] == '.')
  235. return 0;
  236. else if (len == 2 && path[0] == '.' && path[1] == '.')
  237. return 0;
  238. else if (memchr(path, '/', len) != NULL)
  239. return 0;
  240. return 1;
  241. }
  242. static int
  243. mi_test_files(const char *files)
  244. {
  245. int fcount = 0;
  246. const char *fdct = benc_first(files);
  247. while (fdct != NULL) {
  248. const char *plst;
  249. const char *path;
  250. int pcount = 0;
  251. if (!benc_isdct(fdct))
  252. return 0;
  253. if (benc_dget_int(fdct, "length") <= 0)
  254. return 0;
  255. if ((plst = benc_dget_lst(fdct, "path")) == NULL)
  256. return 0;
  257. path = benc_first(plst);
  258. while (path != NULL) {
  259. size_t plen;
  260. const char *pstr = benc_mem(path, &plen, &path);
  261. if (pstr == NULL || !mi_test_path(pstr, plen))
  262. return 0;
  263. pcount++;
  264. }
  265. if (pcount == 0)
  266. return 0;
  267. fcount++;
  268. fdct = benc_next(fdct);
  269. }
  270. return fcount > 0 ? 1 : 0;
  271. }
  272. static int
  273. mi_test_announce_list(const char *alst)
  274. {
  275. int lstcount = 0;
  276. const char *t = benc_first(alst);
  277. while (t != NULL && benc_islst(t)) {
  278. int strcount = 0;
  279. const char *s = benc_first(t);
  280. while (s != NULL && benc_isstr(s)) {
  281. strcount++;
  282. s = benc_next(s);
  283. }
  284. if (strcount == 0)
  285. return 0;
  286. lstcount++;
  287. t = benc_next(t);
  288. }
  289. return lstcount > 0 ? 1 : 0;
  290. }
  291. int
  292. mi_test(const char *p, size_t size)
  293. {
  294. const char *info;
  295. const char *alst;
  296. const char *pieces;
  297. const char *files;
  298. const char *fdct;
  299. const char *name;
  300. size_t slen, npieces;
  301. off_t length = 0, piece_length;
  302. if (benc_validate(p, size) != 0 || !benc_isdct(p))
  303. return 0;
  304. if ((alst = benc_dget_any(p, "announce-list")) != NULL) {
  305. if (!benc_islst(alst))
  306. return 0;
  307. if (!mi_test_announce_list(alst))
  308. return 0;
  309. } else if (benc_dget_mem(p, "announce", NULL) == NULL)
  310. return 0;
  311. if ((info = benc_dget_dct(p, "info")) == NULL)
  312. return 0;
  313. if ((name = benc_dget_mem(info, "name", &slen)) != NULL)
  314. if (!mi_test_path(name, slen))
  315. return 0;
  316. if ((piece_length = benc_dget_int(info, "piece length")) <= 0)
  317. return 0;
  318. if ((pieces = benc_dget_mem(info, "pieces", &slen)) == NULL ||
  319. slen % 20 != 0)
  320. return 0;
  321. npieces = slen / 20;
  322. if ((length = benc_dget_int(info, "length")) != 0) {
  323. if (length < 0 || benc_dget_any(info, "files") != NULL)
  324. return 0;
  325. } else {
  326. if ((files = benc_dget_lst(info, "files")) == NULL)
  327. return 0;
  328. if (!mi_test_files(files))
  329. return 0;
  330. fdct = benc_first(files);
  331. while (fdct != NULL) {
  332. length += benc_dget_int(fdct, "length");
  333. fdct = benc_next(fdct);
  334. }
  335. }
  336. if (length < (npieces - 1) * piece_length ||
  337. length > npieces * piece_length)
  338. return 0;
  339. return 1;
  340. }
  341. char *
  342. mi_load(const char *path, size_t *size)
  343. {
  344. void *res = NULL;
  345. size_t mi_size = (1 << 21);
  346. if ((errno = read_whole_file(&res, &mi_size, path)) != 0)
  347. return NULL;
  348. if (!mi_test(res, mi_size)) {
  349. free(res);
  350. errno = EINVAL;
  351. return NULL;
  352. }
  353. if (size != NULL)
  354. *size = mi_size;
  355. return res;
  356. }