]>
Commit | Line | Data |
---|---|---|
753ac610 CM |
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 | } |