1
/******************************************************************************
2
* $Id: inout.c 346 2006-06-13 00:28:03Z titer $
4
* Copyright (c) 2005-2006 Transmission authors and contributors
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:
13
* The above copyright notice and this permission notice shall be included in
14
* all copies or substantial portions of the Software.
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
*****************************************************************************/
25
#include "transmission.h"
32
-1 = we haven't started to download this piece yet
33
n = we have started or completed the piece in slot n */
44
#include "fastresume.h"
46
/***********************************************************************
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 );
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)
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)
63
/***********************************************************************
65
***********************************************************************
66
* Try to load the fast resume file
67
**********************************************************************/
68
void tr_ioLoadResume( tr_torrent_t * tor )
71
tr_info_t * inf = &tor->info;
73
io = malloc( sizeof( tr_io_t ) );
76
io->pieceSlot = malloc( inf->pieceCount * sizeof( int ) );
77
io->slotPiece = malloc( inf->pieceCount * sizeof( int ) );
81
free( io->pieceSlot );
82
free( io->slotPiece );
86
/***********************************************************************
88
***********************************************************************
89
* Open all files we are going to write to
90
**********************************************************************/
91
tr_io_t * tr_ioInit( tr_torrent_t * tor )
95
io = malloc( sizeof( tr_io_t ) );
98
if( createFiles( io ) || checkFiles( io ) )
107
/***********************************************************************
109
***********************************************************************
111
**********************************************************************/
112
int tr_ioRead( tr_io_t * io, int index, int begin, int length,
116
tr_info_t * inf = &io->tor->info;
118
offset = (uint64_t) io->pieceSlot[index] *
119
(uint64_t) inf->pieceSize + (uint64_t) begin;
121
return readBytes( io, offset, length, buf );
124
/***********************************************************************
126
***********************************************************************
128
**********************************************************************/
129
int tr_ioWrite( tr_io_t * io, int index, int begin, int length,
132
tr_torrent_t * tor = io->tor;
133
tr_info_t * inf = &io->tor->info;
136
uint8_t hash[SHA_DIGEST_LENGTH];
139
int startBlock, endBlock;
141
if( io->pieceSlot[index] < 0 )
143
findSlotForPiece( io, index );
144
tr_inf( "Piece %d: starting in slot %d", index,
145
io->pieceSlot[index] );
148
offset = (uint64_t) io->pieceSlot[index] *
149
(uint64_t) inf->pieceSize + (uint64_t) begin;
151
if( writeBytes( io, offset, length, buf ) )
156
startBlock = tr_pieceStartBlock( index );
157
endBlock = startBlock + tr_pieceCountBlocks( index );
158
for( i = startBlock; i < endBlock; i++ )
160
if( !tr_cpBlockIsComplete( tor->completion, i ) )
162
/* The piece is not complete */
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 );
175
hashFailed = memcmp( hash, &inf->pieces[20*index], SHA_DIGEST_LENGTH );
178
tr_inf( "Piece %d (slot %d): hash FAILED", index,
179
io->pieceSlot[index] );
181
/* We will need to reload the whole piece */
182
for( i = startBlock; i < endBlock; i++ )
184
tr_cpBlockRem( tor->completion, i );
189
tr_inf( "Piece %d (slot %d): hash OK", index,
190
io->pieceSlot[index] );
191
tr_cpPieceAdd( tor->completion, index );
194
/* Assign blame or credit to peers */
195
for( i = 0; i < tor->peerCount; i++ )
197
tr_peerBlame( tor, tor->peers[i], index, !hashFailed );
203
void tr_ioClose( tr_io_t * io )
207
fastResumeSave( io );
209
free( io->pieceSlot );
210
free( io->slotPiece );
214
void tr_ioSaveResume( tr_io_t * io )
216
fastResumeSave( io );
219
/***********************************************************************
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 )
227
tr_torrent_t * tor = io->tor;
228
tr_info_t * inf = &tor->info;
235
tr_dbg( "Creating files..." );
237
for( i = 0; i < inf->fileCount; i++ )
239
asprintf( &path, "%s/%s", tor->destination, inf->files[i].name );
242
if( NULL != ( p = strrchr( path, '/' ) ) )
245
if( tr_mkdir( path ) )
253
if( stat( path, &sb ) )
255
/* File doesn't exist yet */
256
if( ( file = open( path, O_WRONLY|O_CREAT|O_TRUNC, 0666 ) ) < 0 )
258
tr_err( "Could not create `%s' (%s)", path,
265
else if( ( sb.st_mode & S_IFMT ) != S_IFREG )
267
/* Node exists but isn't a file */
268
printf( "Remove %s, it's in the way.\n", path );
279
/***********************************************************************
281
***********************************************************************
283
**********************************************************************/
284
static int checkFiles( tr_io_t * io )
286
tr_torrent_t * tor = io->tor;
287
tr_info_t * inf = &tor->info;
291
uint8_t hash[SHA_DIGEST_LENGTH];
293
io->pieceSlot = malloc( inf->pieceCount * sizeof( int ) );
294
io->slotPiece = malloc( inf->pieceCount * sizeof( int ) );
296
if( !fastResumeLoad( io ) )
301
tr_dbg( "Checking pieces..." );
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 ) );
309
buf = malloc( inf->pieceSize );
310
for( i = 0; i < inf->pieceCount; i++ )
314
if( readSlot( io, i, buf, &size ) )
319
io->slotsUsed = i + 1;
320
SHA1( buf, size, hash );
322
for( j = i; j < inf->pieceCount - 1; j++ )
324
if( !memcmp( hash, &inf->pieces[20*j], SHA_DIGEST_LENGTH ) )
326
io->pieceSlot[j] = i;
327
io->slotPiece[i] = j;
329
tr_cpPieceAdd( tor->completion, j );
334
if( io->slotPiece[i] > -1 )
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 ) )
344
io->pieceSlot[inf->pieceCount - 1] = i;
345
io->slotPiece[i] = inf->pieceCount - 1;
347
tr_cpPieceAdd( tor->completion, inf->pieceCount - 1 );
355
/***********************************************************************
357
**********************************************************************/
358
static void closeFiles( tr_io_t * io )
360
tr_torrent_t * tor = io->tor;
361
tr_info_t * inf = &tor->info;
366
for( i = 0; i < inf->fileCount; i++ )
368
asprintf( &path, "%s/%s", tor->destination, inf->files[i].name );
369
tr_fdFileClose( tor->fdlimit, path );
374
/***********************************************************************
376
***********************************************************************
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 )
383
tr_torrent_t * tor = io->tor;
384
tr_info_t * inf = &tor->info;
386
int piece = offset / inf->pieceSize;
387
int begin = offset % inf->pieceSize;
392
iofunc readOrWrite = isWrite ? (iofunc) write : (iofunc) read;
394
/* Release the torrent lock so the UI can still update itself if
395
this blocks for a while */
396
tr_lockUnlock( &tor->lock );
398
/* We don't ever read or write more than a piece at a time */
399
if( tr_pieceSize( piece ) < begin + size )
401
tr_err( "readOrWriteBytes: trying to write more than a piece" );
405
/* Find which file we shall start reading/writing in */
406
for( i = 0; i < inf->fileCount; i++ )
408
if( offset < inf->files[i].length )
410
/* This is the file */
413
offset -= inf->files[i].length;
415
if( i >= inf->fileCount )
417
/* Should not happen */
418
tr_err( "readOrWriteBytes: offset out of range (%lld, %d, %d)",
419
offset, size, write );
425
/* How much can we put or take with this file */
426
if( inf->files[i].length < offset + size )
428
cur = (int) ( inf->files[i].length - offset );
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 );
440
tr_err( "readOrWriteBytes: could not open file '%s'", path );
446
/* seek to the right offset... */
447
if( lseek( file, offset, SEEK_SET ) < 0 )
452
/* do what we are here to do... */
453
if( readOrWrite( file, buf, cur ) != cur )
458
/* and close the stream. */
459
tr_fdFileRelease( tor->fdlimit, file );
461
/* 'cur' bytes done, 'size - cur' bytes to go with the next file */
468
tr_lockLock( &tor->lock );
472
tr_lockLock( &tor->lock );
476
/***********************************************************************
478
***********************************************************************
480
**********************************************************************/
481
static int readOrWriteSlot( tr_io_t * io, int slot, uint8_t * buf,
482
int * size, int write )
484
tr_torrent_t * tor = io->tor;
485
tr_info_t * inf = &tor->info;
487
uint64_t offset = (uint64_t) slot * (uint64_t) inf->pieceSize;
490
if( slot == inf->pieceCount - 1 )
492
*size = inf->totalSize % inf->pieceSize;
496
*size = inf->pieceSize;
499
return readOrWriteBytes( io, offset, *size, buf, write );
502
static void invertSlots( tr_io_t * io, int slot1, int slot2 )
504
tr_torrent_t * tor = io->tor;
505
tr_info_t * inf = &tor->info;
507
uint8_t * buf1, * buf2;
508
int piece1, piece2, foo;
510
buf1 = calloc( inf->pieceSize, 1 );
511
buf2 = calloc( inf->pieceSize, 1 );
513
readSlot( io, slot1, buf1, &foo );
514
readSlot( io, slot2, buf2, &foo );
516
writeSlot( io, slot1, buf2, &foo );
517
writeSlot( io, slot2, buf1, &foo );
522
piece1 = io->slotPiece[slot1];
523
piece2 = io->slotPiece[slot2];
524
io->slotPiece[slot1] = piece2;
525
io->slotPiece[slot2] = piece1;
528
io->pieceSlot[piece1] = slot2;
532
io->pieceSlot[piece2] = slot1;
536
static void reorderPieces( tr_io_t * io )
538
tr_torrent_t * tor = io->tor;
539
tr_info_t * inf = &tor->info;
543
/* Try to move pieces to their final places */
548
for( i = 0; i < inf->pieceCount; i++ )
550
if( io->pieceSlot[i] < 0 )
552
/* We haven't started this piece yet */
555
if( io->pieceSlot[i] == i )
557
/* Already in place */
560
if( i >= io->slotsUsed )
562
/* File is not big enough yet */
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] );
571
} while( didInvert );
574
static void findSlotForPiece( tr_io_t * io, int piece )
578
tr_torrent_t * tor = io->tor;
579
tr_info_t * inf = &tor->info;
581
tr_dbg( "Entering findSlotForPiece" );
583
for( i = 0; i < inf->pieceCount; i++ )
584
printf( "%02d ", io->slotPiece[i] );
586
for( i = 0; i < inf->pieceCount; i++ )
587
printf( "%02d ", io->pieceSlot[i] );
591
/* Look for an empty slot somewhere */
592
for( i = 0; i < io->slotsUsed; i++ )
594
if( io->slotPiece[i] < 0 )
596
io->pieceSlot[piece] = i;
597
io->slotPiece[i] = piece;
602
/* No empty slot, extend the file */
603
io->pieceSlot[piece] = io->slotsUsed;
604
io->slotPiece[io->slotsUsed] = piece;
611
for( i = 0; i < inf->pieceCount; i++ )
612
printf( "%02d ", io->slotPiece[i] );
614
for( i = 0; i < inf->pieceCount; i++ )
615
printf( "%02d ", io->pieceSlot[i] );
618
printf( "Leaving findSlotForPiece\n" );