Merge branch 'upstream'
[nativeclient.git] / service_runtime / nacl_desc_io.c
blobf41ca31263e1d9c507a358fdb171a3ce7e4a5427
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 basep->vtbl = (struct NaClDescVtbl *) NULL;
79 if (!NaClDescCtor(basep)) {
80 return 0;
82 self->hd = hd;
83 basep->vtbl = &kNaClDescIoDescVtbl;
84 return 1;
87 void NaClDescIoDescDtor(struct NaClDesc *vself)
89 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
91 NaClLog(4, "NaClDescIoDescDtor(0x%08"PRIxPTR").\n",
92 (uintptr_t) vself);
93 NaClHostDescClose(self->hd);
94 free(self->hd);
95 self->hd = NULL;
96 vself->vtbl = (struct NaClDescVtbl *) NULL;
97 NaClDescDtor(&self->base);
100 struct NaClDescIoDesc *NaClDescIoDescMake(struct NaClHostDesc *nhdp)
102 struct NaClDescIoDesc *ndp;
104 ndp = malloc(sizeof *ndp);
105 if (NULL == ndp) {
106 NaClLog(LOG_FATAL,
107 "NaClDescIoDescMake: no memory for 0x%08"PRIxPTR"\n",
108 (uintptr_t) nhdp);
110 if (!NaClDescIoDescCtor(ndp, nhdp)) {
111 NaClLog(LOG_FATAL,
112 ("NaClDescIoDescMake:"
113 " NaClDescIoDescCtor(0x%08"PRIxPTR",0x%08"PRIxPTR") failed\n"),
114 (uintptr_t) ndp,
115 (uintptr_t) nhdp);
117 return ndp;
120 struct NaClDescIoDesc *NaClDescIoDescOpen(char *path,
121 int mode,
122 int perms)
124 struct NaClHostDesc *nhdp;
126 nhdp = malloc(sizeof *nhdp);
127 if (NULL == nhdp) {
128 NaClLog(LOG_FATAL, "NaClDescIoDescOpen: no memory for %s\n", path);
130 if (!NaClHostDescOpen(nhdp, path, mode, perms)) {
131 NaClLog(LOG_FATAL, "NaClDescIoDescOpen: NaClHostDescOpen failed for %s\n",
132 path);
134 return NaClDescIoDescMake(nhdp);
137 int NaClDescIoDescMap(struct NaClDesc *vself,
138 struct NaClDescEffector *effp,
139 void *start_addr,
140 size_t len,
141 int prot,
142 int flags,
143 off_t offset)
145 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
146 int rv;
147 int status;
150 * prot must be PROT_NONE or a combination of PROT_{READ|WRITE}
152 if (0 != (~(NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC) & prot)) {
153 NaClLog(LOG_INFO,
154 ("NaClDescImcDescMap: prot has other bits"
155 " than PROT_{READ|WRITE}\n"));
156 return -NACL_ABI_EINVAL;
159 if (0 != (rv = (*effp->vtbl->UnmapMemory)(effp,
160 (uintptr_t) start_addr,
161 len))) {
162 NaClLog(LOG_FATAL,
163 ("NaClDescIoDescMap: error %d --"
164 " could not unmap 0x%08"PRIxPTR", length 0x%"PRIxS"\n"),
166 (uintptr_t) start_addr,
167 len);
170 status = NaClHostDescMap((NULL == self) ? NULL : self->hd,
171 start_addr,
172 len,
173 prot,
174 flags,
175 offset);
176 return status;
179 int NaClDescIoDescUnmapCommon(struct NaClDesc *vself,
180 struct NaClDescEffector *effp,
181 void *start_addr,
182 size_t len,
183 int safe_mode)
185 int status;
187 if (safe_mode) {
188 status = NaClHostDescUnmap(start_addr, len);
189 } else {
190 status = NaClHostDescUnmapUnsafe(start_addr, len);
193 return status;
197 * NB: User code should never be able to invoke the Unsafe method.
199 int NaClDescIoDescUnmapUnsafe(struct NaClDesc *vself,
200 struct NaClDescEffector *effp,
201 void *start_addr,
202 size_t len)
204 return NaClDescIoDescUnmapCommon(vself, effp, start_addr, len, 0);
207 int NaClDescIoDescUnmap(struct NaClDesc *vself,
208 struct NaClDescEffector *effp,
209 void *start_addr,
210 size_t len)
212 return NaClDescIoDescUnmapCommon(vself, effp, start_addr, len, 1);
215 ssize_t NaClDescIoDescRead(struct NaClDesc *vself,
216 struct NaClDescEffector *effp,
217 void *buf,
218 size_t len)
220 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
222 return NaClHostDescRead(self->hd, buf, len);
225 ssize_t NaClDescIoDescWrite(struct NaClDesc *vself,
226 struct NaClDescEffector *effp,
227 void const *buf,
228 size_t len)
230 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
232 return NaClHostDescWrite(self->hd, buf, len);
235 int NaClDescIoDescSeek(struct NaClDesc *vself,
236 struct NaClDescEffector *effp,
237 off_t offset,
238 int whence)
240 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
242 return NaClHostDescSeek(self->hd, offset, whence);
245 int NaClDescIoDescIoctl(struct NaClDesc *vself,
246 struct NaClDescEffector *effp,
247 int request,
248 void *arg)
250 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
252 return NaClHostDescIoctl(self->hd, request, arg);
255 int NaClDescIoDescFstat(struct NaClDesc *vself,
256 struct NaClDescEffector *effp,
257 struct nacl_abi_stat *statbuf)
259 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
261 return NaClHostDescFstat(self->hd, statbuf);
264 int NaClDescIoDescClose(struct NaClDesc *vself,
265 struct NaClDescEffector *effp)
267 NaClDescUnref(vself);
268 return 0;
271 int NaClDescIoDescExternalizeSize(struct NaClDesc *vself,
272 size_t *nbytes,
273 size_t *nhandles)
275 *nbytes = 0;
276 *nhandles = 1;
277 return 0;
281 * TODO -- this depends on implementation of IMC being able to xfer
282 * Unix descriptors or Windows Handles as NaclHandles. Should this be
283 * part of IMC requirements? Also, Windows POSIX layer library may have
284 * strange side effects due to extra buffering. TEST AND DECIDE.
286 int NaClDescIoDescExternalize(struct NaClDesc *vself,
287 struct NaClDescXferState *xfer)
289 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
291 #if NACL_WINDOWS
292 HANDLE h = (HANDLE) _get_osfhandle(self->hd->d);
294 NaClLog(LOG_WARNING, "NaClDescIoDescExternalize is EXPERIMENTAL\n");
295 NaClLog(LOG_WARNING, "handle 0x%x\n", (uintptr_t) h);
297 *xfer->next_handle++ = (NaClHandle) h;
298 #else
299 *xfer->next_handle++ = self->hd->d;
300 #endif
301 return 0;
304 struct NaClDescVtbl const kNaClDescIoDescVtbl = {
305 NaClDescIoDescDtor,
306 NaClDescIoDescMap,
307 NaClDescIoDescUnmapUnsafe,
308 NaClDescIoDescUnmap,
309 NaClDescIoDescRead,
310 NaClDescIoDescWrite,
311 NaClDescIoDescSeek,
312 NaClDescIoDescIoctl,
313 NaClDescIoDescFstat,
314 NaClDescIoDescClose,
315 NaClDescGetdentsNotImplemented,
316 NACL_DESC_HOST_IO,
317 NaClDescIoDescExternalizeSize,
318 NaClDescIoDescExternalize,
319 NaClDescLockNotImplemented,
320 NaClDescTryLockNotImplemented,
321 NaClDescUnlockNotImplemented,
322 NaClDescWaitNotImplemented,
323 NaClDescTimedWaitAbsNotImplemented,
324 NaClDescSignalNotImplemented,
325 NaClDescBroadcastNotImplemented,
326 NaClDescSendMsgNotImplemented,
327 NaClDescRecvMsgNotImplemented,
328 NaClDescConnectAddrNotImplemented,
329 NaClDescAcceptConnNotImplemented,
330 NaClDescPostNotImplemented,
331 NaClDescSemWaitNotImplemented,
332 NaClDescGetValueNotImplemented,
335 /* set *baseptr to struct NaClDescIo * output */
336 int NaClDescIoInternalize(struct NaClDesc **baseptr,
337 struct NaClDescXferState *xfer)
339 int rv;
340 NaClHandle h;
341 int d;
342 struct NaClHostDesc *nhdp;
343 struct NaClDescIoDesc *ndidp;
345 rv = -NACL_ABI_EIO; /* catch-all */
346 h = NACL_INVALID_HANDLE;
347 nhdp = NULL;
348 ndidp = NULL;
350 if (xfer->next_handle == xfer->handle_buffer_end) {
351 rv = -NACL_ABI_EIO;
352 goto cleanup;
354 nhdp = malloc(sizeof *nhdp);
355 if (NULL == nhdp) {
356 rv = -NACL_ABI_ENOMEM;
357 goto cleanup;
359 ndidp = malloc(sizeof *ndidp);
360 if (!ndidp) {
361 rv = -NACL_ABI_ENOMEM;
362 goto cleanup;
364 h = *xfer->next_handle;
365 *xfer->next_handle++ = NACL_INVALID_HANDLE;
366 #if NACL_WINDOWS
367 if (-1 == (d = _open_osfhandle((intptr_t) h, _O_RDWR | _O_BINARY))) {
368 rv = -NACL_ABI_EIO;
369 goto cleanup;
371 #else
372 d = h;
373 #endif
375 * We mark it as read/write, but don't really know for sure until we
376 * try to make those syscalls (in which case we'd get EBADF).
378 if ((rv = NaClHostDescPosixTake(nhdp, d, NACL_ABI_O_RDWR)) < 0) {
379 goto cleanup;
381 h = NACL_INVALID_HANDLE; /* nhdp took ownership of h */
383 if (!NaClDescIoDescCtor(ndidp, nhdp)) {
384 rv = -NACL_ABI_ENOMEM;
385 goto cleanup_hd_dtor;
388 * ndidp took ownership of nhdp, now give ownership of ndidp to caller.
390 *baseptr = (struct NaClDesc *) ndidp;
391 rv = 0;
392 cleanup_hd_dtor:
393 if (rv < 0) {
394 (void) NaClHostDescClose(nhdp);
396 cleanup:
397 if (rv < 0) {
398 free(nhdp);
399 free(ndidp);
400 if (NACL_INVALID_HANDLE != h) {
401 NaClClose(h);
404 return rv;