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