1/*-
2 * Copyright (c) 2009 Michihiro NAKAJIMA
3 * Copyright (c) 2003-2007 Kees Zeelenberg
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29/*
30 * A set of compatibility glue for building libarchive on Windows platforms.
31 *
32 * Originally created as "libarchive-nonposix.c" by Kees Zeelenberg
33 * for the GnuWin32 project, trimmed significantly by Tim Kientzle.
34 *
35 * Much of the original file was unnecessary for libarchive, because
36 * many of the features it emulated were not strictly necessary for
37 * libarchive.  I hope for this to shrink further as libarchive
38 * internals are gradually reworked to sit more naturally on both
39 * POSIX and Windows.  Any ideas for this are greatly appreciated.
40 *
41 * The biggest remaining issue is the dev/ino emulation; libarchive
42 * has a couple of public APIs that rely on dev/ino uniquely
43 * identifying a file.  This doesn't match well with Windows.  I'm
44 * considering alternative APIs.
45 */
46
47#if defined(_WIN32) && !defined(__CYGWIN__)
48
49#include "archive_platform.h"
50#include "archive_private.h"
51#include "archive_hash.h"
52#include <ctype.h>
53#include <errno.h>
54#include <stddef.h>
55#ifdef HAVE_SYS_UTIME_H
56#include <sys/utime.h>
57#endif
58#include <sys/stat.h>
59#include <process.h>
60#include <stdlib.h>
61#include <wchar.h>
62#include <windows.h>
63
64#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
65
66#if defined(_MSC_VER) && _MSC_VER < 1300
67/* VS 6 does not provide SetFilePointerEx, so define it here.  */
68static BOOL SetFilePointerEx(HANDLE hFile,
69                             LARGE_INTEGER liDistanceToMove,
70                             PLARGE_INTEGER lpNewFilePointer,
71                             DWORD dwMoveMethod)
72{
73	LARGE_INTEGER li;
74	li.QuadPart = liDistanceToMove.QuadPart;
75	li.LowPart = SetFilePointer(
76	    hFile, li.LowPart, &li.HighPart, dwMoveMethod);
77	if(lpNewFilePointer) {
78		lpNewFilePointer->QuadPart = li.QuadPart;
79	}
80	return li.LowPart != -1 || GetLastError() == NO_ERROR;
81}
82#endif
83
84struct ustat {
85	int64_t		st_atime;
86	uint32_t	st_atime_nsec;
87	int64_t		st_ctime;
88	uint32_t	st_ctime_nsec;
89	int64_t		st_mtime;
90	uint32_t	st_mtime_nsec;
91	gid_t		st_gid;
92	/* 64bits ino */
93	int64_t		st_ino;
94	mode_t		st_mode;
95	uint32_t	st_nlink;
96	uint64_t	st_size;
97	uid_t		st_uid;
98	dev_t		st_dev;
99	dev_t		st_rdev;
100};
101
102/* Local replacement for undocumented Windows CRT function. */
103static void la_dosmaperr(unsigned long e);
104
105/* Transform 64-bits ino into 32-bits by hashing.
106 * You do not forget that really unique number size is 64-bits.
107 */
108#define INOSIZE (8*sizeof(ino_t)) /* 32 */
109static __inline ino_t
110getino(struct ustat *ub)
111{
112	ULARGE_INTEGER ino64;
113	ino64.QuadPart = ub->st_ino;
114	/* I don't know this hashing is correct way */
115	return (ino64.LowPart ^ (ino64.LowPart >> INOSIZE));
116}
117
118/*
119 * Prepend "\\?\" to the path name and convert it to unicode to permit
120 * an extended-length path for a maximum total path length of 32767
121 * characters.
122 * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx
123 */
124static wchar_t *
125permissive_name(const char *name)
126{
127	wchar_t *wn, *wnp;
128	wchar_t *ws, *wsp;
129	DWORD l, len, slen;
130	int unc;
131
132	len = (DWORD)strlen(name);
133	wn = malloc((len + 1) * sizeof(wchar_t));
134	if (wn == NULL)
135		return (NULL);
136	l = MultiByteToWideChar(CP_ACP, 0, name, (int)len, wn, (int)len);
137	if (l == 0) {
138		free(wn);
139		return (NULL);
140	}
141	wn[l] = L'\0';
142
143	/* Get a full path names */
144	l = GetFullPathNameW(wn, 0, NULL, NULL);
145	if (l == 0) {
146		free(wn);
147		return (NULL);
148	}
149	wnp = malloc(l * sizeof(wchar_t));
150	if (wnp == NULL) {
151		free(wn);
152		return (NULL);
153	}
154	len = GetFullPathNameW(wn, l, wnp, NULL);
155	free(wn);
156	wn = wnp;
157
158	if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
159	    wnp[2] == L'?' && wnp[3] == L'\\')
160		/* We have already permissive names. */
161		return (wn);
162
163	if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
164		wnp[2] == L'.' && wnp[3] == L'\\') {
165		/* Device names */
166		if (((wnp[4] >= L'a' && wnp[4] <= L'z') ||
167		     (wnp[4] >= L'A' && wnp[4] <= L'Z')) &&
168		    wnp[5] == L':' && wnp[6] == L'\\')
169			wnp[2] = L'?';/* Not device names. */
170		return (wn);
171	}
172
173	unc = 0;
174	if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {
175		wchar_t *p = &wnp[2];
176
177		/* Skip server-name letters. */
178		while (*p != L'\\' && *p != L'\0')
179			++p;
180		if (*p == L'\\') {
181			wchar_t *rp = ++p;
182			/* Skip share-name letters. */
183			while (*p != L'\\' && *p != L'\0')
184				++p;
185			if (*p == L'\\' && p != rp) {
186				/* Now, match patterns such as
187				 * "\\server-name\share-name\" */
188				wnp += 2;
189				len -= 2;
190				unc = 1;
191			}
192		}
193	}
194
195	slen = 4 + (unc * 4) + len + 1;
196	ws = wsp = malloc(slen * sizeof(wchar_t));
197	if (ws == NULL) {
198		free(wn);
199		return (NULL);
200	}
201	/* prepend "\\?\" */
202	wcsncpy(wsp, L"\\\\?\\", 4);
203	wsp += 4;
204	slen -= 4;
205	if (unc) {
206		/* append "UNC\" ---> "\\?\UNC\" */
207		wcsncpy(wsp, L"UNC\\", 4);
208		wsp += 4;
209		slen -= 4;
210	}
211	wcsncpy(wsp, wnp, slen);
212	wsp[slen - 1] = L'\0'; /* Ensure null termination. */
213	free(wn);
214	return (ws);
215}
216
217static HANDLE
218la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
219    LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
220    DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
221{
222	wchar_t *wpath;
223	HANDLE handle;
224
225	handle = CreateFileA(path, dwDesiredAccess, dwShareMode,
226	    lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
227	    hTemplateFile);
228	if (handle != INVALID_HANDLE_VALUE)
229		return (handle);
230	if (GetLastError() != ERROR_PATH_NOT_FOUND)
231		return (handle);
232	wpath = permissive_name(path);
233	if (wpath == NULL)
234		return (handle);
235	handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode,
236	    lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
237	    hTemplateFile);
238	free(wpath);
239	return (handle);
240}
241
242static void *
243la_GetFunctionKernel32(const char *name)
244{
245	static HINSTANCE lib;
246	static int set;
247	if (!set) {
248		set = 1;
249		lib = LoadLibrary("kernel32.dll");
250	}
251	if (lib == NULL) {
252		fprintf(stderr, "Can't load kernel32.dll?!\n");
253		exit(1);
254	}
255	return (void *)GetProcAddress(lib, name);
256}
257
258static int
259la_CreateHardLinkW(wchar_t *linkname, wchar_t *target)
260{
261	static BOOLEAN (WINAPI *f)(LPWSTR, LPWSTR, LPSECURITY_ATTRIBUTES);
262	static int set;
263	if (!set) {
264		set = 1;
265		f = la_GetFunctionKernel32("CreateHardLinkW");
266	}
267	return f == NULL ? 0 : (*f)(linkname, target, NULL);
268}
269
270
271/* Make a link to src called dst.  */
272static int
273__link(const char *src, const char *dst)
274{
275	wchar_t *wsrc, *wdst;
276	int res, retval;
277	DWORD attr;
278
279	if (src == NULL || dst == NULL) {
280		set_errno (EINVAL);
281		return -1;
282	}
283
284	wsrc = permissive_name(src);
285	wdst = permissive_name(dst);
286	if (wsrc == NULL || wdst == NULL) {
287		free(wsrc);
288		free(wdst);
289		set_errno (EINVAL);
290		return -1;
291	}
292
293	if ((attr = GetFileAttributesW(wsrc)) != (DWORD)-1) {
294		res = la_CreateHardLinkW(wdst, wsrc);
295	} else {
296		/* wsrc does not exist; try src prepend it with the dirname of wdst */
297		wchar_t *wnewsrc, *slash;
298		int i, n, slen, wlen;
299
300		if (strlen(src) >= 3 && isalpha((unsigned char)src[0]) &&
301		    src[1] == ':' && src[2] == '\\') {
302			/* Original src name is already full-path */
303			retval = -1;
304			goto exit;
305		}
306		if (src[0] == '\\') {
307			/* Original src name is almost full-path
308			 * (maybe src name is without drive) */
309			retval = -1;
310			goto exit;
311		}
312
313		wnewsrc = malloc ((wcslen(wsrc) + wcslen(wdst) + 1) * sizeof(wchar_t));
314		if (wnewsrc == NULL) {
315			errno = ENOMEM;
316			retval = -1;
317			goto exit;
318		}
319		/* Copying a dirname of wdst */
320		wcscpy(wnewsrc, wdst);
321		slash = wcsrchr(wnewsrc, L'\\');
322		if (slash != NULL)
323			*++slash = L'\0';
324		else
325			wcscat(wnewsrc, L"\\");
326		/* Converting multi-byte src to wide-char src */
327		wlen = (int)wcslen(wsrc);
328		slen = (int)strlen(src);
329		n = MultiByteToWideChar(CP_ACP, 0, src, slen, wsrc, wlen);
330		if (n == 0) {
331			free (wnewsrc);
332			retval = -1;
333			goto exit;
334		}
335		for (i = 0; i < n; i++)
336			if (wsrc[i] == L'/')
337				wsrc[i] = L'\\';
338		wcsncat(wnewsrc, wsrc, n);
339		/* Check again */
340		attr = GetFileAttributesW(wnewsrc);
341		if (attr == (DWORD)-1 || (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
342			if (attr == (DWORD)-1)
343				la_dosmaperr(GetLastError());
344			else
345				errno = EPERM;
346			free (wnewsrc);
347			retval = -1;
348			goto exit;
349		}
350		res = la_CreateHardLinkW(wdst, wnewsrc);
351		free (wnewsrc);
352	}
353	if (res == 0) {
354		la_dosmaperr(GetLastError());
355		retval = -1;
356	} else
357		retval = 0;
358exit:
359	free(wsrc);
360	free(wdst);
361	return (retval);
362}
363
364/* Make a hard link to src called dst.  */
365int
366__la_link(const char *src, const char *dst)
367{
368	return __link(src, dst);
369}
370
371int
372__la_ftruncate(int fd, off_t length)
373{
374	LARGE_INTEGER distance;
375	HANDLE handle;
376
377	if (fd < 0) {
378		errno = EBADF;
379		return (-1);
380	}
381	handle = (HANDLE)_get_osfhandle(fd);
382	if (GetFileType(handle) != FILE_TYPE_DISK) {
383		errno = EBADF;
384		return (-1);
385	}
386	distance.QuadPart = length;
387	if (!SetFilePointerEx(handle, distance, NULL, FILE_BEGIN)) {
388		la_dosmaperr(GetLastError());
389		return (-1);
390	}
391	if (!SetEndOfFile(handle)) {
392		la_dosmaperr(GetLastError());
393		return (-1);
394	}
395	return (0);
396}
397
398#define WINTIME(sec, usec)	((Int32x32To64(sec, 10000000) + EPOC_TIME) + (usec * 10))
399static int
400__hutimes(HANDLE handle, const struct __timeval *times)
401{
402	ULARGE_INTEGER wintm;
403	FILETIME fatime, fmtime;
404
405	wintm.QuadPart = WINTIME(times[0].tv_sec, times[0].tv_usec);
406	fatime.dwLowDateTime = wintm.LowPart;
407	fatime.dwHighDateTime = wintm.HighPart;
408	wintm.QuadPart = WINTIME(times[1].tv_sec, times[1].tv_usec);
409	fmtime.dwLowDateTime = wintm.LowPart;
410	fmtime.dwHighDateTime = wintm.HighPart;
411	if (SetFileTime(handle, NULL, &fatime, &fmtime) == 0) {
412		errno = EINVAL;
413		return (-1);
414	}
415	return (0);
416}
417
418int
419__la_futimes(int fd, const struct __timeval *times)
420{
421
422	return (__hutimes((HANDLE)_get_osfhandle(fd), times));
423}
424
425int
426__la_utimes(const char *name, const struct __timeval *times)
427{
428	int ret;
429	HANDLE handle;
430
431	handle = la_CreateFile(name, GENERIC_READ | GENERIC_WRITE,
432	    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
433	    FILE_FLAG_BACKUP_SEMANTICS, NULL);
434	if (handle == INVALID_HANDLE_VALUE) {
435		la_dosmaperr(GetLastError());
436		return (-1);
437	}
438	ret = __hutimes(handle, times);
439	CloseHandle(handle);
440	return (ret);
441}
442
443int
444__la_chdir(const char *path)
445{
446	wchar_t *ws;
447	int r;
448
449	r = SetCurrentDirectoryA(path);
450	if (r == 0) {
451		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
452			la_dosmaperr(GetLastError());
453			return (-1);
454		}
455	} else
456		return (0);
457	ws = permissive_name(path);
458	if (ws == NULL) {
459		errno = EINVAL;
460		return (-1);
461	}
462	r = SetCurrentDirectoryW(ws);
463	free(ws);
464	if (r == 0) {
465		la_dosmaperr(GetLastError());
466		return (-1);
467	}
468	return (0);
469}
470
471int
472__la_chmod(const char *path, mode_t mode)
473{
474	wchar_t *ws;
475	DWORD attr;
476	BOOL r;
477
478	ws = NULL;
479	attr = GetFileAttributesA(path);
480	if (attr == (DWORD)-1) {
481		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
482			la_dosmaperr(GetLastError());
483			return (-1);
484		}
485		ws = permissive_name(path);
486		if (ws == NULL) {
487			errno = EINVAL;
488			return (-1);
489		}
490		attr = GetFileAttributesW(ws);
491		if (attr == (DWORD)-1) {
492			free(ws);
493			la_dosmaperr(GetLastError());
494			return (-1);
495		}
496	}
497	if (mode & _S_IWRITE)
498		attr &= ~FILE_ATTRIBUTE_READONLY;
499	else
500		attr |= FILE_ATTRIBUTE_READONLY;
501	if (ws == NULL)
502		r = SetFileAttributesA(path, attr);
503	else {
504		r = SetFileAttributesW(ws, attr);
505		free(ws);
506	}
507	if (r == 0) {
508		la_dosmaperr(GetLastError());
509		return (-1);
510	}
511	return (0);
512}
513
514/*
515 * This fcntl is limited implemention.
516 */
517int
518__la_fcntl(int fd, int cmd, int val)
519{
520	HANDLE handle;
521
522	handle = (HANDLE)_get_osfhandle(fd);
523	if (GetFileType(handle) == FILE_TYPE_PIPE) {
524		if (cmd == F_SETFL && val == 0) {
525			DWORD mode = PIPE_WAIT;
526			if (SetNamedPipeHandleState(
527			    handle, &mode, NULL, NULL) != 0)
528				return (0);
529		}
530	}
531	errno = EINVAL;
532	return (-1);
533}
534
535__int64
536__la_lseek(int fd, __int64 offset, int whence)
537{
538	LARGE_INTEGER distance;
539	LARGE_INTEGER newpointer;
540	HANDLE handle;
541
542	if (fd < 0) {
543		errno = EBADF;
544		return (-1);
545	}
546	handle = (HANDLE)_get_osfhandle(fd);
547	if (GetFileType(handle) != FILE_TYPE_DISK) {
548		errno = EBADF;
549		return (-1);
550	}
551	distance.QuadPart = offset;
552	if (!SetFilePointerEx(handle, distance, &newpointer, whence)) {
553		DWORD lasterr;
554
555		lasterr = GetLastError();
556		if (lasterr == ERROR_BROKEN_PIPE)
557			return (0);
558		if (lasterr == ERROR_ACCESS_DENIED)
559			errno = EBADF;
560		else
561			la_dosmaperr(lasterr);
562		return (-1);
563	}
564	return (newpointer.QuadPart);
565}
566
567int
568__la_mkdir(const char *path, mode_t mode)
569{
570	wchar_t *ws;
571	int r;
572
573	(void)mode;/* UNUSED */
574	r = CreateDirectoryA(path, NULL);
575	if (r == 0) {
576		DWORD lasterr = GetLastError();
577		if (lasterr != ERROR_FILENAME_EXCED_RANGE &&
578			lasterr != ERROR_PATH_NOT_FOUND) {
579			la_dosmaperr(GetLastError());
580			return (-1);
581		}
582	} else
583		return (0);
584	ws = permissive_name(path);
585	if (ws == NULL) {
586		errno = EINVAL;
587		return (-1);
588	}
589	r = CreateDirectoryW(ws, NULL);
590	free(ws);
591	if (r == 0) {
592		la_dosmaperr(GetLastError());
593		return (-1);
594	}
595	return (0);
596}
597
598/* Windows' mbstowcs is differrent error handling from other unix mbstowcs.
599 * That one is using MultiByteToWideChar function with MB_PRECOMPOSED and
600 * MB_ERR_INVALID_CHARS flags.
601 * This implements for only to pass libarchive_test.
602 */
603size_t
604__la_mbstowcs(wchar_t *wcstr, const char *mbstr, size_t nwchars)
605{
606
607	return (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
608	    mbstr, (int)strlen(mbstr), wcstr,
609	    (int)nwchars));
610}
611
612int
613__la_open(const char *path, int flags, ...)
614{
615	va_list ap;
616	wchar_t *ws;
617	int r, pmode;
618	DWORD attr;
619
620	va_start(ap, flags);
621	pmode = va_arg(ap, int);
622	va_end(ap);
623	ws = NULL;
624	if ((flags & ~O_BINARY) == O_RDONLY) {
625		/*
626		 * When we open a directory, _open function returns
627		 * "Permission denied" error.
628		 */
629		attr = GetFileAttributesA(path);
630		if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) {
631			ws = permissive_name(path);
632			if (ws == NULL) {
633				errno = EINVAL;
634				return (-1);
635			}
636			attr = GetFileAttributesW(ws);
637		}
638		if (attr == (DWORD)-1) {
639			la_dosmaperr(GetLastError());
640			free(ws);
641			return (-1);
642		}
643		if (attr & FILE_ATTRIBUTE_DIRECTORY) {
644			HANDLE handle;
645
646			if (ws != NULL)
647				handle = CreateFileW(ws, 0, 0, NULL,
648				    OPEN_EXISTING,
649				    FILE_FLAG_BACKUP_SEMANTICS |
650				    FILE_ATTRIBUTE_READONLY,
651					NULL);
652			else
653				handle = CreateFileA(path, 0, 0, NULL,
654				    OPEN_EXISTING,
655				    FILE_FLAG_BACKUP_SEMANTICS |
656				    FILE_ATTRIBUTE_READONLY,
657					NULL);
658			free(ws);
659			if (handle == INVALID_HANDLE_VALUE) {
660				la_dosmaperr(GetLastError());
661				return (-1);
662			}
663			r = _open_osfhandle((intptr_t)handle, _O_RDONLY);
664			return (r);
665		}
666	}
667	if (ws == NULL) {
668#if defined(__BORLANDC__)
669		/* Borland has no mode argument.
670		   TODO: Fix mode of new file.  */
671		r = _open(path, flags);
672#else
673		r = _open(path, flags, pmode);
674#endif
675		if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
676			/* simular other POSIX system action to pass a test */
677			attr = GetFileAttributesA(path);
678			if (attr == (DWORD)-1)
679				la_dosmaperr(GetLastError());
680			else if (attr & FILE_ATTRIBUTE_DIRECTORY)
681				errno = EISDIR;
682			else
683				errno = EACCES;
684			return (-1);
685		}
686		if (r >= 0 || errno != ENOENT)
687			return (r);
688		ws = permissive_name(path);
689		if (ws == NULL) {
690			errno = EINVAL;
691			return (-1);
692		}
693	}
694	r = _wopen(ws, flags, pmode);
695	if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) {
696		/* simular other POSIX system action to pass a test */
697		attr = GetFileAttributesW(ws);
698		if (attr == (DWORD)-1)
699			la_dosmaperr(GetLastError());
700		else if (attr & FILE_ATTRIBUTE_DIRECTORY)
701			errno = EISDIR;
702		else
703			errno = EACCES;
704	}
705	free(ws);
706	return (r);
707}
708
709ssize_t
710__la_read(int fd, void *buf, size_t nbytes)
711{
712	HANDLE handle;
713	DWORD bytes_read, lasterr;
714	int r;
715
716#ifdef _WIN64
717	if (nbytes > UINT32_MAX)
718		nbytes = UINT32_MAX;
719#endif
720	if (fd < 0) {
721		errno = EBADF;
722		return (-1);
723	}
724	handle = (HANDLE)_get_osfhandle(fd);
725	if (GetFileType(handle) == FILE_TYPE_PIPE) {
726		DWORD sta;
727		if (GetNamedPipeHandleState(
728		    handle, &sta, NULL, NULL, NULL, NULL, 0) != 0 &&
729		    (sta & PIPE_NOWAIT) == 0) {
730			DWORD avail = -1;
731			int cnt = 3;
732
733			while (PeekNamedPipe(
734			    handle, NULL, 0, NULL, &avail, NULL) != 0 &&
735			    avail == 0 && --cnt)
736				Sleep(100);
737			if (avail == 0)
738				return (0);
739		}
740	}
741	r = ReadFile(handle, buf, (uint32_t)nbytes,
742	    &bytes_read, NULL);
743	if (r == 0) {
744		lasterr = GetLastError();
745		if (lasterr == ERROR_NO_DATA) {
746			errno = EAGAIN;
747			return (-1);
748		}
749		if (lasterr == ERROR_BROKEN_PIPE)
750			return (0);
751		if (lasterr == ERROR_ACCESS_DENIED)
752			errno = EBADF;
753		else
754			la_dosmaperr(lasterr);
755		return (-1);
756	}
757	return ((ssize_t)bytes_read);
758}
759
760/* Remove directory */
761int
762__la_rmdir(const char *path)
763{
764	wchar_t *ws;
765	int r;
766
767	r = _rmdir(path);
768	if (r >= 0 || errno != ENOENT)
769		return (r);
770	ws = permissive_name(path);
771	if (ws == NULL) {
772		errno = EINVAL;
773		return (-1);
774	}
775	r = _wrmdir(ws);
776	free(ws);
777	return (r);
778}
779
780/* Convert Windows FILETIME to UTC */
781__inline static void
782fileTimeToUTC(const FILETIME *filetime, time_t *time, long *ns)
783{
784	ULARGE_INTEGER utc;
785
786	utc.HighPart = filetime->dwHighDateTime;
787	utc.LowPart  = filetime->dwLowDateTime;
788	if (utc.QuadPart >= EPOC_TIME) {
789		utc.QuadPart -= EPOC_TIME;
790		*time = (time_t)(utc.QuadPart / 10000000);	/* milli seconds base */
791		*ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
792	} else {
793		*time = 0;
794		*ns = 0;
795	}
796}
797
798/* Stat by handle
799 * Windows' stat() does not accept path which is added "\\?\" especially "?"
800 * character.
801 * It means we cannot access a long name path(which is longer than MAX_PATH).
802 * So I've implemented simular Windows' stat() to access the long name path.
803 * And I've added some feature.
804 * 1. set st_ino by nFileIndexHigh and nFileIndexLow of
805 *    BY_HANDLE_FILE_INFORMATION.
806 * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION.
807 * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION.
808 */
809static int
810__hstat(HANDLE handle, struct ustat *st)
811{
812	BY_HANDLE_FILE_INFORMATION info;
813	ULARGE_INTEGER ino64;
814	DWORD ftype;
815	mode_t mode;
816	time_t time;
817	long ns;
818
819	switch (ftype = GetFileType(handle)) {
820	case FILE_TYPE_UNKNOWN:
821		errno = EBADF;
822		return (-1);
823	case FILE_TYPE_CHAR:
824	case FILE_TYPE_PIPE:
825		if (ftype == FILE_TYPE_CHAR) {
826			st->st_mode = S_IFCHR;
827			st->st_size = 0;
828		} else {
829			DWORD avail;
830
831			st->st_mode = S_IFIFO;
832			if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL))
833				st->st_size = avail;
834			else
835				st->st_size = 0;
836		}
837		st->st_atime = 0;
838		st->st_atime_nsec = 0;
839		st->st_mtime = 0;
840		st->st_mtime_nsec = 0;
841		st->st_ctime = 0;
842		st->st_ctime_nsec = 0;
843		st->st_ino = 0;
844		st->st_nlink = 1;
845		st->st_uid = 0;
846		st->st_gid = 0;
847		st->st_rdev = 0;
848		st->st_dev = 0;
849		return (0);
850	case FILE_TYPE_DISK:
851		break;
852	default:
853		/* This ftype is undocumented type. */
854		la_dosmaperr(GetLastError());
855		return (-1);
856	}
857
858	ZeroMemory(&info, sizeof(info));
859	if (!GetFileInformationByHandle (handle, &info)) {
860		la_dosmaperr(GetLastError());
861		return (-1);
862	}
863
864	mode = S_IRUSR | S_IRGRP | S_IROTH;
865	if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
866		mode |= S_IWUSR | S_IWGRP | S_IWOTH;
867	if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
868		mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
869	else
870		mode |= S_IFREG;
871	st->st_mode = mode;
872
873	fileTimeToUTC(&info.ftLastAccessTime, &time, &ns);
874	st->st_atime = time;
875	st->st_atime_nsec = ns;
876	fileTimeToUTC(&info.ftLastWriteTime, &time, &ns);
877	st->st_mtime = time;
878	st->st_mtime_nsec = ns;
879	fileTimeToUTC(&info.ftCreationTime, &time, &ns);
880	st->st_ctime = time;
881	st->st_ctime_nsec = ns;
882	st->st_size =
883	    ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1))
884		+ (int64_t)(info.nFileSizeLow);
885#ifdef SIMULATE_WIN_STAT
886	st->st_ino = 0;
887	st->st_nlink = 1;
888	st->st_dev = 0;
889#else
890	/* Getting FileIndex as i-node. We have to remove a sequence which
891	 * is high-16-bits of nFileIndexHigh. */
892	ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL;
893	ino64.LowPart  = info.nFileIndexLow;
894	st->st_ino = ino64.QuadPart;
895	st->st_nlink = info.nNumberOfLinks;
896	if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
897		++st->st_nlink;/* Add parent directory. */
898	st->st_dev = info.dwVolumeSerialNumber;
899#endif
900	st->st_uid = 0;
901	st->st_gid = 0;
902	st->st_rdev = 0;
903	return (0);
904}
905
906static void
907copy_stat(struct stat *st, struct ustat *us)
908{
909	st->st_atime = us->st_atime;
910	st->st_ctime = us->st_ctime;
911	st->st_mtime = us->st_mtime;
912	st->st_gid = us->st_gid;
913	st->st_ino = getino(us);
914	st->st_mode = us->st_mode;
915	st->st_nlink = us->st_nlink;
916	st->st_size = us->st_size;
917	st->st_uid = us->st_uid;
918	st->st_dev = us->st_dev;
919	st->st_rdev = us->st_rdev;
920}
921
922int
923__la_fstat(int fd, struct stat *st)
924{
925	struct ustat u;
926	int ret;
927
928	if (fd < 0) {
929		errno = EBADF;
930		return (-1);
931	}
932	ret = __hstat((HANDLE)_get_osfhandle(fd), &u);
933	if (ret >= 0) {
934		copy_stat(st, &u);
935		if (u.st_mode & (S_IFCHR | S_IFIFO)) {
936			st->st_dev = fd;
937			st->st_rdev = fd;
938		}
939	}
940	return (ret);
941}
942
943int
944__la_stat(const char *path, struct stat *st)
945{
946	HANDLE handle;
947	struct ustat u;
948	int ret;
949
950	handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING,
951		FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY,
952		NULL);
953	if (handle == INVALID_HANDLE_VALUE) {
954		la_dosmaperr(GetLastError());
955		return (-1);
956	}
957	ret = __hstat(handle, &u);
958	CloseHandle(handle);
959	if (ret >= 0) {
960		char *p;
961
962		copy_stat(st, &u);
963		p = strrchr(path, '.');
964		if (p != NULL && strlen(p) == 4) {
965			char exttype[4];
966
967			++ p;
968			exttype[0] = toupper(*p++);
969			exttype[1] = toupper(*p++);
970			exttype[2] = toupper(*p++);
971			exttype[3] = '\0';
972			if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") ||
973				!strcmp(exttype, "BAT") || !strcmp(exttype, "COM"))
974				st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
975		}
976	}
977	return (ret);
978}
979
980int
981__la_unlink(const char *path)
982{
983	wchar_t *ws;
984	int r;
985
986	r = _unlink(path);
987	if (r >= 0 || errno != ENOENT)
988		return (r);
989	ws = permissive_name(path);
990	if (ws == NULL) {
991		errno = EINVAL;
992		return (-1);
993	}
994	r = _wunlink(ws);
995	free(ws);
996	return (r);
997}
998
999/*
1000 * This waitpid is limited implemention.
1001 */
1002pid_t
1003__la_waitpid(pid_t wpid, int *status, int option)
1004{
1005	HANDLE child;
1006	DWORD cs, ret;
1007
1008	(void)option;/* UNUSED */
1009	child = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, wpid);
1010	if (child == NULL) {
1011		la_dosmaperr(GetLastError());
1012		return (-1);
1013	}
1014	ret = WaitForSingleObject(child, INFINITE);
1015	if (ret == WAIT_FAILED) {
1016		CloseHandle(child);
1017		la_dosmaperr(GetLastError());
1018		return (-1);
1019	}
1020	if (GetExitCodeProcess(child, &cs) == 0) {
1021		CloseHandle(child);
1022		la_dosmaperr(GetLastError());
1023		return (-1);
1024	}
1025	if (cs == STILL_ACTIVE)
1026		*status = 0x100;
1027	else
1028		*status = (int)(cs & 0xff);
1029	CloseHandle(child);
1030	return (wpid);
1031}
1032
1033ssize_t
1034__la_write(int fd, const void *buf, size_t nbytes)
1035{
1036	DWORD bytes_written;
1037
1038#ifdef _WIN64
1039	if (nbytes > UINT32_MAX)
1040		nbytes = UINT32_MAX;
1041#endif
1042	if (fd < 0) {
1043		errno = EBADF;
1044		return (-1);
1045	}
1046	if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes,
1047	    &bytes_written, NULL)) {
1048		DWORD lasterr;
1049
1050		lasterr = GetLastError();
1051		if (lasterr == ERROR_ACCESS_DENIED)
1052			errno = EBADF;
1053		else
1054			la_dosmaperr(lasterr);
1055		return (-1);
1056	}
1057	return (bytes_written);
1058}
1059
1060/*
1061 * The following function was modified from PostgreSQL sources and is
1062 * subject to the copyright below.
1063 */
1064/*-------------------------------------------------------------------------
1065 *
1066 * win32error.c
1067 *	  Map win32 error codes to errno values
1068 *
1069 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
1070 *
1071 * IDENTIFICATION
1072 *	  $PostgreSQL: pgsql/src/port/win32error.c,v 1.4 2008/01/01 19:46:00 momjian Exp $
1073 *
1074 *-------------------------------------------------------------------------
1075 */
1076/*
1077PostgreSQL Database Management System
1078(formerly known as Postgres, then as Postgres95)
1079
1080Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
1081
1082Portions Copyright (c) 1994, The Regents of the University of California
1083
1084Permission to use, copy, modify, and distribute this software and its
1085documentation for any purpose, without fee, and without a written agreement
1086is hereby granted, provided that the above copyright notice and this
1087paragraph and the following two paragraphs appear in all copies.
1088
1089IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
1090DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
1091LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
1092DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
1093POSSIBILITY OF SUCH DAMAGE.
1094
1095THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
1096INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
1097AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
1098ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
1099PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1100*/
1101
1102static const struct {
1103	DWORD		winerr;
1104	int		doserr;
1105} doserrors[] =
1106{
1107	{	ERROR_INVALID_FUNCTION, EINVAL	},
1108	{	ERROR_FILE_NOT_FOUND, ENOENT	},
1109	{	ERROR_PATH_NOT_FOUND, ENOENT	},
1110	{	ERROR_TOO_MANY_OPEN_FILES, EMFILE	},
1111	{	ERROR_ACCESS_DENIED, EACCES	},
1112	{	ERROR_INVALID_HANDLE, EBADF	},
1113	{	ERROR_ARENA_TRASHED, ENOMEM	},
1114	{	ERROR_NOT_ENOUGH_MEMORY, ENOMEM	},
1115	{	ERROR_INVALID_BLOCK, ENOMEM	},
1116	{	ERROR_BAD_ENVIRONMENT, E2BIG	},
1117	{	ERROR_BAD_FORMAT, ENOEXEC	},
1118	{	ERROR_INVALID_ACCESS, EINVAL	},
1119	{	ERROR_INVALID_DATA, EINVAL	},
1120	{	ERROR_INVALID_DRIVE, ENOENT	},
1121	{	ERROR_CURRENT_DIRECTORY, EACCES	},
1122	{	ERROR_NOT_SAME_DEVICE, EXDEV	},
1123	{	ERROR_NO_MORE_FILES, ENOENT	},
1124	{	ERROR_LOCK_VIOLATION, EACCES	},
1125	{	ERROR_SHARING_VIOLATION, EACCES	},
1126	{	ERROR_BAD_NETPATH, ENOENT	},
1127	{	ERROR_NETWORK_ACCESS_DENIED, EACCES	},
1128	{	ERROR_BAD_NET_NAME, ENOENT	},
1129	{	ERROR_FILE_EXISTS, EEXIST	},
1130	{	ERROR_CANNOT_MAKE, EACCES	},
1131	{	ERROR_FAIL_I24, EACCES	},
1132	{	ERROR_INVALID_PARAMETER, EINVAL	},
1133	{	ERROR_NO_PROC_SLOTS, EAGAIN	},
1134	{	ERROR_DRIVE_LOCKED, EACCES	},
1135	{	ERROR_BROKEN_PIPE, EPIPE	},
1136	{	ERROR_DISK_FULL, ENOSPC	},
1137	{	ERROR_INVALID_TARGET_HANDLE, EBADF	},
1138	{	ERROR_INVALID_HANDLE, EINVAL	},
1139	{	ERROR_WAIT_NO_CHILDREN, ECHILD	},
1140	{	ERROR_CHILD_NOT_COMPLETE, ECHILD	},
1141	{	ERROR_DIRECT_ACCESS_HANDLE, EBADF	},
1142	{	ERROR_NEGATIVE_SEEK, EINVAL	},
1143	{	ERROR_SEEK_ON_DEVICE, EACCES	},
1144	{	ERROR_DIR_NOT_EMPTY, ENOTEMPTY	},
1145	{	ERROR_NOT_LOCKED, EACCES	},
1146	{	ERROR_BAD_PATHNAME, ENOENT	},
1147	{	ERROR_MAX_THRDS_REACHED, EAGAIN	},
1148	{	ERROR_LOCK_FAILED, EACCES	},
1149	{	ERROR_ALREADY_EXISTS, EEXIST	},
1150	{	ERROR_FILENAME_EXCED_RANGE, ENOENT	},
1151	{	ERROR_NESTING_NOT_ALLOWED, EAGAIN	},
1152	{	ERROR_NOT_ENOUGH_QUOTA, ENOMEM	}
1153};
1154
1155static void
1156la_dosmaperr(unsigned long e)
1157{
1158	int			i;
1159
1160	if (e == 0)
1161	{
1162		errno = 0;
1163		return;
1164	}
1165
1166	for (i = 0; i < sizeof(doserrors); i++)
1167	{
1168		if (doserrors[i].winerr == e)
1169		{
1170			errno = doserrors[i].doserr;
1171			return;
1172		}
1173	}
1174
1175	/* fprintf(stderr, "unrecognized win32 error code: %lu", e); */
1176	errno = EINVAL;
1177	return;
1178}
1179
1180#if defined(ARCHIVE_HASH_MD5_WIN)    ||\
1181    defined(ARCHIVE_HASH_SHA1_WIN)   || defined(ARCHIVE_HASH_SHA256_WIN) ||\
1182    defined(ARCHIVE_HASH_SHA384_WIN) || defined(ARCHIVE_HASH_SHA512_WIN)
1183/*
1184 * Message digest functions.
1185 */
1186void
1187__la_hash_Init(Digest_CTX *ctx, ALG_ID algId)
1188{
1189
1190	ctx->valid = 0;
1191	if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
1192	    PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
1193		if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
1194			return;
1195		if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
1196		    PROV_RSA_FULL, CRYPT_NEWKEYSET))
1197			return;
1198	}
1199
1200	if (!CryptCreateHash(ctx->cryptProv, algId, 0, 0, &ctx->hash)) {
1201		CryptReleaseContext(ctx->cryptProv, 0);
1202		return;
1203	}
1204
1205	ctx->valid = 1;
1206}
1207
1208void
1209__la_hash_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
1210{
1211
1212	if (!ctx->valid)
1213	return;
1214
1215	CryptHashData(ctx->hash,
1216		      (unsigned char *)(uintptr_t)buf,
1217		      (DWORD)len, 0);
1218}
1219
1220void
1221__la_hash_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
1222{
1223	DWORD siglen = bufsize;
1224
1225	if (!ctx->valid)
1226		return;
1227
1228	CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0);
1229	CryptDestroyHash(ctx->hash);
1230	CryptReleaseContext(ctx->cryptProv, 0);
1231	ctx->valid = 0;
1232}
1233
1234#endif /* defined(ARCHIVE_HASH_*_WIN) */
1235
1236#endif /* _WIN32 && !__CYGWIN__ */
1237