BRL-CAD
db_io.c
Go to the documentation of this file.
1 /* D B _ I O . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1988-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @addtogroup db4 */
21 /** @{ */
22 /** @file librt/db_io.c
23  *
24  * v4 database read/write I/O routines
25  *
26  */
27 
28 #include "common.h"
29 
30 #include <string.h>
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34 #include "bio.h"
35 
36 #include "bu/parallel.h"
37 #include "vmath.h"
38 #include "db.h"
39 #include "raytrace.h"
40 
41 
42 /**
43  * Reads 'count' bytes at file offset 'offset' into buffer at 'addr'.
44  * A wrapper for the UNIX read() sys-call that takes into account
45  * syscall semaphores, stdio-only machines, and in-memory buffering.
46  *
47  * Returns -
48  * 0 OK
49  * -1 FAILURE
50  */
51 HIDDEN int
52 db_read(const struct db_i *dbip, void *addr, size_t count, off_t offset)
53 /* byte count */
54 /* byte offset from start of file */
55 {
56  size_t got;
57  int ret;
58 
59  RT_CK_DBI(dbip);
60  if (RT_G_DEBUG&DEBUG_DB) {
61  bu_log("db_read(dbip=%p, addr=%p, count=%zu., offset=x%lx)\n",
62  (void *)dbip, addr, count, offset);
63  }
64  if (count == 0) {
65  return -1;
66  }
67  if (offset+count > (size_t)dbip->dbi_eof) {
68  /* Attempt to read off the end of the file */
69  bu_log("db_read(%s) ERROR offset=%zd, count=%zu, dbi_eof=%zd\n",
70  dbip->dbi_filename,
71  offset, count, dbip->dbi_eof);
72  return -1;
73  }
74  if (dbip->dbi_inmem) {
75  memcpy(addr, ((char *)dbip->dbi_inmem) + offset, count);
76  return 0;
77  }
79 
80  ret = bu_fseek(dbip->dbi_fp, offset, 0);
81  if (ret)
82  bu_bomb("db_read: fseek error\n");
83  got = (size_t)fread(addr, 1, count, dbip->dbi_fp);
84 
86 
87  if (got != count) {
88  perror(dbip->dbi_filename);
89  bu_log("db_read(%s): read error. Wanted %zu, got %zu bytes\n", dbip->dbi_filename, count, got);
90  return -1;
91  }
92  return 0; /* OK */
93 }
94 
95 
96 union record *
97 db_getmrec(const struct db_i *dbip, const struct directory *dp)
98 {
99  union record *where;
100 
101  RT_CK_DBI(dbip);
102  RT_CK_DIR(dp);
103 
104  if (dbip->dbi_version > 4) {
105  /* can't get an mrec on a v5 */
106  return (union record *)NULL;
107  }
108 
109  if (RT_G_DEBUG&DEBUG_DB) bu_log("db_getmrec(%s) %p, %p\n",
110  dp->d_namep, (void *)dbip, (void *)dp);
111 
112  if (dp->d_addr == RT_DIR_PHONY_ADDR)
113  return (union record *)0; /* was dummy DB entry */
114  where = (union record *)bu_malloc(
115  dp->d_len * sizeof(union record),
116  "db_getmrec record[]");
117 
118  if (dp->d_flags & RT_DIR_INMEM) {
119  memcpy((char *)where, dp->d_un.ptr, dp->d_len * sizeof(union record));
120  return where;
121  }
122 
123  if (db_read(dbip, (char *)where,
124  dp->d_len * sizeof(union record),
125  dp->d_addr) < 0) {
126  bu_free((void *)where, "db_getmrec record[]");
127  return (union record *)0; /* VERY BAD */
128  }
129  return where;
130 }
131 
132 
133 int
134 db_get(const struct db_i *dbip, const struct directory *dp, union record *where, off_t offset, size_t len)
135 {
136 
137  RT_CK_DBI(dbip);
138  RT_CK_DIR(dp);
139  if (RT_G_DEBUG&DEBUG_DB) bu_log("db_get(%s) %p, %p %p off=%ld len=%zu\n",
140  dp->d_namep, (void *)dbip, (void *)dp, (void *)where, offset, len);
141 
142  if (dp->d_addr == RT_DIR_PHONY_ADDR) {
143  where->u_id = '\0'; /* undefined id */
144  return -1;
145  }
146  if (offset < 0 || len+(size_t)offset > dp->d_len) {
147  bu_log("db_get(%s): xfer %lu..%lu exceeds 0..%zu\n",
148  dp->d_namep, offset, offset+len, dp->d_len);
149  where->u_id = '\0'; /* undefined id */
150  return -1;
151  }
152 
153  if (dp->d_flags & RT_DIR_INMEM) {
154  memcpy((char *)where,
155  ((char *)dp->d_un.ptr) + offset * sizeof(union record),
156  len * sizeof(union record));
157  return 0; /* OK */
158  }
159 
160  if (db_read(dbip, (char *)where, len * sizeof(union record),
161  dp->d_addr + offset * sizeof(union record)) < 0) {
162  where->u_id = '\0'; /* undefined id */
163  return -1;
164  }
165  return 0; /* OK */
166 }
167 
168 
169 int
170 db_write(struct db_i *dbip, const void *addr, size_t count, off_t offset)
171 {
172  register size_t got;
173 
174  RT_CK_DBI(dbip);
175  if (RT_G_DEBUG&DEBUG_DB) {
176  bu_log("db_write(dbip=%p, addr=%p, count=%zu., offset=x%lx)\n",
177  (void *)dbip, addr, count, offset);
178  }
179  if (dbip->dbi_read_only) {
180  bu_log("db_write(%s): READ-ONLY file\n",
181  dbip->dbi_filename);
182  return -1;
183  }
184  if (count == 0) {
185  return -1;
186  }
187  if (dbip->dbi_inmem) {
188  bu_log("db_write() in memory?\n");
189  return -1;
190  }
193 
194  (void)bu_fseek(dbip->dbi_fp, offset, 0);
195  got = fwrite(addr, 1, count, dbip->dbi_fp);
196  fflush(dbip->dbi_fp);
197 
200  if (got != count) {
201  perror("db_write");
202  bu_log("db_write(%s): write error. Wanted %zu, got %zu bytes.\nFile forced read-only.\n",
203  dbip->dbi_filename, count, got);
204  dbip->dbi_read_only = 1;
205  return -1;
206  }
207  return 0; /* OK */
208 }
209 
210 
211 int
212 db_put(struct db_i *dbip, const struct directory *dp, union record *where, off_t offset, size_t len)
213 {
214  RT_CK_DBI(dbip);
215  RT_CK_DIR(dp);
216 
217  if (RT_G_DEBUG&DEBUG_DB) bu_log("db_put(%s) %p, %p %p off=%ld len=%zu\n",
218  dp->d_namep, (void *)dbip, (void *)dp, (void *)where, offset, len);
219 
220  if ((len+(size_t)offset) > dp->d_len) {
221  bu_log("db_put(%s): xfer %ld..%lu exceeds 0..%zu\n",
222  dp->d_namep, offset, offset+len, dp->d_len);
223  return -1;
224  }
225 
226  if (dp->d_flags & RT_DIR_INMEM) {
227  memcpy(((char *)dp->d_un.ptr) + offset * sizeof(union record),
228  (char *)where,
229  len * sizeof(union record));
230  return 0; /* OK */
231  }
232 
233  if (dbip->dbi_read_only) {
234  bu_log("db_put(%s): READ-ONLY file\n",
235  dbip->dbi_filename);
236  return -1;
237  }
238 
239  if (db_write(dbip, (char *)where, len * sizeof(union record),
240  dp->d_addr + offset * sizeof(union record)) < 0) {
241  return -1;
242  }
243  return 0;
244 }
245 
246 
247 int
248 db_get_external(register struct bu_external *ep, const struct directory *dp, const struct db_i *dbip)
249 {
250  RT_CK_DBI(dbip);
251  RT_CK_DIR(dp);
252  if (RT_G_DEBUG&DEBUG_DB) bu_log("db_get_external(%s) ep=%p, dbip=%p, dp=%p\n",
253  dp->d_namep, (void *)ep, (void *)dbip, (void *)dp);
254 
255  if ((dp->d_flags & RT_DIR_INMEM) == 0 && dp->d_addr == RT_DIR_PHONY_ADDR)
256  return -1; /* was dummy DB entry */
257 
258  BU_EXTERNAL_INIT(ep);
259  if (dbip->dbi_version < 5)
260  ep->ext_nbytes = dp->d_len * sizeof(union record);
261  else
262  ep->ext_nbytes = dp->d_len;
263  ep->ext_buf = (uint8_t *)bu_malloc(ep->ext_nbytes, "db_get_ext ext_buf");
264 
265  if (dp->d_flags & RT_DIR_INMEM) {
266  memcpy((char *)ep->ext_buf, dp->d_un.ptr, ep->ext_nbytes);
267  return 0;
268  }
269 
270  if (db_read(dbip, (char *)ep->ext_buf, ep->ext_nbytes, dp->d_addr) < 0) {
271  bu_free(ep->ext_buf, "db_get_ext ext_buf");
272  ep->ext_buf = (uint8_t *)NULL;
273  ep->ext_nbytes = 0;
274  return -1; /* VERY BAD */
275  }
276  return 0;
277 }
278 
279 
280 int
281 db_put_external(struct bu_external *ep, struct directory *dp, struct db_i *dbip)
282 {
283 
284  RT_CK_DBI(dbip);
285  RT_CK_DIR(dp);
286  BU_CK_EXTERNAL(ep);
287  if (RT_G_DEBUG&DEBUG_DB) bu_log("db_put_external(%s) ep=%p, dbip=%p, dp=%p\n",
288  dp->d_namep, (void *)ep, (void *)dbip, (void *)dp);
289 
290 
291  if (dbip->dbi_read_only) {
292  bu_log("db_put_external(%s): READ-ONLY file\n",
293  dbip->dbi_filename);
294  return -1;
295  }
296 
297  if (db_version(dbip) == 5)
298  return db_put_external5(ep, dp, dbip);
299 
300  if (db_version(dbip) < 5) {
301  size_t ngran;
302 
303  ngran = (ep->ext_nbytes+sizeof(union record)-1)/sizeof(union record);
304  if (ngran != dp->d_len) {
305  if (dp->d_addr != RT_DIR_PHONY_ADDR) {
306  if (db_delete(dbip, dp))
307  return -2;
308  }
309  if (db_alloc(dbip, dp, ngran)) {
310  return -3;
311  }
312  }
313  /* Sanity check */
314  if (ngran != dp->d_len) {
315  bu_log("db_put_external(%s) ngran=%zu != dp->d_len %zu\n",
316  dp->d_namep, ngran, dp->d_len);
317  bu_bomb("db_io.c: db_put_external()");
318  }
319 
320  db_wrap_v4_external(ep, dp->d_namep);
321  } else
322  bu_bomb("db_put_external(): unknown dbi_version\n");
323 
324  if (dp->d_flags & RT_DIR_INMEM) {
325  memcpy(dp->d_un.ptr, (char *)ep->ext_buf, ep->ext_nbytes);
326  return 0;
327  }
328 
329  if (db_write(dbip, (char *)ep->ext_buf, ep->ext_nbytes, dp->d_addr) < 0) {
330  return -1;
331  }
332  return 0;
333 }
334 
335 
336 int
337 db_fwrite_external(FILE *fp, const char *name, struct bu_external *ep)
338 {
339 
340  if (RT_G_DEBUG&DEBUG_DB) bu_log("db_fwrite_external(%s) ep=%p\n", name, (void *)ep);
341 
342  BU_CK_EXTERNAL(ep);
343 
344  db_wrap_v4_external(ep, name);
345 
346  return bu_fwrite_external(fp, ep);
347 }
348 
349 
350 /** @} */
351 /*
352  * Local Variables:
353  * mode: C
354  * tab-width: 8
355  * indent-tabs-mode: t
356  * c-file-style: "stroustrup"
357  * End:
358  * ex: shiftwidth=4 tabstop=8
359  */
char * d_namep
pointer to name string
Definition: raytrace.h:859
Definition: raytrace.h:800
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
int bu_restore_interrupts(void)
Definition: interrupt.c:217
size_t d_len
of db granules used
Definition: raytrace.h:867
#define RT_DIR_INMEM
object is in memory (only)
Definition: raytrace.h:889
Definition: clone.c:90
void bu_semaphore_acquire(unsigned int i)
Definition: semaphore.c:180
int bu_fwrite_external(FILE *fp, const struct bu_external *ep)
Definition: parse.c:2368
int bu_fseek(FILE *stream, off_t offset, int origin)
Definition: file.c:330
int db_version(struct db_i *dbip)
Definition: db5_scan.c:414
Header file for the BRL-CAD common definitions.
int db_put_external5(struct bu_external *ep, struct directory *dp, struct db_i *dbip)
Definition: db5_io.c:744
#define HIDDEN
Definition: common.h:86
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
HIDDEN int db_read(const struct db_i *dbip, void *addr, size_t count, off_t offset)
Definition: db_io.c:52
#define RT_G_DEBUG
Definition: raytrace.h:1718
#define RT_CK_DIR(_dp)
Definition: raytrace.h:876
off_t dbi_eof
PRIVATE: End+1 pos after db_scan()
Definition: raytrace.h:816
int db_alloc(struct db_i *, struct directory *dp, size_t count)
uint8_t * ext_buf
Definition: parse.h:216
void * dbi_inmem
PRIVATE: ptr to in-memory copy.
Definition: raytrace.h:820
#define RT_DIR_PHONY_ADDR
Special marker for d_addr field.
Definition: raytrace.h:879
void db_wrap_v4_external(struct bu_external *op, const char *name)
Definition: db_comb.c:885
int db_fwrite_external(FILE *fp, const char *name, struct bu_external *ep)
Definition: db_io.c:337
FILE * dbi_fp
PRIVATE: object hash table.
Definition: raytrace.h:815
void bu_semaphore_release(unsigned int i)
Definition: semaphore.c:218
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
int dbi_read_only
!0 => read only file
Definition: raytrace.h:806
int db_get_external(register struct bu_external *ep, const struct directory *dp, const struct db_i *dbip)
Definition: db_io.c:248
union directory::@8 d_un
#define DEBUG_DB
5 Database debugging
Definition: raytrace.h:88
#define BU_SEM_SYSCALL
Definition: parallel.h:178
int db_write(struct db_i *dbip, const void *addr, size_t count, off_t offset)
Definition: db_io.c:170
int db_get(const struct db_i *dbip, const struct directory *dp, union record *where, off_t offset, size_t len)
Definition: db_io.c:134
#define BU_EXTERNAL_INIT(_p)
Definition: parse.h:229
void * ptr
ptr to in-memory-only obj
Definition: raytrace.h:862
int db_put_external(struct bu_external *ep, struct directory *dp, struct db_i *dbip)
Definition: db_io.c:281
int bu_suspend_interrupts(void)
Definition: interrupt.c:191
int dbi_version
PRIVATE: use db_version()
Definition: raytrace.h:824
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
#define BU_CK_EXTERNAL(_p)
Definition: parse.h:224
size_t ext_nbytes
Definition: parse.h:210
union record * db_getmrec(const struct db_i *dbip, const struct directory *dp)
Definition: db_io.c:97
int d_flags
flags
Definition: raytrace.h:869
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
char * dbi_filename
file name
Definition: raytrace.h:805
int db_delete(struct db_i *, struct directory *dp)
Definition: db_alloc.c:132
int db_put(struct db_i *dbip, const struct directory *dp, union record *where, off_t offset, size_t len)
Definition: db_io.c:212