summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--btpd/tlib.c127
-rw-r--r--btpd/tlib.h8
-rw-r--r--btpd/torrent.c3
3 files changed, 100 insertions, 38 deletions
diff --git a/btpd/tlib.c b/btpd/tlib.c
index 812a141..bff6b0b 100644
--- a/btpd/tlib.c
+++ b/btpd/tlib.c
@@ -70,15 +70,52 @@ tlib_del(struct tlib *tl)
     return 0;
 }
 
+static void
+dct_subst_save(FILE *fp, const char *dct1, const char *dct2)
+{
+    fprintf(fp, "d");
+    const char *k1 = benc_first(dct1), *k2 = benc_first(dct2);
+    const char *val, *str, *rest;
+    size_t len;
+
+    while (k1 != NULL && k2 != NULL) {
+        int test = benc_strcmp(k1, k2);
+        if (test < 0) {
+            str = benc_mem(k1, &len, &val);
+            fprintf(fp, "%d:%.*s", (int)len, (int)len, str);
+            fwrite(val, 1, benc_length(val), fp);
+            k1 = benc_next(val);
+        } else {
+            str = benc_mem(k2, &len, &val);
+            fprintf(fp, "%d:%.*s", (int)len, (int)len, str);
+            fwrite(val, 1, benc_length(val), fp);
+            k2 = benc_next(val);
+            if (test == 0)
+                k1 = benc_next(benc_next(k1));
+        }
+    }
+    rest = k1 != NULL ? k1 : k2;
+    while (rest != NULL) {
+        str = benc_mem(rest, &len, &val);
+        fprintf(fp, "%d:%.*s", (int)len, (int)len, str);
+        fwrite(val, 1, benc_length(val), fp);
+        rest = benc_next(val);
+    }
+    fprintf(fp, "e");
+}
+
 static int
 valid_info(char *buf, size_t len)
 {
     size_t slen;
+    const char *info;
     if (benc_validate(buf, len) != 0)
         return 0;
-    if (benc_dget_mem(buf, "name", &slen) == NULL || slen == 0)
+    if ((info = benc_dget_dct(buf, "info")) == NULL)
+        return 0;
+    if (benc_dget_mem(info, "name", &slen) == NULL || slen == 0)
         return 0;
-    if ((benc_dget_mem(buf, "dir", &slen) == NULL ||
+    if ((benc_dget_mem(info, "dir", &slen) == NULL ||
             (slen == 0 || slen >= PATH_MAX)))
         return 0;
     return 1;
@@ -89,6 +126,7 @@ load_info(struct tlib *tl, const char *path)
 {
     size_t size = 1 << 14;
     char buf[size], *p = buf;
+    const char *info;
 
     if ((errno = read_whole_file((void **)&p, &size, path)) != 0) {
         btpd_log(BTPD_L_ERROR, "couldn't load '%s' (%s).\n", path,
@@ -98,39 +136,57 @@ load_info(struct tlib *tl, const char *path)
 
     if (!valid_info(buf, size)) {
         btpd_log(BTPD_L_ERROR, "bad info file '%s'.\n", path);
-        return ;
+        return;
     }
 
-    tl->name = benc_dget_str(buf, "name", NULL);
-    tl->dir = benc_dget_str(buf, "dir", NULL);
-#if 0
-    tl->t_added = benc_dget_int(buf, "time added");
-    tl->t_active = benc_dget_int(buf, "time active");
-    tl->tot_up = benc_dget_int(buf, "total upload");
-    tl->tot_down = benc_dget_int(buf, "total download");
-#endif
+    info = benc_dget_dct(buf, "info");
+    tl->name = benc_dget_str(info, "name", NULL);
+    tl->dir = benc_dget_str(info, "dir", NULL);
+    tl->tot_up = benc_dget_int(info, "total upload");
+    tl->tot_down = benc_dget_int(info, "total download");
+    tl->content_size = benc_dget_int(info, "content size");
+    tl->content_have = benc_dget_int(info, "content have");
     if (tl->name == NULL || tl->dir == NULL)
-        btpd_err("out of memory.\n");
+        btpd_err("Out of memory.\n");
 }
 
 static void
-save_info(struct tlib *tl, const char *path)
+save_info(struct tlib *tl)
 {
     FILE *fp;
-    char wpath[PATH_MAX];
+    char relpath[SHAHEXSIZE], path[PATH_MAX], wpath[PATH_MAX];
+    char *old = NULL;
+    size_t size = 1 << 14;
+    struct io_buffer iob = buf_init(1 << 10);
+
+    buf_print(&iob,
+        "d4:infod"
+        "12:content havei%llde12:content sizei%llde"
+        "3:dir%d:%s4:name%d:%s"
+        "14:total downloadi%llde12:total uploadi%llde"
+        "ee",
+        tl->content_have, tl->content_size,
+        (int)strlen(tl->dir), tl->dir, (int)strlen(tl->name), tl->name,
+        tl->tot_down, tl->tot_up);
+    if (iob.error)
+        btpd_err("Out of memory.\n");
+
+    if ((errno = read_whole_file((void **)&old, &size, path)) != 0
+            && errno != ENOENT)
+        btpd_log(BTPD_L_ERROR, "couldn't load '%s' (%s).\n", path,
+            strerror(errno));
+
+    bin2hex(tl->hash, relpath, 20);
+    snprintf(path, PATH_MAX, "torrents/%s/info", relpath);
     snprintf(wpath, PATH_MAX, "%s.write", path);
     if ((fp = fopen(wpath, "w")) == NULL)
         btpd_err("failed to open '%s' (%s).\n", wpath, strerror(errno));
-    fprintf(fp, "d3:dir%d:%s4:name%d:%s", (int)strlen(tl->dir), tl->dir,
-        (int)strlen(tl->name), tl->name);
-#if 0
-    fprintf(fp, "11:time activei%lde10:time addedi%lde", tl->t_active,
-        tl->t_added);
-    fprintf(fp, "14:total downloadi%llde12:total uploadi%lldee", tl->tot_down,
-        tl->tot_up);
-#else
-    fprintf(fp, "e");
-#endif
+    if (old != NULL) {
+        dct_subst_save(fp, old, iob.buf);
+        free(old);
+    } else
+        dct_subst_save(fp, "de", iob.buf);
+    buf_free(&iob);
     if (ferror(fp) || fclose(fp) != 0)
         btpd_err("failed to write '%s'.\n", wpath);
     if (rename(wpath, path) != 0)
@@ -138,6 +194,17 @@ save_info(struct tlib *tl, const char *path)
             strerror(errno));
 }
 
+void
+tlib_update_info(struct tlib *tl)
+{
+    assert(tl->tp != NULL);
+    tl->tot_down += tl->tp->net->downloaded;
+    tl->tot_up += tl->tp->net->uploaded;
+    tl->content_have = cm_content(tl->tp);
+    tl->content_size = tl->tp->total_length;
+    save_info(tl);
+}
+
 static void
 write_torrent(const char *mi, size_t mi_size, const char *path)
 {
@@ -160,9 +227,6 @@ tlib_add(const uint8_t *hash, const char *mi, size_t mi_size,
     const char *content, char *name)
 {
     struct tlib *tl = tlib_create(hash);
-#if 0
-    struct timeval tv;
-#endif
     char relpath[RELPATH_SIZE], file[PATH_MAX];
     bin2hex(hash, relpath, 20);
 
@@ -170,23 +234,18 @@ tlib_add(const uint8_t *hash, const char *mi, size_t mi_size,
         if ((name = mi_name(mi)) == NULL)
             btpd_err("out of memory.\n");
 
+    tl->content_size = mi_total_length(mi);
     tl->name = name;
     tl->dir = strdup(content);
     if (tl->name == NULL || tl->dir == NULL)
         btpd_err("out of memory.\n");
 
-#if 0
-    gettimeofday(&tv, NULL);
-    tl->t_added = tv.tv_sec;
-#endif
-
     snprintf(file, PATH_MAX, "torrents/%s", relpath);
     if (mkdir(file, 0777) != 0)
         btpd_err("failed to create dir '%s' (%s).\n", file, strerror(errno));
     snprintf(file, PATH_MAX, "torrents/%s/torrent", relpath);
     write_torrent(mi, mi_size, file);
-    snprintf(file, PATH_MAX, "torrents/%s/info", relpath);
-    save_info(tl, file);
+    save_info(tl);
     return tl;
 }
 
diff --git a/btpd/tlib.h b/btpd/tlib.h
index 2dc604e..4578bad 100644
--- a/btpd/tlib.h
+++ b/btpd/tlib.h
@@ -8,10 +8,10 @@ struct tlib {
 
     char *name;
     char *dir;
-#if 0
+
     unsigned long long tot_up, tot_down;
-    long t_added, t_active;
-#endif
+    off_t content_size, content_have;
+
     HTBL_ENTRY(nchain);
     HTBL_ENTRY(hchain);
 };
@@ -23,6 +23,8 @@ struct tlib *tlib_add(const uint8_t *hash, const char *mi, size_t mi_size,
     const char *content, char *name);
 int tlib_del(struct tlib *tl);
 
+void tlib_update_info(struct tlib *tl);
+
 struct tlib *tlib_by_hash(const uint8_t *hash);
 struct tlib *tlib_by_num(unsigned num);
 unsigned tlib_count(void);
diff --git a/btpd/torrent.c b/btpd/torrent.c
index 552a5ae..99fb68d 100644
--- a/btpd/torrent.c
+++ b/btpd/torrent.c
@@ -171,8 +171,9 @@ torrent_stop(struct torrent *tp)
 {
     int tra, cma;
     switch (tp->state) {
-    case T_STARTING:
     case T_ACTIVE:
+        tlib_update_info(tp->tl);
+    case T_STARTING:
         tp->state = T_STOPPING;
         if (net_active(tp))
             net_stop(tp);