Merge branch 'master' of ssh://www.aleph1.co.uk/home/aleph1/git/yaffs2
[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 values and fits
16  * 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
29 #include "yaffs_nameval.h"
30
31 #include "yportenv.h"
32  
33 static int nval_find(const char *xb, int xb_size, const YCHAR *name,
34                 int *exist_size)
35 {
36         int pos=0;
37         int size;
38
39         memcpy(&size,xb,sizeof(int));
40         while(size > 0 && (size < xb_size) && (pos + size < xb_size)){
41                 if(yaffs_strncmp((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, then zero out the rest of buffer */
80                 memcpy(&size,xb+pos,sizeof(int));
81                 memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
82                 memset(xb + (xb_size - size),0,size);
83                 return 0;
84         } else
85                 return -ENODATA;
86 }
87
88 int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags)
89 {
90         int pos;
91         int namelen = yaffs_strnlen(name,xb_size);
92         int reclen;
93         int size_exist = 0;
94         int space;
95         int start;
96
97         pos = nval_find(xb,xb_size,name, &size_exist);
98
99         if(flags & XATTR_CREATE && pos >= 0)
100                 return -EEXIST;
101         if(flags & XATTR_REPLACE && pos < 0)
102                 return -ENODATA;
103
104         start = nval_used(xb,xb_size);
105         space = xb_size - start + size_exist;
106
107         reclen = (sizeof(int) + namelen + 1 + bsize);
108
109         if(reclen > space)
110                 return -ENOSPC;
111
112         if(pos >= 0){
113                 nval_del(xb,xb_size,name);
114                 start = nval_used(xb, xb_size);
115         }
116
117         pos = start;
118
119         memcpy(xb + pos,&reclen,sizeof(int));
120         pos +=sizeof(int);
121         yaffs_strncpy((YCHAR *)(xb + pos), name, reclen);
122         pos+= (namelen+1);
123         memcpy(xb + pos,buf,bsize);
124         return 0;
125 }
126
127 int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize)
128 {
129         int pos = nval_find(xb,xb_size,name,NULL);
130         int size;
131         
132         if(pos >= 0 && pos< xb_size){
133                 
134                 memcpy(&size,xb +pos,sizeof(int));
135                 pos+=sizeof(int); /* advance past record length */
136                 size -= sizeof(int);
137
138                 /* Advance over name string */
139                 while(xb[pos] && size > 0 && pos < xb_size){
140                         pos++;
141                         size--;
142                 }
143                 /*Advance over NUL */
144                 pos++;
145                 size--;
146
147                 if(size <= bsize){
148                         memcpy(buf,xb + pos,size);
149                         return size;
150                 }
151                 
152         }
153         if(pos >= 0)
154                 return -ERANGE;
155         else
156                 return -ENODATA;
157 }
158
159 int nval_list(const char *xb, int xb_size, char *buf, int bsize)
160 {
161         int pos = 0;
162         int size;
163         int name_len;
164         int ncopied = 0;
165         int filled = 0;
166
167         memcpy(&size,xb + pos,sizeof(int));
168         while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){
169                 pos+= sizeof(int);
170                 size-=sizeof(int);
171                 name_len = yaffs_strnlen((YCHAR *)(xb + pos), size);
172                 if(ncopied + name_len + 1 < bsize){
173                         memcpy(buf,xb+pos,name_len * sizeof(YCHAR));
174                         buf+= name_len;
175                         *buf = '\0';
176                         buf++;
177                         if(sizeof(YCHAR) > 1){
178                                 *buf = '\0';
179                                 buf++;
180                         }
181                         ncopied += (name_len+1);
182                 } else
183                         filled = 1;
184                 pos+=size;
185                 if(pos < xb_size -sizeof(int))
186                         memcpy(&size,xb + pos,sizeof(int));
187                 else
188                         size = 0;
189         }
190         return ncopied;
191 }
192
193 int nval_load(char *xb, int xb_size, const char *src, int src_size)
194 {
195         int tx_size;
196         int used;
197         
198         tx_size = xb_size;
199         if(tx_size > src_size)
200                 tx_size = src_size;
201
202         memcpy(xb,src,tx_size);
203         used = nval_used(xb, xb_size);
204         
205         if( used < xb_size)
206                 memset(xb+ used, 0, xb_size - used);
207         return used;    
208 }
209
210 int nval_save(const char *xb, int xb_size, char *dest, int dest_size)
211 {
212         int tx_size;
213         
214         tx_size = xb_size;
215         if(tx_size > dest_size)
216                 tx_size = dest_size;
217
218         memcpy(dest,xb,tx_size);
219         return tx_size;
220 }