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. */
SetFilePointerEx(HANDLE hFile,LARGE_INTEGER liDistanceToMove,PLARGE_INTEGER lpNewFilePointer,DWORD dwMoveMethod)68 static 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
84 struct 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. */
103 static 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 */
109 static __inline ino_t
getino(struct ustat * ub)110 getino(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 */
124 static wchar_t *
permissive_name(const char * name)125 permissive_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
217 static HANDLE
la_CreateFile(const char * path,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)218 la_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
242 static void *
la_GetFunctionKernel32(const char * name)243 la_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
258 static int
la_CreateHardLinkW(wchar_t * linkname,wchar_t * target)259 la_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. */
272 static int
__link(const char * src,const char * dst)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;
358 exit:
359 free(wsrc);
360 free(wdst);
361 return (retval);
362 }
363
364 /* Make a hard link to src called dst. */
365 int
__la_link(const char * src,const char * dst)366 __la_link(const char *src, const char *dst)
367 {
368 return __link(src, dst);
369 }
370
371 int
__la_ftruncate(int fd,off_t length)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))
399 static int
__hutimes(HANDLE handle,const struct __timeval * times)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
418 int
__la_futimes(int fd,const struct __timeval * times)419 __la_futimes(int fd, const struct __timeval *times)
420 {
421
422 return (__hutimes((HANDLE)_get_osfhandle(fd), times));
423 }
424
425 int
__la_utimes(const char * name,const struct __timeval * times)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
443 int
__la_chdir(const char * path)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
471 int
__la_chmod(const char * path,mode_t mode)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 */
517 int
__la_fcntl(int fd,int cmd,int val)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
__la_lseek(int fd,__int64 offset,int whence)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
567 int
__la_mkdir(const char * path,mode_t mode)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 */
603 size_t
__la_mbstowcs(wchar_t * wcstr,const char * mbstr,size_t nwchars)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
612 int
__la_open(const char * path,int flags,...)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
709 ssize_t
__la_read(int fd,void * buf,size_t nbytes)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 */
761 int
__la_rmdir(const char * path)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
fileTimeToUTC(const FILETIME * filetime,time_t * time,long * ns)782 fileTimeToUTC(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 */
809 static int
__hstat(HANDLE handle,struct ustat * st)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
906 static void
copy_stat(struct stat * st,struct ustat * us)907 copy_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
922 int
__la_fstat(int fd,struct stat * st)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
943 int
__la_stat(const char * path,struct stat * st)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
980 int
__la_unlink(const char * path)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 */
1002 pid_t
__la_waitpid(pid_t wpid,int * status,int option)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
1033 ssize_t
__la_write(int fd,const void * buf,size_t nbytes)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 /*
1077 PostgreSQL Database Management System
1078 (formerly known as Postgres, then as Postgres95)
1079
1080 Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
1081
1082 Portions Copyright (c) 1994, The Regents of the University of California
1083
1084 Permission to use, copy, modify, and distribute this software and its
1085 documentation for any purpose, without fee, and without a written agreement
1086 is hereby granted, provided that the above copyright notice and this
1087 paragraph and the following two paragraphs appear in all copies.
1088
1089 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
1090 DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
1091 LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
1092 DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
1093 POSSIBILITY OF SUCH DAMAGE.
1094
1095 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
1096 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
1097 AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
1098 ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
1099 PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1100 */
1101
1102 static 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
1155 static void
la_dosmaperr(unsigned long e)1156 la_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 */
1186 void
__la_hash_Init(Digest_CTX * ctx,ALG_ID algId)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
1208 void
__la_hash_Update(Digest_CTX * ctx,const unsigned char * buf,size_t len)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
1220 void
__la_hash_Final(unsigned char * buf,size_t bufsize,Digest_CTX * ctx)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