nkiss

WIP
git clone git://git.nihaljere.xyz/nkiss
Log | Files | Refs

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:
Mutil.c | 100++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mutil.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 */