commit 1b95d93ca2bc0cd467e48f69c983cd421e53dc23
parent bd3979b9d7b029d898e9718d19fa855bf191c5c4
Author: sin <sin@2f30.org>
Date: Fri, 18 Dec 2015 15:04:29 +0000
Add {load,unload}torrent()
Diffstat:
M | sbtd.h | | | 16 | ++++++++++++++++ |
M | torrent.c | | | 81 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 97 insertions(+), 0 deletions(-)
diff --git a/sbtd.h b/sbtd.h
@@ -25,6 +25,18 @@ struct ben {
struct ben *next;
};
+struct torrent {
+ char *buf;
+ size_t buflen;
+ struct ben *ben;
+ struct ben *info;
+ char *announce;
+ uint8_t infohash[20];
+ long long length;
+ long long piecelen;
+ long long npieces;
+};
+
/* ben.c */
char *bdecode(char *, char *, struct ben **);
void bencode(char **, size_t *, struct ben *);
@@ -35,6 +47,10 @@ struct ben *dlookstr(struct ben *, char *);
void bfree(struct ben *);
void bprint(struct ben *, int);
+/* torrent.c */
+struct torrent *loadtorrent(char *);
+void unloadtorrent(struct torrent *);
+
/* util.c */
void *emalloc(size_t);
void *ecalloc(size_t, size_t);
diff --git a/torrent.c b/torrent.c
@@ -13,3 +13,84 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+
+#include <err.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sbtd.h"
+#include "sha1.h"
+
+static void
+calcinfohash(struct torrent *t)
+{
+ char *buf;
+ size_t n;
+
+ bencode(&buf, &n, t->info);
+ sha1sum((unsigned char *)buf, n, t->infohash);
+ free(buf);
+}
+
+struct torrent *
+loadtorrent(char *f)
+{
+ struct torrent *t;
+
+ t = emalloc(sizeof(*t));
+ if (readfile(f, &t->buf, &t->buflen) < 0) {
+ warnx("failed to read %s", f);
+ goto err0;
+ }
+ if (!bdecode(t->buf, t->buf + t->buflen, &t->ben)) {
+ warnx("failed to decode %s", f);
+ goto err1;
+ }
+
+ t->info = dlookstr(t->ben, "info");
+ if (!t->info) {
+ warnx("no info dictionary in %s", f);
+ goto err2;
+ }
+
+ if (!dlookstr(t->ben, "announce")) {
+ warnx("no announce field in %s", f);
+ goto err2;
+ }
+ t->announce = bstr2str(dlookstr(t->ben, "announce"));
+
+ if (!dlookstr(t->info, "length")) {
+ warnx("no length field in %s", f);
+ goto err2;
+ }
+ t->length = dlookstr(t->info, "length")->i;
+
+ if (!dlookstr(t->info, "piece length")) {
+ warnx("no piece length field in %s", f);
+ goto err2;
+ }
+ t->piecelen = dlookstr(t->info, "piece length")->i;
+
+ t->npieces = (t->length + t->piecelen - 1) / t->piecelen;
+
+ calcinfohash(t);
+ return t;
+err2:
+ bfree(t->ben);
+err1:
+ free(t->buf);
+err0:
+ free(t);
+ return NULL;
+}
+
+void
+unloadtorrent(struct torrent *t)
+{
+ if (!t)
+ return;
+ bfree(t->ben);
+ free(t->buf);
+ free(t);
+}