static void saveProgress( tr_benc * dict, tr_torrent * tor ) { tr_benc * l; tr_benc * prog; tr_file_index_t fi; const tr_info * inf = tr_torrentInfo( tor ); const time_t now = tr_time( ); prog = tr_bencDictAddDict( dict, KEY_PROGRESS, 3 ); /* add the file/piece check timestamps... */ l = tr_bencDictAddList( prog, KEY_PROGRESS_CHECKTIME, inf->fileCount ); for( fi=0; fi<inf->fileCount; ++fi ) { const tr_piece * p; const tr_piece * pend; time_t oldest_nonzero = now; time_t newest = 0; bool has_zero = false; const time_t mtime = tr_torrentGetFileMTime( tor, fi ); const tr_file * f = &inf->files[fi]; /* get the oldest and newest nonzero timestamps for pieces in this file */ for( p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]; p!=pend; ++p ) { if( !p->timeChecked ) has_zero = true; else if( oldest_nonzero > p->timeChecked ) oldest_nonzero = p->timeChecked; if( newest < p->timeChecked ) newest = p->timeChecked; } /* 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. */ if( !has_zero && ( mtime <= oldest_nonzero ) ) /* all checked */ tr_bencListAddInt( l, oldest_nonzero ); else if( newest < mtime ) /* none checked */ tr_bencListAddInt( l, newest ); else { /* some are checked, some aren't... so list piece by piece */ const int offset = oldest_nonzero - 1; tr_benc * ll = tr_bencListAddList( l, 2 + f->lastPiece - f->firstPiece ); tr_bencListAddInt( ll, offset ); for( p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]+1; p!=pend; ++p ) tr_bencListAddInt( ll, p->timeChecked ? p->timeChecked - offset : 0 ); } } /* add the progress */ if( tor->completeness == TR_SEED ) tr_bencDictAddStr( prog, KEY_PROGRESS_HAVE, "all" ); /* add the blocks bitfield */ bitfieldToBenc( &tor->completion.blockBitfield, tr_bencDictAdd( prog, KEY_PROGRESS_BLOCKS ) ); }
static void saveProgress(tr_variant* dict, tr_torrent* tor) { tr_variant* l; tr_variant* prog; tr_info const* inf = tr_torrentInfo(tor); time_t const now = tr_time(); prog = tr_variantDictAddDict(dict, TR_KEY_progress, 3); /* add the file/piece check timestamps... */ l = tr_variantDictAddList(prog, TR_KEY_time_checked, inf->fileCount); for (tr_file_index_t fi = 0; fi < inf->fileCount; ++fi) { time_t oldest_nonzero = now; time_t newest = 0; bool has_zero = false; time_t const mtime = tr_torrentGetFileMTime(tor, fi); tr_file const* f = &inf->files[fi]; /* get the oldest and newest nonzero timestamps for pieces in this file */ for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i) { tr_piece const* const p = &inf->pieces[i]; if (p->timeChecked == 0) { has_zero = true; } else if (oldest_nonzero > p->timeChecked) { oldest_nonzero = p->timeChecked; } if (newest < p->timeChecked) { newest = p->timeChecked; } } /* If some of a file's pieces have been checked more recently than the file's mtime, and some less 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. */ if (!has_zero && mtime <= oldest_nonzero) /* all checked */ { tr_variantListAddInt(l, oldest_nonzero); } else if (newest < mtime) /* none checked */ { tr_variantListAddInt(l, newest); } else /* some are checked, some aren't... so list piece by piece */ { int const offset = oldest_nonzero - 1; tr_variant* ll = tr_variantListAddList(l, 2 + f->lastPiece - f->firstPiece); tr_variantListAddInt(ll, offset); for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i) { tr_piece const* const p = &inf->pieces[i]; tr_variantListAddInt(ll, p->timeChecked != 0 ? p->timeChecked - offset : 0); } } } /* add the progress */ if (tor->completeness == TR_SEED) { tr_variantDictAddStr(prog, TR_KEY_have, "all"); } /* add the blocks bitfield */ bitfieldToBenc(&tor->completion.blockBitfield, tr_variantDictAdd(prog, TR_KEY_blocks)); }