From 05020632bc1cb10a84805143e19d01f7244059be Mon Sep 17 00:00:00 2001
From: Luis Gerhorst <privat@luisgerhorst.de>
Date: Thu, 13 May 2021 20:42:41 +0200
Subject: [PATCH] fp-based find-magic

---
 src/task-find-magic     |  2 +-
 src/task_filter_magic.c | 67 ++++++++++++++++++++++++++++++++++-------
 2 files changed, 57 insertions(+), 12 deletions(-)

diff --git a/src/task-find-magic b/src/task-find-magic
index a97489e..f3d77e6 100755
--- a/src/task-find-magic
+++ b/src/task-find-magic
@@ -6,4 +6,4 @@ args=${@:2}
 
 src_dir=$(dirname "$(command -v $0)")
 
-find "${path}" | env -C "$src_dir" ./task_filter_magic ${args}
+find "${path}" | ${src_dir}/task_filter_magic ${args}
diff --git a/src/task_filter_magic.c b/src/task_filter_magic.c
index 45a0c7a..4194008 100644
--- a/src/task_filter_magic.c
+++ b/src/task_filter_magic.c
@@ -181,20 +181,17 @@ destroy:
 	return EXIT_SUCCESS;
 }
 
-static char *safe_fgets(char *s, int size, FILE *stream) {
-    char *res = fgets(s, size, stream);
-    if (res == NULL && ferror(stream)) {
-        perror("fgets");
-        exit(EXIT_FAILURE);
-    }
-    return res;
-}
-
 #define MAX_PATHLEN 512
 
 static int filter_magic(size_t offset, const char *magic) {
+	int err;
+	size_t magic_size = strlen(magic) + 1;
+	char buf[magic_size];
+	buf[magic_size-1] = '\0';
+
 	while (true) {
 		char pathbuf[MAX_PATHLEN];
+		/* TODO: What if line too long? */
 		char *ptr = fgets(pathbuf, MAX_PATHLEN, stdin);
 		if (ptr == NULL) {
 			if (ferror(stdin)) {
@@ -206,9 +203,57 @@ static int filter_magic(size_t offset, const char *magic) {
 			}
 		}
 
-		pathbuf[strlen(pathbuf)] = '\0';
-
+		/* Line must end with a newline. */
+		pathbuf[strlen(pathbuf)-1] = '\0';
 		log_debug("pathbuf = %s", pathbuf);
+
+		FILE *fp = fopen(pathbuf, "r");
+		if (!fp) {
+			perror(pathbuf);
+			return EXIT_FAILURE;
+		}
+
+		struct stat statbuf;
+		err = fstat(fileno(fp), &statbuf);
+		if (err != 0) {
+			log_debug("Skipping %s: Error fstat()ing file.", pathbuf);
+			goto fclose;
+		}
+
+		// handling only regular files and FIFOs
+		if (!S_ISREG(statbuf.st_mode) && !S_ISFIFO(statbuf.st_mode)) {
+			log_debug("Skipping %s: Mode %u is not a file.", pathbuf, statbuf.st_mode);
+			goto fclose;
+		}
+
+		if (statbuf.st_size < offset + magic_size-1) {
+			goto fclose;
+		}
+
+		if (offset) {
+			err = fseek(fp, offset, SEEK_SET);
+			if (err) {
+				perror("fseek");
+				return EXIT_FAILURE;
+			}
+		}
+
+		size_t nread = fread(buf, sizeof(char), magic_size-1, fp);
+		if (nread < magic_size-1) {
+			log_err("fread(%s) returned short item count", pathbuf);
+			return EXIT_FAILURE;
+		}
+
+		if (strcmp(magic, buf) == 0) {
+			printf("%s\n", pathbuf);
+		}
+
+	fclose:
+		err = fclose(fp);
+		if (err) {
+			perror("fclose");
+			return EXIT_FAILURE;
+		}
 	}
 }
 
-- 
GitLab