ssize_t NaClDescQuotaPWrite(struct NaClDesc *vself, void const *buf, size_t len, nacl_off64_t offset) { struct NaClDescQuota *self = (struct NaClDescQuota *) vself; uint64_t len_u64; int64_t allowed; ssize_t rv; if (0 == len) { allowed = 0; } else { NACL_COMPILE_TIME_ASSERT(SIZE_T_MAX <= NACL_UMAX_VAL(uint64_t)); /* * Write can always return a short, non-zero transfer count. */ len_u64 = (uint64_t) len; /* get rid of the always-true/always-false comparison warning */ if (len_u64 > NACL_MAX_VAL(int64_t)) { len = (size_t) NACL_MAX_VAL(int64_t); } if (NULL == self->quota_interface) { /* If there is no quota_interface, do not allow writes. */ allowed = 0; } else { allowed = (*NACL_VTBL(NaClDescQuotaInterface, self->quota_interface)-> WriteRequest)(self->quota_interface, self->file_id, offset, len); } if (allowed <= 0) { rv = -NACL_ABI_EDQUOT; goto abort; } /* * allowed <= len should be a post-condition, but we check for * it anyway. */ if ((uint64_t) allowed > len) { NaClLog(LOG_WARNING, ("NaClDescQuotaPWrite: WriteRequest returned an allowed quota" " that is larger than that requested; reducing to original" " request amount.\n")); allowed = len; } } /* * It is possible for Write to write fewer than bytes than the quota * that was granted, in which case quota will leak. * TODO(sehr,bsy): eliminate quota leakage. */ rv = (*NACL_VTBL(NaClDesc, self->desc)->PWrite)(self->desc, buf, (size_t) allowed, offset); abort: return rv; }
/* set *out_desc to struct NaClDescIo * output */ int NaClDescIoInternalize(struct NaClDesc **out_desc, struct NaClDescXferState *xfer, struct NaClDescQuotaInterface *quota_interface) { int rv; NaClHandle h; int d; int flags; struct NaClHostDesc *nhdp; struct NaClDescIoDesc *ndidp; UNREFERENCED_PARAMETER(quota_interface); rv = -NACL_ABI_EIO; /* catch-all */ h = NACL_INVALID_HANDLE; nhdp = NULL; ndidp = NULL; nhdp = malloc(sizeof *nhdp); if (NULL == nhdp) { rv = -NACL_ABI_ENOMEM; goto cleanup; } ndidp = malloc(sizeof *ndidp); if (!ndidp) { rv = -NACL_ABI_ENOMEM; goto cleanup; } if (!NaClDescInternalizeCtor((struct NaClDesc *) ndidp, xfer)) { rv = -NACL_ABI_ENOMEM; goto cleanup; } if (xfer->next_handle == xfer->handle_buffer_end || xfer->next_byte + sizeof ndidp->hd->flags > xfer->byte_buffer_end) { rv = -NACL_ABI_EIO; goto cleanup_ndidp_dtor; } NACL_COMPILE_TIME_ASSERT(sizeof flags == sizeof(ndidp->hd->flags)); memcpy(&flags, xfer->next_byte, sizeof flags); xfer->next_byte += sizeof flags; h = *xfer->next_handle; *xfer->next_handle++ = NACL_INVALID_HANDLE; #if NACL_WINDOWS if (-1 == (d = _open_osfhandle((intptr_t) h, _O_RDWR | _O_BINARY))) { rv = -NACL_ABI_EIO; goto cleanup_ndidp_dtor; } #else d = h; #endif /* * We mark it as read/write, but don't really know for sure until we * try to make those syscalls (in which case we'd get EBADF). */ if ((rv = NaClHostDescPosixTake(nhdp, d, flags)) < 0) { goto cleanup_ndidp_dtor; } h = NACL_INVALID_HANDLE; /* nhdp took ownership of h */ if (!NaClDescIoDescSubclassCtor(ndidp, nhdp)) { rv = -NACL_ABI_ENOMEM; goto cleanup_nhdp_dtor; } /* * ndidp took ownership of nhdp, now give ownership of ndidp to caller. */ *out_desc = (struct NaClDesc *) ndidp; rv = 0; cleanup_nhdp_dtor: if (rv < 0) { if (0 != NaClHostDescClose(nhdp)) { NaClLog(LOG_FATAL, "NaClDescIoInternalize: NaClHostDescClose failed\n"); } } cleanup_ndidp_dtor: if (rv < 0) { NaClDescSafeUnref((struct NaClDesc *) ndidp); ndidp = NULL; } cleanup: if (rv < 0) { free(nhdp); free(ndidp); if (NACL_INVALID_HANDLE != h) { (void) NaClClose(h); } } return rv; }