From: Michael Tremer Date: Sat, 4 Jan 2025 15:27:26 +0000 (+0000) Subject: file: Build a function to search a file for a string X-Git-Tag: 0.9.30~538 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e073d0d4e2e0499e0579271056823495c5cce9a1;p=pakfire.git file: Build a function to search a file for a string This is done by mapping the file into memory and performing a fast string search. Signed-off-by: Michael Tremer --- diff --git a/src/pakfire/file.c b/src/pakfire/file.c index d2e7e8048..c7a254908 100644 --- a/src/pakfire/file.c +++ b/src/pakfire/file.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -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; } diff --git a/src/pakfire/file.h b/src/pakfire/file.h index d5bdfbe50..e77f3d00f 100644 --- a/src/pakfire/file.h +++ b/src/pakfire/file.h @@ -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);