static ssize_t child_write(struct archive_write_filter *f, struct archive_write_program_data *data, const char *buf, size_t buf_len) { ssize_t ret; if (data->child_stdin == -1) return (-1); if (buf_len == 0) return (-1); for (;;) { do { ret = write(data->child_stdin, buf, buf_len); } while (ret == -1 && errno == EINTR); if (ret > 0) return (ret); if (ret == 0) { close(data->child_stdin); data->child_stdin = -1; fcntl(data->child_stdout, F_SETFL, 0); return (0); } if (ret == -1 && errno != EAGAIN) return (-1); if (data->child_stdout == -1) { fcntl(data->child_stdin, F_SETFL, 0); __archive_check_child(data->child_stdin, data->child_stdout); continue; } do { ret = read(data->child_stdout, data->child_buf + data->child_buf_avail, data->child_buf_len - data->child_buf_avail); } while (ret == -1 && errno == EINTR); if (ret == 0 || (ret == -1 && errno == EPIPE)) { close(data->child_stdout); data->child_stdout = -1; fcntl(data->child_stdin, F_SETFL, 0); continue; } if (ret == -1 && errno == EAGAIN) { __archive_check_child(data->child_stdin, data->child_stdout); continue; } if (ret == -1) return (-1); data->child_buf_avail += ret; ret = __archive_write_filter(f->next_filter, data->child_buf, data->child_buf_avail); if (ret != ARCHIVE_OK) return (-1); data->child_buf_avail = 0; } }
/* * Use select() to decide whether the child is ready for read or write. */ static ssize_t child_read(struct archive_read_filter *self, char *buf, size_t buf_len) { struct program_filter *state = self->data; ssize_t ret, requested, avail; const char *p; requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len; for (;;) { do { ret = read(state->child_stdout, buf, requested); } while (ret == -1 && errno == EINTR); if (ret > 0) return (ret); if (ret == 0 || (ret == -1 && errno == EPIPE)) /* Child has closed its output; reap the child * and return the status. */ return (child_stop(self, state)); if (ret == -1 && errno != EAGAIN) return (-1); if (state->child_stdin == -1) { /* Block until child has some I/O ready. */ __archive_check_child(state->child_stdin, state->child_stdout); continue; } /* Get some more data from upstream. */ p = __archive_read_filter_ahead(self->upstream, 1, &avail); if (p == NULL) { close(state->child_stdin); state->child_stdin = -1; fcntl(state->child_stdout, F_SETFL, 0); if (avail < 0) return (avail); continue; } do { ret = write(state->child_stdin, p, avail); } while (ret == -1 && errno == EINTR); if (ret > 0) { /* Consume whatever we managed to write. */ __archive_read_filter_consume(self->upstream, ret); } else if (ret == -1 && errno == EAGAIN) { /* Block until child has some I/O ready. */ __archive_check_child(state->child_stdin, state->child_stdout); } else { /* Write failed. */ close(state->child_stdin); state->child_stdin = -1; fcntl(state->child_stdout, F_SETFL, 0); /* If it was a bad error, we're done; otherwise * it was EPIPE or EOF, and we can still read * from the child. */ if (ret == -1 && errno != EPIPE) return (-1); } } }
static ssize_t child_write(struct archive_write_filter *f, const char *buf, size_t buf_len) { struct private_data *data = f->data; ssize_t ret; if (data->child_stdin == -1) return (-1); if (buf_len == 0) return (-1); restart_write: do { ret = write(data->child_stdin, buf, buf_len); } while (ret == -1 && errno == EINTR); if (ret > 0) return (ret); if (ret == 0) { close(data->child_stdin); data->child_stdin = -1; fcntl(data->child_stdout, F_SETFL, 0); return (0); } if (ret == -1 && errno != EAGAIN) return (-1); if (data->child_stdout == -1) { fcntl(data->child_stdin, F_SETFL, 0); __archive_check_child(data->child_stdin, data->child_stdout); goto restart_write; } do { ret = read(data->child_stdout, data->child_buf + data->child_buf_avail, data->child_buf_len - data->child_buf_avail); } while (ret == -1 && errno == EINTR); if (ret == 0 || (ret == -1 && errno == EPIPE)) { close(data->child_stdout); data->child_stdout = -1; fcntl(data->child_stdin, F_SETFL, 0); goto restart_write; } if (ret == -1 && errno == EAGAIN) { __archive_check_child(data->child_stdin, data->child_stdout); goto restart_write; } if (ret == -1) return (-1); data->child_buf_avail += ret; ret = __archive_write_filter(f->next_filter, data->child_buf, data->child_buf_avail); if (ret <= 0) return (-1); if ((size_t)ret < data->child_buf_avail) { memmove(data->child_buf, data->child_buf + ret, data->child_buf_avail - ret); } data->child_buf_avail -= ret; goto restart_write; }
static ssize_t child_write(struct archive_write *a, const char *buf, size_t buf_len) { struct private_data *state = a->compressor.data; ssize_t ret; if (state->child_stdin == -1) return (-1); if (buf_len == 0) return (-1); restart_write: do { ret = write(state->child_stdin, buf, buf_len); } while (ret == -1 && errno == EINTR); if (ret > 0) return (ret); if (ret == 0) { close(state->child_stdin); state->child_stdin = -1; fcntl(state->child_stdout, F_SETFL, 0); return (0); } if (ret == -1 && errno != EAGAIN) return (-1); if (state->child_stdout == -1) { fcntl(state->child_stdin, F_SETFL, 0); __archive_check_child(state->child_stdin, state->child_stdout); goto restart_write; } do { ret = read(state->child_stdout, state->child_buf + state->child_buf_avail, state->child_buf_len - state->child_buf_avail); } while (ret == -1 && errno == EINTR); if (ret == 0 || (ret == -1 && errno == EPIPE)) { close(state->child_stdout); state->child_stdout = -1; fcntl(state->child_stdin, F_SETFL, 0); goto restart_write; } if (ret == -1 && errno == EAGAIN) { __archive_check_child(state->child_stdin, state->child_stdout); goto restart_write; } if (ret == -1) return (-1); state->child_buf_avail += ret; ret = (a->client_writer)(&a->archive, a->client_data, state->child_buf, state->child_buf_avail); if (ret <= 0) return (-1); if ((size_t)ret < state->child_buf_avail) { memmove(state->child_buf, state->child_buf + ret, state->child_buf_avail - ret); } state->child_buf_avail -= ret; a->archive.raw_position += ret; goto restart_write; }
/* * Use select() to decide whether the child is ready for read or write. */ static ssize_t child_read(struct archive_read_filter *self, char *buf, size_t buf_len) { struct program_filter *state = self->data; ssize_t ret, requested, avail; const char *p; #if defined(_WIN32) && !defined(__CYGWIN__) HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout); #endif requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len; for (;;) { do { #if defined(_WIN32) && !defined(__CYGWIN__) /* Avoid infinity wait. * Note: If there is no data in the pipe, ReadFile() * called in read() never returns and so we won't * write remaining encoded data to the pipe. * Note: This way may cause performance problem. * we are looking forward to great code to resolve * this. */ DWORD pipe_avail = -1; int cnt = 2; while (PeekNamedPipe(handle, NULL, 0, NULL, &pipe_avail, NULL) != 0 && pipe_avail == 0 && cnt--) Sleep(5); if (pipe_avail == 0) { ret = -1; errno = EAGAIN; break; } #endif ret = read(state->child_stdout, buf, requested); } while (ret == -1 && errno == EINTR); if (ret > 0) return (ret); if (ret == 0 || (ret == -1 && errno == EPIPE)) /* Child has closed its output; reap the child * and return the status. */ return (child_stop(self, state)); if (ret == -1 && errno != EAGAIN) return (-1); if (state->child_stdin == -1) { /* Block until child has some I/O ready. */ __archive_check_child(state->child_stdin, state->child_stdout); continue; } /* Get some more data from upstream. */ p = __archive_read_filter_ahead(self->upstream, 1, &avail); if (p == NULL) { close(state->child_stdin); state->child_stdin = -1; fcntl(state->child_stdout, F_SETFL, 0); if (avail < 0) return (avail); continue; } do { ret = write(state->child_stdin, p, avail); } while (ret == -1 && errno == EINTR); if (ret > 0) { /* Consume whatever we managed to write. */ __archive_read_filter_consume(self->upstream, ret); } else if (ret == -1 && errno == EAGAIN) { /* Block until child has some I/O ready. */ __archive_check_child(state->child_stdin, state->child_stdout); } else { /* Write failed. */ close(state->child_stdin); state->child_stdin = -1; fcntl(state->child_stdout, F_SETFL, 0); /* If it was a bad error, we're done; otherwise * it was EPIPE or EOF, and we can still read * from the child. */ if (ret == -1 && errno != EPIPE) return (-1); } } }