A clone of btpd with my configuration changes.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

276 řádky
5.6 KiB

  1. #include <sys/types.h>
  2. #include <sys/mman.h>
  3. #include <sys/stat.h>
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <inttypes.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <unistd.h>
  11. #include <openssl/sha.h>
  12. #include "benc.h"
  13. #include "metainfo.h"
  14. #include "subr.h"
  15. /*
  16. * d
  17. * announce = url
  18. * info = d
  19. * name = advisory file/dir save name
  20. * piece length = power of two length of each block
  21. * pieces = 20b of sha1-hash * num of pieces
  22. * length = length of file in bytes in single file download
  23. * files = l d
  24. * length = length of file in bytes
  25. * path = l path components
  26. *
  27. */
  28. #ifndef PRId64
  29. #define PRId64 "lld"
  30. #endif
  31. #ifndef PRIu32
  32. #define PRIu32 "u"
  33. #endif
  34. void
  35. print_metainfo(struct metainfo *tp)
  36. {
  37. unsigned i;
  38. printf("Info hash: ");
  39. for (i = 0; i < 20; i++)
  40. printf("%.2x", tp->info_hash[i]);
  41. printf("\n");
  42. printf("Tracker URL: %s\n", tp->announce);
  43. printf("Piece length: %" PRId64 "\n", (int64_t)tp->piece_length);
  44. printf("Number of pieces: %" PRIu32 "\n", tp->npieces);
  45. printf("Number of files: %u\n", tp->nfiles);
  46. printf("Advisory name: %s\n", tp->name);
  47. printf("Files:\n");
  48. for (i = 0; i < tp->nfiles; i++) {
  49. printf("%s (%" PRId64 ")\n",
  50. tp->files[i].path, (int64_t)tp->files[i].length);
  51. }
  52. printf("Total length: %" PRId64 "\n\n", (int64_t)tp->total_length);
  53. }
  54. static int
  55. check_path(const char *path, size_t len)
  56. {
  57. if (len == 0)
  58. return 0;
  59. else if (len == 1 && path[0] == '.')
  60. return 0;
  61. else if (len == 2 && path[0] == '.' && path[1] == '.')
  62. return 0;
  63. else if (memchr(path, '/', len) != NULL)
  64. return 0;
  65. return 1;
  66. }
  67. int
  68. fill_fileinfo(const char *fdct, struct fileinfo *tfp)
  69. {
  70. int err;
  71. size_t npath, plen, len;
  72. const char *plst, *iter, *str;
  73. if ((err = benc_dget_off(fdct, "length", &tfp->length)) != 0)
  74. return err;
  75. if ((err = benc_dget_lst(fdct, "path", &plst)) != 0)
  76. return err;
  77. npath = plen = 0;
  78. iter = benc_first(plst);
  79. while (iter != NULL) {
  80. if (!benc_isstr(iter))
  81. return EINVAL;
  82. benc_str(iter, &str, &len, &iter);
  83. if (!check_path(str, len))
  84. return EINVAL;
  85. npath++;
  86. plen += len;
  87. }
  88. if (npath == 0)
  89. return EINVAL;
  90. if ((tfp->path = malloc(plen + (npath - 1) + 1)) == NULL)
  91. return ENOMEM;
  92. iter = benc_first(plst);
  93. benc_str(iter, &str, &len, &iter);
  94. memcpy(tfp->path, str, len);
  95. plen = len;
  96. npath--;
  97. while (npath > 0) {
  98. tfp->path[plen++] = '/';
  99. benc_str(iter, &str, &len, &iter);
  100. memcpy(tfp->path + plen, str, len);
  101. plen += len;
  102. npath--;
  103. }
  104. tfp->path[plen] = '\0';
  105. return 0;
  106. }
  107. void
  108. clear_metainfo(struct metainfo *mip)
  109. {
  110. int i;
  111. if (mip->piece_hash != NULL)
  112. free(mip->piece_hash);
  113. if (mip->announce != NULL)
  114. free(mip->announce);
  115. if (mip->files != NULL) {
  116. for (i = 0; i < mip->nfiles; i++) {
  117. if (mip->files[i].path != NULL)
  118. free(mip->files[i].path);
  119. }
  120. free(mip->files);
  121. }
  122. if (mip->name != NULL)
  123. free(mip->name);
  124. }
  125. int
  126. fill_metainfo(const char *bep, struct metainfo *tp, int mem_hashes)
  127. {
  128. size_t len;
  129. int err;
  130. const char *base_addr = bep;
  131. const char *hash_addr;
  132. if (!benc_isdct(bep))
  133. return EINVAL;
  134. if ((err = benc_dget_strz(bep, "announce", &tp->announce, NULL)) != 0)
  135. goto out;
  136. if ((err = benc_dget_dct(bep, "info", &bep)) != 0)
  137. goto out;
  138. SHA1(bep, benc_length(bep), tp->info_hash);
  139. if ((err = benc_dget_off(bep, "piece length", &tp->piece_length)) != 0)
  140. goto out;
  141. if ((err = benc_dget_str(bep, "pieces", &hash_addr, &len)) != 0)
  142. goto out;
  143. if (len % 20 != 0) {
  144. err = EINVAL;
  145. goto out;
  146. }
  147. tp->npieces = len / 20;
  148. tp->pieces_off = hash_addr - base_addr;
  149. if (mem_hashes) {
  150. if ((tp->piece_hash = malloc(len)) == NULL) {
  151. err = ENOMEM;
  152. goto out;
  153. }
  154. bcopy(hash_addr, tp->piece_hash, len);
  155. }
  156. if ((err = benc_dget_strz(bep, "name", &tp->name, NULL)) != 0)
  157. goto out;
  158. err = benc_dget_off(bep, "length", &tp->total_length);
  159. if (err == 0) {
  160. tp->nfiles = 1;
  161. tp->files = calloc(1, sizeof(struct fileinfo));
  162. if (tp->files != NULL) {
  163. tp->files[0].length = tp->total_length;
  164. tp->files[0].path = strdup(tp->name);
  165. if (tp->files[0].path == NULL) {
  166. err = ENOMEM;
  167. goto out;
  168. }
  169. } else {
  170. err = ENOMEM;
  171. goto out;
  172. }
  173. }
  174. else if (err == ENOENT) {
  175. int i;
  176. const char *flst, *fdct;
  177. if ((err = benc_dget_lst(bep, "files", &flst)) != 0)
  178. goto out;
  179. tp->nfiles = benc_nelems(flst);
  180. if (tp->nfiles < 1) {
  181. err = EINVAL;
  182. goto out;
  183. }
  184. tp->files = calloc(tp->nfiles, sizeof(struct fileinfo));
  185. tp->total_length = 0;
  186. i = 0;
  187. for (fdct = benc_first(flst); fdct != NULL; fdct = benc_next(fdct)) {
  188. if (!benc_isdct(fdct)) {
  189. err = EINVAL;
  190. goto out;
  191. }
  192. if ((err = fill_fileinfo(fdct, &tp->files[i])) != 0)
  193. goto out;
  194. tp->total_length += tp->files[i].length;
  195. i++;
  196. }
  197. }
  198. else
  199. goto out;
  200. out:
  201. if (err != 0)
  202. clear_metainfo(tp);
  203. return err;
  204. }
  205. int
  206. load_metainfo(const char *path, off_t size, int mem_hashes,
  207. struct metainfo **res)
  208. {
  209. char *buf;
  210. int fd, err = 0;
  211. if ((fd = open(path, O_RDONLY)) == -1)
  212. return errno;
  213. if (size <= 0) {
  214. struct stat sb;
  215. if (fstat(fd, &sb) == -1) {
  216. close(fd);
  217. return errno;
  218. } else
  219. size = sb.st_size;
  220. }
  221. if ((buf = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
  222. err = errno;
  223. close(fd);
  224. if (err == 0)
  225. err = benc_validate(buf, size);
  226. if (err == 0)
  227. if ((*res = calloc(1, sizeof(**res))) == NULL)
  228. err = ENOMEM;
  229. if (err == 0)
  230. if ((err = fill_metainfo(buf, *res, mem_hashes)) != 0)
  231. free(*res);
  232. munmap(buf, size);
  233. return err;
  234. }