#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifdef SYS_DARWIN
+#include <fcntl.h>
+#endif
#include <sys/types.h>
#include <sys/stat.h>
****
***/
+static int
+preallocateFile( int fd UNUSED, uint64_t length UNUSED )
+{
+#ifdef HAVE_FALLOCATE
+
+ return fallocate( fd, 0, offset, length );
+
+#elif defined(HAVE_POSIX_FALLOCATE)
+
+ return posix_fallocate( fd, 0, length );
+
+#elif defined(SYS_DARWIN)
+
+ fstore_t fst;
+ fst.fst_flags = F_ALLOCATECONTIG;
+ fst.fst_posmode = F_PEOFPOSMODE;
+ fst.fst_offset = 0;
+ fst.fst_length = length;
+ fst.fst_bytesalloc = 0;
+ return fcntl( fd, F_PREALLOCATE, &fst );
+
+#else
+
+ #warning no known method to preallocate files on this platform
+ return -1;
+
+#endif
+}
+
/**
* returns 0 on success, or an errno value on failure.
* errno values include ENOENT if the parent folder doesn't exist,
TrOpenFile( int i,
const char * folder,
const char * torrentFile,
- int write )
+ int doWrite,
+ int doPreallocate,
+ uint64_t desiredFileSize )
{
struct tr_openfile * file = &gFd->open[i];
int flags;
char * filename;
struct stat sb;
+ int alreadyExisted;
/* confirm the parent folder exists */
if( stat( folder, &sb ) || !S_ISDIR( sb.st_mode ) )
/* create subfolders, if any */
filename = tr_buildPath( folder, torrentFile, NULL );
- if( write )
+ if( doWrite )
{
char * tmp = tr_dirname( filename );
const int err = tr_mkdirp( tmp, 0777 ) ? errno : 0;
}
}
+ alreadyExisted = !stat( filename, &sb ) && S_ISREG( sb.st_mode );
+
/* open the file */
- flags = write ? ( O_RDWR | O_CREAT ) : O_RDONLY;
+ flags = doWrite ? ( O_RDWR | O_CREAT ) : O_RDONLY;
#ifdef O_LARGEFILE
flags |= O_LARGEFILE;
#endif
return err;
}
+ if( ( file->fd >= 0 ) && !alreadyExisted && doPreallocate )
+ if( !preallocateFile( file->fd, desiredFileSize ) )
+ tr_inf( _( "Preallocated file \"%s\"" ), filename );
+
tr_free( filename );
return 0;
}
int
tr_fdFileCheckout( const char * folder,
const char * torrentFile,
- int write )
+ int doWrite,
+ int doPreallocate,
+ uint64_t desiredFileSize )
{
int i, winner = -1;
struct tr_openfile * o;
assert( folder && *folder );
assert( torrentFile && *torrentFile );
- assert( write == 0 || write == 1 );
+ assert( doWrite == 0 || doWrite == 1 );
filename = tr_buildPath( folder, torrentFile, NULL );
dbgmsg( "looking for file '%s', writable %c", filename,
- write ? 'y' : 'n' );
+ doWrite ? 'y' : 'n' );
tr_lockLock( gFd->lock );
continue;
}
- if( write && !o->isWritable )
+ if( doWrite && !o->isWritable )
{
dbgmsg(
"found it! it's open and available, but isn't writable. closing..." );
o = &gFd->open[winner];
if( !fileIsOpen( o ) )
{
- const int err = TrOpenFile( winner, folder, torrentFile, write );
+ const int err = TrOpenFile( winner, folder, torrentFile, doWrite, doPreallocate, desiredFileSize );
if( err ) {
tr_lockUnlock( gFd->lock );
tr_free( filename );
return -1;
}
- dbgmsg( "opened '%s' in slot %d, write %c", filename, winner,
- write ? 'y' : 'n' );
+ dbgmsg( "opened '%s' in slot %d, doWrite %c", filename, winner,
+ doWrite ? 'y' : 'n' );
tr_strlcpy( o->filename, filename, sizeof( o->filename ) );
- o->isWritable = write;
+ o->isWritable = doWrite;
}
dbgmsg( "checking out '%s' in slot %d", filename, winner );
if( ( ioMode == TR_IO_READ ) && !fileExists ) /* does file exist? */
err = errno;
- else if( ( fd = tr_fdFileCheckout ( tor->downloadDir,
- file->name,
- ioMode == TR_IO_WRITE ) ) < 0 )
+ else if( ( fd = tr_fdFileCheckout ( tor->downloadDir, file->name, ioMode == TR_IO_WRITE, !file->dnd, file->length ) ) < 0 )
err = errno;
else if( lseek( fd, (off_t)fileOffset, SEEK_SET ) == ( (off_t)-1 ) )
err = errno;
assert( 0 <= fileIndex && fileIndex < tor->info.fileCount );
assert( minBytes <= file->length );
- fd = tr_fdFileCheckout( tor->downloadDir, file->name, TRUE );
+ fd = tr_fdFileCheckout( tor->downloadDir,
+ file->name,
+ TRUE,
+ tor->session->doPreallocateFiles && !file->dnd,
+ file->length );
+
if( fd < 0 ) /* bad fd */
err = errno;
else if( fstat ( fd, &sb ) ) /* how big is the file? */