1 : /*
2 : * Copyright (c) 2008 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 : * 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/bits/mman.h"
35 : #include "native_client/src/trusted/service_runtime/include/sys/dirent.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/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 4 : int NaClHostDirOpen(struct NaClHostDir *d,
47 4 : char *path) {
48 4 : DIR *dirp;
49 :
50 4 : NaClLog(3, "NaClHostDirOpen(0x%08"NACL_PRIxPTR", %s)\n", (uintptr_t) d, path);
51 4 : if (NULL == d) {
52 0 : NaClLog(LOG_FATAL, "NaClHostDirOpen: 'this' is NULL\n");
53 0 : }
54 :
55 4 : 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 4 : NaClLog(3, "NaClHostDirOpen: invoking POSIX opendir(%s)\n", path);
62 4 : dirp = opendir(path);
63 4 : NaClLog(3, "NaClHostDirOpen: got DIR* 0x%08"NACL_PRIxPTR"\n",
64 : (uintptr_t) dirp);
65 4 : if (NULL == dirp) {
66 0 : NaClLog(LOG_ERROR,
67 0 : "NaClHostDirOpen: open returned NULL, errno %d\n", errno);
68 0 : return -NaClXlateErrno(errno);
69 : }
70 4 : d->dirp = dirp;
71 4 : d->dp = readdir(d->dirp);
72 4 : d->off = 0;
73 4 : NaClLog(3, "NaClHostDirOpen: success.\n");
74 4 : return 0;
75 4 : }
76 :
77 22 : ssize_t NaClHostDirGetdents(struct NaClHostDir *d,
78 22 : void *buf,
79 22 : size_t len) {
80 22 : struct nacl_abi_dirent *p;
81 22 : int rec_length;
82 22 : ssize_t i;
83 :
84 22 : if (NULL == d) {
85 0 : NaClLog(LOG_FATAL, "NaClHostDirGetdents: 'this' is NULL\n");
86 0 : }
87 22 : NaClLog(3, "NaClHostDirGetdents(0x%08"NACL_PRIxPTR", %"NACL_PRIuS"):\n",
88 : (uintptr_t) buf, len);
89 :
90 22 : NaClXMutexLock(&d->mu);
91 :
92 22 : i = 0;
93 115 : while ((size_t) i < len) {
94 92 : if (NULL == d->dp) {
95 6 : goto done;
96 : }
97 86 : if (i > SSIZE_T_MAX - d->dp->d_reclen) {
98 0 : NaClLog(LOG_FATAL, "NaClHostDirGetdents: buffer impossibly large\n");
99 0 : }
100 86 : if ((size_t) i + d->dp->d_reclen > len) {
101 15 : if (0 == i) {
102 8 : i = (size_t) -NACL_ABI_EINVAL;
103 8 : }
104 15 : goto done;
105 : }
106 71 : p = (struct nacl_abi_dirent *) (((char *) buf) + i);
107 71 : p->nacl_abi_d_ino = 0x6c43614e;
108 71 : p->nacl_abi_d_off = ++d->off;
109 213 : 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 71 : 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 71 : ((volatile struct nacl_abi_dirent *) p)->nacl_abi_d_reclen = rec_length;
125 71 : if ((size_t) i > SIZE_T_MAX - rec_length) {
126 0 : NaClLog(LOG_FATAL, "NaClHostDirGetdents: buffer offset overflow\n");
127 0 : }
128 71 : i += rec_length;
129 71 : d->dp = readdir(d->dirp);
130 72 : }
131 : done:
132 22 : NaClXMutexUnlock(&d->mu);
133 22 : return (ssize_t) i;
134 : }
135 :
136 1 : int NaClHostDirRewind(struct NaClHostDir *d) {
137 1 : if (NULL == d) {
138 0 : NaClLog(LOG_FATAL, "NaClHostDirRewind: 'this' is NULL\n");
139 0 : }
140 1 : rewinddir(d->dirp);
141 1 : d->dp = readdir(d->dirp);
142 1 : return 0;
143 : }
144 :
145 3 : int NaClHostDirClose(struct NaClHostDir *d) {
146 3 : int retval;
147 :
148 3 : if (NULL == d) {
149 0 : NaClLog(LOG_FATAL, "NaClHostDirClose: 'this' is NULL\n");
150 0 : }
151 3 : NaClLog(3, "NaClHostDirClose(0x%08"NACL_PRIxPTR")\n", (uintptr_t) d->dirp);
152 3 : retval = closedir(d->dirp);
153 3 : if (-1 != retval) {
154 3 : d->dirp = NULL;
155 3 : }
156 3 : NaClMutexDtor(&d->mu);
157 9 : return (-1 == retval) ? -NaClXlateErrno(errno) : retval;
158 : }
|