A clone of btpd with my configuration changes.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

242 lines
4.9 KiB

  1. #include <assert.h>
  2. #include <errno.h>
  3. #include <inttypes.h>
  4. #include <fcntl.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. struct bt_stream_ro *
  12. bts_open_ro(struct metainfo *meta, off_t off, F_fdcb fd_cb, void *fd_arg)
  13. {
  14. struct bt_stream_ro *bts = malloc(sizeof(*bts));
  15. if (bts == NULL)
  16. return NULL;
  17. bts->meta = meta;
  18. bts->fd_cb = fd_cb;
  19. bts->fd_arg = fd_arg;
  20. bts->t_off = 0;
  21. bts->f_off = 0;
  22. bts->index = 0;
  23. bts->fd = -1;
  24. bts_seek_ro(bts, off);
  25. return bts;
  26. }
  27. void
  28. bts_seek_ro(struct bt_stream_ro *bts, off_t off)
  29. {
  30. struct fileinfo *files = bts->meta->files;
  31. assert(off >= 0 && off <= bts->meta->total_length);
  32. if (bts->fd != -1) {
  33. close(bts->fd);
  34. bts->fd = -1;
  35. }
  36. bts->t_off = off;
  37. bts->index = 0;
  38. while (off >= files[bts->index].length) {
  39. off -= files[bts->index].length;
  40. bts->index++;
  41. }
  42. bts->f_off = off;
  43. }
  44. int
  45. bts_read_ro(struct bt_stream_ro *bts, char *buf, size_t len)
  46. {
  47. struct fileinfo *files = bts->meta->files;
  48. size_t boff, wantread;
  49. ssize_t didread;
  50. assert(bts->t_off + len <= bts->meta->total_length);
  51. boff = 0;
  52. while (boff < len) {
  53. if (bts->fd == -1) {
  54. int err =
  55. bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg);
  56. if (err != 0)
  57. return err;
  58. if (bts->f_off != 0)
  59. lseek(bts->fd, bts->f_off, SEEK_SET);
  60. }
  61. wantread = min(len - boff, files[bts->index].length - bts->f_off);
  62. again:
  63. didread = read(bts->fd, buf + boff, wantread);
  64. if (didread == -1) {
  65. if (errno == EINTR)
  66. goto again;
  67. else
  68. return errno;
  69. }
  70. boff += didread;
  71. bts->f_off += didread;
  72. bts->t_off += didread;
  73. if (bts->f_off == files[bts->index].length) {
  74. close(bts->fd);
  75. bts->fd = -1;
  76. bts->f_off = 0;
  77. bts->index++;
  78. }
  79. if (didread != wantread)
  80. return ENOENT;
  81. }
  82. return 0;
  83. }
  84. void
  85. bts_close_ro(struct bt_stream_ro *bts)
  86. {
  87. if (bts->fd != -1)
  88. close(bts->fd);
  89. free(bts);
  90. }
  91. #define SHAFILEBUF (1 << 15)
  92. int
  93. bts_sha(struct bt_stream_ro *bts, off_t length, uint8_t *hash)
  94. {
  95. SHA_CTX ctx;
  96. char buf[SHAFILEBUF];
  97. size_t wantread;
  98. int err = 0;
  99. SHA1_Init(&ctx);
  100. while (length > 0) {
  101. wantread = min(length, SHAFILEBUF);
  102. if ((err = bts_read_ro(bts, buf, wantread)) != 0)
  103. break;
  104. length -= wantread;
  105. SHA1_Update(&ctx, buf, wantread);
  106. }
  107. SHA1_Final(hash, &ctx);
  108. return err;
  109. }
  110. int
  111. bts_hashes(struct metainfo *meta,
  112. F_fdcb fd_cb,
  113. void (*cb)(uint32_t, uint8_t *, void *),
  114. void *arg)
  115. {
  116. int err = 0;
  117. uint8_t hash[SHA_DIGEST_LENGTH];
  118. uint32_t piece;
  119. struct bt_stream_ro *bts;
  120. off_t plen = meta->piece_length;
  121. off_t llen = meta->total_length % plen;
  122. if ((bts = bts_open_ro(meta, 0, fd_cb, arg)) == NULL)
  123. return ENOMEM;
  124. for (piece = 0; piece < meta->npieces; piece++) {
  125. if (piece < meta->npieces - 1)
  126. err = bts_sha(bts, plen, hash);
  127. else
  128. err = bts_sha(bts, llen, hash);
  129. if (err == 0)
  130. cb(piece, hash, arg);
  131. else if (err == ENOENT) {
  132. cb(piece, NULL, arg);
  133. if (piece < meta->npieces - 1)
  134. bts_seek_ro(bts, (piece + 1) * plen);
  135. err = 0;
  136. } else
  137. break;
  138. }
  139. bts_close_ro(bts);
  140. return err;
  141. }
  142. struct bt_stream_wo *
  143. bts_open_wo(struct metainfo *meta, off_t off, F_fdcb fd_cb, void *fd_arg)
  144. {
  145. struct bt_stream_wo *bts = malloc(sizeof(*bts));
  146. if (bts == NULL)
  147. return NULL;
  148. bts->meta = meta;
  149. bts->fd_cb = fd_cb;
  150. bts->fd_arg = fd_arg;
  151. bts->t_off = 0;
  152. bts->f_off = 0;
  153. bts->index = 0;
  154. bts->fd = -1;
  155. bts_seek_ro((struct bt_stream_ro *)bts, off);
  156. return bts;
  157. }
  158. int
  159. bts_write_wo(struct bt_stream_wo *bts, const char *buf, size_t len)
  160. {
  161. struct fileinfo *files = bts->meta->files;
  162. size_t boff, wantwrite;
  163. ssize_t didwrite;
  164. assert(bts->t_off + len <= bts->meta->total_length);
  165. boff = 0;
  166. while (boff < len) {
  167. if (bts->fd == -1) {
  168. int err =
  169. bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg);
  170. if (err != 0)
  171. return err;
  172. if (bts->f_off != 0)
  173. lseek(bts->fd, bts->f_off, SEEK_SET);
  174. }
  175. wantwrite = min(len - boff, files[bts->index].length - bts->f_off);
  176. didwrite = write(bts->fd, buf + boff, wantwrite);
  177. if (didwrite == -1)
  178. return errno;
  179. boff += didwrite;
  180. bts->f_off += didwrite;
  181. bts->t_off += didwrite;
  182. if (bts->f_off == files[bts->index].length) {
  183. if (fsync(bts->fd) == -1) {
  184. int err = errno;
  185. close(bts->fd);
  186. return err;
  187. }
  188. if (close(bts->fd) == -1)
  189. return errno;
  190. bts->fd = -1;
  191. bts->f_off = 0;
  192. bts->index++;
  193. }
  194. }
  195. return 0;
  196. }
  197. int
  198. bts_close_wo(struct bt_stream_wo *bts)
  199. {
  200. int err = 0;
  201. if (bts->fd != -1) {
  202. if (fsync(bts->fd) == -1) {
  203. err = errno;
  204. close(bts->fd);
  205. } else if (close(bts->fd) == -1)
  206. err = errno;
  207. }
  208. free(bts);
  209. return err;
  210. }