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

File:
1 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}
Note: See TracChangeset for help on using the changeset viewer.