Changeset 14321


Ignore:
Timestamp:
Jul 8, 2014, 12:15:12 AM (8 years ago)
Author:
jordan
Message:

(trunk, libT) #4160 'foreign character support' -- merge mike.dld's 4160-03a-file.platch, which introduces tr_sys_file_*() portability wrappers

Location:
trunk/libtransmission
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/file-posix.c

    r14314 r14321  
    88 */
    99
    10 #if defined (HAVE_CANONICALIZE_FILE_NAME) && !defined (_GNU_SOURCE)
     10#if (defined (HAVE_POSIX_FADVISE) || defined (HAVE_POSIX_FALLOCATE)) && (!defined (_XOPEN_SOURCE) || _XOPEN_SOURCE < 600)
     11 #ifdef _XOPEN_SOURCE
     12  #undef _XOPEN_SOURCE
     13 #endif
     14 #define _XOPEN_SOURCE 600
     15#endif
     16
     17#if (defined (HAVE_FALLOCATE64) || defined (HAVE_CANONICALIZE_FILE_NAME)) && !defined (_GNU_SOURCE)
    1118 #define _GNU_SOURCE
     19#endif
     20
     21#if defined (__APPLE__) && !defined (_DARWIN_C_SOURCE)
     22 #define _DARWIN_C_SOURCE
    1223#endif
    1324
    1425#include <assert.h>
    1526#include <errno.h>
     27#include <fcntl.h> /* O_LARGEFILE, posix_fadvise (), [posix_]fallocate () */
    1628#include <libgen.h> /* basename (), dirname () */
    1729#include <limits.h> /* PATH_MAX */
    1830#include <stdio.h>
    1931#include <stdlib.h>
     32#include <string.h>
     33#include <sys/mman.h> /* mmap (), munmap () */
    2034#include <sys/types.h>
    2135#include <sys/stat.h>
    22 #include <unistd.h>
     36#include <unistd.h> /* lseek (), write (), ftruncate (), pread (), pwrite (), pathconf (), etc */
     37
     38#ifdef HAVE_XFS_XFS_H
     39 #include <xfs/xfs.h>
     40#endif
    2341
    2442#include "transmission.h"
    2543#include "file.h"
     44#include "platform.h"
    2645#include "utils.h"
     46
     47#ifndef O_LARGEFILE
     48 #define O_LARGEFILE 0
     49#endif
     50#ifndef O_BINARY
     51 #define O_BINARY 0
     52#endif
     53#ifndef O_SEQUENTIAL
     54 #define O_SEQUENTIAL 0
     55#endif
     56#ifndef O_CLOEXEC
     57 #define O_CLOEXEC 0
     58#endif
    2759
    2860#ifndef PATH_MAX
    2961 #define PATH_MAX 4096
     62#endif
     63
     64/* don't use pread/pwrite on old versions of uClibc because they're buggy.
     65 * https://trac.transmissionbt.com/ticket/3826 */
     66#ifdef __UCLIBC__
     67#define TR_UCLIBC_CHECK_VERSION(major,minor,micro) \
     68  (__UCLIBC_MAJOR__ > (major) || \
     69   (__UCLIBC_MAJOR__ == (major) && __UCLIBC_MINOR__ > (minor)) || \
     70   (__UCLIBC_MAJOR__ == (major) && __UCLIBC_MINOR__ == (minor) && \
     71      __UCLIBC_SUBLEVEL__ >= (micro)))
     72#if !TR_UCLIBC_CHECK_VERSION (0,9,28)
     73 #undef HAVE_PREAD
     74 #undef HAVE_PWRITE
     75#endif
     76#endif
     77
     78#ifdef __APPLE__
     79 #ifndef HAVE_PREAD
     80  #define HAVE_PREAD
     81 #endif
     82 #ifndef HAVE_PWRITE
     83  #define HAVE_PWRITE
     84 #endif
     85 #ifndef HAVE_MKDTEMP
     86  #define HAVE_MKDTEMP
     87 #endif
    3088#endif
    3189
     
    63121}
    64122
     123static void
     124set_file_for_single_pass (tr_sys_file_t handle)
     125{
     126  /* Set hints about the lookahead buffer and caching. It's okay
     127     for these to fail silently, so don't let them affect errno */
     128
     129  const int err = errno;
     130
     131  if (handle == TR_BAD_SYS_FILE)
     132    return;
     133
     134#ifdef HAVE_POSIX_FADVISE
     135
     136  posix_fadvise (handle, 0, 0, POSIX_FADV_SEQUENTIAL);
     137
     138#endif
     139
     140#ifdef __APPLE__
     141
     142  fcntl (handle, F_RDAHEAD, 1);
     143  fcntl (handle, F_NOCACHE, 1);
     144
     145#endif
     146
     147  errno = err;
     148}
     149
    65150bool
    66151tr_sys_path_exists (const char  * path,
     
    239324  return ret;
    240325}
     326
     327tr_sys_file_t
     328tr_sys_file_get_std (tr_std_sys_file_t    std_file,
     329                     tr_error          ** error)
     330{
     331  tr_sys_file_t ret = TR_BAD_SYS_FILE;
     332
     333  switch (std_file)
     334    {
     335    case TR_STD_SYS_FILE_IN:
     336      ret = STDIN_FILENO;
     337      break;
     338    case TR_STD_SYS_FILE_OUT:
     339      ret = STDOUT_FILENO;
     340      break;
     341    case TR_STD_SYS_FILE_ERR:
     342      ret = STDERR_FILENO;
     343      break;
     344    default:
     345      assert (0 && "Unknown standard file");
     346      set_system_error (error, EINVAL);
     347    }
     348
     349  return ret;
     350}
     351
     352tr_sys_file_t
     353tr_sys_file_open (const char  * path,
     354                  int           flags,
     355                  int           permissions,
     356                  tr_error   ** error)
     357{
     358  tr_sys_file_t ret;
     359  int native_flags = 0;
     360
     361  assert (path != NULL);
     362  assert ((flags & (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE)) != 0);
     363
     364  if ((flags & (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE)) == (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE))
     365    native_flags |= O_RDWR;
     366  else if (flags & TR_SYS_FILE_READ)
     367    native_flags |= O_RDONLY;
     368  else if (flags & TR_SYS_FILE_WRITE)
     369    native_flags |= O_WRONLY;
     370
     371  native_flags |=
     372    (flags & TR_SYS_FILE_CREATE ? O_CREAT : 0) |
     373    (flags & TR_SYS_FILE_CREATE_NEW ? O_CREAT | O_EXCL : 0) |
     374    (flags & TR_SYS_FILE_APPEND ? O_APPEND : 0) |
     375    (flags & TR_SYS_FILE_TRUNCATE ? O_TRUNC : 0) |
     376    (flags & TR_SYS_FILE_SEQUENTIAL ? O_SEQUENTIAL : 0) |
     377    O_BINARY | O_LARGEFILE | O_CLOEXEC;
     378
     379  ret = open (path, native_flags, permissions);
     380
     381  if (ret != TR_BAD_SYS_FILE)
     382    {
     383      if (flags & TR_SYS_FILE_SEQUENTIAL)
     384        set_file_for_single_pass (ret);
     385    }
     386  else
     387    {
     388      set_system_error (error, errno);
     389    }
     390
     391  return ret;
     392}
     393
     394tr_sys_file_t
     395tr_sys_file_open_temp (char      * path_template,
     396                       tr_error ** error)
     397{
     398  tr_sys_file_t ret;
     399
     400  assert (path_template != NULL);
     401
     402  ret = mkstemp (path_template);
     403
     404  if (ret == TR_BAD_SYS_FILE)
     405    set_system_error (error, errno);
     406
     407  set_file_for_single_pass (ret);
     408
     409  return ret;
     410}
     411
     412bool
     413tr_sys_file_close (tr_sys_file_t    handle,
     414                   tr_error      ** error)
     415{
     416  bool ret;
     417
     418  assert (handle != TR_BAD_SYS_FILE);
     419
     420  ret = close (handle) != -1;
     421
     422  if (!ret)
     423    set_system_error (error, errno);
     424
     425  return ret;
     426}
     427
     428bool
     429tr_sys_file_get_info (tr_sys_file_t       handle,
     430                      tr_sys_path_info  * info,
     431                      tr_error         ** error)
     432{
     433  bool ret;
     434  struct stat sb;
     435
     436  assert (handle != TR_BAD_SYS_FILE);
     437  assert (info != NULL);
     438
     439  ret = fstat (handle, &sb) != -1;
     440
     441  if (ret)
     442    stat_to_sys_path_info (&sb, info);
     443  else
     444    set_system_error (error, errno);
     445
     446  return ret;
     447}
     448
     449bool
     450tr_sys_file_seek (tr_sys_file_t       handle,
     451                  int64_t             offset,
     452                  tr_seek_origin_t    origin,
     453                  uint64_t          * new_offset,
     454                  tr_error         ** error)
     455{
     456  bool ret = false;
     457  off_t my_new_offset;
     458
     459  TR_STATIC_ASSERT (TR_SEEK_SET == SEEK_SET, "values should match");
     460  TR_STATIC_ASSERT (TR_SEEK_CUR == SEEK_CUR, "values should match");
     461  TR_STATIC_ASSERT (TR_SEEK_END == SEEK_END, "values should match");
     462
     463  TR_STATIC_ASSERT (sizeof (*new_offset) >= sizeof (my_new_offset), "");
     464
     465  assert (handle != TR_BAD_SYS_FILE);
     466  assert (origin == TR_SEEK_SET || origin == TR_SEEK_CUR || origin == TR_SEEK_END);
     467
     468  my_new_offset = lseek (handle, offset, origin);
     469
     470  if (my_new_offset != (off_t)-1)
     471    {
     472      if (new_offset != NULL)
     473        *new_offset = my_new_offset;
     474      ret = true;
     475    }
     476  else
     477    {
     478      set_system_error (error, errno);
     479    }
     480
     481  return ret;
     482}
     483
     484bool
     485tr_sys_file_read (tr_sys_file_t    handle,
     486                  void           * buffer,
     487                  uint64_t         size,
     488                  uint64_t       * bytes_read,
     489                  tr_error      ** error)
     490{
     491  bool ret = false;
     492  ssize_t my_bytes_read;
     493
     494  TR_STATIC_ASSERT (sizeof (*bytes_read) >= sizeof (my_bytes_read), "");
     495
     496  assert (handle != TR_BAD_SYS_FILE);
     497  assert (buffer != NULL || size == 0);
     498
     499  my_bytes_read = read (handle, buffer, size);
     500
     501  if (my_bytes_read != -1)
     502    {
     503      if (bytes_read != NULL)
     504        *bytes_read = my_bytes_read;
     505      ret = true;
     506    }
     507  else
     508    {
     509      set_system_error (error, errno);
     510    }
     511
     512  return ret;
     513}
     514
     515bool
     516tr_sys_file_read_at (tr_sys_file_t    handle,
     517                     void           * buffer,
     518                     uint64_t         size,
     519                     uint64_t         offset,
     520                     uint64_t       * bytes_read,
     521                     tr_error      ** error)
     522{
     523  bool ret = false;
     524  ssize_t my_bytes_read;
     525
     526  TR_STATIC_ASSERT (sizeof (*bytes_read) >= sizeof (my_bytes_read), "");
     527
     528  assert (handle != TR_BAD_SYS_FILE);
     529  assert (buffer != NULL || size == 0);
     530
     531#ifdef HAVE_PREAD
     532
     533  my_bytes_read = pread (handle, buffer, size, offset);
     534
     535#else
     536
     537  if (lseek (handle, offset, SEEK_SET) != -1)
     538    my_bytes_read = read (handle, buffer, size);
     539  else
     540    my_bytes_read = -1;
     541
     542#endif
     543
     544  if (my_bytes_read != -1)
     545    {
     546      if (bytes_read != NULL)
     547        *bytes_read = my_bytes_read;
     548      ret = true;
     549    }
     550  else
     551    {
     552      set_system_error (error, errno);
     553    }
     554
     555  return ret;
     556}
     557
     558bool
     559tr_sys_file_write (tr_sys_file_t    handle,
     560                   const void     * buffer,
     561                   uint64_t         size,
     562                   uint64_t       * bytes_written,
     563                   tr_error      ** error)
     564{
     565  bool ret = false;
     566  ssize_t my_bytes_written;
     567
     568  TR_STATIC_ASSERT (sizeof (*bytes_written) >= sizeof (my_bytes_written), "");
     569
     570  assert (handle != TR_BAD_SYS_FILE);
     571  assert (buffer != NULL || size == 0);
     572
     573  my_bytes_written = write (handle, buffer, size);
     574
     575  if (my_bytes_written != -1)
     576    {
     577      if (bytes_written != NULL)
     578        *bytes_written = my_bytes_written;
     579      ret = true;
     580    }
     581  else
     582    {
     583      set_system_error (error, errno);
     584    }
     585
     586  return ret;
     587}
     588
     589bool
     590tr_sys_file_write_at (tr_sys_file_t    handle,
     591                      const void     * buffer,
     592                      uint64_t         size,
     593                      uint64_t         offset,
     594                      uint64_t       * bytes_written,
     595                      tr_error      ** error)
     596{
     597  bool ret = false;
     598  ssize_t my_bytes_written;
     599
     600  TR_STATIC_ASSERT (sizeof (*bytes_written) >= sizeof (my_bytes_written), "");
     601
     602  assert (handle != TR_BAD_SYS_FILE);
     603  assert (buffer != NULL || size == 0);
     604
     605#ifdef HAVE_PWRITE
     606
     607  my_bytes_written = pwrite (handle, buffer, size, offset);
     608
     609#else
     610
     611  if (lseek (handle, offset, SEEK_SET) != -1)
     612    my_bytes_written = write (handle, buffer, size);
     613  else
     614    my_bytes_written = -1;
     615
     616#endif
     617
     618  if (my_bytes_written != -1)
     619    {
     620      if (bytes_written != NULL)
     621        *bytes_written = my_bytes_written;
     622      ret = true;
     623    }
     624  else
     625    {
     626      set_system_error (error, errno);
     627    }
     628
     629  return ret;
     630}
     631
     632bool
     633tr_sys_file_flush (tr_sys_file_t    handle,
     634                   tr_error      ** error)
     635{
     636  bool ret;
     637
     638  assert (handle != TR_BAD_SYS_FILE);
     639
     640  ret = fsync (handle) != -1;
     641
     642  if (!ret)
     643    set_system_error (error, errno);
     644
     645  return ret;
     646}
     647
     648bool
     649tr_sys_file_truncate (tr_sys_file_t    handle,
     650                      uint64_t         size,
     651                      tr_error      ** error)
     652{
     653  bool ret;
     654
     655  assert (handle != TR_BAD_SYS_FILE);
     656
     657  ret = ftruncate (handle, size) != -1;
     658
     659  if (!ret)
     660    set_system_error (error, errno);
     661
     662  return ret;
     663}
     664
     665bool
     666tr_sys_file_prefetch (tr_sys_file_t    handle,
     667                      uint64_t         offset,
     668                      uint64_t         size,
     669                      tr_error      ** error)
     670{
     671  bool ret = false;
     672
     673#if defined (HAVE_POSIX_FADVISE)
     674
     675  int code;
     676
     677  assert (handle != TR_BAD_SYS_FILE);
     678  assert (size > 0);
     679
     680  code = posix_fadvise (handle, offset, size, POSIX_FADV_WILLNEED);
     681
     682  if (code == 0)
     683    ret = true;
     684  else
     685    set_system_error (error, code);
     686
     687#elif defined (__APPLE__)
     688
     689  struct radvisory radv;
     690
     691  assert (handle != TR_BAD_SYS_FILE);
     692  assert (size > 0);
     693
     694  radv.ra_offset = offset;
     695  radv.ra_count = size;
     696
     697  ret = fcntl (handle, F_RDADVISE, &radv) != -1;
     698
     699  if (!ret)
     700    set_system_error (error, errno);
     701
     702#endif
     703
     704  return ret;
     705}
     706
     707bool
     708tr_sys_file_preallocate (tr_sys_file_t    handle,
     709                         uint64_t         size,
     710                         int              flags,
     711                         tr_error      ** error)
     712{
     713  bool ret = false;
     714
     715  assert (handle != TR_BAD_SYS_FILE);
     716
     717  errno = 0;
     718
     719#ifdef HAVE_FALLOCATE64
     720
     721  /* fallocate64 is always preferred, so try it first */
     722  ret = fallocate64 (handle, 0, 0, size) != -1;
     723
     724#endif
     725
     726  if (!ret && (flags & TR_SYS_FILE_PREALLOC_SPARSE) == 0)
     727    {
     728      int code = errno;
     729
     730#ifdef HAVE_XFS_XFS_H
     731
     732      if (!ret && platform_test_xfs_fd (handle))
     733        {
     734          xfs_flock64_t fl;
     735
     736          fl.l_whence = 0;
     737          fl.l_start = 0;
     738          fl.l_len = size;
     739
     740          ret = xfsctl (NULL, handle, XFS_IOC_RESVSP64, &fl) != -1;
     741
     742          code = errno;
     743        }
     744
     745#endif
     746
     747#ifdef __APPLE__
     748
     749      if (!ret)
     750        {
     751          fstore_t fst;
     752
     753          fst.fst_flags = F_ALLOCATECONTIG;
     754          fst.fst_posmode = F_PEOFPOSMODE;
     755          fst.fst_offset = 0;
     756          fst.fst_length = size;
     757          fst.fst_bytesalloc = 0;
     758
     759          ret = fcntl (handle, F_PREALLOCATE, &fst) != -1;
     760
     761          if (ret)
     762            ret = ftruncate (handle, size) != -1;
     763
     764          code = errno;
     765        }
     766
     767#endif
     768
     769#ifdef HAVE_POSIX_FALLOCATE
     770
     771      if (!ret)
     772        {
     773          code = posix_fallocate (handle, 0, size);
     774          ret = code == 0;
     775        }
     776
     777#endif
     778
     779      errno = code;
     780    }
     781
     782  if (!ret)
     783    set_system_error (error, errno);
     784
     785  return ret;
     786}
     787
     788void *
     789tr_sys_file_map_for_reading (tr_sys_file_t    handle,
     790                             uint64_t         offset,
     791                             uint64_t         size,
     792                             tr_error      ** error)
     793{
     794  void * ret;
     795
     796  assert (handle != TR_BAD_SYS_FILE);
     797  assert (size > 0);
     798
     799  ret = mmap (NULL, size, PROT_READ, MAP_SHARED, handle, offset);
     800
     801  if (ret == MAP_FAILED)
     802    {
     803      set_system_error (error, errno);
     804      ret = NULL;
     805    }
     806
     807  return ret;
     808}
     809
     810bool
     811tr_sys_file_unmap (const void  * address,
     812                   uint64_t      size,
     813                   tr_error   ** error)
     814{
     815  bool ret;
     816
     817  assert (address != NULL);
     818  assert (size > 0);
     819
     820  ret = munmap ((void *) address, size) != -1;
     821
     822  if (!ret)
     823    set_system_error (error, errno);
     824
     825  return ret;
     826}
  • trunk/libtransmission/file-test.c

    r14314 r14321  
    138138}
    139139
     140static bool
     141validate_permissions (const char   * path,
     142                      unsigned int   permissions)
     143{
     144#ifndef _WIN32
     145
     146  struct stat sb;
     147  return stat (path, &sb) != -1 && (sb.st_mode & 0777) == permissions;
     148
     149#else
     150
     151  /* No UNIX permissions on Windows */
     152  return true;
     153
     154#endif
     155}
     156
    140157static int
    141158test_get_info (void)
     
    143160  char * const test_dir = create_test_dir (__FUNCTION__);
    144161  tr_sys_path_info info;
     162  tr_sys_file_t fd;
    145163  tr_error * err = NULL;
    146164  char * path1, * path2;
     
    163181  check_int_eq (4, info.size);
    164182  check (info.last_modified_at >= time(0) - 1 && info.last_modified_at <= time(0));
     183
     184  /* Good file info (by handle) */
     185  fd = tr_sys_file_open (path1, TR_SYS_FILE_READ, 0, NULL);
     186  clear_path_info (&info);
     187  check (tr_sys_file_get_info (fd, &info, &err));
     188  check (err == NULL);
     189  check_int_eq (TR_SYS_PATH_IS_FILE, info.type);
     190  check_int_eq (4, info.size);
     191  check (info.last_modified_at >= time(0) - 1 && info.last_modified_at <= time(0));
     192  tr_sys_file_close (fd, NULL);
    165193
    166194  tr_sys_path_remove (path1, NULL);
     
    192220      check_int_eq (4, info.size);
    193221      check (info.last_modified_at >= time(0) - 1 && info.last_modified_at <= time(0));
     222
     223      /* Good file info (by handle) */
     224      fd = tr_sys_file_open (path1, TR_SYS_FILE_READ, 0, NULL);
     225      clear_path_info (&info);
     226      check (tr_sys_file_get_info (fd, &info, &err));
     227      check (err == NULL);
     228      check_int_eq (TR_SYS_PATH_IS_FILE, info.type);
     229      check_int_eq (4, info.size);
     230      check (info.last_modified_at >= time(0) - 1 && info.last_modified_at <= time(0));
     231      tr_sys_file_close (fd, NULL);
    194232
    195233      tr_sys_path_remove (path2, NULL);
     
    776814}
    777815
     816static int
     817test_file_open (void)
     818{
     819  char * const test_dir = create_test_dir (__FUNCTION__);
     820  tr_error * err = NULL;
     821  char * path1;
     822  tr_sys_file_t fd;
     823  uint64_t n;
     824  tr_sys_path_info info;
     825
     826  path1 = tr_buildPath (test_dir, "a", NULL);
     827
     828  /* Can't open non-existent file */
     829  check (!tr_sys_path_exists (path1, NULL));
     830  check (tr_sys_file_open (path1, TR_SYS_FILE_READ, 0600, &err) == TR_BAD_SYS_FILE);
     831  check (err != NULL);
     832  check (!tr_sys_path_exists (path1, NULL));
     833  tr_error_clear (&err);
     834  check (tr_sys_file_open (path1, TR_SYS_FILE_WRITE, 0600, &err) == TR_BAD_SYS_FILE);
     835  check (err != NULL);
     836  check (!tr_sys_path_exists (path1, NULL));
     837  tr_error_clear (&err);
     838
     839  /* Can't open directory */
     840  tr_mkdirp (path1, 0777);
     841#ifdef _WIN32
     842  /* This works on *NIX */
     843  check (tr_sys_file_open (path1, TR_SYS_FILE_READ, 0600, &err) == TR_BAD_SYS_FILE);
     844  check (err != NULL);
     845  tr_error_clear (&err);
     846#endif
     847  check (tr_sys_file_open (path1, TR_SYS_FILE_WRITE, 0600, &err) == TR_BAD_SYS_FILE);
     848  check (err != NULL);
     849  tr_error_clear (&err);
     850
     851  tr_sys_path_remove (path1, NULL);
     852
     853  /* Can create non-existent file */
     854  fd = tr_sys_file_open (path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0640, &err);
     855  check (fd != TR_BAD_SYS_FILE);
     856  check (err == NULL);
     857  tr_sys_file_close (fd, NULL);
     858  check (tr_sys_path_exists (path1, NULL));
     859  check (validate_permissions (path1, 0640));
     860
     861  /* Can open existing file */
     862  check (tr_sys_path_exists (path1, NULL));
     863  fd = tr_sys_file_open (path1, TR_SYS_FILE_READ, 0600, &err);
     864  check (fd != TR_BAD_SYS_FILE);
     865  check (err == NULL);
     866  tr_sys_file_close (fd, NULL);
     867  fd = tr_sys_file_open (path1, TR_SYS_FILE_WRITE, 0600, &err);
     868  check (fd != TR_BAD_SYS_FILE);
     869  check (err == NULL);
     870  tr_sys_file_close (fd, NULL);
     871
     872  tr_sys_path_remove (path1, NULL);
     873  libtest_create_file_with_string_contents (path1, "test");
     874
     875  /* Can't create new file if it already exists */
     876  fd = tr_sys_file_open (path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE_NEW, 0640, &err);
     877  check (fd == TR_BAD_SYS_FILE);
     878  check (err != NULL);
     879  tr_error_clear (&err);
     880  tr_sys_path_get_info (path1, TR_SYS_PATH_NO_FOLLOW, &info, NULL);
     881  check_int_eq (4, info.size);
     882
     883  /* Pointer is at the end of file */
     884  tr_sys_path_get_info (path1, TR_SYS_PATH_NO_FOLLOW, &info, NULL);
     885  check_int_eq (4, info.size);
     886  fd = tr_sys_file_open (path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_APPEND, 0600, &err);
     887  check (fd != TR_BAD_SYS_FILE);
     888  check (err == NULL);
     889  tr_sys_file_write (fd, "s", 1, NULL, NULL); /* On *NIX, pointer is positioned on each write but not initially */
     890  tr_sys_file_seek (fd, 0, TR_SEEK_CUR, &n, NULL);
     891  check_int_eq (5, n);
     892  tr_sys_file_close (fd, NULL);
     893
     894  /* File gets truncated */
     895  tr_sys_path_get_info (path1, TR_SYS_PATH_NO_FOLLOW, &info, NULL);
     896  check_int_eq (5, info.size);
     897  fd = tr_sys_file_open (path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_TRUNCATE, 0600, &err);
     898  check (fd != TR_BAD_SYS_FILE);
     899  check (err == NULL);
     900  tr_sys_file_get_info (fd, &info, NULL);
     901  check_int_eq (0, info.size);
     902  tr_sys_file_close (fd, NULL);
     903  tr_sys_path_get_info (path1, TR_SYS_PATH_NO_FOLLOW, &info, NULL);
     904  check_int_eq (0, info.size);
     905
     906  /* TODO: symlink and hardlink tests */
     907
     908  tr_sys_path_remove (path1, NULL);
     909
     910  tr_free (path1);
     911
     912  tr_free (test_dir);
     913  return 0;
     914}
     915
     916static int
     917test_file_read_write_seek (void)
     918{
     919  char * const test_dir = create_test_dir (__FUNCTION__);
     920  tr_error * err = NULL;
     921  char * path1;
     922  tr_sys_file_t fd;
     923  uint64_t n;
     924  char buf[100];
     925
     926  path1 = tr_buildPath (test_dir, "a", NULL);
     927
     928  fd = tr_sys_file_open (path1, TR_SYS_FILE_READ | TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600, NULL);
     929
     930  check (tr_sys_file_seek (fd, 0, TR_SEEK_CUR, &n, &err));
     931  check (err == NULL);
     932  check_int_eq (0, n);
     933
     934  check (tr_sys_file_write (fd, "test", 4, &n, &err));
     935  check (err == NULL);
     936  check_int_eq (4, n);
     937
     938  check (tr_sys_file_seek (fd, 0, TR_SEEK_CUR, &n, &err));
     939  check (err == NULL);
     940  check_int_eq (4, n);
     941
     942  check (tr_sys_file_seek (fd, 0, TR_SEEK_SET, &n, &err));
     943  check (err == NULL);
     944  check_int_eq (0, n);
     945
     946  check (tr_sys_file_read (fd, buf, sizeof (buf), &n, &err));
     947  check (err == NULL);
     948  check_int_eq (4, n);
     949
     950  check_int_eq (0, memcmp (buf, "test", 4));
     951
     952  check (tr_sys_file_seek (fd, -3, TR_SEEK_CUR, &n, &err));
     953  check (err == NULL);
     954  check_int_eq (1, n);
     955
     956  check (tr_sys_file_write (fd, "E", 1, &n, &err));
     957  check (err == NULL);
     958  check_int_eq (1, n);
     959
     960  check (tr_sys_file_seek (fd, -2, TR_SEEK_CUR, &n, &err));
     961  check (err == NULL);
     962  check_int_eq (0, n);
     963
     964  check (tr_sys_file_read (fd, buf, sizeof (buf), &n, &err));
     965  check (err == NULL);
     966  check_int_eq (4, n);
     967
     968  check_int_eq (0, memcmp (buf, "tEst", 4));
     969
     970  check (tr_sys_file_seek (fd, 0, TR_SEEK_END, &n, &err));
     971  check (err == NULL);
     972  check_int_eq (4, n);
     973
     974  check (tr_sys_file_write (fd, " ok", 3, &n, &err));
     975  check (err == NULL);
     976  check_int_eq (3, n);
     977
     978  check (tr_sys_file_seek (fd, 0, TR_SEEK_SET, &n, &err));
     979  check (err == NULL);
     980  check_int_eq (0, n);
     981
     982  check (tr_sys_file_read (fd, buf, sizeof (buf), &n, &err));
     983  check (err == NULL);
     984  check_int_eq (7, n);
     985
     986  check_int_eq (0, memcmp (buf, "tEst ok", 7));
     987
     988  check (tr_sys_file_write_at (fd, "-", 1, 4, &n, &err));
     989  check (err == NULL);
     990  check_int_eq (1, n);
     991
     992  check (tr_sys_file_read_at (fd, buf, 5, 2, &n, &err));
     993  check (err == NULL);
     994  check_int_eq (5, n);
     995
     996  check_int_eq (0, memcmp (buf, "st-ok", 5));
     997
     998  tr_sys_file_close (fd, NULL);
     999
     1000  tr_sys_path_remove (path1, NULL);
     1001
     1002  tr_free (path1);
     1003
     1004  tr_free (test_dir);
     1005  return 0;
     1006}
     1007
     1008static int
     1009test_file_truncate (void)
     1010{
     1011  char * const test_dir = create_test_dir (__FUNCTION__);
     1012  tr_error * err = NULL;
     1013  char * path1;
     1014  tr_sys_file_t fd;
     1015  tr_sys_path_info info;
     1016
     1017  path1 = tr_buildPath (test_dir, "a", NULL);
     1018
     1019  fd = tr_sys_file_open (path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600, NULL);
     1020
     1021  check (tr_sys_file_truncate (fd, 10, &err));
     1022  check (err == NULL);
     1023  tr_sys_file_get_info (fd, &info, NULL);
     1024  check_int_eq (10, info.size);
     1025
     1026  check (tr_sys_file_truncate (fd, 20, &err));
     1027  check (err == NULL);
     1028  tr_sys_file_get_info (fd, &info, NULL);
     1029  check_int_eq (20, info.size);
     1030
     1031  check (tr_sys_file_truncate (fd, 0, &err));
     1032  check (err == NULL);
     1033  tr_sys_file_get_info (fd, &info, NULL);
     1034  check_int_eq (0, info.size);
     1035
     1036  check (tr_sys_file_truncate (fd, 50, &err));
     1037  check (err == NULL);
     1038
     1039  tr_sys_file_close (fd, NULL);
     1040
     1041  tr_sys_path_get_info (path1, 0, &info, NULL);
     1042  check_int_eq (50, info.size);
     1043
     1044  fd = tr_sys_file_open (path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600, NULL);
     1045
     1046  check (tr_sys_file_truncate (fd, 25, &err));
     1047  check (err == NULL);
     1048
     1049  tr_sys_file_close (fd, NULL);
     1050
     1051  tr_sys_path_get_info (path1, 0, &info, NULL);
     1052  check_int_eq (25, info.size);
     1053
     1054  tr_sys_path_remove (path1, NULL);
     1055
     1056  tr_free (path1);
     1057
     1058  tr_free (test_dir);
     1059  return 0;
     1060}
     1061
     1062static int
     1063test_file_preallocate (void)
     1064{
     1065  char * const test_dir = create_test_dir (__FUNCTION__);
     1066  tr_error * err = NULL;
     1067  char * path1;
     1068  tr_sys_file_t fd;
     1069  tr_sys_path_info info;
     1070
     1071  path1 = tr_buildPath (test_dir, "a", NULL);
     1072
     1073  fd = tr_sys_file_open (path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600, NULL);
     1074
     1075  if (tr_sys_file_preallocate (fd, 50, 0, &err))
     1076    {
     1077      check (err == NULL);
     1078      tr_sys_file_get_info (fd, &info, NULL);
     1079      check_int_eq (50, info.size);
     1080    }
     1081  else
     1082    {
     1083      check (err != NULL);
     1084      fprintf (stderr, "WARNING: [%s] unable to preallocate file (full): %s (%d)\n", __FUNCTION__, err->message, err->code);
     1085      tr_error_clear (&err);
     1086    }
     1087
     1088  tr_sys_file_close (fd, NULL);
     1089
     1090  tr_sys_path_remove (path1, NULL);
     1091
     1092  fd = tr_sys_file_open (path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600, NULL);
     1093
     1094  if (tr_sys_file_preallocate (fd, 500 * 1024 * 1024, TR_SYS_FILE_PREALLOC_SPARSE, &err))
     1095    {
     1096      check (err == NULL);
     1097      tr_sys_file_get_info (fd, &info, NULL);
     1098      check_int_eq (500 * 1024 * 1024, info.size);
     1099    }
     1100  else
     1101    {
     1102      check (err != NULL);
     1103      fprintf (stderr, "WARNING: [%s] unable to preallocate file (sparse): %s (%d)\n", __FUNCTION__, err->message, err->code);
     1104      tr_error_clear (&err);
     1105    }
     1106
     1107  tr_sys_file_close (fd, NULL);
     1108
     1109  tr_sys_path_remove (path1, NULL);
     1110
     1111  tr_free (path1);
     1112
     1113  tr_free (test_dir);
     1114  return 0;
     1115}
     1116
     1117static int
     1118test_file_map (void)
     1119{
     1120  char * const test_dir = create_test_dir (__FUNCTION__);
     1121  tr_error * err = NULL;
     1122  char * path1;
     1123  tr_sys_file_t fd;
     1124  char * view;
     1125
     1126  path1 = tr_buildPath (test_dir, "a", NULL);
     1127
     1128  libtest_create_file_with_string_contents (path1, "test");
     1129
     1130  fd = tr_sys_file_open (path1, TR_SYS_FILE_READ | TR_SYS_FILE_WRITE, 0600, NULL);
     1131
     1132  view = tr_sys_file_map_for_reading (fd, 0, 4, &err);
     1133  check (view != NULL);
     1134  check (err == NULL);
     1135
     1136  check_int_eq (0, memcmp (view, "test", 4));
     1137
     1138  tr_sys_file_write_at (fd, "E", 1, 1, NULL, NULL);
     1139
     1140  check_int_eq (0, memcmp (view, "tEst", 4));
     1141
     1142  check (tr_sys_file_unmap (view, 4, &err));
     1143  check (err == NULL);
     1144
     1145  tr_sys_file_close (fd, NULL);
     1146
     1147  tr_sys_path_remove (path1, NULL);
     1148
     1149  tr_free (path1);
     1150
     1151  tr_free (test_dir);
     1152  return 0;
     1153}
     1154
    7781155int
    7791156main (void)
     
    7871164      test_path_basename_dirname,
    7881165      test_path_rename,
    789       test_path_remove
     1166      test_path_remove,
     1167      test_file_open,
     1168      test_file_read_write_seek,
     1169      test_file_truncate,
     1170      test_file_preallocate,
     1171      test_file_map
    7901172    };
    7911173  int ret;
  • trunk/libtransmission/file-win32.c

    r14314 r14321  
    1111#include <stdlib.h> /* _splitpath_s (), _makepath_s () */
    1212
     13#include <winioctl.h> /* FSCTL_SET_SPARSE */
     14
    1315#include "transmission.h"
     16#include "crypto.h" /* tr_cryptoRandInt () */
    1417#include "file.h"
    1518#include "utils.h"
     19
     20#ifndef MAXSIZE_T
     21 #define MAXSIZE_T ((SIZE_T)~((SIZE_T)0))
     22#endif
    1623
    1724/* MSDN (http://msdn.microsoft.com/en-us/library/2k2xf226.aspx) only mentions
     
    9198}
    9299
    93 static bool
    94 get_file_info (HANDLE              handle,
    95                tr_sys_path_info  * info,
    96                tr_error         ** error);
     100static tr_sys_file_t
     101open_file (const char  * path,
     102           DWORD         access,
     103           DWORD         disposition,
     104           DWORD         flags,
     105           tr_error   ** error)
     106{
     107  tr_sys_file_t ret = TR_BAD_SYS_FILE;
     108  wchar_t * wide_path;
     109
     110  assert (path != NULL);
     111
     112  wide_path = tr_win32_utf8_to_native (path, -1);
     113
     114  if (wide_path != NULL)
     115    ret = CreateFileW (wide_path, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
     116                       NULL, disposition, flags, NULL);
     117
     118  if (ret == TR_BAD_SYS_FILE)
     119    set_system_error (error, GetLastError ());
     120
     121  tr_free (wide_path);
     122
     123  return ret;
     124}
     125
     126static void
     127create_temp_path (char      * path_template,
     128                  void     (* callback) (const char * path, void * param, tr_error ** error),
     129                  void      * callback_param,
     130                  tr_error ** error)
     131{
     132  char * path;
     133  size_t path_size;
     134  int attempt;
     135  tr_error * my_error = NULL;
     136
     137  assert (path_template != NULL);
     138  assert (callback != NULL);
     139
     140  path = tr_strdup (path_template);
     141  path_size = strlen (path);
     142
     143  assert (path_size > 0);
     144
     145  for (attempt = 0; attempt < 100; ++attempt)
     146    {
     147      size_t i = path_size;
     148
     149      while (i > 0 && path_template[i - 1] == 'X')
     150        {
     151          const int c = tr_cryptoRandInt (26 + 26 + 10);
     152          path[i - 1] = c < 26 ? c + 'A' : (c < 26 + 26 ? (c - 26) + 'a' : (c - 26 - 26) + '0');
     153          --i;
     154        }
     155
     156      assert (path_size >= i + 6);
     157
     158      tr_error_clear (&my_error);
     159
     160      (*callback) (path, callback_param, &my_error);
     161
     162      if (my_error == NULL)
     163        break;
     164    }
     165
     166  if (my_error != NULL)
     167    tr_error_propagate(error, &my_error);
     168  else
     169    memcpy (path_template, path, path_size);
     170
     171  goto cleanup;
     172
     173fail:
     174  set_system_error (error, GetLastError ());
     175
     176cleanup:
     177  tr_free (path);
     178}
    97179
    98180bool
     
    162244        {
    163245          tr_error * my_error = NULL;
    164           ret = get_file_info (handle, info, &my_error);
     246          ret = tr_sys_file_get_info (handle, info, &my_error);
    165247          if (!ret)
    166248            tr_error_propagate (error, &my_error);
     
    429511}
    430512
    431 static bool
    432 get_file_info (HANDLE              handle,
    433                tr_sys_path_info  * info,
    434                tr_error         ** error)
     513tr_sys_file_t
     514tr_sys_file_get_std (tr_std_sys_file_t    std_file,
     515                     tr_error          ** error)
     516{
     517  tr_sys_file_t ret = TR_BAD_SYS_FILE;
     518
     519  switch (std_file)
     520    {
     521    case TR_STD_SYS_FILE_IN:
     522      ret = GetStdHandle (STD_INPUT_HANDLE);
     523      break;
     524    case TR_STD_SYS_FILE_OUT:
     525      ret = GetStdHandle (STD_OUTPUT_HANDLE);
     526      break;
     527    case TR_STD_SYS_FILE_ERR:
     528      ret = GetStdHandle (STD_ERROR_HANDLE);
     529      break;
     530    default:
     531      assert (0 && "Unknown standard file");
     532      set_system_error (error, ERROR_INVALID_PARAMETER);
     533      return TR_BAD_SYS_FILE;
     534    }
     535
     536  if (ret == TR_BAD_SYS_FILE)
     537    set_system_error (error, GetLastError ());
     538  else if (ret == NULL)
     539    ret = TR_BAD_SYS_FILE;
     540
     541  return ret;
     542}
     543
     544tr_sys_file_t
     545tr_sys_file_open (const char  * path,
     546                  int           flags,
     547                  int           permissions,
     548                  tr_error   ** error)
     549{
     550  tr_sys_file_t ret;
     551  DWORD native_access = 0;
     552  DWORD native_disposition = OPEN_EXISTING;
     553  DWORD native_flags = FILE_ATTRIBUTE_NORMAL;
     554  bool success;
     555
     556  assert (path != NULL);
     557  assert ((flags & (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE)) != 0);
     558
     559  if (flags & TR_SYS_FILE_READ)
     560    native_access |= GENERIC_READ;
     561  if (flags & TR_SYS_FILE_WRITE)
     562    native_access |= GENERIC_WRITE;
     563
     564  if (flags & TR_SYS_FILE_CREATE_NEW)
     565    native_disposition = CREATE_NEW;
     566  else if (flags & TR_SYS_FILE_CREATE)
     567    native_disposition = flags & TR_SYS_FILE_TRUNCATE ? CREATE_ALWAYS : OPEN_ALWAYS;
     568  else if (flags & TR_SYS_FILE_TRUNCATE)
     569    native_disposition = TRUNCATE_EXISTING;
     570
     571  if (flags & TR_SYS_FILE_SEQUENTIAL)
     572    native_flags |= FILE_FLAG_SEQUENTIAL_SCAN;
     573
     574  ret = open_file (path, native_access, native_disposition, native_flags, error);
     575
     576  success = ret != TR_BAD_SYS_FILE;
     577
     578  if (success && (flags & TR_SYS_FILE_APPEND))
     579    success = SetFilePointer (ret, 0, NULL, FILE_END) != INVALID_SET_FILE_POINTER;
     580
     581  if (!success)
     582    {
     583      if (error == NULL)
     584        set_system_error (error, GetLastError ());
     585
     586      CloseHandle (ret);
     587      ret = TR_BAD_SYS_FILE;
     588    }
     589
     590  return ret;
     591}
     592
     593static void
     594file_open_temp_callback (const char  * path,
     595                         void        * param,
     596                         tr_error   ** error)
     597{
     598  tr_sys_file_t * result = (tr_sys_file_t *) param;
     599
     600  assert (result != NULL);
     601
     602  *result = open_file (path,
     603                       GENERIC_READ | GENERIC_WRITE,
     604                       CREATE_NEW,
     605                       FILE_ATTRIBUTE_TEMPORARY,
     606                       error);
     607}
     608
     609tr_sys_file_t
     610tr_sys_file_open_temp (char      * path_template,
     611                       tr_error ** error)
     612{
     613  tr_sys_file_t ret = TR_BAD_SYS_FILE;
     614
     615  assert (path_template != NULL);
     616
     617  create_temp_path (path_template, file_open_temp_callback, &ret, error);
     618
     619  return ret;
     620}
     621
     622bool
     623tr_sys_file_close (tr_sys_file_t    handle,
     624                   tr_error      ** error)
     625{
     626  bool ret;
     627
     628  assert (handle != TR_BAD_SYS_FILE);
     629
     630  ret = CloseHandle (handle);
     631
     632  if (!ret)
     633    set_system_error (error, GetLastError ());
     634
     635  return ret;
     636}
     637
     638bool
     639tr_sys_file_get_info (tr_sys_file_t       handle,
     640                      tr_sys_path_info  * info,
     641                      tr_error         ** error)
    435642{
    436643  bool ret;
    437644  BY_HANDLE_FILE_INFORMATION attributes;
    438645
    439   assert (handle != INVALID_HANDLE_VALUE);
     646  assert (handle != TR_BAD_SYS_FILE);
    440647  assert (info != NULL);
    441648
     
    451658  return ret;
    452659}
     660
     661bool
     662tr_sys_file_seek (tr_sys_file_t       handle,
     663                  int64_t             offset,
     664                  tr_seek_origin_t    origin,
     665                  uint64_t          * new_offset,
     666                  tr_error         ** error)
     667{
     668  bool ret = false;
     669  LARGE_INTEGER native_offset, new_native_pointer;
     670
     671  TR_STATIC_ASSERT (TR_SEEK_SET == FILE_BEGIN,   "values should match");
     672  TR_STATIC_ASSERT (TR_SEEK_CUR == FILE_CURRENT, "values should match");
     673  TR_STATIC_ASSERT (TR_SEEK_END == FILE_END,     "values should match");
     674
     675  assert (handle != TR_BAD_SYS_FILE);
     676  assert (origin == TR_SEEK_SET || origin == TR_SEEK_CUR || origin == TR_SEEK_END);
     677
     678  native_offset.QuadPart = offset;
     679
     680  if (SetFilePointerEx (handle, native_offset, &new_native_pointer, origin))
     681    {
     682      if (new_offset != NULL)
     683        *new_offset = new_native_pointer.QuadPart;
     684      ret = true;
     685    }
     686  else
     687    {
     688      set_system_error (error, GetLastError ());
     689    }
     690
     691  return ret;
     692}
     693
     694bool
     695tr_sys_file_read (tr_sys_file_t    handle,
     696                  void           * buffer,
     697                  uint64_t         size,
     698                  uint64_t       * bytes_read,
     699                  tr_error      ** error)
     700{
     701  bool ret = false;
     702  DWORD my_bytes_read;
     703
     704  assert (handle != TR_BAD_SYS_FILE);
     705  assert (buffer != NULL || size == 0);
     706
     707  if (size > MAXDWORD)
     708    {
     709      set_system_error (error, ERROR_INVALID_PARAMETER);
     710      return false;
     711    }
     712
     713  if (ReadFile (handle, buffer, (DWORD)size, &my_bytes_read, NULL))
     714    {
     715      if (bytes_read != NULL)
     716        *bytes_read = my_bytes_read;
     717      ret = true;
     718    }
     719  else
     720    {
     721      set_system_error (error, GetLastError ());
     722    }
     723
     724  return ret;
     725}
     726
     727bool
     728tr_sys_file_read_at (tr_sys_file_t    handle,
     729                     void           * buffer,
     730                     uint64_t         size,
     731                     uint64_t         offset,
     732                     uint64_t       * bytes_read,
     733                     tr_error      ** error)
     734{
     735  bool ret = false;
     736  OVERLAPPED overlapped;
     737  DWORD my_bytes_read;
     738
     739  assert (handle != TR_BAD_SYS_FILE);
     740  assert (buffer != NULL || size == 0);
     741
     742  if (size > MAXDWORD)
     743    {
     744      set_system_error (error, ERROR_INVALID_PARAMETER);
     745      return false;
     746    }
     747
     748  overlapped.Offset = (DWORD)offset;
     749  offset >>= 32;
     750  overlapped.OffsetHigh = (DWORD)offset;
     751  overlapped.hEvent = NULL;
     752
     753  if (ReadFile (handle, buffer, (DWORD)size, &my_bytes_read, &overlapped))
     754    {
     755      if (bytes_read != NULL)
     756        *bytes_read = my_bytes_read;
     757      ret = true;
     758    }
     759  else
     760    {
     761      set_system_error (error, GetLastError ());
     762    }
     763
     764  return ret;
     765}
     766
     767bool
     768tr_sys_file_write (tr_sys_file_t    handle,
     769                   const void     * buffer,
     770                   uint64_t         size,
     771                   uint64_t       * bytes_written,
     772                   tr_error      ** error)
     773{
     774  bool ret = false;
     775  DWORD my_bytes_written;
     776
     777  assert (handle != TR_BAD_SYS_FILE);
     778  assert (buffer != NULL || size == 0);
     779
     780  if (size > MAXDWORD)
     781    {
     782      set_system_error (error, ERROR_INVALID_PARAMETER);
     783      return false;
     784    }
     785
     786  if (WriteFile (handle, buffer, (DWORD)size, &my_bytes_written, NULL))
     787    {
     788      if (bytes_written != NULL)
     789        *bytes_written = my_bytes_written;
     790      ret = true;
     791    }
     792  else
     793    {
     794      set_system_error (error, GetLastError ());
     795    }
     796
     797  return ret;
     798}
     799
     800bool
     801tr_sys_file_write_at (tr_sys_file_t    handle,
     802                      const void     * buffer,
     803                      uint64_t         size,
     804                      uint64_t         offset,
     805                      uint64_t       * bytes_written,
     806                      tr_error      ** error)
     807{
     808  bool ret = false;
     809  OVERLAPPED overlapped;
     810  DWORD my_bytes_written;
     811
     812  assert (handle != TR_BAD_SYS_FILE);
     813  assert (buffer != NULL || size == 0);
     814
     815  if (size > MAXDWORD)
     816    {
     817      set_system_error (error, ERROR_INVALID_PARAMETER);
     818      return false;
     819    }
     820
     821  overlapped.Offset = (DWORD)offset;
     822  offset >>= 32;
     823  overlapped.OffsetHigh = (DWORD)offset;
     824  overlapped.hEvent = NULL;
     825
     826  if (WriteFile (handle, buffer, (DWORD)size, &my_bytes_written, &overlapped))
     827    {
     828      if (bytes_written != NULL)
     829        *bytes_written = my_bytes_written;
     830      ret = true;
     831    }
     832  else
     833    {
     834      set_system_error (error, GetLastError ());
     835    }
     836
     837  return ret;
     838}
     839
     840bool
     841tr_sys_file_flush (tr_sys_file_t    handle,
     842                   tr_error      ** error)
     843{
     844  bool ret;
     845
     846  assert (handle != TR_BAD_SYS_FILE);
     847
     848  ret = FlushFileBuffers (handle);
     849
     850  if (!ret)
     851    set_system_error (error, GetLastError ());
     852
     853  return ret;
     854}
     855
     856bool
     857tr_sys_file_truncate (tr_sys_file_t    handle,
     858                      uint64_t         size,
     859                      tr_error      ** error)
     860{
     861  bool ret = false;
     862  FILE_END_OF_FILE_INFO info;
     863
     864  assert (handle != TR_BAD_SYS_FILE);
     865
     866  info.EndOfFile.QuadPart = size;
     867
     868  ret = SetFileInformationByHandle (handle, FileEndOfFileInfo, &info, sizeof (info));
     869
     870  if (!ret)
     871    set_system_error (error, GetLastError ());
     872
     873  return ret;
     874}
     875
     876bool
     877tr_sys_file_prefetch (tr_sys_file_t    handle,
     878                      uint64_t         offset,
     879                      uint64_t         size,
     880                      tr_error      ** error)
     881{
     882  bool ret = false;
     883
     884  assert (handle != TR_BAD_SYS_FILE);
     885  assert (size > 0);
     886
     887  /* ??? */
     888
     889  return ret;
     890}
     891
     892bool
     893tr_sys_file_preallocate (tr_sys_file_t    handle,
     894                         uint64_t         size,
     895                         int              flags,
     896                         tr_error      ** error)
     897{
     898  assert (handle != TR_BAD_SYS_FILE);
     899
     900  if ((flags & TR_SYS_FILE_PREALLOC_SPARSE) != 0)
     901    {
     902      DWORD tmp;
     903      if (!DeviceIoControl (handle, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &tmp, NULL))
     904        {
     905          set_system_error (error, GetLastError ());
     906          return false;
     907        }
     908    }
     909
     910  return tr_sys_file_truncate (handle, size, error);
     911}
     912
     913void *
     914tr_sys_file_map_for_reading (tr_sys_file_t    handle,
     915                             uint64_t         offset,
     916                             uint64_t         size,
     917                             tr_error      ** error)
     918{
     919  void * ret = NULL;
     920  HANDLE mappingHandle;
     921
     922  assert (handle != TR_BAD_SYS_FILE);
     923  assert (size > 0);
     924
     925  if (size > MAXSIZE_T)
     926    {
     927      set_system_error (error, ERROR_INVALID_PARAMETER);
     928      return false;
     929    }
     930
     931  mappingHandle = CreateFileMappingW (handle, NULL, PAGE_READONLY, 0, 0, NULL);
     932
     933  if (mappingHandle != NULL)
     934    {
     935      ULARGE_INTEGER native_offset;
     936
     937      native_offset.QuadPart = offset;
     938
     939      ret = MapViewOfFile (mappingHandle, FILE_MAP_READ, native_offset.u.HighPart,
     940                           native_offset.u.LowPart, (SIZE_T)size);
     941    }
     942
     943  if (ret == NULL)
     944    set_system_error (error, GetLastError ());
     945
     946  CloseHandle (mappingHandle);
     947
     948  return ret;
     949}
     950
     951bool
     952tr_sys_file_unmap (const void  * address,
     953                   uint64_t      size,
     954                   tr_error   ** error)
     955{
     956  bool ret;
     957
     958  assert (address != NULL);
     959  assert (size > 0);
     960
     961  ret = UnmapViewOfFile (address);
     962
     963  if (!ret)
     964    set_system_error (error, GetLastError ());
     965
     966  return ret;
     967}
  • trunk/libtransmission/file.h

    r14314 r14321  
    2929 */
    3030
     31#ifndef _WIN32
     32 /** @brief Platform-specific file descriptor type. */
     33 typedef int tr_sys_file_t;
     34 /** @brief Platform-specific invalid file descriptor constant. */
     35 #define TR_BAD_SYS_FILE (-1)
     36#else
     37 typedef HANDLE tr_sys_file_t;
     38 #define TR_BAD_SYS_FILE INVALID_HANDLE_VALUE
     39#endif
     40
    3141typedef enum
    3242{
     43  TR_STD_SYS_FILE_IN,
     44  TR_STD_SYS_FILE_OUT,
     45  TR_STD_SYS_FILE_ERR
     46}
     47tr_std_sys_file_t;
     48
     49typedef enum
     50{
     51  TR_SYS_FILE_READ       = 1 << 0,
     52  TR_SYS_FILE_WRITE      = 1 << 1,
     53  TR_SYS_FILE_CREATE     = 1 << 2,
     54  TR_SYS_FILE_CREATE_NEW = 1 << 3,
     55  TR_SYS_FILE_APPEND     = 1 << 4,
     56  TR_SYS_FILE_TRUNCATE   = 1 << 5,
     57  TR_SYS_FILE_SEQUENTIAL = 1 << 6
     58}
     59tr_sys_file_open_flags_t;
     60
     61typedef enum
     62{
     63  TR_SEEK_SET,
     64  TR_SEEK_CUR,
     65  TR_SEEK_END
     66}
     67tr_seek_origin_t;
     68
     69typedef enum
     70{
    3371    TR_SYS_PATH_NO_FOLLOW = 1 << 0
    3472}
    3573tr_sys_path_get_info_flags_t;
     74
     75typedef enum
     76{
     77    TR_SYS_FILE_PREALLOC_SPARSE = 1 << 0
     78}
     79tr_sys_file_preallocate_flags_t;
    3680
    3781typedef enum
     
    56100 * Following functions accept paths in UTF-8 encoding and convert them to native
    57101 * encoding internally if needed.
     102 * Descriptors returned (@ref tr_sys_file_t) may have different type depending
     103 * on platform and should generally not be passed to native functions, but to
     104 * wrapper functions instead.
    58105 *
    59106 * @{
     
    184231                                             tr_error          ** error);
    185232
     233/* File-related wrappers */
     234
     235/**
     236 * @brief Get handle to one of standard I/O files.
     237 *
     238 * @param[in]  std_file Standard file identifier.
     239 * @param[out] error    Pointer to error object. Optional, pass `NULL` if you
     240 *                      are not interested in error details.
     241 *
     242 * @return Opened file descriptor on success, `TR_BAD_SYS_FILE` otherwise (with
     243 *         `error` set accordingly). DO NOT pass this descriptor to
     244 *         @ref tr_sys_file_close (unless you know what you are doing).
     245 */
     246tr_sys_file_t   tr_sys_file_get_std         (tr_std_sys_file_t    std_file,
     247                                             tr_error          ** error);
     248
     249/**
     250 * @brief Portability wrapper for `open ()`.
     251 *
     252 * @param[in]  path        Path to file.
     253 * @param[in]  flags       Combination of @ref tr_sys_file_open_flags_t values.
     254 * @param[in]  permissions Permissions to create file with (in case
     255                           @ref TR_SYS_FILE_CREATE is used). Not used on Windows.
     256 * @param[out] error       Pointer to error object. Optional, pass `NULL` if you
     257 *                         are not interested in error details.
     258 *
     259 * @return Opened file descriptor on success, `TR_BAD_SYS_FILE` otherwise (with
     260 *         `error` set accordingly).
     261 */
     262tr_sys_file_t   tr_sys_file_open            (const char         * path,
     263                                             int                  flags,
     264                                             int                  permissions,
     265                                             tr_error          ** error);
     266
     267/**
     268 * @brief Portability wrapper for `mkstemp ()`.
     269 *
     270 * @param[in,out] path_template Template path to file. Should end with at least
     271 *                              six 'X' characters. Upon success, trailing 'X'
     272 *                              characters are replaced with actual random
     273 *                              characters used to form a unique path to
     274 *                              temporary file.
     275 * @param[out]    error         Pointer to error object. Optional, pass `NULL`
     276 *                              if you are not interested in error details.
     277 *
     278 * @return Opened file descriptor on success, `TR_BAD_SYS_FILE` otherwise (with
     279 *         `error` set accordingly).
     280 */
     281tr_sys_file_t   tr_sys_file_open_temp       (char               * path_template,
     282                                             tr_error          ** error);
     283
     284/**
     285 * @brief Portability wrapper for `close ()`.
     286 *
     287 * @param[in]  handle Valid file descriptor.
     288 * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
     289 *                    not interested in error details.
     290 *
     291 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     292 */
     293bool            tr_sys_file_close           (tr_sys_file_t        handle,
     294                                             tr_error          ** error);
     295
     296/**
     297 * @brief Portability wrapper for `fstat ()`.
     298 *
     299 * @param[in]  handle Valid file descriptor.
     300 * @param[out] info   Result buffer.
     301 * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
     302 *                    not interested in error details.
     303 *
     304 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     305 */
     306bool            tr_sys_file_get_info        (tr_sys_file_t        handle,
     307                                             tr_sys_path_info   * info,
     308                                             tr_error          ** error);
     309
     310/**
     311 * @brief Portability wrapper for `lseek ()`.
     312 *
     313 * @param[in]  handle     Valid file descriptor.
     314 * @param[in]  offset     Relative file offset in bytes to seek to.
     315 * @param[in]  origin     Offset origin.
     316 * @param[out] new_offset New offset in bytes from beginning of file. Optional,
     317 *                        pass `NULL` if you are not interested.
     318 * @param[out] error      Pointer to error object. Optional, pass `NULL` if you
     319 *                        are not interested in error details.
     320 *
     321 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     322 */
     323bool            tr_sys_file_seek            (tr_sys_file_t        handle,
     324                                             int64_t              offset,
     325                                             tr_seek_origin_t     origin,
     326                                             uint64_t           * new_offset,
     327                                             tr_error          ** error);
     328
     329/**
     330 * @brief Portability wrapper for `read ()`.
     331 *
     332 * @param[in]  handle     Valid file descriptor.
     333 * @param[out] buffer     Buffer to store read data to.
     334 * @param[in]  size       Number of bytes to read.
     335 * @param[out] bytes_read Number of bytes actually read. Optional, pass `NULL`
     336 *                        if you are not interested.
     337 * @param[out] error      Pointer to error object. Optional, pass `NULL` if you
     338 *                        are not interested in error details.
     339 *
     340 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     341 */
     342bool            tr_sys_file_read            (tr_sys_file_t        handle,
     343                                             void               * buffer,
     344                                             uint64_t             size,
     345                                             uint64_t           * bytes_read,
     346                                             tr_error          ** error);
     347
     348/**
     349 * @brief Like `pread ()`, except that the position is undefined afterwards.
     350 *        Not thread-safe.
     351 *
     352 * @param[in]  handle     Valid file descriptor.
     353 * @param[out] buffer     Buffer to store read data to.
     354 * @param[in]  size       Number of bytes to read.
     355 * @param[in]  offset     File offset in bytes to start reading from.
     356 * @param[out] bytes_read Number of bytes actually read. Optional, pass `NULL`
     357 *                        if you are not interested.
     358 * @param[out] error      Pointer to error object. Optional, pass `NULL` if you
     359 *                        are not interested in error details.
     360 *
     361 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     362 */
     363bool            tr_sys_file_read_at         (tr_sys_file_t        handle,
     364                                             void               * buffer,
     365                                             uint64_t             size,
     366                                             uint64_t             offset,
     367                                             uint64_t           * bytes_read,
     368                                             tr_error          ** error);
     369
     370/**
     371 * @brief Portability wrapper for `write ()`.
     372 *
     373 * @param[in]  handle        Valid file descriptor.
     374 * @param[in]  buffer        Buffer to get data being written from.
     375 * @param[in]  size          Number of bytes to write.
     376 * @param[out] bytes_written Number of bytes actually written. Optional, pass
     377 *                           `NULL` if you are not interested.
     378 * @param[out] error         Pointer to error object. Optional, pass `NULL` if
     379 *                           you are not interested in error details.
     380 *
     381 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     382 */
     383bool            tr_sys_file_write           (tr_sys_file_t        handle,
     384                                             const void         * buffer,
     385                                             uint64_t             size,
     386                                             uint64_t           * bytes_written,
     387                                             tr_error          ** error);
     388
     389/**
     390 * @brief Like `pwrite ()`, except that the position is undefined afterwards.
     391 *        Not thread-safe.
     392 *
     393 * @param[in]  handle        Valid file descriptor.
     394 * @param[in]  buffer        Buffer to get data being written from.
     395 * @param[in]  size          Number of bytes to write.
     396 * @param[in]  offset        File offset in bytes to start writing from.
     397 * @param[out] bytes_written Number of bytes actually written. Optional, pass
     398 *                           `NULL` if you are not interested.
     399 * @param[out] error         Pointer to error object. Optional, pass `NULL` if you
     400 *                           are not interested in error details.
     401 *
     402 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     403 */
     404bool            tr_sys_file_write_at        (tr_sys_file_t        handle,
     405                                             const void         * buffer,
     406                                             uint64_t             size,
     407                                             uint64_t             offset,
     408                                             uint64_t           * bytes_written,
     409                                             tr_error          ** error);
     410
     411/**
     412 * @brief Portability wrapper for `fsync ()`.
     413 *
     414 * @param[in]  handle Valid file descriptor.
     415 * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
     416 *                    not interested in error details.
     417 *
     418 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     419 */
     420bool            tr_sys_file_flush           (tr_sys_file_t        handle,
     421                                             tr_error          ** error);
     422
     423/**
     424 * @brief Portability wrapper for `ftruncate ()`.
     425 *
     426 * @param[in]  handle Valid file descriptor.
     427 * @param[in]  size   Number of bytes to truncate (or extend) file to.
     428 * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
     429 *                    not interested in error details.
     430 *
     431 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     432 */
     433bool            tr_sys_file_truncate        (tr_sys_file_t        handle,
     434                                             uint64_t             size,
     435                                             tr_error          ** error);
     436
     437/**
     438 * @brief Tell system to prefetch some part of file which is to be read soon.
     439 *
     440 * @param[in]  handle Valid file descriptor.
     441 * @param[in]  offset Offset in file to prefetch from.
     442 * @param[in]  size   Number of bytes to prefetch.
     443 * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
     444 *                    not interested in error details.
     445 *
     446 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     447 */
     448bool            tr_sys_file_prefetch        (tr_sys_file_t        handle,
     449                                             uint64_t             offset,
     450                                             uint64_t             size,
     451                                             tr_error          ** error);
     452
     453/**
     454 * @brief Preallocate file to specified size in full or sparse mode.
     455 *
     456 * @param[in]  handle Valid file descriptor.
     457 * @param[in]  size   Number of bytes to preallocate file to.
     458 * @param[in]  flags  Combination of @ref tr_sys_file_preallocate_flags_t values.
     459 * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
     460 *                    not interested in error details.
     461 *
     462 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     463 */
     464bool            tr_sys_file_preallocate     (tr_sys_file_t        handle,
     465                                             uint64_t             size,
     466                                             int                  flags,
     467                                             tr_error          ** error);
     468
     469/**
     470 * @brief Portability wrapper for `mmap ()` for files.
     471 *
     472 * @param[in]  handle Valid file descriptor.
     473 * @param[in]  offset Offset in file to map from.
     474 * @param[in]  size   Number of bytes to map.
     475 * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
     476 *                    not interested in error details.
     477 *
     478 * @return Pointer to mapped file data on success, `NULL` otherwise (with
     479 *         `error` set accordingly).
     480 */
     481void          * tr_sys_file_map_for_reading (tr_sys_file_t        handle,
     482                                             uint64_t             offset,
     483                                             uint64_t             size,
     484                                             tr_error          ** error);
     485
     486/**
     487 * @brief Portability wrapper for `munmap ()` for files.
     488 *
     489 * @param[in]  address Pointer to mapped file data.
     490 * @param[in]  size    Size of mapped data in bytes.
     491 * @param[out] error   Pointer to error object. Optional, pass `NULL` if you are
     492 *                     not interested in error details.
     493 *
     494 * @return `True` on success, `false` otherwise (with `error` set accordingly).
     495 */
     496bool            tr_sys_file_unmap           (const void         * address,
     497                                             uint64_t             size,
     498                                             tr_error          ** error);
     499
    186500/** @} */
    187501/** @} */
  • trunk/libtransmission/tr-lpd.c

    r14316 r14321  
    412412     * and tr_lpdConsiderAnnounce. However, the code is designed to function as long
    413413     * as interfaces to the rest of the lib remain compatible with char* strings. */
    414     STATIC_ASSERT (sizeof (lpd_torStaticType->info.hashString[0]) == sizeof (char));
     414    TR_STATIC_ASSERT (sizeof (lpd_torStaticType->info.hashString[0]) == sizeof (char), "");
    415415}
    416416/**
  • trunk/libtransmission/tr-lpd.h

    r13625 r14321  
    4747
    4848/**
    49 * @def STATIC_ASSERT
    50 * @brief This helper allows to perform static checks at compile time */
    51 #define STATIC_ASSERT(x) { const char static_check[ ((x) ? 1 : -1)] UNUSED; }
    52 
    53 /**
    5449* @} */
    5550
  • trunk/libtransmission/utils.h

    r14320 r14321  
    7171
    7272
     73#ifndef __has_feature
     74 #define __has_feature(x) 0
     75#endif
     76#ifndef __has_extension
     77 #define __has_extension __has_feature
     78#endif
     79
     80/**
     81 * @def TR_STATIC_ASSERT
     82 * @brief This helper allows to perform static checks at compile time
     83 */
     84#if defined (static_assert)
     85 #define TR_STATIC_ASSERT static_assert
     86#elif __has_feature (c_static_assert) || __has_extension (c_static_assert)
     87 #define TR_STATIC_ASSERT _Static_assert
     88#else
     89 #define TR_STATIC_ASSERT(x, msg) { const char static_check[((x) ? 1 : -1)] UNUSED; }
     90#endif
     91
     92
    7393/***
    7494****
Note: See TracChangeset for help on using the changeset viewer.