Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Avoid infinity wait in ReadFile during running an external program as

decoding filter on Windows.
  • Loading branch information...
commit ed8cd1269439c076df039cb73e5d91fe09c42a78 1 parent 40722a2
Michihiro NAKAJIMA ggcueroad authored
51 libarchive/archive_read_support_filter_program.c
@@ -171,7 +171,11 @@ static int program_bidder_free(struct archive_read_filter_bidder *);
171 171 */
172 172 struct program_filter {
173 173 struct archive_string description;
  174 +#if defined(_WIN32) && !defined(__CYGWIN__)
  175 + HANDLE child;
  176 +#else
174 177 pid_t child;
  178 +#endif
175 179 int exit_status;
176 180 int waitpid_return;
177 181 int child_stdin, child_stdout;
@@ -435,6 +439,9 @@ child_stop(struct archive_read_filter *self, struct program_filter *state)
435 439 state->waitpid_return
436 440 = waitpid(state->child, &state->exit_status, 0);
437 441 } while (state->waitpid_return == -1 && errno == EINTR);
  442 +#if defined(_WIN32) && !defined(__CYGWIN__)
  443 + CloseHandle(state->child);
  444 +#endif
438 445 state->child = 0;
439 446 }
440 447
@@ -487,11 +494,35 @@ child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
487 494 struct program_filter *state = self->data;
488 495 ssize_t ret, requested, avail;
489 496 const char *p;
  497 +#if defined(_WIN32) && !defined(__CYGWIN__)
  498 + HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout);
  499 +#endif
490 500
491 501 requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
492 502
493 503 for (;;) {
494 504 do {
  505 +#if defined(_WIN32) && !defined(__CYGWIN__)
  506 + /* Avoid infinity wait.
  507 + * Note: If there is no data in the pipe, ReadFile()
  508 + * called in read() never returns and so we won't
  509 + * write remaining encoded data to the pipe.
  510 + * Note: This way may cause performance problem.
  511 + * we are looking forward to great code to resolve
  512 + * this. */
  513 + DWORD pipe_avail = -1;
  514 + int cnt = 2;
  515 +
  516 + while (PeekNamedPipe(handle, NULL, 0, NULL,
  517 + &pipe_avail, NULL) != 0 && pipe_avail == 0 &&
  518 + cnt--)
  519 + Sleep(5);
  520 + if (pipe_avail == 0) {
  521 + ret = -1;
  522 + errno = EAGAIN;
  523 + break;
  524 + }
  525 +#endif
495 526 ret = read(state->child_stdout, buf, requested);
496 527 } while (ret == -1 && errno == EINTR);
497 528
@@ -624,6 +655,7 @@ __archive_read_programv(struct archive_read_filter *self, const char *cmd,
624 655 static const size_t out_buf_len = 65536;
625 656 char *out_buf;
626 657 const char *prefix = "Program: ";
  658 + pid_t child;
627 659 int i;
628 660 size_t l;
629 661
@@ -654,8 +686,9 @@ __archive_read_programv(struct archive_read_filter *self, const char *cmd,
654 686 state->out_buf = out_buf;
655 687 state->out_buf_len = out_buf_len;
656 688
657   - if ((state->child = __archive_create_child(cmd, argv,
658   - &state->child_stdin, &state->child_stdout)) == -1) {
  689 + child = __archive_create_child(cmd, argv, &state->child_stdin,
  690 + &state->child_stdout);
  691 + if (child == -1) {
659 692 free(state->out_buf);
660 693 free(state);
661 694 archive_set_error(&self->archive->archive, EINVAL,
@@ -663,6 +696,20 @@ __archive_read_programv(struct archive_read_filter *self, const char *cmd,
663 696 cmd);
664 697 return (ARCHIVE_FATAL);
665 698 }
  699 +#if defined(_WIN32) && !defined(__CYGWIN__)
  700 + state->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child);
  701 + if (state->child == NULL) {
  702 + child_stop(self, state);
  703 + free(state->out_buf);
  704 + free(state);
  705 + archive_set_error(&self->archive->archive, EINVAL,
  706 + "Can't initialize filter; unable to run program \"%s\"",
  707 + cmd);
  708 + return (ARCHIVE_FATAL);
  709 + }
  710 +#else
  711 + state->child = child;
  712 +#endif
666 713
667 714 self->data = state;
668 715 self->read = program_filter_read;
39 libarchive/archive_windows.c
@@ -633,35 +633,22 @@ __la_stat(const char *path, struct stat *st)
633 633 * This waitpid is limited implementation.
634 634 */
635 635 pid_t
636   -__la_waitpid(pid_t wpid, int *status, int option)
  636 +__la_waitpid(HANDLE child, int *status, int option)
637 637 {
638   - HANDLE child;
639   - DWORD cs, ret;
  638 + DWORD cs;
640 639
641 640 (void)option;/* UNUSED */
642   - *status = 0;
643   - child = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, wpid);
644   - if (child == NULL) {
645   - la_dosmaperr(GetLastError());
646   - return (-1);
647   - }
648   - ret = WaitForSingleObject(child, INFINITE);
649   - if (ret == WAIT_FAILED) {
650   - CloseHandle(child);
651   - la_dosmaperr(GetLastError());
652   - return (-1);
653   - }
654   - if (GetExitCodeProcess(child, &cs) == 0) {
655   - CloseHandle(child);
656   - la_dosmaperr(GetLastError());
657   - return (-1);
658   - }
659   - if (cs == STILL_ACTIVE)
660   - *status = 0x100;
661   - else
662   - *status = (int)(cs & 0xff);
663   - CloseHandle(child);
664   - return (wpid);
  641 + do {
  642 + if (GetExitCodeProcess(child, &cs) == 0) {
  643 + CloseHandle(child);
  644 + la_dosmaperr(GetLastError());
  645 + *status = 0;
  646 + return (-1);
  647 + }
  648 + } while (cs == STILL_ACTIVE);
  649 +
  650 + *status = (int)(cs & 0xff);
  651 + return (0);
665 652 }
666 653
667 654 ssize_t
2  libarchive/archive_windows.h
@@ -264,7 +264,7 @@ extern __int64 __la_lseek(int fd, __int64 offset, int whence);
264 264 extern int __la_open(const char *path, int flags, ...);
265 265 extern ssize_t __la_read(int fd, void *buf, size_t nbytes);
266 266 extern int __la_stat(const char *path, struct stat *st);
267   -extern pid_t __la_waitpid(pid_t wpid, int *status, int option);
  267 +extern pid_t __la_waitpid(HANDLE child, int *status, int option);
268 268 extern ssize_t __la_write(int fd, const void *buf, size_t nbytes);
269 269
270 270 #define _stat64i32(path, st) __la_stat(path, st)
33 libarchive/archive_write_add_filter_program.c
@@ -62,7 +62,11 @@ struct private_data {
62 62 char *cmd;
63 63 char **argv;
64 64 struct archive_string description;
  65 +#if defined(_WIN32) && !defined(__CYGWIN__)
  66 + HANDLE child;
  67 +#else
65 68 pid_t child;
  69 +#endif
66 70 int child_stdin, child_stdout;
67 71
68 72 char *child_buf;
@@ -235,6 +239,7 @@ static int
235 239 archive_compressor_program_open(struct archive_write_filter *f)
236 240 {
237 241 struct private_data *data = (struct private_data *)f->data;
  242 + pid_t child;
238 243 int ret;
239 244
240 245 ret = __archive_write_open_filter(f->next_filter);
@@ -253,13 +258,27 @@ archive_compressor_program_open(struct archive_write_filter *f)
253 258 }
254 259 }
255 260
256   - if ((data->child = __archive_create_child(data->cmd,
257   - (char * const *)data->argv,
258   - &data->child_stdin, &data->child_stdout)) == -1) {
  261 + child = __archive_create_child(data->cmd, (char * const *)data->argv,
  262 + &data->child_stdin, &data->child_stdout);
  263 + if (child == -1) {
  264 + archive_set_error(f->archive, EINVAL,
  265 + "Can't initialise filter");
  266 + return (ARCHIVE_FATAL);
  267 + }
  268 +#if defined(_WIN32) && !defined(__CYGWIN__)
  269 + data->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child);
  270 + if (data->child == NULL) {
  271 + close(data->child_stdin);
  272 + data->child_stdin = -1;
  273 + close(data->child_stdout);
  274 + data->child_stdout = -1;
259 275 archive_set_error(f->archive, EINVAL,
260 276 "Can't initialise filter");
261 277 return (ARCHIVE_FATAL);
262 278 }
  279 +#else
  280 + data->child = child;
  281 +#endif
263 282
264 283 f->write = archive_compressor_program_write;
265 284 f->close = archive_compressor_program_close;
@@ -411,6 +430,10 @@ archive_compressor_program_close(struct archive_write_filter *f)
411 430 close(data->child_stdout);
412 431 while (waitpid(data->child, &status, 0) == -1 && errno == EINTR)
413 432 continue;
  433 +#if defined(_WIN32) && !defined(__CYGWIN__)
  434 + CloseHandle(data->child);
  435 +#endif
  436 + data->child = 0;
414 437
415 438 if (status != 0) {
416 439 archive_set_error(f->archive, EIO,
@@ -427,6 +450,10 @@ archive_compressor_program_free(struct archive_write_filter *f)
427 450 struct private_data *data = (struct private_data *)f->data;
428 451
429 452 if (data) {
  453 +#if defined(_WIN32) && !defined(__CYGWIN__)
  454 + if (data->child)
  455 + CloseHandle(data->child);
  456 +#endif
430 457 if (data->argv != NULL) {
431 458 int i;
432 459 for (i = 0; data->argv[i] != NULL; i++)

0 comments on commit ed8cd12

Please sign in to comment.
Something went wrong with that request. Please try again.