Blame libarchive/archive_windows.c

Packit 08bd4c
/*-
Packit 08bd4c
 * Copyright (c) 2009-2011 Michihiro NAKAJIMA
Packit 08bd4c
 * Copyright (c) 2003-2007 Kees Zeelenberg
Packit 08bd4c
 * All rights reserved.
Packit 08bd4c
 *
Packit 08bd4c
 * Redistribution and use in source and binary forms, with or without
Packit 08bd4c
 * modification, are permitted provided that the following conditions
Packit 08bd4c
 * are met:
Packit 08bd4c
 * 1. Redistributions of source code must retain the above copyright
Packit 08bd4c
 *    notice, this list of conditions and the following disclaimer.
Packit 08bd4c
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 08bd4c
 *    notice, this list of conditions and the following disclaimer in the
Packit 08bd4c
 *    documentation and/or other materials provided with the distribution.
Packit 08bd4c
 *
Packit 08bd4c
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
Packit 08bd4c
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit 08bd4c
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit 08bd4c
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit 08bd4c
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit 08bd4c
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 08bd4c
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 08bd4c
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 08bd4c
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit 08bd4c
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 08bd4c
 *
Packit 08bd4c
 * $FreeBSD$
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * A set of compatibility glue for building libarchive on Windows platforms.
Packit 08bd4c
 *
Packit 08bd4c
 * Originally created as "libarchive-nonposix.c" by Kees Zeelenberg
Packit 08bd4c
 * for the GnuWin32 project, trimmed significantly by Tim Kientzle.
Packit 08bd4c
 *
Packit 08bd4c
 * Much of the original file was unnecessary for libarchive, because
Packit 08bd4c
 * many of the features it emulated were not strictly necessary for
Packit 08bd4c
 * libarchive.  I hope for this to shrink further as libarchive
Packit 08bd4c
 * internals are gradually reworked to sit more naturally on both
Packit 08bd4c
 * POSIX and Windows.  Any ideas for this are greatly appreciated.
Packit 08bd4c
 *
Packit 08bd4c
 * The biggest remaining issue is the dev/ino emulation; libarchive
Packit 08bd4c
 * has a couple of public APIs that rely on dev/ino uniquely
Packit 08bd4c
 * identifying a file.  This doesn't match well with Windows.  I'm
Packit 08bd4c
 * considering alternative APIs.
Packit 08bd4c
 */
Packit 08bd4c
Packit 08bd4c
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 08bd4c
Packit 08bd4c
#include "archive_platform.h"
Packit 08bd4c
#include "archive_private.h"
Packit 08bd4c
#include "archive_entry.h"
Packit 08bd4c
#include <ctype.h>
Packit 08bd4c
#include <errno.h>
Packit 08bd4c
#include <stddef.h>
Packit 08bd4c
#ifdef HAVE_SYS_UTIME_H
Packit 08bd4c
#include <sys/utime.h>
Packit 08bd4c
#endif
Packit 08bd4c
#include <sys/stat.h>
Packit 08bd4c
#include <locale.h>
Packit 08bd4c
#include <process.h>
Packit 08bd4c
#include <stdlib.h>
Packit 08bd4c
#include <wchar.h>
Packit 08bd4c
#include <windows.h>
Packit 08bd4c
#include <share.h>
Packit 08bd4c
Packit 08bd4c
#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
Packit 08bd4c
Packit 08bd4c
#if defined(__LA_LSEEK_NEEDED)
Packit 08bd4c
static BOOL SetFilePointerEx_perso(HANDLE hFile,
Packit 08bd4c
				   LARGE_INTEGER liDistanceToMove,
Packit 08bd4c
				   PLARGE_INTEGER lpNewFilePointer,
Packit 08bd4c
				   DWORD dwMoveMethod)
Packit 08bd4c
{
Packit 08bd4c
	LARGE_INTEGER li;
Packit 08bd4c
	li.QuadPart = liDistanceToMove.QuadPart;
Packit 08bd4c
	li.LowPart = SetFilePointer(
Packit 08bd4c
		hFile, li.LowPart, &li.HighPart, dwMoveMethod);
Packit 08bd4c
	if(lpNewFilePointer) {
Packit 08bd4c
		lpNewFilePointer->QuadPart = li.QuadPart;
Packit 08bd4c
	}
Packit 08bd4c
	return li.LowPart != -1 || GetLastError() == NO_ERROR;
Packit 08bd4c
}
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
struct ustat {
Packit 08bd4c
	int64_t		st_atime;
Packit 08bd4c
	uint32_t	st_atime_nsec;
Packit 08bd4c
	int64_t		st_ctime;
Packit 08bd4c
	uint32_t	st_ctime_nsec;
Packit 08bd4c
	int64_t		st_mtime;
Packit 08bd4c
	uint32_t	st_mtime_nsec;
Packit 08bd4c
	gid_t		st_gid;
Packit 08bd4c
	/* 64bits ino */
Packit 08bd4c
	int64_t		st_ino;
Packit 08bd4c
	mode_t		st_mode;
Packit 08bd4c
	uint32_t	st_nlink;
Packit 08bd4c
	uint64_t	st_size;
Packit 08bd4c
	uid_t		st_uid;
Packit 08bd4c
	dev_t		st_dev;
Packit 08bd4c
	dev_t		st_rdev;
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
/* Transform 64-bits ino into 32-bits by hashing.
Packit 08bd4c
 * You do not forget that really unique number size is 64-bits.
Packit 08bd4c
 */
Packit 08bd4c
#define INOSIZE (8*sizeof(ino_t)) /* 32 */
Packit 08bd4c
static __inline ino_t
Packit 08bd4c
getino(struct ustat *ub)
Packit 08bd4c
{
Packit 08bd4c
	ULARGE_INTEGER ino64;
Packit 08bd4c
	ino64.QuadPart = ub->st_ino;
Packit 08bd4c
	/* I don't know this hashing is correct way */
Packit 08bd4c
	return ((ino_t)(ino64.LowPart ^ (ino64.LowPart >> INOSIZE)));
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Prepend "\\?\" to the path name and convert it to unicode to permit
Packit 08bd4c
 * an extended-length path for a maximum total path length of 32767
Packit 08bd4c
 * characters.
Packit 08bd4c
 * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx
Packit 08bd4c
 */
Packit 08bd4c
wchar_t *
Packit 08bd4c
__la_win_permissive_name(const char *name)
Packit 08bd4c
{
Packit 08bd4c
	wchar_t *wn;
Packit 08bd4c
	wchar_t *ws;
Packit 08bd4c
	size_t ll;
Packit 08bd4c
Packit 08bd4c
	ll = strlen(name);
Packit 08bd4c
	wn = malloc((ll + 1) * sizeof(wchar_t));
Packit 08bd4c
	if (wn == NULL)
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	ll = mbstowcs(wn, name, ll);
Packit 08bd4c
	if (ll == (size_t)-1) {
Packit 08bd4c
		free(wn);
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	}
Packit 08bd4c
	wn[ll] = L'\0';
Packit 08bd4c
	ws = __la_win_permissive_name_w(wn);
Packit 08bd4c
	free(wn);
Packit 08bd4c
	return (ws);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
wchar_t *
Packit 08bd4c
__la_win_permissive_name_w(const wchar_t *wname)
Packit 08bd4c
{
Packit 08bd4c
	wchar_t *wn, *wnp;
Packit 08bd4c
	wchar_t *ws, *wsp;
Packit 08bd4c
	DWORD l, len, slen;
Packit 08bd4c
	int unc;
Packit 08bd4c
Packit 08bd4c
	/* Get a full-pathname. */
Packit 08bd4c
	l = GetFullPathNameW(wname, 0, NULL, NULL);
Packit 08bd4c
	if (l == 0)
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	/* NOTE: GetFullPathNameW has a bug that if the length of the file
Packit 08bd4c
	 * name is just 1 then it returns incomplete buffer size. Thus, we
Packit 08bd4c
	 * have to add three to the size to allocate a sufficient buffer
Packit 08bd4c
	 * size for the full-pathname of the file name. */
Packit 08bd4c
	l += 3;
Packit 08bd4c
	wnp = malloc(l * sizeof(wchar_t));
Packit 08bd4c
	if (wnp == NULL)
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	len = GetFullPathNameW(wname, l, wnp, NULL);
Packit 08bd4c
	wn = wnp;
Packit 08bd4c
Packit 08bd4c
	if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
Packit 08bd4c
	    wnp[2] == L'?' && wnp[3] == L'\\')
Packit 08bd4c
		/* We have already a permissive name. */
Packit 08bd4c
		return (wn);
Packit 08bd4c
Packit 08bd4c
	if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
Packit 08bd4c
		wnp[2] == L'.' && wnp[3] == L'\\') {
Packit 08bd4c
		/* This is a device name */
Packit 08bd4c
		if (((wnp[4] >= L'a' && wnp[4] <= L'z') ||
Packit 08bd4c
		     (wnp[4] >= L'A' && wnp[4] <= L'Z')) &&
Packit 08bd4c
		    wnp[5] == L':' && wnp[6] == L'\\')
Packit 08bd4c
			wnp[2] = L'?';/* Not device name. */
Packit 08bd4c
		return (wn);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	unc = 0;
Packit 08bd4c
	if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {
Packit 08bd4c
		wchar_t *p = &wnp[2];
Packit 08bd4c
Packit 08bd4c
		/* Skip server-name letters. */
Packit 08bd4c
		while (*p != L'\\' && *p != L'\0')
Packit 08bd4c
			++p;
Packit 08bd4c
		if (*p == L'\\') {
Packit 08bd4c
			wchar_t *rp = ++p;
Packit 08bd4c
			/* Skip share-name letters. */
Packit 08bd4c
			while (*p != L'\\' && *p != L'\0')
Packit 08bd4c
				++p;
Packit 08bd4c
			if (*p == L'\\' && p != rp) {
Packit 08bd4c
				/* Now, match patterns such as
Packit 08bd4c
				 * "\\server-name\share-name\" */
Packit 08bd4c
				wnp += 2;
Packit 08bd4c
				len -= 2;
Packit 08bd4c
				unc = 1;
Packit 08bd4c
			}
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	slen = 4 + (unc * 4) + len + 1;
Packit 08bd4c
	ws = wsp = malloc(slen * sizeof(wchar_t));
Packit 08bd4c
	if (ws == NULL) {
Packit 08bd4c
		free(wn);
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	}
Packit 08bd4c
	/* prepend "\\?\" */
Packit 08bd4c
	wcsncpy(wsp, L"\\\\?\\", 4);
Packit 08bd4c
	wsp += 4;
Packit 08bd4c
	slen -= 4;
Packit 08bd4c
	if (unc) {
Packit 08bd4c
		/* append "UNC\" ---> "\\?\UNC\" */
Packit 08bd4c
		wcsncpy(wsp, L"UNC\\", 4);
Packit 08bd4c
		wsp += 4;
Packit 08bd4c
		slen -= 4;
Packit 08bd4c
	}
Packit 08bd4c
	wcsncpy(wsp, wnp, slen);
Packit 08bd4c
	wsp[slen - 1] = L'\0'; /* Ensure null termination. */
Packit 08bd4c
	free(wn);
Packit 08bd4c
	return (ws);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Create a file handle.
Packit 08bd4c
 * This can exceed MAX_PATH limitation.
Packit 08bd4c
 */
Packit 08bd4c
static HANDLE
Packit 08bd4c
la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
Packit 08bd4c
    LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
Packit 08bd4c
    DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
Packit 08bd4c
{
Packit 08bd4c
	wchar_t *wpath;
Packit 08bd4c
	HANDLE handle;
Packit 08bd4c
Packit 08bd4c
	handle = CreateFileA(path, dwDesiredAccess, dwShareMode,
Packit 08bd4c
	    lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
Packit 08bd4c
	    hTemplateFile);
Packit 08bd4c
	if (handle != INVALID_HANDLE_VALUE)
Packit 08bd4c
		return (handle);
Packit 08bd4c
	if (GetLastError() != ERROR_PATH_NOT_FOUND)
Packit 08bd4c
		return (handle);
Packit 08bd4c
	wpath = __la_win_permissive_name(path);
Packit 08bd4c
	if (wpath == NULL)
Packit 08bd4c
		return (handle);
Packit 08bd4c
	handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode,
Packit 08bd4c
	    lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
Packit 08bd4c
	    hTemplateFile);
Packit 08bd4c
	free(wpath);
Packit 08bd4c
	return (handle);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
#if defined(__LA_LSEEK_NEEDED)
Packit 08bd4c
__int64
Packit 08bd4c
__la_lseek(int fd, __int64 offset, int whence)
Packit 08bd4c
{
Packit 08bd4c
	LARGE_INTEGER distance;
Packit 08bd4c
	LARGE_INTEGER newpointer;
Packit 08bd4c
	HANDLE handle;
Packit 08bd4c
Packit 08bd4c
	if (fd < 0) {
Packit 08bd4c
		errno = EBADF;
Packit 08bd4c
		return (-1);
Packit 08bd4c
	}
Packit 08bd4c
	handle = (HANDLE)_get_osfhandle(fd);
Packit 08bd4c
	if (GetFileType(handle) != FILE_TYPE_DISK) {
Packit 08bd4c
		errno = EBADF;
Packit 08bd4c
		return (-1);
Packit 08bd4c
	}
Packit 08bd4c
	distance.QuadPart = offset;
Packit 08bd4c
	if (!SetFilePointerEx_perso(handle, distance, &newpointer, whence)) {
Packit 08bd4c
		DWORD lasterr;
Packit 08bd4c
Packit 08bd4c
		lasterr = GetLastError();
Packit 08bd4c
		if (lasterr == ERROR_BROKEN_PIPE)
Packit 08bd4c
			return (0);
Packit 08bd4c
		if (lasterr == ERROR_ACCESS_DENIED)
Packit 08bd4c
			errno = EBADF;
Packit 08bd4c
		else
Packit 08bd4c
			la_dosmaperr(lasterr);
Packit 08bd4c
		return (-1);
Packit 08bd4c
	}
Packit 08bd4c
	return (newpointer.QuadPart);
Packit 08bd4c
}
Packit 08bd4c
#endif
Packit 08bd4c
Packit 08bd4c
/* This can exceed MAX_PATH limitation. */
Packit 08bd4c
int
Packit 08bd4c
__la_open(const char *path, int flags, ...)
Packit 08bd4c
{
Packit 08bd4c
	va_list ap;
Packit 08bd4c
	wchar_t *ws;
Packit 08bd4c
	int r, pmode;
Packit 08bd4c
	DWORD attr;
Packit 08bd4c
Packit 08bd4c
	va_start(ap, flags);
Packit 08bd4c
	pmode = va_arg(ap, int);
Packit 08bd4c
	va_end(ap);
Packit 08bd4c
	ws = NULL;
Packit 08bd4c
	if ((flags & ~O_BINARY) == O_RDONLY) {
Packit 08bd4c
		/*
Packit 08bd4c
		 * When we open a directory, _open function returns
Packit 08bd4c
		 * "Permission denied" error.
Packit 08bd4c
		 */
Packit 08bd4c
		attr = GetFileAttributesA(path);
Packit 08bd4c
		if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) {
Packit 08bd4c
			ws = __la_win_permissive_name(path);
Packit 08bd4c
			if (ws == NULL) {
Packit 08bd4c
				errno = EINVAL;
Packit 08bd4c
				return (-1);
Packit 08bd4c
			}
Packit 08bd4c
			attr = GetFileAttributesW(ws);
Packit 08bd4c
		}
Packit 08bd4c
		if (attr == (DWORD)-1) {
Packit 08bd4c
			la_dosmaperr(GetLastError());
Packit 08bd4c
			free(ws);
Packit 08bd4c
			return (-1);
Packit 08bd4c
		}
Packit 08bd4c
		if (attr & FILE_ATTRIBUTE_DIRECTORY) {
Packit 08bd4c
			HANDLE handle;
Packit 08bd4c
Packit 08bd4c
			if (ws != NULL)
Packit 08bd4c
				handle = CreateFileW(ws, 0, 0, NULL,
Packit 08bd4c
				    OPEN_EXISTING,
Packit 08bd4c
				    FILE_FLAG_BACKUP_SEMANTICS |
Packit 08bd4c
				    FILE_ATTRIBUTE_READONLY,
Packit 08bd4c
					NULL);
Packit 08bd4c
			else
Packit 08bd4c
				handle = CreateFileA(path, 0, 0, NULL,
Packit 08bd4c
				    OPEN_EXISTING,
Packit 08bd4c
				    FILE_FLAG_BACKUP_SEMANTICS |
Packit 08bd4c
				    FILE_ATTRIBUTE_READONLY,
Packit 08bd4c
					NULL);
Packit 08bd4c
			free(ws);
Packit 08bd4c
			if (handle == INVALID_HANDLE_VALUE) {
Packit 08bd4c
				la_dosmaperr(GetLastError());
Packit 08bd4c
				return (-1);
Packit 08bd4c
			}
Packit 08bd4c
			r = _open_osfhandle((intptr_t)handle, _O_RDONLY);
Packit 08bd4c
			return (r);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	if (ws == NULL) {
Packit 08bd4c
#if defined(__BORLANDC__)
Packit 08bd4c
		/* Borland has no mode argument.
Packit 08bd4c
		   TODO: Fix mode of new file.  */
Packit 08bd4c
		r = _open(path, flags);
Packit 08bd4c
#else
Packit 08bd4c
		r = _open(path, flags, pmode);
Packit 08bd4c
#endif
Packit 08bd4c
		if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
Packit 08bd4c
			/* Simulate other POSIX system action to pass our test suite. */
Packit 08bd4c
			attr = GetFileAttributesA(path);
Packit 08bd4c
			if (attr == (DWORD)-1)
Packit 08bd4c
				la_dosmaperr(GetLastError());
Packit 08bd4c
			else if (attr & FILE_ATTRIBUTE_DIRECTORY)
Packit 08bd4c
				errno = EISDIR;
Packit 08bd4c
			else
Packit 08bd4c
				errno = EACCES;
Packit 08bd4c
			return (-1);
Packit 08bd4c
		}
Packit 08bd4c
		if (r >= 0 || errno != ENOENT)
Packit 08bd4c
			return (r);
Packit 08bd4c
		ws = __la_win_permissive_name(path);
Packit 08bd4c
		if (ws == NULL) {
Packit 08bd4c
			errno = EINVAL;
Packit 08bd4c
			return (-1);
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	r = _wopen(ws, flags, pmode);
Packit 08bd4c
	if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
Packit 08bd4c
		/* Simulate other POSIX system action to pass our test suite. */
Packit 08bd4c
		attr = GetFileAttributesW(ws);
Packit 08bd4c
		if (attr == (DWORD)-1)
Packit 08bd4c
			la_dosmaperr(GetLastError());
Packit 08bd4c
		else if (attr & FILE_ATTRIBUTE_DIRECTORY)
Packit 08bd4c
			errno = EISDIR;
Packit 08bd4c
		else
Packit 08bd4c
			errno = EACCES;
Packit 08bd4c
	}
Packit 08bd4c
	free(ws);
Packit 08bd4c
	return (r);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
ssize_t
Packit 08bd4c
__la_read(int fd, void *buf, size_t nbytes)
Packit 08bd4c
{
Packit 08bd4c
	HANDLE handle;
Packit 08bd4c
	DWORD bytes_read, lasterr;
Packit 08bd4c
	int r;
Packit 08bd4c
Packit 08bd4c
#ifdef _WIN64
Packit 08bd4c
	if (nbytes > UINT32_MAX)
Packit 08bd4c
		nbytes = UINT32_MAX;
Packit 08bd4c
#endif
Packit 08bd4c
	if (fd < 0) {
Packit 08bd4c
		errno = EBADF;
Packit 08bd4c
		return (-1);
Packit 08bd4c
	}
Packit 08bd4c
	/* Do not pass 0 to third parameter of ReadFile(), read bytes.
Packit 08bd4c
	 * This will not return to application side. */
Packit 08bd4c
	if (nbytes == 0)
Packit 08bd4c
		return (0);
Packit 08bd4c
	handle = (HANDLE)_get_osfhandle(fd);
Packit 08bd4c
	r = ReadFile(handle, buf, (uint32_t)nbytes,
Packit 08bd4c
	    &bytes_read, NULL);
Packit 08bd4c
	if (r == 0) {
Packit 08bd4c
		lasterr = GetLastError();
Packit 08bd4c
		if (lasterr == ERROR_NO_DATA) {
Packit 08bd4c
			errno = EAGAIN;
Packit 08bd4c
			return (-1);
Packit 08bd4c
		}
Packit 08bd4c
		if (lasterr == ERROR_BROKEN_PIPE)
Packit 08bd4c
			return (0);
Packit 08bd4c
		if (lasterr == ERROR_ACCESS_DENIED)
Packit 08bd4c
			errno = EBADF;
Packit 08bd4c
		else
Packit 08bd4c
			la_dosmaperr(lasterr);
Packit 08bd4c
		return (-1);
Packit 08bd4c
	}
Packit 08bd4c
	return ((ssize_t)bytes_read);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* Convert Windows FILETIME to UTC */
Packit 08bd4c
__inline static void
Packit 08bd4c
fileTimeToUTC(const FILETIME *filetime, time_t *t, long *ns)
Packit 08bd4c
{
Packit 08bd4c
	ULARGE_INTEGER utc;
Packit 08bd4c
Packit 08bd4c
	utc.HighPart = filetime->dwHighDateTime;
Packit 08bd4c
	utc.LowPart  = filetime->dwLowDateTime;
Packit 08bd4c
	if (utc.QuadPart >= EPOC_TIME) {
Packit 08bd4c
		utc.QuadPart -= EPOC_TIME;
Packit 08bd4c
		*t = (time_t)(utc.QuadPart / 10000000);	/* milli seconds base */
Packit 08bd4c
		*ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
Packit 08bd4c
	} else {
Packit 08bd4c
		*t = 0;
Packit 08bd4c
		*ns = 0;
Packit 08bd4c
	}
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* Stat by handle
Packit 08bd4c
 * Windows' stat() does not accept the path added "\\?\" especially "?"
Packit 08bd4c
 * character.
Packit 08bd4c
 * It means we cannot access the long name path longer than MAX_PATH.
Packit 08bd4c
 * So I've implemented simular Windows' stat() to access the long name path.
Packit 08bd4c
 * And I've added some feature.
Packit 08bd4c
 * 1. set st_ino by nFileIndexHigh and nFileIndexLow of
Packit 08bd4c
 *    BY_HANDLE_FILE_INFORMATION.
Packit 08bd4c
 * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION.
Packit 08bd4c
 * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
__hstat(HANDLE handle, struct ustat *st)
Packit 08bd4c
{
Packit 08bd4c
	BY_HANDLE_FILE_INFORMATION info;
Packit 08bd4c
	ULARGE_INTEGER ino64;
Packit 08bd4c
	DWORD ftype;
Packit 08bd4c
	mode_t mode;
Packit 08bd4c
	time_t t;
Packit 08bd4c
	long ns;
Packit 08bd4c
Packit 08bd4c
	switch (ftype = GetFileType(handle)) {
Packit 08bd4c
	case FILE_TYPE_UNKNOWN:
Packit 08bd4c
		errno = EBADF;
Packit 08bd4c
		return (-1);
Packit 08bd4c
	case FILE_TYPE_CHAR:
Packit 08bd4c
	case FILE_TYPE_PIPE:
Packit 08bd4c
		if (ftype == FILE_TYPE_CHAR) {
Packit 08bd4c
			st->st_mode = S_IFCHR;
Packit 08bd4c
			st->st_size = 0;
Packit 08bd4c
		} else {
Packit 08bd4c
			DWORD avail;
Packit 08bd4c
Packit 08bd4c
			st->st_mode = S_IFIFO;
Packit 08bd4c
			if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL))
Packit 08bd4c
				st->st_size = avail;
Packit 08bd4c
			else
Packit 08bd4c
				st->st_size = 0;
Packit 08bd4c
		}
Packit 08bd4c
		st->st_atime = 0;
Packit 08bd4c
		st->st_atime_nsec = 0;
Packit 08bd4c
		st->st_mtime = 0;
Packit 08bd4c
		st->st_mtime_nsec = 0;
Packit 08bd4c
		st->st_ctime = 0;
Packit 08bd4c
		st->st_ctime_nsec = 0;
Packit 08bd4c
		st->st_ino = 0;
Packit 08bd4c
		st->st_nlink = 1;
Packit 08bd4c
		st->st_uid = 0;
Packit 08bd4c
		st->st_gid = 0;
Packit 08bd4c
		st->st_rdev = 0;
Packit 08bd4c
		st->st_dev = 0;
Packit 08bd4c
		return (0);
Packit 08bd4c
	case FILE_TYPE_DISK:
Packit 08bd4c
		break;
Packit 08bd4c
	default:
Packit 08bd4c
		/* This ftype is undocumented type. */
Packit 08bd4c
		la_dosmaperr(GetLastError());
Packit 08bd4c
		return (-1);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	ZeroMemory(&info, sizeof(info));
Packit 08bd4c
	if (!GetFileInformationByHandle (handle, &info)) {
Packit 08bd4c
		la_dosmaperr(GetLastError());
Packit 08bd4c
		return (-1);
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	mode = S_IRUSR | S_IRGRP | S_IROTH;
Packit 08bd4c
	if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
Packit 08bd4c
		mode |= S_IWUSR | S_IWGRP | S_IWOTH;
Packit 08bd4c
	if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
Packit 08bd4c
		mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
Packit 08bd4c
	else
Packit 08bd4c
		mode |= S_IFREG;
Packit 08bd4c
	st->st_mode = mode;
Packit 08bd4c
Packit 08bd4c
	fileTimeToUTC(&info.ftLastAccessTime, &t, &ns);
Packit 08bd4c
	st->st_atime = t;
Packit 08bd4c
	st->st_atime_nsec = ns;
Packit 08bd4c
	fileTimeToUTC(&info.ftLastWriteTime, &t, &ns);
Packit 08bd4c
	st->st_mtime = t;
Packit 08bd4c
	st->st_mtime_nsec = ns;
Packit 08bd4c
	fileTimeToUTC(&info.ftCreationTime, &t, &ns);
Packit 08bd4c
	st->st_ctime = t;
Packit 08bd4c
	st->st_ctime_nsec = ns;
Packit 08bd4c
	st->st_size =
Packit 08bd4c
	    ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1))
Packit 08bd4c
		+ (int64_t)(info.nFileSizeLow);
Packit 08bd4c
#ifdef SIMULATE_WIN_STAT
Packit 08bd4c
	st->st_ino = 0;
Packit 08bd4c
	st->st_nlink = 1;
Packit 08bd4c
	st->st_dev = 0;
Packit 08bd4c
#else
Packit 08bd4c
	/* Getting FileIndex as i-node. We should remove a sequence which
Packit 08bd4c
	 * is high-16-bits of nFileIndexHigh. */
Packit 08bd4c
	ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL;
Packit 08bd4c
	ino64.LowPart  = info.nFileIndexLow;
Packit 08bd4c
	st->st_ino = ino64.QuadPart;
Packit 08bd4c
	st->st_nlink = info.nNumberOfLinks;
Packit 08bd4c
	if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
Packit 08bd4c
		++st->st_nlink;/* Add parent directory. */
Packit 08bd4c
	st->st_dev = info.dwVolumeSerialNumber;
Packit 08bd4c
#endif
Packit 08bd4c
	st->st_uid = 0;
Packit 08bd4c
	st->st_gid = 0;
Packit 08bd4c
	st->st_rdev = 0;
Packit 08bd4c
	return (0);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static void
Packit 08bd4c
copy_stat(struct stat *st, struct ustat *us)
Packit 08bd4c
{
Packit 08bd4c
	st->st_atime = us->st_atime;
Packit 08bd4c
	st->st_ctime = us->st_ctime;
Packit 08bd4c
	st->st_mtime = us->st_mtime;
Packit 08bd4c
	st->st_gid = us->st_gid;
Packit 08bd4c
	st->st_ino = getino(us);
Packit 08bd4c
	st->st_mode = us->st_mode;
Packit 08bd4c
	st->st_nlink = us->st_nlink;
Packit 08bd4c
	st->st_size = (off_t)us->st_size;
Packit 08bd4c
	st->st_uid = us->st_uid;
Packit 08bd4c
	st->st_dev = us->st_dev;
Packit 08bd4c
	st->st_rdev = us->st_rdev;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * TODO: Remove a use of __la_fstat and __la_stat.
Packit 08bd4c
 * We should use GetFileInformationByHandle in place
Packit 08bd4c
 * where We still use the *stat functions.
Packit 08bd4c
 */
Packit 08bd4c
int
Packit 08bd4c
__la_fstat(int fd, struct stat *st)
Packit 08bd4c
{
Packit 08bd4c
	struct ustat u;
Packit 08bd4c
	int ret;
Packit 08bd4c
Packit 08bd4c
	if (fd < 0) {
Packit 08bd4c
		errno = EBADF;
Packit 08bd4c
		return (-1);
Packit 08bd4c
	}
Packit 08bd4c
	ret = __hstat((HANDLE)_get_osfhandle(fd), &u);
Packit 08bd4c
	if (ret >= 0) {
Packit 08bd4c
		copy_stat(st, &u);
Packit 08bd4c
		if (u.st_mode & (S_IFCHR | S_IFIFO)) {
Packit 08bd4c
			st->st_dev = fd;
Packit 08bd4c
			st->st_rdev = fd;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	return (ret);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/* This can exceed MAX_PATH limitation. */
Packit 08bd4c
int
Packit 08bd4c
__la_stat(const char *path, struct stat *st)
Packit 08bd4c
{
Packit 08bd4c
	HANDLE handle;
Packit 08bd4c
	struct ustat u;
Packit 08bd4c
	int ret;
Packit 08bd4c
Packit 08bd4c
	handle = la_CreateFile(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
Packit 08bd4c
		FILE_FLAG_BACKUP_SEMANTICS,
Packit 08bd4c
		NULL);
Packit 08bd4c
	if (handle == INVALID_HANDLE_VALUE) {
Packit 08bd4c
		la_dosmaperr(GetLastError());
Packit 08bd4c
		return (-1);
Packit 08bd4c
	}
Packit 08bd4c
	ret = __hstat(handle, &u);
Packit 08bd4c
	CloseHandle(handle);
Packit 08bd4c
	if (ret >= 0) {
Packit 08bd4c
		char *p;
Packit 08bd4c
Packit 08bd4c
		copy_stat(st, &u);
Packit 08bd4c
		p = strrchr(path, '.');
Packit 08bd4c
		if (p != NULL && strlen(p) == 4) {
Packit 08bd4c
			char exttype[4];
Packit 08bd4c
Packit 08bd4c
			++ p;
Packit 08bd4c
			exttype[0] = toupper(*p++);
Packit 08bd4c
			exttype[1] = toupper(*p++);
Packit 08bd4c
			exttype[2] = toupper(*p++);
Packit 08bd4c
			exttype[3] = '\0';
Packit 08bd4c
			if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") ||
Packit 08bd4c
				!strcmp(exttype, "BAT") || !strcmp(exttype, "COM"))
Packit 08bd4c
				st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
	return (ret);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * This waitpid is limited implementation.
Packit 08bd4c
 */
Packit 08bd4c
pid_t
Packit 08bd4c
__la_waitpid(HANDLE child, int *status, int option)
Packit 08bd4c
{
Packit 08bd4c
	DWORD cs;
Packit 08bd4c
Packit 08bd4c
	(void)option;/* UNUSED */
Packit 08bd4c
	do {
Packit 08bd4c
		if (GetExitCodeProcess(child, &cs) == 0) {
Packit 08bd4c
			CloseHandle(child);
Packit 08bd4c
			la_dosmaperr(GetLastError());
Packit 08bd4c
			*status = 0;
Packit 08bd4c
			return (-1);
Packit 08bd4c
		}
Packit 08bd4c
	} while (cs == STILL_ACTIVE);
Packit 08bd4c
Packit 08bd4c
	*status = (int)(cs & 0xff);
Packit 08bd4c
	return (0);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
ssize_t
Packit 08bd4c
__la_write(int fd, const void *buf, size_t nbytes)
Packit 08bd4c
{
Packit 08bd4c
	DWORD bytes_written;
Packit 08bd4c
Packit 08bd4c
#ifdef _WIN64
Packit 08bd4c
	if (nbytes > UINT32_MAX)
Packit 08bd4c
		nbytes = UINT32_MAX;
Packit 08bd4c
#endif
Packit 08bd4c
	if (fd < 0) {
Packit 08bd4c
		errno = EBADF;
Packit 08bd4c
		return (-1);
Packit 08bd4c
	}
Packit 08bd4c
	if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes,
Packit 08bd4c
	    &bytes_written, NULL)) {
Packit 08bd4c
		DWORD lasterr;
Packit 08bd4c
Packit 08bd4c
		lasterr = GetLastError();
Packit 08bd4c
		if (lasterr == ERROR_ACCESS_DENIED)
Packit 08bd4c
			errno = EBADF;
Packit 08bd4c
		else
Packit 08bd4c
			la_dosmaperr(lasterr);
Packit 08bd4c
		return (-1);
Packit 08bd4c
	}
Packit 08bd4c
	return (bytes_written);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * Replace the Windows path separator '\' with '/'.
Packit 08bd4c
 */
Packit 08bd4c
static int
Packit 08bd4c
replace_pathseparator(struct archive_wstring *ws, const wchar_t *wp)
Packit 08bd4c
{
Packit 08bd4c
	wchar_t *w;
Packit 08bd4c
	size_t path_length;
Packit 08bd4c
Packit 08bd4c
	if (wp == NULL)
Packit 08bd4c
		return(0);
Packit 08bd4c
	if (wcschr(wp, L'\\') == NULL)
Packit 08bd4c
		return(0);
Packit 08bd4c
	path_length = wcslen(wp);
Packit 08bd4c
	if (archive_wstring_ensure(ws, path_length) == NULL)
Packit 08bd4c
		return(-1);
Packit 08bd4c
	archive_wstrncpy(ws, wp, path_length);
Packit 08bd4c
	for (w = ws->s; *w; w++) {
Packit 08bd4c
		if (*w == L'\\')
Packit 08bd4c
			*w = L'/';
Packit 08bd4c
	}
Packit 08bd4c
	return(1);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
static int
Packit 08bd4c
fix_pathseparator(struct archive_entry *entry)
Packit 08bd4c
{
Packit 08bd4c
	struct archive_wstring ws;
Packit 08bd4c
	const wchar_t *wp;
Packit 08bd4c
	int ret = ARCHIVE_OK;
Packit 08bd4c
Packit 08bd4c
	archive_string_init(&ws);
Packit 08bd4c
	wp = archive_entry_pathname_w(entry);
Packit 08bd4c
	switch (replace_pathseparator(&ws, wp)) {
Packit 08bd4c
	case 0: /* Not replaced. */
Packit 08bd4c
		break;
Packit 08bd4c
	case 1: /* Replaced. */
Packit 08bd4c
		archive_entry_copy_pathname_w(entry, ws.s);
Packit 08bd4c
		break;
Packit 08bd4c
	default:
Packit 08bd4c
		ret = ARCHIVE_FAILED;
Packit 08bd4c
	}
Packit 08bd4c
	wp = archive_entry_hardlink_w(entry);
Packit 08bd4c
	switch (replace_pathseparator(&ws, wp)) {
Packit 08bd4c
	case 0: /* Not replaced. */
Packit 08bd4c
		break;
Packit 08bd4c
	case 1: /* Replaced. */
Packit 08bd4c
		archive_entry_copy_hardlink_w(entry, ws.s);
Packit 08bd4c
		break;
Packit 08bd4c
	default:
Packit 08bd4c
		ret = ARCHIVE_FAILED;
Packit 08bd4c
	}
Packit 08bd4c
	wp = archive_entry_symlink_w(entry);
Packit 08bd4c
	switch (replace_pathseparator(&ws, wp)) {
Packit 08bd4c
	case 0: /* Not replaced. */
Packit 08bd4c
		break;
Packit 08bd4c
	case 1: /* Replaced. */
Packit 08bd4c
		archive_entry_copy_symlink_w(entry, ws.s);
Packit 08bd4c
		break;
Packit 08bd4c
	default:
Packit 08bd4c
		ret = ARCHIVE_FAILED;
Packit 08bd4c
	}
Packit 08bd4c
	archive_wstring_free(&ws);
Packit 08bd4c
	return(ret);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
struct archive_entry *
Packit 08bd4c
__la_win_entry_in_posix_pathseparator(struct archive_entry *entry)
Packit 08bd4c
{
Packit 08bd4c
	struct archive_entry *entry_main;
Packit 08bd4c
	const wchar_t *wp;
Packit 08bd4c
	int has_backslash = 0;
Packit 08bd4c
	int ret;
Packit 08bd4c
Packit 08bd4c
	wp = archive_entry_pathname_w(entry);
Packit 08bd4c
	if (wp != NULL && wcschr(wp, L'\\') != NULL)
Packit 08bd4c
		has_backslash = 1;
Packit 08bd4c
	if (!has_backslash) {
Packit 08bd4c
		wp = archive_entry_hardlink_w(entry);
Packit 08bd4c
		if (wp != NULL && wcschr(wp, L'\\') != NULL)
Packit 08bd4c
			has_backslash = 1;
Packit 08bd4c
	}
Packit 08bd4c
	if (!has_backslash) {
Packit 08bd4c
		wp = archive_entry_symlink_w(entry);
Packit 08bd4c
		if (wp != NULL && wcschr(wp, L'\\') != NULL)
Packit 08bd4c
			has_backslash = 1;
Packit 08bd4c
	}
Packit 08bd4c
	/*
Packit 08bd4c
	 * If there is no backslash chars, return the original.
Packit 08bd4c
	 */
Packit 08bd4c
	if (!has_backslash)
Packit 08bd4c
		return (entry);
Packit 08bd4c
Packit 08bd4c
	/* Copy entry so we can modify it as needed. */
Packit 08bd4c
	entry_main = archive_entry_clone(entry);
Packit 08bd4c
	if (entry_main == NULL)
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	/* Replace the Windows path-separator '\' with '/'. */
Packit 08bd4c
	ret = fix_pathseparator(entry_main);
Packit 08bd4c
	if (ret < ARCHIVE_WARN) {
Packit 08bd4c
		archive_entry_free(entry_main);
Packit 08bd4c
		return (NULL);
Packit 08bd4c
	}
Packit 08bd4c
	return (entry_main);
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
Packit 08bd4c
/*
Packit 08bd4c
 * The following function was modified from PostgreSQL sources and is
Packit 08bd4c
 * subject to the copyright below.
Packit 08bd4c
 */
Packit 08bd4c
/*-------------------------------------------------------------------------
Packit 08bd4c
 *
Packit 08bd4c
 * win32error.c
Packit 08bd4c
 *	  Map win32 error codes to errno values
Packit 08bd4c
 *
Packit 08bd4c
 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
Packit 08bd4c
 *
Packit 08bd4c
 * IDENTIFICATION
Packit 08bd4c
 *	  $PostgreSQL: pgsql/src/port/win32error.c,v 1.4 2008/01/01 19:46:00 momjian Exp $
Packit 08bd4c
 *
Packit 08bd4c
 *-------------------------------------------------------------------------
Packit 08bd4c
 */
Packit 08bd4c
/*
Packit 08bd4c
PostgreSQL Database Management System
Packit 08bd4c
(formerly known as Postgres, then as Postgres95)
Packit 08bd4c
Packit 08bd4c
Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
Packit 08bd4c
Packit 08bd4c
Portions Copyright (c) 1994, The Regents of the University of California
Packit 08bd4c
Packit 08bd4c
Permission to use, copy, modify, and distribute this software and its
Packit 08bd4c
documentation for any purpose, without fee, and without a written agreement
Packit 08bd4c
is hereby granted, provided that the above copyright notice and this
Packit 08bd4c
paragraph and the following two paragraphs appear in all copies.
Packit 08bd4c
Packit 08bd4c
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
Packit 08bd4c
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
Packit 08bd4c
LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
Packit 08bd4c
DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
Packit 08bd4c
POSSIBILITY OF SUCH DAMAGE.
Packit 08bd4c
Packit 08bd4c
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
Packit 08bd4c
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
Packit 08bd4c
AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
Packit 08bd4c
ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
Packit 08bd4c
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Packit 08bd4c
*/
Packit 08bd4c
Packit 08bd4c
static const struct {
Packit 08bd4c
	DWORD		winerr;
Packit 08bd4c
	int		doserr;
Packit 08bd4c
} doserrors[] =
Packit 08bd4c
{
Packit 08bd4c
	{	ERROR_INVALID_FUNCTION, EINVAL	},
Packit 08bd4c
	{	ERROR_FILE_NOT_FOUND, ENOENT	},
Packit 08bd4c
	{	ERROR_PATH_NOT_FOUND, ENOENT	},
Packit 08bd4c
	{	ERROR_TOO_MANY_OPEN_FILES, EMFILE	},
Packit 08bd4c
	{	ERROR_ACCESS_DENIED, EACCES	},
Packit 08bd4c
	{	ERROR_INVALID_HANDLE, EBADF	},
Packit 08bd4c
	{	ERROR_ARENA_TRASHED, ENOMEM	},
Packit 08bd4c
	{	ERROR_NOT_ENOUGH_MEMORY, ENOMEM	},
Packit 08bd4c
	{	ERROR_INVALID_BLOCK, ENOMEM	},
Packit 08bd4c
	{	ERROR_BAD_ENVIRONMENT, E2BIG	},
Packit 08bd4c
	{	ERROR_BAD_FORMAT, ENOEXEC	},
Packit 08bd4c
	{	ERROR_INVALID_ACCESS, EINVAL	},
Packit 08bd4c
	{	ERROR_INVALID_DATA, EINVAL	},
Packit 08bd4c
	{	ERROR_INVALID_DRIVE, ENOENT	},
Packit 08bd4c
	{	ERROR_CURRENT_DIRECTORY, EACCES	},
Packit 08bd4c
	{	ERROR_NOT_SAME_DEVICE, EXDEV	},
Packit 08bd4c
	{	ERROR_NO_MORE_FILES, ENOENT	},
Packit 08bd4c
	{	ERROR_LOCK_VIOLATION, EACCES	},
Packit 08bd4c
	{	ERROR_SHARING_VIOLATION, EACCES	},
Packit 08bd4c
	{	ERROR_BAD_NETPATH, ENOENT	},
Packit 08bd4c
	{	ERROR_NETWORK_ACCESS_DENIED, EACCES	},
Packit 08bd4c
	{	ERROR_BAD_NET_NAME, ENOENT	},
Packit 08bd4c
	{	ERROR_FILE_EXISTS, EEXIST	},
Packit 08bd4c
	{	ERROR_CANNOT_MAKE, EACCES	},
Packit 08bd4c
	{	ERROR_FAIL_I24, EACCES	},
Packit 08bd4c
	{	ERROR_INVALID_PARAMETER, EINVAL	},
Packit 08bd4c
	{	ERROR_NO_PROC_SLOTS, EAGAIN	},
Packit 08bd4c
	{	ERROR_DRIVE_LOCKED, EACCES	},
Packit 08bd4c
	{	ERROR_BROKEN_PIPE, EPIPE	},
Packit 08bd4c
	{	ERROR_DISK_FULL, ENOSPC	},
Packit 08bd4c
	{	ERROR_INVALID_TARGET_HANDLE, EBADF	},
Packit 08bd4c
	{	ERROR_INVALID_HANDLE, EINVAL	},
Packit 08bd4c
	{	ERROR_WAIT_NO_CHILDREN, ECHILD	},
Packit 08bd4c
	{	ERROR_CHILD_NOT_COMPLETE, ECHILD	},
Packit 08bd4c
	{	ERROR_DIRECT_ACCESS_HANDLE, EBADF	},
Packit 08bd4c
	{	ERROR_NEGATIVE_SEEK, EINVAL	},
Packit 08bd4c
	{	ERROR_SEEK_ON_DEVICE, EACCES	},
Packit 08bd4c
	{	ERROR_DIR_NOT_EMPTY, ENOTEMPTY	},
Packit 08bd4c
	{	ERROR_NOT_LOCKED, EACCES	},
Packit 08bd4c
	{	ERROR_BAD_PATHNAME, ENOENT	},
Packit 08bd4c
	{	ERROR_MAX_THRDS_REACHED, EAGAIN	},
Packit 08bd4c
	{	ERROR_LOCK_FAILED, EACCES	},
Packit 08bd4c
	{	ERROR_ALREADY_EXISTS, EEXIST	},
Packit 08bd4c
	{	ERROR_FILENAME_EXCED_RANGE, ENOENT	},
Packit 08bd4c
	{	ERROR_NESTING_NOT_ALLOWED, EAGAIN	},
Packit 08bd4c
	{	ERROR_NOT_ENOUGH_QUOTA, ENOMEM	}
Packit 08bd4c
};
Packit 08bd4c
Packit 08bd4c
void
Packit 08bd4c
__la_dosmaperr(unsigned long e)
Packit 08bd4c
{
Packit 08bd4c
	int			i;
Packit 08bd4c
Packit 08bd4c
	if (e == 0)
Packit 08bd4c
	{
Packit 08bd4c
		errno = 0;
Packit 08bd4c
		return;
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	for (i = 0; i < (int)(sizeof(doserrors)/sizeof(doserrors[0])); i++)
Packit 08bd4c
	{
Packit 08bd4c
		if (doserrors[i].winerr == e)
Packit 08bd4c
		{
Packit 08bd4c
			errno = doserrors[i].doserr;
Packit 08bd4c
			return;
Packit 08bd4c
		}
Packit 08bd4c
	}
Packit 08bd4c
Packit 08bd4c
	/* fprintf(stderr, "unrecognized win32 error code: %lu", e); */
Packit 08bd4c
	errno = EINVAL;
Packit 08bd4c
	return;
Packit 08bd4c
}
Packit 08bd4c
Packit 08bd4c
#endif /* _WIN32 && !__CYGWIN__ */