static uint64_t loadProgress (tr_variant * dict, tr_torrent * tor) { size_t i, n; uint64_t ret = 0; tr_variant * prog; const tr_info * inf = tr_torrentInfo (tor); for (i=0, n=inf->pieceCount; i<n; ++i) inf->pieces[i].timeChecked = 0; if (tr_variantDictFindDict (dict, TR_KEY_progress, &prog)) { const char * err; const char * str; const uint8_t * raw; size_t rawlen; tr_variant * l; tr_variant * b; struct tr_bitfield blocks = TR_BITFIELD_INIT; if (tr_variantDictFindList (prog, TR_KEY_time_checked, &l)) { /* per-piece timestamps were added in 2.20. If some of a file's pieces have been checked more recently than the file's mtime, and some lest recently, then that file will have a list containing timestamps for each piece. However, the most common use case is that the file doesn't change after it's downloaded. To reduce overhead in the .resume file, only a single timestamp is saved for the file if *all* or *none* of the pieces were tested more recently than the file's mtime. */ tr_file_index_t fi; for (fi=0; fi<inf->fileCount; ++fi) { tr_variant * b = tr_variantListChild (l, fi); const tr_file * f = &inf->files[fi]; tr_piece * p = &inf->pieces[f->firstPiece]; const tr_piece * pend = &inf->pieces[f->lastPiece]+1; if (tr_variantIsInt (b)) { int64_t t; tr_variantGetInt (b, &t); for (; p!=pend; ++p) p->timeChecked = (time_t)t; } else if (tr_variantIsList (b)) { int i = 0; int64_t offset = 0; const int pieces = f->lastPiece + 1 - f->firstPiece; tr_variantGetInt (tr_variantListChild (b, 0), &offset); for (i=0; i<pieces; ++i) { int64_t t = 0; tr_variantGetInt (tr_variantListChild (b, i+1), &t); inf->pieces[f->firstPiece+i].timeChecked = (time_t)(t ? t + offset : 0); } } } } else if (tr_variantDictFindList (prog, TR_KEY_mtimes, &l)) { tr_file_index_t fi; /* Before 2.20, we stored the files' mtimes in the .resume file. When loading the .resume file, a torrent's file would be flagged as untested if its stored mtime didn't match its real mtime. */ for (fi=0; fi<inf->fileCount; ++fi) { int64_t t; if (tr_variantGetInt (tr_variantListChild (l, fi), &t)) { const tr_file * f = &inf->files[fi]; tr_piece * p = &inf->pieces[f->firstPiece]; const tr_piece * pend = &inf->pieces[f->lastPiece]; const time_t mtime = tr_torrentGetFileMTime (tor, fi); const time_t timeChecked = mtime==t ? mtime : 0; for (; p!=pend; ++p) p->timeChecked = timeChecked; } } } err = NULL; tr_bitfieldConstruct (&blocks, tor->blockCount); if ((b = tr_variantDictFind (prog, TR_KEY_blocks))) { size_t buflen; const uint8_t * buf; if (!tr_variantGetRaw (b, &buf, &buflen)) err = "Invalid value for \"blocks\""; else if ((buflen == 3) && !memcmp (buf, "all", 3)) tr_bitfieldSetHasAll (&blocks); else if ((buflen == 4) && !memcmp (buf, "none", 4)) tr_bitfieldSetHasNone (&blocks); else tr_bitfieldSetRaw (&blocks, buf, buflen, true); } else if (tr_variantDictFindStr (prog, TR_KEY_have, &str, NULL)) { if (!strcmp (str, "all")) tr_bitfieldSetHasAll (&blocks); else err = "Invalid value for HAVE"; } else if (tr_variantDictFindRaw (prog, TR_KEY_bitfield, &raw, &rawlen)) { tr_bitfieldSetRaw (&blocks, raw, rawlen, true); } else err = "Couldn't find 'pieces' or 'have' or 'bitfield'"; if (err != NULL) tr_logAddTorDbg (tor, "Torrent needs to be verified - %s", err); else tr_cpBlockInit (&tor->completion, &blocks); tr_bitfieldDestruct (&blocks); ret = TR_FR_PROGRESS; } return ret; }
static char const* parseFiles(tr_info* inf, tr_variant* files, tr_variant const* length) { int64_t len; inf->totalSize = 0; if (tr_variantIsList(files)) /* multi-file mode */ { struct evbuffer* buf; char const* result; if (path_component_is_suspicious(inf->name)) { return "path"; } buf = evbuffer_new(); result = NULL; inf->isFolder = true; inf->fileCount = tr_variantListSize(files); inf->files = tr_new0(tr_file, inf->fileCount); for (tr_file_index_t i = 0; i < inf->fileCount; i++) { tr_variant* file; tr_variant* path; file = tr_variantListChild(files, i); if (!tr_variantIsDict(file)) { result = "files"; break; } if (!tr_variantDictFindList(file, TR_KEY_path_utf_8, &path)) { if (!tr_variantDictFindList(file, TR_KEY_path, &path)) { result = "path"; break; } } if (!getfile(&inf->files[i].name, inf->name, path, buf)) { result = "path"; break; } if (!tr_variantDictFindInt(file, TR_KEY_length, &len)) { result = "length"; break; } inf->files[i].length = len; inf->totalSize += len; } evbuffer_free(buf); return result; } else if (tr_variantGetInt(length, &len)) /* single-file mode */ { if (path_component_is_suspicious(inf->name)) { return "path"; } inf->isFolder = false; inf->fileCount = 1; inf->files = tr_new0(tr_file, 1); inf->files[0].name = tr_strdup(inf->name); inf->files[0].length = len; inf->totalSize += len; } else { return "length"; } return NULL; }