static int program_filter_close(struct archive_read_filter *self) { struct program_filter *state; int e; state = (struct program_filter *)self->data; e = child_stop(self, state); /* Release our private data. */ free(state->out_buf); free(state->description); free(state); return (e); }
int __archive_read_program(struct archive_read_filter *self, const char *cmd) { struct program_filter *state; static const size_t out_buf_len = 65536; char *out_buf; const char *prefix = "Program: "; pid_t child; size_t l; l = strlen(prefix) + strlen(cmd) + 1; state = (struct program_filter *)calloc(1, sizeof(*state)); out_buf = (char *)malloc(out_buf_len); if (state == NULL || out_buf == NULL || archive_string_ensure(&state->description, l) == NULL) { archive_set_error(&self->archive->archive, ENOMEM, "Can't allocate input data"); if (state != NULL) { archive_string_free(&state->description); free(state); } free(out_buf); return (ARCHIVE_FATAL); } archive_strcpy(&state->description, prefix); archive_strcat(&state->description, cmd); self->code = ARCHIVE_FILTER_PROGRAM; self->name = state->description.s; state->out_buf = out_buf; state->out_buf_len = out_buf_len; child = __archive_create_child(cmd, &state->child_stdin, &state->child_stdout); if (child == -1) { free(state->out_buf); free(state); archive_set_error(&self->archive->archive, EINVAL, "Can't initialize filter; unable to run program \"%s\"", cmd); return (ARCHIVE_FATAL); } #if defined(_WIN32) && !defined(__CYGWIN__) state->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child); if (state->child == NULL) { child_stop(self, state); free(state->out_buf); free(state); archive_set_error(&self->archive->archive, EINVAL, "Can't initialize filter; unable to run program \"%s\"", cmd); return (ARCHIVE_FATAL); } #else state->child = child; #endif self->data = state; self->read = program_filter_read; self->skip = NULL; self->close = program_filter_close; /* XXX Check that we can read at least one byte? */ return (ARCHIVE_OK); }
/* * 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); } } }
/* * 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); } } }