commit 7b179d04562e1e25ed0b1d093a99d9f21b8fcdb5
parent 5e7672736a68726a151262675c750b492e5d9fff
Author: Nihal Jere <nihal@nihaljere.xyz>
Date: Mon, 22 Feb 2021 17:46:17 -0600
util.*: add file_dropadd
This function takes a path and two string parameters a and b, dropping
lines in the file point to by path that match a, and adding b, while
retaining lexographical sorting.
A function called 'mv' is also added, which moves a file, regardless of
what device its on.
Diffstat:
M | util.c | | | 100 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
M | util.h | | | 2 | ++ |
2 files changed, 99 insertions(+), 3 deletions(-)
diff --git a/util.c b/util.c
@@ -1,4 +1,6 @@
/* See LICENSE file for copyright and license details. */
+#define _BSD_SOURCE
+
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -7,10 +9,7 @@
#include <stdlib.h>
#include <string.h>
#include <tls.h>
-
-#ifdef __OpenBSD__
#include <unistd.h>
-#endif /* __OpenBSD__ */
#include "util.h"
@@ -69,6 +68,101 @@ strrepl(char *str, const char a, const char b)
}
}
+int
+mv(char *oldpath, char *newpath)
+{
+ char buf[BUFSIZ];
+ FILE *old, *new;
+
+ /* try simply renaming */
+ if (rename(oldpath, newpath) == -1) {
+ /* if that doesn't work because its on a different device, we have to
+ * copy content of the file */
+ if (errno == EXDEV) {
+ if ((old = fopen(oldpath, "r")) == NULL)
+ return -1;
+
+ if ((new = fopen(newpath, "w")) == NULL) {
+ fclose(old);
+ return -1;
+ }
+
+ /* TODO proper error handling */
+ while (fgets(buf, BUFSIZ, old) != NULL)
+ fputs(buf, new);
+
+ fclose(old);
+ fclose(new);
+
+ unlink(oldpath);
+ } else return -1;
+ }
+
+ return 0;
+}
+
+/* drop lines matching a, add lines matching b, while retaining reverse
+ * lexographical sorting.
+ * the main use for this will be rewriting manifest files on alt swap */
+int
+file_dropadd(char *path, char *a, char *b)
+{
+ int fd, found = 0;
+ FILE *file, *temp;
+ char temppath[] = "/tmp/kissmanifestXXXXXX";
+ char line[512], *p;
+
+ if (!a || !b || !path)
+ return -1;
+
+ if ((fd = mkstemp(temppath)) == -1)
+ return -1;
+
+ if ((temp = fdopen(fd, "w")) == NULL) {
+ close(fd);
+ return -1;
+ }
+
+ if ((file = fopen(path, "r")) == NULL) {
+ fclose(temp);
+ return -1;
+ }
+
+ while (fgets(line, 512, file)) {
+ if ((p = strchr(line, '\n')) == NULL) {
+ fclose(temp);
+ fclose(file);
+ return -1;
+ }
+
+ /* temporarily replace newline with \0 so the comparison works */
+ *p = '\0';
+ if (strcmp(a, line) == 0)
+ continue;
+
+ /* insert b if greater than line.
+ * i think the edge case where strcmp(b, line) == 0 can be ignored, as
+ * a manifest shouldn't already contain b when dealing with
+ * alternatives */
+ if (!found && strcmp(b, line) > 0) {
+ found = 1;
+ fputs(b, temp);
+ fputc('\n', temp);
+ }
+
+ *p = '\n';
+ fputs(line, temp);
+ }
+
+ fclose(temp);
+ fclose(file);
+
+ if (mv(temppath, path) == -1)
+ return -1;
+
+ return 0;
+}
+
/* essentially mkdir -p */
int
mkdirs(const char *path)
diff --git a/util.h b/util.h
@@ -16,5 +16,7 @@ void die(const char *, ...);
int vstrcmp(const void *p1, const void *p2);
void strrepl(char *str, const char a, const char b);
int mkdirs(const char *path);
+int mv(char *oldpath, char *newpath);
+int file_dropadd(char *path, char *a, char *b);
#endif /* UTIL_H */