transmission 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,25 @@
1
+ /******************************************************************************
2
+ * $Id: clients.h 261 2006-05-29 21:27:31Z titer $
3
+ *
4
+ * Copyright (c) 2005 Transmission authors and contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
+ * DEALINGS IN THE SOFTWARE.
23
+ *****************************************************************************/
24
+
25
+ char * tr_clientForId( uint8_t * );
@@ -0,0 +1,266 @@
1
+ /******************************************************************************
2
+ * $Id: completion.c 261 2006-05-29 21:27:31Z titer $
3
+ *
4
+ * Copyright (c) 2005 Transmission authors and contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
+ * DEALINGS IN THE SOFTWARE.
23
+ *****************************************************************************/
24
+
25
+ #include "transmission.h"
26
+
27
+ tr_completion_t * tr_cpInit( tr_torrent_t * tor )
28
+ {
29
+ tr_completion_t * cp;
30
+
31
+ cp = malloc( sizeof( tr_completion_t ) );
32
+ cp->tor = tor;
33
+ cp->blockBitfield = malloc( ( tor->blockCount + 7 ) / 8 );
34
+ cp->blockDownloaders = malloc( tor->blockCount );
35
+ cp->pieceBitfield = malloc( ( tor->info.pieceCount + 7 ) / 8 );
36
+ cp->missingBlocks = malloc( tor->info.pieceCount * sizeof( int ) );
37
+
38
+ tr_cpReset( cp );
39
+
40
+ return cp;
41
+ }
42
+
43
+ void tr_cpClose( tr_completion_t * cp )
44
+ {
45
+ free( cp->blockBitfield );
46
+ free( cp->blockDownloaders );
47
+ free( cp->pieceBitfield );
48
+ free( cp->missingBlocks );
49
+ free( cp );
50
+ }
51
+
52
+ void tr_cpReset( tr_completion_t * cp )
53
+ {
54
+ tr_torrent_t * tor = cp->tor;
55
+ int i;
56
+
57
+ cp->blockCount = 0;
58
+ memset( cp->blockBitfield, 0, ( tor->blockCount + 7 ) / 8 );
59
+ memset( cp->blockDownloaders, 0, tor->blockCount );
60
+ memset( cp->pieceBitfield, 0, ( tor->info.pieceCount + 7 ) / 8 );
61
+ for( i = 0; i < tor->info.pieceCount; i++ )
62
+ {
63
+ cp->missingBlocks[i] = tr_pieceCountBlocks( i );
64
+ }
65
+ }
66
+
67
+ float tr_cpCompletionAsFloat( tr_completion_t * cp )
68
+ {
69
+ return (float) cp->blockCount / (float) cp->tor->blockCount;
70
+ }
71
+
72
+ uint64_t tr_cpLeftBytes( tr_completion_t * cp )
73
+ {
74
+ tr_torrent_t * tor = cp->tor;
75
+ uint64_t left;
76
+ left = (uint64_t) ( cp->tor->blockCount - cp->blockCount ) *
77
+ (uint64_t) tor->blockSize;
78
+ if( !tr_bitfieldHas( cp->blockBitfield, cp->tor->blockCount - 1 ) &&
79
+ tor->info.totalSize % tor->blockSize )
80
+ {
81
+ left += tor->info.totalSize % tor->blockSize;
82
+ left -= tor->blockSize;
83
+ }
84
+ return left;
85
+ }
86
+
87
+ /* Pieces */
88
+ int tr_cpPieceIsComplete( tr_completion_t * cp, int piece )
89
+ {
90
+ return tr_bitfieldHas( cp->pieceBitfield, piece );
91
+ }
92
+
93
+ uint8_t * tr_cpPieceBitfield( tr_completion_t * cp )
94
+ {
95
+ return cp->pieceBitfield;
96
+ }
97
+
98
+ void tr_cpPieceAdd( tr_completion_t * cp, int piece )
99
+ {
100
+ tr_torrent_t * tor = cp->tor;
101
+ int startBlock, endBlock, i;
102
+
103
+ startBlock = tr_pieceStartBlock( piece );
104
+ endBlock = startBlock + tr_pieceCountBlocks( piece );
105
+ for( i = startBlock; i < endBlock; i++ )
106
+ {
107
+ tr_cpBlockAdd( cp, i );
108
+ }
109
+
110
+ tr_bitfieldAdd( cp->pieceBitfield, piece );
111
+ }
112
+
113
+ /* Blocks */
114
+ void tr_cpDownloaderAdd( tr_completion_t * cp, int block )
115
+ {
116
+ tr_torrent_t * tor = cp->tor;
117
+ if( !cp->blockDownloaders[block] && !tr_cpBlockIsComplete( cp, block ) )
118
+ {
119
+ cp->missingBlocks[tr_blockPiece(block)]--;
120
+ }
121
+ (cp->blockDownloaders[block])++;
122
+ }
123
+
124
+ void tr_cpDownloaderRem( tr_completion_t * cp, int block )
125
+ {
126
+ tr_torrent_t * tor = cp->tor;
127
+ (cp->blockDownloaders[block])--;
128
+ if( !cp->blockDownloaders[block] && !tr_cpBlockIsComplete( cp, block ) )
129
+ {
130
+ cp->missingBlocks[tr_blockPiece(block)]++;
131
+ }
132
+ }
133
+
134
+ int tr_cpBlockIsComplete( tr_completion_t * cp, int block )
135
+ {
136
+ return tr_bitfieldHas( cp->blockBitfield, block );
137
+ }
138
+
139
+ void tr_cpBlockAdd( tr_completion_t * cp, int block )
140
+ {
141
+ tr_torrent_t * tor = cp->tor;
142
+ if( !tr_cpBlockIsComplete( cp, block ) )
143
+ {
144
+ (cp->blockCount)++;
145
+ if( !cp->blockDownloaders[block] )
146
+ {
147
+ (cp->missingBlocks[tr_blockPiece(block)])--;
148
+ }
149
+ }
150
+ tr_bitfieldAdd( cp->blockBitfield, block );
151
+ }
152
+
153
+ void tr_cpBlockRem( tr_completion_t * cp, int block )
154
+ {
155
+ tr_torrent_t * tor = cp->tor;
156
+ if( tr_cpBlockIsComplete( cp, block ) )
157
+ {
158
+ (cp->blockCount)--;
159
+ if( !cp->blockDownloaders[block] )
160
+ {
161
+ (cp->missingBlocks[tr_blockPiece(block)])++;
162
+ }
163
+ }
164
+ tr_bitfieldRem( cp->blockBitfield, block );
165
+ }
166
+
167
+ uint8_t * tr_cpBlockBitfield( tr_completion_t * cp )
168
+ {
169
+ return cp->blockBitfield;
170
+ }
171
+
172
+ void tr_cpBlockBitfieldSet( tr_completion_t * cp, uint8_t * bitfield )
173
+ {
174
+ tr_torrent_t * tor = cp->tor;
175
+ int i, j;
176
+ int startBlock, endBlock;
177
+ int pieceComplete;
178
+
179
+ for( i = 0; i < cp->tor->info.pieceCount; i++ )
180
+ {
181
+ startBlock = tr_pieceStartBlock( i );
182
+ endBlock = startBlock + tr_pieceCountBlocks( i );
183
+ pieceComplete = 1;
184
+
185
+ for( j = startBlock; j < endBlock; j++ )
186
+ {
187
+ if( tr_bitfieldHas( bitfield, j ) )
188
+ {
189
+ tr_cpBlockAdd( cp, j );
190
+ }
191
+ else
192
+ {
193
+ pieceComplete = 0;
194
+ }
195
+ }
196
+ if( pieceComplete )
197
+ {
198
+ tr_cpPieceAdd( cp, i );
199
+ }
200
+ }
201
+ }
202
+
203
+ int tr_cpMissingBlockInPiece( tr_completion_t * cp, int piece )
204
+ {
205
+ tr_torrent_t * tor = cp->tor;
206
+ int start, count, end, i;
207
+
208
+ start = tr_pieceStartBlock( piece );
209
+ count = tr_pieceCountBlocks( piece );
210
+ end = start + count;
211
+
212
+ for( i = start; i < end; i++ )
213
+ {
214
+ if( tr_cpBlockIsComplete( cp, i ) || cp->blockDownloaders[i] )
215
+ {
216
+ continue;
217
+ }
218
+ return i;
219
+ }
220
+
221
+ return -1;
222
+ }
223
+
224
+ int tr_cpMostMissingBlockInPiece( tr_completion_t * cp, int piece,
225
+ int * downloaders )
226
+ {
227
+ tr_torrent_t * tor = cp->tor;
228
+ int start, count, end, i;
229
+ int * pool, poolSize, min, ret;
230
+
231
+ start = tr_pieceStartBlock( piece );
232
+ count = tr_pieceCountBlocks( piece );
233
+ end = start + count;
234
+
235
+ pool = malloc( count * sizeof( int ) );
236
+ poolSize = 0;
237
+ min = 255;
238
+
239
+ for( i = start; i < end; i++ )
240
+ {
241
+ if( tr_cpBlockIsComplete( cp, i ) || cp->blockDownloaders[i] > min )
242
+ {
243
+ continue;
244
+ }
245
+ if( cp->blockDownloaders[i] < min )
246
+ {
247
+ min = cp->blockDownloaders[i];
248
+ poolSize = 0;
249
+ }
250
+ if( cp->blockDownloaders[i] <= min )
251
+ {
252
+ pool[poolSize++] = i;
253
+ }
254
+ }
255
+
256
+ if( poolSize < 1 )
257
+ {
258
+ return -1;
259
+ }
260
+
261
+ ret = pool[0];
262
+ free( pool );
263
+ *downloaders = min;
264
+ return ret;
265
+ }
266
+
@@ -0,0 +1,67 @@
1
+ /******************************************************************************
2
+ * $Id: completion.h 261 2006-05-29 21:27:31Z titer $
3
+ *
4
+ * Copyright (c) 2005 Transmission authors and contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
+ * DEALINGS IN THE SOFTWARE.
23
+ *****************************************************************************/
24
+
25
+ struct tr_completion_s
26
+ {
27
+ tr_torrent_t * tor;
28
+ uint8_t * blockBitfield;
29
+ uint8_t * blockDownloaders;
30
+ int blockCount;
31
+ uint8_t * pieceBitfield;
32
+ int * missingBlocks;
33
+ };
34
+
35
+ tr_completion_t * tr_cpInit( tr_torrent_t * );
36
+ void tr_cpClose( tr_completion_t * );
37
+ void tr_cpReset( tr_completion_t * );
38
+
39
+ /* General */
40
+ float tr_cpCompletionAsFloat( tr_completion_t * );
41
+ static inline int tr_cpIsSeeding( tr_completion_t * cp )
42
+ {
43
+ return ( cp->blockCount == cp->tor->blockCount );
44
+ }
45
+ uint64_t tr_cpLeftBytes( tr_completion_t * );
46
+
47
+ /* Pieces */
48
+ int tr_cpPieceIsComplete( tr_completion_t *, int piece );
49
+ uint8_t * tr_cpPieceBitfield( tr_completion_t * );
50
+ void tr_cpPieceAdd( tr_completion_t *, int piece );
51
+
52
+ /* Blocks */
53
+ void tr_cpDownloaderAdd( tr_completion_t *, int block );
54
+ void tr_cpDownloaderRem( tr_completion_t *, int block );
55
+ int tr_cpBlockIsComplete( tr_completion_t *, int block );
56
+ void tr_cpBlockAdd( tr_completion_t *, int block );
57
+ void tr_cpBlockRem( tr_completion_t *, int block );
58
+ uint8_t * tr_cpBlockBitfield( tr_completion_t * );
59
+ void tr_cpBlockBitfieldSet( tr_completion_t *, uint8_t * );
60
+ /* Missing = we don't have it and we are not getting it from any peer yet */
61
+ static inline int tr_cpMissingBlocksForPiece( tr_completion_t * cp, int piece )
62
+ {
63
+ return cp->missingBlocks[piece];
64
+ }
65
+ int tr_cpMissingBlockInPiece( tr_completion_t *, int piece );
66
+ int tr_cpMostMissingBlockInPiece( tr_completion_t *, int piece,
67
+ int * downloaders );
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("transmission")
@@ -0,0 +1,375 @@
1
+ /******************************************************************************
2
+ * $Id: fastresume.h 326 2006-06-11 04:32:41Z joshe $
3
+ *
4
+ * Copyright (c) 2005-2006 Transmission authors and contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
+ * DEALINGS IN THE SOFTWARE.
23
+ *****************************************************************************/
24
+
25
+ /***********************************************************************
26
+ * Fast resume
27
+ ***********************************************************************
28
+ * The format of the resume file is a 4 byte format version (currently 1),
29
+ * followed by several variable-sized blocks of data. Each block is
30
+ * preceded by a 1 byte ID and a 4 byte length. The currently recognized
31
+ * IDs are defined below by the FR_ID_* macros. The length does not include
32
+ * the 5 bytes for the ID and length.
33
+ *
34
+ * The name of the resume file is "resume.<hash>".
35
+ *
36
+ * All values are stored in the native endianness. Moving a
37
+ * libtransmission resume file from an architecture to another will not
38
+ * work, although it will not hurt either (the version will be wrong,
39
+ * so the resume file will not be read).
40
+ **********************************************************************/
41
+
42
+ /* progress data:
43
+ * - 4 bytes * number of files: mtimes of files
44
+ * - 1 bit * number of blocks: whether we have the block or not
45
+ * - 4 bytes * number of pieces (byte aligned): the pieces that have
46
+ * been completed or started in each slot
47
+ */
48
+ #define FR_ID_PROGRESS 0x01
49
+ /* number of bytes downloaded */
50
+ #define FR_ID_DOWNLOADED 0x02
51
+ /* number of bytes uploaded */
52
+ #define FR_ID_UPLOADED 0x03
53
+
54
+ /* macros for the length of various pieces of the progress data */
55
+ #define FR_MTIME_LEN( t ) \
56
+ ( 4 * (t)->info.fileCount )
57
+ #define FR_BLOCK_BITFIELD_LEN( t ) \
58
+ ( ( (t)->blockCount + 7 ) / 8 )
59
+ #define FR_SLOTPIECE_LEN( t ) \
60
+ ( 4 * (t)->info.pieceCount )
61
+ #define FR_PROGRESS_LEN( t ) \
62
+ ( FR_MTIME_LEN( t ) + FR_BLOCK_BITFIELD_LEN( t ) + FR_SLOTPIECE_LEN( t ) )
63
+
64
+ static char * fastResumeFileName( tr_io_t * io )
65
+ {
66
+ char * ret;
67
+
68
+ asprintf( &ret, "%s/resume.%s", tr_getCacheDirectory(),
69
+ io->tor->info.hashString );
70
+
71
+ return ret;
72
+ }
73
+
74
+ static int fastResumeMTimes( tr_io_t * io, int * tab )
75
+ {
76
+ tr_torrent_t * tor = io->tor;
77
+ tr_info_t * inf = &tor->info;
78
+
79
+ int i;
80
+ char * path;
81
+ struct stat sb;
82
+
83
+ for( i = 0; i < inf->fileCount; i++ )
84
+ {
85
+ asprintf( &path, "%s/%s", tor->destination, inf->files[i].name );
86
+ if( stat( path, &sb ) )
87
+ {
88
+ tr_err( "Could not stat '%s'", path );
89
+ free( path );
90
+ return 1;
91
+ }
92
+ if( ( sb.st_mode & S_IFMT ) != S_IFREG )
93
+ {
94
+ tr_err( "Wrong st_mode for '%s'", path );
95
+ free( path );
96
+ return 1;
97
+ }
98
+ free( path );
99
+
100
+ #ifdef SYS_DARWIN
101
+ tab[i] = ( sb.st_mtimespec.tv_sec & 0x7FFFFFFF );
102
+ #else
103
+ tab[i] = ( sb.st_mtime & 0x7FFFFFFF );
104
+ #endif
105
+ }
106
+
107
+ return 0;
108
+ }
109
+
110
+ static inline void fastResumeWriteData( uint8_t id, void * data, uint32_t size,
111
+ uint32_t count, FILE * file )
112
+ {
113
+ uint32_t datalen = size * count;
114
+
115
+ fwrite( &id, 1, 1, file );
116
+ fwrite( &datalen, 4, 1, file );
117
+ fwrite( data, size, count, file );
118
+ }
119
+
120
+ static void fastResumeSave( tr_io_t * io )
121
+ {
122
+ tr_torrent_t * tor = io->tor;
123
+
124
+ FILE * file;
125
+ int version = 1;
126
+ char * path;
127
+ uint8_t * buf;
128
+
129
+ buf = malloc( FR_PROGRESS_LEN( tor ) );
130
+
131
+ /* Get file sizes */
132
+ if( fastResumeMTimes( io, (int*)buf ) )
133
+ {
134
+ free( buf );
135
+ return;
136
+ }
137
+
138
+ /* Create/overwrite the resume file */
139
+ path = fastResumeFileName( io );
140
+ if( !( file = fopen( path, "w" ) ) )
141
+ {
142
+ tr_err( "Could not open '%s' for writing", path );
143
+ free( buf );
144
+ free( path );
145
+ return;
146
+ }
147
+
148
+ /* Write format version */
149
+ fwrite( &version, 4, 1, file );
150
+
151
+ /* Build and copy the bitfield for blocks */
152
+ memcpy(buf + FR_MTIME_LEN( tor ), tr_cpBlockBitfield( tor->completion ),
153
+ FR_BLOCK_BITFIELD_LEN( tor ) );
154
+
155
+ /* Copy the 'slotPiece' table */
156
+ memcpy(buf + FR_MTIME_LEN( tor ) + FR_BLOCK_BITFIELD_LEN( tor ),
157
+ io->slotPiece, FR_SLOTPIECE_LEN( tor ) );
158
+
159
+ /* Write progress data */
160
+ fastResumeWriteData( FR_ID_PROGRESS, buf, 1, FR_PROGRESS_LEN( tor ), file );
161
+ free( buf );
162
+
163
+ /* Write download and upload totals */
164
+ fastResumeWriteData( FR_ID_DOWNLOADED, &tor->downloaded, 8, 1, file );
165
+ fastResumeWriteData( FR_ID_UPLOADED, &tor->uploaded, 8, 1, file );
166
+
167
+ fclose( file );
168
+
169
+ tr_dbg( "Resume file '%s' written", path );
170
+ free( path );
171
+ }
172
+
173
+ static int fastResumeLoadProgress( tr_io_t * io, FILE * file )
174
+ {
175
+ tr_torrent_t * tor = io->tor;
176
+ tr_info_t * inf = &tor->info;
177
+
178
+ int * fileMTimes;
179
+ int i, j;
180
+ uint8_t * buf;
181
+ size_t len;
182
+
183
+ len = FR_PROGRESS_LEN( tor );
184
+ buf = calloc( len, 1 );
185
+ if( len != fread( buf, 1, len, file ) )
186
+ {
187
+ tr_inf( "Could not read from resume file" );
188
+ free( buf );
189
+ return 1;
190
+ }
191
+
192
+ /* Compare file mtimes */
193
+ fileMTimes = malloc( FR_MTIME_LEN( tor ) );
194
+ if( fastResumeMTimes( io, fileMTimes ) )
195
+ {
196
+ free( buf );
197
+ free( fileMTimes );
198
+ return 1;
199
+ }
200
+ if( memcmp( fileMTimes, buf, FR_MTIME_LEN( tor ) ) )
201
+ {
202
+ tr_inf( "File mtimes don't match" );
203
+ free( buf );
204
+ free( fileMTimes );
205
+ return 1;
206
+ }
207
+ free( fileMTimes );
208
+
209
+ /* Copy the bitfield for blocks and fill blockHave */
210
+ tr_cpBlockBitfieldSet( tor->completion, buf + FR_MTIME_LEN( tor ) );
211
+
212
+ /* Copy the 'slotPiece' table */
213
+ memcpy( io->slotPiece, buf + FR_MTIME_LEN( tor ) +
214
+ FR_BLOCK_BITFIELD_LEN( tor ), FR_SLOTPIECE_LEN( tor ) );
215
+
216
+ free( buf );
217
+
218
+ /* Update io->pieceSlot, io->slotsUsed, and tor->bitfield */
219
+ io->slotsUsed = 0;
220
+ for( i = 0; i < inf->pieceCount; i++ )
221
+ {
222
+ io->pieceSlot[i] = -1;
223
+ for( j = 0; j < inf->pieceCount; j++ )
224
+ {
225
+ if( io->slotPiece[j] == i )
226
+ {
227
+ // tr_dbg( "Has piece %d in slot %d", i, j );
228
+ io->pieceSlot[i] = j;
229
+ io->slotsUsed = MAX( io->slotsUsed, j + 1 );
230
+ break;
231
+ }
232
+ }
233
+ }
234
+ // tr_dbg( "Slot used: %d", io->slotsUsed );
235
+
236
+ return 0;
237
+ }
238
+
239
+ static int fastResumeLoadOld( tr_io_t * io, FILE * file )
240
+ {
241
+ tr_torrent_t * tor = io->tor;
242
+
243
+ int size;
244
+
245
+ /* Check the size */
246
+ size = 4 + FR_PROGRESS_LEN( tor );
247
+ fseek( file, 0, SEEK_END );
248
+ if( ftell( file ) != size )
249
+ {
250
+ tr_inf( "Wrong size for resume file (%d bytes, %d expected)",
251
+ ftell( file ), size );
252
+ fclose( file );
253
+ return 1;
254
+ }
255
+
256
+ /* load progress information */
257
+ fseek( file, 4, SEEK_SET );
258
+ if( fastResumeLoadProgress( io, file ) )
259
+ {
260
+ fclose( file );
261
+ return 1;
262
+ }
263
+
264
+ fclose( file );
265
+
266
+ tr_inf( "Fast resuming successful (version 0)" );
267
+
268
+ return 0;
269
+ }
270
+
271
+ static int fastResumeLoad( tr_io_t * io )
272
+ {
273
+ tr_torrent_t * tor = io->tor;
274
+
275
+ FILE * file;
276
+ int version = 0;
277
+ char * path;
278
+ uint8_t id;
279
+ uint32_t len;
280
+ int ret;
281
+
282
+ /* Open resume file */
283
+ path = fastResumeFileName( io );
284
+ if( !( file = fopen( path, "r" ) ) )
285
+ {
286
+ tr_inf( "Could not open '%s' for reading", path );
287
+ free( path );
288
+ return 1;
289
+ }
290
+ tr_dbg( "Resume file '%s' loaded", path );
291
+ free( path );
292
+
293
+ /* Check format version */
294
+ fread( &version, 4, 1, file );
295
+ if( 0 == version )
296
+ {
297
+ return fastResumeLoadOld( io, file );
298
+ }
299
+ if( 1 != version )
300
+ {
301
+ tr_inf( "Resume file has version %d, not supported", version );
302
+ fclose( file );
303
+ return 1;
304
+ }
305
+
306
+ ret = 1;
307
+ /* read each block of data */
308
+ while( 1 == fread( &id, 1, 1, file ) && 1 == fread( &len, 4, 1, file ) )
309
+ {
310
+ switch( id )
311
+ {
312
+ case FR_ID_PROGRESS:
313
+ /* read progress data */
314
+ if( (uint32_t)FR_PROGRESS_LEN( tor ) == len )
315
+ {
316
+ if( fastResumeLoadProgress( io, file ) )
317
+ {
318
+ if( feof( file ) || ferror( file ) )
319
+ {
320
+ fclose( file );
321
+ return 1;
322
+ }
323
+ }
324
+ else
325
+ {
326
+ ret = 0;
327
+ }
328
+ continue;
329
+ }
330
+ break;
331
+
332
+ case FR_ID_DOWNLOADED:
333
+ /* read download total */
334
+ if( 8 == len)
335
+ {
336
+ if( 1 != fread( &tor->downloaded, 8, 1, file ) )
337
+ {
338
+ fclose( file );
339
+ return 1;
340
+ }
341
+ continue;
342
+ }
343
+ break;
344
+
345
+ case FR_ID_UPLOADED:
346
+ /* read upload total */
347
+ if( 8 == len)
348
+ {
349
+ if( 1 != fread( &tor->uploaded, 8, 1, file ) )
350
+ {
351
+ fclose( file );
352
+ return 1;
353
+ }
354
+ continue;
355
+ }
356
+ break;
357
+
358
+ default:
359
+ break;
360
+ }
361
+
362
+ /* if we didn't read the data, seek past it */
363
+ tr_inf( "Skipping resume data type %02x, %u bytes", id, len );
364
+ fseek( file, len, SEEK_CUR );
365
+ }
366
+
367
+ fclose( file );
368
+
369
+ if( !ret )
370
+ {
371
+ tr_inf( "Fast resuming successful" );
372
+ }
373
+
374
+ return ret;
375
+ }