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(*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 if (aclp != NULL) { 2594 free(aclp); 2595 aclp = NULL; 2596 } 2597 break; 2598 } 2599 } 2600 2601 *aclcnt = cnt; 2602 return (aclp); 2603 } 2604 #endif /* ARCHIVE_ACL_SUNOS */ 2605 2606 /* 2607 * Set test ACLs on a path 2608 * Return values: 2609 * 0: error setting ACLs 2610 * ARCHIVE_TEST_ACL_TYPE_POSIX1E: POSIX.1E ACLs have been set 2611 * ARCHIVE_TEST_ACL_TYPE_NFS4: NFSv4 or extended ACLs have been set 2612 */ 2613 int 2614 setTestAcl(const char *path) 2615 { 2616 #if ARCHIVE_ACL_SUPPORT 2617 int r = 1; 2618 #if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_DARWIN 2619 acl_t acl; 2620 #endif 2621 #if ARCHIVE_ACL_LIBRICHACL 2622 struct richacl *richacl; 2623 #endif 2624 #if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD 2625 const char *acltext_posix1e = "user:1:rw-," 2626 "group:15:r-x," 2627 "user::rwx," 2628 "group::rwx," 2629 "other::r-x," 2630 "mask::rwx"; 2631 #elif ARCHIVE_ACL_SUNOS /* Solaris POSIX.1e */ 2632 aclent_t aclp_posix1e[] = { 2633 { USER_OBJ, -1, 4 | 2 | 1 }, 2634 { USER, 1, 4 | 2 }, 2635 { GROUP_OBJ, -1, 4 | 2 | 1 }, 2636 { GROUP, 15, 4 | 1 }, 2637 { CLASS_OBJ, -1, 4 | 2 | 1 }, 2638 { OTHER_OBJ, -1, 4 | 2 | 1 } 2639 }; 2640 #endif 2641 #if ARCHIVE_ACL_FREEBSD /* FreeBSD NFS4 */ 2642 const char *acltext_nfs4 = "user:1:rwpaRcs::allow:1," 2643 "group:15:rxaRcs::allow:15," 2644 "owner@:rwpxaARWcCos::allow," 2645 "group@:rwpxaRcs::allow," 2646 "everyone@:rxaRcs::allow"; 2647 #elif ARCHIVE_ACL_LIBRICHACL 2648 const char *acltext_nfs4 = "owner:rwpxaARWcCoS::mask," 2649 "group:rwpxaRcS::mask," 2650 "other:rxaRcS::mask," 2651 "user:1:rwpaRcS::allow," 2652 "group:15:rxaRcS::allow," 2653 "owner@:rwpxaARWcCoS::allow," 2654 "group@:rwpxaRcS::allow," 2655 "everyone@:rxaRcS::allow"; 2656 #elif ARCHIVE_ACL_SUNOS_NFS4 /* Solaris NFS4 */ 2657 ace_t aclp_nfs4[] = { 2658 { 1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA | 2659 ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | ACE_READ_ACL | 2660 ACE_SYNCHRONIZE, 0, ACE_ACCESS_ALLOWED_ACE_TYPE }, 2661 { 15, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES | 2662 ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE, 2663 ACE_IDENTIFIER_GROUP, ACE_ACCESS_ALLOWED_ACE_TYPE }, 2664 { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA | 2665 ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_WRITE_ATTRIBUTES | 2666 ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS | 2667 ACE_READ_ACL | ACE_WRITE_ACL | ACE_WRITE_OWNER | ACE_SYNCHRONIZE, 2668 ACE_OWNER, ACE_ACCESS_ALLOWED_ACE_TYPE }, 2669 { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA | 2670 ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | 2671 ACE_READ_ACL | ACE_SYNCHRONIZE, ACE_GROUP | ACE_IDENTIFIER_GROUP, 2672 ACE_ACCESS_ALLOWED_ACE_TYPE }, 2673 { -1, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES | 2674 ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE, 2675 ACE_EVERYONE, ACE_ACCESS_ALLOWED_ACE_TYPE } 2676 }; 2677 #elif ARCHIVE_ACL_DARWIN /* Mac OS X */ 2678 acl_entry_t aclent; 2679 acl_permset_t permset; 2680 const uid_t uid = 1; 2681 uuid_t uuid; 2682 int i; 2683 const acl_perm_t acl_perms[] = { 2684 ACL_READ_DATA, 2685 ACL_WRITE_DATA, 2686 ACL_APPEND_DATA, 2687 ACL_EXECUTE, 2688 ACL_READ_ATTRIBUTES, 2689 ACL_READ_EXTATTRIBUTES, 2690 ACL_READ_SECURITY, 2691 #if HAVE_DECL_ACL_SYNCHRONIZE 2692 ACL_SYNCHRONIZE 2693 #endif 2694 }; 2695 #endif /* ARCHIVE_ACL_DARWIN */ 2696 2697 #if ARCHIVE_ACL_FREEBSD 2698 acl = acl_from_text(acltext_nfs4); 2699 failure("acl_from_text() error: %s", strerror(errno)); 2700 if (assert(acl != NULL) == 0) 2701 return (0); 2702 #elif ARCHIVE_ACL_LIBRICHACL 2703 richacl = richacl_from_text(acltext_nfs4, NULL, NULL); 2704 failure("richacl_from_text() error: %s", strerror(errno)); 2705 if (assert(richacl != NULL) == 0) 2706 return (0); 2707 #elif ARCHIVE_ACL_DARWIN 2708 acl = acl_init(1); 2709 failure("acl_init() error: %s", strerror(errno)); 2710 if (assert(acl != NULL) == 0) 2711 return (0); 2712 r = acl_create_entry(&acl, &aclent); 2713 failure("acl_create_entry() error: %s", strerror(errno)); 2714 if (assertEqualInt(r, 0) == 0) 2715 goto testacl_free; 2716 r = acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW); 2717 failure("acl_set_tag_type() error: %s", strerror(errno)); 2718 if (assertEqualInt(r, 0) == 0) 2719 goto testacl_free; 2720 r = acl_get_permset(aclent, &permset); 2721 failure("acl_get_permset() error: %s", strerror(errno)); 2722 if (assertEqualInt(r, 0) == 0) 2723 goto testacl_free; 2724 for (i = 0; i < (int)(sizeof(acl_perms) / sizeof(acl_perms[0])); i++) { 2725 r = acl_add_perm(permset, acl_perms[i]); 2726 failure("acl_add_perm() error: %s", strerror(errno)); 2727 if (assertEqualInt(r, 0) == 0) 2728 goto testacl_free; 2729 } 2730 r = acl_set_permset(aclent, permset); 2731 failure("acl_set_permset() error: %s", strerror(errno)); 2732 if (assertEqualInt(r, 0) == 0) 2733 goto testacl_free; 2734 r = mbr_uid_to_uuid(uid, uuid); 2735 failure("mbr_uid_to_uuid() error: %s", strerror(errno)); 2736 if (assertEqualInt(r, 0) == 0) 2737 goto testacl_free; 2738 r = acl_set_qualifier(aclent, uuid); 2739 failure("acl_set_qualifier() error: %s", strerror(errno)); 2740 if (assertEqualInt(r, 0) == 0) 2741 goto testacl_free; 2742 #endif /* ARCHIVE_ACL_DARWIN */ 2743 2744 #if ARCHIVE_ACL_NFS4 2745 #if ARCHIVE_ACL_FREEBSD 2746 r = acl_set_file(path, ACL_TYPE_NFS4, acl); 2747 acl_free(acl); 2748 #elif ARCHIVE_ACL_LIBRICHACL 2749 r = richacl_set_file(path, richacl); 2750 richacl_free(richacl); 2751 #elif ARCHIVE_ACL_SUNOS_NFS4 2752 r = acl(path, ACE_SETACL, 2753 (int)(sizeof(aclp_nfs4)/sizeof(aclp_nfs4[0])), aclp_nfs4); 2754 #elif ARCHIVE_ACL_DARWIN 2755 r = acl_set_file(path, ACL_TYPE_EXTENDED, acl); 2756 acl_free(acl); 2757 #endif 2758 if (r == 0) 2759 return (ARCHIVE_TEST_ACL_TYPE_NFS4); 2760 #endif /* ARCHIVE_ACL_NFS4 */ 2761 2762 #if ARCHIVE_ACL_POSIX1E 2763 #if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_LIBACL 2764 acl = acl_from_text(acltext_posix1e); 2765 failure("acl_from_text() error: %s", strerror(errno)); 2766 if (assert(acl != NULL) == 0) 2767 return (0); 2768 2769 r = acl_set_file(path, ACL_TYPE_ACCESS, acl); 2770 acl_free(acl); 2771 #elif ARCHIVE_ACL_SUNOS 2772 r = acl(path, SETACL, 2773 (int)(sizeof(aclp_posix1e)/sizeof(aclp_posix1e[0])), aclp_posix1e); 2774 #endif 2775 if (r == 0) 2776 return (ARCHIVE_TEST_ACL_TYPE_POSIX1E); 2777 else 2778 return (0); 2779 #endif /* ARCHIVE_ACL_POSIX1E */ 2780 #if ARCHIVE_ACL_DARWIN 2781 testacl_free: 2782 acl_free(acl); 2783 #endif 2784 #endif /* ARCHIVE_ACL_SUPPORT */ 2785 (void)path; /* UNUSED */ 2786 return (0); 2787 } 2788 2789 /* 2790 * Sleep as needed; useful for verifying disk timestamp changes by 2791 * ensuring that the wall-clock time has actually changed before we 2792 * go back to re-read something from disk. 2793 */ 2794 void 2795 sleepUntilAfter(time_t t) 2796 { 2797 while (t >= time(NULL)) 2798 #if defined(_WIN32) && !defined(__CYGWIN__) 2799 Sleep(500); 2800 #else 2801 sleep(1); 2802 #endif 2803 } 2804 2805 /* 2806 * Call standard system() call, but build up the command line using 2807 * sprintf() conventions. 2808 */ 2809 int 2810 systemf(const char *fmt, ...) 2811 { 2812 char buff[8192]; 2813 va_list ap; 2814 int r; 2815 2816 va_start(ap, fmt); 2817 vsprintf(buff, fmt, ap); 2818 if (verbosity > VERBOSITY_FULL) 2819 logprintf("Cmd: %s\n", buff); 2820 r = system(buff); 2821 va_end(ap); 2822 return (r); 2823 } 2824 2825 /* 2826 * Slurp a file into memory for ease of comparison and testing. 2827 * Returns size of file in 'sizep' if non-NULL, null-terminates 2828 * data in memory for ease of use. 2829 */ 2830 char * 2831 slurpfile(size_t * sizep, const char *fmt, ...) 2832 { 2833 char filename[8192]; 2834 struct stat st; 2835 va_list ap; 2836 char *p; 2837 ssize_t bytes_read; 2838 FILE *f; 2839 int r; 2840 2841 va_start(ap, fmt); 2842 vsprintf(filename, fmt, ap); 2843 va_end(ap); 2844 2845 f = fopen(filename, "rb"); 2846 if (f == NULL) { 2847 /* Note: No error; non-existent file is okay here. */ 2848 return (NULL); 2849 } 2850 r = fstat(fileno(f), &st); 2851 if (r != 0) { 2852 logprintf("Can't stat file %s\n", filename); 2853 fclose(f); 2854 return (NULL); 2855 } 2856 p = malloc((size_t)st.st_size + 1); 2857 if (p == NULL) { 2858 logprintf("Can't allocate %ld bytes of memory to read file %s\n", 2859 (long int)st.st_size, filename); 2860 fclose(f); 2861 return (NULL); 2862 } 2863 bytes_read = fread(p, 1, (size_t)st.st_size, f); 2864 if (bytes_read < st.st_size) { 2865 logprintf("Can't read file %s\n", filename); 2866 fclose(f); 2867 free(p); 2868 return (NULL); 2869 } 2870 p[st.st_size] = '\0'; 2871 if (sizep != NULL) 2872 *sizep = (size_t)st.st_size; 2873 fclose(f); 2874 return (p); 2875 } 2876 2877 /* 2878 * Slurp a file into memory for ease of comparison and testing. 2879 * Returns size of file in 'sizep' if non-NULL, null-terminates 2880 * data in memory for ease of use. 2881 */ 2882 void 2883 dumpfile(const char *filename, void *data, size_t len) 2884 { 2885 ssize_t bytes_written; 2886 FILE *f; 2887 2888 f = fopen(filename, "wb"); 2889 if (f == NULL) { 2890 logprintf("Can't open file %s for writing\n", filename); 2891 return; 2892 } 2893 bytes_written = fwrite(data, 1, len, f); 2894 if (bytes_written < (ssize_t)len) 2895 logprintf("Can't write file %s\n", filename); 2896 fclose(f); 2897 } 2898 2899 /* Read a uuencoded file from the reference directory, decode, and 2900 * write the result into the current directory. */ 2901 #define VALID_UUDECODE(c) (c >= 32 && c <= 96) 2902 #define UUDECODE(c) (((c) - 0x20) & 0x3f) 2903 void 2904 extract_reference_file(const char *name) 2905 { 2906 char buff[1024]; 2907 FILE *in, *out; 2908 2909 sprintf(buff, "%s/%s.uu", refdir, name); 2910 in = fopen(buff, "r"); 2911 failure("Couldn't open reference file %s", buff); 2912 assert(in != NULL); 2913 if (in == NULL) 2914 return; 2915 /* Read up to and including the 'begin' line. */ 2916 for (;;) { 2917 if (fgets(buff, sizeof(buff), in) == NULL) { 2918 /* TODO: This is a failure. */ 2919 return; 2920 } 2921 if (memcmp(buff, "begin ", 6) == 0) 2922 break; 2923 } 2924 /* Now, decode the rest and write it. */ 2925 out = fopen(name, "wb"); 2926 while (fgets(buff, sizeof(buff), in) != NULL) { 2927 char *p = buff; 2928 int bytes; 2929 2930 if (memcmp(buff, "end", 3) == 0) 2931 break; 2932 2933 bytes = UUDECODE(*p++); 2934 while (bytes > 0) { 2935 int n = 0; 2936 /* Write out 1-3 bytes from that. */ 2937 if (bytes > 0) { 2938 assert(VALID_UUDECODE(p[0])); 2939 assert(VALID_UUDECODE(p[1])); 2940 n = UUDECODE(*p++) << 18; 2941 n |= UUDECODE(*p++) << 12; 2942 fputc(n >> 16, out); 2943 --bytes; 2944 } 2945 if (bytes > 0) { 2946 assert(VALID_UUDECODE(p[0])); 2947 n |= UUDECODE(*p++) << 6; 2948 fputc((n >> 8) & 0xFF, out); 2949 --bytes; 2950 } 2951 if (bytes > 0) { 2952 assert(VALID_UUDECODE(p[0])); 2953 n |= UUDECODE(*p++); 2954 fputc(n & 0xFF, out); 2955 --bytes; 2956 } 2957 } 2958 } 2959 fclose(out); 2960 fclose(in); 2961 } 2962 2963 void 2964 copy_reference_file(const char *name) 2965 { 2966 char buff[1024]; 2967 FILE *in, *out; 2968 size_t rbytes; 2969 2970 sprintf(buff, "%s/%s", refdir, name); 2971 in = fopen(buff, "rb"); 2972 failure("Couldn't open reference file %s", buff); 2973 assert(in != NULL); 2974 if (in == NULL) 2975 return; 2976 /* Now, decode the rest and write it. */ 2977 /* Not a lot of error checking here; the input better be right. */ 2978 out = fopen(name, "wb"); 2979 while ((rbytes = fread(buff, 1, sizeof(buff), in)) > 0) { 2980 if (fwrite(buff, 1, rbytes, out) != rbytes) { 2981 logprintf("Error: fwrite\n"); 2982 break; 2983 } 2984 } 2985 fclose(out); 2986 fclose(in); 2987 } 2988 2989 int 2990 is_LargeInode(const char *file) 2991 { 2992 #if defined(_WIN32) && !defined(__CYGWIN__) 2993 BY_HANDLE_FILE_INFORMATION bhfi; 2994 int r; 2995 2996 r = my_GetFileInformationByName(file, &bhfi); 2997 if (r != 0) 2998 return (0); 2999 return (bhfi.nFileIndexHigh & 0x0000FFFFUL); 3000 #else 3001 struct stat st; 3002 int64_t ino; 3003 3004 if (stat(file, &st) < 0) 3005 return (0); 3006 ino = (int64_t)st.st_ino; 3007 return (ino > 0xffffffff); 3008 #endif 3009 } 3010 3011 void 3012 extract_reference_files(const char **names) 3013 { 3014 while (names && *names) 3015 extract_reference_file(*names++); 3016 } 3017 3018 #ifndef PROGRAM 3019 /* Set ACLs */ 3020 int 3021 assertion_entry_set_acls(const char *file, int line, struct archive_entry *ae, 3022 struct archive_test_acl_t *acls, int n) 3023 { 3024 int i, r, ret; 3025 3026 assertion_count(file, line); 3027 3028 ret = 0; 3029 archive_entry_acl_clear(ae); 3030 for (i = 0; i < n; i++) { 3031 r = archive_entry_acl_add_entry(ae, 3032 acls[i].type, acls[i].permset, acls[i].tag, 3033 acls[i].qual, acls[i].name); 3034 if (r != 0) { 3035 ret = 1; 3036 failure_start(file, line, "type=%#010x, ", 3037 "permset=%#010x, tag=%d, qual=%d name=%s", 3038 acls[i].type, acls[i].permset, acls[i].tag, 3039 acls[i].qual, acls[i].name); 3040 failure_finish(NULL); 3041 } 3042 } 3043 3044 return (ret); 3045 } 3046 3047 static int 3048 archive_test_acl_match(struct archive_test_acl_t *acl, int type, int permset, 3049 int tag, int qual, const char *name) 3050 { 3051 if (type != acl->type) 3052 return (0); 3053 if (permset != acl->permset) 3054 return (0); 3055 if (tag != acl->tag) 3056 return (0); 3057 if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) 3058 return (1); 3059 if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) 3060 return (1); 3061 if (tag == ARCHIVE_ENTRY_ACL_EVERYONE) 3062 return (1); 3063 if (tag == ARCHIVE_ENTRY_ACL_OTHER) 3064 return (1); 3065 if (qual != acl->qual) 3066 return (0); 3067 if (name == NULL) { 3068 if (acl->name == NULL || acl->name[0] == '\0') 3069 return (1); 3070 return (0); 3071 } 3072 if (acl->name == NULL) { 3073 if (name[0] == '\0') 3074 return (1); 3075 return (0); 3076 } 3077 return (0 == strcmp(name, acl->name)); 3078 } 3079 3080 /* Compare ACLs */ 3081 int 3082 assertion_entry_compare_acls(const char *file, int line, 3083 struct archive_entry *ae, struct archive_test_acl_t *acls, int cnt, 3084 int want_type, int mode) 3085 { 3086 int *marker; 3087 int i, r, n, ret; 3088 int type, permset, tag, qual; 3089 int matched; 3090 const char *name; 3091 3092 assertion_count(file, line); 3093 3094 ret = 0; 3095 n = 0; 3096 marker = malloc(sizeof(marker[0]) * cnt); 3097 3098 for (i = 0; i < cnt; i++) { 3099 if ((acls[i].type & want_type) != 0) { 3100 marker[n] = i; 3101 n++; 3102 } 3103 } 3104 3105 if (n == 0) { 3106 failure_start(file, line, "No ACL's to compare, type mask: %d", 3107 want_type); 3108 return (1); 3109 } 3110 3111 while (0 == (r = archive_entry_acl_next(ae, want_type, 3112 &type, &permset, &tag, &qual, &name))) { 3113 for (i = 0, matched = 0; i < n && !matched; i++) { 3114 if (archive_test_acl_match(&acls[marker[i]], type, 3115 permset, tag, qual, name)) { 3116 /* We found a match; remove it. */ 3117 marker[i] = marker[n - 1]; 3118 n--; 3119 matched = 1; 3120 } 3121 } 3122 if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS 3123 && tag == ARCHIVE_ENTRY_ACL_USER_OBJ) { 3124 if (!matched) { 3125 failure_start(file, line, "No match for " 3126 "user_obj perm"); 3127 failure_finish(NULL); 3128 ret = 1; 3129 } 3130 if ((permset << 6) != (mode & 0700)) { 3131 failure_start(file, line, "USER_OBJ permset " 3132 "(%02o) != user mode (%02o)", permset, 3133 07 & (mode >> 6)); 3134 failure_finish(NULL); 3135 ret = 1; 3136 } 3137 } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS 3138 && tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) { 3139 if (!matched) { 3140 failure_start(file, line, "No match for " 3141 "group_obj perm"); 3142 failure_finish(NULL); 3143 ret = 1; 3144 } 3145 if ((permset << 3) != (mode & 0070)) { 3146 failure_start(file, line, "GROUP_OBJ permset " 3147 "(%02o) != group mode (%02o)", permset, 3148 07 & (mode >> 3)); 3149 failure_finish(NULL); 3150 ret = 1; 3151 } 3152 } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS 3153 && tag == ARCHIVE_ENTRY_ACL_OTHER) { 3154 if (!matched) { 3155 failure_start(file, line, "No match for " 3156 "other perm"); 3157 failure_finish(NULL); 3158 ret = 1; 3159 } 3160 if ((permset << 0) != (mode & 0007)) { 3161 failure_start(file, line, "OTHER permset " 3162 "(%02o) != other mode (%02o)", permset, 3163 mode & 07); 3164 failure_finish(NULL); 3165 ret = 1; 3166 } 3167 } else if (matched != 1) { 3168 failure_start(file, line, "Could not find match for " 3169 "ACL (type=%#010x,permset=%#010x,tag=%d,qual=%d," 3170 "name=``%s'')", type, permset, tag, qual, name); 3171 failure_finish(NULL); 3172 ret = 1; 3173 } 3174 } 3175 if (r != ARCHIVE_EOF) { 3176 failure_start(file, line, "Should not exit before EOF"); 3177 failure_finish(NULL); 3178 ret = 1; 3179 } 3180 if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 && 3181 (mode_t)(mode & 0777) != (archive_entry_mode(ae) & 0777)) { 3182 failure_start(file, line, "Mode (%02o) and entry mode (%02o) " 3183 "mismatch", mode, archive_entry_mode(ae)); 3184 failure_finish(NULL); 3185 ret = 1; 3186 } 3187 if (n != 0) { 3188 failure_start(file, line, "Could not find match for ACL " 3189 "(type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s'')", 3190 acls[marker[0]].type, acls[marker[0]].permset, 3191 acls[marker[0]].tag, acls[marker[0]].qual, 3192 acls[marker[0]].name); 3193 failure_finish(NULL); 3194 ret = 1; 3195 /* Number of ACLs not matched should == 0 */ 3196 } 3197 free(marker); 3198 return (ret); 3199 } 3200 #endif /* !defined(PROGRAM) */ 3201 3202 /* 3203 * 3204 * TEST management 3205 * 3206 */ 3207 3208 /* 3209 * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has 3210 * a line like 3211 * DEFINE_TEST(test_function) 3212 * for each test. 3213 */ 3214 3215 /* Use "list.h" to declare all of the test functions. */ 3216 #undef DEFINE_TEST 3217 #define DEFINE_TEST(name) void name(void); 3218 #include "list.h" 3219 3220 /* Use "list.h" to create a list of all tests (functions and names). */ 3221 #undef DEFINE_TEST 3222 #define DEFINE_TEST(n) { n, #n, 0 }, 3223 struct test_list_t tests[] = { 3224 #include "list.h" 3225 }; 3226 3227 /* 3228 * Summarize repeated failures in the just-completed test. 3229 */ 3230 static void 3231 test_summarize(int failed, int skips_num) 3232 { 3233 unsigned int i; 3234 3235 switch (verbosity) { 3236 case VERBOSITY_SUMMARY_ONLY: 3237 printf(failed ? "E" : "."); 3238 fflush(stdout); 3239 break; 3240 case VERBOSITY_PASSFAIL: 3241 printf(failed ? "FAIL\n" : skips_num ? "ok (S)\n" : "ok\n"); 3242 break; 3243 } 3244 3245 log_console = (verbosity == VERBOSITY_LIGHT_REPORT); 3246 3247 for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) { 3248 if (failed_lines[i].count > 1 && !failed_lines[i].skip) 3249 logprintf("%s:%d: Summary: Failed %d times\n", 3250 failed_filename, i, failed_lines[i].count); 3251 } 3252 /* Clear the failure history for the next file. */ 3253 failed_filename = NULL; 3254 memset(failed_lines, 0, sizeof(failed_lines)); 3255 } 3256 3257 /* 3258 * Actually run a single test, with appropriate setup and cleanup. 3259 */ 3260 static int 3261 test_run(int i, const char *tmpdir) 3262 { 3263 char workdir[1024]; 3264 char logfilename[64]; 3265 int failures_before = failures; 3266 int skips_before = skips; 3267 int oldumask; 3268 3269 switch (verbosity) { 3270 case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */ 3271 break; 3272 case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */ 3273 printf("%3d: %-64s", i, tests[i].name); 3274 fflush(stdout); 3275 break; 3276 default: /* Title of test, details will follow */ 3277 printf("%3d: %s\n", i, tests[i].name); 3278 } 3279 3280 /* Chdir to the top-level work directory. */ 3281 if (!assertChdir(tmpdir)) { 3282 fprintf(stderr, 3283 "ERROR: Can't chdir to top work dir %s\n", tmpdir); 3284 exit(1); 3285 } 3286 /* Create a log file for this test. */ 3287 sprintf(logfilename, "%s.log", tests[i].name); 3288 logfile = fopen(logfilename, "w"); 3289 fprintf(logfile, "%s\n\n", tests[i].name); 3290 /* Chdir() to a work dir for this specific test. */ 3291 snprintf(workdir, sizeof(workdir), "%s/%s", tmpdir, tests[i].name); 3292 testworkdir = workdir; 3293 if (!assertMakeDir(testworkdir, 0755) 3294 || !assertChdir(testworkdir)) { 3295 fprintf(stderr, 3296 "ERROR: Can't chdir to work dir %s\n", testworkdir); 3297 exit(1); 3298 } 3299 /* Explicitly reset the locale before each test. */ 3300 setlocale(LC_ALL, "C"); 3301 /* Record the umask before we run the test. */ 3302 umask(oldumask = umask(0)); 3303 /* 3304 * Run the actual test. 3305 */ 3306 (*tests[i].func)(); 3307 /* 3308 * Clean up and report afterwards. 3309 */ 3310 testworkdir = NULL; 3311 /* Restore umask */ 3312 umask(oldumask); 3313 /* Reset locale. */ 3314 setlocale(LC_ALL, "C"); 3315 /* Reset directory. */ 3316 if (!assertChdir(tmpdir)) { 3317 fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n", 3318 tmpdir); 3319 exit(1); 3320 } 3321 /* Report per-test summaries. */ 3322 tests[i].failures = failures - failures_before; 3323 test_summarize(tests[i].failures, skips - skips_before); 3324 /* Close the per-test log file. */ 3325 fclose(logfile); 3326 logfile = NULL; 3327 /* If there were no failures, we can remove the work dir and logfile. */ 3328 if (tests[i].failures == 0) { 3329 if (!keep_temp_files && assertChdir(tmpdir)) { 3330 #if defined(_WIN32) && !defined(__CYGWIN__) 3331 /* Make sure not to leave empty directories. 3332 * Sometimes a processing of closing files used by tests 3333 * is not done, then rmdir will be failed and it will 3334 * leave a empty test directory. So we should wait a few 3335 * seconds and retry rmdir. */ 3336 int r, t; 3337 for (t = 0; t < 10; t++) { 3338 if (t > 0) 3339 Sleep(1000); 3340 r = systemf("rmdir /S /Q %s", tests[i].name); 3341 if (r == 0) 3342 break; 3343 } 3344 systemf("del %s", logfilename); 3345 #else 3346 systemf("rm -rf %s", tests[i].name); 3347 systemf("rm %s", logfilename); 3348 #endif 3349 } 3350 } 3351 /* Return appropriate status. */ 3352 return (tests[i].failures); 3353 } 3354 3355 /* 3356 * 3357 * 3358 * MAIN and support routines. 3359 * 3360 * 3361 */ 3362 3363 static void 3364 usage(const char *program) 3365 { 3366 static const int limit = sizeof(tests) / sizeof(tests[0]); 3367 int i; 3368 3369 printf("Usage: %s [options] <test> <test> ...\n", program); 3370 printf("Default is to run all tests.\n"); 3371 printf("Otherwise, specify the numbers of the tests you wish to run.\n"); 3372 printf("Options:\n"); 3373 printf(" -d Dump core after any failure, for debugging.\n"); 3374 printf(" -k Keep all temp files.\n"); 3375 printf(" Default: temp files for successful tests deleted.\n"); 3376 #ifdef PROGRAM 3377 printf(" -p <path> Path to executable to be tested.\n"); 3378 printf(" Default: path taken from " ENVBASE " environment variable.\n"); 3379 #endif 3380 printf(" -q Quiet.\n"); 3381 printf(" -r <dir> Path to dir containing reference files.\n"); 3382 printf(" Default: Current directory.\n"); 3383 printf(" -u Keep running specifies tests until one fails.\n"); 3384 printf(" -v Verbose.\n"); 3385 printf("Available tests:\n"); 3386 for (i = 0; i < limit; i++) 3387 printf(" %d: %s\n", i, tests[i].name); 3388 exit(1); 3389 } 3390 3391 static char * 3392 get_refdir(const char *d) 3393 { 3394 size_t tried_size, buff_size; 3395 char *buff, *tried, *pwd = NULL, *p = NULL; 3396 3397 #ifdef PATH_MAX 3398 buff_size = PATH_MAX; 3399 #else 3400 buff_size = 8192; 3401 #endif 3402 buff = calloc(buff_size, 1); 3403 if (buff == NULL) { 3404 fprintf(stderr, "Unable to allocate memory\n"); 3405 exit(1); 3406 } 3407 3408 /* Allocate a buffer to hold the various directories we checked. */ 3409 tried_size = buff_size * 2; 3410 tried = calloc(tried_size, 1); 3411 if (tried == NULL) { 3412 fprintf(stderr, "Unable to allocate memory\n"); 3413 exit(1); 3414 } 3415 3416 /* If a dir was specified, try that */ 3417 if (d != NULL) { 3418 pwd = NULL; 3419 snprintf(buff, buff_size, "%s", d); 3420 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3421 if (p != NULL) goto success; 3422 strncat(tried, buff, tried_size - strlen(tried) - 1); 3423 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3424 goto failure; 3425 } 3426 3427 /* Get the current dir. */ 3428 #ifdef PATH_MAX 3429 pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ 3430 #else 3431 pwd = getcwd(NULL, 0); 3432 #endif 3433 while (pwd[strlen(pwd) - 1] == '\n') 3434 pwd[strlen(pwd) - 1] = '\0'; 3435 3436 /* Look for a known file. */ 3437 snprintf(buff, buff_size, "%s", pwd); 3438 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3439 if (p != NULL) goto success; 3440 strncat(tried, buff, tried_size - strlen(tried) - 1); 3441 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3442 3443 snprintf(buff, buff_size, "%s/test", pwd); 3444 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3445 if (p != NULL) goto success; 3446 strncat(tried, buff, tried_size - strlen(tried) - 1); 3447 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3448 3449 #if defined(LIBRARY) 3450 snprintf(buff, buff_size, "%s/%s/test", pwd, LIBRARY); 3451 #else 3452 snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM); 3453 #endif 3454 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3455 if (p != NULL) goto success; 3456 strncat(tried, buff, tried_size - strlen(tried) - 1); 3457 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3458 3459 #if defined(PROGRAM_ALIAS) 3460 snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM_ALIAS); 3461 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3462 if (p != NULL) goto success; 3463 strncat(tried, buff, tried_size - strlen(tried) - 1); 3464 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3465 #endif 3466 3467 if (memcmp(pwd, "/usr/obj", 8) == 0) { 3468 snprintf(buff, buff_size, "%s", pwd + 8); 3469 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3470 if (p != NULL) goto success; 3471 strncat(tried, buff, tried_size - strlen(tried) - 1); 3472 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3473 3474 snprintf(buff, buff_size, "%s/test", pwd + 8); 3475 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); 3476 if (p != NULL) goto success; 3477 strncat(tried, buff, tried_size - strlen(tried) - 1); 3478 strncat(tried, "\n", tried_size - strlen(tried) - 1); 3479 } 3480 3481 failure: 3482 printf("Unable to locate known reference file %s\n", KNOWNREF); 3483 printf(" Checked following directories:\n%s\n", tried); 3484 printf("Use -r option to specify full path to reference directory\n"); 3485 #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) 3486 DebugBreak(); 3487 #endif 3488 exit(1); 3489 3490 success: 3491 free(p); 3492 free(pwd); 3493 free(tried); 3494 3495 /* Copy result into a fresh buffer to reduce memory usage. */ 3496 p = strdup(buff); 3497 free(buff); 3498 return p; 3499 } 3500 3501 int 3502 main(int argc, char **argv) 3503 { 3504 static const int limit = sizeof(tests) / sizeof(tests[0]); 3505 int test_set[sizeof(tests) / sizeof(tests[0])]; 3506 int i = 0, j = 0, tests_run = 0, tests_failed = 0, option; 3507 time_t now; 3508 char *refdir_alloc = NULL; 3509 const char *progname; 3510 char **saved_argv; 3511 const char *tmp, *option_arg, *p; 3512 char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL; 3513 char tmpdir_timestamp[256]; 3514 3515 (void)argc; /* UNUSED */ 3516 3517 /* Get the current dir. */ 3518 #ifdef PATH_MAX 3519 pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ 3520 #else 3521 pwd = getcwd(NULL, 0); 3522 #endif 3523 while (pwd[strlen(pwd) - 1] == '\n') 3524 pwd[strlen(pwd) - 1] = '\0'; 3525 3526 #if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__) 3527 /* To stop to run the default invalid parameter handler. */ 3528 _set_invalid_parameter_handler(invalid_parameter_handler); 3529 /* Disable annoying assertion message box. */ 3530 _CrtSetReportMode(_CRT_ASSERT, 0); 3531 #endif 3532 3533 /* 3534 * Name of this program, used to build root of our temp directory 3535 * tree. 3536 */ 3537 progname = p = argv[0]; 3538 if ((testprogdir = (char *)malloc(strlen(progname) + 1)) == NULL) 3539 { 3540 fprintf(stderr, "ERROR: Out of memory."); 3541 exit(1); 3542 } 3543 strcpy(testprogdir, progname); 3544 while (*p != '\0') { 3545 /* Support \ or / dir separators for Windows compat. */ 3546 if (*p == '/' || *p == '\\') 3547 { 3548 progname = p + 1; 3549 i = j; 3550 } 3551 ++p; 3552 j++; 3553 } 3554 testprogdir[i] = '\0'; 3555 #if defined(_WIN32) && !defined(__CYGWIN__) 3556 if (testprogdir[0] != '/' && testprogdir[0] != '\\' && 3557 !(((testprogdir[0] >= 'a' && testprogdir[0] <= 'z') || 3558 (testprogdir[0] >= 'A' && testprogdir[0] <= 'Z')) && 3559 testprogdir[1] == ':' && 3560 (testprogdir[2] == '/' || testprogdir[2] == '\\'))) 3561 #else 3562 if (testprogdir[0] != '/') 3563 #endif 3564 { 3565 /* Fixup path for relative directories. */ 3566 if ((testprogdir = (char *)realloc(testprogdir, 3567 strlen(pwd) + 1 + strlen(testprogdir) + 1)) == NULL) 3568 { 3569 fprintf(stderr, "ERROR: Out of memory."); 3570 exit(1); 3571 } 3572 memmove(testprogdir + strlen(pwd) + 1, testprogdir, 3573 strlen(testprogdir) + 1); 3574 memcpy(testprogdir, pwd, strlen(pwd)); 3575 testprogdir[strlen(pwd)] = '/'; 3576 } 3577 3578 #ifdef PROGRAM 3579 /* Get the target program from environment, if available. */ 3580 testprogfile = getenv(ENVBASE); 3581 #endif 3582 3583 if (getenv("TMPDIR") != NULL) 3584 tmp = getenv("TMPDIR"); 3585 else if (getenv("TMP") != NULL) 3586 tmp = getenv("TMP"); 3587 else if (getenv("TEMP") != NULL) 3588 tmp = getenv("TEMP"); 3589 else if (getenv("TEMPDIR") != NULL) 3590 tmp = getenv("TEMPDIR"); 3591 else 3592 tmp = "/tmp"; 3593 3594 /* Allow -d to be controlled through the environment. */ 3595 if (getenv(ENVBASE "_DEBUG") != NULL) 3596 dump_on_failure = 1; 3597 3598 /* Allow -v to be controlled through the environment. */ 3599 if (getenv("_VERBOSITY_LEVEL") != NULL) 3600 { 3601 vlevel = getenv("_VERBOSITY_LEVEL"); 3602 verbosity = atoi(vlevel); 3603 if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL) 3604 { 3605 /* Unsupported verbosity levels are silently ignored */ 3606 vlevel = NULL; 3607 verbosity = VERBOSITY_PASSFAIL; 3608 } 3609 } 3610 3611 /* Get the directory holding test files from environment. */ 3612 refdir = getenv(ENVBASE "_TEST_FILES"); 3613 3614 /* 3615 * Parse options, without using getopt(), which isn't available 3616 * on all platforms. 3617 */ 3618 ++argv; /* Skip program name */ 3619 while (*argv != NULL) { 3620 if (**argv != '-') 3621 break; 3622 p = *argv++; 3623 ++p; /* Skip '-' */ 3624 while (*p != '\0') { 3625 option = *p++; 3626 option_arg = NULL; 3627 /* If 'opt' takes an argument, parse that. */ 3628 if (option == 'p' || option == 'r') { 3629 if (*p != '\0') 3630 option_arg = p; 3631 else if (*argv == NULL) { 3632 fprintf(stderr, 3633 "Option -%c requires argument.\n", 3634 option); 3635 usage(progname); 3636 } else 3637 option_arg = *argv++; 3638 p = ""; /* End of this option word. */ 3639 } 3640 3641 /* Now, handle the option. */ 3642 switch (option) { 3643 case 'd': 3644 dump_on_failure = 1; 3645 break; 3646 case 'k': 3647 keep_temp_files = 1; 3648 break; 3649 case 'p': 3650 #ifdef PROGRAM 3651 testprogfile = option_arg; 3652 #else 3653 fprintf(stderr, "-p option not permitted\n"); 3654 usage(progname); 3655 #endif 3656 break; 3657 case 'q': 3658 if (!vlevel) 3659 verbosity--; 3660 break; 3661 case 'r': 3662 refdir = option_arg; 3663 break; 3664 case 'u': 3665 until_failure++; 3666 break; 3667 case 'v': 3668 if (!vlevel) 3669 verbosity++; 3670 break; 3671 default: 3672 fprintf(stderr, "Unrecognized option '%c'\n", 3673 option); 3674 usage(progname); 3675 } 3676 } 3677 } 3678 3679 /* 3680 * Sanity-check that our options make sense. 3681 */ 3682 #ifdef PROGRAM 3683 if (testprogfile == NULL) 3684 { 3685 if ((tmp2 = (char *)malloc(strlen(testprogdir) + 1 + 3686 strlen(PROGRAM) + 1)) == NULL) 3687 { 3688 fprintf(stderr, "ERROR: Out of memory."); 3689 exit(1); 3690 } 3691 strcpy(tmp2, testprogdir); 3692 strcat(tmp2, "/"); 3693 strcat(tmp2, PROGRAM); 3694 testprogfile = tmp2; 3695 } 3696 3697 { 3698 char *testprg; 3699 #if defined(_WIN32) && !defined(__CYGWIN__) 3700 /* Command.com sometimes rejects '/' separators. */ 3701 testprg = strdup(testprogfile); 3702 for (i = 0; testprg[i] != '\0'; i++) { 3703 if (testprg[i] == '/') 3704 testprg[i] = '\\'; 3705 } 3706 testprogfile = testprg; 3707 #endif 3708 /* Quote the name that gets put into shell command lines. */ 3709 testprg = malloc(strlen(testprogfile) + 3); 3710 strcpy(testprg, "\""); 3711 strcat(testprg, testprogfile); 3712 strcat(testprg, "\""); 3713 testprog = testprg; 3714 } 3715 #endif 3716 3717 #if !defined(_WIN32) && defined(SIGPIPE) 3718 { /* Ignore SIGPIPE signals */ 3719 struct sigaction sa; 3720 sa.sa_handler = SIG_IGN; 3721 sigemptyset(&sa.sa_mask); 3722 sa.sa_flags = 0; 3723 sigaction(SIGPIPE, &sa, NULL); 3724 } 3725 #endif 3726 3727 /* 3728 * Create a temp directory for the following tests. 3729 * Include the time the tests started as part of the name, 3730 * to make it easier to track the results of multiple tests. 3731 */ 3732 now = time(NULL); 3733 for (i = 0; ; i++) { 3734 strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp), 3735 "%Y-%m-%dT%H.%M.%S", 3736 localtime(&now)); 3737 sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname, 3738 tmpdir_timestamp, i); 3739 if (assertMakeDir(tmpdir,0755)) 3740 break; 3741 if (i >= 999) { 3742 fprintf(stderr, 3743 "ERROR: Unable to create temp directory %s\n", 3744 tmpdir); 3745 exit(1); 3746 } 3747 } 3748 3749 /* 3750 * If the user didn't specify a directory for locating 3751 * reference files, try to find the reference files in 3752 * the "usual places." 3753 */ 3754 refdir = refdir_alloc = get_refdir(refdir); 3755 3756 /* 3757 * Banner with basic information. 3758 */ 3759 printf("\n"); 3760 printf("If tests fail or crash, details will be in:\n"); 3761 printf(" %s\n", tmpdir); 3762 printf("\n"); 3763 if (verbosity > VERBOSITY_SUMMARY_ONLY) { 3764 printf("Reference files will be read from: %s\n", refdir); 3765 #ifdef PROGRAM 3766 printf("Running tests on: %s\n", testprog); 3767 #endif 3768 printf("Exercising: "); 3769 fflush(stdout); 3770 printf("%s\n", EXTRA_VERSION); 3771 } else { 3772 printf("Running "); 3773 fflush(stdout); 3774 } 3775 3776 /* 3777 * Run some or all of the individual tests. 3778 */ 3779 saved_argv = argv; 3780 do { 3781 argv = saved_argv; 3782 do { 3783 int test_num; 3784 3785 test_num = get_test_set(test_set, limit, *argv, tests); 3786 if (test_num < 0) { 3787 printf("*** INVALID Test %s\n", *argv); 3788 free(refdir_alloc); 3789 free(testprogdir); 3790 usage(progname); 3791 return (1); 3792 } 3793 for (i = 0; i < test_num; i++) { 3794 tests_run++; 3795 if (test_run(test_set[i], tmpdir)) { 3796 tests_failed++; 3797 if (until_failure) 3798 goto finish; 3799 } 3800 } 3801 if (*argv != NULL) 3802 argv++; 3803 } while (*argv != NULL); 3804 } while (until_failure); 3805 3806 finish: 3807 /* Must be freed after all tests run */ 3808 free(tmp2); 3809 free(testprogdir); 3810 free(pwd); 3811 3812 /* 3813 * Report summary statistics. 3814 */ 3815 if (verbosity > VERBOSITY_SUMMARY_ONLY) { 3816 printf("\n"); 3817 printf("Totals:\n"); 3818 printf(" Tests run: %8d\n", tests_run); 3819 printf(" Tests failed: %8d\n", tests_failed); 3820 printf(" Assertions checked:%8d\n", assertions); 3821 printf(" Assertions failed: %8d\n", failures); 3822 printf(" Skips reported: %8d\n", skips); 3823 } 3824 if (failures) { 3825 printf("\n"); 3826 printf("Failing tests:\n"); 3827 for (i = 0; i < limit; ++i) { 3828 if (tests[i].failures) 3829 printf(" %d: %s (%d failures)\n", i, 3830 tests[i].name, tests[i].failures); 3831 } 3832 printf("\n"); 3833 printf("Details for failing tests: %s\n", tmpdir); 3834 printf("\n"); 3835 } else { 3836 if (verbosity == VERBOSITY_SUMMARY_ONLY) 3837 printf("\n"); 3838 printf("%d tests passed, no failures\n", tests_run); 3839 } 3840 3841 free(refdir_alloc); 3842 3843 /* If the final tmpdir is empty, we can remove it. */ 3844 /* This should be the usual case when all tests succeed. */ 3845 assertChdir(".."); 3846 rmdir(tmpdir); 3847 3848 return (tests_failed ? 1 : 0); 3849 } 3850