]> git.ipfire.org Git - people/ric9/pakfire.git/commitdiff
file: Build a function to search a file for a string
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 4 Jan 2025 15:27:26 +0000 (15:27 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 4 Jan 2025 15:27:26 +0000 (15:27 +0000)
This is done by mapping the file into memory and performing a fast
string search.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/pakfire/file.c
src/pakfire/file.h

index d2e7e8048db5635d8d9e906d6ed454bdbe193a6e..c7a25490896c45e4a3e7d60a1c301446aa2c9854 100644 (file)
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/capability.h>
+#include <sys/mman.h>
 #include <sys/sendfile.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -1126,55 +1127,86 @@ FILE* pakfire_file_fopen(struct pakfire_file* file, const char* mode) {
        return f;
 }
 
-int pakfire_file_payload_matches(struct pakfire_file* file,
-               const void* needle, const size_t length) {
-       char buffer[1024 * 1024];
-       FILE* f = NULL;
-       void* p = NULL;
+/*
+       Opens the file and returns a mapping of the payload in memory
+*/
+static int pakfire_file_mmap(struct pakfire_file* file, char** data, size_t* length) {
+       struct stat st = {};
+       char* buffer = NULL;
+       int fd = -EBADF;
+       int r;
+
+       // Open the file
+       fd = r = pakfire_file_open(file, O_RDONLY);
+       if (fd < 0)
+               goto ERROR;
+
+       // Stat the file
+       r = fstat(fd, &st);
+       if (r < 0) {
+               ERROR(file->ctx, "Could not stat %s: %m\n", pakfire_file_get_path(file));
+               r = -errno;
+               goto ERROR;
+       }
+
+       // Map the data
+       buffer = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (buffer == MAP_FAILED) {
+               ERROR(file->ctx, "Could not map %s: %m\n", pakfire_file_get_path(file));
+               r = -errno;
+               goto ERROR;
+       }
+
+       // Return the values
+       *data = buffer;
+       *length = st.st_size;
+
+ERROR:
+       if (fd >= 0)
+               close(fd);
+
+       return r;
+}
+
+int pakfire_file_contains(struct pakfire_file* file, const char* needle, ssize_t length) {
+       char* haystack = NULL;
+       size_t l = 0;
+       int pos;
        int r;
 
+       // Check inputs
+       if (!needle)
+               return -EINVAL;
+
        const mode_t mode = pakfire_file_get_mode(file);
 
        // Only run for regular files
        if (!S_ISREG(mode))
                return 0;
 
-       const size_t size = pakfire_file_get_size(file);
-
-       // Skip empty files
-       if (!size)
-               return 0;
-
-       // Open the file
-       f = pakfire_file_fopen(file, "r");
-       if (!f) {
-               r = 1;
+       // Map the file into memory
+       r = pakfire_file_mmap(file, &haystack, &l);
+       if (r < 0)
                goto ERROR;
-       }
 
-       while (!feof(f)) {
-               size_t bytes_read = fread(buffer, 1, sizeof(buffer), f);
+       // Perform the search
+       pos = pakfire_string_search(haystack, l, needle, length);
 
-               // Raise any reading errors
-               if (ferror(f)) {
-                       r = 1;
-                       goto ERROR;
-               }
+       // No match found
+       if (pos == -1)
+               r = 0;
 
-               // Search for the needle
-               p = memmem(buffer, bytes_read, needle, length);
-               if (p) {
-                       r = 1;
-                       goto ERROR;
-               }
-       }
+       // Match found
+       else if (pos >= 0)
+               r = pos;
 
-       // No match
-       r = 0;
+       // Error
+       else if (pos < 0)
+               r = pos;
 
 ERROR:
-       if (f)
-               fclose(f);
+       if (haystack)
+               munmap(haystack, l);
 
        return r;
 }
index d5bdfbe50c7593a7bbfe252ae17e27adaac48ec0..e77f3d00f23cd1f6fa43278650eea8cb3d9f6f1f 100644 (file)
@@ -159,8 +159,7 @@ const char* pakfire_file_get_abspath(struct pakfire_file* file);
 int pakfire_file_open(struct pakfire_file* file, int flags);
 FILE* pakfire_file_fopen(struct pakfire_file* file, const char* mode);
 
-int pakfire_file_payload_matches(struct pakfire_file* file,
-       const void* needle, const size_t length);
+int pakfire_file_contains(struct pakfire_file* file, const char* needle, ssize_t length);
 
 int pakfire_file_compute_digests(struct pakfire_file* file, const int types);