A clone of btpd with my configuration changes.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

306 lignes
7.6 KiB

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <dirent.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include "btpd.h"
  7. HTBL_TYPE(numtbl, tlib, unsigned, num, nchain);
  8. HTBL_TYPE(hashtbl, tlib, uint8_t, hash, hchain);
  9. static unsigned m_nextnum;
  10. static unsigned m_ntlibs;
  11. static struct numtbl *m_numtbl;
  12. static struct hashtbl *m_hashtbl;
  13. unsigned
  14. tlib_count(void)
  15. {
  16. return m_ntlibs;
  17. }
  18. struct tlib *
  19. tlib_by_num(unsigned num)
  20. {
  21. return numtbl_find(m_numtbl, &num);
  22. }
  23. struct tlib *
  24. tlib_by_hash(const uint8_t *hash)
  25. {
  26. return hashtbl_find(m_hashtbl, hash);
  27. }
  28. void
  29. tlib_kill(struct tlib *tl)
  30. {
  31. numtbl_remove(m_numtbl, &tl->num);
  32. hashtbl_remove(m_hashtbl, tl->hash);
  33. free(tl);
  34. m_ntlibs--;
  35. }
  36. struct tlib *
  37. tlib_create(const uint8_t *hash)
  38. {
  39. struct tlib *tl = btpd_calloc(1, sizeof(*tl));
  40. char hex[SHAHEXSIZE];
  41. bin2hex(hash, hex, 20);
  42. tl->num = m_nextnum;
  43. bcopy(hash, tl->hash, 20);
  44. m_nextnum++;
  45. m_ntlibs++;
  46. numtbl_insert(m_numtbl, tl);
  47. hashtbl_insert(m_hashtbl, tl);
  48. return tl;
  49. }
  50. int
  51. tlib_del(struct tlib *tl)
  52. {
  53. char relpath[RELPATH_SIZE];
  54. char cmd[PATH_MAX];
  55. assert(tl->tp == NULL);
  56. snprintf(cmd, PATH_MAX, "rm -r torrents/%s",
  57. bin2hex(tl->hash, relpath, 20));
  58. system(cmd);
  59. tlib_kill(tl);
  60. return 0;
  61. }
  62. static void
  63. dct_subst_save(FILE *fp, const char *dct1, const char *dct2)
  64. {
  65. fprintf(fp, "d");
  66. const char *k1 = benc_first(dct1), *k2 = benc_first(dct2);
  67. const char *val, *str, *rest;
  68. size_t len;
  69. while (k1 != NULL && k2 != NULL) {
  70. int test = benc_strcmp(k1, k2);
  71. if (test < 0) {
  72. str = benc_mem(k1, &len, &val);
  73. fprintf(fp, "%d:%.*s", (int)len, (int)len, str);
  74. fwrite(val, 1, benc_length(val), fp);
  75. k1 = benc_next(val);
  76. } else {
  77. str = benc_mem(k2, &len, &val);
  78. fprintf(fp, "%d:%.*s", (int)len, (int)len, str);
  79. fwrite(val, 1, benc_length(val), fp);
  80. k2 = benc_next(val);
  81. if (test == 0)
  82. k1 = benc_next(benc_next(k1));
  83. }
  84. }
  85. rest = k1 != NULL ? k1 : k2;
  86. while (rest != NULL) {
  87. str = benc_mem(rest, &len, &val);
  88. fprintf(fp, "%d:%.*s", (int)len, (int)len, str);
  89. fwrite(val, 1, benc_length(val), fp);
  90. rest = benc_next(val);
  91. }
  92. fprintf(fp, "e");
  93. }
  94. static int
  95. valid_info(char *buf, size_t len)
  96. {
  97. size_t slen;
  98. const char *info;
  99. if (benc_validate(buf, len) != 0)
  100. return 0;
  101. if ((info = benc_dget_dct(buf, "info")) == NULL)
  102. return 0;
  103. if (benc_dget_mem(info, "name", &slen) == NULL || slen == 0)
  104. return 0;
  105. if ((benc_dget_mem(info, "dir", &slen) == NULL ||
  106. (slen == 0 || slen >= PATH_MAX)))
  107. return 0;
  108. return 1;
  109. }
  110. static void
  111. load_info(struct tlib *tl, const char *path)
  112. {
  113. size_t size = 1 << 14;
  114. char buf[size], *p = buf;
  115. const char *info;
  116. if ((errno = read_whole_file((void **)&p, &size, path)) != 0) {
  117. btpd_log(BTPD_L_ERROR, "couldn't load '%s' (%s).\n", path,
  118. strerror(errno));
  119. return;
  120. }
  121. if (!valid_info(buf, size)) {
  122. btpd_log(BTPD_L_ERROR, "bad info file '%s'.\n", path);
  123. return;
  124. }
  125. info = benc_dget_dct(buf, "info");
  126. tl->name = benc_dget_str(info, "name", NULL);
  127. tl->dir = benc_dget_str(info, "dir", NULL);
  128. tl->tot_up = benc_dget_int(info, "total upload");
  129. tl->tot_down = benc_dget_int(info, "total download");
  130. tl->content_size = benc_dget_int(info, "content size");
  131. tl->content_have = benc_dget_int(info, "content have");
  132. if (tl->name == NULL || tl->dir == NULL)
  133. btpd_err("Out of memory.\n");
  134. }
  135. static void
  136. save_info(struct tlib *tl)
  137. {
  138. FILE *fp;
  139. char relpath[SHAHEXSIZE], path[PATH_MAX], wpath[PATH_MAX];
  140. char *old = NULL;
  141. size_t size = 1 << 14;
  142. struct io_buffer iob = buf_init(1 << 10);
  143. buf_print(&iob,
  144. "d4:infod"
  145. "12:content havei%llde12:content sizei%llde"
  146. "3:dir%d:%s4:name%d:%s"
  147. "14:total downloadi%llde12:total uploadi%llde"
  148. "ee",
  149. tl->content_have, tl->content_size,
  150. (int)strlen(tl->dir), tl->dir, (int)strlen(tl->name), tl->name,
  151. tl->tot_down, tl->tot_up);
  152. if (iob.error)
  153. btpd_err("Out of memory.\n");
  154. if ((errno = read_whole_file((void **)&old, &size, path)) != 0
  155. && errno != ENOENT)
  156. btpd_log(BTPD_L_ERROR, "couldn't load '%s' (%s).\n", path,
  157. strerror(errno));
  158. bin2hex(tl->hash, relpath, 20);
  159. snprintf(path, PATH_MAX, "torrents/%s/info", relpath);
  160. snprintf(wpath, PATH_MAX, "%s.write", path);
  161. if ((fp = fopen(wpath, "w")) == NULL)
  162. btpd_err("failed to open '%s' (%s).\n", wpath, strerror(errno));
  163. if (old != NULL) {
  164. dct_subst_save(fp, old, iob.buf);
  165. free(old);
  166. } else
  167. dct_subst_save(fp, "de", iob.buf);
  168. buf_free(&iob);
  169. if (ferror(fp) || fclose(fp) != 0)
  170. btpd_err("failed to write '%s'.\n", wpath);
  171. if (rename(wpath, path) != 0)
  172. btpd_err("failed to rename: '%s' -> '%s' (%s).\n", wpath, path,
  173. strerror(errno));
  174. }
  175. void
  176. tlib_update_info(struct tlib *tl)
  177. {
  178. assert(tl->tp != NULL);
  179. tl->tot_down += tl->tp->net->downloaded;
  180. tl->tot_up += tl->tp->net->uploaded;
  181. tl->content_have = cm_content(tl->tp);
  182. tl->content_size = tl->tp->total_length;
  183. save_info(tl);
  184. }
  185. static void
  186. write_torrent(const char *mi, size_t mi_size, const char *path)
  187. {
  188. FILE *fp;
  189. if ((fp = fopen(path, "w")) == NULL)
  190. goto err;
  191. if (fwrite(mi, mi_size, 1, fp) != 1) {
  192. errno = EIO;
  193. goto err;
  194. }
  195. if (fclose(fp) != 0)
  196. goto err;
  197. return;
  198. err:
  199. btpd_err("failed to write metainfo '%s' (%s).\n", path, strerror(errno));
  200. }
  201. struct tlib *
  202. tlib_add(const uint8_t *hash, const char *mi, size_t mi_size,
  203. const char *content, char *name)
  204. {
  205. struct tlib *tl = tlib_create(hash);
  206. char relpath[RELPATH_SIZE], file[PATH_MAX];
  207. bin2hex(hash, relpath, 20);
  208. if (name == NULL)
  209. if ((name = mi_name(mi)) == NULL)
  210. btpd_err("out of memory.\n");
  211. tl->content_size = mi_total_length(mi);
  212. tl->name = name;
  213. tl->dir = strdup(content);
  214. if (tl->name == NULL || tl->dir == NULL)
  215. btpd_err("out of memory.\n");
  216. snprintf(file, PATH_MAX, "torrents/%s", relpath);
  217. if (mkdir(file, 0777) != 0)
  218. btpd_err("failed to create dir '%s' (%s).\n", file, strerror(errno));
  219. snprintf(file, PATH_MAX, "torrents/%s/torrent", relpath);
  220. write_torrent(mi, mi_size, file);
  221. save_info(tl);
  222. return tl;
  223. }
  224. static int
  225. num_test(const void *k1, const void *k2)
  226. {
  227. return *(const unsigned *)k1 == *(const unsigned *)k2;
  228. }
  229. static uint32_t
  230. num_hash(const void *k)
  231. {
  232. return *(const unsigned *)k;
  233. }
  234. static int
  235. id_test(const void *k1, const void *k2)
  236. {
  237. return bcmp(k1, k2, 20) == 0;
  238. }
  239. static uint32_t
  240. id_hash(const void *k)
  241. {
  242. return net_read32(k + 16);
  243. }
  244. void
  245. tlib_put_all(struct tlib **v)
  246. {
  247. hashtbl_tov(m_hashtbl, v);
  248. }
  249. void
  250. tlib_init(void)
  251. {
  252. DIR *dirp;
  253. struct dirent *dp;
  254. uint8_t hash[20];
  255. char file[PATH_MAX];
  256. m_numtbl = numtbl_create(num_test, num_hash);
  257. m_hashtbl = hashtbl_create(id_test, id_hash);
  258. if (m_numtbl == NULL || m_hashtbl == NULL)
  259. btpd_err("Out of memory.\n");
  260. if ((dirp = opendir("torrents")) == NULL)
  261. btpd_err("couldn't open the torrents directory.\n");
  262. while ((dp = readdir(dirp)) != NULL) {
  263. if (dp->d_namlen == 40 && ishex(dp->d_name)) {
  264. struct tlib * tl = tlib_create(hex2bin(dp->d_name, hash, 20));
  265. snprintf(file, PATH_MAX, "torrents/%s/info", dp->d_name);
  266. load_info(tl, file);
  267. }
  268. }
  269. closedir(dirp);
  270. }