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