]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/global/lib/dbop.c
Import Global v3_4_2 sources.
[FreeBSD/FreeBSD.git] / contrib / global / lib / dbop.c
1 /*
2  * Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
3  *
4  * Redilogibution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redilogibutions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redilogibutions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the dilogibution.
12  * 3. All advertising materials mentioning features or use of this software
13  *    must display the following acknowledgement:
14  *      This product includes software developed by Shigio Yamaguchi.
15  * 4. Neither the name of the author nor the names of any co-contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *      dbop.c                                  12-Nov-98
32  *
33  */
34 #include <sys/types.h>
35 #include <sys/stat.h>
36
37 #include <assert.h>
38 #include <fcntl.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include "dbop.h"
44 #include "die.h"
45 #include "test.h"
46
47 static DBT      key;                            /* key of record        */
48 static DBT      dat;                            /* data of record       */
49 /*
50  * dbop_open: open db database.
51  *
52  *      i)      dbname  database name
53  *      i)      mode    0: read only, 1: create, 2: modify
54  *      i)      perm    file permission
55  *      i)      flags
56  *                      DBOP_DUP: allow duplicate records.
57  *                      DBOP_REMOVE: remove on closed.
58  *      r)              descripter for dbop_xxx()
59  */
60 DBOP    *
61 dbop_open(dbname, mode, perm, flags)
62 const char *dbname;
63 int     mode;
64 int     perm;
65 int     flags;
66 {
67         DB      *db;
68         int     rw = 0;
69         DBOP    *dbop;
70         BTREEINFO info;
71
72         /*
73          * setup argments.
74          */
75         switch (mode) {
76         case 0:
77                 rw = O_RDONLY;
78                 break;
79         case 1:
80                 rw = O_RDWR|O_CREAT|O_TRUNC;
81                 break;
82         case 2:
83                 rw = O_RDWR;
84                 break;
85         default:
86                 assert(0);
87         }
88         memset(&info, 0, sizeof(info));
89         if (flags & DBOP_DUP)
90                 info.flags |= R_DUP;
91         info.cachesize = 500000;
92
93         /*
94          * if unlink do job normally, those who already open tag file can use
95          * it until closing.
96          */
97         if (mode == 1 && test("f", dbname))
98                 (void)unlink(dbname);
99         db = dbopen(dbname, rw, 0600, DB_BTREE, &info);
100         if (!db)
101                 return NULL;
102         if (!(dbop = (DBOP *)malloc(sizeof(DBOP))))
103                 die("short of memory.");
104         strcpy(dbop->dbname, dbname);
105         dbop->db        = db;
106         dbop->openflags = flags;
107         dbop->perm      = (mode == 1) ? perm : 0;
108         dbop->lastkey   = NULL;
109         dbop->lastdat   = NULL;
110
111         return dbop;
112 }
113 /*
114  * dbop_get: get data by a key.
115  *
116  *      i)      dbop    descripter
117  *      i)      name    name
118  *      r)              pointer to data
119  */
120 char    *
121 dbop_get(dbop, name)
122 DBOP    *dbop;
123 const char *name;
124 {
125         DB      *db = dbop->db;
126         int     status;
127
128         key.data = (char *)name;
129         key.size = strlen(name)+1;
130
131         status = (*db->get)(db, &key, &dat, 0);
132         dbop->lastkey   = (char *)key.data;
133         dbop->lastdat   = (char *)dat.data;
134         switch (status) {
135         case RET_SUCCESS:
136                 break;
137         case RET_ERROR:
138                 die("cannot read from database.");
139         case RET_SPECIAL:
140                 return (NULL);
141         }
142         return((char *)dat.data);
143 }
144 /*
145  * dbop_put: put data by a key.
146  *
147  *      i)      dbop    descripter
148  *      i)      name    key
149  *      i)      data    data
150  */
151 void
152 dbop_put(dbop, name, data)
153 DBOP    *dbop;
154 const char *name;
155 const char *data;
156 {
157         DB      *db = dbop->db;
158         int     status;
159
160         if (strlen(name) > MAXKEYLEN)
161                 die("primary key too long.");
162         key.data = (char *)name;
163         key.size = strlen(name)+1;
164         dat.data = (char *)data;
165         dat.size = strlen(data)+1;
166
167         status = (*db->put)(db, &key, &dat, 0);
168         switch (status) {
169         case RET_SUCCESS:
170                 break;
171         case RET_ERROR:
172         case RET_SPECIAL:
173                 die("cannot write to database.");
174         }
175 }
176 /*
177  * dbop_del: delete record by a key.
178  *
179  *      i)      dbop    descripter
180  *      i)      name    key
181  */
182 void
183 dbop_del(dbop, name)
184 DBOP    *dbop;
185 const char *name;
186 {
187         DB      *db = dbop->db;
188         int     status;
189
190         if (name) {
191                 key.data = (char *)name;
192                 key.size = strlen(name)+1;
193                 status = (*db->del)(db, &key, 0);
194         } else
195                 status = (*db->del)(db, &key, R_CURSOR);
196         if (status == RET_ERROR)
197                 die("cannot delete record.");
198 }
199 /*
200  * dbop_first: get first record. 
201  * 
202  *      i)      dbop    dbop descripter
203  *      i)      name    key
204  *                      !=NULL: indexed read by key
205  *                      ==NULL: sequential read
206  *      i)      flags   following dbop_next call take over this.
207  *                      DBOP_KEY        read key part
208  *                      DBOP_PREFIX     prefix read
209  *                                      only valied when sequential read
210  *      r)              data
211  */
212 char    *
213 dbop_first(dbop, name, flags)
214 DBOP    *dbop;
215 const char *name;
216 int     flags;
217 {
218         DB      *db = dbop->db;
219         int     status;
220
221         if (flags & DBOP_PREFIX && !name)
222                 flags &= ~DBOP_PREFIX;
223         if (name) {
224                 if (strlen(name) > MAXKEYLEN)
225                         die("primary key too long.");
226                 strcpy(dbop->key, name);
227                 key.data = (char *)name;
228                 key.size = strlen(name);
229                 /*
230                  * includes NULL character unless prefix read.
231                  */
232                 if (!(flags & DBOP_PREFIX))
233                         key.size++;
234                 dbop->keylen = key.size;
235                 status = (*db->seq)(db, &key, &dat, R_CURSOR);
236         } else {
237                 dbop->keylen = dbop->key[0] = 0;
238                 /* skip META records */
239                 for (status = (*db->seq)(db, &key, &dat, R_FIRST);
240                         status == RET_SUCCESS;
241                         status = (*db->seq)(db, &key, &dat, R_NEXT)) {
242                         int c = (flags & DBOP_KEY) ? *((char *)key.data) : *((char *)dat.data);
243                         if (c != ' ')
244                                 break;
245                 }
246         }
247         dbop->lastkey   = (char *)key.data;
248         dbop->lastdat   = (char *)dat.data;
249         switch (status) {
250         case RET_SUCCESS:
251                 break;
252         case RET_ERROR:
253                 die("dbop_first failed.");
254         case RET_SPECIAL:
255                 return (NULL);
256         }
257         dbop->ioflags = flags;
258         if (flags & DBOP_PREFIX) {
259                 if (strncmp((char *)key.data, dbop->key, dbop->keylen))
260                         return NULL;
261         } else if (dbop->keylen) {
262                 if (strcmp((char *)key.data, dbop->key))
263                         return NULL;
264         }
265         if (flags & DBOP_KEY) {
266                 strcpy(dbop->prev, (char *)key.data);
267                 return (char *)key.data;
268         }
269         return ((char *)dat.data);
270 }
271 /*
272  * dbop_next: get next record. 
273  * 
274  *      i)      dbop    dbop descripter
275  *      r)              data
276  *
277  * Db_next always skip meta records.
278  */
279 char    *
280 dbop_next(dbop)
281 DBOP    *dbop;
282 {
283         DB      *db = dbop->db;
284         int     flags = dbop->ioflags;
285         int     status;
286
287         while ((status = (*db->seq)(db, &key, &dat, R_NEXT)) == RET_SUCCESS) {
288                 assert(dat.data != NULL);
289                 if (flags & DBOP_KEY && *((char *)key.data) == ' ')
290                         continue;
291                 else if (*((char *)dat.data) == ' ')
292                         continue;
293                 if (flags & DBOP_KEY) {
294                         if (!strcmp(dbop->prev, (char *)key.data))
295                                 continue;
296                         if (strlen((char *)key.data) > MAXKEYLEN)
297                                 die("primary key too long.");
298                         strcpy(dbop->prev, (char *)key.data);
299                 }
300                 dbop->lastkey   = (char *)key.data;
301                 dbop->lastdat   = (char *)dat.data;
302                 if (flags & DBOP_PREFIX) {
303                         if (strncmp((char *)key.data, dbop->key, dbop->keylen))
304                                 return NULL;
305                 } else if (dbop->keylen) {
306                         if (strcmp((char *)key.data, dbop->key))
307                                 return NULL;
308                 }
309                 return (flags & DBOP_KEY) ? (char *)key.data : (char *)dat.data;
310         }
311         if (status == RET_ERROR)
312                 die("dbop_next failed.");
313         return NULL;
314 }
315 /*
316  * dbop_close: close db
317  * 
318  *      i)      dbop    dbop descripter
319  */
320 void
321 dbop_close(dbop)
322 DBOP    *dbop;
323 {
324         DB      *db = dbop->db;
325
326         (void)db->close(db);
327         if (dbop->openflags & DBOP_REMOVE)
328                 (void)unlink(dbop->dbname);
329         else if (dbop->perm && chmod(dbop->dbname, dbop->perm) < 0)
330                 die("cannot change file mode.");
331         (void)free(dbop);
332 }