A clone of btpd with my configuration changes.
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

394 líneas
9.7 KiB

  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 = 0;
  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. }