~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/tdb/open.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 2 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, write to the Free Software
26
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 
*/
28
 
 
29
 
#include "tdb_private.h"
30
 
 
31
 
/* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
32
 
static struct tdb_context *tdbs = NULL;
33
 
 
34
 
 
35
 
/* This is based on the hash algorithm from gdbm */
36
 
static unsigned int default_tdb_hash(TDB_DATA *key)
37
 
{
38
 
        u32 value;      /* Used to compute the hash value.  */
39
 
        u32   i;        /* Used to cycle through random values. */
40
 
 
41
 
        /* Set the initial value from the key size. */
42
 
        for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
43
 
                value = (value + (key->dptr[i] << (i*5 % 24)));
44
 
 
45
 
        return (1103515243 * value + 12345);  
46
 
}
47
 
 
48
 
 
49
 
/* initialise a new database with a specified hash size */
50
 
static int tdb_new_database(struct tdb_context *tdb, int hash_size)
51
 
{
52
 
        struct tdb_header *newdb;
53
 
        int size, ret = -1;
54
 
 
55
 
        /* We make it up in memory, then write it out if not internal */
56
 
        size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t);
57
 
        if (!(newdb = calloc(size, 1)))
58
 
                return TDB_ERRCODE(TDB_ERR_OOM, -1);
59
 
 
60
 
        /* Fill in the header */
61
 
        newdb->version = TDB_VERSION;
62
 
        newdb->hash_size = hash_size;
63
 
        if (tdb->flags & TDB_INTERNAL) {
64
 
                tdb->map_size = size;
65
 
                tdb->map_ptr = (char *)newdb;
66
 
                memcpy(&tdb->header, newdb, sizeof(tdb->header));
67
 
                /* Convert the `ondisk' version if asked. */
68
 
                CONVERT(*newdb);
69
 
                return 0;
70
 
        }
71
 
        if (lseek(tdb->fd, 0, SEEK_SET) == -1)
72
 
                goto fail;
73
 
 
74
 
        if (ftruncate(tdb->fd, 0) == -1)
75
 
                goto fail;
76
 
 
77
 
        /* This creates an endian-converted header, as if read from disk */
78
 
        CONVERT(*newdb);
79
 
        memcpy(&tdb->header, newdb, sizeof(tdb->header));
80
 
        /* Don't endian-convert the magic food! */
81
 
        memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
82
 
        if (write(tdb->fd, newdb, size) != size) {
83
 
                ret = -1;
84
 
        } else {
85
 
                ret = 0;
86
 
        }
87
 
 
88
 
  fail:
89
 
        SAFE_FREE(newdb);
90
 
        return ret;
91
 
}
92
 
 
93
 
 
94
 
 
95
 
static int tdb_already_open(dev_t device,
96
 
                            ino_t ino)
97
 
{
98
 
        struct tdb_context *i;
99
 
        
100
 
        for (i = tdbs; i; i = i->next) {
101
 
                if (i->device == device && i->inode == ino) {
102
 
                        return 1;
103
 
                }
104
 
        }
105
 
 
106
 
        return 0;
107
 
}
108
 
 
109
 
/* open the database, creating it if necessary 
110
 
 
111
 
   The open_flags and mode are passed straight to the open call on the
112
 
   database file. A flags value of O_WRONLY is invalid. The hash size
113
 
   is advisory, use zero for a default value.
114
 
 
115
 
   Return is NULL on error, in which case errno is also set.  Don't 
116
 
   try to call tdb_error or tdb_errname, just do strerror(errno).
117
 
 
118
 
   @param name may be NULL for internal databases. */
119
 
struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
120
 
                      int open_flags, mode_t mode)
121
 
{
122
 
        return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL, NULL);
123
 
}
124
 
 
125
 
/* a default logging function */
126
 
static void null_log_fn(struct tdb_context *tdb, int level, const char *fmt, ...)
127
 
{
128
 
}
129
 
 
130
 
 
131
 
struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
132
 
                         int open_flags, mode_t mode,
133
 
                         tdb_log_func log_fn,
134
 
                         tdb_hash_func hash_fn)
135
 
{
136
 
        struct tdb_context *tdb;
137
 
        struct stat st;
138
 
        int rev = 0, locked = 0;
139
 
        unsigned char *vp;
140
 
        u32 vertest;
141
 
 
142
 
        if (!(tdb = calloc(1, sizeof *tdb))) {
143
 
                /* Can't log this */
144
 
                errno = ENOMEM;
145
 
                goto fail;
146
 
        }
147
 
        tdb_io_init(tdb);
148
 
        tdb->fd = -1;
149
 
        tdb->name = NULL;
150
 
        tdb->map_ptr = NULL;
151
 
        tdb->flags = tdb_flags;
152
 
        tdb->open_flags = open_flags;
153
 
        tdb->log_fn = log_fn?log_fn:null_log_fn;
154
 
        tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash;
155
 
 
156
 
        /* cache the page size */
157
 
        tdb->page_size = getpagesize();
158
 
        if (tdb->page_size <= 0) {
159
 
                tdb->page_size = 0x2000;
160
 
        }
161
 
 
162
 
        if ((open_flags & O_ACCMODE) == O_WRONLY) {
163
 
                TDB_LOG((tdb, 0, "tdb_open_ex: can't open tdb %s write-only\n",
164
 
                         name));
165
 
                errno = EINVAL;
166
 
                goto fail;
167
 
        }
168
 
        
169
 
        if (hash_size == 0)
170
 
                hash_size = DEFAULT_HASH_SIZE;
171
 
        if ((open_flags & O_ACCMODE) == O_RDONLY) {
172
 
                tdb->read_only = 1;
173
 
                /* read only databases don't do locking or clear if first */
174
 
                tdb->flags |= TDB_NOLOCK;
175
 
                tdb->flags &= ~TDB_CLEAR_IF_FIRST;
176
 
        }
177
 
 
178
 
        /* internal databases don't mmap or lock, and start off cleared */
179
 
        if (tdb->flags & TDB_INTERNAL) {
180
 
                tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
181
 
                tdb->flags &= ~TDB_CLEAR_IF_FIRST;
182
 
                if (tdb_new_database(tdb, hash_size) != 0) {
183
 
                        TDB_LOG((tdb, 0, "tdb_open_ex: tdb_new_database failed!"));
184
 
                        goto fail;
185
 
                }
186
 
                goto internal;
187
 
        }
188
 
 
189
 
        if ((tdb->fd = open(name, open_flags, mode)) == -1) {
190
 
                TDB_LOG((tdb, 5, "tdb_open_ex: could not open file %s: %s\n",
191
 
                         name, strerror(errno)));
192
 
                goto fail;      /* errno set by open(2) */
193
 
        }
194
 
 
195
 
        /* ensure there is only one process initialising at once */
196
 
        if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0) == -1) {
197
 
                TDB_LOG((tdb, 0, "tdb_open_ex: failed to get global lock on %s: %s\n",
198
 
                         name, strerror(errno)));
199
 
                goto fail;      /* errno set by tdb_brlock */
200
 
        }
201
 
 
202
 
        /* we need to zero database if we are the only one with it open */
203
 
        if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
204
 
            (locked = (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0) == 0))) {
205
 
                open_flags |= O_CREAT;
206
 
                if (ftruncate(tdb->fd, 0) == -1) {
207
 
                        TDB_LOG((tdb, 0, "tdb_open_ex: "
208
 
                                 "failed to truncate %s: %s\n",
209
 
                                 name, strerror(errno)));
210
 
                        goto fail; /* errno set by ftruncate */
211
 
                }
212
 
        }
213
 
 
214
 
        if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header)
215
 
            || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0
216
 
            || (tdb->header.version != TDB_VERSION
217
 
                && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION))))) {
218
 
                /* its not a valid database - possibly initialise it */
219
 
                if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) {
220
 
                        errno = EIO; /* ie bad format or something */
221
 
                        goto fail;
222
 
                }
223
 
                rev = (tdb->flags & TDB_CONVERT);
224
 
        }
225
 
        vp = (unsigned char *)&tdb->header.version;
226
 
        vertest = (((u32)vp[0]) << 24) | (((u32)vp[1]) << 16) |
227
 
                  (((u32)vp[2]) << 8) | (u32)vp[3];
228
 
        tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0;
229
 
        if (!rev)
230
 
                tdb->flags &= ~TDB_CONVERT;
231
 
        else {
232
 
                tdb->flags |= TDB_CONVERT;
233
 
                tdb_convert(&tdb->header, sizeof(tdb->header));
234
 
        }
235
 
        if (fstat(tdb->fd, &st) == -1)
236
 
                goto fail;
237
 
 
238
 
        if (tdb->header.rwlocks != 0) {
239
 
                TDB_LOG((tdb, 5, "tdb_open_ex: spinlocks no longer supported\n"));
240
 
                goto fail;
241
 
        }
242
 
 
243
 
        /* Is it already in the open list?  If so, fail. */
244
 
        if (tdb_already_open(st.st_dev, st.st_ino)) {
245
 
                TDB_LOG((tdb, 2, "tdb_open_ex: "
246
 
                         "%s (%d,%d) is already open in this process\n",
247
 
                         name, (int)st.st_dev, (int)st.st_ino));
248
 
                errno = EBUSY;
249
 
                goto fail;
250
 
        }
251
 
 
252
 
        if (!(tdb->name = (char *)strdup(name))) {
253
 
                errno = ENOMEM;
254
 
                goto fail;
255
 
        }
256
 
 
257
 
        tdb->map_size = st.st_size;
258
 
        tdb->device = st.st_dev;
259
 
        tdb->inode = st.st_ino;
260
 
        tdb->locked = calloc(tdb->header.hash_size+1, sizeof(tdb->locked[0]));
261
 
        if (!tdb->locked) {
262
 
                TDB_LOG((tdb, 2, "tdb_open_ex: "
263
 
                         "failed to allocate lock structure for %s\n",
264
 
                         name));
265
 
                errno = ENOMEM;
266
 
                goto fail;
267
 
        }
268
 
        tdb_mmap(tdb);
269
 
        if (locked) {
270
 
                if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0) == -1) {
271
 
                        TDB_LOG((tdb, 0, "tdb_open_ex: "
272
 
                                 "failed to take ACTIVE_LOCK on %s: %s\n",
273
 
                                 name, strerror(errno)));
274
 
                        goto fail;
275
 
                }
276
 
 
277
 
        }
278
 
 
279
 
        /* We always need to do this if the CLEAR_IF_FIRST flag is set, even if
280
 
           we didn't get the initial exclusive lock as we need to let all other
281
 
           users know we're using it. */
282
 
 
283
 
        if (tdb_flags & TDB_CLEAR_IF_FIRST) {
284
 
                /* leave this lock in place to indicate it's in use */
285
 
                if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)
286
 
                        goto fail;
287
 
        }
288
 
 
289
 
        /* if needed, run recovery */
290
 
        if (tdb_transaction_recover(tdb) == -1) {
291
 
                goto fail;
292
 
        }
293
 
 
294
 
 internal:
295
 
        /* Internal (memory-only) databases skip all the code above to
296
 
         * do with disk files, and resume here by releasing their
297
 
         * global lock and hooking into the active list. */
298
 
        if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0) == -1)
299
 
                goto fail;
300
 
        tdb->next = tdbs;
301
 
        tdbs = tdb;
302
 
        return tdb;
303
 
 
304
 
 fail:
305
 
        { int save_errno = errno;
306
 
 
307
 
        if (!tdb)
308
 
                return NULL;
309
 
        
310
 
        if (tdb->map_ptr) {
311
 
                if (tdb->flags & TDB_INTERNAL)
312
 
                        SAFE_FREE(tdb->map_ptr);
313
 
                else
314
 
                        tdb_munmap(tdb);
315
 
        }
316
 
        SAFE_FREE(tdb->name);
317
 
        if (tdb->fd != -1)
318
 
                if (close(tdb->fd) != 0)
319
 
                        TDB_LOG((tdb, 5, "tdb_open_ex: failed to close tdb->fd on error!\n"));
320
 
        SAFE_FREE(tdb->locked);
321
 
        SAFE_FREE(tdb);
322
 
        errno = save_errno;
323
 
        return NULL;
324
 
        }
325
 
}
326
 
 
327
 
/**
328
 
 * Close a database.
329
 
 *
330
 
 * @returns -1 for error; 0 for success.
331
 
 **/
332
 
int tdb_close(struct tdb_context *tdb)
333
 
{
334
 
        struct tdb_context **i;
335
 
        int ret = 0;
336
 
 
337
 
        if (tdb->transaction) {
338
 
                tdb_transaction_cancel(tdb);
339
 
        }
340
 
 
341
 
        if (tdb->map_ptr) {
342
 
                if (tdb->flags & TDB_INTERNAL)
343
 
                        SAFE_FREE(tdb->map_ptr);
344
 
                else
345
 
                        tdb_munmap(tdb);
346
 
        }
347
 
        SAFE_FREE(tdb->name);
348
 
        if (tdb->fd != -1)
349
 
                ret = close(tdb->fd);
350
 
        SAFE_FREE(tdb->locked);
351
 
 
352
 
        /* Remove from contexts list */
353
 
        for (i = &tdbs; *i; i = &(*i)->next) {
354
 
                if (*i == tdb) {
355
 
                        *i = tdb->next;
356
 
                        break;
357
 
                }
358
 
        }
359
 
 
360
 
        memset(tdb, 0, sizeof(*tdb));
361
 
        SAFE_FREE(tdb);
362
 
 
363
 
        return ret;
364
 
}
365
 
 
366
 
/* register a loging function */
367
 
void tdb_logging_function(struct tdb_context *tdb, void (*fn)(struct tdb_context *, int , const char *, ...))
368
 
{
369
 
        tdb->log_fn = fn?fn:null_log_fn;
370
 
}
371
 
 
372
 
 
373
 
/* reopen a tdb - this can be used after a fork to ensure that we have an independent
374
 
   seek pointer from our parent and to re-establish locks */
375
 
int tdb_reopen(struct tdb_context *tdb)
376
 
{
377
 
        struct stat st;
378
 
 
379
 
        if (tdb->flags & TDB_INTERNAL) {
380
 
                return 0; /* Nothing to do. */
381
 
        }
382
 
 
383
 
        if (tdb->num_locks != 0) {
384
 
                TDB_LOG((tdb, 0, "tdb_reopen: reopen not allowed with locks held\n"));
385
 
                goto fail;
386
 
        }
387
 
 
388
 
        if (tdb->transaction != 0) {
389
 
                TDB_LOG((tdb, 0, "tdb_reopen: reopen not allowed inside a transaction\n"));
390
 
                goto fail;
391
 
        }
392
 
 
393
 
        if (tdb_munmap(tdb) != 0) {
394
 
                TDB_LOG((tdb, 0, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
395
 
                goto fail;
396
 
        }
397
 
        if (close(tdb->fd) != 0)
398
 
                TDB_LOG((tdb, 0, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
399
 
        tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
400
 
        if (tdb->fd == -1) {
401
 
                TDB_LOG((tdb, 0, "tdb_reopen: open failed (%s)\n", strerror(errno)));
402
 
                goto fail;
403
 
        }
404
 
        if ((tdb->flags & TDB_CLEAR_IF_FIRST) && 
405
 
            (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0) == -1)) {
406
 
                TDB_LOG((tdb, 0, "tdb_reopen: failed to obtain active lock\n"));
407
 
                goto fail;
408
 
        }
409
 
        if (fstat(tdb->fd, &st) != 0) {
410
 
                TDB_LOG((tdb, 0, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
411
 
                goto fail;
412
 
        }
413
 
        if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
414
 
                TDB_LOG((tdb, 0, "tdb_reopen: file dev/inode has changed!\n"));
415
 
                goto fail;
416
 
        }
417
 
        tdb_mmap(tdb);
418
 
 
419
 
        return 0;
420
 
 
421
 
fail:
422
 
        tdb_close(tdb);
423
 
        return -1;
424
 
}
425
 
 
426
 
/* reopen all tdb's */
427
 
int tdb_reopen_all(int parent_longlived)
428
 
{
429
 
        struct tdb_context *tdb;
430
 
 
431
 
        for (tdb=tdbs; tdb; tdb = tdb->next) {
432
 
                /*
433
 
                 * If the parent is longlived (ie. a
434
 
                 * parent daemon architecture), we know
435
 
                 * it will keep it's active lock on a
436
 
                 * tdb opened with CLEAR_IF_FIRST. Thus
437
 
                 * for child processes we don't have to
438
 
                 * add an active lock. This is essential
439
 
                 * to improve performance on systems that
440
 
                 * keep POSIX locks as a non-scalable data
441
 
                 * structure in the kernel.
442
 
                 */
443
 
                if (parent_longlived) {
444
 
                        /* Ensure no clear-if-first. */
445
 
                        tdb->flags &= ~TDB_CLEAR_IF_FIRST;
446
 
                }
447
 
 
448
 
                if (tdb_reopen(tdb) != 0)
449
 
                        return -1;
450
 
        }
451
 
 
452
 
        return 0;
453
 
}