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.

metainfo.c 9.7 KiB

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