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.
8 * NaCl Service Runtime. I/O Descriptor / Handle abstraction. Memory
9 * mapping using descriptors.
11 #include "native_client/src/include/portability.h"
12 #include "native_client/src/include/portability_io.h"
17 #include <sys/types.h>
21 #include "native_client/src/include/nacl_macros.h"
22 #include "native_client/src/include/nacl_platform.h"
23 #include "native_client/src/shared/platform/nacl_check.h"
24 #include "native_client/src/shared/platform/nacl_find_addrsp.h"
25 #include "native_client/src/shared/platform/nacl_host_desc.h"
26 #include "native_client/src/shared/platform/nacl_log.h"
27 #include "native_client/src/shared/platform/nacl_sync.h"
28 #include "native_client/src/shared/platform/nacl_sync_checked.h"
29 #include "native_client/src/shared/platform/win/xlate_system_error.h"
30 #include "native_client/src/trusted/desc/nacl_desc_effector.h"
32 #include "native_client/src/trusted/service_runtime/nacl_config.h"
33 #include "native_client/src/trusted/service_runtime/internal_errno.h"
34 #include "native_client/src/trusted/service_runtime/sel_util-inl.h"
36 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
37 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
38 #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
39 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
41 #define OFFSET_FOR_FILEPOS_LOCK (GG_LONGLONG(0x7000000000000000))
44 * By convention, we use locking the byte at OFFSET_FOR_FILEPOS_LOCK
45 * as locking for the implicit file position associated with a file
46 * handle. According to MSDN, LockFileEx of a byte range that does
47 * not (yet) exist in a file is not an error, which makes sense in
48 * that one might want to have exclusive access to a file region that
49 * is beyond the end of the file before populating it. We assume that
50 * OFFSET_FOR_FILEPOS_LOCK is large enough that no real file will
51 * actually be that big (even if sparse) and cause problems.
53 * One drawback of this is that two independent file handles on the
54 * same file will share the same lock. If this leads to actual
55 * contention issues, we can use the following randomized approach,
56 * ASSUMING that each file handle / posix-level host descriptor is
57 * introduced to NaCl at most once (e.g., no dup'ing and invoking
58 * NaClHostDescPosixTake multiple times): we pick a random offset from
59 * OFFSET_FOR_FILEPOS_LOCK, and make sure we transfer that with the
60 * file handle in the nrd_xfer protocol. This way, we use a range of
61 * byte offsets for locking files and avoid false contention. We
62 * would be subject to the birthday paradox, of course, so if we
63 * picked a 16-bit random offset to use, then if a file is opened ~256
64 * times we would start seeing performance issues caused by
65 * contention, which is probably acceptable; a 32-bit nonce would be
68 * On Windows, fcntl is not available. A very similar function to
69 * lockf, _locking, exists in the Windows CRT. It does not permit
70 * specification of the start of a region, only size (just like lockf)
71 * -- implicitly from the current position -- which is less than
72 * useful for our purposes.
74 static void NaClTakeFilePosLock(HANDLE hFile) {
78 memset(&overlap, 0, sizeof overlap);
79 overlap.Offset = (DWORD) OFFSET_FOR_FILEPOS_LOCK;
80 overlap.OffsetHigh = (DWORD) (OFFSET_FOR_FILEPOS_LOCK >> 32);
82 * LockFileEx should never fail -- untrusted code cannot cause hFile
83 * to become invalid, since all NaClHostDesc objects are wrapped in
84 * NaClDesc objects and all uses of NaClDesc objects take a
85 * reference before use, so a threading race that closes a
86 * descriptor at the untrusted code level will only dereference the
87 * NaClDesc (and make it unavailable to the untrusted code), but the
88 * object will not be destroyed until after the NaClDesc-level
89 * operation (which in turn invokes the NaClHostDesc level
90 * operation) completes. Only after the operation completes will
91 * the reference to the NaClDesc be drop by the syscall handler.
93 if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK,
95 /* nNumberOfBytesToLockLow= */ 1,
96 /* nNumberOfBytesToLockHigh= */ 0,
99 NaClLog(LOG_FATAL, "NaClTakeFilePosLock: LockFileEx failed, error %u\n",
104 static void NaClDropFilePosLock(HANDLE hFile) {
108 memset(&overlap, 0, sizeof overlap);
109 overlap.Offset = (DWORD) OFFSET_FOR_FILEPOS_LOCK;
110 overlap.OffsetHigh = (DWORD) (OFFSET_FOR_FILEPOS_LOCK >> 32);
111 if (!UnlockFileEx(hFile,
113 /* nNumberOfBytesToLockLow= */ 1,
114 /* nNumberOfBytesToLockHigh= */ 0,
116 err = GetLastError();
117 NaClLog(LOG_FATAL, "NaClDropFilePosLock: UnlockFileEx failed, error %u\n",
122 static nacl_off64_t NaClLockAndGetCurrentFilePos(HANDLE hFile) {
123 LARGE_INTEGER to_move;
124 LARGE_INTEGER cur_pos;
127 NaClTakeFilePosLock(hFile);
128 to_move.QuadPart = 0;
129 if (!SetFilePointerEx(hFile, to_move, &cur_pos, FILE_CURRENT)) {
130 err = GetLastError();
132 "NaClLockAndGetCurrentFilePos: SetFilePointerEx failed, error %u\n",
135 return cur_pos.QuadPart;
138 static void NaClSetCurrentFilePosAndUnlock(HANDLE hFile,
140 LARGE_INTEGER to_move;
143 to_move.QuadPart = pos;
144 if (!SetFilePointerEx(hFile, to_move, (LARGE_INTEGER *) NULL, FILE_BEGIN)) {
145 err = GetLastError();
147 "NaClSetCurrentFilePosAndUnlock: SetFilePointerEx failed:"
151 NaClDropFilePosLock(hFile);
155 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
157 * The implementation of the host descriptor abstractions will
158 * probably change. In particularly, blocking I/O calls must be
159 * interruptible in order to implement the address-space move
160 * mechanism for mmap error recovery, and the it seems that the only
161 * way that this would be feasible is to do the following: instead of
162 * using the POSIX abstraction layer, do the I/O using Windows file
163 * handles opened for asynchronous operations. When a potentially
164 * blocking system call (e.g., read or write) is performed, use
165 * overlapped I/O via ReadFile/WriteFile to initiate the I/O operation
166 * in a non-blocking manner, and use a separate event object, so that
167 * the thread can, after initiating the I/O, perform
168 * WaitForMultipleObjects on both I/O completion (event in the
169 * OVERLAPPED structure) and on mmap-generated interrupts. The event
170 * can be signalled via SetEvent by any other thread that wish to
171 * perform a safe mmap operation.
173 * When the safe mmap is to occur, all other application threads are
174 * stopped (beware, of course, of the race condition where two threads
175 * try to do mmap), and the remaining running thread performs
176 * VirtualFree and MapViewOfFileEx. If a thread (from some injected
177 * DLL) puts some memory in the hole created by VirtualFree before the
178 * MapViewOfFileEx runs, then we have to move the entire address space
179 * to avoid allowing the untrusted NaCl app from touching this
180 * innocent thread's memory.
182 * What this implies is that a mechanism must exist in order for the
183 * mmapping thread to stop all other application threads, and this is
184 * why the blocking syscalls must be interruptible. When interrupted,
185 * the thread that initiated the I/O must perform CancelIo and check,
186 * via GetOverlappedResult, to see how much have completed, etc, then
187 * put itself into a restartable state -- we might simply return EINTR
188 * if no work has been dnoe and require libc to restart the syscall in
189 * the SysV style, though it should be possible to just restart the
190 * syscall in the BSD style -- and to signal the mmapping thread that
193 * Alternatively, these interrupted operations can return a private
194 * version of EAGAIN, so that the code calling the host descriptor
195 * (syscall handler) can quiesce the thread and restart the I/O
196 * operation once the address space move is complete.
198 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
202 * TODO(bsy, gregoryd): check that _get_errno is indeed a thread-safe way
203 * to get the error from the last 'syscall' into the posix layer.
208 (void) _get_errno(&thread_errno);
209 return NaClXlateErrno(thread_errno);
212 static INLINE size_t size_min(size_t a, size_t b) {
213 return (a < b) ? a : b;
217 * The mapping and unmapping code work in 64K chunks rather than a
218 * single large allocation because all of our uses will use 64K
219 * chunks. Higher level code keeps track of whether memory came from
220 * VirtualAlloc or NaClHostDescMap, and will call the appropriate
221 * deallocation functions.
223 * NB: if prot is NACL_ABI_PROT_NONE, then the memory should be
224 * deallocated via VirtualFree as if it came from paging file rather
225 * than via a file mapping object representing the paging file (and
226 * thus UnmapViewOfFile).
230 * out_flProtect == 0 means error, and the error string can be used
231 * for a logging message (except for the cases that the caller should
234 * in parameters are all NACL_ABI_ values or bool (0/1).
236 * accmode may be NACL_ABI_O_RDONLY or NACL_ABI_O_RDWR, but not
237 * NACL_ABI_O_WRONLY (see below).
239 * Caller should check for:
241 * - PROT_NONE -> special case handling,
242 * - NACL_ABI_O_APPEND and PROT_WRITE -> EACCES,
243 * - accmode is O_WRONLY -> EACCES,
245 * The interpretation here is that PROT_EXEC or PROT_WRITE implies
246 * asking for PROT_READ, since most hardware behaves this way. So if
247 * the descriptor is O_WRONLY, we generally refuse.
249 * The file mapping object created by CreateFileMapping's flProtect
250 * argument specifies the MAXIMUM protection, and MapViewOfFileEx will
251 * request a lesser level of access. We should always
252 * CreateFileMapping with a high level of access so that
253 * VirtualProtect (used by mprotect) can be used to turn on write when
254 * the initial mmap had read-only mappings.
256 * BUG(phosek): Due to Windows XP limitation, in particular the missing
257 * PAGE_EXECUTE_WRITECOPY protection support for file mapping objects,
258 * we cannot mmap r/o file as private, read/write and later make it
259 * executable or vice versa mmap r/o file as private, read/execute and
260 * later make it writable. This is a platform difference, but since
261 * untrusted code is not allowed to mmap files as write/execute, this
262 * difference is invisible to application developers and will therefore
263 * likely remain unresolved as the solution would likely be very
264 * expensive. Furthemore, after dropping the support for Windows XP, this
265 * difference can be easily resolved by updating the flag mapping.
267 void NaClflProtectAndDesiredAccessMap(int prot,
270 DWORD *out_flMappingProtect,
271 DWORD *out_flProtect,
272 DWORD *out_dwDesiredAccess,
273 char const **out_msg) {
274 #define M(mp,p,da,err) { mp, p, da, err, #mp, #p, #da }
276 DWORD flMappingProtect;
278 DWORD dwDesiredAccess;
280 char const *flMappingProtect_str;
281 char const *flProtect_str;
282 char const *dwDesiredAccess_str;
287 M(PAGE_EXECUTE_READ, PAGE_NOACCESS, FILE_MAP_READ, NULL),
289 M(PAGE_EXECUTE_READ, PAGE_READONLY, FILE_MAP_READ, NULL),
291 M(0, 0, 0, "file open for read only; no shared write allowed"),
292 /* PROT_READ | PROT_WRITE */
293 M(0, 0, 0, "file open for read only; no shared read/write allowed"),
295 M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE,
296 FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
297 /* PROT_READ | PROT_EXEC */
298 M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READ,
299 FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
300 /* PROT_WRITE | PROT_EXEC */
301 M(0, 0, 0, "file open for read only; no shared write/exec allowed"),
302 /* PROT_READ | PROT_WRITE | PROT_EXEC */
303 M(0, 0, 0, "file open for read only; no shared read/write/exec allowed"),
307 M(PAGE_EXECUTE_READ, PAGE_NOACCESS, FILE_MAP_READ, NULL),
309 M(PAGE_EXECUTE_READ, PAGE_READONLY, FILE_MAP_READ, NULL),
311 M(PAGE_EXECUTE_READ, PAGE_WRITECOPY, FILE_MAP_COPY, NULL),
312 /* PROT_READ | PROT_WRITE */
313 M(PAGE_EXECUTE_READ, PAGE_WRITECOPY, FILE_MAP_COPY, NULL),
316 * NB: PAGE_EXECUTE_WRITECOPY is not supported on Server 2003 or
317 * XP, which means that the mmap will fail. In this case we fallback
318 * to PAGE_EXECUTE_READ.
320 * Even with PAGE_EXECUTE_WRITECOPY, the PROT_WRITE | PROT_EXEC
321 * case where we are asking for FILE_MAP_COPY | FILE_MAP_EXECUTE
322 * seems to always fail, with GetLastError() yielding 87
323 * (ERROR_INVALID_PARAMETER). This may be due to antivirus.
327 M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE,
328 FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
329 /* PROT_READ | PROT_EXEC */
330 M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READ,
331 FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
332 /* PROT_WRITE | PROT_EXEC */
333 M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY,
334 FILE_MAP_COPY | FILE_MAP_EXECUTE, NULL),
335 /* PROT_READ | PROT_WRITE | PROT_EXEC */
336 M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY,
337 FILE_MAP_COPY | FILE_MAP_EXECUTE, NULL),
342 M(PAGE_EXECUTE_READWRITE, PAGE_NOACCESS, FILE_MAP_READ, NULL),
344 M(PAGE_EXECUTE_READWRITE, PAGE_READONLY, FILE_MAP_READ, NULL),
346 M(PAGE_EXECUTE_READWRITE, PAGE_READWRITE, FILE_MAP_WRITE, NULL),
347 /* PROT_READ | PROT_WRITE */
348 M(PAGE_EXECUTE_READWRITE, PAGE_READWRITE, FILE_MAP_WRITE, NULL),
351 M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE,
352 FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
353 /* PROT_READ | PROT_EXEC */
354 M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_READ,
355 FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
356 /* PROT_WRITE | PROT_EXEC */
357 M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_READWRITE,
358 FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
359 /* PROT_READ | PROT_WRITE | PROT_EXEC */
360 M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_READWRITE,
361 FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
365 M(PAGE_EXECUTE_READWRITE, PAGE_NOACCESS, FILE_MAP_READ, NULL),
367 M(PAGE_EXECUTE_READWRITE, PAGE_READONLY, FILE_MAP_READ, NULL),
369 M(PAGE_EXECUTE_READWRITE, PAGE_WRITECOPY, FILE_MAP_COPY, NULL),
370 /* PROT_READ | PROT_WRITE */
371 M(PAGE_EXECUTE_READWRITE, PAGE_WRITECOPY, FILE_MAP_COPY, NULL),
374 M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE,
375 FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
376 /* PROT_READ | PROT_EXEC */
377 M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_READ,
378 FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
379 /* PROT_WRITE | PROT_EXEC */
380 M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY,
381 FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
382 /* PROT_READ | PROT_WRITE | PROT_EXEC */
383 M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY,
384 FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
391 "NaClflProtectAndDesiredAccessMap(prot 0x%x,"
392 " priv 0x%x, accmode 0x%x, ...)\n",
393 prot, is_private, accmode);
395 NACL_COMPILE_TIME_ASSERT(NACL_ABI_O_RDONLY == 0);
396 NACL_COMPILE_TIME_ASSERT(NACL_ABI_O_RDWR == 2);
397 NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_NONE == 0);
398 NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_READ == 1);
399 NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_WRITE == 2);
400 NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_EXEC == 4);
402 CHECK(accmode != NACL_ABI_O_WRONLY);
405 * NACL_ABI_O_RDONLY == 0, NACL_ABI_O_RDWR == 2, so multiplying by 8
406 * yields a base separation of 8 for the 16 element subtable indexed
407 * by the NACL_ABI_PROT_{READ|WRITE|EXEC} and is_private values.
409 ix = ((prot & NACL_ABI_PROT_MASK) +
411 ((accmode & NACL_ABI_O_ACCMODE) << 3));
413 CHECK(ix < NACL_ARRAY_SIZE(table)); /* compiler should elide this */
415 if (NULL != out_flMappingProtect) {
416 *out_flMappingProtect = table[ix].flMappingProtect;
418 if (NULL != out_flProtect) {
419 *out_flProtect = table[ix].flProtect;
421 if (NULL != out_dwDesiredAccess) {
422 *out_dwDesiredAccess = table[ix].dwDesiredAccess;
424 if (NULL != out_msg) {
425 *out_msg = table[ix].err;
428 NaClLog(3, "NaClflProtectAndDesiredAccessMap: %s %s %s\n",
429 table[ix].flMappingProtect_str,
430 table[ix].flProtect_str,
431 table[ix].dwDesiredAccess_str);
435 * Returns flProtect flags for VirtualAlloc'd memory, file based
436 * mappings should always use NaClflProtectAndDesiredAccessMap.
438 DWORD NaClflProtectMap(int prot) {
439 #define M(p) { p, #p }
442 char const *flProtect_str;
450 /* PROT_READ | PROT_WRITE */
455 /* PROT_READ | PROT_EXEC */
456 M(PAGE_EXECUTE_READ),
457 /* PROT_WRITE | PROT_EXEC */
458 M(PAGE_EXECUTE_READWRITE),
459 /* PROT_READ | PROT_WRITE | PROT_EXEC */
460 M(PAGE_EXECUTE_READWRITE),
466 NaClLog(3, "NaClflProtectMap(prot 0x%x)\n", prot);
468 NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_NONE == 0);
469 NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_READ == 1);
470 NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_WRITE == 2);
471 NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_EXEC == 4);
473 ix = (prot & NACL_ABI_PROT_MASK);
474 CHECK(ix < NACL_ARRAY_SIZE(table)); /* compiler should elide this */
476 NaClLog(3, "NaClflProtectMap: %s\n", table[ix].flProtect_str);
478 return table[ix].flProtect;
482 * Unfortunately, when the descriptor is imported via
483 * NaClHostDescPosixTake or NaClHostDescPosixDup, the underlying file
484 * handle may not have GENERIC_EXECUTE permission associated with it,
485 * unlike the files open using NaClHostDescOpen. This means that the
486 * CreateFileMapping with flMappingProtect that specifies PAGE_EXECUTE_*
487 * will fail. Since we don't know whether GENERIC_EXECUTE without doing
488 * a query, we instead lazily determine the need by detecting the
489 * CreateFileMapping error and retrying using a fallback
490 * flMappingProtect that does not have EXECUTE rights. We record this
491 * in the descriptor so that the next time we do not have to try with
492 * the PAGE_EXECUTE_* and have it deterministically fail.
494 * This function is also used when mapping in anonymous memory. We
495 * assume that we never map anonymous executable memory -- mmap of
496 * executable data is always from a file, and the page will be
497 * non-writable -- and we ensure that anonymous memory is never
500 static DWORD NaClflProtectRemoveExecute(DWORD flProtect) {
503 return PAGE_NOACCESS;
504 case PAGE_EXECUTE_READ:
505 return PAGE_READONLY;
506 case PAGE_EXECUTE_READWRITE:
507 return PAGE_READWRITE;
508 case PAGE_EXECUTE_WRITECOPY:
509 return PAGE_WRITECOPY;
514 /* Check if flProtect has executable permission. */
515 static int NaClflProtectHasExecute(DWORD flProtect) {
516 return flProtect == PAGE_EXECUTE ||
517 flProtect == PAGE_EXECUTE_READ ||
518 flProtect == PAGE_EXECUTE_READWRITE ||
519 flProtect == PAGE_EXECUTE_WRITECOPY;
523 * TODO(mseaborn): Reduce duplication between this function and
524 * nacl::Map()/NaClMap().
526 uintptr_t NaClHostDescMap(struct NaClHostDesc *d,
527 struct NaClDescEffector *effp,
532 nacl_off64_t offset) {
539 DWORD flMappingProtect;
540 DWORD dwDesiredAccess;
544 DWORD dwMaximumSizeHigh;
545 DWORD dwMaximumSizeLow;
546 uintptr_t map_result;
552 ("NaClHostDescMap(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR
553 ", 0x%"NACL_PRIxS", 0x%x, 0x%x, 0x%016"NACL_PRIxNACL_OFF64")\n"),
554 (uintptr_t) d, (uintptr_t) start_addr,
555 len, prot, flags, offset);
556 if (NULL == d && 0 == (flags & NACL_ABI_MAP_ANONYMOUS)) {
557 NaClLog(LOG_FATAL, "NaClHostDescMap: 'this' is NULL and not anon map\n");
559 if (NULL != d && -1 == d->d) {
560 NaClLog(LOG_FATAL, "NaClHostDescMap: already closed\n");
562 if ((0 == (flags & NACL_ABI_MAP_SHARED)) ==
563 (0 == (flags & NACL_ABI_MAP_PRIVATE))) {
565 "NaClHostDescMap: exactly one of NACL_ABI_MAP_SHARED"
566 " and NACL_ABI_MAP_PRIVATE must be set.\n");
568 addr = (uintptr_t) start_addr;
569 prot &= NACL_ABI_PROT_MASK;
572 * Check that if FIXED, start_addr is not NULL.
573 * Use platform free address space locator to set start_addr if NULL and
576 if (0 == (flags & NACL_ABI_MAP_FIXED)) {
578 * Not fixed, addr is a hint... which we ignore. We cannot just
579 * let windows pick, since we are mapping memory in chunks of
580 * 64-kB to permit piecewise unmapping.
582 if (!NaClFindAddressSpace(&addr, len)) {
584 "NaClHostDescMap: not fixed, and could not find space\n");
585 return (uintptr_t) -NACL_ABI_ENOMEM;
589 "NaClHostDescMap: NOT FIXED, found space at %"NACL_PRIxPTR"\n",
592 start_addr = (void *) addr;
598 if (0 != (flags & NACL_ABI_MAP_ANONYMOUS)) {
600 * anonymous memory must be free'able later via VirtualFree
602 NaClLog(3, "NaClHostDescMap: anonymous mapping\n");
604 flProtect = NaClflProtectMap(prot & (~PROT_EXEC));
605 NaClLog(3, "NaClHostDescMap: flProtect 0x%x\n", flProtect);
607 for (chunk_offset = 0;
609 chunk_offset += NACL_MAP_PAGESIZE) {
610 uintptr_t chunk_addr = addr + chunk_offset;
612 (*effp->vtbl->UnmapMemory)(effp, chunk_addr, NACL_MAP_PAGESIZE);
615 "NaClHostDescMap: VirtualAlloc(0x%08x,,%x,%x)\n",
616 (void *) (addr + chunk_offset),
617 MEM_COMMIT | MEM_RESERVE,
619 map_result = (uintptr_t) VirtualAlloc((void *) chunk_addr,
621 MEM_COMMIT | MEM_RESERVE,
623 if (map_result != addr + chunk_offset) {
625 ("Could not VirtualAlloc anonymous memory at"
626 " addr 0x%08x with prot %x\n"),
627 addr + chunk_offset, flProtect);
630 NaClLog(3, "NaClHostDescMap: (anon) returning 0x%08"NACL_PRIxPTR"\n",
632 return (uintptr_t) start_addr;
636 desc_flags = NACL_ABI_O_RDWR;
638 desc_flags = d->flags;
641 if (0 != (desc_flags & NACL_ABI_O_APPEND) &&
642 0 != (prot & NACL_ABI_PROT_WRITE)) {
643 return (uintptr_t) -NACL_ABI_EACCES;
645 if (NACL_ABI_O_WRONLY == (desc_flags & NACL_ABI_O_ACCMODE)) {
646 return (uintptr_t) -NACL_ABI_EACCES;
648 NaClflProtectAndDesiredAccessMap(prot,
649 0 != (flags & NACL_ABI_MAP_PRIVATE),
650 (desc_flags & NACL_ABI_O_ACCMODE),
655 if (0 == flProtect) {
656 NaClLog(3, "NaClHostDescMap: %s\n", err_msg);
657 return (uintptr_t) -NACL_ABI_EACCES;
660 "NaClHostDescMap: flMappingProtect 0x%x,"
661 " dwDesiredAccess 0x%x, flProtect 0x%x\n",
662 flMappingProtect, dwDesiredAccess, flProtect);
664 hFile = (HANDLE) _get_osfhandle(d->d);
665 dwMaximumSizeLow = 0;
666 dwMaximumSizeHigh = 0;
669 * Ensure consistency of the d->flMappingProtect access.
671 NaClFastMutexLock(&d->mu);
672 if (0 != d->flMappingProtect) {
673 flMappingProtect = d->flMappingProtect;
678 NaClFastMutexUnlock(&d->mu);
681 * Finite retry cycle. We can fallback from PAGE_EXECUTE_WRITECOPY to
682 * PAGE_EXECUTE_READ and from having executable permissions to not having
687 * If hFile is INVALID_HANDLE_VALUE, the memory is backed by the
688 * system paging file. Why does it returns NULL instead of
689 * INVALID_HANDLE_VALUE when there is an error?
691 hMap = CreateFileMapping(hFile,
697 if (NULL == hMap && retry_fallback) {
699 * PAGE_EXECUTE_WRITECOPY is not supported on Windows XP so we fallback
700 * to PAGE_EXECUTE_READ.
702 if (PAGE_EXECUTE_WRITECOPY == flMappingProtect) {
704 "NaClHostDescMap: CreateFileMapping failed, retrying with"
705 " PAGE_EXECUTE_READ instead of PAGE_EXECUTE_WRITECOPY\n");
706 flMappingProtect = PAGE_EXECUTE_READ;
709 if (0 == (prot & NACL_ABI_PROT_EXEC) &&
710 NaClflProtectHasExecute(flMappingProtect)) {
712 "NaClHostDescMap: CreateFileMapping failed, retrying without"
713 " execute permission. Original flMappingProtect 0x%x\n",
715 NaClflProtectAndDesiredAccessMap(prot & (~PROT_EXEC),
716 0 != (flags & NACL_ABI_MAP_PRIVATE),
717 (desc_flags & NACL_ABI_O_ACCMODE),
722 if (0 == flProtect) {
723 NaClLog(3, "NaClHostDescMap: %s\n", err_msg);
724 return (uintptr_t) -NACL_ABI_EACCES;
726 flMappingProtect = NaClflProtectRemoveExecute(flMappingProtect);
728 "NaClHostDescMap: fallback flMappingProtect 0x%x,"
729 " dwDesiredAccess 0x%x, flProtect 0x%x\n",
730 flMappingProtect, dwDesiredAccess, flProtect);
734 "NaClHostDescMap: not retrying, since caller explicitly asked"
735 " for NACL_ABI_PROT_EXEC\n");
739 * Remember successful flProtect used. Note that this just
740 * ensures reads of d->flMappingProtect gets a consistent value;
741 * we have a potential race where two threads perform mmap and in
742 * parallel determine the replacement flProtect value. This is
743 * okay, since those two threads should arrive at the same
744 * replacement value. This could be replaced with an atomic
747 NaClFastMutexLock(&d->mu);
748 d->flMappingProtect = flMappingProtect;
749 NaClFastMutexUnlock(&d->mu);
754 DWORD err = GetLastError();
756 "NaClHostDescMap: CreateFileMapping failed: %d\n",
758 return -NaClXlateSystemError(err);
760 NaClLog(3, "NaClHostDescMap: CreateFileMapping got handle %d\n", (int) hMap);
761 NaClLog(3, "NaClHostDescMap: dwDesiredAccess 0x%x\n", dwDesiredAccess);
763 retval = (uintptr_t) -NACL_ABI_EINVAL;
765 for (chunk_offset = 0;
767 chunk_offset += NACL_MAP_PAGESIZE) {
768 uintptr_t chunk_addr = addr + chunk_offset;
769 nacl_off64_t net_offset;
770 uint32_t net_offset_high;
771 uint32_t net_offset_low;
773 (*effp->vtbl->UnmapMemory)(effp, chunk_addr, NACL_MAP_PAGESIZE);
775 chunk_size = size_min(len - chunk_offset, NACL_MAP_PAGESIZE);
776 /* in case MapViewOfFile cares that we exceed the file size */
777 net_offset = offset + chunk_offset;
778 net_offset_high = (uint32_t) (net_offset >> 32);
779 net_offset_low = (uint32_t) net_offset;
781 "NaClHostDescMap: MapViewOfFileEx(hMap=%d, dwDesiredAccess=0x%x,"
782 " net_offset_high = 0x%08x, net_offset_low = 0x%08x,"
783 " chunk_size = 0x%"NACL_PRIxS", chunk_addr = 0x%"NACL_PRIxPTR"\n",
784 hMap, dwDesiredAccess, net_offset_high, net_offset_low,
785 chunk_size, chunk_addr);
786 map_result = (uintptr_t) MapViewOfFileEx(hMap,
791 (void *) chunk_addr);
793 "NaClHostDescMap: map_result %"NACL_PRIxPTR
794 ", chunk_addr %"NACL_PRIxPTR
795 ", addr + chunk_offset %"NACL_PRIxPTR"\n",
796 map_result, chunk_addr, (addr + chunk_offset));
797 if ((addr + chunk_offset) != map_result) {
798 DWORD err = GetLastError();
800 "MapViewOfFileEx failed at 0x%08"NACL_PRIxPTR
801 ", got 0x%08"NACL_PRIxPTR", err %x\n",
805 for (unmap_offset = 0;
806 unmap_offset < chunk_offset;
807 unmap_offset += NACL_MAP_PAGESIZE) {
808 (void) UnmapViewOfFile((void *) (addr + unmap_offset));
810 retval = (uintptr_t) -NaClXlateSystemError(err);
813 if (!VirtualProtect((void *) map_result,
814 NaClRoundPage(chunk_size),
817 DWORD err = GetLastError();
819 "VirtualProtect failed at 0x%08x, err %x\n",
821 retval = (uintptr_t) -NaClXlateSystemError(err);
825 retval = (uintptr_t) start_addr;
827 (void) CloseHandle(hMap);
828 NaClLog(3, "NaClHostDescMap: returning %"NACL_PRIxPTR"\n", retval);
832 int NaClHostDescUnmapUnsafe(void *start_addr,
837 addr = (uintptr_t) start_addr;
839 for (off = 0; off < len; off += NACL_MAP_PAGESIZE) {
840 if (!UnmapViewOfFile((void *) (addr + off))) {
842 "NaClHostDescUnmap: UnmapViewOfFile(0x%08x) failed\n",
844 return -NACL_ABI_EINVAL;
850 static void NaClHostDescCtorIntern(struct NaClHostDesc *hd,
853 nacl_host_stat_t stbuf;
857 hd->flMappingProtect = 0;
858 if (_fstat64(posix_d, &stbuf) != 0) {
859 /* inherited non-fstat'able are IPC channels, e.g., for bootstrap channel */
861 "NaClHostDescCtorIntern: could not _fstat64,"
862 " assuming non-seekable\n");
863 hd->protect_filepos = 0;
865 int file_type = stbuf.st_mode & S_IFMT;
867 * Inherited stdio are console handles and are not seekable.
869 * Posix descriptors (wrapping Windows HANDLES) opened for
870 * O_WRONLY | O_APPEND cannot have byte range locks applied, which
871 * is how the protect_filepos mechanism is implemented. Luckily,
872 * this is only needed for O_RDWR | O_APPEND or non-append
875 hd->protect_filepos = (((S_IFREG == file_type) ||
876 (S_IFDIR == file_type)) &&
877 !((flags & NACL_ABI_O_APPEND) != 0 &&
878 (flags & NACL_ABI_O_ACCMODE) ==
881 if (!NaClFastMutexCtor(&hd->mu)) {
882 NaClLog(LOG_FATAL, "NaClHostDescCtorIntern: NaClFastMutexCtor failed\n");
886 int NaClHostDescOpen(struct NaClHostDesc *d,
890 DWORD dwDesiredAccess;
891 DWORD dwCreationDisposition;
892 DWORD dwFlagsAndAttributes;
894 int truncate_after_open = 0;
900 * TODO(bsy): do something reasonable with perms. In particular,
901 * Windows does support read-only files, so if (perms &
902 * NACL_ABI_IRWXU) == NACL_ABI_S_IRUSR, we could create the file
903 * with FILE_ATTRIBUTE_READONLY. Since only test code is allowed to
904 * open files, this is low priority.
906 UNREFERENCED_PARAMETER(perms);
908 NaClLog(LOG_FATAL, "NaClHostDescOpen: 'this' is NULL\n");
911 * Sanitize access flags.
913 if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
914 return -NACL_ABI_EINVAL;
917 switch (flags & NACL_ABI_O_ACCMODE) {
918 case NACL_ABI_O_RDONLY:
919 dwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
920 oflags = _O_RDONLY | _O_BINARY;
922 case NACL_ABI_O_RDWR:
923 oflags = _O_RDWR | _O_BINARY;
924 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE;
926 case NACL_ABI_O_WRONLY: /* Enforced in the Read call */
927 oflags = _O_WRONLY | _O_BINARY;
928 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE;
932 "NaClHostDescOpen: bad access flags 0x%x.\n",
934 return -NACL_ABI_EINVAL;
937 * Possibly make the file read-only. The file attribute only
938 * applies if the file is created; if it pre-exists, the attributes
939 * from the file is combined with the FILE_FLAG_* values.
941 if (0 == (perms & NACL_ABI_S_IWUSR)) {
942 dwFlagsAndAttributes = (FILE_ATTRIBUTE_READONLY |
943 FILE_FLAG_POSIX_SEMANTICS);
945 dwFlagsAndAttributes = (FILE_ATTRIBUTE_NORMAL |
946 FILE_FLAG_POSIX_SEMANTICS);
949 * Postcondition: flags & NACL_ABI_O_ACCMODE is one of the three
952 switch (flags & (NACL_ABI_O_CREAT | NACL_ABI_O_TRUNC)) {
954 dwCreationDisposition = OPEN_EXISTING;
956 case NACL_ABI_O_CREAT:
957 dwCreationDisposition = OPEN_ALWAYS;
959 case NACL_ABI_O_TRUNC:
960 dwCreationDisposition = TRUNCATE_EXISTING;
961 truncate_after_open = 1;
963 case NACL_ABI_O_CREAT | NACL_ABI_O_TRUNC:
964 dwCreationDisposition = OPEN_ALWAYS;
965 truncate_after_open = 1;
967 if (0 != (flags & NACL_ABI_O_APPEND)) {
972 "NaClHostDescOpen: CreateFileA(path=%s, desired_access=0x%x,"
973 " share_mode=ALL, security_attributes=NULL, creation_disposition=%d,"
974 " flags_and_attributes=%d, template_file=NULL)\n",
975 path, dwDesiredAccess, dwCreationDisposition, dwFlagsAndAttributes);
977 hFile = CreateFileA(path, dwDesiredAccess,
982 dwCreationDisposition,
983 dwFlagsAndAttributes,
985 if (INVALID_HANDLE_VALUE == hFile) {
986 err = GetLastError();
987 NaClLog(3, "NaClHostDescOpen: CreateFile failed %d\n", err);
988 return -NaClXlateSystemError(err);
990 if (truncate_after_open &&
991 NACL_ABI_O_RDONLY != (flags & NACL_ABI_O_ACCMODE)) {
992 NaClLog(4, "NaClHostDescOpen: Truncating file\n");
993 if (!SetEndOfFile(hFile)) {
994 int last_error = GetLastError();
996 "NaClHostDescOpen: could not truncate file:"
999 if (last_error == ERROR_USER_MAPPED_FILE) {
1001 "NaClHostDescOpen: this is due to an existing mapping"
1002 " of the same file.\n");
1006 fd = _open_osfhandle((intptr_t) hFile, oflags);
1008 * oflags _O_APPEND, _O_RDONLY, and _O_TEXT are meaningful; unclear
1009 * whether _O_RDWR, _O_WRONLY, etc has any effect.
1012 NaClLog(LOG_FATAL, "NaClHostDescOpen failed: err %d\n",
1015 NaClHostDescCtorIntern(d, fd, flags);
1019 int NaClHostDescPosixDup(struct NaClHostDesc *d,
1024 NaClLog(3, "NaClHostDescPosixDup(0x%08x, %d, 0%o)\n",
1025 (uintptr_t) d, posix_d, flags);
1027 NaClLog(LOG_FATAL, "NaClHostDescPosixDup: 'this' is NULL\n");
1030 * Sanitize access flags.
1032 if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
1033 return -NACL_ABI_EINVAL;
1035 switch (flags & NACL_ABI_O_ACCMODE) {
1036 case NACL_ABI_O_RDONLY:
1037 case NACL_ABI_O_WRONLY:
1038 case NACL_ABI_O_RDWR:
1042 "NaClHostDescOpen: bad access flags 0x%x.\n",
1044 return -NACL_ABI_EINVAL;
1047 host_desc = _dup(posix_d);
1048 if (-1 == host_desc) {
1051 NaClHostDescCtorIntern(d, host_desc, flags);
1055 int NaClHostDescPosixTake(struct NaClHostDesc *d,
1059 NaClLog(LOG_FATAL, "NaClHostDescPosixTake: 'this' is NULL\n");
1062 * Sanitize access flags.
1064 if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
1065 return -NACL_ABI_EINVAL;
1067 switch (flags & NACL_ABI_O_ACCMODE) {
1068 case NACL_ABI_O_RDONLY:
1069 case NACL_ABI_O_WRONLY:
1070 case NACL_ABI_O_RDWR:
1074 "NaClHostDescOpen: bad access flags 0x%x.\n",
1076 return -NACL_ABI_EINVAL;
1078 NaClHostDescCtorIntern(d, posix_d, flags);
1082 ssize_t NaClHostDescRead(struct NaClHostDesc *d,
1085 /* Windows ReadFile only supports DWORD, so we need
1086 * to clamp the length. */
1087 unsigned int actual_len;
1089 DWORD bytes_received;
1092 if (len < UINT_MAX) {
1093 actual_len = (unsigned int) len;
1095 actual_len = UINT_MAX;
1098 NaClHostDescCheckValidity("NaClHostDescRead", d);
1099 if (NACL_ABI_O_WRONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
1100 NaClLog(3, "NaClHostDescRead: WRONLY file\n");
1101 return -NACL_ABI_EBADF;
1104 * We drop into using Windows ReadFile rather than using _read from
1105 * the POSIX compatibility layer here. The reason for this is
1106 * because the pread/pwrite implementation uses ReadFile/WriteFile,
1107 * it would be more consistent with the pread/pwrite implementation
1108 * to just also use ReadFile/WriteFile directly here as well.
1110 * NB: contrary to the documentation available on MSDN, operations
1111 * on synchronous files with non-NULL LPOVERLAPPED arguments result
1112 * in the *implicit* file position getting updated before the
1113 * ReadFile/WriteFile returning, rather than the Offset/OffsetHigh
1114 * members of the explicit OVERLAPPED structure (!). In order to
1115 * support mixed read/pread syscall sequences (and similarly mixed
1116 * write/pwrite sequences) we must effectively lock the file
1117 * position from access by other threads and then read/write, so
1118 * that when pread/pwrite mess up the implicit file position
1119 * temporarily, it would not be visible.
1121 fh = (HANDLE) _get_osfhandle(d->d);
1122 CHECK(INVALID_HANDLE_VALUE != fh);
1125 * Ensure that we do not corrupt shared implicit file position.
1127 if (d->protect_filepos) {
1128 NaClTakeFilePosLock(fh);
1130 if (!ReadFile(fh, buf, actual_len, &bytes_received, NULL)) {
1131 err = GetLastError();
1132 if (ERROR_HANDLE_EOF == err) {
1135 NaClLog(4, "NaClHostDescRead: ReadFile error %d\n", err);
1136 bytes_received = -NaClXlateSystemError(err);
1139 if (d->protect_filepos) {
1140 NaClDropFilePosLock(fh);
1143 return bytes_received;
1146 ssize_t NaClHostDescWrite(struct NaClHostDesc *d,
1150 * Windows WriteFile only supports DWORD uint, so we need to clamp
1153 unsigned int actual_len;
1155 DWORD bytes_written;
1158 OVERLAPPED *overlap_ptr = NULL;
1160 if (NACL_ABI_O_RDONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
1161 NaClLog(3, "NaClHostDescWrite: RDONLY file\n");
1162 return -NACL_ABI_EBADF;
1164 if (len < UINT_MAX) {
1165 actual_len = (unsigned int) len;
1167 actual_len = UINT_MAX;
1170 NaClHostDescCheckValidity("NaClHostDescWrite", d);
1172 * See discussion in NaClHostDescRead above wrt why we use WriteFile
1173 * instead of _write below.
1175 if (0 != (NACL_ABI_O_APPEND & d->flags)) {
1176 nacl_off64_t offset = GG_LONGLONG(0xffffffffffffffff);
1177 memset(&overlap, 0, sizeof overlap);
1178 overlap.Offset = (DWORD) offset;
1179 overlap.OffsetHigh = (DWORD) (offset >> 32);
1180 overlap_ptr = &overlap;
1182 fh = (HANDLE) _get_osfhandle(d->d);
1183 CHECK(INVALID_HANDLE_VALUE != fh);
1185 * Ensure that we do not corrupt shared implicit file position.
1187 if (d->protect_filepos) {
1188 NaClTakeFilePosLock(fh);
1190 if (!WriteFile(fh, buf, actual_len, &bytes_written, overlap_ptr)) {
1191 err = GetLastError();
1192 NaClLog(4, "NaClHostDescWrite: WriteFile error %d\n", err);
1194 bytes_written = -NaClXlateSystemError(err);
1196 if (d->protect_filepos) {
1197 NaClDropFilePosLock(fh);
1200 return bytes_written;
1203 nacl_off64_t NaClHostDescSeek(struct NaClHostDesc *d,
1204 nacl_off64_t offset,
1207 nacl_off64_t retval;
1209 NaClHostDescCheckValidity("NaClHostDescSeek", d);
1210 hFile = (HANDLE) _get_osfhandle(d->d);
1211 CHECK(INVALID_HANDLE_VALUE != hFile);
1212 if (d->protect_filepos) {
1213 NaClTakeFilePosLock(hFile);
1215 retval = _lseeki64(d->d, offset, whence);
1216 if (d->protect_filepos) {
1217 NaClDropFilePosLock(hFile);
1219 return (-1 == retval) ? -errno : retval;
1222 ssize_t NaClHostDescPRead(struct NaClHostDesc *d,
1225 nacl_off64_t offset) {
1228 DWORD bytes_received;
1230 nacl_off64_t orig_pos = 0;
1232 NaClHostDescCheckValidity("NaClHostDescPRead", d);
1233 if (NACL_ABI_O_WRONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
1234 NaClLog(3, "NaClHostDescPRead: WRONLY file\n");
1235 return -NACL_ABI_EBADF;
1238 return -NACL_ABI_EINVAL;
1241 * There are reports of driver issues that may require clamping len
1242 * to a megabyte or so, lest ReadFile returns an error with
1243 * GetLastError() returning ERROR_INVALID_PARAMETER, but since we
1244 * do not expect to ever read from / write to anything other than
1245 * filesystem files, we do not clamp.
1247 fh = (HANDLE) _get_osfhandle(d->d);
1248 CHECK(INVALID_HANDLE_VALUE != fh);
1249 memset(&overlap, 0, sizeof overlap);
1250 overlap.Offset = (DWORD) offset;
1251 overlap.OffsetHigh = (DWORD) (offset >> 32);
1252 if (len > UINT_MAX) {
1255 if (d->protect_filepos) {
1256 orig_pos = NaClLockAndGetCurrentFilePos(fh);
1258 if (!ReadFile(fh, buf, (DWORD) len, &bytes_received, &overlap)) {
1259 err = GetLastError();
1260 if (ERROR_HANDLE_EOF == err) {
1262 /* handle as if returned true. */
1264 NaClLog(4, "NaClHostDescPRead: ReadFile failed, error %d\n", err);
1265 NaClSetCurrentFilePosAndUnlock(fh, orig_pos);
1266 bytes_received = -NaClXlateSystemError(err);
1269 if (d->protect_filepos) {
1270 NaClSetCurrentFilePosAndUnlock(fh, orig_pos);
1272 return bytes_received;
1275 ssize_t NaClHostDescPWrite(struct NaClHostDesc *d,
1278 nacl_off64_t offset) {
1283 nacl_off64_t orig_pos = 0;
1285 NaClHostDescCheckValidity("NaClHostDescPWrite", d);
1286 if (NACL_ABI_O_RDONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
1287 NaClLog(3, "NaClHostDescPWrite: RDONLY file\n");
1288 return -NACL_ABI_EBADF;
1292 * This also avoids the case where having 0xffffffff in both
1293 * overlap.Offset and overlap.OffsetHigh means append to the file.
1294 * In Posix, offset does not permit special meanings being encoded
1297 return -NACL_ABI_EINVAL;
1299 fh = (HANDLE) _get_osfhandle(d->d);
1300 CHECK(INVALID_HANDLE_VALUE != fh);
1301 memset(&overlap, 0, sizeof overlap);
1302 overlap.Offset = (DWORD) offset;
1303 overlap.OffsetHigh = (DWORD) (offset >> 32);
1304 if (len > UINT_MAX) {
1307 if (d->protect_filepos) {
1308 orig_pos = NaClLockAndGetCurrentFilePos(fh);
1310 if (!WriteFile(fh, buf, (DWORD) len, &bytes_sent, &overlap)) {
1311 err = GetLastError();
1312 if (ERROR_HANDLE_EOF == err) {
1314 /* handle as if returned true. */
1317 "NaClHostDescPWrite: WriteFile failed, error %d\n", err);
1318 bytes_sent = -NaClXlateSystemError(err);
1321 if (d->protect_filepos) {
1322 NaClSetCurrentFilePosAndUnlock(fh, orig_pos);
1327 int NaClHostDescFstat(struct NaClHostDesc *d,
1328 nacl_host_stat_t *nasp) {
1329 NaClHostDescCheckValidity("NaClHostDescFstat", d);
1330 if (NACL_HOST_FSTAT64(d->d, nasp) == -1) {
1337 int NaClHostDescIsatty(struct NaClHostDesc *d) {
1340 NaClHostDescCheckValidity("NaClHostDescIsatty", d);
1341 retval = _isatty(d->d);
1342 /* When windows _isatty fails it returns zero, but does not set errno. */
1343 return (0 == retval) ? -NACL_ABI_ENOTTY : 1;
1346 int NaClHostDescClose(struct NaClHostDesc *d) {
1349 NaClHostDescCheckValidity("NaClHostDescClose", d);
1351 retval = _close(d->d);
1357 NaClFastMutexDtor(&d->mu);
1362 * This is not a host descriptor function, but is closely related to
1363 * fstat and should behave similarly.
1365 int NaClHostDescStat(char const *host_os_pathname,
1366 nacl_host_stat_t *nhsp) {
1367 if (NACL_HOST_STAT64(host_os_pathname, nhsp) == -1) {
1374 int NaClHostDescMkdir(const char *path, int mode) {
1375 UNREFERENCED_PARAMETER(mode);
1376 if (_mkdir(path) != 0)
1377 return -NaClXlateErrno(errno);
1381 int NaClHostDescRmdir(const char *path) {
1382 if (_rmdir(path) != 0)
1383 return -NaClXlateErrno(errno);
1387 int NaClHostDescChdir(const char *path) {
1388 if (_chdir(path) != 0)
1389 return -NaClXlateErrno(errno);
1393 int NaClHostDescGetcwd(char *path, size_t len) {
1394 if (_getcwd(path, (int) len) == NULL)
1395 return -NaClXlateErrno(errno);
1399 int NaClHostDescUnlink(const char *path) {
1400 if (_unlink(path) != 0)