Last active
June 14, 2023 03:00
-
-
Save 61131/7b137d758338ff41e8028aa588631f05 to your computer and use it in GitHub Desktop.
Build array of all directories under given file location (without recursion!)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <limits.h> | |
#include <dirent.h> | |
#include <errno.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
/* See https://gist.github.com/61131/a4d5846dd2fb4aaa22ecf9e05a3b34a1 */ | |
#include <strl.h> | |
#define IS_DIR_SEP(c) (((c) == '/') || ((c) == '\\')) | |
static int | |
_isdir(char const *path) { | |
struct stat buf; | |
if (lstat(path, &buf) < 0) { | |
if (errno == ENOENT) { | |
return 0; | |
} | |
return 0; | |
} | |
return (int)(S_ISDIR(buf.st_mode) && !S_ISLNK(buf.st_mode)); | |
} | |
/* | |
This function takes an array of canonical absolute directory paths that will | |
be validated in turn and expanded such that the paths array contains list of | |
_all_ directory paths under the original directory locations. | |
*/ | |
int | |
build_tree(int ndirs, char **dirs) { | |
char **paths, rpath[PATH_MAX]; | |
DIR *dp; | |
struct dirent *entry; | |
char path[PATH_MAX]; | |
int count, index; | |
count = 0; | |
paths = NULL; | |
for (index = 0; index < ndirs; ++index) { | |
if (!realpath(dirs[index], rpath)) { | |
return -1; | |
} | |
if (!_isdir(rpath)) { | |
continue; | |
} | |
if ((paths = realloc(paths, ++count * sizeof(char *))) == NULL) { | |
return -1; | |
} | |
paths[count - 1] = strdup(dirs[index]); | |
} | |
for (index = 0; index < count; ++index) { | |
if ((dp = opendir(paths[index])) == NULL) { | |
/* | |
The current array entry either does not appear to be a directory or is | |
otherwise inaccessible and as such, should be removed from the array. | |
*/ | |
free(paths[index]); | |
memmove(&paths[index], &paths[index + 1], (count - index) * sizeof(char *)); | |
if ((paths = realloc(paths, --count * sizeof(char *))) == NULL) { | |
return -1; | |
} | |
--index; | |
continue; | |
} | |
while ((entry = readdir(dp)) != NULL) { | |
if ((strcmp(entry->d_name, ".") == 0) || | |
(strcmp(entry->d_name, "..") == 0)) { | |
continue; | |
} | |
strlcpy(path, paths[index], PATH_MAX); | |
if (!IS_DIR_SEP(path[strlen(path) - 1])) { | |
strlcat(path, "/", PATH_MAX); | |
} | |
strlcat(path, entry->d_name, PATH_MAX); | |
if (!realpath(path, rpath) || | |
!_isdir(rpath)) { | |
continue; | |
} | |
if ((paths = realloc(paths, ++count * sizeof(char *))) == NULL) { | |
return -1; | |
} | |
/* | |
Depth-first: if (index < (count - 2)) { | |
memmove(&paths[index + 2], &paths[index + 1], (count - index - 2) * sizeof(char *)); | |
} | |
paths[index + 1] = strdup(rpath); | |
Breadth-first: paths[count - 1] = strdup(rpath); | |
*/ | |
if (index < (count - 2)) { | |
memmove(&paths[index + 2], &paths[index + 1], (count - index - 2) * sizeof(char *)); | |
} | |
paths[index + 1] = strdup(rpath); | |
} | |
closedir(dp); | |
} | |
/* | |
Now do something with paths, which has count elements ... | |
qsort(paths, count, sizeof(paths[0]), _strcmp); | |
for (index = 0; index < count; ++index) { | |
printf("%s\n", paths[index]); | |
} | |
*/ | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment