void tr_fdFileClose( const char * filename ) { int i; tr_lockLock( gFd->lock ); for( i = 0; i < TR_MAX_OPEN_FILES; ++i ) { struct tr_openfile * o = &gFd->open[i]; if( !fileIsOpen( o ) || strcmp( filename, o->filename ) ) continue; dbgmsg( "tr_fdFileClose closing '%s'", filename ); if( !o->isCheckedOut ) { dbgmsg( "not checked out, so closing it now... '%s'", filename ); TrCloseFile( i ); } else { dbgmsg( "flagging file '%s', slot #%d to be closed when checked in", gFd->open[i].filename, i ); o->closeWhenDone = 1; } } tr_lockUnlock( gFd->lock ); }
void tr_fdSetFileLimit( tr_session * session, int limit ) { struct tr_fdInfo * gFd; ensureSessionFdInfoExists( session ); gFd = session->fdInfo; if( gFd->openFileLimit != limit ) { int i; struct tr_openfile * o; const struct tr_openfile * end; /* close any files we've got open */ for( o=gFd->openFiles, end=o+gFd->openFileLimit; o!=end; ++o ) if( fileIsOpen( o ) ) TrCloseFile( o ); /* rebuild the openFiles array */ tr_free( gFd->openFiles ); gFd->openFiles = tr_new0( struct tr_openfile, limit ); gFd->openFileLimit = limit; for( i=0; i<gFd->openFileLimit; ++i ) gFd->openFiles[i].fd = -1; }
void tr_fdFileClose( tr_session * session, const tr_torrent * tor, tr_file_index_t fileNum ) { struct tr_openfile * o; struct tr_fdInfo * gFd; const struct tr_openfile * end; const int torrentId = tr_torrentId( tor ); assert( tr_isSession( session ) ); assert( session->fdInfo != NULL ); assert( tr_isTorrent( tor ) ); assert( fileNum < tor->info.fileCount ); gFd = session->fdInfo; for( o=gFd->openFiles, end=o+gFd->openFileLimit; o!=end; ++o ) { if( torrentId != o->torrentId ) continue; if( fileNum != o->fileNum ) continue; if( !fileIsOpen( o ) ) continue; dbgmsg( "tr_fdFileClose closing \"%s\"", o->filename ); TrCloseFile( o ); } }
void tr_fdClose( void ) { int i = 0; for( i = 0; i < TR_MAX_OPEN_FILES; ++i ) if( fileIsOpen( &gFd->open[i] ) ) TrCloseFile( i ); tr_lockFree( gFd->lock ); tr_free( gFd ); gFd = NULL; }
void tr_fdTorrentClose( tr_session * session, int torrentId ) { assert( tr_isSession( session ) ); if( session->fdInfo != NULL ) { struct tr_openfile * o; const struct tr_openfile * end; struct tr_fdInfo * gFd = session->fdInfo; for( o=gFd->openFiles, end=o+gFd->openFileLimit; o!=end; ++o ) if( fileIsOpen( o ) && ( o->torrentId == torrentId ) ) TrCloseFile( o ); } }
void tr_fdClose( tr_session * session ) { struct tr_fdInfo * gFd; struct tr_openfile * o; const struct tr_openfile * end; assert( tr_isSession( session ) ); assert( session->fdInfo != NULL ); gFd = session->fdInfo; for( o=gFd->openFiles, end=o+gFd->openFileLimit; o!=end; ++o ) if( fileIsOpen( o ) ) TrCloseFile( o ); tr_free( gFd->openFiles ); tr_free( gFd ); session->fdInfo = NULL; }
void tr_fdFileReturn( int fd ) { int i; tr_lockLock( gFd->lock ); for( i = 0; i < TR_MAX_OPEN_FILES; ++i ) { struct tr_openfile * o = &gFd->open[i]; if( o->fd != fd ) continue; dbgmsg( "releasing file '%s' in slot #%d", o->filename, i ); o->isCheckedOut = 0; if( o->closeWhenDone ) TrCloseFile( i ); break; } tr_lockUnlock( gFd->lock ); }
/* returns an fd on success, or a -1 on failure and sets errno */ int tr_fdFileCheckout( const char * folder, const char * torrentFile, int doWrite, int doPreallocate, uint64_t desiredFileSize ) { int i, winner = -1; struct tr_openfile * o; char * filename; assert( folder && *folder ); assert( torrentFile && *torrentFile ); assert( doWrite == 0 || doWrite == 1 ); filename = tr_buildPath( folder, torrentFile, NULL ); dbgmsg( "looking for file '%s', writable %c", filename, doWrite ? 'y' : 'n' ); tr_lockLock( gFd->lock ); /* Is it already open? */ for( i = 0; i < TR_MAX_OPEN_FILES; ++i ) { o = &gFd->open[i]; if( !fileIsOpen( o ) ) continue; if( strcmp( filename, o->filename ) ) continue; if( fileIsCheckedOut( o ) ) { dbgmsg( "found it! it's open, but checked out. waiting..." ); tr_lockUnlock( gFd->lock ); tr_wait( 200 ); tr_lockLock( gFd->lock ); i = -1; /* reloop */ continue; } if( doWrite && !o->isWritable ) { dbgmsg( "found it! it's open and available, but isn't writable. closing..." ); TrCloseFile( i ); break; } dbgmsg( "found it! it's ready for use!" ); winner = i; break; } dbgmsg( "it's not already open. looking for an open slot or an old file." ); while( winner < 0 ) { uint64_t date = tr_date( ) + 1; /* look for the file that's been open longest */ for( i = 0; i < TR_MAX_OPEN_FILES; ++i ) { o = &gFd->open[i]; if( !fileIsOpen( o ) ) { winner = i; dbgmsg( "found an empty slot in %d", winner ); break; } if( date > o->date ) { date = o->date; winner = i; } } if( winner >= 0 ) { if( fileIsOpen( &gFd->open[winner] ) ) { dbgmsg( "closing file '%s', slot #%d", gFd->open[winner].filename, winner ); TrCloseFile( winner ); } } else { dbgmsg( "everything's full! waiting for someone else to finish something" ); tr_lockUnlock( gFd->lock ); tr_wait( 200 ); tr_lockLock( gFd->lock ); } } assert( winner >= 0 ); o = &gFd->open[winner]; if( !fileIsOpen( o ) ) { const int err = TrOpenFile( winner, folder, torrentFile, doWrite, doPreallocate, desiredFileSize ); if( err ) { tr_lockUnlock( gFd->lock ); tr_free( filename ); errno = err; return -1; } dbgmsg( "opened '%s' in slot %d, doWrite %c", filename, winner, doWrite ? 'y' : 'n' ); tr_strlcpy( o->filename, filename, sizeof( o->filename ) ); o->isWritable = doWrite; } dbgmsg( "checking out '%s' in slot %d", filename, winner ); o->isCheckedOut = 1; o->closeWhenDone = 0; o->date = tr_date( ); tr_free( filename ); tr_lockUnlock( gFd->lock ); return o->fd; }
/* returns an fd on success, or a -1 on failure and sets errno */ int tr_fdFileCheckout( tr_session * session, int torrentId, tr_file_index_t fileNum, const char * filename, tr_bool doWrite, tr_preallocation_mode preallocationMode, uint64_t desiredFileSize ) { int i, winner = -1; struct tr_fdInfo * gFd; struct tr_openfile * o; assert( tr_isSession( session ) ); assert( session->fdInfo != NULL ); assert( torrentId > 0 ); assert( filename && *filename ); assert( tr_isBool( doWrite ) ); gFd = session->fdInfo; dbgmsg( "looking for file '%s', writable %c", filename, doWrite ? 'y' : 'n' ); /* is it already open? */ for( i=0; i<gFd->openFileLimit; ++i ) { o = &gFd->openFiles[i]; if( torrentId != o->torrentId ) continue; if( fileNum != o->fileNum ) continue; if( !fileIsOpen( o ) ) continue; if( doWrite && !o->isWritable ) { dbgmsg( "found it! it's open and available, but isn't writable. closing..." ); TrCloseFile( o ); break; } dbgmsg( "found it! it's ready for use!" ); winner = i; break; } dbgmsg( "it's not already open. looking for an open slot or an old file." ); while( winner < 0 ) { time_t date = tr_time( ) + 1; /* look for the file that's been open longest */ for( i=0; i<gFd->openFileLimit; ++i ) { o = &gFd->openFiles[i]; if( !fileIsOpen( o ) ) { winner = i; dbgmsg( "found an empty slot in %d", winner ); break; } if( date > o->date ) { date = o->date; winner = i; } } assert( winner >= 0 ); if( fileIsOpen( &gFd->openFiles[winner] ) ) { dbgmsg( "closing file \"%s\"", gFd->openFiles[winner].filename ); TrCloseFile( &gFd->openFiles[winner] ); } } assert( winner >= 0 ); o = &gFd->openFiles[winner]; if( !fileIsOpen( o ) ) { const int err = TrOpenFile( session, winner, filename, doWrite, preallocationMode, desiredFileSize ); if( err ) { errno = err; return -1; } dbgmsg( "opened '%s' in slot %d, doWrite %c", filename, winner, doWrite ? 'y' : 'n' ); tr_strlcpy( o->filename, filename, sizeof( o->filename ) ); o->isWritable = doWrite; } dbgmsg( "checking out '%s' in slot %d", filename, winner ); o->torrentId = torrentId; o->fileNum = fileNum; o->date = tr_time( ); return o->fd; }