A clone of btpd with my configuration changes.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

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