From: Michihiro NAKAJIMA Date: Thu, 19 Feb 2009 06:15:21 +0000 (-0500) Subject: On Windows, libarchive/bsdtar can deal with an external program. X-Git-Tag: v2.7.0~243 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb5a2db789e6c2ac4028293c7880a7e98f597fb1;p=thirdparty%2Flibarchive.git On Windows, libarchive/bsdtar can deal with an external program. SVN-Revision: 674 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 55a931286..6ff1d30e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -622,6 +622,7 @@ SET(libarchive_MANS IF(WIN32) LIST(APPEND libarchive_SOURCES libarchive/archive_windows.c) LIST(APPEND libarchive_SOURCES libarchive/archive_windows.h) + LIST(APPEND libarchive_SOURCES libarchive/filter_fork_windows.c) ENDIF(WIN32) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libarchive) diff --git a/libarchive/archive_read_support_compression_program.c b/libarchive/archive_read_support_compression_program.c index 31adaeb36..f26bfcca1 100644 --- a/libarchive/archive_read_support_compression_program.c +++ b/libarchive/archive_read_support_compression_program.c @@ -60,8 +60,8 @@ archive_read_support_compression_program(struct archive *a, const char *cmd) /* This capability is only available on POSIX systems. */ -#if !defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \ - !(defined(HAVE_FORK) || defined(HAVE_VFORK)) +#if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \ + !(defined(HAVE_FORK) || defined(HAVE_VFORK))) && !defined(_WIN32) /* * On non-Posix systems, allow the program to build, but choke if diff --git a/libarchive/archive_windows.c b/libarchive/archive_windows.c index 9be562e3e..779e5c4a3 100644 --- a/libarchive/archive_windows.c +++ b/libarchive/archive_windows.c @@ -533,6 +533,27 @@ la_chmod(const char *path, mode_t mode) return (r); } +/* + * This fcntl is limited implemention. + */ +int +la_fcntl(int fd, int cmd, int val) +{ + HANDLE handle; + + handle = (HANDLE)_get_osfhandle(fd); + if (GetFileType(handle) == FILE_TYPE_PIPE) { + if (cmd == F_SETFL && val == 0) { + DWORD mode = PIPE_WAIT; + if (SetNamedPipeHandleState( + handle, &mode, NULL, NULL) != 0) + return (0); + } + } + errno = EINVAL; + return (-1); +} + __int64 la_lseek(int fd, __int64 offset, int whence) { @@ -658,6 +679,7 @@ la_open(const char *path, int flags, ...) ssize_t la_read(int fd, void *buf, size_t nbytes) { + HANDLE handle; DWORD bytes_read, lasterr; int r; @@ -669,10 +691,31 @@ la_read(int fd, void *buf, size_t nbytes) errno = EBADF; return (-1); } - r = ReadFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes, + handle = (HANDLE)_get_osfhandle(fd); + if (GetFileType(handle) == FILE_TYPE_PIPE) { + DWORD sta; + if (GetNamedPipeHandleState( + handle, &sta, NULL, NULL, NULL, NULL, 0) != 0 && + (sta & PIPE_NOWAIT) == 0) { + DWORD avail = -1; + int cnt = 3; + + while (PeekNamedPipe( + handle, NULL, 0, NULL, &avail, NULL) != 0 && + avail == 0 && --cnt) + Sleep(100); + if (avail == 0) + return (0); + } + } + r = ReadFile(handle, buf, (uint32_t)nbytes, &bytes_read, NULL); if (r == 0) { lasterr = GetLastError(); + if (lasterr == ERROR_NO_DATA) { + errno = EAGAIN; + return (-1); + } if (lasterr == ERROR_BROKEN_PIPE) return (0); if (lasterr == ERROR_ACCESS_DENIED) @@ -921,6 +964,36 @@ la_unlink(const char *path) return (r); } +/* + * This waitpid is limited implemention. + */ +pid_t +la_waitpid(pid_t wpid, int *status, int option) +{ + HANDLE child; + DWORD cs, ret; + + (void)option;/* UNUSED */ + child = OpenProcess(PROCESS_ALL_ACCESS, FALSE, wpid); + if (child == NULL) + return (-1); + ret = WaitForSingleObject(child, INFINITE); + if (ret == WAIT_FAILED) { + CloseHandle(child); + return (-1); + } + if (GetExitCodeProcess(child, &cs) == 0) { + CloseHandle(child); + return (-1); + } + if (cs == STILL_ACTIVE) + *status = 0x100; + else + *status = (int)(cs & 0xff); + CloseHandle(child); + return (wpid); +} + ssize_t la_write(int fd, const void *buf, size_t nbytes) { diff --git a/libarchive/archive_windows.h b/libarchive/archive_windows.h index 0b060a9ea..7c326a99a 100644 --- a/libarchive/archive_windows.h +++ b/libarchive/archive_windows.h @@ -85,6 +85,7 @@ #define chdir la_chdir #define chmod la_chmod #define close _close +#define fcntl la_fcntl #define fileno _fileno #define fstat la_fstat #define getcwd _getcwd @@ -101,6 +102,7 @@ #define tzset _tzset #define umask _umask #define unlink la_unlink +#define waitpid la_waitpid #define write la_write #define O_RDONLY _O_RDONLY @@ -256,6 +258,8 @@ struct _timeval64i32 { #define __timeval _timeval64i32 #endif +typedef int pid_t; + #define SYSTEM_PATH_CHAR '\\' /* Message digest define */ @@ -311,6 +315,7 @@ extern int utimes(const char *name, const struct __timeval *times); /* Replacement POSIX function */ extern int la_chdir(const char *path); extern int la_chmod(const char *path, mode_t mode); +extern int la_fcntl(int fd, int cmd, int val); extern int la_fstat(int fd, struct stat *st); extern __int64 la_lseek(int fd, __int64 offset, int whence); extern int la_mkdir(const char *path, mode_t mode); @@ -320,6 +325,7 @@ extern ssize_t la_read(int fd, void *buf, size_t nbytes); extern int la_rmdir(const char *path); extern int la_stat(const char *path, struct stat *st); extern int la_unlink(const char *path); +extern pid_t la_waitpid(pid_t wpid, int *status, int option); extern ssize_t la_write(int fd, const void *buf, size_t nbytes); #define _stat64i32(path, st) la_stat(path, st) diff --git a/libarchive/archive_write_set_compression_program.c b/libarchive/archive_write_set_compression_program.c index 69c5d4286..a27c64793 100644 --- a/libarchive/archive_write_set_compression_program.c +++ b/libarchive/archive_write_set_compression_program.c @@ -28,8 +28,8 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_program.c,v 1.3 2008/06/15 10:45:57 kientzle Exp $"); /* This capability is only available on POSIX systems. */ -#if !defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \ - !(defined(HAVE_FORK) || defined(HAVE_VFORK)) +#if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \ + !(defined(HAVE_FORK) || defined(HAVE_VFORK))) && !defined(_WIN32) #include "archive.h" /* diff --git a/libarchive/filter_fork_windows.c b/libarchive/filter_fork_windows.c new file mode 100644 index 000000000..838005315 --- /dev/null +++ b/libarchive/filter_fork_windows.c @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 2009 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" + +#ifdef _WIN32 + +#include "filter_fork.h" + +pid_t +__archive_create_child(const char *path, int *child_stdin, int *child_stdout) +{ + HANDLE childStdout[2], childStdin[2], childStdinWr, childStdoutRd; + SECURITY_ATTRIBUTES secAtts; + STARTUPINFO staInfo; + PROCESS_INFORMATION childInfo; + char cmd[MAX_PATH]; + DWORD mode; + + secAtts.nLength = sizeof(SECURITY_ATTRIBUTES); + secAtts.bInheritHandle = TRUE; + secAtts.lpSecurityDescriptor = NULL; + if (CreatePipe(&childStdout[0], &childStdout[1], &secAtts, 0) == 0) + goto fail; + if (DuplicateHandle(GetCurrentProcess(), childStdout[0], + GetCurrentProcess(), &childStdoutRd, 0, FALSE, + DUPLICATE_SAME_ACCESS) == 0) { + CloseHandle(childStdout[0]); + CloseHandle(childStdout[1]); + goto fail; + } + CloseHandle(childStdout[0]); + + if (CreatePipe(&childStdin[0], &childStdin[1], &secAtts, 0) == 0) { + CloseHandle(childStdoutRd); + CloseHandle(childStdout[1]); + goto fail; + } + + if (DuplicateHandle(GetCurrentProcess(), childStdin[1], + GetCurrentProcess(), &childStdinWr, 0, FALSE, + DUPLICATE_SAME_ACCESS) == 0) { + CloseHandle(childStdoutRd); + CloseHandle(childStdout[1]); + CloseHandle(childStdin[0]); + CloseHandle(childStdin[1]); + goto fail; + } + CloseHandle(childStdin[1]); + + memset(&staInfo, 0, sizeof(staInfo)); + staInfo.cb = sizeof(staInfo); + staInfo.hStdOutput = childStdout[1]; + staInfo.hStdInput = childStdin[0]; + staInfo.wShowWindow = SW_HIDE; + staInfo.dwFlags = STARTF_USEFILLATTRIBUTE | STARTF_USECOUNTCHARS | + STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + strncpy(cmd, path, sizeof(cmd)-1); + cmd[sizeof(cmd)-1] = '\0'; + if (CreateProcessA(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, + &staInfo, &childInfo) == 0) { + CloseHandle(childStdoutRd); + CloseHandle(childStdout[1]); + CloseHandle(childStdin[0]); + CloseHandle(childStdinWr); + goto fail; + } + WaitForInputIdle(childInfo.hProcess, INFINITE); + CloseHandle(childInfo.hProcess); + CloseHandle(childInfo.hThread); + + mode = PIPE_NOWAIT; + SetNamedPipeHandleState(childStdoutRd, &mode, NULL, NULL); + *child_stdout = _open_osfhandle((intptr_t)childStdoutRd, _O_RDONLY); + *child_stdin = _open_osfhandle((intptr_t)childStdinWr, _O_WRONLY); + + return (childInfo.dwProcessId); + +fail: + return (-1); +} + +void +__archive_check_child(int in, int out) +{ + Sleep(100); +} + +#endif /* _WIN32 */