1 /* 2 * Copyright (c) 2003-2009 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "test.h" 27 #include "test_utils.h" 28 #ifdef HAVE_SYS_IOCTL_H 29 #include <sys/ioctl.h> 30 #endif 31 #ifdef HAVE_SYS_TIME_H 32 #include <sys/time.h> 33 #endif 34 #include <errno.h> 35 #ifdef HAVE_ICONV_H 36 #include <iconv.h> 37 #endif 38 /* 39 * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. 40 * As the include guards don't agree, the order of include is important. 41 */ 42 #ifdef HAVE_LINUX_EXT2_FS_H 43 #include <linux/ext2_fs.h> /* for Linux file flags */ 44 #endif 45 #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) 46 #include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ 47 #endif 48 #ifdef HAVE_LINUX_FS_H 49 #include <linux/fs.h> 50 #endif 51 #include <limits.h> 52 #include <locale.h> 53 #ifdef HAVE_SIGNAL_H 54 #include <signal.h> 55 #endif 56 #include <stdarg.h> 57 #include <time.h> 58 59 #ifdef HAVE_SIGNAL_H 60 #endif 61 #ifdef HAVE_ACL_LIBACL_H 62 #include <acl/libacl.h> 63 #endif 64 #ifdef HAVE_SYS_TYPES_H 65 #include <sys/types.h> 66 #endif 67 #ifdef HAVE_SYS_ACL_H 68 #include <sys/acl.h> 69 #endif 70 #ifdef HAVE_SYS_EA_H 71 #include <sys/ea.h> 72 #endif 73 #ifdef HAVE_SYS_EXTATTR_H 74 #include <sys/extattr.h> 75 #endif 76 #if HAVE_SYS_XATTR_H 77 #include <sys/xattr.h> 78 #elif HAVE_ATTR_XATTR_H 79 #include <attr/xattr.h> 80 #endif 81 #ifdef HAVE_SYS_RICHACL_H 82 #include <sys/richacl.h> 83 #endif 84 #if HAVE_MEMBERSHIP_H 85 #include <membership.h> 86 #endif 87 #if !defined(_WIN32) || defined(__CYGWIN__) 88 # if HAVE_POSIX_SPAWN 89 # if HAVE_SYS_WAIT_H 90 # include <sys/wait.h> 91 # endif 92 # if HAVE_SPAWN_H 93 # include <spawn.h> 94 # endif 95 extern char **environ; 96 # define USE_POSIX_SPAWN 1 97 # endif 98 #endif 99 100 #ifndef nitems 101 #define nitems(arr) (sizeof(arr) / sizeof((arr)[0])) 102 #endif 103 104 /* 105 * 106 * Windows support routines 107 * 108 * Note: Configuration is a tricky issue. Using HAVE_* feature macros 109 * in the test harness is dangerous because they cover up 110 * configuration errors. The classic example of this is omitting a 111 * configure check. If libarchive and libarchive_test both look for 112 * the same feature macro, such errors are hard to detect. Platform 113 * macros (e.g., _WIN32 or __GNUC__) are a little better, but can 114 * easily lead to very messy code. It's best to limit yourself 115 * to only the most generic programming techniques in the test harness 116 * and thus avoid conditionals altogether. Where that's not possible, 117 * try to minimize conditionals by grouping platform-specific tests in 118 * one place (e.g., test_acl_freebsd) or by adding new assert() 119 * functions (e.g., assertMakeHardlink()) to cover up platform 120 * differences. Platform-specific coding in libarchive_test is often 121 * a symptom that some capability is missing from libarchive itself. 122 */ 123 #if defined(_WIN32) && !defined(__CYGWIN__) 124 #include <io.h> 125 #include <direct.h> 126 #include <windows.h> 127 #ifndef F_OK 128 #define F_OK (0) 129 #endif 130 #ifndef S_ISDIR 131 #define S_ISDIR(m) ((m) & _S_IFDIR) 132 #endif 133 #ifndef S_ISREG 134 #define S_ISREG(m) ((m) & _S_IFREG) 135 #endif 136 #if !defined(__BORLANDC__) 137 #define access _access 138 #undef chdir 139 #define chdir _chdir 140 #undef chmod 141 #define chmod _chmod 142 #endif 143 #ifndef fileno 144 #define fileno _fileno 145 #endif 146 /*#define fstat _fstat64*/ 147 #if !defined(__BORLANDC__) 148 #define getcwd _getcwd 149 #endif 150 #define lstat stat 151 /*#define lstat _stat64*/ 152 /*#define stat _stat64*/ 153 #define rmdir _rmdir 154 #if !defined(__BORLANDC__) 155 #define strdup _strdup 156 #define umask _umask 157 #endif 158 #define int64_t __int64 159 #endif 160 161 #if defined(HAVE__CrtSetReportMode) 162 # include <crtdbg.h> 163 #endif 164 165 mode_t umasked(mode_t expected_mode) 166 { 167 mode_t mode = umask(0); 168 umask(mode); 169 return expected_mode & ~mode; 170 } 171 172 /* Path to working directory for current test */ 173 const char *testworkdir; 174 #ifdef PROGRAM 175 /* Pathname of exe to be tested. */ 176 const char *testprogfile; 177 /* Name of exe to use in printf-formatted command strings. */ 178 /* On Windows, this includes leading/trailing quotes. */ 179 const char *testprog; 180 #endif 181 182 #if defined(_WIN32) && !defined(__CYGWIN__) 183 static void *GetFunctionKernel32(const char *); 184 static int my_CreateSymbolicLinkA(const char *, const char *, int); 185 static int my_CreateHardLinkA(const char *, const char *); 186 static int my_GetFileInformationByName(const char *, 187 BY_HANDLE_FILE_INFORMATION *); 188 189 typedef struct _REPARSE_DATA_BUFFER { 190 ULONG ReparseTag; 191 USHORT ReparseDataLength; 192 USHORT Reserved; 193 union { 194 struct { 195 USHORT SubstituteNameOffset; 196 USHORT SubstituteNameLength; 197 USHORT PrintNameOffset; 198 USHORT PrintNameLength; 199 ULONG Flags; 200 WCHAR PathBuffer[1]; 201 } SymbolicLinkReparseBuffer; 202 struct { 203 USHORT SubstituteNameOffset; 204 USHORT SubstituteNameLength; 205 USHORT PrintNameOffset; 206 USHORT PrintNameLength; 207 WCHAR PathBuffer[1]; 208 } MountPointReparseBuffer; 209 struct { 210 UCHAR DataBuffer[1]; 211 } GenericReparseBuffer; 212 } DUMMYUNIONNAME; 213 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; 214 215 static void * 216 GetFunctionKernel32(const char *name) 217 { 218 static HINSTANCE lib; 219 static int set; 220 if (!set) { 221 set = 1; 222 lib = LoadLibrary("kernel32.dll"); 223 } 224 if (lib == NULL) { 225 fprintf(stderr, "Can't load kernel32.dll?!\n"); 226 exit(1); 227 } 228 return (void *)GetProcAddress(lib, name); 229 } 230 231 static int 232 my_CreateSymbolicLinkA(const char *linkname, const char *target, 233 int targetIsDir) 234 { 235 static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD); 236 DWORD attrs; 237 static int set; 238 int ret, tmpflags; 239 size_t llen, tlen; 240 int flags = 0; 241 char *src, *tgt, *p; 242 if (!set) { 243 set = 1; 244 f = GetFunctionKernel32("CreateSymbolicLinkA"); 245 } 246 if (f == NULL) 247 return (0); 248 249 tlen = strlen(target); 250 llen = strlen(linkname); 251 252 if (tlen == 0 || llen == 0) 253 return (0); 254 255 tgt = malloc(tlen + 1); 256 if (tgt == NULL) 257 return (0); 258 src = malloc(llen + 1); 259 if (src == NULL) { 260 free(tgt); 261 return (0); 262 } 263 264 /* 265 * Translate slashes to backslashes 266 */ 267 p = src; 268 while(*linkname != '\0') { 269 if (*linkname == '/') 270 *p = '\\'; 271 else 272 *p = *linkname; 273 linkname++; 274 p++; 275 } 276 *p = '\0'; 277 278 p = tgt; 279 while(*target != '\0') { 280 if (*target == '/') 281 *p = '\\'; 282 else 283 *p = *target; 284 target++; 285 p++; 286 } 287 *p = '\0'; 288 289 /* 290 * Each test has to specify if a file or a directory symlink 291 * should be created. 292 */ 293 if (targetIsDir) { 294 #if defined(SYMBOLIC_LINK_FLAG_DIRECTORY) 295 flags |= SYMBOLIC_LINK_FLAG_DIRECTORY; 296 #else 297 flags |= 0x1; 298 #endif 299 } 300 301 #if defined(SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) 302 tmpflags = flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; 303 #else 304 tmpflags = flags | 0x2; 305 #endif 306 /* 307 * Windows won't overwrite existing links 308 */ 309 attrs = GetFileAttributesA(linkname); 310 if (attrs != INVALID_FILE_ATTRIBUTES) { 311 if (attrs & FILE_ATTRIBUTE_DIRECTORY) 312 RemoveDirectoryA(linkname); 313 else 314 DeleteFileA(linkname); 315 } 316 317 ret = (*f)(src, tgt, tmpflags); 318 /* 319 * Prior to Windows 10 the SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 320 * is not understood 321 */ 322 if (!ret) 323 ret = (*f)(src, tgt, flags); 324 325 free(src); 326 free(tgt); 327 return (ret); 328 } 329 330 static int 331 my_CreateHardLinkA(const char *linkname, const char *target) 332 { 333 static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES); 334 static int set; 335 if (!set) { 336 set = 1; 337 f = GetFunctionKernel32("CreateHardLinkA"); 338 } 339 return f == NULL ? 0 : (*f)(linkname, target, NULL); 340 } 341 342 static int 343 my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi) 344 { 345 HANDLE h; 346 int r; 347 348 memset(bhfi, 0, sizeof(*bhfi)); 349 h = CreateFileA(path, FILE_READ_ATTRIBUTES, 0, NULL, 350 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 351 if (h == INVALID_HANDLE_VALUE) 352 return (0); 353 r = GetFileInformationByHandle(h, bhfi); 354 CloseHandle(h); 355 return (r); 356 } 357 #endif 358 359 #if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__) 360 static void 361 invalid_parameter_handler(const wchar_t * expression, 362 const wchar_t * function, const wchar_t * file, 363 unsigned int line, uintptr_t pReserved) 364 { 365 /* nop */ 366 // Silence unused-parameter compiler warnings. 367 (void)expression; 368 (void)function; 369 (void)file; 370 (void)line; 371 (void)pReserved; 372 } 373 #endif 374 375 /* 376 * 377 * OPTIONS FLAGS 378 * 379 */ 380 381 /* Enable core dump on failure. */ 382 static int dump_on_failure = 0; 383 /* Default is to remove temp dirs and log data for successful tests. */ 384 static int keep_temp_files = 0; 385 /* Default is to only return a failure code (1) if there were test failures. If enabled, exit with code 2 if there were no failures, but some tests were skipped. */ 386 static int fail_if_tests_skipped = 0; 387 /* Default is to run the specified tests once and report errors. */ 388 static int until_failure = 0; 389 /* Default is to just report pass/fail for each test. */ 390 static int verbosity = 0; 391 #define VERBOSITY_SUMMARY_ONLY -1 /* -q */ 392 #define VERBOSITY_PASSFAIL 0 /* Default */ 393 #define VERBOSITY_LIGHT_REPORT 1 /* -v */ 394 #define VERBOSITY_FULL 2 /* -vv */ 395 /* A few places generate even more output for verbosity > VERBOSITY_FULL, 396 * mostly for debugging the test harness itself. */ 397 /* Cumulative count of assertion failures. */ 398 static int failures = 0; 399 /* Cumulative count of reported skips. */ 400 static int skips = 0; 401 /* Cumulative count of assertions checked. */ 402 static int assertions = 0; 403 404 /* Directory where uuencoded reference files can be found. */ 405 static const char *refdir; 406 407 /* 408 * Report log information selectively to console and/or disk log. 409 */ 410 static int log_console = 0; 411 static FILE *logfile; 412 static void __LA_PRINTFLIKE(1, 0) 413 vlogprintf(const char *fmt, va_list ap) 414 { 415 #ifdef va_copy 416 va_list lfap; 417 va_copy(lfap, ap); 418 #endif 419 if (log_console) 420 vfprintf(stdout, fmt, ap); 421 if (logfile != NULL) 422 #ifdef va_copy 423 vfprintf(logfile, fmt, lfap); 424 va_end(lfap); 425 #else 426 vfprintf(logfile, fmt, ap); 427 #endif 428 } 429 430 static void __LA_PRINTFLIKE(1, 2) 431 logprintf(const char *fmt, ...) 432 { 433 va_list ap; 434 va_start(ap, fmt); 435 vlogprintf(fmt, ap); 436 va_end(ap); 437 } 438 439 /* Set up a message to display only if next assertion fails. */ 440 static char msgbuff[4096]; 441 static const char *msg, *nextmsg; 442 void 443 failure(const char *fmt, ...) 444 { 445 va_list ap; 446 if (fmt == NULL) { 447 nextmsg = NULL; 448 } else { 449 va_start(ap, fmt); 450 vsnprintf(msgbuff, sizeof(msgbuff), fmt, ap); 451 va_end(ap); 452 nextmsg = msgbuff; 453 } 454 } 455 456 /* 457 * Copy arguments into file-local variables. 458 * This was added to permit vararg assert() functions without needing 459 * variadic wrapper macros. Turns out that the vararg capability is almost 460 * never used, so almost all of the vararg assertions can be simplified 461 * by removing the vararg capability and reworking the wrapper macro to 462 * pass __FILE__, __LINE__ directly into the function instead of using 463 * this hook. I suspect this machinery is used so rarely that we 464 * would be better off just removing it entirely. That would simplify 465 * the code here noticeably. 466 */ 467 static const char *skipping_filename; 468 static int skipping_line; 469 void skipping_setup(const char *filename, int line) 470 { 471 skipping_filename = filename; 472 skipping_line = line; 473 } 474 475 /* Called at the beginning of each assert() function. */ 476 static void 477 assertion_count(const char *file, int line) 478 { 479 (void)file; /* UNUSED */ 480 (void)line; /* UNUSED */ 481 ++assertions; 482 /* Proper handling of "failure()" message. */ 483 msg = nextmsg; 484 nextmsg = NULL; 485 /* Uncomment to print file:line after every assertion. 486 * Verbose, but occasionally useful in tracking down crashes. */ 487 /* printf("Checked %s:%d\n", file, line); */ 488 } 489 490 /* 491 * For each test source file, we remember how many times each 492 * assertion was reported. Cleared before each new test, 493 * used by test_summarize(). 494 */ 495 static struct line { 496 int count; 497 int skip; 498 } failed_lines[10000]; 499 static const char *failed_filename; 500 501 /* Count this failure, setup up log destination and handle initial report. */ 502 static void __LA_PRINTFLIKE(3, 4) 503 failure_start(const char *filename, int line, const char *fmt, ...) 504 { 505 va_list ap; 506 507 /* Record another failure for this line. */ 508 ++failures; 509 failed_filename = filename; 510 failed_lines[line].count++; 511 512 /* Determine whether to log header to console. */ 513 switch (verbosity) { 514 case VERBOSITY_LIGHT_REPORT: 515 log_console = (failed_lines[line].count < 2); 516 break; 517 default: 518 log_console = (verbosity >= VERBOSITY_FULL); 519 } 520 521 /* Log file:line header for this failure */ 522 va_start(ap, fmt); 523 #if _MSC_VER 524 logprintf("%s(%d): ", filename, line); 525 #else 526 logprintf("%s:%d: ", filename, line); 527 #endif 528 vlogprintf(fmt, ap); 529 va_end(ap); 530 logprintf("\n"); 531 532 if (msg != NULL && msg[0] != '\0') { 533 logprintf(" Description: %s\n", msg); 534 msg = NULL; 535 } 536 537 /* Determine whether to log details to console. */ 538 if (verbosity == VERBOSITY_LIGHT_REPORT) 539 log_console = 0; 540 } 541 542 /* Complete reporting of failed tests. */ 543 /* 544 * The 'extra' hook here is used by libarchive to include libarchive 545 * error messages with assertion failures. It could also be used 546 * to add strerror() output, for example. Just define the EXTRA_DUMP() 547 * macro appropriately. 548 */ 549 static void 550 failure_finish(void *extra) 551 { 552 (void)extra; /* UNUSED (maybe) */ 553 #ifdef EXTRA_DUMP 554 if (extra != NULL) { 555 logprintf(" errno: %d\n", EXTRA_ERRNO(extra)); 556 logprintf(" detail: %s\n", EXTRA_DUMP(extra)); 557 } 558 #endif 559 560 if (dump_on_failure) { 561 fprintf(stderr, 562 " *** forcing core dump so failure can be debugged ***\n"); 563 abort(); 564 } 565 } 566 567 /* Inform user that we're skipping some checks. */ 568 void 569 test_skipping(const char *fmt, ...) 570 { 571 char buff[1024]; 572 va_list ap; 573 574 va_start(ap, fmt); 575 vsnprintf(buff, sizeof(buff), fmt, ap); 576 va_end(ap); 577 /* Use failure() message if set. */ 578 msg = nextmsg; 579 nextmsg = NULL; 580 /* failure_start() isn't quite right, but is awfully convenient. */ 581 failure_start(skipping_filename, skipping_line, "SKIPPING: %s", buff); 582 --failures; /* Undo failures++ in failure_start() */ 583 /* Don't failure_finish() here. */ 584 /* Mark as skip, so doesn't count as failed test. */ 585 failed_lines[skipping_line].skip = 1; 586 ++skips; 587 } 588 589 /* 590 * 591 * ASSERTIONS 592 * 593 */ 594 595 /* Generic assert() just displays the failed condition. */ 596 int 597 assertion_assert(const char *file, int line, int value, 598 const char *condition, void *extra) 599 { 600 assertion_count(file, line); 601 if (!value) { 602 failure_start(file, line, "Assertion failed: %s", condition); 603 failure_finish(extra); 604 } 605 return (value); 606 } 607 608 /* chdir() and report any errors */ 609 int 610 assertion_chdir(const char *file, int line, const char *pathname) 611 { 612 assertion_count(file, line); 613 if (chdir(pathname) == 0) 614 return (1); 615 failure_start(file, line, "chdir(\"%s\")", pathname); 616 failure_finish(NULL); 617 return (0); 618 619 } 620 621 /* change file/directory permissions and errors if it fails */ 622 int 623 assertion_chmod(const char *file, int line, const char *pathname, int mode) 624 { 625 assertion_count(file, line); 626 if (chmod(pathname, (mode_t)mode) == 0) 627 return (1); 628 failure_start(file, line, "chmod(\"%s\", %4.o)", pathname, 629 (unsigned int)mode); 630 failure_finish(NULL); 631 return (0); 632 633 } 634 635 /* Verify two integers are equal. */ 636 int 637 assertion_equal_int(const char *file, int line, 638 long long v1, const char *e1, long long v2, const char *e2, void *extra) 639 { 640 assertion_count(file, line); 641 if (v1 == v2) 642 return (1); 643 failure_start(file, line, "%s != %s", e1, e2); 644 logprintf(" %s=%lld (0x%llx, 0%llo)\n", e1, v1, 645 (unsigned long long)v1, (unsigned long long)v1); 646 logprintf(" %s=%lld (0x%llx, 0%llo)\n", e2, v2, 647 (unsigned long long)v2, (unsigned long long)v2); 648 failure_finish(extra); 649 return (0); 650 } 651 652 /* Verify two pointers are equal. */ 653 int 654 assertion_equal_address(const char *file, int line, 655 const void *v1, const char *e1, const void *v2, const char *e2, void *extra) 656 { 657 assertion_count(file, line); 658 if (v1 == v2) 659 return (1); 660 failure_start(file, line, "%s != %s", e1, e2); 661 logprintf(" %s=0x%llx\n", e1, (unsigned long long)(uintptr_t)v1); 662 logprintf(" %s=0x%llx\n", e2, (unsigned long long)(uintptr_t)v2); 663 failure_finish(extra); 664 return (0); 665 } 666 667 /* 668 * Utility to convert a single UTF-8 sequence. 669 */ 670 static int 671 _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) 672 { 673 static const char utf8_count[256] = { 674 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */ 675 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */ 676 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */ 677 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */ 678 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */ 679 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */ 680 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */ 681 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */ 682 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */ 683 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */ 684 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */ 685 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */ 686 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */ 687 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */ 688 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */ 689 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ 690 }; 691 int ch; 692 int cnt; 693 uint32_t wc; 694 695 *pwc = 0; 696 697 /* Sanity check. */ 698 if (n == 0) 699 return (0); 700 /* 701 * Decode 1-4 bytes depending on the value of the first byte. 702 */ 703 ch = (unsigned char)*s; 704 if (ch == 0) 705 return (0); /* Standard: return 0 for end-of-string. */ 706 cnt = utf8_count[ch]; 707 708 /* Invalid sequence or there are not plenty bytes. */ 709 if (n < (size_t)cnt) 710 return (-1); 711 712 /* Make a Unicode code point from a single UTF-8 sequence. */ 713 switch (cnt) { 714 case 1: /* 1 byte sequence. */ 715 *pwc = ch & 0x7f; 716 return (cnt); 717 case 2: /* 2 bytes sequence. */ 718 if ((s[1] & 0xc0) != 0x80) return (-1); 719 *pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f); 720 return (cnt); 721 case 3: /* 3 bytes sequence. */ 722 if ((s[1] & 0xc0) != 0x80) return (-1); 723 if ((s[2] & 0xc0) != 0x80) return (-1); 724 wc = ((ch & 0x0f) << 12) 725 | ((s[1] & 0x3f) << 6) 726 | (s[2] & 0x3f); 727 if (wc < 0x800) 728 return (-1);/* Overlong sequence. */ 729 break; 730 case 4: /* 4 bytes sequence. */ 731 if (n < 4) 732 return (-1); 733 if ((s[1] & 0xc0) != 0x80) return (-1); 734 if ((s[2] & 0xc0) != 0x80) return (-1); 735 if ((s[3] & 0xc0) != 0x80) return (-1); 736 wc = ((ch & 0x07) << 18) 737 | ((s[1] & 0x3f) << 12) 738 | ((s[2] & 0x3f) << 6) 739 | (s[3] & 0x3f); 740 if (wc < 0x10000) 741 return (-1);/* Overlong sequence. */ 742 break; 743 default: 744 return (-1); 745 } 746 747 /* The code point larger than 0x10FFFF is not legal 748 * Unicode values. */ 749 if (wc > 0x10FFFF) 750 return (-1); 751 /* Correctly gets a Unicode, returns used bytes. */ 752 *pwc = wc; 753 return (cnt); 754 } 755 756 static void strdump(const char *e, const char *p, int ewidth, int utf8) 757 { 758 const char *q = p; 759 760 logprintf(" %*s = ", ewidth, e); 761 if (p == NULL) { 762 logprintf("NULL\n"); 763 return; 764 } 765 logprintf("\""); 766 while (*p != '\0') { 767 unsigned int c = 0xff & *p++; 768 switch (c) { 769 case '\a': logprintf("\\a"); break; 770 case '\b': logprintf("\\b"); break; 771 case '\n': logprintf("\\n"); break; 772 case '\r': logprintf("\\r"); break; 773 default: 774 if (c >= 32 && c < 127) 775 logprintf("%c", (int)c); 776 else 777 logprintf("\\x%02X", c); 778 } 779 } 780 logprintf("\""); 781 logprintf(" (length %d)", q == NULL ? -1 : (int)strlen(q)); 782 783 /* 784 * If the current string is UTF-8, dump its code points. 785 */ 786 if (utf8) { 787 size_t len; 788 uint32_t uc; 789 int n; 790 int cnt = 0; 791 792 p = q; 793 len = strlen(p); 794 logprintf(" ["); 795 while ((n = _utf8_to_unicode(&uc, p, len)) > 0) { 796 if (p != q) 797 logprintf(" "); 798 logprintf("%04X", uc); 799 p += n; 800 len -= n; 801 cnt++; 802 } 803 logprintf("]"); 804 logprintf(" (count %d", cnt); 805 if (n < 0) { 806 logprintf(",unknown %zu bytes", len); 807 } 808 logprintf(")"); 809 810 } 811 logprintf("\n"); 812 } 813 814 /* Verify two strings are equal, dump them if not. */ 815 int 816 assertion_equal_string(const char *file, int line, 817 const char *v1, const char *e1, 818 const char *v2, const char *e2, 819 void *extra, int utf8) 820 { 821 int l1, l2; 822 823 assertion_count(file, line); 824 if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 0)) 825 return (1); 826 failure_start(file, line, "%s != %s", e1, e2); 827 l1 = (int)strlen(e1); 828 l2 = (int)strlen(e2); 829 if (l1 < l2) 830 l1 = l2; 831 strdump(e1, v1, l1, utf8); 832 strdump(e2, v2, l1, utf8); 833 failure_finish(extra); 834 return (0); 835 } 836 837 static void 838 wcsdump(const char *e, const wchar_t *w) 839 { 840 logprintf(" %s = ", e); 841 if (w == NULL) { 842 logprintf("(null)"); 843 return; 844 } 845 logprintf("\""); 846 while (*w != L'\0') { 847 unsigned int c = *w++; 848 if (c >= 32 && c < 127) 849 logprintf("%c", (int)c); 850 else if (c < 256) 851 logprintf("\\x%02X", c); 852 else if (c < 0x10000) 853 logprintf("\\u%04X", c); 854 else 855 logprintf("\\U%08X", c); 856 } 857 logprintf("\"\n"); 858 } 859 860 #ifndef HAVE_WCSCMP 861 static int 862 wcscmp(const wchar_t *s1, const wchar_t *s2) 863 { 864 865 while (*s1 == *s2++) { 866 if (*s1++ == L'\0') 867 return 0; 868 } 869 if (*s1 > *--s2) 870 return 1; 871 else 872 return -1; 873 } 874 #endif 875 876 /* Verify that two wide strings are equal, dump them if not. */ 877 int 878 assertion_equal_wstring(const char *file, int line, 879 const wchar_t *v1, const char *e1, 880 const wchar_t *v2, const char *e2, 881 void *extra) 882 { 883 assertion_count(file, line); 884 if (v1 == v2) 885 return (1); 886 if (v1 != NULL && v2 != NULL && wcscmp(v1, v2) == 0) 887 return (1); 888 failure_start(file, line, "%s != %s", e1, e2); 889 wcsdump(e1, v1); 890 wcsdump(e2, v2); 891 failure_finish(extra); 892 return (0); 893 } 894 895 /* 896 * Pretty standard hexdump routine. As a bonus, if ref != NULL, then 897 * any bytes in p that differ from ref will be highlighted with '_' 898 * before and after the hex value. 899 */ 900 static void 901 hexdump(const char *p, const char *ref, size_t l, size_t offset) 902 { 903 size_t i, j; 904 char sep; 905 906 if (p == NULL) { 907 logprintf("(null)\n"); 908 return; 909 } 910 for(i=0; i < l; i+=16) { 911 logprintf("%04x", (unsigned)(i + offset)); 912 sep = ' '; 913 for (j = 0; j < 16 && i + j < l; j++) { 914 if (ref != NULL && p[i + j] != ref[i + j]) 915 sep = '_'; 916 logprintf("%c%02x", sep, 0xff & (unsigned int)p[i+j]); 917 if (ref != NULL && p[i + j] == ref[i + j]) 918 sep = ' '; 919 } 920 for (; j < 16; j++) { 921 logprintf("%c ", sep); 922 sep = ' '; 923 } 924 logprintf("%c", sep); 925 for (j=0; j < 16 && i + j < l; j++) { 926 int c = p[i + j]; 927 if (c >= ' ' && c <= 126) 928 logprintf("%c", c); 929 else 930 logprintf("."); 931 } 932 logprintf("\n"); 933 } 934 } 935 936 /* Verify that two blocks of memory are the same, display the first 937 * block of differences if they're not. */ 938 int 939 assertion_equal_mem(const char *file, int line, 940 const void *_v1, const char *e1, 941 const void *_v2, const char *e2, 942 size_t l, const char *ld, void *extra) 943 { 944 const char *v1 = (const char *)_v1; 945 const char *v2 = (const char *)_v2; 946 size_t offset; 947 948 assertion_count(file, line); 949 if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0)) 950 return (1); 951 if (v1 == NULL || v2 == NULL) 952 return (0); 953 954 failure_start(file, line, "%s != %s", e1, e2); 955 logprintf(" size %s = %d\n", ld, (int)l); 956 /* Dump 48 bytes (3 lines) so that the first difference is 957 * in the second line. */ 958 offset = 0; 959 while (l > 64 && memcmp(v1, v2, 32) == 0) { 960 /* Two lines agree, so step forward one line. */ 961 v1 += 16; 962 v2 += 16; 963 l -= 16; 964 offset += 16; 965 } 966 logprintf(" Dump of %s\n", e1); 967 hexdump(v1, v2, l < 128 ? l : 128, offset); 968 logprintf(" Dump of %s\n", e2); 969 hexdump(v2, v1, l < 128 ? l : 128, offset); 970 logprintf("\n"); 971 failure_finish(extra); 972 return (0); 973 } 974 975 /* Verify that a block of memory is filled with the specified byte. */ 976 int 977 assertion_memory_filled_with(const char *file, int line, 978 const void *_v1, const char *vd, 979 size_t l, const char *ld, 980 char b, const char *bd, void *extra) 981 { 982 const char *v1 = (const char *)_v1; 983 size_t c = 0; 984 size_t i; 985 (void)ld; /* UNUSED */ 986 987 assertion_count(file, line); 988 989 for (i = 0; i < l; ++i) { 990 if (v1[i] == b) { 991 ++c; 992 } 993 } 994 if (c == l) 995 return (1); 996 997 failure_start(file, line, "%s (size %d) not filled with %s", vd, (int)l, bd); 998 logprintf(" Only %d bytes were correct\n", (int)c); 999 failure_finish(extra); 1000 return (0); 1001 } 1002 1003 /* Verify that the named file exists and is empty. */ 1004 int 1005 assertion_empty_file(const char *filename, int line, const char *f1) 1006 { 1007 char buff[1024]; 1008 struct stat st; 1009 ssize_t s; 1010 FILE *f; 1011 1012 assertion_count(filename, line); 1013 1014 if (stat(f1, &st) != 0) { 1015 failure_start(filename, line, "Stat failed: %s", f1); 1016 failure_finish(NULL); 1017 return (0); 1018 } 1019 if (st.st_size == 0) 1020 return (1); 1021 1022 failure_start(filename, line, "File should be empty: %s", f1); 1023 logprintf(" File size: %d\n", (int)st.st_size); 1024 logprintf(" Contents:\n"); 1025 f = fopen(f1, "rb"); 1026 if (f == NULL) { 1027 logprintf(" Unable to open %s\n", f1); 1028 } else { 1029 s = ((off_t)sizeof(buff) < st.st_size) ? 1030 (ssize_t)sizeof(buff) : (ssize_t)st.st_size; 1031 s = fread(buff, 1, s, f); 1032 hexdump(buff, NULL, s, 0); 1033 fclose(f); 1034 } 1035 failure_finish(NULL); 1036 return (0); 1037 } 1038 1039 /* Verify that the named file exists and is not empty. */ 1040 int 1041 assertion_non_empty_file(const char *filename, int line, const char *f1) 1042 { 1043 struct stat st; 1044 1045 assertion_count(filename, line); 1046 1047 if (stat(f1, &st) != 0) { 1048 failure_start(filename, line, "Stat failed: %s", f1); 1049 failure_finish(NULL); 1050 return (0); 1051 } 1052 if (st.st_size == 0) { 1053 failure_start(filename, line, "File empty: %s", f1); 1054 failure_finish(NULL); 1055 return (0); 1056 } 1057 return (1); 1058 } 1059 1060 /* Verify that two files have the same contents. */ 1061 /* TODO: hexdump the first bytes that actually differ. */ 1062 int 1063 assertion_equal_file(const char *filename, int line, const char *fn1, const char *fn2) 1064 { 1065 char buff1[1024]; 1066 char buff2[1024]; 1067 FILE *f1, *f2; 1068 int n1, n2; 1069 1070 assertion_count(filename, line); 1071 1072 f1 = fopen(fn1, "rb"); 1073 f2 = fopen(fn2, "rb"); 1074 if (f1 == NULL || f2 == NULL) { 1075 if (f1) fclose(f1); 1076 if (f2) fclose(f2); 1077 return (0); 1078 } 1079 for (;;) { 1080 n1 = (int)fread(buff1, 1, sizeof(buff1), f1); 1081 n2 = (int)fread(buff2, 1, sizeof(buff2), f2); 1082 if (n1 != n2) 1083 break; 1084 if (n1 == 0 && n2 == 0) { 1085 fclose(f1); 1086 fclose(f2); 1087 return (1); 1088 } 1089 if (memcmp(buff1, buff2, n1) != 0) 1090 break; 1091 } 1092 fclose(f1); 1093 fclose(f2); 1094 failure_start(filename, line, "Files not identical"); 1095 logprintf(" file1=\"%s\"\n", fn1); 1096 logprintf(" file2=\"%s\"\n", fn2); 1097 failure_finish(NULL); 1098 return (0); 1099 } 1100 1101 /* Verify that the named file does exist. */ 1102 int 1103 assertion_file_exists(const char *filename, int line, const char *f) 1104 { 1105 assertion_count(filename, line); 1106 1107 #if defined(_WIN32) && !defined(__CYGWIN__) 1108 if (!_access(f, 0)) 1109 return (1); 1110 #else 1111 if (!access(f, F_OK)) 1112 return (1); 1113 #endif 1114 failure_start(filename, line, "File should exist: %s", f); 1115 failure_finish(NULL); 1116 return (0); 1117 } 1118 1119 /* Verify that the named file doesn't exist. */ 1120 int 1121 assertion_file_not_exists(const char *filename, int line, const char *f) 1122 { 1123 assertion_count(filename, line); 1124 1125 #if defined(_WIN32) && !defined(__CYGWIN__) 1126 if (_access(f, 0)) 1127 return (1); 1128 #else 1129 if (access(f, F_OK)) 1130 return (1); 1131 #endif 1132 failure_start(filename, line, "File should not exist: %s", f); 1133 failure_finish(NULL); 1134 return (0); 1135 } 1136 1137 /* Compare the contents of a file to a block of memory. */ 1138 int 1139 assertion_file_contents(const char *filename, int line, const void *buff, int s, const char *fn) 1140 { 1141 char *contents; 1142 FILE *f; 1143 int n; 1144 1145 assertion_count(filename, line); 1146 1147 f = fopen(fn, "rb"); 1148 if (f == NULL) { 1149 failure_start(filename, line, 1150 "File should exist: %s", fn); 1151 failure_finish(NULL); 1152 return (0); 1153 } 1154 contents = malloc(s * 2); 1155 n = (int)fread(contents, 1, s * 2, f); 1156 fclose(f); 1157 if (n == s && memcmp(buff, contents, s) == 0) { 1158 free(contents); 1159 return (1); 1160 } 1161 failure_start(filename, line, "File contents don't match"); 1162 logprintf(" file=\"%s\"\n", fn); 1163 if (n > 0) 1164 hexdump(contents, buff, n > 512 ? 512 : n, 0); 1165 else { 1166 logprintf(" File empty, contents should be:\n"); 1167 hexdump(buff, NULL, s > 512 ? 512 : s, 0); 1168 } 1169 failure_finish(NULL); 1170 free(contents); 1171 return (0); 1172 } 1173 1174 /* Check the contents of a text file, being tolerant of line endings. */ 1175 int 1176 assertion_text_file_contents(const char *filename, int line, const char *buff, const char *fn) 1177 { 1178 char *contents; 1179 const char *btxt, *ftxt; 1180 FILE *f; 1181 int n, s; 1182 1183 assertion_count(filename, line); 1184 f = fopen(fn, "r"); 1185 if (f == NULL) { 1186 failure_start(filename, line, 1187 "File doesn't exist: %s", fn); 1188 failure_finish(NULL); 1189 return (0); 1190 } 1191 s = (int)strlen(buff); 1192 contents = malloc(s * 2 + 128); 1193 n = (int)fread(contents, 1, s * 2 + 128 - 1, f); 1194 if (n >= 0) 1195 contents[n] = '\0'; 1196 fclose(f); 1197 /* Compare texts. */ 1198 btxt = buff; 1199 ftxt = (const char *)contents; 1200 while (*btxt != '\0' && *ftxt != '\0') { 1201 if (*btxt == *ftxt) { 1202 ++btxt; 1203 ++ftxt; 1204 continue; 1205 } 1206 if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') { 1207 /* Pass over different new line characters. */ 1208 ++btxt; 1209 ftxt += 2; 1210 continue; 1211 } 1212 break; 1213 } 1214 if (*btxt == '\0' && *ftxt == '\0') { 1215 free(contents); 1216 return (1); 1217 } 1218 failure_start(filename, line, "Contents don't match"); 1219 logprintf(" file=\"%s\"\n", fn); 1220 if (n > 0) { 1221 hexdump(contents, buff, n, 0); 1222 logprintf(" expected\n"); 1223 hexdump(buff, contents, s, 0); 1224 } else { 1225 logprintf(" File empty, contents should be:\n"); 1226 hexdump(buff, NULL, s, 0); 1227 } 1228 failure_finish(NULL); 1229 free(contents); 1230 return (0); 1231 } 1232 1233 /* Verify that a text file contains the specified lines, regardless of order */ 1234 /* This could be more efficient if we sorted both sets of lines, etc, but 1235 * since this is used only for testing and only ever deals with a dozen or so 1236 * lines at a time, this relatively crude approach is just fine. */ 1237 int 1238 assertion_file_contains_lines_any_order(const char *file, int line, 1239 const char *pathname, const char *lines[]) 1240 { 1241 char *buff; 1242 size_t buff_size; 1243 size_t expected_count, actual_count, i, j; 1244 char **expected = NULL; 1245 char *p, **actual = NULL; 1246 char c; 1247 int expected_failure = 0, actual_failure = 0; 1248 1249 assertion_count(file, line); 1250 1251 buff = slurpfile(&buff_size, "%s", pathname); 1252 if (buff == NULL) { 1253 failure_start(pathname, line, "Can't read file: %s", pathname); 1254 failure_finish(NULL); 1255 return (0); 1256 } 1257 1258 /* Make a copy of the provided lines and count up the expected 1259 * file size. */ 1260 for (i = 0; lines[i] != NULL; ++i) { 1261 } 1262 expected_count = i; 1263 if (expected_count) { 1264 expected = calloc(expected_count, sizeof(*expected)); 1265 if (expected == NULL) { 1266 failure_start(pathname, line, "Can't allocate memory"); 1267 failure_finish(NULL); 1268 goto cleanup; 1269 } 1270 for (i = 0; lines[i] != NULL; ++i) { 1271 expected[i] = strdup(lines[i]); 1272 if (expected[i] == NULL) { 1273 failure_start(pathname, line, "Can't allocate memory"); 1274 failure_finish(NULL); 1275 goto cleanup; 1276 } 1277 } 1278 } 1279 1280 /* Break the file into lines */ 1281 actual_count = 0; 1282 for (c = '\0', p = buff; p < buff + buff_size; ++p) { 1283 if (*p == '\x0d' || *p == '\x0a') 1284 *p = '\0'; 1285 if (c == '\0' && *p != '\0') 1286 ++actual_count; 1287 c = *p; 1288 } 1289 if (actual_count) { 1290 actual = calloc(actual_count, sizeof(char *)); 1291 if (actual == NULL) { 1292 failure_start(pathname, line, "Can't allocate memory"); 1293 failure_finish(NULL); 1294 goto cleanup; 1295 } 1296 for (j = 0, p = buff; p < buff + buff_size; 1297 p += 1 + strlen(p)) { 1298 if (*p != '\0') { 1299 actual[j] = p; 1300 ++j; 1301 } 1302 } 1303 } 1304 1305 /* Erase matching lines from both lists */ 1306 for (i = 0; i < expected_count; ++i) { 1307 for (j = 0; j < actual_count; ++j) { 1308 if (actual[j] == NULL) 1309 continue; 1310 if (strcmp(expected[i], actual[j]) == 0) { 1311 free(expected[i]); 1312 expected[i] = NULL; 1313 actual[j] = NULL; 1314 break; 1315 } 1316 } 1317 } 1318 1319 /* If there's anything left, it's a failure */ 1320 for (i = 0; i < expected_count; ++i) { 1321 if (expected[i] != NULL) 1322 ++expected_failure; 1323 } 1324 for (j = 0; j < actual_count; ++j) { 1325 if (actual[j] != NULL) 1326 ++actual_failure; 1327 } 1328 if (expected_failure == 0 && actual_failure == 0) { 1329 free(actual); 1330 free(expected); 1331 free(buff); 1332 return (1); 1333 } 1334 failure_start(file, line, "File doesn't match: %s", pathname); 1335 for (i = 0; i < expected_count; ++i) { 1336 if (expected[i] != NULL) { 1337 logprintf(" Expected but not present: %s\n", expected[i]); 1338 free(expected[i]); 1339 expected[i] = NULL; 1340 } 1341 } 1342 for (j = 0; j < actual_count; ++j) { 1343 if (actual[j] != NULL) 1344 logprintf(" Present but not expected: %s\n", actual[j]); 1345 } 1346 failure_finish(NULL); 1347 cleanup: 1348 free(actual); 1349 if (expected != NULL) { 1350 for (i = 0; i < expected_count; ++i) 1351 if (expected[i] != NULL) 1352 free(expected[i]); 1353 free(expected); 1354 } 1355 free(buff); 1356 return (0); 1357 } 1358 1359 /* Verify that a text file does not contains the specified strings */ 1360 int 1361 assertion_file_contains_no_invalid_strings(const char *file, int line, 1362 const char *pathname, const char *strings[]) 1363 { 1364 char *buff; 1365 int i; 1366 1367 buff = slurpfile(NULL, "%s", pathname); 1368 if (buff == NULL) { 1369 failure_start(file, line, "Can't read file: %s", pathname); 1370 failure_finish(NULL); 1371 return (0); 1372 } 1373 1374 for (i = 0; strings[i] != NULL; ++i) { 1375 if (strstr(buff, strings[i]) != NULL) { 1376 failure_start(file, line, "Invalid string in %s: %s", pathname, 1377 strings[i]); 1378 failure_finish(NULL); 1379 free(buff); 1380 return(0); 1381 } 1382 } 1383 1384 free(buff); 1385 return (0); 1386 } 1387 1388 /* Test that two paths point to the same file. */ 1389 /* As a side-effect, asserts that both files exist. */ 1390 static int 1391 is_hardlink(const char *file, int line, 1392 const char *path1, const char *path2) 1393 { 1394 #if defined(_WIN32) && !defined(__CYGWIN__) 1395 BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2; 1396 int r; 1397 1398 assertion_count(file, line); 1399 r = my_GetFileInformationByName(path1, &bhfi1); 1400 if (r == 0) { 1401 failure_start(file, line, "File %s can't be inspected?", path1); 1402 failure_finish(NULL); 1403 return (0); 1404 } 1405 r = my_GetFileInformationByName(path2, &bhfi2); 1406 if (r == 0) { 1407 failure_start(file, line, "File %s can't be inspected?", path2); 1408 failure_finish(NULL); 1409 return (0); 1410 } 1411 return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber 1412 && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh 1413 && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow); 1414 #else 1415 struct stat st1, st2; 1416 int r; 1417 1418 assertion_count(file, line); 1419 r = lstat(path1, &st1); 1420 if (r != 0) { 1421 failure_start(file, line, "File should exist: %s", path1); 1422 failure_finish(NULL); 1423 return (0); 1424 } 1425 r = lstat(path2, &st2); 1426 if (r != 0) { 1427 failure_start(file, line, "File should exist: %s", path2); 1428 failure_finish(NULL); 1429 return (0); 1430 } 1431 return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev); 1432 #endif 1433 } 1434 1435 int 1436 assertion_is_hardlink(const char *file, int line, 1437 const char *path1, const char *path2) 1438 { 1439 if (is_hardlink(file, line, path1, path2)) 1440 return (1); 1441 failure_start(file, line, 1442 "Files %s and %s are not hardlinked", path1, path2); 1443 failure_finish(NULL); 1444 return (0); 1445 } 1446 1447 int 1448 assertion_is_not_hardlink(const char *file, int line, 1449 const char *path1, const char *path2) 1450 { 1451 if (!is_hardlink(file, line, path1, path2)) 1452 return (1); 1453 failure_start(file, line, 1454 "Files %s and %s should not be hardlinked", path1, path2); 1455 failure_finish(NULL); 1456 return (0); 1457 } 1458 1459 /* Verify a/b/mtime of 'pathname'. */ 1460 /* If 'recent', verify that it's within last 10 seconds. */ 1461 static int 1462 assertion_file_time(const char *file, int line, 1463 const char *pathname, long t, long nsec, char type, int recent) 1464 { 1465 long long filet, filet_nsec; 1466 int r; 1467 1468 #if defined(_WIN32) && !defined(__CYGWIN__) 1469 #define EPOC_TIME (116444736000000000ULL) 1470 FILETIME fxtime, fbirthtime, fatime, fmtime; 1471 ULARGE_INTEGER wintm; 1472 HANDLE h; 1473 fxtime.dwLowDateTime = 0; 1474 fxtime.dwHighDateTime = 0; 1475 1476 assertion_count(file, line); 1477 /* Note: FILE_FLAG_BACKUP_SEMANTICS applies to open 1478 * a directory file. If not, CreateFile() will fail when 1479 * the pathname is a directory. */ 1480 h = CreateFileA(pathname, FILE_READ_ATTRIBUTES, 0, NULL, 1481 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 1482 if (h == INVALID_HANDLE_VALUE) { 1483 failure_start(file, line, "Can't access %s\n", pathname); 1484 failure_finish(NULL); 1485 return (0); 1486 } 1487 r = GetFileTime(h, &fbirthtime, &fatime, &fmtime); 1488 switch (type) { 1489 case 'a': fxtime = fatime; break; 1490 case 'b': fxtime = fbirthtime; break; 1491 case 'm': fxtime = fmtime; break; 1492 } 1493 CloseHandle(h); 1494 if (r == 0) { 1495 failure_start(file, line, "Can't GetFileTime %s\n", pathname); 1496 failure_finish(NULL); 1497 return (0); 1498 } 1499 wintm.LowPart = fxtime.dwLowDateTime; 1500 wintm.HighPart = fxtime.dwHighDateTime; 1501 filet = (wintm.QuadPart - EPOC_TIME) / 10000000; 1502 filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100; 1503 nsec = (nsec / 100) * 100; /* Round the request */ 1504 #else 1505 struct stat st; 1506 1507 assertion_count(file, line); 1508 r = lstat(pathname, &st); 1509 if (r != 0) { 1510 failure_start(file, line, "Can't stat %s\n", pathname); 1511 failure_finish(NULL); 1512 return (0); 1513 } 1514 switch (type) { 1515 case 'a': filet = st.st_atime; break; 1516 case 'm': filet = st.st_mtime; break; 1517 case 'b': filet = 0; break; 1518 default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); 1519 exit(1); 1520 } 1521 #if defined(__FreeBSD__) 1522 switch (type) { 1523 case 'a': filet_nsec = st.st_atimespec.tv_nsec; break; 1524 case 'b': filet = st.st_birthtime; 1525 /* FreeBSD filesystems that don't support birthtime 1526 * (e.g., UFS1) always return -1 here. */ 1527 if (filet == -1) { 1528 return (1); 1529 } 1530 filet_nsec = st.st_birthtimespec.tv_nsec; break; 1531 case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break; 1532 default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); 1533 exit(1); 1534 } 1535 /* FreeBSD generally only stores to microsecond res, so round. */ 1536 filet_nsec = (filet_nsec / 1000) * 1000; 1537 nsec = (nsec / 1000) * 1000; 1538 #else 1539 filet_nsec = nsec = 0; /* Generic POSIX only has whole seconds. */ 1540 if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */ 1541 #if defined(__HAIKU__) 1542 if (type == 'a') return (1); /* Haiku doesn't have atime. */ 1543 #endif 1544 #endif 1545 #endif 1546 if (recent) { 1547 /* Check that requested time is up-to-date. */ 1548 time_t now = time(NULL); 1549 if (filet < now - 10 || filet > now + 1) { 1550 failure_start(file, line, 1551 "File %s has %ctime %lld, %lld seconds ago\n", 1552 pathname, type, filet, now - filet); 1553 failure_finish(NULL); 1554 return (0); 1555 } 1556 } else if (filet != t || filet_nsec != nsec) { 1557 failure_start(file, line, 1558 "File %s has %ctime %lld.%09lld, expected %ld.%09ld", 1559 pathname, type, filet, filet_nsec, t, nsec); 1560 failure_finish(NULL); 1561 return (0); 1562 } 1563 return (1); 1564 } 1565 1566 /* Verify atime of 'pathname'. */ 1567 int 1568 assertion_file_atime(const char *file, int line, 1569 const char *pathname, long t, long nsec) 1570 { 1571 return assertion_file_time(file, line, pathname, t, nsec, 'a', 0); 1572 } 1573 1574 /* Verify atime of 'pathname' is up-to-date. */ 1575 int 1576 assertion_file_atime_recent(const char *file, int line, const char *pathname) 1577 { 1578 return assertion_file_time(file, line, pathname, 0, 0, 'a', 1); 1579 } 1580 1581 /* Verify birthtime of 'pathname'. */ 1582 int 1583 assertion_file_birthtime(const char *file, int line, 1584 const char *pathname, long t, long nsec) 1585 { 1586 return assertion_file_time(file, line, pathname, t, nsec, 'b', 0); 1587 } 1588 1589 /* Verify birthtime of 'pathname' is up-to-date. */ 1590 int 1591 assertion_file_birthtime_recent(const char *file, int line, 1592 const char *pathname) 1593 { 1594 return assertion_file_time(file, line, pathname, 0, 0, 'b', 1); 1595 } 1596 1597 /* Verify mode of 'pathname'. */ 1598 int 1599 assertion_file_mode(const char *file, int line, const char *pathname, int expected_mode) 1600 { 1601 int mode; 1602 int r; 1603 1604 assertion_count(file, line); 1605 #if defined(_WIN32) && !defined(__CYGWIN__) 1606 failure_start(file, line, "assertFileMode not yet implemented for Windows"); 1607 (void)mode; /* UNUSED */ 1608 (void)r; /* UNUSED */ 1609 (void)pathname; /* UNUSED */ 1610 (void)expected_mode; /* UNUSED */ 1611 #else 1612 { 1613 struct stat st; 1614 r = lstat(pathname, &st); 1615 mode = (int)(st.st_mode & 0777); 1616 } 1617 if (r == 0 && mode == expected_mode) 1618 return (1); 1619 failure_start(file, line, "File %s has mode %o, expected %o", 1620 pathname, (unsigned int)mode, (unsigned int)expected_mode); 1621 #endif 1622 failure_finish(NULL); 1623 return (0); 1624 } 1625 1626 /* Verify mtime of 'pathname'. */ 1627 int 1628 assertion_file_mtime(const char *file, int line, 1629 const char *pathname, long t, long nsec) 1630 { 1631 return assertion_file_time(file, line, pathname, t, nsec, 'm', 0); 1632 } 1633 1634 /* Verify mtime of 'pathname' is up-to-date. */ 1635 int 1636 assertion_file_mtime_recent(const char *file, int line, const char *pathname) 1637 { 1638 return assertion_file_time(file, line, pathname, 0, 0, 'm', 1); 1639 } 1640 1641 /* Verify number of links to 'pathname'. */ 1642 int 1643 assertion_file_nlinks(const char *file, int line, 1644 const char *pathname, int nlinks) 1645 { 1646 #if defined(_WIN32) && !defined(__CYGWIN__) 1647 BY_HANDLE_FILE_INFORMATION bhfi; 1648 int r; 1649 1650 assertion_count(file, line); 1651 r = my_GetFileInformationByName(pathname, &bhfi); 1652 if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks) 1653 return (1); 1654 failure_start(file, line, "File %s has %jd links, expected %d", 1655 pathname, (intmax_t)bhfi.nNumberOfLinks, nlinks); 1656 failure_finish(NULL); 1657 return (0); 1658 #else 1659 struct stat st; 1660 int r; 1661 1662 assertion_count(file, line); 1663 r = lstat(pathname, &st); 1664 if (r == 0 && (int)st.st_nlink == nlinks) 1665 return (1); 1666 failure_start(file, line, "File %s has %jd links, expected %d", 1667 pathname, (intmax_t)st.st_nlink, nlinks); 1668 failure_finish(NULL); 1669 return (0); 1670 #endif 1671 } 1672 1673 /* Verify size of 'pathname'. */ 1674 int 1675 assertion_file_size(const char *file, int line, const char *pathname, long size) 1676 { 1677 int64_t filesize; 1678 int r; 1679 1680 assertion_count(file, line); 1681 #if defined(_WIN32) && !defined(__CYGWIN__) 1682 { 1683 BY_HANDLE_FILE_INFORMATION bhfi; 1684 r = !my_GetFileInformationByName(pathname, &bhfi); 1685 filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow; 1686 } 1687 #else 1688 { 1689 struct stat st; 1690 r = lstat(pathname, &st); 1691 filesize = st.st_size; 1692 } 1693 #endif 1694 if (r == 0 && filesize == size) 1695 return (1); 1696 failure_start(file, line, "File %s has size %ld, expected %ld", 1697 pathname, (long)filesize, (long)size); 1698 failure_finish(NULL); 1699 return (0); 1700 } 1701 1702 /* Assert that 'pathname' is a dir. If mode >= 0, verify that too. */ 1703 int 1704 assertion_is_dir(const char *file, int line, const char *pathname, int mode) 1705 { 1706 struct stat st; 1707 int r; 1708 1709 #if defined(_WIN32) && !defined(__CYGWIN__) 1710 (void)mode; /* UNUSED */ 1711 #endif 1712 assertion_count(file, line); 1713 r = lstat(pathname, &st); 1714 if (r != 0) { 1715 failure_start(file, line, "Dir should exist: %s", pathname); 1716 failure_finish(NULL); 1717 return (0); 1718 } 1719 if (!S_ISDIR(st.st_mode)) { 1720 failure_start(file, line, "%s is not a dir", pathname); 1721 failure_finish(NULL); 1722 return (0); 1723 } 1724 #if !defined(_WIN32) || defined(__CYGWIN__) 1725 /* Windows doesn't handle permissions the same way as POSIX, 1726 * so just ignore the mode tests. */ 1727 /* TODO: Can we do better here? */ 1728 if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) { 1729 failure_start(file, line, "Dir %s has wrong mode", pathname); 1730 logprintf(" Expected: 0%3o\n", (unsigned int)mode); 1731 logprintf(" Found: 0%3o\n", (unsigned int)st.st_mode & 07777); 1732 failure_finish(NULL); 1733 return (0); 1734 } 1735 #endif 1736 return (1); 1737 } 1738 1739 /* Verify that 'pathname' is a regular file. If 'mode' is >= 0, 1740 * verify that too. */ 1741 int 1742 assertion_is_reg(const char *file, int line, const char *pathname, int mode) 1743 { 1744 struct stat st; 1745 int r; 1746 1747 #if defined(_WIN32) && !defined(__CYGWIN__) 1748 (void)mode; /* UNUSED */ 1749 #endif 1750 assertion_count(file, line); 1751 r = lstat(pathname, &st); 1752 if (r != 0 || !S_ISREG(st.st_mode)) { 1753 failure_start(file, line, "File should exist: %s", pathname); 1754 failure_finish(NULL); 1755 return (0); 1756 } 1757 #if !defined(_WIN32) || defined(__CYGWIN__) 1758 /* Windows doesn't handle permissions the same way as POSIX, 1759 * so just ignore the mode tests. */ 1760 /* TODO: Can we do better here? */ 1761 if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) { 1762 failure_start(file, line, "File %s has wrong mode", pathname); 1763 logprintf(" Expected: 0%3o\n", (unsigned int)mode); 1764 logprintf(" Found: 0%3o\n", (unsigned int)st.st_mode & 07777); 1765 failure_finish(NULL); 1766 return (0); 1767 } 1768 #endif 1769 return (1); 1770 } 1771 1772 /* 1773 * Check whether 'pathname' is a symbolic link. If 'contents' is 1774 * non-NULL, verify that the symlink has those contents. 1775 * 1776 * On platforms with directory symlinks, set isdir to 0 to test for a file 1777 * symlink and to 1 to test for a directory symlink. On other platforms 1778 * the variable is ignored. 1779 */ 1780 static int 1781 is_symlink(const char *file, int line, 1782 const char *pathname, const char *contents, int isdir) 1783 { 1784 #if defined(_WIN32) && !defined(__CYGWIN__) 1785 HANDLE h; 1786 DWORD inbytes; 1787 REPARSE_DATA_BUFFER *buf; 1788 BY_HANDLE_FILE_INFORMATION st; 1789 size_t len, len2; 1790 wchar_t *linknamew, *contentsw; 1791 const char *p; 1792 char *s, *pn; 1793 int ret = 0; 1794 BYTE *indata; 1795 const DWORD flag = FILE_FLAG_BACKUP_SEMANTICS | 1796 FILE_FLAG_OPEN_REPARSE_POINT; 1797 1798 /* Replace slashes with backslashes in pathname */ 1799 pn = malloc(strlen(pathname) + 1); 1800 if (pn == NULL) { 1801 failure_start(file, line, "Can't allocate memory"); 1802 failure_finish(NULL); 1803 return (0); 1804 } 1805 for (p = pathname, s = pn; *p != '\0'; p++, s++) { 1806 if (*p == '/') 1807 *s = '\\'; 1808 else 1809 *s = *p; 1810 } 1811 *s = '\0'; 1812 1813 h = CreateFileA(pn, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, 1814 flag, NULL); 1815 free(pn); 1816 if (h == INVALID_HANDLE_VALUE) { 1817 failure_start(file, line, "Can't access %s\n", pathname); 1818 failure_finish(NULL); 1819 return (0); 1820 } 1821 ret = GetFileInformationByHandle(h, &st); 1822 if (ret == 0) { 1823 failure_start(file, line, 1824 "Can't stat: %s", pathname); 1825 failure_finish(NULL); 1826 } else if ((st.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) { 1827 failure_start(file, line, 1828 "Not a symlink: %s", pathname); 1829 failure_finish(NULL); 1830 ret = 0; 1831 } 1832 if (isdir && ((st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) { 1833 failure_start(file, line, 1834 "Not a directory symlink: %s", pathname); 1835 failure_finish(NULL); 1836 ret = 0; 1837 } 1838 if (!isdir && 1839 ((st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) { 1840 failure_start(file, line, 1841 "Not a file symlink: %s", pathname); 1842 failure_finish(NULL); 1843 ret = 0; 1844 } 1845 if (ret == 0) { 1846 CloseHandle(h); 1847 return (0); 1848 } 1849 1850 indata = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 1851 ret = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, indata, 1852 1024, &inbytes, NULL); 1853 CloseHandle(h); 1854 if (ret == 0) { 1855 free(indata); 1856 failure_start(file, line, 1857 "Could not retrieve symlink target: %s", pathname); 1858 failure_finish(NULL); 1859 return (0); 1860 } 1861 1862 buf = (REPARSE_DATA_BUFFER *) indata; 1863 if (buf->ReparseTag != IO_REPARSE_TAG_SYMLINK) { 1864 free(indata); 1865 /* File is not a symbolic link */ 1866 failure_start(file, line, 1867 "Not a symlink: %s", pathname); 1868 failure_finish(NULL); 1869 return (0); 1870 } 1871 1872 if (contents == NULL) { 1873 free(indata); 1874 return (1); 1875 } 1876 1877 len = buf->SymbolicLinkReparseBuffer.SubstituteNameLength; 1878 1879 linknamew = malloc(len + sizeof(wchar_t)); 1880 if (linknamew == NULL) { 1881 free(indata); 1882 return (0); 1883 } 1884 1885 memcpy(linknamew, &((BYTE *)buf->SymbolicLinkReparseBuffer.PathBuffer) 1886 [buf->SymbolicLinkReparseBuffer.SubstituteNameOffset], len); 1887 free(indata); 1888 1889 linknamew[len / sizeof(wchar_t)] = L'\0'; 1890 1891 contentsw = malloc(len + sizeof(wchar_t)); 1892 if (contentsw == NULL) { 1893 free(linknamew); 1894 return (0); 1895 } 1896 1897 len2 = mbsrtowcs(contentsw, &contents, (len + sizeof(wchar_t) 1898 / sizeof(wchar_t)), NULL); 1899 1900 if (len2 > 0 && wcscmp(linknamew, contentsw) != 0) 1901 ret = 1; 1902 1903 free(linknamew); 1904 free(contentsw); 1905 return (ret); 1906 #else 1907 char buff[300]; 1908 struct stat st; 1909 ssize_t linklen; 1910 int r; 1911 1912 (void)isdir; /* UNUSED */ 1913 assertion_count(file, line); 1914 r = lstat(pathname, &st); 1915 if (r != 0) { 1916 failure_start(file, line, 1917 "Symlink should exist: %s", pathname); 1918 failure_finish(NULL); 1919 return (0); 1920 } 1921 if (!S_ISLNK(st.st_mode)) 1922 return (0); 1923 if (contents == NULL) 1924 return (1); 1925 linklen = readlink(pathname, buff, sizeof(buff) - 1); 1926 if (linklen < 0) { 1927 failure_start(file, line, "Can't read symlink %s", pathname); 1928 failure_finish(NULL); 1929 return (0); 1930 } 1931 buff[linklen] = '\0'; 1932 if (strcmp(buff, contents) != 0) 1933 return (0); 1934 return (1); 1935 #endif 1936 } 1937 1938 /* Assert that path is a symlink that (optionally) contains contents. */ 1939 int 1940 assertion_is_symlink(const char *file, int line, 1941 const char *path, const char *contents, int isdir) 1942 { 1943 if (is_symlink(file, line, path, contents, isdir)) 1944 return (1); 1945 if (contents) 1946 failure_start(file, line, "File %s is not a symlink to %s", 1947 path, contents); 1948 else 1949 failure_start(file, line, "File %s is not a symlink", path); 1950 failure_finish(NULL); 1951 return (0); 1952 } 1953 1954 1955 /* Create a directory and report any errors. */ 1956 int 1957 assertion_make_dir(const char *file, int line, const char *dirname, int mode) 1958 { 1959 assertion_count(file, line); 1960 #if defined(_WIN32) && !defined(__CYGWIN__) 1961 (void)mode; /* UNUSED */ 1962 if (0 == _mkdir(dirname)) 1963 return (1); 1964 #else 1965 if (0 == mkdir(dirname, (mode_t)mode)) { 1966 if (0 == chmod(dirname, (mode_t)mode)) { 1967 assertion_file_mode(file, line, dirname, mode); 1968 return (1); 1969 } 1970 } 1971 #endif 1972 failure_start(file, line, "Could not create directory %s", dirname); 1973 failure_finish(NULL); 1974 return(0); 1975 } 1976 1977 /* Create a file with the specified contents and report any failures. */ 1978 int 1979 assertion_make_file(const char *file, int line, 1980 const char *path, int mode, int csize, const void *contents) 1981 { 1982 #if defined(_WIN32) && !defined(__CYGWIN__) 1983 /* TODO: Rework this to set file mode as well. */ 1984 FILE *f; 1985 (void)mode; /* UNUSED */ 1986 assertion_count(file, line); 1987 f = fopen(path, "wb"); 1988 if (f == NULL) { 1989 failure_start(file, line, "Could not create file %s", path); 1990 failure_finish(NULL); 1991 return (0); 1992 } 1993 if (contents != NULL) { 1994 size_t wsize; 1995 1996 if (csize < 0) 1997 wsize = strlen(contents); 1998 else 1999 wsize = (size_t)csize; 2000 if (wsize != fwrite(contents, 1, wsize, f)) { 2001 fclose(f); 2002 failure_start(file, line, 2003 "Could not write file %s", path); 2004 failure_finish(NULL); 2005 return (0); 2006 } 2007 } 2008 fclose(f); 2009 return (1); 2010 #else 2011 int fd; 2012 assertion_count(file, line); 2013 fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644); 2014 if (fd < 0) { 2015 failure_start(file, line, "Could not create %s", path); 2016 failure_finish(NULL); 2017 return (0); 2018 } 2019 #ifdef HAVE_FCHMOD 2020 if (0 != fchmod(fd, (mode_t)mode)) 2021 #else 2022 if (0 != chmod(path, (mode_t)mode)) 2023 #endif 2024 { 2025 failure_start(file, line, "Could not chmod %s", path); 2026 failure_finish(NULL); 2027 close(fd); 2028 return (0); 2029 } 2030 if (contents != NULL) { 2031 ssize_t wsize; 2032 2033 if (csize < 0) 2034 wsize = (ssize_t)strlen(contents); 2035 else 2036 wsize = (ssize_t)csize; 2037 if (wsize != write(fd, contents, wsize)) { 2038 close(fd); 2039 failure_start(file, line, 2040 "Could not write to %s", path); 2041 failure_finish(NULL); 2042 close(fd); 2043 return (0); 2044 } 2045 } 2046 close(fd); 2047 assertion_file_mode(file, line, path, mode); 2048 return (1); 2049 #endif 2050 } 2051 2052 /* Create a hardlink and report any failures. */ 2053 int 2054 assertion_make_hardlink(const char *file, int line, 2055 const char *newpath, const char *linkto) 2056 { 2057 int succeeded; 2058 2059 assertion_count(file, line); 2060 #if defined(_WIN32) && !defined(__CYGWIN__) 2061 succeeded = my_CreateHardLinkA(newpath, linkto); 2062 #elif HAVE_LINK 2063 succeeded = !link(linkto, newpath); 2064 #else 2065 succeeded = 0; 2066 #endif 2067 if (succeeded) 2068 return (1); 2069 failure_start(file, line, "Could not create hardlink"); 2070 logprintf(" New link: %s\n", newpath); 2071 logprintf(" Old name: %s\n", linkto); 2072 failure_finish(NULL); 2073 return(0); 2074 } 2075 2076 /* 2077 * Create a symlink and report any failures. 2078 * 2079 * Windows symlinks need to know if the target is a directory. 2080 */ 2081 int 2082 assertion_make_symlink(const char *file, int line, 2083 const char *newpath, const char *linkto, int targetIsDir) 2084 { 2085 #if defined(_WIN32) && !defined(__CYGWIN__) 2086 assertion_count(file, line); 2087 if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir)) 2088 return (1); 2089 #elif HAVE_SYMLINK 2090 (void)targetIsDir; /* UNUSED */ 2091 assertion_count(file, line); 2092 if (0 == symlink(linkto, newpath)) 2093 return (1); 2094 #else 2095 (void)targetIsDir; /* UNUSED */ 2096 #endif 2097 failure_start(file, line, "Could not create symlink"); 2098 logprintf(" New link: %s\n", newpath); 2099 logprintf(" Old name: %s\n", linkto); 2100 failure_finish(NULL); 2101 return(0); 2102 } 2103 2104 /* Set umask, report failures. */ 2105 int 2106 assertion_umask(const char *file, int line, int mask) 2107 { 2108 assertion_count(file, line); 2109 (void)file; /* UNUSED */ 2110 (void)line; /* UNUSED */ 2111 umask((mode_t)mask); 2112 return (1); 2113 } 2114 2115 /* Set times, report failures. */ 2116 int 2117 assertion_utimes(const char *file, int line, const char *pathname, 2118 time_t at, suseconds_t at_nsec, time_t mt, suseconds_t mt_nsec) 2119 { 2120 int r; 2121 2122 #if defined(_WIN32) && !defined(__CYGWIN__) 2123 #define WINTIME(sec, nsec) (((sec * 10000000LL) + EPOC_TIME)\ 2124 + (((nsec)/1000)*10)) 2125 HANDLE h; 2126 ULARGE_INTEGER wintm; 2127 FILETIME fatime, fmtime; 2128 FILETIME *pat, *pmt; 2129 2130 assertion_count(file, line); 2131 h = CreateFileA(pathname,GENERIC_READ | GENERIC_WRITE, 2132 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 2133 FILE_FLAG_BACKUP_SEMANTICS, NULL); 2134 if (h == INVALID_HANDLE_VALUE) { 2135 failure_start(file, line, "Can't access %s\n", pathname); 2136 failure_finish(NULL); 2137 return (0); 2138 } 2139 2140 if (at > 0 || at_nsec > 0) { 2141 wintm.QuadPart = WINTIME(at, at_nsec); 2142 fatime.dwLowDateTime = wintm.LowPart; 2143 fatime.dwHighDateTime = wintm.HighPart; 2144 pat = &fatime; 2145 } else 2146 pat = NULL; 2147 if (mt > 0 || mt_nsec > 0) { 2148 wintm.QuadPart = WINTIME(mt, mt_nsec); 2149 fmtime.dwLowDateTime = wintm.LowPart; 2150 fmtime.dwHighDateTime = wintm.HighPart; 2151 pmt = &fmtime; 2152 } else 2153 pmt = NULL; 2154 if (pat != NULL || pmt != NULL) 2155 r = SetFileTime(h, NULL, pat, pmt); 2156 else 2157 r = 1; 2158 CloseHandle(h); 2159 if (r == 0) { 2160 failure_start(file, line, "Can't SetFileTime %s\n", pathname); 2161 failure_finish(NULL); 2162 return (0); 2163 } 2164 return (1); 2165 #else /* defined(_WIN32) && !defined(__CYGWIN__) */ 2166 struct stat st; 2167 struct timeval times[2]; 2168 2169 #if !defined(__FreeBSD__) 2170 mt_nsec = at_nsec = 0; /* Generic POSIX only has whole seconds. */ 2171 #endif 2172 if (mt == 0 && mt_nsec == 0 && at == 0 && at_nsec == 0) 2173 return (1); 2174 2175 r = lstat(pathname, &st); 2176 if (r < 0) { 2177 failure_start(file, line, "Can't stat %s\n", pathname); 2178 failure_finish(NULL); 2179 return (0); 2180 } 2181 2182 if (mt == 0 && mt_nsec == 0) { 2183 mt = st.st_mtime; 2184 #if defined(__FreeBSD__) 2185 mt_nsec = st.st_mtimespec.tv_nsec; 2186 /* FreeBSD generally only stores to microsecond res, so round. */ 2187 mt_nsec = (mt_nsec / 1000) * 1000; 2188 #endif 2189 } 2190 if (at == 0 && at_nsec == 0) { 2191 at = st.st_atime; 2192 #if defined(__FreeBSD__) 2193 at_nsec = st.st_atimespec.tv_nsec; 2194 /* FreeBSD generally only stores to microsecond res, so round. */ 2195 at_nsec = (at_nsec / 1000) * 1000; 2196 #endif 2197 } 2198 2199 times[1].tv_sec = mt; 2200 times[1].tv_usec = mt_nsec / 1000; 2201 2202 times[0].tv_sec = at; 2203 times[0].tv_usec = at_nsec / 1000; 2204 2205 #ifdef HAVE_LUTIMES 2206 r = lutimes(pathname, times); 2207 #else 2208 r = utimes(pathname, times); 2209 #endif 2210 if (r < 0) { 2211 failure_start(file, line, "Can't utimes %s\n", pathname); 2212 failure_finish(NULL); 2213 return (0); 2214 } 2215 return (1); 2216 #endif /* defined(_WIN32) && !defined(__CYGWIN__) */ 2217 } 2218 2219 /* Compare file flags */ 2220 int 2221 assertion_compare_fflags(const char *file, int line, const char *patha, 2222 const char *pathb, int nomatch) 2223 { 2224 #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) 2225 struct stat sa, sb; 2226 2227 assertion_count(file, line); 2228 2229 if (stat(patha, &sa) < 0) 2230 return (0); 2231 if (stat(pathb, &sb) < 0) 2232 return (0); 2233 if (!nomatch && sa.st_flags != sb.st_flags) { 2234 failure_start(file, line, "File flags should be identical: " 2235 "%s=%#010x %s=%#010x", patha, sa.st_flags, pathb, 2236 sb.st_flags); 2237 failure_finish(NULL); 2238 return (0); 2239 } 2240 if (nomatch && sa.st_flags == sb.st_flags) { 2241 failure_start(file, line, "File flags should be different: " 2242 "%s=%#010x %s=%#010x", patha, sa.st_flags, pathb, 2243 sb.st_flags); 2244 failure_finish(NULL); 2245 return (0); 2246 } 2247 #elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS) && \ 2248 defined(FS_NODUMP_FL)) || \ 2249 (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) \ 2250 && defined(EXT2_NODUMP_FL)) 2251 int fd, r, flagsa, flagsb; 2252 2253 assertion_count(file, line); 2254 fd = open(patha, O_RDONLY | O_NONBLOCK); 2255 if (fd < 0) { 2256 failure_start(file, line, "Can't open %s\n", patha); 2257 failure_finish(NULL); 2258 return (0); 2259 } 2260 r = ioctl(fd, 2261 #ifdef FS_IOC_GETFLAGS 2262 FS_IOC_GETFLAGS, 2263 #else 2264 EXT2_IOC_GETFLAGS, 2265 #endif 2266 &flagsa); 2267 close(fd); 2268 if (r < 0) { 2269 failure_start(file, line, "Can't get flags %s\n", patha); 2270 failure_finish(NULL); 2271 return (0); 2272 } 2273 fd = open(pathb, O_RDONLY | O_NONBLOCK); 2274 if (fd < 0) { 2275 failure_start(file, line, "Can't open %s\n", pathb); 2276 failure_finish(NULL); 2277 return (0); 2278 } 2279 r = ioctl(fd, 2280 #ifdef FS_IOC_GETFLAGS 2281 FS_IOC_GETFLAGS, 2282 #else 2283 EXT2_IOC_GETFLAGS, 2284 #endif 2285 &flagsb); 2286 close(fd); 2287 if (r < 0) { 2288 failure_start(file, line, "Can't get flags %s\n", pathb); 2289 failure_finish(NULL); 2290 return (0); 2291 } 2292 if (!nomatch && flagsa != flagsb) { 2293 failure_start(file, line, "File flags should be identical: " 2294 "%s=%#010x %s=%#010x", patha, flagsa, pathb, flagsb); 2295 failure_finish(NULL); 2296 return (0); 2297 } 2298 if (nomatch && flagsa == flagsb) { 2299 failure_start(file, line, "File flags should be different: " 2300 "%s=%#010x %s=%#010x", patha, flagsa, pathb, flagsb); 2301 failure_finish(NULL); 2302 return (0); 2303 } 2304 #else 2305 (void)patha; /* UNUSED */ 2306 (void)pathb; /* UNUSED */ 2307 (void)nomatch; /* UNUSED */ 2308 assertion_count(file, line); 2309 #endif 2310 return (1); 2311 } 2312 2313 /* Set nodump, report failures. */ 2314 int 2315 assertion_set_nodump(const char *file, int line, const char *pathname) 2316 { 2317 #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) 2318 int r; 2319 2320 assertion_count(file, line); 2321 r = chflags(pathname, UF_NODUMP); 2322 if (r < 0) { 2323 failure_start(file, line, "Can't set nodump %s\n", pathname); 2324 failure_finish(NULL); 2325 return (0); 2326 } 2327 #elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS) && \ 2328 defined(FS_NODUMP_FL)) || \ 2329 (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) \ 2330 && defined(EXT2_NODUMP_FL)) 2331 int fd, r, flags; 2332 2333 assertion_count(file, line); 2334 fd = open(pathname, O_RDONLY | O_NONBLOCK); 2335 if (fd < 0) { 2336 failure_start(file, line, "Can't open %s\n", pathname); 2337 failure_finish(NULL); 2338 return (0); 2339 } 2340 r = ioctl(fd, 2341 #ifdef FS_IOC_GETFLAGS 2342 FS_IOC_GETFLAGS, 2343 #else 2344 EXT2_IOC_GETFLAGS, 2345 #endif 2346 &flags); 2347 if (r < 0) { 2348 failure_start(file, line, "Can't get flags %s\n", pathname); 2349 failure_finish(NULL); 2350 return (0); 2351 } 2352 #ifdef FS_NODUMP_FL 2353 flags |= FS_NODUMP_FL; 2354 #else 2355 flags |= EXT2_NODUMP_FL; 2356 #endif 2357 2358 r = ioctl(fd, 2359 #ifdef FS_IOC_SETFLAGS 2360 FS_IOC_SETFLAGS, 2361 #else 2362 EXT2_IOC_SETFLAGS, 2363 #endif 2364 &flags); 2365 if (r < 0) { 2366 failure_start(file, line, "Can't set nodump %s\n", pathname); 2367 failure_finish(NULL); 2368 return (0); 2369 } 2370 close(fd); 2371 #else 2372 (void)pathname; /* UNUSED */ 2373 assertion_count(file, line); 2374 #endif 2375 return (1); 2376 } 2377 2378 #ifdef PROGRAM 2379 static void assert_version_id(char **qq, size_t *ss) 2380 { 2381 char *q = *qq; 2382 size_t s = *ss; 2383 2384 /* Version number is a series of digits and periods. */ 2385 while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) { 2386 ++q; 2387 --s; 2388 } 2389 2390 if (q[0] == 'd' && q[1] == 'e' && q[2] == 'v') { 2391 q += 3; 2392 s -= 3; 2393 } 2394 2395 /* Skip a single trailing a,b,c, or d. */ 2396 if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd') 2397 ++q; 2398 2399 /* Version number terminated by space. */ 2400 failure("No space after version: ``%s''", q); 2401 assert(s > 1); 2402 failure("No space after version: ``%s''", q); 2403 assert(*q == ' '); 2404 2405 ++q; --s; 2406 2407 *qq = q; 2408 *ss = s; 2409 } 2410 2411 2412 /* 2413 * Check program version 2414 */ 2415 void assertVersion(const char *prog, const char *base) 2416 { 2417 int r; 2418 char *p, *q; 2419 size_t s; 2420 size_t prog_len = strlen(base); 2421 2422 r = systemf("%s --version >version.stdout 2>version.stderr", prog); 2423 if (r != 0) 2424 r = systemf("%s -W version >version.stdout 2>version.stderr", 2425 prog); 2426 2427 failure("Unable to run either %s --version or %s -W version", 2428 prog, prog); 2429 if (!assert(r == 0)) 2430 return; 2431 2432 /* --version should generate nothing to stdout. */ 2433 assertEmptyFile("version.stderr"); 2434 2435 /* Verify format of version message. */ 2436 q = p = slurpfile(&s, "version.stdout"); 2437 2438 /* Version message should start with name of program, then space. */ 2439 assert(s > prog_len + 1); 2440 2441 failure("Version must start with '%s': ``%s''", base, p); 2442 if (!assertEqualMem(q, base, prog_len)) { 2443 free(p); 2444 return; 2445 } 2446 2447 q += prog_len; s -= prog_len; 2448 2449 assert(*q == ' '); 2450 q++; s--; 2451 2452 assert_version_id(&q, &s); 2453 2454 /* Separator. */ 2455 failure("No `-' between program name and versions: ``%s''", p); 2456 assertEqualMem(q, "- ", 2); 2457 q += 2; s -= 2; 2458 2459 failure("Not long enough for libarchive version: ``%s''", p); 2460 assert(s > 11); 2461 2462 failure("Libarchive version must start with `libarchive': ``%s''", p); 2463 assertEqualMem(q, "libarchive ", 11); 2464 2465 q += 11; s -= 11; 2466 2467 assert_version_id(&q, &s); 2468 2469 /* Skip arbitrary third-party version numbers. */ 2470 while (s > 0 && (*q == ' ' || *q == '-' || *q == '/' || *q == '.' || 2471 *q == '_' || isalnum((unsigned char)*q))) { 2472 ++q; 2473 --s; 2474 } 2475 2476 /* All terminated by end-of-line. */ 2477 assert(s >= 1); 2478 2479 /* Skip an optional CR character (e.g., Windows) */ 2480 failure("Version output must end with \\n or \\r\\n"); 2481 2482 if (*q == '\r') { ++q; --s; } 2483 assertEqualMem(q, "\n", 1); 2484 2485 free(p); 2486 } 2487 #endif /* PROGRAM */ 2488 2489 /* 2490 * 2491 * UTILITIES for use by tests. 2492 * 2493 */ 2494 2495 /* 2496 * Check whether platform supports symlinks. This is intended 2497 * for tests to use in deciding whether to bother testing symlink 2498 * support; if the platform doesn't support symlinks, there's no point 2499 * in checking whether the program being tested can create them. 2500 * 2501 * Note that the first time this test is called, we actually go out to 2502 * disk to create and verify a symlink. This is necessary because 2503 * symlink support is actually a property of a particular filesystem 2504 * and can thus vary between directories on a single system. After 2505 * the first call, this returns the cached result from memory, so it's 2506 * safe to call it as often as you wish. 2507 */ 2508 int 2509 canSymlink(void) 2510 { 2511 /* Remember the test result */ 2512 static int value = 0, tested = 0; 2513 if (tested) 2514 return (value); 2515 2516 ++tested; 2517 assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a"); 2518 /* Note: Cygwin has its own symlink() emulation that does not 2519 * use the Win32 CreateSymbolicLink() function. */ 2520 #if defined(_WIN32) && !defined(__CYGWIN__) 2521 value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0) 2522 && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0", 2523 0); 2524 #elif HAVE_SYMLINK 2525 value = (0 == symlink("canSymlink.0", "canSymlink.1")) 2526 && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0", 2527 0); 2528 #endif 2529 return (value); 2530 } 2531 2532 /* Platform-dependent options for hiding the output of a subcommand. */ 2533 #if defined(_WIN32) && !defined(__CYGWIN__) 2534 static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */ 2535 #else 2536 static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */ 2537 #endif 2538 2539 /* 2540 * Can this platform run the specified command? 2541 */ 2542 int 2543 canRunCommand(const char *cmd, int *tested) 2544 { 2545 int value = tested ? *tested : 0; 2546 if (!value) { 2547 value = systemf("%s %s", cmd, redirectArgs) ? -1 : +1; 2548 if (tested) 2549 *tested = value; 2550 } 2551 return (value > 0); 2552 } 2553 2554 #define CAN_RUN_FUNC(Program, Command) \ 2555 int can##Program(void) { \ 2556 static int tested = 0; \ 2557 return canRunCommand((Command), &tested); \ 2558 } 2559 2560 /* 2561 * Can this platform run the bzip2 program? 2562 */ 2563 CAN_RUN_FUNC(Bzip2, "bzip2 --help") 2564 2565 /* 2566 * Can this platform run the grzip program? 2567 */ 2568 CAN_RUN_FUNC(Grzip, "grzip -V") 2569 2570 /* 2571 * Can this platform run the gzip program? 2572 */ 2573 CAN_RUN_FUNC(Gzip, "gzip --help") 2574 2575 /* 2576 * Can this platform run the lrzip program? 2577 */ 2578 CAN_RUN_FUNC(Lrzip, "lrzip -V") 2579 2580 /* 2581 * Can this platform run the lz4 program? 2582 */ 2583 CAN_RUN_FUNC(Lz4, "lz4 --help") 2584 2585 /* 2586 * Can this platform run the zstd program? 2587 */ 2588 CAN_RUN_FUNC(Zstd, "zstd --help") 2589 2590 /* 2591 * Can this platform run the lzip program? 2592 */ 2593 CAN_RUN_FUNC(Lzip, "lzip --help") 2594 2595 /* 2596 * Can this platform run the lzma program? 2597 */ 2598 CAN_RUN_FUNC(Lzma, "lzma --help") 2599 2600 /* 2601 * Can this platform run the lzop program? 2602 */ 2603 CAN_RUN_FUNC(Lzop, "lzop --help") 2604 2605 /* 2606 * Can this platform run the xz program? 2607 */ 2608 CAN_RUN_FUNC(Xz, "xz --help") 2609 2610 /* 2611 * Can this filesystem handle nodump flags. 2612 */ 2613 int 2614 canNodump(void) 2615 { 2616 #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) 2617 const char *path = "cannodumptest"; 2618 struct stat sb; 2619 2620 assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); 2621 if (chflags(path, UF_NODUMP) < 0) 2622 return (0); 2623 if (stat(path, &sb) < 0) 2624 return (0); 2625 if (sb.st_flags & UF_NODUMP) 2626 return (1); 2627 #elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS) \ 2628 && defined(FS_NODUMP_FL)) || \ 2629 (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) \ 2630 && defined(EXT2_NODUMP_FL)) 2631 const char *path = "cannodumptest"; 2632 int fd, r, flags; 2633 2634 assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); 2635 fd = open(path, O_RDONLY | O_NONBLOCK); 2636 if (fd < 0) 2637 return (0); 2638 r = ioctl(fd, 2639 #ifdef FS_IOC_GETFLAGS 2640 FS_IOC_GETFLAGS, 2641 #else 2642 EXT2_IOC_GETFLAGS, 2643 #endif 2644 &flags); 2645 if (r < 0) 2646 return (0); 2647 #ifdef FS_NODUMP_FL 2648 flags |= FS_NODUMP_FL; 2649 #else 2650 flags |= EXT2_NODUMP_FL; 2651 #endif 2652 r = ioctl(fd, 2653 #ifdef FS_IOC_SETFLAGS 2654 FS_IOC_SETFLAGS, 2655 #else 2656 EXT2_IOC_SETFLAGS, 2657 #endif 2658 &flags); 2659 if (r < 0) 2660 return (0); 2661 close(fd); 2662 fd = open(path, O_RDONLY | O_NONBLOCK); 2663 if (fd < 0) 2664 return (0); 2665 r = ioctl(fd, 2666 #ifdef FS_IOC_GETFLAGS 2667 FS_IOC_GETFLAGS, 2668 #else 2669 EXT2_IOC_GETFLAGS, 2670 #endif 2671 &flags); 2672 if (r < 0) 2673 return (0); 2674 close(fd); 2675 #ifdef FS_NODUMP_FL 2676 if (flags & FS_NODUMP_FL) 2677 #else 2678 if (flags & EXT2_NODUMP_FL) 2679 #endif 2680 return (1); 2681 #endif 2682 return (0); 2683 } 2684 2685 /* Get extended attribute value from a path */ 2686 void * 2687 getXattr(const char *path, const char *name, size_t *sizep) 2688 { 2689 void *value = NULL; 2690 #if ARCHIVE_XATTR_SUPPORT 2691 ssize_t size; 2692 #if ARCHIVE_XATTR_LINUX 2693 size = lgetxattr(path, name, NULL, 0); 2694 #elif ARCHIVE_XATTR_DARWIN 2695 size = getxattr(path, name, NULL, 0, 0, XATTR_NOFOLLOW); 2696 #elif ARCHIVE_XATTR_AIX 2697 size = lgetea(path, name, NULL, 0); 2698 #elif ARCHIVE_XATTR_FREEBSD 2699 size = extattr_get_link(path, EXTATTR_NAMESPACE_USER, name + 5, 2700 NULL, 0); 2701 #endif 2702 2703 if (size >= 0) { 2704 value = malloc(size); 2705 #if ARCHIVE_XATTR_LINUX 2706 size = lgetxattr(path, name, value, size); 2707 #elif ARCHIVE_XATTR_DARWIN 2708 size = getxattr(path, name, value, size, 0, XATTR_NOFOLLOW); 2709 #elif ARCHIVE_XATTR_AIX 2710 size = lgetea(path, name, value, size); 2711 #elif ARCHIVE_XATTR_FREEBSD 2712 size = extattr_get_link(path, EXTATTR_NAMESPACE_USER, name + 5, 2713 value, size); 2714 #endif 2715 if (size < 0) { 2716 free(value); 2717 value = NULL; 2718 } 2719 } 2720 if (size < 0) 2721 *sizep = 0; 2722 else 2723 *sizep = (size_t)size; 2724 #else /* !ARCHIVE_XATTR_SUPPORT */ 2725 (void)path; /* UNUSED */ 2726 (void)name; /* UNUSED */ 2727 *sizep = 0; 2728 #endif /* !ARCHIVE_XATTR_SUPPORT */ 2729 return (value); 2730 } 2731 2732 /* 2733 * Set extended attribute on a path 2734 * Returns 0 on error, 1 on success 2735 */ 2736 int 2737 setXattr(const char *path, const char *name, const void *value, size_t size) 2738 { 2739 #if ARCHIVE_XATTR_SUPPORT 2740 #if ARCHIVE_XATTR_LINUX 2741 if (lsetxattr(path, name, value, size, 0) == 0) 2742 #elif ARCHIVE_XATTR_DARWIN 2743 if (setxattr(path, name, value, size, 0, XATTR_NOFOLLOW) == 0) 2744 #elif ARCHIVE_XATTR_AIX 2745 if (lsetea(path, name, value, size, 0) == 0) 2746 #elif ARCHIVE_XATTR_FREEBSD 2747 if (extattr_set_link(path, EXTATTR_NAMESPACE_USER, name + 5, value, 2748 size) > -1) 2749 #else 2750 if (0) 2751 #endif 2752 return (1); 2753 #else /* !ARCHIVE_XATTR_SUPPORT */ 2754 (void)path; /* UNUSED */ 2755 (void)name; /* UNUSED */ 2756 (void)value; /* UNUSED */ 2757 (void)size; /* UNUSED */ 2758 #endif /* !ARCHIVE_XATTR_SUPPORT */ 2759 return (0); 2760 } 2761 2762 #if ARCHIVE_ACL_SUNOS 2763 /* Fetch ACLs on Solaris using acl() or facl() */ 2764 void * 2765 sunacl_get(int cmd, int *aclcnt, int fd, const char *path) 2766 { 2767 int cnt, cntcmd; 2768 size_t size; 2769 void *aclp; 2770 2771 if (cmd == GETACL) { 2772 cntcmd = GETACLCNT; 2773 size = sizeof(aclent_t); 2774 } 2775 #if ARCHIVE_ACL_SUNOS_NFS4 2776 else if (cmd == ACE_GETACL) { 2777 cntcmd = ACE_GETACLCNT; 2778 size = sizeof(ace_t); 2779 } 2780 #endif 2781 else { 2782 errno = EINVAL; 2783 *aclcnt = -1; 2784 return (NULL); 2785 } 2786 2787 aclp = NULL; 2788 cnt = -2; 2789 while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) { 2790 if (path != NULL) 2791 cnt = acl(path, cntcmd, 0, NULL); 2792 else 2793 cnt = facl(fd, cntcmd, 0, NULL); 2794 2795 if (cnt > 0) { 2796 if (aclp == NULL) 2797 aclp = malloc(cnt * size); 2798 else 2799 aclp = realloc(NULL, cnt * size); 2800 if (aclp != NULL) { 2801 if (path != NULL) 2802 cnt = acl(path, cmd, cnt, aclp); 2803 else 2804 cnt = facl(fd, cmd, cnt, aclp); 2805 } 2806 } else { 2807 free(aclp); 2808 aclp = NULL; 2809 break; 2810 } 2811 } 2812 2813 *aclcnt = cnt; 2814 return (aclp); 2815 } 2816 #endif /* ARCHIVE_ACL_SUNOS */ 2817 2818 /* 2819 * Set test ACLs on a path 2820 * Return values: 2821 * 0: error setting ACLs 2822 * ARCHIVE_TEST_ACL_TYPE_POSIX1E: POSIX.1E ACLs have been set 2823 * ARCHIVE_TEST_ACL_TYPE_NFS4: NFSv4 or extended ACLs have been set 2824 */ 2825 int 2826 setTestAcl(const char *path) 2827 { 2828 #if ARCHIVE_ACL_SUPPORT 2829 int r = 1; 2830 #if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_DARWIN 2831 acl_t acl; 2832 #endif 2833 #if ARCHIVE_ACL_LIBRICHACL 2834 struct richacl *richacl; 2835 #endif 2836 #if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD 2837 const char *acltext_posix1e = "user:1:rw-," 2838 "group:15:r-x," 2839 "user::rwx," 2840 "group::rwx," 2841 "other::r-x," 2842 "mask::rwx"; 2843 #elif ARCHIVE_ACL_SUNOS /* Solaris POSIX.1e */ 2844 aclent_t aclp_posix1e[] = { 2845 { USER_OBJ, -1, 4 | 2 | 1 }, 2846 { USER, 1, 4 | 2 }, 2847 { GROUP_OBJ, -1, 4 | 2 | 1 }, 2848 { GROUP, 15, 4 | 1 }, 2849 { CLASS_OBJ, -1, 4 | 2 | 1 }, 2850 { OTHER_OBJ, -1, 4 | 2 | 1 } 2851 }; 2852 #endif 2853 #if ARCHIVE_ACL_FREEBSD /* FreeBSD NFS4 */ 2854 const char *acltext_nfs4 = "user:1:rwpaRcs::allow:1," 2855 "group:15:rxaRcs::allow:15," 2856 "owner@:rwpxaARWcCos::allow," 2857 "group@:rwpxaRcs::allow," 2858 "everyone@:rxaRcs::allow"; 2859 #elif ARCHIVE_ACL_LIBRICHACL 2860 const char *acltext_nfs4 = "owner:rwpxaARWcCoS::mask," 2861 "group:rwpxaRcS::mask," 2862 "other:rxaRcS::mask," 2863 "user:1:rwpaRcS::allow," 2864 "group:15:rxaRcS::allow," 2865 "owner@:rwpxaARWcCoS::allow," 2866 "group@:rwpxaRcS::allow," 2867 "everyone@:rxaRcS::allow"; 2868 #elif ARCHIVE_ACL_SUNOS_NFS4 /* Solaris NFS4 */ 2869 ace_t aclp_nfs4[] = { 2870 { 1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA | 2871 ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | ACE_READ_ACL | 2872 ACE_SYNCHRONIZE, 0, ACE_ACCESS_ALLOWED_ACE_TYPE }, 2873 { 15, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES | 2874 ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE, 2875 ACE_IDENTIFIER_GROUP, ACE_ACCESS_ALLOWED_ACE_TYPE }, 2876 { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA | 2877 ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_WRITE_ATTRIBUTES | 2878 ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS | 2879 ACE_READ_ACL | ACE_WRITE_ACL | ACE_WRITE_OWNER | ACE_SYNCHRONIZE, 2880 ACE_OWNER, ACE_ACCESS_ALLOWED_ACE_TYPE }, 2881 { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA | 2882 ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | 2883 ACE_READ_ACL | ACE_SYNCHRONIZE, ACE_GROUP | ACE_IDENTIFIER_GROUP, 2884 ACE_ACCESS_ALLOWED_ACE_TYPE }, 2885 { -1, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES | 2886 ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE, 2887 ACE_EVERYONE, ACE_ACCESS_ALLOWED_ACE_TYPE } 2888 }; 2889 #elif ARCHIVE_ACL_DARWIN /* Mac OS X */ 2890 acl_entry_t aclent; 2891 acl_permset_t permset; 2892 const uid_t uid = 1; 2893 uuid_t uuid; 2894 const acl_perm_t acl_perms[] = { 2895 ACL_READ_DATA, 2896 ACL_WRITE_DATA, 2897 ACL_APPEND_DATA, 2898 ACL_EXECUTE, 2899 ACL_READ_ATTRIBUTES, 2900 ACL_READ_EXTATTRIBUTES, 2901 ACL_READ_SECURITY, 2902 #if HAVE_DECL_ACL_SYNCHRONIZE 2903 ACL_SYNCHRONIZE 2904 #endif 2905 }; 2906 #endif /* ARCHIVE_ACL_DARWIN */ 2907 2908 #if ARCHIVE_ACL_FREEBSD 2909 acl = acl_from_text(acltext_nfs4); 2910 failure("acl_from_text() error: %s", strerror(errno)); 2911 if (assert(acl != NULL) == 0) 2912 return (0); 2913 #elif ARCHIVE_ACL_LIBRICHACL 2914 richacl = richacl_from_text(acltext_nfs4, NULL, NULL); 2915 failure("richacl_from_text() error: %s", strerror(errno)); 2916 if (assert(richacl != NULL) == 0) 2917 return (0); 2918 #elif ARCHIVE_ACL_DARWIN 2919 acl = acl_init(1); 2920 failure("acl_init() error: %s", strerror(errno)); 2921 if (assert(acl != NULL) == 0) 2922 return (0); 2923 r = acl_create_entry(&acl, &aclent); 2924 failure("acl_create_entry() error: %s", strerror(errno)); 2925 if (assertEqualInt(r, 0) == 0) 2926 goto testacl_free; 2927 r = acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW); 2928 failure("acl_set_tag_type() error: %s", strerror(errno)); 2929 if (assertEqualInt(r, 0) == 0) 2930 goto testacl_free; 2931 r = acl_get_permset(aclent, &permset); 2932 failure("acl_get_permset() error: %s", strerror(errno)); 2933 if (assertEqualInt(r, 0) == 0) 2934 goto testacl_free; 2935 for (size_t i = 0; i < nitems(acl_perms); i++) { 2936 r = acl_add_perm(permset, acl_perms[i]); 2937 failure("acl_add_perm() error: %s", strerror(errno)); 2938 if (assertEqualInt(r, 0) == 0) 2939 goto testacl_free; 2940 } 2941 r = acl_set_permset(aclent, permset); 2942 failure("acl_set_permset() error: %s", strerror(errno)); 2943 if (assertEqualInt(r, 0) == 0) 2944 goto testacl_free; 2945 r = mbr_uid_to_uuid(uid, uuid); 2946 failure("mbr_uid_to_uuid() error: %s", strerror(errno)); 2947 if (assertEqualInt(r, 0) == 0) 2948 goto testacl_free; 2949 r = acl_set_qualifier(aclent, uuid); 2950 failure("acl_set_qualifier() error: %s", strerror(errno)); 2951 if (assertEqualInt(r, 0) == 0) 2952 goto testacl_free; 2953 #endif /* ARCHIVE_ACL_DARWIN */ 2954 2955 #if ARCHIVE_ACL_NFS4 2956 #if ARCHIVE_ACL_FREEBSD 2957 r = acl_set_file(path, ACL_TYPE_NFS4, acl); 2958 acl_free(acl); 2959 #elif ARCHIVE_ACL_LIBRICHACL 2960 r = richacl_set_file(path, richacl); 2961 richacl_free(richacl); 2962 #elif ARCHIVE_ACL_SUNOS_NFS4 2963 r = acl(path, ACE_SETACL, 2964 (int)(sizeof(aclp_nfs4)/sizeof(aclp_nfs4[0])), aclp_nfs4); 2965 #elif ARCHIVE_ACL_DARWIN 2966 r = acl_set_file(path, ACL_TYPE_EXTENDED, acl); 2967 acl_free(acl); 2968 #endif 2969 if (r == 0) 2970 return (ARCHIVE_TEST_ACL_TYPE_NFS4); 2971 #endif /* ARCHIVE_ACL_NFS4 */ 2972 2973 #if ARCHIVE_ACL_POSIX1E 2974 #if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_LIBACL 2975 acl = acl_from_text(acltext_posix1e); 2976 failure("acl_from_text() error: %s", strerror(errno)); 2977 if (assert(acl != NULL) == 0) 2978 return (0); 2979 2980 r = acl_set_file(path, ACL_TYPE_ACCESS, acl); 2981 acl_free(acl); 2982 #elif ARCHIVE_ACL_SUNOS 2983 r = acl(path, SETACL, 2984 (int)(sizeof(aclp_posix1e)/sizeof(aclp_posix1e[0])), aclp_posix1e); 2985 #endif 2986 if (r == 0) 2987 return (ARCHIVE_TEST_ACL_TYPE_POSIX1E); 2988 else 2989 return (0); 2990 #endif /* ARCHIVE_ACL_POSIX1E */ 2991 #if ARCHIVE_ACL_DARWIN 2992 testacl_free: 2993 acl_free(acl); 2994 #endif 2995 #endif /* ARCHIVE_ACL_SUPPORT */ 2996 (void)path; /* UNUSED */ 2997 return (0); 2998 } 2999 3000 /* 3001 * Sleep as needed; useful for verifying disk timestamp changes by 3002 * ensuring that the wall-clock time has actually changed before we 3003 * go back to re-read something from disk. 3004 */ 3005 void 3006 sleepUntilAfter(time_t t) 3007 { 3008 while (t >= time(NULL)) 3009 #if defined(_WIN32) && !defined(__CYGWIN__) 3010 Sleep(500); 3011 #else 3012 sleep(1); 3013 #endif 3014 } 3015 3016 /* 3017 * Call standard system() call, but build up the command line using 3018 * sprintf() conventions. 3019 */ 3020 int 3021 systemf(const char *fmt, ...) 3022 { 3023 char buff[8192]; 3024 #if USE_POSIX_SPAWN 3025 char *argv[] = { "/bin/sh", "-c", buff, NULL }; 3026 pid_t pid; 3027 #endif 3028 va_list ap; 3029 int r; 3030 3031 va_start(ap, fmt); 3032 vsnprintf(buff, sizeof(buff), fmt, ap); 3033 va_end(ap); 3034 if (verbosity > VERBOSITY_FULL) 3035 logprintf("Cmd: %s\n", buff); 3036 #if USE_POSIX_SPAWN 3037 if ((r = posix_spawn(&pid, *argv, NULL, NULL, argv, environ)) == 0) { 3038 while (waitpid(pid, &r, 0) == -1) { 3039 if (errno != EINTR) 3040 return (-1); 3041 } 3042 } 3043 #else 3044 r = system(buff); 3045 #endif 3046 return (r); 3047 } 3048 3049 /* 3050 * Slurp a file into memory for ease of comparison and testing. 3051 * Returns size of file in 'sizep' if non-NULL, null-terminates 3052 * data in memory for ease of use. 3053 */ 3054 char * 3055 slurpfile(size_t * sizep, const char *fmt, ...) 3056 { 3057 char filename[8192]; 3058 struct stat st; 3059 va_list ap; 3060 char *p; 3061 ssize_t bytes_read; 3062 FILE *f; 3063 int r; 3064 3065 va_start(ap, fmt); 3066 vsnprintf(filename, sizeof(filename), fmt, ap); 3067 va_end(ap); 3068 3069 f = fopen(filename, "rb"); 3070 if (f == NULL) { 3071 /* Note: No error; non-existent file is okay here. */ 3072 return (NULL); 3073 } 3074 r = fstat(fileno(f), &st); 3075 if (r != 0) { 3076 logprintf("Can't stat file %s\n", filename); 3077 fclose(f); 3078 return (NULL); 3079 } 3080 p = malloc((size_t)st.st_size + 1); 3081 if (p == NULL) { 3082 logprintf("Can't allocate %ld bytes of memory to read file %s\n", 3083 (long int)st.st_size, filename); 3084 fclose(f); 3085 return (NULL); 3086 } 3087 bytes_read = fread(p, 1, (size_t)st.st_size, f); 3088 if (bytes_read < st.st_size) { 3089 logprintf("Can't read file %s\n", filename); 3090 fclose(f); 3091 free(p); 3092 return (NULL); 3093 } 3094 p[st.st_size] = '\0'; 3095 if (sizep != NULL) 3096 *sizep = (size_t)st.st_size; 3097 fclose(f); 3098 return (p); 3099 } 3100 3101 /* 3102 * Slurp a file into memory for ease of comparison and testing. 3103 * Returns size of file in 'sizep' if non-NULL, null-terminates 3104 * data in memory for ease of use. 3105 */ 3106 void 3107 dumpfile(const char *filename, void *data, size_t len) 3108 { 3109 ssize_t bytes_written; 3110 FILE *f; 3111 3112 f = fopen(filename, "wb"); 3113 if (f == NULL) { 3114 logprintf("Can't open file %s for writing\n", filename); 3115 return; 3116 } 3117 bytes_written = fwrite(data, 1, len, f); 3118 if (bytes_written < (ssize_t)len) 3119 logprintf("Can't write file %s\n", filename); 3120 fclose(f); 3121 } 3122 3123 /* Read a uuencoded file from the reference directory, decode, and 3124 * write the result into the current directory. */ 3125 #define VALID_UUDECODE(c) (c >= 32 && c <= 96) 3126 #define UUDECODE(c) (((c) - 0x20) & 0x3f) 3127 void 3128 extract_reference_file(const char *name) 3129 { 3130 char buff[1024]; 3131 FILE *in, *out; 3132 3133 snprintf(buff, sizeof(buff), "%s/%s.uu", refdir, name); 3134 in = fopen(buff, "r"); 3135 failure("Couldn't open reference file %s", buff); 3136 assert(in != NULL); 3137 if (in == NULL) 3138 return; 3139 /* Read up to and including the 'begin' line. */ 3140 for (;;) { 3141 if (fgets(buff, sizeof(buff), in) == NULL) { 3142 /* TODO: This is a failure. */ 3143 return; 3144 } 3145 if (memcmp(buff, "begin ", 6) == 0) 3146 break; 3147 } 3148 /* Now, decode the rest and write it. */ 3149 out = fopen(name, "wb"); 3150 while (fgets(buff, sizeof(buff), in) != NULL) { 3151 char *p = buff; 3152 int bytes; 3153 3154 if (memcmp(buff, "end", 3) == 0) 3155 break; 3156 3157 bytes = UUDECODE(*p++); 3158 while (bytes > 0) { 3159 int n = 0; 3160 /* Write out 1-3 bytes from that. */ 3161 assert(VALID_UUDECODE(p[0])); 3162 assert(VALID_UUDECODE(p[1])); 3163 n = UUDECODE(*p++) << 18; 3164 n |= UUDECODE(*p++) << 12; 3165 fputc(n >> 16, out); 3166 --bytes; 3167 if (bytes > 0) { 3168 assert(VALID_UUDECODE(p[0])); 3169 n |= UUDECODE(*p++) << 6; 3170 fputc((n >> 8) & 0xFF, out); 3171 --bytes; 3172 } 3173 if (bytes > 0) { 3174 assert(VALID_UUDECODE(p[0])); 3175 n |= UUDECODE(*p++); 3176 fputc(n & 0xFF, out); 3177 --bytes; 3178 } 3179 } 3180 } 3181 fclose(out); 3182 fclose(in); 3183 } 3184 3185 void 3186 copy_reference_file(const char *name) 3187 { 3188 char buff[1024]; 3189 FILE *in, *out; 3190 size_t rbytes; 3191 3192 snprintf(buff, sizeof(buff), "%s/%s", refdir, name); 3193 in = fopen(buff, "rb"); 3194 failure("Couldn't open reference file %s", buff); 3195 assert(in != NULL); 3196 if (in == NULL) 3197 return; 3198 /* Now, decode the rest and write it. */ 3199 /* Not a lot of error checking here; the input better be right. */ 3200 out = fopen(name, "wb"); 3201 while ((rbytes = fread(buff, 1, sizeof(buff), in)) > 0) { 3202 if (fwrite(buff, 1, rbytes, out) != rbytes) { 3203 logprintf("Error: fwrite\n"); 3204 break; 3205 } 3206 } 3207 fclose(out); 3208 fclose(in); 3209 } 3210 3211 int 3212 is_LargeInode(const char *file) 3213 { 3214 #if defined(_WIN32) && !defined(__CYGWIN__) 3215 BY_HANDLE_FILE_INFORMATION bhfi; 3216 int r; 3217 3218 r = my_GetFileInformationByName(file, &bhfi); 3219 if (r != 0) 3220 return (0); 3221 return (bhfi.nFileIndexHigh & 0x0000FFFFUL); 3222 #else 3223 struct stat st; 3224 int64_t ino; 3225 3226 if (stat(file, &st) < 0) 3227 return (0); 3228 ino = (int64_t)st.st_ino; 3229 return (ino > 0xffffffff); 3230 #endif 3231 } 3232 3233 void 3234 extract_reference_files(const char **names) 3235 { 3236 while (names && *names) 3237 extract_reference_file(*names++); 3238 } 3239 3240 #ifndef PROGRAM 3241 /* Set ACLs */ 3242 int 3243 assertion_entry_set_acls(const char *file, int line, struct archive_entry *ae, 3244 struct archive_test_acl_t *acls, int n) 3245 { 3246 int i, r, ret; 3247 3248 assertion_count(file, line); 3249 3250 ret = 0; 3251 archive_entry_acl_clear(ae); 3252 for (i = 0; i < n; i++) { 3253 r = archive_entry_acl_add_entry(ae, 3254 acls[i].type, acls[i].permset, acls[i].tag, 3255 acls[i].qual, acls[i].name); 3256 if (r != 0) { 3257 ret = 1; 3258 failure_start(file, line, "type=%#010x, " 3259 "permset=%#010x, tag=%d, qual=%d name=%s", 3260 (unsigned int)acls[i].type, 3261 (unsigned int)acls[i].permset, acls[i].tag, 3262 acls[i].qual, acls[i].name); 3263 failure_finish(NULL); 3264 } 3265 } 3266 3267 return (ret); 3268 } 3269 3270 static int 3271 archive_test_acl_match(struct archive_test_acl_t *acl, int type, int permset, 3272 int tag, int qual, const char *name) 3273 { 3274 if (type != acl->type) 3275 return (0); 3276 if (permset != acl->permset) 3277 return (0); 3278 if (tag != acl->tag) 3279 return (0); 3280 if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 3281 return (1); 3282 if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) 3283 return (1); 3284 if (tag == ARCHIVE_ENTRY_ACL_EVERYONE) 3285 return (1); 3286 if (tag == ARCHIVE_ENTRY_ACL_OTHER) 3287 return (1); 3288 if (qual != acl->qual) 3289 return (0); 3290 if (name == NULL) { 3291 if (acl->name == NULL || acl->name[0] == '\0') 3292 return (1); 3293 return (0); 3294 } 3295 if (acl->name == NULL) { 3296 if (name[0] == '\0') 3297 return (1); 3298 return (0); 3299 } 3300 return (0 == strcmp(name, acl->name)); 3301 } 3302 3303 /* Compare ACLs */ 3304 int 3305 assertion_entry_compare_acls(const char *file, int line, 3306 struct archive_entry *ae, struct archive_test_acl_t *acls, int cnt, 3307 int want_type, int mode) 3308 { 3309 int *marker; 3310 int i, r, n, ret; 3311 int type, permset, tag, qual; 3312 int matched; 3313 const char *name; 3314 3315 assertion_count(file, line); 3316 3317 ret = 0; 3318 n = 0; 3319 marker = malloc(sizeof(marker[0]) * cnt); 3320 3321 for (i = 0; i < cnt; i++) { 3322 if ((acls[i].type & want_type) != 0) { 3323 marker[n] = i; 3324 n++; 3325 } 3326 } 3327 3328 if (n == 0) { 3329 failure_start(file, line, "No ACL's to compare, type mask: %d", 3330 want_type); 3331 return (1); 3332 } 3333 3334 while (0 == (r = archive_entry_acl_next(ae, want_type, 3335 &type, &permset, &tag, &qual, &name))) { 3336 for (i = 0, matched = 0; i < n && !matched; i++) { 3337 if (archive_test_acl_match(&acls[marker[i]], type, 3338 permset, tag, qual, name)) { 3339 /* We found a match; remove it. */ 3340 marker[i] = marker[n - 1]; 3341 n--; 3342 matched = 1; 3343 } 3344 } 3345 if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS 3346 && tag == ARCHIVE_ENTRY_ACL_USER_OBJ) { 3347 if (!matched) { 3348 failure_start(file, line, "No match for " 3349 "user_obj perm"); 3350 failure_finish(NULL); 3351 ret = 1; 3352 } 3353 if ((permset << 6) != (mode & 0700)) { 3354 failure_start(file, line, "USER_OBJ permset " 3355 "(%02o) != user mode (%02o)", 3356 (unsigned int)permset, 3357 (unsigned int)(07 & (mode >> 6))); 3358 failure_finish(NULL); 3359 ret = 1; 3360 } 3361 } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS 3362 && tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) { 3363 if (!matched) { 3364 failure_start(file, line, "No match for " 3365 "group_obj perm"); 3366 failure_finish(NULL); 3367 ret = 1; 3368 } 3369 if ((permset << 3) != (mode & 0070)) { 3370 failure_start(file, line, "GROUP_OBJ permset " 3371 "(%02o) != group mode (%02o)", 3372 (unsigned int)permset, 3373 (unsigned int)(07 & (mode >> 3))); 3374 failure_finish(NULL); 3375 ret = 1; 3376 } 3377 } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS 3378 && tag == ARCHIVE_ENTRY_ACL_OTHER) { 3379 if (!matched) { 3380 failure_start(file, line, "No match for " 3381 "other perm"); 3382 failure_finish(NULL); 3383 ret = 1; 3384 } 3385 if ((permset << 0) != (mode & 0007)) { 3386 failure_start(file, line, "OTHER permset " 3387 "(%02o) != other mode (%02o)", 3388 (unsigned int)permset, 3389 (unsigned int)mode & 07); 3390 failure_finish(NULL); 3391 ret = 1; 3392 } 3393 } else if (matched != 1) { 3394 failure_start(file, line, "Could not find match for " 3395 "ACL (type=%#010x,permset=%#010x,tag=%d,qual=%d," 3396 "name=``%s'')", (unsigned int)type, 3397 (unsigned int)permset, tag, qual, name); 3398 failure_finish(NULL); 3399 ret = 1; 3400 } 3401 } 3402 if (r != ARCHIVE_EOF) { 3403 failure_start(file, line, "Should not exit before EOF"); 3404 failure_finish(NULL); 3405 ret = 1; 3406 } 3407 if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 && 3408 (mode_t)(mode & 0777) != (archive_entry_mode(ae) & 0777)) { 3409 failure_start(file, line, "Mode (%02o) and entry mode (%02o) " 3410 "mismatch", (unsigned int)mode, 3411 (unsigned int)archive_entry_mode(ae)); 3412 failure_finish(NULL); 3413 ret = 1; 3414 } 3415 if (n != 0) { 3416 failure_start(file, line, "Could not find match for ACL " 3417 "(type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s'')", 3418 (unsigned int)acls[marker[0]].type, 3419 (unsigned int)acls[marker[0]].permset, 3420 acls[marker[0]].tag, acls[marker[0]].qual, 3421 acls[marker[0]].name); 3422 failure_finish(NULL); 3423 ret = 1; 3424 /* Number of ACLs not matched should == 0 */ 3425 } 3426 free(marker); 3427 return (ret); 3428 } 3429 #endif /* !defined(PROGRAM) */ 3430 3431 /* 3432 * 3433 * TEST management 3434 * 3435 */ 3436 3437 /* 3438 * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has 3439 * a line like 3440 * DEFINE_TEST(test_function) 3441 * for each test. 3442 */ 3443 struct test_list_t 3444 { 3445 void (*func)(void); 3446 const char *name; 3447 int failures; 3448 }; 3449 3450 /* Use "list.h" to declare all of the test functions. */ 3451 #undef DEFINE_TEST 3452 #define DEFINE_TEST(name) void name(void); 3453 #include "list.h" 3454 3455 /* Use "list.h" to create a list of all tests (functions and names). */ 3456 #undef DEFINE_TEST 3457 #define DEFINE_TEST(n) { n, #n, 0 }, 3458 static struct test_list_t tests[] = { 3459 #include "list.h" 3460 }; 3461 3462 /* 3463 * Summarize repeated failures in the just-completed test. 3464 */ 3465 static void 3466 test_summarize(int failed, int skips_num) 3467 { 3468 unsigned int i; 3469 3470 switch (verbosity) { 3471 case VERBOSITY_SUMMARY_ONLY: 3472 printf(failed ? "E" : "."); 3473 fflush(stdout); 3474 break; 3475 case VERBOSITY_PASSFAIL: 3476 printf(failed ? "FAIL\n" : skips_num ? "skipped\n" : "ok\n"); 3477 break; 3478 } 3479 3480 log_console = (verbosity == VERBOSITY_LIGHT_REPORT); 3481 3482 for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) { 3483 if (failed_lines[i].count > 1 && !failed_lines[i].skip) 3484 logprintf("%s:%u: Summary: Failed %d times\n", 3485 failed_filename, i, failed_lines[i].count); 3486 } 3487 /* Clear the failure history for the next file. */ 3488 failed_filename = NULL; 3489 memset(failed_lines, 0, sizeof(failed_lines)); 3490 } 3491 3492 /* 3493 * Set or unset environment variable. 3494 */ 3495 static void 3496 set_environment(const char *key, const char *value) 3497 { 3498 3499 #if defined(_WIN32) && !defined(__CYGWIN__) 3500 if (!SetEnvironmentVariable(key, value)) { 3501 fprintf(stderr, "SetEnvironmentVariable failed with %d\n", 3502 (int)GetLastError()); 3503 } 3504 #else 3505 if (value == NULL) { 3506 if (unsetenv(key) == -1) 3507 fprintf(stderr, "unsetenv: %s\n", strerror(errno)); 3508 } else { 3509 if (setenv(key, value, 1) == -1) 3510 fprintf(stderr, "setenv: %s\n", strerror(errno)); 3511 } 3512 #endif 3513 } 3514 3515 /* 3516 * Enforce C locale for (sub)processes. 3517 */ 3518 static void 3519 set_c_locale(void) 3520 { 3521 static const char *lcs[] = { 3522 "LC_ADDRESS", 3523 "LC_ALL", 3524 "LC_COLLATE", 3525 "LC_CTYPE", 3526 "LC_IDENTIFICATION", 3527 "LC_MEASUREMENT", 3528 "LC_MESSAGES", 3529 "LC_MONETARY", 3530 "LC_NAME", 3531 "LC_NUMERIC", 3532 "LC_PAPER", 3533 "LC_TELEPHONE", 3534 "LC_TIME", 3535 NULL 3536 }; 3537 size_t i; 3538 3539 setlocale(LC_ALL, "C"); 3540 set_environment("LANG", "C"); 3541 for (i = 0; lcs[i] != NULL; i++) 3542 set_environment(lcs[i], NULL); 3543 } 3544 3545 /* 3546 * Actually run a single test, with appropriate setup and cleanup. 3547 */ 3548 static int 3549 test_run(int i, const char *tmpdir) 3550 { 3551 #ifdef PATH_MAX 3552 char workdir[PATH_MAX * 2]; 3553 #else 3554 char workdir[1024 * 2]; 3555 #endif 3556 char logfilename[256]; 3557 int failures_before = failures; 3558 int skips_before = skips; 3559 int tmp; 3560 mode_t oldumask; 3561 3562 switch (verbosity) { 3563 case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */ 3564 break; 3565 case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */ 3566 printf("%3d: %-64s", i, tests[i].name); 3567 fflush(stdout); 3568 break; 3569 default: /* Title of test, details will follow */ 3570 printf("%3d: %s\n", i, tests[i].name); 3571 } 3572 3573 /* Chdir to the top-level work directory. */ 3574 if (!assertChdir(tmpdir)) { 3575 fprintf(stderr, 3576 "ERROR: Can't chdir to top work dir %s\n", tmpdir); 3577 exit(1); 3578 } 3579 /* Create a log file for this test. */ 3580 tmp = snprintf(logfilename, sizeof(logfilename), "%s.log", tests[i].name); 3581 if (tmp < 0) { 3582 fprintf(stderr, 3583 "ERROR can't create %s.log: %s\n", 3584 tests[i].name, strerror(errno)); 3585 exit(1); 3586 } 3587 if ((size_t)tmp >= sizeof(logfilename)) { 3588 fprintf(stderr, 3589 "ERROR can't create %s.log: Name too long. " 3590 "Length %d; Max allowed length %zu\n", 3591 tests[i].name, tmp, sizeof(logfilename) - 1); 3592 exit(1); 3593 } 3594 logfile = fopen(logfilename, "w"); 3595 fprintf(logfile, "%s\n\n", tests[i].name); 3596 /* Chdir() to a work dir for this specific test. */ 3597 tmp = snprintf(workdir, 3598 sizeof(workdir), "%s/%s", tmpdir, tests[i].name); 3599 if (tmp < 0) { 3600 fprintf(stderr, 3601 "ERROR can't create %s/%s: %s\n", 3602 tmpdir, tests[i].name, strerror(errno)); 3603 exit(1); 3604 } 3605 if ((size_t)tmp >= sizeof(workdir)) { 3606 fprintf(stderr, 3607 "ERROR can't create %s/%s: Path too long. " 3608 "Length %d; Max allowed length %zu\n", 3609 tmpdir, tests[i].name, tmp, sizeof(workdir) - 1); 3610 exit(1); 3611 } 3612 testworkdir = workdir; 3613 if (!assertMakeDir(testworkdir, 0755) 3614 || !assertChdir(testworkdir)) { 3615 fprintf(stderr, 3616 "ERROR: Can't chdir to work dir %s\n", testworkdir); 3617 exit(1); 3618 } 3619 /* Explicitly reset the locale before each test. */ 3620 set_c_locale(); 3621 /* Record the umask before we run the test. */ 3622 umask(oldumask = umask(0)); 3623 /* 3624 * Run the actual test. 3625 */ 3626 (*tests[i].func)(); 3627 /* 3628 * Clean up and report afterwards. 3629 */ 3630 testworkdir = NULL; 3631 /* Restore umask */ 3632 umask(oldumask); 3633 /* Reset locale. */ 3634 set_c_locale(); 3635 /* Reset directory. */ 3636 if (!assertChdir(tmpdir)) { 3637 fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n", 3638 tmpdir); 3639 exit(1); 3640 } 3641 /* Report per-test summaries. */ 3642 tests[i].failures = failures - failures_before; 3643 test_summarize(tests[i].failures, skips - skips_before); 3644 /* Close the per-test log file. */ 3645 fclose(logfile); 3646 logfile = NULL; 3647 /* If there were no failures, we can remove the work dir and logfile. */ 3648 if (tests[i].failures == 0) { 3649 if (!keep_temp_files && assertChdir(tmpdir)) { 3650 #if defined(_WIN32) && !defined(__CYGWIN__) 3651 /* Make sure not to leave empty directories. 3652 * Sometimes a processing of closing files used by tests 3653 * is not done, then rmdir will be failed and it will 3654 * leave a empty test directory. So we should wait a few 3655 * seconds and retry rmdir. */ 3656 int r, t; 3657 for (t = 0; t < 10; t++) { 3658 if (t > 0) 3659 Sleep(1000); 3660 r = systemf("rmdir /S /Q %s", tests[i].name); 3661 if (r == 0) 3662 break; 3663 } 3664 systemf("del %s", logfilename); 3665 #else 3666 systemf("rm -rf %s", tests[i].name); 3667 systemf("rm %s", logfilename); 3668 #endif 3669 } 3670 } 3671 /* Return appropriate status. */ 3672 return (tests[i].failures); 3673 } 3674 3675 /* 3676 * 3677 * 3678 * MAIN and support routines. 3679 * 3680 * 3681 */ 3682 3683 static void 3684 usage(const char *program) 3685 { 3686 static const int limit = nitems(tests); 3687 int i; 3688 3689 printf("Usage: %s [options] <test> <test> ...\n", program); 3690 printf("Default is to run all tests.\n"); 3691 printf("Otherwise, specify the numbers of the tests you wish to run.\n"); 3692 printf("Options:\n"); 3693 printf(" -d Dump core after any failure, for debugging.\n"); 3694 printf(" -k Keep all temp files.\n"); 3695 printf(" Default: temp files for successful tests deleted.\n"); 3696 #ifdef PROGRAM 3697 printf(" -p <path> Path to executable to be tested.\n"); 3698 printf(" Default: path taken from " ENVBASE " environment variable.\n"); 3699 #endif 3700 printf(" -q Quiet.\n"); 3701 printf(" -r <dir> Path to dir containing reference files.\n"); 3702 printf(" Default: Current directory.\n"); 3703 printf(" -s Exit with code 2 if any tests were skipped.\n"); 3704 printf(" -u Keep running specified tests until one fails.\n"); 3705 printf(" -v Verbose.\n"); 3706 printf("Available tests:\n"); 3707 for (i = 0; i < limit; i++) 3708 printf(" %d: %s\n", i, tests[i].name); 3709 exit(1); 3710 } 3711 3712 static char * 3713 get_refdir(const char *d) 3714 { 3715 size_t tried_size, buff_size; 3716 char *buff, *tried, *pwd = NULL, *p = NULL; 3717 3718 #ifdef PATH_MAX 3719 buff_size = PATH_MAX; 3720 #else 3721 buff_size = 8192; 3722 #endif 3723 buff = calloc(buff_size, 1); 3724 if (buff == NULL) { 3725 fprintf(stderr, "Unable to allocate memory\n"); 3726 exit(1); 3727 } 3728 3729 /* Allocate a buffer to hold the various directories we checked. */ 3730 tried_size = buff_size * 2; 3731 tried = calloc(tried_size, 1); 3732 if (tried == NULL) { 3733 fprintf(stderr, "Unable to allocate memory\n"); 3734 exit(1); 3735 } 3736 3737 /* If a dir was specified, try that */ 3738 if (d != NULL) { 3739 pwd = NULL; 3740 snprintf(buff, buff_size, "%s", d); 3741 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3742 if (p != NULL) goto success; 3743 strncat(tried, buff, tried_size - strlen(tried) - 1); 3744 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3745 goto failure; 3746 } 3747 3748 /* Get the current dir. */ 3749 #if defined(PATH_MAX) && !defined(__GLIBC__) 3750 pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ 3751 #else 3752 pwd = getcwd(NULL, 0); 3753 #endif 3754 while (pwd[strlen(pwd) - 1] == '\n') 3755 pwd[strlen(pwd) - 1] = '\0'; 3756 3757 /* Look for a known file. */ 3758 snprintf(buff, buff_size, "%s", pwd); 3759 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3760 if (p != NULL) goto success; 3761 strncat(tried, buff, tried_size - strlen(tried) - 1); 3762 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3763 3764 snprintf(buff, buff_size, "%s/test", pwd); 3765 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3766 if (p != NULL) goto success; 3767 strncat(tried, buff, tried_size - strlen(tried) - 1); 3768 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3769 3770 #if defined(LIBRARY) 3771 snprintf(buff, buff_size, "%s/%s/test", pwd, LIBRARY); 3772 #else 3773 snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM); 3774 #endif 3775 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3776 if (p != NULL) goto success; 3777 strncat(tried, buff, tried_size - strlen(tried) - 1); 3778 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3779 3780 #if defined(PROGRAM_ALIAS) 3781 snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM_ALIAS); 3782 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3783 if (p != NULL) goto success; 3784 strncat(tried, buff, tried_size - strlen(tried) - 1); 3785 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3786 #endif 3787 3788 if (memcmp(pwd, "/usr/obj", 8) == 0) { 3789 snprintf(buff, buff_size, "%s", pwd + 8); 3790 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3791 if (p != NULL) goto success; 3792 strncat(tried, buff, tried_size - strlen(tried) - 1); 3793 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3794 3795 snprintf(buff, buff_size, "%s/test", pwd + 8); 3796 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3797 if (p != NULL) goto success; 3798 strncat(tried, buff, tried_size - strlen(tried) - 1); 3799 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3800 } 3801 3802 failure: 3803 printf("Unable to locate known reference file %s\n", KNOWNREF); 3804 printf(" Checked following directories:\n%s\n", tried); 3805 printf("Use -r option to specify full path to reference directory\n"); 3806 #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) 3807 DebugBreak(); 3808 #endif 3809 exit(1); 3810 3811 success: 3812 free(p); 3813 free(pwd); 3814 free(tried); 3815 3816 /* Copy result into a fresh buffer to reduce memory usage. */ 3817 p = strdup(buff); 3818 free(buff); 3819 return p; 3820 } 3821 3822 /* Filter tests against a glob pattern. Returns non-zero if test matches 3823 * pattern, zero otherwise. A '^' at the beginning of the pattern negates 3824 * the return values (i.e. returns zero for a match, non-zero otherwise. 3825 */ 3826 static int 3827 test_filter(const char *pattern, const char *test) 3828 { 3829 int retval = 0; 3830 int negate = 0; 3831 const char *p = pattern; 3832 const char *t = test; 3833 3834 if (p[0] == '^') 3835 { 3836 negate = 1; 3837 p++; 3838 } 3839 3840 while (1) 3841 { 3842 if (p[0] == '\\') 3843 p++; 3844 else if (p[0] == '*') 3845 { 3846 while (p[0] == '*') 3847 p++; 3848 if (p[0] == '\\') 3849 p++; 3850 if ((t = strchr(t, p[0])) == 0) 3851 break; 3852 } 3853 if (p[0] != t[0]) 3854 break; 3855 if (p[0] == '\0') { 3856 retval = 1; 3857 break; 3858 } 3859 p++; 3860 t++; 3861 } 3862 3863 return (negate) ? !retval : retval; 3864 } 3865 3866 static int 3867 get_test_set(int *test_set, int limit, const char *test) 3868 { 3869 int start, end; 3870 int idx = 0; 3871 3872 if (test == NULL) { 3873 /* Default: Run all tests. */ 3874 for (;idx < limit; idx++) 3875 test_set[idx] = idx; 3876 return (limit); 3877 } 3878 if (*test >= '0' && *test <= '9') { 3879 const char *vp = test; 3880 start = 0; 3881 while (*vp >= '0' && *vp <= '9') { 3882 start *= 10; 3883 start += *vp - '0'; 3884 ++vp; 3885 } 3886 if (*vp == '\0') { 3887 end = start; 3888 } else if (*vp == '-') { 3889 ++vp; 3890 if (*vp == '\0') { 3891 end = limit - 1; 3892 } else { 3893 end = 0; 3894 while (*vp >= '0' && *vp <= '9') { 3895 end *= 10; 3896 end += *vp - '0'; 3897 ++vp; 3898 } 3899 } 3900 } else 3901 return (-1); 3902 if (start < 0 || end >= limit || start > end) 3903 return (-1); 3904 while (start <= end) 3905 test_set[idx++] = start++; 3906 } else { 3907 for (start = 0; start < limit; ++start) { 3908 const char *name = tests[start].name; 3909 if (test_filter(test, name)) 3910 test_set[idx++] = start; 3911 } 3912 } 3913 return ((idx == 0)?-1:idx); 3914 } 3915 3916 int 3917 main(int argc, char **argv) 3918 { 3919 static const int limit = nitems(tests); 3920 int test_set[nitems(tests)]; 3921 int i = 0, j = 0, tests_run = 0, tests_failed = 0, option; 3922 size_t testprogdir_len; 3923 size_t tmplen; 3924 #ifdef PROGRAM 3925 size_t tmp2_len; 3926 #endif 3927 time_t now; 3928 struct tm *tmptr; 3929 #if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S) 3930 struct tm tmbuf; 3931 #endif 3932 char *refdir_alloc = NULL; 3933 const char *progname; 3934 char **saved_argv; 3935 const char *tmp, *option_arg, *p; 3936 #ifdef PATH_MAX 3937 char tmpdir[PATH_MAX]; 3938 #else 3939 char tmpdir[256]; 3940 #endif 3941 char *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL; 3942 char tmpdir_timestamp[32]; 3943 3944 (void)argc; /* UNUSED */ 3945 3946 /* Get the current dir. */ 3947 #if defined(PATH_MAX) && !defined(__GLIBC__) 3948 pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ 3949 #else 3950 pwd = getcwd(NULL, 0); 3951 #endif 3952 while (pwd[strlen(pwd) - 1] == '\n') 3953 pwd[strlen(pwd) - 1] = '\0'; 3954 3955 #if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__) 3956 /* To stop to run the default invalid parameter handler. */ 3957 _set_invalid_parameter_handler(invalid_parameter_handler); 3958 /* Disable annoying assertion message box. */ 3959 _CrtSetReportMode(_CRT_ASSERT, 0); 3960 #endif 3961 3962 /* 3963 * Name of this program, used to build root of our temp directory 3964 * tree. 3965 */ 3966 progname = p = argv[0]; 3967 testprogdir_len = strlen(progname) + 1; 3968 if ((testprogdir = malloc(testprogdir_len)) == NULL) 3969 { 3970 fprintf(stderr, "ERROR: Out of memory."); 3971 exit(1); 3972 } 3973 strncpy(testprogdir, progname, testprogdir_len); 3974 while (*p != '\0') { 3975 /* Support \ or / dir separators for Windows compat. */ 3976 if (*p == '/' || *p == '\\') 3977 { 3978 progname = p + 1; 3979 i = j; 3980 } 3981 ++p; 3982 j++; 3983 } 3984 testprogdir[i] = '\0'; 3985 #if defined(_WIN32) && !defined(__CYGWIN__) 3986 if (testprogdir[0] != '/' && testprogdir[0] != '\\' && 3987 !(((testprogdir[0] >= 'a' && testprogdir[0] <= 'z') || 3988 (testprogdir[0] >= 'A' && testprogdir[0] <= 'Z')) && 3989 testprogdir[1] == ':' && 3990 (testprogdir[2] == '/' || testprogdir[2] == '\\'))) 3991 #else 3992 if (testprogdir[0] != '/') 3993 #endif 3994 { 3995 /* Fixup path for relative directories. */ 3996 if ((testprogdir = realloc(testprogdir, 3997 strlen(pwd) + 1 + strlen(testprogdir) + 1)) == NULL) 3998 { 3999 fprintf(stderr, "ERROR: Out of memory."); 4000 exit(1); 4001 } 4002 memmove(testprogdir + strlen(pwd) + 1, testprogdir, 4003 strlen(testprogdir) + 1); 4004 memcpy(testprogdir, pwd, strlen(pwd)); 4005 testprogdir[strlen(pwd)] = '/'; 4006 } 4007 4008 #ifdef PROGRAM 4009 /* Get the target program from environment, if available. */ 4010 testprogfile = getenv(ENVBASE); 4011 #endif 4012 4013 if (getenv("TMPDIR") != NULL) 4014 tmp = getenv("TMPDIR"); 4015 else if (getenv("TMP") != NULL) 4016 tmp = getenv("TMP"); 4017 else if (getenv("TEMP") != NULL) 4018 tmp = getenv("TEMP"); 4019 else if (getenv("TEMPDIR") != NULL) 4020 tmp = getenv("TEMPDIR"); 4021 else 4022 tmp = "/tmp"; 4023 tmplen = strlen(tmp); 4024 while (tmplen > 0 && tmp[tmplen - 1] == '/') 4025 tmplen--; 4026 4027 /* Allow -d to be controlled through the environment. */ 4028 if (getenv(ENVBASE "_DEBUG") != NULL) 4029 dump_on_failure = 1; 4030 4031 /* Allow -v to be controlled through the environment. */ 4032 if (getenv("_VERBOSITY_LEVEL") != NULL) 4033 { 4034 vlevel = getenv("_VERBOSITY_LEVEL"); 4035 verbosity = atoi(vlevel); 4036 if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL) 4037 { 4038 /* Unsupported verbosity levels are silently ignored */ 4039 vlevel = NULL; 4040 verbosity = VERBOSITY_PASSFAIL; 4041 } 4042 } 4043 4044 /* Get the directory holding test files from environment. */ 4045 refdir = getenv(ENVBASE "_TEST_FILES"); 4046 4047 /* 4048 * Parse options, without using getopt(), which isn't available 4049 * on all platforms. 4050 */ 4051 ++argv; /* Skip program name */ 4052 while (*argv != NULL) { 4053 if (**argv != '-') 4054 break; 4055 p = *argv++; 4056 ++p; /* Skip '-' */ 4057 while (*p != '\0') { 4058 option = *p++; 4059 option_arg = NULL; 4060 /* If 'opt' takes an argument, parse that. */ 4061 if (option == 'p' || option == 'r') { 4062 if (*p != '\0') 4063 option_arg = p; 4064 else if (*argv == NULL) { 4065 fprintf(stderr, 4066 "Option -%c requires argument.\n", 4067 option); 4068 usage(progname); 4069 } else 4070 option_arg = *argv++; 4071 p = ""; /* End of this option word. */ 4072 } 4073 4074 /* Now, handle the option. */ 4075 switch (option) { 4076 case 'd': 4077 dump_on_failure = 1; 4078 break; 4079 case 'k': 4080 keep_temp_files = 1; 4081 break; 4082 case 'p': 4083 #ifdef PROGRAM 4084 testprogfile = option_arg; 4085 #else 4086 fprintf(stderr, "-p option not permitted\n"); 4087 usage(progname); 4088 #endif 4089 break; 4090 case 'q': 4091 if (!vlevel) 4092 verbosity--; 4093 break; 4094 case 'r': 4095 refdir = option_arg; 4096 break; 4097 case 's': 4098 fail_if_tests_skipped = 1; 4099 break; 4100 case 'u': 4101 until_failure++; 4102 break; 4103 case 'v': 4104 if (!vlevel) 4105 verbosity++; 4106 break; 4107 default: 4108 fprintf(stderr, "Unrecognized option '%c'\n", 4109 option); 4110 usage(progname); 4111 } 4112 } 4113 } 4114 4115 /* 4116 * Sanity-check that our options make sense. 4117 */ 4118 #ifdef PROGRAM 4119 if (testprogfile == NULL) 4120 { 4121 tmp2_len = strlen(testprogdir) + 1 + strlen(PROGRAM) + 1; 4122 #if defined(_WIN32) && !defined(__CYGWIN__) 4123 tmp2_len += 4; 4124 #endif 4125 if ((tmp2 = malloc(tmp2_len)) == NULL) 4126 { 4127 fprintf(stderr, "ERROR: Out of memory."); 4128 exit(1); 4129 } 4130 strncpy(tmp2, testprogdir, tmp2_len); 4131 strncat(tmp2, "/", tmp2_len); 4132 strncat(tmp2, PROGRAM, tmp2_len); 4133 #if defined(_WIN32) && !defined(__CYGWIN__) 4134 strncat(tmp2, ".exe", tmp2_len); 4135 #endif 4136 testprogfile = tmp2; 4137 } 4138 4139 { 4140 char *testprg; 4141 size_t testprg_len; 4142 #if defined(_WIN32) && !defined(__CYGWIN__) 4143 /* Command.com sometimes rejects '/' separators. */ 4144 testprg = strdup(testprogfile); 4145 for (i = 0; testprg[i] != '\0'; i++) { 4146 if (testprg[i] == '/') 4147 testprg[i] = '\\'; 4148 } 4149 testprogfile = testprg; 4150 #endif 4151 /* Quote the name that gets put into shell command lines. */ 4152 testprg_len = strlen(testprogfile) + 3; 4153 testprg = malloc(testprg_len); 4154 strncpy(testprg, "\"", testprg_len); 4155 strncat(testprg, testprogfile, testprg_len); 4156 strncat(testprg, "\"", testprg_len); 4157 testprog = testprg; 4158 } 4159 4160 /* Sanity check: reject a relative path for refdir. */ 4161 if (refdir != NULL) { 4162 #if defined(_WIN32) && !defined(__CYGWIN__) 4163 /* TODO: probably use PathIsRelative() from <shlwapi.h>. */ 4164 #else 4165 if (refdir[0] != '/') { 4166 fprintf(stderr, 4167 "ERROR: Cannot use relative path for refdir\n"); 4168 exit(1); 4169 } 4170 #endif 4171 } 4172 #endif 4173 4174 #if !defined(_WIN32) && defined(SIGPIPE) 4175 { /* Ignore SIGPIPE signals */ 4176 struct sigaction sa; 4177 sa.sa_handler = SIG_IGN; 4178 sigemptyset(&sa.sa_mask); 4179 sa.sa_flags = 0; 4180 sigaction(SIGPIPE, &sa, NULL); 4181 } 4182 #endif 4183 4184 /* 4185 * Create a temp directory for the following tests. 4186 * Include the time the tests started as part of the name, 4187 * to make it easier to track the results of multiple tests. 4188 */ 4189 now = time(NULL); 4190 for (i = 0; ; i++) { 4191 #if defined(HAVE_LOCALTIME_S) 4192 tmptr = localtime_s(&tmbuf, &now) ? NULL : &tmbuf; 4193 #elif defined(HAVE_LOCALTIME_R) 4194 tmptr = localtime_r(&now, &tmbuf); 4195 #else 4196 tmptr = localtime(&now); 4197 #endif 4198 strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp), 4199 "%Y-%m-%dT%H.%M.%S", tmptr); 4200 if (tmplen + 1 + strlen(progname) + 1 + 4201 strlen(tmpdir_timestamp) + 1 + 3 >= 4202 nitems(tmpdir)) { 4203 fprintf(stderr, 4204 "ERROR: Temp directory pathname too long\n"); 4205 exit(1); 4206 } 4207 snprintf(tmpdir, sizeof(tmpdir), "%.*s/%s.%s-%03d", 4208 (int)tmplen, tmp, progname, tmpdir_timestamp, i); 4209 if (assertMakeDir(tmpdir, 0755)) 4210 break; 4211 if (i >= 999) { 4212 fprintf(stderr, 4213 "ERROR: Unable to create temp directory %s\n", 4214 tmpdir); 4215 exit(1); 4216 } 4217 } 4218 4219 /* 4220 * If the user didn't specify a directory for locating 4221 * reference files, try to find the reference files in 4222 * the "usual places." 4223 */ 4224 refdir = refdir_alloc = get_refdir(refdir); 4225 4226 /* 4227 * Banner with basic information. 4228 */ 4229 printf("\n"); 4230 printf("If tests fail or crash, details will be in:\n"); 4231 printf(" %s\n", tmpdir); 4232 printf("\n"); 4233 if (verbosity > VERBOSITY_SUMMARY_ONLY) { 4234 printf("Reference files will be read from: %s\n", refdir); 4235 #ifdef PROGRAM 4236 printf("Running tests on: %s\n", testprog); 4237 #endif 4238 printf("Exercising: "); 4239 fflush(stdout); 4240 printf("%s\n", EXTRA_VERSION); 4241 } else { 4242 printf("Running "); 4243 fflush(stdout); 4244 } 4245 4246 /* 4247 * Run some or all of the individual tests. 4248 */ 4249 saved_argv = argv; 4250 do { 4251 argv = saved_argv; 4252 do { 4253 int test_num; 4254 4255 test_num = get_test_set(test_set, limit, *argv); 4256 if (test_num < 0) { 4257 printf("*** INVALID Test %s\n", *argv); 4258 free(refdir_alloc); 4259 free(testprogdir); 4260 usage(progname); 4261 } 4262 for (i = 0; i < test_num; i++) { 4263 tests_run++; 4264 if (test_run(test_set[i], tmpdir)) { 4265 tests_failed++; 4266 if (until_failure) 4267 goto finish; 4268 } 4269 } 4270 if (*argv != NULL) 4271 argv++; 4272 } while (*argv != NULL); 4273 } while (until_failure); 4274 4275 finish: 4276 /* Must be freed after all tests run */ 4277 free(tmp2); 4278 free(testprogdir); 4279 free(pwd); 4280 4281 /* 4282 * Report summary statistics. 4283 */ 4284 if (verbosity > VERBOSITY_SUMMARY_ONLY) { 4285 printf("\n"); 4286 printf("Totals:\n"); 4287 printf(" Tests run: %8d\n", tests_run); 4288 printf(" Tests failed: %8d\n", tests_failed); 4289 printf(" Assertions checked:%8d\n", assertions); 4290 printf(" Assertions failed: %8d\n", failures); 4291 printf(" Skips reported: %8d\n", skips); 4292 } 4293 if (failures) { 4294 printf("\n"); 4295 printf("Failing tests:\n"); 4296 for (i = 0; i < limit; ++i) { 4297 if (tests[i].failures) 4298 printf(" %d: %s (%d failures)\n", i, 4299 tests[i].name, tests[i].failures); 4300 } 4301 printf("\n"); 4302 printf("Details for failing tests: %s\n", tmpdir); 4303 printf("\n"); 4304 } else { 4305 if (verbosity == VERBOSITY_SUMMARY_ONLY) 4306 printf("\n"); 4307 printf("%d tests passed, no failures\n", tests_run); 4308 } 4309 4310 free(refdir_alloc); 4311 4312 /* If the final tmpdir is empty, we can remove it. */ 4313 /* This should be the usual case when all tests succeed. */ 4314 assertChdir(".."); 4315 rmdir(tmpdir); 4316 4317 if (tests_failed) return 1; 4318 4319 if (fail_if_tests_skipped == 1 && skips > 0) return 2; 4320 4321 return 0; 4322 } 4323