1 /*
2  * DB1->3 compatibility layer
3  */
4 
5 #include "config.h"
6 
7 #include <assert.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <fcntl.h>
13 
14 #include "../common/vi_db.h"
15 #include "../common/dbinternal.h"
16 
17 /*
18  * DB_ENV emulation
19  */
20 
21 static int db1_dbenv_close(DB_ENV *, u_int32_t);
22 static int db1_dbenv_open(DB_ENV *, char *, u_int32_t, int);
23 static int db1_dbenv_remove(DB_ENV *, char *, u_int32_t);
24 
25 int
db_env_create(DB_ENV ** dbenvp,u_int32_t flags)26 db_env_create(DB_ENV **dbenvp, u_int32_t flags) {
27           DB_ENV *dbenv;
28 
29           assert(flags == 0);
30 
31           dbenv = malloc(sizeof *dbenv);
32           if (dbenv == NULL)
33                     return -1;
34 
35           dbenv->close = db1_dbenv_close;
36           dbenv->open = db1_dbenv_open;
37           dbenv->remove = db1_dbenv_remove;
38 
39           dbenv->base_path = NULL;
40           dbenv->mode = 0;
41 
42           *dbenvp = dbenv;
43           return 0;
44 }
45 
46 static int
db1_dbenv_close(DB_ENV * dbenv,u_int32_t flags)47 db1_dbenv_close(DB_ENV *dbenv, u_int32_t flags) {
48           assert(flags == 0);
49 
50           if (dbenv->base_path != NULL)
51                     free(dbenv->base_path);
52 
53           free(dbenv);
54           return 0;
55 }
56 
57 static int
db1_dbenv_open(DB_ENV * dbenv,char * base_path,u_int32_t flags,int mode)58 db1_dbenv_open(DB_ENV *dbenv, char *base_path, u_int32_t flags, int mode) {
59 
60           /* We ignore flags on purpose */
61 
62           dbenv->base_path = strdup(base_path);
63           if (dbenv->base_path == NULL)
64                     return ENOSPC;
65 
66           dbenv->mode = mode != 0? mode : 0660;
67           return 0;
68 }
69 
70 static int
db1_dbenv_remove(DB_ENV * dbenv_fake,char * base_path,u_int32_t flags)71 db1_dbenv_remove(DB_ENV *dbenv_fake, char *base_path, u_int32_t flags) {
72           /* dbenv_fake is not a useful environment */
73           /* XXX check if we have to remove files here */
74 
75           return 0;
76 }
77 
78 /*
79  * DB emulation
80  */
81 static int db1_db_close(DB *, u_int32_t);
82 static int db1_db_open(DB *, const char *, const char *, DBTYPE, u_int32_t, int);
83 static int db1_db_sync(DB *, u_int32_t);
84 static int db1_db_get(DB *, DB_TXN *, DBT *, DBT *, u_int32_t);
85 static int db1_db_put(DB *, DB_TXN *, DBT *, DBT *, u_int32_t);
86 static int db1_db_del(DB *, DB_TXN *, DBT *, u_int32_t);
87 static int db1_db_set_flags(DB *, u_int32_t);
88 static int db1_db_set_pagesize(DB *, u_int32_t);
89 static int db1_db_set_re_delim(DB *, int);
90 static int db1_db_set_re_source(DB *, const char *);
91 static int db1_db_cursor(DB *, DB_TXN *, DBC **, u_int32_t);
92 
93 int
db_create(DB ** dbp,DB_ENV * dbenv,u_int32_t flags)94 db_create(DB **dbp, DB_ENV *dbenv, u_int32_t flags) {
95           assert(flags == 0);
96 
97           *dbp = malloc(sizeof **dbp);
98           if (*dbp == NULL)
99                     return -1;
100 
101           (*dbp)->type = DB_UNKNOWN;
102           (*dbp)->actual_db = NULL;
103           (*dbp)->_pagesize = 0;
104           (*dbp)->_flags = 0;
105           memset(&(*dbp)->_recno_info, 0, sizeof (RECNOINFO));
106 
107           (*dbp)->close = db1_db_close;
108           (*dbp)->open = db1_db_open;
109           (*dbp)->sync = db1_db_sync;
110           (*dbp)->get = db1_db_get;
111           (*dbp)->put = db1_db_put;
112           (*dbp)->del = db1_db_del;
113           (*dbp)->set_flags = db1_db_set_flags;
114           (*dbp)->set_pagesize = db1_db_set_pagesize;
115           (*dbp)->set_re_delim = db1_db_set_re_delim;
116           (*dbp)->set_re_source = db1_db_set_re_source;
117           (*dbp)->cursor = db1_db_cursor;
118 
119           return 0;
120 }
121 
122 const char *
db_strerror(int error)123 db_strerror(int error) {
124           return error > 0? strerror(error) : "record not found";
125 }
126 
127 static int
db1_db_close(DB * db,u_int32_t flags)128 db1_db_close(DB *db, u_int32_t flags) {
129           if (flags & DB_NOSYNC) {
130                     /* XXX warn user? */
131           }
132           db->actual_db->close(db->actual_db);
133 
134           db->type = DB_UNKNOWN;
135           db->actual_db = NULL;
136           db->_pagesize = 0;
137           db->_flags = 0;
138           memset(&db->_recno_info, 0, sizeof (RECNOINFO));
139 
140           return 0;
141 }
142 
143 static int
db1_db_open(DB * db,const char * file,const char * database,DBTYPE type,u_int32_t flags,int mode)144 db1_db_open(DB *db, const char *file, const char *database, DBTYPE type,
145                                                             u_int32_t flags, int mode) {
146           int oldflags = 0;
147 
148           assert(database == NULL && !(flags & ~(DB_CREATE | DB_TRUNCATE)));
149 
150           db->type = type;
151 
152           if (flags & DB_CREATE)
153                     oldflags |= O_CREAT;
154           if (flags & DB_TRUNCATE)
155                     oldflags |= O_TRUNC;
156 
157           if (type == DB_RECNO) {
158                     const char *tmp = file;
159 
160                     /* The interface is reversed in DB3 */
161                     file = db->_recno_info.bfname;
162                     db->_recno_info.bfname = __UNCONST(tmp);
163 
164                     /* ... and so, we should avoid to truncate the main file! */
165                     oldflags &= ~O_TRUNC;
166 
167                     db->_recno_info.flags =
168                               db->_flags & DB_SNAPSHOT? R_SNAPSHOT : 0;
169                     db->_recno_info.psize = db->_pagesize;
170           }
171 
172           db->actual_db = dbopen(file, oldflags, mode, type,
173                                         type == DB_RECNO? &db->_recno_info : NULL);
174 
175           return db->actual_db == NULL? errno : 0;
176 }
177 
178 static int
db1_db_sync(DB * db,u_int32_t flags)179 db1_db_sync(DB *db, u_int32_t flags) {
180           assert(flags == 0);
181 
182           return db->actual_db->sync(db->actual_db, db->type == DB_UNKNOWN?
183                                                   R_RECNOSYNC : 0) == 0? 0 : errno;
184 }
185 
186 static int
db1_db_get(DB * db,DB_TXN * txnid,DBT * key,DBT * data,u_int32_t flags)187 db1_db_get(DB *db, DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags) {
188           int err;
189           DBT_v1 data1;
190 
191           assert(flags == 0 && txnid == NULL);
192 
193           err = db->actual_db->get(db->actual_db, (DBT_v1 *) key, &data1, flags);
194           if (err == 1)
195                     return DB_NOTFOUND;
196           else if (err == -1)
197                     return errno;
198 
199           if (data->flags & DB_DBT_USERMEM) {
200                     data->size = data1.size;
201                     if (data1.size > data->ulen)
202                               return DB_BUFFER_SMALL;
203 
204                     memcpy(data->data, data1.data, data1.size);
205           }
206 
207           return 0;
208 }
209 
210 static int
db1_db_put(DB * db,DB_TXN * txnid,DBT * key,DBT * data,u_int32_t flags)211 db1_db_put(DB *db, DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags) {
212           int err;
213           DB_old *db_v1 = db->actual_db;
214           DBT data1;
215           DBT key1;
216           recno_t recno = 1;
217 
218           assert((flags & ~DB_APPEND) == 0 && txnid == NULL);
219 
220           key1 = *key;
221 
222           if (flags & DB_APPEND) {
223                     if (db_v1->seq(db_v1, (DBT_v1 *)(void *)key,
224                         (DBT_v1 *)(void *)&data1, R_LAST) == 1) {
225                               key1.data = &recno;
226                               key1.size = sizeof recno;
227                     }
228           }
229           err = db_v1->put(db_v1, (DBT_v1 *)(void *)&key1, (DBT_v1 *)(void *)data,
230               0);
231 
232           return err == -1? errno : err;
233 }
234 
235 static int
db1_db_del(DB * db,DB_TXN * txnid,DBT * key,u_int32_t flags)236 db1_db_del(DB *db, DB_TXN *txnid, DBT *key, u_int32_t flags) {
237           int err;
238           DB_old *db_v1 = db->actual_db;
239 
240           assert(txnid == NULL && flags == 0);
241 
242           err = db_v1->del(db_v1, (DBT_v1 *) key, 0);
243           return err == -1? errno : err;
244 }
245 
246 static int
db1_db_set_flags(DB * db,u_int32_t flags)247 db1_db_set_flags(DB *db, u_int32_t flags) {
248           assert((flags & ~(DB_RENUMBER | DB_SNAPSHOT)) == 0);
249 
250           /* Can't prevent renumbering from happening with DB1 */
251           assert((flags | db->_flags) & DB_RENUMBER);
252 
253 
254           db->_flags |= flags;
255 
256           return 0;
257 }
258 
259 static int
db1_db_set_pagesize(DB * db,u_int32_t pagesize)260 db1_db_set_pagesize(DB *db, u_int32_t pagesize) {
261           db->_pagesize = pagesize;
262 
263           return 0;
264 }
265 
266 static int
db1_db_set_re_delim(DB * db,int re_delim)267 db1_db_set_re_delim(DB *db, int re_delim) {
268           db->_recno_info.bval = re_delim;
269 
270           return 0;
271 }
272 
273 static int
db1_db_set_re_source(DB * db,const char * re_source)274 db1_db_set_re_source(DB *db, const char *re_source) {
275           db->_recno_info.bfname = __UNCONST(re_source);
276 
277           return 0;
278 }
279 
280 /* DBC emulation. Very basic, only one cursor at a time, enough for vi */
281 
282 static int db1_dbc_close(DBC *);
283 static int db1_dbc_get(DBC *, DBT *, DBT *, u_int32_t);
284 static int db1_dbc_put(DBC *, DBT *, DBT *, u_int32_t);
285 
286 static int
db1_db_cursor(DB * db,DB_TXN * txn,DBC ** cursorp,u_int32_t flags)287 db1_db_cursor(DB *db, DB_TXN *txn, DBC **cursorp, u_int32_t flags) {
288           DBC *cursor;
289 
290           assert(txn == NULL && flags == 0);
291 
292           cursor = malloc(sizeof *cursor);
293           if (cursor == NULL)
294                     return -1;
295 
296           cursor->db = db;
297           cursor->pos_key.data = &cursor->pos;
298           cursor->pos_key.size = sizeof cursor->pos;
299           cursor->c_close = db1_dbc_close;
300           cursor->c_get = db1_dbc_get;
301           cursor->c_put = db1_dbc_put;
302 
303           *cursorp = cursor;
304 
305           return 0;
306 }
307 
308 static int
db1_dbc_close(DBC * cursor)309 db1_dbc_close(DBC *cursor) {
310           free(cursor);
311           return 0;
312 }
313 
314 static int
db1_dbc_get(DBC * cursor,DBT * key,DBT * data,u_int32_t flags)315 db1_dbc_get(DBC *cursor, DBT *key, DBT *data, u_int32_t flags) {
316           DB *db = cursor->db;
317           DB_old *db_v1 = db->actual_db;
318           int ret = 0;
319 
320 
321           switch(flags) {
322           case DB_SET:
323                     ret = db_v1->seq(db_v1, (DBT_v1 *) key, (DBT_v1 *) data,
324                               R_CURSOR);
325                     cursor->pos = * (db_recno_t *) key->data;
326                     break;
327           case DB_FIRST:
328                     ret = db_v1->seq(db_v1, (DBT_v1 *) key, (DBT_v1 *) data,
329                               R_FIRST);
330                     if (ret == 1)
331                               ret = DB_NOTFOUND;
332                     cursor->pos = * (db_recno_t *) key->data;
333                     break;
334           case DB_LAST:
335                     ret = db_v1->seq(db_v1, (DBT_v1 *) key, (DBT_v1 *) data,
336                               R_LAST);
337                     if (ret == 1)
338                               ret = DB_NOTFOUND;
339                     cursor->pos = * (db_recno_t *) key->data;
340                     break;
341           default:
342                     abort();
343           }
344 
345           return ret;
346 }
347 
348 static int
db1_dbc_put(DBC * cursor,DBT * key,DBT * data,u_int32_t flags)349 db1_dbc_put(DBC *cursor, DBT *key, DBT *data, u_int32_t flags) {
350           DB *db = cursor->db;
351           DB_old *db_v1 = db->actual_db;
352           int ret = 0;
353 
354           assert((flags & ~(DB_BEFORE | DB_AFTER)) == 0);
355 
356           ret = db_v1->put(db_v1, &cursor->pos_key, (DBT_v1 *) data,
357                     flags == DB_BEFORE? R_IBEFORE : R_IAFTER);
358 
359           return ret == -1? errno : ret;
360 }
361