A clone of btpd with my configuration changes.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

metainfo.c 9.7 KiB

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