#define FIRST_MODULE #include "dbinc.h" /***************************************************************************** * * * COMMON OCEANOGRAPHIC DATA ACCESS SYSTEM (CODAS) * * * * WRITTEN BY: RAMON CABRERA, ERIC FIRING, and JULIE RANADA * * JOINT INSTITUTE FOR MARINE AND ATMOSPHERIC RESEARCH * * 1000 POPE ROAD MSB 312 * * HONOLULU, HI 96822 * * * * VERSION: 3.10 * * * * DATE: APRIL 1989, AUGUST 1995 * * * *****************************************************************************/ /* FILE: dbcommon.c SYSTEM FUNCTIONS FOR ACCESSING DATABASE WHETHER FOR CREATE, READ, OR UPDATE = DBCLOSE and supporting routines; routines common to both DBCREATE and DBOPEN */ /*----------------------------------------------------------------------------- FUNCTION: DBCLOSE It closes the current database. PARAMETERS: ierr = pointer to error code RETURNS: VOID */ void DBCLOSE(int *ierr) { unsigned int nb; *ierr = 0; if ((!(db_ptr)) || first_database_call) { *ierr = DB_IS_NOT_OPEN; return; } if (db_ptr->new_block_is_open) { *ierr = NEW_BLOCK_IS_OPEN; return; } /* ---> CLOSE ANY OPEN BLOCK */ if (db_ptr->block_is_open) if (close_block()) goto error_found; /* ---> IF BLOCK DIRECTORY WAS MODIFIED UPDATE IT */ if (db_ptr->block_dir_modified) { /* ---> IF BLOCK DIR NOT IN MEMORY LOAD IT */ if (!(db_ptr->block_dir_in_memory)) { nb = db_ptr->block_dir_hdr.dir_nentries * db_ptr->block_dir_hdr.dir_entry_nbytes; if ((db_ptr->block_dir = malloc(nb)) == NULL) { db_ptr->error_code = INSUFFICIENT_MEMORY; db_ptr->error_data = BLOCK_DIR; goto error_found; } db_ptr->block_dir_in_memory = 1; if (load_block_dir()) goto error_found; } else if (!(db_ptr->block_dir_loaded)) { if (load_block_dir()) goto error_found; } /* ---> UPDATE HEADER AND DIRECTORY AND REWRITE THEM */ update_block_dir(); if (write_block_dir_hdr()) goto error_found; if (write_block_dir()) goto error_found; } /* ---> CLOSE BLOCK DIRECTORY */ if (close_block_dir()) goto error_found; /* ---> RELEASE DATABASE */ release_database(); return; error_found: report_db_error("DBCLOSE"); *ierr = db_ptr->error_code * 1000 - db_ptr->error_data; release_database(); } /*----------------------------------------------------------------------------- FUNCTION: report_db_error It writes to standard output a short description of a database-related error. PARAMETER: fun = pointer to name of function reporting the error */ NAME_LIST_ENTRY_TYPE ERROR_CODE[] = { {"EOF", -1}, {"UNABLE_TO_OPEN", -2}, {"FILE_DOES_NOT_EXIST", -3}, {"FILE_ALREADY_EXISTS", -4}, {"FILE_PROTECTION_ERROR", -5}, {"READ_ERROR", -6}, {"WRITE_ERROR", -7}, {"SEEK_ERROR", -8}, {"CLOSE_ERROR", -9}, {"INSUFFICIENT_MEMORY", -10}, {"", 0}, /* no error */ {"INVALID_DATABASE_NUMBER", 1}, {"DB_IS_NOT_OPEN", 2}, {"DB_ALREADY_OPEN", 3}, {"NO_OPEN_FOR_WRITE", 4}, {"NO_OPEN_FOR_CREATE", 5}, {"OPEN_FOR_CREATE", 6}, {"DATABASE_IS_EMPTY", 7}, {"INCORRECT_DATABASE_VERSION", 8}, {"UNEXPECTED_STRUCTURE_SIZE", 9}, {"NO_BLOCK_IS_OPEN", 11}, {"NO_PROFILE_IS_OPEN", 12}, {"NO_NEW_BLOCK_IS_OPEN", 13}, {"NO_NEW_PROFILE_IS_OPEN", 14}, {"NEW_BLOCK_IS_OPEN", 15}, {"NEW_PROFILE_IS_OPEN", 16}, {"BLOCK_DIR_IS_FULL", 21}, {"BLOCK_IS_FULL", 22}, {"INSUFFICIENT_SPACE", 23}, {"BLOCK_DIR_IS_EMPTY", 26}, {"PROFILE_DIR_IS_EMPTY", 27}, {"DATA_LIST_IS_EMPTY", 28}, {"INVALID_TYPE_REQUEST", 31}, {"INVALID_TIME", 32}, {"INVALID_POSITION", 33}, {"INVALID_VALUE_TYPE", 34}, {"INVALID_ACCESS_TYPE", 35}, {"NO_SUCH_BLOCK_PROFILE", 36}, {"INVALID_BUFFER_SIZE", 37}, {"INVALID_DIRECTORY_TYPE", 38}, {"MAXIMUM_SIZE_EXCEEDED", 39}, {"SEARCH_BEYOND_END", 41}, {"SEARCH_BEFORE_BEGINNING", 42}, {"ZERO_SCALE", 51}, {"PATHNAME_TOO_LONG", 61}, {"DBNAME_TOO_LONG", 62}, {"UNDEFINED_STRUCTURE", 70}, {"UNKNOWN_HOST_ERROR", 71}, {"INCOMPATIBLE_HOST_ERROR", 72}, {"STRUCTURE_NOT_PRESENT", 73}, {"NO_SUCH_ELEMENT", 74}, {"FORMAT_ERROR", 80} }; NAME_LIST_ENTRY_TYPE DATA_CODE[] = { {"", 0}, {"DATASET_ID", 100}, {"PRODUCER_ID", 101}, {"TIME", 102}, {"POSITION", 103}, {"DATA_MASK", 104}, {"DATA_PROC_MASK", 105}, {"DEPTH_RANGE", 106}, {"DATABASE_VERSION", 200}, {"PRODUCER_HOST", 201}, {"DATABASE_NUMBER", 202}, {"BLOCK_PROFILE_INDEX", 203}, {"BLOCK_DIR_FILE", 300}, {"BLOCK_FILE", 301}, {"PRODUCER_DEF_FILE", 302}, {"TEMP_DATA_FILE", 303}, {"BLOCK_DIR_HDR", 304}, {"BLOCK_DIR", 305}, {"BLOCK_HDR", 306}, {"DATA_LIST", 307}, {"PROFILE_DIR", 308}, {"DATA_DIR", 309}, {"PROFILE_DATA", 310}, {"PRODUCER_DEF", 311}, {"STRUCTURE_DEF", 312}, {"STRUCTURE_FORMATS", 313} }; void report_db_error(char *fun) { printf("\n CODAS ERROR: %-30s", get_name(ERROR_CODE, db_ptr->error_code)); printf("\t ACCESSING: %s", get_name(DATA_CODE, db_ptr->error_data)); printf("\n FROM FUNCTION: %-30s", fun); /*ef*/ printf("\t IN DATABASE: %d\n", current_database + 1); /*ef*/ } /*----------------------------------------------------------------------------- FUNCTION: close_block_dir() It closes an open block directory file. RETURNS: 0 if okay CLOSE_ERROR otherwise */ int close_block_dir(void) { if (fclose(db_ptr->fpblkdir)) { db_ptr->error_code = CLOSE_ERROR; db_ptr->error_data = BLOCK_DIR_FILE; goto error_found; } db_ptr->block_dir_is_open = 0; db_ptr->block_dir_loaded = 0; return(0); error_found: report_db_error("close_block_dir"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: close_block() It closes a block data file. RETURNS: 0 if okay db_ptr->error_code otherwise */ int close_block(void) { unsigned int nb, temp_dir_loaded = 0; /* ---> IF BLOCK WAS MODIFIED UPDATE IT */ if (db_ptr->block_modified) { /* ---> IF PROFILE DIR NOT IN MEMORY LOAD IT */ if (!(db_ptr->profile_dir_in_memory)) { nb = (db_ptr->block_hdr.dir_nentries) * db_ptr->block_hdr.dir_entry_nbytes; if ((db_ptr->profile_dir = malloc(nb)) == NULL) { db_ptr->error_code = INSUFFICIENT_MEMORY; db_ptr->error_data = PROFILE_DIR; goto error_found; } temp_dir_loaded = 1; if (load_profile_dir()) goto error_found; } else if (!(db_ptr->profile_dir_loaded)) { if (load_profile_dir()) goto error_found; } /* ---> UPDATE HEADER AND DIRECTORY AND REWRITE THEM */ update_block(); if (write_block_hdr()) goto error_found; if (write_profile_dir()) goto error_found; update_block_dir_entry(); if (write_block_dir_entry()) goto error_found; db_ptr->block_dir_modified = 1; } /* ---> CLOSE BLOCK FILE */ if (temp_dir_loaded) { free(db_ptr->profile_dir); db_ptr->profile_dir_loaded = 0; } release_block(); return(0); error_found: if (temp_dir_loaded) { free(db_ptr->profile_dir); db_ptr->profile_dir_loaded = 0; } release_block(); report_db_error("close_block"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: release_database It closes files and releases all memory allocated for a database. RETURNS: VOID */ void release_database(void) { if (db_ptr) { if (db_ptr->block_is_open) fclose(db_ptr->fpblkdata); if (db_ptr->block_dir_is_open) fclose(db_ptr->fpblkdir); if (db_ptr->producer_in_memory) free(db_ptr->producer); if (db_ptr->block_dir_in_memory) free(db_ptr->block_dir); if (db_ptr->profile_dir_in_memory) free(db_ptr->profile_dir); if (db_ptr->next_strdef != NULL) free(db_ptr->next_strdef); else if (db_ptr->prev_strdef != NULL) free(db_ptr->struct_def); if (db_ptr->block_strdef_loaded) free(db_ptr->block_strdef); free(database_table[current_database]); } db_ptr = NULL; database_table[current_database] = NULL; } /*----------------------------------------------------------------------------- FUNCTION: release_block It closes the block file and resets the respective flags. RETURNS: VOID */ void release_block(void) { if (db_ptr->block_is_open) fclose(db_ptr->fpblkdata); if (!db_ptr->create_mode) if (db_ptr->block_strdef_loaded) { if (db_ptr->struct_def == db_ptr->block_strdef) db_ptr->struct_def = NULL; free(db_ptr->block_strdef); db_ptr->block_strdef_loaded = 0; } db_ptr->block_is_open = 0; db_ptr->block_modified = 0; db_ptr->profile_is_open = 0; db_ptr->new_block_is_open = 0; db_ptr->new_profile_is_open = 0; db_ptr->data_list_loaded = 0; db_ptr->formats_matched = 0; db_ptr->profile_dir_loaded = 0; db_ptr->block_host = UNKNOWN_HOST; } /*----------------------------------------------------------------------------- FUNCTION: update_block_dir IT SETS THE STDR OF THE BLOCK DIR HDR BASED ON THE CURRENT ENTRIES' STDRS NOTES: - BLOCK_DIRECTORY MUST ALREADY BE OPEN - HEADER MUST BE IN db_ptr->block_dir_hdr - BLOCK DIR MUST BE IN db_ptr->block_dir RETURNS: VOID */ void update_block_dir(void) { unsigned int nb; int i, ndel; long minE = MAXLONG, minW = MAXLONG, maxE = MINLONG, maxW = MINLONG; long l1, l2; BLOCK_DIR_ENTRY_TYPE *ptr; /* ---> SET FIELDS AS FOR AN EMPTY DIRECTORY */ db_ptr->block_dir_hdr.time1 = MAXULONG; db_ptr->block_dir_hdr.time2 = MINULONG; db_ptr->block_dir_hdr.lon1 = MAXLONG; db_ptr->block_dir_hdr.lat1 = MAXLONG; db_ptr->block_dir_hdr.depth1 = MAXSHORT; db_ptr->block_dir_hdr.lon2 = MINLONG; db_ptr->block_dir_hdr.lat2 = MINLONG; db_ptr->block_dir_hdr.depth2 = MINSHORT; db_ptr->block_dir_hdr.data_mask = 0; db_ptr->block_dir_hdr.data_proc_mask = 0; /* ---> ERASE EMPTY BLOCKS */ nb = db_ptr->block_dir_hdr.dir_entry_nbytes; ptr = db_ptr->block_dir_entry_ptr = (BLOCK_DIR_ENTRY_TYPE *) db_ptr->block_dir; ndel = 0; for (i = 0; i < (int)db_ptr->block_dir_hdr.dir_nentries; i++) { if (ptr != db_ptr->block_dir_entry_ptr) move_byte((char *) ptr, (char *) db_ptr->block_dir_entry_ptr, nb); if (db_ptr->block_dir_entry_ptr->file_id < 0) { sprintf( (db_ptr->block_file+db_ptr->path_nchar), db_ptr->block_dir_hdr.block_file_template, -db_ptr->block_dir_entry_ptr->file_id); db_ptr->fpblkdata = open_binary_file(db_ptr->block_file, READ_WRITE); fclose(db_ptr->fpblkdata); ndel++; } else db_ptr->block_dir_entry_ptr += 1; ptr += 1; } db_ptr->block_dir_hdr.dir_nentries -= ndel; /* ---> SORT BLOCK DIR */ sort_block_dir(); /* ---> UPDATE HEADER */ db_ptr->block_dir_entry_ptr = (BLOCK_DIR_ENTRY_TYPE *) db_ptr->block_dir; db_ptr->block_dir_hdr.time1 = db_ptr->block_dir_entry_ptr->time1; db_ptr->block_dir_hdr.time2 = (db_ptr->block_dir_entry_ptr + (db_ptr->block_dir_hdr.dir_nentries - 1))->time2; for (i = 0; i < (int)db_ptr->block_dir_hdr.dir_nentries; i++, (db_ptr->block_dir_entry_ptr)++) { db_ptr->block_dir_hdr.lat1 = min_val(db_ptr->block_dir_hdr.lat1, db_ptr->block_dir_entry_ptr->lat1); db_ptr->block_dir_hdr.lat2 = max_val(db_ptr->block_dir_hdr.lat2, db_ptr->block_dir_entry_ptr->lat2); db_ptr->block_dir_hdr.depth1 = min_val(db_ptr->block_dir_hdr.depth1, db_ptr->block_dir_entry_ptr->depth1); db_ptr->block_dir_hdr.depth2 = max_val(db_ptr->block_dir_hdr.depth2, db_ptr->block_dir_entry_ptr->depth2); db_ptr->block_dir_hdr.data_mask = (db_ptr->block_dir_hdr.data_mask) | (db_ptr->block_dir_entry_ptr->data_mask); db_ptr->block_dir_hdr.data_proc_mask = (db_ptr->block_dir_hdr.data_proc_mask) | (db_ptr->block_dir_entry_ptr->data_proc_mask); /* ---> SPECIAL TREATMENT FOR LONGITUDE */ if (db_ptr->block_dir_entry_ptr->lon1 != MAXLONG) { if ((l1 = db_ptr->block_dir_entry_ptr->lon1) > 129600000L) l1 -= 129600000L; if ((l2 = db_ptr->block_dir_entry_ptr->lon2) > 129600000L) l2 -= 129600000L; if (l1 <= 64800000L) { minE = min_val(minE, l1); maxE = max_val(maxE, l1); } else { minW = min_val(minW, l1); maxW = max_val(maxW, l1); } if (l2 <= 64800000L) { minE = min_val(minE, l2); maxE = max_val(maxE, l2); } else { minW = min_val(minW, l2); maxW = max_val(maxW, l2); } } if (minE == MAXLONG) { db_ptr->block_dir_hdr.lon1 = minW; db_ptr->block_dir_hdr.lon2 = maxW; } else if (minW == MAXLONG) { db_ptr->block_dir_hdr.lon1 = minE; db_ptr->block_dir_hdr.lon2 = maxE; } else { l1 = minW - maxE; l2 = minE - maxW + 129600000L; if (l1 <= l2) { db_ptr->block_dir_hdr.lon1 = minE; db_ptr->block_dir_hdr.lon2 = maxW; } else { db_ptr->block_dir_hdr.lon1 = minW; db_ptr->block_dir_hdr.lon2 = maxE + 129600000L; } } } } /*----------------------------------------------------------------------------- FUNCTION: update_block It sets the position, time, and depth range of the block header based on the current entries' position, time and depth ranges. NOTE: - Block must already be open. - Header must be in db_ptr->block_hdr. - Profile directory must be in db_ptr->profile_dir. - Block access must be set. RETURNS: VOID */ void update_block(void) { YMDHMS_TIME_TYPE tstruct; char *ptr; LONG mintime, tdiff; LONG minE = MAXLONG, minW = MAXLONG, maxE = MINLONG, maxW = MINLONG; LONG l1, l2; int i, ndel=0, profile_time_in_seconds, profile_key_type; unsigned int nb; /* ---> ERASE EMPTY PROFILES */ nb = db_ptr->block_hdr.dir_entry_nbytes; ptr = db_ptr->profile_dir; db_ptr->profile_dir_entry_ptr = (PROFILE_DIR_3_ENTRY_TYPE *) ptr; ndel = 0; for (i = 0; i < (int)db_ptr->block_hdr.dir_nentries; i++) { if (ptr != (CHAR *) db_ptr->profile_dir_entry_ptr) move_byte(ptr, (char *) db_ptr->profile_dir_entry_ptr, nb); if (db_ptr->profile_dir_entry_ptr->ofs < 0) ndel++; else db_ptr->profile_dir_entry_ptr = (PROFILE_DIR_3_ENTRY_TYPE *) ((char *) db_ptr->profile_dir_entry_ptr + nb); ptr += nb; } db_ptr->block_hdr.dir_nentries -= ndel; /* if there are no profiles left in a block, this block should be deleted */ if (db_ptr->block_hdr.dir_nentries == 0) { if (db_ptr->block_dir_entry_ptr->file_id > 0) db_ptr->block_dir_entry_ptr->file_id = -db_ptr->block_dir_entry_ptr->file_id; if (write_block_dir_entry()) report_db_error("update_block"); db_ptr->block_dir_modified = 1; return; } /* ---> SORT PROFILE DIR */ sort_profile_dir(); /* ---> SET BLOCK TIME, POSITION RANGE, AND DEPTH RANGE */ mintime = ((PROFILE_DIR_3_ENTRY_TYPE *)db_ptr->profile_dir)->time; nb = db_ptr->block_hdr.dir_entry_nbytes; profile_key_type = db_ptr->block_hdr.dir_type; for (i = 0; i < (int)db_ptr->block_hdr.dir_nentries; i++) { db_ptr->profile_dir_entry_ptr = (PROFILE_DIR_3_ENTRY_TYPE *) (db_ptr->profile_dir + i * nb); if ((profile_key_type == 1) || (profile_key_type == 3)) /* profile directory entry includes position */ { if (db_ptr->profile_dir_entry_ptr->lat != MAXLONG) { db_ptr->block_hdr.lat1 = min_val(db_ptr->block_hdr.lat1, db_ptr->profile_dir_entry_ptr->lat); db_ptr->block_hdr.lat2 = max_val(db_ptr->block_hdr.lat2, db_ptr->profile_dir_entry_ptr->lat); } if (db_ptr->profile_dir_entry_ptr->lon != MAXLONG) { if ((l1 = db_ptr->profile_dir_entry_ptr->lon) <= 64800000L) { minE = min_val(minE, l1); maxE = max_val(maxE, l1); } else { minW = min_val(minW, l1); maxW = max_val(maxW, l1); } } } if ((profile_key_type == 2) || (profile_key_type == 3)) /* profile directory entry includes depth */ { db_ptr->block_hdr.depth1 = min_val(db_ptr->block_hdr.depth1, db_ptr->profile_dir_entry_ptr->depth1); db_ptr->block_hdr.depth2 = max_val(db_ptr->block_hdr.depth2, db_ptr->profile_dir_entry_ptr->depth2); } } /* ---> SET BLOCK TIME RANGE AND DISPLACE PROFILE TIMES IF NEEDED */ profile_time_in_seconds = (db_ptr->block_hdr.dir_time_flag == DIR_TIME_IN_SECONDS); if ((mintime < 0) || (profile_time_in_seconds && mintime >= 60) || (!profile_time_in_seconds && mintime >= 6000)) /* WE HAVE TO CHANGE BLOCK BASE TIME */ /* SO PROFILE TIME OFFSETS ARE POSITIVE */ { move_byte((char *) &(db_ptr->block_base_time), (char *) &(tstruct), sizeof(YMDHMS_TIME_TYPE)); if (profile_time_in_seconds) DIFTIM(&(tstruct), &(db_ptr->block_base_time), &mintime); else HDIFTIM(&(tstruct), &(db_ptr->block_base_time), &mintime); db_ptr->block_hdr.time1 = PCKTIM(&(db_ptr->block_base_time)); UPCKTIM(&(db_ptr->block_base_time), &(db_ptr->block_hdr.time1)); if (profile_time_in_seconds) tdiff = TIMDIF(&(db_ptr->block_base_time), &(tstruct)); else tdiff = HTIMDIF(&(db_ptr->block_base_time), &(tstruct)); for (i = 0; i < db_ptr->block_hdr.dir_nentries; i++) { db_ptr->profile_dir_entry_ptr = (PROFILE_DIR_3_ENTRY_TYPE *) (db_ptr->profile_dir + i * nb); db_ptr->profile_dir_entry_ptr->time += tdiff; } } tdiff = db_ptr->profile_dir_entry_ptr->time; /* tdiff is now the offset, in seconds or hundredths, of the last profile in the block. Round it up to the next minute if necessary, so that when converted to minutes it will be >= the actual last time offset in the block. */ if (profile_time_in_seconds) { if (tdiff % 60) tdiff += 60; DIFTIM(&(db_ptr->block_base_time), &(db_ptr->block_last_time), &tdiff); } else { if (tdiff % 6000) tdiff += 6000; HDIFTIM(&(db_ptr->block_base_time), &(db_ptr->block_last_time), &tdiff); } db_ptr->block_hdr.time2 = PCKTIM(&(db_ptr->block_last_time)); /* ---> SET LONGITUDE RANGE IF NEEDED */ if ((profile_key_type == 1) || (profile_key_type == 3)) { if (minE == MAXLONG) { db_ptr->block_hdr.lon1 = minW; db_ptr->block_hdr.lon2 = maxW; } else if (minW == MAXLONG) { db_ptr->block_hdr.lon1 = minE; db_ptr->block_hdr.lon2 = maxE; } else { l1 = minW - maxE; l2 = minE - maxW + 129600000L; if (l1 <= l2) { db_ptr->block_hdr.lon1 = minE; db_ptr->block_hdr.lon2 = maxW; } else { db_ptr->block_hdr.lon1 = minW; db_ptr->block_hdr.lon2 = maxE + 129600000L; } } } } /*----------------------------------------------------------------------------- FUNCTION: update_block_dir_entry It sets the fields of the block directory entry for the current block. RETURNS: VOID */ void update_block_dir_entry(void) { strcpy((char *)&(db_ptr->block_dir_entry_ptr->producer_id), (char *)&(db_ptr->block_hdr.producer_id)); db_ptr->block_dir_entry_ptr->time1 = db_ptr->block_hdr.time1; db_ptr->block_dir_entry_ptr->time2 = db_ptr->block_hdr.time2; db_ptr->block_dir_entry_ptr->lon1 = db_ptr->block_hdr.lon1; db_ptr->block_dir_entry_ptr->lon2 = db_ptr->block_hdr.lon2; db_ptr->block_dir_entry_ptr->lat1 = db_ptr->block_hdr.lat1; db_ptr->block_dir_entry_ptr->lat2 = db_ptr->block_hdr.lat2; db_ptr->block_dir_entry_ptr->depth1 = db_ptr->block_hdr.depth1; db_ptr->block_dir_entry_ptr->depth2 = db_ptr->block_hdr.depth2; db_ptr->block_dir_entry_ptr->block_nbytes = db_ptr->block_hdr.block_nbytes; db_ptr->block_dir_entry_ptr->data_mask = db_ptr->block_hdr.data_mask; db_ptr->block_dir_entry_ptr->data_proc_mask = db_ptr->block_hdr.data_proc_mask; } /*----------------------------------------------------------------------------- FUNCTION: write_block_dir_hdr It rewrites the block directory header. Note that the block directory must be open. RETURNS: 0 if successful db_ptr->error_code otherwise */ int write_block_dir_hdr(void) { unsigned int nb = BLOCK_DIR_HDR_SIZE; if (write_data(db_ptr->fpblkdir, (char *) &(db_ptr->block_dir_hdr), 0L, nb) != 0) { db_ptr->error_code = WRITE_ERROR; db_ptr->error_data = BLOCK_DIR_HDR; goto error_found; } return(0); error_found: report_db_error("write_block_dir_hdr"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: write_block_dir It rewrites the block directory. This is useful after the directory has been sorted. The block directory must be open and the directory must be loaded in memory at the location pointed to by db_ptr->block_dir. RETURNS: 0 if successful db_ptr->error_code otherwise */ int write_block_dir(void) { unsigned int nb; long ofs = BLOCK_DIR_HDR_SIZE; nb = db_ptr->block_dir_hdr.dir_nentries * db_ptr->block_dir_hdr.dir_entry_nbytes; if ((db_ptr->error_code = write_data(db_ptr->fpblkdir, db_ptr->block_dir, ofs, nb)) != 0) { db_ptr->error_data = BLOCK_DIR; goto error_found; } return(0); error_found: report_db_error("write_block_dir"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: write_block_dir_entry It rewrites the current block directory entry. RETURNS: 0 if successful db_ptr->error_code otherwise */ int write_block_dir_entry(void) { unsigned int nb; long ofs; nb = db_ptr->block_dir_hdr.dir_entry_nbytes; ofs = BLOCK_DIR_HDR_SIZE + nb * db_ptr->block_dir_index; if ((db_ptr->error_code = write_data(db_ptr->fpblkdir, (char *) db_ptr->block_dir_entry_ptr, ofs, nb)) != 0) { db_ptr->error_data = BLOCK_DIR; goto error_found; } return(0); error_found: report_db_error("write_block_dir_entry"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: write_block_hdr It rewrites the block header. The block must be open. RETURNS: 0 if successful db_ptr->error_code otherwise */ int write_block_hdr(void) { unsigned int nb = BLOCK_HDR_SIZE; if (write_data(db_ptr->fpblkdata, (char *) &(db_ptr->block_hdr), 0L, nb) != 0) { db_ptr->error_code = WRITE_ERROR; db_ptr->error_data = BLOCK_HDR; goto error_found; } return(0); error_found: report_db_error("write_block_hdr"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: write_profile_dir It rewrites the profile directory. This is useful after the directory has been sorted. The profile directory must be open and loaded into memory at the location pointed to by db_ptr->profile_dir. RETURNS: 0 if successful db_ptr->error_code otherwise */ int write_profile_dir(void) { unsigned int nb; long ofs; ofs = db_ptr->block_hdr.dir_ofs; nb = db_ptr->block_hdr.dir_nentries * db_ptr->block_hdr.dir_entry_nbytes; if ((db_ptr->error_code = write_data(db_ptr->fpblkdata, db_ptr->profile_dir, ofs, nb)) != 0) { db_ptr->error_data = PROFILE_DIR; goto error_found; } return(0); error_found: report_db_error("write_profile_dir"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: sort_block_dir It sorts the block directory into ascending order by time. RETURNS: VOID */ void sort_block_dir(void) { int l, n; l = db_ptr->block_dir_hdr.dir_entry_nbytes; n = db_ptr->block_dir_hdr.dir_nentries; db_ptr->block_dir_entry_ptr = (BLOCK_DIR_ENTRY_TYPE *) db_ptr->block_dir; if (db_ptr->block_dir_hdr.dir_nentries > 1) DSORTAS((char *) db_ptr->block_dir, (char *) &(db_ptr->block_dir_entry_ptr->time1), &l, &n); } /*----------------------------------------------------------------------------- FUNCTION: sort_profile_dir It sorts the profile directory into ascending order by time. RETURNS: VOID */ void sort_profile_dir(void) { int l, n; l = db_ptr->block_hdr.dir_entry_nbytes; n = db_ptr->block_hdr.dir_nentries; db_ptr->profile_dir_entry_ptr = (PROFILE_DIR_3_ENTRY_TYPE *) db_ptr->profile_dir; if (db_ptr->block_hdr.dir_nentries > 1) DSORTAS((CHAR *)db_ptr->profile_dir, (CHAR *)&(db_ptr->profile_dir_entry_ptr->time), &l, &n); } /*----------------------------------------------------------------------------- FUNCTION: load_block_dir() It loads the block directory into the memory location pointed to by db_ptr->block_dir. RETURNS: 0 if okay READ_ERROR OR SEEK_ERROR otherwise */ int load_block_dir(void) { unsigned int nb; long ofs; /* ---> READ BLOCK DIRECTORY */ ofs = BLOCK_DIR_HDR_SIZE; if (db_ptr->block_dir_hdr.dir_nentries) { nb = db_ptr->block_dir_hdr.dir_nentries * db_ptr->block_dir_hdr.dir_entry_nbytes; if ((db_ptr->error_code = read_data(db_ptr->fpblkdir, db_ptr->block_dir, ofs, nb)) != 0) { db_ptr->error_data = BLOCK_DIR; goto error_found; } if (db_ptr->block_dir_host != HOST_ENVIRONMENT) { if (convert_array_struct((char *) db_ptr->block_dir, (char *) db_ptr->block_dir, db_ptr->block_dir_host, HOST_ENVIRONMENT, db_ptr->block_dir_hdr.dir_nentries, "block_dir_entry", &(dbint_sd[0].block_dir_entry)) == BADUINT) { db_ptr->error_code = CONVERT_ERROR; db_ptr->error_data = BLOCK_DIR; goto error_found; } } } db_ptr->block_dir_loaded = 1; return(0); error_found: report_db_error("load_block_dir"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: load_profile_dir() It loads the profile directory into memory. RETURNS: 0 if okay SEEK_ERROR OR READ_ERROR otherwise */ int load_profile_dir(void) { unsigned int nb; long ofs; char struct_def_name[20]; if (db_ptr->block_hdr.dir_nentries) { nb = db_ptr->block_hdr.dir_nentries * db_ptr->block_hdr.dir_entry_nbytes; ofs = db_ptr->block_hdr.dir_ofs; if ((db_ptr->error_code = read_data(db_ptr->fpblkdata, db_ptr->profile_dir, ofs, nb)) != 0) { db_ptr->error_data = PROFILE_DIR; goto error_found; } } if (db_ptr->block_host != HOST_ENVIRONMENT) { sprintf(struct_def_name, "profile_dir_%1d_entry", (int) db_ptr->block_hdr.dir_type); if (convert_array_struct(db_ptr->profile_dir, db_ptr->profile_dir, db_ptr->block_host, HOST_ENVIRONMENT, db_ptr->block_hdr.dir_nentries, struct_def_name, &(dbint_sd[0].profile_dir_0_entry)) == BADUINT) { db_ptr->error_code = CONVERT_ERROR; db_ptr->error_data = PROFILE_DIR; goto error_found; } } db_ptr->profile_dir_loaded = 1; return(0); error_found: db_ptr->error_data = PROFILE_DIR; report_db_error("load_profile_dir"); return (db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: load_data_list() It loads the block data access list. RETURNS: 0 if okay SEEK_ERROR OR READ_ERROR otherwise */ int load_data_list(void) { unsigned int nb; long ofs; nb = db_ptr->block_hdr.data_list_nentries * DATA_LIST_ENTRY_SIZE; ofs = db_ptr->block_hdr.data_list_ofs; if ((db_ptr->error_code = read_data(db_ptr->fpblkdata, (char *) db_ptr->data_list, ofs, nb)) != 0) { db_ptr->error_data = DATA_LIST; goto error_found; } if (db_ptr->block_host != HOST_ENVIRONMENT && convert_array_struct((char *) db_ptr->data_list, (char *) db_ptr->data_list, db_ptr->block_host, HOST_ENVIRONMENT, db_ptr->block_hdr.data_list_nentries, "data_list_entry", &(dbint_sd[0].data_list_entry)) == BADUINT) { db_ptr->error_code = CONVERT_ERROR; db_ptr->error_data = DATA_LIST; goto error_found; } db_ptr->data_list_loaded = 1; return(0); error_found: report_db_error("load_data_list"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: open_block_dir() It opens a block directory file and loads the header into block_dir_hdr. RETURNS: 0 if okay UNABLE_TO_OPEN OR READ_ERROR otherwise */ int open_block_dir(void) { int nb; if ((db_ptr->fpblkdir = open_binary_file(db_ptr->block_dir_file, db_ptr->access_mode)) == NULL) { db_ptr->error_code = UNABLE_TO_OPEN; db_ptr->error_data = BLOCK_DIR_FILE; goto error_found; } nb = BLOCK_DIR_HDR_SIZE; if (fread((CHAR *) &(db_ptr->block_dir_hdr), 1, nb, db_ptr->fpblkdir) != nb) { db_ptr->error_code = READ_ERROR; db_ptr->error_data = BLOCK_DIR_HDR; goto error_found; } /* ---> CHECK MACHINE SIGNATURE -- jr+ 95/07 */ if ( (db_ptr->block_dir_host = identify_ms_code(db_ptr->block_dir_hdr.ms_code)) == UNKNOWN_HOST ) { if (!strncmp(db_ptr->block_dir_hdr.ms_code, "\0\0\0\0", 4)) { /* uninitialized field in old database */ union {ULONG all; UBYTE bytes[4];} nsq; nsq.all = db_ptr->block_dir_hdr.next_seq_number; if (nsq.bytes[0] == 0) /* big-endian */ { db_ptr->block_dir_host = SUN3_COMPATIBLE_HOST; } else /* little-endian */ { db_ptr->block_dir_host = PC_COMPATIBLE_HOST; } /* This identification should work so long as the old database is either PC or SUN3, which I expect to be the case. It might be wise to add a warning here--run mkblkdir on these old databases so that they are brought up to date. */ } else { db_ptr->error_code = UNKNOWN_HOST_ERROR; db_ptr->error_data = BLOCK_DIR_HDR; goto error_found; } } if (db_ptr->block_dir_host != HOST_ENVIRONMENT) { if (db_ptr->access_mode == READ_WRITE) /* cross-environment read-write */ /* access not permitted for now */ { db_ptr->error_code = INCOMPATIBLE_HOST_ERROR; db_ptr->error_data = BLOCK_DIR_HDR; goto error_found; } else { if (convert_struct((char *) &(db_ptr->block_dir_hdr), (char *) &(db_ptr->block_dir_hdr), db_ptr->block_dir_host, HOST_ENVIRONMENT, "block_dir_hdr", &(dbint_sd[0].block_dir_hdr)) == BADUINT) { db_ptr->error_code = CONVERT_ERROR; db_ptr->error_data = BLOCK_DIR_HDR; goto error_found; } } } db_ptr->block_dir_is_open = 1; return(0); error_found: report_db_error("open_block_dir"); return(db_ptr->error_code); } /*-------------------------------------------------------------------------- FUNCTION: open_block() It opens a block data file and loads the header into block_hdr. db_ptr->block_dir_entry_ptr points to the corresponding block directory entry. RETURNS: 0 if okay UNABLE_TO_OPEN OR READ_ERROR otherwise */ int open_block(void) { int nb; /* ---> SET BLOCK FILE NAME */ sprintf((db_ptr->block_file + db_ptr->path_nchar), db_ptr->block_dir_hdr.block_file_template, db_ptr->block_dir_entry_ptr->file_id); /* ---> ATTEMPT TO OPEN BLOCK FILE */ if ((db_ptr->fpblkdata = open_binary_file(db_ptr->block_file, db_ptr->access_mode)) == NULL) { db_ptr->error_code = UNABLE_TO_OPEN; db_ptr->error_data = BLOCK_FILE; goto error_found; } /* ---> READ HEADER */ nb = BLOCK_HDR_SIZE; if (fread((char *) &(db_ptr->block_hdr), 1, nb, db_ptr->fpblkdata) != nb) { db_ptr->error_code = READ_ERROR; db_ptr->error_data = BLOCK_HDR; goto error_found; } db_ptr->block_is_open = 1; /* ---> CHECK MACHINE SIGNATURE */ /* if (strncmp(db_ptr->block_hdr.ms_code, MS_TABLE[identify_ms((char *) MACHINE_SIGNATURE)].ms_code, 4)) { db_ptr->error_code = INCOMPATIBLE_HOST_ERROR; db_ptr->error_data = BLOCK_HDR; goto error_found; } */ if ( (db_ptr->block_host = identify_ms_code(db_ptr->block_hdr.ms_code)) == UNKNOWN_HOST) { db_ptr->error_code = UNKNOWN_HOST_ERROR; db_ptr->error_data = BLOCK_HDR; goto error_found; } if (db_ptr->block_host != HOST_ENVIRONMENT) { if (db_ptr->access_mode == READ_WRITE) /* cross-environment read-write */ /* access not permitted for now */ { db_ptr->error_code = INCOMPATIBLE_HOST_ERROR; db_ptr->error_data = BLOCK_HDR; goto error_found; } else { if (convert_struct((char *) &(db_ptr->block_hdr), (char *) &(db_ptr->block_hdr), db_ptr->block_host, HOST_ENVIRONMENT, "block_hdr", &(dbint_sd[0].block_hdr)) == BADUINT) { db_ptr->error_code = CONVERT_ERROR; db_ptr->error_data = BLOCK_HDR; goto error_found; } } } return(0); error_found: report_db_error("open_block"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: allocate_memory_for_directories It allocates memory for the block and profile directories. RETURNS: 0 if okay < 0 otherwise */ int add_memory_for_block_dir(void) { unsigned int nb; nb = ((db_ptr->block_dir_max_nentries + BLOCK_DIR_CHUNK) * BLOCK_DIR_ENTRY_SIZE); if ((db_ptr->block_dir = realloc(db_ptr->block_dir, nb)) == NULL) { db_ptr->error_code = INSUFFICIENT_MEMORY; db_ptr->error_data = BLOCK_DIR; goto error_found; } db_ptr->block_dir_max_nentries += BLOCK_DIR_CHUNK; return(0); error_found: report_db_error("add_memory_for_block_dir"); return(db_ptr->error_code); } int allocate_memory_for_directories(void) { unsigned int nb; db_ptr->block_dir_max_nentries = 0; db_ptr->block_dir = NULL; if (add_memory_for_block_dir()) goto error_found; db_ptr->block_dir_in_memory = 1; nb = MAX_PROFILE_DIR_NBYTES; if ((db_ptr->profile_dir = malloc(nb)) == NULL) { db_ptr->error_code = INSUFFICIENT_MEMORY; db_ptr->error_data = PROFILE_DIR; goto error_found; } db_ptr->profile_dir_in_memory = 1; return(0); error_found: report_db_error("allocate_memory_for_directories"); return(db_ptr->error_code); } /*----------------------------------------------------------------------------- FUNCTION: alignment_check It checks that all structures internal to the database have the expected sizes. RETURNS: 0 if okay UNEXPECTED_STRUCTURE_SIZE otherwise */ int alignment_check(void) { if ((BLOCK_DIR_HDR_SIZE != EXPECTED_BLOCK_DIR_HDR_SIZE) || (BLOCK_DIR_ENTRY_SIZE != EXPECTED_BLOCK_DIR_ENTRY_SIZE) || (BLOCK_HDR_SIZE != EXPECTED_BLOCK_HDR_SIZE) || (DATA_LIST_ENTRY_SIZE != EXPECTED_DATA_LIST_ENTRY_SIZE) || (STRUCT_DEF_HDR_SIZE != EXPECTED_STRUCT_DEF_HDR_SIZE) || (STRUCT_DEF_ELEM_SIZE != EXPECTED_STRUCT_DEF_ELEM_SIZE) || (PROFILE_DIR_0_ENTRY_SIZE != XPCTD_PROFILE_DIR_0_ENTRY_SIZE) || (PROFILE_DIR_1_ENTRY_SIZE != XPCTD_PROFILE_DIR_1_ENTRY_SIZE) || (PROFILE_DIR_2_ENTRY_SIZE != XPCTD_PROFILE_DIR_2_ENTRY_SIZE) || (PROFILE_DIR_3_ENTRY_SIZE != XPCTD_PROFILE_DIR_3_ENTRY_SIZE) || (DATA_DIR_ENTRY_SIZE != EXPECTED_DATA_DIR_ENTRY_SIZE)) return(UNEXPECTED_STRUCTURE_SIZE); else return(0); } /*----------------------------------------------------------------------------- FUNCTION: identify_ms It identifies the system corresponding to a given machine signature. ARGUMENT: ms = machine signature to be identified RETURNS: machine id (0, 1, 2, ...) if known UNKNOWN_HOST (-1) otherwise */ int identify_ms(char *ms) { int i = 0; while (*(MS_TABLE[i].ms_name)) { if (!strncmp(ms, (char *)MS_TABLE[i].signature, MS_SIZE)) return(i); i++; } return(UNKNOWN_HOST); } /*----------------------------------------------------------------------------- FUNCTION: identify_ms_code Given the ms_code ("0000", "1111", "1122", etc.), it returns the machine type for that code. PARAMETER: ms_code = string containing machine signature code RETURNS: 0, 1, 2, ... for machine type assigned to that code UNKNOWN_HOST (-1) if unrecognized */ int identify_ms_code(char *ms_code) { int i = 0; while (*(MS_TABLE[i].ms_name)) { if (!strncmp(ms_code, MS_TABLE[i].ms_code, 4)) return(i); i++; } return(UNKNOWN_HOST); }