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 : }
|