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