Changeset 5608 for trunk/libtransmission/resume.c
- Timestamp:
- Apr 13, 2008, 10:31:07 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/resume.c
r5606 r5608 11 11 */ 12 12 13 #include <sys/types.h> /* stat */ 14 #include <sys/stat.h> /* stat */ 15 #include <unistd.h> /* unlink, stat */ 16 13 17 #include <string.h> 14 #include <unistd.h> /* unlink */15 18 16 19 #include "transmission.h" 20 #include "bencode.h" 21 #include "completion.h" 17 22 #include "fastresume.h" 23 #include "peer-mgr.h" /* pex */ 18 24 #include "platform.h" /* tr_getResumeDir */ 19 25 #include "resume.h" … … 21 27 #include "utils.h" /* tr_buildPath */ 22 28 29 #define KEY_CORRUPT "corrupt" 30 #define KEY_DESTINATION "destination" 31 #define KEY_DOWNLOADED "downloaded" 32 #define KEY_MAX_PEERS "max-peers" 33 #define KEY_PAUSED "paused" 34 #define KEY_PEERS "peers" 35 #define KEY_PRIORITY "priority" 36 #define KEY_PROGRESS "progress" 37 #define KEY_SPEEDLIMIT "speed-limit" 38 #define KEY_UPLOADED "uploaded" 39 40 #define KEY_SPEEDLIMIT_DOWN_SPEED "down-speed" 41 #define KEY_SPEEDLIMIT_DOWN_MODE "down-mode" 42 #define KEY_SPEEDLIMIT_UP_SPEED "up-speed" 43 #define KEY_SPEEDLIMIT_UP_MODE "up-mode" 44 45 #define KEY_PROGRESS_MTIMES "mtimes" 46 #define KEY_PROGRESS_BITFIELD "bitfield" 47 48 /*** 49 **** 50 ***/ 51 52 static time_t* 53 getMTimes( const tr_torrent * tor, int * setme_n ) 54 { 55 int i; 56 const int n = tor->info.fileCount; 57 time_t * m = tr_new( time_t, n ); 58 59 for( i=0; i<n; ++i ) { 60 char fname[MAX_PATH_LENGTH]; 61 struct stat sb; 62 tr_buildPath( fname, sizeof(fname), 63 tor->destination, tor->info.files[i].name, NULL ); 64 if ( !stat( fname, &sb ) && S_ISREG( sb.st_mode ) ) { 65 #ifdef SYS_DARWIN 66 m[i] = sb.st_mtimespec.tv_sec; 67 #else 68 m[i] = sb.st_mtime; 69 #endif 70 } 71 } 72 73 *setme_n = n; 74 return m; 75 } 76 23 77 static void 24 78 getResumeFilename( char * buf, size_t buflen, const tr_torrent * tor ) … … 26 80 const char * dir = tr_getResumeDir( tor->handle ); 27 81 char base[4096]; 28 snprintf( base, sizeof( base ), "%s.%1 0.10s.resume", tor->info.name, tor->info.hashString );82 snprintf( base, sizeof( base ), "%s.%16.16s.resume", tor->info.name, tor->info.hashString ); 29 83 tr_buildPath( buf, buflen, dir, base, NULL ); 30 fprintf( stderr, "filename is [%s]\n", buf ); 84 } 85 86 /*** 87 **** 88 ***/ 89 90 static void 91 savePeers( tr_benc * dict, const tr_torrent * tor ) 92 { 93 tr_pex * pex; 94 const int count = tr_peerMgrGetPeers( tor->handle->peerMgr, tor->info.hash, &pex ); 95 if( count > 0 ) { 96 tr_benc * child = tr_bencDictAdd( dict, KEY_PEERS ); 97 tr_bencInitStrDupLen( child, (const char*)pex, sizeof(tr_pex)*count ); 98 tr_free( pex ); 99 } 100 } 101 102 static uint64_t 103 loadPeers( tr_benc * dict, tr_torrent * tor ) 104 { 105 uint64_t ret = 0; 106 tr_benc * p; 107 108 if(( p = tr_bencDictFindType( dict, KEY_PEERS, TYPE_STR ))) 109 { 110 int i; 111 const char * str = p->val.s.s; 112 const size_t len = p->val.s.i; 113 const int count = len / sizeof( tr_pex ); 114 for( i=0; i<count; ++i ) { 115 tr_pex pex; 116 memcpy( &pex, str + (i*sizeof(tr_pex)), sizeof(tr_pex) ); 117 tr_peerMgrAddPex( tor->handle->peerMgr, tor->info.hash, TR_PEER_FROM_CACHE, &pex ); 118 } 119 tr_tordbg( tor, "Loaded %d peers from resume file", count ); 120 ret = TR_FR_PEERS; 121 } 122 123 return ret; 124 } 125 126 static void 127 savePriorities( tr_benc * dict, const tr_torrent * tor ) 128 { 129 const tr_info * inf = &tor->info; 130 const tr_file_index_t n = inf->fileCount; 131 tr_file_index_t i; 132 tr_benc * list; 133 134 list = tr_bencDictAddList( dict, KEY_PRIORITY, tor->info.fileCount ); 135 for( i=0; i<n; ++i ) 136 tr_bencInitInt( tr_bencListAdd( list ), inf->files[i].priority ); 137 } 138 139 static uint64_t 140 loadPriorities( tr_benc * dict, tr_torrent * tor ) 141 { 142 uint64_t ret = 0; 143 tr_info * inf = &tor->info; 144 const tr_file_index_t n = inf->fileCount; 145 tr_benc * list; 146 147 if( tr_bencDictFindList( dict, KEY_PRIORITY, &list ) && ( list->val.l.count == (int)n ) ) 148 { 149 int64_t tmp; 150 tr_file_index_t i; 151 for( i=0; i<n; ++i ) 152 if( tr_bencGetInt( &list->val.l.vals[i], &tmp ) ) 153 inf->files[i].priority = tmp; 154 ret = TR_FR_PRIORITY; 155 } 156 157 return ret; 158 } 159 160 static void 161 saveSpeedLimits( tr_benc * dict, const tr_torrent * tor ) 162 { 163 tr_benc * d = tr_bencDictAddDict( dict, KEY_SPEEDLIMIT, 4 ); 164 tr_bencDictAddInt( d, KEY_SPEEDLIMIT_DOWN_SPEED, 165 tr_torrentGetSpeedLimit( tor, TR_DOWN ) ); 166 tr_bencDictAddInt( d, KEY_SPEEDLIMIT_DOWN_MODE, 167 tr_torrentGetSpeedMode( tor, TR_DOWN ) ); 168 tr_bencDictAddInt( d, KEY_SPEEDLIMIT_UP_SPEED, 169 tr_torrentGetSpeedLimit( tor, TR_UP ) ); 170 tr_bencDictAddInt( d, KEY_SPEEDLIMIT_UP_MODE, 171 tr_torrentGetSpeedMode( tor, TR_UP ) ); 172 } 173 174 static uint64_t 175 loadSpeedLimits( tr_benc * dict, tr_torrent * tor ) 176 { 177 uint64_t ret = 0; 178 tr_benc * d; 179 180 if( tr_bencDictFindDict( dict, KEY_SPEEDLIMIT, &d ) ) 181 { 182 int64_t i; 183 if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_SPEED, &i ) ) 184 tr_torrentSetSpeedLimit( tor, TR_DOWN, i ); 185 if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_MODE, &i ) ) 186 tr_torrentSetSpeedMode( tor, TR_DOWN, i ); 187 if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_SPEED, &i ) ) 188 tr_torrentSetSpeedLimit( tor, TR_UP, i ); 189 if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_MODE, &i ) ) 190 tr_torrentSetSpeedMode( tor, TR_UP, i ); 191 ret = TR_FR_SPEEDLIMIT; 192 } 193 194 return ret; 195 } 196 197 static void 198 saveProgress( tr_benc * dict, const tr_torrent * tor ) 199 { 200 int i; 201 int n; 202 time_t * mtimes; 203 tr_benc * p; 204 tr_benc * m; 205 tr_benc * b; 206 const tr_bitfield * bitfield; 207 208 p = tr_bencDictAdd( dict, KEY_PROGRESS ); 209 tr_bencInitDict( p, 2 ); 210 211 /* add the mtimes */ 212 m = tr_bencDictAdd( p, KEY_PROGRESS_MTIMES ); 213 mtimes = getMTimes( tor, &n ); 214 tr_bencInitList( m, n ); 215 for( i=0; i<n; ++i ) { 216 if( !tr_torrentIsFileChecked( tor, i ) ) 217 mtimes[i] = ~(time_t)0; /* force a recheck next time */ 218 tr_bencInitInt( tr_bencListAdd( m ), mtimes[i] ); 219 } 220 221 /* add the bitfield */ 222 bitfield = tr_cpBlockBitfield( tor->completion ); 223 b = tr_bencDictAdd( p, KEY_PROGRESS_BITFIELD ); 224 tr_bencInitStrDupLen( b, (const char*)bitfield->bits, bitfield->len ); 225 226 /* cleanup */ 227 tr_free( mtimes ); 228 } 229 230 static uint64_t 231 loadProgress( tr_benc * dict, tr_torrent * tor ) 232 { 233 uint64_t ret = 0; 234 tr_benc * p; 235 236 if( tr_bencDictFindDict( dict, KEY_PROGRESS, &p ) ) 237 { 238 tr_benc * m; 239 tr_benc * b; 240 int n; 241 time_t * curMTimes = getMTimes( tor, &n ); 242 243 if( tr_bencDictFindList( p, KEY_PROGRESS_MTIMES, &m ) 244 && ( m->val.l.count == (int64_t)tor->info.fileCount ) 245 && ( m->val.l.count == n ) ) 246 { 247 int i; 248 for( i=0; i<m->val.l.count; ++i ) 249 { 250 int64_t tmp; 251 const time_t t = tr_bencGetInt( &m->val.l.vals[i], &tmp ) 252 ? tmp : ~(time_t)0; 253 if( curMTimes[i] == t ) 254 tr_torrentSetFileChecked( tor, i, TRUE ); 255 else { 256 tr_torrentSetFileChecked( tor, i, FALSE ); 257 tr_tordbg( tor, "File #%d needs to be verified", i ); 258 } 259 } 260 } 261 else 262 { 263 tr_torrentUncheck( tor ); 264 tr_tordbg( tor, "Torrent needs to be verified - unable to find mtimes" ); 265 } 266 267 if(( b = tr_bencDictFindType( p, KEY_PROGRESS_BITFIELD, TYPE_STR ))) 268 { 269 tr_bitfield tmp; 270 tmp.len = b->val.s.i; 271 tmp.bits = (uint8_t*) b->val.s.s; 272 if( tr_cpBlockBitfieldSet( tor->completion, &tmp ) ) { 273 tr_torrentUncheck( tor ); 274 tr_tordbg( tor, "Torrent needs to be verified - error loading bitfield" ); 275 } 276 } 277 else 278 { 279 tr_torrentUncheck( tor ); 280 tr_tordbg( tor, "Torrent needs to be verified - unable to find bitfield" ); 281 } 282 283 tr_free( curMTimes ); 284 ret = TR_FR_PROGRESS; 285 } 286 287 return ret; 288 } 289 290 void 291 tr_torrentSaveResume( const tr_torrent * tor ) 292 { 293 tr_benc top; 294 char * encoded; 295 int len; 296 297 /* populate the bencoded data */ 298 tr_bencInitDict( &top, 10 ); 299 tr_bencDictAddInt( &top, KEY_CORRUPT, tor->corruptPrev + tor->corruptCur ); 300 tr_bencDictAddStr( &top, KEY_DESTINATION, tor->destination ); 301 tr_bencDictAddInt( &top, KEY_DOWNLOADED, tor->downloadedPrev + tor->downloadedCur ); 302 tr_bencDictAddInt( &top, KEY_UPLOADED, tor->uploadedPrev + tor->uploadedCur ); 303 tr_bencDictAddInt( &top, KEY_MAX_PEERS, tor->maxConnectedPeers ); 304 tr_bencDictAddInt( &top, KEY_PAUSED, tor->isRunning?0:1 ); 305 savePeers( &top, tor ); 306 savePriorities( &top, tor ); 307 saveProgress( &top, tor ); 308 saveSpeedLimits( &top, tor ); 309 310 /* save the bencoded data */ 311 if(( encoded = tr_bencSave( &top, &len ))) 312 { 313 char filename[MAX_PATH_LENGTH]; 314 FILE * fp; 315 getResumeFilename( filename, sizeof( filename ), tor ); 316 fp = fopen( filename, "wb+" ); 317 fwrite( encoded, len, 1, fp ); 318 fclose( fp ); 319 tr_free( encoded ); 320 } 321 322 /* cleanup */ 323 tr_bencFree( &top ); 31 324 } 32 325 … … 36 329 const tr_ctor * ctor ) 37 330 { 331 int64_t i; 332 const char * str; 333 int benc_loaded = FALSE; 38 334 uint64_t fieldsLoaded = 0; 39 uint8_t * content ;335 uint8_t * content = NULL; 40 336 size_t contentLen; 41 337 char filename[MAX_PATH_LENGTH]; 338 tr_benc top; 42 339 43 340 getResumeFilename( filename, sizeof( filename ), tor ); 341 44 342 content = tr_loadFile( filename, &contentLen ); 45 if( content )46 {343 benc_loaded = content && !tr_bencLoad( content, contentLen, &top, NULL ); 344 if( !benc_loaded ) { 47 345 tr_free( content ); 48 } 49 else 50 { 51 fieldsLoaded = tr_fastResumeLoad( tor, fieldsToLoad, ctor ); 52 } 53 346 tr_tordbg( tor, "Couldn't read \"%s\"; trying old resume file format.", filename ); 347 return tr_fastResumeLoad( tor, fieldsToLoad, ctor ); 348 } 349 350 tr_tordbg( tor, "Read resume file \"%s\"", filename ); 351 352 if( tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) ) { 353 tor->corruptPrev = i; 354 fieldsLoaded |= TR_FR_CORRUPT; 355 } 356 357 if( tr_bencDictFindStr( &top, KEY_DESTINATION, &str ) ) { 358 tr_free( tor->destination ); 359 tor->destination = tr_strdup( str ); 360 fieldsLoaded |= TR_FR_DESTINATION; 361 } 362 363 if( tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) ) { 364 tor->downloadedPrev = i; 365 fieldsLoaded |= TR_FR_DOWNLOADED; 366 } 367 368 if( tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) ) { 369 tor->uploadedPrev = i; 370 fieldsLoaded |= TR_FR_UPLOADED; 371 } 372 373 if( tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) ) { 374 tor->maxConnectedPeers = i; 375 fieldsLoaded |= TR_FR_MAX_PEERS; 376 } 377 378 if( tr_bencDictFindInt( &top, KEY_PAUSED, &i ) ) { 379 tor->isRunning = i ? 0 : 1; 380 fieldsLoaded |= TR_FR_RUN; 381 } 382 383 fieldsLoaded |= loadPeers( &top, tor ); 384 fieldsLoaded |= loadPriorities( &top, tor ); 385 fieldsLoaded |= loadProgress( &top, tor ); 386 fieldsLoaded |= loadSpeedLimits( &top, tor ); 387 388 tr_bencFree( &top ); 54 389 return fieldsLoaded; 55 }56 57 void58 tr_torrentSaveResume( const tr_torrent * tor )59 {60 char filename[MAX_PATH_LENGTH];61 getResumeFilename( filename, sizeof( filename ), tor );62 63 /* (temporary) */64 tr_fastResumeSave( tor );65 390 } 66 391
Note: See TracChangeset
for help on using the changeset viewer.