FreeCalypso > hg > fc-tourmaline
view src/g23m-aci/aci/db.c @ 99:8142e6773a49
mmiBlk*.h: bogotab fixes
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 08 Nov 2020 08:33:36 +0000 |
parents | fa8dc04885d8 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : PHB | Modul : DBM +----------------------------------------------------------------------------- | Copyright 2005 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : Implementation of DBM functions +----------------------------------------------------------------------------- */ #ifdef TI_PS_FFS_PHB #include "db_int.h" #include <string.h> #ifdef _SIMULATION_ int sprintf (char *, const char *, ...); /* Use appropriate include ... */ #endif /* For DB Testing */ /* Check if we are closing FFS files properly */ /* Implements measure 54 */ /* A simple check to make sure that all allocated memory is freed to avoid memory leak */ // #define DB_MEMORY_CHECK /************************** D E F I N I T I O N S & D E C L A R A T I O N S **************************/ #define INVALID_FD (-1) #define IS_FD_VALID(fd) ((fd) >= 0) GLOBAL UBYTE UsedDBs; /* Number of existing databases */ GLOBAL int LastFFS_ReturnCode; /* Last FFS return code */ GLOBAL T_DBM_MASTERRECORD DbmMaster [MAX_DBs]; /* Database Master */ GLOBAL T_DBM_STATE DBM_State = DBM_NOT_INITIALISED; /* DBM State */ GLOBAL T_DB_CHANGED DB_History_log; /* History log */ /* Implements Measure#32: Row 1167, 1171, 1189 & 1200 */ LOCAL const char * const format_sUDd_str="%s/UD_%04X"; /* Implements Measure#32: Row 1170, 1177 & 1193 */ LOCAL const char * const format_sUDd_sortd_str="%s/UD_%04X_sort_%d"; /* Implements Measure#32: Row 1178, 1182, 1186, 1190, 1195, 1198 & 1202 */ LOCAL const char * const format_sDDd_str="%s/DD_%d"; #ifdef FFS_CLOSE_BEFORE_OPEN T_FFS_FD Dummy_FFSFileHandle = INVALID_FD; #define INVALID_FLD_CTR 0xFF #define NOT_OPENED 0x00 #define OPENED_FOR_READ 0x01 #define OPENED_FOR_WRITE 0x02 #endif #ifdef DB_TEST S8 db_test_ffs_open_ctr = 0; T_FFS_SIZE db_test_ffs_ret_code = EFFS_OK; #define DB_FFS_OPEN( ret, file, flag ) \ { \ ret = ffs_open( file, flag ); \ \ if( ret >= EFFS_OK ) \ { \ ++db_test_ffs_open_ctr; \ TRACE_EVENT_P1( "DB_FFS_OPEN:db_test_ffs_open_ctr:%d", db_test_ffs_open_ctr ); \ } else { \ TRACE_EVENT_P1( "DB_FFS_OPEN:FFS ERROR:%d", ret ); \ } \ } #define DB_FFS_CLOSE( fd ) \ { \ T_FFS_SIZE db_test_ffs_ret_code = ffs_close( fd ); \ \ if( db_test_ffs_ret_code >= EFFS_OK ) \ { \ --db_test_ffs_open_ctr; \ TRACE_EVENT_P1( "DB_FFS_CLOSE:db_test_ffs_open_ctr:%d", db_test_ffs_open_ctr ); \ } else { \ TRACE_EVENT_P1( "DB_FFS_CLOSE:FFS ERROR:%d", db_test_ffs_ret_code ); \ } \ \ fd = INVALID_FD; \ } #define DB_RETURN( ret ) \ { \ TRACE_EVENT_P1( "DB_RETURN:ret:%d", ret ); \ return ret; \ } #define DB_VALUE_RETURN( ret ) \ { \ TRACE_EVENT_P1( "DB_VALUE_RETURN:ret:%d", ret ); \ return ret; \ } #else #define DB_FFS_OPEN( ret, file, flag ) { ret = ffs_open( file, flag ); } #define DB_FFS_CLOSE( fd ) { ffs_close( fd ); fd = INVALID_FD; } #define DB_RETURN( ret ) return ret; #define DB_VALUE_RETURN( ret ) return ret; #endif #ifdef DB_MEMORY_CHECK LOCAL UBYTE alloc_ctr = 0; LOCAL void db_mfree (void *ptr) { if (ptr NEQ NULL) { --alloc_ctr; TRACE_EVENT_P1( "DB Memory Free:%d", alloc_ctr ); ACI_MFREE( ptr ); } else { TRACE_ERROR ("Attempted to free NULL"); } } LOCAL void *db_malloc (ULONG num_of_bytes) { void *ptr; ++alloc_ctr; TRACE_EVENT_P1( "DB Memory Alloc:%d", alloc_ctr ); ACI_MALLOC( ptr, num_of_bytes ); return ptr; } #define DB_MALLOC( ptr, size ) { ptr = db_malloc ( size ); } #define DB_MFREE( ptr ) { db_mfree ( ptr ); } #else #define DB_MALLOC( ptr, num_of_bytes ) ACI_MALLOC( ptr, num_of_bytes ) #define DB_MFREE( ptr ) ACI_MFREE( ptr ) #endif #ifdef _SIMULATION_ #define DB_DIR "/dbm" #define DB_MASTER_FILE "/dbm/DD_master" #else #define DB_DIR "/gsm/dbm" #define DB_MASTER_FILE "/gsm/dbm/DD_master" #endif /* Implements Measure#32: Row 1179, 1184, 1191, 1196, 1199 & 1203 */ LOCAL const char * const db_dir=DB_DIR; /* Implements Measure#32: Row 1181, 1188 & 1201 */ LOCAL char * const db_master_file=DB_MASTER_FILE; #define FILENAME_LEN 40 #define T_DB_MASTER_RECORD_SIZE 18 /* DBM master record File: DB_DIR/DD_master Data: 1) DBDirectory (16 bytes, based on MAX_LEN_DIRECTORY=16) 2) NumOfFiles (1 byte, based on MAX_NUM_FILES=255) 3) Clean (1 byte) */ #define T_DB_FIELD_RECORD_SIZE 43 /* Based on the following data written into FFS File: DB_DIR/DD_<DBDirectory> Data: 1) FieldID (2 bytes, given in Interface) 2) DBType (1 byte) 3) RecordSize (2 bytes, based on MAX_RECORD_SIZE=65kb) 4) NumOfRecords (1 byte, based on MAX_NUM_RECORDS=255) 5) SortIndexes (MAX_NUM_OF_SORT_INDEXS bytes, 1 byte for each index) 6) RecordBitMap (32 bytes, as of now based on MAX_NUM_RECORDS=255) 7) Clean (1 byte) */ #define RecordBitMap_OFFSET 10 /* depending on structure in DB_DIR/DD_<DBDirectory> */ #define SortIndexList_OFFSET 6 /* depending on structure in DB_DIR/DD_<DBDirectory> */ #define SEARCH_FAILED -1 /* For FFS strctures */ #define FFS_CLEAN 0x01 #define FFS_DIRTY 0x00 #define FFS_TRACKED 0x01 #define FFS_NOT_TRACKED 0x00 #define NOT ! #define INVALID_RECORD_NUM 0xFF /* Internal function to initialize RAM structures with FFS */ LOCAL T_DB_CODE init_RAM_with_FFS ( void ); #define DBM_State_check \ if ( DBM_State EQ DBM_NOT_INITIALISED ) DB_RETURN( DB_NOT_INITIALISED ); LOCAL T_DB_CODE db_handle_check ( int db_handle ); LOCAL UBYTE field_id_search ( int db_handle, USHORT field_id ); LOCAL T_DB_CODE update_history_log ( int db_handle, USHORT field_id, USHORT record_num ); LOCAL void db_set_bit_in_bitmap (UBYTE *bitmap, USHORT position, BOOL value); LOCAL UBYTE db_search_bit_in_bitmap (UBYTE* bitmap, USHORT max_record, BOOL value); LOCAL T_DB_CODE populate_sorted_list_from_FFS ( #ifdef FFS_CLOSE_BEFORE_OPEN UBYTE db_ctr, #endif char* sort_file, UBYTE num_of_elements, UBYTE** sort_list_ptr ); LOCAL T_DB_CODE write_sorted_list_to_FFS ( #ifdef FFS_CLOSE_BEFORE_OPEN UBYTE db_ctr, #endif char* sort_file, UBYTE num_of_elements, UBYTE* sort_list ); LOCAL int db_binary_search ( UBYTE* sort_list, UBYTE num_of_elements, SHORT* order_num, T_SEARCH_FUNC search_function, ULONG flags, const UBYTE* search_tag, int db_handle, USHORT field_id ); LOCAL T_DB_CODE update_field_data_in_FFS ( T_FFS_FD* filehandle, UBYTE db_handle, UBYTE fld_ctr, UBYTE* field_data, USHORT offset, USHORT length ); LOCAL UBYTE cal_NextRecordNum ( const char* DBDirectory, USHORT FieldID, USHORT RecordSize ); LOCAL T_DB_CODE read_write_user_record_from_FFS ( const char *user_field_file, #ifdef FFS_CLOSE_BEFORE_OPEN UBYTE db_ctr, UBYTE fld_ctr, #endif T_FFS_FD *filehandle, UBYTE record_num, USHORT record_size, USHORT offset, USHORT length, UBYTE *record_buffer, T_FFS_OPEN_FLAGS open_option); LOCAL T_DB_CODE check_ffs_ret_code (T_FFS_SIZE ffs_ret_code, T_FFS_FD *filehandle, T_FFS_FD ffs_fd, BOOL check_invalid); LOCAL T_DB_CODE delete_file_dir_from_FFS ( const char* filename ); LOCAL T_DB_CODE update_dbm_data_in_FFS ( const char* filename, UBYTE db_ctr, UBYTE db_data_max_size, UBYTE* db_data, USHORT offset, USHORT length ); LOCAL T_DB_CODE remove_field_from_FFS ( UBYTE db_ctr, UBYTE fld_ctr ); #ifdef FFS_CLOSE_BEFORE_OPEN LOCAL T_FFS_FD db_open_user_field_file ( UBYTE db_ctr, UBYTE fld_ctr, const char* user_field_file, T_FFS_OPEN_FLAGS open_option ); LOCAL void db_close_user_field_files ( UBYTE db_ctr ); LOCAL BOOL db_open_full_for_read ( UBYTE db_ctr ); LOCAL BOOL db_open_full_for_write ( UBYTE db_ctr ); LOCAL void db_close_for_write ( UBYTE db_ctr ); LOCAL void db_close_for_read ( UBYTE db_ctr ); LOCAL UBYTE db_status_user_field_file ( UBYTE db_ctr, UBYTE fld_ctr ); #endif /* FFS_CLOSE_BEFORE_OPEN */ LOCAL T_DB_CODE delete_dir_forced ( const char* filename ); LOCAL void get_sort_lists_from_FFS ( UBYTE db_ctr, UBYTE fld_ctr ); LOCAL void new_in_sort_lists ( UBYTE db_ctr, UBYTE fld_ctr, UBYTE record_num ); LOCAL void update_in_sort_lists ( UBYTE db_ctr, UBYTE fld_ctr, UBYTE record_num ); LOCAL void delete_in_sort_lists ( UBYTE db_ctr, UBYTE fld_ctr, UBYTE record_num ); LOCAL void insertion_sort ( UBYTE* sort_list, UBYTE num_of_elements, T_COMP_FUNC compare_function, ULONG flags, int db_handle, USHORT field_id ); LOCAL void insert_element ( UBYTE* sort_list, UBYTE num_of_elements, UBYTE bottom, UBYTE top, UBYTE record_num, T_COMP_FUNC compare_function, ULONG flags, int db_handle, USHORT field_id ); LOCAL T_DB_CODE internal_db_sort ( int db_handle, USHORT field_id, UBYTE sort_index, T_COMP_FUNC compare_function, ULONG flags ); LOCAL void db_close_for_read_write ( FileHandleRecord *tmp_open_fields, UBYTE *tmp_old, UBYTE max_per_db); /****************************** I M P L E M E N T A T I O N ******************************/ /**********************/ /* INTERNAL FUNCTIONS */ /**********************/ /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_handle_check | +--------------------------------------------------------------------+ PURPOSE : DB Handle checks */ LOCAL T_DB_CODE db_handle_check ( int db_handle ) { /* Check for db_handle range */ if( db_handle >= MAX_DBs ) return DB_INVALID_DB; /* Check for DBState of db_handle is CLOSED or UNUSED_ENTRY If yes, return DB_INVALID_DB */ if( ( DbmMaster[db_handle].DBState EQ CLOSED ) OR ( DbmMaster[db_handle].DBState EQ UNUSED_ENTRY ) ) return DB_INVALID_DB; return DB_OK; } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: field_id_search | +--------------------------------------------------------------------+ PURPOSE : checks for the existence of field id in RAM */ LOCAL UBYTE field_id_search ( int db_handle, USHORT field_id ) { UBYTE fld_ctr; for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr ) { if( DbmMaster[db_handle].ptrFieldRecord[fld_ctr].FieldID EQ field_id ) { return fld_ctr; } } return fld_ctr; } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: update_history_log | +--------------------------------------------------------------------+ PURPOSE : Updating history log */ LOCAL T_DB_CODE update_history_log ( int db_handle, USHORT field_id, USHORT record_num ) { UBYTE i; /* Check if database is tracked */ if (!DbmMaster[db_handle].Tracked) /* if db is NOT tracked */ return DB_OK; /* Search history log if the record is present If present, return DB_OK */ for( i = 0; i < DB_History_log.entries; ++i ) { if( DB_History_log.field_id[i] EQ field_id ) if( DB_History_log.record[i] EQ record_num ) return DB_OK; } /* If the number of existing logs in history is reached limit, DB_MAX_AFFECTED, return error "DB_HISTORY_FULL". */ if( DB_History_log.entries EQ DB_MAX_AFFECTED ) return DB_HISTORY_FULL; /* Add new entry */ DB_History_log.field_id [DB_History_log.entries] = field_id; DB_History_log.record [DB_History_log.entries] = record_num; ++DB_History_log.entries; return DB_OK; } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_get_bit_in_bitmap | +--------------------------------------------------------------------+ PURPOSE : Gets a bit in record bitmap */ LOCAL BOOL db_get_bit_in_bitmap (const UBYTE *bitmap, USHORT position) { USHORT offset; UBYTE mask; position--; /* We count from 1 */ offset = position >> 3; mask = 0x80 >> (position & 0x7); return ((bitmap[offset] & mask) NEQ 0); } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: set_bit_in_bitmap | +--------------------------------------------------------------------+ PURPOSE : Sets a bit in record bitmap */ LOCAL void db_set_bit_in_bitmap (UBYTE *bitmap, USHORT position, BOOL value) { USHORT offset; UBYTE mask; //TISH modified for MSIM if (position==0) return; position--; /* We count from 1 */ offset = position >> 3; mask = 0x80 >> (position & 0x7); if (value) bitmap[offset] |= mask; else bitmap[offset] &= ~mask; } /* +----------------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_search_bit_in_bitmap | +----------------------------------------------------------------------------+ PURPOSE : Searches for the bit not set in record bitmap which indicates free record */ LOCAL UBYTE db_search_bit_in_bitmap (UBYTE* bitmap, USHORT max_record, BOOL value) { UBYTE i; for (i = 1; i <= max_record; i++) { if (db_get_bit_in_bitmap (bitmap, i) EQ value) return i; } return 0; /* Not found */ } /* +----------------------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: populate_sorted_list_from_FFS | +----------------------------------------------------------------------------------+ PURPOSE : Reads the sorted list from FFS */ LOCAL T_DB_CODE populate_sorted_list_from_FFS ( #ifdef FFS_CLOSE_BEFORE_OPEN UBYTE db_ctr, #endif char* sort_file, UBYTE num_of_elements, UBYTE** sort_list_ptr ) { T_FFS_FD ffs_fd_sort_file; T_FFS_SIZE ffs_ret_code; UBYTE* sort_list; #ifdef FFS_CLOSE_BEFORE_OPEN /* READ */ if( db_open_full_for_read( db_ctr ) ) { db_close_for_read( db_ctr ); } #endif DB_FFS_OPEN( ffs_fd_sort_file, sort_file, FFS_O_RDONLY ); if( (ffs_fd_sort_file EQ EFFS_NAMETOOLONG ) OR (ffs_fd_sort_file EQ EFFS_BADNAME ) OR (ffs_fd_sort_file EQ EFFS_NOTFOUND ) OR (ffs_fd_sort_file EQ EFFS_INVALID ) OR (ffs_fd_sort_file EQ EFFS_LOCKED ) ) { TRACE_EVENT_P1( "populate_sorted_list_from_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file ); return DB_FAIL; } if( ffs_fd_sort_file < EFFS_OK ) { LastFFS_ReturnCode = ffs_fd_sort_file; TRACE_EVENT_P1( "populate_sorted_list_from_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file ); return DB_FAIL_FS; } /* This seek is not required as file pointer will be at start of file, but ffs guide doesn't say so ! This needs to be clarified and accordingly all ffs_seek at start of file after opening the file can be removed ! */ ffs_ret_code = ffs_seek( ffs_fd_sort_file, 0, FFS_SEEK_SET ); if( ( ffs_ret_code EQ EFFS_BADFD ) OR ( ffs_ret_code EQ EFFS_INVALID ) OR ( ffs_ret_code EQ EFFS_BADOP ) ) { DB_FFS_CLOSE( ffs_fd_sort_file ); TRACE_EVENT_P1( "populate_sorted_list_from_FFS:ffs_seek %d", ffs_ret_code ); return DB_FAIL; } DB_MALLOC( sort_list, num_of_elements + 1 ); memset( sort_list, INVALID_RECORD_NUM, num_of_elements + 1 ); ffs_ret_code = ffs_read( ffs_fd_sort_file, sort_list, num_of_elements ); if( (ffs_ret_code EQ EFFS_BADFD ) OR (ffs_ret_code EQ EFFS_BADOP ) ) { DB_MFREE( sort_list ); DB_FFS_CLOSE( ffs_fd_sort_file ); TRACE_EVENT_P1( "populate_sorted_list_from_FFS:ffs_read %d", ffs_ret_code ); return DB_FAIL; } if( ffs_ret_code < EFFS_OK ) { LastFFS_ReturnCode = ffs_fd_sort_file; DB_MFREE( sort_list ); TRACE_EVENT_P1( "populate_sorted_list_from_FFS:ffs_read %d", ffs_ret_code ); DB_FFS_CLOSE( ffs_fd_sort_file ); return DB_FAIL_FS; } DB_FFS_CLOSE( ffs_fd_sort_file ); /* to avoid memory leak */ if( *sort_list_ptr NEQ NULL ) DB_MFREE( *sort_list_ptr ); *sort_list_ptr = sort_list; return DB_OK; } /* +-----------------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: write_sorted_list_to_FFS | +-----------------------------------------------------------------------------+ PURPOSE : Writes the sorted list into FFS */ LOCAL T_DB_CODE write_sorted_list_to_FFS ( #ifdef FFS_CLOSE_BEFORE_OPEN UBYTE db_ctr, #endif char* sort_file, UBYTE num_of_elements, UBYTE* sort_list ) { T_FFS_FD ffs_fd_sort_file; T_FFS_SIZE ffs_ret_code; #ifdef FFS_CLOSE_BEFORE_OPEN /* WRITE */ if( db_open_full_for_write( db_ctr ) ) { db_close_for_write( db_ctr ); } #endif /* FFS_O_TRUNC => If file already exists and it is opened for writing, its length is truncated to zero. */ DB_FFS_OPEN( ffs_fd_sort_file, sort_file, FFS_O_CREATE | FFS_O_WRONLY | FFS_O_TRUNC ); if( (ffs_fd_sort_file EQ EFFS_NAMETOOLONG ) OR (ffs_fd_sort_file EQ EFFS_BADNAME ) ) { TRACE_EVENT_P1( "write_sorted_list_to_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file ); return DB_FAIL; } if( ffs_fd_sort_file < EFFS_OK ) { TRACE_EVENT_P1( "write_sorted_list_to_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file ); LastFFS_ReturnCode = ffs_fd_sort_file; return DB_FAIL_FS; } ffs_ret_code = ffs_seek( ffs_fd_sort_file, 0, FFS_SEEK_SET ); if( ( ffs_ret_code EQ EFFS_BADFD ) OR ( ffs_ret_code EQ EFFS_INVALID ) OR ( ffs_ret_code EQ EFFS_BADOP ) ) { TRACE_EVENT_P1( "write_sorted_list_to_FFS:ffs_seek %d", ffs_ret_code ); DB_FFS_CLOSE( ffs_fd_sort_file ); return DB_FAIL; } ffs_ret_code = ffs_write( ffs_fd_sort_file, sort_list, num_of_elements ); if( ( ffs_ret_code EQ EFFS_BADFD ) OR ( ffs_ret_code EQ EFFS_BADOP ) ) { DB_FFS_CLOSE( ffs_fd_sort_file ); ffs_ret_code = ffs_remove( sort_file ); TRACE_EVENT_P1( "write_sorted_list_to_FFS:ffs_write %d", ffs_ret_code ); return DB_FAIL; } if( ffs_ret_code < EFFS_OK ) { LastFFS_ReturnCode = ffs_ret_code; DB_FFS_CLOSE( ffs_fd_sort_file ); ffs_ret_code = ffs_remove( sort_file ); TRACE_EVENT_P1( "write_sorted_list_to_FFS:ffs_write %d", ffs_ret_code ); return DB_FAIL_FS; } DB_FFS_CLOSE( ffs_fd_sort_file ); /* yeah, we close it here ! */ return DB_OK; } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_binary_search | +--------------------------------------------------------------------+ PURPOSE : Searches for the record; uses binary search and compare function is passed as a parameter. */ LOCAL int db_binary_search ( UBYTE* sort_list, UBYTE num_of_elements, SHORT* order_num, T_SEARCH_FUNC search_function, ULONG flags, const UBYTE* search_tag, int db_handle, USHORT field_id ) { UINT32 left, right; UINT32 mid; int cmp_res; BOOL matched; TRACE_FUNCTION ("db_binary_search()"); left = *order_num; right = num_of_elements; if (left >= right) return SEARCH_FAILED; /* As often the 1st element is the matching one we try a shortcut. */ cmp_res = search_function (flags, search_tag, db_handle, field_id, sort_list[left]); if (cmp_res EQ 0) { *order_num = left + 1; return *order_num; } else if (cmp_res > 0) return SEARCH_FAILED; /* We learned already no exact match possible */ /* Get the first (leftmost) matching element in the sorted list. */ matched = FALSE; do { mid = (left + right) >> 1; cmp_res = search_function (flags, search_tag, db_handle, field_id, sort_list[mid]); if (cmp_res EQ 0) matched = TRUE; if (cmp_res < 0) left = mid + 1; else right = mid; } while (left < right); if (matched) { *order_num = left + 1; return *order_num; } return SEARCH_FAILED; } /* +-----------------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: update_field_data_in_FFS | +-----------------------------------------------------------------------------+ PURPOSE : Updates elementary file data in FFS PARAMS: filehandle: Pointer to file handle, maybe INVALID_FD db_handle: Handle of the particular DB fld_ctr: Number of field (0..n) field_data: (const) Pointer to data to be written offset: offset within the data length: length of data to be written */ LOCAL T_DB_CODE update_field_data_in_FFS ( T_FFS_FD* filehandle, UBYTE db_handle, UBYTE fld_ctr, UBYTE* field_data, USHORT offset, USHORT length ) { T_FFS_FD ffs_fd = *filehandle; T_FFS_SIZE ffs_ret_code; CHAR field_file[FILENAME_LEN]; /* Updating field data in FFS in file "field_file" */ /* Implements Measure#32: */ sprintf(field_file, format_sDDd_str, db_dir, db_handle); if (!IS_FD_VALID(ffs_fd)) { DB_FFS_OPEN( ffs_fd, field_file, FFS_O_WRONLY ); if( ( ffs_fd EQ EFFS_NOTFOUND ) OR ( ffs_fd EQ EFFS_NAMETOOLONG ) OR ( ffs_fd EQ EFFS_BADNAME ) OR ( ffs_fd EQ EFFS_INVALID ) ) { TRACE_EVENT_P1( "update_field_data_in_FFS:DB_FFS_OPEN %d", ffs_fd ); return DB_FAIL; } if( ffs_fd < EFFS_OK ) { LastFFS_ReturnCode = ffs_fd; TRACE_EVENT_P1( "update_field_data_in_FFS:DB_FFS_OPEN %d", ffs_fd ); return DB_FAIL_FS; } *filehandle = ffs_fd; } /* filehandle invalid? */ /* Seek the file to fld_ctr position to update the entry */ ffs_ret_code = ffs_seek( ffs_fd, ( fld_ctr * T_DB_FIELD_RECORD_SIZE ) + offset, FFS_SEEK_SET ); if( ( ffs_ret_code EQ EFFS_BADFD ) OR ( ffs_ret_code EQ EFFS_INVALID ) OR ( ffs_ret_code EQ EFFS_BADOP ) ) { TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_seek %d", ffs_ret_code ); DB_FFS_CLOSE( ffs_fd ); *filehandle = INVALID_FD; return DB_FAIL; } if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_seek %d", ffs_ret_code ); LastFFS_ReturnCode = ffs_ret_code; DB_FFS_CLOSE( ffs_fd ); *filehandle = INVALID_FD; return DB_FAIL_FS; } /* clean is reset in memset, so no processing for it (in case of non-tracked database, anyway we ignore it ! */ ffs_ret_code = ffs_write( ffs_fd, field_data, length ); if( (ffs_ret_code EQ EFFS_BADFD ) OR (ffs_ret_code EQ EFFS_BADOP ) ) { TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_write %d", ffs_ret_code ); DB_FFS_CLOSE( ffs_fd ); *filehandle = INVALID_FD; return DB_FAIL; } if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_write %d", ffs_ret_code ); DB_FFS_CLOSE ( ffs_fd ); *filehandle = INVALID_FD; LastFFS_ReturnCode = ffs_ret_code; return DB_FAIL_FS; } /* DB_FFS_CLOSE( ffs_fd ); we will do it in db_flush */ /* updation is over */ #ifdef FFS_OPEN_PROBLEM_PATCH DB_FFS_CLOSE( ffs_fd ); *filehandle = INVALID_FD; #endif #ifndef FFS_CLOSE_BEFORE_OPEN /* this is db file, but we do not close it */ #endif return DB_OK; } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: cal_NextRecordNum | +--------------------------------------------------------------------+ PURPOSE : Reads the status of the file and returns the next available record (position) */ LOCAL UBYTE cal_NextRecordNum ( const char* db_directory, USHORT field_id, USHORT record_size ) { char user_field_file[FILENAME_LEN]; T_FFS_SIZE ffs_ret_code; T_FFS_STAT ffs_file_stat; /* Implements Measure#32: Row 1167 */ sprintf( user_field_file, format_sUDd_str, db_directory, field_id ); ffs_ret_code = ffs_stat( user_field_file, &ffs_file_stat ); if( ffs_ret_code EQ EFFS_OK ) { return ( (ffs_file_stat.size / record_size) + 1); } if( ffs_ret_code EQ EFFS_NOTFOUND ) { TRACE_EVENT( "cal_NextRecordNum:ffs_stat:FILE NOT FOUND" ); return 1; } /* this is a problem with user_field_file, raise an error and return 0 */ TRACE_ERROR( "cal_NextRecordNum: PROBLEM with user_field_file" ); TRACE_EVENT_P1( "cal_NextRecordNum:ffs_stat %d", ffs_ret_code ); return 1; } /* Implements Measure # 211 */ /* +-----------------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: delete_file_dir_from_FFS | +-----------------------------------------------------------------------------+ PURPOSE : Deletes a file from FFS */ LOCAL T_DB_CODE delete_file_dir_from_FFS ( const char* filename ) { T_FFS_SIZE ffs_ret_code; TRACE_EVENT_P1( "delete_file_dir_from_FFS %s", filename ); ffs_ret_code = ffs_remove( filename ); if( ffs_ret_code EQ EFFS_DIRNOTEMPTY ) { TRACE_EVENT( "Inconsistency; going for delete_dir_forced" ); return delete_dir_forced( filename ); } if( ffs_ret_code EQ EFFS_NOTFOUND ) { TRACE_EVENT( "delete_file_dir_from_FFS:ffs_remove:FILE NOT FOUND" ); return DB_OK; } if( ( ffs_ret_code EQ EFFS_ACCESS ) OR ( ffs_ret_code EQ EFFS_LOCKED ) ) { TRACE_EVENT_P1( "delete_file_dir_from_FFS:ffs_remove %d", ffs_ret_code ); return DB_FAIL; } if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P1( "delete_file_dir_from_FFS:ffs_remove %d", ffs_ret_code ); LastFFS_ReturnCode = ffs_ret_code; return DB_FAIL_FS; } return DB_OK; } /* +---------------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: update_dbm_data_in_FFS | +---------------------------------------------------------------------------+ PURPOSE : Updates the database manager information of a particular database */ LOCAL T_DB_CODE update_dbm_data_in_FFS ( const char* filename, UBYTE db_ctr, UBYTE db_data_max_size, UBYTE* db_data, USHORT offset, USHORT length ) { T_FFS_FD ffs_fd = INVALID_FD; T_FFS_SIZE ffs_ret_code; /* See if file already opened, if not open it and update the file handle */ #ifdef FFS_CLOSE_BEFORE_OPEN /* WRITE */ if( db_open_full_for_write( db_ctr ) ) { db_close_for_write( db_ctr ); } #endif DB_FFS_OPEN( ffs_fd, filename, FFS_O_WRONLY ); if( ( ffs_fd EQ EFFS_NAMETOOLONG ) OR ( ffs_fd EQ EFFS_BADNAME ) OR ( ffs_fd EQ EFFS_NOTFOUND ) OR ( ffs_fd EQ EFFS_INVALID ) OR ( ffs_fd EQ EFFS_LOCKED ) ) { TRACE_EVENT_P1( "update_dbm_data_in_FFS:DB_FFS_OPEN %d", ffs_fd ); return DB_FAIL; } if( ffs_fd < EFFS_OK ) { TRACE_EVENT_P1( "update_dbm_data_in_FFS:DB_FFS_OPEN %d", ffs_fd ); LastFFS_ReturnCode = ffs_fd; return DB_FAIL_FS; } ffs_ret_code = ffs_seek( ffs_fd, db_ctr * db_data_max_size, FFS_SEEK_SET ); if( ( ffs_ret_code EQ EFFS_BADFD ) OR ( ffs_ret_code EQ EFFS_INVALID ) OR ( ffs_ret_code EQ EFFS_BADOP ) ) { TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_seek %d", ffs_ret_code ); DB_FFS_CLOSE( ffs_fd ); return DB_FAIL; } if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_seek %d", ffs_ret_code ); LastFFS_ReturnCode = ffs_ret_code; DB_FFS_CLOSE( ffs_fd ); return DB_FAIL_FS; } ffs_ret_code = ffs_write( ffs_fd, db_data, db_data_max_size ); if( ( ffs_ret_code EQ EFFS_BADFD ) OR ( ffs_ret_code EQ EFFS_BADOP ) ) { TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_write %d", ffs_ret_code ); DB_FFS_CLOSE( ffs_fd ); return DB_FAIL; } if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_write %d", ffs_ret_code ); DB_FFS_CLOSE( ffs_fd ); LastFFS_ReturnCode = ffs_ret_code; return DB_FAIL_FS; } DB_FFS_CLOSE( ffs_fd ); /* yeah, DB file, so ok to close it here ! */ /* updation of dbm data done */ return DB_OK; } /* +--------------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: remove_field_from_FFS | +--------------------------------------------------------------------------+ PURPOSE : Removes the elementary file and associated Index file from FFS */ LOCAL T_DB_CODE remove_field_from_FFS ( UBYTE db_ctr, UBYTE fld_ctr ) { T_DBM_FIELDRECORD* tmp_ptrFieldRecord; char user_field_file[FILENAME_LEN], sort_file[FILENAME_LEN]; T_DB_CODE db_ret_code; UBYTE sort_index_ctr; /* Assumed that DBState is not IN_USE */ tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr; if( tmp_ptrFieldRecord -> FieldID EQ INVALID_FIELD_ID ) /* if not valid field id */ return DB_OK; /* Close of user record files not required as DBState is not IN_USE */ /* Delete file "<DBDirectory>/UD_<field_id>" */ /* Implements Measure#32: Row 1171 */ sprintf( user_field_file, format_sUDd_str, (char *)DbmMaster[db_ctr].DBDirectory, tmp_ptrFieldRecord -> FieldID ); db_ret_code = delete_file_dir_from_FFS ( user_field_file ); if( db_ret_code NEQ DB_OK ) return db_ret_code; /* For sorted lists */ for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr ) { /* Delete the SortedLists from memory */ if (tmp_ptrFieldRecord->SortedLists[sort_index_ctr] NEQ NULL) { DB_MFREE (tmp_ptrFieldRecord->SortedLists[sort_index_ctr]); tmp_ptrFieldRecord->SortedLists[sort_index_ctr] = NULL; } /* Delete the SortedLists from the FFS */ if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX ) { /* Sort file, "<DBDirectory>/UD_<field_id>_sort_<sort_index>" */ /* Implements Measure#32: Row 1170 */ sprintf( sort_file, format_sUDd_sortd_str, (char *)DbmMaster[db_ctr].DBDirectory, tmp_ptrFieldRecord -> FieldID, tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] ); db_ret_code = delete_file_dir_from_FFS ( sort_file ); if( db_ret_code NEQ DB_OK ) return db_ret_code; } } return DB_OK; } #ifdef FFS_CLOSE_BEFORE_OPEN LOCAL T_FFS_FD db_open_user_field_file ( UBYTE db_ctr, UBYTE fld_ctr, const char* user_field_file, T_FFS_OPEN_FLAGS open_option ) { UBYTE i; FileHandleRecord* tmp_open_fields; UBYTE* tmp_old; UBYTE tmp_max; /* sanity checks not done (db_ctr >= MAX_DBs OR fld_ctr EQ INVALID_FLD_CTR) */ /* note that we store field counters and not field ids */ /* Search in write/read list */ for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i ) { if( DbmMaster[db_ctr].WRITE_OPEN_FIELDS[i].fld_ctr EQ fld_ctr ) return DbmMaster[db_ctr].WRITE_OPEN_FIELDS[i].filehandle; } /* for */ /* Search in read only list */ for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i ) { if( DbmMaster[db_ctr].READ_OPEN_FIELDS[i].fld_ctr EQ fld_ctr ) { if( NOT ( open_option & FFS_O_WRONLY ) ) /* if not opened for writing */ { return DbmMaster[db_ctr].READ_OPEN_FIELDS[i].filehandle; } /* we need to reopen it in write mode */ DB_FFS_CLOSE( DbmMaster[db_ctr].READ_OPEN_FIELDS[i].filehandle ); DbmMaster[db_ctr].READ_OPEN_FIELDS[i].filehandle = INVALID_FD; DbmMaster[db_ctr].READ_OPEN_FIELDS[i].fld_ctr = INVALID_FLD_CTR; break; } } /* for */ /* field is not present in both lists */ if( open_option & FFS_O_WRONLY ) { /* for writing and reading both */ tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS; tmp_old = &(DbmMaster[db_ctr].old_write); tmp_max = MAX_OPEN_WRITE_PER_DB; } else { /* for reading only */ tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS; tmp_old = &(DbmMaster[db_ctr].old_read); tmp_max = MAX_OPEN_READ_PER_DB; } /* search the list */ for( i = 0; i < tmp_max; ++i ) { if( tmp_open_fields[i].fld_ctr EQ INVALID_FLD_CTR ) { DB_FFS_OPEN( tmp_open_fields[i].filehandle, user_field_file, open_option ); tmp_open_fields[i].fld_ctr = fld_ctr; return tmp_open_fields[i].filehandle; } } /* for */ /* we need to close the some file for opening this */ if( *tmp_old >= tmp_max ) *tmp_old = 0; DB_FFS_CLOSE( tmp_open_fields[*tmp_old].filehandle ); DB_FFS_OPEN( tmp_open_fields[*tmp_old].filehandle, user_field_file, open_option ); if( tmp_open_fields[*tmp_old].filehandle >= EFFS_OK ) { tmp_open_fields[*tmp_old].fld_ctr = fld_ctr; ++(*tmp_old); return tmp_open_fields[*tmp_old - 1].filehandle; } tmp_open_fields[*tmp_old].fld_ctr = INVALID_FLD_CTR; return tmp_open_fields[*tmp_old].filehandle; } LOCAL void db_close_user_field_files ( UBYTE db_ctr ) { UBYTE i; FileHandleRecord* tmp_open_fields; /* sanity check not done */ /* for write list */ tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS; for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i ) { if( tmp_open_fields[i].fld_ctr NEQ INVALID_FLD_CTR ) { DB_FFS_CLOSE( tmp_open_fields[i].filehandle ); tmp_open_fields[i].filehandle = INVALID_FD; tmp_open_fields[i].fld_ctr = INVALID_FLD_CTR; } } /* for read list */ tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS; for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i ) { if( tmp_open_fields[i].fld_ctr NEQ INVALID_FLD_CTR ) { DB_FFS_CLOSE( tmp_open_fields[i].filehandle ); tmp_open_fields[i].filehandle = INVALID_FD; tmp_open_fields[i].fld_ctr = INVALID_FLD_CTR; } } } LOCAL BOOL db_open_full_for_read ( UBYTE db_ctr ) { UBYTE i; FileHandleRecord* tmp_open_fields; /* sanity check not done */ /* for read list */ tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS; for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i ) { if( tmp_open_fields[i].fld_ctr EQ INVALID_FLD_CTR ) return FALSE; } return TRUE; } LOCAL BOOL db_open_full_for_write ( UBYTE db_ctr ) { UBYTE i; FileHandleRecord* tmp_open_fields; /* sanity check not done */ /* for write list */ tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS; for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i ) { if( tmp_open_fields[i].fld_ctr EQ INVALID_FLD_CTR ) return FALSE; } return TRUE; } LOCAL void db_close_for_read ( UBYTE db_ctr ) { /* Implements Measure # 83 */ db_close_for_read_write (DbmMaster[db_ctr].READ_OPEN_FIELDS, &(DbmMaster[db_ctr].old_read), MAX_OPEN_READ_PER_DB); return; } LOCAL void db_close_for_write ( UBYTE db_ctr ) { /* Implements Measure # 83 */ db_close_for_read_write (DbmMaster[db_ctr].WRITE_OPEN_FIELDS, &(DbmMaster[db_ctr].old_write), MAX_OPEN_WRITE_PER_DB); return; } LOCAL UBYTE db_status_user_field_file ( UBYTE db_ctr, UBYTE fld_ctr ) { UBYTE i; FileHandleRecord* tmp_open_fields; /* sanity check not done */ /* for write list */ tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS; for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i ) { if( tmp_open_fields[i].fld_ctr EQ fld_ctr ) return OPENED_FOR_WRITE; } /* for read list */ tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS; for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i ) { if( tmp_open_fields[i].fld_ctr EQ fld_ctr ) return OPENED_FOR_READ; } return NOT_OPENED; } #endif /* FFS_CLOSE_BEFORE_OPEN */ /* +-----------------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: delete_dir_forced | +-----------------------------------------------------------------------------+ PURPOSE : Removes contents of dir and then delete the dir (it uses recursion) */ LOCAL T_DB_CODE delete_dir_forced ( const char* dir ) { T_FFS_SIZE ffs_ret_code; T_FFS_DIR ffs_dir; /*lint !e813 big var on stack, not true for target */ T_FFS_STAT tmp_ffs_stat; char pathname[FILENAME_LEN]; UBYTE dir_len; /* Open dir, if does not exist, just return DB_OK */ ffs_ret_code = ffs_opendir (dir, &ffs_dir); if( ffs_ret_code EQ EFFS_NOTFOUND ) DB_RETURN( DB_OK ); if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P2( "delete_dir_forced:ffs_remove %d, %s", ffs_ret_code, dir ); LastFFS_ReturnCode = ffs_ret_code; DB_RETURN( DB_FAIL_FS ) } /* read dir recursively */ sprintf( pathname, "%s/", dir ); dir_len = strlen( pathname ); while( 1 ) { /* filename inside the directory would be copied at pathname + dirlen */ ffs_ret_code = ffs_readdir( &ffs_dir, pathname + dir_len, FILENAME_LEN - dir_len - 1 ); if( ffs_ret_code EQ 0 ) /* dir is empty now */ { break; } if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P2( "delete_dir_forced:ffs_readdir:%d, %s", ffs_ret_code, dir ); LastFFS_ReturnCode = ffs_ret_code; DB_RETURN( DB_FAIL_FS ) } ffs_ret_code = ffs_stat( pathname, &tmp_ffs_stat ); if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P2( "delete_dir_forced:ffs_stat:%d, %s", ffs_ret_code, pathname); LastFFS_ReturnCode = ffs_ret_code; DB_RETURN( DB_FAIL_FS ) } if( tmp_ffs_stat.type EQ OT_DIR ) { /* Directory !! */ T_DB_CODE db_code; TRACE_EVENT_P1( "Warning: directory %s", pathname ); /* Recursion */ db_code = delete_dir_forced( pathname ); if( db_code NEQ DB_OK ) DB_RETURN( db_code ); } else { /* normal file (OT_FILE) or symbolic link (OT_LINK) */ ffs_ret_code = ffs_remove( pathname ); if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P2( "delete_dir_forced:ffs_remove:%d, %s", ffs_ret_code, pathname ); LastFFS_ReturnCode = ffs_ret_code; DB_RETURN( DB_FAIL_FS ) } } /* if( tmp_ffs_stat.type EQ OT_DIR ) */ } /* while( 1 ) */ /* now delete the directory */ ffs_ret_code = ffs_remove( dir ); if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P2( "delete_dir_forced:ffs_remove:%d, %s", ffs_ret_code, dir ); LastFFS_ReturnCode = ffs_ret_code; DB_RETURN( DB_FAIL_FS ) } DB_RETURN( DB_OK ) } LOCAL void get_sort_lists_from_FFS ( UBYTE db_ctr, UBYTE fld_ctr ) { UBYTE sort_index_ctr; T_DB_CODE db_ret_code; char sort_file[FILENAME_LEN]; T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr; /* for all existing sort indexes */ for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr ) { /* valid index ? */ if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX ) { /* Check if we already have sorted list in RAM structure SortedLists */ if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] EQ NULL ) { /* If no, populate the sorted list from file, "<DBDirectory>/UD_<field_id>_sort_<sort_index>". Sorted lists are freed in db_flush */ /* Implements Measure#32: Row 1177 */ sprintf( sort_file, format_sUDd_sortd_str, (char *)DbmMaster[db_ctr].DBDirectory, tmp_ptrFieldRecord -> FieldID, tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] ); db_ret_code = populate_sorted_list_from_FFS ( #ifdef FFS_CLOSE_BEFORE_OPEN db_ctr, #endif sort_file, tmp_ptrFieldRecord -> NumOfRecords, &(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr]) ); if( db_ret_code NEQ DB_OK ) { /* Failure, still we can continue as later during actual sorting, FFS would be retried */ TRACE_EVENT( "Warning: populate_sorted_list_from_FFS failed" ); TRACE_EVENT_P3( "db_ctr %d field_id %04X sort_index %d", db_ctr, tmp_ptrFieldRecord -> FieldID, tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] ); continue; } } /* if we have sort list */ } /* if valid index */ } /* for all sort indexes */ return; } LOCAL void new_in_sort_lists ( UBYTE db_ctr, UBYTE fld_ctr, UBYTE record_num ) { UBYTE sort_index_ctr; T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr; /* make a note that this record needs to be sorted */ /* for all existing sort indexes */ for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr ) { if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX ) { /* add it at the end like all sorted records + INVALID RECORD + .... */ tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords] = record_num; } } return; } LOCAL void update_in_sort_lists ( UBYTE db_ctr, UBYTE fld_ctr, UBYTE record_num ) { UBYTE sort_index_ctr, rec_ctr; T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr; /* make a note that this record needs to be sorted */ /* for all existing sort indexes */ for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr ) { if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX ) { /* search entry in sorted records */ rec_ctr = 0; while( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM ) { if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] EQ record_num ) { /* found in sorted records, now delete this entry */ memmove( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr, /* dest */ (const char*)(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr + 1), /* source */ tmp_ptrFieldRecord -> UsedRecords - rec_ctr ); /* size */ tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords] = record_num; break; } ++rec_ctr; } } /* NEQ INVALID_SORT_INDEX */ } /* for sort_index_ctr */ return; } LOCAL void delete_in_sort_lists ( UBYTE db_ctr, UBYTE fld_ctr, UBYTE record_num ) { UBYTE sort_index_ctr, rec_ctr; T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr; /* make a note that this record needs to be sorted */ /* for all existing sort indexes */ for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr ) { if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX ) { /* search entry in sorted records */ rec_ctr = 0; while( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM ) { if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] EQ record_num ) break; ++rec_ctr; } if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM ) { /* found in sorted records, now delete this entry */ memmove( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr, (const char*)(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr + 1), tmp_ptrFieldRecord -> UsedRecords - rec_ctr ); tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords] = INVALID_RECORD_NUM; } else { /* search in UN-sorted records */ ++rec_ctr; while( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM ) { if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] EQ record_num ) { /* delete this entry */ memmove( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr, (const char*)(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr + 1), tmp_ptrFieldRecord -> UsedRecords - rec_ctr ); tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords] = INVALID_RECORD_NUM; break; } ++rec_ctr; } } } /* NEQ INVALID_SORT_INDEX */ } /* for sort_index_ctr */ return; } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: insertion_sort | +--------------------------------------------------------------------+ PURPOSE : Sorts the user data records in FFS based on insertion sort method */ LOCAL void insertion_sort ( UBYTE* sort_list, UBYTE num_of_elements, T_COMP_FUNC compare_function, ULONG flags, int db_handle, USHORT field_id ) { UBYTE rec_ctr; /* sanity check */ if( num_of_elements EQ 0 ) return; if( sort_list[0] EQ INVALID_RECORD_NUM ) { /* This is beginning of new sort list, Let's add first element */ sort_list[0] = sort_list[1]; sort_list[1] = INVALID_RECORD_NUM; } /* So now here we have list something like this { Sorted records } + INVALID_RECORD_NUM + { UNsorted records } */ /* let's get to Unsorted records */ rec_ctr = 1; while( sort_list[rec_ctr] NEQ INVALID_RECORD_NUM ) { ++rec_ctr; } ++rec_ctr; /* rec_ctr is now pointing at UNsorted records */ /* now add UNsorted records one by one */ /* Not required "( sort_list[rec_ctr] NEQ INVALID_RECORD_NUM )", right ? */ while( rec_ctr <= num_of_elements ) { insert_element( sort_list, rec_ctr, /* num_of_elements */ 0, /* bottom */ rec_ctr - 2, /* top */ sort_list[rec_ctr], /* record_num to be inserted */ compare_function, flags, db_handle, field_id ); ++rec_ctr; } /* done ! */ return; } LOCAL void insert_element ( UBYTE* sort_list, UBYTE num_of_elements, UBYTE bottom, UBYTE top, UBYTE record_num, T_COMP_FUNC compare_function, ULONG flags, int db_handle, USHORT field_id ) { UBYTE middle = ( top + bottom ) / 2; /* use binary algorithm to find the right place for insertion */ while( middle NEQ bottom ) { if( compare_function( db_handle, field_id, sort_list[middle], record_num, flags ) < 0 ) { bottom = middle; } else { top = middle; } middle = ( top + bottom ) / 2; } /* while( middle NEQ bottom ) */ if( compare_function( db_handle, field_id, sort_list[bottom], record_num, flags ) < 0 ) { if( compare_function( db_handle, field_id, sort_list[top], record_num, flags ) < 0 ) { /* insert at top + 1 */ memmove( sort_list + top + 2, /* dest */ sort_list + top + 1, /* source */ num_of_elements - (top + 1) ); /* size */ sort_list[top + 1] = record_num; } else { /* insert at bottom + 1 */ memmove( sort_list + bottom + 2, /* dest */ sort_list + bottom + 1, /* source */ num_of_elements - (bottom + 1) ); /* size */ sort_list[bottom + 1] = record_num; } /* if top_th < insert_th */ } else { /* insert at bottom */ memmove( sort_list + bottom + 1, /* dest */ sort_list + bottom, /* source */ num_of_elements - bottom ); /* size */ sort_list[bottom] = record_num; } /* if bottom_th < insert_th */ return; } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: internal_db_sort | +--------------------------------------------------------------------+ PURPOSE : (Internal) Creates or updates a sort index for a given (database, field) */ LOCAL T_DB_CODE internal_db_sort ( int db_handle, USHORT field_id, UBYTE sort_index, T_COMP_FUNC compare_function, ULONG flags ) { UBYTE fld_ctr, sort_index_ctr, remb_sort_index_ctr, record_num; UBYTE* sort_list; UBYTE* copy_sort_list; T_DB_CODE db_ret_code; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; UBYTE* field_data; TRACE_FUNCTION("internal_db_sort()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; /* Check if this is existing sort index */ remb_sort_index_ctr = MAX_NUM_OF_SORT_INDEXS; for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr ) { if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index ) break; if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ INVALID_SORT_INDEX ) remb_sort_index_ctr = sort_index_ctr; } if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS ) { /* ok, this is new index, so Check if limit for sort list corresponding to field_id (for a given database) has reached limit, MAX_NUM_OF_SORT_INDEXS. If so, return DB_FULL. */ if( remb_sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS ) DB_RETURN( DB_FULL ); sort_index_ctr = remb_sort_index_ctr; /* update file , "~/dbm/DD_<db_handle>" for SortIndexes. */ /* create the field data that is to be written */ DB_MALLOC( field_data, MAX_NUM_OF_SORT_INDEXS ); memcpy( field_data, tmp_ptrFieldRecord -> SortIndexList, MAX_NUM_OF_SORT_INDEXS ); field_data[sort_index_ctr] = sort_index; db_ret_code = update_field_data_in_FFS ( &DbmMaster[db_handle].FFSFileHandle, db_handle, fld_ctr, field_data, SortIndexList_OFFSET, MAX_NUM_OF_SORT_INDEXS ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( field_data ); DB_RETURN( db_ret_code ) } DB_MFREE( field_data ); /* updation of DD_<db_handle> is over */ } /* create sort list (if not there) */ if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] NEQ NULL ) { sort_list = tmp_ptrFieldRecord -> SortedLists[sort_index_ctr]; } else { DB_MALLOC( sort_list, tmp_ptrFieldRecord -> NumOfRecords + 1 ); memset( sort_list, INVALID_RECORD_NUM, tmp_ptrFieldRecord -> NumOfRecords + 1 ); /* the first element would be INVALID_RECORD_NUM (0xFF) */ copy_sort_list = sort_list + 1; /* The list of available records is prepared from RecordBitMap */ for (record_num = 1; record_num <= tmp_ptrFieldRecord->NumOfRecords; record_num++) { if (db_get_bit_in_bitmap (tmp_ptrFieldRecord->RecordBitMap, record_num)) { *copy_sort_list++ = record_num; } } } /* sort_list is NULL */ /* Sort the records with given "comparison_function" (it takes record numbers, field_id and db_handle). Note that the sorted list would be kept in RAM (structure SortedLists, part of field record) till db_flush is called and cleared in db_flush. */ insertion_sort( sort_list, tmp_ptrFieldRecord -> UsedRecords, /* only used records */ compare_function, flags, db_handle, field_id ); /* writing sorted list to FFS would be done in db_flush */ /* Update corresponding field SortIndexList in RAM structures. */ tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] = sort_index; tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = sort_list; DB_RETURN( DB_OK ) } /***********************/ /* INTERFACE FUNCTIONS */ /***********************/ /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_init | +--------------------------------------------------------------------+ PURPOSE : Initialises database manager */ void db_init ( void ) { UBYTE db_ctr; #ifdef FFS_CLOSE_BEFORE_OPEN UBYTE fld_ctr; #endif TRACE_FUNCTION("db_init()"); /* 1) Check DBM_State and if already initialized, return DB_OK */ if ( DBM_State EQ DBM_INITIALISED ) return; /* 2) Initialize DbmMaster structure */ for ( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr ) { DbmMaster[db_ctr].DBState = UNUSED_ENTRY; #ifdef FFS_CLOSE_BEFORE_OPEN for( fld_ctr = 0; fld_ctr < MAX_OPEN_READ_PER_DB; ++fld_ctr ) { DbmMaster[db_ctr].READ_OPEN_FIELDS[fld_ctr].fld_ctr = INVALID_FLD_CTR; } for( fld_ctr = 0; fld_ctr < MAX_OPEN_WRITE_PER_DB; ++fld_ctr ) { DbmMaster[db_ctr].WRITE_OPEN_FIELDS[fld_ctr].fld_ctr = INVALID_FLD_CTR; } DbmMaster[db_ctr].old_read = 0; DbmMaster[db_ctr].old_write = 0; #endif } UsedDBs = 0; #ifdef _SIMULATION_ { T_FFS_SIZE ffs_ret_code = ffs_init(); TRACE_EVENT_P1("Initialization of FFS Simulation %d", ffs_ret_code ); /* Delete existing database */ init_RAM_with_FFS(); for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr ) { if( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY ) db_remove( DbmMaster[db_ctr].DBDirectory ); } db_exit(); } #endif return; } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: init_RAM_with_FFS | +--------------------------------------------------------------------+ PURPOSE : Initialise DBM RAM structures with FFS data */ LOCAL T_DB_CODE init_RAM_with_FFS ( void ) { /* Initializing "DBM related data" in RAM from FFS */ T_FFS_FD ffs_dbm_fd; T_FFS_SIZE ffs_ret_code; T_FFS_STAT ffs_status; UBYTE* db_buffer; UBYTE* remb_db_buffer; UBYTE* field_buffer; UBYTE* remb_field_buffer; UBYTE db_ctr, fld_ctr, i; char filename[FILENAME_LEN]; /* Implements Measure#32: Row 1181 */ char* dbm_file = db_master_file; T_DBM_MASTERRECORD *dbm; TRACE_FUNCTION("init_RAM_with_FFS()"); /* Check the presence of FFS directory DB_DIR */ /* Implements Measure#32: Row 1184 */ ffs_ret_code = ffs_stat( db_dir, &ffs_status ); TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_stat %d", ffs_ret_code ); /* error values of ffs_ret_code are handled later */ if( ffs_ret_code >= EFFS_OK ) { /* Directory is present */ /* Synchronize DB related data between FFS and RAM i.e. structures DbmMasterRecord and corresponding DbmFieldRecord. */ /* For DbmMaster */ DB_FFS_OPEN( ffs_dbm_fd, dbm_file, FFS_O_RDONLY ); if( (ffs_dbm_fd EQ EFFS_NAMETOOLONG ) OR (ffs_dbm_fd EQ EFFS_BADNAME ) OR (ffs_dbm_fd EQ EFFS_NOTFOUND ) OR (ffs_dbm_fd EQ EFFS_INVALID ) OR (ffs_dbm_fd EQ EFFS_LOCKED ) ) { TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd ); return DB_FAIL; } if( ffs_dbm_fd < EFFS_OK ) { TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd ); LastFFS_ReturnCode = ffs_dbm_fd; return DB_FAIL_FS; } /* buffer for master records */ DB_MALLOC( db_buffer, T_DB_MASTER_RECORD_SIZE ); remb_db_buffer = db_buffer; for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr ) { dbm = &DbmMaster[db_ctr]; db_buffer = remb_db_buffer; ffs_ret_code = ffs_read( ffs_dbm_fd, db_buffer, T_DB_MASTER_RECORD_SIZE ); if( ( ffs_ret_code EQ EFFS_BADFD ) OR ( ffs_ret_code EQ EFFS_BADOP ) ) { TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_read %d", ffs_ret_code ); DB_FFS_CLOSE( ffs_dbm_fd ); DB_MFREE( db_buffer ); return DB_FAIL; } if( ffs_ret_code EQ 0 ) /* number of bytes read EQ 0 */ break; if( *db_buffer EQ 0xFF ) /* if invalid database */ continue; memcpy( dbm->DBDirectory, db_buffer, MAX_LEN_DIRECTORY ); db_buffer += MAX_LEN_DIRECTORY; dbm->NumOfFiles = *db_buffer++; /* Maximum number of supported fields */ dbm->Clean = TRUE; dbm->Tracked = (*db_buffer++ EQ FFS_TRACKED); dbm->UsedFiles = 0; dbm->DBState = CLOSED; ++UsedDBs; /* we need not "seek" here file pointer would have moved to next */ } DB_FFS_CLOSE( ffs_dbm_fd ); DB_MFREE( remb_db_buffer ); /* freeing db_buffer */ /* For FieldRecords */ /* buffer for field records */ DB_MALLOC( field_buffer, T_DB_FIELD_RECORD_SIZE ); remb_field_buffer = field_buffer; for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr ) { dbm = &DbmMaster[db_ctr]; if( dbm->DBState EQ UNUSED_ENTRY ) continue; /* Field file = DD_<pos. in DD_master> */ /* Implements Measure#32: Row 1182, 1184 */ sprintf( filename, format_sDDd_str, db_dir, db_ctr); DB_FFS_OPEN( ffs_dbm_fd, filename, FFS_O_RDONLY ); if( ( ffs_dbm_fd EQ EFFS_NOTFOUND ) OR /* Field file not found */ ( ffs_dbm_fd EQ EFFS_NUMFD ) OR /* FFS specific errors */ ( ffs_dbm_fd EQ EFFS_LOCKED) ) { TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd ); DB_MFREE( field_buffer ); return DB_FAIL; } /* Allocate memory for field records */ DB_MALLOC( dbm->ptrFieldRecord, dbm->NumOfFiles * sizeof(T_DBM_FIELDRECORD) ); for (fld_ctr = 0; fld_ctr < dbm->NumOfFiles; fld_ctr++) { field_buffer = remb_field_buffer; ffs_ret_code = ffs_read( ffs_dbm_fd, field_buffer, T_DB_FIELD_RECORD_SIZE ); if( (ffs_ret_code EQ EFFS_BADFD ) OR (ffs_ret_code EQ EFFS_BADOP ) ) { TRACE_EVENT_P2( "init_RAM_with_FFS:ffs_read %d, fld_ctr %d", ffs_ret_code, fld_ctr ); DB_FFS_CLOSE ( ffs_dbm_fd ); DB_MFREE( field_buffer ); DB_MFREE( dbm->ptrFieldRecord ); dbm->ptrFieldRecord = NULL; return DB_FAIL; } if( ffs_ret_code < T_DB_FIELD_RECORD_SIZE ) { /* we need not go further, just make rest of field ids as invalid (not existing) */ for( ; fld_ctr < dbm->NumOfFiles; ++fld_ctr ) { dbm->ptrFieldRecord[fld_ctr].FieldID = INVALID_FIELD_ID; } break; } /* Syncing of field records (FFS => RAM) */ dbm->ptrFieldRecord[fld_ctr].FieldID = *field_buffer++; dbm->ptrFieldRecord[fld_ctr].FieldID <<= 8; dbm->ptrFieldRecord[fld_ctr].FieldID |= *field_buffer++; dbm->ptrFieldRecord[fld_ctr].DBType = (T_DB_TYPE)*field_buffer++; dbm->ptrFieldRecord[fld_ctr].RecordSize = *field_buffer++; dbm->ptrFieldRecord[fld_ctr].RecordSize <<= 8; dbm->ptrFieldRecord[fld_ctr].RecordSize |= *field_buffer++; dbm->ptrFieldRecord[fld_ctr].NumOfRecords = *field_buffer++; for (i = 0; i < MAX_NUM_OF_SORT_INDEXS; i++) { dbm->ptrFieldRecord[fld_ctr].SortIndexList[i] = *field_buffer++; dbm->ptrFieldRecord[fld_ctr].SortedLists[i] = NULL; } memcpy (dbm->ptrFieldRecord[fld_ctr].RecordBitMap, field_buffer, RECORD_BITMAP_SIZE); field_buffer += RECORD_BITMAP_SIZE; dbm->ptrFieldRecord[fld_ctr].Clean = *field_buffer++; if ( dbm->ptrFieldRecord[fld_ctr].FieldID NEQ INVALID_FIELD_ID ) { /* * Trace out whether we consider the respective field as not clean. */ if (!dbm->ptrFieldRecord[fld_ctr].Clean) { TRACE_EVENT_P1 ("Field %04X not clean in master file", dbm->ptrFieldRecord[fld_ctr].FieldID); } /* * Consistency check. * Check whether the respective user field exists. * If it does not exist set it to invalid. * We are not taking care about possibly left over sort indexes. * This inconsistency can happen when we got a hard power cycle * during some database updating operation. */ sprintf (filename, "%s/UD_%04X", (char *)dbm->DBDirectory, dbm->ptrFieldRecord[fld_ctr].FieldID); ffs_ret_code = ffs_stat (filename, &ffs_status); if (ffs_ret_code NEQ EFFS_OK) { TRACE_EVENT_P1 ("User data %s not existing in FFS", filename); dbm->ptrFieldRecord[fld_ctr].FieldID = INVALID_FIELD_ID; dbm->Clean = FALSE; /* Mark DB as not clean */ } /* * Consistency check. * Check that the respective user data does not exist twice. * Normally it is expected that this inconsistency should not happen, * if it happens we ignore all subsequent entries. */ if ( dbm->ptrFieldRecord[fld_ctr].FieldID NEQ INVALID_FIELD_ID ) { for (i = 0; i < fld_ctr; i++) { if (dbm->ptrFieldRecord[fld_ctr].FieldID EQ dbm->ptrFieldRecord[i].FieldID) { TRACE_EVENT_P1 ("User data %04x existed twice", dbm->ptrFieldRecord[fld_ctr].FieldID); dbm->ptrFieldRecord[fld_ctr].FieldID = INVALID_FIELD_ID; dbm->ptrFieldRecord[i].Clean = FALSE; /* Don't trust this field */ dbm->Clean = FALSE; /* Mark DB as not clean */ break; } } } /* * Consistency check. * Check whether the sorted index really exists in the FFS. * If it does not exist set it to invalid. */ if ( dbm->ptrFieldRecord[fld_ctr].FieldID NEQ INVALID_FIELD_ID ) { for( i = 0; i < MAX_NUM_OF_SORT_INDEXS; i++ ) { if (dbm->ptrFieldRecord[fld_ctr].SortIndexList[i] NEQ INVALID_SORT_INDEX) { sprintf(filename, "%s/UD_%04X_sort_%d", (char *)dbm->DBDirectory, dbm->ptrFieldRecord[fld_ctr].FieldID, dbm->ptrFieldRecord[fld_ctr].SortIndexList[i]); ffs_ret_code = ffs_stat (filename, &ffs_status); if (ffs_ret_code NEQ EFFS_OK) { TRACE_EVENT_P1 ("Sort index %s not existing in FFS", filename); dbm->ptrFieldRecord[fld_ctr].SortIndexList[i] = INVALID_SORT_INDEX; dbm->ptrFieldRecord[fld_ctr].Clean = FALSE; /* Don't trust this field */ } } } } #ifndef FFS_CLOSE_BEFORE_OPEN tmp_ptrFieldRecord -> FFSFileHandle = INVALID_FD; #endif /* we need to get size of user file <DBDirectory>/UD_<field_id> NextRecordNum = (size of user file) / record size */ dbm->ptrFieldRecord[fld_ctr].NextRecordNum = cal_NextRecordNum ( (const char*)DbmMaster[db_ctr].DBDirectory, dbm->ptrFieldRecord[fld_ctr].FieldID, dbm->ptrFieldRecord[fld_ctr].RecordSize ); /* Update database records for UsedFiles, Clean, and UsedRecords */ dbm->UsedFiles++; /* Mark DB as not clean if only one field is not clean */ if (!dbm->ptrFieldRecord[fld_ctr].Clean) dbm->Clean = FALSE; /* For calculating UsedRecords */ dbm->ptrFieldRecord[fld_ctr].UsedRecords = 0; for (i = 1; i <= dbm->ptrFieldRecord[fld_ctr].NumOfRecords; i++) { if (db_get_bit_in_bitmap (dbm->ptrFieldRecord[fld_ctr].RecordBitMap, i)) dbm->ptrFieldRecord[fld_ctr].UsedRecords++; } } /* FieldID NEQ INVALID_FIELD_ID */ } /* for( fld_ctr ) ... all fields */ /* close the DD_<db_handle> file */ DB_FFS_CLOSE( ffs_dbm_fd ); } /* ffs_ret_code >= EFFS_OK */ DB_MFREE( remb_field_buffer ); /* freeing field buffer */ DBM_State = DBM_INITIALISED; return DB_OK; } /* if( ffs_ret_code >= EFFS_OK ) */ /* Directory not present */ if( ffs_ret_code EQ EFFS_NOTFOUND ) { /* Create DBM directory */ /* Implements Measure#32: Row 1184 */ ffs_ret_code = ffs_mkdir( db_dir ); if( (ffs_ret_code EQ EFFS_NAMETOOLONG ) OR (ffs_ret_code EQ EFFS_BADNAME ) ) { TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_mkdir %d", ffs_ret_code ); return DB_FAIL; } if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_mkdir %d", ffs_ret_code ); LastFFS_ReturnCode = ffs_ret_code; return DB_FAIL_FS; } /* Create empty file DD_master FFS_O_EXCL => Generate error if FFS_O_CREATE is also specified and the file already exists. */ DB_FFS_OPEN( ffs_dbm_fd, dbm_file, FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL ); if( (ffs_dbm_fd EQ EFFS_NAMETOOLONG ) OR (ffs_dbm_fd EQ EFFS_BADNAME ) ) { TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd ); /* Implements Measure#32: Row 1184 */ ffs_ret_code = ffs_remove( db_dir ); /* undo creating of DBM directory */ return DB_FAIL; } if( ffs_dbm_fd < EFFS_OK ) { TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd ); LastFFS_ReturnCode = ffs_dbm_fd; /* Implements Measure#32: Row 1184 */ ffs_ret_code = ffs_remove( db_dir ); /* undo creating of DBM directory */ return DB_FAIL_FS; } DB_FFS_CLOSE( ffs_dbm_fd ); DBM_State = DBM_INITIALISED; return DB_OK; } /* Unexpected error: Not a directory */ return DB_FAIL; } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_create | +--------------------------------------------------------------------+ PURPOSE : Create a new database in the given directory of the FFS. The directory must not to exist yet, it will be created. */ int db_create ( const char* directory, UBYTE num_of_fields, BOOL tracked ) { int db_handle; T_DB_CODE db_ret_code; UBYTE fld_ctr; S8 db_ctr; T_FFS_SIZE ffs_ret_code; T_FFS_FD ffs_fd; char field_file[FILENAME_LEN]; char* field_file_ptr = field_file; UBYTE* dbm_data; UBYTE* remb_dbm_data; TRACE_FUNCTION("db_create()"); /* If DBM is not in initialized state, call init_RAM_with_FFS (). */ if( DBM_State NEQ DBM_INITIALISED ) { T_DB_CODE db_ret_code; db_ret_code = init_RAM_with_FFS(); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); } /* See if you have reached the maximum number of DBs, ? (UsedDBs+1) > MAX_DBs */ if( UsedDBs EQ MAX_DBs ) DB_RETURN( DB_FULL ); /* Check DbmMaster if already database for "directory" exists. If yes, return error "DB_EXISTS" */ db_handle = -1; for( db_ctr = (MAX_DBs - 1); db_ctr >= 0; --db_ctr ) { if ( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY ) { if( memcmp( DbmMaster[db_ctr].DBDirectory, directory, strlen( directory ) ) EQ 0 ) DB_RETURN( DB_EXISTS ) } else { db_handle = db_ctr; } } /* sanity check */ if( num_of_fields <= 0 ) /*lint !e775 check for <= on non-negative*/ DB_RETURN( DB_FAIL ); if (db_handle EQ -1) { /* No free slot found */ DB_RETURN ( DB_FAIL ) /* DB_FULL maybe better choice */ } /* Create a directory, "<DBDirectory>" (DBDirectory = directory) */ ffs_ret_code = ffs_mkdir( directory ); if( ffs_ret_code < EFFS_OK ) { TRACE_EVENT_P1( "db_create:ffs_mkdir %d", ffs_ret_code ); LastFFS_ReturnCode = ffs_ret_code; DB_RETURN( DB_FAIL_FS ) } /* Create a empty file, "~/dbm/DD_<position in DD_master = db_handle>"; if this FFS operation fails, we need to delete the directory before returning error. */ /* Implements Measure#32: Row 1182, 1191 */ sprintf( field_file, format_sDDd_str, db_dir, db_handle); TRACE_EVENT_P1( "field_file %s", field_file ); /* FFS_O_EXCL => Generate error if FFS_O_CREATE is also specified and the file already exists. */ DB_FFS_OPEN( ffs_fd, field_file_ptr, FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL ); if( ( ffs_fd EQ EFFS_EXISTS ) OR ( ffs_fd EQ EFFS_NAMETOOLONG ) OR ( ffs_fd EQ EFFS_BADNAME ) OR ( ffs_fd EQ EFFS_INVALID ) ) { TRACE_EVENT_P1( "db_create:DB_FFS_OPEN %d", ffs_fd ); ffs_fd = ffs_remove( directory ); DB_RETURN( DB_FAIL ) } if( ffs_fd < EFFS_OK ) { TRACE_EVENT_P1( "db_create:DB_FFS_OPEN %d", ffs_fd ); LastFFS_ReturnCode = ffs_fd; ffs_ret_code = ffs_remove( directory ); DB_RETURN( DB_FAIL_FS ) } /* DB_FFS_CLOSE( ffs_fd ); we will close it in db_flush */ #ifdef FFS_OPEN_PROBLEM_PATCH DB_FFS_CLOSE( ffs_fd ); ffs_fd = INVALID_FD; #endif #ifdef FFS_CLOSE_BEFORE_OPEN /* no we do not close it */ #endif /* Update FFS data i.e. file, "~/dbm/DD_master". */ /* prepare the dbm data and write */ DB_MALLOC( dbm_data, T_DB_MASTER_RECORD_SIZE ); memset( dbm_data, 0, T_DB_MASTER_RECORD_SIZE ); remb_dbm_data = dbm_data; memcpy( dbm_data, directory, MAX_LEN_DIRECTORY ); dbm_data += MAX_LEN_DIRECTORY; *dbm_data++ = num_of_fields; *dbm_data++ = ( tracked ) ? FFS_TRACKED : FFS_NOT_TRACKED; dbm_data = remb_dbm_data; /* Implements Measure#32: Row 1188 */ db_ret_code = update_dbm_data_in_FFS ( db_master_file, (UBYTE) db_handle, /* to supress warning */ T_DB_MASTER_RECORD_SIZE, dbm_data, 0, T_DB_MASTER_RECORD_SIZE ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( dbm_data ); ffs_ret_code = ffs_remove( directory ); DB_FFS_CLOSE( ffs_fd ); ffs_ret_code = ffs_remove( field_file ); DB_RETURN( db_ret_code ) } DB_MFREE( dbm_data ); /* updation of DD_master done now update RAM structures */ memcpy( DbmMaster[db_handle].DBDirectory, directory, strlen(directory) ); DbmMaster[db_handle].NumOfFiles = num_of_fields; DbmMaster[db_handle].UsedFiles = 0; DbmMaster[db_handle].Clean = TRUE; DbmMaster[db_handle].Tracked = tracked; DbmMaster[db_handle].DBState = OPEN; DbmMaster[db_handle].FFSFileHandle = ffs_fd; #ifdef FFS_CLOSE_BEFORE_OPEN /* No files corresponding to fields have been opened This initialization is already done in db_init */ #endif /* Allocate memory for storing field information and initialize the memory with "FF" */ DB_MALLOC( DbmMaster[db_handle].ptrFieldRecord, num_of_fields * sizeof(T_DBM_FIELDRECORD) ); for( fld_ctr = 0; fld_ctr < num_of_fields; ++fld_ctr ) { DbmMaster[db_handle].ptrFieldRecord[fld_ctr].FieldID = INVALID_FIELD_ID; } UsedDBs++; DB_RETURN( db_handle ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_open | +--------------------------------------------------------------------+ PURPOSE : Open an existing database */ int db_open ( const char *directory ) { T_DB_CODE db_ret_code; UBYTE db_ctr; TRACE_FUNCTION("db_open()"); /* If DBM is not in initialized state, call init_RAM_with_FFS (). */ if( DBM_State NEQ DBM_INITIALISED ) { db_ret_code = init_RAM_with_FFS(); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); } /* Search for "directory" in DbmMaster */ for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr ) { if( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY ) { if( memcmp( DbmMaster[db_ctr].DBDirectory, directory, strlen(directory) ) EQ 0 ) break; } } /* If "directory" not found, return DB_FAIL. */ if( db_ctr EQ MAX_DBs ) DB_RETURN( DB_INVALID_DB ); /* Update DBState as "OPEN". */ DbmMaster[db_ctr].DBState = OPEN; /* Return corresponding DBHandle. */ DB_RETURN( db_ctr ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_create_field | +--------------------------------------------------------------------+ PURPOSE : Create a new elementary file of a given type with a given numeric identifier and a given record size. */ T_DB_CODE db_create_field ( int db_handle, T_DB_TYPE db_type, USHORT field_id, USHORT record_size, USHORT num_of_records ) { T_DB_CODE db_ret_code; char user_field_file[FILENAME_LEN]; UBYTE fld_ctr, sort_index_ctr; T_FFS_FD ffs_fd_user_field_file; UBYTE* field_data; UBYTE* remb_field_data; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; TRACE_FUNCTION("db_create_field()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field id found, return error DB_FIELD_EXISTS */ if( field_id_search( db_handle, field_id ) NEQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_FIELD_EXISTS ); /* If limit for number of fields for this DB has been reached, return error DB_FULL. */ if( DbmMaster[db_handle].UsedFiles EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_FULL ); /* Search for free field entry in field records corresponding to the database. */ for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr ) { if( DbmMaster[db_handle].ptrFieldRecord[fld_ctr].FieldID EQ INVALID_FIELD_ID ) break; } if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) { /* this is "inconsistency"; should never happen */ DB_RETURN( DB_FAIL ) } /* sanity check */ /*lint -e{775} check for <= on non-negative */ if ((num_of_records <= 0) OR (record_size <= 0)) { DB_RETURN( DB_FAIL ) } /* Create file "<DBDirectory>/UD_<field_id>" */ /* Implements Measure#32: Row 1189 */ sprintf( user_field_file, format_sUDd_str, (char *)DbmMaster[db_handle].DBDirectory, field_id ); /* FFS_O_EXCL => Generate error if FFS_O_CREATE is also specified and the file already exists. */ #ifndef FFS_CLOSE_BEFORE_OPEN DB_FFS_OPEN( ffs_fd_user_field_file, user_field_file, FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL ); #else ffs_fd_user_field_file = db_open_user_field_file( db_handle, fld_ctr, user_field_file, FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL ); #endif if( ( ffs_fd_user_field_file EQ EFFS_EXISTS ) OR ( ffs_fd_user_field_file EQ EFFS_NAMETOOLONG ) OR ( ffs_fd_user_field_file EQ EFFS_BADNAME ) OR ( ffs_fd_user_field_file EQ EFFS_INVALID ) ) { TRACE_EVENT_P1( "db_create_field:DB_FFS_OPEN %d", ffs_fd_user_field_file ); DB_RETURN( DB_FAIL ) } if( ffs_fd_user_field_file < EFFS_OK ) { TRACE_EVENT_P1( "db_create_field:DB_FFS_OPEN %d", ffs_fd_user_field_file ); LastFFS_ReturnCode = ffs_fd_user_field_file; DB_RETURN( DB_FAIL_FS ) } /* We will close this file in db_flush */ #ifdef FFS_OPEN_PROBLEM_PATCH DB_FFS_CLOSE( ffs_fd_user_field_file ); ffs_fd_user_field_file = INVALID_FD; #endif /* file "<DBDirectory>/UD_<field_id>" has been created Now, Add new field entry in "~/dbm/DD_<db_handle>" */ /* create the field data that needs to be written */ DB_MALLOC( field_data, T_DB_FIELD_RECORD_SIZE ); memset( field_data, 0, T_DB_FIELD_RECORD_SIZE ); remb_field_data = field_data; *field_data = (UBYTE) ( (field_id & 0xFF00) >> 8 ); ++field_data; *field_data = (UBYTE) (field_id & 0x00FF); ++field_data; *field_data = db_type; ++field_data; *field_data = (UBYTE) ( (record_size & 0xFF00) >> 8 ); ++field_data; *field_data = (UBYTE) (record_size & 0x00FF); ++field_data; *field_data = (UBYTE)num_of_records; field_data++; memset( field_data, 0xFF, MAX_NUM_OF_SORT_INDEXS ); field_data += MAX_NUM_OF_SORT_INDEXS; memset( field_data, 0, RECORD_BITMAP_SIZE ); field_data += RECORD_BITMAP_SIZE; *field_data = FFS_CLEAN; field_data = remb_field_data; db_ret_code = update_field_data_in_FFS ( &DbmMaster[db_handle].FFSFileHandle, db_handle, fld_ctr, field_data, 0, T_DB_FIELD_RECORD_SIZE ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( field_data ); ffs_remove( user_field_file ); DB_RETURN( db_ret_code ) } DB_MFREE( field_data ); /* updation of DD_<db_handle> is over */ /* Add new field entry in field records in RAM. */ tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; tmp_ptrFieldRecord -> FieldID = field_id; tmp_ptrFieldRecord -> DBType = db_type; tmp_ptrFieldRecord -> RecordSize = record_size; tmp_ptrFieldRecord -> NumOfRecords = (UBYTE)num_of_records; tmp_ptrFieldRecord -> UsedRecords = 0; tmp_ptrFieldRecord -> Clean = TRUE; #ifndef FFS_CLOSE_BEFORE_OPEN tmp_ptrFieldRecord -> FFSFileHandle = ffs_fd_user_field_file; #endif tmp_ptrFieldRecord -> NextRecordNum = 1; memset( tmp_ptrFieldRecord -> RecordBitMap, 0, RECORD_BITMAP_SIZE ); for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr ) { tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] = INVALID_SORT_INDEX; tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = NULL; } /* Increment UsedFiles for the particular database in RAM */ DbmMaster[db_handle].UsedFiles += 1; /* everyting ok */ DB_RETURN( DB_OK ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_write_record | +--------------------------------------------------------------------+ PURPOSE : Write length bytes at offset into the given record in (database, field) */ int db_write_record ( int db_handle, USHORT field_id, USHORT record_num, USHORT offset, USHORT length, const UBYTE* buffer ) { T_DB_CODE db_ret_code; UBYTE fld_ctr, rec_ctr; char user_field_file[FILENAME_LEN]; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; UBYTE* record_buffer; UBYTE* field_data; BOOL this_is_new_record = TRUE; TRACE_FUNCTION("db_write_record()"); TRACE_EVENT_P1("field_id %04X", field_id); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; /* Check if record exceeds the record size (i.e. offset + length > record size); if it exceeds, return error DB_INVALID_SIZE */ if( (offset + length) > tmp_ptrFieldRecord -> RecordSize ) DB_RETURN( DB_INVALID_SIZE ); /* Check if FFS file is already opened using FFSFileHandle, part of field record. If it is not yet opened, open the FFS file and update FFSFileHandle. This is taken care in read_user_record_from_FFS */ /* User data file name is "<DBDirectory>/UD_<field_id>" This would be used below */ /* Implements Measure#32: Row 1200 */ sprintf( user_field_file, format_sUDd_str, (char *)DbmMaster[db_handle].DBDirectory, tmp_ptrFieldRecord -> FieldID ); if( record_num EQ 0 ) { /* If given record is equal to zero, o Find a free record using RecordBitMap. o If free record not found, return DB_FULL */ record_num = db_search_bit_in_bitmap (tmp_ptrFieldRecord->RecordBitMap, tmp_ptrFieldRecord->NumOfRecords, FALSE); if (record_num EQ 0) DB_RETURN( DB_FULL ); } else { /* If given record is not equal to zero, o Check if record exists using RecordBitMap; if not found, proceed to writing.. o Read the record from "<DBDirectory>/UD_<field_id>" and compare it with given record (partially if offset > 0). Memcmp would be used. o If record match, return DB_OK. */ if (db_get_bit_in_bitmap (tmp_ptrFieldRecord->RecordBitMap, record_num)) { /* record exists */ this_is_new_record = FALSE; DB_MALLOC( record_buffer, length); /* Implements Measure # 211 */ db_ret_code = read_write_user_record_from_FFS ( user_field_file, #ifndef FFS_CLOSE_BEFORE_OPEN &(tmp_ptrFieldRecord -> FFSFileHandle), #else db_handle, fld_ctr, &Dummy_FFSFileHandle, #endif (UBYTE)record_num, tmp_ptrFieldRecord -> RecordSize, offset, length, record_buffer, FFS_O_RDONLY ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( record_buffer ); DB_RETURN( db_ret_code ) } /* See if there is same data, if so, we need not overwrite */ if( memcmp( record_buffer, buffer, length) EQ 0 ) { /* matching data */ DB_MFREE( record_buffer ); DB_RETURN( DB_OK ) } DB_MFREE( record_buffer ); } /* record exists */ } /* record_num EQ 0 ? */ /* As per the request, write record in FFS in "<DBDirectory>/UD_<field_id>" */ /* in case of new record, we need to create fill unfilled-data with FF */ if( this_is_new_record ) { /* new record */ DB_MALLOC( record_buffer, tmp_ptrFieldRecord -> RecordSize ); memset( record_buffer, 0xFF, tmp_ptrFieldRecord -> RecordSize ) ; /* To take care of non-sequential write For example, initially when file is empty, and say user writes 3rd record, 1st and 2nd record should be addded as dummy and then 3rd record */ rec_ctr = tmp_ptrFieldRecord -> NextRecordNum; while( rec_ctr < record_num ) { /* Implements Measure # 211 */ db_ret_code = read_write_user_record_from_FFS ( user_field_file, #ifndef FFS_CLOSE_BEFORE_OPEN &(tmp_ptrFieldRecord -> FFSFileHandle), #else db_handle, fld_ctr, &Dummy_FFSFileHandle, #endif rec_ctr, tmp_ptrFieldRecord -> RecordSize, 0, tmp_ptrFieldRecord -> RecordSize, record_buffer, FFS_O_RDWR ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( record_buffer ); DB_RETURN( db_ret_code ) } ++rec_ctr; } /* Add the new record */ memcpy( record_buffer + offset, buffer, length ); /* Implements Measure # 211 */ db_ret_code = read_write_user_record_from_FFS ( user_field_file, #ifndef FFS_CLOSE_BEFORE_OPEN &(tmp_ptrFieldRecord -> FFSFileHandle), #else db_handle, fld_ctr, &Dummy_FFSFileHandle, #endif (UBYTE)record_num, tmp_ptrFieldRecord -> RecordSize, 0, tmp_ptrFieldRecord -> RecordSize, record_buffer, FFS_O_RDWR ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( record_buffer ); DB_RETURN( db_ret_code ) } DB_MFREE( record_buffer ); /* writing of record is over, update DBState (as IN_USE). */ DbmMaster[db_handle].DBState = IN_USE; } else { /* overwritten record */ /* Implements Measure # 211 */ db_ret_code = read_write_user_record_from_FFS ( user_field_file, #ifndef FFS_CLOSE_BEFORE_OPEN &(tmp_ptrFieldRecord -> FFSFileHandle), #else db_handle, fld_ctr, &Dummy_FFSFileHandle, #endif (UBYTE)record_num, tmp_ptrFieldRecord -> RecordSize, offset, length, (UBYTE*)buffer, FFS_O_RDWR ); if( db_ret_code NEQ DB_OK ) { DB_RETURN( db_ret_code ) } /* writing of record is over, update DBState (as IN_USE). */ DbmMaster[db_handle].DBState = IN_USE; /* get the sort lists in RAM from FFS */ get_sort_lists_from_FFS( (UBYTE)db_handle, fld_ctr ); /* this is updation of record, so need to be re-sorted */ update_in_sort_lists( (UBYTE)db_handle, fld_ctr, (UBYTE)record_num ); /* if database is not tracked, no need to go further for history log writing */ if (!DbmMaster[db_handle].Tracked) DB_VALUE_RETURN( record_num ); /* if already Clean has been reset, only history updation */ if (!DbmMaster[db_handle].Clean) { db_ret_code = update_history_log( db_handle, field_id, record_num ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); DB_VALUE_RETURN( record_num ) } } /* this_is_new_record */ /* Updating RecordBitMap and Clean in FFS, ~/dbm/DD_<db_handle> */ /* create the field data that is to be written */ DB_MALLOC( field_data, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); memset( field_data, 0, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); memcpy( field_data, tmp_ptrFieldRecord -> RecordBitMap, RECORD_BITMAP_SIZE ); if( this_is_new_record ) { /* RecordBitMap to be updated only for new records */ db_set_bit_in_bitmap (field_data, record_num, TRUE); } /* clean is reset in memset, so no processing for it (in case of non-tracked database, anyway we ignore it ! */ db_ret_code = update_field_data_in_FFS ( &DbmMaster[db_handle].FFSFileHandle, db_handle, fld_ctr, field_data, RecordBitMap_OFFSET, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( field_data ); DB_RETURN( db_ret_code ) } DB_MFREE( field_data ); /* updation of DD_<db_handle> is over */ /* Updating RAM (both DbmMaster and Field records) strctures */ tmp_ptrFieldRecord->Clean = FALSE; if( this_is_new_record ) { /* RecordBitMap to be updated only for new records */ db_set_bit_in_bitmap (tmp_ptrFieldRecord->RecordBitMap, record_num, TRUE); ++tmp_ptrFieldRecord -> UsedRecords; tmp_ptrFieldRecord -> NextRecordNum = ( (record_num + 1) > tmp_ptrFieldRecord -> NextRecordNum ) ? (record_num + 1) : tmp_ptrFieldRecord -> NextRecordNum ; /* get the sort lists in RAM from FFS */ get_sort_lists_from_FFS( (UBYTE)db_handle, fld_ctr ); /* note the record number for sorting later yeah, we call it *after* updating UsedRecords */ new_in_sort_lists( (UBYTE)db_handle, fld_ctr, (UBYTE)record_num ); } DbmMaster[db_handle].Clean = FALSE; /* history log updation */ db_ret_code = update_history_log( db_handle, field_id, record_num ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); DB_VALUE_RETURN( record_num ) } int db_update_ext_bitmap(int db_handle, USHORT field_id, USHORT record_num, BOOL flag) { T_DB_CODE db_ret_code; UBYTE fld_ctr; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; UBYTE* record_buffer; UBYTE* field_data; BOOL this_is_new_record = TRUE; TRACE_FUNCTION("db_update_ext_bimap()"); /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; /* Updating RecordBitMap and Clean in FFS, DD_<db_handle> */ /* create the field data that is to be written */ DB_MALLOC( field_data, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); memset( field_data, 0, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); memcpy( field_data, tmp_ptrFieldRecord -> RecordBitMap, RECORD_BITMAP_SIZE ); /* RecordBitMap to be updated only for new records */ db_set_bit_in_bitmap (field_data, record_num, flag); /* clean is reset in memset, so no processing for it (in case of non-tracked database, anyway we ignore it ! */ db_ret_code = update_field_data_in_FFS ( &DbmMaster[db_handle].FFSFileHandle, db_handle, fld_ctr, field_data, RecordBitMap_OFFSET, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( field_data ); DB_RETURN( db_ret_code ) } DB_MFREE( field_data ); /* RecordBitMap to be updated only for new records */ db_set_bit_in_bitmap (tmp_ptrFieldRecord->RecordBitMap, record_num, flag); ++tmp_ptrFieldRecord -> UsedRecords; tmp_ptrFieldRecord -> NextRecordNum = ( (record_num + 1) > tmp_ptrFieldRecord -> NextRecordNum ) ? (record_num + 1) : tmp_ptrFieldRecord -> NextRecordNum ; DB_VALUE_RETURN( record_num ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | PURPOSE : Creates or updates a sort index for a given (database, field) */ T_DB_CODE db_create_index ( int db_handle, USHORT field_id, UBYTE sort_index, T_COMP_FUNC compare_function, ULONG flags ) { return internal_db_sort( db_handle, field_id, sort_index, compare_function, flags ); } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_update_index | +--------------------------------------------------------------------+ PURPOSE : Sort the list for newly added/deleted records (uses incremental sort i.e. add the element at the right place) */ T_DB_CODE db_update_index ( int db_handle, USHORT field_id, UBYTE sort_index, T_COMP_FUNC compare_function, ULONG flags ) { return internal_db_sort( db_handle, field_id, sort_index, compare_function, flags ); } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_get_phy_from_idx | +--------------------------------------------------------------------+ PURPOSE : Translates a logical entry within a given sort index to the physical record number */ T_DB_CODE db_get_phy_from_idx ( int db_handle, USHORT field_id, UBYTE sort_index, USHORT order_num ) { T_DB_CODE db_ret_code; UBYTE fld_ctr, sort_index_ctr; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; char sort_file[FILENAME_LEN]; TRACE_FUNCTION("db_get_phy_from_idx()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; /* sanity check on order_num */ if( ( order_num > tmp_ptrFieldRecord -> NumOfRecords ) OR ( order_num EQ 0 ) ) DB_RETURN( DB_FAIL ); /* may be we can return 0xFF => no record for it ! */ /* Search given sort_index in SortIndexList for above field_id; if not found, return DB_INVALID_INDEX. */ for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr ) { if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index ) break; } if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS ) DB_RETURN( DB_INVALID_INDEX ); /* Check if we already have sorted list in RAM structure SortedLists */ if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] EQ NULL ) { /* If no, populate the sorted list from file, "<DBDirectory>/UD_<field_id>_sort_<sort_index>". Sorted lists are freed in db_flush */ /* Implements Measure#32: Row 1177 */ sprintf( sort_file, format_sUDd_sortd_str, (char *)DbmMaster[db_handle].DBDirectory, tmp_ptrFieldRecord -> FieldID, sort_index ); db_ret_code = populate_sorted_list_from_FFS ( #ifdef FFS_CLOSE_BEFORE_OPEN db_handle, #endif sort_file, tmp_ptrFieldRecord -> NumOfRecords, &(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr]) ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); } /* if we have sort list */ /* Get (physical) record number for given order_num from sorted list. */ DB_VALUE_RETURN((T_DB_CODE)tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][order_num - 1] ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_flush | +--------------------------------------------------------------------+ PURPOSE : Flush all internal data structures of the database described by db_handle */ T_DB_CODE db_flush ( int db_handle) { T_DB_CODE db_ret_code; UBYTE clean_byte, /* Coded as in the FFS */ fld_ctr, i; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; char sort_file[FILENAME_LEN]; T_FFS_STAT ffs_file_stat; T_FFS_SIZE ffs_ret_code; TRACE_FUNCTION("db_flush()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* Clear "clean" in "~/dbm/DD_<db_handle>" for fields. after ffs updation, update RAM data */ clean_byte = FFS_CLEAN; /* Update the affected field records */ #ifdef FFS_CLOSE_BEFORE_OPEN db_close_user_field_files( db_handle ); #endif tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord; for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr ) { if( tmp_ptrFieldRecord -> FieldID EQ INVALID_FIELD_ID ) /* if not valid field id */ { ++tmp_ptrFieldRecord; /* next field */ continue; } /* Clear file handles */ #ifndef FFS_CLOSE_BEFORE_OPEN if (IS_FD_VALID(tmp_ptrFieldRecord->FFSFileHandle)) { DB_FFS_CLOSE( tmp_ptrFieldRecord -> FFSFileHandle ); tmp_ptrFieldRecord -> FFSFileHandle = INVALID_FD; } #else /* Done it closing before for loop */ #endif /* Write sort lists to FFS and clear (free memory) sort lists */ for( i = 0; i < MAX_NUM_OF_SORT_INDEXS; ++i ) { if( tmp_ptrFieldRecord -> SortedLists[i] NEQ NULL ) { /* currently I am not removing unused entries in sort list */ /* Write sorted lists to "<DBDirectory>/UD_<field_id>_sort_<sort_index>". */ /* Implements Measure#32: Row 1193 */ sprintf( sort_file, format_sUDd_sortd_str, (char *)DbmMaster[db_handle].DBDirectory, tmp_ptrFieldRecord -> FieldID, tmp_ptrFieldRecord -> SortIndexList[i] ); /* writing sorted lists to FFS s required in two cases 1) the field is not clean and/or 2) sort file does not exist, but we have sort list (happen during bootup time with zero records) */ ffs_ret_code = ffs_stat( sort_file, &ffs_file_stat ); if( ( ffs_ret_code NEQ EFFS_OK ) AND ( ffs_ret_code NEQ EFFS_NOTFOUND ) ) { LastFFS_ReturnCode = ffs_ret_code; DB_MFREE( tmp_ptrFieldRecord -> SortedLists[i] ); tmp_ptrFieldRecord -> SortedLists[i] = NULL; DB_RETURN( DB_FAIL_FS ) } if( ( NOT tmp_ptrFieldRecord -> Clean ) OR /* not clean (consistent) */ ( ffs_ret_code EQ EFFS_NOTFOUND ) ) /* file does not exist */ { db_ret_code = write_sorted_list_to_FFS ( #ifdef FFS_CLOSE_BEFORE_OPEN db_handle, #endif sort_file, tmp_ptrFieldRecord -> NumOfRecords, tmp_ptrFieldRecord -> SortedLists[i] ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( tmp_ptrFieldRecord -> SortedLists[i] ); tmp_ptrFieldRecord -> SortedLists[i] = NULL; DB_RETURN( db_ret_code ) } } /* writing in sort file is over */ DB_MFREE( tmp_ptrFieldRecord -> SortedLists[i] ); tmp_ptrFieldRecord -> SortedLists[i] = NULL; } } if( tmp_ptrFieldRecord -> Clean ) /* is it clean (consistent) ? */ { ++tmp_ptrFieldRecord; /* next field */ continue; } /* Clear "clean" in "~/dbm/DD_<db_handle>" if not clean */ db_ret_code = update_field_data_in_FFS ( &DbmMaster[db_handle].FFSFileHandle, db_handle, fld_ctr, &clean_byte, ( T_DB_FIELD_RECORD_SIZE - 1 ), 1 ); /* "Clean" contained in last one byte */ if( db_ret_code NEQ DB_OK ) { /* this leaves out FFS and RAM in consistent state, this is ok since FFS is in correct state for some of fields ! */ DB_RETURN( db_ret_code ) } tmp_ptrFieldRecord->Clean = TRUE; ++tmp_ptrFieldRecord; /* next field */ } /* for all field records */ if (IS_FD_VALID(DbmMaster[db_handle].FFSFileHandle)) { DB_FFS_CLOSE( DbmMaster[db_handle].FFSFileHandle ); DbmMaster[db_handle].FFSFileHandle = INVALID_FD; } /* updation of FFS is over */ /* Update corresponding "clean" field for database in RAM data structures, also DBState = OPEN */ DbmMaster[db_handle].Clean = TRUE; DbmMaster[db_handle].DBState = OPEN; /* done */ DB_RETURN( DB_OK ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_search | +--------------------------------------------------------------------+ PURPOSE : Searches for an entry within a given database and a given file */ int db_search ( int db_handle, USHORT field_id, UBYTE sort_index, SHORT* order_num, T_SEARCH_FUNC search_function, ULONG flags, const UBYTE* search_tag ) { T_DB_CODE db_ret_code; UBYTE fld_ctr, sort_index_ctr; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; char sort_file[FILENAME_LEN]; int record_num = 0, index_num ; TRACE_FUNCTION("db_search()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; if( sort_index EQ 0 ) { /* If sort_index is zero, o Do linear search using RecordBitMap, search/comparison function is given by caller. o If search is successful, return the record number. o Otherwise return DB_RECORD_NOT_FOUND. */ /* Sanity check */ if( (*order_num) > tmp_ptrFieldRecord -> NumOfRecords ) DB_RETURN( DB_FAIL ); /* search from next record, search_node->top would be zero for fresh search */ for (record_num = *order_num + 1; record_num <= tmp_ptrFieldRecord->NumOfRecords; record_num++) { if (db_get_bit_in_bitmap (tmp_ptrFieldRecord->RecordBitMap, record_num)) { /* ok, this is a valid record */ if( search_function( flags, search_tag, db_handle, field_id, (UBYTE)record_num ) EQ 0 ) /* yeah, "EQ 0" is success */ { /* found it ! */ *order_num = record_num; /* for next search */ DB_VALUE_RETURN( record_num ) } } } /* for bytes in bitmap */ /* record not found */ DB_RETURN( DB_RECORD_NOT_FOUND ) } /* If sort_index is not zero, search using sorted list */ else { /* Search given sort_index in SortIndexList for above field_id; if not found, return DB_INVALID_INDEX. */ for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr ) { if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index ) break; } if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS ) DB_RETURN( DB_INVALID_INDEX ); if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] EQ NULL ) { /* If no, populate the sorted list from file, "<DBDirectory>/UD_<field_id>_sort_<sort_index>". Sorted lists are freed in db_flush */ /* Implements Measure#32: Row 1193 */ sprintf( sort_file, format_sUDd_sortd_str, (char *)DbmMaster[db_handle].DBDirectory, tmp_ptrFieldRecord -> FieldID, sort_index ); db_ret_code = populate_sorted_list_from_FFS ( #ifdef FFS_CLOSE_BEFORE_OPEN db_handle, #endif sort_file, tmp_ptrFieldRecord -> NumOfRecords, &(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr]) ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); } /* (Binary) search the sorted list, search/compare function is given by caller. o If search is successful, return the record number. o Otherwise return DB_RECORD_NOT_FOUND */ index_num = db_binary_search( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr], tmp_ptrFieldRecord -> UsedRecords, order_num, search_function, flags, search_tag, db_handle, field_id ); if( index_num EQ SEARCH_FAILED ) DB_RETURN( DB_RECORD_NOT_FOUND ); DB_VALUE_RETURN( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][index_num - 1] ) } } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_delete_record | +--------------------------------------------------------------------+ PURPOSE : Delete a record in the given field of the given database */ T_DB_CODE db_delete_record ( int db_handle, USHORT field_id, USHORT record_num ) { T_DB_CODE db_ret_code; UBYTE fld_ctr; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; UBYTE* field_data; TRACE_FUNCTION("db_delete_record()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; /* Using RecordBitMap, check whether record_num exists; if it does not exist, return DB_OK. */ if (!db_get_bit_in_bitmap (tmp_ptrFieldRecord->RecordBitMap, record_num)) { /* if record does *not* exist */ DB_RETURN( DB_OK ) } /* Update "Clean" and "RecordBitMap" fields in "~/dbm/DD_<db_handle>" */ /* create the field data that is to be written */ DB_MALLOC( field_data, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); memset( field_data, 0, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); memcpy( field_data, tmp_ptrFieldRecord -> RecordBitMap, RECORD_BITMAP_SIZE ); /* updating RecordBitMap */ db_set_bit_in_bitmap (field_data, record_num, FALSE); /* clean is reset in memset, so no processing for it (in case of non-tracked database, anyway we ignore it ! */ db_ret_code = update_field_data_in_FFS ( &DbmMaster[db_handle].FFSFileHandle, db_handle, fld_ctr, field_data, RecordBitMap_OFFSET, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( field_data ); DB_RETURN( db_ret_code ) } DB_MFREE( field_data ); /* updation of DD_<db_handle> is over */ /* Update corresponding "Clean" and "RecordBitMap" fields in RAM data structures, also update DBState (as IN_USE) and decrement UsedRecords. */ tmp_ptrFieldRecord->Clean = FALSE; /* updating RecordBitMap */ db_set_bit_in_bitmap (tmp_ptrFieldRecord->RecordBitMap, record_num, FALSE); /* get the sort lists in RAM from FFS */ get_sort_lists_from_FFS( (UBYTE)db_handle, fld_ctr ); /* delete in available sort lists yeah, we call it *before* updating UsedRecords */ delete_in_sort_lists( (UBYTE)db_handle, fld_ctr, (UBYTE)record_num ); --tmp_ptrFieldRecord -> UsedRecords; DbmMaster[db_handle].Clean = FALSE; DbmMaster[db_handle].DBState = IN_USE; /* history log updation */ return update_history_log( db_handle, field_id, record_num ); } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_read_record | +--------------------------------------------------------------------+ PURPOSE : Read length bytes at offset from the record in given (database, field) */ int db_read_record ( int db_handle, USHORT field_id, USHORT record_num, USHORT offset, USHORT length, UBYTE* record_buffer ) { T_DB_CODE db_ret_code; UBYTE fld_ctr; char user_field_file[FILENAME_LEN]; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; TRACE_FUNCTION("db_read_record()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); /* Using RecordBitMap, check whether record_num exists; if it does not exist, return DB_EMPTY_RECORD. */ tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; if (!db_get_bit_in_bitmap (tmp_ptrFieldRecord -> RecordBitMap, record_num)) { /* if record does *not* exist */ DB_RETURN( DB_EMPTY_RECORD ) } /* Check if record exceeds the record size (i.e. offset + length > record size); if it exceeds, return error DB_INVALID_SIZE */ if( (offset + length) > tmp_ptrFieldRecord -> RecordSize ) DB_RETURN( DB_INVALID_SIZE ); /* Check if FFS file is already opened using FFSFileHandle, part of field record. If it is not yet opened, open the FFS file and update FFSFileHandle. This is taken care in read_user_record_from_FFS below. */ /* Read record_num from "<DBDirectory>/UD_<field_id>" Put "length" number of bytes from "offset" in buffer. (assuming that buffer contain enough memory i.e. caller should take care of allocating enough memory space for buffer) */ /* User data file name is "<DBDirectory>/UD_<field_id>" */ /* Implements Measure#32: Row 1200 */ sprintf( user_field_file, format_sUDd_str, (char *)DbmMaster[db_handle].DBDirectory, tmp_ptrFieldRecord -> FieldID ); /* Implements Measure # 211 */ db_ret_code = read_write_user_record_from_FFS ( user_field_file, #ifndef FFS_CLOSE_BEFORE_OPEN &(tmp_ptrFieldRecord -> FFSFileHandle), #else db_handle, fld_ctr, &Dummy_FFSFileHandle, #endif (UBYTE)record_num, tmp_ptrFieldRecord -> RecordSize, offset, length, record_buffer, FFS_O_RDONLY ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); DB_VALUE_RETURN( record_num ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_remove | +--------------------------------------------------------------------+ PURPOSE : Remove a database. The database must not be in use. */ T_DB_CODE db_remove ( const char* directory ) { int db_handle; UBYTE db_ctr, fld_ctr; T_DB_CODE db_ret_code; UBYTE* dbm_data; UBYTE field_file[FILENAME_LEN]; TRACE_FUNCTION("db_remove()"); /* DBM_State check */ DBM_State_check; /* Search for "directory" in DbmMaster If not found, return DB_INVALID_DB */ for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr ) { if ( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY ) { if( memcmp( DbmMaster[db_ctr].DBDirectory, directory, strlen(directory) ) EQ 0 ) break; } } if( db_ctr EQ MAX_DBs ) DB_RETURN( DB_INVALID_DB ); db_handle = db_ctr; /* If DBState for found database in DbmMaster is OPEN or IN_USE, return error DB_IN_USE */ if( ( DbmMaster[db_ctr].DBState EQ OPEN ) OR ( DbmMaster[db_ctr].DBState EQ IN_USE ) ) DB_RETURN( DB_IN_USE ); /* Delete all files under directory "<DBDirectory>" (DBDirectory = directory) */ for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr ) { db_ret_code = remove_field_from_FFS( (UBYTE)db_handle, fld_ctr ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); } /* Delete the DBDirectory */ db_ret_code = delete_file_dir_from_FFS ( (const char*)DbmMaster[db_handle].DBDirectory ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* Delete Field file = DD_<pos. in DD_master> */ /* Implements Measure#32: Row 1195, 1203 */ sprintf( (char*)field_file, format_sDDd_str, db_dir, db_ctr); db_ret_code = delete_file_dir_from_FFS ( (const char*)field_file ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* Update FFS data i.e. file, "~/dbm/DD_master" */ /* prepare the dbm data and write */ DB_MALLOC( dbm_data, T_DB_MASTER_RECORD_SIZE ); memset( dbm_data, 0xFF, T_DB_MASTER_RECORD_SIZE ); /* Implements Measure#32: Row 1201 */ db_ret_code = update_dbm_data_in_FFS ( db_master_file, (UBYTE) db_handle, /* to supress warning */ T_DB_MASTER_RECORD_SIZE, dbm_data, 0, T_DB_MASTER_RECORD_SIZE ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( dbm_data ); DB_RETURN( db_ret_code ) } DB_MFREE( dbm_data ); /* updation of DD_master done */ /* Free the memory for field records. Update this entry in DbmMaster as unused. (DBState = UNUSED_ENTRY). Also, decrement UsedDBs. */ DB_MFREE( DbmMaster[db_handle].ptrFieldRecord ); DbmMaster[db_handle].DBState = UNUSED_ENTRY; --UsedDBs; /* everything ok ! */ DB_RETURN( DB_OK ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_close | +--------------------------------------------------------------------+ PURPOSE : Close a database; if in use, it flushes it before closing it. */ T_DB_CODE db_close ( int db_handle ) { TRACE_FUNCTION("db_close()"); /* DBM_State check */ DBM_State_check; /* Check for db_handle range */ if( db_handle >= MAX_DBs ) DB_RETURN( DB_INVALID_DB ); /* If DBState for db_handleth position in DbmMaster is o UNUSED_ENTRY, return error DB_INVALID_DB o CLOSED, return DB_OK. o OPEN, update DBState as CLOSED and return DB_OK. o IN_USE, call db_flush, update DBState as CLOSED and return DB_OK */ switch( DbmMaster[db_handle].DBState ) { case UNUSED_ENTRY: DB_RETURN( DB_INVALID_DB ) case CLOSED: DB_RETURN( DB_OK ) case OPEN: case IN_USE: { db_flush( db_handle ); DbmMaster[db_handle].DBState = CLOSED; DB_RETURN( DB_OK ) } default: break; } DB_RETURN( DB_FAIL ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_exit | +--------------------------------------------------------------------+ PURPOSE : Shutdown the data base */ void db_exit ( void ) { /* It is assumed as "forced" exit and so no error would be raised even if database is in use. Also, here we will not delete the database, but just sync the database and free the RAM structures. 1) Call db_flush for all databases present in DbmMaster. 2) Free the memory for field records for all databases. 3) Update all entries in DbmMaster as unused (this step is not required) 4) Set DBM_State as DBM_NOT_INITIALISED. */ UBYTE db_ctr; for ( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr ) { if( DbmMaster[db_ctr].DBState EQ UNUSED_ENTRY ) continue; db_close( db_ctr ); DB_MFREE( DbmMaster[db_ctr].ptrFieldRecord ); DbmMaster[db_ctr].DBState = UNUSED_ENTRY; } DBM_State = DBM_NOT_INITIALISED; UsedDBs = 0; return; } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_remove_field | +--------------------------------------------------------------------+ PURPOSE : Delete field in given database */ T_DB_CODE db_remove_field ( int db_handle, USHORT field_id ) { UBYTE fld_ctr; T_DB_CODE db_ret_code; UBYTE* field_data; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; TRACE_FUNCTION("db_remove_field()"); TRACE_EVENT_P1 ("Removing field %04X", field_id); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field id not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; /* >>>HM 4-Sep-2006 It would be nice if we would close here only the file which is opened and not everything, but such a solution is impossible within the work environment at the customer.*/ #ifdef FFS_CLOSE_BEFORE_OPEN db_close_user_field_files( db_handle ); #endif /* <<< HM 4-Sep-2006 */ #ifndef FFS_CLOSE_BEFORE_OPEN /* Check if FFS file is open using FFSFileHandle, part of field record; if so, return error DB_IN_USE. */ if (IS_FD_VALID(tmp_ptrFieldRecord->FFSFileHandle) { TRACE_ERROR ("File handle in use"); DB_RETURN( DB_IN_USE ); } #else if( db_status_user_field_file( db_handle, fld_ctr ) EQ OPENED_FOR_WRITE ) { TRACE_ERROR ("File handle in use for writing"); DB_RETURN( DB_IN_USE ) } #endif /* Remove file "<DBDirectory>/UD_<field_id>" */ db_ret_code = remove_field_from_FFS( (UBYTE)db_handle, fld_ctr ); if( db_ret_code NEQ DB_OK ) { TRACE_ERROR ("Could not remove user field file"); DB_RETURN( db_ret_code ) } /* Update "~/dbm/DD_<db_handle>" for removed field id. */ /* create the field data that is to be written */ DB_MALLOC( field_data, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); memset( field_data, 0xFF, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); db_ret_code = update_field_data_in_FFS ( &DbmMaster[db_handle].FFSFileHandle, db_handle, fld_ctr, field_data, RecordBitMap_OFFSET, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) ); if( db_ret_code NEQ DB_OK ) { TRACE_ERROR ("Could not update master file"); DB_MFREE( field_data ); DB_RETURN( db_ret_code ) } DB_MFREE( field_data ); /* updation of DD_<db_handle> is over */ /* update in RAM */ tmp_ptrFieldRecord -> FieldID = INVALID_FIELD_ID; /* One field less */ DbmMaster[db_handle].UsedFiles--; // HM 5-Sep-2006 Midnight patch ADN FDN switch DB_RETURN( DB_OK ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_read_change_log | +--------------------------------------------------------------------+ PURPOSE : Get an information about the changed records since the last call of this function */ T_DB_CODE db_read_change_log ( int db_handle, T_DB_CHANGED* changed) { T_DB_CODE db_ret_code; TRACE_FUNCTION("db_read_change_log()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* Copy contents of internal history log to HistoryRecord */ *changed = DB_History_log; /* This would work ?? */ /* Clear internal history log. */ DB_History_log.entries = 0; /* this is enough for clearing history log ! */ /* done */ DB_RETURN( DB_OK ) } #ifdef _SIMULATION_ /* HM 19-Oct-2006: Currently not used but to be kept */ /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_remove_index | +--------------------------------------------------------------------+ PURPOSE : Removes a sort index */ T_DB_CODE db_remove_index ( int db_handle, USHORT field_id, UBYTE sort_index ) { T_DB_CODE db_ret_code; UBYTE fld_ctr,sort_index_ctr; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; char sort_file[FILENAME_LEN]; UBYTE* field_data; TRACE_FUNCTION("db_remove_index()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; /* Search given sort_index in SortIndexList for above field_id; if not found, return DB_INVALID_INDEX. */ for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr ) { if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index ) break; } if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS ) DB_RETURN( DB_INVALID_INDEX ); /* Remove file, "<DBDirectory>/UD_<field_id>_sort_<sort_index>" */ /* Implements Measure#32: Row 1193 */ sprintf( sort_file, format_sUDd_sortd_str, DbmMaster[db_handle].DBDirectory, tmp_ptrFieldRecord -> FieldID, tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] ); db_ret_code = delete_file_dir_from_FFS ( sort_file ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* Update file , "~/dbm/DD_<db_handle>" for SortIndexes. */ /* create the field data that is to be written */ DB_MALLOC( field_data, MAX_NUM_OF_SORT_INDEXS ); memcpy( field_data, tmp_ptrFieldRecord -> SortIndexList, MAX_NUM_OF_SORT_INDEXS ); field_data[sort_index_ctr] = INVALID_SORT_INDEX; db_ret_code = update_field_data_in_FFS ( &DbmMaster[db_handle].FFSFileHandle, db_handle, fld_ctr, field_data, SortIndexList_OFFSET, MAX_NUM_OF_SORT_INDEXS ); if( db_ret_code NEQ DB_OK ) { DB_MFREE( field_data ); DB_RETURN( db_ret_code ) } DB_MFREE( field_data ); /* updation of DD_<db_handle> is over */ /* Update corresponding RAM structure i.e. DbmFieldRecord Check if we have sort list corresponding to this sort index; if so, free it. */ tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] = INVALID_SORT_INDEX; if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] NEQ NULL ) { DB_MFREE( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] ); tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = NULL; } DB_RETURN( DB_OK ) } #endif /* #ifdef _SIMULATION_ */ #ifdef _SIMULATION_ /* HM 19-Oct-2006: Currently not used but to be kept */ /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_field_changed | +--------------------------------------------------------------------+ PURPOSE : Check whether a database field has been changed since last db_flush(). */ T_DB_CODE db_field_changed ( int db_handle, USHORT field_id, BOOL* changed ) { UBYTE fld_ctr; T_DB_CODE db_ret_code; TRACE_FUNCTION("db_field_changed()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); /* Check "Clean" field in field record; a) if (Clean = true), changed = false. */ *changed = NOT DbmMaster[db_handle].ptrFieldRecord[fld_ctr].Clean; DB_RETURN( DB_OK ) } #endif /* #ifdef _SIMULATION_ */ /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_record_empty | +--------------------------------------------------------------------+ PURPOSE : Check whether a database field is empty. The result is given to the caller in the *empty variable */ T_DB_CODE db_record_empty ( int db_handle, USHORT field_id, USHORT record_num, BOOL* empty ) { UBYTE fld_ctr; T_DB_CODE db_ret_code; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; TRACE_FUNCTION("db_record_empty()"); *empty = TRUE; /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; /* Using RecordBitMap, check whether record_num is free; if so, empty = true and false otherwise */ if (db_get_bit_in_bitmap (tmp_ptrFieldRecord -> RecordBitMap, record_num)) { /* if record exist */ *empty = FALSE; } DB_RETURN( DB_OK ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_find_free_record | +--------------------------------------------------------------------+ PURPOSE : Find an free record in given (database, field) */ int db_find_free_record ( int db_handle, USHORT field_id ) { UBYTE fld_ctr; T_DB_CODE db_ret_code; int record_num; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; TRACE_FUNCTION("db_find_free_record()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; /* Using RecordBitMap, search for free record. If found , return the found record_num Return DB_RECORD_NOT_FOUND */ record_num = db_search_bit_in_bitmap (tmp_ptrFieldRecord->RecordBitMap, tmp_ptrFieldRecord->NumOfRecords, FALSE); if (record_num EQ 0) DB_RETURN( DB_RECORD_NOT_FOUND ); DB_VALUE_RETURN( record_num ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_info | +--------------------------------------------------------------------+ PURPOSE : Get information about an open database */ T_DB_CODE db_info ( int db_handle, T_DB_INFO* db_info ) { T_DB_CODE db_ret_code; TRACE_FUNCTION("db_info()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); (*db_info).clean = DbmMaster[db_handle].Clean; (*db_info).tracked = DbmMaster[db_handle].Tracked; DB_RETURN( DB_OK ) } /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_info_field | +--------------------------------------------------------------------+ PURPOSE : Get general information about a field in an open database. */ T_DB_CODE db_info_field ( int db_handle, USHORT field_id, T_DB_INFO_FIELD* info_field ) { UBYTE fld_ctr; T_DB_CODE db_ret_code; T_DBM_FIELDRECORD* tmp_ptrFieldRecord; TRACE_FUNCTION("db_info_field()"); /* DBM_State check */ DBM_State_check; /* db_handle check */ db_ret_code = db_handle_check( db_handle ); if( db_ret_code NEQ DB_OK ) DB_RETURN( db_ret_code ); /* field id search; if field not found, return error DB_INVALID_FIELD */ fld_ctr = field_id_search( db_handle, field_id ); if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles ) DB_RETURN( DB_INVALID_FIELD ); tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr; /* Using data available in RAM in field record, fill up info_field (i.e. clean, db_type, num_of_records and used_records). */ (*info_field).clean = tmp_ptrFieldRecord -> Clean; (*info_field).entry_type = tmp_ptrFieldRecord -> DBType; (*info_field).record_size = tmp_ptrFieldRecord -> RecordSize; (*info_field).num_records = tmp_ptrFieldRecord -> NumOfRecords; (*info_field).used_records = tmp_ptrFieldRecord -> UsedRecords; DB_RETURN( DB_OK ) } #ifdef _SIMULATION_ /* HM 19-Oct-2006: Currently not used but to be kept */ /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUINE: db_get_last_fs_error | +--------------------------------------------------------------------+ PURPOSE : Delivers the last error provided by the (flash) file system that resulted in DB_FAIL_FS. */ int db_get_last_fs_error ( void ) { DB_VALUE_RETURN( LastFFS_ReturnCode ) } #endif /* #ifdef _SIMULATION_ */ /* Implements Measure # 83 */ /* +--------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUTINE: db_close_for_read_write| +--------------------------------------------------------------------+ PURPOSE : Close Read & write FFS Operations */ LOCAL void db_close_for_read_write ( FileHandleRecord *tmp_open_fields, UBYTE *tmp_old, UBYTE max_per_db) { TRACE_FUNCTION ("db_close_for_read_write ()"); if( *tmp_old >= max_per_db ) { *tmp_old = 0; } DB_FFS_CLOSE( tmp_open_fields[*tmp_old].filehandle ); tmp_open_fields[*tmp_old].filehandle = INVALID_FD; tmp_open_fields[*tmp_old].fld_ctr = INVALID_FLD_CTR; ++(*tmp_old); } /* Implements Measure # 211 */ /* +-------------------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUTINE: read_write_user_record_from_FFS | +-------------------------------------------------------------------------------+ PURPOSE : Reads OR Writes user record into FFS */ LOCAL T_DB_CODE read_write_user_record_from_FFS ( const char *user_field_file, #ifdef FFS_CLOSE_BEFORE_OPEN UBYTE db_ctr, UBYTE fld_ctr, #endif T_FFS_FD *filehandle, UBYTE record_num, USHORT record_size, USHORT offset, USHORT length, UBYTE *record_buffer, T_FFS_OPEN_FLAGS open_option) { T_FFS_FD ffs_fd = INVALID_FD; T_FFS_SIZE ffs_ret_code; T_DB_CODE db_code; /* See if file already opened, if not open it and update the file handle */ TRACE_FUNCTION ("read_write_user_record_from_FFS ()"); #ifndef FFS_CLOSE_BEFORE_OPEN ffs_fd = *filehandle; if( !IS_FD_VALID(ffs_fd) ) { DB_FFS_OPEN( ffs_fd, user_field_file, open_option ); if (open_option EQ FFS_O_RDONLY ) { TRACE_EVENT_P1( "read_user_record_from_FFS:DB_FFS_OPEN %d", ffs_fd ); } else { TRACE_EVENT_P1( "write_user_record_to_FFS:DB_FFS_OPEN %d", ffs_fd ); } if( (ffs_fd EQ EFFS_NOTFOUND) OR (ffs_fd EQ EFFS_NAMETOOLONG) OR (ffs_fd EQ EFFS_BADNAME) OR (ffs_fd EQ EFFS_INVALID) OR (ffs_fd EQ EFFS_LOCKED) ) { return DB_FAIL; } if( ffs_fd < EFFS_OK ) { LastFFS_ReturnCode = ffs_fd; return DB_FAIL_FS; } *filehandle = ffs_fd; } #else /* FFS_CLOSE_BEFORE_OPEN */ ffs_fd = db_open_user_field_file( db_ctr, fld_ctr, user_field_file, open_option ); #endif /* FFS_CLOSE_BEFORE_OPEN */ ffs_ret_code = ffs_seek( ffs_fd, ( (record_num - 1) * (record_size) + offset), FFS_SEEK_SET ); if (open_option EQ FFS_O_RDONLY ) { TRACE_EVENT_P1( "read_user_record_from_FFS:ffs_seek %d", ffs_ret_code ); } else { TRACE_EVENT_P1( "write_user_record_to_FFS:ffs_seek %d", ffs_ret_code ); } db_code = check_ffs_ret_code (ffs_ret_code, filehandle, ffs_fd, TRUE); if (db_code NEQ DB_OK) { return db_code; } if (open_option EQ FFS_O_RDONLY ) { ffs_ret_code = ffs_read( ffs_fd, record_buffer, length ); TRACE_EVENT_P1( "read_user_record_from_FFS:ffs_read %d", ffs_ret_code ); } else { ffs_ret_code = ffs_write( ffs_fd, record_buffer, length ); TRACE_EVENT_P1( "write_user_record_to_FFS:ffs_write %d", ffs_ret_code ); } db_code = check_ffs_ret_code (ffs_ret_code, filehandle, ffs_fd, FALSE); if (db_code NEQ DB_OK) { return db_code; } /* DB_FFS_CLOSE( ffs_fd ); we will do it in db_flush */ #ifdef FFS_OPEN_PROBLEM_PATCH DB_FFS_CLOSE( ffs_fd ); *filehandle = INVALID_FD; #endif return DB_OK; } /* Implements Measure # 211 */ /* +-------------------------------------------------------------------------------+ | PROJECT: PHB MODULE: DBM | | ROUTINE: check_ffs_ret_code | +-------------------------------------------------------------------------------+ PURPOSE : Checks ffs_ret_code */ LOCAL T_DB_CODE check_ffs_ret_code (T_FFS_SIZE ffs_ret_code, T_FFS_FD *filehandle, T_FFS_FD ffs_fd, BOOL check_invalid) { TRACE_FUNCTION ("check_ffs_ret_code ()"); if( ( ffs_ret_code EQ EFFS_BADFD ) OR ( (ffs_ret_code EQ EFFS_INVALID) AND check_invalid ) OR ( ffs_ret_code EQ EFFS_BADOP ) ) { DB_FFS_CLOSE( ffs_fd ); *filehandle = INVALID_FD; return DB_FAIL; } if( ffs_ret_code < EFFS_OK ) { LastFFS_ReturnCode = ffs_ret_code; DB_FFS_CLOSE( ffs_fd ); *filehandle = INVALID_FD; return DB_FAIL_FS; } return DB_OK; } #endif /* #ifdef TI_PS_FFS_PHB */