diff options
| author | Marcel Holtmann <marcel@holtmann.org> | 2005-05-06 19:56:46 +0000 | 
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2005-05-06 19:56:46 +0000 | 
| commit | c6f99123f1269ad3742100eec084902a31e774bd (patch) | |
| tree | 99418f1b5275673f2cfad1f3cd1776dcae3618bd | |
| parent | e7b5f3c69c6a7303b951e7a1398c87a568a16761 (diff) | |
Implement textfile writing support
| -rw-r--r-- | common/textfile.c | 160 | ||||
| -rw-r--r-- | common/textfile.h | 1 | 
2 files changed, 149 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;  } diff --git a/common/textfile.h b/common/textfile.h index 56a0bc10..8871f53c 100644 --- a/common/textfile.h +++ b/common/textfile.h @@ -26,4 +26,5 @@   *  $Id$   */ +int textfile_put(const char *pathname, const char *key, const char *value);  char *textfile_get(const char *pathname, const char *key); | 
