A clone of btpd with my configuration changes.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
4.8 KiB

  1. #include <assert.h>
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <inttypes.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <openssl/sha.h>
  8. #include "metainfo.h"
  9. #include "subr.h"
  10. #include "stream.h"
  11. int
  12. bts_open(struct bt_stream **res, struct metainfo *meta, fdcb_t fd_cb,
  13. void *fd_arg)
  14. {
  15. struct bt_stream *bts = calloc(1, sizeof(*bts));
  16. if (bts == NULL)
  17. return ENOMEM;
  18. bts->meta = meta;
  19. bts->fd_cb = fd_cb;
  20. bts->fd_arg = fd_arg;
  21. bts->fd = -1;
  22. *res = bts;
  23. return 0;
  24. }
  25. int
  26. bts_close(struct bt_stream *bts)
  27. {
  28. int err = 0;
  29. if (bts->fd != -1 && close(bts->fd) == -1)
  30. err = errno;
  31. free(bts);
  32. return err;
  33. }
  34. int
  35. bts_seek(struct bt_stream *bts, off_t off)
  36. {
  37. if (bts->t_off == off)
  38. return 0;
  39. bts->t_off = off;
  40. struct fileinfo *files = bts->meta->files;
  41. unsigned i;
  42. for (i = 0; off >= files[i].length; i++)
  43. off -= files[i].length;
  44. if (i != bts->index) {
  45. if (bts->fd != -1) {
  46. if (close(bts->fd) == -1)
  47. return errno;
  48. bts->fd = -1;
  49. }
  50. } else if (bts->fd != -1)
  51. lseek(bts->fd, off, SEEK_SET);
  52. bts->index = i;
  53. bts->f_off = off;
  54. return 0;
  55. }
  56. int
  57. bts_get(struct bt_stream *bts, off_t off, uint8_t *buf, size_t len)
  58. {
  59. struct fileinfo *files = bts->meta->files;
  60. size_t boff, wantread;
  61. ssize_t didread;
  62. int err;
  63. assert(off + len <= bts->meta->total_length);
  64. if ((err = bts_seek(bts, off)) != 0)
  65. return err;
  66. boff = 0;
  67. while (boff < len) {
  68. if (bts->fd == -1) {
  69. err = bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg);
  70. if (err != 0)
  71. return err;
  72. if (bts->f_off != 0)
  73. lseek(bts->fd, bts->f_off, SEEK_SET);
  74. }
  75. wantread = min(len - boff, files[bts->index].length - bts->f_off);
  76. didread = read(bts->fd, buf + boff, wantread);
  77. if (didread == -1)
  78. return errno;
  79. boff += didread;
  80. bts->f_off += didread;
  81. bts->t_off += didread;
  82. if (bts->f_off == files[bts->index].length) {
  83. close(bts->fd);
  84. bts->fd = -1;
  85. bts->f_off = 0;
  86. bts->index++;
  87. }
  88. if (didread != wantread)
  89. return ENOENT;
  90. }
  91. return 0;
  92. }
  93. int
  94. bts_put(struct bt_stream *bts, off_t off, const uint8_t *buf, size_t len)
  95. {
  96. struct fileinfo *files = bts->meta->files;
  97. size_t boff, wantwrite;
  98. ssize_t didwrite;
  99. int err;
  100. assert(off + len <= bts->meta->total_length);
  101. if ((err = bts_seek(bts, off)) != 0)
  102. return err;
  103. boff = 0;
  104. while (boff < len) {
  105. if (bts->fd == -1) {
  106. err = bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg);
  107. if (err != 0)
  108. return err;
  109. if (bts->f_off != 0)
  110. lseek(bts->fd, bts->f_off, SEEK_SET);
  111. }
  112. wantwrite = min(len - boff, files[bts->index].length - bts->f_off);
  113. didwrite = write(bts->fd, buf + boff, wantwrite);
  114. if (didwrite == -1)
  115. return errno;
  116. boff += didwrite;
  117. bts->f_off += didwrite;
  118. bts->t_off += didwrite;
  119. if (bts->f_off == files[bts->index].length) {
  120. if (fsync(bts->fd) == -1) {
  121. int err = errno;
  122. close(bts->fd);
  123. return err;
  124. }
  125. if (close(bts->fd) == -1)
  126. return errno;
  127. bts->fd = -1;
  128. bts->f_off = 0;
  129. bts->index++;
  130. }
  131. }
  132. return 0;
  133. }
  134. #define SHAFILEBUF (1 << 15)
  135. int
  136. bts_sha(struct bt_stream *bts, off_t start, off_t length, uint8_t *hash)
  137. {
  138. SHA_CTX ctx;
  139. char buf[SHAFILEBUF];
  140. size_t wantread;
  141. int err = 0;
  142. SHA1_Init(&ctx);
  143. while (length > 0) {
  144. wantread = min(length, SHAFILEBUF);
  145. if ((err = bts_get(bts, start, buf, wantread)) != 0)
  146. break;
  147. length -= wantread;
  148. start += wantread;
  149. SHA1_Update(&ctx, buf, wantread);
  150. }
  151. SHA1_Final(hash, &ctx);
  152. return err;
  153. }
  154. int
  155. bts_hashes(struct metainfo *meta, fdcb_t fd_cb, hashcb_t cb, void *arg)
  156. {
  157. int err = 0;
  158. uint8_t hash[SHA_DIGEST_LENGTH];
  159. uint32_t piece;
  160. struct bt_stream *bts;
  161. off_t plen = meta->piece_length;
  162. off_t llen = meta->total_length % plen;
  163. if ((err = bts_open(&bts, meta, fd_cb, arg)) != 0)
  164. return err;
  165. for (piece = 0; piece < meta->npieces; piece++) {
  166. off_t start = piece * plen;
  167. if (piece < meta->npieces - 1)
  168. err = bts_sha(bts, start, plen, hash);
  169. else
  170. err = bts_sha(bts, start, llen, hash);
  171. if (err == 0)
  172. cb(piece, hash, arg);
  173. else if (err == ENOENT) {
  174. cb(piece, NULL, arg);
  175. err = 0;
  176. } else
  177. break;
  178. }
  179. bts_close(bts);
  180. return err;
  181. }