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