Created
January 16, 2025 15:49
-
-
Save laamalif/96b0aa743c497048ebded948521586a5 to your computer and use it in GitHub Desktop.
rm with getdents
This file contains hidden or 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
| #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