diff --git a/Makefile b/Makefile index db0c9cb..ff78e45 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS=-g -O1 -Wall -Wno-switch -Wextra -Wwrite-strings -fstack-protector-strong -D_FORTIFY_SOURCE=2 -ALL = scan thread hdr show +ALL = scan thread hdr show list all: $(ALL) @@ -8,6 +8,7 @@ scan: blaze822.o scan.o rfc2047.o thread: blaze822.o thread.o hdr: blaze822.o hdr.o show: blaze822.o show.o +list: list.o clean: FRC -rm -f $(ALL) *.o diff --git a/list.c b/list.c new file mode 100644 index 0000000..7b7f02d --- /dev/null +++ b/list.c @@ -0,0 +1,202 @@ +#define _GNU_SOURCE +#include /* Defines DT_* constants */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define handle_error(msg) \ + do { perror(msg); exit(EXIT_FAILURE); } while (0) + +#define lc(c) ((c) | 0x20) +#define uc(c) ((c) & 0xdf) + +/* + +PRSTDF +prstdf + +-N new +-n not new + +-C cur +-c not cur + +-m age + +-r recursive? + +*/ + +static int8_t flags[255]; +static int flagsum; +static int flagset; +static int Nflag; +static int Cflag; + +void +list(char *prefix, char *file) +{ + if (flagset) { + int sum = 0; + char *f = strstr(file, ":2,"); + if (!f) + return; + f += 3; + while (*f) { + if (flags[(unsigned int)*f] == -1) + return; + if (flags[(unsigned int)*f] == 1) + sum++; + f++; + } + if (sum != flagsum) + return; + } + + if (prefix) { + fputs(prefix, stdout); + putc('/', stdout); + } + puts(file); +} + +#ifdef __linux__ +// faster implementation of readdir using a bigger getdents buffer + +struct linux_dirent64 { + ino64_t d_ino; /* 64-bit inode number */ + off64_t d_off; /* 64-bit offset to next structure */ + unsigned short d_reclen; /* Size of this dirent */ + unsigned char d_type; /* File type */ + char d_name[]; /* Filename (null-terminated) */ +}; +#define BUF_SIZE 1024000 + +void +listdir(char *dir) +{ + int fd, nread; + char buf[BUF_SIZE]; + struct linux_dirent64 *d; + int bpos; + + fd = open(dir, O_RDONLY | O_DIRECTORY); + if (fd == -1) { + perror("open"); + return; + } + + while (1) { + nread = syscall(SYS_getdents64, fd, buf, BUF_SIZE); + if (nread == -1) + handle_error("getdents64"); + + if (nread == 0) + break; + + for (bpos = 0; bpos < nread;) { + d = (struct linux_dirent64 *) (buf + bpos); + if (d->d_type != DT_REG && d->d_type != DT_UNKNOWN) + goto next; + if (d->d_name[0] == '.') + goto next; + list(dir, d->d_name); +next: + bpos += d->d_reclen; + } + } + + close(fd); +} +#else +void +listdir(char *dir) +{ + DIR *fd; + struct dirent *d; + + fd = opendir(dir); + if (!fd) + return; + while ((d = readdir(fd))) { + if (d->d_type != DT_REG && d->d_type != DT_UNKNOWN) + continue; + if (d->d_name[0] == '.') + continue; + list(dir, d->d_name); + } + closedir(fd); +} +#endif + +int +main(int argc, char *argv[]) +{ + int c; + while ((c = getopt(argc, argv, "PRSTDFprstdfNnCcm:")) != -1) + switch(c) { + case 'P': case 'R': case 'S': case 'T': case 'D': case 'F': + flags[(unsigned int)c] = 1; + break; + case 'p': case 'r': case 's': case 't': case 'd': case 'f': + flags[(unsigned int)uc(c)] = -1; + break; + case 'N': Nflag = 1; break; + case 'n': Nflag = -1; break; + case 'C': Cflag = 1; break; + case 'c': Cflag = -1; break; + case 'm': // XXX todo + default: + // XXX usage + exit(1); + } + + int i; + + for (i = 0, flagsum = 0, flagset = 0; i < sizeof flags; i++) { + if (flags[i] != 0) + flagset++; + if (flags[i] == 1) + flagsum++; + } + + for (i = optind; i < argc; i++) { + struct stat st; + if (stat(argv[i], &st) < 0) + continue; + if (S_ISDIR(st.st_mode)) { + char subdir[PATH_MAX]; + struct stat st2; + int maildir = 0; + + snprintf(subdir, sizeof subdir, "%s/cur", argv[i]); + if (stat(subdir, &st2) == 0) { + maildir = 1; + if (Cflag >= 0 && Nflag <= 0) + listdir(subdir); + } + + snprintf(subdir, sizeof subdir, "%s/new", argv[i]); + if (stat(subdir, &st2) == 0) { + maildir = 1; + if (Nflag >= 0 && Cflag <= 0) + listdir(subdir); + } + + if (!maildir) + listdir(argv[i]); + } else if (S_ISREG(st.st_mode)) { + list(0, argv[i]); + } + } + +exit(0); + + exit(EXIT_SUCCESS); +}