Get timothy quick tests building cleanly.
[yaffs2.git] / yaffs_nameval.c
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(size) bytes   record size.
20  *  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 #include "yaffs_guts.h"
30 #include "yportenv.h"
31 #include "yaffs_endian.h"
32
33 static int nval_find(struct yaffs_dev *dev,
34                      const char *xb, int xb_size, const YCHAR *name,
35                      int *exist_size)
36 {
37         int pos = 0;
38         s32 size;
39
40         memcpy(&size, xb, sizeof(size));
41         yaffs_do_endian_s32(dev, &size);
42
43         while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
44                 if (!strncmp((YCHAR *) (xb + pos + sizeof(size)),
45                                 name, size)) {
46                         if (exist_size)
47                                 *exist_size = size;
48                         return pos;
49                 }
50                 pos += size;
51                 if (pos < (int)(xb_size - sizeof(size))) {
52                         memcpy(&size, xb + pos, sizeof(size));
53                         yaffs_do_endian_s32(dev, &size);
54
55                 } else
56                         size = 0;
57         }
58         if (exist_size)
59                 *exist_size = 0;
60         return -ENODATA;
61 }
62
63 static int nval_used(struct yaffs_dev *dev, const char *xb, int xb_size)
64 {
65         int pos = 0;
66         s32 size;
67
68         memcpy(&size, xb + pos, sizeof(size));
69         yaffs_do_endian_s32(dev, &size);
70
71         while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
72                 pos += size;
73                 if (pos < (int)(xb_size - sizeof(size))) {
74                         memcpy(&size, xb + pos, sizeof(size));
75                         yaffs_do_endian_s32(dev, &size);
76                 } else
77                         size = 0;
78         }
79         return pos;
80 }
81
82 int nval_del(struct yaffs_dev *dev, char *xb, int xb_size, const YCHAR *name)
83 {
84         int pos = nval_find(dev, xb, xb_size, name, NULL);
85         s32 size;
86
87         if (pos < 0 || pos >= xb_size)
88                 return -ENODATA;
89
90         /* Find size, shift rest over this record,
91          * then zero out the rest of buffer */
92         memcpy(&size, xb + pos, sizeof(size));
93         yaffs_do_endian_s32(dev, &size);
94
95         memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
96         memset(xb + (xb_size - size), 0, size);
97         return 0;
98 }
99
100 int nval_set(struct yaffs_dev *dev,
101              char *xb, int xb_size, const YCHAR *name, const char *buf,
102              int bsize, int flags)
103 {
104         int pos;
105         int namelen = strnlen(name, xb_size);
106         int size_exist = 0;
107         int space;
108         int start;
109         s32 reclen;
110         s32 reclen_endianised;
111
112         pos = nval_find(dev, xb, xb_size, name, &size_exist);
113
114         if (flags & XATTR_CREATE && pos >= 0)
115                 return -EEXIST;
116         if (flags & XATTR_REPLACE && pos < 0)
117                 return -ENODATA;
118
119         start = nval_used(dev, xb, xb_size);
120         space = xb_size - start + size_exist;
121
122         reclen = (sizeof(reclen) + namelen + 1 + bsize);
123
124         if (reclen > space)
125                 return -ENOSPC;
126
127         if (pos >= 0) {
128                 /* Exists, so delete it. */
129                 nval_del(dev, xb, xb_size, name);
130                 start = nval_used(dev, xb, xb_size);
131         }
132
133         pos = start;
134
135         reclen_endianised = reclen;
136         yaffs_do_endian_s32(dev, &reclen_endianised);
137         memcpy(xb + pos, &reclen_endianised, sizeof(reclen_endianised));
138         pos += sizeof(reclen_endianised);
139         strncpy((YCHAR *) (xb + pos), name, reclen);
140         pos += (namelen + 1);
141         memcpy(xb + pos, buf, bsize);
142         return 0;
143 }
144
145 int nval_get(struct yaffs_dev *dev,
146              const char *xb, int xb_size, const YCHAR * name, char *buf,
147              int bsize)
148 {
149         int pos = nval_find(dev, xb, xb_size, name, NULL);
150         s32 size;
151
152         if (pos >= 0 && pos < xb_size) {
153
154                 memcpy(&size, xb + pos, sizeof(size));
155                 yaffs_do_endian_s32(dev, &size);
156                 pos += sizeof(size);    /* advance past record length */
157                 size -= sizeof(size);
158
159                 /* Advance over name string */
160                 while (xb[pos] && size > 0 && pos < xb_size) {
161                         pos++;
162                         size--;
163                 }
164                 /*Advance over NUL */
165                 pos++;
166                 size--;
167
168                 /* If bsize is zero then this is a size query.
169                  * Return the size, but don't copy.
170                  */
171                 if (!bsize)
172                         return size;
173
174                 if (size <= bsize) {
175                         memcpy(buf, xb + pos, size);
176                         return size;
177                 }
178         }
179         if (pos >= 0)
180                 return -ERANGE;
181
182         return -ENODATA;
183 }
184
185 int nval_list(struct yaffs_dev *dev, const char *xb, int xb_size, char *buf, int bsize)
186 {
187         int pos = 0;
188         s32 size;
189         int name_len;
190         int ncopied = 0;
191         int filled = 0;
192
193         memcpy(&size, xb + pos, sizeof(size));
194         yaffs_do_endian_s32(dev, &size);
195
196         while (size > (int)(sizeof(size)) &&
197                 size <= xb_size &&
198                 (pos + size) < xb_size &&
199                 !filled) {
200                 pos += sizeof(size);
201                 size -= sizeof(size);
202                 name_len = strnlen((YCHAR *) (xb + pos), size);
203                 if (ncopied + name_len + 1 < bsize) {
204                         memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
205                         buf += name_len;
206                         *buf = '\0';
207                         buf++;
208                         if (sizeof(YCHAR) > 1) {
209                                 *buf = '\0';
210                                 buf++;
211                         }
212                         ncopied += (name_len + 1);
213                 } else {
214                         filled = 1;
215                 }
216                 pos += size;
217                 if (pos < (int)(xb_size - sizeof(size))) {
218                         memcpy(&size, xb + pos, sizeof(size));
219                         yaffs_do_endian_s32(dev, &size);
220                 }
221                 else
222                         size = 0;
223         }
224         return ncopied;
225 }
226
227 int nval_hasvalues(struct yaffs_dev *dev, const char *xb, int xb_size)
228 {
229         return nval_used(dev, xb, xb_size) > 0;
230 }