xref: /openbmc/u-boot/fs/yaffs2/yaffs_nameval.c (revision d330e04d9d427a26381b59f40875af17f4c288a2)
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@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