Merge pull request #3167 from stoeckmann/unzip_windows
unzip: Add Windows port
(cherry picked from commit 4558c310de)
This commit is contained in:
1 parent
cc711d6a7f
commit
9cc3e46314
12 files changed
+907
-28
No files matched your search
+3
-7
@@ -246,13 +246,8 @@ OPTION(ENABLE_CPIO "Enable cpio building" ON)
|
||||
OPTION(ENABLE_CPIO_SHARED "Enable dynamic build of cpio" FALSE)
|
||||
OPTION(ENABLE_CAT "Enable cat building" ON)
|
||||
OPTION(ENABLE_CAT_SHARED "Enable dynamic build of cat" FALSE)
|
||||
IF(WIN32 AND NOT CYGWIN)
|
||||
SET(ENABLE_UNZIP FALSE)
|
||||
SET(ENABLE_UNZIP_SHARED FALSE)
|
||||
ELSE()
|
||||
OPTION(ENABLE_UNZIP "Enable unzip building" ON)
|
||||
OPTION(ENABLE_UNZIP_SHARED "Enable dynamic build of unzip" FALSE)
|
||||
ENDIF()
|
||||
OPTION(ENABLE_UNZIP "Enable unzip building" ON)
|
||||
OPTION(ENABLE_UNZIP_SHARED "Enable dynamic build of unzip" FALSE)
|
||||
OPTION(ENABLE_XATTR "Enable extended attribute support" ON)
|
||||
OPTION(ENABLE_ACL "Enable ACL support" ON)
|
||||
OPTION(ENABLE_ICONV "Enable iconv support" ON)
|
||||
@@ -1500,6 +1495,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(getpwnam_r HAVE_GETPWNAM_R)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(getpwuid_r HAVE_GETPWUID_R)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(getresgid HAVE_GETRESGID)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(getresuid HAVE_GETRESUID)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(gettimeofday HAVE_GETTIMEOFDAY)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(getvfsbyname HAVE_GETVFSBYNAME)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(gmtime_r HAVE_GMTIME_R)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(issetugid HAVE_ISSETUGID)
|
||||
|
||||
+17
-2
@@ -1670,8 +1670,10 @@ bsdunzip_SOURCES= \
|
||||
unzip/cmdline.c
|
||||
|
||||
if INC_WINDOWS_FILES
|
||||
noinst_HEADERS+=
|
||||
bsdunzip_SOURCES+=
|
||||
noinst_HEADERS+= \
|
||||
unzip/bsdunzip_windows.h
|
||||
bsdunzip_SOURCES+= \
|
||||
unzip/bsdunzip_windows.c
|
||||
endif
|
||||
|
||||
bsdunzip_DEPENDENCIES = libarchive.la libarchive_fe.la
|
||||
@@ -1689,7 +1691,20 @@ bsdunzip_LDADD= libarchive_fe.la libarchive.la $(LTLIBICONV)
|
||||
bsdunzip_CPPFLAGS= -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe $(bsdunzip_ccstatic) $(PLATFORMCPPFLAGS)
|
||||
bsdunzip_LDFLAGS= $(bsdunzip_ldstatic) $(DEAD_CODE_REMOVAL)
|
||||
|
||||
if INC_WINDOWS_FILES
|
||||
# Embed an application manifest marking bsdunzip as long-path aware.
|
||||
unzip/bsdunzip_rc.$(OBJEXT): $(top_srcdir)/unzip/bsdunzip.rc $(top_srcdir)/unzip/bsdunzip.exe.manifest
|
||||
$(AM_V_GEN)$(WINDRES) -I $(top_srcdir)/unzip -i $(top_srcdir)/unzip/bsdunzip.rc -o $@
|
||||
bsdunzip_LDADD += unzip/bsdunzip_rc.$(OBJEXT)
|
||||
bsdunzip_DEPENDENCIES += unzip/bsdunzip_rc.$(OBJEXT)
|
||||
CLEANFILES += unzip/bsdunzip_rc.$(OBJEXT)
|
||||
endif
|
||||
|
||||
bsdunzip_EXTRA_DIST= \
|
||||
unzip/bsdunzip_windows.h \
|
||||
unzip/bsdunzip_windows.c \
|
||||
unzip/bsdunzip.rc \
|
||||
unzip/bsdunzip.exe.manifest \
|
||||
unzip/bsdunzip.1 \
|
||||
unzip/CMakeLists.txt
|
||||
|
||||
|
||||
@@ -666,6 +666,9 @@ typedef uint64_t uintmax_t;
|
||||
/* Define to 1 if you have the `getpwuid_r' function. */
|
||||
#cmakedefine HAVE_GETPWUID_R 1
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#cmakedefine HAVE_GETTIMEOFDAY 1
|
||||
|
||||
/* Define to 1 if you have the `getvfsbyname' function. */
|
||||
#cmakedefine HAVE_GETVFSBYNAME 1
|
||||
|
||||
|
||||
+1
-1
@@ -831,7 +831,7 @@ AC_CHECK_FUNCS([fstat fstatat fstatfs fstatvfs ftruncate])
|
||||
AC_CHECK_FUNCS([futimens futimes futimesat])
|
||||
AC_CHECK_FUNCS([getegid geteuid getline getpid getresgid getresuid])
|
||||
AC_CHECK_FUNCS([getgrgid_r getgrnam_r getpwnam_r getpwuid_r])
|
||||
AC_CHECK_FUNCS([getvfsbyname gmtime_r])
|
||||
AC_CHECK_FUNCS([gettimeofday getvfsbyname gmtime_r])
|
||||
AC_CHECK_FUNCS([issetugid])
|
||||
AC_CHECK_FUNCS([lchflags lchmod lchown link linkat localtime_r lstat lutimes])
|
||||
AC_CHECK_FUNCS([mbrtowc memmove memset])
|
||||
|
||||
@@ -25,6 +25,19 @@ IF(ENABLE_UNZIP)
|
||||
../libarchive_fe/passphrase.h
|
||||
)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libarchive_fe)
|
||||
IF(WIN32 AND NOT CYGWIN)
|
||||
LIST(APPEND bsdunzip_SOURCES bsdunzip_windows.c)
|
||||
LIST(APPEND bsdunzip_SOURCES bsdunzip_windows.h)
|
||||
IF(NOT MSVC)
|
||||
# The GNU toolchains (MinGW/Clang) do not generate an application
|
||||
# manifest, so we embed one through a resource script.
|
||||
ENABLE_LANGUAGE(RC)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
LIST(APPEND bsdunzip_SOURCES bsdunzip.rc)
|
||||
SET_SOURCE_FILES_PROPERTIES(bsdunzip.rc PROPERTIES
|
||||
OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bsdunzip.exe.manifest)
|
||||
ENDIF(NOT MSVC)
|
||||
ENDIF(WIN32 AND NOT CYGWIN)
|
||||
|
||||
# bsdunzip documentation
|
||||
SET(bsdunzip_MANS bsdunzip.1)
|
||||
@@ -38,6 +51,10 @@ IF(ENABLE_UNZIP)
|
||||
SET_TARGET_PROPERTIES(bsdunzip PROPERTIES COMPILE_DEFINITIONS
|
||||
LIBARCHIVE_STATIC)
|
||||
ENDIF(ENABLE_UNZIP_SHARED)
|
||||
IF(WIN32 AND NOT CYGWIN AND MSVC)
|
||||
# MSVC merges .manifest sources into the linker's default manifest
|
||||
TARGET_SOURCES(bsdunzip PRIVATE bsdunzip.exe.manifest)
|
||||
ENDIF(WIN32 AND NOT CYGWIN AND MSVC)
|
||||
|
||||
# Installation rules
|
||||
IF(ENABLE_INSTALL)
|
||||
|
||||
+35
-14
@@ -145,6 +145,7 @@ errorx(const char *fmt, ...)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#if defined(HAVE_LCHMOD) || defined(HAVE_UTIMENSAT) || defined(HAVE_LUTIMES)
|
||||
/* non-fatal error message + errno */
|
||||
static void
|
||||
warning(const char *fmt, ...)
|
||||
@@ -160,6 +161,7 @@ warning(const char *fmt, ...)
|
||||
va_end(ap);
|
||||
fprintf(stderr, ": %s\n", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* non-fatal error message, no errno */
|
||||
static void
|
||||
@@ -326,6 +328,30 @@ accept_pathname(const char *pathname)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* System call to create a directory. */
|
||||
static int
|
||||
system_mkdir(const char *pathname, int mode)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
(void)mode; /* UNUSED */
|
||||
return _mkdir(pathname);
|
||||
#else
|
||||
return mkdir(pathname, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
system_unlink(const char *pathname) {
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
if (unlink(pathname) == -1) {
|
||||
/* Windows treats directory symbolic links specially. */
|
||||
rmdir(pathname);
|
||||
}
|
||||
#else
|
||||
(void)unlink(pathname);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the specified directory with the specified mode, taking certain
|
||||
* precautions on they way.
|
||||
@@ -346,14 +372,9 @@ make_dir(const char *path, int mode)
|
||||
* even compromise (if this non-directory happens to be a
|
||||
* symlink to somewhere unsafe), so we don't.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Don't check unlink() result; failure will cause mkdir()
|
||||
* to fail later, which we will catch.
|
||||
*/
|
||||
(void)unlink(path);
|
||||
system_unlink(path);
|
||||
}
|
||||
if (mkdir(path, (mode_t)mode) != 0 && errno != EEXIST)
|
||||
if (system_mkdir(path, (mode_t)mode) != 0 && errno != EEXIST)
|
||||
error("mkdir('%s')", path);
|
||||
}
|
||||
|
||||
@@ -378,10 +399,10 @@ make_parent(char *path)
|
||||
*sep = '/';
|
||||
return;
|
||||
}
|
||||
unlink(path);
|
||||
system_unlink(path);
|
||||
}
|
||||
make_parent(path);
|
||||
mkdir(path, 0755);
|
||||
system_mkdir(path, 0755);
|
||||
*sep = '/';
|
||||
|
||||
#if 0
|
||||
@@ -458,7 +479,7 @@ handle_existing_file(char **path)
|
||||
/* FALLTHROUGH */
|
||||
case 'y':
|
||||
case 'Y':
|
||||
(void)unlink(*path);
|
||||
system_unlink(*path);
|
||||
return 1;
|
||||
case 'N':
|
||||
n_opt = 1;
|
||||
@@ -658,10 +679,10 @@ recheck:
|
||||
#endif
|
||||
))
|
||||
return;
|
||||
(void)unlink(*path);
|
||||
system_unlink(*path);
|
||||
} else if (o_opt) {
|
||||
/* overwrite */
|
||||
(void)unlink(*path);
|
||||
system_unlink(*path);
|
||||
} else if (n_opt) {
|
||||
/* do not overwrite */
|
||||
return;
|
||||
@@ -897,9 +918,9 @@ list(struct archive *a, struct archive_entry *e)
|
||||
mtime = archive_entry_mtime(e);
|
||||
tm = localtime(&mtime);
|
||||
if (*y_str)
|
||||
strftime(buf, sizeof(buf), "%m-%d-%Y %R", tm);
|
||||
strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M", tm);
|
||||
else
|
||||
strftime(buf, sizeof(buf), "%m-%d-%y %R", tm);
|
||||
strftime(buf, sizeof(buf), "%m-%d-%y %H:%M", tm);
|
||||
|
||||
pathname = archive_entry_pathname(e);
|
||||
if (!pathname)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||
<ws2:longPathAware>true</ws2:longPathAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Embed an application manifest that marks bsdunzip as long-path aware.
|
||||
*
|
||||
* bsdunzip's file name handling is limited to MAX_PATH (260) characters unless
|
||||
* the process opts in to long paths via a "longPathAware" manifest.
|
||||
* A system-wide LongPathsEnabled registry value is not sufficient on its own;
|
||||
* the executable must also carry this manifest. Without it, extracting into
|
||||
* deeply nested destination directories fails.
|
||||
*
|
||||
* See:
|
||||
* https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation
|
||||
*/
|
||||
|
||||
#define RT_MANIFEST 24
|
||||
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
|
||||
|
||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "bsdunzip.exe.manifest"
|
||||
@@ -22,6 +22,10 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#include "bsdunzip_windows.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBARCHIVE
|
||||
/* If we're using the platform libarchive, include system headers. */
|
||||
#include <archive.h>
|
||||
|
||||
@@ -0,0 +1,728 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2003-2010 Tim Kientzle
|
||||
* Copyright (c) 2003-2007 Kees Zeelenberg
|
||||
* Copyright (c) 2009-2012 Michihiro NAKAJIMA
|
||||
* Copyright (c) 2026 Tobias Stoeckmann
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
|
||||
#include "bsdunzip_platform.h"
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_IO_H
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <winnt.h>
|
||||
|
||||
#ifndef S_IFIFO
|
||||
#define S_IFIFO _S_IFIFO
|
||||
#endif
|
||||
|
||||
#define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC)
|
||||
#define _S_IXUSR _S_IEXEC /* read permission, user */
|
||||
#define _S_IWUSR _S_IWRITE /* write permission, user */
|
||||
#define _S_IRUSR _S_IREAD /* execute/search permission, user */
|
||||
#define _S_IRWXG (_S_IRWXU >> 3)
|
||||
#define _S_IXGRP (_S_IXUSR >> 3) /* read permission, group */
|
||||
#define _S_IWGRP (_S_IWUSR >> 3) /* write permission, group */
|
||||
#define _S_IRGRP (_S_IRUSR >> 3) /* execute/search permission, group */
|
||||
#define _S_IRWXO (_S_IRWXG >> 3)
|
||||
#define _S_IXOTH (_S_IXGRP >> 3) /* read permission, other */
|
||||
#define _S_IWOTH (_S_IWGRP >> 3) /* write permission, other */
|
||||
#define _S_IROTH (_S_IRGRP >> 3) /* execute/search permission, other */
|
||||
|
||||
#ifndef S_IRWXU
|
||||
#define S_IRWXU _S_IRWXU
|
||||
#define S_IXUSR _S_IXUSR
|
||||
#define S_IWUSR _S_IWUSR
|
||||
#define S_IRUSR _S_IRUSR
|
||||
#endif
|
||||
#ifndef S_IRWXG
|
||||
#define S_IRWXG _S_IRWXG
|
||||
#define S_IXGRP _S_IXGRP
|
||||
#define S_IWGRP _S_IWGRP
|
||||
#endif
|
||||
#ifndef S_IRGRP
|
||||
#define S_IRGRP _S_IRGRP
|
||||
#endif
|
||||
#ifndef S_IRWXO
|
||||
#define S_IRWXO _S_IRWXO
|
||||
#define S_IXOTH _S_IXOTH
|
||||
#define S_IWOTH _S_IWOTH
|
||||
#define S_IROTH _S_IROTH
|
||||
#endif
|
||||
|
||||
#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
|
||||
#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
|
||||
#endif
|
||||
|
||||
#define NTFS_EPOC_TIME 11644473600ULL
|
||||
#define NTFS_TICKS 10000000ULL
|
||||
#define NTFS_EPOC_TICKS (NTFS_EPOC_TIME * NTFS_TICKS)
|
||||
#define WINTIME(sec, usec) (((sec * 10000000LL) + NTFS_EPOC_TICKS) + (usec * 10))
|
||||
|
||||
static void unzip_dosmaperr(unsigned long);
|
||||
|
||||
/*
|
||||
* Convert the path name to unicode.
|
||||
*/
|
||||
static wchar_t *
|
||||
unzip_strtowcs(const char *name)
|
||||
{
|
||||
wchar_t *wn;
|
||||
DWORD l, len;
|
||||
|
||||
len = (DWORD)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);
|
||||
errno = EILSEQ;
|
||||
return (NULL);
|
||||
}
|
||||
wn[l] = L'\0';
|
||||
|
||||
return wn;
|
||||
}
|
||||
|
||||
static wchar_t *
|
||||
unzip_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)
|
||||
return (NULL);
|
||||
len = GetFullPathNameW(wname, l, wnp, NULL);
|
||||
wn = wnp;
|
||||
|
||||
if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
|
||||
wnp[2] == L'?' && wnp[3] == L'\\')
|
||||
/* We have already a permissive name. */
|
||||
return (wn);
|
||||
|
||||
if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
|
||||
wnp[2] == L'.' && wnp[3] == L'\\') {
|
||||
/* 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 name. */
|
||||
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(wsp, wnp, slen);
|
||||
wsp[slen - 1] = L'\0'; /* Ensure null termination. */
|
||||
free(wn);
|
||||
return (ws);
|
||||
}
|
||||
|
||||
/* Windows FILETIME to unix time. */
|
||||
static uint64_t
|
||||
unzip_FILETIME_to_unix(const FILETIME *filetime)
|
||||
{
|
||||
ULARGE_INTEGER utc;
|
||||
uint64_t ntfs, unix;
|
||||
|
||||
utc.HighPart = filetime->dwHighDateTime;
|
||||
utc.LowPart = filetime->dwLowDateTime;
|
||||
ntfs = utc.QuadPart;
|
||||
|
||||
if (ntfs > INT64_MAX) {
|
||||
ntfs -= NTFS_EPOC_TICKS;
|
||||
unix = ntfs / NTFS_TICKS;
|
||||
} else {
|
||||
lldiv_t tdiv;
|
||||
int64_t value = (int64_t)ntfs - (int64_t)NTFS_EPOC_TICKS;
|
||||
|
||||
tdiv = lldiv(value, NTFS_TICKS);
|
||||
unix = tdiv.quot;
|
||||
}
|
||||
return unix;
|
||||
}
|
||||
|
||||
static HANDLE
|
||||
unzip_get_handle(const wchar_t *path, int access, int open_link, int *is_link)
|
||||
{
|
||||
HANDLE h;
|
||||
DWORD flag = FILE_FLAG_BACKUP_SEMANTICS;
|
||||
WIN32_FIND_DATAW findData;
|
||||
#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
|
||||
CREATEFILE2_EXTENDED_PARAMETERS createExParams;
|
||||
#endif
|
||||
|
||||
h = FindFirstFileW(path, &findData);
|
||||
if (h == INVALID_HANDLE_VALUE &&
|
||||
GetLastError() == ERROR_INVALID_NAME) {
|
||||
wchar_t *full;
|
||||
full = unzip_win_permissive_name_w(path);
|
||||
h = FindFirstFileW(full, &findData);
|
||||
free(full);
|
||||
}
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
return (h);
|
||||
FindClose(h);
|
||||
|
||||
/* Is symlink file? */
|
||||
if (((findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||
(findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK))) {
|
||||
if (open_link)
|
||||
flag |= FILE_FLAG_OPEN_REPARSE_POINT;
|
||||
*is_link = 1;
|
||||
} else
|
||||
*is_link = 0;
|
||||
|
||||
#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
|
||||
ZeroMemory(&createExParams, sizeof(createExParams));
|
||||
createExParams.dwSize = sizeof(createExParams);
|
||||
createExParams.dwFileFlags = flag;
|
||||
h = CreateFile2(path, access, 0, OPEN_EXISTING, &createExParams);
|
||||
#else
|
||||
h = CreateFileW(path, access, 0, NULL, OPEN_EXISTING, flag, NULL);
|
||||
#endif
|
||||
if (h == INVALID_HANDLE_VALUE &&
|
||||
GetLastError() == ERROR_INVALID_NAME) {
|
||||
wchar_t *full;
|
||||
full = unzip_win_permissive_name_w(path);
|
||||
#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */
|
||||
h = CreateFile2(full, access, 0,
|
||||
OPEN_EXISTING, &createExParams);
|
||||
#else
|
||||
h = CreateFileW(full, access, 0, NULL,
|
||||
OPEN_EXISTING, flag, NULL);
|
||||
#endif
|
||||
free(full);
|
||||
}
|
||||
|
||||
return (h);
|
||||
}
|
||||
|
||||
static int
|
||||
unzip_stat_w(const wchar_t *path, int stat_link, struct stat *st)
|
||||
{
|
||||
HANDLE h;
|
||||
int is_link, r;
|
||||
DWORD ftype;
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
ULARGE_INTEGER ino64;
|
||||
|
||||
h = unzip_get_handle(path, 0, stat_link, &is_link);
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
unzip_dosmaperr(GetLastError());
|
||||
return (-1);
|
||||
}
|
||||
ZeroMemory(&info, sizeof(info));
|
||||
r = GetFileInformationByHandle(h, &info);
|
||||
|
||||
switch (ftype = GetFileType(h)) {
|
||||
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(h, NULL, 0, NULL, &avail, NULL))
|
||||
st->st_size = avail;
|
||||
else
|
||||
st->st_size = 0;
|
||||
}
|
||||
st->st_atime = 0;
|
||||
st->st_mtime = 0;
|
||||
st->st_ctime = 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. */
|
||||
unzip_dosmaperr(GetLastError());
|
||||
return (-1);
|
||||
}
|
||||
|
||||
CloseHandle(h);
|
||||
if (r == 0) {
|
||||
unzip_dosmaperr(GetLastError());
|
||||
return (-1);
|
||||
}
|
||||
|
||||
st->st_mode = S_IRUSR | S_IRGRP | S_IROTH;
|
||||
if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
|
||||
st->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
|
||||
if ((info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && is_link)
|
||||
st->st_mode |= S_IFLNK;
|
||||
else if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
|
||||
else {
|
||||
const wchar_t *p;
|
||||
|
||||
st->st_mode |= S_IFREG;
|
||||
p = wcsrchr(path, L'.');
|
||||
if (p != NULL && wcslen(p) == 4) {
|
||||
switch (p[1]) {
|
||||
case L'B': case L'b':
|
||||
if ((p[2] == L'A' || p[2] == L'a' ) &&
|
||||
(p[3] == L'T' || p[3] == L't' ))
|
||||
st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
|
||||
break;
|
||||
case L'C': case L'c':
|
||||
if (((p[2] == L'M' || p[2] == L'm' ) &&
|
||||
(p[3] == L'D' || p[3] == L'd' )))
|
||||
st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
|
||||
break;
|
||||
case L'E': case L'e':
|
||||
if ((p[2] == L'X' || p[2] == L'x' ) &&
|
||||
(p[3] == L'E' || p[3] == L'e' ))
|
||||
st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
st->st_atime = unzip_FILETIME_to_unix(&info.ftLastAccessTime);
|
||||
st->st_mtime = unzip_FILETIME_to_unix(&info.ftLastWriteTime);
|
||||
st->st_ctime = unzip_FILETIME_to_unix(&info.ftCreationTime);
|
||||
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 should 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);
|
||||
}
|
||||
|
||||
int
|
||||
lstat(const char *path, struct stat *st)
|
||||
{
|
||||
wchar_t *wcs;
|
||||
int r;
|
||||
|
||||
wcs = unzip_strtowcs(path);
|
||||
if (wcs == NULL)
|
||||
return (-1);
|
||||
|
||||
r = unzip_stat_w(wcs, 1, st);
|
||||
free(wcs);
|
||||
return r == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
unzip_unlink(const wchar_t *path)
|
||||
{
|
||||
wchar_t *fullname;
|
||||
int r;
|
||||
|
||||
r = _wunlink(path);
|
||||
if (r != 0 && GetLastError() == ERROR_INVALID_NAME) {
|
||||
fullname = unzip_win_permissive_name_w(path);
|
||||
r = _wunlink(fullname);
|
||||
free(fullname);
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
unzip_rmdir(const wchar_t *path)
|
||||
{
|
||||
wchar_t *fullname;
|
||||
int r;
|
||||
|
||||
r = _wrmdir(path);
|
||||
if (r != 0 && GetLastError() == ERROR_INVALID_NAME) {
|
||||
fullname = unzip_win_permissive_name_w(path);
|
||||
r = _wrmdir(fullname);
|
||||
free(fullname);
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create file or directory symbolic link
|
||||
*
|
||||
* Guess linktype from the link target
|
||||
*/
|
||||
static int
|
||||
unzip_CreateSymbolicLinkW(const wchar_t *linkname, const wchar_t *target) {
|
||||
BOOL ret = 0;
|
||||
#if _WIN32_WINNT < _WIN32_WINNT_VISTA ||\
|
||||
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||||
(void)linkname; /* UNUSED */
|
||||
(void)target; /* UNUSED */
|
||||
#else
|
||||
struct stat st;
|
||||
wchar_t *ttarget, *p;
|
||||
size_t len;
|
||||
DWORD attrs = 0;
|
||||
DWORD flags = 0;
|
||||
DWORD newflags = 0;
|
||||
|
||||
len = wcslen(target);
|
||||
if (len == 0) {
|
||||
errno = EINVAL;
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* When writing path targets, we need to translate slashes
|
||||
* to backslashes
|
||||
*/
|
||||
ttarget = malloc((len + 1) * sizeof(wchar_t));
|
||||
if (ttarget == NULL)
|
||||
return(0);
|
||||
|
||||
p = ttarget;
|
||||
|
||||
while(*target != L'\0') {
|
||||
if (*target == L'/')
|
||||
*p = L'\\';
|
||||
else
|
||||
*p = *target;
|
||||
target++;
|
||||
p++;
|
||||
}
|
||||
*p = L'\0';
|
||||
|
||||
/* Check target type if available. */
|
||||
if (unzip_stat_w(ttarget, 0, &st) == 0) {
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We guess symlink type from the target.
|
||||
* If the target equals ".", "..", ends with a backslash or a
|
||||
* backslash followed by "." or ".." we assume it is a directory
|
||||
* symlink. In all other cases we assume a file symlink.
|
||||
*/
|
||||
if (*(p - 1) == L'\\' || (*(p - 1) == L'.' && (
|
||||
len == 1 || *(p - 2) == L'\\' || ( *(p - 2) == L'.' && (
|
||||
len == 2 || *(p - 3) == L'\\'))))) {
|
||||
flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)
|
||||
newflags = flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
|
||||
#else
|
||||
newflags = flags | 0x2;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Windows won't overwrite existing links
|
||||
*/
|
||||
attrs = GetFileAttributesW(linkname);
|
||||
if (attrs != INVALID_FILE_ATTRIBUTES) {
|
||||
if (attrs & FILE_ATTRIBUTE_DIRECTORY)
|
||||
unzip_rmdir(linkname);
|
||||
else
|
||||
unzip_unlink(linkname);
|
||||
}
|
||||
|
||||
ret = CreateSymbolicLinkW(linkname, ttarget, newflags);
|
||||
/*
|
||||
* Prior to Windows 10 calling CreateSymbolicLinkW() will fail
|
||||
* if SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE is set
|
||||
*/
|
||||
if (!ret) {
|
||||
ret = CreateSymbolicLinkW(linkname, ttarget, flags);
|
||||
}
|
||||
free(ttarget);
|
||||
#endif
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
symlink(const char *target, const char *source)
|
||||
{
|
||||
wchar_t *wcsource, *wctarget;
|
||||
int r;
|
||||
|
||||
wcsource = unzip_strtowcs(source);
|
||||
wctarget = unzip_strtowcs(target);
|
||||
|
||||
if (wcsource != NULL && wctarget != NULL) {
|
||||
r = unzip_CreateSymbolicLinkW(wcsource, wctarget);
|
||||
if (r == 0)
|
||||
unzip_dosmaperr(GetLastError());
|
||||
} else {
|
||||
errno = ENOMEM;
|
||||
r = 0;
|
||||
}
|
||||
free(wcsource);
|
||||
free(wctarget);
|
||||
return r == 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
unzip_set_times(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) {
|
||||
unzip_dosmaperr(GetLastError());
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
futimes(int fd, const struct timeval *times)
|
||||
{
|
||||
return (unzip_set_times((HANDLE)_get_osfhandle(fd), times));
|
||||
}
|
||||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
int
|
||||
gettimeofday(struct timeval *tv, struct timezone *tz) {
|
||||
FILETIME ft;
|
||||
uint64_t time;
|
||||
|
||||
(void)tz; /* UNUSED */
|
||||
|
||||
GetSystemTimePreciseAsFileTime(&ft);
|
||||
time = unzip_FILETIME_to_unix(&ft);
|
||||
|
||||
tv->tv_sec = (long)(time / NTFS_TICKS);
|
||||
tv->tv_usec = (long)((time % NTFS_TICKS) / 10ULL);
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
lutimes(const char *path, const struct timeval *times)
|
||||
{
|
||||
HANDLE h;
|
||||
wchar_t *p;
|
||||
int link, ret;
|
||||
|
||||
p = unzip_strtowcs(path);
|
||||
if (p == NULL)
|
||||
return (-1);
|
||||
|
||||
h = unzip_get_handle(p, FILE_WRITE_ATTRIBUTES, 1, &link);
|
||||
ret = unzip_set_times(h, times);
|
||||
|
||||
free(p);
|
||||
CloseHandle(h);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following function was modified from PostgreSQL sources and is
|
||||
* subject to the copyright below.
|
||||
*/
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* win32error.c
|
||||
* Map win32 error codes to errno values
|
||||
*
|
||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/port/win32error.c,v 1.4 2008/01/01 19:46:00 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
PostgreSQL Database Management System
|
||||
(formerly known as Postgres, then as Postgres95)
|
||||
|
||||
Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||
|
||||
Portions Copyright (c) 1994, The Regents of the University of California
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose, without fee, and without a written agreement
|
||||
is hereby granted, provided that the above copyright notice and this
|
||||
paragraph and the following two paragraphs appear in all copies.
|
||||
|
||||
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
|
||||
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
|
||||
LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
|
||||
DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
|
||||
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
static const struct {
|
||||
DWORD winerr;
|
||||
int doserr;
|
||||
} doserrors[] =
|
||||
{
|
||||
{ ERROR_INVALID_FUNCTION, EINVAL },
|
||||
{ ERROR_FILE_NOT_FOUND, ENOENT },
|
||||
{ ERROR_PATH_NOT_FOUND, ENOENT },
|
||||
{ ERROR_TOO_MANY_OPEN_FILES, EMFILE },
|
||||
{ ERROR_ACCESS_DENIED, EACCES },
|
||||
{ ERROR_INVALID_HANDLE, EBADF },
|
||||
{ ERROR_ARENA_TRASHED, ENOMEM },
|
||||
{ ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
|
||||
{ ERROR_INVALID_BLOCK, ENOMEM },
|
||||
{ ERROR_BAD_ENVIRONMENT, E2BIG },
|
||||
{ ERROR_BAD_FORMAT, ENOEXEC },
|
||||
{ ERROR_INVALID_ACCESS, EINVAL },
|
||||
{ ERROR_INVALID_DATA, EINVAL },
|
||||
{ ERROR_INVALID_DRIVE, ENOENT },
|
||||
{ ERROR_CURRENT_DIRECTORY, EACCES },
|
||||
{ ERROR_NOT_SAME_DEVICE, EXDEV },
|
||||
{ ERROR_NO_MORE_FILES, ENOENT },
|
||||
{ ERROR_LOCK_VIOLATION, EACCES },
|
||||
{ ERROR_SHARING_VIOLATION, EACCES },
|
||||
{ ERROR_BAD_NETPATH, ENOENT },
|
||||
{ ERROR_NETWORK_ACCESS_DENIED, EACCES },
|
||||
{ ERROR_BAD_NET_NAME, ENOENT },
|
||||
{ ERROR_FILE_EXISTS, EEXIST },
|
||||
{ ERROR_CANNOT_MAKE, EACCES },
|
||||
{ ERROR_FAIL_I24, EACCES },
|
||||
{ ERROR_INVALID_PARAMETER, EINVAL },
|
||||
{ ERROR_NO_PROC_SLOTS, EAGAIN },
|
||||
{ ERROR_DRIVE_LOCKED, EACCES },
|
||||
{ ERROR_BROKEN_PIPE, EPIPE },
|
||||
{ ERROR_DISK_FULL, ENOSPC },
|
||||
{ ERROR_INVALID_TARGET_HANDLE, EBADF },
|
||||
{ ERROR_INVALID_HANDLE, EINVAL },
|
||||
{ ERROR_WAIT_NO_CHILDREN, ECHILD },
|
||||
{ ERROR_CHILD_NOT_COMPLETE, ECHILD },
|
||||
{ ERROR_DIRECT_ACCESS_HANDLE, EBADF },
|
||||
{ ERROR_NEGATIVE_SEEK, EINVAL },
|
||||
{ ERROR_SEEK_ON_DEVICE, EACCES },
|
||||
{ ERROR_DIR_NOT_EMPTY, ENOTEMPTY },
|
||||
{ ERROR_NOT_LOCKED, EACCES },
|
||||
{ ERROR_BAD_PATHNAME, ENOENT },
|
||||
{ ERROR_MAX_THRDS_REACHED, EAGAIN },
|
||||
{ ERROR_LOCK_FAILED, EACCES },
|
||||
{ ERROR_ALREADY_EXISTS, EEXIST },
|
||||
{ ERROR_FILENAME_EXCED_RANGE, ENOENT },
|
||||
{ ERROR_NESTING_NOT_ALLOWED, EAGAIN },
|
||||
{ ERROR_PRIVILEGE_NOT_HELD, EPERM },
|
||||
{ ERROR_NOT_ENOUGH_QUOTA, ENOMEM }
|
||||
};
|
||||
|
||||
static void
|
||||
unzip_dosmaperr(unsigned long e)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (e == 0)
|
||||
{
|
||||
errno = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)(sizeof(doserrors)/sizeof(doserrors[0])); i++)
|
||||
{
|
||||
if (doserrors[i].winerr == e)
|
||||
{
|
||||
errno = doserrors[i].doserr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* fprintf(stderr, "unrecognized win32 error code: %lu", e); */
|
||||
errno = EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2003-2010 Tim Kientzle
|
||||
* Copyright (c) 2003-2007 Kees Zeelenberg
|
||||
* Copyright (c) 2009-2012 Michihiro NAKAJIMA
|
||||
* Copyright (c) 2026 Tobias Stoeckmann
|
||||
* All rights reserved.
|
||||
*/
|
||||
#ifndef BSDUNZIP_WINDOWS_H
|
||||
#define BSDUNZIP_WINDOWS_H 1
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifdef HAVE_DIRECT_H
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
#ifndef _S_IFLNK
|
||||
#define _S_IFLNK 0120000 /* symbolic link */
|
||||
#endif
|
||||
#ifndef S_IFLNK
|
||||
#define S_IFLNK _S_IFLNK
|
||||
#endif
|
||||
|
||||
#ifndef S_ISDIR
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) /* directory */
|
||||
#endif
|
||||
#ifndef S_ISREG
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) /* regular file */
|
||||
#endif
|
||||
#ifndef S_ISLNK
|
||||
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) /* symbolic link */
|
||||
#endif
|
||||
|
||||
#ifndef STDOUT_FILENO
|
||||
#define STDOUT_FILENO 1
|
||||
#endif
|
||||
|
||||
#define HAVE_FUTIMES 1
|
||||
#define HAVE_LUTIMES 1
|
||||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
struct timezone {
|
||||
int tz_minuteswest;
|
||||
int tz_dsttime;
|
||||
};
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||
#endif
|
||||
|
||||
int futimes(int fd, const struct timeval *times);
|
||||
int lstat(const char *path, struct stat *st);
|
||||
int lutimes(const char *path, const struct timeval *times);
|
||||
int symlink(const char *target, const char *source);
|
||||
|
||||
#endif /* !BSDUNZIP_WINDOWS_H */
|
||||
+4
-4
@@ -13,13 +13,10 @@
|
||||
/* Test I arg - file name encoding */
|
||||
DEFINE_TEST(test_I)
|
||||
{
|
||||
const char *reffile = "test_I.zip";
|
||||
#if !defined(_WIN32) || defined(__CYGWIN__)
|
||||
const char *reffile = "test_I.zip";
|
||||
const char *envstr = "env LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 "
|
||||
"LC_CTYPE=en_US.UTF-8";
|
||||
#else
|
||||
const char *envstr = "";
|
||||
#endif
|
||||
int r;
|
||||
|
||||
#if HAVE_SETLOCALE
|
||||
@@ -39,4 +36,7 @@ DEFINE_TEST(test_I)
|
||||
assertEmptyFile("test.err");
|
||||
|
||||
assertTextFileContents("Hello, World!\n", "Γειά σου Κόσμε.txt");
|
||||
#else
|
||||
skipping("Windows not supported");
|
||||
#endif
|
||||
}
|
||||
Reference in new issue
Block a user