Ignore:
Timestamp:
Nov 27, 2012, 4:43:17 PM (13 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: updated trunk to 3.6.0

Location:
trunk/server
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/server

  • trunk/server/lib/tdb/common/open.c

    r456 r745  
    77   Copyright (C) Paul `Rusty' Russell              2000
    88   Copyright (C) Jeremy Allison                    2000-2003
    9    
     9
    1010     ** NOTE! The following LGPL license applies to the tdb
    1111     ** library. This does NOT imply that all of Samba is released
    1212     ** under the LGPL
    13    
     13
    1414   This library is free software; you can redistribute it and/or
    1515   modify it under the terms of the GNU Lesser General Public
     
    3636static struct tdb_context *tdbs = NULL;
    3737
    38 
    39 /* This is based on the hash algorithm from gdbm */
    40 static unsigned int default_tdb_hash(TDB_DATA *key)
    41 {
    42         uint32_t value; /* Used to compute the hash value.  */
    43         uint32_t   i;   /* Used to cycle through random values. */
    44 
    45         /* Set the initial value from the key size. */
    46         for (value = 0x238F13AF * key->dsize, i=0; i < key->dsize; i++)
    47                 value = (value + (key->dptr[i] << (i*5 % 24)));
    48 
    49         return (1103515243 * value + 12345); 
    50 }
    51 
     38/* We use two hashes to double-check they're using the right hash function. */
     39void tdb_header_hash(struct tdb_context *tdb,
     40                     uint32_t *magic1_hash, uint32_t *magic2_hash)
     41{
     42        TDB_DATA hash_key;
     43        uint32_t tdb_magic = TDB_MAGIC;
     44
     45        hash_key.dptr = discard_const_p(unsigned char, TDB_MAGIC_FOOD);
     46        hash_key.dsize = sizeof(TDB_MAGIC_FOOD);
     47        *magic1_hash = tdb->hash_fn(&hash_key);
     48
     49        hash_key.dptr = (unsigned char *)CONVERT(tdb_magic);
     50        hash_key.dsize = sizeof(tdb_magic);
     51        *magic2_hash = tdb->hash_fn(&hash_key);
     52
     53        /* Make sure at least one hash is non-zero! */
     54        if (*magic1_hash == 0 && *magic2_hash == 0)
     55                *magic1_hash = 1;
     56}
    5257
    5358/* initialise a new database with a specified hash size */
     
    5762        size_t size;
    5863        int ret = -1;
    59         ssize_t written;
    6064
    6165        /* We make it up in memory, then write it out if not internal */
     
    6973        newdb->version = TDB_VERSION;
    7074        newdb->hash_size = hash_size;
     75
     76        tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash);
     77
     78        /* Make sure older tdbs (which don't check the magic hash fields)
     79         * will refuse to open this TDB. */
     80        if (tdb->flags & TDB_INCOMPATIBLE_HASH)
     81                newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC;
     82
    7183        if (tdb->flags & TDB_INTERNAL) {
    7284                tdb->map_size = size;
     
    89101        memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
    90102        /* we still have "ret == -1" here */
    91         written = write(tdb->fd, newdb, size);
    92         if (written == size) {
     103        if (tdb_write_all(tdb->fd, newdb, size))
    93104                ret = 0;
    94         } else if (written != -1) {
    95                 /* call write once again, this usually should return -1 and
    96                  * set errno appropriately */
    97                 size -= written;
    98                 written = write(tdb->fd, newdb+written, size);
    99                 if (written == size) {
    100                 ret = 0;
    101                 } else if (written >= 0) {
    102                         /* a second incomplete write - we give up.
    103                          * guessing the errno... */
    104                         errno = ENOSPC;
    105                 }
    106         }
    107105
    108106  fail:
     
    117115{
    118116        struct tdb_context *i;
    119        
     117
    120118        for (i = tdbs; i; i = i->next) {
    121119                if (i->device == device && i->inode == ino) {
     
    137135
    138136   @param name may be NULL for internal databases. */
    139 struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
     137_PUBLIC_ struct tdb_context *tdb_open(const char *name, int hash_size, int tdb_flags,
    140138                      int open_flags, mode_t mode)
    141139{
     
    149147}
    150148
    151 
    152 struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
     149static bool check_header_hash(struct tdb_context *tdb,
     150                              bool default_hash, uint32_t *m1, uint32_t *m2)
     151{
     152        tdb_header_hash(tdb, m1, m2);
     153        if (tdb->header.magic1_hash == *m1 &&
     154            tdb->header.magic2_hash == *m2) {
     155                return true;
     156        }
     157
     158        /* If they explicitly set a hash, always respect it. */
     159        if (!default_hash)
     160                return false;
     161
     162        /* Otherwise, try the other inbuilt hash. */
     163        if (tdb->hash_fn == tdb_old_hash)
     164                tdb->hash_fn = tdb_jenkins_hash;
     165        else
     166                tdb->hash_fn = tdb_old_hash;
     167        return check_header_hash(tdb, false, m1, m2);
     168}
     169
     170_PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
    153171                                int open_flags, mode_t mode,
    154172                                const struct tdb_logging_context *log_ctx,
     
    161179        uint32_t vertest;
    162180        unsigned v;
     181        const char *hash_alg;
     182        uint32_t magic1, magic2;
    163183
    164184        if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
     
    182202                tdb->log.log_private = NULL;
    183203        }
    184         tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash;
     204
     205        if (name == NULL && (tdb_flags & TDB_INTERNAL)) {
     206                name = "__TDB_INTERNAL__";
     207        }
     208
     209        if (name == NULL) {
     210                tdb->name = discard_const_p(char, "__NULL__");
     211                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: called with name == NULL\n"));
     212                tdb->name = NULL;
     213                errno = EINVAL;
     214                goto fail;
     215        }
     216
     217        /* now make a copy of the name, as the caller memory might went away */
     218        if (!(tdb->name = (char *)strdup(name))) {
     219                /*
     220                 * set the name as the given string, so that tdb_name() will
     221                 * work in case of an error.
     222                 */
     223                tdb->name = discard_const_p(char, name);
     224                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: can't strdup(%s)\n",
     225                         name));
     226                tdb->name = NULL;
     227                errno = ENOMEM;
     228                goto fail;
     229        }
     230
     231        if (hash_fn) {
     232                tdb->hash_fn = hash_fn;
     233                hash_alg = "the user defined";
     234        } else {
     235                /* This controls what we use when creating a tdb. */
     236                if (tdb->flags & TDB_INCOMPATIBLE_HASH) {
     237                        tdb->hash_fn = tdb_jenkins_hash;
     238                } else {
     239                        tdb->hash_fn = tdb_old_hash;
     240                }
     241                hash_alg = "either default";
     242        }
    185243
    186244#ifdef __OS2__
     
    189247        }
    190248#endif
    191 
    192249        /* cache the page size */
    193250        tdb->page_size = getpagesize();
     
    204261                goto fail;
    205262        }
    206        
     263
    207264        if (hash_size == 0)
    208265                hash_size = DEFAULT_HASH_SIZE;
     
    223280        }
    224281
     282        if (getenv("TDB_NO_FSYNC")) {
     283                tdb->flags |= TDB_NOSYNC;
     284        }
     285
    225286        /*
    226287         * TDB_ALLOW_NESTING is the default behavior.
     
    253314
    254315        /* ensure there is only one process initialising at once */
    255         if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
    256                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get global lock on %s: %s\n",
     316        if (tdb_nest_lock(tdb, OPEN_LOCK, F_WRLCK, TDB_LOCK_WAIT) == -1) {
     317                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to get open lock on %s: %s\n",
    257318                         name, strerror(errno)));
    258319                goto fail;      /* errno set by tdb_brlock */
     
    261322        /* we need to zero database if we are the only one with it open */
    262323        if ((tdb_flags & TDB_CLEAR_IF_FIRST) &&
    263             (!tdb->read_only)
    264324#ifndef __OS2__
    265             && (locked = (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_WRLCK, F_SETLK, 0, 1) == 0))
    266 #endif
    267             ) {
     325            (!tdb->read_only) &&
     326            (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) {
     327#else
     328            (!tdb->read_only) ) {
     329#endif
    268330                open_flags |= O_CREAT;
    269331                if (ftruncate(tdb->fd, 0) == -1) {
     
    304366                goto fail;
    305367
    306         if (tdb->header.rwlocks != 0) {
     368        if (tdb->header.rwlocks != 0 &&
     369            tdb->header.rwlocks != TDB_HASH_RWLOCK_MAGIC) {
    307370                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
     371                goto fail;
     372        }
     373
     374        if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) {
     375                /* older TDB without magic hash references */
     376                tdb->hash_fn = tdb_old_hash;
     377        } else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) {
     378                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
     379                         "%s was not created with %s hash function we are using\n"
     380                         "magic1_hash[0x%08X %s 0x%08X] "
     381                         "magic2_hash[0x%08X %s 0x%08X]\n",
     382                         name, hash_alg,
     383                         tdb->header.magic1_hash,
     384                         (tdb->header.magic1_hash == magic1) ? "==" : "!=",
     385                         magic1,
     386                         tdb->header.magic2_hash,
     387                         (tdb->header.magic2_hash == magic2) ? "==" : "!=",
     388                         magic2));
     389                errno = EINVAL;
    308390                goto fail;
    309391        }
     
    318400        }
    319401
    320         if (!(tdb->name = (char *)strdup(name))) {
    321                 errno = ENOMEM;
    322                 goto fail;
    323         }
    324 
    325402        tdb->map_size = st.st_size;
    326403        tdb->device = st.st_dev;
     
    329406        if (locked) {
    330407#ifndef __OS2__
    331                 if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_UNLCK, F_SETLK, 0, 1) == -1) {
     408                if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) {
    332409                        TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
    333                                  "failed to take ACTIVE_LOCK on %s: %s\n",
     410                                 "failed to release ACTIVE_LOCK on %s: %s\n",
    334411                                 name, strerror(errno)));
    335412                        goto fail;
    336413                }
    337 
    338414#endif
    339415        }
     
    346422        if (tdb_flags & TDB_CLEAR_IF_FIRST) {
    347423                /* leave this lock in place to indicate it's in use */
    348                 if (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)
     424                if (tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
    349425                        goto fail;
     426                }
    350427        }
    351428#endif
     
    358435#ifdef __OS2__
    359436        // YD internal databases do not get global lock!
    360         if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1)
     437        if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1)
    361438                goto fail;
    362439#endif
     
    381458        /* Internal (memory-only) databases skip all the code above to
    382459         * do with disk files, and resume here by releasing their
    383          * global lock and hooking into the active list. */
     460         * open lock and hooking into the active list. */
    384461#ifndef __OS2__
    385         if (tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1) == -1)
    386                 goto fail;
     462        if (tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false) == -1) {
     463                goto fail;
     464        }
    387465#endif
    388466        tdb->next = tdbs;
    389                 tdbs = tdb;
     467        tdbs = tdb;
    390468        return tdb;
    391469
     
    405483                        tdb_munmap(tdb);
    406484        }
    407         SAFE_FREE(tdb->name);
     485        if (tdb->fd != -1)
     486                if (close(tdb->fd) != 0)
     487                        TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
    408488#ifdef __OS2__
    409489        DosCloseMutexSem( tdb->hGlobalLock);
     
    414494        tdb->hTransactionLock = 0;
    415495#endif
    416         if (tdb->fd != -1)
    417                 if (close(tdb->fd) != 0)
    418                         TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: failed to close tdb->fd on error!\n"));
     496        SAFE_FREE(tdb->lockrecs);
     497        SAFE_FREE(tdb->name);
    419498        SAFE_FREE(tdb);
    420499        errno = save_errno;
     
    427506 */
    428507
    429 void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)
     508_PUBLIC_ void tdb_set_max_dead(struct tdb_context *tdb, int max_dead)
    430509{
    431510        tdb->max_dead_records = max_dead;
     
    437516 * @returns -1 for error; 0 for success.
    438517 **/
    439 int tdb_close(struct tdb_context *tdb)
     518_PUBLIC_ int tdb_close(struct tdb_context *tdb)
    440519{
    441520        struct tdb_context **i;
    442521        int ret = 0;
    443522
     523        if (tdb->transaction) {
     524                tdb_transaction_cancel(tdb);
     525        }
    444526        tdb_trace(tdb, "tdb_close");
    445         if (tdb->transaction) {
    446                 _tdb_transaction_cancel(tdb);
    447         }
    448527
    449528        if (tdb->map_ptr) {
     
    457536        // YD internal databases do not have a global lock
    458537        if (!(tdb->flags & TDB_INTERNAL))
    459                 tdb->methods->tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLK, 0, 1);
     538        tdb_nest_unlock(tdb, OPEN_LOCK, F_WRLCK, false);
    460539#endif
    461540        if (tdb->fd != -1) {
     
    491570
    492571/* register a loging function */
    493 void tdb_set_logging_function(struct tdb_context *tdb,
    494                               const struct tdb_logging_context *log_ctx)
     572_PUBLIC_ void tdb_set_logging_function(struct tdb_context *tdb,
     573                                       const struct tdb_logging_context *log_ctx)
    495574{
    496575        tdb->log = *log_ctx;
    497576}
    498577
    499 void *tdb_get_logging_private(struct tdb_context *tdb)
     578_PUBLIC_ void *tdb_get_logging_private(struct tdb_context *tdb)
    500579{
    501580        return tdb->log.log_private;
     
    526605#endif
    527606
    528         if (tdb->num_locks != 0 || tdb->global_lock.count) {
     607        if (tdb_have_extra_locks(tdb)) {
    529608                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_reopen: reopen not allowed with locks held\n"));
    530609                goto fail;
     
    561640#endif /* fake pread or pwrite */
    562641
    563         if (active_lock &&
    564             (tdb->methods->tdb_brlock(tdb, ACTIVE_LOCK, F_RDLCK, F_SETLKW, 0, 1) == -1)) {
     642        /* We may still think we hold the active lock. */
     643        tdb->num_lockrecs = 0;
     644        SAFE_FREE(tdb->lockrecs);
     645
     646        if (active_lock && tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
    565647                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: failed to obtain active lock\n"));
    566648                goto fail;
     
    576658/* reopen a tdb - this can be used after a fork to ensure that we have an independent
    577659   seek pointer from our parent and to re-establish locks */
    578 int tdb_reopen(struct tdb_context *tdb)
     660_PUBLIC_ int tdb_reopen(struct tdb_context *tdb)
    579661{
    580662        return tdb_reopen_internal(tdb, tdb->flags & TDB_CLEAR_IF_FIRST);
     
    582664
    583665/* reopen all tdb's */
    584 int tdb_reopen_all(int parent_longlived)
     666_PUBLIC_ int tdb_reopen_all(int parent_longlived)
    585667{
    586668        struct tdb_context *tdb;
     
    623705                // extract path info
    624706                _splitpath( name, drive, dir, fname, ext);
    625                 sprintf( szSem, "\\SEM32\\TDB_GL_%s%s%s%i", dir, fname, ext, global_Sem32Add);
     707                sprintf( szSem, "\\SEM32\\TDB_OL_%s%s%s%i", dir, fname, ext, global_Sem32Add);
    626708                rc = DosCreateMutexSem( szSem, &tdb->hGlobalLock, 0, FALSE);
    627709                if (rc == ERROR_DUPLICATE_NAME)
     
    632714                        return -1;
    633715                }
    634                 TDB_LOG((tdb, TDB_DEBUG_TRACE,"%s pid %d global handle %d\n", caller, getpid(), tdb->hGlobalLock));
     716                TDB_LOG((tdb, TDB_DEBUG_TRACE,"%s pid %d open handle %d\n", caller, getpid(), tdb->hGlobalLock));
    635717
    636718                sprintf( szSem, "\\SEM32\\TDB_AL_%s%s%s%i", dir, fname, ext, global_Sem32Add);
     
    659741}
    660742#endif
    661                
Note: See TracChangeset for help on using the changeset viewer.