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:
M | sbtd.h | | | 8 | +++++++- |
M | torrent.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: