Skip to content

Instantly share code, notes, and snippets.

@laamalif
Created January 16, 2025 15:52
Show Gist options
  • Save laamalif/4389a22afd5b5ceca08f93da9067ad2b to your computer and use it in GitHub Desktop.
Save laamalif/4389a22afd5b5ceca08f93da9067ad2b to your computer and use it in GitHub Desktop.
List directories using getdents()
/*
* List directories using getdents() because ls, find and Python libraries
* use readdir() which is slower (but uses getdents() underneath.
*
* $ gcc gs.c -o gs
*/
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <string.h>
#include <limits.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
struct linux_dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[];
};
#define BUF_SIZE 1024*1024*5
void apply_color(mode_t mode, char *name) {
if (S_ISDIR(mode)) {
printf("\033[1;34m%s\033[0m", name); // Blue for directories
} else if (S_ISLNK(mode)) {
printf("\033[1;36m%s\033[0m", name); // Cyan for symlinks
} else if (mode & S_IXUSR) {
printf("\033[1;32m%s\033[0m", name); // Green for executables
} else {
printf("%s", name); // Default color
}
}
void list_directory(const char *path, int show_hidden) {
int fd, nread;
char buf[BUF_SIZE];
struct linux_dirent *d;
int bpos;
char d_type;
struct stat st;
char fullpath[PATH_MAX];
fd = open(path, O_RDONLY | O_DIRECTORY);
if (fd == -1)
handle_error("open");
for (;;) {
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1)
handle_error("getdents");
if (nread == 0)
break;
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
d_type = *(buf + bpos + d->d_reclen - 1);
// Skip "." and ".."
if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) {
bpos += d->d_reclen;
continue;
}
// Skip hidden files unless `-a` is provided
if (!show_hidden && d->d_name[0] == '.') {
bpos += d->d_reclen;
continue;
}
snprintf(fullpath, sizeof(fullpath), "%s/%s", path, d->d_name);
if (stat(fullpath, &st) == -1) {
perror("stat");
bpos += d->d_reclen;
continue;
}
apply_color(st.st_mode, d->d_name);
printf("\n");
bpos += d->d_reclen;
}
}
close(fd);
}
int main(int argc, char *argv[]) {
int show_hidden = 0;
char *path = ".";
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-a") == 0) {
show_hidden = 1;
} else {
path = argv[i];
}
}
list_directory(path, show_hidden);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment