summaryrefslogtreecommitdiffstats
path: root/common/textfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/textfile.c')
-rw-r--r--common/textfile.c160
1 files changed, 148 insertions, 12 deletions
diff --git a/common/textfile.c b/common/textfile.c
index 6f84cfa9..0bda2a94 100644
--- a/common/textfile.c
+++ b/common/textfile.c
@@ -40,51 +40,186 @@
#include <sys/stat.h>
#include <sys/mman.h>
+static int write_key_value(const int fd, const char *key, const char *value)
+{
+ char *str;
+ int size, err = 0;
+
+ size = strlen(key) + strlen(value) + 2;
+
+ str = malloc(size);
+ if (!str)
+ return ENOMEM;
+
+ sprintf(str, "%s %s\n", key, value);
+
+ if (write(fd, str, size) < 0)
+ err = errno;
+
+ free(str);
+
+ return err;
+}
+
+int textfile_put(const char *pathname, const char *key, const char *value)
+{
+ struct stat st;
+ char *map, *off, *end, *str;
+ off_t size, pos; size_t base, len;
+ int fd, err = 0;
+
+ fd = open(pathname, O_RDWR);
+ if (fd < 0)
+ return -errno;
+
+ if (flock(fd, LOCK_EX) < 0) {
+ err = errno;
+ goto close;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ err = errno;
+ goto unlock;
+ }
+
+ size = st.st_size;
+
+ if (!size) {
+ pos = lseek(fd, size, SEEK_SET);
+ err = write_key_value(fd, key, value);
+ goto unlock;
+ }
+
+ map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED) {
+ err = errno;
+ goto unlock;
+ }
+
+ off = strstr(map, key);
+ if (!off) {
+ munmap(map, size);
+ pos = lseek(fd, size, SEEK_SET);
+ err = write_key_value(fd, key, value);
+ goto unlock;
+ }
+
+ if (off > map) {
+ while (*(off - 1) != '\r' && *(off - 1) != '\n') {
+ off = strstr(off, key);
+ if (!off) {
+ munmap(map, size);
+ pos = lseek(fd, size, SEEK_SET);
+ err = write_key_value(fd, key, value);
+ goto unlock;
+ }
+ }
+ }
+
+ base = off - map;
+
+ end = strpbrk(off, "\r\n");
+ if (!end) {
+ err = EILSEQ;
+ goto unmap;
+ }
+
+ len = strspn(end, "\r\n");
+ end += len;
+
+ len = size - (end - map);
+
+ str = malloc(len);
+ if (!str) {
+ err = errno;
+ goto unmap;
+ }
+
+ memcpy(str, end, len);
+ munmap(map, size);
+
+ ftruncate(fd, base);
+ pos = lseek(fd, base, SEEK_SET);
+
+ write_key_value(fd, key, value);
+ write(fd, str, len);
+
+ free(str);
+
+ goto unlock;
+
+unmap:
+ munmap(map, size);
+
+unlock:
+ flock(fd, LOCK_UN);
+
+close:
+ close(fd);
+ errno = err;
+
+ return -err;
+}
+
char *textfile_get(const char *pathname, const char *key)
{
struct stat st;
char *map, *off, *end, *str = NULL;
off_t size; size_t len;
- int fd;
+ int fd, err = 0;
fd = open(pathname, O_RDONLY);
if (fd < 0)
return NULL;
- if (flock(fd, LOCK_SH) < 0)
+ if (flock(fd, LOCK_SH) < 0) {
+ err = errno;
goto close;
+ }
- if (fstat(fd, &st) < 0)
+ if (fstat(fd, &st) < 0) {
+ err = errno;
goto unlock;
+ }
size = st.st_size;
- map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
- if (map == MAP_FAILED)
- goto close;
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED) {
+ err = errno;
+ goto unlock;
+ }
off = strstr(map, key);
- if (!off)
+ if (!off) {
+ err = EILSEQ;
goto unmap;
+ }
if (off > map) {
while (*(off - 1) != '\r' && *(off - 1) != '\n') {
- off = strstr(map, key);
- if (!off)
+ off = strstr(off, key);
+ if (!off) {
+ err = EILSEQ;
goto unmap;
+ }
}
}
end = strpbrk(off, "\r\n");
- if (!end)
+ if (!end) {
+ err = EILSEQ;
goto unmap;
+ }
len = strlen(key);
str = malloc(end - off - len);
- memset(str, 0, end - off - len);
- if (!str)
+ if (!str) {
+ err = EILSEQ;
goto unmap;
+ }
+ memset(str, 0, end - off - len);
strncpy(str, off + len + 1, end - off - len - 1);
unmap:
@@ -95,6 +230,7 @@ unlock:
close:
close(fd);
+ errno = err;
return str;
}