about summary refs log tree commit diff
path: root/list.c
diff options
context:
space:
mode:
authorChristian Neukirchen <chneukirchen@gmail.com>2016-07-12 17:51:34 +0200
committerChristian Neukirchen <chneukirchen@gmail.com>2016-07-12 17:51:34 +0200
commit89e5dedf8b683e40b578b9211615beabfe58fa68 (patch)
treee6f45cd5f635c55fc9d75ff327164b442648cff0 /list.c
parent9b2a97416d60eac35b689dcc8a42681c5770e9f3 (diff)
downloadmblaze-89e5dedf8b683e40b578b9211615beabfe58fa68.tar.gz
mblaze-89e5dedf8b683e40b578b9211615beabfe58fa68.tar.xz
mblaze-89e5dedf8b683e40b578b9211615beabfe58fa68.zip
add list
Diffstat (limited to 'list.c')
-rw-r--r--list.c202
1 files changed, 202 insertions, 0 deletions
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 <dirent.h>     /* Defines DT_* constants */
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <stdint.h>
+#include <limits.h>
+
+#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);
+}