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 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 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 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 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 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 * 123 db_strerror(int error) { 124 return error > 0? strerror(error) : "record not found"; 125 } 126 127 static int 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 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 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 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 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 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 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 260 db1_db_set_pagesize(DB *db, u_int32_t pagesize) { 261 db->_pagesize = pagesize; 262 263 return 0; 264 } 265 266 static int 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 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 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 309 db1_dbc_close(DBC *cursor) { 310 free(cursor); 311 return 0; 312 } 313 314 static int 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 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