transmission 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,297 @@
1
+ /******************************************************************************
2
+ * $Id: fdlimit.c 261 2006-05-29 21:27:31Z titer $
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
+ #include "transmission.h"
26
+
27
+ #define TR_MAX_OPEN_FILES 16 /* That is, real files, not sockets */
28
+ #define TR_RESERVED_FDS 16 /* Number of sockets reserved for
29
+ connections to trackers */
30
+
31
+ typedef struct tr_openFile_s
32
+ {
33
+ char path[MAX_PATH_LENGTH];
34
+ int file;
35
+
36
+ #define STATUS_INVALID 1
37
+ #define STATUS_UNUSED 2
38
+ #define STATUS_USED 4
39
+ #define STATUS_CLOSING 8
40
+ int status;
41
+
42
+ uint64_t date;
43
+
44
+ } tr_openFile_t;
45
+
46
+ struct tr_fd_s
47
+ {
48
+ tr_lock_t lock;
49
+
50
+ int reserved;
51
+
52
+ int normal;
53
+ int normalMax;
54
+
55
+ tr_openFile_t open[TR_MAX_OPEN_FILES];
56
+ };
57
+
58
+ /***********************************************************************
59
+ * tr_fdInit
60
+ **********************************************************************/
61
+ tr_fd_t * tr_fdInit()
62
+ {
63
+ tr_fd_t * f;
64
+ int i, j, s[4096];
65
+
66
+ f = calloc( sizeof( tr_fd_t ), 1 );
67
+
68
+ /* Init lock */
69
+ tr_lockInit( &f->lock );
70
+
71
+ /* Detect the maximum number of open files or sockets */
72
+ for( i = 0; i < 4096; i++ )
73
+ {
74
+ if( ( s[i] = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
75
+ {
76
+ break;
77
+ }
78
+ }
79
+ for( j = 0; j < i; j++ )
80
+ {
81
+ tr_netClose( s[j] );
82
+ }
83
+
84
+ tr_dbg( "%d usable file descriptors", i );
85
+
86
+ f->reserved = 0;
87
+ f->normal = 0;
88
+
89
+ f->normalMax = i - TR_RESERVED_FDS - 10;
90
+ /* To be safe, in case the UI needs to write a preferences file
91
+ or something */
92
+
93
+ for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
94
+ {
95
+ f->open[i].status = STATUS_INVALID;
96
+ }
97
+
98
+ return f;
99
+ }
100
+
101
+ /***********************************************************************
102
+ * tr_fdFileOpen
103
+ **********************************************************************/
104
+ int tr_fdFileOpen( tr_fd_t * f, char * path )
105
+ {
106
+ int i, winner;
107
+ uint64_t date;
108
+
109
+ tr_lockLock( &f->lock );
110
+
111
+ /* Is it already open? */
112
+ for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
113
+ {
114
+ if( f->open[i].status > STATUS_INVALID &&
115
+ !strcmp( path, f->open[i].path ) )
116
+ {
117
+ if( f->open[i].status & STATUS_CLOSING )
118
+ {
119
+ /* Wait until the file is closed */
120
+ tr_lockUnlock( &f->lock );
121
+ tr_wait( 10 );
122
+ tr_lockLock( &f->lock );
123
+ i = -1;
124
+ continue;
125
+ }
126
+ winner = i;
127
+ goto done;
128
+ }
129
+ }
130
+
131
+ /* Can we open one more file? */
132
+ for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
133
+ {
134
+ if( f->open[i].status & STATUS_INVALID )
135
+ {
136
+ winner = i;
137
+ goto open;
138
+ }
139
+ }
140
+
141
+ for( ;; )
142
+ {
143
+ /* Close the oldest currently unused file */
144
+ date = tr_date() + 1;
145
+ winner = -1;
146
+
147
+ for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
148
+ {
149
+ if( !( f->open[i].status & STATUS_UNUSED ) )
150
+ {
151
+ continue;
152
+ }
153
+ if( f->open[i].date < date )
154
+ {
155
+ winner = i;
156
+ date = f->open[i].date;
157
+ }
158
+ }
159
+
160
+ if( winner >= 0 )
161
+ {
162
+ /* Close the file: we mark it as closing then release the
163
+ lock while doing so, because close may take same time
164
+ and we don't want to block other threads */
165
+ tr_dbg( "Closing %s", f->open[winner].path );
166
+ f->open[winner].status = STATUS_CLOSING;
167
+ tr_lockUnlock( &f->lock );
168
+ close( f->open[winner].file );
169
+ tr_lockLock( &f->lock );
170
+ goto open;
171
+ }
172
+
173
+ /* All used! Wait a bit and try again */
174
+ tr_lockUnlock( &f->lock );
175
+ tr_wait( 10 );
176
+ tr_lockLock( &f->lock );
177
+ }
178
+
179
+ open:
180
+ tr_dbg( "Opening %s", path );
181
+ snprintf( f->open[winner].path, MAX_PATH_LENGTH, "%s", path );
182
+ f->open[winner].file = open( path, O_RDWR, 0 );
183
+
184
+ done:
185
+ f->open[winner].status = STATUS_USED;
186
+ f->open[winner].date = tr_date();
187
+ tr_lockUnlock( &f->lock );
188
+
189
+ return f->open[winner].file;
190
+ }
191
+
192
+ /***********************************************************************
193
+ * tr_fdFileRelease
194
+ **********************************************************************/
195
+ void tr_fdFileRelease( tr_fd_t * f, int file )
196
+ {
197
+ int i;
198
+ tr_lockLock( &f->lock );
199
+
200
+ for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
201
+ {
202
+ if( f->open[i].file == file )
203
+ {
204
+ f->open[i].status = STATUS_UNUSED;
205
+ break;
206
+ }
207
+ }
208
+
209
+ tr_lockUnlock( &f->lock );
210
+ }
211
+
212
+ /***********************************************************************
213
+ * tr_fdFileClose
214
+ **********************************************************************/
215
+ void tr_fdFileClose( tr_fd_t * f, char * path )
216
+ {
217
+ int i;
218
+
219
+ tr_lockLock( &f->lock );
220
+
221
+ /* Is it already open? */
222
+ for( i = 0; i < TR_MAX_OPEN_FILES; i++ )
223
+ {
224
+ if( f->open[i].status & STATUS_INVALID )
225
+ {
226
+ continue;
227
+ }
228
+ if( !strcmp( path, f->open[i].path ) )
229
+ {
230
+ tr_dbg( "Closing %s", path );
231
+ close( f->open[i].file );
232
+ f->open[i].status = STATUS_INVALID;
233
+ break;
234
+ }
235
+ }
236
+
237
+ tr_lockUnlock( &f->lock );
238
+ }
239
+
240
+ int tr_fdSocketWillCreate( tr_fd_t * f, int reserved )
241
+ {
242
+ int ret;
243
+
244
+ tr_lockLock( &f->lock );
245
+
246
+ if( reserved )
247
+ {
248
+ if( f->reserved < TR_RESERVED_FDS )
249
+ {
250
+ ret = 0;
251
+ (f->reserved)++;
252
+ }
253
+ else
254
+ {
255
+ ret = 1;
256
+ }
257
+ }
258
+ else
259
+ {
260
+ if( f->normal < f->normalMax )
261
+ {
262
+ ret = 0;
263
+ (f->normal)++;
264
+ }
265
+ else
266
+ {
267
+ ret = 1;
268
+ }
269
+ }
270
+
271
+ tr_lockUnlock( &f->lock );
272
+
273
+ return ret;
274
+ }
275
+
276
+ void tr_fdSocketClosed( tr_fd_t * f, int reserved )
277
+ {
278
+ tr_lockLock( &f->lock );
279
+
280
+ if( reserved )
281
+ {
282
+ (f->reserved)--;
283
+ }
284
+ else
285
+ {
286
+ (f->normal)--;
287
+ }
288
+
289
+ tr_lockUnlock( &f->lock );
290
+ }
291
+
292
+ void tr_fdClose( tr_fd_t * f )
293
+ {
294
+ tr_lockClose( &f->lock );
295
+ free( f );
296
+ }
297
+
@@ -0,0 +1,36 @@
1
+ /******************************************************************************
2
+ * $Id: fdlimit.h 261 2006-05-29 21:27:31Z titer $
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
+ typedef struct tr_fd_s tr_fd_t;
26
+
27
+ tr_fd_t * tr_fdInit();
28
+
29
+ int tr_fdFileOpen ( tr_fd_t *, char * );
30
+ void tr_fdFileRelease ( tr_fd_t *, int );
31
+ void tr_fdFileClose ( tr_fd_t *, char * );
32
+
33
+ int tr_fdSocketWillCreate ( tr_fd_t *, int );
34
+ void tr_fdSocketClosed ( tr_fd_t *, int );
35
+
36
+ void tr_fdClose ( tr_fd_t * );
@@ -0,0 +1,620 @@
1
+ /******************************************************************************
2
+ * $Id: inout.c 346 2006-06-13 00:28:03Z titer $
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
+ #include "transmission.h"
26
+
27
+ struct tr_io_s
28
+ {
29
+ tr_torrent_t * tor;
30
+
31
+ /* Position of pieces
32
+ -1 = we haven't started to download this piece yet
33
+ n = we have started or completed the piece in slot n */
34
+ int * pieceSlot;
35
+
36
+ /* Pieces in slot
37
+ -1 = unused slot
38
+ n = piece n */
39
+ int * slotPiece;
40
+
41
+ int slotsUsed;
42
+ };
43
+
44
+ #include "fastresume.h"
45
+
46
+ /***********************************************************************
47
+ * Local prototypes
48
+ **********************************************************************/
49
+ static int createFiles( tr_io_t * );
50
+ static int checkFiles( tr_io_t * );
51
+ static void closeFiles( tr_io_t * );
52
+ static int readOrWriteBytes( tr_io_t *, uint64_t, int, uint8_t *, int );
53
+ static int readOrWriteSlot( tr_io_t * io, int slot, uint8_t * buf,
54
+ int * size, int write );
55
+ static void findSlotForPiece( tr_io_t *, int );
56
+
57
+ #define readBytes(io,o,s,b) readOrWriteBytes(io,o,s,b,0)
58
+ #define writeBytes(io,o,s,b) readOrWriteBytes(io,o,s,b,1)
59
+
60
+ #define readSlot(io,sl,b,s) readOrWriteSlot(io,sl,b,s,0)
61
+ #define writeSlot(io,sl,b,s) readOrWriteSlot(io,sl,b,s,1)
62
+
63
+ /***********************************************************************
64
+ * tr_ioLoadResume
65
+ ***********************************************************************
66
+ * Try to load the fast resume file
67
+ **********************************************************************/
68
+ void tr_ioLoadResume( tr_torrent_t * tor )
69
+ {
70
+ tr_io_t * io;
71
+ tr_info_t * inf = &tor->info;
72
+
73
+ io = malloc( sizeof( tr_io_t ) );
74
+ io->tor = tor;
75
+
76
+ io->pieceSlot = malloc( inf->pieceCount * sizeof( int ) );
77
+ io->slotPiece = malloc( inf->pieceCount * sizeof( int ) );
78
+
79
+ fastResumeLoad( io );
80
+
81
+ free( io->pieceSlot );
82
+ free( io->slotPiece );
83
+ free( io );
84
+ }
85
+
86
+ /***********************************************************************
87
+ * tr_ioInit
88
+ ***********************************************************************
89
+ * Open all files we are going to write to
90
+ **********************************************************************/
91
+ tr_io_t * tr_ioInit( tr_torrent_t * tor )
92
+ {
93
+ tr_io_t * io;
94
+
95
+ io = malloc( sizeof( tr_io_t ) );
96
+ io->tor = tor;
97
+
98
+ if( createFiles( io ) || checkFiles( io ) )
99
+ {
100
+ free( io );
101
+ return NULL;
102
+ }
103
+
104
+ return io;
105
+ }
106
+
107
+ /***********************************************************************
108
+ * tr_ioRead
109
+ ***********************************************************************
110
+ *
111
+ **********************************************************************/
112
+ int tr_ioRead( tr_io_t * io, int index, int begin, int length,
113
+ uint8_t * buf )
114
+ {
115
+ uint64_t offset;
116
+ tr_info_t * inf = &io->tor->info;
117
+
118
+ offset = (uint64_t) io->pieceSlot[index] *
119
+ (uint64_t) inf->pieceSize + (uint64_t) begin;
120
+
121
+ return readBytes( io, offset, length, buf );
122
+ }
123
+
124
+ /***********************************************************************
125
+ * tr_ioWrite
126
+ ***********************************************************************
127
+ *
128
+ **********************************************************************/
129
+ int tr_ioWrite( tr_io_t * io, int index, int begin, int length,
130
+ uint8_t * buf )
131
+ {
132
+ tr_torrent_t * tor = io->tor;
133
+ tr_info_t * inf = &io->tor->info;
134
+ uint64_t offset;
135
+ int i, hashFailed;
136
+ uint8_t hash[SHA_DIGEST_LENGTH];
137
+ uint8_t * pieceBuf;
138
+ int pieceSize;
139
+ int startBlock, endBlock;
140
+
141
+ if( io->pieceSlot[index] < 0 )
142
+ {
143
+ findSlotForPiece( io, index );
144
+ tr_inf( "Piece %d: starting in slot %d", index,
145
+ io->pieceSlot[index] );
146
+ }
147
+
148
+ offset = (uint64_t) io->pieceSlot[index] *
149
+ (uint64_t) inf->pieceSize + (uint64_t) begin;
150
+
151
+ if( writeBytes( io, offset, length, buf ) )
152
+ {
153
+ return 1;
154
+ }
155
+
156
+ startBlock = tr_pieceStartBlock( index );
157
+ endBlock = startBlock + tr_pieceCountBlocks( index );
158
+ for( i = startBlock; i < endBlock; i++ )
159
+ {
160
+ if( !tr_cpBlockIsComplete( tor->completion, i ) )
161
+ {
162
+ /* The piece is not complete */
163
+ return 0;
164
+ }
165
+ }
166
+
167
+ /* The piece is complete, check the hash */
168
+ pieceSize = tr_pieceSize( index );
169
+ pieceBuf = malloc( pieceSize );
170
+ readBytes( io, (uint64_t) io->pieceSlot[index] *
171
+ (uint64_t) inf->pieceSize, pieceSize, pieceBuf );
172
+ SHA1( pieceBuf, pieceSize, hash );
173
+ free( pieceBuf );
174
+
175
+ hashFailed = memcmp( hash, &inf->pieces[20*index], SHA_DIGEST_LENGTH );
176
+ if( hashFailed )
177
+ {
178
+ tr_inf( "Piece %d (slot %d): hash FAILED", index,
179
+ io->pieceSlot[index] );
180
+
181
+ /* We will need to reload the whole piece */
182
+ for( i = startBlock; i < endBlock; i++ )
183
+ {
184
+ tr_cpBlockRem( tor->completion, i );
185
+ }
186
+ }
187
+ else
188
+ {
189
+ tr_inf( "Piece %d (slot %d): hash OK", index,
190
+ io->pieceSlot[index] );
191
+ tr_cpPieceAdd( tor->completion, index );
192
+ }
193
+
194
+ /* Assign blame or credit to peers */
195
+ for( i = 0; i < tor->peerCount; i++ )
196
+ {
197
+ tr_peerBlame( tor, tor->peers[i], index, !hashFailed );
198
+ }
199
+
200
+ return 0;
201
+ }
202
+
203
+ void tr_ioClose( tr_io_t * io )
204
+ {
205
+ closeFiles( io );
206
+
207
+ fastResumeSave( io );
208
+
209
+ free( io->pieceSlot );
210
+ free( io->slotPiece );
211
+ free( io );
212
+ }
213
+
214
+ void tr_ioSaveResume( tr_io_t * io )
215
+ {
216
+ fastResumeSave( io );
217
+ }
218
+
219
+ /***********************************************************************
220
+ * createFiles
221
+ ***********************************************************************
222
+ * Make sure the existing folders/files have correct types and
223
+ * permissions, and create missing folders and files
224
+ **********************************************************************/
225
+ static int createFiles( tr_io_t * io )
226
+ {
227
+ tr_torrent_t * tor = io->tor;
228
+ tr_info_t * inf = &tor->info;
229
+
230
+ int i;
231
+ char * path, * p;
232
+ struct stat sb;
233
+ int file;
234
+
235
+ tr_dbg( "Creating files..." );
236
+
237
+ for( i = 0; i < inf->fileCount; i++ )
238
+ {
239
+ asprintf( &path, "%s/%s", tor->destination, inf->files[i].name );
240
+
241
+ /* Create folders */
242
+ if( NULL != ( p = strrchr( path, '/' ) ) )
243
+ {
244
+ *p = '\0';
245
+ if( tr_mkdir( path ) )
246
+ {
247
+ free( path );
248
+ return 1;
249
+ }
250
+ *p = '/';
251
+ }
252
+
253
+ if( stat( path, &sb ) )
254
+ {
255
+ /* File doesn't exist yet */
256
+ if( ( file = open( path, O_WRONLY|O_CREAT|O_TRUNC, 0666 ) ) < 0 )
257
+ {
258
+ tr_err( "Could not create `%s' (%s)", path,
259
+ strerror( errno ) );
260
+ free( path );
261
+ return 1;
262
+ }
263
+ close( file );
264
+ }
265
+ else if( ( sb.st_mode & S_IFMT ) != S_IFREG )
266
+ {
267
+ /* Node exists but isn't a file */
268
+ printf( "Remove %s, it's in the way.\n", path );
269
+ free( path );
270
+ return 1;
271
+ }
272
+
273
+ free( path );
274
+ }
275
+
276
+ return 0;
277
+ }
278
+
279
+ /***********************************************************************
280
+ * checkFiles
281
+ ***********************************************************************
282
+ * Look for pieces
283
+ **********************************************************************/
284
+ static int checkFiles( tr_io_t * io )
285
+ {
286
+ tr_torrent_t * tor = io->tor;
287
+ tr_info_t * inf = &tor->info;
288
+
289
+ int i;
290
+ uint8_t * buf;
291
+ uint8_t hash[SHA_DIGEST_LENGTH];
292
+
293
+ io->pieceSlot = malloc( inf->pieceCount * sizeof( int ) );
294
+ io->slotPiece = malloc( inf->pieceCount * sizeof( int ) );
295
+
296
+ if( !fastResumeLoad( io ) )
297
+ {
298
+ return 0;
299
+ }
300
+
301
+ tr_dbg( "Checking pieces..." );
302
+
303
+ /* Yet we don't have anything */
304
+ memset( io->pieceSlot, 0xFF, inf->pieceCount * sizeof( int ) );
305
+ memset( io->slotPiece, 0xFF, inf->pieceCount * sizeof( int ) );
306
+
307
+ /* Check pieces */
308
+ io->slotsUsed = 0;
309
+ buf = malloc( inf->pieceSize );
310
+ for( i = 0; i < inf->pieceCount; i++ )
311
+ {
312
+ int size, j;
313
+
314
+ if( readSlot( io, i, buf, &size ) )
315
+ {
316
+ break;
317
+ }
318
+
319
+ io->slotsUsed = i + 1;
320
+ SHA1( buf, size, hash );
321
+
322
+ for( j = i; j < inf->pieceCount - 1; j++ )
323
+ {
324
+ if( !memcmp( hash, &inf->pieces[20*j], SHA_DIGEST_LENGTH ) )
325
+ {
326
+ io->pieceSlot[j] = i;
327
+ io->slotPiece[i] = j;
328
+
329
+ tr_cpPieceAdd( tor->completion, j );
330
+ break;
331
+ }
332
+ }
333
+
334
+ if( io->slotPiece[i] > -1 )
335
+ {
336
+ continue;
337
+ }
338
+
339
+ /* Special case for the last piece */
340
+ SHA1( buf, tr_pieceSize( inf->pieceCount - 1 ), hash );
341
+ if( !memcmp( hash, &inf->pieces[20 * (inf->pieceCount - 1)],
342
+ SHA_DIGEST_LENGTH ) )
343
+ {
344
+ io->pieceSlot[inf->pieceCount - 1] = i;
345
+ io->slotPiece[i] = inf->pieceCount - 1;
346
+
347
+ tr_cpPieceAdd( tor->completion, inf->pieceCount - 1 );
348
+ }
349
+ }
350
+ free( buf );
351
+
352
+ return 0;
353
+ }
354
+
355
+ /***********************************************************************
356
+ * closeFiles
357
+ **********************************************************************/
358
+ static void closeFiles( tr_io_t * io )
359
+ {
360
+ tr_torrent_t * tor = io->tor;
361
+ tr_info_t * inf = &tor->info;
362
+
363
+ int i;
364
+ char * path;
365
+
366
+ for( i = 0; i < inf->fileCount; i++ )
367
+ {
368
+ asprintf( &path, "%s/%s", tor->destination, inf->files[i].name );
369
+ tr_fdFileClose( tor->fdlimit, path );
370
+ free( path );
371
+ }
372
+ }
373
+
374
+ /***********************************************************************
375
+ * readOrWriteBytes
376
+ ***********************************************************************
377
+ *
378
+ **********************************************************************/
379
+ typedef size_t (* iofunc) ( int, void *, size_t );
380
+ static int readOrWriteBytes( tr_io_t * io, uint64_t offset, int size,
381
+ uint8_t * buf, int isWrite )
382
+ {
383
+ tr_torrent_t * tor = io->tor;
384
+ tr_info_t * inf = &tor->info;
385
+
386
+ int piece = offset / inf->pieceSize;
387
+ int begin = offset % inf->pieceSize;
388
+ int i;
389
+ size_t cur;
390
+ char * path;
391
+ int file;
392
+ iofunc readOrWrite = isWrite ? (iofunc) write : (iofunc) read;
393
+
394
+ /* Release the torrent lock so the UI can still update itself if
395
+ this blocks for a while */
396
+ tr_lockUnlock( &tor->lock );
397
+
398
+ /* We don't ever read or write more than a piece at a time */
399
+ if( tr_pieceSize( piece ) < begin + size )
400
+ {
401
+ tr_err( "readOrWriteBytes: trying to write more than a piece" );
402
+ goto fail;
403
+ }
404
+
405
+ /* Find which file we shall start reading/writing in */
406
+ for( i = 0; i < inf->fileCount; i++ )
407
+ {
408
+ if( offset < inf->files[i].length )
409
+ {
410
+ /* This is the file */
411
+ break;
412
+ }
413
+ offset -= inf->files[i].length;
414
+ }
415
+ if( i >= inf->fileCount )
416
+ {
417
+ /* Should not happen */
418
+ tr_err( "readOrWriteBytes: offset out of range (%lld, %d, %d)",
419
+ offset, size, write );
420
+ goto fail;
421
+ }
422
+
423
+ while( size > 0 )
424
+ {
425
+ /* How much can we put or take with this file */
426
+ if( inf->files[i].length < offset + size )
427
+ {
428
+ cur = (int) ( inf->files[i].length - offset );
429
+ }
430
+ else
431
+ {
432
+ cur = size;
433
+ }
434
+
435
+ /* Now let's get a stream on the file... */
436
+ asprintf( &path, "%s/%s", tor->destination, inf->files[i].name );
437
+ file = tr_fdFileOpen( tor->fdlimit, path );
438
+ if( file < 0 )
439
+ {
440
+ tr_err( "readOrWriteBytes: could not open file '%s'", path );
441
+ free( path );
442
+ goto fail;
443
+ }
444
+ free( path );
445
+
446
+ /* seek to the right offset... */
447
+ if( lseek( file, offset, SEEK_SET ) < 0 )
448
+ {
449
+ goto fail;
450
+ }
451
+
452
+ /* do what we are here to do... */
453
+ if( readOrWrite( file, buf, cur ) != cur )
454
+ {
455
+ goto fail;
456
+ }
457
+
458
+ /* and close the stream. */
459
+ tr_fdFileRelease( tor->fdlimit, file );
460
+
461
+ /* 'cur' bytes done, 'size - cur' bytes to go with the next file */
462
+ i += 1;
463
+ offset = 0;
464
+ size -= cur;
465
+ buf += cur;
466
+ }
467
+
468
+ tr_lockLock( &tor->lock );
469
+ return 0;
470
+
471
+ fail:
472
+ tr_lockLock( &tor->lock );
473
+ return 1;
474
+ }
475
+
476
+ /***********************************************************************
477
+ * readSlot
478
+ ***********************************************************************
479
+ *
480
+ **********************************************************************/
481
+ static int readOrWriteSlot( tr_io_t * io, int slot, uint8_t * buf,
482
+ int * size, int write )
483
+ {
484
+ tr_torrent_t * tor = io->tor;
485
+ tr_info_t * inf = &tor->info;
486
+
487
+ uint64_t offset = (uint64_t) slot * (uint64_t) inf->pieceSize;
488
+
489
+ *size = 0;
490
+ if( slot == inf->pieceCount - 1 )
491
+ {
492
+ *size = inf->totalSize % inf->pieceSize;
493
+ }
494
+ if( !*size )
495
+ {
496
+ *size = inf->pieceSize;
497
+ }
498
+
499
+ return readOrWriteBytes( io, offset, *size, buf, write );
500
+ }
501
+
502
+ static void invertSlots( tr_io_t * io, int slot1, int slot2 )
503
+ {
504
+ tr_torrent_t * tor = io->tor;
505
+ tr_info_t * inf = &tor->info;
506
+
507
+ uint8_t * buf1, * buf2;
508
+ int piece1, piece2, foo;
509
+
510
+ buf1 = calloc( inf->pieceSize, 1 );
511
+ buf2 = calloc( inf->pieceSize, 1 );
512
+
513
+ readSlot( io, slot1, buf1, &foo );
514
+ readSlot( io, slot2, buf2, &foo );
515
+
516
+ writeSlot( io, slot1, buf2, &foo );
517
+ writeSlot( io, slot2, buf1, &foo );
518
+
519
+ free( buf1 );
520
+ free( buf2 );
521
+
522
+ piece1 = io->slotPiece[slot1];
523
+ piece2 = io->slotPiece[slot2];
524
+ io->slotPiece[slot1] = piece2;
525
+ io->slotPiece[slot2] = piece1;
526
+ if( piece1 >= 0 )
527
+ {
528
+ io->pieceSlot[piece1] = slot2;
529
+ }
530
+ if( piece2 >= 0 )
531
+ {
532
+ io->pieceSlot[piece2] = slot1;
533
+ }
534
+ }
535
+
536
+ static void reorderPieces( tr_io_t * io )
537
+ {
538
+ tr_torrent_t * tor = io->tor;
539
+ tr_info_t * inf = &tor->info;
540
+
541
+ int i, didInvert;
542
+
543
+ /* Try to move pieces to their final places */
544
+ do
545
+ {
546
+ didInvert = 0;
547
+
548
+ for( i = 0; i < inf->pieceCount; i++ )
549
+ {
550
+ if( io->pieceSlot[i] < 0 )
551
+ {
552
+ /* We haven't started this piece yet */
553
+ continue;
554
+ }
555
+ if( io->pieceSlot[i] == i )
556
+ {
557
+ /* Already in place */
558
+ continue;
559
+ }
560
+ if( i >= io->slotsUsed )
561
+ {
562
+ /* File is not big enough yet */
563
+ continue;
564
+ }
565
+
566
+ /* Move piece i into slot i */
567
+ tr_inf( "invert %d and %d", io->pieceSlot[i], i );
568
+ invertSlots( io, i, io->pieceSlot[i] );
569
+ didInvert = 1;
570
+ }
571
+ } while( didInvert );
572
+ }
573
+
574
+ static void findSlotForPiece( tr_io_t * io, int piece )
575
+ {
576
+ int i;
577
+ #if 0
578
+ tr_torrent_t * tor = io->tor;
579
+ tr_info_t * inf = &tor->info;
580
+
581
+ tr_dbg( "Entering findSlotForPiece" );
582
+
583
+ for( i = 0; i < inf->pieceCount; i++ )
584
+ printf( "%02d ", io->slotPiece[i] );
585
+ printf( "\n" );
586
+ for( i = 0; i < inf->pieceCount; i++ )
587
+ printf( "%02d ", io->pieceSlot[i] );
588
+ printf( "\n" );
589
+ #endif
590
+
591
+ /* Look for an empty slot somewhere */
592
+ for( i = 0; i < io->slotsUsed; i++ )
593
+ {
594
+ if( io->slotPiece[i] < 0 )
595
+ {
596
+ io->pieceSlot[piece] = i;
597
+ io->slotPiece[i] = piece;
598
+ goto reorder;
599
+ }
600
+ }
601
+
602
+ /* No empty slot, extend the file */
603
+ io->pieceSlot[piece] = io->slotsUsed;
604
+ io->slotPiece[io->slotsUsed] = piece;
605
+ (io->slotsUsed)++;
606
+
607
+ reorder:
608
+ reorderPieces( io );
609
+
610
+ #if 0
611
+ for( i = 0; i < inf->pieceCount; i++ )
612
+ printf( "%02d ", io->slotPiece[i] );
613
+ printf( "\n" );
614
+ for( i = 0; i < inf->pieceCount; i++ )
615
+ printf( "%02d ", io->pieceSlot[i] );
616
+ printf( "\n" );
617
+
618
+ printf( "Leaving findSlotForPiece\n" );
619
+ #endif
620
+ }