comparison g23m/condat/ms/src/aci/db.c @ 0:509db1a7b7b8

initial import: leo2moko-r1
author Space Falcon <falcon@ivan.Harhan.ORG>
date Mon, 01 Jun 2015 03:24:05 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:509db1a7b7b8
1 /*
2 +-----------------------------------------------------------------------------
3 | Project : PHB
4 | Modul : DBM
5 +-----------------------------------------------------------------------------
6 | Copyright 2005 Texas Instruments Berlin, AG
7 | All rights reserved.
8 |
9 | This file is confidential and a trade secret of Texas
10 | Instruments Berlin, AG
11 | The receipt of or possession of this file does not convey
12 | any rights to reproduce or disclose its contents or to
13 | manufacture, use, or sell anything it may describe, in
14 | whole, or in part, without the specific written consent of
15 | Texas Instruments Berlin, AG.
16 +-----------------------------------------------------------------------------
17 | Purpose : Implementation of DBM functions
18 +-----------------------------------------------------------------------------
19 */
20
21 #ifdef TI_PS_FFS_PHB
22
23 #include "db_int.h"
24 #include <string.h>
25
26 /* For DB Testing */
27
28 /* Check if we are closing FFS files properly */
29 #define DB_TEST
30
31 /* A simple check to make sure that all allocated
32 memory is freed to avoid memory leak */
33 #define DB_MEMORY_CHECK
34
35 /* if dir is not empty during deletion, we do not
36 raise the error, rather we go ahead and remove
37 all the contents and then delete the dir */
38 #define FORCED_DIR_REMOVAL
39
40 /**************************
41 D E F I N I T I O N S &
42 D E C L A R A T I O N S
43 **************************/
44
45
46 GLOBAL UBYTE UsedDBs; /* Number of existing databases */
47 GLOBAL int LastFFS_ReturnCode; /* Last FFS return code */
48 GLOBAL T_DBM_MASTERRECORD DbmMaster [MAX_DBs]; /* Database Master */
49 GLOBAL T_DBM_STATE DBM_State = DBM_NOT_INITIALISED; /* DBM State */
50 GLOBAL T_DB_CHANGED DB_History_log; /* History log */
51
52 #ifdef FFS_CLOSE_BEFORE_OPEN
53
54 T_FFS_FD Dummy_FFSFileHandle = NULL;
55 #define INVALID_FLD_CTR 0xFF
56 #define NOT_OPENED 0x00
57 #define OPENED_FOR_READ 0x01
58 #define OPENED_FOR_WRITE 0x02
59
60 #endif
61
62 #ifdef DB_TEST
63
64 S8 db_test_ffs_open_ctr = 0;
65 T_FFS_SIZE db_test_ffs_ret_code = EFFS_OK;
66
67 #define DB_FFS_OPEN( ret, file, flag ) \
68 { \
69 ret = ffs_open( file, flag ); \
70 \
71 if( ret >= EFFS_OK ) \
72 { \
73 ++db_test_ffs_open_ctr; \
74 TRACE_EVENT_P1( "DB_FFS_OPEN:db_test_ffs_open_ctr:%d", db_test_ffs_open_ctr ); \
75 } else { \
76 TRACE_EVENT_P1( "DB_FFS_OPEN:FFS ERROR:%d", ret ); \
77 } \
78 }
79
80
81 #define DB_FFS_CLOSE( fd ) \
82 { \
83 T_FFS_SIZE db_test_ffs_ret_code = ffs_close( fd ); \
84 \
85 if( db_test_ffs_ret_code >= EFFS_OK ) \
86 { \
87 --db_test_ffs_open_ctr; \
88 TRACE_EVENT_P1( "DB_FFS_CLOSE:db_test_ffs_open_ctr:%d", db_test_ffs_open_ctr ); \
89 } else { \
90 TRACE_EVENT_P1( "DB_FFS_CLOSE:FFS ERROR:%d", db_test_ffs_ret_code ); \
91 } \
92 \
93 fd = NULL; \
94 }
95
96 #define DB_RETURN( ret ) \
97 { \
98 TRACE_EVENT_P1( "DB_RETURN:ret:%d", ret ); \
99 return ret; \
100 }
101
102 #define DB_VALUE_RETURN( ret ) \
103 { \
104 TRACE_EVENT_P1( "DB_VALUE_RETURN:ret:%d", ret ); \
105 return ret; \
106 }
107
108 #else
109
110 #define DB_FFS_OPEN( ret, file, flag ) ret = ffs_open( file, flag )
111 #define DB_FFS_CLOSE( fd ) { ffs_close( fd ); fd = NULL; }
112 #define DB_RETURN( ret ) return ret
113 #define DB_VALUE_RETURN( ret ) return ret
114
115 #endif
116
117 #ifdef DB_MEMORY_CHECK
118
119 UBYTE alloc_ctr = 0;
120
121 #define DB_MALLOC( ptr, num_of_bytes ) \
122 { \
123 ++alloc_ctr; \
124 TRACE_EVENT_P1( "DB Memory Alloc:%d", alloc_ctr ); \
125 ACI_MALLOC( ptr, num_of_bytes ); \
126 }
127
128 #define DB_MFREE( ptr ) \
129 { \
130 --alloc_ctr; \
131 TRACE_EVENT_P1( "DB Memory Free:%d", alloc_ctr ); \
132 ACI_MFREE( ptr ); \
133 }
134
135 #else
136
137 #define DB_MALLOC( ptr, num_of_bytes ) ACI_MALLOC( ptr, num_of_bytes )
138 #define DB_MFREE( ptr ) ACI_MFREE( ptr )
139
140 #endif
141
142
143 #ifdef _SIMULATION_
144 #define DB_DIR "/dbm"
145 #define DB_MASTER_FILE "/dbm/DD_master"
146 #else
147 #define DB_DIR "/gsm/dbm"
148 #define DB_MASTER_FILE "/gsm/dbm/DD_master"
149 #endif
150
151 #define FILENAME_LEN 40
152
153 #define T_DB_MASTER_RECORD_SIZE 18
154 /* DBM master record
155 File: DB_DIR/DD_master
156 Data:
157 1) DBDirectory (16 bytes, based on MAX_LEN_DIRECTORY=16)
158 2) NumOfFiles (1 byte, based on MAX_NUM_FILES=255)
159 3) Tracked (1 byte)
160 */
161
162
163 #define T_DB_FIELD_RECORD_SIZE 43
164 /* Based on the following data written into FFS
165 File: DB_DIR/DD_<DBDirectory>
166 Data:
167 1) FieldID (2 bytes, given in Interface)
168 2) DBType (1 byte)
169 3) RecordSize (2 bytes, based on MAX_RECORD_SIZE=65kb)
170 4) NumOfRecords (1 byte, based on MAX_NUM_RECORDS=255)
171 5) SortIndexes (MAX_NUM_OF_SORT_INDEXS bytes, 1 byte for each index )
172 6) RecordBitMap (32 bytes, as of now based on MAX_NUM_RECORDS=255)
173 7) Clean (1 byte, this can be clubbed with DBType )
174 */
175
176 #define RecordBitMap_OFFSET 10 /* depending on structure in DB_DIR/DD_<DBDirectory> */
177
178 #define SortIndexList_OFFSET 6 /* depending on structure in DB_DIR/DD_<DBDirectory> */
179
180 #define QuickSort_BufferStackSize 8 /* For Non recursive quick sort,
181 allows sorting of 2 ^ 8 = 256 elements */
182
183 #define SEARCH_FAILED -1
184
185 #define MAX_BIT_POS 8
186
187 #define BITMAP_INDEX( num ) ( ( num - 1 ) / MAX_BIT_POS )
188 #define BIT_POS( num ) ( ( num - 1 ) % MAX_BIT_POS )
189
190 /* For RAM strctures */
191 #define TRACKED_AND_CLEAN 0x03
192
193 #define TRACKED 0x02
194
195 #define CLEAN 0x01
196
197 #define NOT_CLEAN 0x00
198
199 /* For FFS strctures */
200 #define FFS_TRACKED 0x01
201
202 #define FFS_NOT_TRACKED 0x00
203
204 #define NOT !
205
206 #define INVALID_RECORD_NUM 0xFF
207
208 /*
209 Internal function to initialize RAM structures with FFS
210 */
211 T_DB_CODE init_RAM_with_FFS ( void );
212
213 #define DBM_State_check \
214 if ( DBM_State EQ DBM_NOT_INITIALISED ) DB_RETURN( DB_NOT_INITIALISED );
215
216 T_DB_CODE db_handle_check ( int db_handle );
217
218 UBYTE field_id_search ( int db_handle,
219 USHORT field_id );
220
221 T_DB_CODE update_history_log ( int db_handle,
222 USHORT field_id,
223 USHORT record_num );
224
225 /* functions swap and parition are required for sorting */
226 void swap ( UBYTE* sort_list,
227 UBYTE low,
228 UBYTE high );
229
230 UBYTE split_list ( UBYTE* sort_list,
231 UBYTE low,
232 UBYTE high,
233 T_COMP_FUNC compare_function,
234 ULONG flags,
235 int db_handle,
236 USHORT field_id );
237
238 void quick_sort ( UBYTE* sort_list,
239 UBYTE num_of_elements,
240 T_COMP_FUNC compare_function,
241 ULONG flags,
242 int db_handle,
243 USHORT field_id );
244
245 UBYTE search_clear_bit_in_bitmap ( UBYTE* bitmap,
246 UBYTE bitmap_size );
247
248 void set_bit_in_bitmap ( UBYTE* bitmap,
249 UBYTE bitmap_size,
250 UBYTE bit_num );
251
252 void reset_bit_in_bitmap ( UBYTE* bitmap,
253 UBYTE bitmap_size,
254 UBYTE bit_num );
255
256 T_DB_CODE populate_sorted_list_from_FFS (
257
258 #ifdef FFS_CLOSE_BEFORE_OPEN
259 UBYTE db_ctr,
260 #endif
261 char* sort_file,
262 UBYTE num_of_elements,
263 UBYTE** sort_list_ptr );
264
265 T_DB_CODE write_sorted_list_to_FFS (
266
267 #ifdef FFS_CLOSE_BEFORE_OPEN
268 UBYTE db_ctr,
269 #endif
270 char* sort_file,
271 UBYTE num_of_elements,
272 UBYTE* sort_list );
273
274 int search ( UBYTE* sort_list,
275 UBYTE num_of_elements,
276 UBYTE* order_num,
277 T_SEARCH_FUNC search_function,
278 ULONG flags,
279 const UBYTE* search_tag,
280 int db_handle,
281 USHORT field_id );
282
283 T_DB_CODE update_field_data_in_FFS ( const char* field_file,
284 T_FFS_FD* filehandle,
285 #ifdef FFS_CLOSE_BEFORE_OPEN
286 UBYTE db_ctr,
287 #endif
288 UBYTE fld_ctr,
289 UBYTE field_data_max_size,
290 UBYTE* field_data,
291 USHORT offset,
292 USHORT length );
293
294 UBYTE cal_NextRecordNum ( const char* DBDirectory,
295 USHORT FieldID,
296 USHORT RecordSize );
297
298 T_DB_CODE read_user_record_from_FFS ( const char* user_field_file,
299
300 #ifdef FFS_CLOSE_BEFORE_OPEN
301 UBYTE db_ctr,
302 UBYTE fld_ctr,
303 #endif
304 T_FFS_FD* filehandle,
305 UBYTE record_num,
306 USHORT record_size,
307 USHORT offset,
308 USHORT length,
309 UBYTE* record_buffer );
310
311 T_DB_CODE write_user_record_to_FFS ( const char* user_field_file,
312
313 #ifdef FFS_CLOSE_BEFORE_OPEN
314 UBYTE db_ctr,
315 UBYTE fld_ctr,
316 #endif
317 T_FFS_FD* filehandle,
318 UBYTE record_num,
319 USHORT record_size,
320 USHORT offset,
321 USHORT length,
322 UBYTE* record_buffer );
323
324 T_DB_CODE delete_file_dir_from_FFS ( const char* filename );
325
326 T_DB_CODE update_dbm_data_in_FFS ( const char* filename,
327 UBYTE db_ctr,
328 UBYTE db_data_max_size,
329 UBYTE* db_data,
330 USHORT offset,
331 USHORT length );
332
333 T_DB_CODE remove_field_from_FFS ( UBYTE db_ctr,
334 UBYTE fld_ctr );
335
336
337 #ifdef FFS_CLOSE_BEFORE_OPEN
338
339 T_FFS_FD db_open_user_field_file ( UBYTE db_ctr,
340 UBYTE fld_ctr,
341 const char* user_field_file,
342 T_FFS_OPEN_FLAGS open_option );
343
344
345 void db_close_user_field_files ( UBYTE db_ctr );
346
347 BOOL db_open_full_for_read ( UBYTE db_ctr );
348
349 BOOL db_open_full_for_write ( UBYTE db_ctr );
350
351 void db_close_for_write ( UBYTE db_ctr );
352
353 void db_close_for_read ( UBYTE db_ctr );
354
355 UBYTE db_status_user_field_file ( UBYTE db_ctr,
356 UBYTE fld_ctr );
357
358
359 #endif /* FFS_CLOSE_BEFORE_OPEN */
360
361
362 #ifdef FORCED_DIR_REMOVAL
363
364 T_DB_CODE delete_dir_forced ( const char* filename );
365
366 #endif /* FORCED_DIR_REMOVAL */
367
368 #ifdef INSERTION_SORT
369
370 void get_sort_lists_from_FFS ( UBYTE db_ctr,
371 UBYTE fld_ctr );
372
373 void new_in_sort_lists ( UBYTE db_ctr,
374 UBYTE fld_ctr,
375 UBYTE record_num );
376
377 void update_in_sort_lists ( UBYTE db_ctr,
378 UBYTE fld_ctr,
379 UBYTE record_num );
380
381 void delete_in_sort_lists ( UBYTE db_ctr,
382 UBYTE fld_ctr,
383 UBYTE record_num );
384
385 void insertion_sort ( UBYTE* sort_list,
386 UBYTE num_of_elements,
387 T_COMP_FUNC compare_function,
388 ULONG flags,
389 int db_handle,
390 USHORT field_id );
391
392 void insert_element ( UBYTE* sort_list,
393 UBYTE num_of_elements,
394 UBYTE bottom,
395 UBYTE top,
396 UBYTE record_num,
397 T_COMP_FUNC compare_function,
398 ULONG flags,
399 int db_handle,
400 USHORT field_id );
401
402 #endif /* INSERTION_SORT */
403
404 T_DB_CODE internal_db_sort ( int db_handle,
405 USHORT field_id,
406 UBYTE sort_index,
407 T_COMP_FUNC compare_function,
408 ULONG flags,
409 T_DB_SORT sort_type );
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435 /******************************
436 I M P L E M E N T A T I O N
437 ******************************/
438
439 /**********************/
440 /* INTERNAL FUNCTIONS */
441 /**********************/
442
443 /*
444 +--------------------------------------------------------------------+
445 | PROJECT: PHB MODULE: DBM |
446 | ROUINE: db_handle_check |
447 +--------------------------------------------------------------------+
448
449 PURPOSE : DB Handle checks
450 */
451
452 T_DB_CODE db_handle_check ( int db_handle )
453 {
454 /* Check for db_handle range */
455 if( db_handle >= MAX_DBs )
456 return DB_INVALID_DB;
457
458 /* Check for DBState of db_handle is CLOSED or UNUSED_ENTRY
459 If yes, return DB_INVALID_DB */
460
461 if( ( DbmMaster[db_handle].DBState EQ CLOSED ) OR
462 ( DbmMaster[db_handle].DBState EQ UNUSED_ENTRY ) )
463 return DB_INVALID_DB;
464
465 return DB_OK;
466 }
467
468 /*
469 +--------------------------------------------------------------------+
470 | PROJECT: PHB MODULE: DBM |
471 | ROUINE: field_id_search |
472 +--------------------------------------------------------------------+
473
474 PURPOSE : checks for the existence of field id in RAM
475 */
476 UBYTE field_id_search ( int db_handle,
477 USHORT field_id )
478 {
479 UBYTE fld_ctr;
480
481 for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr )
482 {
483 if( DbmMaster[db_handle].ptrFieldRecord[fld_ctr].FieldID EQ field_id )
484 {
485 return fld_ctr;
486 }
487 }
488 return fld_ctr;
489 }
490
491
492 /*
493 +--------------------------------------------------------------------+
494 | PROJECT: PHB MODULE: DBM |
495 | ROUINE: update_history_log |
496 +--------------------------------------------------------------------+
497
498 PURPOSE : Updating history log
499 */
500 T_DB_CODE update_history_log ( int db_handle,
501 USHORT field_id,
502 USHORT record_num )
503 {
504 UBYTE i;
505
506 /* Check if database is tracked */
507 if( NOT ( DbmMaster[db_handle].Tracked_Clean & TRACKED ) ) /* if db is NOT tracked */
508 return DB_OK;
509
510 /* Search history log if the record is present
511 If present, return DB_OK */
512 for( i = 0; i < DB_History_log.entries; ++i )
513 {
514 if( DB_History_log.field_id[i] EQ field_id )
515 if( DB_History_log.record[i] EQ record_num )
516 return DB_OK;
517 }
518
519 /* If the number of existing logs in history is reached limit, DB_MAX_AFFECTED,
520 return error "DB_HISTORY_FULL". */
521 if( DB_History_log.entries EQ DB_MAX_AFFECTED )
522 return DB_HISTORY_FULL;
523
524 /* Add new entry */
525 DB_History_log.field_id [DB_History_log.entries] = field_id;
526 DB_History_log.record [DB_History_log.entries] = record_num;
527 ++DB_History_log.entries;
528
529 return DB_OK;
530
531 }
532
533 /*
534 +--------------------------------------------------------------------+
535 | PROJECT: PHB MODULE: DBM |
536 | ROUINE: swap |
537 +--------------------------------------------------------------------+
538
539 PURPOSE : Swaps the data
540 */
541 void swap ( UBYTE* sort_list,
542 UBYTE low,
543 UBYTE high )
544 {
545 UBYTE tmp = sort_list[low - 1];
546
547 sort_list[low - 1] = sort_list[high - 1];
548 sort_list[high - 1] = tmp;
549
550 return;
551
552 }
553
554 /*
555 +--------------------------------------------------------------------+
556 | PROJECT: PHB MODULE: DBM |
557 | ROUINE: split_list |
558 +--------------------------------------------------------------------+
559
560 PURPOSE :
561 */
562 UBYTE split_list ( UBYTE* sort_list,
563 UBYTE low,
564 UBYTE high,
565 T_COMP_FUNC compare_function,
566 ULONG flags,
567 int db_handle,
568 USHORT field_id )
569 {
570 UBYTE i,
571 pivot_loc;
572
573 /* put pivot at first position */
574 swap( sort_list, low, (UBYTE)((low + high)/2));
575
576 pivot_loc = low;
577
578 for( i = low + 1; i <= high; ++i )
579 {
580 if( compare_function( db_handle,
581 field_id,
582 sort_list[i - 1],
583 sort_list[low - 1],
584 flags )
585 < 0 )
586 {
587 ++pivot_loc;
588 swap( sort_list, pivot_loc, i );
589 }
590 }
591
592 swap( sort_list, low, pivot_loc );
593
594 return pivot_loc;
595 }
596
597
598 /*
599 +--------------------------------------------------------------------+
600 | PROJECT: PHB MODULE: DBM |
601 | ROUINE: quick_sort |
602 +--------------------------------------------------------------------+
603
604 PURPOSE : Sorts the user data records in FFS based
605 on non-recursive qsort method
606 */
607 void quick_sort ( UBYTE* sort_list,
608 UBYTE num_of_elements,
609 T_COMP_FUNC compare_function,
610 ULONG flags,
611 int db_handle,
612 USHORT field_id )
613 {
614 /* This is non-recursive version of QuickSort
615
616 - It requires additional storage of (2 * QuickSort_BufferStackSize) bytes
617 compared to recursive version of quick sort
618
619 - It supports sorting of 2 ^ QuickSort_BufferStackSize elements. */
620
621 /* It is assumed that MAX_NUM_RECORDS = 254;if we want to support the
622 sorting of list bigger than 254 elements, change following UBYTE
623 to U16, U32 etc. and update QuickSort_BufferStackSize accordingly ! */
624
625 UBYTE low,
626 high,
627 pivot_loc,
628 buff_stack_ctr = 0,
629 buffer_low[QuickSort_BufferStackSize],
630 buffer_high[QuickSort_BufferStackSize];
631
632 low = 1;
633 high = num_of_elements;
634
635 do
636 {
637 if( buff_stack_ctr > 0 )
638 {
639 --buff_stack_ctr;
640 low = buffer_low[buff_stack_ctr];
641 high = buffer_high[buff_stack_ctr];
642 }
643
644 while( low < high )
645 {
646 pivot_loc = split_list( sort_list,
647 low,
648 high,
649 compare_function,
650 flags,
651 db_handle,
652 field_id );
653
654 if( buff_stack_ctr >= QuickSort_BufferStackSize )
655 {
656 /* This should never happen ! */
657 TRACE_ERROR( "Value set for QuickSort_BufferStackSize is small !");
658 return;
659 }
660
661 /* Remember larger sublist, and process smaller */
662
663 if( (pivot_loc - low) < (high - pivot_loc) )
664 {
665 /* right list is bigger */
666 buffer_low[buff_stack_ctr] = pivot_loc + 1;
667 buffer_high[buff_stack_ctr] = high;
668 ++buff_stack_ctr;
669 high = pivot_loc - 1;
670
671 } else {
672 /* left list is bigger */
673 buffer_low[buff_stack_ctr] = low;
674 buffer_high[buff_stack_ctr] = pivot_loc - 1;
675 ++buff_stack_ctr;
676 low = pivot_loc + 1;
677
678 }
679 }
680 } while( buff_stack_ctr != 0 );
681
682 return;
683 }
684
685 /*
686 +-------------------------------------------------------------------------------+
687 | PROJECT: PHB MODULE: DBM |
688 | ROUINE: search_clear_bit_in_bitmap |
689 +-------------------------------------------------------------------------------+
690
691 PURPOSE : Searches for the bit not set in record bitmap which
692 indicates free record
693 */
694 UBYTE search_clear_bit_in_bitmap ( UBYTE* bitmap,
695 UBYTE bitmap_size )
696 {
697 UBYTE* tmp_byte_ptr = bitmap + bitmap_size - 1 ;
698 UBYTE bitmap_num = 0,
699 bit_num,
700 tmp_byte;
701
702 /* we will go byte by byte */
703 while( bitmap_num < ( bitmap_size * MAX_BIT_POS ) )
704 {
705 tmp_byte = *tmp_byte_ptr;
706
707 for( bit_num = 0; bit_num < MAX_BIT_POS; ++bit_num )
708 {
709 if( NOT (tmp_byte & 0x01) )
710 {
711 return bitmap_num;
712 }
713 tmp_byte >>= 1;
714 ++bitmap_num;
715 }
716
717 --tmp_byte_ptr;
718 }
719
720 return bitmap_num;
721
722 }
723
724 /*
725 +--------------------------------------------------------------------+
726 | PROJECT: PHB MODULE: DBM |
727 | ROUINE: set_bit_in_bitmap |
728 +--------------------------------------------------------------------+
729
730 PURPOSE : Sets a bit in record bitmap
731 */
732 void set_bit_in_bitmap ( UBYTE* bitmap,
733 UBYTE bitmap_size,
734 UBYTE bit_num )
735 {
736 bitmap[ bitmap_size - BITMAP_INDEX(bit_num) - 1 ] |= (0x01 << BIT_POS(bit_num) );
737 }
738
739 /*
740 +------------------------------------------------------------------------+
741 | PROJECT: PHB MODULE: DBM |
742 | ROUINE: reset_bit_in_bitmap |
743 +------------------------------------------------------------------------+
744
745 PURPOSE : resets a bit in record bitmap
746 */
747 void reset_bit_in_bitmap ( UBYTE* bitmap,
748 UBYTE bitmap_size,
749 UBYTE bit_num )
750 {
751 bitmap[ bitmap_size - BITMAP_INDEX(bit_num) - 1 ] &= ~ (0x01 << BIT_POS(bit_num));
752 }
753
754 /*
755 +----------------------------------------------------------------------------------+
756 | PROJECT: PHB MODULE: DBM |
757 | ROUINE: populate_sorted_list_from_FFS |
758 +----------------------------------------------------------------------------------+
759
760 PURPOSE : Reads the sorted list from FFS
761 */
762 T_DB_CODE populate_sorted_list_from_FFS (
763
764 #ifdef FFS_CLOSE_BEFORE_OPEN
765 UBYTE db_ctr,
766 #endif
767 char* sort_file,
768 UBYTE num_of_elements,
769 UBYTE** sort_list_ptr )
770 {
771 T_FFS_FD ffs_fd_sort_file;
772 T_FFS_SIZE ffs_ret_code;
773 UBYTE* sort_list;
774
775 #ifdef FFS_CLOSE_BEFORE_OPEN
776 /* READ */
777 if( db_open_full_for_read( db_ctr ) )
778 {
779 db_close_for_read( db_ctr );
780 }
781 #endif
782
783 DB_FFS_OPEN( ffs_fd_sort_file, sort_file, FFS_O_RDONLY );
784
785 if( (ffs_fd_sort_file EQ EFFS_NAMETOOLONG ) OR
786 (ffs_fd_sort_file EQ EFFS_BADNAME ) OR
787 (ffs_fd_sort_file EQ EFFS_NOTFOUND ) OR
788 (ffs_fd_sort_file EQ EFFS_INVALID ) OR
789 (ffs_fd_sort_file EQ EFFS_LOCKED ) )
790
791 {
792 TRACE_EVENT_P1( "populate_sorted_list_from_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file );
793 return DB_FAIL;
794 }
795
796 if( ffs_fd_sort_file < EFFS_OK )
797 {
798 LastFFS_ReturnCode = ffs_fd_sort_file;
799 TRACE_EVENT_P1( "populate_sorted_list_from_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file );
800 return DB_FAIL_FS;
801 }
802
803 /* This seek is not required as file pointer will be at start of file,
804 but ffs guide doesn't say so ! This needs to be clarified and
805 accordingly all ffs_seek at start of file after opening the file
806 can be removed ! */
807 ffs_ret_code = ffs_seek( ffs_fd_sort_file, 0, FFS_SEEK_SET );
808
809 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
810 ( ffs_ret_code EQ EFFS_INVALID ) OR
811 ( ffs_ret_code EQ EFFS_BADOP ) )
812 {
813 DB_FFS_CLOSE( ffs_fd_sort_file );
814 TRACE_EVENT_P1( "populate_sorted_list_from_FFS:ffs_seek %d", ffs_ret_code );
815 return DB_FAIL;
816 }
817
818
819 #ifndef INSERTION_SORT
820
821 DB_MALLOC( sort_list, num_of_elements );
822 memset( sort_list, INVALID_RECORD_NUM, num_of_elements );
823
824 #else /* INSERTION_SORT */
825
826 DB_MALLOC( sort_list, num_of_elements + 1 );
827 memset( sort_list, INVALID_RECORD_NUM, num_of_elements + 1 );
828
829 #endif /* INSERTION_SORT */
830
831 ffs_ret_code = ffs_read( ffs_fd_sort_file,
832 sort_list,
833 num_of_elements );
834
835 if( (ffs_ret_code EQ EFFS_BADFD ) OR
836 (ffs_ret_code EQ EFFS_BADOP ) )
837 {
838 DB_MFREE( sort_list );
839 DB_FFS_CLOSE( ffs_fd_sort_file );
840 TRACE_EVENT_P1( "populate_sorted_list_from_FFS:ffs_read %d", ffs_ret_code );
841 return DB_FAIL;
842 }
843
844 if( ffs_ret_code < EFFS_OK )
845 {
846 LastFFS_ReturnCode = ffs_fd_sort_file;
847 DB_MFREE( sort_list );
848 TRACE_EVENT_P1( "populate_sorted_list_from_FFS:ffs_read %d", ffs_ret_code );
849 DB_FFS_CLOSE( ffs_fd_sort_file );
850 return DB_FAIL_FS;
851 }
852
853 DB_FFS_CLOSE( ffs_fd_sort_file );
854
855 /* to avoid memory leak */
856 if( *sort_list_ptr NEQ NULL )
857 DB_MFREE( *sort_list_ptr );
858
859 *sort_list_ptr = sort_list;
860
861 return DB_OK;
862 }
863
864 /*
865 +-----------------------------------------------------------------------------+
866 | PROJECT: PHB MODULE: DBM |
867 | ROUINE: write_sorted_list_to_FFS |
868 +-----------------------------------------------------------------------------+
869
870 PURPOSE : Writes the sorted list into FFS
871 */
872 T_DB_CODE write_sorted_list_to_FFS (
873
874 #ifdef FFS_CLOSE_BEFORE_OPEN
875 UBYTE db_ctr,
876 #endif
877 char* sort_file,
878 UBYTE num_of_elements,
879 UBYTE* sort_list )
880 {
881 T_FFS_FD ffs_fd_sort_file;
882 T_FFS_SIZE ffs_ret_code;
883
884 #ifdef FFS_CLOSE_BEFORE_OPEN
885 /* WRITE */
886 if( db_open_full_for_write( db_ctr ) )
887 {
888 db_close_for_write( db_ctr );
889 }
890 #endif
891
892 /* FFS_O_TRUNC => If file already exists and it is opened for writing, its
893 length is truncated to zero. */
894
895 DB_FFS_OPEN( ffs_fd_sort_file, sort_file, FFS_O_CREATE | FFS_O_WRONLY | FFS_O_TRUNC );
896
897 if( (ffs_fd_sort_file EQ EFFS_NAMETOOLONG ) OR
898 (ffs_fd_sort_file EQ EFFS_BADNAME ) )
899 {
900 TRACE_EVENT_P1( "write_sorted_list_to_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file );
901 return DB_FAIL;
902 }
903
904 if( ffs_fd_sort_file < EFFS_OK )
905 {
906 TRACE_EVENT_P1( "write_sorted_list_to_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file );
907 LastFFS_ReturnCode = ffs_fd_sort_file;
908 return DB_FAIL_FS;
909 }
910
911
912 ffs_ret_code = ffs_seek( ffs_fd_sort_file, 0, FFS_SEEK_SET );
913
914 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
915 ( ffs_ret_code EQ EFFS_INVALID ) OR
916 ( ffs_ret_code EQ EFFS_BADOP ) )
917 {
918 TRACE_EVENT_P1( "write_sorted_list_to_FFS:ffs_seek %d", ffs_ret_code );
919 DB_FFS_CLOSE( ffs_fd_sort_file );
920 return DB_FAIL;
921 }
922
923 ffs_ret_code = ffs_write( ffs_fd_sort_file,
924 sort_list,
925 num_of_elements );
926
927 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
928 ( ffs_ret_code EQ EFFS_BADOP ) )
929 {
930 DB_FFS_CLOSE( ffs_fd_sort_file );
931 ffs_ret_code = ffs_remove( sort_file );
932 TRACE_EVENT_P1( "write_sorted_list_to_FFS:ffs_write %d", ffs_ret_code );
933 return DB_FAIL;
934 }
935
936 if( ffs_ret_code < EFFS_OK )
937 {
938 LastFFS_ReturnCode = ffs_ret_code;
939 DB_FFS_CLOSE( ffs_fd_sort_file );
940 ffs_ret_code = ffs_remove( sort_file );
941 TRACE_EVENT_P1( "write_sorted_list_to_FFS:ffs_write %d", ffs_ret_code );
942 return DB_FAIL_FS;
943 }
944
945 DB_FFS_CLOSE( ffs_fd_sort_file ); /* yeah, we close it here ! */
946
947 return DB_OK;
948
949 }
950
951 /*
952 +--------------------------------------------------------------------+
953 | PROJECT: PHB MODULE: DBM |
954 | ROUINE: search |
955 +--------------------------------------------------------------------+
956
957 PURPOSE : Searches for the record; uses binary search and compare
958 function is passed as a parameter.
959 */
960 int search ( UBYTE* sort_list,
961 UBYTE num_of_elements,
962 UBYTE* order_num,
963 T_SEARCH_FUNC search_function,
964 ULONG flags,
965 const UBYTE* search_tag,
966 int db_handle,
967 USHORT field_id )
968 {
969 /* Binary search is used */
970 UBYTE top,
971 bottom,
972 middle;
973
974 S8 result;
975
976 /* Strictly speaking, this check is not required, but
977 it would save some processing time */
978 if( num_of_elements EQ 0 )
979 return SEARCH_FAILED;
980
981 if( (*order_num) EQ 0 )
982 {
983 /* Complete list search */
984 top = num_of_elements - 1;
985 bottom = 0;
986
987 } else {
988
989 /* Strictly speaking, this check is not required, but
990 it would save some processing time */
991 if( *order_num >= num_of_elements )
992 return SEARCH_FAILED;
993
994 /* Give the next element in sort list if matching */
995 if( search_function( flags,
996 search_tag,
997 db_handle,
998 field_id,
999 sort_list[ (*order_num) ] )
1000 EQ 0 )
1001 {
1002 *order_num += 1;
1003 return *order_num;
1004 }
1005
1006 return SEARCH_FAILED;
1007 }
1008
1009 if( num_of_elements EQ 2 )
1010 {
1011 /* Special case of two elements */
1012
1013 if( search_function( flags,
1014 search_tag,
1015 db_handle,
1016 field_id,
1017 sort_list[ 0 ] )
1018 EQ 0 )
1019 {
1020 *order_num = 1;
1021 return 1;
1022 }
1023
1024 if( search_function( flags,
1025 search_tag,
1026 db_handle,
1027 field_id,
1028 sort_list[ 1 ] )
1029 EQ 0 )
1030 {
1031 *order_num = 2;
1032 return 2;
1033 }
1034
1035 return SEARCH_FAILED;
1036 }
1037
1038 /* basic concept is here is to get first matching element in sort list and
1039 so we need to compare bottom_th element for returning */
1040
1041 while( top >= bottom )
1042 {
1043 /* if bottom_th element match, return PASS */
1044 if( search_function( flags,
1045 search_tag,
1046 db_handle,
1047 field_id,
1048 sort_list[ bottom ] )
1049 EQ 0 )
1050 {
1051 *order_num = bottom + 1;
1052 return *order_num;
1053 }
1054
1055 /* end of list */
1056 if( bottom EQ top )
1057 return SEARCH_FAILED;
1058
1059 /* now binary search comes into play */
1060
1061 middle = (top + bottom) / 2;
1062
1063 result = search_function( flags,
1064 search_tag,
1065 db_handle,
1066 field_id,
1067 sort_list[ middle ] );
1068
1069 if( result EQ 0 )
1070 {
1071 ++bottom;
1072
1073 if( bottom EQ middle )
1074 {
1075 /* middle has already matched so,
1076 instead of going to next loop, we return PASS here ! */
1077 *order_num = bottom + 1;
1078 return *order_num;
1079 }
1080
1081 top = middle;
1082
1083 } else {
1084
1085 if( result > 0 )
1086 {
1087 ++bottom;
1088
1089 } else {
1090
1091 bottom = middle + 1;
1092
1093 }
1094
1095 } /* result EQ 0 */
1096
1097 } /* while top >= bottom */
1098
1099 return SEARCH_FAILED;
1100
1101 }
1102
1103
1104 /*
1105 +-----------------------------------------------------------------------------+
1106 | PROJECT: PHB MODULE: DBM |
1107 | ROUINE: update_field_data_in_FFS |
1108 +-----------------------------------------------------------------------------+
1109
1110 PURPOSE : Updates elementary file data in FFS
1111 */
1112 T_DB_CODE update_field_data_in_FFS ( const char* field_file,
1113 T_FFS_FD* filehandle,
1114 #ifdef FFS_CLOSE_BEFORE_OPEN
1115 UBYTE db_ctr,
1116 #endif
1117 UBYTE fld_ctr,
1118 UBYTE field_data_max_size,
1119 UBYTE* field_data,
1120 USHORT offset,
1121 USHORT length )
1122 {
1123 T_FFS_FD ffs_fd = *filehandle;
1124 T_FFS_SIZE ffs_ret_code;
1125
1126 /* Updating field data in FFS in file "field_file" */
1127
1128 if( ffs_fd EQ NULL )
1129 {
1130 DB_FFS_OPEN( ffs_fd, field_file, FFS_O_WRONLY );
1131
1132 if( ( ffs_fd EQ EFFS_NOTFOUND ) OR
1133 ( ffs_fd EQ EFFS_NAMETOOLONG ) OR
1134 ( ffs_fd EQ EFFS_BADNAME ) OR
1135 ( ffs_fd EQ EFFS_INVALID ) )
1136 {
1137 TRACE_EVENT_P1( "update_field_data_in_FFS:DB_FFS_OPEN %d", ffs_fd );
1138 return DB_FAIL;
1139 }
1140
1141 if( ffs_fd < EFFS_OK )
1142 {
1143 LastFFS_ReturnCode = ffs_fd;
1144 TRACE_EVENT_P1( "update_field_data_in_FFS:DB_FFS_OPEN %d", ffs_fd );
1145 return DB_FAIL_FS;
1146 }
1147
1148 *filehandle = ffs_fd;
1149
1150 } /* filehandle EQ NULL ? */
1151
1152 /* Seek the file to fld_ctr position to update the entry */
1153 ffs_ret_code = ffs_seek( ffs_fd,
1154 ( fld_ctr * field_data_max_size ) + offset,
1155 FFS_SEEK_SET );
1156
1157 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
1158 ( ffs_ret_code EQ EFFS_INVALID ) OR
1159 ( ffs_ret_code EQ EFFS_BADOP ) )
1160 {
1161 TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_seek %d", ffs_ret_code );
1162 DB_FFS_CLOSE( ffs_fd );
1163 *filehandle = NULL;
1164 return DB_FAIL;
1165 }
1166
1167 if( ffs_ret_code < EFFS_OK )
1168 {
1169 TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_seek %d", ffs_ret_code );
1170 LastFFS_ReturnCode = ffs_ret_code;
1171 DB_FFS_CLOSE( ffs_fd );
1172 *filehandle = NULL;
1173 return DB_FAIL_FS;
1174 }
1175
1176 /* clean is reset in memset, so no processing for it
1177 (in case of non-tracked database, anyway we ignore it ! */
1178
1179 ffs_ret_code = ffs_write( ffs_fd,
1180 field_data,
1181 length );
1182
1183 if( (ffs_ret_code EQ EFFS_BADFD ) OR
1184 (ffs_ret_code EQ EFFS_BADOP ) )
1185 {
1186 TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_write %d", ffs_ret_code );
1187 DB_FFS_CLOSE( ffs_fd );
1188 *filehandle = NULL;
1189 return DB_FAIL;
1190 }
1191
1192 if( ffs_ret_code < EFFS_OK )
1193 {
1194 TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_write %d", ffs_ret_code );
1195 DB_FFS_CLOSE ( ffs_fd );
1196 *filehandle = NULL;
1197 LastFFS_ReturnCode = ffs_ret_code;
1198 return DB_FAIL_FS;
1199 }
1200
1201 /* DB_FFS_CLOSE( ffs_fd ); we will do it in db_flush */
1202 /* updation is over */
1203
1204 #ifdef FFS_OPEN_PROBLEM_PATCH
1205 DB_FFS_CLOSE( ffs_fd );
1206 *filehandle = NULL;
1207 #endif
1208
1209 #ifndef FFS_CLOSE_BEFORE_OPEN
1210 /* this is db file, but we do not close it */
1211 #endif
1212
1213 return DB_OK;
1214
1215 }
1216
1217 /*
1218 +--------------------------------------------------------------------+
1219 | PROJECT: PHB MODULE: DBM |
1220 | ROUINE: cal_NextRecordNum |
1221 +--------------------------------------------------------------------+
1222
1223 PURPOSE : Reads the status of the file and returns
1224 the next available record (position)
1225 */
1226 UBYTE cal_NextRecordNum ( const char* db_directory,
1227 USHORT field_id,
1228 USHORT record_size )
1229 {
1230 char user_field_file[FILENAME_LEN];
1231
1232 T_FFS_SIZE ffs_ret_code;
1233 T_FFS_STAT ffs_file_stat;
1234
1235 sprintf( user_field_file,
1236 "%s/UD_%d",
1237 db_directory,
1238 field_id );
1239
1240 ffs_ret_code = ffs_stat( user_field_file, &ffs_file_stat );
1241
1242 if( ffs_ret_code EQ EFFS_OK )
1243 {
1244 return ( (ffs_file_stat.size / record_size) + 1);
1245 }
1246
1247 if( ffs_ret_code EQ EFFS_NOTFOUND )
1248 {
1249 TRACE_EVENT( "cal_NextRecordNum:ffs_stat:FILE NOT FOUND" );
1250 return 1;
1251 }
1252
1253 /* this is a problem with user_field_file, raise an error and
1254 return 0 */
1255
1256 TRACE_ERROR( "cal_NextRecordNum: PROBLEM with user_field_file" );
1257 TRACE_EVENT_P1( "cal_NextRecordNum:ffs_stat %d", ffs_ret_code );
1258 return 1;
1259
1260 }
1261
1262
1263 /*
1264 +------------------------------------------------------------------------------+
1265 | PROJECT: PHB MODULE: DBM |
1266 | ROUINE: read_user_record_from_FFS |
1267 +------------------------------------------------------------------------------+
1268
1269 PURPOSE : Reads a user record from FFS
1270 */
1271 T_DB_CODE read_user_record_from_FFS ( const char* user_field_file,
1272
1273 #ifdef FFS_CLOSE_BEFORE_OPEN
1274 UBYTE db_ctr,
1275 UBYTE fld_ctr,
1276 #endif
1277 T_FFS_FD* filehandle,
1278 UBYTE record_num,
1279 USHORT record_size,
1280 USHORT offset,
1281 USHORT length,
1282 UBYTE* record_buffer )
1283 {
1284 T_FFS_FD ffs_fd = NULL;
1285 T_FFS_SIZE ffs_ret_code;
1286
1287 /* See if file already opened,
1288 if not open it and update the file handle */
1289
1290 #ifndef FFS_CLOSE_BEFORE_OPEN
1291 ffs_fd = *filehandle;
1292
1293 if( ffs_fd EQ NULL )
1294 {
1295 DB_FFS_OPEN( ffs_fd, user_field_file, FFS_O_RDONLY );
1296
1297 if( (ffs_fd EQ EFFS_NOTFOUND) OR
1298 (ffs_fd EQ EFFS_NAMETOOLONG) OR
1299 (ffs_fd EQ EFFS_BADNAME) OR
1300 (ffs_fd EQ EFFS_INVALID) OR
1301 (ffs_fd EQ EFFS_LOCKED) )
1302 {
1303 TRACE_EVENT_P1( "read_user_record_from_FFS:DB_FFS_OPEN %d", ffs_fd );
1304 return DB_FAIL;
1305 }
1306
1307 if( ffs_fd < EFFS_OK )
1308 {
1309 TRACE_EVENT_P1( "read_user_record_from_FFS:DB_FFS_OPEN %d", ffs_fd );
1310 LastFFS_ReturnCode = ffs_fd;
1311 return DB_FAIL_FS;
1312 }
1313
1314 *filehandle = ffs_fd;
1315 }
1316
1317 #else /* FFS_CLOSE_BEFORE_OPEN */
1318
1319 ffs_fd = db_open_user_field_file( db_ctr, fld_ctr, user_field_file, FFS_O_RDONLY );
1320
1321 #endif /* FFS_CLOSE_BEFORE_OPEN */
1322
1323 ffs_ret_code = ffs_seek( ffs_fd,
1324 ( (record_num - 1) * (record_size) + offset),
1325 FFS_SEEK_SET );
1326
1327 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
1328 ( ffs_ret_code EQ EFFS_INVALID ) OR
1329 ( ffs_ret_code EQ EFFS_BADOP ) )
1330 {
1331 TRACE_EVENT_P1( "read_user_record_from_FFS:ffs_seek %d", ffs_ret_code );
1332 DB_FFS_CLOSE( ffs_fd );
1333 *filehandle = NULL;
1334 return DB_FAIL;
1335 }
1336
1337 if( ffs_ret_code < EFFS_OK )
1338 {
1339 TRACE_EVENT_P1( "read_user_record_from_FFS:ffs_seek %d", ffs_ret_code );
1340 LastFFS_ReturnCode = ffs_ret_code;
1341 DB_FFS_CLOSE( ffs_fd );
1342 *filehandle = NULL;
1343 return DB_FAIL_FS;
1344 }
1345
1346 ffs_ret_code = ffs_read( ffs_fd,
1347 record_buffer,
1348 length );
1349
1350 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
1351 ( ffs_ret_code EQ EFFS_BADOP ) )
1352 {
1353 TRACE_EVENT_P1( "read_user_record_from_FFS:ffs_read %d", ffs_ret_code );
1354 DB_FFS_CLOSE( ffs_fd );
1355 *filehandle = NULL;
1356 return DB_FAIL;
1357 }
1358
1359 if( ffs_ret_code < EFFS_OK )
1360 {
1361 TRACE_EVENT_P1( "read_user_record_from_FFS:ffs_read %d", ffs_ret_code );
1362 LastFFS_ReturnCode = ffs_ret_code;
1363 DB_FFS_CLOSE( ffs_fd );
1364 *filehandle = NULL;
1365 return DB_FAIL_FS;
1366 }
1367
1368 /* DB_FFS_CLOSE( ffs_fd ); we will do it in db_flush */
1369
1370 #ifdef FFS_OPEN_PROBLEM_PATCH
1371 DB_FFS_CLOSE( ffs_fd );
1372 *filehandle = NULL;
1373 #endif
1374
1375 return DB_OK;
1376 }
1377
1378 /*
1379 +-------------------------------------------------------------------------------+
1380 | PROJECT: PHB MODULE: DBM |
1381 | ROUINE: write_user_record_to_FFS |
1382 +-------------------------------------------------------------------------------+
1383
1384 PURPOSE : Writes user record into FFS
1385 */
1386 T_DB_CODE write_user_record_to_FFS ( const char* user_field_file,
1387
1388 #ifdef FFS_CLOSE_BEFORE_OPEN
1389 UBYTE db_ctr,
1390 UBYTE fld_ctr,
1391 #endif
1392 T_FFS_FD* filehandle,
1393 UBYTE record_num,
1394 USHORT record_size,
1395 USHORT offset,
1396 USHORT length,
1397 UBYTE* record_buffer )
1398 {
1399 T_FFS_FD ffs_fd = NULL;
1400 T_FFS_SIZE ffs_ret_code;
1401
1402 /* See if file already opened,
1403 if not open it and update the file handle */
1404
1405 #ifndef FFS_CLOSE_BEFORE_OPEN
1406 ffs_fd = *filehandle;
1407
1408 if( ffs_fd EQ NULL )
1409 {
1410 DB_FFS_OPEN( ffs_fd, user_field_file, FFS_O_RDWR );
1411
1412 if( (ffs_fd EQ EFFS_NOTFOUND) OR
1413 (ffs_fd EQ EFFS_NAMETOOLONG) OR
1414 (ffs_fd EQ EFFS_BADNAME) OR
1415 (ffs_fd EQ EFFS_INVALID) OR
1416 (ffs_fd EQ EFFS_LOCKED) )
1417 {
1418 TRACE_EVENT_P1( "write_user_record_to_FFS:DB_FFS_OPEN %d", ffs_fd );
1419 return DB_FAIL;
1420 }
1421
1422 if( ffs_fd < EFFS_OK )
1423 {
1424 TRACE_EVENT_P1( "write_user_record_to_FFS:DB_FFS_OPEN %d", ffs_fd );
1425 LastFFS_ReturnCode = ffs_fd;
1426 return DB_FAIL_FS;
1427 }
1428
1429 *filehandle = ffs_fd;
1430 }
1431
1432 #else /* FFS_CLOSE_BEFORE_OPEN */
1433
1434 ffs_fd = db_open_user_field_file( db_ctr, fld_ctr, user_field_file, FFS_O_RDWR );
1435
1436 #endif /* FFS_CLOSE_BEFORE_OPEN */
1437
1438 ffs_ret_code = ffs_seek( ffs_fd,
1439 ( (record_num - 1) * (record_size) + offset),
1440 FFS_SEEK_SET );
1441
1442 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
1443 ( ffs_ret_code EQ EFFS_INVALID ) OR
1444 ( ffs_ret_code EQ EFFS_BADOP ) )
1445 {
1446 TRACE_EVENT_P1( "write_user_record_to_FFS:ffs_seek %d", ffs_ret_code );
1447 DB_FFS_CLOSE( ffs_fd );
1448 *filehandle = NULL;
1449 return DB_FAIL;
1450 }
1451
1452 if( ffs_ret_code < EFFS_OK )
1453 {
1454 TRACE_EVENT_P1( "write_user_record_to_FFS:ffs_seek %d", ffs_ret_code );
1455 LastFFS_ReturnCode = ffs_ret_code;
1456 DB_FFS_CLOSE( ffs_fd );
1457 *filehandle = NULL;
1458 return DB_FAIL_FS;
1459 }
1460
1461 ffs_ret_code = ffs_write( ffs_fd,
1462 record_buffer,
1463 length );
1464
1465 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
1466 ( ffs_ret_code EQ EFFS_BADOP ) )
1467 {
1468 TRACE_EVENT_P1( "write_user_record_to_FFS:ffs_write %d", ffs_ret_code );
1469 DB_FFS_CLOSE( ffs_fd );
1470 *filehandle = NULL;
1471 return DB_FAIL;
1472 }
1473
1474 if( ffs_ret_code < EFFS_OK )
1475 {
1476 TRACE_EVENT_P1( "write_user_record_to_FFS:ffs_write %d", ffs_ret_code );
1477 LastFFS_ReturnCode = ffs_ret_code;
1478 DB_FFS_CLOSE( ffs_fd );
1479 *filehandle = NULL;
1480 return DB_FAIL_FS;
1481 }
1482
1483 /* DB_FFS_CLOSE( ffs_fd ); we will do it in db_flush */
1484
1485 #ifdef FFS_OPEN_PROBLEM_PATCH
1486 DB_FFS_CLOSE( ffs_fd );
1487 *filehandle = NULL;
1488 #endif
1489
1490 return DB_OK;
1491 }
1492
1493 /*
1494 +-----------------------------------------------------------------------------+
1495 | PROJECT: PHB MODULE: DBM |
1496 | ROUINE: delete_file_dir_from_FFS |
1497 +-----------------------------------------------------------------------------+
1498
1499 PURPOSE : Deletes a file from FFS
1500 */
1501 T_DB_CODE delete_file_dir_from_FFS ( const char* filename )
1502 {
1503 T_FFS_SIZE ffs_ret_code;
1504
1505 TRACE_EVENT_P1( "delete_file_dir_from_FFS %s", filename );
1506
1507 ffs_ret_code = ffs_remove( filename );
1508
1509 #ifdef FORCED_DIR_REMOVAL
1510
1511 if( ffs_ret_code EQ EFFS_DIRNOTEMPTY )
1512 {
1513 TRACE_EVENT( "Inconsistency; going for delete_dir_forced" );
1514 return delete_dir_forced( filename );
1515 }
1516
1517 #endif
1518
1519 if( ffs_ret_code EQ EFFS_NOTFOUND )
1520 {
1521 TRACE_EVENT( "delete_file_dir_from_FFS:ffs_remove:FILE NOT FOUND" );
1522 return DB_OK;
1523 }
1524
1525 if( ( ffs_ret_code EQ EFFS_ACCESS ) OR
1526 ( ffs_ret_code EQ EFFS_LOCKED ) )
1527 {
1528 TRACE_EVENT_P1( "delete_file_dir_from_FFS:ffs_remove %d", ffs_ret_code );
1529 return DB_FAIL;
1530 }
1531
1532 if( ffs_ret_code < EFFS_OK )
1533 {
1534 TRACE_EVENT_P1( "delete_file_dir_from_FFS:ffs_remove %d", ffs_ret_code );
1535 LastFFS_ReturnCode = ffs_ret_code;
1536 return DB_FAIL_FS;
1537 }
1538
1539 return DB_OK;
1540
1541 }
1542
1543 /*
1544 +---------------------------------------------------------------------------+
1545 | PROJECT: PHB MODULE: DBM |
1546 | ROUINE: update_dbm_data_in_FFS |
1547 +---------------------------------------------------------------------------+
1548
1549 PURPOSE : Updates the database manager information of a
1550 particular database
1551 */
1552 T_DB_CODE update_dbm_data_in_FFS ( const char* filename,
1553 UBYTE db_ctr,
1554 UBYTE db_data_max_size,
1555 UBYTE* db_data,
1556 USHORT offset,
1557 USHORT length )
1558 {
1559 T_FFS_FD ffs_fd = NULL;
1560 T_FFS_SIZE ffs_ret_code;
1561
1562 /* See if file already opened,
1563 if not open it and update the file handle */
1564
1565 #ifdef FFS_CLOSE_BEFORE_OPEN
1566 /* WRITE */
1567 if( db_open_full_for_write( db_ctr ) )
1568 {
1569 db_close_for_write( db_ctr );
1570 }
1571 #endif
1572
1573 DB_FFS_OPEN( ffs_fd, filename, FFS_O_WRONLY );
1574
1575 if( ( ffs_fd EQ EFFS_NAMETOOLONG ) OR
1576 ( ffs_fd EQ EFFS_BADNAME ) OR
1577 ( ffs_fd EQ EFFS_NOTFOUND ) OR
1578 ( ffs_fd EQ EFFS_INVALID ) OR
1579 ( ffs_fd EQ EFFS_LOCKED ) )
1580 {
1581 TRACE_EVENT_P1( "update_dbm_data_in_FFS:DB_FFS_OPEN %d", ffs_fd );
1582 return DB_FAIL;
1583 }
1584
1585 if( ffs_fd < EFFS_OK )
1586 {
1587 TRACE_EVENT_P1( "update_dbm_data_in_FFS:DB_FFS_OPEN %d", ffs_fd );
1588 LastFFS_ReturnCode = ffs_fd;
1589 return DB_FAIL_FS;
1590 }
1591
1592 ffs_ret_code = ffs_seek( ffs_fd, db_ctr * db_data_max_size, FFS_SEEK_SET );
1593
1594 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
1595 ( ffs_ret_code EQ EFFS_INVALID ) OR
1596 ( ffs_ret_code EQ EFFS_BADOP ) )
1597 {
1598 TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_seek %d", ffs_ret_code );
1599 DB_FFS_CLOSE( ffs_fd );
1600 return DB_FAIL;
1601 }
1602
1603 if( ffs_ret_code < EFFS_OK )
1604 {
1605 TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_seek %d", ffs_ret_code );
1606 LastFFS_ReturnCode = ffs_ret_code;
1607 DB_FFS_CLOSE( ffs_fd );
1608 return DB_FAIL_FS;
1609 }
1610
1611 ffs_ret_code = ffs_write( ffs_fd, db_data, db_data_max_size );
1612
1613 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
1614 ( ffs_ret_code EQ EFFS_BADOP ) )
1615 {
1616 TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_write %d", ffs_ret_code );
1617 DB_FFS_CLOSE( ffs_fd );
1618 return DB_FAIL;
1619 }
1620
1621 if( ffs_ret_code < EFFS_OK )
1622 {
1623 TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_write %d", ffs_ret_code );
1624 DB_FFS_CLOSE( ffs_fd );
1625 LastFFS_ReturnCode = ffs_ret_code;
1626 return DB_FAIL_FS;
1627 }
1628
1629 DB_FFS_CLOSE( ffs_fd ); /* yeah, DB file, so ok to close it here ! */
1630
1631 /* updation of dbm data done */
1632
1633 return DB_OK;
1634 }
1635
1636 /*
1637 +--------------------------------------------------------------------------+
1638 | PROJECT: PHB MODULE: DBM |
1639 | ROUINE: remove_field_from_FFS |
1640 +--------------------------------------------------------------------------+
1641
1642 PURPOSE : Removes the elementary file and associated Index
1643 file from FFS
1644 */
1645 T_DB_CODE remove_field_from_FFS ( UBYTE db_ctr,
1646 UBYTE fld_ctr )
1647 {
1648 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
1649 char user_field_file[FILENAME_LEN],
1650 sort_file[FILENAME_LEN];
1651 T_DB_CODE db_ret_code;
1652 UBYTE sort_index_ctr;
1653
1654 /* Assumed that DBState is not IN_USE */
1655
1656 tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr;
1657
1658 if( tmp_ptrFieldRecord -> FieldID EQ INVALID_FIELD_ID ) /* if not valid field id */
1659 return DB_OK;
1660
1661 /* Close of user record files not required as DBState is not IN_USE */
1662
1663 /* Delete file "<DBDirectory>/UD_<field_id>" */
1664
1665 sprintf( user_field_file,
1666 "%s/UD_%d",
1667 DbmMaster[db_ctr].DBDirectory,
1668 tmp_ptrFieldRecord -> FieldID );
1669
1670 db_ret_code = delete_file_dir_from_FFS ( user_field_file );
1671
1672 if( db_ret_code NEQ DB_OK )
1673 return db_ret_code;
1674
1675 /* For sorted lists */
1676
1677 for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
1678 {
1679 if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX )
1680 {
1681 /* Sort file, "<DBDirectory>/UD_<field_id>_sort_<sort_index>" */
1682
1683 sprintf( sort_file,
1684 "%s/UD_%d_sort_%d",
1685 DbmMaster[db_ctr].DBDirectory,
1686 tmp_ptrFieldRecord -> FieldID,
1687 tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] );
1688
1689 db_ret_code = delete_file_dir_from_FFS ( sort_file );
1690
1691 if( db_ret_code NEQ DB_OK )
1692 return db_ret_code;
1693 }
1694 }
1695
1696 return DB_OK;
1697
1698 }
1699
1700
1701
1702 #ifdef FFS_CLOSE_BEFORE_OPEN
1703
1704 T_FFS_FD db_open_user_field_file ( UBYTE db_ctr,
1705 UBYTE fld_ctr,
1706 const char* user_field_file,
1707 T_FFS_OPEN_FLAGS open_option )
1708 {
1709 UBYTE i;
1710 FileHandleRecord* tmp_open_fields;
1711 UBYTE* tmp_old;
1712 UBYTE tmp_max;
1713
1714 /* sanity checks not done (db_ctr >= MAX_DBs OR fld_ctr EQ INVALID_FLD_CTR) */
1715
1716 /* note that we store field counters and not field ids */
1717
1718 /* Search in write/read list */
1719 for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i )
1720 {
1721 if( DbmMaster[db_ctr].WRITE_OPEN_FIELDS[i].fld_ctr EQ fld_ctr )
1722 return DbmMaster[db_ctr].WRITE_OPEN_FIELDS[i].filehandle;
1723 } /* for */
1724
1725 /* Search in read only list */
1726 for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i )
1727 {
1728 if( DbmMaster[db_ctr].READ_OPEN_FIELDS[i].fld_ctr EQ fld_ctr )
1729 {
1730 if( NOT ( open_option & FFS_O_WRONLY ) ) /* if not opened for writing */
1731 {
1732 return DbmMaster[db_ctr].READ_OPEN_FIELDS[i].filehandle;
1733 }
1734
1735 /* we need to reopen it in write mode */
1736 DB_FFS_CLOSE( DbmMaster[db_ctr].READ_OPEN_FIELDS[i].filehandle );
1737
1738 DbmMaster[db_ctr].READ_OPEN_FIELDS[i].fld_ctr = INVALID_FLD_CTR;
1739
1740 break;
1741
1742 }
1743 } /* for */
1744
1745 /* field is not present in both lists */
1746
1747 if( open_option & FFS_O_WRONLY )
1748 {
1749
1750 /* for writing and reading both */
1751 tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS;
1752 tmp_old = &(DbmMaster[db_ctr].old_write);
1753 tmp_max = MAX_OPEN_WRITE_PER_DB;
1754
1755 } else {
1756
1757 /* for reading only */
1758 tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS;
1759 tmp_old = &(DbmMaster[db_ctr].old_read);
1760 tmp_max = MAX_OPEN_READ_PER_DB;
1761 }
1762
1763
1764 /* search the list */
1765 for( i = 0; i < tmp_max; ++i )
1766 {
1767 if( tmp_open_fields[i].fld_ctr EQ INVALID_FLD_CTR )
1768 {
1769 DB_FFS_OPEN( tmp_open_fields[i].filehandle,
1770 user_field_file,
1771 open_option );
1772
1773 tmp_open_fields[i].fld_ctr = fld_ctr;
1774
1775 return tmp_open_fields[i].filehandle;
1776 }
1777 } /* for */
1778
1779 /* we need to close the some file for opening this */
1780
1781 if( *tmp_old >= tmp_max )
1782 *tmp_old = 0;
1783
1784 DB_FFS_CLOSE( tmp_open_fields[*tmp_old].filehandle );
1785
1786 DB_FFS_OPEN( tmp_open_fields[*tmp_old].filehandle,
1787 user_field_file,
1788 open_option );
1789
1790 if( tmp_open_fields[*tmp_old].filehandle >= EFFS_OK )
1791 {
1792 tmp_open_fields[*tmp_old].fld_ctr = fld_ctr;
1793 ++(*tmp_old);
1794 return tmp_open_fields[*tmp_old - 1].filehandle;
1795 }
1796
1797 tmp_open_fields[*tmp_old].fld_ctr = INVALID_FLD_CTR;
1798
1799 return tmp_open_fields[*tmp_old].filehandle;
1800
1801 }
1802
1803 void db_close_user_field_files ( UBYTE db_ctr )
1804 {
1805 UBYTE i;
1806 FileHandleRecord* tmp_open_fields;
1807
1808 /* sanity check not done */
1809
1810 /* for write list */
1811
1812 tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS;
1813
1814 for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i )
1815 {
1816 if( tmp_open_fields[i].fld_ctr NEQ INVALID_FLD_CTR )
1817 {
1818 DB_FFS_CLOSE( tmp_open_fields[i].filehandle );
1819 tmp_open_fields[i].fld_ctr = INVALID_FLD_CTR;
1820 }
1821 }
1822
1823 /* for read list */
1824
1825 tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS;
1826
1827 for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i )
1828 {
1829 if( tmp_open_fields[i].fld_ctr NEQ INVALID_FLD_CTR )
1830 {
1831 DB_FFS_CLOSE( tmp_open_fields[i].filehandle );
1832 tmp_open_fields[i].fld_ctr = INVALID_FLD_CTR;
1833 }
1834 }
1835
1836 }
1837
1838 BOOL db_open_full_for_read ( UBYTE db_ctr )
1839 {
1840 UBYTE i;
1841 FileHandleRecord* tmp_open_fields;
1842
1843 /* sanity check not done */
1844
1845 /* for read list */
1846
1847 tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS;
1848
1849 for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i )
1850 {
1851 if( tmp_open_fields[i].fld_ctr EQ INVALID_FLD_CTR )
1852 return FALSE;
1853 }
1854
1855 return TRUE;
1856 }
1857
1858 BOOL db_open_full_for_write ( UBYTE db_ctr )
1859 {
1860 UBYTE i;
1861 FileHandleRecord* tmp_open_fields;
1862
1863 /* sanity check not done */
1864
1865 /* for write list */
1866
1867 tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS;
1868
1869 for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i )
1870 {
1871 if( tmp_open_fields[i].fld_ctr EQ INVALID_FLD_CTR )
1872 return FALSE;
1873 }
1874
1875 return TRUE;
1876 }
1877
1878 void db_close_for_read ( UBYTE db_ctr )
1879 {
1880 FileHandleRecord* tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS;
1881 UBYTE *tmp_old = &(DbmMaster[db_ctr].old_read);
1882
1883 /* sanity check not done */
1884
1885 /* for read list */
1886
1887 if( *tmp_old >= MAX_OPEN_READ_PER_DB )
1888 *tmp_old = 0;
1889
1890 DB_FFS_CLOSE( tmp_open_fields[*tmp_old].filehandle );
1891
1892 tmp_open_fields[*tmp_old].fld_ctr = INVALID_FLD_CTR;
1893
1894 ++(*tmp_old);
1895
1896 return;
1897
1898 }
1899
1900 void db_close_for_write ( UBYTE db_ctr )
1901 {
1902 FileHandleRecord* tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS;
1903 UBYTE *tmp_old = &(DbmMaster[db_ctr].old_write);
1904
1905 /* sanity check not done */
1906
1907 /* for read list */
1908
1909 if( *tmp_old >= MAX_OPEN_WRITE_PER_DB )
1910 *tmp_old = 0;
1911
1912 DB_FFS_CLOSE( tmp_open_fields[*tmp_old].filehandle );
1913
1914 tmp_open_fields[*tmp_old].fld_ctr = INVALID_FLD_CTR;
1915
1916 ++(*tmp_old);
1917
1918 return;
1919
1920 }
1921
1922 UBYTE db_status_user_field_file ( UBYTE db_ctr,
1923 UBYTE fld_ctr )
1924 {
1925 UBYTE i;
1926 FileHandleRecord* tmp_open_fields;
1927
1928 /* sanity check not done */
1929
1930 /* for write list */
1931
1932 tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS;
1933
1934 for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i )
1935 {
1936 if( tmp_open_fields[i].fld_ctr EQ fld_ctr )
1937 return OPENED_FOR_WRITE;
1938 }
1939
1940 /* for read list */
1941
1942 tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS;
1943
1944 for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i )
1945 {
1946 if( tmp_open_fields[i].fld_ctr EQ fld_ctr )
1947 return OPENED_FOR_READ;
1948 }
1949
1950 return NOT_OPENED;
1951
1952 }
1953
1954 #endif /* FFS_CLOSE_BEFORE_OPEN */
1955
1956
1957 #ifdef FORCED_DIR_REMOVAL
1958
1959 /*
1960 +-----------------------------------------------------------------------------+
1961 | PROJECT: PHB MODULE: DBM |
1962 | ROUINE: delete_dir_forced |
1963 +-----------------------------------------------------------------------------+
1964
1965 PURPOSE : Removes contents of dir and then delete the dir
1966 (it uses recursion)
1967 */
1968 T_DB_CODE delete_dir_forced ( const char* dir )
1969 {
1970 T_FFS_SIZE ffs_ret_code;
1971 T_FFS_DIR ffs_dir;
1972 T_FFS_STAT tmp_ffs_stat;
1973
1974 char pathname[FILENAME_LEN];
1975 UBYTE dir_len;
1976
1977 /* Open dir, if does not exist, just return DB_OK */
1978
1979 ffs_ret_code = ffs_opendir (dir, &ffs_dir);
1980
1981 if( ffs_ret_code EQ EFFS_NOTFOUND )
1982 DB_RETURN( DB_OK );
1983
1984 if( ffs_ret_code < EFFS_OK )
1985 {
1986 TRACE_EVENT_P2( "delete_dir_forced:ffs_remove %d, %s", ffs_ret_code, dir );
1987 LastFFS_ReturnCode = ffs_ret_code;
1988 DB_RETURN( DB_FAIL_FS );
1989 }
1990
1991 /* read dir recursively */
1992 sprintf( pathname,
1993 "%s/",
1994 dir );
1995
1996 dir_len = strlen( pathname );
1997
1998 while( 1 )
1999 {
2000 /* filename inside the directory would be copied at pathname + dirlen */
2001
2002 ffs_ret_code = ffs_readdir( &ffs_dir,
2003 pathname + dir_len,
2004 FILENAME_LEN - dir_len - 1 );
2005
2006 if( ffs_ret_code EQ 0 ) /* dir is empty now */
2007 {
2008 break;
2009 }
2010
2011 if( ffs_ret_code < EFFS_OK )
2012 {
2013 TRACE_EVENT_P2( "delete_dir_forced:ffs_readdir:%d, %s", ffs_ret_code, dir );
2014 LastFFS_ReturnCode = ffs_ret_code;
2015 DB_RETURN( DB_FAIL_FS );
2016 }
2017
2018 ffs_ret_code = ffs_stat( pathname, &tmp_ffs_stat );
2019
2020 if( ffs_ret_code < EFFS_OK )
2021 {
2022 TRACE_EVENT_P2( "delete_dir_forced:ffs_stat:%d, %s", ffs_ret_code, pathname);
2023 LastFFS_ReturnCode = ffs_ret_code;
2024 DB_RETURN( DB_FAIL_FS );
2025 }
2026
2027 if( tmp_ffs_stat.type EQ OT_DIR )
2028 {
2029 /* Directory !! */
2030
2031 T_DB_CODE db_code;
2032
2033 TRACE_EVENT_P1( "Warning: directory %s", pathname );
2034
2035 /* Recursion */
2036 db_code = delete_dir_forced( pathname );
2037
2038 if( db_code NEQ DB_OK )
2039 DB_RETURN( db_code );
2040
2041 } else {
2042
2043 /* normal file (OT_FILE) or symbolic link (OT_LINK) */
2044
2045 ffs_ret_code = ffs_remove( pathname );
2046
2047 if( ffs_ret_code < EFFS_OK )
2048 {
2049 TRACE_EVENT_P2( "delete_dir_forced:ffs_remove:%d, %s", ffs_ret_code, pathname );
2050 LastFFS_ReturnCode = ffs_ret_code;
2051 DB_RETURN( DB_FAIL_FS );
2052 }
2053
2054 } /* if( tmp_ffs_stat.type EQ OT_DIR ) */
2055
2056 } /* while( 1 ) */
2057
2058 /* now delete the directory */
2059 ffs_ret_code = ffs_remove( dir );
2060
2061 if( ffs_ret_code < EFFS_OK )
2062 {
2063 TRACE_EVENT_P2( "delete_dir_forced:ffs_remove:%d, %s", ffs_ret_code, dir );
2064 LastFFS_ReturnCode = ffs_ret_code;
2065 DB_RETURN( DB_FAIL_FS );
2066 }
2067
2068 DB_RETURN( DB_OK );
2069 }
2070
2071
2072 #endif /* FORCED_DIR_REMOVAL */
2073
2074
2075 #ifdef INSERTION_SORT
2076
2077 void get_sort_lists_from_FFS ( UBYTE db_ctr,
2078 UBYTE fld_ctr )
2079 {
2080 UBYTE sort_index_ctr;
2081
2082 T_DB_CODE db_ret_code;
2083
2084 char sort_file[FILENAME_LEN];
2085
2086 T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr;
2087
2088 /* for all existing sort indexes */
2089 for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
2090 {
2091 /* valid index ? */
2092 if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX )
2093 {
2094 /* Check if we already have sorted list in RAM structure SortedLists */
2095
2096 if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] EQ NULL )
2097 {
2098 /* If no, populate the sorted list from file,
2099 "<DBDirectory>/UD_<field_id>_sort_<sort_index>".
2100 Sorted lists are freed in db_flush */
2101
2102 sprintf( sort_file,
2103 "%s/UD_%d_sort_%d",
2104 DbmMaster[db_ctr].DBDirectory,
2105 tmp_ptrFieldRecord -> FieldID,
2106 tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] );
2107
2108 db_ret_code =
2109 populate_sorted_list_from_FFS (
2110 #ifdef FFS_CLOSE_BEFORE_OPEN
2111 db_ctr,
2112 #endif
2113 sort_file,
2114 tmp_ptrFieldRecord -> NumOfRecords,
2115 &(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr]) );
2116 if( db_ret_code NEQ DB_OK )
2117 {
2118 /* Failure, still we can continue as later during actual sorting,
2119 FFS would be retried */
2120
2121 TRACE_EVENT( "Warning: populate_sorted_list_from_FFS failed" );
2122 TRACE_EVENT_P3( "db_ctr %d field_id %d sort_index %d",
2123 db_ctr,
2124 tmp_ptrFieldRecord -> FieldID,
2125 tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] );
2126
2127 continue;
2128 }
2129
2130 } /* if we have sort list */
2131
2132 } /* if valid index */
2133
2134 } /* for all sort indexes */
2135
2136 return;
2137
2138 }
2139
2140 void new_in_sort_lists ( UBYTE db_ctr,
2141 UBYTE fld_ctr,
2142 UBYTE record_num )
2143 {
2144 UBYTE sort_index_ctr;
2145
2146 T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr;
2147
2148 /* make a note that this record needs to be sorted */
2149
2150 /* for all existing sort indexes */
2151 for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
2152 {
2153 if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX )
2154 {
2155 /* add it at the end like all sorted records + INVALID RECORD + .... */
2156 tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords]
2157 = record_num;
2158 }
2159 }
2160
2161 return;
2162
2163 }
2164
2165 void update_in_sort_lists ( UBYTE db_ctr,
2166 UBYTE fld_ctr,
2167 UBYTE record_num )
2168 {
2169 UBYTE sort_index_ctr,
2170 rec_ctr;
2171
2172 T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr;
2173
2174 /* make a note that this record needs to be sorted */
2175
2176 /* for all existing sort indexes */
2177 for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
2178 {
2179 if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX )
2180 {
2181 /* search entry in sorted records */
2182 rec_ctr = 0;
2183 while( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM )
2184 {
2185 if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] EQ record_num )
2186 {
2187 /* found in sorted records,
2188 now delete this entry */
2189
2190 memmove( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr, /* dest */
2191 (const char*)(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr + 1), /* source */
2192 tmp_ptrFieldRecord -> UsedRecords - rec_ctr ); /* size */
2193
2194 tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords]
2195 = record_num;
2196
2197 break;
2198 }
2199
2200 ++rec_ctr;
2201 }
2202
2203 } /* NEQ INVALID_SORT_INDEX */
2204
2205 } /* for sort_index_ctr */
2206
2207 return;
2208 }
2209
2210 void delete_in_sort_lists ( UBYTE db_ctr,
2211 UBYTE fld_ctr,
2212 UBYTE record_num )
2213 {
2214 UBYTE sort_index_ctr,
2215 rec_ctr;
2216
2217 T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr;
2218
2219 /* make a note that this record needs to be sorted */
2220
2221 /* for all existing sort indexes */
2222 for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
2223 {
2224 if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX )
2225 {
2226 /* search entry in sorted records */
2227 rec_ctr = 0;
2228 while( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM )
2229 {
2230 if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] EQ record_num )
2231 break;
2232
2233 ++rec_ctr;
2234 }
2235
2236 if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM )
2237 {
2238 /* found in sorted records,
2239 now delete this entry */
2240
2241 memmove( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr,
2242 (const char*)(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr + 1),
2243 tmp_ptrFieldRecord -> UsedRecords - rec_ctr );
2244
2245 tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords]
2246 = INVALID_RECORD_NUM;
2247
2248 } else {
2249
2250 /* search in UN-sorted records */
2251
2252 ++rec_ctr;
2253 while( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM )
2254 {
2255 if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] EQ record_num )
2256 {
2257 /* delete this entry */
2258 memmove( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr,
2259 (const char*)(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr + 1),
2260 tmp_ptrFieldRecord -> UsedRecords - rec_ctr );
2261
2262 tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords]
2263 = INVALID_RECORD_NUM;
2264
2265 break;
2266 }
2267 ++rec_ctr;
2268 }
2269
2270 }
2271
2272 } /* NEQ INVALID_SORT_INDEX */
2273
2274 } /* for sort_index_ctr */
2275
2276 return;
2277 }
2278
2279 /*
2280 +--------------------------------------------------------------------+
2281 | PROJECT: PHB MODULE: DBM |
2282 | ROUINE: insertion_sort |
2283 +--------------------------------------------------------------------+
2284
2285 PURPOSE : Sorts the user data records in FFS based on insertion sort method
2286 */
2287 void insertion_sort ( UBYTE* sort_list,
2288 UBYTE num_of_elements,
2289 T_COMP_FUNC compare_function,
2290 ULONG flags,
2291 int db_handle,
2292 USHORT field_id )
2293 {
2294 UBYTE rec_ctr;
2295
2296 /* sanity check */
2297 if( num_of_elements EQ 0 )
2298 return;
2299
2300 if( sort_list[0] EQ INVALID_RECORD_NUM )
2301 {
2302 /* This is beginning of new sort list,
2303 Let's add first element */
2304 sort_list[0] = sort_list[1];
2305 sort_list[1] = INVALID_RECORD_NUM;
2306 }
2307
2308
2309 /* So now here we have list something like this
2310 { Sorted records } + INVALID_RECORD_NUM + { UNsorted records }
2311 */
2312
2313 /* let's get to Unsorted records */
2314 rec_ctr = 1;
2315 while( sort_list[rec_ctr] NEQ INVALID_RECORD_NUM )
2316 {
2317 ++rec_ctr;
2318 }
2319 ++rec_ctr;
2320
2321 /* rec_ctr is now pointing at UNsorted records */
2322
2323 /* now add UNsorted records one by one */
2324
2325 /* Not required "( sort_list[rec_ctr] NEQ INVALID_RECORD_NUM )", right ? */
2326
2327 while( rec_ctr <= num_of_elements )
2328 {
2329 insert_element( sort_list,
2330 rec_ctr, /* num_of_elements */
2331 0, /* bottom */
2332 rec_ctr - 2, /* top */
2333 sort_list[rec_ctr], /* record_num to be inserted */
2334 compare_function,
2335 flags,
2336 db_handle,
2337 field_id );
2338
2339 ++rec_ctr;
2340 }
2341
2342 /* done ! */
2343 return;
2344 }
2345
2346 void insert_element ( UBYTE* sort_list,
2347 UBYTE num_of_elements,
2348 UBYTE bottom,
2349 UBYTE top,
2350 UBYTE record_num,
2351 T_COMP_FUNC compare_function,
2352 ULONG flags,
2353 int db_handle,
2354 USHORT field_id )
2355 {
2356 UBYTE middle = ( top + bottom ) / 2;
2357
2358 /* use binary algorithm to find the right place for insertion */
2359 while( middle NEQ bottom )
2360 {
2361 if( compare_function( db_handle,
2362 field_id,
2363 sort_list[middle],
2364 record_num,
2365 flags )
2366 < 0 )
2367 {
2368 bottom = middle;
2369 } else {
2370 top = middle;
2371 }
2372 middle = ( top + bottom ) / 2;
2373
2374 } /* while( middle NEQ bottom ) */
2375
2376 if( compare_function( db_handle,
2377 field_id,
2378 sort_list[bottom],
2379 record_num,
2380 flags )
2381 < 0 )
2382 {
2383
2384 if( compare_function( db_handle,
2385 field_id,
2386 sort_list[top],
2387 record_num,
2388 flags )
2389 < 0 )
2390 {
2391 /* insert at top + 1 */
2392 memmove( sort_list + top + 2, /* dest */
2393 sort_list + top + 1, /* source */
2394 num_of_elements - (top + 1) ); /* size */
2395
2396 sort_list[top + 1] = record_num;
2397
2398 } else {
2399
2400 /* insert at bottom + 1 */
2401 memmove( sort_list + bottom + 2, /* dest */
2402 sort_list + bottom + 1, /* source */
2403 num_of_elements - (bottom + 1) ); /* size */
2404
2405 sort_list[bottom + 1] = record_num;
2406
2407 } /* if top_th < insert_th */
2408
2409 } else {
2410
2411 /* insert at bottom */
2412 memmove( sort_list + bottom + 1, /* dest */
2413 sort_list + bottom, /* source */
2414 num_of_elements - bottom ); /* size */
2415
2416 sort_list[bottom] = record_num;
2417
2418 } /* if bottom_th < insert_th */
2419
2420 return;
2421 }
2422
2423 #endif /* INSERTION_SORT */
2424
2425
2426 /*
2427 +--------------------------------------------------------------------+
2428 | PROJECT: PHB MODULE: DBM |
2429 | ROUINE: internal_db_sort |
2430 +--------------------------------------------------------------------+
2431
2432 PURPOSE : (Internal) Creates or updates a sort index for
2433 a given (database, field)
2434 */
2435 T_DB_CODE internal_db_sort ( int db_handle,
2436 USHORT field_id,
2437 UBYTE sort_index,
2438 T_COMP_FUNC compare_function,
2439 ULONG flags,
2440 T_DB_SORT sort_type )
2441 {
2442 UBYTE fld_ctr,
2443 sort_index_ctr,
2444 remb_sort_index_ctr,
2445 tmp_byte,
2446 bit_num,
2447 record_num;
2448
2449 UBYTE* sort_list;
2450 UBYTE* copy_sort_list;
2451
2452 UBYTE* tmp_byte_ptr;
2453
2454 T_DB_CODE db_ret_code;
2455
2456 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
2457
2458 UBYTE* field_data;
2459 UBYTE field_file[FILENAME_LEN];
2460
2461 TRACE_FUNCTION("internal_db_sort()");
2462
2463 /* DBM_State check */
2464 DBM_State_check;
2465
2466 /* db_handle check */
2467 db_ret_code = db_handle_check( db_handle );
2468 if( db_ret_code NEQ DB_OK )
2469 DB_RETURN( db_ret_code );
2470
2471 /* field id search; if field not found, return error DB_INVALID_FIELD */
2472 fld_ctr = field_id_search( db_handle, field_id );
2473 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
2474 DB_RETURN( DB_INVALID_FIELD );
2475
2476 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
2477
2478 /* Check if this is existing sort index */
2479 remb_sort_index_ctr = MAX_NUM_OF_SORT_INDEXS;
2480
2481 for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
2482 {
2483 if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index )
2484 break;
2485
2486 if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ INVALID_SORT_INDEX )
2487 remb_sort_index_ctr = sort_index_ctr;
2488
2489 }
2490
2491 if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS )
2492 {
2493 /* ok, this is new index, so
2494 Check if limit for sort list corresponding to field_id (for a given database)
2495 has reached limit, MAX_NUM_OF_SORT_INDEXS. If so, return DB_FULL. */
2496
2497 if( remb_sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS )
2498 DB_RETURN( DB_FULL );
2499
2500 sort_index_ctr = remb_sort_index_ctr;
2501
2502 /* update file , "~/dbm/DD_<db_handle>" for SortIndexes. */
2503
2504 /* create the field data that is to be written */
2505
2506 DB_MALLOC( field_data, MAX_NUM_OF_SORT_INDEXS );
2507 memcpy( field_data, tmp_ptrFieldRecord -> SortIndexList, MAX_NUM_OF_SORT_INDEXS );
2508
2509 field_data[sort_index_ctr] = sort_index;
2510
2511 sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
2512
2513 db_ret_code =
2514 update_field_data_in_FFS ( (const char*)field_file,
2515 &DbmMaster[db_handle].FFSFileHandle,
2516 #ifdef FFS_CLOSE_BEFORE_OPEN
2517 db_handle,
2518 #endif
2519 fld_ctr,
2520 T_DB_FIELD_RECORD_SIZE,
2521 field_data,
2522 SortIndexList_OFFSET,
2523 MAX_NUM_OF_SORT_INDEXS );
2524 if( db_ret_code NEQ DB_OK )
2525 {
2526 DB_MFREE( field_data );
2527 DB_RETURN( db_ret_code );
2528 }
2529
2530 DB_MFREE( field_data );
2531 /* updation of DD_<db_handle> is over */
2532 }
2533
2534 if( ( sort_type EQ QUICK_SORT ) AND
2535 ( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] NEQ NULL ) )
2536 {
2537 /* free earlier list */
2538 DB_MFREE( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] );
2539 tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = NULL;
2540 }
2541
2542 /* create sort list (if not there) */
2543 if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] NEQ NULL )
2544 {
2545 sort_list = tmp_ptrFieldRecord -> SortedLists[sort_index_ctr];
2546 } else {
2547
2548 #ifndef INSERTION_SORT
2549 DB_MALLOC( sort_list, tmp_ptrFieldRecord -> NumOfRecords );
2550 memset( sort_list, INVALID_RECORD_NUM, tmp_ptrFieldRecord -> NumOfRecords );
2551
2552 copy_sort_list = sort_list;
2553 #else
2554 DB_MALLOC( sort_list, tmp_ptrFieldRecord -> NumOfRecords + 1 );
2555 memset( sort_list, INVALID_RECORD_NUM, tmp_ptrFieldRecord -> NumOfRecords + 1 );
2556
2557 if( sort_type EQ INCREMENTAL_SORT )
2558 {
2559 /* the first element would be INVALID_RECORD_NUM (0xFF) */
2560 copy_sort_list = sort_list + 1;
2561
2562 } else {
2563
2564 copy_sort_list = sort_list;
2565 }
2566 #endif /* INSERTION_SORT */
2567
2568 /* The list of available records is prepared from RecordBitMap */
2569
2570 tmp_byte_ptr = tmp_ptrFieldRecord -> RecordBitMap + RECORD_BITMAP_SIZE - 1;
2571 record_num = 0;
2572
2573 while( record_num < tmp_ptrFieldRecord -> NumOfRecords )
2574 {
2575 tmp_byte = *tmp_byte_ptr;
2576 for( bit_num = 0; bit_num < MAX_BIT_POS; ++bit_num )
2577 {
2578 ++record_num;
2579
2580 if( record_num > tmp_ptrFieldRecord -> NumOfRecords )
2581 break;
2582
2583 if( tmp_byte & 0x01 )
2584 {
2585 *copy_sort_list = record_num;
2586 ++copy_sort_list;
2587 }
2588
2589
2590 tmp_byte >>= 1;
2591 }
2592 --tmp_byte_ptr;
2593
2594 } /* population of records */
2595
2596 } /* sort_list is NULL */
2597
2598 /* Sort the records with given "comparison_function" (it takes record numbers,
2599 field_id and db_handle). Note that the sorted list would be kept in RAM
2600 (structure SortedLists, part of field record) till db_flush is called and
2601 cleared in db_flush. */
2602
2603 if( sort_type EQ QUICK_SORT )
2604 {
2605 quick_sort( sort_list,
2606 tmp_ptrFieldRecord -> UsedRecords, /* only used records */
2607 compare_function,
2608 flags,
2609 db_handle,
2610 field_id );
2611 }
2612
2613 #ifdef INSERTION_SORT
2614
2615 if( sort_type EQ INCREMENTAL_SORT )
2616 {
2617 insertion_sort( sort_list,
2618 tmp_ptrFieldRecord -> UsedRecords, /* only used records */
2619 compare_function,
2620 flags,
2621 db_handle,
2622 field_id );
2623 }
2624
2625 #endif /* INSERTION_SORT */
2626
2627 /* writing sorted list to FFS would be done in db_flush */
2628
2629 /* Update corresponding field SortIndexList in RAM structures. */
2630
2631 tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] = sort_index;
2632 tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = sort_list;
2633
2634 DB_RETURN( DB_OK );
2635 }
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661 /***********************/
2662 /* INTERFACE FUNCTIONS */
2663 /***********************/
2664
2665
2666 /*
2667 +--------------------------------------------------------------------+
2668 | PROJECT: PHB MODULE: DBM |
2669 | ROUINE: db_init |
2670 +--------------------------------------------------------------------+
2671
2672 PURPOSE : Initialises database manager
2673 */
2674 void db_init ( void )
2675 {
2676 UBYTE db_ctr;
2677
2678 #ifdef FFS_CLOSE_BEFORE_OPEN
2679 UBYTE fld_ctr;
2680 #endif
2681
2682 TRACE_FUNCTION("db_init()");
2683
2684 /* 1) Check DBM_State and if already initialized, return DB_OK */
2685 if ( DBM_State EQ DBM_INITIALISED )
2686 return;
2687
2688 /* 2) Initialize DbmMaster structure */
2689 for ( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
2690 {
2691 DbmMaster[db_ctr].DBState = UNUSED_ENTRY;
2692
2693 #ifdef FFS_CLOSE_BEFORE_OPEN
2694
2695 for( fld_ctr = 0; fld_ctr < MAX_OPEN_READ_PER_DB; ++fld_ctr )
2696 {
2697 DbmMaster[db_ctr].READ_OPEN_FIELDS[fld_ctr].fld_ctr = INVALID_FLD_CTR;
2698 }
2699 for( fld_ctr = 0; fld_ctr < MAX_OPEN_WRITE_PER_DB; ++fld_ctr )
2700 {
2701 DbmMaster[db_ctr].WRITE_OPEN_FIELDS[fld_ctr].fld_ctr = INVALID_FLD_CTR;
2702 }
2703 DbmMaster[db_ctr].old_read = 0;
2704 DbmMaster[db_ctr].old_write = 0;
2705
2706 #endif
2707
2708 }
2709
2710 UsedDBs = 0;
2711
2712 #ifdef _SIMULATION_
2713 {
2714 T_FFS_SIZE ffs_ret_code = ffs_init();
2715
2716 TRACE_EVENT_P1("Initialization of FFS Simulation %d", ffs_ret_code );
2717
2718 /* Delete existing database */
2719 init_RAM_with_FFS();
2720
2721 for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
2722 {
2723 if( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY )
2724 db_remove( DbmMaster[db_ctr].DBDirectory );
2725 }
2726
2727 db_exit();
2728 }
2729 #endif
2730
2731 return;
2732 }
2733
2734 /*
2735 +--------------------------------------------------------------------+
2736 | PROJECT: PHB MODULE: DBM |
2737 | ROUINE: init_RAM_with_FFS |
2738 +--------------------------------------------------------------------+
2739
2740 PURPOSE : Initialise DBM RAM structures with FFS data
2741 */
2742 T_DB_CODE init_RAM_with_FFS ( void )
2743 {
2744 /* Initializing "DBM related data" in RAM from FFS */
2745
2746 T_FFS_FD ffs_dbm_fd;
2747 T_FFS_SIZE ffs_ret_code;
2748 T_FFS_STAT ffs_dir_stat;
2749 UBYTE* db_buffer;
2750 UBYTE* remb_db_buffer;
2751 UBYTE* tmp_byte_ptr;
2752 UBYTE* field_buffer;
2753 UBYTE* remb_field_buffer;
2754 UBYTE db_ctr,
2755 fld_ctr,
2756 sort_index_ctr,
2757 tmp_byte,
2758 tmp_num_records,
2759 bit_num,
2760 record_num;
2761 char field_file[FILENAME_LEN];
2762 char* field_file_ptr = field_file;
2763 char* dbm_file = DB_MASTER_FILE;
2764 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
2765
2766
2767 TRACE_FUNCTION("init_RAM_with_FFS()");
2768
2769 /* Check the presence of FFS directory DB_DIR */
2770 ffs_ret_code = ffs_stat( DB_DIR, &ffs_dir_stat );
2771
2772 TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_stat %d", ffs_ret_code );
2773 /* error values of ffs_ret_code are handled later */
2774
2775 if( ffs_ret_code >= EFFS_OK )
2776 {
2777 /* Directory is present */
2778
2779 /* Synchronize DB related data between FFS and RAM
2780 i.e. structures DbmMasterRecord and corresponding DbmFieldRecord. */
2781
2782 /* For DbmMaster */
2783
2784 DB_FFS_OPEN( ffs_dbm_fd, dbm_file, FFS_O_RDONLY );
2785
2786 if( (ffs_dbm_fd EQ EFFS_NAMETOOLONG ) OR
2787 (ffs_dbm_fd EQ EFFS_BADNAME ) OR
2788 (ffs_dbm_fd EQ EFFS_NOTFOUND ) OR
2789 (ffs_dbm_fd EQ EFFS_INVALID ) OR
2790 (ffs_dbm_fd EQ EFFS_LOCKED ) )
2791
2792 {
2793 TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd );
2794 return DB_FAIL;
2795 }
2796
2797 if( ffs_dbm_fd < EFFS_OK )
2798 {
2799 TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd );
2800 LastFFS_ReturnCode = ffs_dbm_fd;
2801 return DB_FAIL_FS;
2802 }
2803
2804 ffs_ret_code = ffs_seek( ffs_dbm_fd, 0, FFS_SEEK_SET );
2805
2806 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
2807 ( ffs_ret_code EQ EFFS_INVALID ) OR
2808 ( ffs_ret_code EQ EFFS_BADOP ) )
2809 {
2810 TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_seek %d", ffs_ret_code );
2811 DB_FFS_CLOSE( ffs_dbm_fd );
2812 return DB_FAIL;
2813 }
2814
2815 /* buffer for master records */
2816 DB_MALLOC( db_buffer, T_DB_MASTER_RECORD_SIZE );
2817 remb_db_buffer = db_buffer;
2818
2819 for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
2820 {
2821 db_buffer = remb_db_buffer;
2822 ffs_ret_code = ffs_read( ffs_dbm_fd, db_buffer, T_DB_MASTER_RECORD_SIZE );
2823
2824 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
2825 ( ffs_ret_code EQ EFFS_BADOP ) )
2826 {
2827 TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_read %d", ffs_ret_code );
2828 DB_FFS_CLOSE( ffs_dbm_fd );
2829 DB_MFREE( db_buffer );
2830 return DB_FAIL;
2831 }
2832
2833 if( ffs_ret_code EQ 0 ) /* number of bytes read EQ 0 */
2834 break;
2835
2836 if( *db_buffer EQ 0xFF ) /* if invalid database */
2837 continue;
2838
2839 memcpy( DbmMaster[db_ctr].DBDirectory, db_buffer, MAX_LEN_DIRECTORY );
2840 db_buffer += MAX_LEN_DIRECTORY;
2841
2842 DbmMaster[db_ctr].NumOfFiles = *db_buffer;
2843 ++db_buffer;
2844
2845 DbmMaster[db_ctr].Tracked_Clean = ( *db_buffer ) ? TRACKED_AND_CLEAN : CLEAN;
2846 ++db_buffer;
2847
2848 DbmMaster[db_ctr].UsedFiles = 0;
2849
2850 DbmMaster[db_ctr].DBState = CLOSED;
2851
2852 ++UsedDBs;
2853
2854 /* we need not "seek" here file pointer would have moved to next */
2855 }
2856
2857 DB_FFS_CLOSE( ffs_dbm_fd );
2858 DB_MFREE( remb_db_buffer ); /* freeing db_buffer */
2859
2860 /* For FieldRecords */
2861
2862 /* buffer for field records */
2863 DB_MALLOC( field_buffer, T_DB_FIELD_RECORD_SIZE );
2864 remb_field_buffer = field_buffer;
2865
2866 for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
2867 {
2868
2869 if( DbmMaster[db_ctr].DBState EQ UNUSED_ENTRY )
2870 continue;
2871
2872 /* Field file = DD_<pos. in DD_master> */
2873
2874 sprintf( field_file, "%s/DD_%d", DB_DIR, db_ctr);
2875
2876 DB_FFS_OPEN( ffs_dbm_fd, field_file_ptr, FFS_O_RDONLY );
2877
2878 if( ( ffs_dbm_fd EQ EFFS_NOTFOUND ) OR /* Field file not found */
2879 ( ffs_dbm_fd EQ EFFS_NUMFD ) OR /* FFS specific errors */
2880 ( ffs_dbm_fd EQ EFFS_LOCKED) )
2881 {
2882 TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd );
2883 DB_MFREE( field_buffer );
2884 return DB_FAIL;
2885 }
2886
2887 ffs_ret_code = ffs_seek( ffs_dbm_fd, 0, FFS_SEEK_SET );
2888
2889 if( ( ffs_ret_code EQ EFFS_BADFD ) OR
2890 ( ffs_ret_code EQ EFFS_INVALID ) OR
2891 ( ffs_ret_code EQ EFFS_BADOP ) )
2892 {
2893 TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_seek %d", ffs_ret_code );
2894 DB_FFS_CLOSE( ffs_dbm_fd );
2895 DB_MFREE( field_buffer );
2896 return DB_FAIL;
2897 }
2898
2899 /* Allocate memory for field records */
2900 DB_MALLOC( DbmMaster[db_ctr].ptrFieldRecord,
2901 DbmMaster[db_ctr].NumOfFiles * sizeof(T_DBM_FIELDRECORD) );
2902
2903 tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord;
2904
2905 for( fld_ctr = 0; fld_ctr < DbmMaster[db_ctr].NumOfFiles; ++fld_ctr )
2906 {
2907 field_buffer = remb_field_buffer;
2908
2909 ffs_ret_code = ffs_read( ffs_dbm_fd, field_buffer, T_DB_FIELD_RECORD_SIZE );
2910
2911 if( (ffs_ret_code EQ EFFS_BADFD ) OR
2912 (ffs_ret_code EQ EFFS_BADOP ) )
2913 {
2914 TRACE_EVENT_P2( "init_RAM_with_FFS:ffs_seek %d, fld_ctr %d", ffs_ret_code, fld_ctr );
2915 DB_FFS_CLOSE ( ffs_dbm_fd );
2916 DB_MFREE( field_buffer );
2917 DB_MFREE( DbmMaster[db_ctr].ptrFieldRecord );
2918 return DB_FAIL;
2919 }
2920
2921 if( ffs_ret_code EQ 0 ) /* number of bytes read EQ 0 */
2922 {
2923 /* we need not go further, just make rest of field ids as invalid (not existing) */
2924 for( ; fld_ctr < DbmMaster[db_ctr].NumOfFiles; ++fld_ctr )
2925 {
2926 tmp_ptrFieldRecord -> FieldID = INVALID_FIELD_ID;
2927 ++tmp_ptrFieldRecord;
2928 }
2929 break;
2930 }
2931
2932 /* Syncing of field records */
2933
2934 tmp_ptrFieldRecord -> FieldID = *field_buffer;
2935 tmp_ptrFieldRecord -> FieldID <<= MAX_BIT_POS;
2936 ++field_buffer;
2937 tmp_ptrFieldRecord -> FieldID |= *field_buffer;
2938 ++field_buffer;
2939
2940 if ( tmp_ptrFieldRecord -> FieldID NEQ INVALID_FIELD_ID )
2941 {
2942 tmp_ptrFieldRecord -> DBType = *field_buffer;
2943 ++field_buffer;
2944
2945 tmp_ptrFieldRecord -> RecordSize = *field_buffer;
2946 tmp_ptrFieldRecord -> RecordSize <<= MAX_BIT_POS;
2947 ++field_buffer;
2948 tmp_ptrFieldRecord -> RecordSize |= *field_buffer;
2949 ++field_buffer;
2950
2951 tmp_ptrFieldRecord -> NumOfRecords = *field_buffer;
2952 ++field_buffer;
2953
2954 for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
2955 {
2956 tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] = *field_buffer;
2957 tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = NULL;
2958 ++field_buffer;
2959 }
2960
2961 memcpy( tmp_ptrFieldRecord -> RecordBitMap, field_buffer, RECORD_BITMAP_SIZE );
2962 field_buffer += RECORD_BITMAP_SIZE;
2963
2964 tmp_ptrFieldRecord -> Clean = *field_buffer;
2965
2966 #ifndef FFS_CLOSE_BEFORE_OPEN
2967 tmp_ptrFieldRecord -> FFSFileHandle = NULL;
2968 #endif
2969 /* we need to get size of user file <DBDirectory>/UD_<field_id>
2970 NextRecordNum = (size of user file) / record size */
2971 tmp_ptrFieldRecord -> NextRecordNum =
2972 cal_NextRecordNum ( (const char*)DbmMaster[db_ctr].DBDirectory,
2973 tmp_ptrFieldRecord -> FieldID,
2974 tmp_ptrFieldRecord -> RecordSize );
2975
2976 /* Update database records for UsedFiles, Clean, and UsedRecords */
2977
2978 DbmMaster[db_ctr].UsedFiles += 1;
2979
2980 if( DbmMaster[db_ctr].Tracked_Clean & TRACKED ) /* if db is tracked */
2981 if( NOT tmp_ptrFieldRecord -> Clean ) /* if field is not clean */
2982 DbmMaster[db_ctr].Tracked_Clean &= ~ CLEAN ; /* make db as not clean */
2983
2984
2985 /* For calculating UsedRecords */
2986
2987 tmp_byte_ptr = tmp_ptrFieldRecord -> RecordBitMap + RECORD_BITMAP_SIZE - 1;
2988 tmp_num_records = 0;
2989 record_num = 0;
2990
2991 while( record_num < tmp_ptrFieldRecord -> NumOfRecords )
2992 {
2993 tmp_byte = *tmp_byte_ptr;
2994
2995 for( bit_num = 0; bit_num < MAX_BIT_POS; ++bit_num )
2996 {
2997 ++record_num;
2998
2999 if( record_num > tmp_ptrFieldRecord -> NumOfRecords )
3000 break;
3001
3002 if( tmp_byte & 0x01 )
3003 ++tmp_num_records;
3004
3005 tmp_byte >>= 1;
3006 }
3007
3008 --tmp_byte_ptr;
3009 }
3010
3011 tmp_ptrFieldRecord -> UsedRecords = tmp_num_records;
3012
3013 } /* FieldID NEQ INVALID_FIELD_ID */
3014
3015 /* go to next field record */
3016
3017 /* seek is not required here ! */
3018
3019 ++tmp_ptrFieldRecord; /* next field */
3020
3021 } /* for( fld_ctr ) ... all fields */
3022
3023 /* close the DD_<db_handle> file */
3024 DB_FFS_CLOSE( ffs_dbm_fd );
3025
3026 } /* ffs_ret_code >= EFFS_OK */
3027
3028 DB_MFREE( remb_field_buffer ); /* freeing field buffer */
3029
3030 DBM_State = DBM_INITIALISED;
3031
3032 return DB_OK;
3033
3034 } /* if( ffs_ret_code >= EFFS_OK ) */
3035
3036 /* Directory not present */
3037 if( ffs_ret_code EQ EFFS_NOTFOUND )
3038 {
3039 /* Create DBM directory */
3040 ffs_ret_code = ffs_mkdir( DB_DIR );
3041
3042 if( (ffs_ret_code EQ EFFS_NAMETOOLONG ) OR
3043 (ffs_ret_code EQ EFFS_BADNAME ) )
3044 {
3045 TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_mkdir %d", ffs_ret_code );
3046 return DB_FAIL;
3047 }
3048
3049 if( ffs_ret_code < EFFS_OK )
3050 {
3051 TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_mkdir %d", ffs_ret_code );
3052 LastFFS_ReturnCode = ffs_ret_code;
3053 return DB_FAIL_FS;
3054 }
3055
3056 /* Create empty file DD_master
3057 FFS_O_EXCL => Generate error if FFS_O_CREATE is also specified and
3058 the file already exists. */
3059
3060 DB_FFS_OPEN( ffs_dbm_fd, dbm_file, FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL );
3061
3062 if( (ffs_dbm_fd EQ EFFS_NAMETOOLONG ) OR
3063 (ffs_dbm_fd EQ EFFS_BADNAME ) )
3064 {
3065 TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd );
3066 ffs_ret_code = ffs_remove( DB_DIR ); /* undo creating of DBM directory */
3067 return DB_FAIL;
3068 }
3069
3070 if( ffs_dbm_fd < EFFS_OK )
3071 {
3072 TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd );
3073 LastFFS_ReturnCode = ffs_dbm_fd;
3074 ffs_ret_code = ffs_remove( DB_DIR ); /* undo creating of DBM directory */
3075 return DB_FAIL_FS;
3076 }
3077
3078 DB_FFS_CLOSE( ffs_dbm_fd );
3079
3080 DBM_State = DBM_INITIALISED;
3081
3082 return DB_OK;
3083 }
3084
3085 /* Unexpected error: Not a directory */
3086 return DB_FAIL;
3087
3088 }
3089
3090 /*
3091 +--------------------------------------------------------------------+
3092 | PROJECT: PHB MODULE: DBM |
3093 | ROUINE: db_create |
3094 +--------------------------------------------------------------------+
3095
3096 PURPOSE : Create a new database in the given directory of the FFS.
3097 The directory must not to exist yet, it will be created.
3098 */
3099 int db_create ( const char* directory,
3100 UBYTE num_of_fields,
3101 BOOL tracked )
3102 {
3103 int db_handle;
3104 T_DB_CODE db_ret_code;
3105 UBYTE fld_ctr;
3106 S8 db_ctr;
3107 T_FFS_SIZE ffs_ret_code;
3108 T_FFS_FD ffs_fd;
3109 char field_file[FILENAME_LEN];
3110 char* field_file_ptr = field_file;
3111 UBYTE* dbm_data;
3112 UBYTE* remb_dbm_data;
3113
3114 TRACE_FUNCTION("db_create()");
3115
3116 /* If DBM is not in initialized state, call init_RAM_with_FFS (). */
3117 if( DBM_State NEQ DBM_INITIALISED )
3118 {
3119 T_DB_CODE db_ret_code;
3120
3121 db_ret_code = init_RAM_with_FFS();
3122
3123 if( db_ret_code NEQ DB_OK )
3124 DB_RETURN( db_ret_code );
3125 }
3126
3127 /* See if you have reached the maximum number of DBs, ?
3128 (UsedDBs+1) > MAX_DBs */
3129
3130 if( UsedDBs EQ MAX_DBs )
3131 DB_RETURN( DB_FULL );
3132
3133
3134 /* Check DbmMaster if already database for "directory" exists.
3135 If yes, return error "DB_EXISTS" */
3136
3137 for( db_ctr = (MAX_DBs - 1); db_ctr >= 0; --db_ctr )
3138 {
3139 if ( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY )
3140 {
3141 if( memcmp( DbmMaster[db_ctr].DBDirectory,
3142 directory,
3143 strlen( directory ) ) EQ 0 )
3144 DB_RETURN( DB_EXISTS );
3145 } else {
3146 db_handle = db_ctr;
3147 }
3148 }
3149
3150 /* sanity check */
3151 if( num_of_fields <= 0 )
3152 DB_RETURN( DB_FAIL );
3153
3154 /* Create a directory, "<DBDirectory>" (DBDirectory = directory) */
3155 ffs_ret_code = ffs_mkdir( directory );
3156
3157 if( ffs_ret_code < EFFS_OK )
3158 {
3159 TRACE_EVENT_P1( "db_create:ffs_mkdir %d", ffs_ret_code );
3160 LastFFS_ReturnCode = ffs_ret_code;
3161 DB_RETURN( DB_FAIL_FS );
3162 }
3163
3164
3165 /* Create a empty file, "~/dbm/DD_<position in DD_master = db_handle>";
3166 if this FFS operation fails, we need to delete the directory
3167 before returning error.
3168 */
3169 sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle);
3170
3171 TRACE_EVENT_P1( "field_file %s", field_file );
3172
3173 /* FFS_O_EXCL => Generate error if FFS_O_CREATE is also specified and
3174 the file already exists. */
3175 DB_FFS_OPEN( ffs_fd, field_file_ptr, FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL );
3176
3177 if( ( ffs_fd EQ EFFS_EXISTS ) OR
3178 ( ffs_fd EQ EFFS_NAMETOOLONG ) OR
3179 ( ffs_fd EQ EFFS_BADNAME ) OR
3180 ( ffs_fd EQ EFFS_INVALID ) )
3181 {
3182 TRACE_EVENT_P1( "db_create:DB_FFS_OPEN %d", ffs_fd );
3183 ffs_fd = ffs_remove( directory );
3184 DB_RETURN( DB_FAIL );
3185 }
3186
3187 if( ffs_fd < EFFS_OK )
3188 {
3189 TRACE_EVENT_P1( "db_create:DB_FFS_OPEN %d", ffs_fd );
3190 LastFFS_ReturnCode = ffs_fd;
3191 ffs_ret_code = ffs_remove( directory );
3192 DB_RETURN( DB_FAIL_FS );
3193 }
3194
3195 /* DB_FFS_CLOSE( ffs_fd ); we will close it in db_flush */
3196
3197 #ifdef FFS_OPEN_PROBLEM_PATCH
3198 DB_FFS_CLOSE( ffs_fd );
3199 #endif
3200
3201 #ifdef FFS_CLOSE_BEFORE_OPEN
3202 /* no we do not close it */
3203 #endif
3204
3205 /* Update FFS data i.e. file, "~/dbm/DD_master". */
3206
3207 /* prepare the dbm data and write */
3208 DB_MALLOC( dbm_data, T_DB_MASTER_RECORD_SIZE );
3209 memset( dbm_data, 0, T_DB_MASTER_RECORD_SIZE );
3210 remb_dbm_data = dbm_data;
3211
3212 memcpy( dbm_data, directory, MAX_LEN_DIRECTORY );
3213 dbm_data += MAX_LEN_DIRECTORY;
3214
3215 *dbm_data = num_of_fields;
3216 ++dbm_data;
3217
3218 *dbm_data = ( tracked ) ? FFS_TRACKED : FFS_NOT_TRACKED;
3219
3220 dbm_data = remb_dbm_data;
3221
3222 db_ret_code =
3223 update_dbm_data_in_FFS ( DB_MASTER_FILE,
3224 (UBYTE) db_handle, /* to supress warning */
3225 T_DB_MASTER_RECORD_SIZE,
3226 dbm_data,
3227 0,
3228 T_DB_MASTER_RECORD_SIZE );
3229
3230 if( db_ret_code NEQ DB_OK )
3231 {
3232 DB_MFREE( dbm_data );
3233 ffs_ret_code = ffs_remove( directory );
3234 DB_FFS_CLOSE( ffs_fd );
3235 ffs_ret_code = ffs_remove( field_file );
3236 DB_RETURN( db_ret_code );
3237 }
3238
3239 DB_MFREE( dbm_data );
3240 /* updation of DD_master done
3241 now update RAM structures */
3242
3243 memcpy( DbmMaster[db_handle].DBDirectory,
3244 directory,
3245 strlen(directory) );
3246
3247 DbmMaster[db_handle].NumOfFiles = num_of_fields;
3248 DbmMaster[db_handle].UsedFiles = 0;
3249 DbmMaster[db_handle].Tracked_Clean = ( tracked ) ? TRACKED_AND_CLEAN : CLEAN;
3250 DbmMaster[db_handle].DBState = OPEN;
3251 DbmMaster[db_handle].FFSFileHandle = ffs_fd;
3252
3253 #ifdef FFS_CLOSE_BEFORE_OPEN
3254
3255 /* No files corresponding to fields have been opened
3256 This initialization is already done in db_init */
3257
3258 #endif
3259
3260 /* Allocate memory for storing field information
3261 and initialize the memory with "FF" */
3262
3263 DB_MALLOC( DbmMaster[db_handle].ptrFieldRecord,
3264 num_of_fields * sizeof(T_DBM_FIELDRECORD) );
3265
3266 for( fld_ctr = 0; fld_ctr < num_of_fields; ++fld_ctr )
3267 {
3268 DbmMaster[db_handle].ptrFieldRecord[fld_ctr].FieldID = INVALID_FIELD_ID;
3269 }
3270
3271 UsedDBs++;
3272
3273 DB_RETURN( db_handle );
3274
3275 }
3276
3277 /*
3278 +--------------------------------------------------------------------+
3279 | PROJECT: PHB MODULE: DBM |
3280 | ROUINE: db_open |
3281 +--------------------------------------------------------------------+
3282
3283 PURPOSE : Open an existing database
3284 */
3285 int db_open ( const char *directory )
3286 {
3287 T_DB_CODE db_ret_code;
3288 UBYTE db_ctr;
3289
3290 TRACE_FUNCTION("db_open()");
3291
3292 /* If DBM is not in initialized state, call init_RAM_with_FFS (). */
3293 if( DBM_State NEQ DBM_INITIALISED )
3294 {
3295 db_ret_code = init_RAM_with_FFS();
3296
3297 if( db_ret_code NEQ DB_OK )
3298 DB_RETURN( db_ret_code );
3299 }
3300
3301 /* Search for "directory" in DbmMaster */
3302 for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
3303 {
3304 if( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY )
3305 {
3306 if( memcmp( DbmMaster[db_ctr].DBDirectory,
3307 directory,
3308 strlen(directory) ) EQ 0 )
3309 break;
3310 }
3311 }
3312
3313 /* If "directory" not found, return DB_FAIL. */
3314 if( db_ctr EQ MAX_DBs )
3315 DB_RETURN( DB_INVALID_DB );
3316
3317 /* Update DBState as "OPEN". */
3318 DbmMaster[db_ctr].DBState = OPEN;
3319
3320 /* Return corresponding DBHandle. */
3321 DB_RETURN( db_ctr );
3322 }
3323
3324 /*
3325 +--------------------------------------------------------------------+
3326 | PROJECT: PHB MODULE: DBM |
3327 | ROUINE: db_create_field |
3328 +--------------------------------------------------------------------+
3329
3330 PURPOSE : Create a new elementary file of a given type with a given
3331 numeric identifier and a given record size.
3332 */
3333 T_DB_CODE db_create_field ( int db_handle,
3334 T_DB_TYPE db_type,
3335 USHORT field_id,
3336 USHORT record_size,
3337 USHORT num_of_records )
3338 {
3339 T_DB_CODE db_ret_code;
3340 char user_field_file[FILENAME_LEN],
3341 field_file[FILENAME_LEN];
3342 char* user_field_file_ptr = user_field_file;
3343 char* field_file_ptr = field_file;
3344 UBYTE fld_ctr,
3345 sort_index_ctr;
3346 T_FFS_SIZE ffs_ret_code;
3347 T_FFS_FD ffs_fd_user_field_file;
3348 UBYTE* field_data;
3349 UBYTE* remb_field_data;
3350 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
3351
3352
3353 TRACE_FUNCTION("db_create_field()");
3354
3355 /* DBM_State check */
3356 DBM_State_check;
3357
3358 /* db_handle check */
3359 db_ret_code = db_handle_check( db_handle );
3360 if( db_ret_code NEQ DB_OK )
3361 DB_RETURN( db_ret_code );
3362
3363 /* field id search; if field id found, return error DB_FIELD_EXISTS */
3364 if( field_id_search( db_handle, field_id ) NEQ DbmMaster[db_handle].NumOfFiles )
3365 DB_RETURN( DB_FIELD_EXISTS );
3366
3367 /* If limit for number of fields for this DB has been reached, return error DB_FULL. */
3368 if( DbmMaster[db_handle].UsedFiles EQ
3369 DbmMaster[db_handle].NumOfFiles )
3370 DB_RETURN( DB_FULL );
3371
3372 /* Search for free field entry in field records corresponding to the database. */
3373 for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr )
3374 {
3375 if( DbmMaster[db_handle].ptrFieldRecord[fld_ctr].FieldID EQ INVALID_FIELD_ID )
3376 break;
3377 }
3378
3379 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
3380 { /* this is "inconsistency"; should never happen */
3381 DB_RETURN( DB_FAIL );
3382 }
3383
3384 /* sanity check */
3385 if( ( num_of_records <= 0 ) OR
3386 ( record_size <= 0 ) )
3387 {
3388 DB_RETURN( DB_FAIL );
3389 }
3390
3391 /* Create file "<DBDirectory>/UD_<field_id>" */
3392 sprintf( user_field_file, "%s/UD_%d", DbmMaster[db_handle].DBDirectory, field_id );
3393
3394 /* FFS_O_EXCL => Generate error if FFS_O_CREATE is also specified and
3395 the file already exists. */
3396 #ifndef FFS_CLOSE_BEFORE_OPEN
3397
3398 DB_FFS_OPEN( ffs_fd_user_field_file, user_field_file_ptr, FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL );
3399
3400 #else
3401
3402 ffs_fd_user_field_file =
3403 db_open_user_field_file( db_handle,
3404 fld_ctr,
3405 user_field_file_ptr,
3406 FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL );
3407 #endif
3408
3409 if( ( ffs_fd_user_field_file EQ EFFS_EXISTS ) OR
3410 ( ffs_fd_user_field_file EQ EFFS_NAMETOOLONG ) OR
3411 ( ffs_fd_user_field_file EQ EFFS_BADNAME ) OR
3412 ( ffs_fd_user_field_file EQ EFFS_INVALID ) )
3413 {
3414 TRACE_EVENT_P1( "db_create_field:DB_FFS_OPEN %d", ffs_fd_user_field_file );
3415 DB_RETURN( DB_FAIL );
3416 }
3417
3418 if( ffs_fd_user_field_file < EFFS_OK )
3419 {
3420 TRACE_EVENT_P1( "db_create_field:DB_FFS_OPEN %d", ffs_fd_user_field_file );
3421 LastFFS_ReturnCode = ffs_fd_user_field_file;
3422 DB_RETURN( DB_FAIL_FS );
3423 }
3424
3425 /* We will close this file in db_flush */
3426
3427 #ifdef FFS_OPEN_PROBLEM_PATCH
3428 DB_FFS_CLOSE( ffs_fd_user_field_file );
3429 #endif
3430
3431
3432 /* file "<DBDirectory>/UD_<field_id>" has been created
3433 Now, Add new field entry in "~/dbm/DD_<db_handle>" */
3434
3435 /* create the field data that needs to be written */
3436
3437 DB_MALLOC( field_data, T_DB_FIELD_RECORD_SIZE );
3438 memset( field_data, 0, T_DB_FIELD_RECORD_SIZE );
3439 remb_field_data = field_data;
3440
3441 *field_data = (UBYTE) ( (field_id & 0xFF00) >> MAX_BIT_POS );
3442 ++field_data;
3443 *field_data = (UBYTE) (field_id & 0x00FF);
3444 ++field_data;
3445
3446 *field_data = db_type;
3447 ++field_data;
3448
3449 *field_data = (UBYTE) ( (record_size & 0xFF00) >> MAX_BIT_POS );
3450 ++field_data;
3451 *field_data = (UBYTE) (record_size & 0x00FF);
3452 ++field_data;
3453
3454 *field_data = (UBYTE)num_of_records;
3455 field_data++;
3456
3457 memset( field_data, 0xFF, MAX_NUM_OF_SORT_INDEXS );
3458 field_data += MAX_NUM_OF_SORT_INDEXS;
3459
3460 memset( field_data, 0, RECORD_BITMAP_SIZE );
3461 field_data += RECORD_BITMAP_SIZE;
3462
3463 *field_data = CLEAN; /* Clean is true */
3464
3465 field_data = remb_field_data;
3466
3467 sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
3468
3469 db_ret_code =
3470 update_field_data_in_FFS ( (const char*)field_file,
3471 &DbmMaster[db_handle].FFSFileHandle,
3472 #ifdef FFS_CLOSE_BEFORE_OPEN
3473 db_handle,
3474 #endif
3475 fld_ctr,
3476 T_DB_FIELD_RECORD_SIZE,
3477 field_data,
3478 0,
3479 T_DB_FIELD_RECORD_SIZE );
3480
3481 if( db_ret_code NEQ DB_OK )
3482 {
3483 DB_MFREE( field_data );
3484 ffs_ret_code = ffs_remove( user_field_file );
3485 DB_RETURN( db_ret_code );
3486 }
3487
3488 DB_MFREE( field_data );
3489 /* updation of DD_<db_handle> is over */
3490
3491 /* Add new field entry in field records in RAM. */
3492 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
3493
3494 tmp_ptrFieldRecord -> FieldID = field_id;
3495 tmp_ptrFieldRecord -> DBType = db_type;
3496 tmp_ptrFieldRecord -> RecordSize = record_size;
3497 tmp_ptrFieldRecord -> NumOfRecords = (UBYTE)num_of_records;
3498 tmp_ptrFieldRecord -> UsedRecords = 0;
3499 tmp_ptrFieldRecord -> Clean = CLEAN;
3500
3501 #ifndef FFS_CLOSE_BEFORE_OPEN
3502 tmp_ptrFieldRecord -> FFSFileHandle = ffs_fd_user_field_file;
3503 #endif
3504
3505 tmp_ptrFieldRecord -> NextRecordNum = 1;
3506
3507 memset( tmp_ptrFieldRecord -> RecordBitMap, 0, RECORD_BITMAP_SIZE );
3508
3509 for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
3510 {
3511 tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] = INVALID_SORT_INDEX;
3512 tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = NULL;
3513 }
3514
3515 /* Increment UsedFiles for the particular database in RAM */
3516 DbmMaster[db_handle].UsedFiles += 1;
3517
3518 /* everyting ok */
3519 DB_RETURN( DB_OK );
3520
3521 }
3522
3523 /*
3524 +--------------------------------------------------------------------+
3525 | PROJECT: PHB MODULE: DBM |
3526 | ROUINE: db_write_record |
3527 +--------------------------------------------------------------------+
3528
3529 PURPOSE : Write length bytes at offset into the given record in
3530 (database, field)
3531 */
3532 int db_write_record ( int db_handle,
3533 USHORT field_id,
3534 USHORT record_num,
3535 USHORT offset,
3536 USHORT length,
3537 const UBYTE* buffer )
3538 {
3539 T_DB_CODE db_ret_code;
3540
3541 UBYTE fld_ctr,
3542 tmp_byte,
3543 rec_ctr;
3544
3545 char user_field_file[FILENAME_LEN],
3546 field_file[FILENAME_LEN];
3547
3548 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
3549
3550 UBYTE* record_buffer;
3551 UBYTE* field_data;
3552
3553 BOOL this_is_new_record = TRUE;
3554
3555 TRACE_FUNCTION("db_write_record()");
3556
3557 TRACE_EVENT_P1("field_id %d", field_id);
3558
3559 /* DBM_State check */
3560 DBM_State_check;
3561
3562 /* db_handle check */
3563 db_ret_code = db_handle_check( db_handle );
3564 if( db_ret_code NEQ DB_OK )
3565 DB_RETURN( db_ret_code );
3566
3567 /* field id search; if field not found, return error DB_INVALID_FIELD */
3568 fld_ctr = field_id_search( db_handle, field_id );
3569 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
3570 DB_RETURN( DB_INVALID_FIELD );
3571
3572 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
3573
3574 /* Check if record exceeds the record size (i.e. offset + length > record size);
3575 if it exceeds, return error DB_INVALID_SIZE */
3576 if( (offset + length) >
3577 tmp_ptrFieldRecord -> RecordSize )
3578 DB_RETURN( DB_INVALID_SIZE );
3579
3580 /* Check if FFS file is already opened using FFSFileHandle, part of field record.
3581 If it is not yet opened, open the FFS file and update FFSFileHandle.
3582 This is taken care in read_user_record_from_FFS */
3583
3584 /* User data file name is "<DBDirectory>/UD_<field_id>"
3585 This would be used below */
3586
3587 sprintf( user_field_file,
3588 "%s/UD_%d",
3589 DbmMaster[db_handle].DBDirectory,
3590 tmp_ptrFieldRecord -> FieldID );
3591
3592 if( record_num EQ 0 )
3593 {
3594 /* If given record is equal to zero,
3595 o Find a free record using RecordBitMap.
3596 o If free record not found, return DB_FULL */
3597
3598 record_num = 1 + search_clear_bit_in_bitmap( tmp_ptrFieldRecord -> RecordBitMap,
3599 RECORD_BITMAP_SIZE );
3600
3601 if( record_num > tmp_ptrFieldRecord -> NumOfRecords )
3602 DB_RETURN( DB_FULL );
3603
3604
3605 } else {
3606 /* If given record is not equal to zero,
3607 o Check if record exists using RecordBitMap;
3608 if not found, proceed to writing..
3609 o Read the record from "<DBDirectory>/UD_<field_id>" and
3610 compare it with given record (partially if offset > 0). Memcmp would be used.
3611 o If record match, return DB_OK. */
3612
3613 /* record_num = bit_pos + (8 * bitmap_idx) + 1;
3614 bitmap_idx = (record_num - 1) / MAX_BIT_POS;
3615 bit_pos = (record_num - 1) % MAX_BIT_POS; */
3616
3617 tmp_byte =
3618 (tmp_ptrFieldRecord -> RecordBitMap)[ RECORD_BITMAP_SIZE - BITMAP_INDEX(record_num) - 1];
3619
3620 if( tmp_byte & ( 0x01 << BIT_POS(record_num) ) ) /* record exists */
3621 {
3622 this_is_new_record = FALSE;
3623
3624 DB_MALLOC( record_buffer, length);
3625
3626 db_ret_code =
3627 read_user_record_from_FFS ( user_field_file,
3628
3629 #ifndef FFS_CLOSE_BEFORE_OPEN
3630 &(tmp_ptrFieldRecord -> FFSFileHandle),
3631 #else
3632 db_handle,
3633 fld_ctr,
3634 &Dummy_FFSFileHandle,
3635 #endif
3636 (UBYTE)record_num,
3637 tmp_ptrFieldRecord -> RecordSize,
3638 offset,
3639 length,
3640 record_buffer );
3641 if( db_ret_code NEQ DB_OK )
3642 {
3643 DB_MFREE( record_buffer );
3644 DB_RETURN( db_ret_code );
3645 }
3646
3647 /* See if there is same data, if so, we need not overwrite */
3648 if( memcmp( record_buffer, buffer, length) EQ 0 )
3649 { /* matching data */
3650 DB_MFREE( record_buffer );
3651 DB_RETURN( DB_OK );
3652 }
3653
3654 DB_MFREE( record_buffer );
3655
3656 } /* record exists */
3657
3658 } /* record_num EQ 0 ? */
3659
3660
3661 /* As per the request, write record in FFS in "<DBDirectory>/UD_<field_id>" */
3662
3663 /* in case of new record, we need to create fill unfilled-data with FF */
3664
3665 if( this_is_new_record )
3666 { /* new record */
3667
3668 DB_MALLOC( record_buffer, tmp_ptrFieldRecord -> RecordSize );
3669 memset( record_buffer, 0xFF, tmp_ptrFieldRecord -> RecordSize ) ;
3670
3671 /* To take care of non-sequential write
3672 For example, initially when file is empty, and say user writes
3673 3rd record, 1st and 2nd record should be addded as dummy and then
3674 3rd record */
3675
3676 rec_ctr = tmp_ptrFieldRecord -> NextRecordNum;
3677
3678 while( rec_ctr < record_num )
3679 {
3680 db_ret_code =
3681 write_user_record_to_FFS ( user_field_file,
3682
3683 #ifndef FFS_CLOSE_BEFORE_OPEN
3684 &(tmp_ptrFieldRecord -> FFSFileHandle),
3685 #else
3686 db_handle,
3687 fld_ctr,
3688 &Dummy_FFSFileHandle,
3689 #endif
3690 rec_ctr,
3691 tmp_ptrFieldRecord -> RecordSize,
3692 0,
3693 tmp_ptrFieldRecord -> RecordSize,
3694 record_buffer );
3695 if( db_ret_code NEQ DB_OK )
3696 {
3697 DB_MFREE( record_buffer );
3698 DB_RETURN( db_ret_code );
3699 }
3700
3701 ++rec_ctr;
3702 }
3703
3704 /* Add the new record */
3705
3706 memcpy( record_buffer + offset, buffer, length );
3707
3708 db_ret_code =
3709 write_user_record_to_FFS ( user_field_file,
3710
3711 #ifndef FFS_CLOSE_BEFORE_OPEN
3712 &(tmp_ptrFieldRecord -> FFSFileHandle),
3713 #else
3714 db_handle,
3715 fld_ctr,
3716 &Dummy_FFSFileHandle,
3717 #endif
3718 (UBYTE)record_num,
3719 tmp_ptrFieldRecord -> RecordSize,
3720 0,
3721 tmp_ptrFieldRecord -> RecordSize,
3722 record_buffer );
3723 if( db_ret_code NEQ DB_OK )
3724 {
3725 DB_MFREE( record_buffer );
3726 DB_RETURN( db_ret_code );
3727 }
3728
3729 DB_MFREE( record_buffer );
3730
3731 /* writing of record is over, update DBState (as IN_USE). */
3732 DbmMaster[db_handle].DBState = IN_USE;
3733
3734 } else {
3735 /* overwritten record */
3736
3737 db_ret_code =
3738 write_user_record_to_FFS ( user_field_file,
3739
3740 #ifndef FFS_CLOSE_BEFORE_OPEN
3741 &(tmp_ptrFieldRecord -> FFSFileHandle),
3742 #else
3743 db_handle,
3744 fld_ctr,
3745 &Dummy_FFSFileHandle,
3746 #endif
3747 (UBYTE)record_num,
3748 tmp_ptrFieldRecord -> RecordSize,
3749 offset,
3750 length,
3751 (UBYTE*)buffer ); /* type casting to suppress warning */
3752 if( db_ret_code NEQ DB_OK )
3753 {
3754 DB_RETURN( db_ret_code );
3755 }
3756
3757 /* writing of record is over, update DBState (as IN_USE). */
3758 DbmMaster[db_handle].DBState = IN_USE;
3759
3760 #ifdef INSERTION_SORT
3761
3762 /* get the sort lists in RAM from FFS */
3763 get_sort_lists_from_FFS( (UBYTE)db_handle, fld_ctr );
3764
3765 /* this is updation of record, so need to be re-sorted */
3766 update_in_sort_lists( (UBYTE)db_handle, fld_ctr, (UBYTE)record_num );
3767
3768 #endif
3769
3770 /* if database is not tracked, no need to go further for history log writing */
3771 if( NOT ( DbmMaster[db_handle].Tracked_Clean & TRACKED ) )
3772 DB_VALUE_RETURN( record_num );
3773
3774 /* if already Clean has been reset, only history updation */
3775 if( NOT ( DbmMaster[db_handle].Tracked_Clean & CLEAN ) )
3776 {
3777 db_ret_code = update_history_log( db_handle, field_id, record_num );
3778
3779 if( db_ret_code NEQ DB_OK )
3780 DB_RETURN( db_ret_code );
3781
3782 DB_VALUE_RETURN( record_num );
3783 }
3784
3785 } /* this_is_new_record */
3786
3787 /* Updating RecordBitMap and Clean in FFS, ~/dbm/DD_<db_handle> */
3788
3789 /* create the field data that is to be written */
3790
3791 DB_MALLOC( field_data, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
3792 memset( field_data, 0, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
3793 memcpy( field_data, tmp_ptrFieldRecord -> RecordBitMap, RECORD_BITMAP_SIZE );
3794
3795 if( this_is_new_record )
3796 { /* RecordBitMap to be updated only for new records */
3797 set_bit_in_bitmap( field_data,
3798 RECORD_BITMAP_SIZE,
3799 (UBYTE)record_num );
3800 }
3801
3802 /* clean is reset in memset, so no processing for it
3803 (in case of non-tracked database, anyway we ignore it ! */
3804
3805 sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
3806
3807 db_ret_code =
3808 update_field_data_in_FFS ( (const char*)field_file,
3809 &DbmMaster[db_handle].FFSFileHandle,
3810 #ifdef FFS_CLOSE_BEFORE_OPEN
3811 db_handle,
3812 #endif
3813 fld_ctr,
3814 T_DB_FIELD_RECORD_SIZE,
3815 field_data,
3816 RecordBitMap_OFFSET,
3817 ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
3818
3819
3820 if( db_ret_code NEQ DB_OK )
3821 {
3822 DB_MFREE( field_data );
3823 DB_RETURN( db_ret_code );
3824 }
3825
3826 DB_MFREE( field_data );
3827 /* updation of DD_<db_handle> is over */
3828
3829 /* Updating RAM (both DbmMaster and Field records) strctures */
3830 tmp_ptrFieldRecord -> Clean = NOT_CLEAN;
3831
3832 if( this_is_new_record )
3833 { /* RecordBitMap to be updated only for new records */
3834 set_bit_in_bitmap( tmp_ptrFieldRecord -> RecordBitMap,
3835 RECORD_BITMAP_SIZE,
3836 (UBYTE)record_num );
3837
3838 ++tmp_ptrFieldRecord -> UsedRecords;
3839
3840 tmp_ptrFieldRecord -> NextRecordNum =
3841 ( (record_num + 1) > tmp_ptrFieldRecord -> NextRecordNum ) ?
3842 (record_num + 1) : tmp_ptrFieldRecord -> NextRecordNum ;
3843
3844 #ifdef INSERTION_SORT
3845
3846 /* get the sort lists in RAM from FFS */
3847 get_sort_lists_from_FFS( (UBYTE)db_handle, fld_ctr );
3848
3849 /* note the record number for sorting later
3850 yeah, we call it *after* updating UsedRecords */
3851 new_in_sort_lists( (UBYTE)db_handle, fld_ctr, (UBYTE)record_num );
3852
3853 #endif
3854
3855 }
3856
3857 DbmMaster[db_handle].Tracked_Clean &= ~(CLEAN);
3858
3859 /* history log updation */
3860
3861 db_ret_code = update_history_log( db_handle, field_id, record_num );
3862
3863 if( db_ret_code NEQ DB_OK )
3864 DB_RETURN( db_ret_code );
3865
3866 DB_VALUE_RETURN( record_num );
3867
3868 }
3869
3870 /*
3871 +--------------------------------------------------------------------+
3872 | PROJECT: PHB MODULE: DBM |
3873 | ROUINE: db_create_index |
3874 +--------------------------------------------------------------------+
3875
3876 PURPOSE : Creates or updates a sort index for a given (database, field)
3877 */
3878 T_DB_CODE db_create_index ( int db_handle,
3879 USHORT field_id,
3880 UBYTE sort_index,
3881 T_COMP_FUNC compare_function,
3882 ULONG flags )
3883 {
3884
3885 return internal_db_sort( db_handle,
3886 field_id,
3887 sort_index,
3888 compare_function,
3889 flags,
3890 QUICK_SORT );
3891 }
3892
3893
3894 #ifdef INSERTION_SORT
3895 /*
3896 +--------------------------------------------------------------------+
3897 | PROJECT: PHB MODULE: DBM |
3898 | ROUINE: db_update_index |
3899 +--------------------------------------------------------------------+
3900
3901 PURPOSE : Sort the list for newly added/deleted records (uses incremental
3902 sort i.e. add the element at the right place)
3903 */
3904 T_DB_CODE db_update_index ( int db_handle,
3905 USHORT field_id,
3906 UBYTE sort_index,
3907 T_COMP_FUNC compare_function,
3908 ULONG flags )
3909 {
3910
3911 return internal_db_sort( db_handle,
3912 field_id,
3913 sort_index,
3914 compare_function,
3915 flags,
3916 INCREMENTAL_SORT );
3917 }
3918 #endif /* INSERTION_SORT */
3919
3920 /*
3921 +--------------------------------------------------------------------+
3922 | PROJECT: PHB MODULE: DBM |
3923 | ROUINE: db_get_phy_from_idx |
3924 +--------------------------------------------------------------------+
3925
3926 PURPOSE : Translates a logical entry within a given sort index to the
3927 physical record number
3928 */
3929 T_DB_CODE db_get_phy_from_idx ( int db_handle,
3930 USHORT field_id,
3931 UBYTE sort_index,
3932 USHORT order_num )
3933 {
3934 T_DB_CODE db_ret_code;
3935 UBYTE fld_ctr,
3936 sort_index_ctr;
3937 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
3938 char sort_file[FILENAME_LEN];
3939
3940
3941 TRACE_FUNCTION("db_get_phy_from_idx()");
3942
3943 /* DBM_State check */
3944 DBM_State_check;
3945
3946 /* db_handle check */
3947 db_ret_code = db_handle_check( db_handle );
3948 if( db_ret_code NEQ DB_OK )
3949 DB_RETURN( db_ret_code );
3950
3951 /* field id search; if field not found, return error DB_INVALID_FIELD */
3952 fld_ctr = field_id_search( db_handle, field_id );
3953 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
3954 DB_RETURN( DB_INVALID_FIELD );
3955
3956 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
3957
3958 /* sanity check on order_num */
3959 if( ( order_num > tmp_ptrFieldRecord -> NumOfRecords ) OR
3960 ( order_num EQ 0 ) )
3961 DB_RETURN( DB_FAIL ); /* may be we can return 0xFF => no record for it ! */
3962
3963 /* Search given sort_index in SortIndexList for above field_id;
3964 if not found, return DB_INVALID_INDEX. */
3965 for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
3966 {
3967 if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index )
3968 break;
3969 }
3970
3971 if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS )
3972 DB_RETURN( DB_INVALID_INDEX );
3973
3974 /* Check if we already have sorted list in RAM structure SortedLists */
3975
3976 if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] EQ NULL )
3977 {
3978 /* If no, populate the sorted list from file,
3979 "<DBDirectory>/UD_<field_id>_sort_<sort_index>".
3980 Sorted lists are freed in db_flush */
3981
3982 sprintf( sort_file,
3983 "%s/UD_%d_sort_%d",
3984 DbmMaster[db_handle].DBDirectory,
3985 tmp_ptrFieldRecord -> FieldID,
3986 sort_index );
3987
3988 db_ret_code =
3989 populate_sorted_list_from_FFS (
3990 #ifdef FFS_CLOSE_BEFORE_OPEN
3991 db_handle,
3992 #endif
3993 sort_file,
3994 tmp_ptrFieldRecord -> NumOfRecords,
3995 &(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr]) );
3996 if( db_ret_code NEQ DB_OK )
3997 DB_RETURN( db_ret_code );
3998
3999 } /* if we have sort list */
4000
4001 /* Get (physical) record number for given order_num from sorted list. */
4002 DB_VALUE_RETURN( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][order_num - 1] );
4003
4004 }
4005
4006 /*
4007 +--------------------------------------------------------------------+
4008 | PROJECT: PHB MODULE: DBM |
4009 | ROUINE: db_flush |
4010 +--------------------------------------------------------------------+
4011
4012 PURPOSE : Flush all internal data structures of the database described by
4013 db_handle
4014 */
4015 T_DB_CODE db_flush ( int db_handle)
4016 {
4017 UBYTE db_ret_code,
4018 clean_byte,
4019 fld_ctr,
4020 i;
4021
4022 char field_file[FILENAME_LEN];
4023
4024 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
4025
4026 char sort_file[FILENAME_LEN];
4027
4028 T_FFS_STAT ffs_file_stat;
4029 T_FFS_SIZE ffs_ret_code;
4030
4031 TRACE_FUNCTION("db_flush()");
4032
4033 /* DBM_State check */
4034 DBM_State_check;
4035
4036 /* db_handle check */
4037 db_ret_code = db_handle_check( db_handle );
4038 if( db_ret_code NEQ DB_OK )
4039 DB_RETURN( db_ret_code );
4040
4041 /* Clear "clean" in "~/dbm/DD_<db_handle>" for fields.
4042 after ffs updation, update RAM data */
4043
4044 sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
4045
4046 clean_byte = CLEAN;
4047
4048 /* Update the affected field records */
4049
4050 #ifdef FFS_CLOSE_BEFORE_OPEN
4051 db_close_user_field_files( db_handle );
4052 #endif;
4053
4054 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord;
4055
4056 for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr )
4057 {
4058 if( tmp_ptrFieldRecord -> FieldID EQ INVALID_FIELD_ID ) /* if not valid field id */
4059 {
4060 ++tmp_ptrFieldRecord; /* next field */
4061 continue;
4062 }
4063
4064 /* Clear file handles */
4065 #ifndef FFS_CLOSE_BEFORE_OPEN
4066
4067 if( tmp_ptrFieldRecord -> FFSFileHandle NEQ NULL )
4068 {
4069 DB_FFS_CLOSE( tmp_ptrFieldRecord -> FFSFileHandle );
4070 tmp_ptrFieldRecord -> FFSFileHandle = NULL;
4071 }
4072
4073 #else
4074 /* Done it closing before for loop */
4075 #endif
4076
4077 /* Write sort lists to FFS and clear (free memory) sort lists */
4078 for( i = 0; i < MAX_NUM_OF_SORT_INDEXS; ++i )
4079 {
4080 if( tmp_ptrFieldRecord -> SortedLists[i] NEQ NULL )
4081 {
4082 /* currently I am not removing unused entries in sort list */
4083 /* Write sorted lists to "<DBDirectory>/UD_<field_id>_sort_<sort_index>". */
4084
4085 sprintf( sort_file,
4086 "%s/UD_%d_sort_%d",
4087 DbmMaster[db_handle].DBDirectory,
4088 tmp_ptrFieldRecord -> FieldID,
4089 tmp_ptrFieldRecord -> SortIndexList[i] );
4090
4091 /* writing sorted lists to FFS s required in two cases
4092 1) the field is not clean and/or
4093 2) sort file does not exist, but we have sort list (happen during
4094 bootup time with zero records)
4095 */
4096
4097 ffs_ret_code = ffs_stat( sort_file, &ffs_file_stat );
4098
4099 if( ( ffs_ret_code NEQ EFFS_OK ) AND
4100 ( ffs_ret_code NEQ EFFS_NOTFOUND ) )
4101 {
4102 LastFFS_ReturnCode = ffs_ret_code;
4103 DB_MFREE( tmp_ptrFieldRecord -> SortedLists[i] );
4104 tmp_ptrFieldRecord -> SortedLists[i] = NULL;
4105 DB_RETURN( DB_FAIL_FS );
4106 }
4107
4108 if( ( NOT tmp_ptrFieldRecord -> Clean ) OR /* not clean (consistent) */
4109 ( ffs_ret_code EQ EFFS_NOTFOUND ) ) /* file does not exist */
4110 {
4111 db_ret_code =
4112 write_sorted_list_to_FFS (
4113 #ifdef FFS_CLOSE_BEFORE_OPEN
4114 db_handle,
4115 #endif
4116 sort_file,
4117 tmp_ptrFieldRecord -> NumOfRecords,
4118 tmp_ptrFieldRecord -> SortedLists[i] );
4119
4120 if( db_ret_code NEQ DB_OK )
4121 {
4122 DB_MFREE( tmp_ptrFieldRecord -> SortedLists[i] );
4123 tmp_ptrFieldRecord -> SortedLists[i] = NULL;
4124 DB_RETURN( db_ret_code );
4125 }
4126 }
4127
4128 /* writing in sort file is over */
4129 DB_MFREE( tmp_ptrFieldRecord -> SortedLists[i] );
4130 tmp_ptrFieldRecord -> SortedLists[i] = NULL;
4131 }
4132 }
4133
4134 if( tmp_ptrFieldRecord -> Clean ) /* is it clean (consistent) ? */
4135 {
4136 ++tmp_ptrFieldRecord; /* next field */
4137 continue;
4138 }
4139
4140 /* Clear "clean" in "~/dbm/DD_<db_handle>" if not clean */
4141
4142 db_ret_code =
4143 update_field_data_in_FFS ( (const char*)field_file,
4144 &DbmMaster[db_handle].FFSFileHandle,
4145 #ifdef FFS_CLOSE_BEFORE_OPEN
4146 db_handle,
4147 #endif
4148 fld_ctr,
4149 T_DB_FIELD_RECORD_SIZE,
4150 &clean_byte,
4151 ( T_DB_FIELD_RECORD_SIZE - 1 ) ,
4152 1 ); /* "Clean" contained in last one byte */
4153
4154 if( db_ret_code NEQ DB_OK )
4155 {
4156 /* this leaves out FFS and RAM in consistent state,
4157 this is ok since FFS is in correct state for some of fields ! */
4158 DB_RETURN( db_ret_code );
4159 }
4160
4161 tmp_ptrFieldRecord -> Clean = CLEAN;
4162
4163 ++tmp_ptrFieldRecord; /* next field */
4164
4165 } /* for all field records */
4166
4167 if( DbmMaster[db_handle].FFSFileHandle NEQ NULL )
4168 {
4169 DB_FFS_CLOSE( DbmMaster[db_handle].FFSFileHandle );
4170 }
4171
4172 /* updation of FFS is over */
4173
4174 /* Update corresponding "clean" field for database in RAM data structures,
4175 also DBState = OPEN */
4176 DbmMaster[db_handle].Tracked_Clean |= CLEAN;
4177 DbmMaster[db_handle].DBState = OPEN;
4178
4179 /* done */
4180 DB_RETURN( DB_OK );
4181 }
4182
4183 /*
4184 +--------------------------------------------------------------------+
4185 | PROJECT: PHB MODULE: DBM |
4186 | ROUINE: db_search |
4187 +--------------------------------------------------------------------+
4188
4189 PURPOSE : Searches for an entry within a given database and a given file
4190 */
4191 int db_search ( int db_handle,
4192 USHORT field_id,
4193 UBYTE sort_index,
4194 UBYTE* order_num,
4195 T_SEARCH_FUNC search_function,
4196 ULONG flags,
4197 const UBYTE* search_tag )
4198 {
4199 T_DB_CODE db_ret_code;
4200
4201 UBYTE fld_ctr,
4202 tmp_byte,
4203 sort_index_ctr,
4204 bit_num;
4205
4206 UBYTE* tmp_byte_ptr;
4207
4208 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
4209
4210 char sort_file[FILENAME_LEN];
4211
4212 int record_num = 0,
4213 index_num ;
4214
4215 TRACE_FUNCTION("db_search()");
4216
4217 /* DBM_State check */
4218 DBM_State_check;
4219
4220 /* db_handle check */
4221 db_ret_code = db_handle_check( db_handle );
4222 if( db_ret_code NEQ DB_OK )
4223 DB_RETURN( db_ret_code );
4224
4225 /* field id search; if field not found, return error DB_INVALID_FIELD */
4226 fld_ctr = field_id_search( db_handle, field_id );
4227 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
4228 DB_RETURN( DB_INVALID_FIELD );
4229
4230 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
4231
4232 if( sort_index EQ 0 )
4233 {
4234 /* If sort_index is zero,
4235 o Do linear search using RecordBitMap, search/comparison function is given by caller.
4236 o If search is successful, return the record number.
4237 o Otherwise return DB_RECORD_NOT_FOUND. */
4238
4239 /* Sanity check */
4240 if( (*order_num) > tmp_ptrFieldRecord -> NumOfRecords )
4241 DB_RETURN( DB_FAIL );
4242
4243 /* search from next record,
4244 search_node->top would be zero for fresh search */
4245
4246 record_num = *order_num;
4247
4248 /* get the correct byte */
4249 tmp_byte_ptr =
4250 tmp_ptrFieldRecord -> RecordBitMap + RECORD_BITMAP_SIZE - BITMAP_INDEX(record_num) - 1;
4251 tmp_byte = *tmp_byte_ptr;
4252
4253 /* get the correct bit position */
4254 bit_num = BIT_POS(record_num);
4255 tmp_byte >>= bit_num;
4256
4257 /* for bytes in bitmap */
4258 while( record_num < tmp_ptrFieldRecord -> NumOfRecords )
4259 {
4260 /* for bits in byte */
4261 while( bit_num < MAX_BIT_POS )
4262 {
4263 if( record_num > tmp_ptrFieldRecord -> NumOfRecords )
4264 break;
4265
4266 if( NOT (tmp_byte & 0x01 ) ) /* if record does not exist, move on to next */
4267 {
4268 tmp_byte >>= 1;
4269 ++bit_num;
4270 ++record_num;
4271 continue;
4272 }
4273
4274 /* ok, this is a valid record */
4275
4276 if( search_function( flags,
4277 search_tag,
4278 db_handle,
4279 field_id,
4280 (UBYTE)record_num )
4281 EQ 0 ) /* yeah, "EQ 0" is success */
4282 {
4283 /* found it ! */
4284 *order_num = record_num; /* for next search */
4285 DB_VALUE_RETURN( record_num );
4286 }
4287
4288 tmp_byte >>= 1;
4289 ++bit_num;
4290 ++record_num;
4291
4292 } /* for bits in byte */
4293
4294 --tmp_byte_ptr;
4295 tmp_byte = *tmp_byte_ptr;
4296 bit_num = 0;
4297
4298 } /* for bytes in bitmap */
4299
4300 /* record not found */
4301 DB_RETURN( DB_RECORD_NOT_FOUND );
4302
4303 } else {
4304 /* If sort_index is not zero, search using sorted list */
4305
4306 /* Search given sort_index in SortIndexList for above field_id;
4307 if not found, return DB_INVALID_INDEX. */
4308 for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
4309 {
4310 if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index )
4311 break;
4312 }
4313
4314 if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS )
4315 DB_RETURN( DB_INVALID_INDEX );
4316
4317 if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] EQ NULL )
4318 {
4319 /* If no, populate the sorted list from file,
4320 "<DBDirectory>/UD_<field_id>_sort_<sort_index>".
4321 Sorted lists are freed in db_flush */
4322
4323 sprintf( sort_file,
4324 "%s/UD_%d_sort_%d",
4325 DbmMaster[db_handle].DBDirectory,
4326 tmp_ptrFieldRecord -> FieldID,
4327 sort_index );
4328
4329 db_ret_code =
4330 populate_sorted_list_from_FFS (
4331
4332 #ifdef FFS_CLOSE_BEFORE_OPEN
4333 db_handle,
4334 #endif
4335 sort_file,
4336 tmp_ptrFieldRecord -> NumOfRecords,
4337 &(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr]) );
4338
4339 if( db_ret_code NEQ DB_OK )
4340 DB_RETURN( db_ret_code );
4341
4342 }
4343
4344 /* (Binary) search the sorted list, search/compare function is given by caller.
4345 o If search is successful, return the record number.
4346 o Otherwise return DB_RECORD_NOT_FOUND */
4347
4348
4349 index_num =
4350 search( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr],
4351 tmp_ptrFieldRecord -> UsedRecords,
4352 order_num,
4353 search_function,
4354 flags,
4355 search_tag,
4356 db_handle,
4357 field_id );
4358
4359 if( index_num EQ SEARCH_FAILED )
4360 DB_RETURN( DB_RECORD_NOT_FOUND );
4361
4362 DB_VALUE_RETURN( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][index_num - 1] );
4363
4364 }
4365 }
4366
4367 /*
4368 +--------------------------------------------------------------------+
4369 | PROJECT: PHB MODULE: DBM |
4370 | ROUINE: db_delete_record |
4371 +--------------------------------------------------------------------+
4372
4373 PURPOSE : Delete a record in the given field of the given database
4374 */
4375 T_DB_CODE db_delete_record ( int db_handle,
4376 USHORT field_id,
4377 USHORT record_num )
4378 {
4379 T_DB_CODE db_ret_code;
4380
4381 UBYTE fld_ctr,
4382 tmp_byte;
4383
4384 char field_file[FILENAME_LEN];
4385
4386 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
4387
4388 UBYTE* field_data;
4389
4390 TRACE_FUNCTION("db_delete_record()");
4391
4392 /* DBM_State check */
4393 DBM_State_check;
4394
4395 /* db_handle check */
4396 db_ret_code = db_handle_check( db_handle );
4397 if( db_ret_code NEQ DB_OK )
4398 DB_RETURN( db_ret_code );
4399
4400 /* field id search; if field not found, return error DB_INVALID_FIELD */
4401 fld_ctr = field_id_search( db_handle, field_id );
4402 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
4403 DB_RETURN( DB_INVALID_FIELD );
4404
4405 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
4406
4407 /* Using RecordBitMap, check whether record_num exists;
4408 if it does not exist, return DB_OK. */
4409
4410 tmp_byte =
4411 (tmp_ptrFieldRecord -> RecordBitMap)[ RECORD_BITMAP_SIZE - BITMAP_INDEX(record_num) - 1];
4412
4413 if( NOT ( tmp_byte & ( 0x01 << BIT_POS(record_num) ) ) ) /* if record does *not* exist */
4414 DB_RETURN( DB_OK );
4415
4416 /* Update "Clean" and "RecordBitMap" fields in "~/dbm/DD_<db_handle>" */
4417
4418 /* create the field data that is to be written */
4419
4420 DB_MALLOC( field_data, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
4421 memset( field_data, 0, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
4422 memcpy( field_data, tmp_ptrFieldRecord -> RecordBitMap, RECORD_BITMAP_SIZE );
4423
4424 /* updating RecordBitMap */
4425 reset_bit_in_bitmap( field_data,
4426 RECORD_BITMAP_SIZE,
4427 (UBYTE)record_num );
4428
4429 /* clean is reset in memset, so no processing for it
4430 (in case of non-tracked database, anyway we ignore it ! */
4431
4432 sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
4433
4434 db_ret_code =
4435 update_field_data_in_FFS ( (const char*)field_file,
4436 &DbmMaster[db_handle].FFSFileHandle,
4437 #ifdef FFS_CLOSE_BEFORE_OPEN
4438 db_handle,
4439 #endif
4440 fld_ctr,
4441 T_DB_FIELD_RECORD_SIZE,
4442 field_data,
4443 RecordBitMap_OFFSET,
4444 ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
4445
4446 if( db_ret_code NEQ DB_OK )
4447 {
4448 DB_MFREE( field_data );
4449 DB_RETURN( db_ret_code );
4450 }
4451
4452 DB_MFREE( field_data );
4453 /* updation of DD_<db_handle> is over */
4454
4455 /* Update corresponding "Clean" and "RecordBitMap" fields in RAM data structures,
4456 also update DBState (as IN_USE) and decrement UsedRecords. */
4457
4458 tmp_ptrFieldRecord -> Clean = NOT_CLEAN;
4459
4460 /* updating RecordBitMap */
4461 reset_bit_in_bitmap( tmp_ptrFieldRecord -> RecordBitMap,
4462 RECORD_BITMAP_SIZE,
4463 (UBYTE)record_num );
4464
4465 #ifdef INSERTION_SORT
4466
4467 /* get the sort lists in RAM from FFS */
4468 get_sort_lists_from_FFS( (UBYTE)db_handle, fld_ctr );
4469
4470 /* delete in available sort lists
4471 yeah, we call it *before* updating UsedRecords */
4472 delete_in_sort_lists( (UBYTE)db_handle, fld_ctr, (UBYTE)record_num );
4473
4474 #endif /* INSERTION_SORT */
4475
4476 --tmp_ptrFieldRecord -> UsedRecords;
4477
4478 DbmMaster[db_handle].Tracked_Clean &= ~ (CLEAN);
4479 DbmMaster[db_handle].DBState = IN_USE;
4480
4481 /* history log updation */
4482
4483 return update_history_log( db_handle, field_id, record_num );
4484
4485 }
4486
4487 /*
4488 +--------------------------------------------------------------------+
4489 | PROJECT: PHB MODULE: DBM |
4490 | ROUINE: db_read_record |
4491 +--------------------------------------------------------------------+
4492
4493 PURPOSE : Read length bytes at offset from the record in given (database, field)
4494 */
4495 int db_read_record ( int db_handle,
4496 USHORT field_id,
4497 USHORT record_num,
4498 USHORT offset,
4499 USHORT length,
4500 UBYTE* record_buffer )
4501 {
4502 T_DB_CODE db_ret_code;
4503
4504 UBYTE fld_ctr,
4505 tmp_byte;
4506
4507 char user_field_file[FILENAME_LEN];
4508
4509 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
4510
4511
4512 TRACE_FUNCTION("db_read_record()");
4513
4514 /* DBM_State check */
4515 DBM_State_check;
4516
4517 /* db_handle check */
4518 db_ret_code = db_handle_check( db_handle );
4519 if( db_ret_code NEQ DB_OK )
4520 DB_RETURN( db_ret_code );
4521
4522 /* field id search; if field not found, return error DB_INVALID_FIELD */
4523 fld_ctr = field_id_search( db_handle, field_id );
4524 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
4525 DB_RETURN( DB_INVALID_FIELD );
4526
4527 /* Using RecordBitMap, check whether record_num exists;
4528 if it does not exist, return DB_EMPTY_RECORD. */
4529
4530 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
4531
4532 tmp_byte =
4533 (tmp_ptrFieldRecord -> RecordBitMap)[ RECORD_BITMAP_SIZE - BITMAP_INDEX(record_num) - 1 ];
4534
4535 if( NOT ( tmp_byte & ( 0x01 << BIT_POS(record_num) ) ) ) /* if record does *not* exist */
4536 DB_RETURN( DB_EMPTY_RECORD );
4537
4538 /* Check if record exceeds the record size (i.e. offset + length > record size);
4539 if it exceeds, return error DB_INVALID_SIZE */
4540 if( (offset + length) >
4541 tmp_ptrFieldRecord -> RecordSize )
4542 DB_RETURN( DB_INVALID_SIZE );
4543
4544 /* Check if FFS file is already opened using FFSFileHandle, part of field record.
4545 If it is not yet opened, open the FFS file and update FFSFileHandle.
4546 This is taken care in read_user_record_from_FFS below. */
4547
4548 /* Read record_num from "<DBDirectory>/UD_<field_id>"
4549 Put "length" number of bytes from "offset" in buffer. (assuming that
4550 buffer contain enough memory i.e. caller should take care of allocating
4551 enough memory space for buffer) */
4552
4553 /* User data file name is "<DBDirectory>/UD_<field_id>" */
4554
4555 sprintf( user_field_file,
4556 "%s/UD_%d",
4557 DbmMaster[db_handle].DBDirectory,
4558 tmp_ptrFieldRecord -> FieldID );
4559
4560 db_ret_code =
4561 read_user_record_from_FFS ( user_field_file,
4562
4563 #ifndef FFS_CLOSE_BEFORE_OPEN
4564 &(tmp_ptrFieldRecord -> FFSFileHandle),
4565 #else
4566 db_handle,
4567 fld_ctr,
4568 &Dummy_FFSFileHandle,
4569 #endif
4570 (UBYTE)record_num,
4571 tmp_ptrFieldRecord -> RecordSize,
4572 offset,
4573 length,
4574 record_buffer );
4575
4576 if( db_ret_code NEQ DB_OK )
4577 DB_RETURN( db_ret_code );
4578
4579 DB_VALUE_RETURN( record_num );
4580 }
4581
4582 /*
4583 +--------------------------------------------------------------------+
4584 | PROJECT: PHB MODULE: DBM |
4585 | ROUINE: db_remove |
4586 +--------------------------------------------------------------------+
4587
4588 PURPOSE : Remove a database. The database must not be in use.
4589 */
4590 T_DB_CODE db_remove ( const char* directory )
4591 {
4592 int db_handle;
4593
4594 UBYTE db_ctr,
4595 fld_ctr;
4596
4597 T_DB_CODE db_ret_code;
4598
4599 UBYTE* dbm_data;
4600 UBYTE field_file[FILENAME_LEN];
4601
4602
4603
4604 TRACE_FUNCTION("db_remove()");
4605
4606 /* DBM_State check */
4607 DBM_State_check;
4608
4609 /* Search for "directory" in DbmMaster
4610 If not found, return DB_INVALID_DB */
4611
4612 for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
4613 {
4614 if ( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY )
4615 {
4616 if( memcmp( DbmMaster[db_ctr].DBDirectory,
4617 directory,
4618 strlen(directory) ) EQ 0 )
4619 break;
4620 }
4621 }
4622
4623 if( db_ctr EQ MAX_DBs )
4624 DB_RETURN( DB_INVALID_DB );
4625
4626 db_handle = db_ctr;
4627
4628 /* If DBState for found database in DbmMaster is OPEN or IN_USE, return error DB_IN_USE */
4629
4630 if( ( DbmMaster[db_ctr].DBState EQ OPEN ) OR
4631 ( DbmMaster[db_ctr].DBState EQ IN_USE ) )
4632 DB_RETURN( DB_IN_USE );
4633
4634
4635 /* Delete all files under directory "<DBDirectory>" (DBDirectory = directory) */
4636
4637 for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr )
4638 {
4639 db_ret_code = remove_field_from_FFS( (UBYTE)db_handle, fld_ctr );
4640
4641 if( db_ret_code NEQ DB_OK )
4642 DB_RETURN( db_ret_code );
4643 }
4644
4645 /* Delete the DBDirectory */
4646 db_ret_code = delete_file_dir_from_FFS ( (const char*)DbmMaster[db_handle].DBDirectory );
4647
4648 if( db_ret_code NEQ DB_OK )
4649 DB_RETURN( db_ret_code );
4650
4651 /* Delete Field file = DD_<pos. in DD_master> */
4652
4653 sprintf( field_file, "%s/DD_%d", DB_DIR, db_ctr);
4654
4655 db_ret_code = delete_file_dir_from_FFS ( (const char*)field_file );
4656
4657 if( db_ret_code NEQ DB_OK )
4658 DB_RETURN( db_ret_code );
4659
4660 /* Update FFS data i.e. file, "~/dbm/DD_master" */
4661
4662 /* prepare the dbm data and write */
4663
4664 DB_MALLOC( dbm_data, T_DB_MASTER_RECORD_SIZE );
4665 memset( dbm_data, 0xFF, T_DB_MASTER_RECORD_SIZE );
4666
4667 db_ret_code =
4668 update_dbm_data_in_FFS ( DB_MASTER_FILE,
4669 (UBYTE) db_handle, /* to supress warning */
4670 T_DB_MASTER_RECORD_SIZE,
4671 dbm_data,
4672 0,
4673 T_DB_MASTER_RECORD_SIZE );
4674
4675 if( db_ret_code NEQ DB_OK )
4676 {
4677 DB_MFREE( dbm_data );
4678 DB_RETURN( db_ret_code );
4679 }
4680
4681 DB_MFREE( dbm_data );
4682
4683 /* updation of DD_master done */
4684
4685 /* Free the memory for field records.
4686 Update this entry in DbmMaster as unused. (DBState = UNUSED_ENTRY).
4687 Also, decrement UsedDBs. */
4688
4689 DB_MFREE( DbmMaster[db_handle].ptrFieldRecord );
4690
4691 DbmMaster[db_handle].DBState = UNUSED_ENTRY;
4692
4693 --UsedDBs;
4694
4695 /* everything ok ! */
4696 DB_RETURN( DB_OK );
4697
4698 }
4699
4700 /*
4701 +--------------------------------------------------------------------+
4702 | PROJECT: PHB MODULE: DBM |
4703 | ROUINE: db_close |
4704 +--------------------------------------------------------------------+
4705
4706 PURPOSE : Close a database; if in use, it flushes it before closing it.
4707 */
4708 T_DB_CODE db_close ( int db_handle )
4709 {
4710 TRACE_FUNCTION("db_close()");
4711
4712 /* DBM_State check */
4713 DBM_State_check;
4714
4715 /* Check for db_handle range */
4716 if( db_handle >= MAX_DBs )
4717 DB_RETURN( DB_INVALID_DB );
4718
4719 /* If DBState for db_handleth position in DbmMaster is
4720 o UNUSED_ENTRY, return error DB_INVALID_DB
4721 o CLOSED, return DB_OK.
4722 o OPEN, update DBState as CLOSED and return DB_OK.
4723 o IN_USE, call db_flush, update DBState as CLOSED and return DB_OK */
4724
4725 switch( DbmMaster[db_handle].DBState )
4726 {
4727 case UNUSED_ENTRY: DB_RETURN( DB_INVALID_DB );
4728
4729 case CLOSED: DB_RETURN( DB_OK );
4730
4731 case OPEN:
4732 case IN_USE: {
4733 db_flush( db_handle );
4734 DbmMaster[db_handle].DBState = CLOSED;
4735 DB_RETURN( DB_OK );
4736 }
4737
4738 default: DB_RETURN( DB_FAIL );
4739 }
4740
4741 }
4742
4743 /*
4744 +--------------------------------------------------------------------+
4745 | PROJECT: PHB MODULE: DBM |
4746 | ROUINE: db_exit |
4747 +--------------------------------------------------------------------+
4748
4749 PURPOSE : Shutdown the data base
4750 */
4751 void db_exit ( void )
4752 {
4753 /* It is assumed as "forced" exit and so no error would be
4754 raised even if database is in use. Also, here we will not
4755 delete the database, but just sync the database and free
4756 the RAM structures.
4757
4758 1) Call db_flush for all databases present in DbmMaster.
4759 2) Free the memory for field records for all databases.
4760 3) Update all entries in DbmMaster as unused (this step is not required)
4761 4) Set DBM_State as DBM_NOT_INITIALISED. */
4762
4763 UBYTE db_ctr;
4764
4765 for ( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
4766 {
4767 if( DbmMaster[db_ctr].DBState EQ UNUSED_ENTRY )
4768 continue;
4769
4770 db_close( db_ctr );
4771
4772 DB_MFREE( DbmMaster[db_ctr].ptrFieldRecord );
4773
4774 DbmMaster[db_ctr].DBState = UNUSED_ENTRY;
4775
4776 }
4777
4778 DBM_State = DBM_NOT_INITIALISED;
4779
4780 UsedDBs = 0;
4781
4782 return;
4783 }
4784
4785 /*
4786 +--------------------------------------------------------------------+
4787 | PROJECT: PHB MODULE: DBM |
4788 | ROUINE: db_remove_field |
4789 +--------------------------------------------------------------------+
4790
4791 PURPOSE : Delete field in given database
4792 */
4793 T_DB_CODE db_remove_field ( int db_handle,
4794 USHORT field_id )
4795 {
4796 UBYTE fld_ctr,
4797 db_ret_code;
4798
4799 UBYTE* field_data;
4800
4801 char field_file[FILENAME_LEN];
4802
4803 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
4804
4805 TRACE_FUNCTION("db_remove_field()");
4806
4807 /* DBM_State check */
4808 DBM_State_check;
4809
4810 /* db_handle check */
4811 db_ret_code = db_handle_check( db_handle );
4812 if( db_ret_code NEQ DB_OK )
4813 DB_RETURN( db_ret_code );
4814
4815 /* field id search; if field id not found, return error DB_INVALID_FIELD */
4816 fld_ctr = field_id_search( db_handle, field_id );
4817 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
4818 DB_RETURN( DB_INVALID_FIELD );
4819
4820 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
4821
4822 #ifndef FFS_CLOSE_BEFORE_OPEN
4823
4824 /* Check if FFS file is open using FFSFileHandle, part of field record;
4825 if so, return error DB_IN_USE. */
4826 if( tmp_ptrFieldRecord -> FFSFileHandle NEQ NULL )
4827 DB_RETURN( DB_IN_USE );
4828
4829 #else
4830
4831 if( db_status_user_field_file( db_handle, fld_ctr ) EQ OPENED_FOR_WRITE )
4832 DB_RETURN( DB_IN_USE );
4833
4834 #endif
4835
4836 /* Remove file "<DBDirectory>/UD_<field_id>" */
4837
4838 db_ret_code = remove_field_from_FFS( (UBYTE)db_handle, fld_ctr );
4839
4840 if( db_ret_code NEQ DB_OK )
4841 DB_RETURN( db_ret_code );
4842
4843 /* Update "~/dbm/DD_<db_handle>" for removed field id. */
4844
4845 /* create the field data that is to be written */
4846
4847 DB_MALLOC( field_data, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
4848 memset( field_data, 0xFF, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
4849
4850 sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
4851
4852 db_ret_code =
4853 update_field_data_in_FFS ( (const char*)field_file,
4854 &DbmMaster[db_handle].FFSFileHandle,
4855 #ifdef FFS_CLOSE_BEFORE_OPEN
4856 db_handle,
4857 #endif
4858 fld_ctr,
4859 T_DB_FIELD_RECORD_SIZE,
4860 field_data,
4861 RecordBitMap_OFFSET,
4862 ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
4863
4864 if( db_ret_code NEQ DB_OK )
4865 {
4866 DB_MFREE( field_data );
4867 DB_RETURN( db_ret_code );
4868 }
4869
4870 DB_MFREE( field_data );
4871 /* updation of DD_<db_handle> is over */
4872
4873 /* update in RAM */
4874
4875 tmp_ptrFieldRecord -> FieldID = INVALID_FIELD_ID;
4876
4877 DB_RETURN( DB_OK );
4878
4879 }
4880
4881 /*
4882 +--------------------------------------------------------------------+
4883 | PROJECT: PHB MODULE: DBM |
4884 | ROUINE: db_read_change_log |
4885 +--------------------------------------------------------------------+
4886
4887 PURPOSE : Get an information about the changed records since the last
4888 call of this function
4889 */
4890 T_DB_CODE db_read_change_log ( int db_handle,
4891 T_DB_CHANGED* changed)
4892 {
4893 T_DB_CODE db_ret_code;
4894 TRACE_FUNCTION("db_read_change_log()");
4895
4896 /* DBM_State check */
4897 DBM_State_check;
4898
4899 /* db_handle check */
4900 db_ret_code = db_handle_check( db_handle );
4901 if( db_ret_code NEQ DB_OK )
4902 DB_RETURN( db_ret_code );
4903
4904 /* Copy contents of internal history log to HistoryRecord */
4905 *changed = DB_History_log; /* This would work ?? */
4906
4907 /* Clear internal history log. */
4908 DB_History_log.entries = 0; /* this is enough for clearing history log ! */
4909
4910 /* done */
4911 DB_RETURN( DB_OK );
4912
4913 }
4914
4915 /*
4916 +--------------------------------------------------------------------+
4917 | PROJECT: PHB MODULE: DBM |
4918 | ROUINE: db_remove_index |
4919 +--------------------------------------------------------------------+
4920
4921 PURPOSE : Removes a sort index
4922 */
4923 T_DB_CODE db_remove_index ( int db_handle,
4924 USHORT field_id,
4925 UBYTE sort_index )
4926 {
4927 UBYTE db_ret_code,
4928 fld_ctr,
4929 sort_index_ctr;
4930 UBYTE field_file[FILENAME_LEN];
4931
4932 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
4933
4934 char sort_file[FILENAME_LEN];
4935
4936 UBYTE* field_data;
4937
4938
4939 TRACE_FUNCTION("db_remove_index()");
4940
4941 /* DBM_State check */
4942 DBM_State_check;
4943
4944 /* db_handle check */
4945 db_ret_code = db_handle_check( db_handle );
4946 if( db_ret_code NEQ DB_OK )
4947 DB_RETURN( db_ret_code );
4948
4949 /* field id search; if field not found, return error DB_INVALID_FIELD */
4950 fld_ctr = field_id_search( db_handle, field_id );
4951 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
4952 DB_RETURN( DB_INVALID_FIELD );
4953
4954 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
4955
4956 /* Search given sort_index in SortIndexList for above field_id;
4957 if not found, return DB_INVALID_INDEX. */
4958 for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
4959 {
4960 if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index )
4961 break;
4962 }
4963
4964 if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS )
4965 DB_RETURN( DB_INVALID_INDEX );
4966
4967 /* Remove file, "<DBDirectory>/UD_<field_id>_sort_<sort_index>" */
4968
4969 sprintf( sort_file,
4970 "%s/UD_%d_sort_%d",
4971 DbmMaster[db_handle].DBDirectory,
4972 tmp_ptrFieldRecord -> FieldID,
4973 tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] );
4974
4975 db_ret_code = delete_file_dir_from_FFS ( sort_file );
4976
4977 if( db_ret_code NEQ DB_OK )
4978 DB_RETURN( db_ret_code );
4979
4980 /* Update file , "~/dbm/DD_<db_handle>" for SortIndexes. */
4981
4982 /* create the field data that is to be written */
4983
4984 DB_MALLOC( field_data, MAX_NUM_OF_SORT_INDEXS );
4985 memcpy( field_data, tmp_ptrFieldRecord -> SortIndexList, MAX_NUM_OF_SORT_INDEXS );
4986
4987 field_data[sort_index_ctr] = INVALID_SORT_INDEX;
4988
4989 sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
4990
4991 db_ret_code =
4992 update_field_data_in_FFS ( (const char*)field_file,
4993 &DbmMaster[db_handle].FFSFileHandle,
4994 #ifdef FFS_CLOSE_BEFORE_OPEN
4995 db_handle,
4996 #endif
4997 fld_ctr,
4998 T_DB_FIELD_RECORD_SIZE,
4999 field_data,
5000 SortIndexList_OFFSET,
5001 MAX_NUM_OF_SORT_INDEXS );
5002 if( db_ret_code NEQ DB_OK )
5003 {
5004 DB_MFREE( field_data );
5005 DB_RETURN( db_ret_code );
5006 }
5007
5008 DB_MFREE( field_data );
5009 /* updation of DD_<db_handle> is over */
5010
5011 /* Update corresponding RAM structure i.e. DbmFieldRecord
5012 Check if we have sort list corresponding to this sort index; if so, free it. */
5013
5014 tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] = INVALID_SORT_INDEX;
5015 if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] NEQ NULL )
5016 {
5017 DB_MFREE( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] );
5018 tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = NULL;
5019 }
5020
5021 DB_RETURN( DB_OK );
5022 }
5023
5024 /*
5025 +--------------------------------------------------------------------+
5026 | PROJECT: PHB MODULE: DBM |
5027 | ROUINE: db_field_changed |
5028 +--------------------------------------------------------------------+
5029
5030 PURPOSE : Check whether a database field has been changed since last
5031 db_flush().
5032 */
5033 T_DB_CODE db_field_changed ( int db_handle,
5034 USHORT field_id,
5035 BOOL* changed )
5036 {
5037 UBYTE fld_ctr;
5038 T_DB_CODE db_ret_code;
5039
5040 TRACE_FUNCTION("db_field_changed()");
5041
5042 /* DBM_State check */
5043 DBM_State_check;
5044
5045 /* db_handle check */
5046 db_ret_code = db_handle_check( db_handle );
5047 if( db_ret_code NEQ DB_OK )
5048 DB_RETURN( db_ret_code );
5049
5050 /* field id search; if field not found, return error DB_INVALID_FIELD */
5051 fld_ctr = field_id_search( db_handle, field_id );
5052 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
5053 DB_RETURN( DB_INVALID_FIELD );
5054
5055 /* Check "Clean" field in field record;
5056 a) if (Clean = true), changed = false. */
5057
5058 *changed = NOT DbmMaster[db_handle].ptrFieldRecord[fld_ctr].Clean;
5059
5060 DB_RETURN( DB_OK );
5061 }
5062
5063 /*
5064 +--------------------------------------------------------------------+
5065 | PROJECT: PHB MODULE: DBM |
5066 | ROUINE: db_record_empty |
5067 +--------------------------------------------------------------------+
5068
5069 PURPOSE : Check whether a database field is empty. The result is
5070 given to the caller in the *empty variable
5071 */
5072 T_DB_CODE db_record_empty ( int db_handle,
5073 USHORT field_id,
5074 USHORT record_num,
5075 BOOL* empty )
5076 {
5077 UBYTE fld_ctr,
5078 tmp_byte;
5079 T_DB_CODE db_ret_code;
5080
5081 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
5082
5083
5084 TRACE_FUNCTION("db_record_empty()");
5085
5086 *empty = TRUE;
5087
5088 /* DBM_State check */
5089 DBM_State_check;
5090
5091 /* db_handle check */
5092 db_ret_code = db_handle_check( db_handle );
5093 if( db_ret_code NEQ DB_OK )
5094 DB_RETURN( db_ret_code );
5095
5096 /* field id search; if field not found, return error DB_INVALID_FIELD */
5097 fld_ctr = field_id_search( db_handle, field_id );
5098 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
5099 DB_RETURN( DB_INVALID_FIELD );
5100
5101 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
5102
5103 /* Using RecordBitMap, check whether record_num is free;
5104 if so, empty = true and false otherwise */
5105
5106 tmp_byte =
5107 (tmp_ptrFieldRecord -> RecordBitMap)[ RECORD_BITMAP_SIZE - BITMAP_INDEX(record_num) - 1 ];
5108
5109 if( tmp_byte & ( 0x01 << BIT_POS(record_num) ) ) /* if record exist */
5110 *empty = FALSE;
5111
5112 DB_RETURN( DB_OK );
5113
5114 }
5115
5116 /*
5117 +--------------------------------------------------------------------+
5118 | PROJECT: PHB MODULE: DBM |
5119 | ROUINE: db_find_free_record |
5120 +--------------------------------------------------------------------+
5121
5122 PURPOSE : Find an free record in given (database, field)
5123 */
5124 int db_find_free_record ( int db_handle,
5125 USHORT field_id )
5126 {
5127 UBYTE fld_ctr;
5128 T_DB_CODE db_ret_code;
5129
5130 int record_num;
5131
5132 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
5133
5134
5135 TRACE_FUNCTION("db_find_free_record()");
5136
5137 /* DBM_State check */
5138 DBM_State_check;
5139
5140 /* db_handle check */
5141 db_ret_code = db_handle_check( db_handle );
5142 if( db_ret_code NEQ DB_OK )
5143 DB_RETURN( db_ret_code );
5144
5145 /* field id search; if field not found, return error DB_INVALID_FIELD */
5146 fld_ctr = field_id_search( db_handle, field_id );
5147 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
5148 DB_RETURN( DB_INVALID_FIELD );
5149
5150 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
5151
5152 /* Using RecordBitMap, search for free record.
5153 If found , return the found record_num
5154 Return DB_RECORD_NOT_FOUND */
5155
5156 record_num = 1 + search_clear_bit_in_bitmap( tmp_ptrFieldRecord -> RecordBitMap,
5157 RECORD_BITMAP_SIZE );
5158
5159 if( record_num > tmp_ptrFieldRecord -> NumOfRecords )
5160 DB_RETURN( DB_RECORD_NOT_FOUND );
5161
5162 DB_VALUE_RETURN( record_num );
5163
5164 }
5165
5166 /*
5167 +--------------------------------------------------------------------+
5168 | PROJECT: PHB MODULE: DBM |
5169 | ROUINE: db_info |
5170 +--------------------------------------------------------------------+
5171
5172 PURPOSE : Get information about an open database
5173 */
5174 T_DB_CODE db_info ( int db_handle,
5175 T_DB_INFO* db_info )
5176 {
5177 T_DB_CODE db_ret_code;
5178
5179 TRACE_FUNCTION("db_info()");
5180
5181 /* DBM_State check */
5182 DBM_State_check;
5183
5184 /* db_handle check */
5185 db_ret_code = db_handle_check( db_handle );
5186 if( db_ret_code NEQ DB_OK )
5187 DB_RETURN( db_ret_code );
5188
5189 (*db_info).clean = ( DbmMaster[db_handle].Tracked_Clean & CLEAN ) ? TRUE : FALSE ;
5190 (*db_info).tracked = ( DbmMaster[db_handle].Tracked_Clean & TRACKED ) ? TRUE : FALSE ;
5191
5192 DB_RETURN( DB_OK );
5193 }
5194
5195 /*
5196 +--------------------------------------------------------------------+
5197 | PROJECT: PHB MODULE: DBM |
5198 | ROUINE: db_info_field |
5199 +--------------------------------------------------------------------+
5200
5201 PURPOSE : Get general information about a field in an open database.
5202 */
5203 T_DB_CODE db_info_field ( int db_handle,
5204 USHORT field_id,
5205 T_DB_INFO_FIELD* info_field )
5206 {
5207 UBYTE fld_ctr;
5208 T_DB_CODE db_ret_code;
5209
5210 T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
5211
5212
5213 TRACE_FUNCTION("db_info_field()");
5214
5215 /* DBM_State check */
5216 DBM_State_check;
5217
5218 /* db_handle check */
5219 db_ret_code = db_handle_check( db_handle );
5220 if( db_ret_code NEQ DB_OK )
5221 DB_RETURN( db_ret_code );
5222
5223 /* field id search; if field not found, return error DB_INVALID_FIELD */
5224 fld_ctr = field_id_search( db_handle, field_id );
5225 if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
5226 DB_RETURN( DB_INVALID_FIELD );
5227
5228 tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
5229
5230 /* Using data available in RAM in field record, fill up info_field
5231 (i.e. clean, db_type, num_of_records and used_records). */
5232
5233 (*info_field).clean = tmp_ptrFieldRecord -> Clean;
5234 (*info_field).entry_type = tmp_ptrFieldRecord -> DBType;
5235 (*info_field).record_size = tmp_ptrFieldRecord -> RecordSize;
5236 (*info_field).num_records = tmp_ptrFieldRecord -> NumOfRecords;
5237 (*info_field).used_records = tmp_ptrFieldRecord -> UsedRecords;
5238
5239 DB_RETURN( DB_OK );
5240
5241 }
5242
5243 /*
5244 +--------------------------------------------------------------------+
5245 | PROJECT: PHB MODULE: DBM |
5246 | ROUINE: db_get_last_fs_error |
5247 +--------------------------------------------------------------------+
5248
5249 PURPOSE : Delivers the last error provided by the (flash) file system
5250 that resulted in DB_FAIL_FS.
5251 */
5252 int db_get_last_fs_error ( void )
5253 {
5254 DB_VALUE_RETURN( LastFFS_ReturnCode );
5255 }
5256
5257 #endif /* #ifdef TI_PS_FFS_PHB */
5258