tdb/common/open.c

説明を見る。
00001  /* 
00002    Unix SMB/CIFS implementation.
00003 
00004    trivial database library
00005 
00006    Copyright (C) Andrew Tridgell              1999-2005
00007    Copyright (C) Paul `Rusty' Russell              2000
00008    Copyright (C) Jeremy Allison                    2000-2003
00009    
00010      ** NOTE! The following LGPL license applies to the tdb
00011      ** library. This does NOT imply that all of Samba is released
00012      ** under the LGPL
00013    
00014    This library is free software; you can redistribute it and/or
00015    modify it under the terms of the GNU Lesser General Public
00016    License as published by the Free Software Foundation; either
00017    version 2 of the License, or (at your option) any later version.
00018 
00019    This library is distributed in the hope that it will be useful,
00020    but WITHOUT ANY WARRANTY; without even the implied warranty of
00021    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00022    Lesser General Public License for more details.
00023 
00024    You should have received a copy of the GNU Lesser General Public
00025    License along with this library; if not, write to the Free Software
00026    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00027 */
00028 
00029 #include "tdb_private.h"
00030 
00031 /* all contexts, to ensure no double-opens (fcntl locks don't nest!) */
00032 static struct tdb_context *tdbs = NULL;
00033 
00034 
00035 /* This is based on the hash algorithm from gdbm */
00036 static unsigned int default_tdb_hash(TDB_DATA *key)
00037 {
00038         u32 value;      /* Used to compute the hash value.  */
00039         u32   i;        /* Used to cycle through random values. */
00040 
00041         /* Set the initial value from the key size. */
00042         for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
00043                 value = (value + (key->dptr[i] << (i*5 % 24)));
00044 
00045         return (1103515243 * value + 12345);  
00046 }
00047 
00048 
00049 /* initialise a new database with a specified hash size */
00050 static int tdb_new_database(struct tdb_context *tdb, int hash_size)
00051 {
00052         struct tdb_header *newdb;
00053         size_t size;
00054         int ret = -1;
00055         ssize_t written;
00056 
00057         /* We make it up in memory, then write it out if not internal */
00058         size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t);
00059         if (!(newdb = (struct tdb_header *)calloc(size, 1)))
00060                 return TDB_ERRCODE(TDB_ERR_OOM, -1);
00061 
00062         /* Fill in the header */
00063         newdb->version = TDB_VERSION;
00064         newdb->hash_size = hash_size;
00065         if (tdb->flags & TDB_INTERNAL) {
00066                 tdb->map_size = size;
00067                 tdb->map_ptr = (char *)newdb;
00068                 memcpy(&tdb->header, newdb, sizeof(tdb->header));
00069                 /* Convert the `ondisk' version if asked. */
00070                 CONVERT(*newdb);
00071                 return 0;
00072         }
00073         if (lseek(tdb->fd, 0, SEEK_SET) == -1)
00074                 goto fail;
00075 
00076         if (ftruncate(tdb->fd, 0) == -1)
00077                 goto fail;
00078 
00079         /* This creates an endian-converted header, as if read from disk */
00080         CONVERT(*newdb);
00081         memcpy(&tdb->header, newdb, sizeof(tdb->header));
00082         /* Don't endian-convert the magic food! */
00083         memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
00084         /* we still have "ret == -1" here */
00085         written = write(tdb->fd, newdb, size);
00086         if (written == size) {
00087                 ret = 0;
00088         } else if (written != -1) {
00089                 /* call write once again, this usually should return -1 and
00090                  * set errno appropriately */
00091                 size -= written;
00092                 written = write(tdb->fd, newdb+written, size);
00093                 if (written == size) {
00094                         ret = 0;
00095                 } else if (written >= 0) {
00096                         /* a second incomplete write - we give up.
00097                          * guessing the errno... */
00098                         errno = ENOSPC;
00099                 }
00100         }
00101 
00102   fail:
00103         SAFE_FREE(newdb);
00104         return ret;
00105 }
00106 
00107 
00108 
00109 static int tdb_already_open(dev_t device,
00110                             ino_t ino)
00111 {
00112         struct tdb_context *i;
00113         
00114         for (i = tdbs; i; i = i->next) {
00115                 if (i->device == device && i->inode == ino) {
00116                         return 1;
00117                 }
00118         }
00119 
00120         return 0;
00121 }
00122 
00123 /* open the database, creating it if necessary 
00124 
00125    The open_flags and mode are passed straight to the open call on the
00126    database file. A flags value of O_WRONLY is invalid. The hash size
00127    is advisory, use zero for a default value.
00128 
00129    Return is NULL on error, in which case errno is also set.  Don't 
00130    try to call tdb_error or tdb_errname, just do strerror(errno).
00131 
00132    @param name may be NULL for internal databases. */
00133 struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
00134                       int open_flags, mode_t mode)
00135 {
00136         return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, NULL, NULL);
00137 }
00138 
00139 /* a default logging function */
00140 static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
00141 static void null_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
00142 {
00143 }
00144 
00145 
00146 struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
00147                                 int open_flags, mode_t mode,
00148                                 const struct tdb_logging_context *log_ctx,
00149                                 tdb_hash_func hash_fn)
00150 {
00151         struct tdb_context *tdb;
00152         struct stat st;
00153         int rev = 0, locked = 0;
00154         unsigned char *vp;
00155         u32 vertest;
00156 
00157         if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
00158                 /* Can't log this */
00159                 errno = ENOMEM;
00160                 goto fail;
00161         }
00162         tdb_io_init(tdb);
00163         tdb->fd = -1;
00164         tdb->name = NULL;
00165         tdb->map_ptr = NULL;
00166         tdb->flags = tdb_flags;
00167         tdb->open_flags = open_flags;
00168         if (log_ctx) {
00169                 tdb->log = *log_ctx;
00170         } else {
00171                 tdb->log.log_fn = null_log_fn;
00172                 tdb->log.log_private = NULL;
00173         }
00174         tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash;
00175 
00176         /* cache the page size */
00177         tdb->page_size = getpagesize();
00178         if (tdb->page_size <= 0) {
00179                 tdb->page_size = 0x2000;
00180         }
00181 
00182         if ((open_flags & O_ACCMODE) == O_WRONLY) {
00183                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't open tdb %s write-only\n",
00184                          name));
00185                 errno = EINVAL;
00186                 goto fail;
00187         }
00188         
00189         if (hash_size == 0)
00190                 hash_size = DEFAULT_HASH_SIZE;
00191         if ((open_flags & O_ACCMODE) == O_RDONLY) {
00192                 tdb->read_only = 1;
00193                 /* read only databases don't do locking or clear if first */
00194                 tdb->flags |= TDB_NOLOCK;
00195                 tdb->flags &= ~TDB_CLEAR_IF_FIRST;
00196         }
00197 
00198         /* internal databases don't mmap or lock, and start off cleared */
00199         if (tdb->flags & TDB_INTERNAL) {
00200                 tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
00201                 tdb->flags &= ~TDB_CLEAR_IF_FIRST;
00202                 if (tdb_new_database(tdb, hash_size) != 0) {
00203                         TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!"));
00204                         goto fail;
00205                 }
00206                 goto internal;
00207         }
00208 
00209         if ((tdb->fd = open(name, open_flags, mode)) == -1) {
00210                 TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_open_ex: could not open file %s: %s\n",
00211                          name, strerror(errno)));
00212                 goto fail;      /* errno set by open(2) */
00213         }
00214 
00215         /* ensure there is only one process initialising at once */
00216         if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
00217                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get global lock on %s: %s\n",
00218                          name, strerror(errno)));
00219                 goto fail;      /* errno set by tdb_brlock */
00220         }
00221 
00222         /* we need to zero database if we are the only one with it open */
00223         if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
00224             (locked = (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 0))) {
00225                 open_flags |= O_CREAT;
00226                 if (ftruncate(tdb->fd, 0) == -1) {
00227                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
00228                                  "failed to truncate %s: %s\n",
00229                                  name, strerror(errno)));
00230                         goto fail; /* errno set by ftruncate */
00231                 }
00232         }
00233 
00234         errno = 0;
00235         if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header)
00236             || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0
00237             || (tdb->header.version != TDB_VERSION
00238                 && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION))))) {
00239                 /* its not a valid database - possibly initialise it */
00240                 if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) {
00241                         if (errno == 0) {
00242                                 errno = EIO; /* ie bad format or something */
00243                         }
00244                         goto fail;
00245                 }
00246                 rev = (tdb->flags & TDB_CONVERT);
00247         }
00248         vp = (unsigned char *)&tdb->header.version;
00249         vertest = (((u32)vp[0]) << 24) | (((u32)vp[1]) << 16) |
00250                   (((u32)vp[2]) << 8) | (u32)vp[3];
00251         tdb->flags |= (vertest==TDB_VERSION) ? TDB_BIGENDIAN : 0;
00252         if (!rev)
00253                 tdb->flags &= ~TDB_CONVERT;
00254         else {
00255                 tdb->flags |= TDB_CONVERT;
00256                 tdb_convert(&tdb->header, sizeof(tdb->header));
00257         }
00258         if (fstat(tdb->fd, &st) == -1)
00259                 goto fail;
00260 
00261         if (tdb->header.rwlocks != 0) {
00262                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
00263                 goto fail;
00264         }
00265 
00266         /* Is it already in the open list?  If so, fail. */
00267         if (tdb_already_open(st.st_dev, st.st_ino)) {
00268                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
00269                          "%s (%d,%d) is already open in this process\n",
00270                          name, (int)st.st_dev, (int)st.st_ino));
00271                 errno = EBUSY;
00272                 goto fail;
00273         }
00274 
00275         if (!(tdb->name = (char *)strdup(name))) {
00276                 errno = ENOMEM;
00277                 goto fail;
00278         }
00279 
00280         tdb->map_size = st.st_size;
00281         tdb->device = st.st_dev;
00282         tdb->inode = st.st_ino;
00283         tdb->max_dead_records = 0;
00284         tdb_mmap(tdb);
00285         if (locked) {
00286                 if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {
00287                         TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
00288                                  "failed to take ACTIVE_LOCK on %s: %s\n",
00289                                  name, strerror(errno)));
00290                         goto fail;
00291                 }
00292 
00293         }
00294 
00295         /* We always need to do this if the CLEAR_IF_FIRST flag is set, even if
00296            we didn't get the initial exclusive lock as we need to let all other
00297            users know we're using it. */
00298 
00299         if (tdb_flags & TDB_CLEAR_IF_FIRST) {
00300                 /* leave this lock in place to indicate it's in use */
00301                 if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)
00302                         goto fail;
00303         }
00304 
00305         /* if needed, run recovery */
00306         if (tdb_transaction_recover(tdb) == -1) {
00307                 goto fail;
00308         }
00309 
00310  internal:
00311         /* Internal (memory-only) databases skip all the code above to
00312          * do with disk files, and resume here by releasing their
00313          * global lock and hooking into the active list. */
00314         if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1)
00315                 goto fail;
00316         tdb->next = tdbs;
00317         tdbs = tdb;
00318         return tdb;
00319 
00320  fail:
00321         { int save_errno = errno;
00322 
00323         if (!tdb)
00324                 return NULL;
00325         
00326         if (tdb->map_ptr) {
00327                 if (tdb->flags & TDB_INTERNAL)
00328                         SAFE_FREE(tdb->map_ptr);
00329                 else
00330                         tdb_munmap(tdb);
00331         }
00332         SAFE_FREE(tdb->name);
00333         if (tdb->fd != -1)
00334                 if (close(tdb->fd) != 0)
00335                         TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
00336         SAFE_FREE(tdb);
00337         errno = save_errno;
00338         return NULL;
00339         }
00340 }
00341 
00342 /*
00343  * Set the maximum number of dead records per hash chain
00344  */
00345 
00346 void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)
00347 {
00348         tdb->max_dead_records = max_dead;
00349 }
00350 
00351 /**
00352  * Close a database.
00353  *
00354  * @returns -1 for error; 0 for success.
00355  **/
00356 int tdb_close(struct tdb_context *tdb)
00357 {
00358         struct tdb_context **i;
00359         int ret = 0;
00360 
00361         if (tdb->transaction) {
00362                 tdb_transaction_cancel(tdb);
00363         }
00364 
00365         if (tdb->map_ptr) {
00366                 if (tdb->flags & TDB_INTERNAL)
00367                         SAFE_FREE(tdb->map_ptr);
00368                 else
00369                         tdb_munmap(tdb);
00370         }
00371         SAFE_FREE(tdb->name);
00372         if (tdb->fd != -1)
00373                 ret = close(tdb->fd);
00374         SAFE_FREE(tdb->lockrecs);
00375 
00376         /* Remove from contexts list */
00377         for (i = &tdbs; *i; i = &(*i)->next) {
00378                 if (*i == tdb) {
00379                         *i = tdb->next;
00380                         break;
00381                 }
00382         }
00383 
00384         memset(tdb, 0, sizeof(*tdb));
00385         SAFE_FREE(tdb);
00386 
00387         return ret;
00388 }
00389 
00390 /* register a loging function */
00391 void tdb_set_logging_function(struct tdb_context *tdb,
00392                               const struct tdb_logging_context *log_ctx)
00393 {
00394         tdb->log = *log_ctx;
00395 }
00396 
00397 void *tdb_get_logging_private(struct tdb_context *tdb)
00398 {
00399         return tdb->log.log_private;
00400 }
00401 
00402 /* reopen a tdb - this can be used after a fork to ensure that we have an independent
00403    seek pointer from our parent and to re-establish locks */
00404 int tdb_reopen(struct tdb_context *tdb)
00405 {
00406         struct stat st;
00407 
00408         if (tdb->flags & TDB_INTERNAL) {
00409                 return 0; /* Nothing to do. */
00410         }
00411 
00412         if (tdb->num_locks != 0 || tdb->global_lock.count) {
00413                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n"));
00414                 goto fail;
00415         }
00416 
00417         if (tdb->transaction != 0) {
00418                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed inside a transaction\n"));
00419                 goto fail;
00420         }
00421 
00422         if (tdb_munmap(tdb) != 0) {
00423                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: munmap failed (%s)\n", strerror(errno)));
00424                 goto fail;
00425         }
00426         if (close(tdb->fd) != 0)
00427                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: WARNING closing tdb->fd failed!\n"));
00428         tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
00429         if (tdb->fd == -1) {
00430                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: open failed (%s)\n", strerror(errno)));
00431                 goto fail;
00432         }
00433         if ((tdb->flags & TDB_CLEAR_IF_FIRST) && 
00434             (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) {
00435                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n"));
00436                 goto fail;
00437         }
00438         if (fstat(tdb->fd, &st) != 0) {
00439                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
00440                 goto fail;
00441         }
00442         if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
00443                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: file dev/inode has changed!\n"));
00444                 goto fail;
00445         }
00446         tdb_mmap(tdb);
00447 
00448         return 0;
00449 
00450 fail:
00451         tdb_close(tdb);
00452         return -1;
00453 }
00454 
00455 /* reopen all tdb's */
00456 int tdb_reopen_all(int parent_longlived)
00457 {
00458         struct tdb_context *tdb;
00459 
00460         for (tdb=tdbs; tdb; tdb = tdb->next) {
00461                 /*
00462                  * If the parent is longlived (ie. a
00463                  * parent daemon architecture), we know
00464                  * it will keep it's active lock on a
00465                  * tdb opened with CLEAR_IF_FIRST. Thus
00466                  * for child processes we don't have to
00467                  * add an active lock. This is essential
00468                  * to improve performance on systems that
00469                  * keep POSIX locks as a non-scalable data
00470                  * structure in the kernel.
00471                  */
00472                 if (parent_longlived) {
00473                         /* Ensure no clear-if-first. */
00474                         tdb->flags &= ~TDB_CLEAR_IF_FIRST;
00475                 }
00476 
00477                 if (tdb_reopen(tdb) != 0)
00478                         return -1;
00479         }
00480 
00481         return 0;
00482 }

Sambaに対してSat Aug 29 21:23:24 2009に生成されました。  doxygen 1.4.7