void tr_torrentSaveResume(tr_torrent* tor) { int err; tr_variant top; char* filename; if (!tr_isTorrent(tor)) { return; } tr_variantInitDict(&top, 50); /* arbitrary "big enough" number */ tr_variantDictAddInt(&top, TR_KEY_seeding_time_seconds, tor->secondsSeeding); tr_variantDictAddInt(&top, TR_KEY_downloading_time_seconds, tor->secondsDownloading); tr_variantDictAddInt(&top, TR_KEY_activity_date, tor->activityDate); tr_variantDictAddInt(&top, TR_KEY_added_date, tor->addedDate); tr_variantDictAddInt(&top, TR_KEY_corrupt, tor->corruptPrev + tor->corruptCur); tr_variantDictAddInt(&top, TR_KEY_done_date, tor->doneDate); tr_variantDictAddStr(&top, TR_KEY_destination, tor->downloadDir); if (tor->incompleteDir != NULL) { tr_variantDictAddStr(&top, TR_KEY_incomplete_dir, tor->incompleteDir); } tr_variantDictAddInt(&top, TR_KEY_downloaded, tor->downloadedPrev + tor->downloadedCur); tr_variantDictAddInt(&top, TR_KEY_uploaded, tor->uploadedPrev + tor->uploadedCur); tr_variantDictAddInt(&top, TR_KEY_max_peers, tor->maxConnectedPeers); tr_variantDictAddInt(&top, TR_KEY_bandwidth_priority, tr_torrentGetPriority(tor)); tr_variantDictAddBool(&top, TR_KEY_paused, !tor->isRunning && !tor->isQueued); savePeers(&top, tor); if (tr_torrentHasMetadata(tor)) { saveFilePriorities(&top, tor); saveDND(&top, tor); saveProgress(&top, tor); } saveSpeedLimits(&top, tor); saveRatioLimits(&top, tor); saveIdleLimits(&top, tor); saveFilenames(&top, tor); saveName(&top, tor); filename = getResumeFilename(tor); if ((err = tr_variantToFile(&top, TR_VARIANT_FMT_BENC, filename)) != 0) { tr_torrentSetLocalError(tor, "Unable to save resume file: %s", tr_strerror(err)); } tr_free(filename); tr_variantFree(&top); }
void tr_torrentSaveResume( tr_torrent * tor ) { int err; tr_benc top; char * filename; if( !tr_isTorrent( tor ) ) return; tr_bencInitDict( &top, 50 ); /* arbitrary "big enough" number */ tr_bencDictAddInt( &top, KEY_TIME_SEEDING, tor->secondsSeeding ); tr_bencDictAddInt( &top, KEY_TIME_DOWNLOADING, tor->secondsDownloading ); tr_bencDictAddInt( &top, KEY_ACTIVITY_DATE, tor->activityDate ); tr_bencDictAddInt( &top, KEY_ADDED_DATE, tor->addedDate ); tr_bencDictAddInt( &top, KEY_CORRUPT, tor->corruptPrev + tor->corruptCur ); tr_bencDictAddInt( &top, KEY_DONE_DATE, tor->doneDate ); tr_bencDictAddStr( &top, KEY_DOWNLOAD_DIR, tor->downloadDir ); if( tor->incompleteDir != NULL ) tr_bencDictAddStr( &top, KEY_INCOMPLETE_DIR, tor->incompleteDir ); tr_bencDictAddInt( &top, KEY_DOWNLOADED, tor->downloadedPrev + tor->downloadedCur ); tr_bencDictAddInt( &top, KEY_UPLOADED, tor->uploadedPrev + tor->uploadedCur ); tr_bencDictAddInt( &top, KEY_MAX_PEERS, tor->maxConnectedPeers ); tr_bencDictAddInt( &top, KEY_BANDWIDTH_PRIORITY, tr_torrentGetPriority( tor ) ); tr_bencDictAddBool( &top, KEY_PAUSED, !tor->isRunning ); savePeers( &top, tor ); if( tr_torrentHasMetadata( tor ) ) { saveFilePriorities( &top, tor ); saveDND( &top, tor ); saveProgress( &top, tor ); } saveSpeedLimits( &top, tor ); saveRatioLimits( &top, tor ); saveIdleLimits( &top, tor ); filename = getResumeFilename( tor ); if(( err = tr_bencToFile( &top, TR_FMT_BENC, filename ))) tr_torrentSetLocalError( tor, "Unable to save resume file: %s", tr_strerror( err ) ); tr_free( filename ); tr_bencFree( &top ); }
/* returns 0 on success, or an errno on failure */ static int readOrWritePiece( tr_torrent * tor, int ioMode, tr_piece_index_t pieceIndex, uint32_t pieceOffset, uint8_t * buf, size_t buflen ) { int err = 0; tr_file_index_t fileIndex; uint64_t fileOffset; const tr_info * info = &tor->info; if( pieceIndex >= tor->info.pieceCount ) return EINVAL; //if( pieceOffset + buflen > tr_torPieceCountBytes( tor, pieceIndex ) ) // return EINVAL; tr_ioFindFileLocation( tor, pieceIndex, pieceOffset, &fileIndex, &fileOffset ); while( buflen && !err ) { const tr_file * file = &info->files[fileIndex]; const uint64_t bytesThisPass = MIN( buflen, file->length - fileOffset ); err = readOrWriteBytes( tor->session, tor, ioMode, fileIndex, fileOffset, buf, bytesThisPass ); buf += bytesThisPass; buflen -= bytesThisPass; //fprintf( stderr, "++fileIndex to %d\n", (int)fileIndex ); ++fileIndex; fileOffset = 0; if( ( err != 0 ) && (ioMode == TR_IO_WRITE ) && ( tor->error != TR_STAT_LOCAL_ERROR ) ) { char * path = tr_buildPath( tor->downloadDir, file->name, NULL ); tr_torrentSetLocalError( tor, "%s (%s)", tr_strerror( err ), path ); tr_free( path ); } } return err; }
/* returns 0 on success, or an errno on failure */ static int readOrWriteBytes( tr_session * session, tr_torrent * tor, int ioMode, tr_file_index_t fileIndex, uint64_t fileOffset, void * buf, size_t buflen ) { const tr_info * info = &tor->info; const tr_file * file = &info->files[fileIndex]; int fd = -1; int err = 0; const tr_bool doWrite = ioMode >= TR_IO_WRITE; //if( doWrite ) // fprintf( stderr, "in file %s at offset %zu, writing %zu bytes; file length is %zu\n", file->name, (size_t)fileOffset, buflen, (size_t)file->length ); assert( fileIndex < info->fileCount ); assert( !file->length || ( fileOffset < file->length ) ); assert( fileOffset + buflen <= file->length ); if( !file->length ) return 0; fd = tr_fdFileGetCached( session, tr_torrentId( tor ), fileIndex, doWrite ); if( fd < 0 ) { /* the fd cache doesn't have this file... * we'll need to open it and maybe create it */ char * subpath; const char * base; tr_bool fileExists; tr_preallocation_mode preallocationMode; fileExists = tr_torrentFindFile2( tor, fileIndex, &base, &subpath ); if( !fileExists ) { base = tr_torrentGetCurrentDir( tor ); if( tr_sessionIsIncompleteFileNamingEnabled( tor->session ) ) subpath = tr_torrentBuildPartial( tor, fileIndex ); else subpath = tr_strdup( file->name ); } if( ( file->dnd ) || ( ioMode < TR_IO_WRITE ) ) preallocationMode = TR_PREALLOCATE_NONE; else preallocationMode = tor->session->preallocationMode; if( ( ioMode < TR_IO_WRITE ) && !fileExists ) /* does file exist? */ { err = ENOENT; } else { char * filename = tr_buildPath( base, subpath, NULL ); if( ( fd = tr_fdFileCheckout( session, tor->uniqueId, fileIndex, filename, doWrite, preallocationMode, file->length ) ) < 0 ) { err = errno; tr_torerr( tor, "tr_fdFileCheckout failed for \"%s\": %s", filename, tr_strerror( err ) ); } tr_free( filename ); } if( doWrite && !err ) tr_statsFileCreated( tor->session ); tr_free( subpath ); } if( !err ) { /* check & see if someone deleted the file while it was in our cache */ struct stat sb; const tr_bool file_disappeared = fstat( fd, &sb ) || sb.st_nlink < 1; if( file_disappeared ) { tr_torrentSetLocalError( tor, "Please Verify Local Data! A file disappeared: \"%s\"", tor->info.files[fileIndex].name ); err = ENOENT; } if( ioMode == TR_IO_READ ) { const int rc = tr_pread( fd, buf, buflen, fileOffset ); if( rc < 0 ) { err = errno; tr_torerr( tor, "read failed for \"%s\": %s", file->name, tr_strerror( err ) ); } } else if( ioMode == TR_IO_PREFETCH ) { const int rc = tr_prefetch( fd, fileOffset, buflen ); if( rc < 0 ) { /* (don't set "err" here... it's okay for prefetch to fail) */ tr_tordbg( tor, "prefetch failed for \"%s\": %s", file->name, tr_strerror( errno ) ); } } else if( ioMode == TR_IO_WRITE ) { const int rc = tr_pwrite( fd, buf, buflen, fileOffset ); if( rc < 0 ) { err = errno; tr_torerr( tor, "write failed for \"%s\": %s", file->name, tr_strerror( err ) ); } } else { abort(); } } return err; }