Пример #1
0
/**
 * returns 0 on success, or an errno value on failure.
 * errno values include ENOENT if the parent folder doesn't exist,
 * plus the errno values set by tr_mkdirp() and open().
 */
static int
TrOpenFile( int          i,
            const char * folder,
            const char * torrentFile,
            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 ) )
        return ENOENT;

    /* create subfolders, if any */
    filename = tr_buildPath( folder, torrentFile, NULL );
    if( doWrite )
    {
        char * tmp = tr_dirname( filename );
        const int err = tr_mkdirp( tmp, 0777 ) ? errno : 0;
        tr_free( tmp );
        if( err ) {
            tr_free( filename );
            return err;
        }
    }

    alreadyExisted = !stat( filename, &sb ) && S_ISREG( sb.st_mode );

    if( doWrite && !alreadyExisted && doPreallocate )
        if( preallocateFile( filename, desiredFileSize ) )
            tr_inf( _( "Preallocated file \"%s\"" ), filename );
    
    /* open the file */
    flags = doWrite ? ( O_RDWR | O_CREAT ) : O_RDONLY;
#ifdef O_LARGEFILE
    flags |= O_LARGEFILE;
#endif
#ifdef WIN32
    flags |= O_BINARY;
#endif
    file->fd = open( filename, flags, 0666 );
    if( file->fd == -1 )
    {
        const int err = errno;
        tr_err( _( "Couldn't open \"%1$s\": %2$s" ), filename,
               tr_strerror( err ) );
        tr_free( filename );
        return err;
    }

    tr_free( filename );
    return 0;
}
Пример #2
0
void
libttest_zero_torrent_populate (tr_torrent * tor, bool complete)
{
  tr_file_index_t i;

  for (i=0; i<tor->info.fileCount; ++i)
    {
      int err;
      uint64_t j;
      FILE * fp;
      char * path;
      char * dirname;
      const tr_file * file = &tor->info.files[i];
      struct stat sb;

      if (!complete && (i==0))
        path = tr_strdup_printf ("%s%c%s.part", tor->currentDir, TR_PATH_DELIMITER, file->name);
      else
        path = tr_strdup_printf ("%s%c%s", tor->currentDir, TR_PATH_DELIMITER, file->name);
      dirname = tr_dirname (path);
      tr_mkdirp (dirname, 0700);
      fp = fopen (path, "wb+");
      for (j=0; j<file->length; ++j)
        fputc (((!complete) && (i==0) && (j<tor->info.pieceSize)) ? '\1' : '\0', fp);
      fclose (fp);

      tr_free (dirname);
      tr_free (path);

      path = tr_torrentFindFile (tor, i);
      assert (path != NULL);
      err = errno;
      errno = 0;
      stat (path, &sb);
      assert (errno == 0);
      errno = err; 
      tr_free (path);
    }

  sync ();
  libttest_blockingTorrentVerify (tor);

  if (complete)
    assert (tr_torrentStat(tor)->leftUntilDone == 0);
  else
    assert (tr_torrentStat(tor)->leftUntilDone == tor->info.pieceSize);
}
Пример #3
0
static void
create_text_file (const char * path, const char * contents)
{
  FILE * fp;
  char * dir;

  dir = tr_dirname (path);
  tr_mkdirp (dir, 0700);
  tr_free (dir);

  tr_remove (path);
  fp = fopen (path, "w+");
  fprintf (fp, "%s", contents);
  fclose (fp);

  sync ();
}
Пример #4
0
/**
 * returns 0 on success, or an errno value on failure.
 * errno values include ENOENT if the parent folder doesn't exist,
 * plus the errno values set by tr_mkdirp () and open ().
 */
static int
cached_file_open (struct tr_cached_file  * o,
                  const char             * filename,
                  bool                     writable,
                  tr_preallocation_mode    allocation,
                  uint64_t                 file_size)
{
    int flags;
    struct stat sb;
    bool alreadyExisted;

    /* create subfolders, if any */
    if (writable)
    {
        char * dir = tr_dirname (filename);
        const int err = tr_mkdirp (dir, 0777) ? errno : 0;
        if (err) {
            tr_err (_("Couldn't create \"%1$s\": %2$s"), dir, tr_strerror (err));
            tr_free (dir);
            return err;
        }
        tr_free (dir);
    }

    alreadyExisted = !stat (filename, &sb) && S_ISREG (sb.st_mode);

    if (writable && !alreadyExisted && (allocation == TR_PREALLOCATE_FULL))
        if (preallocate_file_full (filename, file_size))
            tr_dbg ("Preallocated file \"%s\"", filename);

    /* open the file */
    flags = writable ? (O_RDWR | O_CREAT) : O_RDONLY;
    flags |= O_LARGEFILE | O_BINARY | O_SEQUENTIAL;
    o->fd = open (filename, flags, 0666);

    if (o->fd == -1)
    {
        const int err = errno;
        tr_err (_("Couldn't open \"%1$s\": %2$s"), filename, tr_strerror (err));
        return err;
    }

    /* If the file already exists and it's too large, truncate it.
     * This is a fringe case that happens if a torrent's been updated
     * and one of the updated torrent's files is smaller.
     * http://trac.transmissionbt.com/ticket/2228
     * https://bugs.launchpad.net/ubuntu/+source/transmission/+bug/318249
     */
    if (alreadyExisted && (file_size < (uint64_t)sb.st_size))
    {
        if (ftruncate (o->fd, file_size) == -1)
        {
            const int err = errno;
            tr_err (_("Couldn't truncate \"%1$s\": %2$s"), filename, tr_strerror (err));
            return err;
        }
    }

    if (writable && !alreadyExisted && (allocation == TR_PREALLOCATE_SPARSE))
        preallocate_file_sparse (o->fd, file_size);

    /* Many (most?) clients request blocks in ascending order,
     * so increase the readahead buffer.
     * Also, disable OS-level caching because "inactive memory" angers users. */
    tr_set_file_for_single_pass (o->fd);

    return 0;
}
Пример #5
0
/**
 * returns 0 on success, or an errno value on failure.
 * errno values include ENOENT if the parent folder doesn't exist,
 * plus the errno values set by tr_mkdirp() and open().
 */
static int
TrOpenFile( tr_session             * session,
            int                      i,
            const char             * filename,
            tr_bool                  doWrite,
            tr_preallocation_mode    preallocationMode,
            uint64_t                 desiredFileSize )
{
    int flags;
    struct stat sb;
    tr_bool alreadyExisted;
    struct tr_openfile * file;

    assert( tr_isSession( session ) );
    assert( session->fdInfo != NULL );

    file = &session->fdInfo->openFiles[i];

    /* create subfolders, if any */
    if( doWrite )
    {
        char * dir = tr_dirname( filename );
        const int err = tr_mkdirp( dir, 0777 ) ? errno : 0;
        if( err ) {
            tr_err( _( "Couldn't create \"%1$s\": %2$s" ), dir, tr_strerror( err ) );
            tr_free( dir );
            return err;
        }
        tr_free( dir );
    }

    alreadyExisted = !stat( filename, &sb ) && S_ISREG( sb.st_mode );

    if( doWrite && !alreadyExisted && ( preallocationMode == TR_PREALLOCATE_FULL ) )
        if( preallocateFileFull( filename, desiredFileSize ) )
            tr_dbg( _( "Preallocated file \"%s\"" ), filename );

    /* open the file */
    flags = doWrite ? ( O_RDWR | O_CREAT ) : O_RDONLY;
#ifdef O_SEQUENTIAL
    flags |= O_SEQUENTIAL;
#endif
#ifdef O_LARGEFILE
    flags |= O_LARGEFILE;
#endif
#ifdef WIN32
    flags |= O_BINARY;
#endif
    file->fd = open( filename, flags, 0666 );
    if( file->fd == -1 )
    {
        const int err = errno;
        tr_err( _( "Couldn't open \"%1$s\": %2$s" ), filename, tr_strerror( err ) );
        return err;
    }

    /* If the file already exists and it's too large, truncate it.
     * This is a fringe case that happens if a torrent's been updated
     * and one of the updated torrent's files is smaller.
     * http://trac.transmissionbt.com/ticket/2228
     * https://bugs.launchpad.net/ubuntu/+source/transmission/+bug/318249
     */
    if( alreadyExisted && ( desiredFileSize < (uint64_t)sb.st_size ) )
        ftruncate( file->fd, desiredFileSize );

    if( doWrite && !alreadyExisted && ( preallocationMode == TR_PREALLOCATE_SPARSE ) )
        preallocateFileSparse( file->fd, desiredFileSize );

#ifdef HAVE_POSIX_FADVISE
    /* this doubles the OS level readahead buffer, which in practice
     * turns out to be a good thing, because many (most?) clients request
     * chunks of blocks in order.
     * It's okay for this to fail silently, so don't let it affect errno */
    {
        const int err = errno;
        posix_fadvise( file->fd, 0, 0, POSIX_FADV_SEQUENTIAL );
        errno = err;
    }
#endif

#if defined( SYS_DARWIN )
    /**
     * 1. Enable readahead for reasons described above w/POSIX_FADV_SEQUENTIAL.
     *
     * 2. Disable OS-level caching due to user reports of adverse effects of
     *    excessive inactive memory.  However this is experimental because
     *    previous attempts at this have *also* had adverse effects (see r8198)
     *
     * It's okay for this to fail silently, so don't let it affect errno
     */
    {
        const int err = errno;
        fcntl( file->fd, F_NOCACHE, 1 );
        fcntl( file->fd, F_RDAHEAD, 1 );
        errno = err;
    }
#endif

    return 0;
}