(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:
parent
2c0276fc23
commit
b33a7d4dc1
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h> /* strlen () */
|
||||
#include <unistd.h> /* sync() */
|
||||
|
||||
#include "transmission.h"
|
||||
|
@ -36,17 +37,16 @@ static const char * contents2 =
|
|||
static void
|
||||
create_text_file (const char * path, const char * contents)
|
||||
{
|
||||
FILE * fp;
|
||||
tr_sys_file_t fd;
|
||||
char * dir;
|
||||
|
||||
dir = tr_sys_path_dirname (path, NULL);
|
||||
tr_mkdirp (dir, 0700);
|
||||
tr_free (dir);
|
||||
|
||||
tr_sys_path_remove (path, NULL);
|
||||
fp = fopen (path, "w+");
|
||||
fprintf (fp, "%s", contents);
|
||||
fclose (fp);
|
||||
fd = tr_sys_file_open (path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0600, NULL);
|
||||
tr_sys_file_write (fd, contents, strlen (contents), NULL, NULL);
|
||||
tr_sys_file_close (fd, NULL);
|
||||
|
||||
sync ();
|
||||
}
|
||||
|
|
|
@ -13,32 +13,14 @@
|
|||
#include <stdlib.h> /* bsearch (), qsort () */
|
||||
#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 "blocklist.h"
|
||||
#include "error.h"
|
||||
#include "file.h"
|
||||
#include "log.h"
|
||||
#include "net.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
|
||||
/***
|
||||
**** PRIVATE
|
||||
|
@ -53,9 +35,9 @@ struct tr_ipv4_range
|
|||
struct tr_blocklistFile
|
||||
{
|
||||
bool isEnabled;
|
||||
int fd;
|
||||
tr_sys_file_t fd;
|
||||
size_t ruleCount;
|
||||
size_t byteCount;
|
||||
uint64_t byteCount;
|
||||
char * filename;
|
||||
struct tr_ipv4_range * rules;
|
||||
};
|
||||
|
@ -65,22 +47,23 @@ blocklistClose (tr_blocklistFile * b)
|
|||
{
|
||||
if (b->rules != NULL)
|
||||
{
|
||||
munmap (b->rules, b->byteCount);
|
||||
close (b->fd);
|
||||
tr_sys_file_unmap (b->rules, b->byteCount, NULL);
|
||||
tr_sys_file_close (b->fd, NULL);
|
||||
b->rules = NULL;
|
||||
b->ruleCount = 0;
|
||||
b->byteCount = 0;
|
||||
b->fd = -1;
|
||||
b->fd = TR_BAD_SYS_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
blocklistLoad (tr_blocklistFile * b)
|
||||
{
|
||||
int fd;
|
||||
size_t byteCount;
|
||||
tr_sys_file_t fd;
|
||||
uint64_t byteCount;
|
||||
tr_sys_path_info info;
|
||||
char * base;
|
||||
tr_error * error = NULL;
|
||||
const char * err_fmt = _("Couldn't read \"%1$s\": %2$s");
|
||||
|
||||
blocklistClose (b);
|
||||
|
@ -88,22 +71,24 @@ blocklistLoad (tr_blocklistFile * b)
|
|||
if (!tr_sys_path_get_info (b->filename, 0, &info, NULL))
|
||||
return;
|
||||
|
||||
byteCount = (size_t) info.size;
|
||||
byteCount = info.size;
|
||||
if (byteCount == 0)
|
||||
return;
|
||||
|
||||
fd = open (b->filename, O_RDONLY | O_BINARY);
|
||||
if (fd == -1)
|
||||
fd = tr_sys_file_open (b->filename, TR_SYS_FILE_READ, 0, &error);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
tr_logAddError (err_fmt, b->filename, tr_strerror (errno));
|
||||
close (fd);
|
||||
tr_logAddError (err_fmt, b->filename, error->message);
|
||||
tr_sys_file_close (fd, NULL);
|
||||
tr_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -151,7 +136,7 @@ tr_blocklistFileNew (const char * filename, bool isEnabled)
|
|||
tr_blocklistFile * b;
|
||||
|
||||
b = tr_new0 (tr_blocklistFile, 1);
|
||||
b->fd = -1;
|
||||
b->fd = TR_BAD_SYS_FILE;
|
||||
b->filename = tr_strdup (filename);
|
||||
b->isEnabled = isEnabled;
|
||||
|
||||
|
|
|
@ -7,38 +7,16 @@
|
|||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_POSIX_FADVISE
|
||||
#ifdef _XOPEN_SOURCE
|
||||
#undef _XOPEN_SOURCE
|
||||
#endif
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.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/resource.h> /* getrlimit */
|
||||
#include <fcntl.h> /* O_LARGEFILE posix_fadvise */
|
||||
#include <unistd.h> /* lseek (), write (), ftruncate (), pread (), pwrite (), etc */
|
||||
|
||||
#include "transmission.h"
|
||||
#include "error.h"
|
||||
#include "fdlimit.h"
|
||||
#include "file.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
|
||||
preallocate_file_sparse (int fd, uint64_t length)
|
||||
preallocate_file_sparse (tr_sys_file_t fd, uint64_t length)
|
||||
{
|
||||
const char zero = '\0';
|
||||
bool success = 0;
|
||||
|
@ -81,15 +46,18 @@ preallocate_file_sparse (int fd, uint64_t length)
|
|||
if (!length)
|
||||
success = true;
|
||||
|
||||
#ifdef HAVE_FALLOCATE64
|
||||
if (!success) /* fallocate64 is always preferred, so try it first */
|
||||
success = !fallocate64 (fd, 0, 0, length);
|
||||
#endif
|
||||
if (!success)
|
||||
success = tr_sys_file_preallocate (fd, length, TR_SYS_FILE_PREALLOC_SPARSE, NULL);
|
||||
|
||||
if (!success) /* fallback: the old-style seek-and-write */
|
||||
success = (lseek (fd, length-1, SEEK_SET) != -1)
|
||||
&& (write (fd, &zero, 1) != -1)
|
||||
&& (ftruncate (fd, length) != -1);
|
||||
{
|
||||
/* seek requires signed offset, so length should be in mod range */
|
||||
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;
|
||||
}
|
||||
|
@ -99,53 +67,10 @@ preallocate_file_full (const char * filename, uint64_t length)
|
|||
{
|
||||
bool success = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
HANDLE hFile = CreateFile (filename, GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
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)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
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
|
||||
success = tr_sys_file_preallocate (fd, length, 0, NULL);
|
||||
|
||||
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;
|
||||
while (success && (length > 0))
|
||||
{
|
||||
const int thisPass = MIN (length, sizeof (buf));
|
||||
success = write (fd, buf, thisPass) == thisPass;
|
||||
const uint64_t thisPass = MIN (length, sizeof (buf));
|
||||
uint64_t bytes_written;
|
||||
success = tr_sys_file_write (fd, buf, thisPass, &bytes_written, NULL) && bytes_written == thisPass;
|
||||
length -= thisPass;
|
||||
}
|
||||
}
|
||||
|
||||
close (fd);
|
||||
tr_sys_file_close (fd, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
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
|
||||
{
|
||||
bool is_writable;
|
||||
int fd;
|
||||
tr_sys_file_t fd;
|
||||
int torrent_id;
|
||||
tr_file_index_t file_index;
|
||||
time_t used_at;
|
||||
|
@ -307,7 +112,7 @@ cached_file_is_open (const struct tr_cached_file * o)
|
|||
{
|
||||
assert (o != NULL);
|
||||
|
||||
return o->fd >= 0;
|
||||
return o->fd != TR_BAD_SYS_FILE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -315,14 +120,14 @@ cached_file_close (struct tr_cached_file * o)
|
|||
{
|
||||
assert (cached_file_is_open (o));
|
||||
|
||||
tr_close_file (o->fd);
|
||||
o->fd = -1;
|
||||
tr_sys_file_close (o->fd, NULL);
|
||||
o->fd = TR_BAD_SYS_FILE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ().
|
||||
* plus the errno values set by tr_mkdirp () and tr_sys_file_open ().
|
||||
*/
|
||||
static int
|
||||
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;
|
||||
bool already_existed;
|
||||
bool resize_needed;
|
||||
tr_error * error = NULL;
|
||||
|
||||
/* create subfolders, if any */
|
||||
if (writable)
|
||||
|
@ -361,14 +167,15 @@ cached_file_open (struct tr_cached_file * o,
|
|||
writable |= resize_needed;
|
||||
|
||||
/* open the file */
|
||||
flags = writable ? (O_RDWR | O_CREAT) : O_RDONLY;
|
||||
flags |= O_LARGEFILE | O_BINARY | O_SEQUENTIAL;
|
||||
o->fd = open (filename, flags, 0666);
|
||||
flags = writable ? (TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE) : 0;
|
||||
flags |= TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL;
|
||||
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;
|
||||
tr_logAddError (_("Couldn't open \"%1$s\": %2$s"), filename, tr_strerror (err));
|
||||
const int err = error->code;
|
||||
tr_logAddError (_("Couldn't open \"%1$s\": %2$s"), filename, error->message);
|
||||
tr_error_free (error);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -378,21 +185,17 @@ cached_file_open (struct tr_cached_file * o,
|
|||
* http://trac.transmissionbt.com/ticket/2228
|
||||
* 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;
|
||||
tr_logAddError (_("Couldn't truncate \"%1$s\": %2$s"), filename, tr_strerror (err));
|
||||
const int err = error->code;
|
||||
tr_logAddError (_("Couldn't truncate \"%1$s\": %2$s"), filename, error->message);
|
||||
tr_error_free (error);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (writable && !already_existed && (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;
|
||||
}
|
||||
|
||||
|
@ -410,7 +213,7 @@ static void
|
|||
fileset_construct (struct tr_fileset * set, int n)
|
||||
{
|
||||
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->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
|
||||
* up-to-date when this function returns to the caller... */
|
||||
if (o->is_writable)
|
||||
tr_fsync (o->fd);
|
||||
tr_sys_file_flush (o->fd, NULL);
|
||||
|
||||
cached_file_close (o);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
tr_sys_file_t
|
||||
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);
|
||||
|
||||
if (!o || (writable && !o->is_writable))
|
||||
return -1;
|
||||
return TR_BAD_SYS_FILE;
|
||||
|
||||
o->used_at = tr_time ();
|
||||
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
|
||||
tr_fdFileGetCachedMTime (tr_session * s, int torrent_id, tr_file_index_t i, time_t * mtime)
|
||||
{
|
||||
bool success;
|
||||
struct stat sb;
|
||||
tr_sys_path_info info;
|
||||
struct tr_cached_file * o = fileset_lookup (get_fileset (s), torrent_id, i);
|
||||
|
||||
if ((success = (o != NULL) && !fstat (o->fd, &sb)))
|
||||
*mtime = TR_STAT_MTIME (sb);
|
||||
if ((success = (o != NULL) && tr_sys_file_get_info (o->fd, &info, NULL)))
|
||||
*mtime = info.last_modified_at;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
@ -612,8 +409,8 @@ tr_fdTorrentClose (tr_session * session, int torrent_id)
|
|||
fileset_close_torrent (get_fileset (session), torrent_id);
|
||||
}
|
||||
|
||||
/* returns an fd on success, or a -1 on failure and sets errno */
|
||||
int
|
||||
/* returns an fd on success, or a TR_BAD_SYS_FILE on failure and sets errno */
|
||||
tr_sys_file_t
|
||||
tr_fdFileCheckout (tr_session * session,
|
||||
int torrent_id,
|
||||
tr_file_index_t i,
|
||||
|
@ -636,7 +433,7 @@ tr_fdFileCheckout (tr_session * session,
|
|||
if (err)
|
||||
{
|
||||
errno = err;
|
||||
return -1;
|
||||
return TR_BAD_SYS_FILE;
|
||||
}
|
||||
|
||||
dbgmsg ("opened '%s' writable %c", filename, writable?'y':'n');
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#endif
|
||||
|
||||
#include "transmission.h"
|
||||
#include "file.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.
|
||||
*
|
||||
|
@ -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.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
int tr_fdFileCheckout (tr_session * session,
|
||||
int torrent_id,
|
||||
tr_file_index_t file_num,
|
||||
const char * filename,
|
||||
bool do_write,
|
||||
tr_preallocation_mode preallocation_mode,
|
||||
uint64_t preallocation_file_size);
|
||||
tr_sys_file_t tr_fdFileCheckout (tr_session * session,
|
||||
int torrent_id,
|
||||
tr_file_index_t file_num,
|
||||
const char * filename,
|
||||
bool do_write,
|
||||
tr_preallocation_mode preallocation_mode,
|
||||
uint64_t preallocation_file_size);
|
||||
|
||||
int tr_fdFileGetCached (tr_session * session,
|
||||
int torrent_id,
|
||||
tr_file_index_t file_num,
|
||||
bool doWrite);
|
||||
tr_sys_file_t tr_fdFileGetCached (tr_session * session,
|
||||
int torrent_id,
|
||||
tr_file_index_t file_num,
|
||||
bool doWrite);
|
||||
|
||||
bool tr_fdFileGetCachedMTime (tr_session * session,
|
||||
int torrent_id,
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
#include "transmission.h"
|
||||
#include "cache.h" /* tr_cacheReadBlock () */
|
||||
#include "error.h"
|
||||
#include "fdlimit.h"
|
||||
#include "file.h"
|
||||
#include "inout.h"
|
||||
#include "log.h"
|
||||
#include "peer-common.h" /* MAX_BLOCK_SIZE */
|
||||
|
@ -46,7 +48,7 @@ readOrWriteBytes (tr_session * session,
|
|||
void * buf,
|
||||
size_t buflen)
|
||||
{
|
||||
int fd;
|
||||
tr_sys_file_t fd;
|
||||
int err = 0;
|
||||
const bool doWrite = ioMode >= TR_IO_WRITE;
|
||||
const tr_info * const info = &tor->info;
|
||||
|
@ -64,7 +66,7 @@ readOrWriteBytes (tr_session * session,
|
|||
***/
|
||||
|
||||
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 */
|
||||
char * subpath;
|
||||
|
@ -94,7 +96,7 @@ readOrWriteBytes (tr_session * session,
|
|||
: tor->session->preallocationMode;
|
||||
if (((fd = tr_fdFileCheckout (session, tor->uniqueId, fileIndex,
|
||||
filename, doWrite,
|
||||
prealloc, file->length))) < 0)
|
||||
prealloc, file->length))) == TR_BAD_SYS_FILE)
|
||||
{
|
||||
err = errno;
|
||||
tr_logAddTorErr (tor, "tr_fdFileCheckout failed for \"%s\": %s",
|
||||
|
@ -118,27 +120,29 @@ readOrWriteBytes (tr_session * session,
|
|||
|
||||
if (!err)
|
||||
{
|
||||
tr_error * error = NULL;
|
||||
|
||||
if (ioMode == TR_IO_READ)
|
||||
{
|
||||
const int rc = tr_pread (fd, buf, buflen, fileOffset);
|
||||
if (rc < 0)
|
||||
if (!tr_sys_file_read_at (fd, buf, buflen, fileOffset, NULL, &error))
|
||||
{
|
||||
err = errno;
|
||||
tr_logAddTorErr (tor, "read failed for \"%s\": %s", file->name, tr_strerror (err));
|
||||
err = error->code;
|
||||
tr_logAddTorErr (tor, "read failed for \"%s\": %s", file->name, error->message);
|
||||
tr_error_free (error);
|
||||
}
|
||||
}
|
||||
else if (ioMode == TR_IO_WRITE)
|
||||
{
|
||||
const int rc = tr_pwrite (fd, buf, buflen, fileOffset);
|
||||
if (rc < 0)
|
||||
if (!tr_sys_file_write_at (fd, buf, buflen, fileOffset, NULL, &error))
|
||||
{
|
||||
err = errno;
|
||||
tr_logAddTorErr (tor, "write failed for \"%s\": %s", file->name, tr_strerror (err));
|
||||
err = error->code;
|
||||
tr_logAddTorErr (tor, "write failed for \"%s\": %s", file->name, error->message);
|
||||
tr_error_free (error);
|
||||
}
|
||||
}
|
||||
else if (ioMode == TR_IO_PREFETCH)
|
||||
{
|
||||
tr_prefetch (fd, fileOffset, buflen);
|
||||
tr_sys_file_prefetch (fd, fileOffset, buflen, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "transmission.h"
|
||||
#include "error.h"
|
||||
#include "file.h"
|
||||
#include "platform.h" /* TR_PATH_DELIMETER */
|
||||
#include "torrent.h"
|
||||
|
@ -373,7 +374,7 @@ libttest_zero_torrent_populate (tr_torrent * tor, bool complete)
|
|||
{
|
||||
int err;
|
||||
uint64_t j;
|
||||
FILE * fp;
|
||||
tr_sys_file_t fd;
|
||||
char * path;
|
||||
char * dirname;
|
||||
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);
|
||||
dirname = tr_sys_path_dirname (path, NULL);
|
||||
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)
|
||||
fputc (((!complete) && (i==0) && (j<tor->info.pieceSize)) ? '\1' : '\0', fp);
|
||||
fclose (fp);
|
||||
tr_sys_file_write (fd, ((!complete) && (i==0) && (j<tor->info.pieceSize)) ? "\1" : "\0", 1, NULL, NULL);
|
||||
tr_sys_file_close (fd, NULL);
|
||||
|
||||
tr_free (dirname);
|
||||
tr_free (path);
|
||||
|
@ -450,15 +451,14 @@ build_parent_dir (const char* path)
|
|||
void
|
||||
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;
|
||||
|
||||
build_parent_dir (path);
|
||||
|
||||
tr_sys_path_remove (path, NULL);
|
||||
fp = fopen (path, "wb");
|
||||
fwrite (payload, 1, n, fp);
|
||||
fclose (fp);
|
||||
fd = tr_sys_file_open (path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0600, NULL);
|
||||
tr_sys_file_write (fd, payload, n, NULL, NULL);
|
||||
tr_sys_file_close (fd, NULL);
|
||||
|
||||
sync ();
|
||||
|
||||
|
@ -474,24 +474,26 @@ libtest_create_file_with_string_contents (const char * path, const char* str)
|
|||
void
|
||||
libtest_create_tmpfile_with_contents (char* tmpl, const void* payload, size_t n)
|
||||
{
|
||||
int fd;
|
||||
tr_sys_file_t fd;
|
||||
const int tmperr = errno;
|
||||
size_t n_left = n;
|
||||
uint64_t n_left = n;
|
||||
tr_error * error = NULL;
|
||||
|
||||
build_parent_dir (tmpl);
|
||||
|
||||
fd = mkstemp (tmpl);
|
||||
fd = tr_sys_file_open_temp (tmpl, NULL);
|
||||
while (n_left > 0)
|
||||
{
|
||||
const ssize_t n = write (fd, payload, n_left);
|
||||
if (n == -1)
|
||||
uint64_t n;
|
||||
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;
|
||||
}
|
||||
n_left -= n;
|
||||
}
|
||||
close (fd);
|
||||
tr_sys_file_close (fd, NULL);
|
||||
|
||||
sync ();
|
||||
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h> /* FILE, stderr */
|
||||
#include <stdlib.h> /* qsort */
|
||||
#include <string.h> /* strcmp, strlen */
|
||||
|
||||
#include <unistd.h> /* read () */
|
||||
#include <dirent.h>
|
||||
|
||||
#include <event2/util.h> /* evutil_ascii_strcasecmp () */
|
||||
|
@ -21,7 +19,6 @@
|
|||
#include "transmission.h"
|
||||
#include "crypto.h" /* tr_sha1 */
|
||||
#include "error.h"
|
||||
#include "fdlimit.h" /* tr_open_file_for_scanning () */
|
||||
#include "file.h"
|
||||
#include "log.h"
|
||||
#include "session.h"
|
||||
|
@ -228,7 +225,8 @@ getHashInfo (tr_metainfo_builder * b)
|
|||
uint8_t *buf;
|
||||
uint64_t totalRemain;
|
||||
uint64_t off = 0;
|
||||
int fd;
|
||||
tr_sys_file_t fd;
|
||||
tr_error * error = NULL;
|
||||
|
||||
if (!b->totalSize)
|
||||
return ret;
|
||||
|
@ -236,16 +234,18 @@ getHashInfo (tr_metainfo_builder * b)
|
|||
buf = tr_valloc (b->pieceSize);
|
||||
b->pieceIndex = 0;
|
||||
totalRemain = b->totalSize;
|
||||
fd = tr_open_file_for_scanning (b->files[fileIndex].filename);
|
||||
if (fd < 0)
|
||||
fd = tr_sys_file_open (b->files[fileIndex].filename, TR_SYS_FILE_READ |
|
||||
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,
|
||||
b->files[fileIndex].filename,
|
||||
sizeof (b->errfile));
|
||||
b->result = TR_MAKEMETA_IO_READ;
|
||||
tr_free (buf);
|
||||
tr_free (ret);
|
||||
tr_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -253,34 +253,37 @@ getHashInfo (tr_metainfo_builder * b)
|
|||
{
|
||||
uint8_t * bufptr = buf;
|
||||
const uint32_t thisPieceSize = (uint32_t) MIN (b->pieceSize, totalRemain);
|
||||
uint32_t leftInPiece = thisPieceSize;
|
||||
uint64_t leftInPiece = thisPieceSize;
|
||||
|
||||
assert (b->pieceIndex < b->pieceCount);
|
||||
|
||||
while (leftInPiece)
|
||||
{
|
||||
const size_t n_this_pass = (size_t) MIN ((b->files[fileIndex].size - off), leftInPiece);
|
||||
const ssize_t n_read = read (fd, bufptr, n_this_pass);
|
||||
const uint64_t n_this_pass = MIN (b->files[fileIndex].size - off, leftInPiece);
|
||||
uint64_t n_read = 0;
|
||||
tr_sys_file_read (fd, bufptr, n_this_pass, &n_read, NULL);
|
||||
bufptr += n_read;
|
||||
off += n_read;
|
||||
leftInPiece -= n_read;
|
||||
if (off == b->files[fileIndex].size)
|
||||
{
|
||||
off = 0;
|
||||
tr_close_file (fd);
|
||||
fd = -1;
|
||||
tr_sys_file_close (fd, NULL);
|
||||
fd = TR_BAD_SYS_FILE;
|
||||
if (++fileIndex < b->fileCount)
|
||||
{
|
||||
fd = tr_open_file_for_scanning (b->files[fileIndex].filename);
|
||||
if (fd < 0)
|
||||
fd = tr_sys_file_open (b->files[fileIndex].filename, TR_SYS_FILE_READ |
|
||||
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,
|
||||
b->files[fileIndex].filename,
|
||||
sizeof (b->errfile));
|
||||
b->result = TR_MAKEMETA_IO_READ;
|
||||
tr_free (buf);
|
||||
tr_free (ret);
|
||||
tr_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -306,8 +309,8 @@ getHashInfo (tr_metainfo_builder * b)
|
|||
|| (walk - ret == (int)(SHA_DIGEST_LENGTH * b->pieceCount)));
|
||||
assert (b->abortFlag || !totalRemain);
|
||||
|
||||
if (fd >= 0)
|
||||
tr_close_file (fd);
|
||||
if (fd != TR_BAD_SYS_FILE)
|
||||
tr_sys_file_close (fd, NULL);
|
||||
|
||||
tr_free (buf);
|
||||
return ret;
|
||||
|
|
|
@ -565,123 +565,3 @@ tr_getWebClientDir (const tr_session * session UNUSED)
|
|||
|
||||
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
|
||||
|
|
|
@ -77,12 +77,6 @@ void tr_lockUnlock (tr_lock *);
|
|||
/** @brief return nonzero if the specified lock is locked */
|
||||
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
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include <unistd.h> /* close */
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <event2/buffer.h>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "transmission.h"
|
||||
#include "completion.h"
|
||||
#include "error.h"
|
||||
#include "fdlimit.h"
|
||||
#include "file.h"
|
||||
#include "log.h"
|
||||
|
@ -1487,13 +1488,14 @@ gotNewBlocklist (tr_session * session,
|
|||
}
|
||||
else /* successfully fetched the blocklist... */
|
||||
{
|
||||
int fd;
|
||||
tr_sys_file_t fd;
|
||||
int err;
|
||||
char * filename;
|
||||
z_stream stream;
|
||||
const char * configDir = tr_sessionGetConfigDir (session);
|
||||
const size_t buflen = 1024 * 128; /* 128 KiB buffer */
|
||||
uint8_t * buf = tr_valloc (buflen);
|
||||
tr_error * error = NULL;
|
||||
|
||||
/* this is an odd Magic Number required by zlib to enable gz support.
|
||||
See zlib's inflateInit2 () documentation for a full description */
|
||||
|
@ -1506,10 +1508,13 @@ gotNewBlocklist (tr_session * session,
|
|||
stream.avail_in = response_byte_count;
|
||||
inflateInit2 (&stream, windowBits);
|
||||
|
||||
filename = tr_buildPath (configDir, "blocklist.tmp", NULL);
|
||||
fd = tr_open_file_for_writing (filename);
|
||||
if (fd < 0)
|
||||
tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, tr_strerror (errno));
|
||||
filename = tr_buildPath (configDir, "blocklist.tmp.XXXXXX", NULL);
|
||||
fd = tr_sys_file_open_temp (filename, &error);
|
||||
if (fd == TR_BAD_SYS_FILE)
|
||||
{
|
||||
tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, error->message);
|
||||
tr_error_clear (&error);
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
@ -1519,10 +1524,10 @@ gotNewBlocklist (tr_session * session,
|
|||
|
||||
if (stream.avail_out < buflen)
|
||||
{
|
||||
const int e = write (fd, buf, buflen - stream.avail_out);
|
||||
if (e < 0)
|
||||
if (!tr_sys_file_write (fd, buf, buflen - stream.avail_out, 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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1538,10 +1543,13 @@ gotNewBlocklist (tr_session * session,
|
|||
inflateEnd (&stream);
|
||||
|
||||
if (err == Z_DATA_ERROR) /* couldn't inflate it... it's probably already uncompressed */
|
||||
if (write (fd, response, response_byte_count) < 0)
|
||||
tr_snprintf (result, sizeof (result), _("Couldn't save file \"%1$s\": %2$s"), filename, tr_strerror (errno));
|
||||
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, error->message);
|
||||
tr_error_clear (&error);
|
||||
}
|
||||
|
||||
tr_close_file(fd);
|
||||
tr_sys_file_close (fd, NULL);
|
||||
|
||||
if (*result)
|
||||
{
|
||||
|
|
|
@ -155,19 +155,19 @@ tr_torrentGetMetadataPiece (tr_torrent * tor, int piece, int * len)
|
|||
|
||||
if (tr_torrentHasMetadata (tor))
|
||||
{
|
||||
FILE * fp;
|
||||
tr_sys_file_t fd;
|
||||
|
||||
ensureInfoDictOffsetIsCached (tor);
|
||||
|
||||
assert (tor->infoDictLength > 0);
|
||||
assert (tor->infoDictOffset >= 0);
|
||||
|
||||
fp = fopen (tor->info.torrent, "rb");
|
||||
if (fp != NULL)
|
||||
fd = tr_sys_file_open (tor->info.torrent, TR_SYS_FILE_READ, 0, NULL);
|
||||
if (fd != TR_BAD_SYS_FILE)
|
||||
{
|
||||
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
|
||||
? METADATA_PIECE_SIZE
|
||||
|
@ -176,8 +176,8 @@ tr_torrentGetMetadataPiece (tr_torrent * tor, int piece, int * len)
|
|||
if (0<l && l<=METADATA_PIECE_SIZE)
|
||||
{
|
||||
char * buf = tr_new (char, l);
|
||||
const int n = fread (buf, 1, l, fp);
|
||||
if (n == l)
|
||||
uint64_t n;
|
||||
if (tr_sys_file_read (fd, buf, l, &n, NULL) && n == (unsigned int) l)
|
||||
{
|
||||
*len = l;
|
||||
ret = buf;
|
||||
|
@ -188,7 +188,7 @@ tr_torrentGetMetadataPiece (tr_torrent * tor, int piece, int * len)
|
|||
}
|
||||
}
|
||||
|
||||
fclose (fp);
|
||||
tr_sys_file_close (fd, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,14 +28,14 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h> /* strerror (), memset (), memmem () */
|
||||
#include <time.h> /* nanosleep () */
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef HAVE_ICONV_OPEN
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h> /* stat (), getpagesize () */
|
||||
#include <unistd.h> /* getpagesize () */
|
||||
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/event.h>
|
||||
|
@ -48,7 +48,6 @@
|
|||
|
||||
#include "transmission.h"
|
||||
#include "error.h"
|
||||
#include "fdlimit.h"
|
||||
#include "file.h"
|
||||
#include "ConvertUTF.h"
|
||||
#include "list.h"
|
||||
|
@ -221,8 +220,7 @@ tr_loadFile (const char * path,
|
|||
{
|
||||
uint8_t * buf;
|
||||
tr_sys_path_info info;
|
||||
int fd;
|
||||
ssize_t n;
|
||||
tr_sys_file_t fd;
|
||||
tr_error * error = NULL;
|
||||
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);
|
||||
|
||||
/* Load the torrent file into our buffer */
|
||||
fd = tr_open_file_for_scanning (path);
|
||||
if (fd < 0)
|
||||
fd = tr_sys_file_open (path, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &error);
|
||||
if (fd == TR_BAD_SYS_FILE)
|
||||
{
|
||||
const int err = errno;
|
||||
tr_logAddError (err_fmt, path, tr_strerror (errno));
|
||||
const int err = error->code;
|
||||
tr_logAddError (err_fmt, path, error->message);
|
||||
tr_error_free (error);
|
||||
errno = err;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -261,22 +260,22 @@ tr_loadFile (const char * path,
|
|||
{
|
||||
const int err = errno;
|
||||
tr_logAddError (err_fmt, path, _("Memory allocation failed"));
|
||||
tr_close_file (fd);
|
||||
tr_sys_file_close (fd, NULL);
|
||||
errno = err;
|
||||
return NULL;
|
||||
}
|
||||
n = read (fd, buf, (size_t)info.size);
|
||||
if (n == -1)
|
||||
if (!tr_sys_file_read (fd, buf, info.size, NULL, &error))
|
||||
{
|
||||
const int err = errno;
|
||||
tr_logAddError (err_fmt, path, tr_strerror (errno));
|
||||
tr_close_file (fd);
|
||||
const int err = error->code;
|
||||
tr_logAddError (err_fmt, path, error->message);
|
||||
tr_sys_file_close (fd, NULL);
|
||||
free (buf);
|
||||
tr_error_free (error);
|
||||
errno = err;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tr_close_file (fd);
|
||||
tr_sys_file_close (fd, NULL);
|
||||
buf[info.size] = '\0';
|
||||
*size = info.size;
|
||||
return buf;
|
||||
|
@ -1544,11 +1543,11 @@ tr_strratio (char * buf, size_t buflen, double ratio, const char * infinity)
|
|||
int
|
||||
tr_moveFile (const char * oldpath, const char * newpath, bool * renamed)
|
||||
{
|
||||
int in;
|
||||
int out;
|
||||
tr_sys_file_t in;
|
||||
tr_sys_file_t out;
|
||||
char * buf;
|
||||
tr_sys_path_info info;
|
||||
off_t bytesLeft;
|
||||
uint64_t bytesLeft;
|
||||
const size_t buflen = 1024 * 128; /* 128 KiB buffer */
|
||||
tr_error * error = NULL;
|
||||
|
||||
|
@ -1586,26 +1585,24 @@ tr_moveFile (const char * oldpath, const char * newpath, bool * renamed)
|
|||
}
|
||||
|
||||
/* copy the file */
|
||||
in = tr_open_file_for_scanning (oldpath);
|
||||
out = tr_open_file_for_writing (newpath);
|
||||
in = tr_sys_file_open (oldpath, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, NULL);
|
||||
out = tr_sys_file_open (newpath, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0666, NULL);
|
||||
buf = tr_valloc (buflen);
|
||||
while (bytesLeft > 0)
|
||||
{
|
||||
ssize_t bytesWritten;
|
||||
const off_t bytesThisPass = MIN (bytesLeft, (off_t)buflen);
|
||||
const int numRead = read (in, buf, bytesThisPass);
|
||||
if (numRead < 0)
|
||||
const uint64_t bytesThisPass = MIN (bytesLeft, buflen);
|
||||
uint64_t numRead, bytesWritten;
|
||||
if (!tr_sys_file_read (in, buf, bytesThisPass, &numRead, NULL))
|
||||
break;
|
||||
bytesWritten = write (out, buf, numRead);
|
||||
if (bytesWritten < 0)
|
||||
if (!tr_sys_file_write (out, buf, numRead, &bytesWritten, NULL))
|
||||
break;
|
||||
bytesLeft -= bytesWritten;
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
tr_free (buf);
|
||||
tr_close_file (out);
|
||||
tr_close_file (in);
|
||||
tr_sys_file_close (out, NULL);
|
||||
tr_sys_file_close (in, NULL);
|
||||
if (bytesLeft != 0)
|
||||
return -1;
|
||||
|
||||
|
|
|
@ -9,24 +9,20 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h> /* strtod(), realloc(), qsort(), mkstemp() */
|
||||
#include <stdlib.h> /* strtod(), realloc(), qsort() */
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32 /* tr_mkstemp() */
|
||||
#include <fcntl.h>
|
||||
#ifdef _WIN32
|
||||
#include <share.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <locale.h> /* setlocale() */
|
||||
#include <unistd.h> /* write() */
|
||||
|
||||
#include <event2/buffer.h>
|
||||
|
||||
#define __LIBTRANSMISSION_VARIANT_MODULE___
|
||||
#include "transmission.h"
|
||||
#include "ConvertUTF.h"
|
||||
#include "fdlimit.h" /* tr_close_file() */
|
||||
#include "error.h"
|
||||
#include "file.h"
|
||||
#include "log.h"
|
||||
|
@ -1125,55 +1121,28 @@ tr_variantToStr (const tr_variant * v, tr_variant_fmt fmt, int * len)
|
|||
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
|
||||
tr_variantToFile (const tr_variant * v,
|
||||
tr_variant_fmt fmt,
|
||||
const char * filename)
|
||||
{
|
||||
char * tmp;
|
||||
int fd;
|
||||
tr_sys_file_t fd;
|
||||
int err = 0;
|
||||
char * real_filename;
|
||||
tr_error * error = NULL;
|
||||
|
||||
/* 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)
|
||||
filename = real_filename;
|
||||
|
||||
/* 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);
|
||||
fd = tr_mkstemp (tmp);
|
||||
tr_set_file_for_single_pass (fd);
|
||||
if (fd >= 0)
|
||||
fd = tr_sys_file_open_temp (tmp, &error);
|
||||
if (fd != TR_BAD_SYS_FILE)
|
||||
{
|
||||
int nleft;
|
||||
uint64_t nleft;
|
||||
|
||||
/* save the variant to a temporary file */
|
||||
{
|
||||
|
@ -1183,34 +1152,31 @@ tr_variantToFile (const tr_variant * v,
|
|||
|
||||
while (nleft > 0)
|
||||
{
|
||||
const int n = write (fd, walk, nleft);
|
||||
if (n >= 0)
|
||||
uint64_t n;
|
||||
if (!tr_sys_file_write (fd, walk, nleft, &n, &error))
|
||||
{
|
||||
nleft -= n;
|
||||
walk += n;
|
||||
}
|
||||
else if (errno != EAGAIN)
|
||||
{
|
||||
err = errno;
|
||||
err = error->code;
|
||||
break;
|
||||
}
|
||||
|
||||
nleft -= n;
|
||||
walk += n;
|
||||
}
|
||||
|
||||
evbuffer_free (buf);
|
||||
}
|
||||
|
||||
tr_sys_file_close (fd, NULL);
|
||||
|
||||
if (nleft > 0)
|
||||
{
|
||||
tr_logAddError (_("Couldn't save temporary file \"%1$s\": %2$s"), tmp, tr_strerror (err));
|
||||
tr_close_file (fd);
|
||||
tr_logAddError (_("Couldn't save temporary file \"%1$s\": %2$s"), tmp, error->message);
|
||||
tr_sys_path_remove (tmp, NULL);
|
||||
tr_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_error * error = NULL;
|
||||
|
||||
tr_close_file (fd);
|
||||
|
||||
tr_error_clear (&error);
|
||||
if (tr_sys_path_rename (tmp, filename, &error))
|
||||
{
|
||||
tr_logAddInfo (_("Saved \"%s\""), filename);
|
||||
|
@ -1226,8 +1192,9 @@ tr_variantToFile (const tr_variant * v,
|
|||
}
|
||||
else
|
||||
{
|
||||
err = errno;
|
||||
tr_logAddError (_("Couldn't save temporary file \"%1$s\": %2$s"), tmp, tr_strerror (err));
|
||||
err = error->code;
|
||||
tr_logAddError (_("Couldn't save temporary file \"%1$s\": %2$s"), tmp, error->message);
|
||||
tr_error_free (error);
|
||||
}
|
||||
|
||||
tr_free (tmp);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include "transmission.h"
|
||||
#include "completion.h"
|
||||
#include "fdlimit.h"
|
||||
#include "file.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "platform.h" /* tr_lock () */
|
||||
|
@ -41,8 +41,8 @@ verifyTorrent (tr_torrent * tor, bool * stopFlag)
|
|||
{
|
||||
time_t end;
|
||||
SHA_CTX sha;
|
||||
int fd = -1;
|
||||
int64_t filePos = 0;
|
||||
tr_sys_file_t fd = TR_BAD_SYS_FILE;
|
||||
uint64_t filePos = 0;
|
||||
bool changed = 0;
|
||||
bool hadPiece = 0;
|
||||
time_t lastSleptAt = 0;
|
||||
|
@ -60,8 +60,8 @@ verifyTorrent (tr_torrent * tor, bool * stopFlag)
|
|||
tr_torrentSetChecked (tor, 0);
|
||||
while (!*stopFlag && (pieceIndex < tor->info.pieceCount))
|
||||
{
|
||||
uint32_t leftInPiece;
|
||||
uint32_t bytesThisPass;
|
||||
uint64_t leftInPiece;
|
||||
uint64_t bytesThisPass;
|
||||
uint64_t leftInFile;
|
||||
const tr_file * file = &tor->info.files[fileIndex];
|
||||
|
||||
|
@ -70,10 +70,11 @@ verifyTorrent (tr_torrent * tor, bool * stopFlag)
|
|||
hadPiece = tr_torrentPieceIsComplete (tor, pieceIndex);
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
prevFileIndex = fileIndex;
|
||||
}
|
||||
|
@ -85,12 +86,12 @@ verifyTorrent (tr_torrent * tor, bool * stopFlag)
|
|||
bytesThisPass = MIN (bytesThisPass, buflen);
|
||||
|
||||
/* read a bit */
|
||||
if (fd >= 0)
|
||||
if (fd != TR_BAD_SYS_FILE)
|
||||
{
|
||||
const ssize_t numRead = tr_pread (fd, buffer, bytesThisPass, filePos);
|
||||
if (numRead > 0)
|
||||
uint64_t numRead;
|
||||
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);
|
||||
#if defined HAVE_POSIX_FADVISE && defined 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 (leftInFile == 0)
|
||||
{
|
||||
if (fd >= 0)
|
||||
if (fd != TR_BAD_SYS_FILE)
|
||||
{
|
||||
tr_close_file (fd);
|
||||
fd = -1;
|
||||
tr_sys_file_close (fd, NULL);
|
||||
fd = TR_BAD_SYS_FILE;
|
||||
}
|
||||
fileIndex++;
|
||||
filePos = 0;
|
||||
|
@ -151,8 +152,8 @@ verifyTorrent (tr_torrent * tor, bool * stopFlag)
|
|||
}
|
||||
|
||||
/* cleanup */
|
||||
if (fd >= 0)
|
||||
tr_close_file (fd);
|
||||
if (fd != TR_BAD_SYS_FILE)
|
||||
tr_sys_file_close (fd, NULL);
|
||||
free (buffer);
|
||||
|
||||
/* stopwatch */
|
||||
|
|
Loading…
Reference in New Issue