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