yaffs: Reformatting to be kernel friendly.
[yaffs2.git] / yaffs_nameval.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2010 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  *  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 (strncmp
41                     ((YCHAR *) (xb + pos + sizeof(int)), name, size) == 0) {
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 -1;
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                 /* Find size, shift rest over this record,
80                  * then zero out the rest of buffer */
81                 memcpy(&size, xb + pos, sizeof(int));
82                 memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
83                 memset(xb + (xb_size - size), 0, size);
84                 return 0;
85         } else {
86                 return -ENODATA;
87         }
88 }
89
90 int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
91                 int bsize, int flags)
92 {
93         int pos;
94         int namelen = strnlen(name, xb_size);
95         int reclen;
96         int size_exist = 0;
97         int space;
98         int start;
99
100         pos = nval_find(xb, xb_size, name, &size_exist);
101
102         if (flags & XATTR_CREATE && pos >= 0)
103                 return -EEXIST;
104         if (flags & XATTR_REPLACE && pos < 0)
105                 return -ENODATA;
106
107         start = nval_used(xb, xb_size);
108         space = xb_size - start + size_exist;
109
110         reclen = (sizeof(int) + namelen + 1 + bsize);
111
112         if (reclen > space)
113                 return -ENOSPC;
114
115         if (pos >= 0) {
116                 nval_del(xb, xb_size, name);
117                 start = nval_used(xb, xb_size);
118         }
119
120         pos = start;
121
122         memcpy(xb + pos, &reclen, sizeof(int));
123         pos += sizeof(int);
124         strncpy((YCHAR *) (xb + pos), name, reclen);
125         pos += (namelen + 1);
126         memcpy(xb + pos, buf, bsize);
127         return 0;
128 }
129
130 int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
131              int bsize)
132 {
133         int pos = nval_find(xb, xb_size, name, NULL);
134         int size;
135
136         if (pos >= 0 && pos < xb_size) {
137
138                 memcpy(&size, xb + pos, sizeof(int));
139                 pos += sizeof(int);     /* advance past record length */
140                 size -= sizeof(int);
141
142                 /* Advance over name string */
143                 while (xb[pos] && size > 0 && pos < xb_size) {
144                         pos++;
145                         size--;
146                 }
147                 /*Advance over NUL */
148                 pos++;
149                 size--;
150
151                 if (size <= bsize) {
152                         memcpy(buf, xb + pos, size);
153                         return size;
154                 }
155
156         }
157         if (pos >= 0)
158                 return -ERANGE;
159         else
160                 return -ENODATA;
161 }
162
163 int nval_list(const char *xb, int xb_size, char *buf, int bsize)
164 {
165         int pos = 0;
166         int size;
167         int name_len;
168         int ncopied = 0;
169         int filled = 0;
170
171         memcpy(&size, xb + pos, sizeof(int));
172         while (size > sizeof(int) &&
173                 size <= xb_size &&
174                 (pos + size) < xb_size &&
175                 !filled) {
176                 pos += sizeof(int);
177                 size -= sizeof(int);
178                 name_len = strnlen((YCHAR *) (xb + pos), size);
179                 if (ncopied + name_len + 1 < bsize) {
180                         memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
181                         buf += name_len;
182                         *buf = '\0';
183                         buf++;
184                         if (sizeof(YCHAR) > 1) {
185                                 *buf = '\0';
186                                 buf++;
187                         }
188                         ncopied += (name_len + 1);
189                 } else {
190                         filled = 1;
191                 }
192                 pos += size;
193                 if (pos < xb_size - sizeof(int))
194                         memcpy(&size, xb + pos, sizeof(int));
195                 else
196                         size = 0;
197         }
198         return ncopied;
199 }
200
201 int nval_hasvalues(const char *xb, int xb_size)
202 {
203         return nval_used(xb, xb_size) > 0;
204 }