Files
libakstdlib/tests/test_dir.c

148 lines
4.9 KiB
C
Raw Normal View History

2026-08-03 13:04:33 -04:00
#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);
}