Skip to content

Instantly share code, notes, and snippets.

@laamalif
Created January 16, 2025 15:49
Show Gist options
  • Save laamalif/96b0aa743c497048ebded948521586a5 to your computer and use it in GitHub Desktop.
Save laamalif/96b0aa743c497048ebded948521586a5 to your computer and use it in GitHub Desktop.
rm with getdents
#define _GNU_SOURCE
#include <dirent.h>
#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>
#include <errno.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
int force = 0;
void delete_entry(const char *path);
void delete_directory(const char *path) {
int fd, nread;
char buf[BUF_SIZE];
struct linux_dirent *d;
int bpos;
char fullpath[PATH_MAX];
fd = open(path, O_RDONLY | O_DIRECTORY);
if (fd == -1) {
if (!force) perror("open directory");
return;
}
for (;;) {
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1) {
if (!force) perror("getdents");
close(fd);
return;
}
if (nread == 0)
break;
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *)(buf + bpos);
// Skip "." and ".."
if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) {
bpos += d->d_reclen;
continue;
}
snprintf(fullpath, sizeof(fullpath), "%s/%s", path, d->d_name);
delete_entry(fullpath);
bpos += d->d_reclen;
}
}
close(fd);
if (rmdir(path) == -1 && !force) {
perror("rmdir");
}
}
void delete_entry(const char *path) {
struct stat st;
if (stat(path, &st) == -1) {
if (!force && errno != ENOENT) perror("stat");
return;
}
if (S_ISDIR(st.st_mode)) {
delete_directory(path);
} else {
if (unlink(path) == -1 && !force) {
perror("unlink");
}
}
}
int main(int argc, char *argv[]) {
int recursive = 0;
if (argc < 2) {
fprintf(stderr, "Usage: %s [-fr] <file_or_directory> [<file_or_directory> ...]\n", argv[0]);
exit(EXIT_FAILURE);
}
// Parse flags
for (int i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
for (char *p = &argv[i][1]; *p; p++) {
if (*p == 'f') {
force = 1;
} else if (*p == 'r') {
recursive = 1;
} else {
fprintf(stderr, "Unknown option: -%c\n", *p);
exit(EXIT_FAILURE);
}
}
} else {
delete_entry(argv[i]);
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment