diff --git a/misc/stream.c b/misc/stream.c index b1f6fc0..4bfab8f 100644 --- a/misc/stream.c +++ b/misc/stream.c @@ -11,61 +11,77 @@ #include "subr.h" #include "stream.h" -struct bt_stream_ro * -bts_open_ro(struct metainfo *meta, off_t off, F_fdcb fd_cb, void *fd_arg) +int +bts_open(struct bt_stream **res, struct metainfo *meta, fdcb_t fd_cb, + void *fd_arg) { - struct bt_stream_ro *bts = malloc(sizeof(*bts)); + struct bt_stream *bts = calloc(1, sizeof(*bts)); if (bts == NULL) - return NULL; + return ENOMEM; bts->meta = meta; bts->fd_cb = fd_cb; bts->fd_arg = fd_arg; - bts->t_off = 0; - bts->f_off = 0; - bts->index = 0; bts->fd = -1; - bts_seek_ro(bts, off); - return bts; + + *res = bts; + return 0; } -void -bts_seek_ro(struct bt_stream_ro *bts, off_t off) +int +bts_close(struct bt_stream *bts) { - struct fileinfo *files = bts->meta->files; - - assert(off >= 0 && off <= bts->meta->total_length); + int err = 0; + if (bts->fd != -1 && close(bts->fd) == -1) + err = errno; + free(bts); + return err; +} - if (bts->fd != -1) { - close(bts->fd); - bts->fd = -1; - } +int +bts_seek(struct bt_stream *bts, off_t off) +{ + if (bts->t_off == off) + return 0; bts->t_off = off; - bts->index = 0; - while (off >= files[bts->index].length) { - off -= files[bts->index].length; - bts->index++; - } + struct fileinfo *files = bts->meta->files; + unsigned i; + for (i = 0; off >= files[i].length; i++) + off -= files[i].length; + if (i != bts->index) { + if (bts->fd != -1) { + if (close(bts->fd) == -1) + return errno; + bts->fd = -1; + } + } else if (bts->fd != -1) + lseek(bts->fd, off, SEEK_SET); + + bts->index = i; bts->f_off = off; + + return 0; } int -bts_read_ro(struct bt_stream_ro *bts, char *buf, size_t len) +bts_get(struct bt_stream *bts, off_t off, uint8_t *buf, size_t len) { struct fileinfo *files = bts->meta->files; size_t boff, wantread; ssize_t didread; + int err; - assert(bts->t_off + len <= bts->meta->total_length); + assert(off + len <= bts->meta->total_length); + if ((err = bts_seek(bts, off)) != 0) + return err; boff = 0; while (boff < len) { if (bts->fd == -1) { - int err = - bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg); + err = bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg); if (err != 0) return err; if (bts->f_off != 0) @@ -92,104 +108,22 @@ bts_read_ro(struct bt_stream_ro *bts, char *buf, size_t len) return 0; } -void -bts_close_ro(struct bt_stream_ro *bts) -{ - if (bts->fd != -1) - close(bts->fd); - free(bts); -} - -#define SHAFILEBUF (1 << 15) - -int -bts_sha(struct bt_stream_ro *bts, off_t length, uint8_t *hash) -{ - SHA_CTX ctx; - char buf[SHAFILEBUF]; - size_t wantread; - int err = 0; - - SHA1_Init(&ctx); - while (length > 0) { - wantread = min(length, SHAFILEBUF); - if ((err = bts_read_ro(bts, buf, wantread)) != 0) - break; - length -= wantread; - SHA1_Update(&ctx, buf, wantread); - } - SHA1_Final(hash, &ctx); - return err; -} - int -bts_hashes(struct metainfo *meta, - F_fdcb fd_cb, - void (*cb)(uint32_t, uint8_t *, void *), - void *arg) -{ - int err = 0; - uint8_t hash[SHA_DIGEST_LENGTH]; - uint32_t piece; - struct bt_stream_ro *bts; - off_t plen = meta->piece_length; - off_t llen = meta->total_length % plen; - - if ((bts = bts_open_ro(meta, 0, fd_cb, arg)) == NULL) - return ENOMEM; - - for (piece = 0; piece < meta->npieces; piece++) { - if (piece < meta->npieces - 1) - err = bts_sha(bts, plen, hash); - else - err = bts_sha(bts, llen, hash); - - if (err == 0) - cb(piece, hash, arg); - else if (err == ENOENT) { - cb(piece, NULL, arg); - if (piece < meta->npieces - 1) - bts_seek_ro(bts, (piece + 1) * plen); - err = 0; - } else - break; - } - bts_close_ro(bts); - return err; -} - -struct bt_stream_wo * -bts_open_wo(struct metainfo *meta, off_t off, F_fdcb fd_cb, void *fd_arg) -{ - struct bt_stream_wo *bts = malloc(sizeof(*bts)); - if (bts == NULL) - return NULL; - - bts->meta = meta; - bts->fd_cb = fd_cb; - bts->fd_arg = fd_arg; - bts->t_off = 0; - bts->f_off = 0; - bts->index = 0; - bts->fd = -1; - bts_seek_ro((struct bt_stream_ro *)bts, off); - return bts; -} - -int -bts_write_wo(struct bt_stream_wo *bts, const char *buf, size_t len) +bts_put(struct bt_stream *bts, off_t off, const uint8_t *buf, size_t len) { struct fileinfo *files = bts->meta->files; size_t boff, wantwrite; ssize_t didwrite; + int err; - assert(bts->t_off + len <= bts->meta->total_length); + assert(off + len <= bts->meta->total_length); + if ((err = bts_seek(bts, off)) != 0) + return err; boff = 0; while (boff < len) { if (bts->fd == -1) { - int err = - bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg); + err = bts->fd_cb(files[bts->index].path, &bts->fd, bts->fd_arg); if (err != 0) return err; if (bts->f_off != 0) @@ -220,17 +154,57 @@ bts_write_wo(struct bt_stream_wo *bts, const char *buf, size_t len) return 0; } +#define SHAFILEBUF (1 << 15) + int -bts_close_wo(struct bt_stream_wo *bts) +bts_sha(struct bt_stream *bts, off_t start, off_t length, uint8_t *hash) { + SHA_CTX ctx; + char buf[SHAFILEBUF]; + size_t wantread; int err = 0; - if (bts->fd != -1) { - if (fsync(bts->fd) == -1) { - err = errno; - close(bts->fd); - } else if (close(bts->fd) == -1) - err = errno; + + SHA1_Init(&ctx); + while (length > 0) { + wantread = min(length, SHAFILEBUF); + if ((err = bts_get(bts, start, buf, wantread)) != 0) + break; + length -= wantread; + start += wantread; + SHA1_Update(&ctx, buf, wantread); } - free(bts); + SHA1_Final(hash, &ctx); + return err; +} + +int +bts_hashes(struct metainfo *meta, fdcb_t fd_cb, hashcb_t cb, void *arg) +{ + int err = 0; + uint8_t hash[SHA_DIGEST_LENGTH]; + uint32_t piece; + struct bt_stream *bts; + off_t plen = meta->piece_length; + off_t llen = meta->total_length % plen; + + if ((err = bts_open(&bts, meta, fd_cb, arg)) != 0) + return err; + + for (piece = 0; piece < meta->npieces; piece++) { + off_t start = piece * plen; + if (piece < meta->npieces - 1) + err = bts_sha(bts, start, plen, hash); + else + err = bts_sha(bts, start, llen, hash); + + if (err == 0) + cb(piece, hash, arg); + else if (err == ENOENT) { + cb(piece, NULL, arg); + err = 0; + } else + break; + } + bts_close(bts); return err; } diff --git a/misc/stream.h b/misc/stream.h index 6ed91d5..30ce443 100644 --- a/misc/stream.h +++ b/misc/stream.h @@ -1,36 +1,27 @@ #ifndef BTPD_STREAM_H #define BTPD_STREAM_H -typedef int (*F_fdcb)(const char *, int *, void *); - -#define def_stream(name) \ -struct name {\ - struct metainfo *meta;\ - F_fdcb fd_cb;\ - void *fd_arg;\ - unsigned index;\ - off_t t_off;\ - off_t f_off;\ - int fd;\ -} - -def_stream(bt_stream_ro); - -struct bt_stream_ro * -bts_open_ro(struct metainfo *meta, off_t off, F_fdcb fd_cb, void *fd_arg); -int bts_read_ro(struct bt_stream_ro *bts, char *buf, size_t len); -void bts_seek_ro(struct bt_stream_ro *bts, off_t nbytes); -void bts_close_ro(struct bt_stream_ro *bts); - -def_stream(bt_stream_wo); - -struct bt_stream_wo * -bts_open_wo(struct metainfo *meta, off_t off, F_fdcb fd_cb, void *fd_arg); -int bts_write_wo(struct bt_stream_wo *bts, const char *buf, size_t len); -int bts_close_wo(struct bt_stream_wo *bts); - -int bts_sha(struct bt_stream_ro *bts, off_t length, uint8_t *hash); -int bts_hashes(struct metainfo *, F_fdcb fd_cb, - void (*cb)(uint32_t, uint8_t *, void *), void *arg); +typedef int (*fdcb_t)(const char *, int *, void *); +typedef void (*hashcb_t)(uint32_t, uint8_t *, void *); + +struct bt_stream { + struct metainfo *meta; + fdcb_t fd_cb; + void *fd_arg; + unsigned index; + off_t t_off; + off_t f_off; + int fd; +}; + +int bts_open(struct bt_stream **res, struct metainfo *meta, fdcb_t fd_cb, + void *fd_arg); +int bts_get(struct bt_stream *bts, off_t off, uint8_t *buf, size_t len); +int bts_put(struct bt_stream *bts, off_t off, const uint8_t *buf, size_t len); +int bts_close(struct bt_stream *bts); + +int bts_sha(struct bt_stream *bts, off_t start, off_t length, uint8_t *hash); +int bts_hashes(struct metainfo *meta, fdcb_t fd_cb, hashcb_t hash_cb, + void *arg); #endif