Ejemplo n.º 1
0
/* returns 0 on success, or an errno on failure */
static int
readOrWriteBytes (tr_session       * session,
                  tr_torrent       * tor,
                  int                ioMode,
                  tr_file_index_t    fileIndex,
                  uint64_t           fileOffset,
                  void             * buf,
                  size_t             buflen)
{
  int fd;
  int err = 0;
  const bool doWrite = ioMode >= TR_IO_WRITE;
  const tr_info * const info = &tor->info;
  const tr_file * const file = &info->files[fileIndex];

  assert (fileIndex < info->fileCount);
  assert (!file->length || (fileOffset < file->length));
  assert (fileOffset + buflen <= file->length);

  if (!file->length)
    return 0;

  /***
  ****  Find the fd
  ***/

  fd = tr_fdFileGetCached (session, tr_torrentId (tor), fileIndex, doWrite);
  if (fd < 0)
    {
      /* it's not cached, so open/create it now */
      char * subpath;
      const char * base;

      /* see if the file exists... */
      if (!tr_torrentFindFile2 (tor, fileIndex, &base, &subpath, NULL))
        {
          /* we can't read a file that doesn't exist... */
          if (!doWrite)
            err = ENOENT;

          /* figure out where the file should go, so we can create it */
          base = tr_torrentGetCurrentDir (tor);
          subpath = tr_sessionIsIncompleteFileNamingEnabled (tor->session)
                  ? tr_torrentBuildPartial (tor, fileIndex)
                  : tr_strdup (file->name);

        }

      if (!err)
        {
          /* open (and maybe create) the file */
          char * filename = tr_buildPath (base, subpath, NULL);
          const int prealloc = file->dnd || !doWrite
                             ? TR_PREALLOCATE_NONE
                             : tor->session->preallocationMode;
          if (((fd = tr_fdFileCheckout (session, tor->uniqueId, fileIndex,
                                        filename, doWrite,
                                        prealloc, file->length))) < 0)
            {
              err = errno;
              tr_torerr (tor, "tr_fdFileCheckout failed for \"%s\": %s",
                         filename, tr_strerror (err));
            }
          else if (doWrite)
            {
              /* make a note that we just created a file */
              tr_statsFileCreated (tor->session);
            }

          tr_free (filename);
        }

      tr_free (subpath);
    }

  /***
  ****  Use the fd
  ***/

  if (!err)
    {
      if (ioMode == TR_IO_READ)
        {
          const int rc = tr_pread (fd, buf, buflen, fileOffset);
          if (rc < 0)
            {
              err = errno;
              tr_torerr (tor, "read failed for \"%s\": %s", file->name, tr_strerror (err));
            }
        }
      else if (ioMode == TR_IO_WRITE)
        {
          const int rc = tr_pwrite (fd, buf, buflen, fileOffset);
          if (rc < 0)
            {
              err = errno;
              tr_torerr (tor, "write failed for \"%s\": %s", file->name, tr_strerror (err));
            }
        }
      else if (ioMode == TR_IO_PREFETCH)
        {
          tr_prefetch (fd, fileOffset, buflen);
        }
      else
        {
          abort ();
        }
    }

  return err;
}
Ejemplo n.º 2
0
/* returns 0 on success, or an errno on failure */
static int
readOrWriteBytes( tr_session       * session,
                  tr_torrent       * tor,
                  int                ioMode,
                  tr_file_index_t    fileIndex,
                  uint64_t           fileOffset,
                  void             * buf,
                  size_t             buflen )
{
    const tr_info * info = &tor->info;
    const tr_file * file = &info->files[fileIndex];

    int             fd = -1;
    int             err = 0;
    const tr_bool doWrite = ioMode >= TR_IO_WRITE;

//if( doWrite )
//    fprintf( stderr, "in file %s at offset %zu, writing %zu bytes; file length is %zu\n", file->name, (size_t)fileOffset, buflen, (size_t)file->length );

    assert( fileIndex < info->fileCount );
    assert( !file->length || ( fileOffset < file->length ) );
    assert( fileOffset + buflen <= file->length );

    if( !file->length )
        return 0;

    fd = tr_fdFileGetCached( session, tr_torrentId( tor ), fileIndex, doWrite );

    if( fd < 0 )
    {
        /* the fd cache doesn't have this file...
         * we'll need to open it and maybe create it */
        char * subpath;
        const char * base;
        tr_bool fileExists;
        tr_preallocation_mode preallocationMode;

        fileExists = tr_torrentFindFile2( tor, fileIndex, &base, &subpath );

        if( !fileExists )
        {
            base = tr_torrentGetCurrentDir( tor );

            if( tr_sessionIsIncompleteFileNamingEnabled( tor->session ) )
                subpath = tr_torrentBuildPartial( tor, fileIndex );
            else
                subpath = tr_strdup( file->name );
        }

        if( ( file->dnd ) || ( ioMode < TR_IO_WRITE ) )
            preallocationMode = TR_PREALLOCATE_NONE;
        else
            preallocationMode = tor->session->preallocationMode;

        if( ( ioMode < TR_IO_WRITE ) && !fileExists ) /* does file exist? */
        {
            err = ENOENT;
        }
        else
        {
            char * filename = tr_buildPath( base, subpath, NULL );

            if( ( fd = tr_fdFileCheckout( session, tor->uniqueId, fileIndex, filename,
                                          doWrite, preallocationMode, file->length ) ) < 0 )
            {
                err = errno;
                tr_torerr( tor, "tr_fdFileCheckout failed for \"%s\": %s", filename, tr_strerror( err ) );
            }

            tr_free( filename );
        }

        if( doWrite && !err )
            tr_statsFileCreated( tor->session );

        tr_free( subpath );
    }

    if( !err )
    {
        /* check & see if someone deleted the file while it was in our cache */
        struct stat sb;
        const tr_bool file_disappeared = fstat( fd, &sb ) || sb.st_nlink < 1;
        if( file_disappeared ) {
            tr_torrentSetLocalError( tor, "Please Verify Local Data! A file disappeared: \"%s\"", tor->info.files[fileIndex].name );
            err = ENOENT;
        }

        if( ioMode == TR_IO_READ ) {
            const int rc = tr_pread( fd, buf, buflen, fileOffset );
            if( rc < 0 ) {
                err = errno;
                tr_torerr( tor, "read failed for \"%s\": %s",
                           file->name, tr_strerror( err ) );
            }
        } else if( ioMode == TR_IO_PREFETCH ) {
            const int rc = tr_prefetch( fd, fileOffset, buflen );
            if( rc < 0 ) {
                /* (don't set "err" here... it's okay for prefetch to fail) */
                tr_tordbg( tor, "prefetch failed for \"%s\": %s",
                           file->name, tr_strerror( errno ) );
            }
        } else if( ioMode == TR_IO_WRITE ) {
            const int rc = tr_pwrite( fd, buf, buflen, fileOffset );
            if( rc < 0 ) {
                err = errno;
                tr_torerr( tor, "write failed for \"%s\": %s",
                           file->name, tr_strerror( err ) );
            }
        } else {
            abort();
        }
    }

    return err;
}