diff options
Diffstat (limited to 'fs/yaffs2/yaffs_nameval.c')
| -rw-r--r-- | fs/yaffs2/yaffs_nameval.c | 208 | 
1 files changed, 208 insertions, 0 deletions
| diff --git a/fs/yaffs2/yaffs_nameval.c b/fs/yaffs2/yaffs_nameval.c new file mode 100644 index 000000000..a20a3e47c --- /dev/null +++ b/fs/yaffs2/yaffs_nameval.c @@ -0,0 +1,208 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + *   for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This simple implementation of a name-value store assumes a small number of +* values and fits into a small finite buffer. + * + * Each attribute is stored as a record: + *  sizeof(int) bytes   record size. + *  yaffs_strnlen+1 bytes name null terminated. + *  nbytes    value. + *  ---------- + *  total size  stored in record size + * + * This code has not been tested with unicode yet. + */ + +#include "yaffs_nameval.h" + +#include "yportenv.h" + +static int nval_find(const char *xb, int xb_size, const YCHAR *name, +		     int *exist_size) +{ +	int pos = 0; +	int size; + +	memcpy(&size, xb, sizeof(int)); +	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { +		if (!yaffs_strncmp((YCHAR *) (xb + pos + sizeof(int)), +				name, size)) { +			if (exist_size) +				*exist_size = size; +			return pos; +		} +		pos += size; +		if (pos < xb_size - sizeof(int)) +			memcpy(&size, xb + pos, sizeof(int)); +		else +			size = 0; +	} +	if (exist_size) +		*exist_size = 0; +	return -ENODATA; +} + +static int nval_used(const char *xb, int xb_size) +{ +	int pos = 0; +	int size; + +	memcpy(&size, xb + pos, sizeof(int)); +	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { +		pos += size; +		if (pos < xb_size - sizeof(int)) +			memcpy(&size, xb + pos, sizeof(int)); +		else +			size = 0; +	} +	return pos; +} + +int nval_del(char *xb, int xb_size, const YCHAR *name) +{ +	int pos = nval_find(xb, xb_size, name, NULL); +	int size; + +	if (pos < 0 || pos >= xb_size) +		return -ENODATA; + +	/* Find size, shift rest over this record, +	 * then zero out the rest of buffer */ +	memcpy(&size, xb + pos, sizeof(int)); +	memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); +	memset(xb + (xb_size - size), 0, size); +	return 0; +} + +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, +		int bsize, int flags) +{ +	int pos; +	int namelen = yaffs_strnlen(name, xb_size); +	int reclen; +	int size_exist = 0; +	int space; +	int start; + +	pos = nval_find(xb, xb_size, name, &size_exist); + +	if (flags & XATTR_CREATE && pos >= 0) +		return -EEXIST; +	if (flags & XATTR_REPLACE && pos < 0) +		return -ENODATA; + +	start = nval_used(xb, xb_size); +	space = xb_size - start + size_exist; + +	reclen = (sizeof(int) + namelen + 1 + bsize); + +	if (reclen > space) +		return -ENOSPC; + +	if (pos >= 0) { +		nval_del(xb, xb_size, name); +		start = nval_used(xb, xb_size); +	} + +	pos = start; + +	memcpy(xb + pos, &reclen, sizeof(int)); +	pos += sizeof(int); +	yaffs_strncpy((YCHAR *) (xb + pos), name, reclen); +	pos += (namelen + 1); +	memcpy(xb + pos, buf, bsize); +	return 0; +} + +int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, +	     int bsize) +{ +	int pos = nval_find(xb, xb_size, name, NULL); +	int size; + +	if (pos >= 0 && pos < xb_size) { + +		memcpy(&size, xb + pos, sizeof(int)); +		pos += sizeof(int);	/* advance past record length */ +		size -= sizeof(int); + +		/* Advance over name string */ +		while (xb[pos] && size > 0 && pos < xb_size) { +			pos++; +			size--; +		} +		/*Advance over NUL */ +		pos++; +		size--; + +		/* If bsize is zero then this is a size query. +		 * Return the size, but don't copy. +		 */ +		if (!bsize) +			return size; + +		if (size <= bsize) { +			memcpy(buf, xb + pos, size); +			return size; +		} +	} +	if (pos >= 0) +		return -ERANGE; + +	return -ENODATA; +} + +int nval_list(const char *xb, int xb_size, char *buf, int bsize) +{ +	int pos = 0; +	int size; +	int name_len; +	int ncopied = 0; +	int filled = 0; + +	memcpy(&size, xb + pos, sizeof(int)); +	while (size > sizeof(int) && +		size <= xb_size && +		(pos + size) < xb_size && +		!filled) { +		pos += sizeof(int); +		size -= sizeof(int); +		name_len = yaffs_strnlen((YCHAR *) (xb + pos), size); +		if (ncopied + name_len + 1 < bsize) { +			memcpy(buf, xb + pos, name_len * sizeof(YCHAR)); +			buf += name_len; +			*buf = '\0'; +			buf++; +			if (sizeof(YCHAR) > 1) { +				*buf = '\0'; +				buf++; +			} +			ncopied += (name_len + 1); +		} else { +			filled = 1; +		} +		pos += size; +		if (pos < xb_size - sizeof(int)) +			memcpy(&size, xb + pos, sizeof(int)); +		else +			size = 0; +	} +	return ncopied; +} + +int nval_hasvalues(const char *xb, int xb_size) +{ +	return nval_used(xb, xb_size) > 0; +} |