comparison g23m-aci/aci/db.c @ 0:75a11d740a02

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