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

187 行
4.2 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, unsigned nfiles, struct mi_file *files,
  13. fdcb_t fd_cb, void *fd_arg)
  14. {
  15. struct bt_stream *bts = calloc(1, sizeof(*bts));
  16. if (bts == NULL)
  17. return ENOMEM;
  18. bts->nfiles = nfiles;
  19. bts->files = files;
  20. bts->fd_cb = fd_cb;
  21. bts->fd_arg = fd_arg;
  22. bts->fd = -1;
  23. for (unsigned i = 0; i < bts->nfiles; i++)
  24. bts->totlen += bts->files[i].length;
  25. *res = bts;
  26. return 0;
  27. }
  28. int
  29. bts_close(struct bt_stream *bts)
  30. {
  31. int err = 0;
  32. if (bts->fd != -1 && close(bts->fd) == -1)
  33. err = errno;
  34. free(bts);
  35. return err;
  36. }
  37. int
  38. bts_seek(struct bt_stream *bts, off_t off)
  39. {
  40. if (bts->t_off == off)
  41. return 0;
  42. bts->t_off = off;
  43. unsigned i;
  44. for (i = 0; off >= bts->files[i].length; i++)
  45. off -= bts->files[i].length;
  46. if (i != bts->index) {
  47. if (bts->fd != -1) {
  48. if (close(bts->fd) == -1)
  49. return errno;
  50. bts->fd = -1;
  51. }
  52. } else if (bts->fd != -1)
  53. lseek(bts->fd, off, SEEK_SET);
  54. bts->index = i;
  55. bts->f_off = off;
  56. return 0;
  57. }
  58. int
  59. bts_get(struct bt_stream *bts, off_t off, uint8_t *buf, size_t len)
  60. {
  61. size_t boff, wantread;
  62. ssize_t didread;
  63. int err;
  64. assert(off + len <= bts->totlen);
  65. if ((err = bts_seek(bts, off)) != 0)
  66. return err;
  67. boff = 0;
  68. while (boff < len) {
  69. if (bts->fd == -1) {
  70. while (bts->files[bts->index].length == 0)
  71. bts->index++;
  72. err = bts->fd_cb(bts->files[bts->index].path,
  73. &bts->fd, bts->fd_arg);
  74. if (err != 0)
  75. return err;
  76. if (bts->f_off != 0)
  77. lseek(bts->fd, bts->f_off, SEEK_SET);
  78. }
  79. wantread = min(len - boff, bts->files[bts->index].length - bts->f_off);
  80. didread = read(bts->fd, buf + boff, wantread);
  81. if (didread == -1)
  82. return errno;
  83. boff += didread;
  84. bts->f_off += didread;
  85. bts->t_off += didread;
  86. if (bts->f_off == bts->files[bts->index].length) {
  87. close(bts->fd);
  88. bts->fd = -1;
  89. bts->f_off = 0;
  90. bts->index++;
  91. }
  92. if (didread != wantread)
  93. return ENOENT;
  94. }
  95. return 0;
  96. }
  97. int
  98. bts_put(struct bt_stream *bts, off_t off, const uint8_t *buf, size_t len)
  99. {
  100. size_t boff, wantwrite;
  101. ssize_t didwrite;
  102. int err;
  103. assert(off + len <= bts->totlen);
  104. if ((err = bts_seek(bts, off)) != 0)
  105. return err;
  106. boff = 0;
  107. while (boff < len) {
  108. if (bts->fd == -1) {
  109. while (bts->files[bts->index].length == 0)
  110. bts->index++;
  111. err = bts->fd_cb(bts->files[bts->index].path,
  112. &bts->fd, bts->fd_arg);
  113. if (err != 0)
  114. return err;
  115. if (bts->f_off != 0)
  116. lseek(bts->fd, bts->f_off, SEEK_SET);
  117. }
  118. wantwrite = min(len - boff, bts->files[bts->index].length - bts->f_off);
  119. didwrite = write(bts->fd, buf + boff, wantwrite);
  120. if (didwrite == -1)
  121. return errno;
  122. boff += didwrite;
  123. bts->f_off += didwrite;
  124. bts->t_off += didwrite;
  125. if (bts->f_off == bts->files[bts->index].length) {
  126. if (close(bts->fd) == -1)
  127. return errno;
  128. bts->fd = -1;
  129. bts->f_off = 0;
  130. bts->index++;
  131. }
  132. }
  133. return 0;
  134. }
  135. #define SHAFILEBUF (1 << 15)
  136. int
  137. bts_sha(struct bt_stream *bts, off_t start, off_t length, uint8_t *hash)
  138. {
  139. SHA_CTX ctx;
  140. char buf[SHAFILEBUF];
  141. size_t wantread;
  142. int err = 0;
  143. SHA1_Init(&ctx);
  144. while (length > 0) {
  145. wantread = min(length, SHAFILEBUF);
  146. if ((err = bts_get(bts, start, buf, wantread)) != 0)
  147. break;
  148. length -= wantread;
  149. start += wantread;
  150. SHA1_Update(&ctx, buf, wantread);
  151. }
  152. SHA1_Final(hash, &ctx);
  153. return err;
  154. }
  155. const char *
  156. bts_filename(struct bt_stream *bts)
  157. {
  158. return bts->files[bts->index].path;
  159. }