bool write_key_values(size_t count, const key_value* key_values) { bool result = true; while (count-->0) { result = result && write_key_value(key_values++); } return result; }
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; }