aboutsummaryrefslogtreecommitdiff
path: root/drive-sdk/deps/bzle/tools/textfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'drive-sdk/deps/bzle/tools/textfile.c')
-rw-r--r--drive-sdk/deps/bzle/tools/textfile.c475
1 files changed, 475 insertions, 0 deletions
diff --git a/drive-sdk/deps/bzle/tools/textfile.c b/drive-sdk/deps/bzle/tools/textfile.c
new file mode 100644
index 0000000..7267f3a
--- /dev/null
+++ b/drive-sdk/deps/bzle/tools/textfile.c
@@ -0,0 +1,475 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+
+#include "textfile.h"
+
+static int create_dirs(const char *filename, const mode_t mode)
+{
+ struct stat st;
+ char dir[PATH_MAX + 1], *prev, *next;
+ int err;
+
+ err = stat(filename, &st);
+ if (!err && S_ISREG(st.st_mode))
+ return 0;
+
+ memset(dir, 0, PATH_MAX + 1);
+ strcat(dir, "/");
+
+ prev = strchr(filename, '/');
+
+ while (prev) {
+ next = strchr(prev + 1, '/');
+ if (!next)
+ break;
+
+ if (next - prev == 1) {
+ prev = next;
+ continue;
+ }
+
+ strncat(dir, prev + 1, next - prev);
+ mkdir(dir, mode);
+
+ prev = next;
+ }
+
+ return 0;
+}
+
+int create_file(const char *filename, const mode_t mode)
+{
+ int fd;
+
+ create_dirs(filename, S_IRUSR | S_IWUSR | S_IXUSR);
+
+ fd = open(filename, O_RDWR | O_CREAT, mode);
+ if (fd < 0)
+ return fd;
+
+ close(fd);
+
+ return 0;
+}
+
+int create_name(char *buf, size_t size, const char *path, const char *address, const char *name)
+{
+ return snprintf(buf, size, "%s/%s/%s", path, address, name);
+}
+
+static inline char *find_key(char *map, size_t size, const char *key, size_t len, int icase)
+{
+ char *ptr = map;
+ size_t ptrlen = size;
+
+ while (ptrlen > len + 1) {
+ int cmp = (icase) ? strncasecmp(ptr, key, len) : strncmp(ptr, key, len);
+ if (cmp == 0) {
+ if (ptr == map && *(ptr + len) == ' ')
+ return ptr;
+
+ if ((*(ptr - 1) == '\r' || *(ptr - 1) == '\n') &&
+ *(ptr + len) == ' ')
+ return ptr;
+ }
+
+ if (icase) {
+ char *p1 = memchr(ptr + 1, tolower(*key), ptrlen - 1);
+ char *p2 = memchr(ptr + 1, toupper(*key), ptrlen - 1);
+
+ if (!p1)
+ ptr = p2;
+ else if (!p2)
+ ptr = p1;
+ else
+ ptr = (p1 < p2) ? p1 : p2;
+ } else
+ ptr = memchr(ptr + 1, *key, ptrlen - 1);
+
+ if (!ptr)
+ return NULL;
+
+ ptrlen = size - (ptr - map);
+ }
+
+ return NULL;
+}
+
+static inline int write_key_value(int fd, const char *key, const char *value)
+{
+ char *str;
+ size_t size;
+ int err = 0;
+
+ size = strlen(key) + strlen(value) + 2;
+
+ str = malloc(size + 1);
+ if (!str)
+ return ENOMEM;
+
+ sprintf(str, "%s %s\n", key, value);
+
+ if (write(fd, str, size) < 0)
+ err = -errno;
+
+ free(str);
+
+ return err;
+}
+
+static char *strnpbrk(const char *s, ssize_t len, const char *accept)
+{
+ const char *p = s;
+ const char *end;
+
+ end = s + len - 1;
+
+ while (p <= end && *p) {
+ const char *a = accept;
+
+ while (*a) {
+ if (*p == *a)
+ return (char *) p;
+ a++;
+ }
+
+ p++;
+ }
+
+ return NULL;
+}
+
+static int write_key(const char *pathname, const char *key, const char *value, int icase)
+{
+ struct stat st;
+ char *map, *off, *end, *str;
+ off_t size;
+ size_t base;
+ int fd, len, 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) {
+ if (value) {
+ lseek(fd, size, SEEK_SET);
+ err = write_key_value(fd, key, value);
+ }
+ goto unlock;
+ }
+
+ map = mmap(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_LOCKED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ err = -errno;
+ goto unlock;
+ }
+
+ len = strlen(key);
+ off = find_key(map, size, key, len, icase);
+ if (!off) {
+ munmap(map, size);
+ if (value) {
+ lseek(fd, size, SEEK_SET);
+ err = write_key_value(fd, key, value);
+ }
+ goto unlock;
+ }
+
+ base = off - map;
+
+ end = strnpbrk(off, size, "\r\n");
+ if (!end) {
+ err = -EILSEQ;
+ goto unmap;
+ }
+
+ if (value && ((ssize_t) strlen(value) == end - off - len - 1) &&
+ !strncmp(off + len + 1, value, end - off - len - 1))
+ goto unmap;
+
+ len = strspn(end, "\r\n");
+ end += len;
+
+ len = size - (end - map);
+ if (!len) {
+ munmap(map, size);
+ if (ftruncate(fd, base) < 0) {
+ err = -errno;
+ goto unlock;
+ }
+ lseek(fd, base, SEEK_SET);
+ if (value)
+ err = write_key_value(fd, key, value);
+
+ goto unlock;
+ }
+
+ if (len < 0 || len > size) {
+ err = -EILSEQ;
+ goto unmap;
+ }
+
+ str = malloc(len);
+ if (!str) {
+ err = -errno;
+ goto unmap;
+ }
+
+ memcpy(str, end, len);
+
+ munmap(map, size);
+ if (ftruncate(fd, base) < 0) {
+ err = -errno;
+ free(str);
+ goto unlock;
+ }
+ lseek(fd, base, SEEK_SET);
+ if (value)
+ err = write_key_value(fd, key, value);
+
+ if (write(fd, str, len) < 0)
+ err = -errno;
+
+ free(str);
+
+ goto unlock;
+
+unmap:
+ munmap(map, size);
+
+unlock:
+ flock(fd, LOCK_UN);
+
+close:
+ fdatasync(fd);
+
+ close(fd);
+ errno = -err;
+
+ return err;
+}
+
+static char *read_key(const char *pathname, const char *key, int icase)
+{
+ struct stat st;
+ char *map, *off, *end, *str = NULL;
+ off_t size; size_t len;
+ int fd, err = 0;
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ if (flock(fd, LOCK_SH) < 0) {
+ err = -errno;
+ goto close;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ err = -errno;
+ goto unlock;
+ }
+
+ size = st.st_size;
+
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ err = -errno;
+ goto unlock;
+ }
+
+ len = strlen(key);
+ off = find_key(map, size, key, len, icase);
+ if (!off) {
+ err = -EILSEQ;
+ goto unmap;
+ }
+
+ end = strnpbrk(off, size - (off - map), "\r\n");
+ if (!end) {
+ err = -EILSEQ;
+ goto unmap;
+ }
+
+ str = malloc(end - off - len);
+ if (!str) {
+ err = -EILSEQ;
+ goto unmap;
+ }
+
+ memset(str, 0, end - off - len);
+ strncpy(str, off + len + 1, end - off - len - 1);
+
+unmap:
+ munmap(map, size);
+
+unlock:
+ flock(fd, LOCK_UN);
+
+close:
+ close(fd);
+ errno = -err;
+
+ return str;
+}
+
+int textfile_put(const char *pathname, const char *key, const char *value)
+{
+ return write_key(pathname, key, value, 0);
+}
+
+int textfile_del(const char *pathname, const char *key)
+{
+ return write_key(pathname, key, NULL, 0);
+}
+
+char *textfile_get(const char *pathname, const char *key)
+{
+ return read_key(pathname, key, 0);
+}
+
+int textfile_foreach(const char *pathname, textfile_cb func, void *data)
+{
+ struct stat st;
+ char *map, *off, *end, *key, *value;
+ off_t size; size_t len;
+ int fd, err = 0;
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0)
+ return -errno;
+
+ if (flock(fd, LOCK_SH) < 0) {
+ err = -errno;
+ goto close;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ err = -errno;
+ goto unlock;
+ }
+
+ size = st.st_size;
+
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!map || map == MAP_FAILED) {
+ err = -errno;
+ goto unlock;
+ }
+
+ off = map;
+
+ while (size - (off - map) > 0) {
+ end = strnpbrk(off, size - (off - map), " ");
+ if (!end) {
+ err = -EILSEQ;
+ break;
+ }
+
+ len = end - off;
+
+ key = malloc(len + 1);
+ if (!key) {
+ err = -errno;
+ break;
+ }
+
+ memset(key, 0, len + 1);
+ memcpy(key, off, len);
+
+ off = end + 1;
+
+ if (size - (off - map) < 0) {
+ err = -EILSEQ;
+ free(key);
+ break;
+ }
+
+ end = strnpbrk(off, size - (off - map), "\r\n");
+ if (!end) {
+ err = -EILSEQ;
+ free(key);
+ break;
+ }
+
+ len = end - off;
+
+ value = malloc(len + 1);
+ if (!value) {
+ err = -errno;
+ free(key);
+ break;
+ }
+
+ memset(value, 0, len + 1);
+ memcpy(value, off, len);
+
+ func(key, value, data);
+
+ free(key);
+ free(value);
+
+ off = end + 1;
+ }
+
+ munmap(map, size);
+
+unlock:
+ flock(fd, LOCK_UN);
+
+close:
+ close(fd);
+ errno = -err;
+
+ return 0;
+}