写在开头:
最近的copy项目要转到windows版本了,一直在跟进做这个事情。
直入主题说下移植过程中可能涉及以下几个方面的调整:
- 编译器和工具链的更改:Windows和Linux使用不同的编译器和工具链,因此需要在Windows上安装和配置相应的编译器和工具链。
- 文件路径和文件系统的更改:Windows和Linux使用不同的文件系统,路径分隔符也不同。因此,需要更改应用程序中使用的文件路径和文件系统相关的代码。
- 库文件和依赖项的更改:应用程序可能会依赖于Linux上特定的库文件和依赖项,这些在Windows上可能不存在或与Linux上的版本不兼容。因此,需要更改代码以使用适当的库文件和依赖项。
- 网络接口的更改:Linux和Windows上的网络接口也有所不同,因此需要更改应用程序中使用的网络接口相关的代码。
- 系统调用的更改:Linux和Windows上的系统调用也不同,因此需要更改应用程序中使用的系统调用相关的代码。
- 测试和调试:移植完成后需要进行测试和调试,以确保应用程序在Windows上能够正常运行。
针对以上方向总结细节:
- 检查源代码是否使用了Linux特有的API或库。
- 文件系统相关
-
Linux下面,文件换行是"\n",而windows下面是"\r\n"。
-
Linux下面,目录分隔符是"/",而windows下面是"\"。
-
Linux中可根据stat的st_mode判断文件类型,有S_ISREG、S_ISDIR等宏。
-
Windows中没有,需要自己定义相应的宏,如#define S_ISREG(m) (((m) & 0170000) == (0100000))#define S_ISDIR(m) (((m) & 0170000) == (0040000))
-
-
Linux中删除文件是unlink,Windows中为DeleteFile
- 在Windows平台上,可以使用ReadDirectoryChangesW API来监控文件变更
-
扫描本地目录
FindFirstFile
和FindNextFile方法?
-
- 网络相关
- linux包含#include <sys/socket.h>、#include <netinet/in.h>、#include <netdb.h>、#include <arpa/inet.h>
windows需要包含#include <winsock.h> - #pragma comment (lib, “ws2_32.lib”) //加载 ws2_32.dll windows socket需要在加载头文件后,加载ws库
- windows需要初始化socket,调用WSAStartup方法。
- Linux中关闭socket为close,Windows中为closesocket。
- 因为linux中的socket与普通的fd一样,所以可以在TCP的socket中,发送与接收数据时,直接使用read和write。windows使用recv和send。
- Linux 使用“文件描述符”的概念,而 Windows 使用“文件句柄”的概念;Linux 不区分 socket 文件和普通文件,而 Windows 区分;
- Linux 下 socket() 函数的返回值为 int 类型,而 Windows 下为 SOCKET 类型,也就是句柄。
-
设置socet选项,比如设置socket为非阻塞的。
-
Linux下为flag = fcntl (fd, F_GETFL);fcntl (fd, F_SETFL, flag | O_NONBLOCK);
-
Windows下为flag = 1;ioctlsocket (fd, FIONBIO, (unsigned long *) &flag);
-
当非阻塞socket的TCP连接正在进行时,Linux的错误号为EINPROGRESS,Windows的错误号为WSAEWOULDBLOCK。
-
- linux包含#include <sys/socket.h>、#include <netinet/in.h>、#include <netdb.h>、#include <arpa/inet.h>
- 多线程
- 头文件(win)process.h --〉(linux)pthread.h
方法_beginthread --> pthread_create
_endthread --> pthread_exit
- 头文件(win)process.h --〉(linux)pthread.h
- 其他
- Linux为srandom和random,Windows为srand和rand。
- Linux为snprintf,Windows为_snprintf。
- Linux为strcasecmp,Windows为_stricmp。
- Linux下面,通常使用全局变量errno来表示函数执行的错误号。Windows下要使用GetLastError ()调用来取得。
- 文件系统相关
-
修改源代码中的环境变量访问方式。
-
确保代码中没有使用Linux下的特殊权限或用户组。
-
如果程序依赖于外部工具或脚本,需要在Windows上安装这些工具并修改调用方式。
-
编写或修改Makefile和编译脚本,使其可以在Windows下编译。
另外:
还可以采用一些工具和技术来帮助移植过程,如使用跨平台的开发工具和集成开发环境(如Visual Studio等)来帮助在Windows平台上进行代码编译和调试,以及使用虚拟化技术来模拟Linux环境以便在Windows上进行程序测试和调试。还有一些第三方的代码转换工具和库可以帮助实现代码的移植和兼容性处理。
总的来说,将Linux代码转移到Windows平台是一个复杂的过程,需要对操作系统和编程语言的细节有深入的了解。通过合理的准备工作和采用适当的工具和技术,可以实现Linux代码向Windows的转换和移植,从而让应用程序能够在不同平台上进行部署和运行。
所以总共有两个方向(使用虚拟化技术模拟linux环境或者vs),三个思路。
方向一
安装gcc,使用vscode
1、windows下安装 MinGW
此方法是说 gcc没有对windows的支撑,MinGW(mini gnu windows) 对gcc进行了打包封装,使其可以在windows上适用,它包含了make、gcc。
2、使用mingw32-make 编译
3、处理编译问题
方案二
由于代码量不大,可以考虑使用visual stdio。
1、在visual stdio下新建解决方案,zcopy,并新建两个项目 zcopy和 zcopy-ctl
2、将zcopy和zcopy-ctl项目引入代码。
解决方案可以设置启动项目,分别调试和启动,目前zcopy和ctl代码在一个项目,很不方便,所以考虑分开两个项目。
3、编译两个工程处理编译问题。
4、如果用MSVC编译开源库麻烦在于第三方的开源库本身还需要一些依赖库,这些依赖库在windows多数并不提供编译好的二进制版本,所以要先编译安装各种依赖库。
方案三
使用msys2的虚拟化环境
MSYS2 是msys2的一个升级版,准确的说是集成了pacman 和mingw-w64的 cygwin 升级版, 与MSYS最大的区别是移植了 linux的软件包管理系统 pacman(其实是与Cygwin的区别)。
但是我使用这个环境的时候,没有想象中好用,我们项目的支持需要openssl、libevent、glib等支持。前两者适配还好,后面第三个可能是版本问题一直有编译问题。
最终决定:
使用vs的IDE来做这个事情,原因有两点:
- 方案1、2第三方虽然说做了很久的支持,但是毕竟微软不是开源的,所以用vs来做应该更靠谱一些,不会出现一些无法解决的问题
- 组里人大部分都一直做linux,想感受win的开发环境和方法。哈哈哈哈哈~
完美的解决思路是什么:
win_port
include
dirent.c
/*-------------------------------------------------------------------------
*
* dirent.c
* opendir/readdir/closedir for win32/msvc
*
*-------------------------------------------------------------------------
*/
#include <win32_port.h>
#include <dirent.h>
struct DIR
{
char *dirname;
struct dirent ret; /* Used to return to caller */
HANDLE handle;
};
DIR *
opendir(const char *dirname)
{
DWORD attr;
DIR *d;
/* Make sure it is a directory */
attr = GetFileAttributes(dirname);
if (attr == INVALID_FILE_ATTRIBUTES)
{
errno = ENOENT;
return NULL;
}
if ((attr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
{
errno = ENOTDIR;
return NULL;
}
d = malloc(sizeof(DIR));
if (!d)
{
errno = ENOMEM;
return NULL;
}
d->dirname = malloc(strlen(dirname) + 4);
if (!d->dirname)
{
errno = ENOMEM;
free(d);
return NULL;
}
strcpy(d->dirname, dirname);
if (d->dirname[strlen(d->dirname) - 1] != '/' &&
d->dirname[strlen(d->dirname) - 1] != '\\')
strcat(d->dirname, "\\"); /* Append backslash if not already there */
strcat(d->dirname, "*"); /* Search for entries named anything */
d->handle = INVALID_HANDLE_VALUE;
d->ret.d_ino = 0; /* no inodes on win32 */
d->ret.d_reclen = 0; /* not used on win32 */
d->ret.d_type = DT_UNKNOWN;
return d;
}
struct dirent *
readdir(DIR *d)
{
WIN32_FIND_DATA fd;
if (d->handle == INVALID_HANDLE_VALUE)
{
d->handle = FindFirstFile(d->dirname, &fd);
if (d->handle == INVALID_HANDLE_VALUE)
{
/* If there are no files, force errno=0 (unlike mingw) */
if (GetLastError() == ERROR_FILE_NOT_FOUND)
errno = 0;
else
_dosmaperr(GetLastError());
return NULL;
}
}
else
{
if (!FindNextFile(d->handle, &fd))
{
/* If there are no more files, force errno=0 (like mingw) */
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
else
_dosmaperr(GetLastError());
return NULL;
}
}
strcpy(d->ret.d_name, fd.cFileName); /* Both strings are MAX_PATH long */
d->ret.d_namlen = strlen(d->ret.d_name);
/*
* For reparse points dwReserved0 field will contain the ReparseTag. We
* check this first, because reparse points are also reported as
* directories.
*/
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0 &&
(fd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT))
d->ret.d_type = DT_LNK;
else if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
d->ret.d_type = DT_DIR;
else
d->ret.d_type = DT_REG;
return &d->ret;
}
int
closedir(DIR *d)
{
int ret = 0;
if (d->handle != INVALID_HANDLE_VALUE)
ret = !FindClose(d->handle);
free(d->dirname);
free(d);
return ret;
}
dirmod.c
/*-------------------------------------------------------------------------
*
* dirmod.c
* directory handling functions
*
* This includes replacement versions of functions that work on
* Windows.
*
*-------------------------------------------------------------------------
*/
#include <win32_port.h>
/* Don't modify declarations in system headers */
#undef rename
#undef unlink
#include <winioctl.h>
#include <stddef.h>
void
z_usleep(long microsec)
{
if (microsec > 0)
{
SleepEx((microsec < 500 ? 1 : (microsec + 500) / 1000), FALSE);
}
}
/*
* zrename
*/
int
zrename(const char *from, const char *to)
{
int loops = 0;
/*
* We need to loop because even though PostgreSQL uses flags that allow
* rename while the file is open, other applications might have the file
* open without those flags. However, we won't wait indefinitely for
* someone else to close the file, as the caller might be holding locks
* and blocking other backends.
*/
while (!MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING))
{
DWORD err = GetLastError();
_dosmaperr(err);
/*
* Modern NT-based Windows versions return ERROR_SHARING_VIOLATION if
* another process has the file open without FILE_SHARE_DELETE.
* ERROR_LOCK_VIOLATION has also been seen with some anti-virus
* software. This used to check for just ERROR_ACCESS_DENIED, so
* presumably you can get that too with some OS versions. We don't
* expect real permission errors where we currently use rename().
*/
if (err != ERROR_ACCESS_DENIED &&
err != ERROR_SHARING_VIOLATION &&
err != ERROR_LOCK_VIOLATION)
return -1;
if (++loops > 100) /* time out after 10 sec */
return -1;
z_usleep(100000); /* us */
}
return 0;
}
/*
* zunlink
*/
int
zunlink(const char *path)
{
BOOL is_lnk;
int loops = 0;
struct stat st;
/*
* This function might be called for a regular file or for a junction
* point (which we use to emulate symlinks). The latter must be unlinked
* with rmdir() on Windows. Before we worry about any of that, let's see
* if we can unlink directly, since that's expected to be the most common
* case.
*/
if (unlink(path) == 0)
return 0;
if (errno != EACCES)
return -1;
/*
* EACCES is reported for many reasons including unlink() of a junction
* point. Check if that's the case so we can redirect to rmdir().
*
* Note that by checking only once, we can't cope with a path that changes
* from regular file to junction point underneath us while we're retrying
* due to sharing violations, but that seems unlikely. We could perhaps
* prevent that by holding a file handle ourselves across the lstat() and
* the retry loop, but that seems like over-engineering for now.
*
* In the special case of a STATUS_DELETE_PENDING error (file already
* unlinked, but someone still has it open), we don't want to report
* ENOENT to the caller immediately, because rmdir(parent) would probably
* fail. We want to wait until the file truly goes away so that simple
* recursive directory unlink algorithms work.
*/
if (lstat(path, &st) < 0)
{
// if (lstat_error_was_status_delete_pending())
// is_lnk = false;
// else
return -1;
}
else
is_lnk = S_ISLNK(st.st_mode);
/*
* We need to loop because even though PostgreSQL uses flags that allow
* unlink while the file is open, other applications might have the file
* open without those flags. However, we won't wait indefinitely for
* someone else to close the file, as the caller might be holding locks
* and blocking other backends.
*/
while ((is_lnk ? rmdir(path) : unlink(path)) < 0)
{
if (errno != EACCES)
return -1;
if (++loops > 100) /* time out after 10 sec */
return -1;
z_usleep(100000); /* us */
}
return 0;
}
/* We undefined these above; now redefine for possible use below */
#define rename(from, to) zrename(from, to)
#define unlink(path) zunlink(path)
/*
* zsymlink support:
*
* This struct is a replacement for REPARSE_DATA_BUFFER which is defined in VC6 winnt.h
* but omitted in later SDK functions.
* We only need the SymbolicLinkReparseBuffer part of the original struct's union.
*/
typedef struct
{
DWORD ReparseTag;
WORD ReparseDataLength;
WORD Reserved;
/* SymbolicLinkReparseBuffer */
WORD SubstituteNameOffset;
WORD SubstituteNameLength;
WORD PrintNameOffset;
WORD PrintNameLength;
WCHAR PathBuffer[FLEXIBLE_ARRAY_MEMBER];
} REPARSE_JUNCTION_DATA_BUFFER;
#define REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE \
FIELD_OFFSET(REPARSE_JUNCTION_DATA_BUFFER, SubstituteNameOffset)
/*
* zsymlink - uses Win32 junction points
*
* For reference: http://www.codeproject.com/KB/winsdk/junctionpoints.aspx
*/
int
zsymlink(const char *oldpath, const char *newpath)
{
HANDLE dirhandle;
DWORD len;
char buffer[MAX_PATH * sizeof(WCHAR) + offsetof(REPARSE_JUNCTION_DATA_BUFFER, PathBuffer)];
char nativeTarget[MAX_PATH];
char *p = nativeTarget;
REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
CreateDirectory(newpath, 0);
dirhandle = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE,
0, 0, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0);
if (dirhandle == INVALID_HANDLE_VALUE)
{
_dosmaperr(GetLastError());
return -1;
}
/* make sure we have an unparsed native win32 path */
if (memcmp("\\??\\", oldpath, 4) != 0)
snprintf(nativeTarget, sizeof(nativeTarget), "\\??\\%s", oldpath);
else
strlcpy(nativeTarget, oldpath, sizeof(nativeTarget));
while ((p = strchr(p, '/')) != NULL)
*p++ = '\\';
len = strlen(nativeTarget) * sizeof(WCHAR);
reparseBuf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
reparseBuf->ReparseDataLength = len + 12;
reparseBuf->Reserved = 0;
reparseBuf->SubstituteNameOffset = 0;
reparseBuf->SubstituteNameLength = len;
reparseBuf->PrintNameOffset = len + sizeof(WCHAR);
reparseBuf->PrintNameLength = 0;
MultiByteToWideChar(CP_ACP, 0, nativeTarget, -1,
reparseBuf->PathBuffer, MAX_PATH);
/*
* FSCTL_SET_REPARSE_POINT is coded differently depending on SDK version;
* we use our own definition
*/
if (!DeviceIoControl(dirhandle,
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_ANY_ACCESS),
reparseBuf,
reparseBuf->ReparseDataLength + REPARSE_JUNCTION_DATA_BUFFER_HEADER_SIZE,
0, 0, &len, 0))
{
LPSTR msg;
int save_errno;
_dosmaperr(GetLastError());
save_errno = errno;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
(LPSTR) &msg, 0, NULL);
printf( "could not set junction for \"%s\": %s\n", nativeTarget, msg);
LocalFree(msg);
CloseHandle(dirhandle);
RemoveDirectory(newpath);
errno = save_errno;
return -1;
}
CloseHandle(dirhandle);
return 0;
}
/*
* zreadlink - uses Win32 junction points
*/
int
zreadlink(const char *path, char *buf, size_t size)
{
DWORD attr;
HANDLE h;
char buffer[MAX_PATH * sizeof(WCHAR) + offsetof(REPARSE_JUNCTION_DATA_BUFFER, PathBuffer)];
REPARSE_JUNCTION_DATA_BUFFER *reparseBuf = (REPARSE_JUNCTION_DATA_BUFFER *) buffer;
DWORD len;
int r;
attr = GetFileAttributes(path);
if (attr == INVALID_FILE_ATTRIBUTES)
{
_dosmaperr(GetLastError());
return -1;
}
if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
{
errno = EINVAL;
return -1;
}
h = CreateFile(path,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
0);
if (h == INVALID_HANDLE_VALUE)
{
_dosmaperr(GetLastError());
return -1;
}
if (!DeviceIoControl(h,
FSCTL_GET_REPARSE_POINT,
NULL,
0,
(LPVOID) reparseBuf,
sizeof(buffer),
&len,
NULL))
{
LPSTR msg;
errno = 0;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
(LPSTR) &msg, 0, NULL);
printf("could not get junction for \"%s\": %s\n",path, msg);
LocalFree(msg);
CloseHandle(h);
errno = EINVAL;
return -1;
}
CloseHandle(h);
/* Got it, let's get some results from this */
if (reparseBuf->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
{
errno = EINVAL;
return -1;
}
r = WideCharToMultiByte(CP_ACP, 0,
reparseBuf->PathBuffer, -1,
buf,
size,
NULL, NULL);
if (r <= 0)
{
errno = EINVAL;
return -1;
}
/* r includes the null terminator */
r -= 1;
/*
* If the path starts with "\??\" followed by a "drive absolute" path
* (known to Windows APIs as RtlPathTypeDriveAbsolute), then strip that
* prefix. This undoes some of the transformation performed by
* zsymlink(), to get back to a format that users are used to seeing. We
* don't know how to transform other path types that might be encountered
* outside data, so we just return them directly.
*/
if (r >= 7 &&
buf[0] == '\\' &&
buf[1] == '?' &&
buf[2] == '?' &&
buf[3] == '\\' &&
isalpha(buf[4]) &&
buf[5] == ':' &&
buf[6] == '\\')
{
memmove(buf, buf + 4, strlen(buf + 4) + 1);
r -= 4;
}
return r;
}
int
fileExist(char* path)
{
DWORD fileAttr = GetFileAttributes(path);
return (fileAttr == INVALID_FILE_ATTRIBUTES ? -1 : 0);
}
open.c
/*-------------------------------------------------------------------------
*
* open.c
* Win32 open() replacement
*
*-------------------------------------------------------------------------
*/
#include <win32_port.h>
#include <win32ntdll.h>
#include <fcntl.h>
#include <assert.h>
/*
* zwin32_get_file_type
*
* Convenience wrapper for GetFileType() with specific error handling for all the
* port implementations. Returns the file type associated with a HANDLE.
*
* On error, sets errno with FILE_TYPE_UNKNOWN as file type.
*/
DWORD
zwin32_get_file_type(HANDLE hFile)
{
DWORD fileType = FILE_TYPE_UNKNOWN;
DWORD lastError;
errno = 0;
/*
* When stdin, stdout, and stderr aren't associated with a stream the
* special value -2 is returned:
* https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle
*/
if (hFile == INVALID_HANDLE_VALUE || hFile == (HANDLE)-2)
{
errno = EINVAL;
return FILE_TYPE_UNKNOWN;
}
fileType = GetFileType(hFile);
lastError = GetLastError();
/*
* Invoke GetLastError in order to distinguish between a "valid" return of
* FILE_TYPE_UNKNOWN and its return due to a calling error. In case of
* success, GetLastError() returns NO_ERROR.
*/
if (fileType == FILE_TYPE_UNKNOWN && lastError != NO_ERROR)
{
_dosmaperr(lastError);
return FILE_TYPE_UNKNOWN;
}
return fileType;
}
static int
openFlagsToCreateFileFlags(int openFlags)
{
switch (openFlags & (O_CREAT | O_TRUNC | O_EXCL))
{
/* O_EXCL is meaningless without O_CREAT */
case 0:
case O_EXCL:
return OPEN_EXISTING;
case O_CREAT:
return OPEN_ALWAYS;
/* O_EXCL is meaningless without O_CREAT */
case O_TRUNC:
case O_TRUNC | O_EXCL:
return TRUNCATE_EXISTING;
case O_CREAT | O_TRUNC:
return CREATE_ALWAYS;
/* O_TRUNC is meaningless with O_CREAT */
case O_CREAT | O_EXCL:
case O_CREAT | O_TRUNC | O_EXCL:
return CREATE_NEW;
}
/* will never get here */
return 0;
}
/*
* Internal function used by zwin32_open() and zstat64(). When
* backup_semantics is true, directories may be opened (for limited uses). On
* failure, INVALID_HANDLE_VALUE is returned and errno is set.
*/
HANDLE
zwin32_open_handle(const char *fileName, int fileFlags, bool backup_semantics)
{
HANDLE h;
SECURITY_ATTRIBUTES sa;
int loops = 0;
if (initialize_ntdll() < 0)
return INVALID_HANDLE_VALUE;
/* Check that we can handle the request */
assert((fileFlags & ((O_RDONLY | O_WRONLY | O_RDWR) | O_APPEND |
(O_RANDOM | O_SEQUENTIAL | O_TEMPORARY) |
_O_SHORT_LIVED | O_DSYNC | O_DIRECT |
(O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags);
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
while ((h = CreateFile(fileName,
/* cannot use O_RDONLY, as it == 0 */
(fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :
((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ),
/* These flags allow concurrent rename/unlink */
(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
&sa,
openFlagsToCreateFileFlags(fileFlags),
FILE_ATTRIBUTE_NORMAL |
(backup_semantics ? FILE_FLAG_BACKUP_SEMANTICS : 0) |
((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) |
((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) |
((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) |
((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0) |
((fileFlags & O_DIRECT) ? FILE_FLAG_NO_BUFFERING : 0) |
((fileFlags & O_DSYNC) ? FILE_FLAG_WRITE_THROUGH : 0),
NULL)) == INVALID_HANDLE_VALUE)
{
/*
* Sharing violation or locking error can indicate antivirus, backup
* or similar software that's locking the file. Wait a bit and try
* again, giving up after 30 seconds.
*/
DWORD err = GetLastError();
if (err == ERROR_SHARING_VIOLATION ||
err == ERROR_LOCK_VIOLATION)
{
printf("could not open file \"%s\": %s", fileName,
(err == ERROR_SHARING_VIOLATION) ? "sharing violation" : "lock violation");
if (loops < 300)
{
z_usleep(100000);
loops++;
continue;
}
}
/*
* ERROR_ACCESS_DENIED is returned if the file is deleted but not yet
* gone (Windows NT status code is STATUS_DELETE_PENDING). In that
* case, we'd better ask for the NT status too so we can translate it
* to a more Unix-like error. We hope that nothing clobbers the NT
* status in between the internal NtCreateFile() call and CreateFile()
* returning.
*
* If there's no O_CREAT flag, then we'll pretend the file is
* invisible. With O_CREAT, we have no choice but to report that
* there's a file in the way (which wouldn't happen on Unix).
*/
if (err == ERROR_ACCESS_DENIED &&
zx_RtlGetLastNtStatus() == STATUS_DELETE_PENDING)
{
if (fileFlags & O_CREAT)
err = ERROR_FILE_EXISTS;
else
err = ERROR_FILE_NOT_FOUND;
}
_dosmaperr(err);
return INVALID_HANDLE_VALUE;
}
return h;
}
int
zwin32_open(const char *fileName, int fileFlags,...)
{
HANDLE h;
int fd;
h = zwin32_open_handle(fileName, fileFlags, false);
if (h == INVALID_HANDLE_VALUE)
return -1;
/* _open_osfhandle will, on error, set errno accordingly */
if ((fd = _open_osfhandle((intptr_t) h, fileFlags & O_APPEND)) < 0)
CloseHandle(h); /* will not affect errno */
else if (fileFlags & (O_TEXT | O_BINARY) &&
_setmode(fd, fileFlags & (O_TEXT | O_BINARY)) < 0)
{
_close(fd);
return -1;
}
return fd;
}
FILE *
zwin32_fopen(const char *fileName, const char *mode)
{
int openmode = 0;
int fd;
if (strstr(mode, "r+"))
openmode |= O_RDWR;
else if (strchr(mode, 'r'))
openmode |= O_RDONLY;
if (strstr(mode, "w+"))
openmode |= O_RDWR | O_CREAT | O_TRUNC;
else if (strchr(mode, 'w'))
openmode |= O_WRONLY | O_CREAT | O_TRUNC;
if (strchr(mode, 'a'))
openmode |= O_WRONLY | O_CREAT | O_APPEND;
if (strchr(mode, 'b'))
openmode |= O_BINARY;
if (strchr(mode, 't'))
openmode |= O_TEXT;
fd = zwin32_open(fileName, openmode);
if (fd == -1)
return NULL;
return _fdopen(fd, mode);
}
pthread-win32.c
#include <win32_port.h>
#include <pthread-win32.h>
DWORD
pthread_self()
{
return GetCurrentThreadId();
}
void
pthread_setspecific(pthread_key_t key, void *val)
{
}
void *
pthread_getspecific(pthread_key_t key)
{
return 0;
}
int
pthread_mutex_init(pthread_mutex_t *mp, void *attr)
{
mp->initstate = 0;
return 0;
}
int
pthread_mutex_lock(pthread_mutex_t *mp)
{
/* Initialize the csection if not already done */
if (mp->initstate != 1)
{
LONG istate;
while ((istate = InterlockedExchange(&mp->initstate, 2)) == 2)
Sleep(0); /* wait, another thread is doing this */
if (istate != 1)
InitializeCriticalSection(&mp->csection);
InterlockedExchange(&mp->initstate, 1);
}
EnterCriticalSection(&mp->csection);
return 0;
}
int
pthread_mutex_unlock(pthread_mutex_t *mp)
{
if (mp->initstate != 1)
return EINVAL;
LeaveCriticalSection(&mp->csection);
return 0;
}
strlcpy.c
/*-------------------------------------------------------------------------
*
* strlcpy.c
* strncpy done right
*
*
* This file was taken from OpenBSD and is used on platforms that don't
* provide strlcpy(). The OpenBSD copyright terms follow.
*-------------------------------------------------------------------------
*/
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <win32_port.h>
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
* Function creation history: http://www.gratisoft.us/todd/papers/strlcpy.html
*/
size_t
strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0)
{
while (--n != 0)
{
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0)
{
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return (s - src - 1); /* count does not include NUL */
}
system.c
/*-------------------------------------------------------------------------
*
* system.c
* Win32 system() and popen() replacements
*
*
* Win32 needs double quotes at the beginning and end of system()
* strings. If not, it gets confused with multiple quoted strings.
* It also requires double-quotes around the executable name and
* any files used for redirection. Filter other args through
* appendShellString() to quote them.
*
* Generated using Win32 "CMD /?":
*
* 1. If all of the following conditions are met, then quote characters
* on the command line are preserved:
*
* - no /S switch
* - exactly two quote characters
* - no special characters between the two quote characters, where special
* is one of: &<>()@^|
* - there are one or more whitespace characters between the two quote
* characters
* - the string between the two quote characters is the name of an
* executable file.
*
* 2. Otherwise, old behavior is to see if the first character is a quote
* character and if so, strip the leading character and remove the last
* quote character on the command line, preserving any text after the last
* quote character.
*
*-------------------------------------------------------------------------
*/
#include <win32_port.h>
#include <fcntl.h>
#undef system
#undef popen
int
zwin32_system(const char *command)
{
size_t cmdlen = strlen(command);
char *buf;
int save_errno;
int res;
/*
* Create a malloc'd copy of the command string, enclosed with an extra
* pair of quotes
*/
buf = malloc(cmdlen + 2 + 1);
if (buf == NULL)
{
errno = ENOMEM;
return -1;
}
buf[0] = '"';
memcpy(&buf[1], command, cmdlen);
buf[cmdlen + 1] = '"';
buf[cmdlen + 2] = '\0';
res = system(buf);
save_errno = errno;
free(buf);
errno = save_errno;
return res;
}
FILE *
zwin32_popen(const char *command, const char *type)
{
size_t cmdlen = strlen(command);
char *buf;
int save_errno;
FILE *res;
/*
* Create a malloc'd copy of the command string, enclosed with an extra
* pair of quotes
*/
buf = malloc(cmdlen + 2 + 1);
if (buf == NULL)
{
errno = ENOMEM;
return NULL;
}
buf[0] = '"';
memcpy(&buf[1], command, cmdlen);
buf[cmdlen + 1] = '"';
buf[cmdlen + 2] = '\0';
res = _popen(buf, type);
save_errno = errno;
free(buf);
errno = save_errno;
return res;
}
win32error.c
/*-------------------------------------------------------------------------
*
* win32error.c
* Map win32 error codes to errno values
*
*-------------------------------------------------------------------------
*/
#include <win32_port.h>
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_NOT_ENOUGH_QUOTA, ENOMEM
},
{
ERROR_DELETE_PENDING, ENOENT
},
{
ERROR_INVALID_NAME, ENOENT
},
{
ERROR_CANT_RESOLVE_FILENAME, ENOENT
}
};
void
_dosmaperr(unsigned long e)
{
int i;
if (e == 0)
{
errno = 0;
return;
}
for (i = 0; i < lengthof(doserrors); i++)
{
if (doserrors[i].winerr == e)
{
int doserr = doserrors[i].doserr;
printf("mapped win32 error code %lu to %d", e, doserr);
errno = doserr;
return;
}
}
printf("unrecognized win32 error code: %lu",e);
errno = EINVAL;
}
win32ntdll.c
/*-------------------------------------------------------------------------
*
* win32ntdll.c
* Dynamically loaded Windows NT functions.
*
*
*-------------------------------------------------------------------------
*/
#include <win32_port.h>
#include <win32ntdll.h>
RtlGetLastNtStatus_t zx_RtlGetLastNtStatus;
RtlNtStatusToDosError_t zx_RtlNtStatusToDosError;
NtFlushBuffersFileEx_t zx_NtFlushBuffersFileEx;
typedef struct NtDllRoutine
{
const char *name;
FARPROC address;
} NtDllRoutine;
static const NtDllRoutine routines[] = {
{"RtlGetLastNtStatus", (FARPROC) &zx_RtlGetLastNtStatus},
{"RtlNtStatusToDosError", (FARPROC) &zx_RtlNtStatusToDosError},
{"NtFlushBuffersFileEx", (FARPROC) &zx_NtFlushBuffersFileEx}
};
static bool initialized;
int
initialize_ntdll(void)
{
HMODULE module;
if (initialized)
return 0;
if (!(module = LoadLibraryEx("ntdll.dll", NULL, 0)))
{
_dosmaperr(GetLastError());
return -1;
}
for (int i = 0; i < lengthof(routines); ++i)
{
FARPROC address;
address = (FARPROC) GetProcAddress(module, routines[i].name);
if (!address)
{
_dosmaperr(GetLastError());
FreeLibrary(module);
return -1;
}
*(FARPROC*) routines[i].address = address;
}
initialized = true;
return 0;
}
win32stat.c
/*-------------------------------------------------------------------------
*
* win32stat.c
* Replacements for <sys/stat.h> functions using GetFileInformationByHandle
*
*-------------------------------------------------------------------------
*/
#include <win32_port.h>
#include "ztype.h"
#include <fcntl.h>
/*
* Convert a FILETIME struct into a 64 bit time_t.
*/
static __time64_t
filetime_to_time(const FILETIME *ft)
{
ULARGE_INTEGER unified_ft = {0};
static const uint64_t EpochShift = UINT64CONST(116444736000000000);
unified_ft.LowPart = ft->dwLowDateTime;
unified_ft.HighPart = ft->dwHighDateTime;
if (unified_ft.QuadPart < EpochShift)
return -1;
unified_ft.QuadPart -= EpochShift;
unified_ft.QuadPart /= 10 * 1000 * 1000;
return unified_ft.QuadPart;
}
/*
* Convert WIN32 file attributes to a Unix-style mode.
*
* Only owner permissions are set.
*/
static unsigned short
fileattr_to_unixmode(int attr)
{
unsigned short uxmode = 0;
uxmode |= (unsigned short) ((attr & FILE_ATTRIBUTE_DIRECTORY) ?
(_S_IFDIR) : (_S_IFREG));
uxmode |= (unsigned short) ((attr & FILE_ATTRIBUTE_READONLY) ?
(_S_IREAD) : (_S_IREAD | _S_IWRITE));
/* there is no need to simulate _S_IEXEC using CMD's PATHEXT extensions */
uxmode |= _S_IEXEC;
return uxmode;
}
/*
* Convert WIN32 file information (from a HANDLE) to a struct stat.
*/
static int
fileinfo_to_stat(HANDLE hFile, struct stat *buf)
{
BY_HANDLE_FILE_INFORMATION fiData;
memset(buf, 0, sizeof(*buf));
/*
* GetFileInformationByHandle minimum supported version: Windows XP and
* Windows Server 2003, so it exists everywhere we care about.
*/
if (!GetFileInformationByHandle(hFile, &fiData))
{
_dosmaperr(GetLastError());
return -1;
}
if (fiData.ftLastWriteTime.dwLowDateTime ||
fiData.ftLastWriteTime.dwHighDateTime)
buf->st_mtime = filetime_to_time(&fiData.ftLastWriteTime);
if (fiData.ftLastAccessTime.dwLowDateTime ||
fiData.ftLastAccessTime.dwHighDateTime)
buf->st_atime = filetime_to_time(&fiData.ftLastAccessTime);
else
buf->st_atime = buf->st_mtime;
if (fiData.ftCreationTime.dwLowDateTime ||
fiData.ftCreationTime.dwHighDateTime)
buf->st_ctime = filetime_to_time(&fiData.ftCreationTime);
else
buf->st_ctime = buf->st_mtime;
buf->st_mode = fileattr_to_unixmode(fiData.dwFileAttributes);
buf->st_nlink = fiData.nNumberOfLinks;
buf->st_size = ((((uint64_t) fiData.nFileSizeHigh) << 32) |
fiData.nFileSizeLow);
return 0;
}
/*
* Windows implementation of lstat().
*/
int
zlstat64(const char *name, struct stat *buf)
{
/*
* Our open wrapper will report STATUS_DELETE_PENDING as ENOENT. We
* request FILE_FLAG_BACKUP_SEMANTICS so that we can open directories too,
* for limited purposes. We use the private handle-based version, so we
* don't risk running out of fds.
*/
HANDLE hFile;
int ret;
hFile = zwin32_open_handle(name, O_RDONLY, true);
if (hFile == INVALID_HANDLE_VALUE)
{
if (errno == ENOENT)
{
/*
* If it's a junction point pointing to a non-existent path, we'll
* have ENOENT here (because zwin32_open_handle does not use
* FILE_FLAG_OPEN_REPARSE_POINT). In that case, we'll try again
* with readlink() below, which will distinguish true ENOENT from
* pseudo-symlink.
*/
memset(buf, 0, sizeof(*buf));
ret = 0;
}
else
return -1;
}
else
ret = fileinfo_to_stat(hFile, buf);
/*
* Junction points appear as directories to fileinfo_to_stat(), so we'll
* need to do a bit more work to distinguish them.
*/
if ((ret == 0 && S_ISDIR(buf->st_mode)) || hFile == INVALID_HANDLE_VALUE)
{
char next[MAX_PATH];
ssize_t size;
/*
* POSIX says we need to put the length of the target path into
* st_size. Use readlink() to get it, or learn that this is not a
* junction point.
*/
size = readlink(name, next, sizeof(next));
if (size < 0)
{
if (errno == EACCES &&
zx_RtlGetLastNtStatus() == STATUS_DELETE_PENDING)
{
/* Unlinked underneath us. */
errno = ENOENT;
ret = -1;
}
else if (errno == EINVAL)
{
/* It's not a junction point, nothing to do. */
}
else
{
/* Some other failure. */
ret = -1;
}
}
else
{
/* It's a junction point, so report it as a symlink. */
buf->st_mode &= ~S_IFDIR;
buf->st_mode |= S_IFLNK;
buf->st_size = size;
ret = 0;
}
}
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
return ret;
}
/*
* Windows implementation of stat().
*/
int
zstat64(const char *name, struct stat *buf)
{
int loops = 0;
int ret;
char curr[MAX_PATH];
ret = zlstat64(name, buf);
strlcpy(curr, name, MAX_PATH);
/* Do we need to follow a symlink (junction point)? */
while (ret == 0 && S_ISLNK(buf->st_mode))
{
char next[MAX_PATH];
ssize_t size;
if (++loops > 8)
{
errno = ELOOP;
return -1;
}
/*
* zlstat64() already called readlink() once to be able to fill in
* st_size, and now we need to do it again to get the path to follow.
* That could be optimized, but stat() on symlinks is probably rare
* and this way is simple.
*/
size = readlink(curr, next, sizeof(next));
if (size < 0)
{
if (errno == EACCES &&
zx_RtlGetLastNtStatus() == STATUS_DELETE_PENDING)
{
/* Unlinked underneath us. */
errno = ENOENT;
}
return -1;
}
if (size >= sizeof(next))
{
errno = ENAMETOOLONG;
return -1;
}
next[size] = 0;
ret = zlstat64(next, buf);
strcpy(curr, next);
}
return ret;
}
/*
* Windows implementation of fstat().
*/
int
zfstat64(int fileno, struct stat *buf)
{
HANDLE hFile = (HANDLE) _get_osfhandle(fileno);
DWORD fileType = FILE_TYPE_UNKNOWN;
unsigned short st_mode;
if (buf == NULL)
{
errno = EINVAL;
return -1;
}
fileType = zwin32_get_file_type(hFile);
if (errno != 0)
return -1;
switch (fileType)
{
/* The specified file is a disk file */
case FILE_TYPE_DISK:
return fileinfo_to_stat(hFile, buf);
/*
* The specified file is a socket, a named pipe, or an anonymous
* pipe.
*/
case FILE_TYPE_PIPE:
st_mode = _S_IFIFO;
break;
/* The specified file is a character file */
case FILE_TYPE_CHAR:
st_mode = _S_IFCHR;
break;
/* Unused flag and unknown file type */
case FILE_TYPE_REMOTE:
case FILE_TYPE_UNKNOWN:
default:
errno = EINVAL;
return -1;
}
memset(buf, 0, sizeof(*buf));
buf->st_mode = st_mode;
buf->st_dev = fileno;
buf->st_rdev = fileno;
buf->st_nlink = 1;
return 0;
}
Include
dirent.h
/*
* win32 native implementation of dirent functions
*/
#ifndef _WIN32VC_DIRENT_H
#define _WIN32VC_DIRENT_H
struct dirent
{
long d_ino;
unsigned short d_reclen;
unsigned char d_type;
unsigned short d_namlen;
char d_name[MAX_PATH];
};
typedef struct DIR DIR;
DIR *opendir(const char *);
struct dirent *readdir(DIR *);
int closedir(DIR *);
/* File types for 'd_type'. */
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
#endif
pthread-win32.h
#ifndef __PTHREAD_H
#define __PTHREAD_H
#include <windows.h>
typedef ULONG pthread_key_t;
typedef struct pthread_mutex_t
{
/* initstate = 0: not initialized; 1: init done; 2: init in progress */
LONG initstate;
CRITICAL_SECTION csection;
} pthread_mutex_t;
#define PTHREAD_MUTEX_INITIALIZER { 0 }
typedef int pthread_once_t;
DWORD pthread_self();
void pthread_setspecific(pthread_key_t, void *);
void *pthread_getspecific(pthread_key_t);
int pthread_mutex_init(pthread_mutex_t *, void *attr);
int pthread_mutex_lock(pthread_mutex_t *);
/* blocking */
int pthread_mutex_unlock(pthread_mutex_t *);
#endif
unistd.h
/*
* MSVC does not define these, nor does _fileno(stdin) etc reliably work
* (returns -1 if stdin/out/err are closed).
*/
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
utime.h
#include <sys/utime.h> /* for non-unicode version */
win32_port.h
/*-------------------------------------------------------------------------
*
* win32_port.h
* Windows-specific compatibility stuff.
*
* Note this is read in MinGW as well as native Windows builds,
* but not in Cygwin builds.
*
*-------------------------------------------------------------------------
*/
#ifndef WIN32_PORT_H
#define WIN32_PORT_H
/* undefine and redefine after #include */
#undef mkdir
/*
* VS2013 and later issue warnings about using the old Winsock API,
* which we don't really want to hear about.
*/
#ifdef _MSC_VER
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#endif
/*
* The MinGW64 headers choke if this is already defined - they
* define it themselves.
*/
#if !defined(__MINGW64_VERSION_MAJOR) || defined(_MSC_VER)
#define _WINSOCKAPI_
#endif
/*
* windows.h includes a lot of other headers, slowing down compilation
* significantly. WIN32_LEAN_AND_MEAN reduces that a bit. It'd be better to
* remove the include of windows.h (as well as indirect inclusions of it) from
* such a central place, but until then...
*
* To be able to include ntstatus.h tell windows.h to not declare NTSTATUS by
* temporarily defining UMDF_USING_NTSTATUS, otherwise we'll get warning about
* macro redefinitions, as windows.h also defines NTSTATUS (yuck). That in
* turn requires including ntstatus.h, winternl.h to get common symbols.
*/
#define WIN32_LEAN_AND_MEAN
#define UMDF_USING_NTSTATUS
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <ntstatus.h>
#include <winternl.h>
#include <corecrt_wstdio.h>
#include <stdlib.h>
#include <process.h>
#include <signal.h>
#include <direct.h>
#include <sys/stat.h>
#ifndef bool
#define bool BOOL
#endif
#ifndef false
#define false FALSE
#endif
#ifndef true
#define true TRUE
#endif
#define FLEXIBLE_ARRAY_MEMBER /* empty */
#define INT64CONST(x) (x##L)
#define UINT64CONST(x) (x##UL)
/*
* lengthof
* Number of elements in an array.
*/
#define lengthof(array) (sizeof (array) / sizeof ((array)[0]))
/* Must be here to avoid conflicting with prototype in windows.h */
#define mkdir(a,b) mkdir(a)
#define ftruncate(a,b) chsize(a,b)
/* Windows doesn't have fsync() as such, use _commit() */
#define fsync(fd) _commit(fd)
/*
* Signal stuff
*
* For WIN32, there is no wait() call so there are no wait() macros
* to interpret the return value of system(). Instead, system()
* return values < 0x100 are used for exit() termination, and higher
* values are used to indicate non-exit() termination, which is
* similar to a unix-style signal exit (think SIGSEGV ==
* STATUS_ACCESS_VIOLATION). Return values are broken up into groups:
*
* https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
*
* NT_SUCCESS 0 - 0x3FFFFFFF
* NT_INFORMATION 0x40000000 - 0x7FFFFFFF
* NT_WARNING 0x80000000 - 0xBFFFFFFF
* NT_ERROR 0xC0000000 - 0xFFFFFFFF
*
* Effectively, we don't care on the severity of the return value from
* system(), we just need to know if it was because of exit() or generated
* by the system, and it seems values >= 0x100 are system-generated.
* See this URL for a list of WIN32 STATUS_* values:
*
* Wine (URL used in our error messages) -
* http://source.winehq.org/source/include/ntstatus.h
* Descriptions -
* https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
*
* The comprehensive exception list is included in ntstatus.h from the
* Windows Driver Kit (WDK). A subset of the list is also included in
* winnt.h from the Windows SDK. Defining WIN32_NO_STATUS before including
* windows.h helps to avoid any conflicts.
*
* Some day we might want to print descriptions for the most common
* exceptions, rather than printing an include file name. We could use
* RtlNtStatusToDosError() and pass to FormatMessage(), which can print
* the text of error values, but MinGW does not support
* RtlNtStatusToDosError().
*/
#define WIFEXITED(w) (((w) & 0XFFFFFF00) == 0)
#define WIFSIGNALED(w) (!WIFEXITED(w))
#define WEXITSTATUS(w) (w)
#define WTERMSIG(w) (w)
#define sigmask(sig) ( 1 << ((sig)-1) )
/* Some extra signals */
#define SIGHUP 1
#define SIGQUIT 3
#define SIGTRAP 5
#define SIGABRT 22 /* Set to match W32 value -- not UNIX value */
#define SIGKILL 9
#define SIGPIPE 13
#define SIGALRM 14
#define SIGSTOP 17
#define SIGTSTP 18
#define SIGCONT 19
#define SIGCHLD 20
#define SIGWINCH 28
#define SIGUSR1 30
#define SIGUSR2 31
/*
* Supplement to <sys/types.h>.
*
* Perl already has typedefs for uid_t and gid_t.
*/
#ifndef PLPERL_HAVE_UID_GID
typedef int uid_t;
typedef int gid_t;
#endif
typedef long key_t;
#ifdef _MSC_VER
typedef int pid_t;
#endif
/* These macros are not provided by older MinGW, nor by MSVC */
#ifndef S_IRUSR
#define S_IRUSR _S_IREAD
#endif
#ifndef S_IWUSR
#define S_IWUSR _S_IWRITE
#endif
#ifndef S_IXUSR
#define S_IXUSR _S_IEXEC
#endif
#ifndef S_IRWXU
#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
#endif
#ifndef S_IRGRP
#define S_IRGRP 0
#endif
#ifndef S_IWGRP
#define S_IWGRP 0
#endif
#ifndef S_IXGRP
#define S_IXGRP 0
#endif
#ifndef S_IRWXG
#define S_IRWXG 0
#endif
#ifndef S_IROTH
#define S_IROTH 0
#endif
#ifndef S_IWOTH
#define S_IWOTH 0
#endif
#ifndef S_IXOTH
#define S_IXOTH 0
#endif
#ifndef S_IRWXO
#define S_IRWXO 0
#endif
#ifndef S_ISDIR
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
#ifndef S_ISREG
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
/*
* In order for lstat() to be able to report junction points as symlinks, we
* need to hijack a bit in st_mode, since neither MSVC nor MinGW provides
* S_ISLNK and there aren't any spare bits. We'll steal the one for character
* devices, because we don't otherwise make use of those.
*/
#ifdef S_ISLNK
#error "S_ISLNK is already defined"
#endif
#ifdef S_IFLNK
#error "S_IFLNK is already defined"
#endif
#define S_IFLNK S_IFCHR
#define S_ISLNK(m) (((m) & S_IFLNK) == S_IFLNK)
/*
* Supplement to <fcntl.h>.
* This is the same value as _O_NOINHERIT in the MS header file. This is
* to ensure that we don't collide with a future definition. It means
* we cannot use _O_NOINHERIT ourselves.
*/
#define O_DSYNC 0x0080
/*
* Our open() replacement does not create inheritable handles, so it is safe to
* ignore O_CLOEXEC. (If we were using Windows' own open(), it might be
* necessary to convert this to _O_NOINHERIT.)
*/
#define O_CLOEXEC 0
/*
* Supplement to <errno.h>.
*
* We redefine network-related Berkeley error symbols as the corresponding WSA
* constants. This allows strerror.c to recognize them as being in the Winsock
* error code range and pass them off to win32_socket_strerror(), since
* Windows' version of plain strerror() won't cope. Note that this will break
* if these names are used for anything else besides Windows Sockets errors.
* See TranslateSocketError() when changing this list.
*/
#undef EAGAIN
#define EAGAIN WSAEWOULDBLOCK
#undef EINTR
#define EINTR WSAEINTR
#undef EMSGSIZE
#define EMSGSIZE WSAEMSGSIZE
#undef EAFNOSUPPORT
#define EAFNOSUPPORT WSAEAFNOSUPPORT
#undef EWOULDBLOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
#undef ECONNABORTED
#define ECONNABORTED WSAECONNABORTED
#undef ECONNRESET
#define ECONNRESET WSAECONNRESET
#undef EINPROGRESS
#define EINPROGRESS WSAEINPROGRESS
#undef EISCONN
#define EISCONN WSAEISCONN
#undef ENOBUFS
#define ENOBUFS WSAENOBUFS
#undef EPROTONOSUPPORT
#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
#undef ECONNREFUSED
#define ECONNREFUSED WSAECONNREFUSED
#undef ENOTSOCK
#define ENOTSOCK WSAENOTSOCK
#undef EOPNOTSUPP
#define EOPNOTSUPP WSAEOPNOTSUPP
#undef EADDRINUSE
#define EADDRINUSE WSAEADDRINUSE
#undef EADDRNOTAVAIL
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
#undef EHOSTDOWN
#define EHOSTDOWN WSAEHOSTDOWN
#undef EHOSTUNREACH
#define EHOSTUNREACH WSAEHOSTUNREACH
#undef ENETDOWN
#define ENETDOWN WSAENETDOWN
#undef ENETRESET
#define ENETRESET WSAENETRESET
#undef ENETUNREACH
#define ENETUNREACH WSAENETUNREACH
#undef ENOTCONN
#define ENOTCONN WSAENOTCONN
#undef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
/*
* Locale stuff.
*
* Extended locale functions with gratuitous underscore prefixes.
* (These APIs are nevertheless fully documented by Microsoft.)
*/
#define locale_t _locale_t
#define tolower_l _tolower_l
#define toupper_l _toupper_l
#define towlower_l _towlower_l
#define towupper_l _towupper_l
#define isdigit_l _isdigit_l
#define iswdigit_l _iswdigit_l
#define isalpha_l _isalpha_l
#define iswalpha_l _iswalpha_l
#define isalnum_l _isalnum_l
#define iswalnum_l _iswalnum_l
#define isupper_l _isupper_l
#define iswupper_l _iswupper_l
#define islower_l _islower_l
#define iswlower_l _iswlower_l
#define isgraph_l _isgraph_l
#define iswgraph_l _iswgraph_l
#define isprint_l _isprint_l
#define iswprint_l _iswprint_l
#define ispunct_l _ispunct_l
#define iswpunct_l _iswpunct_l
#define isspace_l _isspace_l
#define iswspace_l _iswspace_l
#define strcoll_l _strcoll_l
#define strxfrm_l _strxfrm_l
#define wcscoll_l _wcscoll_l
#define wcstombs_l _wcstombs_l
#define mbstowcs_l _mbstowcs_l
#define RTLD_NOW 1
#define RTLD_GLOBAL 0
/* Things that exist in MinGW headers, but need to be added to MSVC */
#ifndef _WIN64
typedef long ssize_t;
#else
typedef __int64 ssize_t;
#endif
typedef unsigned short mode_t;
#define F_OK 0
#define W_OK 2
#define R_OK 4
extern void _dosmaperr(unsigned long);
extern int zsymlink(const char *oldpath, const char *newpath);
extern int zreadlink(const char *path, char *buf, size_t size);
#define symlink(oldpath, newpath) zsymlink(oldpath, newpath)
#define readlink(path, buf, size) zreadlink(path, buf, size)
extern int zfstat64(int fileno, struct stat *buf);
extern int zstat64(const char *name, struct stat *buf);
extern int zlstat64(const char *name, struct stat *buf);
#define fstat(fileno, sb) zfstat64(fileno, sb)
#define stat(path, sb) zstat64(path, sb)
#define lstat(path, sb) zlstat64(path, sb)
extern size_t strlcpy(char *dst, const char *src, size_t siz);
/*
* open() and fopen() replacements to allow deletion of open files and
* passing of other special options.
*/
#define O_DIRECT 0x80000000
extern HANDLE zwin32_open_handle(const char *, int, bool);
extern int zwin32_open(const char *, int, ...);
extern FILE *zwin32_fopen(const char *, const char *);
//#define open(a,b,c) zwin32_open(a,b,c)
//#define fopen(a,b) zwin32_fopen(a,b)
extern DWORD zwin32_get_file_type(HANDLE hFile);
extern int zwin32_system(const char *command);
extern FILE *zwin32_popen(const char *command, const char *type);
#define system(a) zwin32_system(a)
#define popen(a,b) zwin32_popen(a,b)
#define pclose(a) _pclose(a)
extern int fileExist(char* path);
#define access(a,b) fileExist(a)
extern void z_usleep(long microsec);
#endif /* WIN32_PORT_H */
win32ntdll.h
/*-------------------------------------------------------------------------
*
* win32ntdll.h
* Dynamically loaded Windows NT functions.
*
*-------------------------------------------------------------------------
*/
#ifndef WIN32NTDLL_H
#define WIN32NTDLL_H
#include <ntstatus.h>
#include <winternl.h>
#ifndef FLUSH_FLAGS_FILE_DATA_SYNC_ONLY
#define FLUSH_FLAGS_FILE_DATA_SYNC_ONLY 0x4
#endif
typedef NTSTATUS (__stdcall * RtlGetLastNtStatus_t) (void);
typedef ULONG (__stdcall * RtlNtStatusToDosError_t) (NTSTATUS);
typedef NTSTATUS (__stdcall * NtFlushBuffersFileEx_t) (HANDLE, ULONG, PVOID, ULONG, PIO_STATUS_BLOCK);
extern __declspec (dllimport) RtlGetLastNtStatus_t z_RtlGetLastNtStatus;
extern __declspec (dllimport) RtlNtStatusToDosError_t z_RtlNtStatusToDosError;
extern __declspec (dllimport) NtFlushBuffersFileEx_t z_NtFlushBuffersFileEx;
extern int initialize_ntdll(void);
#endif /* WIN32NTDLL_H */