commit c37dcd6c0ddfee55ec676ddf644e863c28c1b453
parent 858326c0faa59d484157d59cf713b2c572e6bfa7
Author: Nihal Jere <nihal@nihaljere.xyz>
Date: Tue, 9 Mar 2021 23:23:15 -0600
add manifest.* to contain manifest operations
Diffstat:
3 files changed, 111 insertions(+), 0 deletions(-)
diff --git a/common.h b/common.h
@@ -10,6 +10,7 @@
#define PATH_LEN 512
#define URL_LEN 2048
#define ALT_MAX 256
+#define MANIFEST_LINES 100
#define KISS_INSTALLED "/var/db/kiss/installed"
#define KISS_CHOICES "/var/db/kiss/choices"
diff --git a/manifest.c b/manifest.c
@@ -0,0 +1,101 @@
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "manifest.h"
+
+int
+manifest_open(struct manifest_t *manifest, char path[PATH_LEN])
+{
+ int fd, linelimit;
+ struct stat s;
+ char *start = NULL, **lines = NULL, **temp;
+ size_t lc, cc;
+
+ linelimit = MANIFEST_LINES;
+ if ((lines = calloc(MANIFEST_LINES, sizeof(char *))) == NULL)
+ goto err;
+
+ if ((fd = open(path, O_RDONLY)) == -1)
+ goto err;
+
+ if (fstat(fd, &s) == -1)
+ goto err;
+
+ /* load the whole manifest into memory, with permissions that will allow us
+ * to write to the memory map without writing to the file */
+ start = mmap(NULL, s.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (start == MAP_FAILED) {
+ start = 0;
+ goto err;
+ }
+ close(fd);
+ fd = 0;
+
+ cc = s.st_size;
+
+ /* create array of pointers to the each line, and replace \n with \0.
+ * since manifest is sorted, we can use this to search for file names when
+ * validating a tarball on install */
+ lines[0] = start;
+ lc = 1;
+ for (int i = 0; i < cc; i++) {
+ if (start[i] != '\n')
+ continue;
+
+ if (lc == linelimit) {
+ if ((temp = realloc(lines, linelimit*2*sizeof(char *))) == NULL)
+ goto err;
+ lines = temp;
+ linelimit *= 2;
+ }
+
+ start[i] = '\0';
+
+ if (++i == cc)
+ break;
+
+ lines[lc++] = start + i;
+ }
+
+ /* one we know how many lines there are, we can shrink to only as much as
+ * we need */
+ if ((temp = realloc(lines, (lc+1)*sizeof(char *))) == NULL)
+ goto err;
+
+ /* null terminate to more easily know when we're done */
+ temp[lc] = 0;
+
+ manifest->start = start;
+ manifest->lines = temp;
+ manifest->lc = lc;
+ manifest->cc = cc;
+
+ return 0;
+err:
+ if (lines) free(lines);
+ if (fd) close(fd);
+ if (start) munmap(start, cc);
+ return -1;
+}
+
+int
+manifest_close(struct manifest_t *manifest)
+{
+ if (munmap(manifest->start, manifest->cc) == -1)
+ return -1;
+ manifest->start = NULL;
+
+ free(manifest->lines);
+ manifest->lines = NULL;
+
+ manifest->lc = 0;
+ manifest->cc = 0;
+
+ return 0;
+}
diff --git a/manifest.h b/manifest.h
@@ -0,0 +1,9 @@
+struct manifest_t {
+ char *start;
+ char **lines;
+ size_t lc;
+ size_t cc;
+};
+
+int manifest_open(struct manifest_t *manifest, char path[PATH_LEN]);
+int manifest_close(struct manifest_t *manifest);