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 if((!mode && (kvpb_block->flags & KVPB_DESC_USE2ND))||(mode==2)) {
325 if(!(kvpb_block->flags&KVPB_DESC_DOUBLE))
328 src=(KVPB_DPTRTYPE kvpb_key_t*)p;
329 p=(KVPB_DPTRTYPE uint8_t *)des;
330 kvpb_block->psum2=kvpb_psum_align(kvpb_block,
331 (KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1);
333 kvpb_block->psum1=kvpb_psum_align(kvpb_block,
334 (KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1);
336 kvpb_block_flush(kvpb_block);
337 kvpb_block_erase(kvpb_block,des,kvpb_block->size);
339 int s=kvpb_chunk_align(kvpb_block,src->size+sizeof(kvpb_key_t));
340 if((*kvpb_keyid_valid(kvpb_block,src)!=KVPB_KEYID_INVALID) && (src->keyid!=keyid)) {
341 kvpb_block_copy(kvpb_block,des,src,s);
342 if (kvpb_block->flags&KVPB_DESC_CHUNKWO) s+=kvpb_chunk_size(kvpb_block);
343 des=(KVPB_DPTRTYPE kvpb_key_t*)((uint8_t*)des+s);
345 src=kvpb_next(kvpb_block, src);
347 kvpb_block_flush(kvpb_block);
351 #ifndef KVPB_WITHOUT_HADLE
353 * kvpb_get_key - Get value for given key ID
354 * @kvpb_block: Pointer to the KVPB access information/state structure
355 * @keyid: Ordinal value representing key ID
356 * @size: The size of the buffer provided to store data into
357 * @buf: Pointer to the buffer, where retrieved data should be copied
359 * Return Value: Number of retrieved value bytes if operation is successful
360 * or -1 if there is no such key ID or operation fails for other reason.
363 int kvpb_get_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, void *buf)
365 int __kvpb_get_key(kvpb_keyid_t keyid, kvpb_size_t size, void *buf)
368 KVPB_DPTRTYPE kvpb_key_t *key;
369 key=kvpb_find(kvpb_block,keyid,0,NULL);
374 memcpy(buf,key+1,size);
380 #ifndef KVPB_WITHOUT_HADLE
382 * kvpb_set_key - Set new value or define new key-value pair
383 * @kvpb_block: Pointer to the KVPB access information/state structure
384 * @keyid: Ordinal value representing key ID, if or-red with %KVPB_KEYID_DUPLIC,
385 * the key ID can be defined/inserted multiple times
386 * @size: Stored value size in bytes
387 * @buf: Pointer to the stored value data
389 * Return Value: Number of stored bytes (equal to @size) if operation is successful
390 * or -1 if operation fails.
393 int kvpb_set_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, const void *buf)
395 int __kvpb_set_key(kvpb_keyid_t keyid, kvpb_size_t size, const void *buf)
398 KVPB_LOCALDATA kvpb_sum_t sum;
399 KVPB_DPTRTYPE kvpb_sum_t *psum;
400 KVPB_DPTRTYPE kvpb_key_t *key;
401 KVPB_DPTRTYPE uint8_t *p;
403 if(!(kvpb_block->flags&KVPB_DESC_VALID))
405 if(kvpb_block->flags&KVPB_DESC_RO)
409 psum=kvpb_psum_align(kvpb_block,kvpb_block->psum1);
411 kvpb_block_copy(kvpb_block,kvpb_psum_valid_loc(kvpb_block,psum),&sum,sizeof(kvpb_sum_t));
412 kvpb_block->psum1=kvpb_psum_align(kvpb_block,kvpb_block->psum1-1);
413 if (!(keyid&KVPB_KEYID_DUPLIC) || !buf) {
414 kvpb_each_from(kvpb_block,keyid,1,key) {
415 kvpb_keyid_t dkeyid=KVPB_KEYID_INVALID;
416 kvpb_block_copy(kvpb_block,kvpb_keyid_valid(kvpb_block,key),&dkeyid,sizeof(kvpb_keyid_t));
419 key=kvpb_get_cfk(kvpb_block,1,size);
421 kvpb_compact_region(kvpb_block,1,(keyid&KVPB_KEYID_DUPLIC)?0:keyid);
422 key=kvpb_get_cfk(kvpb_block,1,size);
424 if (keyid && key && buf) {
425 kvpb_block_copy(kvpb_block,&key->size,&size,sizeof(kvpb_size_t));
426 kvpb_block_copy(kvpb_block,&key->keyid,&keyid,sizeof(kvpb_keyid_t));
427 kvpb_block_copy(kvpb_block,(uint8_t*)(key+1),buf,/*align???*/ size);
429 /* need flush data to count correct value of new check sum */
430 kvpb_block_flush(kvpb_block);
432 p=kvpb_region_base(kvpb_block,0);
433 sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum1-p);
434 kvpb_block_copy(kvpb_block,kvpb_block->psum1,&sum,sizeof(kvpb_sum_t));
435 kvpb_block_flush(kvpb_block);
436 if(!(kvpb_block->flags&KVPB_DESC_DOUBLE))
439 /*Write in the first region failed, switching to backup region */
440 if(kvpb_block->flags&KVPB_DESC_RO){
441 kvpb_block->flags|=KVPB_DESC_USE2ND;
446 psum=kvpb_psum_align(kvpb_block,kvpb_block->psum2);
448 kvpb_block_copy(kvpb_block,kvpb_psum_valid_loc(kvpb_block,psum),&sum,sizeof(kvpb_sum_t));
449 kvpb_block->psum2=kvpb_psum_align(kvpb_block,kvpb_block->psum2-1);
450 if (!(keyid&KVPB_KEYID_DUPLIC) || !buf) {
451 kvpb_each_from(kvpb_block,keyid,2,key) {
452 kvpb_keyid_t dkeyid=KVPB_KEYID_INVALID;
453 kvpb_block_copy(kvpb_block,kvpb_keyid_valid(kvpb_block,key),&dkeyid,sizeof(kvpb_keyid_t));
456 key=kvpb_get_cfk(kvpb_block,2,size);
458 kvpb_compact_region(kvpb_block,2,(keyid&KVPB_KEYID_DUPLIC)?0:keyid);
459 key=kvpb_get_cfk(kvpb_block,2,size);
461 if (keyid && key && buf) {
462 kvpb_block_copy(kvpb_block,&key->size,&size,sizeof(kvpb_size_t));
463 kvpb_block_copy(kvpb_block,&key->keyid,&keyid,sizeof(kvpb_keyid_t));
464 kvpb_block_copy(kvpb_block,(uint8_t*)(key+1),buf,/*align???*/ size);
466 kvpb_block_flush(kvpb_block);
468 p=kvpb_region_base(kvpb_block,1);
469 sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum2-p);
470 kvpb_block_copy(kvpb_block,kvpb_block->psum2,&sum,sizeof(kvpb_sum_t));
471 kvpb_block_flush(kvpb_block);
472 /*Write in the second region failed, switching to the first region */
473 if(kvpb_block->flags&KVPB_DESC_RO){
474 kvpb_block->flags&=~KVPB_DESC_USE2ND;
481 #ifndef KVPB_MINIMALIZED
483 * kvpb_err_keys - Erase/delete key-value pair
484 * @kvpb_block: Pointer to the KVPB access information/state structure
485 * @keyid: Ordinal value representing key ID
487 * Return Value: Positive or zero value informs about successful operation,
488 * -1 if operation fails.
491 int kvpb_err_keys(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid)
493 return kvpb_set_key(kvpb_block,keyid,0,NULL);
495 #endif /*KVPB_MINIMALIZED*/