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