Home | History | Annotate | Download | only in yaffs2
      1 /*
      2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
      3  *
      4  * Copyright (C) 2002-2011 Aleph One Ltd.
      5  *   for Toby Churchill Ltd and Brightstar Engineering
      6  *
      7  * Created by Charles Manning <charles (at) aleph1.co.uk>
      8  *
      9  * This program is free software; you can redistribute it and/or modify
     10  * it under the terms of the GNU General Public License version 2 as
     11  * published by the Free Software Foundation.
     12  */
     13 
     14 /*
     15  * This simple implementation of a name-value store assumes a small number of
     16 * values and fits into a small finite buffer.
     17  *
     18  * Each attribute is stored as a record:
     19  *  sizeof(int) bytes   record size.
     20  *  yaffs_strnlen+1 bytes name null terminated.
     21  *  nbytes    value.
     22  *  ----------
     23  *  total size  stored in record size
     24  *
     25  * This code has not been tested with unicode yet.
     26  */
     27 
     28 #include "yaffs_nameval.h"
     29 
     30 #include "yportenv.h"
     31 
     32 static int nval_find(const char *xb, int xb_size, const YCHAR *name,
     33 		     int *exist_size)
     34 {
     35 	int pos = 0;
     36 	int size;
     37 
     38 	memcpy(&size, xb, sizeof(int));
     39 	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
     40 		if (!yaffs_strncmp((YCHAR *) (xb + pos + sizeof(int)),
     41 				name, size)) {
     42 			if (exist_size)
     43 				*exist_size = size;
     44 			return pos;
     45 		}
     46 		pos += size;
     47 		if (pos < xb_size - sizeof(int))
     48 			memcpy(&size, xb + pos, sizeof(int));
     49 		else
     50 			size = 0;
     51 	}
     52 	if (exist_size)
     53 		*exist_size = 0;
     54 	return -ENODATA;
     55 }
     56 
     57 static int nval_used(const char *xb, int xb_size)
     58 {
     59 	int pos = 0;
     60 	int size;
     61 
     62 	memcpy(&size, xb + pos, sizeof(int));
     63 	while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
     64 		pos += size;
     65 		if (pos < xb_size - sizeof(int))
     66 			memcpy(&size, xb + pos, sizeof(int));
     67 		else
     68 			size = 0;
     69 	}
     70 	return pos;
     71 }
     72 
     73 int nval_del(char *xb, int xb_size, const YCHAR *name)
     74 {
     75 	int pos = nval_find(xb, xb_size, name, NULL);
     76 	int size;
     77 
     78 	if (pos < 0 || pos >= xb_size)
     79 		return -ENODATA;
     80 
     81 	/* Find size, shift rest over this record,
     82 	 * then zero out the rest of buffer */
     83 	memcpy(&size, xb + pos, sizeof(int));
     84 	memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
     85 	memset(xb + (xb_size - size), 0, size);
     86 	return 0;
     87 }
     88 
     89 int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
     90 		int bsize, int flags)
     91 {
     92 	int pos;
     93 	int namelen = yaffs_strnlen(name, xb_size);
     94 	int reclen;
     95 	int size_exist = 0;
     96 	int space;
     97 	int start;
     98 
     99 	pos = nval_find(xb, xb_size, name, &size_exist);
    100 
    101 	if (flags & XATTR_CREATE && pos >= 0)
    102 		return -EEXIST;
    103 	if (flags & XATTR_REPLACE && pos < 0)
    104 		return -ENODATA;
    105 
    106 	start = nval_used(xb, xb_size);
    107 	space = xb_size - start + size_exist;
    108 
    109 	reclen = (sizeof(int) + namelen + 1 + bsize);
    110 
    111 	if (reclen > space)
    112 		return -ENOSPC;
    113 
    114 	if (pos >= 0) {
    115 		nval_del(xb, xb_size, name);
    116 		start = nval_used(xb, xb_size);
    117 	}
    118 
    119 	pos = start;
    120 
    121 	memcpy(xb + pos, &reclen, sizeof(int));
    122 	pos += sizeof(int);
    123 	yaffs_strncpy((YCHAR *) (xb + pos), name, reclen);
    124 	pos += (namelen + 1);
    125 	memcpy(xb + pos, buf, bsize);
    126 	return 0;
    127 }
    128 
    129 int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
    130 	     int bsize)
    131 {
    132 	int pos = nval_find(xb, xb_size, name, NULL);
    133 	int size;
    134 
    135 	if (pos >= 0 && pos < xb_size) {
    136 
    137 		memcpy(&size, xb + pos, sizeof(int));
    138 		pos += sizeof(int);	/* advance past record length */
    139 		size -= sizeof(int);
    140 
    141 		/* Advance over name string */
    142 		while (xb[pos] && size > 0 && pos < xb_size) {
    143 			pos++;
    144 			size--;
    145 		}
    146 		/*Advance over NUL */
    147 		pos++;
    148 		size--;
    149 
    150 		/* If bsize is zero then this is a size query.
    151 		 * Return the size, but don't copy.
    152 		 */
    153 		if (!bsize)
    154 			return size;
    155 
    156 		if (size <= bsize) {
    157 			memcpy(buf, xb + pos, size);
    158 			return size;
    159 		}
    160 	}
    161 	if (pos >= 0)
    162 		return -ERANGE;
    163 
    164 	return -ENODATA;
    165 }
    166 
    167 int nval_list(const char *xb, int xb_size, char *buf, int bsize)
    168 {
    169 	int pos = 0;
    170 	int size;
    171 	int name_len;
    172 	int ncopied = 0;
    173 	int filled = 0;
    174 
    175 	memcpy(&size, xb + pos, sizeof(int));
    176 	while (size > sizeof(int) &&
    177 		size <= xb_size &&
    178 		(pos + size) < xb_size &&
    179 		!filled) {
    180 		pos += sizeof(int);
    181 		size -= sizeof(int);
    182 		name_len = yaffs_strnlen((YCHAR *) (xb + pos), size);
    183 		if (ncopied + name_len + 1 < bsize) {
    184 			memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
    185 			buf += name_len;
    186 			*buf = '\0';
    187 			buf++;
    188 			if (sizeof(YCHAR) > 1) {
    189 				*buf = '\0';
    190 				buf++;
    191 			}
    192 			ncopied += (name_len + 1);
    193 		} else {
    194 			filled = 1;
    195 		}
    196 		pos += size;
    197 		if (pos < xb_size - sizeof(int))
    198 			memcpy(&size, xb + pos, sizeof(int));
    199 		else
    200 			size = 0;
    201 	}
    202 	return ncopied;
    203 }
    204 
    205 int nval_hasvalues(const char *xb, int xb_size)
    206 {
    207 	return nval_used(xb, xb_size) > 0;
    208 }
    209