2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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"
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
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
)) {
83 basep
->vtbl
= &kNaClDescIoDescVtbl
;
87 void NaClDescIoDescDtor(struct NaClDesc
*vself
)
89 struct NaClDescIoDesc
*self
= (struct NaClDescIoDesc
*) vself
;
91 NaClLog(4, "NaClDescIoDescDtor(0x%08"PRIxPTR
").\n",
93 NaClHostDescClose(self
->hd
);
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
);
107 "NaClDescIoDescMake: no memory for 0x%08"PRIxPTR
"\n",
110 if (!NaClDescIoDescCtor(ndp
, nhdp
)) {
112 ("NaClDescIoDescMake:"
113 " NaClDescIoDescCtor(0x%08"PRIxPTR
",0x%08"PRIxPTR
") failed\n"),
120 struct NaClDescIoDesc
*NaClDescIoDescOpen(char *path
,
124 struct NaClHostDesc
*nhdp
;
126 nhdp
= malloc(sizeof *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",
134 return NaClDescIoDescMake(nhdp
);
137 int NaClDescIoDescMap(struct NaClDesc
*vself
,
138 struct NaClDescEffector
*effp
,
145 struct NaClDescIoDesc
*self
= (struct NaClDescIoDesc
*) vself
;
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
)) {
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
,
163 ("NaClDescIoDescMap: error %d --"
164 " could not unmap 0x%08"PRIxPTR
", length 0x%"PRIxS
"\n"),
166 (uintptr_t) start_addr
,
170 status
= NaClHostDescMap((NULL
== self
) ? NULL
: self
->hd
,
179 int NaClDescIoDescUnmapCommon(struct NaClDesc
*vself
,
180 struct NaClDescEffector
*effp
,
188 status
= NaClHostDescUnmap(start_addr
, len
);
190 status
= NaClHostDescUnmapUnsafe(start_addr
, len
);
197 * NB: User code should never be able to invoke the Unsafe method.
199 int NaClDescIoDescUnmapUnsafe(struct NaClDesc
*vself
,
200 struct NaClDescEffector
*effp
,
204 return NaClDescIoDescUnmapCommon(vself
, effp
, start_addr
, len
, 0);
207 int NaClDescIoDescUnmap(struct NaClDesc
*vself
,
208 struct NaClDescEffector
*effp
,
212 return NaClDescIoDescUnmapCommon(vself
, effp
, start_addr
, len
, 1);
215 ssize_t
NaClDescIoDescRead(struct NaClDesc
*vself
,
216 struct NaClDescEffector
*effp
,
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
,
230 struct NaClDescIoDesc
*self
= (struct NaClDescIoDesc
*) vself
;
232 return NaClHostDescWrite(self
->hd
, buf
, len
);
235 int NaClDescIoDescSeek(struct NaClDesc
*vself
,
236 struct NaClDescEffector
*effp
,
240 struct NaClDescIoDesc
*self
= (struct NaClDescIoDesc
*) vself
;
242 return NaClHostDescSeek(self
->hd
, offset
, whence
);
245 int NaClDescIoDescIoctl(struct NaClDesc
*vself
,
246 struct NaClDescEffector
*effp
,
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
);
271 int NaClDescIoDescExternalizeSize(struct NaClDesc
*vself
,
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
;
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
;
299 *xfer
->next_handle
++ = self
->hd
->d
;
304 struct NaClDescVtbl
const kNaClDescIoDescVtbl
= {
307 NaClDescIoDescUnmapUnsafe
,
315 NaClDescGetdentsNotImplemented
,
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
)
342 struct NaClHostDesc
*nhdp
;
343 struct NaClDescIoDesc
*ndidp
;
345 rv
= -NACL_ABI_EIO
; /* catch-all */
346 h
= NACL_INVALID_HANDLE
;
350 if (xfer
->next_handle
== xfer
->handle_buffer_end
) {
354 nhdp
= malloc(sizeof *nhdp
);
356 rv
= -NACL_ABI_ENOMEM
;
359 ndidp
= malloc(sizeof *ndidp
);
361 rv
= -NACL_ABI_ENOMEM
;
364 h
= *xfer
->next_handle
;
365 *xfer
->next_handle
++ = NACL_INVALID_HANDLE
;
367 if (-1 == (d
= _open_osfhandle((intptr_t) h
, _O_RDWR
| _O_BINARY
))) {
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) {
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
;
394 (void) NaClHostDescClose(nhdp
);
400 if (NACL_INVALID_HANDLE
!= h
) {