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