db_io.c

Go to the documentation of this file.
00001 /*                         D B _ I O . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1988-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup db4 */
00023 
00024 /*@{*/
00025 /** @file db_io.c
00026  *
00027  * Functions -
00028  *      db_getmrec      Read all records into malloc()ed memory chunk
00029  *      db_get          Get records from database
00030  *      db_put          Put records to database
00031  *
00032  *
00033  *  Authors -
00034  *      Michael John Muuss
00035  *
00036  *  Source -
00037  *      SECAD/VLD Computing Consortium, Bldg 394
00038  *      The U. S. Army Ballistic Research Laboratory
00039  *      Aberdeen Proving Ground, Maryland  21005-5066
00040  *
00041  */
00042 
00043 #ifndef lint
00044 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/db_io.c,v 14.19 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00045 #endif
00046 
00047 #include "common.h"
00048 
00049 #include <stdio.h>
00050 #ifdef HAVE_UNISTD_H
00051 #  include <unistd.h>
00052 #endif
00053 #ifdef HAVE_SYS_TYPES_H
00054 #  include <sys/types.h>
00055 #endif
00056 #ifdef HAVE_STRING_H
00057 #  include <string.h>
00058 #else
00059 #  include <strings.h>
00060 #endif
00061 
00062 #include "machine.h"
00063 #include "vmath.h"
00064 #include "db.h"
00065 #include "raytrace.h"
00066 
00067 #include "./debug.h"
00068 
00069 /**
00070  *                      D B _ R E A D
00071  *
00072  *  Reads 'count' bytes at file offset 'offset' into buffer at 'addr'.
00073  *  A wrapper for the UNIX read() sys-call that takes into account
00074  *  syscall semaphores, stdio-only machines, and in-memory buffering.
00075  *
00076  *  Returns -
00077  *       0      OK
00078  *      -1      failure
00079  */
00080 /* should be HIDDEN */
00081 int
00082 db_read(const struct db_i *dbip, genptr_t addr, long int count, long int offset)
00083                                 /* byte count */
00084                                 /* byte offset from start of file */
00085 {
00086         register int    got;
00087 #ifdef HAVE_UNIX_IO
00088         register long   s;
00089 #endif
00090 
00091         RT_CK_DBI(dbip);
00092         if(RT_G_DEBUG&DEBUG_DB)  {
00093                 bu_log("db_read(dbip=x%x, addr=x%x, count=%d., offset=x%x)\n",
00094                         dbip, addr, count, offset );
00095         }
00096         if( count <= 0 || offset < 0 )  {
00097                 return(-1);
00098         }
00099         if( offset+count > dbip->dbi_eof )  {
00100             /* Attempt to read off the end of the file */
00101             bu_log("db_read(%s) ERROR offset=%d, count=%d, dbi_eof=%d\n",
00102                    dbip->dbi_filename,
00103                    offset, count, dbip->dbi_eof );
00104             return -1;
00105         }
00106         if( dbip->dbi_inmem )  {
00107                 memcpy( addr, ((char *)dbip->dbi_inmem) + offset, count );
00108                 return(0);
00109         }
00110         bu_semaphore_acquire( BU_SEM_SYSCALL );
00111 #ifdef HAVE_LSEEK
00112         if ((s=(long)lseek( dbip->dbi_fd, (off_t)offset, 0 )) != offset) {
00113                 bu_log("db_read: lseek returns %d not %d\n", s, offset);
00114                 bu_bomb("db_read: Goodbye");
00115         }
00116         got = read( dbip->dbi_fd, addr, count );
00117 #else
00118         if (fseek( dbip->dbi_fp, offset, 0 ))
00119                 bu_bomb("db_read: fseek error\n");
00120         got = fread( addr, 1, count, dbip->dbi_fp );
00121 #endif
00122         bu_semaphore_release( BU_SEM_SYSCALL );
00123 
00124         if( got != count )  {
00125             if (got < 0) {
00126                 perror(dbip->dbi_filename);
00127             }
00128             bu_log("db_read(%s):  read error.  Wanted %d, got %d bytes\n",
00129                    dbip->dbi_filename, count, got );
00130             return(-1);
00131         }
00132         return(0);                      /* OK */
00133 }
00134 
00135 /**
00136  *                      D B _ G E T M R E C
00137  *
00138  *  Retrieve all records in the database pertaining to an object,
00139  *  and place them in malloc()'ed storage, which the caller is
00140  *  responsible for free()'ing.
00141  *
00142  *  This loads the combination into a local record buffer.
00143  *  This is in external v4 format.
00144  *
00145  *  Returns -
00146  *      union record *          OK
00147  *      (union record *)0       failure
00148  */
00149 union record *
00150 db_getmrec(const struct db_i *dbip, const struct directory *dp)
00151 {
00152         union record    *where;
00153 
00154         RT_CK_DBI(dbip);
00155         RT_CK_DIR(dp);
00156 
00157         if( dbip->dbi_version >= 5 ) {
00158             /* can't get an mrec on a v5 */
00159             return (union record *)NULL;
00160         }
00161 
00162         if(RT_G_DEBUG&DEBUG_DB) bu_log("db_getmrec(%s) x%x, x%x\n",
00163                 dp->d_namep, dbip, dp );
00164 
00165         if( dp->d_addr < 0 )
00166                 return( (union record *)0 );    /* was dummy DB entry */
00167         where = (union record *)bu_malloc(
00168                 dp->d_len * sizeof(union record),
00169                 "db_getmrec record[]");
00170 
00171         if( dp->d_flags & RT_DIR_INMEM )  {
00172                 bcopy( dp->d_un.ptr, (char *)where, dp->d_len * sizeof(union record) );
00173                 return where;
00174         }
00175 
00176         if( db_read( dbip, (char *)where,
00177             (long)dp->d_len * sizeof(union record),
00178             dp->d_addr ) < 0 )  {
00179                 bu_free( (genptr_t)where, "db_getmrec record[]" );
00180                 return( (union record *)0 );    /* VERY BAD */
00181         }
00182         return( where );
00183 }
00184 
00185 /**
00186  *                      D B _ G E T
00187  *
00188  *  Retrieve 'len' records from the database,
00189  *  "offset" granules into this entry.
00190  *
00191  *  Returns -
00192  *       0      OK
00193  *      -1      failure
00194  */
00195 int
00196 db_get(const struct db_i *dbip, const struct directory *dp, union record *where, int offset, int len)
00197 {
00198 
00199         RT_CK_DBI(dbip);
00200         RT_CK_DIR(dp);
00201         if(RT_G_DEBUG&DEBUG_DB) bu_log("db_get(%s) x%x, x%x x%x off=%d len=%d\n",
00202                 dp->d_namep, dbip, dp, where, offset, len );
00203 
00204         if( dp->d_addr < 0 )  {
00205                 where->u_id = '\0';     /* undefined id */
00206                 return(-1);
00207         }
00208         if( offset < 0 || offset+len > dp->d_len )  {
00209                 bu_log("db_get(%s):  xfer %d..%x exceeds 0..%d\n",
00210                         dp->d_namep, offset, offset+len, dp->d_len );
00211                 where->u_id = '\0';     /* undefined id */
00212                 return(-1);
00213         }
00214 
00215         if( dp->d_flags & RT_DIR_INMEM )  {
00216                 bcopy( ((char *)dp->d_un.ptr) + offset * sizeof(union record),
00217                         (char *)where,
00218                         len * sizeof(union record) );
00219                 return 0;               /* OK */
00220         }
00221 
00222         if( db_read( dbip, (char *)where, (long)len * sizeof(union record),
00223             dp->d_addr + offset * sizeof(union record) ) < 0 )  {
00224                 where->u_id = '\0';     /* undefined id */
00225                 return(-1);
00226         }
00227         return(0);                      /* OK */
00228 }
00229 
00230 /**
00231  *                      D B _ W R I T E
00232  *
00233  *  Writes 'count' bytes into at file offset 'offset' from buffer at 'addr'.
00234  *  A wrapper for the UNIX write() sys-call that takes into account
00235  *  syscall semaphores, stdio-only machines, and in-memory buffering.
00236  *
00237  *  Returns -
00238  *       0      OK
00239  *      -1      failure
00240  */
00241 /* should be HIDDEN */
00242 int
00243 db_write(struct db_i *dbip, const genptr_t addr, long int count, long int offset)
00244 {
00245         register int    got;
00246 
00247         RT_CK_DBI(dbip);
00248         if(RT_G_DEBUG&DEBUG_DB)  {
00249                 bu_log("db_write(dbip=x%x, addr=x%x, count=%d., offset=x%x)\n",
00250                         dbip, addr, count, offset );
00251         }
00252         if( dbip->dbi_read_only )  {
00253                 bu_log("db_write(%s):  READ-ONLY file\n",
00254                         dbip->dbi_filename);
00255                 return(-1);
00256         }
00257         if( count <= 0 || offset < 0 )  {
00258                 return(-1);
00259         }
00260         if( dbip->dbi_inmem )  {
00261                 bu_log("db_write() in memory?\n");
00262                 return(-1);
00263         }
00264         bu_semaphore_acquire( BU_SEM_SYSCALL );
00265 #ifdef HAVE_UNIX_IO
00266         (void)lseek( dbip->dbi_fd, offset, 0 );
00267         got = write( dbip->dbi_fd, addr, count );
00268 #else
00269         (void)fseek( dbip->dbi_fp, offset, 0 );
00270         got = fwrite( addr, 1, count, dbip->dbi_fp );
00271         fflush(dbip->dbi_fp);
00272 #endif
00273         bu_semaphore_release( BU_SEM_SYSCALL );
00274         if( got != count )  {
00275                 perror("db_write");
00276                 bu_log("db_write(%s):  write error.  Wanted %d, got %d bytes.\nFile forced read-only.\n",
00277                         dbip->dbi_filename, count, got );
00278                 dbip->dbi_read_only = 1;
00279                 return(-1);
00280         }
00281         return(0);                      /* OK */
00282 }
00283 
00284 /**
00285  *                      D B _ P U T
00286  *
00287  *  Store 'len' records to the database,
00288  *  "offset" granules into this entry.
00289  *
00290  *  Returns -
00291  *       0      OK
00292  *      -1      failure
00293  */
00294 int
00295 db_put(struct db_i *dbip, const struct directory *dp, union record *where, int offset, int len)
00296 {
00297 
00298         RT_CK_DBI(dbip);
00299         RT_CK_DIR(dp);
00300         if(RT_G_DEBUG&DEBUG_DB) bu_log("db_put(%s) x%x, x%x x%x off=%d len=%d\n",
00301                 dp->d_namep, dbip, dp, where, offset, len );
00302 
00303         if( offset < 0 || offset+len > dp->d_len )  {
00304                 bu_log("db_put(%s):  xfer %d..%x exceeds 0..%d\n",
00305                         dp->d_namep, offset, offset+len, dp->d_len );
00306                 return(-1);
00307         }
00308 
00309         if( dp->d_flags & RT_DIR_INMEM )  {
00310                 bcopy( (char *)where,
00311                         ((char *)dp->d_un.ptr) + offset * sizeof(union record),
00312                         len * sizeof(union record) );
00313                 return 0;               /* OK */
00314         }
00315 
00316         if( dbip->dbi_read_only )  {
00317                 bu_log("db_put(%s):  READ-ONLY file\n",
00318                         dbip->dbi_filename);
00319                 return(-1);
00320         }
00321 
00322         if( db_write( dbip, (char *)where, (long)len * sizeof(union record),
00323             dp->d_addr + offset * sizeof(union record) ) < 0 )  {
00324                 return(-1);
00325         }
00326         return(0);
00327 }
00328 
00329 
00330 
00331 /**
00332  *                      D B _ G E T _ E X T E R N A L
00333  *
00334  *  Obtains a object from the database, leaving it in external (on-disk)
00335  *  format.
00336  *  The bu_external structure represented by 'ep' is initialized here,
00337  *  the caller need not pre-initialize it.  On error, 'ep' is left
00338  *  un-initialized and need not be freed, to simplify error recovery.
00339  *  On success, the caller is responsible for calling bu_free_external(ep);
00340  *
00341  *  Returns -
00342  *      -1      error
00343  *       0      success
00344  */
00345 int
00346 db_get_external(register struct bu_external *ep, const struct directory *dp, const struct db_i *dbip)
00347 {
00348         RT_CK_DBI(dbip);
00349         RT_CK_DIR(dp);
00350         if(RT_G_DEBUG&DEBUG_DB) bu_log("db_get_external(%s) ep=x%x, dbip=x%x, dp=x%x\n",
00351                 dp->d_namep, ep, dbip, dp );
00352 
00353         if( (dp->d_flags & RT_DIR_INMEM) == 0 && dp->d_addr < 0 )
00354                 return( -1 );           /* was dummy DB entry */
00355 
00356         BU_INIT_EXTERNAL(ep);
00357         if( dbip->dbi_version <= 4 )
00358                 ep->ext_nbytes = dp->d_len * sizeof(union record);
00359         else
00360                 ep->ext_nbytes = dp->d_len;
00361         ep->ext_buf = (genptr_t)bu_malloc(ep->ext_nbytes, "db_get_ext ext_buf");
00362 
00363         if( dp->d_flags & RT_DIR_INMEM )  {
00364                 bcopy( dp->d_un.ptr, (char *)ep->ext_buf, ep->ext_nbytes );
00365                 return 0;
00366         }
00367 
00368         if( db_read( dbip, (char *)ep->ext_buf,
00369             (long)ep->ext_nbytes, dp->d_addr ) < 0 )  {
00370                 bu_free( ep->ext_buf, "db_get_ext ext_buf" );
00371                 ep->ext_buf = (genptr_t)NULL;
00372                 ep->ext_nbytes = 0;
00373                 return( -1 );   /* VERY BAD */
00374         }
00375         return(0);
00376 }
00377 
00378 /**
00379  *
00380  *                      D B _ P U T _ E X T E R N A L
00381  *
00382  *  Given that caller already has an external representation of
00383  *  the database object,  update it to have a new name
00384  *  (taken from dp->d_namep) in that external representation,
00385  *  and write the new object into the database, obtaining different storage if
00386  *  the size has changed.
00387  *
00388  *  Caller is responsible for freeing memory of external representation,
00389  *  using bu_free_external().
00390  *
00391  *  This routine is used to efficiently support MGED's "cp" and "keep"
00392  *  commands, which don't need to import objects just to rename and copy them.
00393  *
00394  *  Returns -
00395  *      -1      error
00396  *       0      success
00397  */
00398 int
00399 db_put_external(struct bu_external *ep, struct directory *dp, struct db_i *dbip)
00400 {
00401 
00402         RT_CK_DBI(dbip);
00403         RT_CK_DIR(dp);
00404         BU_CK_EXTERNAL(ep);
00405         if(RT_G_DEBUG&DEBUG_DB) bu_log("db_put_external(%s) ep=x%x, dbip=x%x, dp=x%x\n",
00406                 dp->d_namep, ep, dbip, dp );
00407 
00408 
00409         if( dbip->dbi_read_only )  {
00410                 bu_log("db_put_external(%s):  READ-ONLY file\n",
00411                         dbip->dbi_filename);
00412                 return(-1);
00413         }
00414 
00415         if( dbip->dbi_version == 5 )
00416                 return db_put_external5( ep, dp, dbip );
00417 
00418         if( dbip->dbi_version <= 4 )  {
00419                 int     ngran;
00420 
00421                 ngran = (ep->ext_nbytes+sizeof(union record)-1)/sizeof(union record);
00422                 if( ngran != dp->d_len )  {
00423                         if( dp->d_addr != -1L )  {
00424                                 if( db_delete( dbip, dp ) < 0 )
00425                                         return -2;
00426                         }
00427                         if( db_alloc( dbip, dp, ngran ) < 0 )  {
00428                                 return -3;
00429                         }
00430                 }
00431                 /* Sanity check */
00432                 if( ngran != dp->d_len )  {
00433                         bu_log("db_put_external(%s) ngran=%d != dp->d_len %d\n",
00434                                 dp->d_namep, ngran, dp->d_len );
00435                         bu_bomb("db_io.c: db_put_external()");
00436                 }
00437 
00438                 db_wrap_v4_external( ep, dp->d_namep );
00439         } else
00440                 bu_bomb("db_put_external(): unknown dbi_version\n");
00441 
00442         if( dp->d_flags & RT_DIR_INMEM )  {
00443                 bcopy( (char *)ep->ext_buf, dp->d_un.ptr, ep->ext_nbytes );
00444                 return 0;
00445         }
00446 
00447         if( db_write( dbip, (char *)ep->ext_buf, ep->ext_nbytes, dp->d_addr ) < 0 )  {
00448                 return(-1);
00449         }
00450         return(0);
00451 }
00452 
00453 
00454 /**
00455  *
00456  *                      D B _ F W R I T E _ E X T E R N A L
00457  *
00458  *  Add name from dp->d_namep to external representation of solid,
00459  *  and write it into a file.
00460  *
00461  *  Caller is responsible for freeing memory of external representation,
00462  *  using bu_free_external().
00463  *
00464  *  The 'name' field of the external representation is modified to
00465  *  contain the desired name.
00466  *
00467  *  Returns -
00468  *      <0      error
00469  *      0       OK
00470  *
00471  *  NOTE:  Callers of this should be using wdb_export_external() instead.
00472  */
00473 int
00474 db_fwrite_external(FILE *fp, const char *name, struct bu_external *ep)
00475 
00476 
00477                                                 /* can't be const */
00478 {
00479 
00480         if(RT_G_DEBUG&DEBUG_DB) bu_log("db_fwrite_external(%s) ep=x%x\n",
00481                 name, ep);
00482 
00483         BU_CK_EXTERNAL(ep);
00484 
00485         db_wrap_v4_external( ep, name );
00486 
00487         return bu_fwrite_external( fp, ep );
00488 }
00489 
00490 /**
00491  *                      D B _ F R E E _ E X T E R N A L
00492  *
00493  *  XXX This is a leftover.  You should call bu_free_external() instead.
00494  */
00495 void
00496 db_free_external(register struct bu_external *ep)
00497 {
00498         BU_CK_EXTERNAL(ep);
00499         bu_free_external(ep);
00500 }
00501 
00502 /*@}*/
00503 /*
00504  * Local Variables:
00505  * mode: C
00506  * tab-width: 8
00507  * c-basic-offset: 4
00508  * indent-tabs-mode: t
00509  * End:
00510  * ex: shiftwidth=4 tabstop=8
00511  */

Generated on Mon Sep 18 01:24:49 2006 for BRL-CAD by  doxygen 1.4.6