Last active
October 24, 2021 18:56
-
-
Save Cxarli/7f8c66221aed61598e4a49f06ff4c059 to your computer and use it in GitHub Desktop.
A little script to write an index of all files in the current directory
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 <sys/types.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <dirent.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <stdlib.h> | |
void printdirent(struct dirent *entry, int parent_fd, char *parent_name); | |
void collect(char *dirname, int parent_fd, char *parent_name); | |
void printdirent(struct dirent *entry, int parent_fd, char *parent_name) | |
{ | |
// Get entryname | |
char *name = entry->d_name; | |
// Get some stats such as size and modification time | |
struct stat statbuf; | |
if (fstatat(parent_fd, name, &statbuf, AT_SYMLINK_NOFOLLOW) == -1) { | |
fprintf(stderr, "lstat failed for %s: %s\n", name, strerror(errno)); | |
return; | |
} | |
off_t size = statbuf.st_size; | |
struct timespec modiftime = statbuf.st_mtim; | |
unsigned mode = statbuf.st_mode; | |
char *type = S_ISREG(mode) ? "REG" : S_ISDIR(mode) ? "DIR" : S_ISLNK(mode) ? "LNK" : "UNK"; | |
// Print all stats | |
printf("size=%ld\1mtime=%lu\1type=%s\1path=%s\1name=%s\n", | |
size, modiftime.tv_sec, type, parent_name, name); | |
} | |
void collect(char *dirname, int parent_fd, char *parent_name) | |
{ | |
// skip Trash directory | |
if (strcmp(dirname, ".Trash-1000") == 0) return; | |
// Open FD for directory | |
int dir_fd = openat(parent_fd, dirname, O_DIRECTORY | O_RDONLY); | |
if (dir_fd == -1) { | |
fprintf(stderr, "open failed for %s%s: %s\n", parent_name, dirname, strerror(errno)); | |
return; | |
} | |
// Get DIR struct for directory | |
DIR *dir = fdopendir(dir_fd); | |
if (dir == NULL) { | |
fprintf(stderr, "opendir failed for %s%s: %s\n", parent_name, dirname, strerror(errno)); | |
return; | |
} | |
// Current directory string | |
// TODO: support paths longer than 1024 chars? | |
char *dirstr = malloc(1024 * sizeof(*dirstr)); | |
strncpy(dirstr, parent_name, 1024); | |
strncat(dirstr, dirname, 1024); | |
strncat(dirstr, "/", 1024); | |
// Loop over all entries in directory | |
struct dirent *stats; | |
while ((stats = readdir(dir)) != NULL) { | |
// Ignore . and .. but do track dotfiles | |
if (strcmp(stats->d_name, ".") == 0 || strcmp(stats->d_name, "..") == 0) continue; | |
// Print stats for current entry | |
printdirent(stats, dir_fd, dirstr); | |
// If directory: recurse | |
if (stats->d_type == DT_DIR) { | |
collect(stats->d_name, dir_fd, dirstr); | |
} | |
} | |
// Clean up all resources | |
free(dirstr); | |
closedir(dir); | |
close(dir_fd); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
// Get directory name from first argument or default to . | |
char *dirname = "."; | |
if (argc > 1) { | |
dirname = argv[1]; | |
} | |
collect(dirname, AT_FDCWD, ""); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Suggestions left for the reader:
\x1F
(unit separator
) instead of\x01
(start of heading
) as separatorstrncat
on the original pointer several times, but keep track where the previous one ended and continue theredu -a --time