From: Michihiro NAKAJIMA Date: Wed, 25 Mar 2009 09:14:53 +0000 (-0400) Subject: Revert r838,r839 and r840. X-Git-Tag: v2.7.0~92 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=926d6bcbadc8efa64484e57f83fb7e0d9ab4a33a;p=thirdparty%2Flibarchive.git Revert r838,r839 and r840. SVN-Revision: 842 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b6ffa86e..646f4f44c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,11 @@ OPTION(ENABLE_TEST "Enable unit and regression tests" ON) IF(ENABLE_TEST) ENABLE_TESTING() ENDIF(ENABLE_TEST) +IF(WIN32 AND NOT CYGWIN) + # Currently, dynamic build only. + SET(ENABLE_TAR_SHARED ON) + SET(ENABLE_CPIO_SHARED ON) +ENDIF(WIN32 AND NOT CYGWIN) # INCLUDE(CheckFileOffsetBits) diff --git a/Makefile.am b/Makefile.am index a6fecb6c1..4cde47ea3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -342,8 +342,7 @@ bsdtar_SOURCES= \ if INC_WINDOWS_FILES bsdtar_SOURCES+= \ tar/bsdtar_windows.h \ - tar/bsdtar_windows.c \ - libarchive/archive_windows.c + tar/bsdtar_windows.c endif if INC_CYGWIN_FILES bsdtar_SOURCES+= \ @@ -446,8 +445,7 @@ bsdcpio_SOURCES= \ if INC_WINDOWS_FILES bsdcpio_SOURCES+= \ cpio/cpio_windows.h \ - cpio/cpio_windows.c \ - libarchive/archive_windows.c + cpio/cpio_windows.c endif if INC_CYGWIN_FILES bsdcpio_SOURCES+= \ diff --git a/cpio/CMakeLists.txt b/cpio/CMakeLists.txt index fe5b13f2e..4744ba142 100644 --- a/cpio/CMakeLists.txt +++ b/cpio/CMakeLists.txt @@ -26,15 +26,10 @@ IF(ENABLE_CPIO) # Register target # ADD_EXECUTABLE(bsdcpio ${bsdcpio_SOURCES}) - IF(WIN32 AND NOT CYGWIN) - ADD_DEPENDENCIES(bsdcpio archive_windows_static) - ENDIF(WIN32 AND NOT CYGWIN) IF(ENABLE_CPIO_SHARED) TARGET_LINK_LIBRARIES(bsdcpio archive ${ADDITIONAL_LIBS}) ELSE(ENABLE_CPIO_SHARED) TARGET_LINK_LIBRARIES(bsdcpio archive_static ${ADDITIONAL_LIBS}) - SET_TARGET_PROPERTIES(bsdcpio PROPERTIES COMPILE_DEFINITIONS - LIBARCHIVE_STATIC) ENDIF(ENABLE_CPIO_SHARED) IF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(bsdcpio PROPERTIES diff --git a/cpio/cpio_cygwin.c b/cpio/cpio_cygwin.c index 2c8d072bc..f2157c55f 100644 --- a/cpio/cpio_cygwin.c +++ b/cpio/cpio_cygwin.c @@ -42,6 +42,7 @@ #include "cpio.h" +#ifndef LIST_H static int _is_privileged(HANDLE thandle, const char *sidlist[]) { @@ -133,4 +134,6 @@ bsdcpio_is_privileged() return (ret); } +#endif /* LIST_H */ + #endif diff --git a/cpio/cpio_windows.c b/cpio/cpio_windows.c index 25c680de2..ea67d9867 100644 --- a/cpio/cpio_windows.c +++ b/cpio/cpio_windows.c @@ -42,12 +42,946 @@ #include "cpio.h" +#define EPOC_TIME (116444736000000000ULL) + +struct ustat { + int64_t st_atime; + uint32_t st_atime_nsec; + int64_t st_ctime; + uint32_t st_ctime_nsec; + int64_t st_mtime; + uint32_t st_mtime_nsec; + gid_t st_gid; + /* 64bits ino */ + int64_t st_ino; + mode_t st_mode; + uint32_t st_nlink; + uint64_t st_size; + uid_t st_uid; + dev_t st_dev; + dev_t st_rdev; +}; + +/* Transform 64-bits ino into 32-bits by hashing. + * You do not forget that really unique number size is 64-bits. + */ +#define INOSIZE (8*sizeof(ino_t)) /* 32 */ +static __inline ino_t +getino(struct ustat *ub) +{ + ULARGE_INTEGER ino64; + + ino64.QuadPart = ub->st_ino; + /* I don't know this hashing is correct way */ + return (ino64.LowPart ^ (ino64.LowPart >> INOSIZE)); +} + +/* + * Prepend "\\?\" to the path name and convert it to unicode to permit + * an extended-length path for a maximum total path length of 32767 + * characters. + * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx + */ +static wchar_t * +permissive_name(const char *name) +{ + wchar_t *wn, *wnp; + wchar_t *ws, *wsp; + size_t l, len, slen; + int unc; + + len = strlen(name); + wn = malloc((len + 1) * sizeof(wchar_t)); + if (wn == NULL) + return (NULL); + l = MultiByteToWideChar(CP_ACP, 0, name, len, wn, len); + if (l == 0) { + free(wn); + return (NULL); + } + wn[l] = L'\0'; + + /* Get a full path names */ + l = GetFullPathNameW(wn, 0, NULL, NULL); + if (l == 0) { + free(wn); + return (NULL); + } + wnp = malloc(l * sizeof(wchar_t)); + if (wnp == NULL) { + free(wn); + return (NULL); + } + len = GetFullPathNameW(wn, l, wnp, NULL); + free(wn); + wn = wnp; + + if (wnp[0] == L'\\' && wnp[1] == L'\\' && + wnp[2] == L'?' && wnp[3] == L'\\') + /* We have already permissive names. */ + return (wn); + + if (wnp[0] == L'\\' && wnp[1] == L'\\' && + wnp[2] == L'.' && wnp[3] == L'\\') { + /* Device names */ + 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. */ + return (wn); + } + + unc = 0; + if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') { + wchar_t *p = &wnp[2]; + + /* Skip server-name letters. */ + while (*p != L'\\' && *p != L'\0') + ++p; + if (*p == L'\\') { + wchar_t *rp = ++p; + /* Skip share-name letters. */ + while (*p != L'\\' && *p != L'\0') + ++p; + if (*p == L'\\' && p != rp) { + /* Now, match patterns such as + * "\\server-name\share-name\" */ + wnp += 2; + len -= 2; + unc = 1; + } + } + } + + slen = 4 + (unc * 4) + len + 1; + ws = wsp = malloc(slen * sizeof(wchar_t)); + if (ws == NULL) { + free(wn); + return (NULL); + } + /* prepend "\\?\" */ + wcsncpy(wsp, L"\\\\?\\", 4); + wsp += 4; + slen -= 4; + if (unc) { + /* append "UNC\" ---> "\\?\UNC\" */ + wcsncpy(wsp, L"UNC\\", 4); + wsp += 4; + slen -= 4; + } + wcsncpy_s(wsp, slen, wnp, _TRUNCATE); + free(wn); + return (ws); +} + +static HANDLE +la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) +{ + wchar_t *wpath; + HANDLE handle; + + handle = CreateFileA(path, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile); + if (handle != INVALID_HANDLE_VALUE) + return (handle); + if (GetLastError() != ERROR_PATH_NOT_FOUND) + return (handle); + wpath = permissive_name(path); + if (wpath == NULL) + return (handle); + handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile); + free(wpath); + return (handle); +} + +static size_t +wequallen(const wchar_t *s1, const wchar_t *s2) +{ + size_t i = 0; + + while (*s1 != L'\0' && *s2 != L'\0' && *s1 == *s2) { + ++s1; ++s2; ++i; + } + return (i); +} + +/* Check that path1 and path2 can be hard-linked by each other. + * Both arguments must be made by permissive_name function. + */ +static int +canHardLinkW(const wchar_t *path1, const wchar_t *path2) +{ + wchar_t root[MAX_PATH]; + wchar_t fs[32]; + const wchar_t *s; + int r; + + r = wequallen(path1, path2); + /* Is volume-name the same? */ + if (r < 7) + return (0); + if (wcsncmp(path1, L"\\\\?\\UNC\\", 8) == 0) { + int len; + + s = path1 + 8; + if (*s == L'\\') + return (0); + /* 012345678 + * Name : "\\?\UNC\Server\Share\" + * ^ search + */ + s = wcschr(++s, L'\\'); + if (s == NULL) + return (0); + if (*++s == L'\\') + return (0); + /* 012345678 + * Name : "\\?\UNC\Server\Share\" + * ^ search + */ + s = wcschr(++s, L'\\'); + if (s == NULL) + return (0); + s++; + /* 012345678 + * Name : "\\?\UNC\Server\Share\xxxx" + * ^--- len ----^ + */ + len = (int)(s - path1 - 8); + /* Is volume-name the same? */ + if (r < len + 8) + return (0); + /* Is volume-name too long? */ + if (sizeof(root) -3 < len) + return (0); + root[0] = root[1] = L'\\'; + wcsncpy(root + 2, path1 + 8 , len); + /* root : "\\Server\Share\" */ + root[2 + len] = L'\0'; + } else if (wcsncmp(path1, L"\\\\?\\", 4) == 0) { + s = path1 + 4; + if ((!iswalpha(*s)) || s[1] != L':' || s[2] != L'\\') + return (0); + wcsncpy(root, path1 + 4, 3); + root[3] = L'\0'; + } else + return (0); + if (!GetVolumeInformationW(root, NULL, 0, NULL, NULL, NULL, fs, sizeof(fs))) + return (0); + if (wcscmp(fs, L"NTFS") == 0) + return (1); + else + return (0); +} + +/* Make a link to src called dst. */ +static int +__link(const char *src, const char *dst, int sym) +{ + 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) { + if (wsrc != NULL) + free(wsrc); + if (wdst != NULL) + free(wdst); + set_errno (EINVAL); + return -1; + } + + if ((attr = GetFileAttributesW(wsrc)) != -1) { + if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + errno = EPERM; + retval = -1; + goto exit; + } + if (!sym && canHardLinkW(wsrc, wdst)) + res = CreateHardLinkW(wdst, wsrc, NULL); + else + res = CopyFileW(wsrc, wdst, FALSE); + } 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 = wcslen(wsrc); + slen = strlen(src); + n = MultiByteToWideChar(CP_ACP, 0, src, slen, wsrc, slen); + 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 == -1 || (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + if (attr == -1) + _dosmaperr(GetLastError()); + else + errno = EPERM; + free (wnewsrc); + retval = -1; + goto exit; + } + if (!sym && canHardLinkW(wnewsrc, wdst)) + res = CreateHardLinkW(wdst, wnewsrc, NULL); + else + res = CopyFileW(wnewsrc, wdst, FALSE); + free (wnewsrc); + } + if (res == 0) { + _dosmaperr(GetLastError()); + retval = -1; + } else + retval = 0; +exit: + free(wsrc); + free(wdst); + return (retval); +} + +/* Make a hard link to src called dst. */ +int +link(const char *src, const char *dst) +{ + return __link (src, dst, 0); +} + +/* Make a symbolic link to FROM called TO. */ +int symlink (from, to) + const char *from; + const char *to; +{ + return __link (from, to, 1); +} + +unsigned int +sleep(unsigned int seconds) +{ + Sleep(seconds * 1000); + 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 +futimes(int fd, const struct __timeval *times) +{ + + return (__hutimes((HANDLE)_get_osfhandle(fd), times)); +} + +int +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) { + _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) { + _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) { + _dosmaperr(GetLastError()); + return (-1); + } + return (0); +} + +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) { + _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) { + _dosmaperr(GetLastError()); + return (-1); + } + return (0); +} + +int +la_open(const char *path, int flags, ...) +{ + va_list ap; + wchar_t *ws; + int r, pmode; + DWORD attr; + + va_start(ap, flags); + pmode = va_arg(ap, int); + va_end(ap); + ws = NULL; + if ((flags & ~O_BINARY) == O_RDONLY) { + /* + * When we open a directory, _open function returns + * "Permission denied" error. + */ + attr = GetFileAttributesA(path); + if (attr == -1 && GetLastError() == ERROR_PATH_NOT_FOUND) { + ws = permissive_name(path); + if (ws == NULL) { + errno = EINVAL; + return (-1); + } + attr = GetFileAttributesW(ws); + } + if (attr == -1) { + _dosmaperr(GetLastError()); + free(ws); + return (-1); + } + if (attr & FILE_ATTRIBUTE_DIRECTORY) { + HANDLE handle; + + if (ws != NULL) + handle = CreateFileW(ws, 0, 0, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_ATTRIBUTE_READONLY, + NULL); + else + handle = CreateFileA(path, 0, 0, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_ATTRIBUTE_READONLY, + NULL); + free(ws); + if (handle == INVALID_HANDLE_VALUE) { + _dosmaperr(GetLastError()); + return (-1); + } + r = _open_osfhandle((intptr_t)handle, _O_RDONLY); + return (r); + } + } + if (ws == NULL) { + r = _open(path, flags, pmode); + if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { + /* simular other POSIX system action to pass a test */ + attr = GetFileAttributesA(path); + if (attr == -1) + _dosmaperr(GetLastError()); + else if (attr & FILE_ATTRIBUTE_DIRECTORY) + errno = EISDIR; + else + errno = EACCES; + return (-1); + } + if (r >= 0 || errno != ENOENT) + return (r); + ws = permissive_name(path); + if (ws == NULL) { + errno = EINVAL; + return (-1); + } + } + r = _wopen(ws, flags, pmode); + if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { + /* simular other POSIX system action to pass a test */ + attr = GetFileAttributesW(ws); + if (attr == -1) + _dosmaperr(GetLastError()); + else if (attr & FILE_ATTRIBUTE_DIRECTORY) + errno = EISDIR; + else + errno = EACCES; + } + free(ws); + return (r); +} + +ssize_t +la_read(int fd, void *buf, size_t nbytes) +{ + HANDLE handle; + DWORD bytes_read, lasterr; + int r; + +#ifdef _WIN64 + if (nbytes > UINT32_MAX) + nbytes = UINT32_MAX; +#endif + if (fd < 0) { + errno = EBADF; + return (-1); + } + 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) + errno = EBADF; + else + _dosmaperr(lasterr); + return (-1); + } + 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) +{ + ULARGE_INTEGER utc; + + utc.HighPart = filetime->dwHighDateTime; + utc.LowPart = filetime->dwLowDateTime; + if (utc.QuadPart >= EPOC_TIME) { + utc.QuadPart -= EPOC_TIME; + *time = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */ + *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */ + } else { + *time = 0; + *ns = 0; + } +} + +/* Stat by handle + * Windows' stat() does not accept path which is added "\\?\" especially "?" + * character. + * It means we cannot access a long name path(which is 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 + * BY_HANDLE_FILE_INFORMATION. + * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION. + * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION. + */ +static int +__hstat(HANDLE handle, struct ustat *st) +{ + BY_HANDLE_FILE_INFORMATION info; + ULARGE_INTEGER ino64; + DWORD ftype; + mode_t mode; + time_t time; + long ns; + + switch (ftype = GetFileType(handle)) { + case FILE_TYPE_UNKNOWN: + errno = EBADF; + return (-1); + case FILE_TYPE_CHAR: + case FILE_TYPE_PIPE: + if (ftype == FILE_TYPE_CHAR) { + st->st_mode = S_IFCHR; + st->st_size = 0; + } else { + DWORD avail; + + st->st_mode = S_IFIFO; + if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL)) + st->st_size = avail; + else + st->st_size = 0; + } + st->st_atime = 0; + st->st_atime_nsec = 0; + st->st_mtime = 0; + st->st_mtime_nsec = 0; + st->st_ctime = 0; + st->st_ctime_nsec = 0; + st->st_ino = 0; + st->st_nlink = 1; + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + st->st_dev = 0; + return (0); + case FILE_TYPE_DISK: + break; + default: + /* This ftype is undocumented type. */ + _dosmaperr(GetLastError()); + return (-1); + } + + ZeroMemory(&info, sizeof(info)); + if (!GetFileInformationByHandle (handle, &info)) { + _dosmaperr(GetLastError()); + return (-1); + } + + mode = S_IRUSR | S_IRGRP | S_IROTH; + if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + else + mode |= S_IFREG; + st->st_mode = mode; + + fileTimeToUTC(&info.ftLastAccessTime, &time, &ns); + st->st_atime = time; + st->st_atime_nsec = ns; + fileTimeToUTC(&info.ftLastWriteTime, &time, &ns); + st->st_mtime = time; + st->st_mtime_nsec = ns; + fileTimeToUTC(&info.ftCreationTime, &time, &ns); + st->st_ctime = time; + st->st_ctime_nsec = ns; + st->st_size = + ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1)) + + (int64_t)(info.nFileSizeLow); +#ifdef SIMULATE_WIN_STAT + st->st_ino = 0; + st->st_nlink = 1; + st->st_dev = 0; +#else + /* Getting FileIndex as i-node. We have to remove a sequence which + * is high-16-bits of nFileIndexHigh. */ + ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL; + ino64.LowPart = info.nFileIndexLow; + st->st_ino = ino64.QuadPart; + st->st_nlink = info.nNumberOfLinks; + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ++st->st_nlink;/* Add parent directory. */ + st->st_dev = info.dwVolumeSerialNumber; +#endif + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + return (0); +} + +static void +copy_stat(struct stat *st, struct ustat *us) +{ + st->st_atime = us->st_atime; + st->st_ctime = us->st_ctime; + st->st_mtime = us->st_mtime; + st->st_gid = us->st_gid; + st->st_ino = getino(us); + st->st_mode = us->st_mode; + st->st_nlink = us->st_nlink; + st->st_size = us->st_size; + st->st_uid = us->st_uid; + st->st_dev = us->st_dev; + st->st_rdev = us->st_rdev; +} + +int +la_fstat(int fd, struct stat *st) +{ + struct ustat u; + int ret; + + if (fd < 0) { + errno = EBADF; + return (-1); + } + ret = __hstat((HANDLE)_get_osfhandle(fd), &u); + if (ret >= 0) { + copy_stat(st, &u); + if (u.st_mode & (S_IFCHR | S_IFIFO)) { + st->st_dev = fd; + st->st_rdev = fd; + } + } + return (ret); +} + +int +la_stat(const char *path, struct stat *st) +{ + HANDLE handle; + struct ustat u; + int ret; + + handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + _dosmaperr(GetLastError()); + return (-1); + } + ret = __hstat(handle, &u); + CloseHandle(handle); + if (ret >= 0) { + char *p; + + copy_stat(st, &u); + p = strrchr(path, '.'); + if (p != NULL && strlen(p) == 4) { + char exttype[4]; + + ++ p; + exttype[0] = toupper(*p++); + exttype[1] = toupper(*p++); + exttype[2] = toupper(*p++); + exttype[3] = '\0'; + if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") || + !strcmp(exttype, "BAT") || !strcmp(exttype, "COM")) + st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; + } + } + return (ret); +} + +ssize_t +la_write(int fd, const void *buf, size_t nbytes) +{ + uint32_t bytes_written; + +#ifdef _WIN64 + if (nbytes > UINT32_MAX) + nbytes = UINT32_MAX; +#endif + if (fd < 0) { + errno = EBADF; + return (-1); + } + if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes, + &bytes_written, NULL)) { + DWORD lasterr; + + lasterr = GetLastError(); + if (lasterr == ERROR_ACCESS_DENIED) + errno = EBADF; + else + _dosmaperr(lasterr); + return (-1); + } + return (bytes_written); +} + +#ifndef LIST_H +static int +_is_privileged(HANDLE thandle, const char *sidlist[]) +{ + TOKEN_USER *tuser; + TOKEN_GROUPS *tgrp; + DWORD bytes; + PSID psid; + DWORD i, g; + int member; + + psid = NULL; + tuser = NULL; + tgrp = NULL; + member = 0; + for (i = 0; sidlist[i] != NULL && member == 0; i++) { + if (psid != NULL) + LocalFree(psid); + if (ConvertStringSidToSidA(sidlist[i], &psid) == 0) { + errno = EPERM; + return (-1); + } + if (tuser == NULL) { + GetTokenInformation(thandle, TokenUser, NULL, 0, &bytes); + tuser = malloc(bytes); + if (tuser == NULL) { + errno = ENOMEM; + member = -1; + break; + } + if (GetTokenInformation(thandle, TokenUser, tuser, bytes, &bytes) == 0) { + errno = EPERM; + member = -1; + break; + } + } + member = EqualSid(tuser->User.Sid, psid); + if (member) + break; + if (tgrp == NULL) { + GetTokenInformation(thandle, TokenGroups, NULL, 0, &bytes); + tgrp = malloc(bytes); + if (tgrp == NULL) { + errno = ENOMEM; + member = -1; + break; + } + if (GetTokenInformation(thandle, TokenGroups, tgrp, bytes, &bytes) == 0) { + errno = EPERM; + member = -1; + break; + } + } + for (g = 0; g < tgrp->GroupCount; g++) { + member = EqualSid(tgrp->Groups[g].Sid, psid); + if (member) + break; + } + } + LocalFree(psid); + free(tuser); + free(tgrp); + + return (member); +} + int bsdcpio_is_privileged() { + HANDLE thandle; int ret; + const char *sidlist[] = { + "S-1-5-32-544", /* Administrators */ + "S-1-5-32-551", /* Backup Operators */ + NULL + }; - ret = la_is_privileged(); + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &thandle) == 0) { + cpio_warnc(EPERM, "Failed to check privilege"); + return (0); + } + ret = _is_privileged(thandle, sidlist); if (ret < 0) { cpio_warnc(errno, "Failed to check privilege"); return (0); @@ -55,4 +989,6 @@ bsdcpio_is_privileged() return (ret); } +#endif /* LIST_H */ + #endif diff --git a/cpio/cpio_windows.h b/cpio/cpio_windows.h index 8c9395d07..5527dbcc1 100644 --- a/cpio/cpio_windows.h +++ b/cpio/cpio_windows.h @@ -51,6 +51,7 @@ struct group { extern "C" { #endif +extern unsigned int sleep(unsigned int seconds); extern int bsdcpio_is_privileged(); #ifdef __cplusplus diff --git a/cpio/test/CMakeLists.txt b/cpio/test/CMakeLists.txt index 59a89d59f..56c484cb4 100644 --- a/cpio/test/CMakeLists.txt +++ b/cpio/test/CMakeLists.txt @@ -33,6 +33,10 @@ IF(ENABLE_CPIO AND ENABLE_TEST) test_passthrough_reverse.c test_pathmatch.c ) + IF(WIN32 AND NOT CYGWIN) + LIST(APPEND bsdcpio_test_SOURCES ../cpio_windows.c) + LIST(APPEND bsdcpio_test_SOURCES ../cpio_windows.h) + ENDIF(WIN32 AND NOT CYGWIN) # # Generate the list.h @@ -45,9 +49,7 @@ IF(ENABLE_CPIO AND ENABLE_TEST) # Register target # ADD_EXECUTABLE(bsdcpio_test ${bsdcpio_test_SOURCES}) - IF(WIN32 AND NOT CYGWIN) - ADD_DEPENDENCIES(bsdcpio_test archive_windows_static) - ENDIF(WIN32 AND NOT CYGWIN) + SET_PROPERTY(TARGET bsdcpio_test PROPERTY COMPILE_DEFINITIONS LIST_H) SET(num 0) FOREACH(test ${bsdcpio_test_SOURCES}) IF(test MATCHES "^test_[^/]+[.]c$") diff --git a/libarchive/CMakeLists.txt b/libarchive/CMakeLists.txt index 36b52ab09..0c2eee18f 100644 --- a/libarchive/CMakeLists.txt +++ b/libarchive/CMakeLists.txt @@ -1,22 +1,3 @@ -############################################ -# -# How to build libarchive_windows_static -# -# This library is internal library and is used for libarchive programs -# on Windows platform only. -# We don't install this one anywhere. -# -############################################ -IF(WIN32 AND NOT CYGWIN) - SET(libarchive_windows_SOURCES - archive_windows.c - archive_windows.h - ) - # - # Register target - # - ADD_LIBRARY(archive_windows_static STATIC ${libarchive_windows_SOURCES}) -ENDIF(WIN32 AND NOT CYGWIN) ############################################ # @@ -116,6 +97,8 @@ SET(libarchive_MANS ) IF(WIN32 AND NOT CYGWIN) + LIST(APPEND libarchive_SOURCES archive_windows.c) + LIST(APPEND libarchive_SOURCES archive_windows.h) LIST(APPEND libarchive_SOURCES filter_fork_windows.c) ENDIF(WIN32 AND NOT CYGWIN) @@ -126,17 +109,10 @@ ENDIF(WIN32 AND NOT CYGWIN) # Libarchive is a library ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS}) TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS}) -IF(WIN32 AND NOT CYGWIN) - ADD_DEPENDENCIES(archive archive_windows_static) -ENDIF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(archive PROPERTIES SOVERSION ${SOVERSION}) SET_TARGET_PROPERTIES(archive PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) ADD_LIBRARY(archive_static STATIC ${libarchive_SOURCES} ${include_HEADERS}) -TARGET_LINK_LIBRARIES(archive_static ${ADDITIONAL_LIBS}) -IF(WIN32 AND NOT CYGWIN) - ADD_DEPENDENCIES(archive_static archive_windows_static) -ENDIF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(archive_static PROPERTIES COMPILE_DEFINITIONS LIBARCHIVE_STATIC) SET_TARGET_PROPERTIES(archive_static PROPERTIES diff --git a/libarchive/archive_windows.c b/libarchive/archive_windows.c index 13104ec05..378232f75 100644 --- a/libarchive/archive_windows.c +++ b/libarchive/archive_windows.c @@ -48,12 +48,7 @@ #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 -#if defined(HAVE_CONFIG_H) -#include "config.h" -#else -/* Warn if the library hasn't been (automatically or manually) configured. */ -#error Oops: No config.h and no pre-built configuration in archive_platform.h. -#endif +#include "archive_platform.h" #include #include #include @@ -62,7 +57,6 @@ #include #include #include -#include #define EPOC_TIME (116444736000000000ULL) @@ -84,14 +78,6 @@ struct ustat { dev_t st_rdev; }; -struct __DIR { - HANDLE handle; - WIN32_FIND_DATAW fileData; - struct direct de; - int first; - BOOL finished; -}; - /* Transform 64-bits ino into 32-bits by hashing. * You do not forget that really unique number size is 64-bits. */ @@ -502,117 +488,6 @@ utimes(const char *name, const struct __timeval *times) return (ret); } -static DIR * -__opendir(const char *path, int ff) -{ - DIR *dir; - wchar_t *wpath, *wfname; - size_t wlen; - - dir = malloc(sizeof(*dir)); - if (dir == NULL) { - errno = ENOMEM; - return (NULL); - } - - wpath = permissive_name(path); - if (wpath == NULL) { - errno = EINVAL; - free(dir); - return (NULL); - } - if (ff) { - wfname = wpath; - wpath = NULL; - } else { - wlen = wcslen(wpath); - wfname = malloc((wlen + 3) * sizeof(wchar_t)); - if (wfname == NULL) { - errno = ENOMEM; - free(dir); - free(wpath); - return (NULL); - } - wcscpy(wfname, wpath); - wcscat(wfname, L"\\*"); - free(wpath); - } - - dir->handle = FindFirstFileW(wfname, &dir->fileData); - if (dir->handle == INVALID_HANDLE_VALUE) { - _dosmaperr(GetLastError()); - free(dir); - free(wfname); - return (NULL); - } - dir->first = 1; - dir->finished = FALSE; - free(wfname); - - return (dir); -} - -DIR * -opendir_findfile(const char *path) -{ - return (__opendir(path, 1)); -} - -DIR * -opendir(const char *path) -{ - return (__opendir(path, 0)); -} - -struct direct * -readdir(DIR *dirp) -{ - size_t len; - - while (!dirp->finished) { - if (!dirp->first && !FindNextFileW(dirp->handle, &dirp->fileData)) { - if (GetLastError() != ERROR_NO_MORE_FILES) - _dosmaperr(GetLastError()); - dirp->finished = TRUE; - break; - } - dirp->first = 0; - len = wcstombs(dirp->de.d_name, dirp->fileData.cFileName, - sizeof(dirp->de.d_name) -1); - if (len == -1) { - errno = EINVAL; - dirp->finished = TRUE; - break; - } - dirp->de.d_name[len] = '\0'; - dirp->de.d_nameln = strlen(dirp->de.d_name); - return (&dirp->de); - } - - return (NULL); -} - -int -closedir(DIR *dirp) -{ - BOOL ret; - - ret = FindClose(dirp->handle); - free(dirp); - if (ret == 0) { - _dosmaperr(GetLastError()); - return (-1); - } - return (0); -} - -unsigned int -sleep(unsigned int seconds) -{ - Sleep(seconds * 1000); - return (0); -} - int la_chdir(const char *path) { @@ -1299,95 +1174,4 @@ DIGEST_FINAL(SHA512, SHA384_DIGEST_LENGTH) #endif /* !HAVE_OPENSSL_MD5_H && !HAVE_OPENSSL_SHA_H */ -static int -_is_privileged(HANDLE thandle, const char *sidlist[]) -{ - TOKEN_USER *tuser; - TOKEN_GROUPS *tgrp; - DWORD bytes; - PSID psid; - DWORD i, g; - int member; - - psid = NULL; - tuser = NULL; - tgrp = NULL; - member = 0; - for (i = 0; sidlist[i] != NULL && member == 0; i++) { - if (psid != NULL) - LocalFree(psid); - if (ConvertStringSidToSidA(sidlist[i], &psid) == 0) { - errno = EPERM; - return (-1); - } - if (tuser == NULL) { - GetTokenInformation(thandle, TokenUser, NULL, 0, - &bytes); - tuser = malloc(bytes); - if (tuser == NULL) { - errno = ENOMEM; - member = -1; - break; - } - if (GetTokenInformation(thandle, TokenUser, tuser, - bytes, &bytes) == 0) { - errno = EPERM; - member = -1; - break; - } - } - member = EqualSid(tuser->User.Sid, psid); - if (member) - break; - if (tgrp == NULL) { - GetTokenInformation(thandle, TokenGroups, NULL, 0, - &bytes); - tgrp = malloc(bytes); - if (tgrp == NULL) { - errno = ENOMEM; - member = -1; - break; - } - if (GetTokenInformation(thandle, TokenGroups, tgrp, - bytes, &bytes) == 0) { - errno = EPERM; - member = -1; - break; - } - } - for (g = 0; g < tgrp->GroupCount; g++) { - member = EqualSid(tgrp->Groups[g].Sid, psid); - if (member) - break; - } - } - LocalFree(psid); - free(tuser); - free(tgrp); - - return (member); -} - -int -la_is_privileged() -{ - HANDLE thandle; - int ret; - const char *sidlist[] = { - "S-1-5-32-544", /* Administrators */ - "S-1-5-32-551", /* Backup Operators */ - NULL - }; - - if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &thandle) == 0) { - errno = EPERM; - return (-1); - } - ret = _is_privileged(thandle, sidlist); - if (ret < 0) { - return (-1); - } - return (ret); -} - #endif /* _WIN32 && !__CYGWIN__ */ diff --git a/libarchive/archive_windows.h b/libarchive/archive_windows.h index 032c4be38..d3369013e 100644 --- a/libarchive/archive_windows.h +++ b/libarchive/archive_windows.h @@ -297,13 +297,6 @@ typedef struct { #endif #endif /* HAVE_OPENSSL_SHA_H */ -struct __DIR; -typedef struct __DIR DIR; -struct direct { - unsigned char d_nameln; - char d_name[MAX_PATH]; -}; - /* End of Win32 definitions. */ #ifdef __cplusplus @@ -316,11 +309,6 @@ extern int symlink (const char *from, const char *to); extern int ftruncate(int fd, off_t length); extern int futimes(int fd, const struct __timeval *times); extern int utimes(const char *name, const struct __timeval *times); -extern DIR *opendir_findfile(const char *path); -extern DIR *opendir(const char *path); -extern struct direct *readdir(DIR *dirp); -extern int closedir(DIR *dirp); -extern unsigned int sleep(unsigned int seconds); /* Replacement POSIX function */ extern int la_chdir(const char *path); @@ -388,9 +376,6 @@ extern void SHA512_Final(unsigned char buf[SHA512_DIGEST_LENGTH], #endif #endif -/* */ -extern int la_is_privileged(); - #ifdef __cplusplus } #endif diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index 2cb50d2c4..6d4e6a3af 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -103,11 +103,8 @@ IF(ENABLE_TEST) # ADD_EXECUTABLE(libarchive_test ${libarchive_test_SOURCES}) TARGET_LINK_LIBRARIES(libarchive_test ${ADDITIONAL_LIBS}) - IF(WIN32 AND NOT CYGWIN) - ADD_DEPENDENCIES(libarchive_test archive_windows_static) - ENDIF(WIN32 AND NOT CYGWIN) SET_PROPERTY(TARGET libarchive_test PROPERTY COMPILE_DEFINITIONS - LIBARCHIVE_STATIC) + LIBARCHIVE_STATIC LIST_H) SET(num 0) FOREACH(test ${libarchive_test_SOURCES}) IF(test MATCHES "^test_[^/]+[.]c$") diff --git a/tar/CMakeLists.txt b/tar/CMakeLists.txt index 25b18aa24..2d60f79a8 100644 --- a/tar/CMakeLists.txt +++ b/tar/CMakeLists.txt @@ -30,15 +30,10 @@ IF (ENABLE_TAR) # Register target # ADD_EXECUTABLE(bsdtar ${bsdtar_SOURCES}) - IF(WIN32 AND NOT CYGWIN) - ADD_DEPENDENCIES(bsdtar archive_windows_static) - ENDIF(WIN32 AND NOT CYGWIN) IF(ENABLE_TAR_SHARED) TARGET_LINK_LIBRARIES(bsdtar archive ${ADDITIONAL_LIBS}) ELSE(ENABLE_TAR_SHARED) TARGET_LINK_LIBRARIES(bsdtar archive_static ${ADDITIONAL_LIBS}) - SET_TARGET_PROPERTIES(bsdtar PROPERTIES COMPILE_DEFINITIONS - LIBARCHIVE_STATIC) ENDIF(ENABLE_TAR_SHARED) IF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(bsdtar PROPERTIES diff --git a/tar/bsdtar_cygwin.c b/tar/bsdtar_cygwin.c index 0408157f3..d31f1122d 100644 --- a/tar/bsdtar_cygwin.c +++ b/tar/bsdtar_cygwin.c @@ -42,6 +42,7 @@ #include "bsdtar.h" +#ifndef LIST_H static int _is_privileged(HANDLE thandle, const char *sidlist[]) { @@ -134,4 +135,7 @@ bsdtar_is_privileged(struct bsdtar *bsdtar) return (ret); } + +#endif /* LIST_H */ + #endif diff --git a/tar/bsdtar_windows.c b/tar/bsdtar_windows.c index 9fc48aa8b..c4e77b451 100644 --- a/tar/bsdtar_windows.c +++ b/tar/bsdtar_windows.c @@ -42,12 +42,1080 @@ #include "bsdtar.h" +#define EPOC_TIME (116444736000000000ULL) + +struct ustat { + int64_t st_atime; + uint32_t st_atime_nsec; + int64_t st_ctime; + uint32_t st_ctime_nsec; + int64_t st_mtime; + uint32_t st_mtime_nsec; + gid_t st_gid; + /* 64bits ino */ + int64_t st_ino; + mode_t st_mode; + uint32_t st_nlink; + uint64_t st_size; + uid_t st_uid; + dev_t st_dev; + dev_t st_rdev; +}; + +struct __DIR { + HANDLE handle; + WIN32_FIND_DATAW fileData; + struct dirent de; + int first; + BOOL finished; +}; + +/* Transform 64-bits ino into 32-bits by hashing. + * You do not forget that really unique number size is 64-bits. + */ +#define INOSIZE (8*sizeof(ino_t)) /* 32 */ +static __inline ino_t +getino(struct ustat *ub) +{ + ULARGE_INTEGER ino64; + + ino64.QuadPart = ub->st_ino; + /* I don't know this hashing is correct way */ + return (ino64.LowPart ^ (ino64.LowPart >> INOSIZE)); +} + +/* + * Prepend "\\?\" to the path name and convert it to unicode to permit + * an extended-length path for a maximum total path length of 32767 + * characters. + * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx + */ +static wchar_t * +permissive_name(const char *name) +{ + wchar_t *wn, *wnp; + wchar_t *ws, *wsp; + size_t l, len, slen; + int unc; + + len = strlen(name); + wn = malloc((len + 1) * sizeof(wchar_t)); + if (wn == NULL) + return (NULL); + l = MultiByteToWideChar(CP_ACP, 0, name, len, wn, len); + if (l == 0) { + free(wn); + return (NULL); + } + wn[l] = L'\0'; + + /* Get a full path names */ + l = GetFullPathNameW(wn, 0, NULL, NULL); + if (l == 0) { + free(wn); + return (NULL); + } + wnp = malloc(l * sizeof(wchar_t)); + if (wnp == NULL) { + free(wn); + return (NULL); + } + len = GetFullPathNameW(wn, l, wnp, NULL); + free(wn); + wn = wnp; + + if (wnp[0] == L'\\' && wnp[1] == L'\\' && + wnp[2] == L'?' && wnp[3] == L'\\') + /* We have already permissive names. */ + return (wn); + + if (wnp[0] == L'\\' && wnp[1] == L'\\' && + wnp[2] == L'.' && wnp[3] == L'\\') { + /* Device names */ + 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. */ + return (wn); + } + + unc = 0; + if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') { + wchar_t *p = &wnp[2]; + + /* Skip server-name letters. */ + while (*p != L'\\' && *p != L'\0') + ++p; + if (*p == L'\\') { + wchar_t *rp = ++p; + /* Skip share-name letters. */ + while (*p != L'\\' && *p != L'\0') + ++p; + if (*p == L'\\' && p != rp) { + /* Now, match patterns such as + * "\\server-name\share-name\" */ + wnp += 2; + len -= 2; + unc = 1; + } + } + } + + slen = 4 + (unc * 4) + len + 1; + ws = wsp = malloc(slen * sizeof(wchar_t)); + if (ws == NULL) { + free(wn); + return (NULL); + } + /* prepend "\\?\" */ + wcsncpy(wsp, L"\\\\?\\", 4); + wsp += 4; + slen -= 4; + if (unc) { + /* append "UNC\" ---> "\\?\UNC\" */ + wcsncpy(wsp, L"UNC\\", 4); + wsp += 4; + slen -= 4; + } + wcsncpy_s(wsp, slen, wnp, _TRUNCATE); + free(wn); + return (ws); +} + +static HANDLE +la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) +{ + wchar_t *wpath; + HANDLE handle; + + handle = CreateFileA(path, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile); + if (handle != INVALID_HANDLE_VALUE) + return (handle); + if (GetLastError() != ERROR_PATH_NOT_FOUND) + return (handle); + wpath = permissive_name(path); + if (wpath == NULL) + return (handle); + handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile); + free(wpath); + return (handle); +} + +static size_t +wequallen(const wchar_t *s1, const wchar_t *s2) +{ + size_t i = 0; + + while (*s1 != L'\0' && *s2 != L'\0' && *s1 == *s2) { + ++s1; ++s2; ++i; + } + return (i); +} + +/* Check that path1 and path2 can be hard-linked by each other. + * Both arguments must be made by permissive_name function. + */ +static int +canHardLinkW(const wchar_t *path1, const wchar_t *path2) +{ + wchar_t root[MAX_PATH]; + wchar_t fs[32]; + const wchar_t *s; + int r; + + r = wequallen(path1, path2); + /* Is volume-name the same? */ + if (r < 7) + return (0); + if (wcsncmp(path1, L"\\\\?\\UNC\\", 8) == 0) { + int len; + + s = path1 + 8; + if (*s == L'\\') + return (0); + /* 012345678 + * Name : "\\?\UNC\Server\Share\" + * ^ search + */ + s = wcschr(++s, L'\\'); + if (s == NULL) + return (0); + if (*++s == L'\\') + return (0); + /* 012345678 + * Name : "\\?\UNC\Server\Share\" + * ^ search + */ + s = wcschr(++s, L'\\'); + if (s == NULL) + return (0); + s++; + /* 012345678 + * Name : "\\?\UNC\Server\Share\xxxx" + * ^--- len ----^ + */ + len = (int)(s - path1 - 8); + /* Is volume-name the same? */ + if (r < len + 8) + return (0); + /* Is volume-name too long? */ + if (sizeof(root) -3 < len) + return (0); + root[0] = root[1] = L'\\'; + wcsncpy(root + 2, path1 + 8 , len); + /* root : "\\Server\Share\" */ + root[2 + len] = L'\0'; + } else if (wcsncmp(path1, L"\\\\?\\", 4) == 0) { + s = path1 + 4; + if ((!iswalpha(*s)) || s[1] != L':' || s[2] != L'\\') + return (0); + wcsncpy(root, path1 + 4, 3); + root[3] = L'\0'; + } else + return (0); + if (!GetVolumeInformationW(root, NULL, 0, NULL, NULL, NULL, fs, sizeof(fs))) + return (0); + if (wcscmp(fs, L"NTFS") == 0) + return (1); + else + return (0); +} + +/* Make a link to src called dst. */ +static int +__link(const char *src, const char *dst, int sym) +{ + 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) { + if (wsrc != NULL) + free(wsrc); + if (wdst != NULL) + free(wdst); + set_errno (EINVAL); + return -1; + } + + if ((attr = GetFileAttributesW(wsrc)) != -1) { + if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + errno = EPERM; + retval = -1; + goto exit; + } + if (!sym && canHardLinkW(wsrc, wdst)) + res = CreateHardLinkW(wdst, wsrc, NULL); + else + res = CopyFileW(wsrc, wdst, FALSE); + } 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 = wcslen(wsrc); + slen = strlen(src); + n = MultiByteToWideChar(CP_ACP, 0, src, slen, wsrc, slen); + 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 == -1 || (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + if (attr == -1) + _dosmaperr(GetLastError()); + else + errno = EPERM; + free (wnewsrc); + retval = -1; + goto exit; + } + if (!sym && canHardLinkW(wnewsrc, wdst)) + res = CreateHardLinkW(wdst, wnewsrc, NULL); + else + res = CopyFileW(wnewsrc, wdst, FALSE); + free (wnewsrc); + } + if (res == 0) { + _dosmaperr(GetLastError()); + retval = -1; + } else + retval = 0; +exit: + free(wsrc); + free(wdst); + return (retval); +} + +/* Make a hard link to src called dst. */ +int +link(const char *src, const char *dst) +{ + return __link (src, dst, 0); +} + +/* Make a symbolic link to FROM called TO. */ +int symlink (from, to) + const char *from; + const char *to; +{ + return __link (from, to, 1); +} + +int +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)) { + _dosmaperr(GetLastError()); + return (-1); + } + if (!SetEndOfFile(handle)) { + _dosmaperr(GetLastError()); + return (-1); + } + return (0); +} + +DIR * +__opendir(const char *path, int ff) +{ + DIR *dir; + wchar_t *wpath, *wfname; + size_t wlen; + + dir = malloc(sizeof(*dir)); + if (dir == NULL) { + errno = ENOMEM; + return (NULL); + } + + wpath = permissive_name(path); + if (wpath == NULL) { + errno = EINVAL; + free(dir); + return (NULL); + } + if (ff) { + wfname = wpath; + wpath = NULL; + } else { + wlen = wcslen(wpath); + wfname = malloc((wlen + 3) * sizeof(wchar_t)); + if (wfname == NULL) { + errno = ENOMEM; + free(dir); + free(wpath); + return (NULL); + } + wcscpy(wfname, wpath); + wcscat(wfname, L"\\*"); + free(wpath); + } + + dir->handle = FindFirstFileW(wfname, &dir->fileData); + if (dir->handle == INVALID_HANDLE_VALUE) { + _dosmaperr(GetLastError()); + free(dir); + free(wfname); + return (NULL); + } + dir->first = 1; + dir->finished = FALSE; + free(wfname); + + return (dir); +} + +static DIR * +opendir_findfile(const char *path) +{ + return (__opendir(path, 1)); +} + +DIR * +opendir(const char *path) +{ + return (__opendir(path, 0)); +} + +struct dirent * +readdir(DIR *dirp) +{ + size_t len; + + while (!dirp->finished) { + if (!dirp->first && !FindNextFileW(dirp->handle, &dirp->fileData)) { + if (GetLastError() != ERROR_NO_MORE_FILES) + _dosmaperr(GetLastError()); + dirp->finished = TRUE; + break; + } + dirp->first = 0; + len = wcstombs(dirp->de.d_name, dirp->fileData.cFileName, + sizeof(dirp->de.d_name) -1); + if (len == -1) { + errno = EINVAL; + dirp->finished = TRUE; + break; + } + dirp->de.d_name[len] = '\0'; + dirp->de.d_nameln = strlen(dirp->de.d_name); + return (&dirp->de); + } + + return (NULL); +} + +int +closedir(DIR *dirp) +{ + BOOL ret; + + ret = FindClose(dirp->handle); + free(dirp); + if (ret == 0) { + _dosmaperr(GetLastError()); + return (-1); + } + return (0); +} + +int +la_chdir(const char *path) +{ + wchar_t *ws; + int r; + + r = SetCurrentDirectoryA(path); + if (r == 0) { + if (GetLastError() != ERROR_FILE_NOT_FOUND) { + _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) { + _dosmaperr(GetLastError()); + return (-1); + } + return (0); +} + +__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 + _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) { + _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) { + _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)); +} + +int +la_open(const char *path, int flags, ...) +{ + va_list ap; + wchar_t *ws; + int r, pmode; + DWORD attr; + + va_start(ap, flags); + pmode = va_arg(ap, int); + va_end(ap); + ws = NULL; + if ((flags & ~O_BINARY) == O_RDONLY) { + /* + * When we open a directory, _open function returns + * "Permission denied" error. + */ + attr = GetFileAttributesA(path); + if (attr == -1 && GetLastError() == ERROR_PATH_NOT_FOUND) { + ws = permissive_name(path); + if (ws == NULL) { + errno = EINVAL; + return (-1); + } + attr = GetFileAttributesW(ws); + } + if (attr == -1) { + _dosmaperr(GetLastError()); + free(ws); + return (-1); + } + if (attr & FILE_ATTRIBUTE_DIRECTORY) { + HANDLE handle; + + if (ws != NULL) + handle = CreateFileW(ws, 0, 0, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_ATTRIBUTE_READONLY, + NULL); + else + handle = CreateFileA(path, 0, 0, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_ATTRIBUTE_READONLY, + NULL); + free(ws); + if (handle == INVALID_HANDLE_VALUE) { + _dosmaperr(GetLastError()); + return (-1); + } + r = _open_osfhandle((intptr_t)handle, _O_RDONLY); + return (r); + } + } + if (ws == NULL) { + r = _open(path, flags, pmode); + if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { + /* simular other POSIX system action to pass a test */ + attr = GetFileAttributesA(path); + if (attr == -1) + _dosmaperr(GetLastError()); + else if (attr & FILE_ATTRIBUTE_DIRECTORY) + errno = EISDIR; + else + errno = EACCES; + return (-1); + } + if (r >= 0 || errno != ENOENT) + return (r); + ws = permissive_name(path); + if (ws == NULL) { + errno = EINVAL; + return (-1); + } + } + r = _wopen(ws, flags, pmode); + if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { + /* simular other POSIX system action to pass a test */ + attr = GetFileAttributesW(ws); + if (attr == -1) + _dosmaperr(GetLastError()); + else if (attr & FILE_ATTRIBUTE_DIRECTORY) + errno = EISDIR; + else + errno = EACCES; + } + free(ws); + return (r); +} + +ssize_t +la_read(int fd, void *buf, size_t nbytes) +{ + HANDLE handle; + DWORD bytes_read, lasterr; + int r; + +#ifdef _WIN64 + if (nbytes > UINT32_MAX) + nbytes = UINT32_MAX; +#endif + if (fd < 0) { + errno = EBADF; + return (-1); + } + 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) + errno = EBADF; + else + _dosmaperr(lasterr); + return (-1); + } + 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) +{ + ULARGE_INTEGER utc; + + utc.HighPart = filetime->dwHighDateTime; + utc.LowPart = filetime->dwLowDateTime; + if (utc.QuadPart >= EPOC_TIME) { + utc.QuadPart -= EPOC_TIME; + *time = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */ + *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */ + } else { + *time = 0; + *ns = 0; + } +} + +/* Stat by handle + * Windows' stat() does not accept path which is added "\\?\" especially "?" + * character. + * It means we cannot access a long name path(which is 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 + * BY_HANDLE_FILE_INFORMATION. + * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION. + * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION. + */ +static int +__hstat(HANDLE handle, struct ustat *st) +{ + BY_HANDLE_FILE_INFORMATION info; + ULARGE_INTEGER ino64; + DWORD ftype; + mode_t mode; + time_t time; + long ns; + + switch (ftype = GetFileType(handle)) { + case FILE_TYPE_UNKNOWN: + errno = EBADF; + return (-1); + case FILE_TYPE_CHAR: + case FILE_TYPE_PIPE: + if (ftype == FILE_TYPE_CHAR) { + st->st_mode = S_IFCHR; + st->st_size = 0; + } else { + DWORD avail; + + st->st_mode = S_IFIFO; + if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL)) + st->st_size = avail; + else + st->st_size = 0; + } + st->st_atime = 0; + st->st_atime_nsec = 0; + st->st_mtime = 0; + st->st_mtime_nsec = 0; + st->st_ctime = 0; + st->st_ctime_nsec = 0; + st->st_ino = 0; + st->st_nlink = 1; + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + st->st_dev = 0; + return (0); + case FILE_TYPE_DISK: + break; + default: + /* This ftype is undocumented type. */ + _dosmaperr(GetLastError()); + return (-1); + } + + ZeroMemory(&info, sizeof(info)); + if (!GetFileInformationByHandle (handle, &info)) { + _dosmaperr(GetLastError()); + return (-1); + } + + mode = S_IRUSR | S_IRGRP | S_IROTH; + if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + else + mode |= S_IFREG; + st->st_mode = mode; + + fileTimeToUTC(&info.ftLastAccessTime, &time, &ns); + st->st_atime = time; + st->st_atime_nsec = ns; + fileTimeToUTC(&info.ftLastWriteTime, &time, &ns); + st->st_mtime = time; + st->st_mtime_nsec = ns; + fileTimeToUTC(&info.ftCreationTime, &time, &ns); + st->st_ctime = time; + st->st_ctime_nsec = ns; + st->st_size = + ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1)) + + (int64_t)(info.nFileSizeLow); +#ifdef SIMULATE_WIN_STAT + st->st_ino = 0; + st->st_nlink = 1; + st->st_dev = 0; +#else + /* Getting FileIndex as i-node. We have to remove a sequence which + * is high-16-bits of nFileIndexHigh. */ + ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL; + ino64.LowPart = info.nFileIndexLow; + st->st_ino = ino64.QuadPart; + st->st_nlink = info.nNumberOfLinks; + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ++st->st_nlink;/* Add parent directory. */ + st->st_dev = info.dwVolumeSerialNumber; +#endif + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + return (0); +} + +static void +copy_stat(struct stat *st, struct ustat *us) +{ + st->st_atime = us->st_atime; + st->st_ctime = us->st_ctime; + st->st_mtime = us->st_mtime; + st->st_gid = us->st_gid; + st->st_ino = getino(us); + st->st_mode = us->st_mode; + st->st_nlink = us->st_nlink; + st->st_size = us->st_size; + st->st_uid = us->st_uid; + st->st_dev = us->st_dev; + st->st_rdev = us->st_rdev; +} + +int +la_fstat(int fd, struct stat *st) +{ + struct ustat u; + int ret; + + if (fd < 0) { + errno = EBADF; + return (-1); + } + ret = __hstat((HANDLE)_get_osfhandle(fd), &u); + if (ret >= 0) { + copy_stat(st, &u); + if (u.st_mode & (S_IFCHR | S_IFIFO)) { + st->st_dev = fd; + st->st_rdev = fd; + } + } + return (ret); +} + +int +la_stat(const char *path, struct stat *st) +{ + HANDLE handle; + struct ustat u; + int ret; + + handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + _dosmaperr(GetLastError()); + return (-1); + } + ret = __hstat(handle, &u); + CloseHandle(handle); + if (ret >= 0) { + char *p; + + copy_stat(st, &u); + p = strrchr(path, '.'); + if (p != NULL && strlen(p) == 4) { + char exttype[4]; + + ++ p; + exttype[0] = toupper(*p++); + exttype[1] = toupper(*p++); + exttype[2] = toupper(*p++); + exttype[3] = '\0'; + if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") || + !strcmp(exttype, "BAT") || !strcmp(exttype, "COM")) + st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; + } + } + return (ret); +} + +ssize_t +la_write(int fd, const void *buf, size_t nbytes) +{ + uint32_t bytes_written; + +#ifdef _WIN64 + if (nbytes > UINT32_MAX) + nbytes = UINT32_MAX; +#endif + if (fd < 0) { + errno = EBADF; + return (-1); + } + if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes, + &bytes_written, NULL)) { + DWORD lasterr; + + lasterr = GetLastError(); + if (lasterr == ERROR_ACCESS_DENIED) + errno = EBADF; + else + _dosmaperr(lasterr); + return (-1); + } + return (bytes_written); +} + +#ifndef LIST_H +static int +_is_privileged(HANDLE thandle, const char *sidlist[]) +{ + TOKEN_USER *tuser; + TOKEN_GROUPS *tgrp; + DWORD bytes; + PSID psid; + DWORD i, g; + int member; + + psid = NULL; + tuser = NULL; + tgrp = NULL; + member = 0; + for (i = 0; sidlist[i] != NULL && member == 0; i++) { + if (psid != NULL) + LocalFree(psid); + if (ConvertStringSidToSidA(sidlist[i], &psid) == 0) { + errno = EPERM; + return (-1); + } + if (tuser == NULL) { + GetTokenInformation(thandle, TokenUser, NULL, 0, &bytes); + tuser = malloc(bytes); + if (tuser == NULL) { + errno = ENOMEM; + member = -1; + break; + } + if (GetTokenInformation(thandle, TokenUser, tuser, bytes, &bytes) == 0) { + errno = EPERM; + member = -1; + break; + } + } + member = EqualSid(tuser->User.Sid, psid); + if (member) + break; + if (tgrp == NULL) { + GetTokenInformation(thandle, TokenGroups, NULL, 0, &bytes); + tgrp = malloc(bytes); + if (tgrp == NULL) { + errno = ENOMEM; + member = -1; + break; + } + if (GetTokenInformation(thandle, TokenGroups, tgrp, bytes, &bytes) == 0) { + errno = EPERM; + member = -1; + break; + } + } + for (g = 0; g < tgrp->GroupCount; g++) { + member = EqualSid(tgrp->Groups[g].Sid, psid); + if (member) + break; + } + } + LocalFree(psid); + free(tuser); + free(tgrp); + + return (member); +} + int bsdtar_is_privileged(struct bsdtar *bsdtar) { + HANDLE thandle; int ret; + const char *sidlist[] = { + "S-1-5-32-544", /* Administrators */ + "S-1-5-32-551", /* Backup Operators */ + NULL + }; - ret = la_is_privileged(); + (void)bsdtar;/* UNUSED */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &thandle) == 0) { + bsdtar_warnc(bsdtar, EPERM, "Failed to check privilege"); + return (0); + } + ret = _is_privileged(thandle, sidlist); if (ret < 0) { bsdtar_warnc(bsdtar, errno, "Failed to check privilege"); return (0); @@ -140,4 +1208,6 @@ try_plain: write_hierarchy(bsdtar, a, path); } +#endif /* LIST_H */ + #endif diff --git a/tar/bsdtar_windows.h b/tar/bsdtar_windows.h index 7624edcc5..5dfe02c5b 100644 --- a/tar/bsdtar_windows.h +++ b/tar/bsdtar_windows.h @@ -31,10 +31,21 @@ #define PRId64 "I64" #define geteuid() 0 +struct __DIR; +typedef struct __DIR DIR; +struct direct { + unsigned char d_nameln; + char d_name[MAX_PATH]; +}; + #ifdef __cplusplus extern "C" { #endif +extern DIR *opendir(const char *path); +extern struct dirent *readdir(DIR *dirp); +extern int closedir(DIR *dirp); + extern int bsdtar_is_privileged(struct bsdtar *bsdtar); extern void write_hierarchy_win(struct bsdtar *bsdtar, struct archive *a, const char *path, diff --git a/tar/test/CMakeLists.txt b/tar/test/CMakeLists.txt index 8e6386a5a..8f1ec77a2 100644 --- a/tar/test/CMakeLists.txt +++ b/tar/test/CMakeLists.txt @@ -23,6 +23,8 @@ IF(ENABLE_TAR AND ENABLE_TEST) test_version.c ) IF(WIN32 AND NOT CYGWIN) + LIST(APPEND bsdtar_test_SOURCES ../bsdtar_windows.c) + LIST(APPEND bsdtar_test_SOURCES ../bsdtar_windows.h) LIST(APPEND bsdtar_test_SOURCES test_windows.c) ENDIF(WIN32 AND NOT CYGWIN) @@ -37,9 +39,7 @@ IF(ENABLE_TAR AND ENABLE_TEST) # Register target # ADD_EXECUTABLE(bsdtar_test ${bsdtar_test_SOURCES}) - IF(WIN32 AND NOT CYGWIN) - ADD_DEPENDENCIES(bsdtar_test archive_windows_static) - ENDIF(WIN32 AND NOT CYGWIN) + SET_PROPERTY(TARGET bsdtar_test PROPERTY COMPILE_DEFINITIONS LIST_H) SET(num 0) FOREACH(test ${bsdtar_test_SOURCES}) IF(test MATCHES "^test_[^/]+[.]c$")