A clone of btpd with my configuration changes.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

391 lines
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. }