diff options
Diffstat (limited to 'libarchive/archive_windows.c')
-rw-r--r-- | libarchive/archive_windows.c | 606 |
1 files changed, 66 insertions, 540 deletions
diff --git a/libarchive/archive_windows.c b/libarchive/archive_windows.c index d9f29b7..4d37a9c 100644 --- a/libarchive/archive_windows.c +++ b/libarchive/archive_windows.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009 Michihiro NAKAJIMA + * Copyright (c) 2009-2011 Michihiro NAKAJIMA * Copyright (c) 2003-2007 Kees Zeelenberg * All rights reserved. * @@ -48,7 +48,6 @@ #include "archive_platform.h" #include "archive_private.h" -#include "archive_hash.h" #include <ctype.h> #include <errno.h> #include <stddef.h> @@ -56,31 +55,15 @@ #include <sys/utime.h> #endif #include <sys/stat.h> +#include <locale.h> #include <process.h> #include <stdlib.h> #include <wchar.h> #include <windows.h> +#include <share.h> #define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) -#if defined(_MSC_VER) && _MSC_VER < 1300 -/* VS 6 does not provide SetFilePointerEx, so define it here. */ -static BOOL SetFilePointerEx(HANDLE hFile, - LARGE_INTEGER liDistanceToMove, - PLARGE_INTEGER lpNewFilePointer, - DWORD dwMoveMethod) -{ - LARGE_INTEGER li; - li.QuadPart = liDistanceToMove.QuadPart; - li.LowPart = SetFilePointer( - hFile, li.LowPart, &li.HighPart, dwMoveMethod); - if(lpNewFilePointer) { - lpNewFilePointer->QuadPart = li.QuadPart; - } - return li.LowPart != -1 || GetLastError() == NO_ERROR; -} -#endif - struct ustat { int64_t st_atime; uint32_t st_atime_nsec; @@ -99,9 +82,6 @@ struct ustat { dev_t st_rdev; }; -/* Local replacement for undocumented Windows CRT function. */ -static void la_dosmaperr(unsigned long e); - /* Transform 64-bits ino into 32-bits by hashing. * You do not forget that really unique number size is 64-bits. */ @@ -121,52 +101,63 @@ getino(struct ustat *ub) * characters. * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx */ -static wchar_t * -permissive_name(const char *name) +wchar_t * +__la_win_permissive_name(const char *name) { - wchar_t *wn, *wnp; - wchar_t *ws, *wsp; - DWORD l, len, slen; - int unc; + wchar_t *wn; + wchar_t *ws; + size_t ll; - len = (DWORD)strlen(name); - wn = malloc((len + 1) * sizeof(wchar_t)); + ll = strlen(name); + wn = malloc((ll + 1) * sizeof(wchar_t)); if (wn == NULL) return (NULL); - l = MultiByteToWideChar(CP_ACP, 0, name, (int)len, wn, (int)len); - if (l == 0) { + ll = mbstowcs(wn, name, ll); + if (ll == (size_t)-1) { free(wn); return (NULL); } - wn[l] = L'\0'; + wn[ll] = L'\0'; + ws = __la_win_permissive_name_w(wn); + free(wn); + return (ws); +} - /* Get a full path names */ - l = GetFullPathNameW(wn, 0, NULL, NULL); - if (l == 0) { - free(wn); +wchar_t * +__la_win_permissive_name_w(const wchar_t *wname) +{ + wchar_t *wn, *wnp; + wchar_t *ws, *wsp; + DWORD l, len, slen; + int unc; + + /* Get a full-pathname. */ + l = GetFullPathNameW(wname, 0, NULL, NULL); + if (l == 0) return (NULL); - } + /* NOTE: GetFullPathNameW has a bug that if the length of the file + * name is just 1 then it returns incomplete buffer size. Thus, we + * have to add three to the size to allocate a sufficient buffer + * size for the full-pathname of the file name. */ + l += 3; wnp = malloc(l * sizeof(wchar_t)); - if (wnp == NULL) { - free(wn); + if (wnp == NULL) return (NULL); - } - len = GetFullPathNameW(wn, l, wnp, NULL); - free(wn); + len = GetFullPathNameW(wname, l, wnp, NULL); wn = wnp; if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] == L'?' && wnp[3] == L'\\') - /* We have already permissive names. */ + /* We have already a permissive name. */ return (wn); if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] == L'.' && wnp[3] == L'\\') { - /* Device names */ + /* This is a device name */ if (((wnp[4] >= L'a' && wnp[4] <= L'z') || (wnp[4] >= L'A' && wnp[4] <= L'Z')) && wnp[5] == L':' && wnp[6] == L'\\') - wnp[2] = L'?';/* Not device names. */ + wnp[2] = L'?';/* Not device name. */ return (wn); } @@ -214,6 +205,10 @@ permissive_name(const char *name) return (ws); } +/* + * Create a file handle. + * This can exceed MAX_PATH limitation. + */ static HANDLE la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, @@ -229,7 +224,7 @@ la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, return (handle); if (GetLastError() != ERROR_PATH_NOT_FOUND) return (handle); - wpath = permissive_name(path); + wpath = __la_win_permissive_name(path); if (wpath == NULL) return (handle); handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode, @@ -239,376 +234,7 @@ la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, return (handle); } -static void * -la_GetFunctionKernel32(const char *name) -{ - static HINSTANCE lib; - static int set; - if (!set) { - set = 1; - lib = LoadLibrary("kernel32.dll"); - } - if (lib == NULL) { - fprintf(stderr, "Can't load kernel32.dll?!\n"); - exit(1); - } - return (void *)GetProcAddress(lib, name); -} - -static int -la_CreateHardLinkW(wchar_t *linkname, wchar_t *target) -{ - static BOOLEAN (WINAPI *f)(LPWSTR, LPWSTR, LPSECURITY_ATTRIBUTES); - static int set; - if (!set) { - set = 1; - f = la_GetFunctionKernel32("CreateHardLinkW"); - } - return f == NULL ? 0 : (*f)(linkname, target, NULL); -} - - -/* Make a link to src called dst. */ -static int -__link(const char *src, const char *dst) -{ - wchar_t *wsrc, *wdst; - int res, retval; - DWORD attr; - - if (src == NULL || dst == NULL) { - set_errno (EINVAL); - return -1; - } - - wsrc = permissive_name(src); - wdst = permissive_name(dst); - if (wsrc == NULL || wdst == NULL) { - free(wsrc); - free(wdst); - set_errno (EINVAL); - return -1; - } - - if ((attr = GetFileAttributesW(wsrc)) != (DWORD)-1) { - res = la_CreateHardLinkW(wdst, wsrc); - } else { - /* wsrc does not exist; try src prepend it with the dirname of wdst */ - wchar_t *wnewsrc, *slash; - int i, n, slen, wlen; - - if (strlen(src) >= 3 && isalpha((unsigned char)src[0]) && - src[1] == ':' && src[2] == '\\') { - /* Original src name is already full-path */ - retval = -1; - goto exit; - } - if (src[0] == '\\') { - /* Original src name is almost full-path - * (maybe src name is without drive) */ - retval = -1; - goto exit; - } - - wnewsrc = malloc ((wcslen(wsrc) + wcslen(wdst) + 1) * sizeof(wchar_t)); - if (wnewsrc == NULL) { - errno = ENOMEM; - retval = -1; - goto exit; - } - /* Copying a dirname of wdst */ - wcscpy(wnewsrc, wdst); - slash = wcsrchr(wnewsrc, L'\\'); - if (slash != NULL) - *++slash = L'\0'; - else - wcscat(wnewsrc, L"\\"); - /* Converting multi-byte src to wide-char src */ - wlen = (int)wcslen(wsrc); - slen = (int)strlen(src); - n = MultiByteToWideChar(CP_ACP, 0, src, slen, wsrc, wlen); - if (n == 0) { - free (wnewsrc); - retval = -1; - goto exit; - } - for (i = 0; i < n; i++) - if (wsrc[i] == L'/') - wsrc[i] = L'\\'; - wcsncat(wnewsrc, wsrc, n); - /* Check again */ - attr = GetFileAttributesW(wnewsrc); - if (attr == (DWORD)-1 || (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { - if (attr == (DWORD)-1) - la_dosmaperr(GetLastError()); - else - errno = EPERM; - free (wnewsrc); - retval = -1; - goto exit; - } - res = la_CreateHardLinkW(wdst, wnewsrc); - free (wnewsrc); - } - if (res == 0) { - la_dosmaperr(GetLastError()); - retval = -1; - } else - retval = 0; -exit: - free(wsrc); - free(wdst); - return (retval); -} - -/* Make a hard link to src called dst. */ -int -__la_link(const char *src, const char *dst) -{ - return __link(src, dst); -} - -int -__la_ftruncate(int fd, off_t length) -{ - LARGE_INTEGER distance; - HANDLE handle; - - if (fd < 0) { - errno = EBADF; - return (-1); - } - handle = (HANDLE)_get_osfhandle(fd); - if (GetFileType(handle) != FILE_TYPE_DISK) { - errno = EBADF; - return (-1); - } - distance.QuadPart = length; - if (!SetFilePointerEx(handle, distance, NULL, FILE_BEGIN)) { - la_dosmaperr(GetLastError()); - return (-1); - } - if (!SetEndOfFile(handle)) { - la_dosmaperr(GetLastError()); - return (-1); - } - return (0); -} - -#define WINTIME(sec, usec) ((Int32x32To64(sec, 10000000) + EPOC_TIME) + (usec * 10)) -static int -__hutimes(HANDLE handle, const struct __timeval *times) -{ - ULARGE_INTEGER wintm; - FILETIME fatime, fmtime; - - wintm.QuadPart = WINTIME(times[0].tv_sec, times[0].tv_usec); - fatime.dwLowDateTime = wintm.LowPart; - fatime.dwHighDateTime = wintm.HighPart; - wintm.QuadPart = WINTIME(times[1].tv_sec, times[1].tv_usec); - fmtime.dwLowDateTime = wintm.LowPart; - fmtime.dwHighDateTime = wintm.HighPart; - if (SetFileTime(handle, NULL, &fatime, &fmtime) == 0) { - errno = EINVAL; - return (-1); - } - return (0); -} - -int -__la_futimes(int fd, const struct __timeval *times) -{ - - return (__hutimes((HANDLE)_get_osfhandle(fd), times)); -} - -int -__la_utimes(const char *name, const struct __timeval *times) -{ - int ret; - HANDLE handle; - - handle = la_CreateFile(name, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (handle == INVALID_HANDLE_VALUE) { - la_dosmaperr(GetLastError()); - return (-1); - } - ret = __hutimes(handle, times); - CloseHandle(handle); - return (ret); -} - -int -__la_chdir(const char *path) -{ - wchar_t *ws; - int r; - - r = SetCurrentDirectoryA(path); - if (r == 0) { - if (GetLastError() != ERROR_FILE_NOT_FOUND) { - la_dosmaperr(GetLastError()); - return (-1); - } - } else - return (0); - ws = permissive_name(path); - if (ws == NULL) { - errno = EINVAL; - return (-1); - } - r = SetCurrentDirectoryW(ws); - free(ws); - if (r == 0) { - la_dosmaperr(GetLastError()); - return (-1); - } - return (0); -} - -int -__la_chmod(const char *path, mode_t mode) -{ - wchar_t *ws; - DWORD attr; - BOOL r; - - ws = NULL; - attr = GetFileAttributesA(path); - if (attr == (DWORD)-1) { - if (GetLastError() != ERROR_FILE_NOT_FOUND) { - la_dosmaperr(GetLastError()); - return (-1); - } - ws = permissive_name(path); - if (ws == NULL) { - errno = EINVAL; - return (-1); - } - attr = GetFileAttributesW(ws); - if (attr == (DWORD)-1) { - free(ws); - la_dosmaperr(GetLastError()); - return (-1); - } - } - if (mode & _S_IWRITE) - attr &= ~FILE_ATTRIBUTE_READONLY; - else - attr |= FILE_ATTRIBUTE_READONLY; - if (ws == NULL) - r = SetFileAttributesA(path, attr); - else { - r = SetFileAttributesW(ws, attr); - free(ws); - } - if (r == 0) { - la_dosmaperr(GetLastError()); - return (-1); - } - return (0); -} - -/* - * 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) -{ - LARGE_INTEGER distance; - LARGE_INTEGER newpointer; - HANDLE handle; - - if (fd < 0) { - errno = EBADF; - return (-1); - } - handle = (HANDLE)_get_osfhandle(fd); - if (GetFileType(handle) != FILE_TYPE_DISK) { - errno = EBADF; - return (-1); - } - distance.QuadPart = offset; - if (!SetFilePointerEx(handle, distance, &newpointer, whence)) { - DWORD lasterr; - - lasterr = GetLastError(); - if (lasterr == ERROR_BROKEN_PIPE) - return (0); - if (lasterr == ERROR_ACCESS_DENIED) - errno = EBADF; - else - la_dosmaperr(lasterr); - return (-1); - } - return (newpointer.QuadPart); -} - -int -__la_mkdir(const char *path, mode_t mode) -{ - wchar_t *ws; - int r; - - (void)mode;/* UNUSED */ - r = CreateDirectoryA(path, NULL); - if (r == 0) { - DWORD lasterr = GetLastError(); - if (lasterr != ERROR_FILENAME_EXCED_RANGE && - lasterr != ERROR_PATH_NOT_FOUND) { - la_dosmaperr(GetLastError()); - return (-1); - } - } else - return (0); - ws = permissive_name(path); - if (ws == NULL) { - errno = EINVAL; - return (-1); - } - r = CreateDirectoryW(ws, NULL); - free(ws); - if (r == 0) { - la_dosmaperr(GetLastError()); - return (-1); - } - return (0); -} - -/* Windows' mbstowcs is differrent error handling from other unix mbstowcs. - * That one is using MultiByteToWideChar function with MB_PRECOMPOSED and - * MB_ERR_INVALID_CHARS flags. - * This implements for only to pass libarchive_test. - */ -size_t -__la_mbstowcs(wchar_t *wcstr, const char *mbstr, size_t nwchars) -{ - - return (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, - mbstr, (int)strlen(mbstr), wcstr, - (int)nwchars)); -} - +/* This can exceed MAX_PATH limitation. */ int __la_open(const char *path, int flags, ...) { @@ -628,7 +254,7 @@ __la_open(const char *path, int flags, ...) */ attr = GetFileAttributesA(path); if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) { - ws = permissive_name(path); + ws = __la_win_permissive_name(path); if (ws == NULL) { errno = EINVAL; return (-1); @@ -673,7 +299,7 @@ __la_open(const char *path, int flags, ...) r = _open(path, flags, pmode); #endif if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { - /* simular other POSIX system action to pass a test */ + /* Simulate other POSIX system action to pass our test suite. */ attr = GetFileAttributesA(path); if (attr == (DWORD)-1) la_dosmaperr(GetLastError()); @@ -685,7 +311,7 @@ __la_open(const char *path, int flags, ...) } if (r >= 0 || errno != ENOENT) return (r); - ws = permissive_name(path); + ws = __la_win_permissive_name(path); if (ws == NULL) { errno = EINVAL; return (-1); @@ -693,7 +319,7 @@ __la_open(const char *path, int flags, ...) } r = _wopen(ws, flags, pmode); if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { - /* simular other POSIX system action to pass a test */ + /* Simulate other POSIX system action to pass our test suite. */ attr = GetFileAttributesW(ws); if (attr == (DWORD)-1) la_dosmaperr(GetLastError()); @@ -721,23 +347,11 @@ __la_read(int fd, void *buf, size_t nbytes) errno = EBADF; return (-1); } + /* Do not pass 0 to third parameter of ReadFile(), read bytes. + * This will not return to application side. */ + if (nbytes == 0) + return (0); 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) { @@ -757,26 +371,6 @@ __la_read(int fd, void *buf, size_t nbytes) return ((ssize_t)bytes_read); } -/* Remove directory */ -int -__la_rmdir(const char *path) -{ - wchar_t *ws; - int r; - - r = _rmdir(path); - if (r >= 0 || errno != ENOENT) - return (r); - ws = permissive_name(path); - if (ws == NULL) { - errno = EINVAL; - return (-1); - } - r = _wrmdir(ws); - free(ws); - return (r); -} - /* Convert Windows FILETIME to UTC */ __inline static void fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns) @@ -796,9 +390,9 @@ fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns) } /* Stat by handle - * Windows' stat() does not accept path which is added "\\?\" especially "?" + * Windows' stat() does not accept the path added "\\?\" especially "?" * character. - * It means we cannot access a long name path(which is longer than MAX_PATH). + * It means we cannot access the long name path longer than MAX_PATH. * So I've implemented simular Windows' stat() to access the long name path. * And I've added some feature. * 1. set st_ino by nFileIndexHigh and nFileIndexLow of @@ -887,7 +481,7 @@ __hstat(HANDLE handle, struct ustat *st) st->st_nlink = 1; st->st_dev = 0; #else - /* Getting FileIndex as i-node. We have to remove a sequence which + /* Getting FileIndex as i-node. We should remove a sequence which * is high-16-bits of nFileIndexHigh. */ ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL; ino64.LowPart = info.nFileIndexLow; @@ -919,6 +513,11 @@ copy_stat(struct stat *st, struct ustat *us) st->st_rdev = us->st_rdev; } +/* + * TODO: Remove a use of __la_fstat and __la_stat. + * We should use GetFileInformationByHandle in place + * where We still use the *stat functions. + */ int __la_fstat(int fd, struct stat *st) { @@ -940,6 +539,7 @@ __la_fstat(int fd, struct stat *st) return (ret); } +/* This can exceed MAX_PATH limitation. */ int __la_stat(const char *path, struct stat *st) { @@ -948,7 +548,7 @@ __la_stat(const char *path, struct stat *st) int ret; handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, + FILE_FLAG_BACKUP_SEMANTICS, NULL); if (handle == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); @@ -977,27 +577,8 @@ __la_stat(const char *path, struct stat *st) return (ret); } -int -__la_unlink(const char *path) -{ - wchar_t *ws; - int r; - - r = _unlink(path); - if (r >= 0 || errno != ENOENT) - return (r); - ws = permissive_name(path); - if (ws == NULL) { - errno = EINVAL; - return (-1); - } - r = _wunlink(ws); - free(ws); - return (r); -} - /* - * This waitpid is limited implemention. + * This waitpid is limited implementation. */ pid_t __la_waitpid(pid_t wpid, int *status, int option) @@ -1006,6 +587,7 @@ __la_waitpid(pid_t wpid, int *status, int option) DWORD cs, ret; (void)option;/* UNUSED */ + *status = 0; child = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, wpid); if (child == NULL) { la_dosmaperr(GetLastError()); @@ -1152,8 +734,8 @@ static const struct { { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } }; -static void -la_dosmaperr(unsigned long e) +void +__la_dosmaperr(unsigned long e) { int i; @@ -1177,60 +759,4 @@ la_dosmaperr(unsigned long e) return; } -#if defined(ARCHIVE_HASH_MD5_WIN) ||\ - defined(ARCHIVE_HASH_SHA1_WIN) || defined(ARCHIVE_HASH_SHA256_WIN) ||\ - defined(ARCHIVE_HASH_SHA384_WIN) || defined(ARCHIVE_HASH_SHA512_WIN) -/* - * Message digest functions. - */ -void -__la_hash_Init(Digest_CTX *ctx, ALG_ID algId) -{ - - ctx->valid = 0; - if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL, - PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - if (GetLastError() != (DWORD)NTE_BAD_KEYSET) - return; - if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL, - PROV_RSA_FULL, CRYPT_NEWKEYSET)) - return; - } - - if (!CryptCreateHash(ctx->cryptProv, algId, 0, 0, &ctx->hash)) { - CryptReleaseContext(ctx->cryptProv, 0); - return; - } - - ctx->valid = 1; -} - -void -__la_hash_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len) -{ - - if (!ctx->valid) - return; - - CryptHashData(ctx->hash, - (unsigned char *)(uintptr_t)buf, - (DWORD)len, 0); -} - -void -__la_hash_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx) -{ - DWORD siglen = bufsize; - - if (!ctx->valid) - return; - - CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0); - CryptDestroyHash(ctx->hash); - CryptReleaseContext(ctx->cryptProv, 0); - ctx->valid = 0; -} - -#endif /* defined(ARCHIVE_HASH_*_WIN) */ - #endif /* _WIN32 && !__CYGWIN__ */ |