#include "aksl_capture.h" #include #include #include #include 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; /* opendir propagates missing-path and non-directory failures. */ 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); /* Every pointer required by the wrapped operation rejects NULL. */ AKSL_CHECK_STATUS(aksl_opendir(NULL, &dirp), AKERR_NULLPOINTER); AKSL_CHECK_STATUS(aksl_opendir(".", NULL), AKERR_NULLPOINTER); /* fdopendir propagates an invalid descriptor and validates its out-param. */ AKSL_CHECK_STATUS(aksl_fdopendir(-1, &dirp), EBADF); AKSL_CHECK_STATUS(aksl_fdopendir(0, NULL), AKERR_NULLPOINTER); /* The remaining wrappers reject NULL streams and destinations. */ 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); }