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