/* db.c */ #include #include #include #include #include #include #include #include #include #define DB_INIT #include "db.h" int errno; /*----- MISCELLANEOUS UTILITY ROUTINES ---------------------------------------*/ /******************************************************************************/ /* pad_key */ /* purpose: */ /* this routine pads the input key with blanks, from a starting character */ /* position to an ending character position */ /* arguments: */ /* s (input/output) = string to pad with blanks */ /* x0 (input) = starting character position for padding */ /* x1 (input) = ending character position+1, i.e. blanks are placed in */ /* positions s[x0] through s[x1-1] */ /******************************************************************************/ void pad_key( char *s,int x0,int x1 ) { int i; for ( i=x0; i reading */ /* 'w' -> writing */ /* fl (output) = file pointer of the lock file */ /******************************************************************************/ DBM *db_open( char *database,char mode,FILE **fl ) { DBM *db; char *dblock = file_lock_name( database ); db_errno = 0; switch ( mode ) { case 'r': /* read only */ if (( *fl = file_lock( dblock,'s' )) == NULL ) /* lock in shared mode */ { db_errno = errno; sprintf( db_error,"problems locking database for reading: %s",strerror( errno )); return( NULL ); } if (( db = dbm_open( database,O_RDONLY,S_IRWXU|S_IRWXG|S_IRWXO )) == NULL ) { db_errno = errno; sprintf( db_error,"problems opening database for reading: %s",strerror( errno )); return( NULL ); } break; case 'w': /* read/write */ if (( *fl = file_lock( dblock,'x' )) == NULL ) /* lock in exclusive mode */ { db_errno = errno; sprintf( db_error,"problems locking database for writing: %s",strerror( errno )); return( NULL ); } if (( db = dbm_open( database,O_RDWR|O_CREAT,S_IRWXU|S_IRWXG|S_IRWXO )) == NULL ) { db_errno = errno; sprintf( db_error,"problems opening database for writing: %s",strerror( errno )); return( NULL ); } break; } return( db ); } /* end of db_open() */ /******************************************************************************/ /* db_close */ /* purpose: */ /* this routine closes the specified database and releases any locks on it. */ /* arguments: */ /* db (input) = the database pointer of the database to close */ /* fl (input) = the file pointer of the database's lock file */ /******************************************************************************/ void db_close( DBM *db,FILE *fl ) { dbm_close( db ); file_unlock( fl ); } /* end of db_close() */ /******************************************************************************/ /* db_insert */ /* purpose: */ /* this routine writes data with a specified key to a specified database. */ /* all the keys in the database must be of a fixed length, but the length of */ /* the data can vary from record to record. */ /* all keys are unique in the database. */ /* this routine writes in INSERT mode, which means that if the argument key */ /* already exists in the database, the routine will return an error */ /* return value: */ /* the routine returns 0 if no errors occurred. */ /* it returns 1 if an error occurred opening the database file (these errors */ /* are reported to stdout). */ /* it returns 2 if the key already exists in the database */ /* it returns < 0 if an error occurred writing to the database file. */ /* arguments: */ /* database (input) = the name of the database to write to */ /* key (input) = the key to write to the database */ /* key_size (input) = the length of "key" */ /* data (input) = the data to store in the database under "key" */ /******************************************************************************/ int db_insert( char *database,char *key,int key_size,char *data ) { datum dkey, ddata; int e; db_errno = 0; if (( db = db_open( database,'w',&fl )) == NULL ) return( 1 ); /* errors reported in db_open */ dkey.dsize = key_size; dkey.dptr = (char *)malloc( dkey.dsize*sizeof( char )); strncpy( dkey.dptr,key,dkey.dsize ); pad_key( dkey.dptr,strlen( dkey.dptr ),dkey.dsize ); ddata.dsize = strlen( data ); ddata.dptr = (char *)malloc( ddata.dsize*sizeof( char )); strncpy( ddata.dptr,data,ddata.dsize ); e = dbm_store( db,dkey,ddata,DBM_INSERT ); if ( e == 1 ) { db_errno = 2; sprintf( db_error,"key already exists in database" ); } else if ( e != 0 ) { db_errno = e; sprintf( db_error,"problems writing to database: return code = %d",e ); } db_close( db,fl ); return( e ); } /* end of db_insert() */ /******************************************************************************/ /* db_write */ /* purpose: */ /* this routine writes data with a specified key to a specified database. */ /* all the keys in the database must be of a fixed length, but the length of */ /* the data can vary from record to record. */ /* all keys are unique in the database. */ /* this routine writes in REPLACE mode, which means that if the argument key */ /* already exists in the database, the argument data will overwrite the data */ /* that already exists in the database under that key. */ /* return value: */ /* the routine returns 0 if no errors occurred. */ /* it returns 1 if an error occurred opening the database file (these errors */ /* are reported to stdout). */ /* it returns < 0 if an error occurred writing to the database file. */ /* arguments: */ /* database (input) = the name of the database to write to */ /* key (input) = the key to write to the database */ /* key_size (input) = the length of "key" */ /* data (input) = the data to store in the database under "key" */ /******************************************************************************/ int db_write( char *database,char *key,int key_size,char *data ) { datum dkey, ddata; int e; db_errno = 0; if (( db = db_open( database,'w',&fl )) == NULL ) return( 1 ); /* errors reported in db_open */ dkey.dsize = key_size; dkey.dptr = (char *)malloc( dkey.dsize*sizeof( char )); strncpy( dkey.dptr,key,dkey.dsize ); pad_key( dkey.dptr,strlen( dkey.dptr ),dkey.dsize ); ddata.dsize = strlen( data ); ddata.dptr = (char *)malloc( ddata.dsize*sizeof( char )); strncpy( ddata.dptr,data,ddata.dsize ); e = dbm_store( db,dkey,ddata,DBM_REPLACE ); if ( e != 0 ) { db_errno = e; sprintf( db_error,"problems writing to database: return code = %d",e ); } db_close( db,fl ); return( e ); } /* end of db_write() */ /******************************************************************************/ /* db_mwrite */ /* purpose: */ /* this routine allows for multiple writes to the specified database by */ /* having 3 calling modes: the first calling mode opens and locks the data- */ /* base for writing and writes a record to the database; the second mode */ /* writes a record to the database (it assumes that the first mode has */ /* already been executed and it does not close the file after writing); in */ /* this way, the calling program can initiate a series of writes, keeping */ /* the database locked between all calls; the third mode writes a record */ /* to the database and closes and unlocks the database. */ /* all the keys in the database must be of a fixed length, but the length of */ /* the data can vary from record to record. */ /* all keys are unique in the database. */ /* this routine writes in REPLACE mode, which means that if the argument key */ /* already exists in the database, the argument data will overwrite the data */ /* that already exists in the database under that key. */ /* return value: */ /* the routine returns 0 if no errors occurred. */ /* it returns 1 if an error occurred opening the database file (these errors */ /* are reported to stdout). */ /* it returns < 0 if an error occurred writing to the database file. */ /* arguments: */ /* database (input) = the name of the database to write to */ /* mode (input) = calling mode: '1' -> open database and write to it */ /* '2' -> write to database (only) */ /* '3' -> write to database and close it */ /* key (input) = the key to write to the database */ /* key_size (input) = the length of "key" */ /* data (input) = the data to store in the database under "key" */ /******************************************************************************/ int db_mwrite( char *database,char mode,char *key,int key_size,char *data ) { datum dkey, ddata; int e; db_errno = 0; /* open file only if mode == '1' */ if ( mode == '1' ) if (( db = db_open( database,'w',&fl )) == NULL ) return( 1 ); /* errors reported in db_open */ /* always write to file */ dkey.dsize = key_size; dkey.dptr = (char *)malloc( dkey.dsize*sizeof( char )); strncpy( dkey.dptr,key,dkey.dsize ); pad_key( dkey.dptr,strlen( dkey.dptr ),dkey.dsize ); ddata.dsize = strlen( data ); ddata.dptr = (char *)malloc( ddata.dsize*sizeof( char )); strncpy( ddata.dptr,data,ddata.dsize ); e = dbm_store( db,dkey,ddata,DBM_REPLACE ); if ( e != 0 ) { db_errno = e; sprintf( db_error,"problems writing to database: return code = %d",e ); } /* close file only if mode == '3' */ if ( mode == '3' ) db_close( db,fl ); return( e ); } /* end of db_mwrite() */ /******************************************************************************/ /* db_find */ /* purpose: */ /* this routine locates and returns the data in the specified database that */ /* is stored under the specified key. */ /* return value: */ /* the routine returns NULL if the specified key is not found; otherwise, */ /* the routine returns the data string that is stored under the key. */ /* arguments: */ /* database (input) = the name of the database to search */ /* key (input) = the key to search for */ /* key_size (input) = the length of "key" */ /******************************************************************************/ char *db_find( char *database,char *key,int key_size ) { datum dkey, ddata; char *data; db_errno = 0; dkey.dsize = key_size; dkey.dptr = (char *)malloc( dkey.dsize*sizeof( char )); strncpy( dkey.dptr,key,dkey.dsize ); pad_key( dkey.dptr,strlen( dkey.dptr ),dkey.dsize ); if (( db = db_open( database,'r',&fl )) == NULL ) return( NULL ); ddata = dbm_fetch( db,dkey ); db_close( db,fl ); if ( ddata.dptr == NULL ) return( NULL ); else { data = (char *)malloc(( ddata.dsize+1 ) * sizeof( data )); strncpy( data,ddata.dptr,ddata.dsize ); data[ddata.dsize] = '\0'; return( data ); } } /* end of db_find() */ /******************************************************************************/ /* db_delete */ /* purpose: */ /* this routine deletes the record in the specified database that matches */ /* the specified key. */ /* return value: */ /* the routine returns 0 if the record was delete successfully. */ /* the routine returns 1 if an error occurred opening the database (these */ /* errors are reported to stdout). */ /* the routine returns < 0 if an error occurred deleting the record. */ /* arguments: */ /* database (input) = the name of the database from which to delete */ /* key (input) = the key of the record to delete */ /* key_size (input) = the length of "key" */ /******************************************************************************/ int db_delete( char *database,char *key,int key_size ) { datum dkey; int e; db_errno = 0; dkey.dsize = key_size; dkey.dptr = (char *)malloc( dkey.dsize*sizeof( char )); strncpy( dkey.dptr,key,dkey.dsize ); pad_key( dkey.dptr,strlen( dkey.dptr ),dkey.dsize ); if (( db = db_open( database,'w',&fl )) == NULL ) return( 1 ); e = dbm_delete( db,dkey ); if ( e != 0 ) { db_errno = e; sprintf( db_error,"problems deleting from database: return code = %d",e ); } db_close( db,fl ); return( e ); } /* end of db_delete() */ /******************************************************************************/ /* db_update */ /* purpose: */ /* this routine is used to update a record in the specified database. to do */ /* this, the routine must be called twice. in the first call, the routine */ /* fetches the data from the database that is associated with the specified */ /* key and returns it to calling process; the routine locks the database in */ /* exclusive mode. then the calling program can update the data string and */ /* this routine is called again (all the while, the database is still locked */ /* in exclusive mode) and the data string is replaced in the database. */ /* this method is provided to ensure that the database remains locked during */ /* the time that the calling process updates the contents of the data string. */ /* if this locking isn't necessary for some reason, then db_find and db_write */ /* could be called instead. */ /* return value: */ /* the routine returns 0 if processing was successful. */ /* the routine returns 1 if an error occurred opening the database (these */ /* errors are reported to stdout). */ /* the routine returns 2 if the specified key was not found in the database. */ /* (in which case, the database is closed/unlocked before returning) */ /* the routine returns < 0 if an error occurred writing to the database. */ /* (database is closed/unlocked before returning) */ /* arguments: */ /* database (input) = the name of the database to update */ /* mode (input) = calling mode: '1' -> first call (see below for details) */ /* '2' -> second call (see below for details) */ /* key (input) = the key of the record to update */ /* key_size (input) = the length of "key" */ /* data (input/output) = when mode = '1', this data is output AND memory is */ /* allocated here */ /* when mode = '2', this data is input */ /******************************************************************************/ int db_update( char *database,char mode,char *key,int key_size,char **data ) { datum dkey, ddata; int e; db_errno = 0; switch ( mode ) { case '1': /* first call: open database for writing, locking in exclusive mode; */ /* fetch data string associated with specified key; */ /* return data string to calling program for update */ dkey.dsize = key_size; dkey.dptr = (char *)malloc( dkey.dsize*sizeof( char )); strncpy( dkey.dptr,key,dkey.dsize ); pad_key( dkey.dptr,strlen( dkey.dptr ),dkey.dsize ); if (( db = db_open( database,'w',&fl )) == NULL ) return( 1 ); ddata = dbm_fetch( db,dkey ); if ( ddata.dptr == NULL ) { db_errno = 2; sprintf( db_error,"problems updating in database: key not found" ); db_close( db,fl ); return( 2 ); } *data = (char *)malloc(( ddata.dsize + 1 ) * sizeof( char )); strncpy( *data,ddata.dptr,ddata.dsize ); (*data)[ddata.dsize] = '\0'; return( 0 ); break; case '2': /* second call: (database is still opened and locked for writing) */ /* replace updated data string in database; */ /* close database and release lock */ dkey.dsize = key_size; dkey.dptr = (char *)malloc( dkey.dsize*sizeof( char )); strncpy( dkey.dptr,key,dkey.dsize ); pad_key( dkey.dptr,strlen( dkey.dptr ),dkey.dsize ); ddata.dsize = strlen( *data ); ddata.dptr = (char *)malloc( ddata.dsize*sizeof( char )); strncpy( ddata.dptr,*data,ddata.dsize ); e = dbm_store( db,dkey,ddata,DBM_REPLACE ); if ( e != 0 ) { db_errno = e; sprintf( db_error,"problems writing to database: return code = %d",e ); } db_close( db,fl ); return( e ); break; } } /* end of db_update() */ /******************************************************************************/ /* db_print */ /* purpose: */ /* this routine prints the specified record on stdout. */ /* arguments: */ /* key (input) = the key to output */ /* data (input) = the data to output */ /* data_size (input) = the length of "data" (in case it is not null- */ /* terminated) */ /******************************************************************************/ void db_print( char *key,int key_size,char *data,int data_size ) { int i; printf( "key=[" ); for ( i=0; i