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,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
+ }