(trunk, libt) #4160 - the slow slog to catch trunk up to mike.dld's 4160 diff continues. This step applies 4160-03b-file.patch, which replaces native file operations with the tr_sys_file_*() portability wrappers added in r14321.

This commit is contained in:
Jordan Lee
2014-07-28 04:13:38 +00:00
parent 2c0276fc23
commit b33a7d4dc1
15 changed files with 229 additions and 607 deletions

View File

@@ -9,6 +9,7 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> /* strlen () */
#include <unistd.h> /* sync() */ #include <unistd.h> /* sync() */
#include "transmission.h" #include "transmission.h"
@@ -36,17 +37,16 @@ static const char * contents2 =
static void static void
create_text_file (const char * path, const char * contents) create_text_file (const char * path, const char * contents)
{ {
FILE * fp; tr_sys_file_t fd;
char * dir; char * dir;
dir = tr_sys_path_dirname (path, NULL); dir = tr_sys_path_dirname (path, NULL);
tr_mkdirp (dir, 0700); tr_mkdirp (dir, 0700);
tr_free (dir); tr_free (dir);
tr_sys_path_remove (path, NULL); fd = tr_sys_file_open (path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0600, NULL);
fp = fopen (path, "w+"); tr_sys_file_write (fd, contents, strlen (contents), NULL, NULL);
fprintf (fp, "%s", contents); tr_sys_file_close (fd, NULL);
fclose (fp);
sync (); sync ();
} }

View File

@@ -13,32 +13,14 @@
#include <stdlib.h> /* bsearch (), qsort () */ #include <stdlib.h> /* bsearch (), qsort () */
#include <string.h> #include <string.h>
#include <unistd.h> /* close () */
#ifdef _WIN32
#include <w32api.h>
#define WINVER WindowsXP
#include <windows.h>
#define PROT_READ PAGE_READONLY
#define MAP_PRIVATE FILE_MAP_COPY
#endif
#ifndef _WIN32
#include <sys/mman.h>
#endif
#include <fcntl.h>
#include "transmission.h" #include "transmission.h"
#include "blocklist.h" #include "blocklist.h"
#include "error.h"
#include "file.h" #include "file.h"
#include "log.h" #include "log.h"
#include "net.h" #include "net.h"
#include "utils.h" #include "utils.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
/*** /***
**** PRIVATE **** PRIVATE
@@ -53,9 +35,9 @@ struct tr_ipv4_range
struct tr_blocklistFile struct tr_blocklistFile
{ {
bool isEnabled; bool isEnabled;
int fd; tr_sys_file_t fd;
size_t ruleCount; size_t ruleCount;
size_t byteCount; uint64_t byteCount;
char * filename; char * filename;
struct tr_ipv4_range * rules; struct tr_ipv4_range * rules;
}; };
@@ -65,22 +47,23 @@ blocklistClose (tr_blocklistFile * b)
{ {
if (b->rules != NULL) if (b->rules != NULL)
{ {
munmap (b->rules, b->byteCount); tr_sys_file_unmap (b->rules, b->byteCount, NULL);
close (b->fd); tr_sys_file_close (b->fd, NULL);
b->rules = NULL; b->rules = NULL;
b->ruleCount = 0; b->ruleCount = 0;
b->byteCount = 0; b->byteCount = 0;
b->fd = -1; b->fd = TR_BAD_SYS_FILE;
} }
} }
static void static void
blocklistLoad (tr_blocklistFile * b) blocklistLoad (tr_blocklistFile * b)
{ {
int fd; tr_sys_file_t fd;
size_t byteCount; uint64_t byteCount;
tr_sys_path_info info; tr_sys_path_info info;
char * base; char * base;
tr_error * error = NULL;
const char * err_fmt = _("Couldn't read \"%1$s\": %2$s"); const char * err_fmt = _("Couldn't read \"%1$s\": %2$s");
blocklistClose (b); blocklistClose (b);
@@ -88,22 +71,24 @@ blocklistLoad (tr_blocklistFile * b)
if (!tr_sys_path_get_info (b->filename, 0, &info, NULL)) if (!tr_sys_path_get_info (b->filename, 0, &info, NULL))
return; return;
byteCount = (size_t) info.size; byteCount = info.size;
if (byteCount == 0) if (byteCount == 0)
return; return;
fd = open (b->filename, O_RDONLY | O_BINARY); fd = tr_sys_file_open (b->filename, TR_SYS_FILE_READ, 0, &error);
if (fd == -1) if (fd == TR_BAD_SYS_FILE)
{ {
tr_logAddError (err_fmt, b->filename, tr_strerror (errno)); tr_logAddError (err_fmt, b->filename, error->message);
tr_error_free (error);
return; return;
} }
b->rules = mmap (NULL, byteCount, PROT_READ, MAP_PRIVATE, fd, 0); b->rules = tr_sys_file_map_for_reading (fd, 0, byteCount, &error);
if (!b->rules) if (!b->rules)
{ {
tr_logAddError (err_fmt, b->filename, tr_strerror (errno)); tr_logAddError (err_fmt, b->filename, error->message);
close (fd); tr_sys_file_close (fd, NULL);
tr_error_free (error);
return; return;
} }
@@ -151,7 +136,7 @@ tr_blocklistFileNew (const char * filename, bool isEnabled)
tr_blocklistFile * b; tr_blocklistFile * b;
b = tr_new0 (tr_blocklistFile, 1); b = tr_new0 (tr_blocklistFile, 1);
b->fd = -1; b->fd = TR_BAD_SYS_FILE;
b->filename = tr_strdup (filename); b->filename = tr_strdup (filename);
b->isEnabled = isEnabled; b->isEnabled = isEnabled;

View File

@@ -7,38 +7,16 @@
* $Id$ * $Id$
*/ */
#ifdef HAVE_POSIX_FADVISE
#ifdef _XOPEN_SOURCE
#undef _XOPEN_SOURCE
#endif
#define _XOPEN_SOURCE 600
#endif
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
#ifdef __APPLE__
#include <fcntl.h>
#endif
#ifdef HAVE_FALLOCATE64
/* FIXME can't find the right #include voodoo to pick up the declaration.. */
extern int fallocate64 (int fd, int mode, uint64_t offset, uint64_t len);
#endif
#ifdef HAVE_XFS_XFS_H
#include <xfs/xfs.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h> /* getrlimit */ #include <sys/time.h> /* getrlimit */
#include <sys/resource.h> /* getrlimit */ #include <sys/resource.h> /* getrlimit */
#include <fcntl.h> /* O_LARGEFILE posix_fadvise */
#include <unistd.h> /* lseek (), write (), ftruncate (), pread (), pwrite (), etc */
#include "transmission.h" #include "transmission.h"
#include "error.h"
#include "fdlimit.h" #include "fdlimit.h"
#include "file.h" #include "file.h"
#include "log.h" #include "log.h"
@@ -59,21 +37,8 @@
**** ****
***/ ***/
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifndef O_SEQUENTIAL
#define O_SEQUENTIAL 0
#endif
static bool static bool
preallocate_file_sparse (int fd, uint64_t length) preallocate_file_sparse (tr_sys_file_t fd, uint64_t length)
{ {
const char zero = '\0'; const char zero = '\0';
bool success = 0; bool success = 0;
@@ -81,15 +46,18 @@ preallocate_file_sparse (int fd, uint64_t length)
if (!length) if (!length)
success = true; success = true;
#ifdef HAVE_FALLOCATE64 if (!success)
if (!success) /* fallocate64 is always preferred, so try it first */ success = tr_sys_file_preallocate (fd, length, TR_SYS_FILE_PREALLOC_SPARSE, NULL);
success = !fallocate64 (fd, 0, 0, length);
#endif
if (!success) /* fallback: the old-style seek-and-write */ if (!success) /* fallback: the old-style seek-and-write */
success = (lseek (fd, length-1, SEEK_SET) != -1) {
&& (write (fd, &zero, 1) != -1) /* seek requires signed offset, so length should be in mod range */
&& (ftruncate (fd, length) != -1); assert (length < 0x7FFFFFFFFFFFFFFFULL);
success = tr_sys_file_seek (fd, length - 1, TR_SEEK_SET, NULL, NULL) &&
tr_sys_file_write (fd, &zero, 1, NULL, NULL) &&
tr_sys_file_truncate (fd, length, NULL);
}
return success; return success;
} }
@@ -99,53 +67,10 @@ preallocate_file_full (const char * filename, uint64_t length)
{ {
bool success = 0; bool success = 0;
#ifdef _WIN32 tr_sys_file_t fd = tr_sys_file_open (filename, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0666, NULL);
if (fd != TR_BAD_SYS_FILE)
HANDLE hFile = CreateFile (filename, GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0);
if (hFile != INVALID_HANDLE_VALUE)
{ {
LARGE_INTEGER li; success = tr_sys_file_preallocate (fd, length, 0, NULL);
li.QuadPart = length;
success = SetFilePointerEx (hFile, li, NULL, FILE_BEGIN) && SetEndOfFile (hFile);
CloseHandle (hFile);
}
#else
int flags = O_RDWR | O_CREAT | O_LARGEFILE;
int fd = open (filename, flags, 0666);
if (fd >= 0)
{
# ifdef HAVE_FALLOCATE64
if (!success)
success = !fallocate64 (fd, 0, 0, length);
# endif
# ifdef HAVE_XFS_XFS_H
if (!success && platform_test_xfs_fd (fd))
{
xfs_flock64_t fl;
fl.l_whence = 0;
fl.l_start = 0;
fl.l_len = length;
success = !xfsctl (NULL, fd, XFS_IOC_RESVSP64, &fl);
}
# endif
# ifdef __APPLE__
if (!success)
{
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;
success = !fcntl (fd, F_PREALLOCATE, &fst);
}
# endif
# ifdef HAVE_POSIX_FALLOCATE
if (!success)
success = !posix_fallocate (fd, 0, length);
# endif
if (!success) /* if nothing else works, do it the old-fashioned way */ if (!success) /* if nothing else works, do it the old-fashioned way */
{ {
@@ -154,139 +79,19 @@ preallocate_file_full (const char * filename, uint64_t length)
success = true; success = true;
while (success && (length > 0)) while (success && (length > 0))
{ {
const int thisPass = MIN (length, sizeof (buf)); const uint64_t thisPass = MIN (length, sizeof (buf));
success = write (fd, buf, thisPass) == thisPass; uint64_t bytes_written;
success = tr_sys_file_write (fd, buf, thisPass, &bytes_written, NULL) && bytes_written == thisPass;
length -= thisPass; length -= thisPass;
} }
} }
close (fd); tr_sys_file_close (fd, NULL);
} }
#endif
return success; return success;
} }
/* portability wrapper for fsync (). */
int
tr_fsync (int fd)
{
#ifdef _WIN32
return _commit (fd);
#else
return fsync (fd);
#endif
}
/* Like pread and pwrite, except that the position is undefined afterwards.
And of course they are not thread-safe. */
/* don't use pread/pwrite on old versions of uClibc because they're buggy.
* https://trac.transmissionbt.com/ticket/3826 */
#ifdef __UCLIBC__
#define TR_UCLIBC_CHECK_VERSION(major,minor,micro) \
(__UCLIBC_MAJOR__ > (major) || \
(__UCLIBC_MAJOR__ == (major) && __UCLIBC_MINOR__ > (minor)) || \
(__UCLIBC_MAJOR__ == (major) && __UCLIBC_MINOR__ == (minor) && \
__UCLIBC_SUBLEVEL__ >= (micro)))
#if !TR_UCLIBC_CHECK_VERSION (0,9,28)
#undef HAVE_PREAD
#undef HAVE_PWRITE
#endif
#endif
#ifdef __APPLE__
#define HAVE_PREAD
#define HAVE_PWRITE
#endif
ssize_t
tr_pread (int fd, void *buf, size_t count, off_t offset)
{
#ifdef HAVE_PREAD
return pread (fd, buf, count, offset);
#else
const off_t lrc = lseek (fd, offset, SEEK_SET);
if (lrc < 0)
return -1;
return read (fd, buf, count);
#endif
}
ssize_t
tr_pwrite (int fd, const void *buf, size_t count, off_t offset)
{
#ifdef HAVE_PWRITE
return pwrite (fd, buf, count, offset);
#else
const off_t lrc = lseek (fd, offset, SEEK_SET);
if (lrc < 0)
return -1;
return write (fd, buf, count);
#endif
}
int
tr_prefetch (int fd UNUSED, off_t offset UNUSED, size_t count UNUSED)
{
#ifdef HAVE_POSIX_FADVISE
return posix_fadvise (fd, offset, count, POSIX_FADV_WILLNEED);
#elif defined (__APPLE__)
struct radvisory radv;
radv.ra_offset = offset;
radv.ra_count = count;
return fcntl (fd, F_RDADVISE, &radv);
#else
return 0;
#endif
}
void
tr_set_file_for_single_pass (int fd)
{
if (fd >= 0)
{
/* Set hints about the lookahead buffer and caching. It's okay
for these to fail silently, so don't let them affect errno */
const int err = errno;
#ifdef HAVE_POSIX_FADVISE
posix_fadvise (fd, 0, 0, POSIX_FADV_SEQUENTIAL);
#endif
#ifdef __APPLE__
fcntl (fd, F_RDAHEAD, 1);
fcntl (fd, F_NOCACHE, 1);
#endif
errno = err;
}
}
static int
open_local_file (const char * filename, int flags)
{
const int fd = open (filename, flags, 0666);
tr_set_file_for_single_pass (fd);
return fd;
}
int
tr_open_file_for_writing (const char * filename)
{
return open_local_file (filename, O_LARGEFILE|O_BINARY|O_CREAT|O_WRONLY);
}
int
tr_open_file_for_scanning (const char * filename)
{
return open_local_file (filename, O_LARGEFILE|O_BINARY|O_SEQUENTIAL|O_RDONLY);
}
void
tr_close_file (int fd)
{
close (fd);
}
/***** /*****
****** ******
****** ******
@@ -296,7 +101,7 @@ tr_close_file (int fd)
struct tr_cached_file struct tr_cached_file
{ {
bool is_writable; bool is_writable;
int fd; tr_sys_file_t fd;
int torrent_id; int torrent_id;
tr_file_index_t file_index; tr_file_index_t file_index;
time_t used_at; time_t used_at;
@@ -307,7 +112,7 @@ cached_file_is_open (const struct tr_cached_file * o)
{ {
assert (o != NULL); assert (o != NULL);
return o->fd >= 0; return o->fd != TR_BAD_SYS_FILE;
} }
static void static void
@@ -315,14 +120,14 @@ cached_file_close (struct tr_cached_file * o)
{ {
assert (cached_file_is_open (o)); assert (cached_file_is_open (o));
tr_close_file (o->fd); tr_sys_file_close (o->fd, NULL);
o->fd = -1; o->fd = TR_BAD_SYS_FILE;
} }
/** /**
* returns 0 on success, or an errno value on failure. * returns 0 on success, or an errno value on failure.
* errno values include ENOENT if the parent folder doesn't exist, * errno values include ENOENT if the parent folder doesn't exist,
* plus the errno values set by tr_mkdirp () and open (). * plus the errno values set by tr_mkdirp () and tr_sys_file_open ().
*/ */
static int static int
cached_file_open (struct tr_cached_file * o, cached_file_open (struct tr_cached_file * o,
@@ -335,6 +140,7 @@ cached_file_open (struct tr_cached_file * o,
tr_sys_path_info info; tr_sys_path_info info;
bool already_existed; bool already_existed;
bool resize_needed; bool resize_needed;
tr_error * error = NULL;
/* create subfolders, if any */ /* create subfolders, if any */
if (writable) if (writable)
@@ -361,14 +167,15 @@ cached_file_open (struct tr_cached_file * o,
writable |= resize_needed; writable |= resize_needed;
/* open the file */ /* open the file */
flags = writable ? (O_RDWR | O_CREAT) : O_RDONLY; flags = writable ? (TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE) : 0;
flags |= O_LARGEFILE | O_BINARY | O_SEQUENTIAL; flags |= TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL;
o->fd = open (filename, flags, 0666); o->fd = tr_sys_file_open (filename, flags, 0666, &error);
if (o->fd == -1) if (o->fd == TR_BAD_SYS_FILE)
{ {
const int err = errno; const int err = error->code;
tr_logAddError (_("Couldn't open \"%1$s\": %2$s"), filename, tr_strerror (err)); tr_logAddError (_("Couldn't open \"%1$s\": %2$s"), filename, error->message);
tr_error_free (error);
return err; return err;
} }
@@ -378,21 +185,17 @@ cached_file_open (struct tr_cached_file * o,
* http://trac.transmissionbt.com/ticket/2228 * http://trac.transmissionbt.com/ticket/2228
* https://bugs.launchpad.net/ubuntu/+source/transmission/+bug/318249 * https://bugs.launchpad.net/ubuntu/+source/transmission/+bug/318249
*/ */
if (resize_needed && (ftruncate (o->fd, file_size) == -1)) if (resize_needed && !tr_sys_file_truncate (o->fd, file_size, &error))
{ {
const int err = errno; const int err = error->code;
tr_logAddError (_("Couldn't truncate \"%1$s\": %2$s"), filename, tr_strerror (err)); tr_logAddError (_("Couldn't truncate \"%1$s\": %2$s"), filename, error->message);
tr_error_free (error);
return err; return err;
} }
if (writable && !already_existed && (allocation == TR_PREALLOCATE_SPARSE)) if (writable && !already_existed && (allocation == TR_PREALLOCATE_SPARSE))
preallocate_file_sparse (o->fd, file_size); 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; return 0;
} }
@@ -410,7 +213,7 @@ static void
fileset_construct (struct tr_fileset * set, int n) fileset_construct (struct tr_fileset * set, int n)
{ {
struct tr_cached_file * o; struct tr_cached_file * o;
const struct tr_cached_file TR_CACHED_FILE_INIT = { 0, -1, 0, 0, 0 }; const struct tr_cached_file TR_CACHED_FILE_INIT = { false, TR_BAD_SYS_FILE, 0, 0, 0 };
set->begin = tr_new (struct tr_cached_file, n); set->begin = tr_new (struct tr_cached_file, n);
set->end = set->begin + n; set->end = set->begin + n;
@@ -567,39 +370,33 @@ tr_fdFileClose (tr_session * s, const tr_torrent * tor, tr_file_index_t i)
/* flush writable files so that their mtimes will be /* flush writable files so that their mtimes will be
* up-to-date when this function returns to the caller... */ * up-to-date when this function returns to the caller... */
if (o->is_writable) if (o->is_writable)
tr_fsync (o->fd); tr_sys_file_flush (o->fd, NULL);
cached_file_close (o); cached_file_close (o);
} }
} }
int tr_sys_file_t
tr_fdFileGetCached (tr_session * s, int torrent_id, tr_file_index_t i, bool writable) tr_fdFileGetCached (tr_session * s, int torrent_id, tr_file_index_t i, bool writable)
{ {
struct tr_cached_file * o = fileset_lookup (get_fileset (s), torrent_id, i); struct tr_cached_file * o = fileset_lookup (get_fileset (s), torrent_id, i);
if (!o || (writable && !o->is_writable)) if (!o || (writable && !o->is_writable))
return -1; return TR_BAD_SYS_FILE;
o->used_at = tr_time (); o->used_at = tr_time ();
return o->fd; return o->fd;
} }
#ifdef __APPLE__
#define TR_STAT_MTIME(sb)((sb).st_mtimespec.tv_sec)
#else
#define TR_STAT_MTIME(sb)((sb).st_mtime)
#endif
bool bool
tr_fdFileGetCachedMTime (tr_session * s, int torrent_id, tr_file_index_t i, time_t * mtime) tr_fdFileGetCachedMTime (tr_session * s, int torrent_id, tr_file_index_t i, time_t * mtime)
{ {
bool success; bool success;
struct stat sb; tr_sys_path_info info;
struct tr_cached_file * o = fileset_lookup (get_fileset (s), torrent_id, i); struct tr_cached_file * o = fileset_lookup (get_fileset (s), torrent_id, i);
if ((success = (o != NULL) && !fstat (o->fd, &sb))) if ((success = (o != NULL) && tr_sys_file_get_info (o->fd, &info, NULL)))
*mtime = TR_STAT_MTIME (sb); *mtime = info.last_modified_at;
return success; return success;
} }
@@ -612,8 +409,8 @@ tr_fdTorrentClose (tr_session * session, int torrent_id)
fileset_close_torrent (get_fileset (session), torrent_id); fileset_close_torrent (get_fileset (session), torrent_id);
} }
/* returns an fd on success, or a -1 on failure and sets errno */ /* returns an fd on success, or a TR_BAD_SYS_FILE on failure and sets errno */
int tr_sys_file_t
tr_fdFileCheckout (tr_session * session, tr_fdFileCheckout (tr_session * session,
int torrent_id, int torrent_id,
tr_file_index_t i, tr_file_index_t i,
@@ -636,7 +433,7 @@ tr_fdFileCheckout (tr_session * session,
if (err) if (err)
{ {
errno = err; errno = err;
return -1; return TR_BAD_SYS_FILE;
} }
dbgmsg ("opened '%s' writable %c", filename, writable?'y':'n'); dbgmsg ("opened '%s' writable %c", filename, writable?'y':'n');

View File

@@ -12,6 +12,7 @@
#endif #endif
#include "transmission.h" #include "transmission.h"
#include "file.h"
#include "net.h" #include "net.h"
/** /**
@@ -23,21 +24,6 @@
**** ****
***/ ***/
void tr_set_file_for_single_pass (int fd);
int tr_open_file_for_scanning (const char * filename);
int tr_open_file_for_writing (const char * filename);
void tr_close_file (int fd);
int tr_fsync (int fd);
ssize_t tr_pread (int fd, void *buf, size_t count, off_t offset);
ssize_t tr_pwrite (int fd, const void *buf, size_t count, off_t offset);
int tr_prefetch (int fd, off_t offset, size_t count);
/** /**
* Returns an fd to the specified filename. * Returns an fd to the specified filename.
* *
@@ -49,22 +35,22 @@ int tr_prefetch (int fd, off_t offset, size_t count);
* - if do_write is true, the target file is created if necessary. * - if do_write is true, the target file is created if necessary.
* *
* on success, a file descriptor >= 0 is returned. * on success, a file descriptor >= 0 is returned.
* on failure, a -1 is returned and errno is set. * on failure, a TR_BAD_SYS_FILE is returned and errno is set.
* *
* @see tr_fdFileClose * @see tr_fdFileClose
*/ */
int tr_fdFileCheckout (tr_session * session, tr_sys_file_t tr_fdFileCheckout (tr_session * session,
int torrent_id, int torrent_id,
tr_file_index_t file_num, tr_file_index_t file_num,
const char * filename, const char * filename,
bool do_write, bool do_write,
tr_preallocation_mode preallocation_mode, tr_preallocation_mode preallocation_mode,
uint64_t preallocation_file_size); uint64_t preallocation_file_size);
int tr_fdFileGetCached (tr_session * session, tr_sys_file_t tr_fdFileGetCached (tr_session * session,
int torrent_id, int torrent_id,
tr_file_index_t file_num, tr_file_index_t file_num,
bool doWrite); bool doWrite);
bool tr_fdFileGetCachedMTime (tr_session * session, bool tr_fdFileGetCachedMTime (tr_session * session,
int torrent_id, int torrent_id,

View File

@@ -16,7 +16,9 @@
#include "transmission.h" #include "transmission.h"
#include "cache.h" /* tr_cacheReadBlock () */ #include "cache.h" /* tr_cacheReadBlock () */
#include "error.h"
#include "fdlimit.h" #include "fdlimit.h"
#include "file.h"
#include "inout.h" #include "inout.h"
#include "log.h" #include "log.h"
#include "peer-common.h" /* MAX_BLOCK_SIZE */ #include "peer-common.h" /* MAX_BLOCK_SIZE */
@@ -46,7 +48,7 @@ readOrWriteBytes (tr_session * session,
void * buf, void * buf,
size_t buflen) size_t buflen)
{ {
int fd; tr_sys_file_t fd;
int err = 0; int err = 0;
const bool doWrite = ioMode >= TR_IO_WRITE; const bool doWrite = ioMode >= TR_IO_WRITE;
const tr_info * const info = &tor->info; const tr_info * const info = &tor->info;
@@ -64,7 +66,7 @@ readOrWriteBytes (tr_session * session,
***/ ***/
fd = tr_fdFileGetCached (session, tr_torrentId (tor), fileIndex, doWrite); fd = tr_fdFileGetCached (session, tr_torrentId (tor), fileIndex, doWrite);
if (fd < 0) if (fd == TR_BAD_SYS_FILE)
{ {
/* it's not cached, so open/create it now */ /* it's not cached, so open/create it now */
char * subpath; char * subpath;
@@ -94,7 +96,7 @@ readOrWriteBytes (tr_session * session,
: tor->session->preallocationMode; : tor->session->preallocationMode;
if (((fd = tr_fdFileCheckout (session, tor->uniqueId, fileIndex, if (((fd = tr_fdFileCheckout (session, tor->uniqueId, fileIndex,
filename, doWrite, filename, doWrite,
prealloc, file->length))) < 0) prealloc, file->length))) == TR_BAD_SYS_FILE)
{ {
err = errno; err = errno;
tr_logAddTorErr (tor, "tr_fdFileCheckout failed for \"%s\": %s", tr_logAddTorErr (tor, "tr_fdFileCheckout failed for \"%s\": %s",
@@ -118,27 +120,29 @@ readOrWriteBytes (tr_session * session,
if (!err) if (!err)
{ {
tr_error * error = NULL;
if (ioMode == TR_IO_READ) if (ioMode == TR_IO_READ)
{ {
const int rc = tr_pread (fd, buf, buflen, fileOffset); if (!tr_sys_file_read_at (fd, buf, buflen, fileOffset, NULL, &error))
if (rc < 0)
{ {
err = errno; err = error->code;
tr_logAddTorErr (tor, "read failed for \"%s\": %s", file->name, tr_strerror (err)); tr_logAddTorErr (tor, "read failed for \"%s\": %s", file->name, error->message);
tr_error_free (error);
} }
} }
else if (ioMode == TR_IO_WRITE) else if (ioMode == TR_IO_WRITE)
{ {
const int rc = tr_pwrite (fd, buf, buflen, fileOffset); if (!tr_sys_file_write_at (fd, buf, buflen, fileOffset, NULL, &error))
if (rc < 0)
{ {
err = errno; err = error->code;
tr_logAddTorErr (tor, "write failed for \"%s\": %s", file->name, tr_strerror (err)); tr_logAddTorErr (tor, "write failed for \"%s\": %s", file->name, error->message);
tr_error_free (error);
} }
} }
else if (ioMode == TR_IO_PREFETCH) else if (ioMode == TR_IO_PREFETCH)
{ {
tr_prefetch (fd, fileOffset, buflen); tr_sys_file_prefetch (fd, fileOffset, buflen, NULL);
} }
else else
{ {

View File

@@ -14,6 +14,7 @@
#include <unistd.h> #include <unistd.h>
#include "transmission.h" #include "transmission.h"
#include "error.h"
#include "file.h" #include "file.h"
#include "platform.h" /* TR_PATH_DELIMETER */ #include "platform.h" /* TR_PATH_DELIMETER */
#include "torrent.h" #include "torrent.h"
@@ -373,7 +374,7 @@ libttest_zero_torrent_populate (tr_torrent * tor, bool complete)
{ {
int err; int err;
uint64_t j; uint64_t j;
FILE * fp; tr_sys_file_t fd;
char * path; char * path;
char * dirname; char * dirname;
const tr_file * file = &tor->info.files[i]; const tr_file * file = &tor->info.files[i];
@@ -384,10 +385,10 @@ libttest_zero_torrent_populate (tr_torrent * tor, bool complete)
path = tr_strdup_printf ("%s%c%s", tor->currentDir, TR_PATH_DELIMITER, file->name); path = tr_strdup_printf ("%s%c%s", tor->currentDir, TR_PATH_DELIMITER, file->name);
dirname = tr_sys_path_dirname (path, NULL); dirname = tr_sys_path_dirname (path, NULL);
tr_mkdirp (dirname, 0700); tr_mkdirp (dirname, 0700);
fp = fopen (path, "wb+"); fd = tr_sys_file_open (path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0600, NULL);
for (j=0; j<file->length; ++j) for (j=0; j<file->length; ++j)
fputc (((!complete) && (i==0) && (j<tor->info.pieceSize)) ? '\1' : '\0', fp); tr_sys_file_write (fd, ((!complete) && (i==0) && (j<tor->info.pieceSize)) ? "\1" : "\0", 1, NULL, NULL);
fclose (fp); tr_sys_file_close (fd, NULL);
tr_free (dirname); tr_free (dirname);
tr_free (path); tr_free (path);
@@ -450,15 +451,14 @@ build_parent_dir (const char* path)
void void
libtest_create_file_with_contents (const char* path, const void* payload, size_t n) libtest_create_file_with_contents (const char* path, const void* payload, size_t n)
{ {
FILE * fp; tr_sys_file_t fd;
const int tmperr = errno; const int tmperr = errno;
build_parent_dir (path); build_parent_dir (path);
tr_sys_path_remove (path, NULL); fd = tr_sys_file_open (path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0600, NULL);
fp = fopen (path, "wb"); tr_sys_file_write (fd, payload, n, NULL, NULL);
fwrite (payload, 1, n, fp); tr_sys_file_close (fd, NULL);
fclose (fp);
sync (); sync ();
@@ -474,24 +474,26 @@ libtest_create_file_with_string_contents (const char * path, const char* str)
void void
libtest_create_tmpfile_with_contents (char* tmpl, const void* payload, size_t n) libtest_create_tmpfile_with_contents (char* tmpl, const void* payload, size_t n)
{ {
int fd; tr_sys_file_t fd;
const int tmperr = errno; const int tmperr = errno;
size_t n_left = n; uint64_t n_left = n;
tr_error * error = NULL;
build_parent_dir (tmpl); build_parent_dir (tmpl);
fd = mkstemp (tmpl); fd = tr_sys_file_open_temp (tmpl, NULL);
while (n_left > 0) while (n_left > 0)
{ {
const ssize_t n = write (fd, payload, n_left); uint64_t n;
if (n == -1) if (!tr_sys_file_write (fd, payload, n_left, &n, &error))
{ {
fprintf (stderr, "Error writing '%s': %s\n", tmpl, tr_strerror(errno)); fprintf (stderr, "Error writing '%s': %s\n", tmpl, error->message);
tr_error_free (error);
break; break;
} }
n_left -= n; n_left -= n;
} }
close (fd); tr_sys_file_close (fd, NULL);
sync (); sync ();

View File

@@ -9,11 +9,9 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> /* FILE, stderr */
#include <stdlib.h> /* qsort */ #include <stdlib.h> /* qsort */
#include <string.h> /* strcmp, strlen */ #include <string.h> /* strcmp, strlen */
#include <unistd.h> /* read () */
#include <dirent.h> #include <dirent.h>
#include <event2/util.h> /* evutil_ascii_strcasecmp () */ #include <event2/util.h> /* evutil_ascii_strcasecmp () */
@@ -21,7 +19,6 @@
#include "transmission.h" #include "transmission.h"
#include "crypto.h" /* tr_sha1 */ #include "crypto.h" /* tr_sha1 */
#include "error.h" #include "error.h"
#include "fdlimit.h" /* tr_open_file_for_scanning () */
#include "file.h" #include "file.h"
#include "log.h" #include "log.h"
#include "session.h" #include "session.h"
@@ -228,7 +225,8 @@ getHashInfo (tr_metainfo_builder * b)
uint8_t *buf; uint8_t *buf;
uint64_t totalRemain; uint64_t totalRemain;
uint64_t off = 0; uint64_t off = 0;
int fd; tr_sys_file_t fd;
tr_error * error = NULL;
if (!b->totalSize) if (!b->totalSize)
return ret; return ret;
@@ -236,16 +234,18 @@ getHashInfo (tr_metainfo_builder * b)
buf = tr_valloc (b->pieceSize); buf = tr_valloc (b->pieceSize);
b->pieceIndex = 0; b->pieceIndex = 0;
totalRemain = b->totalSize; totalRemain = b->totalSize;
fd = tr_open_file_for_scanning (b->files[fileIndex].filename); fd = tr_sys_file_open (b->files[fileIndex].filename, TR_SYS_FILE_READ |
if (fd < 0) TR_SYS_FILE_SEQUENTIAL, 0, &error);
if (fd == TR_BAD_SYS_FILE)
{ {
b->my_errno = errno; b->my_errno = error->code;
tr_strlcpy (b->errfile, tr_strlcpy (b->errfile,
b->files[fileIndex].filename, b->files[fileIndex].filename,
sizeof (b->errfile)); sizeof (b->errfile));
b->result = TR_MAKEMETA_IO_READ; b->result = TR_MAKEMETA_IO_READ;
tr_free (buf); tr_free (buf);
tr_free (ret); tr_free (ret);
tr_error_free (error);
return NULL; return NULL;
} }
@@ -253,34 +253,37 @@ getHashInfo (tr_metainfo_builder * b)
{ {
uint8_t * bufptr = buf; uint8_t * bufptr = buf;
const uint32_t thisPieceSize = (uint32_t) MIN (b->pieceSize, totalRemain); const uint32_t thisPieceSize = (uint32_t) MIN (b->pieceSize, totalRemain);
uint32_t leftInPiece = thisPieceSize; uint64_t leftInPiece = thisPieceSize;
assert (b->pieceIndex < b->pieceCount); assert (b->pieceIndex < b->pieceCount);
while (leftInPiece) while (leftInPiece)
{ {
const size_t n_this_pass = (size_t) MIN ((b->files[fileIndex].size - off), leftInPiece); const uint64_t n_this_pass = MIN (b->files[fileIndex].size - off, leftInPiece);
const ssize_t n_read = read (fd, bufptr, n_this_pass); uint64_t n_read = 0;
tr_sys_file_read (fd, bufptr, n_this_pass, &n_read, NULL);
bufptr += n_read; bufptr += n_read;
off += n_read; off += n_read;
leftInPiece -= n_read; leftInPiece -= n_read;
if (off == b->files[fileIndex].size) if (off == b->files[fileIndex].size)
{ {
off = 0; off = 0;
tr_close_file (fd); tr_sys_file_close (fd, NULL);
fd = -1; fd = TR_BAD_SYS_FILE;
if (++fileIndex < b->fileCount) if (++fileIndex < b->fileCount)
{ {
fd = tr_open_file_for_scanning (b->files[fileIndex].filename); fd = tr_sys_file_open (b->files[fileIndex].filename, TR_SYS_FILE_READ |
if (fd < 0) TR_SYS_FILE_SEQUENTIAL, 0, &error);
if (fd == TR_BAD_SYS_FILE)
{ {
b->my_errno = errno; b->my_errno = error->code;
tr_strlcpy (b->errfile, tr_strlcpy (b->errfile,
b->files[fileIndex].filename, b->files[fileIndex].filename,
sizeof (b->errfile)); sizeof (b->errfile));
b->result = TR_MAKEMETA_IO_READ; b->result = TR_MAKEMETA_IO_READ;
tr_free (buf); tr_free (buf);
tr_free (ret); tr_free (ret);
tr_error_free (error);
return NULL; return NULL;
} }
} }
@@ -306,8 +309,8 @@ getHashInfo (tr_metainfo_builder * b)
|| (walk - ret == (int)(SHA_DIGEST_LENGTH * b->pieceCount))); || (walk - ret == (int)(SHA_DIGEST_LENGTH * b->pieceCount)));
assert (b->abortFlag || !totalRemain); assert (b->abortFlag || !totalRemain);
if (fd >= 0) if (fd != TR_BAD_SYS_FILE)
tr_close_file (fd); tr_sys_file_close (fd, NULL);
tr_free (buf); tr_free (buf);
return ret; return ret;

View File

@@ -565,123 +565,3 @@ tr_getWebClientDir (const tr_session * session UNUSED)
return s; return s;
} }
#ifdef _WIN32
/* The following mmap functions are by Joerg Walter, and were taken from
* his paper at: http://www.genesys-e.de/jwalter/mix4win.htm */
#if defined (_MSC_VER)
__declspec (align (4)) static LONG volatile g_sl;
#else
static LONG volatile g_sl __attribute__((aligned (4)));
#endif
/* Wait for spin lock */
static int
slwait (LONG volatile *sl)
{
while (InterlockedCompareExchange (sl, 1, 0) != 0)
Sleep (0);
return 0;
}
/* Release spin lock */
static int
slrelease (LONG volatile *sl)
{
InterlockedExchange (sl, 0);
return 0;
}
/* getpagesize for windows */
static long
getpagesize (void)
{
static long g_pagesize = 0;
if (!g_pagesize)
{
SYSTEM_INFO system_info;
GetSystemInfo (&system_info);
g_pagesize = system_info.dwPageSize;
}
return g_pagesize;
}
static long
getregionsize (void)
{
static long g_regionsize = 0;
if (!g_regionsize)
{
SYSTEM_INFO system_info;
GetSystemInfo (&system_info);
g_regionsize = system_info.dwAllocationGranularity;
}
return g_regionsize;
}
void *
mmap (void *ptr, long size, long prot, long type, long handle, long arg)
{
static long g_pagesize;
static long g_regionsize;
/* Wait for spin lock */
slwait (&g_sl);
/* First time initialization */
if (!g_pagesize)
g_pagesize = getpagesize ();
if (!g_regionsize)
g_regionsize = getregionsize ();
/* Allocate this */
ptr = VirtualAlloc (ptr, size, MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE);
if (!ptr)
{
ptr = (void *) -1;
goto mmap_exit;
}
mmap_exit:
/* Release spin lock */
slrelease (&g_sl);
return ptr;
}
long
munmap (void *ptr, long size)
{
static long g_pagesize;
static long g_regionsize;
int rc = -1;
/* Wait for spin lock */
slwait (&g_sl);
/* First time initialization */
if (!g_pagesize)
g_pagesize = getpagesize ();
if (!g_regionsize)
g_regionsize = getregionsize ();
/* Free this */
if (!VirtualFree (ptr, 0, MEM_RELEASE))
goto munmap_exit;
rc = 0;
munmap_exit:
/* Release spin lock */
slrelease (&g_sl);
return rc;
}
#endif

View File

@@ -77,12 +77,6 @@ void tr_lockUnlock (tr_lock *);
/** @brief return nonzero if the specified lock is locked */ /** @brief return nonzero if the specified lock is locked */
int tr_lockHave (const tr_lock *); int tr_lockHave (const tr_lock *);
#ifdef _WIN32
void * mmap (void *ptr, long size, long prot, long type, long handle, long arg);
long munmap (void *ptr, long size);
#endif
/* @} */ /* @} */
#endif #endif

View File

@@ -11,8 +11,6 @@
#include <errno.h> #include <errno.h>
#include <string.h> /* memcpy */ #include <string.h> /* memcpy */
#include <unistd.h> /* close */
#include <zlib.h> #include <zlib.h>
#include <event2/buffer.h> #include <event2/buffer.h>

View File

@@ -19,6 +19,7 @@
#include "transmission.h" #include "transmission.h"
#include "completion.h" #include "completion.h"
#include "error.h"
#include "fdlimit.h" #include "fdlimit.h"
#include "file.h" #include "file.h"
#include "log.h" #include "log.h"
@@ -1487,13 +1488,14 @@ gotNewBlocklist (tr_session * session,
} }
else /* successfully fetched the blocklist... */ else /* successfully fetched the blocklist... */
{ {
int fd; tr_sys_file_t fd;
int err; int err;
char * filename; char * filename;
z_stream stream; z_stream stream;
const char * configDir = tr_sessionGetConfigDir (session); const char * configDir = tr_sessionGetConfigDir (session);
const size_t buflen = 1024 * 128; /* 128 KiB buffer */ const size_t buflen = 1024 * 128; /* 128 KiB buffer */
uint8_t * buf = tr_valloc (buflen); uint8_t * buf = tr_valloc (buflen);
tr_error * error = NULL;
/* this is an odd Magic Number required by zlib to enable gz support. /* this is an odd Magic Number required by zlib to enable gz support.
See zlib's inflateInit2 () documentation for a full description */ See zlib's inflateInit2 () documentation for a full description */
@@ -1506,10 +1508,13 @@ gotNewBlocklist (tr_session * session,
stream.avail_in = response_byte_count; stream.avail_in = response_byte_count;
inflateInit2 (&stream, windowBits); inflateInit2 (&stream, windowBits);
filename = tr_buildPath (configDir, "blocklist.tmp", NULL); filename = tr_buildPath (configDir, "blocklist.tmp.XXXXXX", NULL);
fd = tr_open_file_for_writing (filename); fd = tr_sys_file_open_temp (filename, &error);
if (fd < 0) if (fd == TR_BAD_SYS_FILE)
tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, tr_strerror (errno)); {
tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, error->message);
tr_error_clear (&error);
}
for (;;) for (;;)
{ {
@@ -1519,10 +1524,10 @@ gotNewBlocklist (tr_session * session,
if (stream.avail_out < buflen) if (stream.avail_out < buflen)
{ {
const int e = write (fd, buf, buflen - stream.avail_out); if (!tr_sys_file_write (fd, buf, buflen - stream.avail_out, NULL, &error))
if (e < 0)
{ {
tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, tr_strerror (errno)); tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, error->message);
tr_error_clear (&error);
break; break;
} }
} }
@@ -1538,10 +1543,13 @@ gotNewBlocklist (tr_session * session,
inflateEnd (&stream); inflateEnd (&stream);
if (err == Z_DATA_ERROR) /* couldn't inflate it... it's probably already uncompressed */ if (err == Z_DATA_ERROR) /* couldn't inflate it... it's probably already uncompressed */
if (write (fd, response, response_byte_count) < 0) if (!tr_sys_file_write (fd, response, response_byte_count, NULL, &error))
tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, tr_strerror (errno)); {
tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, error->message);
tr_error_clear (&error);
}
tr_close_file(fd); tr_sys_file_close (fd, NULL);
if (*result) if (*result)
{ {

View File

@@ -155,19 +155,19 @@ tr_torrentGetMetadataPiece (tr_torrent * tor, int piece, int * len)
if (tr_torrentHasMetadata (tor)) if (tr_torrentHasMetadata (tor))
{ {
FILE * fp; tr_sys_file_t fd;
ensureInfoDictOffsetIsCached (tor); ensureInfoDictOffsetIsCached (tor);
assert (tor->infoDictLength > 0); assert (tor->infoDictLength > 0);
assert (tor->infoDictOffset >= 0); assert (tor->infoDictOffset >= 0);
fp = fopen (tor->info.torrent, "rb"); fd = tr_sys_file_open (tor->info.torrent, TR_SYS_FILE_READ, 0, NULL);
if (fp != NULL) if (fd != TR_BAD_SYS_FILE)
{ {
const int o = piece * METADATA_PIECE_SIZE; const int o = piece * METADATA_PIECE_SIZE;
if (!fseek (fp, tor->infoDictOffset + o, SEEK_SET)) if (tr_sys_file_seek (fd, tor->infoDictOffset + o, TR_SEEK_SET, NULL, NULL))
{ {
const int l = o + METADATA_PIECE_SIZE <= tor->infoDictLength const int l = o + METADATA_PIECE_SIZE <= tor->infoDictLength
? METADATA_PIECE_SIZE ? METADATA_PIECE_SIZE
@@ -176,8 +176,8 @@ tr_torrentGetMetadataPiece (tr_torrent * tor, int piece, int * len)
if (0<l && l<=METADATA_PIECE_SIZE) if (0<l && l<=METADATA_PIECE_SIZE)
{ {
char * buf = tr_new (char, l); char * buf = tr_new (char, l);
const int n = fread (buf, 1, l, fp); uint64_t n;
if (n == l) if (tr_sys_file_read (fd, buf, l, &n, NULL) && n == (unsigned int) l)
{ {
*len = l; *len = l;
ret = buf; ret = buf;
@@ -188,7 +188,7 @@ tr_torrentGetMetadataPiece (tr_torrent * tor, int piece, int * len)
} }
} }
fclose (fp); tr_sys_file_close (fd, NULL);
} }
} }

View File

@@ -28,14 +28,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> /* strerror (), memset (), memmem () */ #include <string.h> /* strerror (), memset (), memmem () */
#include <time.h> /* nanosleep () */ #include <time.h> /* nanosleep () */
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_ICONV_OPEN #ifdef HAVE_ICONV_OPEN
#include <iconv.h> #include <iconv.h>
#endif #endif
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <unistd.h> /* getpagesize () */
#include <sys/stat.h>
#include <unistd.h> /* stat (), getpagesize () */
#include <event2/buffer.h> #include <event2/buffer.h>
#include <event2/event.h> #include <event2/event.h>
@@ -48,7 +48,6 @@
#include "transmission.h" #include "transmission.h"
#include "error.h" #include "error.h"
#include "fdlimit.h"
#include "file.h" #include "file.h"
#include "ConvertUTF.h" #include "ConvertUTF.h"
#include "list.h" #include "list.h"
@@ -221,8 +220,7 @@ tr_loadFile (const char * path,
{ {
uint8_t * buf; uint8_t * buf;
tr_sys_path_info info; tr_sys_path_info info;
int fd; tr_sys_file_t fd;
ssize_t n;
tr_error * error = NULL; tr_error * error = NULL;
const char * const err_fmt = _("Couldn't read \"%1$s\": %2$s"); const char * const err_fmt = _("Couldn't read \"%1$s\": %2$s");
@@ -248,11 +246,12 @@ tr_loadFile (const char * path,
assert (info.size <= SIZE_MAX); assert (info.size <= SIZE_MAX);
/* Load the torrent file into our buffer */ /* Load the torrent file into our buffer */
fd = tr_open_file_for_scanning (path); fd = tr_sys_file_open (path, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &error);
if (fd < 0) if (fd == TR_BAD_SYS_FILE)
{ {
const int err = errno; const int err = error->code;
tr_logAddError (err_fmt, path, tr_strerror (errno)); tr_logAddError (err_fmt, path, error->message);
tr_error_free (error);
errno = err; errno = err;
return NULL; return NULL;
} }
@@ -261,22 +260,22 @@ tr_loadFile (const char * path,
{ {
const int err = errno; const int err = errno;
tr_logAddError (err_fmt, path, _("Memory allocation failed")); tr_logAddError (err_fmt, path, _("Memory allocation failed"));
tr_close_file (fd); tr_sys_file_close (fd, NULL);
errno = err; errno = err;
return NULL; return NULL;
} }
n = read (fd, buf, (size_t)info.size); if (!tr_sys_file_read (fd, buf, info.size, NULL, &error))
if (n == -1)
{ {
const int err = errno; const int err = error->code;
tr_logAddError (err_fmt, path, tr_strerror (errno)); tr_logAddError (err_fmt, path, error->message);
tr_close_file (fd); tr_sys_file_close (fd, NULL);
free (buf); free (buf);
tr_error_free (error);
errno = err; errno = err;
return NULL; return NULL;
} }
tr_close_file (fd); tr_sys_file_close (fd, NULL);
buf[info.size] = '\0'; buf[info.size] = '\0';
*size = info.size; *size = info.size;
return buf; return buf;
@@ -1544,11 +1543,11 @@ tr_strratio (char * buf, size_t buflen, double ratio, const char * infinity)
int int
tr_moveFile (const char * oldpath, const char * newpath, bool * renamed) tr_moveFile (const char * oldpath, const char * newpath, bool * renamed)
{ {
int in; tr_sys_file_t in;
int out; tr_sys_file_t out;
char * buf; char * buf;
tr_sys_path_info info; tr_sys_path_info info;
off_t bytesLeft; uint64_t bytesLeft;
const size_t buflen = 1024 * 128; /* 128 KiB buffer */ const size_t buflen = 1024 * 128; /* 128 KiB buffer */
tr_error * error = NULL; tr_error * error = NULL;
@@ -1586,26 +1585,24 @@ tr_moveFile (const char * oldpath, const char * newpath, bool * renamed)
} }
/* copy the file */ /* copy the file */
in = tr_open_file_for_scanning (oldpath); in = tr_sys_file_open (oldpath, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, NULL);
out = tr_open_file_for_writing (newpath); out = tr_sys_file_open (newpath, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0666, NULL);
buf = tr_valloc (buflen); buf = tr_valloc (buflen);
while (bytesLeft > 0) while (bytesLeft > 0)
{ {
ssize_t bytesWritten; const uint64_t bytesThisPass = MIN (bytesLeft, buflen);
const off_t bytesThisPass = MIN (bytesLeft, (off_t)buflen); uint64_t numRead, bytesWritten;
const int numRead = read (in, buf, bytesThisPass); if (!tr_sys_file_read (in, buf, bytesThisPass, &numRead, NULL))
if (numRead < 0)
break; break;
bytesWritten = write (out, buf, numRead); if (!tr_sys_file_write (out, buf, numRead, &bytesWritten, NULL))
if (bytesWritten < 0)
break; break;
bytesLeft -= bytesWritten; bytesLeft -= bytesWritten;
} }
/* cleanup */ /* cleanup */
tr_free (buf); tr_free (buf);
tr_close_file (out); tr_sys_file_close (out, NULL);
tr_close_file (in); tr_sys_file_close (in, NULL);
if (bytesLeft != 0) if (bytesLeft != 0)
return -1; return -1;

View File

@@ -9,24 +9,20 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h> /* strtod(), realloc(), qsort(), mkstemp() */ #include <stdlib.h> /* strtod(), realloc(), qsort() */
#include <string.h> #include <string.h>
#ifdef _WIN32 /* tr_mkstemp() */ #ifdef _WIN32
#include <fcntl.h>
#include <share.h> #include <share.h>
#include <sys/stat.h>
#endif #endif
#include <locale.h> /* setlocale() */ #include <locale.h> /* setlocale() */
#include <unistd.h> /* write() */
#include <event2/buffer.h> #include <event2/buffer.h>
#define __LIBTRANSMISSION_VARIANT_MODULE___ #define __LIBTRANSMISSION_VARIANT_MODULE___
#include "transmission.h" #include "transmission.h"
#include "ConvertUTF.h" #include "ConvertUTF.h"
#include "fdlimit.h" /* tr_close_file() */
#include "error.h" #include "error.h"
#include "file.h" #include "file.h"
#include "log.h" #include "log.h"
@@ -1125,55 +1121,28 @@ tr_variantToStr (const tr_variant * v, tr_variant_fmt fmt, int * len)
return ret; return ret;
} }
/* portability wrapper for mkstemp(). */
static int
tr_mkstemp (char * template)
{
#ifdef _WIN32
const int n = strlen (template) + 1;
const int flags = O_RDWR | O_BINARY | O_CREAT | O_EXCL | _O_SHORT_LIVED;
const mode_t mode = _S_IREAD | _S_IWRITE;
wchar_t templateUTF16[n];
if (MultiByteToWideChar(CP_UTF8, 0, template, -1, templateUTF16, n))
{
_wmktemp(templateUTF16);
WideCharToMultiByte(CP_UTF8, 0, templateUTF16, -1, template, n, NULL, NULL);
return _wopen(chkFilename(templateUTF16), flags, mode);
}
errno = EINVAL;
return -1;
#else
return mkstemp (template);
#endif
}
int int
tr_variantToFile (const tr_variant * v, tr_variantToFile (const tr_variant * v,
tr_variant_fmt fmt, tr_variant_fmt fmt,
const char * filename) const char * filename)
{ {
char * tmp; char * tmp;
int fd; tr_sys_file_t fd;
int err = 0; int err = 0;
char * real_filename; char * real_filename;
tr_error * error = NULL;
/* follow symlinks to find the "real" file, to make sure the temporary /* follow symlinks to find the "real" file, to make sure the temporary
* we build with tr_mkstemp() is created on the right partition */ * we build with tr_sys_file_open_temp() is created on the right partition */
if ((real_filename = tr_sys_path_resolve (filename, NULL)) != NULL) if ((real_filename = tr_sys_path_resolve (filename, NULL)) != NULL)
filename = real_filename; filename = real_filename;
/* if the file already exists, try to move it out of the way & keep it as a backup */ /* if the file already exists, try to move it out of the way & keep it as a backup */
tmp = tr_strdup_printf ("%s.tmp.XXXXXX", filename); tmp = tr_strdup_printf ("%s.tmp.XXXXXX", filename);
fd = tr_mkstemp (tmp); fd = tr_sys_file_open_temp (tmp, &error);
tr_set_file_for_single_pass (fd); if (fd != TR_BAD_SYS_FILE)
if (fd >= 0)
{ {
int nleft; uint64_t nleft;
/* save the variant to a temporary file */ /* save the variant to a temporary file */
{ {
@@ -1183,34 +1152,31 @@ tr_variantToFile (const tr_variant * v,
while (nleft > 0) while (nleft > 0)
{ {
const int n = write (fd, walk, nleft); uint64_t n;
if (n >= 0) if (!tr_sys_file_write (fd, walk, nleft, &n, &error))
{ {
nleft -= n; err = error->code;
walk += n;
}
else if (errno != EAGAIN)
{
err = errno;
break; break;
} }
nleft -= n;
walk += n;
} }
evbuffer_free (buf); evbuffer_free (buf);
} }
tr_sys_file_close (fd, NULL);
if (nleft > 0) if (nleft > 0)
{ {
tr_logAddError (_("Couldn't save temporary file \"%1$s\": %2$s"), tmp, tr_strerror (err)); tr_logAddError (_("Couldn't save temporary file \"%1$s\": %2$s"), tmp, error->message);
tr_close_file (fd);
tr_sys_path_remove (tmp, NULL); tr_sys_path_remove (tmp, NULL);
tr_error_free (error);
} }
else else
{ {
tr_error * error = NULL; tr_error_clear (&error);
tr_close_file (fd);
if (tr_sys_path_rename (tmp, filename, &error)) if (tr_sys_path_rename (tmp, filename, &error))
{ {
tr_logAddInfo (_("Saved \"%s\""), filename); tr_logAddInfo (_("Saved \"%s\""), filename);
@@ -1226,8 +1192,9 @@ tr_variantToFile (const tr_variant * v,
} }
else else
{ {
err = errno; err = error->code;
tr_logAddError (_("Couldn't save temporary file \"%1$s\": %2$s"), tmp, tr_strerror (err)); tr_logAddError (_("Couldn't save temporary file \"%1$s\": %2$s"), tmp, error->message);
tr_error_free (error);
} }
tr_free (tmp); tr_free (tmp);

View File

@@ -19,7 +19,7 @@
#include "transmission.h" #include "transmission.h"
#include "completion.h" #include "completion.h"
#include "fdlimit.h" #include "file.h"
#include "list.h" #include "list.h"
#include "log.h" #include "log.h"
#include "platform.h" /* tr_lock () */ #include "platform.h" /* tr_lock () */
@@ -41,8 +41,8 @@ verifyTorrent (tr_torrent * tor, bool * stopFlag)
{ {
time_t end; time_t end;
SHA_CTX sha; SHA_CTX sha;
int fd = -1; tr_sys_file_t fd = TR_BAD_SYS_FILE;
int64_t filePos = 0; uint64_t filePos = 0;
bool changed = 0; bool changed = 0;
bool hadPiece = 0; bool hadPiece = 0;
time_t lastSleptAt = 0; time_t lastSleptAt = 0;
@@ -60,8 +60,8 @@ verifyTorrent (tr_torrent * tor, bool * stopFlag)
tr_torrentSetChecked (tor, 0); tr_torrentSetChecked (tor, 0);
while (!*stopFlag && (pieceIndex < tor->info.pieceCount)) while (!*stopFlag && (pieceIndex < tor->info.pieceCount))
{ {
uint32_t leftInPiece; uint64_t leftInPiece;
uint32_t bytesThisPass; uint64_t bytesThisPass;
uint64_t leftInFile; uint64_t leftInFile;
const tr_file * file = &tor->info.files[fileIndex]; const tr_file * file = &tor->info.files[fileIndex];
@@ -70,10 +70,11 @@ verifyTorrent (tr_torrent * tor, bool * stopFlag)
hadPiece = tr_torrentPieceIsComplete (tor, pieceIndex); hadPiece = tr_torrentPieceIsComplete (tor, pieceIndex);
/* if we're starting a new file... */ /* if we're starting a new file... */
if (!filePos && (fd<0) && (fileIndex!=prevFileIndex)) if (filePos == 0 && fd == TR_BAD_SYS_FILE && fileIndex != prevFileIndex)
{ {
char * filename = tr_torrentFindFile (tor, fileIndex); char * filename = tr_torrentFindFile (tor, fileIndex);
fd = filename == NULL ? -1 : tr_open_file_for_scanning (filename); fd = filename == NULL ? TR_BAD_SYS_FILE : tr_sys_file_open (filename,
TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, NULL);
tr_free (filename); tr_free (filename);
prevFileIndex = fileIndex; prevFileIndex = fileIndex;
} }
@@ -85,12 +86,12 @@ verifyTorrent (tr_torrent * tor, bool * stopFlag)
bytesThisPass = MIN (bytesThisPass, buflen); bytesThisPass = MIN (bytesThisPass, buflen);
/* read a bit */ /* read a bit */
if (fd >= 0) if (fd != TR_BAD_SYS_FILE)
{ {
const ssize_t numRead = tr_pread (fd, buffer, bytesThisPass, filePos); uint64_t numRead;
if (numRead > 0) if (tr_sys_file_read_at (fd, buffer, bytesThisPass, filePos, &numRead, NULL) && numRead > 0)
{ {
bytesThisPass = (uint32_t)numRead; bytesThisPass = numRead;
SHA1_Update (&sha, buffer, bytesThisPass); SHA1_Update (&sha, buffer, bytesThisPass);
#if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED #if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED
posix_fadvise (fd, filePos, bytesThisPass, POSIX_FADV_DONTNEED); posix_fadvise (fd, filePos, bytesThisPass, POSIX_FADV_DONTNEED);
@@ -140,10 +141,10 @@ verifyTorrent (tr_torrent * tor, bool * stopFlag)
/* if we're finishing a file... */ /* if we're finishing a file... */
if (leftInFile == 0) if (leftInFile == 0)
{ {
if (fd >= 0) if (fd != TR_BAD_SYS_FILE)
{ {
tr_close_file (fd); tr_sys_file_close (fd, NULL);
fd = -1; fd = TR_BAD_SYS_FILE;
} }
fileIndex++; fileIndex++;
filePos = 0; filePos = 0;
@@ -151,8 +152,8 @@ verifyTorrent (tr_torrent * tor, bool * stopFlag)
} }
/* cleanup */ /* cleanup */
if (fd >= 0) if (fd != TR_BAD_SYS_FILE)
tr_close_file (fd); tr_sys_file_close (fd, NULL);
free (buffer); free (buffer);
/* stopwatch */ /* stopwatch */