1 /*******************************************************************
2 Key Value Persistent Storage
4 keyvalpb.c - key value parameters block
6 (C) Copyright 2003-2005 by Pavel Pisa - Originator
7 (C) Copyright 2004-2005 by Petr Smolik - Originator
9 The uLan utilities library can be used, copied and modified under
11 - GPL - GNU General Public License
12 - LGPL - GNU Lesser General Public License
13 - MPL - Mozilla Public License
14 - and other licenses added by project originators
15 Code can be modified and re-distributed under any combination
16 of the above listed licenses. If contributor does not agree with
17 some of the licenses, he/she can delete appropriate line.
18 Warning, if you delete all lines, you are not allowed to
19 distribute source code and/or binaries utilizing code.
21 See files COPYING and README for details.
23 *******************************************************************/
29 * kvpb_memsum - Compute checksum of given memory area
30 * @base: Pointer to the base of of the region
31 * @size: Size of utilized part of the region
33 * Return Value: Computed checksum value
36 kvpb_sum_t kvpb_memsum(KVPB_DPTRTYPE uint8_t *base, kvpb_size_t size)
38 KVPB_LOCALDATA kvpb_sum_t sum=0;
39 KVPB_DPTRTYPE uint16_t *p=(KVPB_DPTRTYPE uint16_t *)base;
49 #ifndef KVPB_WITHOUT_HADLE
51 * kvpb_get_psum - Get pointer to the region check sum
52 * @kvpb_block: Pointer to the KVPB access information/state structure
53 * @base: Pointer to the base of of the region
54 * @size: Size of one data block region
56 * Return Value: Pointer to the actual region check sum placement
59 KVPB_DPTRTYPE kvpb_sum_t *kvpb_get_psum(kvpb_block_t *kvpb_block,
60 KVPB_DPTRTYPE uint8_t *base, kvpb_size_t size)
62 KVPB_DPTRTYPE kvpb_sum_t *__kvpb_get_psum(
63 KVPB_DPTRTYPE uint8_t *base, kvpb_size_t size)
66 KVPB_DPTRTYPE kvpb_sum_t *psum;
67 psum=kvpb_psum_align(kvpb_block,(KVPB_DPTRTYPE kvpb_sum_t*)(base+size)-1);
68 while((KVPB_DPTRTYPE uint8_t*)psum>=base) {
69 if (*kvpb_psum_valid_loc(kvpb_block,psum)!=0)
71 psum=kvpb_psum_align(kvpb_block,psum-1);
76 #ifndef KVPB_WITHOUT_HADLE
78 * kvpb_get_cfk - Get space where to place new key-value pair
79 * @kvpb_block: Pointer to the KVPB access information/state structure
80 * @mode: 0 .. work on active/valid data region;
81 * 1 .. work on the first copy/region, 2 .. work on the second copy/region
82 * @size: Size of required space for stored value
84 * Return Value: Pointer where next pair should be stored or %NULL
87 KVPB_DPTRTYPE kvpb_key_t *kvpb_get_cfk(kvpb_block_t *kvpb_block,uint8_t mode,int size)
89 KVPB_DPTRTYPE kvpb_key_t *__kvpb_get_cfk(uint8_t mode,int size)
92 KVPB_DPTRTYPE kvpb_sum_t *psum;
93 KVPB_DPTRTYPE uint8_t *p;
94 KVPB_DPTRTYPE uint8_t *r;
95 p=kvpb_region_base(kvpb_block,0);
96 size=kvpb_chunk_align(kvpb_block,size+sizeof(kvpb_key_t))+
97 (kvpb_block->flags&KVPB_DESC_CHUNKWO?kvpb_chunk_size(kvpb_block):0);
98 psum=kvpb_block->psum1;
99 if((!mode && (kvpb_block->flags & KVPB_DESC_USE2ND))||(mode==2)) {
100 if(!(kvpb_block->flags&KVPB_DESC_DOUBLE))
102 p=kvpb_region_base(kvpb_block,1);
103 psum=kvpb_block->psum2;
106 kvpb_size_t ksize=((KVPB_DPTRTYPE kvpb_key_t *)p)->size;
107 if(ksize==KVPB_EMPTY)
109 if(((uint8_t*)psum-(uint8_t*)p)<ksize)
111 p+=kvpb_chunk_align(kvpb_block,ksize+sizeof(kvpb_key_t))+
112 (kvpb_block->flags&KVPB_DESC_CHUNKWO?kvpb_chunk_size(kvpb_block):0);
114 r=(KVPB_DPTRTYPE uint8_t*)p+size+sizeof(kvpb_key_t);
117 if ((uint8_t*)kvpb_psum_align(kvpb_block,psum-1)<r) {
120 return (KVPB_DPTRTYPE kvpb_key_t*)p;
124 #ifndef KVPB_WITHOUT_HADLE
126 * kvpb_check - Check data consistency of the KVPB storage
127 * @kvpb_block: Pointer to the KVPB access information/state structure
128 * @mode: if mode is nonzero, try to restore valid state or erase all data
130 * Return Value: 0 .. all regions are correct, 1 .. the first region is valid, the second
131 * region is invalid or has been updated if @mode has been set, 2 .. the second region
132 * is valid, the first is invalid or has been updated if @mode has been set, 3 .. both
133 * regions has been erased and emptied, -1 .. the state is inconsistent and no valid
134 * region has been found and state has not be corrected
137 int kvpb_check(kvpb_block_t *kvpb_block, uint8_t mode)
139 int __kvpb_check(uint8_t mode)
142 KVPB_DPTRTYPE uint8_t *p;
143 KVPB_LOCALDATA int ret=-1;
144 KVPB_LOCALDATA kvpb_sum_t sum;
146 kvpb_block->flags&=~KVPB_DESC_USE2ND;
148 p=kvpb_region_base(kvpb_block,0);
149 kvpb_block->psum1=kvpb_get_psum(kvpb_block,p,kvpb_block->size);
150 if (kvpb_block->psum1) {
151 sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum1-p);
152 if(*kvpb_block->psum1==sum){
157 if(kvpb_block->flags&KVPB_DESC_DOUBLE){
158 p=kvpb_region_base(kvpb_block,1);
159 kvpb_block->psum2=kvpb_get_psum(kvpb_block,p,kvpb_block->size);
160 if (kvpb_block->psum2) {
161 sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum2-p);
162 if(*kvpb_block->psum2==sum) {
167 kvpb_block->flags|=KVPB_DESC_USE2ND;
178 kvpb_block->flags|=KVPB_DESC_RO;
180 /* correct for FLASH */
182 p=kvpb_region_base(kvpb_block,0);
183 kvpb_block_erase(kvpb_block,p,kvpb_block->size);
184 kvpb_block->psum1=kvpb_psum_align(kvpb_block,(KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1);
185 sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum1-p);
186 kvpb_block_copy(kvpb_block,kvpb_block->psum1,&sum,sizeof(kvpb_sum_t));
187 if(kvpb_block->flags&KVPB_DESC_DOUBLE){
188 p=kvpb_region_base(kvpb_block,1);
189 kvpb_block_erase(kvpb_block,p,kvpb_block->size);
190 kvpb_block->psum2=kvpb_psum_align(kvpb_block,(KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1);
191 sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum2-p);
192 kvpb_block_copy(kvpb_block,kvpb_block->psum2,&sum,sizeof(kvpb_sum_t));
197 kvpb_block_erase(kvpb_block,kvpb_region_base(kvpb_block,1),kvpb_block->size);
198 kvpb_block_copy(kvpb_block,kvpb_region_base(kvpb_block,1),
199 kvpb_region_base(kvpb_block,0),kvpb_block->size);
202 kvpb_block_erase(kvpb_block,kvpb_region_base(kvpb_block,0),kvpb_block->size);
203 kvpb_block_copy(kvpb_block,kvpb_region_base(kvpb_block,0),
204 kvpb_region_base(kvpb_block,1),kvpb_block->size);
207 kvpb_block->flags&=~KVPB_DESC_RO;
210 kvpb_block_flush(kvpb_block);
211 if(ret>=0) kvpb_block->flags|=KVPB_DESC_VALID;
215 #ifndef KVPB_WITHOUT_HADLE
217 * kvpb_first - Get pointer to the first key-value pair in the KVPB storage
218 * @kvpb_block: Pointer to the KVPB access information/state structure
219 * @mode: 0 .. iterate over active/valid data region;
220 * 1 .. iterate over first copy/region, 2 .. iterate over second copy/region
222 * Return Value: Pointer to the first key-value pair
223 * or %NULL if no pair exist.
226 KVPB_DPTRTYPE kvpb_key_t *kvpb_first(kvpb_block_t *kvpb_block, uint8_t mode)
228 KVPB_DPTRTYPE kvpb_key_t *__kvpb_first(uint8_t mode)
231 KVPB_DPTRTYPE kvpb_key_t *key=(KVPB_DPTRTYPE kvpb_key_t *)kvpb_region_base(kvpb_block,0);
232 if((!mode && (kvpb_block->flags & KVPB_DESC_USE2ND))||(mode==2)) {
233 if(!(kvpb_block->flags&KVPB_DESC_DOUBLE))
235 key=(KVPB_DPTRTYPE kvpb_key_t *)kvpb_region_base(kvpb_block,1);
237 while(*kvpb_keyid_valid(kvpb_block,key)==KVPB_KEYID_INVALID) {
238 key=kvpb_next(kvpb_block,key);
242 return key->size!=KVPB_EMPTY?key:NULL;
245 #ifndef KVPB_WITHOUT_HADLE
247 * kvpb_next - Iterate to the next consecutive key-value pair
248 * @kvpb_block: Pointer to the KVPB access information/state structure
249 * @key: Pointer to the previous key-value pair
251 * Return Value: Pointer to the next key-value pair
252 * or %NULL if no/no-more pairs exist.
255 KVPB_DPTRTYPE kvpb_key_t *kvpb_next(kvpb_block_t *kvpb_block, KVPB_DPTRTYPE kvpb_key_t *key)
257 KVPB_DPTRTYPE kvpb_key_t *__kvpb_next(KVPB_DPTRTYPE kvpb_key_t *key)
261 key=(KVPB_DPTRTYPE kvpb_key_t *)((KVPB_DPTRTYPE uint8_t *)key+
262 kvpb_chunk_align(kvpb_block,key->size+sizeof(kvpb_key_t))+
263 (kvpb_block->flags&KVPB_DESC_CHUNKWO?kvpb_chunk_size(kvpb_block):0));
264 if (key->size==KVPB_EMPTY) return NULL;
265 } while(*kvpb_keyid_valid(kvpb_block,key)==KVPB_KEYID_INVALID);
269 #ifndef KVPB_WITHOUT_HADLE
271 * kvpb_find - Find first of occurrence of given key ID
272 * @kvpb_block: Pointer to the KVPB access information/state structure
273 * @keyid: Ordinal value representing key ID
274 * @mode: iteration mode modifier: 0 .. search in the active/valid data region;
275 * 1 .. search in the first copy/region, 2 .. search in the second copy/region
276 * @key: Previous key occurrence pointer or %NULL value to find first key ID named key-value pair
278 * Return Value: Pointer to the first on subsequent occurrence of key-value pair addressed by given key ID
279 * or %NULL if no/no-more occurrences exists.
282 KVPB_DPTRTYPE kvpb_key_t *kvpb_find(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, uint8_t mode, KVPB_DPTRTYPE kvpb_key_t *key)
284 KVPB_DPTRTYPE kvpb_key_t *__kvpb_find(kvpb_keyid_t keyid, uint8_t mode, KVPB_DPTRTYPE kvpb_key_t *key)
287 if(!(kvpb_block->flags&KVPB_DESC_VALID))
290 key=kvpb_next(kvpb_block, key);
292 key=kvpb_first(kvpb_block, mode);
295 if((key->keyid==keyid) || (keyid==0))
297 key=kvpb_next(kvpb_block, key);
302 #ifndef KVPB_WITHOUT_HADLE
304 * kvpb_compact_region - Compact one KVPB data block/region
305 * @kvpb_block: Pointer to the KVPB access information/state structure
306 * @keyid: Key ID which should be omitted from compacted data
307 * @mode: 0 .. compact active/valid data region;
308 * 1 .. compact the first data copy, 2 .. compact the second copy
310 * Return Value: Operation cannot be finished.
313 int kvpb_compact_region(kvpb_block_t *kvpb_block, uint8_t mode, kvpb_keyid_t keyid)
315 int __kvpb_compact_region(uint8_t mode, kvpb_keyid_t keyid)
318 KVPB_DPTRTYPE uint8_t *p;
319 KVPB_DPTRTYPE kvpb_key_t *des,*src;
321 p=kvpb_region_base(kvpb_block,0);
322 src=(KVPB_DPTRTYPE kvpb_key_t*)kvpb_region_base(kvpb_block,1);
323 des=(KVPB_DPTRTYPE kvpb_key_t*)p;
324 kvpb_block->psum1=kvpb_psum_align(kvpb_block,
325 (KVPB_DPTRTYPE kvpb_sum_t*)(kvpb_region_base(kvpb_block,1))-1);
326 if((!mode && (kvpb_block->flags & KVPB_DESC_USE2ND))||(mode==2)) {
327 if(!(kvpb_block->flags&KVPB_DESC_DOUBLE))
329 src=(KVPB_DPTRTYPE kvpb_key_t*)p;
330 des=(KVPB_DPTRTYPE kvpb_key_t*)kvpb_region_base(kvpb_block,1);
331 kvpb_block->psum2=kvpb_psum_align(kvpb_block,
332 (KVPB_DPTRTYPE kvpb_sum_t*)(kvpb_region_base(kvpb_block,2))-1);
334 kvpb_block_flush(kvpb_block);
335 kvpb_block_erase(kvpb_block,des,kvpb_block->size);
337 int s=kvpb_chunk_align(kvpb_block,src->size+sizeof(kvpb_key_t));
338 if((*kvpb_keyid_valid(kvpb_block,src)!=KVPB_KEYID_INVALID) && (src->keyid!=keyid)) {
339 kvpb_block_copy(kvpb_block,des,src,s);
340 if (kvpb_block->flags&KVPB_DESC_CHUNKWO) s+=kvpb_chunk_size(kvpb_block);
341 des=(KVPB_DPTRTYPE kvpb_key_t*)((uint8_t*)des+s);
343 src=kvpb_next(kvpb_block, src);
345 kvpb_block_flush(kvpb_block);
349 #ifndef KVPB_WITHOUT_HADLE
351 * kvpb_get_key - Get value for given key ID
352 * @kvpb_block: Pointer to the KVPB access information/state structure
353 * @keyid: Ordinal value representing key ID
354 * @size: The size of the buffer provided to store data into
355 * @buf: Pointer to the buffer, where retrieved data should be copied
357 * Return Value: Number of retrieved value bytes if operation is successful
358 * or -1 if there is no such key ID or operation fails for other reason.
361 int kvpb_get_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, void *buf)
363 int __kvpb_get_key(kvpb_keyid_t keyid, kvpb_size_t size, void *buf)
366 KVPB_DPTRTYPE kvpb_key_t *key;
367 key=kvpb_find(kvpb_block,keyid,0,NULL);
372 memcpy(buf,key+1,size);
378 #ifndef KVPB_WITHOUT_HADLE
380 * kvpb_set_key - Set new value or define new key-value pair
381 * @kvpb_block: Pointer to the KVPB access information/state structure
382 * @keyid: Ordinal value representing key ID, if or-red with %KVPB_KEYID_DUPLIC,
383 * the key ID can be defined/inserted multiple times
384 * @size: Stored value size in bytes
385 * @buf: Pointer to the stored value data
387 * Return Value: Number of stored bytes (equal to @size) if operation is successful
388 * or -1 if operation fails.
391 int kvpb_set_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, const void *buf)
393 int __kvpb_set_key(kvpb_keyid_t keyid, kvpb_size_t size, const void *buf)
396 KVPB_LOCALDATA kvpb_sum_t sum;
397 KVPB_DPTRTYPE kvpb_sum_t *psum;
398 KVPB_DPTRTYPE kvpb_key_t *key;
399 KVPB_DPTRTYPE uint8_t *p;
401 if(!(kvpb_block->flags&KVPB_DESC_VALID))
403 if(kvpb_block->flags&KVPB_DESC_RO)
407 psum=kvpb_psum_align(kvpb_block,kvpb_block->psum1);
409 kvpb_block_copy(kvpb_block,kvpb_psum_valid_loc(kvpb_block,psum),&sum,sizeof(kvpb_sum_t));
410 kvpb_block->psum1=kvpb_psum_align(kvpb_block,kvpb_block->psum1-1);
411 if (!(keyid&KVPB_KEYID_DUPLIC) || !buf) {
412 kvpb_each_from(kvpb_block,keyid,1,key) {
413 kvpb_keyid_t dkeyid=KVPB_KEYID_INVALID;
414 kvpb_block_copy(kvpb_block,kvpb_keyid_valid(kvpb_block,key),&dkeyid,sizeof(kvpb_keyid_t));
417 key=kvpb_get_cfk(kvpb_block,1,size);
419 kvpb_compact_region(kvpb_block,1,(keyid&KVPB_KEYID_DUPLIC)?0:keyid);
420 key=kvpb_get_cfk(kvpb_block,1,size);
422 if (keyid && key && buf) {
423 kvpb_block_copy(kvpb_block,&key->size,&size,sizeof(kvpb_size_t));
424 kvpb_block_copy(kvpb_block,&key->keyid,&keyid,sizeof(kvpb_keyid_t));
425 kvpb_block_copy(kvpb_block,(uint8_t*)(key+1),buf,/*align???*/ size);
427 /* need flush data to count correct value of new check sum */
428 kvpb_block_flush(kvpb_block);
430 p=kvpb_region_base(kvpb_block,0);
431 sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum1-p);
432 kvpb_block_copy(kvpb_block,kvpb_block->psum1,&sum,sizeof(kvpb_sum_t));
433 kvpb_block_flush(kvpb_block);
434 if(!(kvpb_block->flags&KVPB_DESC_DOUBLE))
437 /*Write in the first region failed, switching to backup region */
438 if(kvpb_block->flags&KVPB_DESC_RO){
439 kvpb_block->flags|=KVPB_DESC_USE2ND;
444 psum=kvpb_psum_align(kvpb_block,kvpb_block->psum2);
446 kvpb_block_copy(kvpb_block,kvpb_psum_valid_loc(kvpb_block,psum),&sum,sizeof(kvpb_sum_t));
447 kvpb_block->psum2=kvpb_psum_align(kvpb_block,kvpb_block->psum2-1);
448 if (!(keyid&KVPB_KEYID_DUPLIC) || !buf) {
449 kvpb_each_from(kvpb_block,keyid,2,key) {
450 kvpb_keyid_t dkeyid=KVPB_KEYID_INVALID;
451 kvpb_block_copy(kvpb_block,kvpb_keyid_valid(kvpb_block,key),&dkeyid,sizeof(kvpb_keyid_t));
454 key=kvpb_get_cfk(kvpb_block,2,size);
456 kvpb_compact_region(kvpb_block,2,(keyid&KVPB_KEYID_DUPLIC)?0:keyid);
457 key=kvpb_get_cfk(kvpb_block,2,size);
459 if (keyid && key && buf) {
460 kvpb_block_copy(kvpb_block,&key->size,&size,sizeof(kvpb_size_t));
461 kvpb_block_copy(kvpb_block,&key->keyid,&keyid,sizeof(kvpb_keyid_t));
462 kvpb_block_copy(kvpb_block,(uint8_t*)(key+1),buf,/*align???*/ size);
464 kvpb_block_flush(kvpb_block);
466 p=kvpb_region_base(kvpb_block,1);
467 sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum2-p);
468 kvpb_block_copy(kvpb_block,kvpb_block->psum2,&sum,sizeof(kvpb_sum_t));
469 kvpb_block_flush(kvpb_block);
470 /*Write in the second region failed, switching to the first region */
471 if(kvpb_block->flags&KVPB_DESC_RO){
472 kvpb_block->flags&=~KVPB_DESC_USE2ND;
479 #ifndef KVPB_MINIMALIZED
481 * kvpb_err_keys - Erase/delete key-value pair
482 * @kvpb_block: Pointer to the KVPB access information/state structure
483 * @keyid: Ordinal value representing key ID
485 * Return Value: Positive or zero value informs about successful operation,
486 * -1 if operation fails.
489 int kvpb_err_keys(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid)
491 return kvpb_set_key(kvpb_block,keyid,0,NULL);
493 #endif /*KVPB_MINIMALIZED*/