LCOV - code coverage report
Current view: directory - src/shared/platform/posix - nacl_host_desc.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 364 275 75.5 %
Date: 2014-06-18 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * NaCl Service Runtime.  I/O Descriptor / Handle abstraction.  Memory
       9                 :  * mapping using descriptors.
      10                 :  *
      11                 :  * Note that we avoid using the thread-specific data / thread local
      12                 :  * storage access to the "errno" variable, and instead use the raw
      13                 :  * system call return interface of small negative numbers as errors.
      14                 :  */
      15                 : 
      16                 : #include <stdint.h>
      17                 : #include <stdio.h>
      18                 : #include <sys/types.h>
      19                 : #include <sys/stat.h>
      20                 : #include <fcntl.h>
      21                 : #include <errno.h>
      22                 : #include <sys/mman.h>
      23                 : #include <unistd.h>
      24                 : 
      25                 : #if NACL_LINUX
      26                 : # include <pthread.h>
      27                 : /* pthread_once for NaClHostDescInit, which is no-op on other OSes */
      28                 : #endif
      29                 : 
      30                 : #include "native_client/src/include/nacl_platform.h"
      31                 : #include "native_client/src/include/portability.h"
      32                 : 
      33                 : #include "native_client/src/shared/platform/nacl_check.h"
      34                 : #include "native_client/src/shared/platform/nacl_host_desc.h"
      35                 : #include "native_client/src/shared/platform/nacl_log.h"
      36                 : 
      37                 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
      38                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      39                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      40                 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
      41                 : #include "native_client/src/trusted/service_runtime/include/sys/unistd.h"
      42                 : 
      43                 : #if NACL_LINUX
      44                 : # include "native_client/src/shared/platform/posix/nacl_file_lock.h"
      45                 : # if NACL_ANDROID
      46                 : #  define PREAD pread
      47                 : #  define PWRITE pwrite
      48                 : # else
      49                 : #  define PREAD pread64
      50                 : #  define PWRITE pwrite64
      51                 : # endif
      52                 : #elif NACL_OSX
      53                 : # define PREAD pread
      54                 : # define PWRITE pwrite
      55                 : #else
      56                 : # error "Which POSIX OS?"
      57                 : #endif
      58                 : 
      59                 : /*
      60                 :  * Map our ABI to the host OS's ABI.
      61                 :  */
      62               1 : static INLINE mode_t NaClMapMode(nacl_abi_mode_t abi_mode) {
      63               1 :   mode_t m = 0;
      64               1 :   if (0 != (abi_mode & NACL_ABI_S_IRUSR))
      65               1 :     m |= S_IRUSR;
      66               1 :   if (0 != (abi_mode & NACL_ABI_S_IWUSR))
      67               0 :     m |= S_IWUSR;
      68               1 :   if (0 != (abi_mode & NACL_ABI_S_IXUSR))
      69               0 :     m |= S_IXUSR;
      70               1 :   return m;
      71                 : }
      72                 : 
      73                 : /*
      74                 :  * Map our ABI to the host OS's ABI.
      75                 :  */
      76               9 : static INLINE int NaClMapAccessMode(int nacl_mode) {
      77               9 :   int mode = 0;
      78               9 :   if (nacl_mode == NACL_ABI_F_OK) {
      79               3 :     mode = F_OK;
      80               3 :   } else {
      81               6 :     if (nacl_mode & NACL_ABI_R_OK)
      82               3 :       mode |= R_OK;
      83               6 :     if (nacl_mode & NACL_ABI_W_OK)
      84               3 :       mode |= W_OK;
      85               6 :     if (nacl_mode & NACL_ABI_X_OK)
      86               0 :       mode |= X_OK;
      87                 :   }
      88               9 :   return mode;
      89                 : }
      90                 : 
      91                 : /*
      92                 :  * Map our ABI to the host OS's ABI.  On linux, this should be a big no-op.
      93                 :  */
      94            1042 : static INLINE int NaClMapOpenFlags(int nacl_flags) {
      95            1042 :   int host_os_flags;
      96                 : 
      97            1042 :   nacl_flags &= (NACL_ABI_O_ACCMODE | NACL_ABI_O_CREAT
      98                 :                  | NACL_ABI_O_TRUNC | NACL_ABI_O_APPEND);
      99                 : 
     100            1042 :   host_os_flags = 0;
     101                 : #define C(H) case NACL_ABI_ ## H: \
     102                 :   host_os_flags |= H;             \
     103                 :   break;
     104            1042 :   switch (nacl_flags & NACL_ABI_O_ACCMODE) {
     105             355 :     C(O_RDONLY);
     106             102 :     C(O_WRONLY);
     107              64 :     C(O_RDWR);
     108                 :   }
     109                 : #undef C
     110                 : #define M(H) do { \
     111                 :     if (0 != (nacl_flags & NACL_ABI_ ## H)) {   \
     112                 :       host_os_flags |= H;                       \
     113                 :     }                                           \
     114                 :   } while (0)
     115            1684 :   M(O_CREAT);
     116            1652 :   M(O_TRUNC);
     117            1575 :   M(O_APPEND);
     118                 : #undef M
     119             521 :   return host_os_flags;
     120                 : }
     121                 : 
     122             521 : static INLINE int NaClMapOpenPerm(int nacl_perm) {
     123             521 :   int host_os_perm;
     124                 : 
     125             521 :   host_os_perm = 0;
     126                 : #define M(H) do { \
     127                 :     if (0 != (nacl_perm & NACL_ABI_ ## H)) { \
     128                 :       host_os_perm |= H; \
     129                 :     } \
     130                 :   } while (0)
     131            1957 :   M(S_IRUSR);
     132            1952 :   M(S_IWUSR);
     133                 : #undef M
     134             521 :   return host_os_perm;
     135                 : }
     136                 : 
     137           71491 : static INLINE int NaClMapFlagMap(int nacl_map_flags) {
     138           71491 :   int host_os_flags;
     139                 : 
     140           71491 :   host_os_flags = 0;
     141                 : #define M(H) do { \
     142                 :     if (0 != (nacl_map_flags & NACL_ABI_ ## H)) { \
     143                 :       host_os_flags |= H; \
     144                 :     } \
     145                 :   } while (0)
     146          214507 :   M(MAP_SHARED);
     147          285930 :   M(MAP_PRIVATE);
     148          285957 :   M(MAP_FIXED);
     149          285890 :   M(MAP_ANONYMOUS);
     150                 : #undef M
     151                 : 
     152           71491 :   return host_os_flags;
     153                 : }
     154                 : 
     155                 : /*
     156                 :  * The NaClHostDescInit function should be invoked in all Ctor-like
     157                 :  * functions.  Since no other NaClHostDesc member function should be
     158                 :  * usable without having invoked a Ctor, lock management functions can
     159                 :  * never be invoked without the lock manager object having been
     160                 :  * initialized.
     161                 :  */
     162                 : #if NACL_LINUX
     163                 : 
     164                 : struct NaClFileLockManager gNaClFileLockManager;
     165                 : 
     166                 : static void NaClHostDescOnceInit(void) {
     167                 :   NaClFileLockManagerCtor(&gNaClFileLockManager);
     168                 : }
     169                 : 
     170                 : /* should be inlined */
     171                 : static INLINE void NaClHostDescInit(void) {
     172                 :   static pthread_once_t control = PTHREAD_ONCE_INIT;
     173                 :   pthread_once(&control, NaClHostDescOnceInit);
     174                 : }
     175                 : 
     176                 : static INLINE void NaClHostDescExclusiveLock(int host_desc) {
     177                 :   NaClFileLockManagerLock(&gNaClFileLockManager, host_desc);
     178                 : }
     179                 : 
     180                 : static INLINE void NaClHostDescExclusiveUnlock(int host_desc) {
     181                 :   NaClFileLockManagerUnlock(&gNaClFileLockManager, host_desc);
     182                 : }
     183                 : 
     184                 : #else
     185                 : 
     186                 : static INLINE void NaClHostDescInit(void) {
     187                 :   ;
     188            1425 : }
     189                 : 
     190               0 : static INLINE void NaClHostDescExclusiveLock(int host_desc) {
     191               0 :   UNREFERENCED_PARAMETER(host_desc);
     192               0 : }
     193                 : 
     194               0 : static INLINE void NaClHostDescExclusiveUnlock(int host_desc) {
     195               0 :   UNREFERENCED_PARAMETER(host_desc);
     196               0 : }
     197                 : 
     198                 : #endif
     199                 : 
     200                 : /*
     201                 :  * TODO(bsy): handle the !NACL_ABI_MAP_FIXED case.
     202                 :  */
     203           71491 : uintptr_t NaClHostDescMap(struct NaClHostDesc *d,
     204           71491 :                           struct NaClDescEffector *effp,
     205           71491 :                           void                *start_addr,
     206           71491 :                           size_t              len,
     207           71491 :                           int                 prot,
     208           71491 :                           int                 flags,
     209           71491 :                           nacl_off64_t        offset) {
     210           71491 :   int   desc;
     211           71491 :   void  *map_addr;
     212           71491 :   int   host_prot;
     213           71491 :   int   tmp_prot;
     214           71491 :   int   host_flags;
     215           71491 :   int   need_exec;
     216          142982 :   UNREFERENCED_PARAMETER(effp);
     217                 : 
     218           71491 :   NaClLog(4,
     219                 :           ("NaClHostDescMap(0x%08"NACL_PRIxPTR", "
     220                 :            "0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxS", "
     221                 :            "0x%x, 0x%x, 0x%08"NACL_PRIx64")\n"),
     222                 :           (uintptr_t) d,
     223                 :           (uintptr_t) start_addr,
     224                 :           len,
     225                 :           prot,
     226                 :           flags,
     227                 :           (int64_t) offset);
     228          142908 :   if (NULL == d && 0 == (flags & NACL_ABI_MAP_ANONYMOUS)) {
     229               0 :     NaClLog(LOG_FATAL, "NaClHostDescMap: 'this' is NULL and not anon map\n");
     230               0 :   }
     231           71565 :   if (NULL != d && -1 == d->d) {
     232               0 :     NaClLog(LOG_FATAL, "NaClHostDescMap: already closed\n");
     233               0 :   }
     234           71491 :   if ((0 == (flags & NACL_ABI_MAP_SHARED)) ==
     235                 :       (0 == (flags & NACL_ABI_MAP_PRIVATE))) {
     236               0 :     NaClLog(LOG_FATAL,
     237                 :             "NaClHostDescMap: exactly one of NACL_ABI_MAP_SHARED"
     238                 :             " and NACL_ABI_MAP_PRIVATE must be set.\n");
     239               0 :   }
     240                 : 
     241           71491 :   prot &= NACL_ABI_PROT_MASK;
     242                 : 
     243           71491 :   if (flags & NACL_ABI_MAP_ANONYMOUS) {
     244           71417 :     desc = -1;
     245           71417 :   } else {
     246              74 :     desc = d->d;
     247                 :   }
     248                 :   /*
     249                 :    * Translate prot, flags to host_prot, host_flags.
     250                 :    */
     251           71491 :   host_prot = NaClProtMap(prot);
     252           71491 :   host_flags = NaClMapFlagMap(flags);
     253                 : 
     254           71491 :   NaClLog(4, "NaClHostDescMap: host_prot 0x%x, host_flags 0x%x\n",
     255                 :           host_prot, host_flags);
     256                 : 
     257                 :   /*
     258                 :    * In chromium-os, the /dev/shm and the user partition (where
     259                 :    * installed apps live) are mounted no-exec, and a special
     260                 :    * modification was made to the chromium-os version of the Linux
     261                 :    * kernel to allow mmap to use files as backing store with
     262                 :    * PROT_EXEC. The standard mmap code path will fail mmap requests
     263                 :    * that ask for PROT_EXEC, but mprotect will allow chaning the
     264                 :    * permissions later. This retains most of the defense-in-depth
     265                 :    * property of disallowing PROT_EXEC in mmap, but enables the use
     266                 :    * case of getting executable code from a file without copying.
     267                 :    *
     268                 :    * See https://code.google.com/p/chromium/issues/detail?id=202321
     269                 :    * for details of the chromium-os change.
     270                 :    */
     271           71491 :   tmp_prot = host_prot & ~PROT_EXEC;
     272           71491 :   need_exec = (0 != (PROT_EXEC & host_prot));
     273           71491 :   map_addr = mmap(start_addr, len, tmp_prot, host_flags, desc, offset);
     274           71498 :   if (need_exec && MAP_FAILED != map_addr) {
     275               7 :     if (0 != mprotect(map_addr, len, host_prot)) {
     276                 :       /*
     277                 :        * Not being able to turn on PROT_EXEC is fatal: we have already
     278                 :        * replaced the original mapping -- restoring them would be too
     279                 :        * painful.  Without scanning /proc (disallowed by outer
     280                 :        * sandbox) or Mach's vm_region call, there is no way
     281                 :        * simple/direct to figure out what was there before.  On Linux
     282                 :        * we could have mremap'd the old memory elsewhere, but still
     283                 :        * would require probing to find the contiguous memory segments
     284                 :        * within the original address range.  And restoring dirtied
     285                 :        * pages on OSX the mappings for which had disappeared may well
     286                 :        * be impossible (getting clean copies of the pages is feasible,
     287                 :        * but insufficient).
     288                 :        */
     289               0 :       NaClLog(LOG_FATAL,
     290                 :               "NaClHostDescMap: mprotect to turn on PROT_EXEC failed,"
     291               0 :               " errno %d\n", errno);
     292               0 :     }
     293               7 :   }
     294                 : 
     295           71491 :   NaClLog(4, "NaClHostDescMap: mmap returned %"NACL_PRIxPTR"\n",
     296                 :           (uintptr_t) map_addr);
     297                 : 
     298           71491 :   if (MAP_FAILED == map_addr) {
     299              14 :     NaClLog(LOG_INFO,
     300                 :             ("NaClHostDescMap: "
     301                 :              "mmap(0x%08"NACL_PRIxPTR", 0x%"NACL_PRIxS", "
     302                 :              "0x%x, 0x%x, 0x%d, 0x%"NACL_PRIx64")"
     303                 :              " failed, errno %d.\n"),
     304                 :             (uintptr_t) start_addr, len, host_prot, host_flags, desc,
     305                 :             (int64_t) offset,
     306               7 :             errno);
     307               7 :     return -NaClXlateErrno(errno);
     308                 :   }
     309          142961 :   if (0 != (flags & NACL_ABI_MAP_FIXED) && map_addr != start_addr) {
     310               0 :     NaClLog(LOG_FATAL,
     311                 :             ("NaClHostDescMap: mmap with MAP_FIXED not fixed:"
     312                 :              " returned 0x%08"NACL_PRIxPTR" instead of 0x%08"NACL_PRIxPTR"\n"),
     313                 :             (uintptr_t) map_addr,
     314                 :             (uintptr_t) start_addr);
     315               0 :   }
     316           71484 :   NaClLog(4, "NaClHostDescMap: returning 0x%08"NACL_PRIxPTR"\n",
     317                 :           (uintptr_t) map_addr);
     318                 : 
     319           71484 :   return (uintptr_t) map_addr;
     320           71491 : }
     321                 : 
     322               7 : int NaClHostDescUnmapUnsafe(void *start_addr, size_t len) {
     323              21 :   return (0 == munmap(start_addr, len)) ? 0 : -errno;
     324                 : }
     325                 : 
     326             515 : static int NaClHostDescCtor(struct NaClHostDesc  *d,
     327             515 :                             int fd,
     328             515 :                             int flags) {
     329             515 :   NaClHostDescInit();
     330             515 :   d->d = fd;
     331             515 :   d->flags = flags;
     332             515 :   NaClLog(3, "NaClHostDescCtor: success.\n");
     333             515 :   return 0;
     334                 : }
     335                 : 
     336             521 : int NaClHostDescOpen(struct NaClHostDesc  *d,
     337             521 :                      char const           *path,
     338             521 :                      int                  flags,
     339             521 :                      int                  mode) {
     340             521 :   int host_desc;
     341             521 :   nacl_host_stat_t stbuf;
     342             521 :   int posix_flags;
     343                 : 
     344             521 :   NaClLog(3, "NaClHostDescOpen(0x%08"NACL_PRIxPTR", %s, 0x%x, 0x%x)\n",
     345                 :           (uintptr_t) d, path, flags, mode);
     346             521 :   if (NULL == d) {
     347               0 :     NaClLog(LOG_FATAL, "NaClHostDescOpen: 'this' is NULL\n");
     348               0 :   }
     349                 :   /*
     350                 :    * Sanitize access flags.
     351                 :    */
     352             521 :   if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
     353               0 :     return -NACL_ABI_EINVAL;
     354                 :   }
     355                 : 
     356             521 :   switch (flags & NACL_ABI_O_ACCMODE) {
     357                 :     case NACL_ABI_O_RDONLY:
     358                 :     case NACL_ABI_O_WRONLY:
     359                 :     case NACL_ABI_O_RDWR:
     360             521 :       break;
     361                 :     default:
     362               0 :       NaClLog(LOG_ERROR,
     363                 :               "NaClHostDescOpen: bad access flags 0x%x.\n",
     364                 :               flags);
     365               0 :       return -NACL_ABI_EINVAL;
     366                 :   }
     367                 : 
     368             521 :   posix_flags = NaClMapOpenFlags(flags);
     369                 : #if NACL_LINUX
     370                 :   posix_flags |= O_LARGEFILE;
     371                 : #endif
     372             521 :   mode = NaClMapOpenPerm(mode);
     373                 : 
     374             521 :   NaClLog(3, "NaClHostDescOpen: invoking POSIX open(%s,0x%x,0%o)\n",
     375                 :           path, posix_flags, mode);
     376             521 :   host_desc = open(path, posix_flags, mode);
     377             521 :   NaClLog(3, "NaClHostDescOpen: got descriptor %d\n", host_desc);
     378             521 :   if (-1 == host_desc) {
     379               6 :     NaClLog(2, "NaClHostDescOpen: open returned -1, errno %d\n", errno);
     380               6 :     return -NaClXlateErrno(errno);
     381                 :   }
     382             515 :   if (-1 == NACL_HOST_FSTAT64(host_desc, &stbuf)
     383                 :       ) {
     384               0 :     NaClLog(LOG_ERROR,
     385               0 :             "NaClHostDescOpen: fstat failed?!?  errno %d\n", errno);
     386               0 :     (void) close(host_desc);
     387               0 :     return -NaClXlateErrno(errno);
     388                 :   }
     389             516 :   if (!S_ISREG(stbuf.st_mode) && !S_ISCHR(stbuf.st_mode)
     390                 :       && !S_ISBLK(stbuf.st_mode)) {
     391               0 :     NaClLog(LOG_INFO,
     392                 :             "NaClHostDescOpen: file type 0x%x, not a file\n", stbuf.st_mode);
     393               0 :     (void) close(host_desc);
     394                 :     /* cannot access anything other than files or char/block devices */
     395               0 :     return -NACL_ABI_EPERM;
     396                 :   }
     397             515 :   return NaClHostDescCtor(d, host_desc, flags);
     398             521 : }
     399                 : 
     400               0 : int NaClHostDescPosixDup(struct NaClHostDesc  *d,
     401               0 :                          int                  posix_d,
     402               0 :                          int                  flags) {
     403               0 :   int host_desc;
     404                 : 
     405               0 :   NaClHostDescInit();
     406               0 :   if (NULL == d) {
     407               0 :     NaClLog(LOG_FATAL, "NaClHostDescPosixDup: 'this' is NULL\n");
     408               0 :   }
     409                 :   /*
     410                 :    * Sanitize access flags.
     411                 :    */
     412               0 :   if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
     413               0 :     return -NACL_ABI_EINVAL;
     414                 :   }
     415                 : 
     416               0 :   switch (flags & NACL_ABI_O_ACCMODE) {
     417                 :     case NACL_ABI_O_RDONLY:
     418                 :     case NACL_ABI_O_WRONLY:
     419                 :     case NACL_ABI_O_RDWR:
     420               0 :       break;
     421                 :     default:
     422               0 :       NaClLog(LOG_ERROR,
     423                 :               "NaClHostDescPosixDup: bad access flags 0x%x.\n",
     424                 :               flags);
     425               0 :       return -NACL_ABI_EINVAL;
     426                 :   }
     427                 : 
     428               0 :   host_desc = dup(posix_d);
     429               0 :   if (-1 == host_desc) {
     430               0 :     return -NACL_ABI_EINVAL;
     431                 :   }
     432               0 :   d->d = host_desc;
     433               0 :   d->flags = flags;
     434               0 :   return 0;
     435               0 : }
     436                 : 
     437             910 : int NaClHostDescPosixTake(struct NaClHostDesc *d,
     438             910 :                           int                 posix_d,
     439             910 :                           int                 flags) {
     440             910 :   NaClHostDescInit();
     441             910 :   if (NULL == d) {
     442               0 :     NaClLog(LOG_FATAL, "NaClHostDescPosixTake: 'this' is NULL\n");
     443               0 :   }
     444                 :   /*
     445                 :    * Sanitize access flags.
     446                 :    */
     447             910 :   if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
     448               0 :     return -NACL_ABI_EINVAL;
     449                 :   }
     450                 : 
     451             910 :   switch (flags & NACL_ABI_O_ACCMODE) {
     452                 :     case NACL_ABI_O_RDONLY:
     453                 :     case NACL_ABI_O_WRONLY:
     454                 :     case NACL_ABI_O_RDWR:
     455             910 :       break;
     456                 :     default:
     457               0 :       NaClLog(LOG_ERROR,
     458                 :               "NaClHostDescPosixTake: bad access flags 0x%x.\n",
     459                 :               flags);
     460               0 :       return -NACL_ABI_EINVAL;
     461                 :   }
     462                 : 
     463             910 :   d->d = posix_d;
     464             910 :   d->flags = flags;
     465             910 :   return 0;
     466             910 : }
     467                 : 
     468             168 : ssize_t NaClHostDescRead(struct NaClHostDesc  *d,
     469             168 :                          void                 *buf,
     470             168 :                          size_t               len) {
     471             168 :   ssize_t retval;
     472                 : 
     473             168 :   NaClHostDescCheckValidity("NaClHostDescRead", d);
     474             168 :   if (NACL_ABI_O_WRONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
     475               4 :     NaClLog(3, "NaClHostDescRead: WRONLY file\n");
     476               4 :     return -NACL_ABI_EBADF;
     477                 :   }
     478             164 :   return ((-1 == (retval = read(d->d, buf, len)))
     479             328 :           ? -NaClXlateErrno(errno) : retval);
     480             168 : }
     481                 : 
     482           59727 : ssize_t NaClHostDescWrite(struct NaClHostDesc *d,
     483           59727 :                           void const          *buf,
     484           59727 :                           size_t              len) {
     485                 :   /*
     486                 :    * See NaClHostDescPWrite for details for why need_lock is required.
     487                 :    */
     488           59727 :   int need_lock;
     489           59727 :   ssize_t retval;
     490                 : 
     491           59727 :   NaClHostDescCheckValidity("NaClHostDescWrite", d);
     492           59727 :   if (NACL_ABI_O_RDONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
     493               4 :     NaClLog(3, "NaClHostDescWrite: RDONLY file\n");
     494               4 :     return -NACL_ABI_EBADF;
     495                 :   }
     496                 : 
     497           59723 :   need_lock = NACL_LINUX && (0 != (d->flags & NACL_ABI_O_APPEND));
     498                 :   /*
     499                 :    * Grab O_APPEND attribute lock, in case pwrite occurs in another
     500                 :    * thread.
     501                 :    */
     502           59723 :   if (need_lock) {
     503               0 :     NaClHostDescExclusiveLock(d->d);
     504               0 :   }
     505           59723 :   retval = write(d->d, buf, len);
     506           59723 :   if (need_lock) {
     507               0 :     NaClHostDescExclusiveUnlock(d->d);
     508               0 :   }
     509           59723 :   if (-1 == retval) {
     510               0 :     retval = -NaClXlateErrno(errno);
     511               0 :   }
     512           59723 :   return retval;
     513           59727 : }
     514                 : 
     515            6765 : nacl_off64_t NaClHostDescSeek(struct NaClHostDesc  *d,
     516            6765 :                               nacl_off64_t         offset,
     517            6765 :                               int                  whence) {
     518            6765 :   nacl_off64_t retval;
     519                 : 
     520            6765 :   NaClHostDescCheckValidity("NaClHostDescSeek", d);
     521                 : #if NACL_LINUX
     522                 :   return ((-1 == (retval = lseek64(d->d, offset, whence)))
     523                 :           ? -NaClXlateErrno(errno) : retval);
     524                 : #elif NACL_OSX
     525            6765 :   return ((-1 == (retval = lseek(d->d, offset, whence)))
     526           13530 :           ? -NaClXlateErrno(errno) : retval);
     527                 : #else
     528                 : # error "What Unix-like OS is this?"
     529                 : #endif
     530                 : }
     531                 : 
     532            1484 : ssize_t NaClHostDescPRead(struct NaClHostDesc *d,
     533            1484 :                           void *buf,
     534            1484 :                           size_t len,
     535            1484 :                           nacl_off64_t offset) {
     536            1484 :   ssize_t retval;
     537                 : 
     538            1484 :   NaClHostDescCheckValidity("NaClHostDescPRead", d);
     539            1484 :   if (NACL_ABI_O_WRONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
     540               1 :     NaClLog(3, "NaClHostDescPRead: WRONLY file\n");
     541               1 :     return -NACL_ABI_EBADF;
     542                 :   }
     543            1483 :   return ((-1 == (retval = PREAD(d->d, buf, len, offset)))
     544            2966 :           ? -NaClXlateErrno(errno) : retval);
     545            1484 : }
     546                 : 
     547              18 : ssize_t NaClHostDescPWrite(struct NaClHostDesc *d,
     548              18 :                            void const *buf,
     549              18 :                            size_t len,
     550              18 :                            nacl_off64_t offset) {
     551              18 :   int need_lock;
     552              18 :   ssize_t retval;
     553                 : 
     554              18 :   NaClHostDescCheckValidity("NaClHostDescPWrite", d);
     555              18 :   if (NACL_ABI_O_RDONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
     556               1 :     NaClLog(3, "NaClHostDescPWrite: RDONLY file\n");
     557               1 :     return -NACL_ABI_EBADF;
     558                 :   }
     559                 :   /*
     560                 :    * Linux's interpretation of what the POSIX standard requires
     561                 :    * differs from OSX.  On Linux, pwrite using a descriptor that was
     562                 :    * opened with O_APPEND will ignore the supplied offset parameter
     563                 :    * and append.  On OSX, the supplied offset parameter wins.
     564                 :    *
     565                 :    * The POSIX specification at
     566                 :    *
     567                 :    *  http://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html
     568                 :    *
     569                 :    * says that pwrite should always pay attention to the supplied offset.
     570                 :    *
     571                 :    * We standardize on POSIX behavior.
     572                 :    */
     573              17 :   need_lock = NACL_LINUX && (0 != (d->flags & NACL_ABI_O_APPEND));
     574              17 :   if (need_lock) {
     575               0 :     int orig_flags;
     576                 :     /*
     577                 :      * Grab lock that all NaCl platform library using applications
     578                 :      * will use.  NB: if the descriptor is shared with a non-NaCl
     579                 :      * platform library-using application, there is a race.
     580                 :      */
     581               0 :     NaClHostDescExclusiveLock(d->d);
     582                 :     /*
     583                 :      * Temporarily disable O_APPEND and issue the pwrite.
     584                 :      */
     585               0 :     orig_flags = fcntl(d->d, F_GETFL, 0);
     586               0 :     CHECK(orig_flags & O_APPEND);
     587               0 :     if (-1 == fcntl(d->d, F_SETFL, orig_flags & ~O_APPEND)) {
     588               0 :       NaClLog(LOG_FATAL,
     589                 :               "NaClHostDescPWrite: could not fcntl F_SETFL (~O_APPEND)\n");
     590               0 :     }
     591               0 :     retval = PWRITE(d->d, buf, len, offset);
     592                 :     /*
     593                 :      * Always re-enable O_APPEND regardless of pwrite success or
     594                 :      * failure.
     595                 :      */
     596               0 :     if (-1 == fcntl(d->d, F_SETFL, orig_flags)) {
     597               0 :       NaClLog(LOG_FATAL,
     598                 :               "NaClHostDescPWrite: could not fcntl F_SETFL (restore)\n");
     599               0 :     }
     600               0 :     NaClHostDescExclusiveUnlock(d->d);
     601               0 :     if (-1 == retval) {
     602               0 :       retval = -NaClXlateErrno(errno);
     603               0 :     }
     604               0 :     return retval;
     605                 :   }
     606                 : 
     607              17 :   return ((-1 == (retval = PWRITE(d->d, buf, len, offset)))
     608              34 :           ? -NaClXlateErrno(errno) : retval);
     609              18 : }
     610                 : 
     611                 : /*
     612                 :  * See NaClHostDescStat below.
     613                 :  */
     614             246 : int NaClHostDescFstat(struct NaClHostDesc  *d,
     615             246 :                       nacl_host_stat_t     *nhsp) {
     616             246 :   NaClHostDescCheckValidity("NaClHostDescFstat", d);
     617             246 :   if (NACL_HOST_FSTAT64(d->d, nhsp) == -1) {
     618               0 :     return -NaClXlateErrno(errno);
     619                 :   }
     620                 : 
     621             246 :   return 0;
     622             246 : }
     623                 : 
     624               2 : int NaClHostDescIsatty(struct NaClHostDesc *d) {
     625               2 :   int retval;
     626                 : 
     627               2 :   NaClHostDescCheckValidity("NaClHostDescIsatty", d);
     628               2 :   retval = isatty(d->d);
     629                 :   /* When isatty fails it returns zero and sets errno. */
     630               6 :   return (0 == retval) ? -NaClXlateErrno(errno) : retval;
     631                 : }
     632                 : 
     633            1001 : int NaClHostDescClose(struct NaClHostDesc *d) {
     634            1001 :   int retval;
     635                 : 
     636            1001 :   NaClHostDescCheckValidity("NaClHostDescClose", d);
     637            1001 :   retval = close(d->d);
     638            1001 :   if (-1 != retval) {
     639            1001 :     d->d = -1;
     640            1001 :   }
     641            3003 :   return (-1 == retval) ? -NaClXlateErrno(errno) : retval;
     642                 : }
     643                 : 
     644                 : /*
     645                 :  * This is not a host descriptor function, but is closely related to
     646                 :  * fstat and should behave similarly.
     647                 :  */
     648             198 : int NaClHostDescStat(char const *path, nacl_host_stat_t *nhsp) {
     649                 : 
     650             198 :   if (NACL_HOST_STAT64(path, nhsp) == -1) {
     651              78 :     return -NaClXlateErrno(errno);
     652                 :   }
     653                 : 
     654             120 :   return 0;
     655             198 : }
     656                 : 
     657               2 : int NaClHostDescMkdir(const char *path, int mode) {
     658               2 :   if (mkdir(path, mode) != 0)
     659               0 :     return -NaClXlateErrno(errno);
     660               2 :   return 0;
     661               2 : }
     662                 : 
     663               6 : int NaClHostDescRmdir(const char *path) {
     664               6 :   if (rmdir(path) != 0)
     665               4 :     return -NaClXlateErrno(errno);
     666               2 :   return 0;
     667               6 : }
     668                 : 
     669               3 : int NaClHostDescChdir(const char *path) {
     670               3 :   if (chdir(path) != 0)
     671               0 :     return -NaClXlateErrno(errno);
     672               3 :   return 0;
     673               3 : }
     674                 : 
     675               5 : int NaClHostDescGetcwd(char *path, size_t len) {
     676               5 :   if (getcwd(path, len) == NULL)
     677               1 :     return -NaClXlateErrno(errno);
     678               4 :   return 0;
     679               5 : }
     680                 : 
     681              12 : int NaClHostDescUnlink(const char *path) {
     682              12 :   if (unlink(path) != 0)
     683               4 :     return -NaClXlateErrno(errno);
     684               8 :   return 0;
     685              12 : }
     686                 : 
     687               2 : int NaClHostDescTruncate(char const *path, nacl_abi_off_t length) {
     688               2 :   if (truncate(path, length) != 0)
     689               0 :     return -NaClXlateErrno(errno);
     690               2 :   return 0;
     691               2 : }
     692                 : 
     693               2 : int NaClHostDescLstat(char const *path, nacl_host_stat_t *nhsp) {
     694               2 :   if (NACL_HOST_LSTAT64(path, nhsp) == -1)
     695               0 :     return -NaClXlateErrno(errno);
     696               2 :   return 0;
     697               2 : }
     698                 : 
     699               1 : int NaClHostDescLink(const char *oldpath, const char *newpath) {
     700               1 :   if (link(oldpath, newpath) != 0)
     701               0 :     return -NaClXlateErrno(errno);
     702               1 :   return 0;
     703               1 : }
     704                 : 
     705               1 : int NaClHostDescRename(const char *oldpath, const char *newpath) {
     706               1 :   if (rename(oldpath, newpath) != 0)
     707               0 :     return -NaClXlateErrno(errno);
     708               1 :   return 0;
     709               1 : }
     710                 : 
     711               2 : int NaClHostDescSymlink(const char *oldpath, const char *newpath) {
     712               2 :   if (symlink(oldpath, newpath) != 0)
     713               1 :     return -NaClXlateErrno(errno);
     714               1 :   return 0;
     715               2 : }
     716                 : 
     717               1 : int NaClHostDescChmod(const char *path, nacl_abi_mode_t mode) {
     718               1 :   if (chmod(path, NaClMapMode(mode)) != 0)
     719               0 :     return -NaClXlateErrno(errno);
     720               1 :   return 0;
     721               1 : }
     722                 : 
     723               9 : int NaClHostDescAccess(const char *path, int amode) {
     724               9 :   if (access(path, NaClMapAccessMode(amode)) != 0)
     725               4 :     return -NaClXlateErrno(errno);
     726               5 :   return 0;
     727               9 : }
     728                 : 
     729               2 : int NaClHostDescReadlink(const char *path, char *buf, size_t bufsize) {
     730               2 :   int retval = readlink(path, buf, bufsize);
     731               2 :   if (retval < 0)
     732               0 :     return -NaClXlateErrno(errno);
     733               2 :   return retval;
     734               2 : }

Generated by: LCOV version 1.7