int storage_file_write(struct storage_msg *msg, const void *r, size_t req_len) { int rc; const struct storage_file_write_req *req = r; if (req_len < sizeof(*req)) { ALOGE("%s: invalid request length (%zd < %zd)\n", __func__, req_len, sizeof(*req)); msg->result = STORAGE_ERR_NOT_VALID; goto err_response; } int fd = lookup_fd(req->handle, true); if (write_with_retry(fd, &req->data[0], req_len - sizeof(*req), req->offset) < 0) { rc = errno; ALOGW("%s: error writing file (fd=%d): %s\n", __func__, fd, strerror(errno)); msg->result = translate_errno(rc); goto err_response; } msg->result = STORAGE_NO_ERROR; err_response: return ipc_respond(msg, NULL, 0); }
struct chan *fdtochan(struct fd_table *fdt, int fd, int mode, int chkmnt, int iref) { struct chan *c; c = lookup_fd(fdt, fd, iref, FALSE); if (!c) { /* We lost the info about why there was a problem (we used to track file * group closed too, can add that in later). */ error(EBADF, ERROR_FIXME); } if (chkmnt && (c->flag & CMSG)) { if (iref) cclose(c); error(EBADF, ERROR_FIXME); } if (mode < 0) return c; if ((mode & c->mode) != mode) { if (iref) cclose(c); error(EBADF, "FD access mode failure: chan mode 0x%x, wanted 0x%x (opened with 0 instead of O_READ?)", c->mode, mode); } return c; }
int storage_file_set_size(struct storage_msg *msg, const void *r, size_t req_len) { const struct storage_file_set_size_req *req = r; if (req_len != sizeof(*req)) { ALOGE("%s: invalid request length (%zd != %zd)\n", __func__, req_len, sizeof(*req)); msg->result = STORAGE_ERR_NOT_VALID; goto err_response; } int fd = lookup_fd(req->handle, true); int rc = TEMP_FAILURE_RETRY(ftruncate(fd, req->size)); if (rc < 0) { rc = errno; ALOGE("%s: error truncating file (fd=%d): %s\n", __func__, fd, strerror(errno)); msg->result = translate_errno(rc); goto err_response; } msg->result = STORAGE_NO_ERROR; err_response: return ipc_respond(msg, NULL, 0); }
int storage_file_get_size(struct storage_msg *msg, const void *r, size_t req_len) { const struct storage_file_get_size_req *req = r; struct storage_file_get_size_resp resp = {0}; if (req_len != sizeof(*req)) { ALOGE("%s: invalid request length (%zd != %zd)\n", __func__, req_len, sizeof(*req)); msg->result = STORAGE_ERR_NOT_VALID; goto err_response; } struct stat stat; int fd = lookup_fd(req->handle, false); int rc = fstat(fd, &stat); if (rc < 0) { rc = errno; ALOGE("%s: error stat'ing file (fd=%d): %s\n", __func__, fd, strerror(errno)); msg->result = translate_errno(rc); goto err_response; } resp.size = stat.st_size; msg->result = STORAGE_NO_ERROR; return ipc_respond(msg, &resp, sizeof(resp)); err_response: return ipc_respond(msg, NULL, 0); }
/* * comm_select * * Called to do the new-style IO, courtesy of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { int num, i; static struct kevent ke[KE_LENGTH]; struct timespec poll_time; void (*hdl)(fde_t *, void *); fde_t *F; /* * remember we are doing NANOseconds here, not micro/milli. God knows * why jlemon used a timespec, but hey, he wrote the interface, not I * -- Adrian */ poll_time.tv_sec = 0; poll_time.tv_nsec = SELECT_DELAY * 1000000; num = kevent(kqfd.fd, kq_fdlist, kqoff, ke, KE_LENGTH, &poll_time); kqoff = 0; set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); /* avoid 99% CPU in comm_select */ #endif return; } for (i = 0; i < num; i++) { F = lookup_fd(ke[i].ident); if (F == NULL || !F->flags.open || (ke[i].flags & EV_ERROR)) continue; if (ke[i].filter == EVFILT_READ) { if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } } if (ke[i].filter == EVFILT_WRITE) { if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } } comm_setselect(F, 0, NULL, NULL, 0); } }
/* Returns the file descriptor associated with the given handle. Terminates the process if HANDLE is not associated with an open directory. */ static struct file_descriptor * lookup_dir_fd (int handle) { struct file_descriptor *fd = lookup_fd (handle); if (fd->dir == NULL) thread_exit (); return fd; }
/* * comm_select * * Called to do the new-style IO, courtesy of of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { int num, ci; void (*hdl)(fde_t *, void *); fde_t *F; num = poll(pollfds, pollnum, SELECT_DELAY); set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); /* avoid 99% CPU in comm_select */ #endif return; } for (ci = 0; ci < pollnum && num > 0; ci++) { int revents = pollfds[ci].revents; if (revents == 0) continue; num--; F = lookup_fd(pollfds[ci].fd); assert(F); if (!F->flags.open) continue; if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) { if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } } if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) { if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } } comm_setselect(F, 0, NULL, NULL, 0); } }
/* * comm_select * * Called to do the new-style IO, courtesy of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { struct timeval to; int num, fd; fde_t *F; PF *hdl; /* Copy over the read/write sets so we don't have to rebuild em */ memcpy(&tmpreadfds, &select_readfds, sizeof(fd_set)); memcpy(&tmpwritefds, &select_writefds, sizeof(fd_set)); to.tv_sec = 0; to.tv_usec = SELECT_DELAY * 1000; num = select(highest_fd + 1, &tmpreadfds, &tmpwritefds, NULL, &to); set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); #endif return; } for (fd = 0; fd <= highest_fd && num > 0; fd++) if (FD_ISSET(fd, &tmpreadfds) || FD_ISSET(fd, &tmpwritefds)) { num--; F = lookup_fd(fd); if (F == NULL || !F->flags.open) continue; if (FD_ISSET(fd, &tmpreadfds)) if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } if (FD_ISSET(fd, &tmpwritefds)) if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } comm_setselect(F, 0, NULL, NULL, 0); } }
/* Close system call. */ static int sys_close (int handle) { struct file_descriptor *fd = lookup_fd (handle); file_close (fd->file); dir_close (fd->dir); list_remove (&fd->elem); free (fd); return 0; }
/* * comm_select * * Called to do the new-style IO, courtesy of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { int num, i; struct pollfd pollfds[128]; struct dvpoll dopoll; void (*hdl)(fde_t *, void *); fde_t *F; dopoll.dp_timeout = SELECT_DELAY; dopoll.dp_nfds = 128; dopoll.dp_fds = &pollfds[0]; num = ioctl(dpfd.fd, DP_POLL, &dopoll); set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); /* avoid 99% CPU in comm_select */ #endif return; } for (i = 0; i < num; i++) { F = lookup_fd(dopoll.dp_fds[i].fd); if (F == NULL || !F->flags.open) continue; if ((dopoll.dp_fds[i].revents & POLLIN)) { if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } } if ((dopoll.dp_fds[i].revents & POLLOUT)) { if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } } comm_setselect(F, 0, NULL, NULL, 0); } }
/* Close system call. */ static int sys_close (int handle) { struct file_descriptor *fd = lookup_fd (handle); lock_acquire (&fs_lock); file_close (fd->file); lock_release (&fs_lock); list_remove (&fd->elem); free (fd); return 0; }
/* Filesize system call. */ static int sys_filesize (int handle) { struct file_descriptor *fd = lookup_fd (handle); int size; lock_acquire (&fs_lock); size = file_length (fd->file); lock_release (&fs_lock); return size; }
/* Seek system call. */ static int sys_seek (int handle, unsigned position) { struct file_descriptor *fd = lookup_fd (handle); lock_acquire (&fs_lock); if ((off_t) position >= 0) file_seek (fd->file, position); lock_release (&fs_lock); return 0; }
/* Tell system call. */ static int sys_tell (int handle) { struct file_descriptor *fd = lookup_fd (handle); unsigned position; lock_acquire (&fs_lock); position = file_tell (fd->file); lock_release (&fs_lock); return position; }
/* Write system call. */ static int sys_write (int handle, void *usrc_, unsigned size) { uint8_t *usrc = usrc_; struct file_descriptor *fd = NULL; int bytes_written = 0; /* Lookup up file descriptor. */ if (handle != STDOUT_FILENO) fd = lookup_fd (handle); while (size > 0) { /* How much bytes to write to this page? */ size_t page_left = PGSIZE - pg_ofs (usrc); size_t write_amt = size < page_left ? size : page_left; off_t retval; /* Write from page into file. */ if (!page_lock (usrc, false)) thread_exit (); lock_acquire (&fs_lock); if (handle == STDOUT_FILENO) { putbuf ((char *) usrc, write_amt); retval = write_amt; } else retval = file_write (fd->file, usrc, write_amt); lock_release (&fs_lock); page_unlock (usrc); /* Handle return value. */ if (retval < 0) { if (bytes_written == 0) bytes_written = -1; break; } bytes_written += retval; /* If it was a short write we're done. */ if (retval != (off_t) write_amt) break; /* Advance. */ usrc += retval; size -= retval; } return bytes_written; }
/* * comm_select * * Called to do the new-style IO, courtesy of of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { int num, ci, revents; PF *hdl; fde_t *F; /* XXX kill that +1 later ! -- adrian */ num = poll(pollfds, pollmax + 1, SELECT_DELAY); set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); /* avoid 99% CPU in comm_select */ #endif return; } for (ci = 0; ci <= pollmax && num > 0; ci++) { if ((revents = pollfds[ci].revents) == 0 || pollfds[ci].fd == -1) continue; num--; F = lookup_fd(pollfds[ci].fd); if (F == NULL || !F->flags.open) continue; if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } comm_setselect(F, 0, NULL, NULL, 0); } }
/* * comm_select() * * Called to do the new-style IO, courtesy of of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { struct epoll_event ep_fdlist[128]; int num, i; void (*hdl)(fde_t *, void *); fde_t *F; num = epoll_wait(efd.fd, ep_fdlist, 128, SELECT_DELAY); set_time(); if (num < 0) { const struct timespec req = { .tv_sec = 0, .tv_nsec = 50000000 }; nanosleep(&req, NULL); /* Avoid 99% CPU in comm_select */ return; } for (i = 0; i < num; i++) { F = lookup_fd(ep_fdlist[i].data.fd); if (F == NULL || !F->flags.open) continue; if ((ep_fdlist[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))) { if ((hdl = F->read_handler)) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } } if ((ep_fdlist[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR))) { if ((hdl = F->write_handler)) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } } comm_setselect(F, 0, NULL, NULL, 0); } }
/* * comm_select() * * Called to do the new-style IO, courtesy of of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { struct epoll_event ep_fdlist[128]; int num, i; PF *hdl; fde_t *F; num = epoll_wait(efd.fd, ep_fdlist, 128, SELECT_DELAY); set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); /* avoid 99% CPU in comm_select */ #endif return; } for (i = 0; i < num; i++) { F = lookup_fd(ep_fdlist[i].data.fd); if (F == NULL || !F->flags.open) continue; if ((ep_fdlist[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))) if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } if ((ep_fdlist[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR))) if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } comm_setselect(F, 0, NULL, NULL, 0); } }
int storage_file_read(struct storage_msg *msg, const void *r, size_t req_len) { int rc; const struct storage_file_read_req *req = r; if (req_len != sizeof(*req)) { ALOGE("%s: invalid request length (%zd != %zd)\n", __func__, req_len, sizeof(*req)); msg->result = STORAGE_ERR_NOT_VALID; goto err_response; } if (req->size > MAX_READ_SIZE) { ALOGW("%s: request is too large (%u > %d) - refusing\n", __func__, req->size, MAX_READ_SIZE); msg->result = STORAGE_ERR_NOT_VALID; goto err_response; } int fd = lookup_fd(req->handle, false); ssize_t read_res = read_with_retry(fd, read_rsp.hdr.data, req->size, (off_t)req->offset); if (read_res < 0) { rc = errno; ALOGW("%s: error reading file (fd=%d): %s\n", __func__, fd, strerror(errno)); msg->result = translate_errno(rc); goto err_response; } msg->result = STORAGE_NO_ERROR; return ipc_respond(msg, &read_rsp, read_res + sizeof(read_rsp.hdr)); err_response: return ipc_respond(msg, NULL, 0); }
/* * Handler for Win32 messages. */ static LRESULT CALLBACK hybrid_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_SOCKET: { fde_t *F = lookup_fd((int) wParam); PF *hdl; if (F != NULL && F->flags.open) switch (WSAGETSELECTEVENT(lParam)) { case FD_ACCEPT: case FD_CLOSE: case FD_READ: if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (F->flags.open) comm_setselect(F, 0, NULL, NULL, 0); } break; case FD_CONNECT: case FD_WRITE: if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (F->flags.open) comm_setselect(F, 0, NULL, NULL, 0); } } return 0; } case WM_DNS: { dlink_node *ptr; DLINK_FOREACH(ptr, dns_queries.head) if (((struct DNSQuery *) ptr->data)->handle == wParam) { struct DNSQuery *query = ptr->data; struct DNSReply *reply = NULL; dlinkDelete(&query->node, &dns_queries); if (WSAGETASYNCERROR(lParam) == 0) { struct hostent *h = (struct hostent *) &query->reply; static struct DNSReply _reply; reply = &_reply; reply->h_name = h->h_name; reply->addr.ss.ss_family = h->h_addrtype; switch (h->h_addrtype) { case AF_INET: memcpy(&((struct sockaddr_in *) &reply->addr)->sin_addr, h->h_addr_list[0], h->h_length); break; #ifdef IPV6 case AF_INET6: memcpy(&((struct sockaddr_in6 *) &reply->addr)->sin6_addr, h->h_addr_list[0], h->h_length); break; #endif default: /* shouldn't happen */ reply = NULL; } } query->callback(query->ptr, reply); return 0; } return 0; } case WM_REHASH: dorehash = 1; return 0; case WM_REMOTD: doremotd = 1; return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } }
/* * comm_setselect * * This is a needed exported function which will be called to register * and deregister interest in a pending IO state for a given FD. */ void comm_setselect(fde_t *F, unsigned int type, void (*handler)(fde_t *, void *), void *client_data, time_t timeout) { int new_events; if ((type & COMM_SELECT_READ)) { F->read_handler = handler; F->read_data = client_data; } if ((type & COMM_SELECT_WRITE)) { F->write_handler = handler; F->write_data = client_data; } new_events = (F->read_handler ? POLLRDNORM : 0) | (F->write_handler ? POLLWRNORM : 0); if (timeout != 0) { F->timeout = CurrentTime + (timeout / 1000); F->timeout_handler = handler; F->timeout_data = client_data; } if (new_events != F->evcache) { if (new_events == 0) { if (F->comm_index != pollnum - 1) { fde_t *other = lookup_fd(pollfds[pollnum - 1].fd); pollfds[F->comm_index].fd = pollfds[pollnum - 1].fd; pollfds[F->comm_index].events = pollfds[pollnum - 1].events; pollfds[F->comm_index].revents = pollfds[pollnum - 1].revents; assert(other); other->comm_index = F->comm_index; } F->comm_index = -1; --pollnum; } else { if (F->evcache == 0) { if (pollnum >= pollfds_size) { pollfds_size *= 2; pollfds = MyRealloc(pollfds, sizeof(struct pollfd) * pollfds_size); } F->comm_index = pollnum++; pollfds[F->comm_index].fd = F->fd; } pollfds[F->comm_index].events = new_events; pollfds[F->comm_index].revents = 0; } F->evcache = new_events; } }
/* Read system call. */ static int sys_read (int handle, void *udst_, unsigned size) { uint8_t *udst = udst_; struct file_descriptor *fd; int bytes_read = 0; fd = lookup_fd (handle); while (size > 0) { /* How much to read into this page? */ size_t page_left = PGSIZE - pg_ofs (udst); size_t read_amt = size < page_left ? size : page_left; off_t retval; /* Read from file into page. */ if (handle != STDIN_FILENO) { if (!page_lock (udst, true)) thread_exit (); lock_acquire (&fs_lock); retval = file_read (fd->file, udst, read_amt); lock_release (&fs_lock); page_unlock (udst); } else { size_t i; for (i = 0; i < read_amt; i++) { char c = input_getc (); if (!page_lock (udst, true)) thread_exit (); udst[i] = c; page_unlock (udst); } bytes_read = read_amt; } /* Check success. */ if (retval < 0) { if (bytes_read == 0) bytes_read = -1; break; } bytes_read += retval; if (retval != (off_t) read_amt) { /* Short read, so we're done. */ break; } /* Advance. */ udst += retval; size -= retval; } return bytes_read; }