Fix file permissions: set executable bit
[nativeclient.git] / service_runtime / nacl_desc_io.c
blob27d6123f8ed6cd0a320af02cdbc261072f5d9175
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * NaCl Service Runtime. I/O Descriptor / Handle abstraction. Memory
34 * mapping using descriptors.
37 #include "native_client/include/portability.h"
39 #include <stdlib.h>
41 #if NACL_WINDOWS
42 # include "io.h"
43 # include "fcntl.h"
44 #endif
46 #include "native_client/service_runtime/nacl_desc_io.h"
48 #include "native_client/service_runtime/internal_errno.h"
50 #include "native_client/service_runtime/nacl_config.h"
51 #include "native_client/service_runtime/nacl_log.h"
52 #include "native_client/service_runtime/nacl_desc_base.h"
53 #include "native_client/service_runtime/nacl_desc_effector.h"
55 #include "native_client/service_runtime/include/sys/errno.h"
56 #include "native_client/service_runtime/include/sys/fcntl.h"
57 #include "native_client/service_runtime/include/sys/mman.h"
59 #include "native_client/intermodule_comm/nacl_imc_c.h"
62 * This file contains the implementation for the NaClIoDesc subclass
63 * of NaClDesc.
65 * NaClDescIoDesc is the subclass that wraps host-OS descriptors
66 * provided by NaClHostDesc (which gives an OS-independent abstraction
67 * for host-OS descriptors).
71 * Takes ownership of hd, will close in Dtor.
73 int NaClDescIoDescCtor(struct NaClDescIoDesc *self,
74 struct NaClHostDesc *hd)
76 struct NaClDesc *basep = (struct NaClDesc *) self;
78 if (!NaClDescCtor(basep)) {
79 return 0;
81 self->hd = hd;
82 basep->vtbl = &kNaClDescIoDescVtbl;
83 return 1;
86 void NaClDescIoDescDtor(struct NaClDesc *vself)
88 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
90 NaClLog(4, "NaClDescIoDescDtor(0x%08x).\n",
91 (uintptr_t) vself);
92 NaClHostDescClose(self->hd);
93 free(self->hd);
94 self->hd = NULL;
95 NaClDescDtor(&self->base);
98 struct NaClDescIoDesc *NaClDescIoDescMake(struct NaClHostDesc *nhdp)
100 struct NaClDescIoDesc *ndp;
102 ndp = malloc(sizeof *ndp);
103 if (NULL == ndp) {
104 NaClLog(LOG_FATAL,
105 "NaClDescIoDescMake: no memory for 0x%08x\n",
106 (uintptr_t) nhdp);
108 if (!NaClDescIoDescCtor(ndp, nhdp)) {
109 NaClLog(LOG_FATAL,
110 "NaClDescIoDescMake: NaClDescIoDescCtor(0x%08x,0x%08x) failed\n",
111 (uintptr_t) ndp,
112 (uintptr_t) nhdp);
114 return ndp;
117 struct NaClDescIoDesc *NaClDescIoDescOpen(char *path,
118 int mode,
119 int perms)
121 struct NaClHostDesc *nhdp;
123 nhdp = malloc(sizeof *nhdp);
124 if (NULL == nhdp) {
125 NaClLog(LOG_FATAL, "NaClDescIoDescOpen: no memory for %s\n", path);
127 if (!NaClHostDescOpen(nhdp, path, mode, perms)) {
128 NaClLog(LOG_FATAL, "NaClDescIoDescOpen: NaClHostDescOpen failed for %s\n",
129 path);
131 return NaClDescIoDescMake(nhdp);
134 int NaClDescIoDescMap(struct NaClDesc *vself,
135 struct NaClDescEffector *effp,
136 void *start_addr,
137 size_t len,
138 int prot,
139 int flags,
140 off_t offset)
142 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
143 int rv;
144 int status;
147 * prot must be PROT_NONE or a combination of PROT_{READ|WRITE}
149 if (0 != (~(NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE) & prot)) {
150 NaClLog(LOG_INFO,
151 ("NaClDescImcDescMap: prot has other bits"
152 " than PROT_{READ|WRITE}\n"));
153 return -NACL_ABI_EINVAL;
156 if (0 != (rv = (*effp->vtbl->UnmapMemory)(effp,
157 (uintptr_t) start_addr,
158 len))) {
159 NaClLog(LOG_FATAL,
160 ("NaClDescIoDescMap: error %d --"
161 " could not unmap 0x%08x, length 0x%x\n"),
163 (uintptr_t) start_addr,
164 len);
167 status = NaClHostDescMap((NULL == self) ? NULL : self->hd,
168 start_addr,
169 len,
170 prot,
171 flags,
172 offset);
173 return status;
176 int NaClDescIoDescUnmapCommon(struct NaClDesc *vself,
177 struct NaClDescEffector *effp,
178 void *start_addr,
179 size_t len,
180 int safe_mode)
182 int status;
184 if (safe_mode) {
185 status = NaClHostDescUnmap(start_addr, len);
186 } else {
187 status = NaClHostDescUnmapUnsafe(start_addr, len);
190 return status;
194 * NB: User code should never be able to invoke the Unsafe method.
196 int NaClDescIoDescUnmapUnsafe(struct NaClDesc *vself,
197 struct NaClDescEffector *effp,
198 void *start_addr,
199 size_t len)
201 return NaClDescIoDescUnmapCommon(vself, effp, start_addr, len, 0);
204 int NaClDescIoDescUnmap(struct NaClDesc *vself,
205 struct NaClDescEffector *effp,
206 void *start_addr,
207 size_t len)
209 return NaClDescIoDescUnmapCommon(vself, effp, start_addr, len, 1);
212 ssize_t NaClDescIoDescRead(struct NaClDesc *vself,
213 struct NaClDescEffector *effp,
214 void *buf,
215 size_t len)
217 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
219 return NaClHostDescRead(self->hd, buf, len);
222 ssize_t NaClDescIoDescWrite(struct NaClDesc *vself,
223 struct NaClDescEffector *effp,
224 void const *buf,
225 size_t len)
227 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
229 return NaClHostDescWrite(self->hd, buf, len);
232 int NaClDescIoDescSeek(struct NaClDesc *vself,
233 struct NaClDescEffector *effp,
234 off_t offset,
235 int whence)
237 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
239 return NaClHostDescSeek(self->hd, offset, whence);
242 int NaClDescIoDescIoctl(struct NaClDesc *vself,
243 struct NaClDescEffector *effp,
244 int request,
245 void *arg)
247 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
249 return NaClHostDescIoctl(self->hd, request, arg);
252 int NaClDescIoDescFstat(struct NaClDesc *vself,
253 struct NaClDescEffector *effp,
254 struct nacl_abi_stat *statbuf)
256 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
258 return NaClHostDescFstat(self->hd, statbuf);
261 int NaClDescIoDescClose(struct NaClDesc *vself,
262 struct NaClDescEffector *effp)
264 NaClDescUnref(vself);
265 return 0;
268 int NaClDescIoDescExternalizeSize(struct NaClDesc *vself,
269 size_t *nbytes,
270 size_t *nhandles)
272 *nbytes = 0;
273 *nhandles = 1;
274 return 0;
278 * TODO -- this depends on implementation of IMC being able to xfer
279 * Unix descriptors or Windows Handles as NaclHandles. Should this be
280 * part of IMC requirements? Also, Windows POSIX layer library may have
281 * strange side effects due to extra buffering. TEST AND DECIDE.
283 int NaClDescIoDescExternalize(struct NaClDesc *vself,
284 struct NaClDescXferState *xfer)
286 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
288 #if NACL_WINDOWS
289 HANDLE h = (HANDLE) _get_osfhandle(self->hd->d);
291 NaClLog(LOG_WARNING, "NaClDescIoDescExternalize is EXPERIMENTAL\n");
292 NaClLog(LOG_WARNING, "handle 0x%x\n", (uintptr_t) h);
294 *xfer->next_handle++ = (NaClHandle) h;
295 #else
296 *xfer->next_handle++ = self->hd->d;
297 #endif
298 return 0;
301 struct NaClDescVtbl const kNaClDescIoDescVtbl = {
302 NaClDescIoDescDtor,
303 NaClDescIoDescMap,
304 NaClDescIoDescUnmapUnsafe,
305 NaClDescIoDescUnmap,
306 NaClDescIoDescRead,
307 NaClDescIoDescWrite,
308 NaClDescIoDescSeek,
309 NaClDescIoDescIoctl,
310 NaClDescIoDescFstat,
311 NaClDescIoDescClose,
312 NaClDescGetdentsNotImplemented,
313 NACL_DESC_HOST_IO,
314 NaClDescIoDescExternalizeSize,
315 NaClDescIoDescExternalize,
316 NaClDescLockNotImplemented,
317 NaClDescTryLockNotImplemented,
318 NaClDescUnlockNotImplemented,
319 NaClDescWaitNotImplemented,
320 NaClDescTimedWaitAbsNotImplemented,
321 NaClDescSignalNotImplemented,
322 NaClDescBroadcastNotImplemented,
323 NaClDescSendMsgNotImplemented,
324 NaClDescRecvMsgNotImplemented,
325 NaClDescConnectAddrNotImplemented,
326 NaClDescAcceptConnNotImplemented,
327 NaClDescPostNotImplemented,
328 NaClDescSemWaitNotImplemented,
329 NaClDescGetValueNotImplemented,
332 /* set *baseptr to struct NaClDescIo * output */
333 int NaClDescIoInternalize(struct NaClDesc **baseptr,
334 struct NaClDescXferState *xfer)
336 int rv;
337 NaClHandle h;
338 int d;
339 struct NaClHostDesc *nhdp;
340 struct NaClDescIoDesc *ndidp;
342 rv = -NACL_ABI_EIO; /* catch-all */
343 h = NACL_INVALID_HANDLE;
344 nhdp = NULL;
345 ndidp = NULL;
347 if (xfer->next_handle == xfer->handle_buffer_end) {
348 rv = -NACL_ABI_EIO;
349 goto cleanup;
351 nhdp = malloc(sizeof *nhdp);
352 if (NULL == nhdp) {
353 rv = -NACL_ABI_ENOMEM;
354 goto cleanup;
356 ndidp = malloc(sizeof *ndidp);
357 if (!ndidp) {
358 rv = -NACL_ABI_ENOMEM;
359 goto cleanup;
361 h = *xfer->next_handle;
362 *xfer->next_handle++ = NACL_INVALID_HANDLE;
363 #if NACL_WINDOWS
364 if (-1 == (d = _open_osfhandle((intptr_t) h, _O_RDWR | _O_BINARY))) {
365 rv = -NACL_ABI_EIO;
366 goto cleanup;
368 #else
369 d = h;
370 #endif
372 * We mark it as read/write, but don't really know for sure until we
373 * try to make those syscalls (in which case we'd get EBADF).
375 if ((rv = NaClHostDescPosixTake(nhdp, d, NACL_ABI_O_RDWR)) < 0) {
376 goto cleanup;
378 h = NACL_INVALID_HANDLE; /* nhdp took ownership of h */
380 if (!NaClDescIoDescCtor(ndidp, nhdp)) {
381 rv = -NACL_ABI_ENOMEM;
382 goto cleanup_hd_dtor;
385 * ndidp took ownership of nhdp, now give ownership of ndidp to caller.
387 *baseptr = (struct NaClDesc *) ndidp;
388 rv = 0;
389 cleanup_hd_dtor:
390 if (rv < 0) {
391 (void) NaClHostDescClose(nhdp);
393 cleanup:
394 if (rv < 0) {
395 free(nhdp);
396 free(ndidp);
397 if (NACL_INVALID_HANDLE != h) {
398 NaClClose(h);
401 return rv;