fix ticket #451 (Files remain in use after removal)

This commit is contained in:
Charles Kerr 2007-11-21 16:16:59 +00:00
parent a7671a3afc
commit 260033847f
4 changed files with 91 additions and 30 deletions

View File

@ -97,6 +97,7 @@ struct tr_openfile
{
unsigned int isCheckedOut : 1;
unsigned int isWritable : 1;
unsigned int closeWhenDone : 1;
char filename[MAX_PATH_LENGTH];
int fd;
uint64_t date;
@ -189,7 +190,7 @@ fileIsCheckedOut( const struct tr_openfile * o )
}
int
tr_fdFileOpen( const char * filename, int write )
tr_fdFileCheckout( const char * filename, int write )
{
int i, winner;
struct tr_openfile * o;
@ -282,24 +283,55 @@ done:
dbgmsg( "checking out '%s' in slot %d", filename, winner );
o->isCheckedOut = 1;
o->closeWhenDone = 0;
o->date = tr_date( );
tr_lockUnlock( gFd->lock );
return o->fd;
}
void
tr_fdFileRelease( int file )
tr_fdFileReturn( int fd )
{
int i;
tr_lockLock( gFd->lock );
for( i=0; i<TR_MAX_OPEN_FILES; ++i ) {
for( i=0; i<TR_MAX_OPEN_FILES; ++i )
{
struct tr_openfile * o = &gFd->open[i];
if( o->fd == file ) {
dbgmsg( "releasing file '%s' in slot #%d", o->filename, i );
/* fsync( o->fd ); */
o->isCheckedOut = 0;
break;
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_condSignal( gFd->cond );
tr_lockUnlock( gFd->lock );
}
void
tr_fdFileClose( const char * filename )
{
int i;
tr_lockLock( gFd->lock );
dbgmsg( "tr_fdFileClose closing '%s'", filename );
for( i=0; i<TR_MAX_OPEN_FILES; ++i )
{
struct tr_openfile * o = &gFd->open[i];
if( !fileIsOpen(o) || strcmp(filename,o->filename) )
continue;
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;
}
}

View File

@ -33,25 +33,43 @@ void tr_fdInit( void );
void tr_fdClose( void );
/***********************************************************************
* tr_fdFileOpen
***********************************************************************
* If it isn't open already, tries to open the file 'name' in the
* directory 'folder'. If 'name' itself contains '/'s, required
* subfolders are created. The file is open read-write if 'write' is 1
* (created if necessary), read-only if 0.
* Returns the file descriptor if successful, otherwise returns
* one of the TR_ERROR_IO_*.
**********************************************************************/
int tr_fdFileOpen( const char * filename, int write );
/**
* Returns an fd to the specified filename.
*
* A small repository of open files is kept to avoid the overhead of continually
* opening and closing the same files when writing piece data during download.
* It's also used to ensure that only one client uses the file at a time.
* Clients must check out a file to use it, then return it, like a library, when done.
*
* if write is nonzero and dirname(filename) doesn't exist, dirname is created.
* if write is nonzero and filename doesn't exist, filename is created.
* returns the fd if successful; otherwise, one of TR_ERROR_IO_*
*
* @see tr_fdFileReturn
* @see tr_fdFileClose
*/
int tr_fdFileCheckout( const char * filename, int write );
/**
* Returns an fd from tr_fdFileCheckout() so that other clients may borrow it.
*
* @see tr_fdFileCheckout
* @see tr_fdFileClose
*/
void tr_fdFileReturn( int file );
/**
* Closes a file that's being held by our file repository.
*
* If the file isn't checked out, it's closed immediately.
* If the file is currently checked out, it will be closed upon its return.
*
* @see tr_fdFileCheckout
* @see tr_fdFileReturn
*/
void tr_fdFileClose( const char * filename );
/***********************************************************************
* tr_fdFileRelease
***********************************************************************
* Indicates that the file whose descriptor is 'file' is unused at the
* moment and can safely be closed.
**********************************************************************/
void tr_fdFileRelease( int file );
/***********************************************************************
* Sockets

View File

@ -66,7 +66,7 @@ readOrWriteBytes( const tr_torrent * tor,
return 0;
else if ((ioMode==TR_IO_READ) && stat( path, &sb ) ) /* does file exist? */
ret = tr_ioErrorFromErrno ();
else if ((fd = tr_fdFileOpen ( path, ioMode==TR_IO_WRITE )) < 0)
else if ((fd = tr_fdFileCheckout ( path, ioMode==TR_IO_WRITE )) < 0)
ret = fd;
else if( lseek( fd, (off_t)fileOffset, SEEK_SET ) == ((off_t)-1) )
ret = TR_ERROR_IO_OTHER;
@ -76,7 +76,7 @@ readOrWriteBytes( const tr_torrent * tor,
ret = TR_OK;
if( fd >= 0 )
tr_fdFileRelease( fd );
tr_fdFileReturn( fd );
return ret;
}
@ -125,7 +125,7 @@ ensureMinimumFileSize( const tr_torrent * tor,
tr_buildPath( path, sizeof(path), tor->destination, file->name, NULL );
fd = tr_fdFileOpen( path, TRUE );
fd = tr_fdFileCheckout( path, TRUE );
if( fd < 0 ) /* bad fd */
ret = fd;
else if (fstat (fd, &sb) ) /* how big is the file? */
@ -138,7 +138,7 @@ ensureMinimumFileSize( const tr_torrent * tor,
ret = tr_ioErrorFromErrno ();
if( fd >= 0 )
tr_fdFileRelease( fd );
tr_fdFileReturn( fd );
return ret;
}

View File

@ -33,6 +33,7 @@
#include "completion.h"
#include "crypto.h" /* for tr_sha1 */
#include "fastresume.h"
#include "fdlimit.h" /* tr_fdFileClose */
#include "handshake.h"
#include "inout.h"
#include "metainfo.h"
@ -1077,10 +1078,20 @@ tr_torrentRecheck( tr_torrent * tor )
static void
stopTorrent( void * vtor )
{
int i;
tr_torrent * tor = vtor;
tr_ioRecheckRemove( tor );
tr_peerMgrStopTorrent( tor->handle->peerMgr, tor->info.hash );
tr_trackerStop( tor->tracker );
for( i=0; i<tor->info.fileCount; ++i )
{
char path[MAX_PATH_LENGTH];
const tr_file * file = &tor->info.files[i];
tr_buildPath( path, sizeof(path), tor->destination, file->name, NULL );
tr_fdFileClose( path );
}
}
void