LCOV - code coverage report
Current view: directory - src/shared/platform/win - nacl_host_dir.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 104 60 57.7 %
Date: 2014-09-25 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.  Directory descriptor / Handle abstraction.
       9                 :  */
      10                 : #include "native_client/src/include/portability.h"
      11                 : #include <windows.h>
      12                 : #include <io.h>
      13                 : #include <fcntl.h>
      14                 : #include <sys/types.h>
      15                 : #include <sys/stat.h>
      16                 : #include <share.h>
      17                 : #include <stddef.h>
      18                 : 
      19                 : #include "native_client/src/include/nacl_platform.h"
      20                 : #include "native_client/src/shared/platform/nacl_check.h"
      21                 : #include "native_client/src/shared/platform/nacl_host_desc.h"
      22                 : #include "native_client/src/shared/platform/nacl_host_dir.h"
      23                 : #include "native_client/src/shared/platform/nacl_log.h"
      24                 : #include "native_client/src/shared/platform/nacl_sync.h"
      25                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      26                 : #include "native_client/src/shared/platform/win/xlate_system_error.h"
      27                 : 
      28                 : #include "native_client/src/trusted/service_runtime/internal_errno.h"
      29                 : 
      30                 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
      31                 : #include "native_client/src/trusted/service_runtime/include/sys/dirent.h"
      32                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      33                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      34                 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
      35                 : 
      36                 : 
      37                 : #define SSIZE_T_MAX ((ssize_t) ((~(size_t) 0) >> 1))
      38                 : 
      39                 : 
      40               1 : static int NaClHostDirInit(struct NaClHostDir *d) {
      41                 :   int retval;
      42                 : 
      43               1 :   d->handle = FindFirstFile(d->pattern, &d->find_data);
      44               1 :   d->off = 0;
      45               1 :   d->done = 0;
      46                 : 
      47               1 :   if (INVALID_HANDLE_VALUE != d->handle) {
      48               1 :     retval = 0;
      49               1 :   } else {
      50               0 :     int win_error = GetLastError();
      51               0 :     NaClLog(LOG_ERROR, "NaClHostDirInit: failed: %d\n", win_error);
      52               0 :     if (ERROR_NO_MORE_FILES == win_error) {
      53               0 :       d->done = 1;
      54               0 :       retval = 0;
      55               0 :     } else if (ERROR_PATH_NOT_FOUND == win_error) {
      56               0 :       retval = -NACL_ABI_ENOTDIR;
      57               0 :     } else {
      58                 :       /* TODO(sehr): fix the errno handling */
      59               0 :       retval = -NaClXlateSystemError(win_error);
      60                 :     }
      61                 :   }
      62               1 :   return retval;
      63               1 : }
      64                 : 
      65                 : int NaClHostDirOpen(struct NaClHostDir  *d,
      66               1 :                     char                *path) {
      67                 :   int     err;
      68                 :   int     retval;
      69                 : 
      70               1 :   if (NULL == d) {
      71               0 :     NaClLog(LOG_FATAL, "NaClHostDirOpen: 'this' is NULL\n");
      72                 :   }
      73                 : 
      74                 : 
      75                 :   /**
      76                 :     * "path" is an 8-bit char string. Convert to UTF-16 here.
      77                 :     * Using Microsoft "Secure CRT" snprintf. Passing _TRUNCATE
      78                 :     * instructs the runtime to truncate and return -1 if the
      79                 :     * buffer is too small, rather than the default behavior of
      80                 :     * dumping core.
      81                 :     *
      82                 :     * NOTE: %hs specifies a single-byte-char string.
      83                 :     */
      84                 :   err = _snwprintf_s(d->pattern,
      85                 :                      NACL_ARRAY_SIZE(d->pattern),
      86               1 :                      _TRUNCATE, L"%hs\\*.*", path);
      87               1 :   if (err < 0) {
      88               0 :     return -NACL_ABI_EOVERFLOW;
      89                 :   }
      90               1 :   if (!NaClMutexCtor(&d->mu)) {
      91               0 :     return -NACL_ABI_ENOMEM;
      92                 :   }
      93                 : 
      94               1 :   retval = NaClHostDirInit(d);
      95               1 :   if (0 != retval) {
      96               0 :     NaClMutexDtor(&d->mu);
      97                 :   }
      98               1 :   return retval;
      99               1 : }
     100                 : 
     101                 : ssize_t NaClHostDirGetdents(struct NaClHostDir  *d,
     102                 :                             void                *buf,
     103               1 :                             size_t               len) {
     104                 :   struct nacl_abi_dirent volatile *p;
     105                 :   size_t                          i;
     106                 :   ssize_t                         retval;
     107                 : 
     108               1 :   if (NULL == d) {
     109               0 :     NaClLog(LOG_FATAL, "NaClHostDirGetdents: 'this' is NULL\n");
     110                 :   }
     111               1 :   NaClLog(3, "NaClHostDirGetdents(0x%08x, %u):\n", buf, len);
     112               1 :   if (len > SSIZE_T_MAX) {
     113               0 :     NaClLog(3, "Clamping to len SSIZE_T_MAX\n");
     114               0 :     len = SSIZE_T_MAX;
     115                 :   }
     116                 : 
     117               1 :   NaClXMutexLock(&d->mu);
     118                 : 
     119               1 :   p = (struct nacl_abi_dirent *) buf;
     120               1 :   i = 0;
     121                 : 
     122                 :   /*
     123                 :    * d->off is currently the record number, assuming that FindNextFile
     124                 :    * output order is deterministic and consistent.
     125                 :    */
     126               1 :   while (1) {
     127                 :     /**
     128                 :      * The FIND_DATA structure contains the filename as a UTF-16
     129                 :      * string of length MAX_PATH.  This may or may not convert into an
     130                 :      * 8-bit char string of similar length.  The safe thing to do here
     131                 :      * is to assume the worst case: every UTF-16 character expands to
     132                 :      * a four-byte MBCS sequence.  This should default to CP_ACP (ANSI
     133                 :      * code page).
     134                 :      *
     135                 :      * TODO(bsy,sehr): consider using WideCharToMultiByte (and
     136                 :      * MultiByteToWideChar before invoking _s_open_s in
     137                 :      * NaClHostDescOpen) with CP_UTF8 to always present UTF8 to
     138                 :      * untrusted application code.  NB: MB_ERR_INVALID_CHARS is needed
     139                 :      * since otherwise we have an issue with silently dropping invalid
     140                 :      * Unicode code points that can cause file name aliasing.
     141                 :      *
     142                 :      * http://code.google.com/p/nativeclient/issues/detail?id=2725
     143                 :      *
     144                 :      * NB: Keep in mind that MAX_PATH is an API limitation, not a
     145                 :      * limitation of the underlying filesystem.
     146                 :      */
     147                 :     char name_mbcs[(MAX_PATH * 4) + 1];
     148                 :     size_t name_length;
     149                 :     size_t rec_length;
     150                 :     uint16_t nacl_abi_rec_length;
     151                 :     int err;
     152                 : 
     153                 :     /* Handle case where NaClHostDirRewind() failed. */
     154               1 :     if (d->handle == INVALID_HANDLE_VALUE) {
     155               0 :       retval = -NACL_ABI_ENOENT;
     156               0 :       goto done;
     157                 :     }
     158                 : 
     159               1 :     if (d->done) {
     160               1 :       retval = 0;
     161               1 :       goto done;
     162                 :     }
     163                 : 
     164                 :     err = _snprintf_s(name_mbcs,
     165                 :                       _countof(name_mbcs),
     166                 :                       _TRUNCATE,
     167               1 :                       "%ws", d->find_data.cFileName);
     168               1 :     if (err < 0) {
     169               0 :       retval = -NACL_ABI_EOVERFLOW;
     170               0 :       goto done;
     171                 :     }
     172               1 :     name_length = strlen(name_mbcs) + 1;
     173                 :     rec_length = (offsetof(struct nacl_abi_dirent, nacl_abi_d_name)
     174                 :                     + (name_length + 3))
     175               1 :                   & ~3;
     176                 : 
     177                 :     /* Check for overflow in record length */
     178               1 :     nacl_abi_rec_length = (uint16_t) rec_length;
     179               1 :     if (rec_length > (size_t) nacl_abi_rec_length) {
     180                 :       /*
     181                 :        * Can there be file names that are longer than 64K?  Windows
     182                 :        * API docs say that 1023 is the maximum file name length, so
     183                 :        * with a 4x expansion we should only get 4092 + 1 or 4093
     184                 :        * bytes.  But this may be filesystem dependent....
     185                 :        */
     186               0 :       retval = -NACL_ABI_EOVERFLOW;
     187               0 :       goto done;
     188                 :     }
     189                 : 
     190               1 :     CHECK(rec_length <= SSIZE_T_MAX - i);
     191                 :     /*
     192                 :      * Should never happen, since len is clamped to SSIZE_T_MAX.
     193                 :      */
     194                 : 
     195               1 :     if (i + rec_length >= len) {
     196                 :       /*
     197                 :        * Insufficent buffer space!  Check if any entries have been
     198                 :        * copied...
     199                 :        */
     200               1 :       if (0 == i) {
     201               1 :         retval = (ssize_t) -NACL_ABI_EINVAL;
     202               1 :       } else {
     203               1 :         retval = (ssize_t) i;
     204                 :       }
     205               1 :       goto done;
     206                 :     }
     207                 : 
     208               1 :     p = (struct nacl_abi_dirent volatile *) (((char *) buf) + i);
     209               1 :     p->nacl_abi_d_ino = NACL_FAKE_INODE_NUM;  /* windows doesn't do inodes */
     210               1 :     p->nacl_abi_d_off = d->off;
     211               1 :     p->nacl_abi_d_reclen = nacl_abi_rec_length;
     212               1 :     memcpy((char *) p->nacl_abi_d_name, name_mbcs, name_length);
     213               1 :     i += nacl_abi_rec_length;
     214               1 :     ++d->off;
     215                 : 
     216               1 :     if (!FindNextFile(d->handle, &d->find_data)) {
     217               1 :       int win_err = GetLastError();
     218               1 :       if (win_err == ERROR_NO_MORE_FILES) {
     219               1 :         d->done = 1;
     220               1 :         retval = (ssize_t) i;
     221               1 :         goto done;
     222                 :       } else {
     223               0 :         retval = -NaClXlateSystemError(win_err);
     224               0 :         goto done;
     225                 :       }
     226                 :     }
     227               1 :   }
     228                 : done:
     229               1 :   NaClXMutexUnlock(&d->mu);
     230               1 :   return retval;
     231               1 : }
     232                 : 
     233               0 : int NaClHostDirRewind(struct NaClHostDir *d) {
     234                 :   int retval;
     235               0 :   if (NULL == d) {
     236               0 :     NaClLog(LOG_FATAL, "NaClHostDirRewind: 'this' is NULL\n");
     237                 :   }
     238                 : 
     239               0 :   NaClXMutexLock(&d->mu);
     240                 : 
     241                 :   /* Close the handle and reopen it at the beginning. */
     242               0 :   if (!FindClose(d->handle)) {
     243                 :     /*
     244                 :      * It's not clear why FindClose() would fail.  Abort because we
     245                 :      * don't want to leave d->handle in an undefined state.
     246                 :      */
     247               0 :     NaClLog(LOG_FATAL, "NaClHostDirRewind(): FindClose() failed\n");
     248                 :   }
     249                 : 
     250               0 :   retval = NaClHostDirInit(d);
     251               0 :   if (retval != 0) {
     252                 :     /*
     253                 :      * If FindFirstFile fails for some reason mark the handle as invalid so that
     254                 :      * future calls to NaClHostDirGetdents can report the error.
     255                 :      */
     256               0 :     d->handle = INVALID_HANDLE_VALUE;
     257                 :   }
     258                 : 
     259               0 :   NaClXMutexUnlock(&d->mu);
     260               0 :   return retval;
     261               0 : }
     262                 : 
     263               0 : int NaClHostDirClose(struct NaClHostDir *d) {
     264               0 :   if (NULL == d) {
     265               0 :     NaClLog(LOG_FATAL, "NaClHostDirClose: 'this' is NULL\n");
     266                 :   }
     267               0 :   NaClMutexDtor(&d->mu);
     268               0 :   if (!FindClose(d->handle)) {
     269               0 :     return -NaClXlateSystemError(GetLastError());
     270                 :   }
     271               0 :   return 0;
     272               0 : }

Generated by: LCOV version 1.7