
Apple clang version 14.0.0 (clang-1400.0.17.3.1) fails the build because stds.h defines `fallthrough` as a macro which is then expanded when base.h evaluates # if __has_attribute(fallthrough) && __clang_major__ >= 5 The macOS SDK defines `DISPATCH_FALLTHROUGH` as the macro instead of `fallthrough`. This change replaces the use of `fallthrough` in the tree with `HEIM_FALLTHROUGH` and updates the declaration in configure logic to define `HEIM_FALLTHROUGH` based upon existing definitions (if any) of `fallthrough` or `DISPATCH_FALLTHROUGH`.
279 lines
6.6 KiB
C
279 lines
6.6 KiB
C
/***********************************************************************
|
|
* Copyright (c) 2009, Secure Endpoints Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* - Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
**********************************************************************/
|
|
#include <config.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <direct.h>
|
|
#include <errno.h>
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <string.h>
|
|
#include "dirent.h"
|
|
|
|
/* Note that we create a known directory structure in a subdirectory
|
|
of the current directory to run our tests. */
|
|
|
|
#define TESTDIR "dirent-test-dir"
|
|
|
|
const char * dir_entries[] = {
|
|
"A",
|
|
"B",
|
|
"C",
|
|
"CAA",
|
|
"CAAA",
|
|
"CABBBB",
|
|
"CAABBB.txt",
|
|
"A filename with spaces"
|
|
};
|
|
|
|
const char * entries_begin_with_C[] = {
|
|
"C",
|
|
"CAA",
|
|
"CAAA",
|
|
"CABBBB",
|
|
"CAABBB.txt"
|
|
};
|
|
|
|
const char * entries_end_with_A[] = {
|
|
"A",
|
|
"CAA",
|
|
"CAAA"
|
|
};
|
|
|
|
const int n_dir_entries = sizeof(dir_entries)/sizeof(dir_entries[0]);
|
|
|
|
int teardown_test(void);
|
|
|
|
void fail_test(const char * reason, ...)
|
|
{
|
|
va_list args;
|
|
|
|
va_start(args, reason);
|
|
vfprintf(stderr, reason, args);
|
|
va_end(args);
|
|
|
|
fprintf(stderr, " : errno = %d (%s)\n", errno, strerror(errno));
|
|
teardown_test();
|
|
abort();
|
|
}
|
|
|
|
void fail_test_nf(const char * format, ...)
|
|
{
|
|
va_list args;
|
|
|
|
fprintf(stderr, "FAIL:");
|
|
|
|
va_start(args, format);
|
|
vfprintf(stderr, format, args);
|
|
va_end(args);
|
|
|
|
fprintf(stderr, " : errno = %d (%s)\n", errno, strerror(errno));
|
|
}
|
|
|
|
int touch(const char * filename)
|
|
{
|
|
int fd;
|
|
|
|
fd = _open(filename, _O_CREAT, _S_IREAD| _S_IWRITE);
|
|
|
|
if (fd == -1)
|
|
return -1;
|
|
|
|
return _close(fd);
|
|
}
|
|
|
|
int setup_test(void)
|
|
{
|
|
int i;
|
|
|
|
fprintf(stderr, "Creating test directory %s ...\n", TESTDIR);
|
|
|
|
if (_mkdir(TESTDIR))
|
|
fail_test("Can't create test directory \"" TESTDIR "\"");
|
|
|
|
if (_chdir(TESTDIR))
|
|
fail_test("Can't change to test directory");
|
|
|
|
for (i=0; i < n_dir_entries; i++) {
|
|
if (touch(dir_entries[i]))
|
|
fail_test("Can't create test file '%s'", dir_entries[i]);
|
|
}
|
|
|
|
fprintf(stderr, "Done with test setup.\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int teardown_test(void)
|
|
{
|
|
char dirname[_MAX_PATH];
|
|
size_t len;
|
|
int i;
|
|
|
|
printf ("Begin cleanup...\n");
|
|
|
|
if (_getcwd(dirname, sizeof(dirname)/sizeof(char)) != NULL &&
|
|
|
|
(len = strlen(dirname)) > sizeof(TESTDIR)/sizeof(char) &&
|
|
|
|
strcmp(dirname + len + 1 - sizeof(TESTDIR)/sizeof(char), TESTDIR) == 0) {
|
|
|
|
HEIM_FALLTHROUGH;
|
|
|
|
} else {
|
|
/* did we create the directory? */
|
|
|
|
if (!_rmdir( TESTDIR )) {
|
|
fprintf(stderr, "Removed test directory\n");
|
|
return 0;
|
|
} else {
|
|
if (errno == ENOTEMPTY) {
|
|
if (_chdir(TESTDIR)) {
|
|
fprintf(stderr, "Can't change to test directory. Aborting cleanup.\n");
|
|
return -1;
|
|
} else {
|
|
HEIM_FALLTHROUGH;
|
|
}
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "Cleaning up test directory %s ...\n", TESTDIR);
|
|
|
|
for (i=0; i < n_dir_entries; i++) {
|
|
if (_unlink(dir_entries[i])) {
|
|
/* if the test setup failed, we expect this to happen for
|
|
at least some files */
|
|
}
|
|
}
|
|
|
|
if (_chdir("..")) {
|
|
fprintf(stderr, "Can't escape test directory. Giving in.\n");
|
|
return -1;
|
|
}
|
|
|
|
if (_rmdir( TESTDIR )) {
|
|
fprintf(stderr, "Can't remove test directory.\n");
|
|
return -1;
|
|
}
|
|
|
|
printf("Cleaned up test directory\n");
|
|
return 0;
|
|
}
|
|
|
|
int check_list(const char * filespec, const char ** list, int n, int expect_dot_and_dotdot)
|
|
{
|
|
DIR * d;
|
|
struct dirent * e;
|
|
int n_found = 0;
|
|
int i;
|
|
int rv = 0;
|
|
int retry = 1;
|
|
|
|
d = opendir(filespec);
|
|
if (d == NULL) {
|
|
fail_test_nf("opendir failed for [%s]", filespec);
|
|
return -1;
|
|
}
|
|
|
|
printf("Checking filespec [%s]... ", filespec);
|
|
|
|
retry:
|
|
while ((e = readdir(d)) != NULL) {
|
|
n_found ++;
|
|
|
|
if (expect_dot_and_dotdot &&
|
|
(strcmp(e->d_name, ".") == 0 ||
|
|
strcmp(e->d_name, "..") == 0))
|
|
continue;
|
|
|
|
for (i=0; i < n; i++) {
|
|
if (strcmp(list[i], e->d_name) == 0)
|
|
break;
|
|
}
|
|
|
|
if (i == n) {
|
|
fail_test_nf("Found unexpected entry [%s]", e->d_name);
|
|
rv = -1;
|
|
}
|
|
}
|
|
|
|
if (n_found != n) {
|
|
fail_test_nf("Unexpected number of entries [%d]. Expected %d", n_found, n);
|
|
rv = -1;
|
|
}
|
|
|
|
if (retry) {
|
|
retry = 0;
|
|
n_found = 0;
|
|
|
|
rewinddir(d);
|
|
goto retry;
|
|
}
|
|
|
|
if (closedir(d)) {
|
|
fail_test_nf("closedir() failed");
|
|
}
|
|
|
|
printf("done\n");
|
|
|
|
return rv;
|
|
}
|
|
|
|
int run_tests()
|
|
{
|
|
/* assumes that the test directory has been set up and we have
|
|
changed into the test directory. */
|
|
|
|
check_list("*", dir_entries, n_dir_entries + 2, 1);
|
|
check_list("*.*", dir_entries, n_dir_entries + 2, 1);
|
|
check_list("C*", entries_begin_with_C, sizeof(entries_begin_with_C)/sizeof(entries_begin_with_C[0]), 0);
|
|
check_list("*A", entries_end_with_A, sizeof(entries_end_with_A)/sizeof(entries_end_with_A[0]), 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char ** argv)
|
|
{
|
|
if (setup_test())
|
|
return 1;
|
|
|
|
run_tests();
|
|
|
|
teardown_test();
|
|
|
|
return 0;
|
|
}
|