1 /*- 2 * Copyright (c) 2009-2011 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 27 /* 28 * A set of compatibility glue for building libarchive on Windows platforms. 29 * 30 * Originally created as "libarchive-nonposix.c" by Kees Zeelenberg 31 * for the GnuWin32 project, trimmed significantly by Tim Kientzle. 32 * 33 * Much of the original file was unnecessary for libarchive, because 34 * many of the features it emulated were not strictly necessary for 35 * libarchive. I hope for this to shrink further as libarchive 36 * internals are gradually reworked to sit more naturally on both 37 * POSIX and Windows. Any ideas for this are greatly appreciated. 38 * 39 * The biggest remaining issue is the dev/ino emulation; libarchive 40 * has a couple of public APIs that rely on dev/ino uniquely 41 * identifying a file. This doesn't match well with Windows. I'm 42 * considering alternative APIs. 43 */ 44 45 #if defined(_WIN32) && !defined(__CYGWIN__) 46 47 #include "archive_platform.h" 48 #include "archive_platform_stat.h" 49 #include "archive_private.h" 50 #include "archive_entry.h" 51 #include "archive_time_private.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 <locale.h> 60 #include <process.h> 61 #include <stdlib.h> 62 #include <wchar.h> 63 #include <windows.h> 64 #include <share.h> 65 66 #if defined(__LA_LSEEK_NEEDED) 67 static BOOL SetFilePointerEx_perso(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 83 struct 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 /* Transform 64-bits ino into 32-bits by hashing. 102 * You do not forget that really unique number size is 64-bits. 103 */ 104 #define INOSIZE (8*sizeof(ino_t)) /* 32 */ 105 static __inline ino_t 106 getino(struct ustat *ub) 107 { 108 ULARGE_INTEGER ino64; 109 ino64.QuadPart = ub->st_ino; 110 /* I don't know this hashing is correct way */ 111 return ((ino_t)(ino64.LowPart ^ (ino64.LowPart >> INOSIZE))); 112 } 113 114 /* 115 * Prepend "\\?\" to the path name and convert it to unicode to permit 116 * an extended-length path for a maximum total path length of 32767 117 * characters. 118 * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx 119 */ 120 wchar_t * 121 __la_win_permissive_name(const char *name) 122 { 123 wchar_t *wn; 124 wchar_t *ws; 125 size_t ll; 126 127 ll = strlen(name); 128 wn = malloc((ll + 1) * sizeof(wchar_t)); 129 if (wn == NULL) 130 return (NULL); 131 ll = mbstowcs(wn, name, ll); 132 if (ll == (size_t)-1) { 133 free(wn); 134 return (NULL); 135 } 136 wn[ll] = L'\0'; 137 ws = __la_win_permissive_name_w(wn); 138 free(wn); 139 return (ws); 140 } 141 142 wchar_t * 143 __la_win_permissive_name_w(const wchar_t *wname) 144 { 145 wchar_t *wn, *wnp; 146 wchar_t *ws, *wsp; 147 DWORD l, len, slen; 148 int unc; 149 150 /* Get a full-pathname. */ 151 l = GetFullPathNameW(wname, 0, NULL, NULL); 152 if (l == 0) 153 return (NULL); 154 /* NOTE: GetFullPathNameW has a bug that if the length of the file 155 * name is just 1 then it returns incomplete buffer size. Thus, we 156 * have to add three to the size to allocate a sufficient buffer 157 * size for the full-pathname of the file name. */ 158 l += 3; 159 wnp = malloc(l * sizeof(wchar_t)); 160 if (wnp == NULL) 161 return (NULL); 162 len = GetFullPathNameW(wname, l, wnp, NULL); 163 wn = wnp; 164 165 if (wnp[0] == L'\\' && wnp[1] == L'\\' && 166 wnp[2] == L'?' && wnp[3] == L'\\') 167 /* We have already a permissive name. */ 168 return (wn); 169 170 if (wnp[0] == L'\\' && wnp[1] == L'\\' && 171 wnp[2] == L'.' && wnp[3] == L'\\') { 172 /* This is a device name */ 173 if (((wnp[4] >= L'a' && wnp[4] <= L'z') || 174 (wnp[4] >= L'A' && wnp[4] <= L'Z')) && 175 wnp[5] == L':' && wnp[6] == L'\\') 176 wnp[2] = L'?';/* Not device name. */ 177 return (wn); 178 } 179 180 unc = 0; 181 if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') { 182 wchar_t *p = &wnp[2]; 183 184 /* Skip server-name letters. */ 185 while (*p != L'\\' && *p != L'\0') 186 ++p; 187 if (*p == L'\\') { 188 wchar_t *rp = ++p; 189 /* Skip share-name letters. */ 190 while (*p != L'\\' && *p != L'\0') 191 ++p; 192 if (*p == L'\\' && p != rp) { 193 /* Now, match patterns such as 194 * "\\server-name\share-name\" */ 195 wnp += 2; 196 len -= 2; 197 unc = 1; 198 } 199 } 200 } 201 202 slen = 4 + (unc * 4) + len + 1; 203 ws = wsp = malloc(slen * sizeof(wchar_t)); 204 if (ws == NULL) { 205 free(wn); 206 return (NULL); 207 } 208 /* prepend "\\?\" */ 209 wcsncpy(wsp, L"\\\\?\\", 4); 210 wsp += 4; 211 slen -= 4; 212 if (unc) { 213 /* append "UNC\" ---> "\\?\UNC\" */ 214 wcsncpy(wsp, L"UNC\\", 4); 215 wsp += 4; 216 slen -= 4; 217 } 218 wcsncpy(wsp, wnp, slen); 219 wsp[slen - 1] = L'\0'; /* Ensure null termination. */ 220 free(wn); 221 return (ws); 222 } 223 224 /* 225 * Create a file handle. 226 * This can exceed MAX_PATH limitation. 227 */ 228 static HANDLE 229 la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, 230 LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, 231 DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) 232 { 233 wchar_t *wpath; 234 HANDLE handle; 235 # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ 236 CREATEFILE2_EXTENDED_PARAMETERS createExParams; 237 #endif 238 239 #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) 240 handle = CreateFileA(path, dwDesiredAccess, dwShareMode, 241 lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, 242 hTemplateFile); 243 if (handle != INVALID_HANDLE_VALUE) 244 return (handle); 245 if (GetLastError() != ERROR_PATH_NOT_FOUND) 246 return (handle); 247 #endif 248 wpath = __la_win_permissive_name(path); 249 if (wpath == NULL) 250 return INVALID_HANDLE_VALUE; 251 # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ 252 ZeroMemory(&createExParams, sizeof(createExParams)); 253 createExParams.dwSize = sizeof(createExParams); 254 createExParams.dwFileAttributes = dwFlagsAndAttributes & 0xFFFF; 255 createExParams.dwFileFlags = dwFlagsAndAttributes & 0xFFF00000; 256 createExParams.dwSecurityQosFlags = dwFlagsAndAttributes & 0x000F0000; 257 createExParams.lpSecurityAttributes = lpSecurityAttributes; 258 createExParams.hTemplateFile = hTemplateFile; 259 handle = CreateFile2(wpath, dwDesiredAccess, dwShareMode, 260 dwCreationDisposition, &createExParams); 261 #else /* !WINAPI_PARTITION_DESKTOP */ 262 handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode, 263 lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, 264 hTemplateFile); 265 #endif /* !WINAPI_PARTITION_DESKTOP */ 266 free(wpath); 267 return (handle); 268 } 269 270 #if defined(__LA_LSEEK_NEEDED) 271 __int64 272 __la_lseek(int fd, __int64 offset, int whence) 273 { 274 LARGE_INTEGER distance; 275 LARGE_INTEGER newpointer; 276 HANDLE handle; 277 278 if (fd < 0) { 279 errno = EBADF; 280 return (-1); 281 } 282 handle = (HANDLE)_get_osfhandle(fd); 283 if (GetFileType(handle) != FILE_TYPE_DISK) { 284 errno = EBADF; 285 return (-1); 286 } 287 distance.QuadPart = offset; 288 if (!SetFilePointerEx_perso(handle, distance, &newpointer, whence)) { 289 DWORD lasterr; 290 291 lasterr = GetLastError(); 292 if (lasterr == ERROR_BROKEN_PIPE) 293 return (0); 294 if (lasterr == ERROR_ACCESS_DENIED) 295 errno = EBADF; 296 else 297 la_dosmaperr(lasterr); 298 return (-1); 299 } 300 return (newpointer.QuadPart); 301 } 302 #endif 303 304 /* This can exceed MAX_PATH limitation. */ 305 int 306 __la_open(const char *path, int flags, ...) 307 { 308 va_list ap; 309 wchar_t *ws; 310 int r, pmode; 311 DWORD attr; 312 313 va_start(ap, flags); 314 pmode = va_arg(ap, int); 315 va_end(ap); 316 ws = NULL; 317 318 /* _(w)sopen_s fails if we provide any other modes */ 319 pmode = pmode & (_S_IREAD | _S_IWRITE); 320 321 if ((flags & ~O_BINARY) == O_RDONLY) { 322 /* 323 * When we open a directory, _open function returns 324 * "Permission denied" error. 325 */ 326 attr = GetFileAttributesA(path); 327 #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) 328 if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) 329 #endif 330 { 331 ws = __la_win_permissive_name(path); 332 if (ws == NULL) { 333 errno = EINVAL; 334 return (-1); 335 } 336 attr = GetFileAttributesW(ws); 337 } 338 if (attr == (DWORD)-1) { 339 la_dosmaperr(GetLastError()); 340 free(ws); 341 return (-1); 342 } 343 if (attr & FILE_ATTRIBUTE_DIRECTORY) { 344 HANDLE handle; 345 #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) 346 if (ws != NULL) 347 handle = CreateFileW(ws, 0, 0, NULL, 348 OPEN_EXISTING, 349 FILE_FLAG_BACKUP_SEMANTICS | 350 FILE_ATTRIBUTE_READONLY, 351 NULL); 352 else 353 handle = CreateFileA(path, 0, 0, NULL, 354 OPEN_EXISTING, 355 FILE_FLAG_BACKUP_SEMANTICS | 356 FILE_ATTRIBUTE_READONLY, 357 NULL); 358 #else /* !WINAPI_PARTITION_DESKTOP */ 359 CREATEFILE2_EXTENDED_PARAMETERS createExParams; 360 ZeroMemory(&createExParams, sizeof(createExParams)); 361 createExParams.dwSize = sizeof(createExParams); 362 createExParams.dwFileAttributes = FILE_ATTRIBUTE_READONLY; 363 createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS; 364 handle = CreateFile2(ws, 0, 0, 365 OPEN_EXISTING, &createExParams); 366 #endif /* !WINAPI_PARTITION_DESKTOP */ 367 free(ws); 368 if (handle == INVALID_HANDLE_VALUE) { 369 la_dosmaperr(GetLastError()); 370 return (-1); 371 } 372 r = _open_osfhandle((intptr_t)handle, _O_RDONLY); 373 return (r); 374 } 375 } 376 if (ws == NULL) { 377 #if defined(__BORLANDC__) 378 /* Borland has no mode argument. 379 TODO: Fix mode of new file. */ 380 r = _open(path, flags); 381 #else 382 _sopen_s(&r, path, flags, _SH_DENYNO, pmode); 383 #endif 384 if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { 385 /* Simulate other POSIX system action to pass our test suite. */ 386 attr = GetFileAttributesA(path); 387 if (attr == (DWORD)-1) 388 la_dosmaperr(GetLastError()); 389 else if (attr & FILE_ATTRIBUTE_DIRECTORY) 390 errno = EISDIR; 391 else 392 errno = EACCES; 393 return (-1); 394 } 395 if (r >= 0 || errno != ENOENT) 396 return (r); 397 ws = __la_win_permissive_name(path); 398 if (ws == NULL) { 399 errno = EINVAL; 400 return (-1); 401 } 402 } 403 _wsopen_s(&r, ws, flags, _SH_DENYNO, pmode); 404 if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { 405 /* Simulate other POSIX system action to pass our test suite. */ 406 attr = GetFileAttributesW(ws); 407 if (attr == (DWORD)-1) 408 la_dosmaperr(GetLastError()); 409 else if (attr & FILE_ATTRIBUTE_DIRECTORY) 410 errno = EISDIR; 411 else 412 errno = EACCES; 413 } 414 free(ws); 415 return (r); 416 } 417 418 int 419 __la_wopen(const wchar_t *path, int flags, ...) 420 { 421 va_list ap; 422 wchar_t *fullpath; 423 int r, pmode; 424 DWORD attr; 425 426 va_start(ap, flags); 427 pmode = va_arg(ap, int); 428 va_end(ap); 429 fullpath = NULL; 430 431 /* _(w)sopen_s fails if we provide any other modes */ 432 pmode = pmode & (_S_IREAD | _S_IWRITE); 433 434 if ((flags & ~O_BINARY) == O_RDONLY) { 435 /* 436 * When we open a directory, _open function returns 437 * "Permission denied" error. 438 */ 439 attr = GetFileAttributesW(path); 440 #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) 441 if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) 442 #endif 443 { 444 fullpath = __la_win_permissive_name_w(path); 445 if (fullpath == NULL) { 446 errno = EINVAL; 447 return (-1); 448 } 449 path = fullpath; 450 attr = GetFileAttributesW(fullpath); 451 } 452 if (attr == (DWORD)-1) { 453 la_dosmaperr(GetLastError()); 454 free(fullpath); 455 return (-1); 456 } 457 if (attr & FILE_ATTRIBUTE_DIRECTORY) { 458 HANDLE handle; 459 #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) 460 if (fullpath != NULL) 461 handle = CreateFileW(fullpath, 0, 0, NULL, 462 OPEN_EXISTING, 463 FILE_FLAG_BACKUP_SEMANTICS | 464 FILE_ATTRIBUTE_READONLY, 465 NULL); 466 else 467 handle = CreateFileW(path, 0, 0, NULL, 468 OPEN_EXISTING, 469 FILE_FLAG_BACKUP_SEMANTICS | 470 FILE_ATTRIBUTE_READONLY, 471 NULL); 472 #else /* !WINAPI_PARTITION_DESKTOP */ 473 CREATEFILE2_EXTENDED_PARAMETERS createExParams; 474 ZeroMemory(&createExParams, sizeof(createExParams)); 475 createExParams.dwSize = sizeof(createExParams); 476 createExParams.dwFileAttributes = FILE_ATTRIBUTE_READONLY; 477 createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS; 478 handle = CreateFile2(fullpath, 0, 0, 479 OPEN_EXISTING, &createExParams); 480 #endif /* !WINAPI_PARTITION_DESKTOP */ 481 free(fullpath); 482 if (handle == INVALID_HANDLE_VALUE) { 483 la_dosmaperr(GetLastError()); 484 return (-1); 485 } 486 r = _open_osfhandle((intptr_t)handle, _O_RDONLY); 487 return (r); 488 } 489 } 490 _wsopen_s(&r, path, flags, _SH_DENYNO, pmode); 491 if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { 492 /* Simulate other POSIX system action to pass our test suite. */ 493 attr = GetFileAttributesW(path); 494 if (attr == (DWORD)-1) 495 la_dosmaperr(GetLastError()); 496 else if (attr & FILE_ATTRIBUTE_DIRECTORY) 497 errno = EISDIR; 498 else 499 errno = EACCES; 500 } 501 free(fullpath); 502 return (r); 503 } 504 505 ssize_t 506 __la_read(int fd, void *buf, size_t nbytes) 507 { 508 HANDLE handle; 509 DWORD bytes_read, lasterr; 510 int r; 511 512 #ifdef _WIN64 513 if (nbytes > UINT32_MAX) 514 nbytes = UINT32_MAX; 515 #endif 516 if (fd < 0) { 517 errno = EBADF; 518 return (-1); 519 } 520 /* Do not pass 0 to third parameter of ReadFile(), read bytes. 521 * This will not return to application side. */ 522 if (nbytes == 0) 523 return (0); 524 handle = (HANDLE)_get_osfhandle(fd); 525 r = ReadFile(handle, buf, (uint32_t)nbytes, 526 &bytes_read, NULL); 527 if (r == 0) { 528 lasterr = GetLastError(); 529 if (lasterr == ERROR_NO_DATA) { 530 errno = EAGAIN; 531 return (-1); 532 } 533 if (lasterr == ERROR_BROKEN_PIPE) 534 return (0); 535 if (lasterr == ERROR_ACCESS_DENIED) 536 errno = EBADF; 537 else 538 la_dosmaperr(lasterr); 539 return (-1); 540 } 541 return ((ssize_t)bytes_read); 542 } 543 544 /* Stat by handle 545 * Windows' stat() does not accept the path added "\\?\" especially "?" 546 * character. 547 * It means we cannot access the long name path longer than MAX_PATH. 548 * So I've implemented a function similar to Windows' stat() to access the 549 * long name path. 550 * And I've added some feature. 551 * 1. set st_ino by nFileIndexHigh and nFileIndexLow of 552 * BY_HANDLE_FILE_INFORMATION. 553 * 2. set st_nlink by nNumberOfLinks of BY_HANDLE_FILE_INFORMATION. 554 * 3. set st_dev by dwVolumeSerialNumber by BY_HANDLE_FILE_INFORMATION. 555 */ 556 static int 557 __hstat(HANDLE handle, struct ustat *st) 558 { 559 BY_HANDLE_FILE_INFORMATION info; 560 ULARGE_INTEGER ino64; 561 DWORD ftype; 562 mode_t mode; 563 564 switch (ftype = GetFileType(handle)) { 565 case FILE_TYPE_UNKNOWN: 566 errno = EBADF; 567 return (-1); 568 case FILE_TYPE_CHAR: 569 case FILE_TYPE_PIPE: 570 if (ftype == FILE_TYPE_CHAR) { 571 st->st_mode = S_IFCHR; 572 st->st_size = 0; 573 } else { 574 DWORD avail; 575 576 st->st_mode = S_IFIFO; 577 if (PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL)) 578 st->st_size = avail; 579 else 580 st->st_size = 0; 581 } 582 st->st_atime = 0; 583 st->st_atime_nsec = 0; 584 st->st_mtime = 0; 585 st->st_mtime_nsec = 0; 586 st->st_ctime = 0; 587 st->st_ctime_nsec = 0; 588 st->st_ino = 0; 589 st->st_nlink = 1; 590 st->st_uid = 0; 591 st->st_gid = 0; 592 st->st_rdev = 0; 593 st->st_dev = 0; 594 return (0); 595 case FILE_TYPE_DISK: 596 break; 597 default: 598 /* This ftype is undocumented type. */ 599 la_dosmaperr(GetLastError()); 600 return (-1); 601 } 602 603 ZeroMemory(&info, sizeof(info)); 604 if (!GetFileInformationByHandle (handle, &info)) { 605 la_dosmaperr(GetLastError()); 606 return (-1); 607 } 608 609 mode = S_IRUSR | S_IRGRP | S_IROTH; 610 if ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) 611 mode |= S_IWUSR | S_IWGRP | S_IWOTH; 612 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 613 mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; 614 else 615 mode |= S_IFREG; 616 st->st_mode = mode; 617 618 ntfs_to_unix(FILETIME_to_ntfs(&info.ftLastAccessTime), &st->st_atime, &st->st_atime_nsec); 619 ntfs_to_unix(FILETIME_to_ntfs(&info.ftLastWriteTime), &st->st_mtime, &st->st_mtime_nsec); 620 ntfs_to_unix(FILETIME_to_ntfs(&info.ftCreationTime), &st->st_ctime, &st->st_ctime_nsec); 621 st->st_size = 622 ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1)) 623 + (int64_t)(info.nFileSizeLow); 624 #ifdef SIMULATE_WIN_STAT 625 st->st_ino = 0; 626 st->st_nlink = 1; 627 st->st_dev = 0; 628 #else 629 /* Getting FileIndex as i-node. We should remove a sequence which 630 * is high-16-bits of nFileIndexHigh. */ 631 ino64.HighPart = info.nFileIndexHigh & 0x0000FFFFUL; 632 ino64.LowPart = info.nFileIndexLow; 633 st->st_ino = ino64.QuadPart; 634 st->st_nlink = info.nNumberOfLinks; 635 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 636 ++st->st_nlink;/* Add parent directory. */ 637 st->st_dev = info.dwVolumeSerialNumber; 638 #endif 639 st->st_uid = 0; 640 st->st_gid = 0; 641 st->st_rdev = 0; 642 return (0); 643 } 644 645 static void 646 copy_stat(struct stat *st, struct ustat *us) 647 { 648 st->st_atime = us->st_atime; 649 st->st_ctime = us->st_ctime; 650 st->st_mtime = us->st_mtime; 651 st->st_gid = us->st_gid; 652 st->st_ino = getino(us); 653 st->st_mode = us->st_mode; 654 st->st_nlink = us->st_nlink; 655 st->st_size = (off_t)us->st_size; 656 if (st->st_size < 0 || (uint64_t)st->st_size != us->st_size) 657 st->st_size = 0; 658 st->st_uid = us->st_uid; 659 st->st_dev = us->st_dev; 660 st->st_rdev = us->st_rdev; 661 } 662 663 /* 664 * TODO: Remove a use of __la_fstat and __la_stat. 665 * We should use GetFileInformationByHandle in place 666 * where We still use the *stat functions. 667 */ 668 int 669 __la_fstat(int fd, struct stat *st) 670 { 671 struct ustat u; 672 int ret; 673 674 if (fd < 0) { 675 errno = EBADF; 676 return (-1); 677 } 678 ret = __hstat((HANDLE)_get_osfhandle(fd), &u); 679 if (ret >= 0) { 680 copy_stat(st, &u); 681 if (u.st_mode & (S_IFCHR | S_IFIFO)) { 682 st->st_dev = fd; 683 st->st_rdev = fd; 684 } 685 } 686 return (ret); 687 } 688 689 /* This can exceed MAX_PATH limitation. */ 690 int 691 __la_stat(const char *path, struct stat *st) 692 { 693 HANDLE handle; 694 struct ustat u; 695 int ret; 696 697 handle = la_CreateFile(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, 698 FILE_FLAG_BACKUP_SEMANTICS, 699 NULL); 700 if (handle == INVALID_HANDLE_VALUE) { 701 la_dosmaperr(GetLastError()); 702 return (-1); 703 } 704 ret = __hstat(handle, &u); 705 CloseHandle(handle); 706 if (ret >= 0) { 707 char *p; 708 709 copy_stat(st, &u); 710 p = strrchr(path, '.'); 711 if (p != NULL && strlen(p) == 4) { 712 char exttype[4]; 713 714 ++ p; 715 exttype[0] = toupper(*p++); 716 exttype[1] = toupper(*p++); 717 exttype[2] = toupper(*p++); 718 exttype[3] = '\0'; 719 if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") || 720 !strcmp(exttype, "BAT") || !strcmp(exttype, "COM")) 721 st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; 722 } 723 } 724 return (ret); 725 } 726 727 static void 728 copy_seek_stat(la_seek_stat_t *st, struct ustat *us) 729 { 730 st->st_mtime = us->st_mtime; 731 st->st_gid = us->st_gid; 732 st->st_ino = getino(us); 733 st->st_mode = us->st_mode; 734 st->st_nlink = us->st_nlink; 735 st->st_size = (la_seek_t)us->st_size; 736 if (st->st_size < 0 || (uint64_t)st->st_size != us->st_size) 737 st->st_size = -1; 738 st->st_uid = us->st_uid; 739 st->st_dev = us->st_dev; 740 st->st_rdev = us->st_rdev; 741 } 742 743 int 744 __la_seek_fstat(int fd, la_seek_stat_t *st) 745 { 746 struct ustat u; 747 int ret; 748 749 ret = __hstat((HANDLE)_get_osfhandle(fd), &u); 750 if (ret >= 0) 751 copy_seek_stat(st, &u); 752 return (ret); 753 } 754 755 int 756 __la_seek_stat(const char *path, la_seek_stat_t *st) 757 { 758 HANDLE handle; 759 struct ustat u; 760 int ret; 761 762 handle = la_CreateFile(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, 763 FILE_FLAG_BACKUP_SEMANTICS, 764 NULL); 765 if (handle == INVALID_HANDLE_VALUE) { 766 la_dosmaperr(GetLastError()); 767 return (-1); 768 } 769 ret = __hstat(handle, &u); 770 CloseHandle(handle); 771 copy_seek_stat(st, &u); 772 return (ret); 773 } 774 775 /* 776 * This waitpid is limited implementation. 777 */ 778 pid_t 779 __la_waitpid(HANDLE child, int *status, int option) 780 { 781 DWORD cs; 782 783 (void)option;/* UNUSED */ 784 do { 785 if (GetExitCodeProcess(child, &cs) == 0) { 786 la_dosmaperr(GetLastError()); 787 CloseHandle(child); 788 *status = 0; 789 return (-1); 790 } 791 } while (cs == STILL_ACTIVE); 792 793 CloseHandle(child); 794 *status = (int)(cs & 0xff); 795 return (0); 796 } 797 798 ssize_t 799 __la_write(int fd, const void *buf, size_t nbytes) 800 { 801 DWORD bytes_written; 802 803 #ifdef _WIN64 804 if (nbytes > UINT32_MAX) 805 nbytes = UINT32_MAX; 806 #endif 807 if (fd < 0) { 808 errno = EBADF; 809 return (-1); 810 } 811 if (!WriteFile((HANDLE)_get_osfhandle(fd), buf, (uint32_t)nbytes, 812 &bytes_written, NULL)) { 813 DWORD lasterr; 814 815 lasterr = GetLastError(); 816 if (lasterr == ERROR_ACCESS_DENIED) 817 errno = EBADF; 818 else 819 la_dosmaperr(lasterr); 820 return (-1); 821 } 822 return (bytes_written); 823 } 824 825 /* 826 * Replace the Windows path separator '\' with '/'. 827 */ 828 static int 829 replace_pathseparator(struct archive_wstring *ws, const wchar_t *wp) 830 { 831 wchar_t *w; 832 size_t path_length; 833 834 if (wp == NULL) 835 return(0); 836 if (wcschr(wp, L'\\') == NULL) 837 return(0); 838 path_length = wcslen(wp); 839 if (archive_wstring_ensure(ws, path_length) == NULL) 840 return(-1); 841 archive_wstrncpy(ws, wp, path_length); 842 for (w = ws->s; *w; w++) { 843 if (*w == L'\\') 844 *w = L'/'; 845 } 846 return(1); 847 } 848 849 static int 850 fix_pathseparator(struct archive_entry *entry) 851 { 852 struct archive_wstring ws; 853 const wchar_t *wp; 854 int ret = ARCHIVE_OK; 855 856 archive_string_init(&ws); 857 wp = archive_entry_pathname_w(entry); 858 switch (replace_pathseparator(&ws, wp)) { 859 case 0: /* Not replaced. */ 860 break; 861 case 1: /* Replaced. */ 862 archive_entry_copy_pathname_w(entry, ws.s); 863 break; 864 default: 865 ret = ARCHIVE_FAILED; 866 } 867 wp = archive_entry_hardlink_w(entry); 868 switch (replace_pathseparator(&ws, wp)) { 869 case 0: /* Not replaced. */ 870 break; 871 case 1: /* Replaced. */ 872 archive_entry_copy_hardlink_w(entry, ws.s); 873 break; 874 default: 875 ret = ARCHIVE_FAILED; 876 } 877 wp = archive_entry_symlink_w(entry); 878 switch (replace_pathseparator(&ws, wp)) { 879 case 0: /* Not replaced. */ 880 break; 881 case 1: /* Replaced. */ 882 archive_entry_copy_symlink_w(entry, ws.s); 883 break; 884 default: 885 ret = ARCHIVE_FAILED; 886 } 887 archive_wstring_free(&ws); 888 return(ret); 889 } 890 891 struct archive_entry * 892 __la_win_entry_in_posix_pathseparator(struct archive_entry *entry) 893 { 894 struct archive_entry *entry_main; 895 const wchar_t *wp; 896 int has_backslash = 0; 897 int ret; 898 899 wp = archive_entry_pathname_w(entry); 900 if (wp != NULL && wcschr(wp, L'\\') != NULL) 901 has_backslash = 1; 902 if (!has_backslash) { 903 wp = archive_entry_hardlink_w(entry); 904 if (wp != NULL && wcschr(wp, L'\\') != NULL) 905 has_backslash = 1; 906 } 907 if (!has_backslash) { 908 wp = archive_entry_symlink_w(entry); 909 if (wp != NULL && wcschr(wp, L'\\') != NULL) 910 has_backslash = 1; 911 } 912 /* 913 * If there is no backslash chars, return the original. 914 */ 915 if (!has_backslash) 916 return (entry); 917 918 /* Copy entry so we can modify it as needed. */ 919 entry_main = archive_entry_clone(entry); 920 if (entry_main == NULL) 921 return (NULL); 922 /* Replace the Windows path-separator '\' with '/'. */ 923 ret = fix_pathseparator(entry_main); 924 if (ret < ARCHIVE_WARN) { 925 archive_entry_free(entry_main); 926 return (NULL); 927 } 928 return (entry_main); 929 } 930 931 932 /* 933 * The following function was modified from PostgreSQL sources and is 934 * subject to the copyright below. 935 */ 936 /*------------------------------------------------------------------------- 937 * 938 * win32error.c 939 * Map win32 error codes to errno values 940 * 941 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group 942 * 943 * IDENTIFICATION 944 * $PostgreSQL: pgsql/src/port/win32error.c,v 1.4 2008/01/01 19:46:00 momjian Exp $ 945 * 946 *------------------------------------------------------------------------- 947 */ 948 /* 949 PostgreSQL Database Management System 950 (formerly known as Postgres, then as Postgres95) 951 952 Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group 953 954 Portions Copyright (c) 1994, The Regents of the University of California 955 956 Permission to use, copy, modify, and distribute this software and its 957 documentation for any purpose, without fee, and without a written agreement 958 is hereby granted, provided that the above copyright notice and this 959 paragraph and the following two paragraphs appear in all copies. 960 961 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR 962 DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING 963 LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS 964 DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE 965 POSSIBILITY OF SUCH DAMAGE. 966 967 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 968 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 969 AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 970 ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO 971 PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 972 */ 973 974 static const struct { 975 DWORD winerr; 976 int doserr; 977 } doserrors[] = 978 { 979 { ERROR_INVALID_FUNCTION, EINVAL }, 980 { ERROR_FILE_NOT_FOUND, ENOENT }, 981 { ERROR_PATH_NOT_FOUND, ENOENT }, 982 { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, 983 { ERROR_ACCESS_DENIED, EACCES }, 984 { ERROR_INVALID_HANDLE, EBADF }, 985 { ERROR_ARENA_TRASHED, ENOMEM }, 986 { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, 987 { ERROR_INVALID_BLOCK, ENOMEM }, 988 { ERROR_BAD_ENVIRONMENT, E2BIG }, 989 { ERROR_BAD_FORMAT, ENOEXEC }, 990 { ERROR_INVALID_ACCESS, EINVAL }, 991 { ERROR_INVALID_DATA, EINVAL }, 992 { ERROR_INVALID_DRIVE, ENOENT }, 993 { ERROR_CURRENT_DIRECTORY, EACCES }, 994 { ERROR_NOT_SAME_DEVICE, EXDEV }, 995 { ERROR_NO_MORE_FILES, ENOENT }, 996 { ERROR_LOCK_VIOLATION, EACCES }, 997 { ERROR_SHARING_VIOLATION, EACCES }, 998 { ERROR_BAD_NETPATH, ENOENT }, 999 { ERROR_NETWORK_ACCESS_DENIED, EACCES }, 1000 { ERROR_BAD_NET_NAME, ENOENT }, 1001 { ERROR_FILE_EXISTS, EEXIST }, 1002 { ERROR_CANNOT_MAKE, EACCES }, 1003 { ERROR_FAIL_I24, EACCES }, 1004 { ERROR_INVALID_PARAMETER, EINVAL }, 1005 { ERROR_NO_PROC_SLOTS, EAGAIN }, 1006 { ERROR_DRIVE_LOCKED, EACCES }, 1007 { ERROR_BROKEN_PIPE, EPIPE }, 1008 { ERROR_DISK_FULL, ENOSPC }, 1009 { ERROR_INVALID_TARGET_HANDLE, EBADF }, 1010 { ERROR_INVALID_HANDLE, EINVAL }, 1011 { ERROR_WAIT_NO_CHILDREN, ECHILD }, 1012 { ERROR_CHILD_NOT_COMPLETE, ECHILD }, 1013 { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, 1014 { ERROR_NEGATIVE_SEEK, EINVAL }, 1015 { ERROR_SEEK_ON_DEVICE, EACCES }, 1016 { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, 1017 { ERROR_NOT_LOCKED, EACCES }, 1018 { ERROR_BAD_PATHNAME, ENOENT }, 1019 { ERROR_MAX_THRDS_REACHED, EAGAIN }, 1020 { ERROR_LOCK_FAILED, EACCES }, 1021 { ERROR_ALREADY_EXISTS, EEXIST }, 1022 { ERROR_FILENAME_EXCED_RANGE, ENOENT }, 1023 { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, 1024 { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } 1025 }; 1026 1027 void 1028 __la_dosmaperr(unsigned long e) 1029 { 1030 int i; 1031 1032 if (e == 0) 1033 { 1034 errno = 0; 1035 return; 1036 } 1037 1038 for (i = 0; i < (int)(sizeof(doserrors)/sizeof(doserrors[0])); i++) 1039 { 1040 if (doserrors[i].winerr == e) 1041 { 1042 errno = doserrors[i].doserr; 1043 return; 1044 } 1045 } 1046 1047 /* fprintf(stderr, "unrecognized win32 error code: %lu", e); */ 1048 errno = EINVAL; 1049 return; 1050 } 1051 1052 #endif /* _WIN32 && !__CYGWIN__ */ 1053