1 : /*
2 : * Copyright 2008 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can
4 : * be found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl Service Runtime. Directory descriptor / Handle abstraction.
9 : *
10 : * Note that we avoid using the thread-specific data / thread local
11 : * storage access to the "errno" variable, and instead use the raw
12 : * system call return interface of small negative numbers as errors.
13 : */
14 :
15 : #include <stddef.h>
16 : #include <stdint.h>
17 : #include <string.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 : #include <dirent.h>
25 :
26 : #include "native_client/src/include/nacl_platform.h"
27 :
28 : #include "native_client/src/shared/platform/nacl_host_desc.h"
29 : #include "native_client/src/shared/platform/nacl_host_dir.h"
30 : #include "native_client/src/shared/platform/nacl_log.h"
31 : #include "native_client/src/shared/platform/nacl_sync.h"
32 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
33 :
34 : #include "native_client/src/trusted/service_runtime/include/sys/dirent.h"
35 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
36 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
37 : #include "native_client/src/trusted/service_runtime/include/sys/mman.h"
38 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
39 :
40 :
41 : #ifndef SSIZE_T_MAX
42 : # define SSIZE_T_MAX ((ssize_t) ((~(size_t) 0) >> 1))
43 : #endif
44 :
45 :
46 : int NaClHostDirOpen(struct NaClHostDir *d,
47 3 : char *path) {
48 : DIR *dirp;
49 :
50 3 : NaClLog(3, "NaClHostDirOpen(0x%08"NACL_PRIxPTR", %s)\n", (uintptr_t) d, path);
51 3 : if (NULL == d) {
52 0 : NaClLog(LOG_FATAL, "NaClHostDirOpen: 'this' is NULL\n");
53 : }
54 :
55 3 : if (!NaClMutexCtor(&d->mu)) {
56 0 : NaClLog(LOG_ERROR,
57 : "NaClHostDirOpen: could not initialize mutex\n");
58 0 : return -NACL_ABI_ENOMEM;
59 : }
60 :
61 3 : NaClLog(3, "NaClHostDirOpen: invoking POSIX opendir(%s)\n", path);
62 3 : dirp = opendir(path);
63 3 : NaClLog(3, "NaClHostDirOpen: got DIR* 0x%08"NACL_PRIxPTR"\n",
64 : (uintptr_t) dirp);
65 3 : if (NULL == dirp) {
66 0 : NaClLog(LOG_ERROR,
67 : "NaClHostDirOpen: open returned NULL, errno %d\n", errno);
68 0 : return -NaClXlateErrno(errno);
69 : }
70 3 : d->dirp = dirp;
71 3 : d->dp = readdir(d->dirp);
72 3 : d->off = 0;
73 3 : NaClLog(3, "NaClHostDirOpen: success.\n");
74 3 : return 0;
75 : }
76 :
77 : ssize_t NaClHostDirGetdents(struct NaClHostDir *d,
78 : void *buf,
79 14 : size_t len) {
80 : struct nacl_abi_dirent *p;
81 : int rec_length;
82 : ssize_t i;
83 :
84 14 : if (NULL == d) {
85 0 : NaClLog(LOG_FATAL, "NaClHostDirGetdents: 'this' is NULL\n");
86 : }
87 14 : NaClLog(3, "NaClHostDirGetdents(0x%08"NACL_PRIxPTR", %"NACL_PRIuS"):\n",
88 : (uintptr_t) buf, len);
89 :
90 14 : NaClXMutexLock(&d->mu);
91 :
92 14 : i = 0;
93 37 : while ((size_t) i < len) {
94 17 : if (NULL == d->dp) {
95 2 : goto done;
96 : }
97 15 : if (i > SSIZE_T_MAX - d->dp->d_reclen) {
98 0 : NaClLog(LOG_FATAL, "NaClHostDirGetdents: buffer impossibly large\n");
99 : }
100 15 : if ((size_t) i + d->dp->d_reclen > len) {
101 6 : if (0 == i) {
102 5 : i = (size_t) -NACL_ABI_EINVAL;
103 : }
104 6 : goto done;
105 : }
106 9 : p = (struct nacl_abi_dirent *) (((char *) buf) + i);
107 9 : p->nacl_abi_d_ino = 0x6c43614e;
108 9 : p->nacl_abi_d_off = ++d->off;
109 9 : memcpy(p->nacl_abi_d_name,
110 : d->dp->d_name,
111 : d->dp->d_namlen + 1);
112 : /*
113 : * Newlib expects entries to start on 0mod4 boundaries.
114 : * Round reclen to the next multiple of four.
115 : */
116 9 : rec_length = (offsetof(struct nacl_abi_dirent, nacl_abi_d_name) +
117 : (d->dp->d_namlen + 1 + 3)) & ~3;
118 : /*
119 : * We cast to a volatile pointer so that the compiler won't ever
120 : * pick up the rec_length value from that user-accessible memory
121 : * location, rather than actually using the value in a register or
122 : * in the local frame.
123 : */
124 9 : ((volatile struct nacl_abi_dirent *) p)->nacl_abi_d_reclen = rec_length;
125 9 : if ((size_t) i > SIZE_T_MAX - rec_length) {
126 0 : NaClLog(LOG_FATAL, "NaClHostDirGetdents: buffer offset overflow\n");
127 : }
128 9 : i += rec_length;
129 9 : d->dp = readdir(d->dirp);
130 : }
131 14 : done:
132 14 : NaClXMutexUnlock(&d->mu);
133 14 : return (ssize_t) i;
134 : }
135 :
136 2 : int NaClHostDirClose(struct NaClHostDir *d) {
137 : int retval;
138 :
139 2 : if (NULL == d) {
140 0 : NaClLog(LOG_FATAL, "NaClHostDirClose: 'this' is NULL\n");
141 : }
142 2 : NaClLog(3, "NaClHostDirClose(0x%08"NACL_PRIxPTR")\n", (uintptr_t) d->dirp);
143 2 : retval = closedir(d->dirp);
144 2 : if (-1 != retval) {
145 2 : d->dirp = NULL;
146 : }
147 2 : NaClMutexDtor(&d->mu);
148 2 : return (-1 == retval) ? -NaClXlateErrno(errno) : retval;
149 : }
|