torrentd

simple torrent daemon
git clone git@git.2f30.org/torrentd.git
Log | Files | Refs | LICENSE

commit 7d546dd306c2f101d6cc41d40db3dc1128c22df2
parent e33b18d011bf61e0eafad98edd381a9544f91a6d
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Fri, 18 Dec 2015 21:27:03 +0100

multi-file mode and other improvements

- unify single-file and multi-file mode.
- use "name" as suggested directory name in multi-file mode
  in single-file mode it is always "".
- calculate length of pieces based on total data size.
- do some additional type checks.

Diffstat:
Msbtd.h | 8+++++++-
Mtorrent.c | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 90 insertions(+), 12 deletions(-)

diff --git a/sbtd.h b/sbtd.h @@ -25,6 +25,11 @@ struct ben { struct ben *next; }; +struct file { + size_t len; + char *path; +}; + struct torrent { char *buf; size_t buflen; @@ -33,8 +38,9 @@ struct torrent { struct ben *pieces; char *announce; char *filename; + struct file *files; + size_t nfiles; uint8_t infohash[20]; - long long length; long long piecelen; long long npieces; uint32_t *piecebm; diff --git a/torrent.c b/torrent.c @@ -36,12 +36,21 @@ dumptorrent(struct torrent *t) uint8_t md[20]; char hex[41]; long long i; + size_t n; printf("announce: %s\n", t->announce); - printf("filename: %s\n", t->filename); + + if (t->filename[0]) + printf("directory: %s\n", t->filename); + if (t->nfiles) + printf("files (%zu):\n", t->nfiles); + for (n = 0; n < t->nfiles; n++) { + printf("\tpath: %s, length: %zu\n", + t->files[n].path, t->files[n].len); + } + bin2hex(t->infohash, hex, 20); printf("infohash: %s\n", hex); - printf("length: %lld\n", t->length); printf("piecelen: %lld\n", t->piecelen); printf("npieces: %lld\n", t->npieces); @@ -56,6 +65,9 @@ struct torrent * loadtorrent(char *f) { struct torrent *t; + struct ben *files, *file; + struct ben *length, *path, *tmp; + size_t n, pathlen, totallen = 0; t = emalloc(sizeof(*t)); if (readfile(f, &t->buf, &t->buflen) < 0) { @@ -95,14 +107,70 @@ loadtorrent(char *f) } t->filename = bstr2str(dlookstr(t->info, "name")); - if (!dlookstr(t->info, "length")) { - warnx("no length field in %s", f); - goto err2; - } - t->length = dlookstr(t->info, "length")->i; - if (t->length <= 0) { - warnx("length is <= 0 in %s", f); - goto err2; + /* multi-file mode or single file ? */ + if ((files = dlookstr(t->info, "files"))) { + if (files->type != 'l') { + warnx("invalid: \"files\" not a list"); + goto err2; + } + t->nfiles = files->len; + t->files = ecalloc(files->len, sizeof(struct file)); + + for (file = files, n = 0; file; file = file->next, n++) { + if (!(length = dlookstr(file->v, "length"))) { + warnx("no length field in %s", f); + goto err3; + } + if (length->type != 'i') { + warnx("length must be of type integer"); + goto err3; + } + if (length->i < 0) { + warnx("length is < 0 in %s", f); + goto err3; + } + totallen += (size_t)length->i; + t->files[n].len = (size_t)length->i; + + if (!(path = dlookstr(file->v, "path"))) + break; + if (path->type != 'l') + warnx("path must be of type list"); + + /* check path list and count path buffer size */ + for (tmp = path, pathlen = 0; tmp; tmp = tmp->next) { + if (tmp->v->type != 's') { + warnx("path item must be of type string"); + goto err2; + } + pathlen += tmp->v->len + 1; + } + t->files[n].path = ecalloc(1, pathlen); + for (tmp = path; tmp; tmp = tmp->next) { + strlcat(t->files[n].path, tmp->v->s, pathlen); + if (tmp != path && tmp->next) + strlcat(t->files[n].path, "/", pathlen); + } + } + } else { + if (!(length = dlookstr(t->info, "length"))) { + warnx("no length field in %s", f); + goto err2; + } + if (length->type != 'i') { + warnx("length must be of type integer"); + goto err2; + } + if (length->i < 0) { + warnx("length is < 0 in %s", f); + goto err2; + } + t->nfiles = n = 1; + t->files = ecalloc(1, sizeof(struct file)); + t->files[0].len = length->i; + t->files[0].path = strdup(t->filename); + t->filename = ""; + totallen = (size_t)length->i; } if (!dlookstr(t->info, "piece length")) { @@ -115,12 +183,16 @@ loadtorrent(char *f) goto err2; } - t->npieces = (t->length + t->piecelen - 1) / t->piecelen; + t->npieces = (totallen + t->piecelen - 1) / t->piecelen; t->piecebm = newbit(t->npieces); calcinfohash(t); return t; +err3: + while (n--) + free(t->files[n].path); + free(t->files); err2: bfree(t->ben); err1: