blob: 9f7505a21ba7190c87cca8a385f74aadaa2a9905 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023 SUSE Linux Products GmbH. All Rights Reserved.
*/
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
/*
* Number of files we add to the test directory after calling opendir(3) and
* before calling rewinddir(3).
*/
#define NUM_FILES 10000
int main(int argc, char *argv[])
{
int file_counters[NUM_FILES] = { 0 };
int dot_count = 0;
int dot_dot_count = 0;
struct dirent *entry;
DIR *dir = NULL;
char *dir_path = NULL;
char *file_path = NULL;
int ret = 0;
int i;
if (argc != 2) {
fprintf(stderr, "Usage: %s <directory>\n", argv[0]);
ret = 1;
goto out;
}
dir_path = malloc(strlen(argv[1]) + strlen("/testdir") + 1);
if (!dir_path) {
fprintf(stderr, "malloc failure\n");
ret = ENOMEM;
goto out;
}
i = strlen(argv[1]);
memcpy(dir_path, argv[1], i);
memcpy(dir_path + i, "/testdir", strlen("/testdir"));
dir_path[i + strlen("/testdir")] = '\0';
/* More than enough to contain any full file path. */
file_path = malloc(strlen(dir_path) + 12);
if (!file_path) {
fprintf(stderr, "malloc failure\n");
ret = ENOMEM;
goto out;
}
ret = mkdir(dir_path, 0700);
if (ret == -1) {
fprintf(stderr, "Failed to create test directory: %d\n", errno);
ret = errno;
goto out;
}
/* Open the directory first. */
dir = opendir(dir_path);
if (dir == NULL) {
fprintf(stderr, "Failed to open directory: %d\n", errno);
ret = errno;
goto out;
}
/*
* Now create all files inside the directory.
* File names go from 1 to NUM_FILES, 0 is unused as it's the return
* value for atoi(3) when an error happens.
*/
for (i = 1; i <= NUM_FILES; i++) {
FILE *f;
sprintf(file_path, "%s/%d", dir_path, i);
f = fopen(file_path, "w");
if (f == NULL) {
fprintf(stderr, "Failed to create file number %d: %d\n",
i, errno);
ret = errno;
goto out;
}
fclose(f);
}
/*
* Rewind the directory and read it.
* POSIX requires that after a rewind, any new names added to the
* directory after the openddir(3) call and before the rewinddir(3)
* call, must be returned by readdir(3) calls
*/
rewinddir(dir);
/*
* readdir(3) returns NULL when it reaches the end of the directory or
* when an error happens, so reset errno to 0 to distinguish between
* both cases later.
*/
errno = 0;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0) {
dot_count++;
continue;
}
if (strcmp(entry->d_name, "..") == 0) {
dot_dot_count++;
continue;
}
i = atoi(entry->d_name);
if (i == 0) {
fprintf(stderr,
"Failed to parse name '%s' to integer: %d\n",
entry->d_name, errno);
ret = errno;
goto out;
}
/* File names go from 1 to NUM_FILES, so subtract 1. */
file_counters[i - 1]++;
}
if (errno) {
fprintf(stderr, "Failed to read directory: %d\n", errno);
ret = errno;
goto out;
}
/*
* Now check that the readdir() calls return every single file name
* and without repeating any of them. If any name is missing or
* repeated, don't exit immediatelly, so that we print a message for
* all missing or repeated names.
*/
for (i = 0; i < NUM_FILES; i++) {
if (file_counters[i] != 1) {
fprintf(stderr, "File name %d appeared %d times\n",
i + 1, file_counters[i]);
ret = EINVAL;
}
}
if (dot_count != 1) {
fprintf(stderr, "File name . appeared %d times\n", dot_count);
ret = EINVAL;
}
if (dot_dot_count != 1) {
fprintf(stderr, "File name .. appeared %d times\n", dot_dot_count);
ret = EINVAL;
}
out:
free(dir_path);
free(file_path);
if (dir != NULL)
closedir(dir);
return ret;
}