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);