transmission 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }