]> git.ozlabs.org Git - ccan/blob - ccan/tdb2/tdb1_open.c
tdb2: merge tdb1_context into tdb_context.
[ccan] / ccan / tdb2 / tdb1_open.c
1  /*
2    Unix SMB/CIFS implementation.
3
4    trivial database library
5
6    Copyright (C) Andrew Tridgell              1999-2005
7    Copyright (C) Paul `Rusty' Russell              2000
8    Copyright (C) Jeremy Allison                    2000-2003
9
10      ** NOTE! The following LGPL license applies to the tdb
11      ** library. This does NOT imply that all of Samba is released
12      ** under the LGPL
13
14    This library is free software; you can redistribute it and/or
15    modify it under the terms of the GNU Lesser General Public
16    License as published by the Free Software Foundation; either
17    version 3 of the License, or (at your option) any later version.
18
19    This library is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22    Lesser General Public License for more details.
23
24    You should have received a copy of the GNU Lesser General Public
25    License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 */
27
28 #include "tdb1_private.h"
29
30 /* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
31 static struct tdb_context *tdb1s = NULL;
32
33 /* We use two hashes to double-check they're using the right hash function. */
34 void tdb1_header_hash(struct tdb_context *tdb,
35                      uint32_t *magic1_hash, uint32_t *magic2_hash)
36 {
37         uint32_t tdb1_magic = TDB1_MAGIC;
38
39         *magic1_hash = tdb_hash(tdb, TDB_MAGIC_FOOD, sizeof(TDB_MAGIC_FOOD));
40         *magic2_hash = tdb_hash(tdb, TDB1_CONV(tdb1_magic), sizeof(tdb1_magic));
41
42         /* Make sure at least one hash is non-zero! */
43         if (*magic1_hash == 0 && *magic2_hash == 0)
44                 *magic1_hash = 1;
45 }
46
47 /* initialise a new database with a specified hash size */
48 static int tdb1_new_database(struct tdb_context *tdb, int hash_size)
49 {
50         struct tdb1_header *newdb;
51         size_t size;
52         int ret = -1;
53
54         /* We make it up in memory, then write it out if not internal */
55         size = sizeof(struct tdb1_header) + (hash_size+1)*sizeof(tdb1_off_t);
56         if (!(newdb = (struct tdb1_header *)calloc(size, 1))) {
57                 tdb->last_error = TDB_ERR_OOM;
58                 return -1;
59         }
60
61         /* Fill in the header */
62         newdb->version = TDB1_VERSION;
63         newdb->hash_size = hash_size;
64
65         tdb1_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash);
66
67         /* Make sure older tdbs (which don't check the magic hash fields)
68          * will refuse to open this TDB. */
69         if (tdb->hash_fn == tdb1_incompatible_hash)
70                 newdb->rwlocks = TDB1_HASH_RWLOCK_MAGIC;
71
72         if (tdb->flags & TDB_INTERNAL) {
73                 tdb->file->fd = -1;
74                 tdb->file->map_size = size;
75                 tdb->file->map_ptr = (char *)newdb;
76                 memcpy(&tdb->tdb1.header, newdb, sizeof(tdb->tdb1.header));
77                 /* Convert the `ondisk' version if asked. */
78                 TDB1_CONV(*newdb);
79                 return 0;
80         }
81         if (lseek(tdb->file->fd, 0, SEEK_SET) == -1)
82                 goto fail;
83
84         if (ftruncate(tdb->file->fd, 0) == -1)
85                 goto fail;
86
87         /* This creates an endian-converted header, as if read from disk */
88         TDB1_CONV(*newdb);
89         memcpy(&tdb->tdb1.header, newdb, sizeof(tdb->tdb1.header));
90         /* Don't endian-convert the magic food! */
91         memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
92         /* we still have "ret == -1" here */
93         if (tdb1_write_all(tdb->file->fd, newdb, size))
94                 ret = 0;
95
96   fail:
97         SAFE_FREE(newdb);
98         return ret;
99 }
100
101
102
103 static int tdb1_already_open(dev_t device,
104                             ino_t ino)
105 {
106         struct tdb_context *i;
107
108         for (i = tdb1s; i; i = i->next) {
109                 if (i->file->device == device && i->file->inode == ino) {
110                         return 1;
111                 }
112         }
113
114         return 0;
115 }
116
117 /* open the database, creating it if necessary
118
119    The open_flags and mode are passed straight to the open call on the
120    database file. A flags value of O_WRONLY is invalid. The hash size
121    is advisory, use zero for a default value.
122
123    Return is NULL on error, in which case errno is also set.  Don't
124    try to call tdb1_error or tdb1_errname, just do strerror(errno).
125
126    @param name may be NULL for internal databases. */
127 struct tdb_context *tdb1_open(const char *name, int hash_size, int tdb1_flags,
128                       int open_flags, mode_t mode)
129 {
130         return tdb1_open_ex(name, hash_size, tdb1_flags, open_flags, mode, NULL, NULL);
131 }
132
133 static bool hash_correct(struct tdb_context *tdb,
134                          uint32_t *m1, uint32_t *m2)
135 {
136         tdb1_header_hash(tdb, m1, m2);
137         return (tdb->tdb1.header.magic1_hash == *m1 &&
138                 tdb->tdb1.header.magic2_hash == *m2);
139 }
140
141 static bool check_header_hash(struct tdb_context *tdb,
142                               uint32_t *m1, uint32_t *m2)
143 {
144         if (hash_correct(tdb, m1, m2))
145                 return true;
146
147         /* If they use one inbuilt, try the other inbuilt hash. */
148         if (tdb->hash_fn == tdb1_old_hash)
149                 tdb->hash_fn = tdb1_incompatible_hash;
150         else if (tdb->hash_fn == tdb1_incompatible_hash)
151                 tdb->hash_fn = tdb1_old_hash;
152         else
153                 return false;
154         return hash_correct(tdb, m1, m2);
155 }
156
157 struct tdb_context *tdb1_open_ex(const char *name, int hash_size, int tdb1_flags,
158                                 int open_flags, mode_t mode,
159                                 const struct tdb1_logging_context *log_ctx,
160                                 tdb1_hash_func hash_fn)
161 {
162         struct tdb_context *tdb;
163         struct stat st;
164         int rev = 0;
165         unsigned v;
166         const char *hash_alg;
167         uint32_t magic1, magic2;
168
169         if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
170                 /* Can't log this */
171                 errno = ENOMEM;
172                 goto fail;
173         }
174         tdb->file = calloc(1, sizeof *tdb->file);
175         if (!tdb->file) {
176                 free(tdb);
177                 errno = ENOMEM;
178                 goto fail;
179         }
180         tdb1_io_init(tdb);
181         tdb->file->fd = -1;
182         tdb->name = NULL;
183         tdb->file->map_ptr = NULL;
184         tdb->flags = tdb1_flags|TDB_VERSION1;
185         tdb->open_flags = open_flags;
186         tdb->lock_fn = tdb_fcntl_lock;
187         tdb->unlock_fn = tdb_fcntl_unlock;
188         if (log_ctx) {
189                 tdb->log_fn = log_ctx->log_fn;
190                 tdb->log_data = log_ctx->log_private;
191         } else
192                 tdb->log_fn = NULL;
193
194         if (name == NULL && (tdb1_flags & TDB_INTERNAL)) {
195                 name = "__TDB1_INTERNAL__";
196         }
197
198         if (name == NULL) {
199                 tdb->name = (char *)"__NULL__";
200                 tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
201                            "tdb1_open_ex: called with name == NULL");
202                 tdb->name = NULL;
203                 errno = EINVAL;
204                 goto fail;
205         }
206
207         /* now make a copy of the name, as the caller memory might went away */
208         if (!(tdb->name = (char *)strdup(name))) {
209                 /*
210                  * set the name as the given string, so that tdb1_name() will
211                  * work in case of an error.
212                  */
213                 tdb->name = (char *)name;
214                 tdb_logerr(tdb, TDB_ERR_OOM, TDB_LOG_ERROR,
215                            "tdb1_open_ex: can't strdup(%s)", name);
216                 tdb->name = NULL;
217                 errno = ENOMEM;
218                 goto fail;
219         }
220         tdb->hash_seed = 0;
221
222         if (hash_fn) {
223                 tdb->hash_fn = hash_fn;
224                 if (hash_fn == tdb1_incompatible_hash)
225                         hash_alg = "tdb1_incompatible_hash";
226                 else
227                         hash_alg = "the user defined";
228         } else {
229                 tdb->hash_fn = tdb1_old_hash;
230                 hash_alg = "default";
231         }
232
233         /* cache the page size */
234         tdb->tdb1.page_size = getpagesize();
235         if (tdb->tdb1.page_size <= 0) {
236                 tdb->tdb1.page_size = 0x2000;
237         }
238
239         /* FIXME: Used to be 5 for TDB_VOLATILE. */
240         tdb->tdb1.max_dead_records = 0;
241
242         if ((open_flags & O_ACCMODE) == O_WRONLY) {
243                 tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
244                            "tdb1_open_ex: can't open tdb %s write-only",
245                            name);
246                 errno = EINVAL;
247                 goto fail;
248         }
249
250         if (hash_size == 0)
251                 hash_size = TDB1_DEFAULT_HASH_SIZE;
252         if ((open_flags & O_ACCMODE) == O_RDONLY) {
253                 tdb->flags |= TDB_RDONLY;
254                 /* read only databases don't do locking */
255                 tdb->flags |= TDB_NOLOCK;
256         }
257
258         /* internal databases don't mmap or lock, and start off cleared */
259         if (tdb->flags & TDB_INTERNAL) {
260                 tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
261                 if (tdb1_new_database(tdb, hash_size) != 0) {
262                         tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
263                                    "tdb1_open_ex: tdb1_new_database failed!");
264                         goto fail;
265                 }
266                 goto internal;
267         }
268
269         if ((tdb->file->fd = open(name, open_flags, mode)) == -1) {
270                 tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
271                            "tdb1_open_ex: could not open file %s: %s",
272                            name, strerror(errno));
273                 goto fail;      /* errno set by open(2) */
274         }
275
276         /* on exec, don't inherit the fd */
277         v = fcntl(tdb->file->fd, F_GETFD, 0);
278         fcntl(tdb->file->fd, F_SETFD, v | FD_CLOEXEC);
279
280         /* ensure there is only one process initialising at once */
281         if (tdb1_nest_lock(tdb, TDB1_OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) {
282                 tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
283                            "tdb1_open_ex: failed to get open lock on %s: %s",
284                            name, strerror(errno));
285                 goto fail;      /* errno set by tdb1_brlock */
286         }
287
288         errno = 0;
289         if (read(tdb->file->fd, &tdb->tdb1.header, sizeof(tdb->tdb1.header)) != sizeof(tdb->tdb1.header)
290             || strcmp(tdb->tdb1.header.magic_food, TDB_MAGIC_FOOD) != 0) {
291                 if (!(open_flags & O_CREAT) || tdb1_new_database(tdb, hash_size) == -1) {
292                         if (errno == 0) {
293                                 errno = EIO; /* ie bad format or something */
294                         }
295                         goto fail;
296                 }
297                 rev = (tdb->flags & TDB_CONVERT);
298         } else if (tdb->tdb1.header.version != TDB1_VERSION
299                    && !(rev = (tdb->tdb1.header.version==TDB1_BYTEREV(TDB1_VERSION)))) {
300                 /* wrong version */
301                 errno = EIO;
302                 goto fail;
303         }
304         if (!rev)
305                 tdb->flags &= ~TDB_CONVERT;
306         else {
307                 tdb->flags |= TDB_CONVERT;
308                 tdb1_convert(&tdb->tdb1.header, sizeof(tdb->tdb1.header));
309         }
310         if (fstat(tdb->file->fd, &st) == -1)
311                 goto fail;
312
313         if (tdb->tdb1.header.rwlocks != 0 &&
314             tdb->tdb1.header.rwlocks != TDB1_HASH_RWLOCK_MAGIC) {
315                 tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
316                            "tdb1_open_ex: spinlocks no longer supported");
317                 goto fail;
318         }
319
320         if ((tdb->tdb1.header.magic1_hash == 0) && (tdb->tdb1.header.magic2_hash == 0)) {
321                 /* older TDB without magic hash references */
322                 tdb->hash_fn = tdb1_old_hash;
323         } else if (!check_header_hash(tdb, &magic1, &magic2)) {
324                 tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_USE_ERROR,
325                            "tdb1_open_ex: "
326                            "%s was not created with %s hash function we are using\n"
327                            "magic1_hash[0x%08X %s 0x%08X] "
328                            "magic2_hash[0x%08X %s 0x%08X]",
329                            name, hash_alg,
330                            tdb->tdb1.header.magic1_hash,
331                            (tdb->tdb1.header.magic1_hash == magic1) ? "==" : "!=",
332                            magic1,
333                            tdb->tdb1.header.magic2_hash,
334                            (tdb->tdb1.header.magic2_hash == magic2) ? "==" : "!=",
335                            magic2);
336                 errno = EINVAL;
337                 goto fail;
338         }
339
340         /* Is it already in the open list?  If so, fail. */
341         if (tdb1_already_open(st.st_dev, st.st_ino)) {
342                 tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_USE_ERROR,
343                            "tdb1_open_ex: "
344                            "%s (%d,%d) is already open in this process",
345                            name, (int)st.st_dev, (int)st.st_ino);
346                 errno = EBUSY;
347                 goto fail;
348         }
349
350         tdb->file->map_size = st.st_size;
351         tdb->file->device = st.st_dev;
352         tdb->file->inode = st.st_ino;
353         tdb1_mmap(tdb);
354
355         /* if needed, run recovery */
356         if (tdb1_transaction_recover(tdb) == -1) {
357                 goto fail;
358         }
359
360  internal:
361         /* Internal (memory-only) databases skip all the code above to
362          * do with disk files, and resume here by releasing their
363          * open lock and hooking into the active list. */
364         if (tdb1_nest_unlock(tdb, TDB1_OPEN_LOCK, F_WRLCK) == -1) {
365                 goto fail;
366         }
367         tdb->next = tdb1s;
368         tdb1s = tdb;
369         return tdb;
370
371  fail:
372         { int save_errno = errno;
373
374         if (!tdb)
375                 return NULL;
376
377         if (tdb->file->map_ptr) {
378                 if (tdb->flags & TDB_INTERNAL)
379                         SAFE_FREE(tdb->file->map_ptr);
380                 else
381                         tdb1_munmap(tdb);
382         }
383         if (tdb->file->fd != -1)
384                 if (close(tdb->file->fd) != 0)
385                         tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
386                                    "tdb1_open_ex: failed to close tdb->fd on error!");
387         if (tdb->file) {
388                 SAFE_FREE(tdb->file->lockrecs);
389                 SAFE_FREE(tdb->file);
390         }
391         SAFE_FREE(tdb->name);
392         SAFE_FREE(tdb);
393         errno = save_errno;
394         return NULL;
395         }
396 }
397
398 /*
399  * Set the maximum number of dead records per hash chain
400  */
401
402 void tdb1_set_max_dead(struct tdb_context *tdb, int max_dead)
403 {
404         tdb->tdb1.max_dead_records = max_dead;
405 }
406
407 /**
408  * Close a database.
409  *
410  * @returns -1 for error; 0 for success.
411  **/
412 int tdb1_close(struct tdb_context *tdb)
413 {
414         struct tdb_context **i;
415         int ret = 0;
416
417         if (tdb->tdb1.transaction) {
418                 tdb1_transaction_cancel(tdb);
419         }
420
421         if (tdb->file->map_ptr) {
422                 if (tdb->flags & TDB_INTERNAL)
423                         SAFE_FREE(tdb->file->map_ptr);
424                 else
425                         tdb1_munmap(tdb);
426         }
427         SAFE_FREE(tdb->name);
428         if (tdb->file->fd != -1) {
429                 ret = close(tdb->file->fd);
430                 tdb->file->fd = -1;
431         }
432         SAFE_FREE(tdb->file->lockrecs);
433         SAFE_FREE(tdb->file);
434
435         /* Remove from contexts list */
436         for (i = &tdb1s; *i; i = &(*i)->next) {
437                 if (*i == tdb) {
438                         *i = tdb->next;
439                         break;
440                 }
441         }
442
443         memset(tdb, 0, sizeof(*tdb));
444         SAFE_FREE(tdb);
445
446         return ret;
447 }