148 lines
4.9 KiB
C
148 lines
4.9 KiB
C
|
|
#include "aksl_capture.h"
|
||
|
|
|
||
|
|
#include <dirent.h>
|
||
|
|
#include <errno.h>
|
||
|
|
#include <fcntl.h>
|
||
|
|
#include <sys/stat.h>
|
||
|
|
|
||
|
|
static int make_directory(char *path, size_t size)
|
||
|
|
{
|
||
|
|
const char *tmp = getenv("TMPDIR");
|
||
|
|
if ( tmp == NULL || tmp[0] == '\0' ) {
|
||
|
|
tmp = "/tmp";
|
||
|
|
}
|
||
|
|
if ( (size_t)snprintf(path, size, "%s/aksl_dir_XXXXXX", tmp) >= size ) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
return mkdtemp(path) == NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int test_open_errors_and_nulls(void)
|
||
|
|
{
|
||
|
|
char file[AKSL_TMP_MAX];
|
||
|
|
DIR *dirp = (DIR *)1;
|
||
|
|
struct dirent entry;
|
||
|
|
|
||
|
|
AKSL_CHECK_STATUS(aksl_opendir("/nonexistent/aksl/dir", &dirp), ENOENT);
|
||
|
|
AKSL_CHECK(dirp == NULL);
|
||
|
|
AKSL_CHECK(aksl_temp_file(file, sizeof(file)) == 0);
|
||
|
|
AKSL_CHECK_STATUS(aksl_opendir(file, &dirp), ENOTDIR);
|
||
|
|
AKSL_CHECK_STATUS(aksl_opendir(NULL, &dirp), AKERR_NULLPOINTER);
|
||
|
|
AKSL_CHECK_STATUS(aksl_opendir(".", NULL), AKERR_NULLPOINTER);
|
||
|
|
AKSL_CHECK_STATUS(aksl_fdopendir(-1, &dirp), EBADF);
|
||
|
|
AKSL_CHECK_STATUS(aksl_fdopendir(0, NULL), AKERR_NULLPOINTER);
|
||
|
|
AKSL_CHECK_STATUS(aksl_readdir(NULL, &entry), AKERR_NULLPOINTER);
|
||
|
|
AKSL_CHECK_OK(aksl_opendir(".", &dirp));
|
||
|
|
AKSL_CHECK_STATUS(aksl_readdir(dirp, NULL), AKERR_NULLPOINTER);
|
||
|
|
AKSL_CHECK_OK(aksl_closedir(dirp));
|
||
|
|
AKSL_CHECK_STATUS(aksl_closedir(NULL), AKERR_NULLPOINTER);
|
||
|
|
AKSL_CHECK_STATUS(aksl_rewinddir(NULL), AKERR_NULLPOINTER);
|
||
|
|
AKSL_CHECK(unlink(file) == 0);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int test_copy_eof_rewind_and_fdopendir(void)
|
||
|
|
{
|
||
|
|
char path[AKSL_TMP_MAX], first_path[AKSL_TMP_MAX], second_path[AKSL_TMP_MAX];
|
||
|
|
struct dirent entry, saved;
|
||
|
|
char first_read[sizeof(entry.d_name)];
|
||
|
|
DIR *dirp = NULL;
|
||
|
|
int fd = -1, seen_first = 0, seen_second = 0;
|
||
|
|
|
||
|
|
AKSL_CHECK(make_directory(path, sizeof(path)) == 0);
|
||
|
|
AKSL_CHECK(snprintf(first_path, sizeof(first_path), "%s/first", path) < (int)sizeof(first_path));
|
||
|
|
AKSL_CHECK(snprintf(second_path, sizeof(second_path), "%s/second", path) < (int)sizeof(second_path));
|
||
|
|
fd = open(first_path, O_CREAT | O_WRONLY, 0600);
|
||
|
|
AKSL_CHECK(fd >= 0);
|
||
|
|
AKSL_CHECK(close(fd) == 0);
|
||
|
|
fd = open(second_path, O_CREAT | O_WRONLY, 0600);
|
||
|
|
AKSL_CHECK(fd >= 0);
|
||
|
|
AKSL_CHECK(close(fd) == 0);
|
||
|
|
|
||
|
|
AKSL_CHECK_OK(aksl_opendir(path, &dirp));
|
||
|
|
do {
|
||
|
|
akerr_ErrorContext *error = aksl_readdir(dirp, &entry);
|
||
|
|
if ( error != NULL ) {
|
||
|
|
int status = error->status;
|
||
|
|
RELEASE_ERROR(error);
|
||
|
|
AKSL_CHECK(status == AKERR_EOF);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if ( strcmp(entry.d_name, "first") == 0 ) { saved = entry; seen_first++; }
|
||
|
|
if ( strcmp(entry.d_name, "second") == 0 ) seen_second++;
|
||
|
|
} while ( 1 );
|
||
|
|
AKSL_CHECK(seen_first == 1 && seen_second == 1);
|
||
|
|
AKSL_CHECK(strcmp(saved.d_name, "first") == 0);
|
||
|
|
AKSL_CHECK_OK(aksl_rewinddir(dirp));
|
||
|
|
AKSL_CHECK_OK(aksl_readdir(dirp, &entry));
|
||
|
|
AKSL_CHECK(snprintf(first_read, sizeof(first_read), "%s", entry.d_name) < (int)sizeof(first_read));
|
||
|
|
AKSL_CHECK_OK(aksl_readdir(dirp, &entry));
|
||
|
|
AKSL_CHECK_OK(aksl_rewinddir(dirp));
|
||
|
|
AKSL_CHECK_OK(aksl_readdir(dirp, &entry));
|
||
|
|
AKSL_CHECK(strcmp(entry.d_name, first_read) == 0);
|
||
|
|
AKSL_CHECK_OK(aksl_closedir(dirp));
|
||
|
|
|
||
|
|
fd = open(path, O_RDONLY | O_DIRECTORY);
|
||
|
|
AKSL_CHECK(fd >= 0);
|
||
|
|
AKSL_CHECK_OK(aksl_fdopendir(fd, &dirp));
|
||
|
|
AKSL_CHECK_OK(aksl_readdir(dirp, &entry));
|
||
|
|
AKSL_CHECK_OK(aksl_closedir(dirp));
|
||
|
|
AKSL_CHECK(unlink(first_path) == 0);
|
||
|
|
AKSL_CHECK(unlink(second_path) == 0);
|
||
|
|
AKSL_CHECK(rmdir(path) == 0);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int test_empty_directory_reaches_eof_after_dot_entries(void)
|
||
|
|
{
|
||
|
|
char path[AKSL_TMP_MAX];
|
||
|
|
struct dirent entry;
|
||
|
|
DIR *dirp = NULL;
|
||
|
|
int count = 0, saw_dot = 0, saw_dotdot = 0;
|
||
|
|
|
||
|
|
AKSL_CHECK(make_directory(path, sizeof(path)) == 0);
|
||
|
|
AKSL_CHECK_OK(aksl_opendir(path, &dirp));
|
||
|
|
for ( ;; ) {
|
||
|
|
akerr_ErrorContext *error = aksl_readdir(dirp, &entry);
|
||
|
|
if ( error != NULL ) {
|
||
|
|
int status = error->status;
|
||
|
|
RELEASE_ERROR(error);
|
||
|
|
AKSL_CHECK(status == AKERR_EOF);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
count++;
|
||
|
|
if ( strcmp(entry.d_name, ".") == 0 ) saw_dot++;
|
||
|
|
if ( strcmp(entry.d_name, "..") == 0 ) saw_dotdot++;
|
||
|
|
}
|
||
|
|
AKSL_CHECK(count == 2 && saw_dot == 1 && saw_dotdot == 1);
|
||
|
|
AKSL_CHECK_OK(aksl_closedir(dirp));
|
||
|
|
AKSL_CHECK(rmdir(path) == 0);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int test_permission_denied(void)
|
||
|
|
{
|
||
|
|
char path[AKSL_TMP_MAX];
|
||
|
|
DIR *dirp = NULL;
|
||
|
|
AKSL_CHECK(make_directory(path, sizeof(path)) == 0);
|
||
|
|
AKSL_CHECK(chmod(path, 0000) == 0);
|
||
|
|
if ( geteuid() == 0 ) {
|
||
|
|
fprintf(stderr, " (skipped: running as root, chmod 000 denies nothing)\n");
|
||
|
|
} else {
|
||
|
|
AKSL_CHECK_STATUS(aksl_opendir(path, &dirp), EACCES);
|
||
|
|
}
|
||
|
|
AKSL_CHECK(chmod(path, 0700) == 0);
|
||
|
|
AKSL_CHECK(rmdir(path) == 0);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(void)
|
||
|
|
{
|
||
|
|
int failures = 0;
|
||
|
|
AKSL_RUN(failures, test_open_errors_and_nulls);
|
||
|
|
AKSL_RUN(failures, test_copy_eof_rewind_and_fdopendir);
|
||
|
|
AKSL_RUN(failures, test_empty_directory_reaches_eof_after_dot_entries);
|
||
|
|
AKSL_RUN(failures, test_permission_denied);
|
||
|
|
AKSL_REPORT(failures);
|
||
|
|
}
|