Changeset 988 for vendor/current/lib/tdb


Ignore:
Timestamp:
Nov 24, 2016, 1:14:11 PM (9 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to version 4.4.3

Location:
vendor/current/lib/tdb
Files:
65 added
2 deleted
31 edited
1 moved

Legend:

Unmodified
Added
Removed
  • vendor/current/lib/tdb/Makefile

    r986 r988  
    1212        $(WAF) uninstall
    1313
    14 test:
     14test: FORCE
    1515        $(WAF) test $(TEST_OPTIONS)
    1616
  • vendor/current/lib/tdb/common/check.c

    r986 r988  
    4040                goto corrupt;
    4141
    42         if (hdr.rwlocks != 0 && hdr.rwlocks != TDB_HASH_RWLOCK_MAGIC)
     42        if (hdr.rwlocks != 0 &&
     43            hdr.rwlocks != TDB_FEATURE_FLAG_MAGIC &&
     44            hdr.rwlocks != TDB_HASH_RWLOCK_MAGIC)
    4345                goto corrupt;
    4446
     
    5153                goto corrupt;
    5254
    53         if (hdr.hash_size != tdb->header.hash_size)
     55        if (hdr.hash_size != tdb->hash_size)
    5456                goto corrupt;
    5557
    5658        if (hdr.recovery_start != 0 &&
    57             hdr.recovery_start < TDB_DATA_START(tdb->header.hash_size))
     59            hdr.recovery_start < TDB_DATA_START(tdb->hash_size))
    5860                goto corrupt;
    5961
     
    7577
    7678        /* Check rec->next: 0 or points to record offset, aligned. */
    77         if (rec->next > 0 && rec->next < TDB_DATA_START(tdb->header.hash_size)){
    78                 TDB_LOG((tdb, TDB_DEBUG_ERROR,
    79                          "Record offset %d too small next %d\n",
     79        if (rec->next > 0 && rec->next < TDB_DATA_START(tdb->hash_size)){
     80                TDB_LOG((tdb, TDB_DEBUG_ERROR,
     81                         "Record offset %u too small next %u\n",
    8082                         off, rec->next));
    8183                goto corrupt;
     
    8385        if (rec->next + sizeof(*rec) < rec->next) {
    8486                TDB_LOG((tdb, TDB_DEBUG_ERROR,
    85                          "Record offset %d too large next %d\n",
     87                         "Record offset %u too large next %u\n",
    8688                         off, rec->next));
    8789                goto corrupt;
     
    8991        if ((rec->next % TDB_ALIGNMENT) != 0) {
    9092                TDB_LOG((tdb, TDB_DEBUG_ERROR,
    91                          "Record offset %d misaligned next %d\n",
     93                         "Record offset %u misaligned next %u\n",
    9294                         off, rec->next));
    9395                goto corrupt;
    9496        }
    95         if (tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0))
     97        if (tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 0))
    9698                goto corrupt;
    9799
     
    99101        if ((rec->rec_len % TDB_ALIGNMENT) != 0) {
    100102                TDB_LOG((tdb, TDB_DEBUG_ERROR,
    101                          "Record offset %d misaligned length %d\n",
     103                         "Record offset %u misaligned length %u\n",
    102104                         off, rec->rec_len));
    103105                goto corrupt;
     
    106108        if (rec->rec_len < sizeof(tailer)) {
    107109                TDB_LOG((tdb, TDB_DEBUG_ERROR,
    108                          "Record offset %d too short length %d\n",
     110                         "Record offset %u too short length %u\n",
    109111                         off, rec->rec_len));
    110112                goto corrupt;
    111113        }
    112114        /* OOB allows "right at the end" access, so this works for last rec. */
    113         if (tdb->methods->tdb_oob(tdb, off+sizeof(*rec)+rec->rec_len, 0))
     115        if (tdb->methods->tdb_oob(tdb, off, sizeof(*rec)+rec->rec_len, 0))
    114116                goto corrupt;
    115117
     
    120122        if (tailer != sizeof(*rec) + rec->rec_len) {
    121123                TDB_LOG((tdb, TDB_DEBUG_ERROR,
    122                          "Record offset %d invalid tailer\n", off));
     124                         "Record offset %u invalid tailer\n", off));
    123125                goto corrupt;
    124126        }
     
    248250        if (rec->key_len + rec->data_len + sizeof(tdb_off_t) > rec->rec_len) {
    249251                TDB_LOG((tdb, TDB_DEBUG_ERROR,
    250                          "Record offset %d too short for contents\n", off));
     252                         "Record offset %u too short for contents\n", off));
    251253                return false;
    252254        }
     
    258260        if (tdb->hash_fn(&key) != rec->full_hash) {
    259261                TDB_LOG((tdb, TDB_DEBUG_ERROR,
    260                          "Record offset %d has incorrect hash\n", off));
     262                         "Record offset %u has incorrect hash\n", off));
    261263                goto fail_put_key;
    262264        }
     
    346348
    347349        /* Make sure we know true size of the underlying file. */
    348         tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
     350        tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1);
    349351
    350352        /* Header must be OK: also gets us the recovery ptr, if any. */
     
    353355
    354356        /* We should have the whole header, too. */
    355         if (tdb->map_size < TDB_DATA_START(tdb->header.hash_size)) {
     357        if (tdb->map_size < TDB_DATA_START(tdb->hash_size)) {
    356358                tdb->ecode = TDB_ERR_CORRUPT;
    357359                TDB_LOG((tdb, TDB_DEBUG_ERROR, "File too short for hashes\n"));
     
    361363        /* One big malloc: pointers then bit arrays. */
    362364        hashes = (unsigned char **)calloc(
    363                         1, sizeof(hashes[0]) * (1+tdb->header.hash_size)
    364                         + BITMAP_BITS / CHAR_BIT * (1+tdb->header.hash_size));
     365                        1, sizeof(hashes[0]) * (1+tdb->hash_size)
     366                        + BITMAP_BITS / CHAR_BIT * (1+tdb->hash_size));
    365367        if (!hashes) {
    366368                tdb->ecode = TDB_ERR_OOM;
     
    369371
    370372        /* Initialize pointers */
    371         hashes[0] = (unsigned char *)(&hashes[1+tdb->header.hash_size]);
    372         for (h = 1; h < 1+tdb->header.hash_size; h++)
     373        hashes[0] = (unsigned char *)(&hashes[1+tdb->hash_size]);
     374        for (h = 1; h < 1+tdb->hash_size; h++)
    373375                hashes[h] = hashes[h-1] + BITMAP_BITS / CHAR_BIT;
    374376
    375377        /* Freelist and hash headers are all in a row: read them. */
    376         for (h = 0; h < 1+tdb->header.hash_size; h++) {
     378        for (h = 0; h < 1+tdb->hash_size; h++) {
    377379                if (tdb_ofs_read(tdb, FREELIST_TOP + h*sizeof(tdb_off_t),
    378380                                 &off) == -1)
     
    383385
    384386        /* For each record, read it in and check it's ok. */
    385         for (off = TDB_DATA_START(tdb->header.hash_size);
     387        for (off = TDB_DATA_START(tdb->hash_size);
    386388             off < tdb->map_size;
    387389             off += sizeof(rec) + rec.rec_len) {
     
    412414
    413415                        TDB_LOG((tdb, TDB_DEBUG_ERROR,
    414                                  "Dead space at %d-%d (of %u)\n",
     416                                 "Dead space at %u-%u (of %u)\n",
    415417                                 off, off + dead, tdb->map_size));
    416418                        rec.rec_len = dead - sizeof(rec);
     
    419421                        if (recovery_start != off) {
    420422                                TDB_LOG((tdb, TDB_DEBUG_ERROR,
    421                                          "Unexpected recovery record at offset %d\n",
     423                                         "Unexpected recovery record at offset %u\n",
    422424                                         off));
    423425                                goto free;
     
    429431                        tdb->ecode = TDB_ERR_CORRUPT;
    430432                        TDB_LOG((tdb, TDB_DEBUG_ERROR,
    431                                  "Bad magic 0x%x at offset %d\n",
     433                                 "Bad magic 0x%x at offset %u\n",
    432434                                 rec.magic, off));
    433435                        goto free;
     
    437439        /* Now, hashes should all be empty: each record exists and is referred
    438440         * to by one other. */
    439         for (h = 0; h < 1+tdb->header.hash_size; h++) {
     441        for (h = 0; h < 1+tdb->hash_size; h++) {
    440442                unsigned int i;
    441443                for (i = 0; i < BITMAP_BITS / CHAR_BIT; i++) {
  • vendor/current/lib/tdb/common/dump.c

    r986 r988  
    1  /* 
     1 /*
    22   Unix SMB/CIFS implementation.
    33
     
    3434        tdb_off_t tailer_ofs, tailer;
    3535
    36         if (tdb->methods->tdb_read(tdb, offset, (char *)&rec, 
     36        if (tdb->methods->tdb_read(tdb, offset, (char *)&rec,
    3737                                   sizeof(rec), DOCONV()) == -1) {
    3838                printf("ERROR: failed to read record at %u\n", offset);
     
    4040        }
    4141
    42         printf(" rec: hash=%d offset=0x%08x next=0x%08x rec_len=%d "
    43                "key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n",
     42        printf(" rec: hash=%d offset=0x%08x next=0x%08x rec_len=%u "
     43               "key_len=%u data_len=%u full_hash=0x%08x magic=0x%08x\n",
    4444               hash, offset, rec.next, rec.rec_len, rec.key_len, rec.data_len,
    4545               rec.full_hash, rec.magic);
     
    8484{
    8585        int i;
    86         for (i=0;i<tdb->header.hash_size;i++) {
     86        for (i=0;i<tdb->hash_size;i++) {
    8787                tdb_dump_chain(tdb, i);
    8888        }
     
    111111        printf("freelist top=[0x%08x]\n", rec_ptr );
    112112        while (rec_ptr) {
    113                 if (tdb->methods->tdb_read(tdb, rec_ptr, (char *)&rec, 
     113                if (tdb->methods->tdb_read(tdb, rec_ptr, (char *)&rec,
    114114                                           sizeof(rec), DOCONV()) == -1) {
    115115                        tdb_unlock(tdb, -1, F_WRLCK);
     
    123123                }
    124124
    125                 printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%d)] (end = 0x%08x)\n",
     125                printf("entry offset=[0x%08x], rec.rec_len = [0x%08x (%u)] (end = 0x%08x)\n",
    126126                       rec_ptr, rec.rec_len, rec.rec_len, rec_ptr + rec.rec_len);
    127127                total_free += rec.rec_len;
     
    130130                rec_ptr = rec.next;
    131131        }
    132         printf("total rec_len = [0x%08x (%d)]\n", (int)total_free,
    133                (int)total_free);
     132        printf("total rec_len = [0x%08lx (%lu)]\n", total_free, total_free);
    134133
    135134        return tdb_unlock(tdb, -1, F_WRLCK);
  • vendor/current/lib/tdb/common/error.c

    r986 r988  
    1  /* 
     1 /*
    22   Unix SMB/CIFS implementation.
    33
  • vendor/current/lib/tdb/common/freelist.c

    r986 r988  
    1  /* 
     1 /*
    22   Unix SMB/CIFS implementation.
    33
     
    2929
    3030/* 'right' merges can involve O(n^2) cost when combined with a
    31    traverse, so they are disabled until we find a way to do them in 
     31   traverse, so they are disabled until we find a way to do them in
    3232   O(1) time
    3333*/
     
    4343                /* this happens when a app is showdown while deleting a record - we should
    4444                   not completely fail when this happens */
    45                 TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read non-free magic 0x%x at offset=%d - fixing\n",
     45                TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read non-free magic 0x%x at offset=%u - fixing\n",
    4646                         rec->magic, off));
    4747                rec->magic = TDB_FREE_MAGIC;
    48                 if (tdb->methods->tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
     48                if (tdb_rec_write(tdb, off, rec) == -1)
    4949                        return -1;
    5050        }
     
    5353                /* Ensure ecode is set for log fn. */
    5454                tdb->ecode = TDB_ERR_CORRUPT;
    55                 TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read bad magic 0x%x at offset=%d\n",
     55                TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read bad magic 0x%x at offset=%u\n",
    5656                           rec->magic, off));
    5757                return -1;
    5858        }
    59         if (tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0) != 0)
     59        if (tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 0) != 0)
    6060                return -1;
    6161        return 0;
     
    8080        }
    8181        tdb->ecode = TDB_ERR_CORRUPT;
    82         TDB_LOG((tdb, TDB_DEBUG_FATAL,"remove_from_freelist: not on list at off=%d\n", off));
     82        TDB_LOG((tdb, TDB_DEBUG_FATAL,"remove_from_freelist: not on list at off=%u\n", off));
    8383        return -1;
    8484}
     
    9898}
    9999
    100 /* Add an element into the freelist. Merge adjacent records if
    101    necessary. */
     100/**
     101 * Read the record directly on the left.
     102 * Fail if there is no record on the left.
     103 */
     104static int read_record_on_left(struct tdb_context *tdb, tdb_off_t rec_ptr,
     105                               tdb_off_t *left_p,
     106                               struct tdb_record *left_r)
     107{
     108        tdb_off_t left_ptr;
     109        tdb_off_t left_size;
     110        struct tdb_record left_rec;
     111        int ret;
     112
     113        left_ptr = rec_ptr - sizeof(tdb_off_t);
     114
     115        if (left_ptr <= TDB_DATA_START(tdb->hash_size)) {
     116                /* no record on the left */
     117                return -1;
     118        }
     119
     120        /* Read in tailer and jump back to header */
     121        ret = tdb_ofs_read(tdb, left_ptr, &left_size);
     122        if (ret == -1) {
     123                TDB_LOG((tdb, TDB_DEBUG_FATAL,
     124                        "tdb_free: left offset read failed at %u\n", left_ptr));
     125                return -1;
     126        }
     127
     128        /* it could be uninitialised data */
     129        if (left_size == 0 || left_size == TDB_PAD_U32) {
     130                return -1;
     131        }
     132
     133        if (left_size > rec_ptr) {
     134                return -1;
     135        }
     136
     137        left_ptr = rec_ptr - left_size;
     138
     139        if (left_ptr < TDB_DATA_START(tdb->hash_size)) {
     140                return -1;
     141        }
     142
     143        /* Now read in the left record */
     144        ret = tdb->methods->tdb_read(tdb, left_ptr, &left_rec,
     145                                     sizeof(left_rec), DOCONV());
     146        if (ret == -1) {
     147                TDB_LOG((tdb, TDB_DEBUG_FATAL,
     148                         "tdb_free: left read failed at %u (%u)\n",
     149                         left_ptr, left_size));
     150                return -1;
     151        }
     152
     153        *left_p = left_ptr;
     154        *left_r = left_rec;
     155
     156        return 0;
     157}
     158
     159/**
     160 * Merge new freelist record with the direct left neighbour.
     161 * This assumes that left_rec represents the record
     162 * directly to the left of right_rec and that this is
     163 * a freelist record.
     164 */
     165static int merge_with_left_record(struct tdb_context *tdb,
     166                                  tdb_off_t left_ptr,
     167                                  struct tdb_record *left_rec,
     168                                  struct tdb_record *right_rec)
     169{
     170        int ret;
     171
     172        left_rec->rec_len += sizeof(*right_rec) + right_rec->rec_len;
     173
     174        ret = tdb_rec_write(tdb, left_ptr, left_rec);
     175        if (ret == -1) {
     176                TDB_LOG((tdb, TDB_DEBUG_FATAL,
     177                         "merge_with_left_record: update_left failed at %u\n",
     178                         left_ptr));
     179                return -1;
     180        }
     181
     182        ret = update_tailer(tdb, left_ptr, left_rec);
     183        if (ret == -1) {
     184                TDB_LOG((tdb, TDB_DEBUG_FATAL,
     185                         "merge_with_left_record: update_tailer failed at %u\n",
     186                         left_ptr));
     187                return -1;
     188        }
     189
     190        return 0;
     191}
     192
     193/**
     194 * Check whether the record left of a given freelist record is
     195 * also a freelist record, and if so, merge the two records.
     196 *
     197 * Return code:
     198 *  -1 upon error
     199 *   0 if left was not a free record
     200 *   1 if left was free and successfully merged.
     201 *
     202 * The currend record is handed in with pointer and fully read record.
     203 *
     204 * The left record pointer and struct can be retrieved as result
     205 * in lp and lr;
     206 */
     207static int check_merge_with_left_record(struct tdb_context *tdb,
     208                                        tdb_off_t rec_ptr,
     209                                        struct tdb_record *rec,
     210                                        tdb_off_t *lp,
     211                                        struct tdb_record *lr)
     212{
     213        tdb_off_t left_ptr;
     214        struct tdb_record left_rec;
     215        int ret;
     216
     217        ret = read_record_on_left(tdb, rec_ptr, &left_ptr, &left_rec);
     218        if (ret != 0) {
     219                return 0;
     220        }
     221
     222        if (left_rec.magic != TDB_FREE_MAGIC) {
     223                return 0;
     224        }
     225
     226        /* It's free - expand to include it. */
     227        ret = merge_with_left_record(tdb, left_ptr, &left_rec, rec);
     228        if (ret != 0) {
     229                return -1;
     230        }
     231
     232        if (lp != NULL) {
     233                *lp = left_ptr;
     234        }
     235
     236        if (lr != NULL) {
     237                *lr = left_rec;
     238        }
     239
     240        return 1;
     241}
     242
     243/**
     244 * Check whether the record left of a given freelist record is
     245 * also a freelist record, and if so, merge the two records.
     246 *
     247 * Return code:
     248 *  -1 upon error
     249 *   0 if left was not a free record
     250 *   1 if left was free and successfully merged.
     251 *
     252 * In this variant, the input record is specified just as the pointer
     253 * and is read from the database if needed.
     254 *
     255 * next_ptr will contain the original record's next pointer after
     256 * successful merging (which will be lost after merging), so that
     257 * the caller can update the last pointer.
     258 */
     259static int check_merge_ptr_with_left_record(struct tdb_context *tdb,
     260                                            tdb_off_t rec_ptr,
     261                                            tdb_off_t *next_ptr)
     262{
     263        tdb_off_t left_ptr;
     264        struct tdb_record rec, left_rec;
     265        int ret;
     266
     267        ret = read_record_on_left(tdb, rec_ptr, &left_ptr, &left_rec);
     268        if (ret != 0) {
     269                return 0;
     270        }
     271
     272        if (left_rec.magic != TDB_FREE_MAGIC) {
     273                return 0;
     274        }
     275
     276        /* It's free - expand to include it. */
     277
     278        ret = tdb->methods->tdb_read(tdb, rec_ptr, &rec,
     279                                     sizeof(rec), DOCONV());
     280        if (ret != 0) {
     281                return -1;
     282        }
     283
     284        ret = merge_with_left_record(tdb, left_ptr, &left_rec, &rec);
     285        if (ret != 0) {
     286                return -1;
     287        }
     288
     289        if (next_ptr != NULL) {
     290                *next_ptr = rec.next;
     291        }
     292
     293        return 1;
     294}
     295
     296/**
     297 * Add an element into the freelist.
     298 *
     299 * We merge the new record into the left record if it is also a
     300 * free record, but not with the right one. This makes the
     301 * operation O(1) instead of O(n): merging with the right record
     302 * requires a traverse of the freelist to find the previous
     303 * record in the free list.
     304 *
     305 * This prevents db traverses from being O(n^2) after a lot of deletes.
     306 */
    102307int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec)
    103308{
     309        int ret;
     310
    104311        /* Allocation and tailer lock */
    105312        if (tdb_lock(tdb, -1, F_WRLCK) != 0)
     
    139346#endif
    140347
    141         /* Look left */
    142         if (offset - sizeof(tdb_off_t) > TDB_DATA_START(tdb->header.hash_size)) {
    143                 tdb_off_t left = offset - sizeof(tdb_off_t);
    144                 struct tdb_record l;
    145                 tdb_off_t leftsize;
    146 
    147                 /* Read in tailer and jump back to header */
    148                 if (tdb_ofs_read(tdb, left, &leftsize) == -1) {
    149                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left offset read failed at %u\n", left));
    150                         goto update;
    151                 }
    152 
    153                 /* it could be uninitialised data */
    154                 if (leftsize == 0 || leftsize == TDB_PAD_U32) {
    155                         goto update;
    156                 }
    157 
    158                 left = offset - leftsize;
    159 
    160                 if (leftsize > offset ||
    161                     left < TDB_DATA_START(tdb->header.hash_size)) {
    162                         goto update;
    163                 }
    164 
    165                 /* Now read in the left record */
    166                 if (tdb->methods->tdb_read(tdb, left, &l, sizeof(l), DOCONV()) == -1) {
    167                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left read failed at %u (%u)\n", left, leftsize));
    168                         goto update;
    169                 }
    170 
    171                 /* If it's free, expand to include it. */
    172                 if (l.magic == TDB_FREE_MAGIC) {
    173                         /* we now merge the new record into the left record, rather than the other
    174                            way around. This makes the operation O(1) instead of O(n). This change
    175                            prevents traverse from being O(n^2) after a lot of deletes */
    176                         l.rec_len += sizeof(*rec) + rec->rec_len;
    177                         if (tdb_rec_write(tdb, left, &l) == -1) {
    178                                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_left failed at %u\n", left));
    179                                 goto fail;
    180                         }
    181                         if (update_tailer(tdb, left, &l) == -1) {
    182                                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
    183                                 goto fail;
    184                         }
    185                         tdb_unlock(tdb, -1, F_WRLCK);
    186                         return 0;
    187                 }
    188         }
    189 
    190 update:
    191 
    192         /* Now, prepend to free list */
     348        ret = check_merge_with_left_record(tdb, offset, rec, NULL, NULL);
     349        if (ret == -1) {
     350                goto fail;
     351        }
     352        if (ret == 1) {
     353                /* merged */
     354                goto done;
     355        }
     356
     357        /* Nothing to merge, prepend to free list */
     358
    193359        rec->magic = TDB_FREE_MAGIC;
    194360
     
    196362            tdb_rec_write(tdb, offset, rec) == -1 ||
    197363            tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
    198                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free record write failed at offset=%d\n", offset));
     364                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free record write failed at offset=%u\n", offset));
    199365                goto fail;
    200366        }
    201367
     368done:
    202369        /* And we're done. */
    203370        tdb_unlock(tdb, -1, F_WRLCK);
     
    211378
    212379
    213 /* 
     380/*
    214381   the core of tdb_allocate - called when we have decided which
    215382   free list entry to use
     
    219386   able to free up the record without fragmentation
    220387 */
    221 static tdb_off_t tdb_allocate_ofs(struct tdb_context *tdb, 
     388static tdb_off_t tdb_allocate_ofs(struct tdb_context *tdb,
    222389                                  tdb_len_t length, tdb_off_t rec_ptr,
    223390                                  struct tdb_record *rec, tdb_off_t last_ptr)
     
    251418
    252419        /* and setup the new record */
    253         rec_ptr += sizeof(*rec) + rec->rec_len; 
     420        rec_ptr += sizeof(*rec) + rec->rec_len;
    254421
    255422        memset(rec, '\0', sizeof(*rec));
     
    274441   0 is returned if the space could not be allocated
    275442 */
    276 tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec)
     443static tdb_off_t tdb_allocate_from_freelist(
     444        struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec)
    277445{
    278446        tdb_off_t rec_ptr, last_ptr, newrec_ptr;
     
    282450        } bestfit;
    283451        float multiplier = 1.0;
    284 
    285         if (tdb_lock(tdb, -1, F_WRLCK) == -1)
    286                 return 0;
     452        bool merge_created_candidate;
    287453
    288454        /* over-allocate to reduce fragmentation */
     
    294460
    295461 again:
     462        merge_created_candidate = false;
    296463        last_ptr = FREELIST_TOP;
    297464
    298465        /* read in the freelist top */
    299466        if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1)
    300                 goto fail;
     467                return 0;
    301468
    302469        bestfit.rec_ptr = 0;
     
    304471        bestfit.rec_len = 0;
    305472
    306         /* 
     473        /*
    307474           this is a best fit allocation strategy. Originally we used
    308475           a first fit strategy, but it suffered from massive fragmentation
     
    310477         */
    311478        while (rec_ptr) {
     479                int ret;
     480                tdb_off_t left_ptr;
     481                struct tdb_record left_rec;
     482
    312483                if (tdb_rec_free_read(tdb, rec_ptr, rec) == -1) {
    313                         goto fail;
     484                        return 0;
     485                }
     486
     487                ret = check_merge_with_left_record(tdb, rec_ptr, rec,
     488                                                   &left_ptr, &left_rec);
     489                if (ret == -1) {
     490                        return 0;
     491                }
     492                if (ret == 1) {
     493                        /* merged */
     494                        rec_ptr = rec->next;
     495                        ret = tdb_ofs_write(tdb, last_ptr, &rec->next);
     496                        if (ret == -1) {
     497                                return 0;
     498                        }
     499
     500                        /*
     501                         * We have merged the current record into the left
     502                         * neighbour. So our traverse of the freelist will
     503                         * skip it and consider the next record in the chain.
     504                         *
     505                         * But the enlarged left neighbour may be a candidate.
     506                         * If it is, we can not directly use it, though.
     507                         * The only thing we can do and have to do here is to
     508                         * update the current best fit size in the chain if the
     509                         * current best fit is the left record. (By that we may
     510                         * worsen the best fit we already had, bit this is not a
     511                         * problem.)
     512                         *
     513                         * If the current best fit is not the left record,
     514                         * all we can do is remember the fact that a merge
     515                         * created a new candidate so that we can trigger
     516                         * a second walk of the freelist if at the end of
     517                         * the first walk we have not found any fit.
     518                         * This way we can avoid expanding the database.
     519                         */
     520
     521                        if (bestfit.rec_ptr == left_ptr) {
     522                                bestfit.rec_len = left_rec.rec_len;
     523                        }
     524
     525                        if (left_rec.rec_len > length) {
     526                                merge_created_candidate = true;
     527                        }
     528
     529                        continue;
    314530                }
    315531
     
    345561        if (bestfit.rec_ptr != 0) {
    346562                if (tdb_rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) {
    347                         goto fail;
    348                 }
    349 
    350                 newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr, 
     563                        return 0;
     564                }
     565
     566                newrec_ptr = tdb_allocate_ofs(tdb, length, bestfit.rec_ptr,
    351567                                              rec, bestfit.last_ptr);
    352                 tdb_unlock(tdb, -1, F_WRLCK);
    353568                return newrec_ptr;
     569        }
     570
     571        if (merge_created_candidate) {
     572                goto again;
    354573        }
    355574
     
    358577        if (tdb_expand(tdb, length + sizeof(*rec)) == 0)
    359578                goto again;
    360  fail:
     579
     580        return 0;
     581}
     582
     583static bool tdb_alloc_dead(
     584        struct tdb_context *tdb, int hash, tdb_len_t length,
     585        tdb_off_t *rec_ptr, struct tdb_record *rec)
     586{
     587        tdb_off_t last_ptr;
     588
     589        *rec_ptr = tdb_find_dead(tdb, hash, rec, length, &last_ptr);
     590        if (*rec_ptr == 0) {
     591                return false;
     592        }
     593        /*
     594         * Unlink the record from the hash chain, it's about to be moved into
     595         * another one.
     596         */
     597        return (tdb_ofs_write(tdb, last_ptr, &rec->next) == 0);
     598}
     599
     600/*
     601 * Chain "hash" is assumed to be locked
     602 */
     603
     604tdb_off_t tdb_allocate(struct tdb_context *tdb, int hash, tdb_len_t length,
     605                       struct tdb_record *rec)
     606{
     607        tdb_off_t ret;
     608        int i;
     609
     610        if (tdb->max_dead_records == 0) {
     611                /*
     612                 * No dead records to expect anywhere. Do the blocking
     613                 * freelist lock without trying to steal from others
     614                 */
     615                goto blocking_freelist_allocate;
     616        }
     617
     618        /*
     619         * The following loop tries to get the freelist lock nonblocking. If
     620         * it gets the lock, allocate from there. If the freelist is busy,
     621         * instead of waiting we try to steal dead records from other hash
     622         * chains.
     623         *
     624         * Be aware that we do nonblocking locks on the other hash chains as
     625         * well and fail gracefully. This way we avoid deadlocks (we block two
     626         * hash chains, something which is pretty bad normally)
     627         */
     628
     629        for (i=0; i<tdb->hash_size; i++) {
     630
     631                int list;
     632
     633                list = BUCKET(hash+i);
     634
     635                if (tdb_lock_nonblock(tdb, list, F_WRLCK) == 0) {
     636                        bool got_dead;
     637
     638                        got_dead = tdb_alloc_dead(tdb, list, length, &ret, rec);
     639                        tdb_unlock(tdb, list, F_WRLCK);
     640
     641                        if (got_dead) {
     642                                return ret;
     643                        }
     644                }
     645
     646                if (tdb_lock_nonblock(tdb, -1, F_WRLCK) == 0) {
     647                        /*
     648                         * Under the freelist lock take the chance to give
     649                         * back our dead records.
     650                         */
     651                        tdb_purge_dead(tdb, hash);
     652
     653                        ret = tdb_allocate_from_freelist(tdb, length, rec);
     654                        tdb_unlock(tdb, -1, F_WRLCK);
     655                        return ret;
     656                }
     657        }
     658
     659blocking_freelist_allocate:
     660
     661        if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
     662                return 0;
     663        }
     664        ret = tdb_allocate_from_freelist(tdb, length, rec);
    361665        tdb_unlock(tdb, -1, F_WRLCK);
    362         return 0;
    363 }
    364 
    365 
    366 
    367 /*
    368    return the size of the freelist - used to decide if we should repack
    369 */
    370 _PUBLIC_ int tdb_freelist_size(struct tdb_context *tdb)
     666        return ret;
     667}
     668
     669/**
     670 * Merge adjacent records in the freelist.
     671 */
     672static int tdb_freelist_merge_adjacent(struct tdb_context *tdb,
     673                                       int *count_records, int *count_merged)
     674{
     675        tdb_off_t cur, next;
     676        int count = 0;
     677        int merged = 0;
     678        int ret;
     679
     680        ret = tdb_lock(tdb, -1, F_RDLCK);
     681        if (ret == -1) {
     682                return -1;
     683        }
     684
     685        cur = FREELIST_TOP;
     686        while (tdb_ofs_read(tdb, cur, &next) == 0 && next != 0) {
     687                tdb_off_t next2;
     688
     689                count++;
     690
     691                ret = check_merge_ptr_with_left_record(tdb, next, &next2);
     692                if (ret == -1) {
     693                        goto done;
     694                }
     695                if (ret == 1) {
     696                        /*
     697                         * merged:
     698                         * now let cur->next point to next2 instead of next
     699                         */
     700
     701                        ret = tdb_ofs_write(tdb, cur, &next2);
     702                        if (ret != 0) {
     703                                goto done;
     704                        }
     705
     706                        next = next2;
     707                        merged++;
     708                }
     709
     710                cur = next;
     711        }
     712
     713        if (count_records != NULL) {
     714                *count_records = count;
     715        }
     716
     717        if (count_merged != NULL) {
     718                *count_merged = merged;
     719        }
     720
     721        ret = 0;
     722
     723done:
     724        tdb_unlock(tdb, -1, F_RDLCK);
     725        return ret;
     726}
     727
     728/**
     729 * return the size of the freelist - no merging done
     730 */
     731static int tdb_freelist_size_no_merge(struct tdb_context *tdb)
    371732{
    372733        tdb_off_t ptr;
     
    385746        return count;
    386747}
     748
     749/**
     750 * return the size of the freelist - used to decide if we should repack
     751 *
     752 * As a side effect, adjacent records are merged unless the
     753 * database is read-only, in order to reduce the fragmentation
     754 * without repacking.
     755 */
     756_PUBLIC_ int tdb_freelist_size(struct tdb_context *tdb)
     757{
     758
     759        int count = 0;
     760
     761        if (tdb->read_only) {
     762                count = tdb_freelist_size_no_merge(tdb);
     763        } else {
     764                int ret;
     765                ret = tdb_freelist_merge_adjacent(tdb, &count, NULL);
     766                if (ret != 0) {
     767                        return -1;
     768                }
     769        }
     770
     771        return count;
     772}
  • vendor/current/lib/tdb/common/freelistcheck.c

    r986 r988  
    3636static int seen_insert(struct tdb_context *mem_tdb, tdb_off_t rec_ptr)
    3737{
    38         TDB_DATA key, data;
     38        TDB_DATA key;
    3939
    40         memset(&data, '\0', sizeof(data));
    4140        key.dptr = (unsigned char *)&rec_ptr;
    4241        key.dsize = sizeof(rec_ptr);
    43         return tdb_store(mem_tdb, key, data, TDB_INSERT);
     42        return tdb_store(mem_tdb, key, tdb_null, TDB_INSERT);
    4443}
    4544
     
    5352        *pnum_entries = 0;
    5453
    55         mem_tdb = tdb_open("flval", tdb->header.hash_size,
     54        mem_tdb = tdb_open("flval", tdb->hash_size,
    5655                                TDB_INTERNAL, O_RDWR, 0600);
    5756        if (!mem_tdb) {
  • vendor/current/lib/tdb/common/hash.c

    r986 r988  
    215215  if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
    216216    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
    217 #ifdef VALGRIND
    218217    const uint8_t  *k8;
    219 #endif
    220218
    221219    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
     
    231229
    232230    /*----------------------------- handle the last (probably partial) block */
    233     /*
    234      * "k[2]&0xffffff" actually reads beyond the end of the string, but
    235      * then masks off the part it's not allowed to read.  Because the
    236      * string is aligned, the masked-off tail is in the same word as the
    237      * rest of the string.  Every machine with memory protection I've seen
    238      * does it on word boundaries, so is OK with this.  But VALGRIND will
    239      * still catch it and complain.  The masking trick does make the hash
    240      * noticably faster for short strings (like English words).
    241      */
    242 #ifndef VALGRIND
    243 
    244     switch(length)
    245     {
    246     case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
    247     case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
    248     case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
    249     case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
    250     case 8 : b+=k[1]; a+=k[0]; break;
    251     case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
    252     case 6 : b+=k[1]&0xffff; a+=k[0]; break;
    253     case 5 : b+=k[1]&0xff; a+=k[0]; break;
    254     case 4 : a+=k[0]; break;
    255     case 3 : a+=k[0]&0xffffff; break;
    256     case 2 : a+=k[0]&0xffff; break;
    257     case 1 : a+=k[0]&0xff; break;
    258     case 0 : return c;              /* zero length strings require no mixing */
    259     }
    260 
    261 #else /* make valgrind happy */
    262 
    263231    k8 = (const uint8_t *)k;
    264232    switch(length)
     
    278246    case 0 : return c;
    279247    }
    280 
    281 #endif /* !valgrind */
    282 
    283248  } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
    284249    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
  • vendor/current/lib/tdb/common/io.c

    r986 r988  
    1  /* 
     1 /*
    22   Unix SMB/CIFS implementation.
    33
     
    2929#include "tdb_private.h"
    3030
     31/*
     32 * We prepend the mutex area, so fixup offsets. See mutex.c for details.
     33 * tdb->hdr_ofs is 0 or header.mutex_size.
     34 *
     35 * Note: that we only have the 4GB limit of tdb_off_t for
     36 * tdb->map_size. The file size on disk can be 4GB + tdb->hdr_ofs!
     37 */
     38
     39static bool tdb_adjust_offset(struct tdb_context *tdb, off_t *off)
     40{
     41        off_t tmp = tdb->hdr_ofs + *off;
     42
     43        if ((tmp < tdb->hdr_ofs) || (tmp < *off)) {
     44                errno = EIO;
     45                return false;
     46        }
     47
     48        *off = tmp;
     49        return true;
     50}
     51
     52static ssize_t tdb_pwrite(struct tdb_context *tdb, const void *buf,
     53                          size_t count, off_t offset)
     54{
     55        if (!tdb_adjust_offset(tdb, &offset)) {
     56                return -1;
     57        }
     58        return pwrite(tdb->fd, buf, count, offset);
     59}
     60
     61static ssize_t tdb_pread(struct tdb_context *tdb, void *buf,
     62                         size_t count, off_t offset)
     63{
     64        if (!tdb_adjust_offset(tdb, &offset)) {
     65                return -1;
     66        }
     67        return pread(tdb->fd, buf, count, offset);
     68}
     69
     70static int tdb_ftruncate(struct tdb_context *tdb, off_t length)
     71{
     72        if (!tdb_adjust_offset(tdb, &length)) {
     73                return -1;
     74        }
     75        return ftruncate(tdb->fd, length);
     76}
     77
     78static int tdb_fstat(struct tdb_context *tdb, struct stat *buf)
     79{
     80        int ret;
     81
     82        ret = fstat(tdb->fd, buf);
     83        if (ret == -1) {
     84                return -1;
     85        }
     86
     87        if (buf->st_size < tdb->hdr_ofs) {
     88                errno = EIO;
     89                return -1;
     90        }
     91        buf->st_size -= tdb->hdr_ofs;
     92
     93        return ret;
     94}
     95
    3196/* check for an out of bounds access - if it is out of bounds then
    3297   see if the database has been expanded by someone else and expand
    33    if necessary
    34    note that "len" is the minimum length needed for the db
     98   if necessary
    3599*/
    36 static int tdb_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
     100static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len,
     101                   int probe)
    37102{
    38103        struct stat st;
    39         if (len <= tdb->map_size)
     104        if (len + off < len) {
     105                if (!probe) {
     106                        /* Ensure ecode is set for log fn. */
     107                        tdb->ecode = TDB_ERR_IO;
     108                        TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob off %u len %u wrap\n",
     109                                 off, len));
     110                }
     111                return -1;
     112        }
     113
     114        if (off + len <= tdb->map_size)
    40115                return 0;
    41116        if (tdb->flags & TDB_INTERNAL) {
     
    43118                        /* Ensure ecode is set for log fn. */
    44119                        tdb->ecode = TDB_ERR_IO;
    45                         TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond internal malloc size %d\n",
    46                                  (int)len, (int)tdb->map_size));
    47                 }
    48                 return -1;
    49         }
    50 
    51         if (fstat(tdb->fd, &st) == -1) {
     120                        TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond internal malloc size %u\n",
     121                                 (int)(off + len), (int)tdb->map_size));
     122                }
     123                return -1;
     124        }
     125
     126        if (tdb_fstat(tdb, &st) == -1) {
    52127                tdb->ecode = TDB_ERR_IO;
    53128                return -1;
    54129        }
    55130
    56         /* Unmap, update size, remap */
     131        /* Beware >4G files! */
     132        if ((tdb_off_t)st.st_size != st.st_size) {
     133                /* Ensure ecode is set for log fn. */
     134                tdb->ecode = TDB_ERR_IO;
     135                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_oob len %llu too large!\n",
     136                         (long long)st.st_size));
     137                return -1;
     138        }
     139
     140        /* Unmap, update size, remap.  We do this unconditionally, to handle
     141         * the unusual case where the db is truncated.
     142         *
     143         * This can happen to a child using tdb_reopen_all(true) on a
     144         * TDB_CLEAR_IF_FIRST tdb whose parent crashes: the next
     145         * opener will truncate the database. */
    57146        if (tdb_munmap(tdb) == -1) {
    58147                tdb->ecode = TDB_ERR_IO;
     
    60149        }
    61150        tdb->map_size = st.st_size;
    62         tdb_mmap(tdb);
    63 
    64         if (st.st_size < (size_t)len) {
     151        if (tdb_mmap(tdb) != 0) {
     152                return -1;
     153        }
     154
     155        if (st.st_size < (size_t)off + len) {
    65156                if (!probe) {
    66157                        /* Ensure ecode is set for log fn. */
    67158                        tdb->ecode = TDB_ERR_IO;
    68                         TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %d beyond eof at %d\n",
    69                                  (int)len, (int)st.st_size));
    70                 }
    71                 return -1;
    72         }
    73 
     159                        TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond eof at %u\n",
     160                                 (int)(off + len), (int)st.st_size));
     161                }
     162                return -1;
     163        }
    74164        return 0;
    75165}
    76166
    77167/* write a lump of data at a specified offset */
    78 static int tdb_write(struct tdb_context *tdb, tdb_off_t off, 
     168static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
    79169                     const void *buf, tdb_len_t len)
    80170{
     
    88178        }
    89179
    90         if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0)
     180        if (tdb->methods->tdb_oob(tdb, off, len, 0) != 0)
    91181                return -1;
    92182
     
    94184                memcpy(off + (char *)tdb->map_ptr, buf, len);
    95185        } else {
    96                 ssize_t written = pwrite(tdb->fd, buf, len, off);
     186#ifdef HAVE_INCOHERENT_MMAP
     187                tdb->ecode = TDB_ERR_IO;
     188                return -1;
     189#else
     190                ssize_t written;
     191
     192                written = tdb_pwrite(tdb, buf, len, off);
     193
    97194                if ((written != (ssize_t)len) && (written != -1)) {
    98195                        /* try once more */
    99196                        tdb->ecode = TDB_ERR_IO;
    100197                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: wrote only "
    101                                  "%d of %d bytes at %d, trying once more\n",
    102                                  (int)written, len, off));
    103                         written = pwrite(tdb->fd, (const char *)buf+written,
    104                                          len-written,
    105                                          off+written);
     198                                 "%zi of %u bytes at %u, trying once more\n",
     199                                 written, len, off));
     200                        written = tdb_pwrite(tdb, (const char *)buf+written,
     201                                             len-written, off+written);
    106202                }
    107203                if (written == -1) {
    108204                        /* Ensure ecode is set for log fn. */
    109205                        tdb->ecode = TDB_ERR_IO;
    110                         TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %d "
    111                                  "len=%d (%s)\n", off, len, strerror(errno)));
     206                        TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_write failed at %u "
     207                                 "len=%u (%s)\n", off, len, strerror(errno)));
    112208                        return -1;
    113209                } else if (written != (ssize_t)len) {
    114210                        tdb->ecode = TDB_ERR_IO;
    115211                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_write: failed to "
    116                                  "write %d bytes at %d in two attempts\n",
     212                                 "write %u bytes at %u in two attempts\n",
    117213                                 len, off));
    118214                        return -1;
    119215                }
     216#endif
    120217        }
    121218        return 0;
     
    133230
    134231/* read a lump of data at a specified offset, maybe convert */
    135 static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf, 
     232static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
    136233                    tdb_len_t len, int cv)
    137234{
    138         if (tdb->methods->tdb_oob(tdb, off + len, 0) != 0) {
     235        if (tdb->methods->tdb_oob(tdb, off, len, 0) != 0) {
    139236                return -1;
    140237        }
     
    143240                memcpy(buf, off + (char *)tdb->map_ptr, len);
    144241        } else {
    145                 ssize_t ret = pread(tdb->fd, buf, len, off);
     242#ifdef HAVE_INCOHERENT_MMAP
     243                tdb->ecode = TDB_ERR_IO;
     244                return -1;
     245#else
     246                ssize_t ret;
     247
     248                ret = tdb_pread(tdb, buf, len, off);
    146249                if (ret != (ssize_t)len) {
    147250                        /* Ensure ecode is set for log fn. */
    148251                        tdb->ecode = TDB_ERR_IO;
    149                         TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %d "
    150                                  "len=%d ret=%d (%s) map_size=%d\n",
    151                                  (int)off, (int)len, (int)ret, strerror(errno),
    152                                  (int)tdb->map_size));
    153                         return -1;
    154                 }
     252                        TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_read failed at %u "
     253                                 "len=%u ret=%zi (%s) map_size=%u\n",
     254                                 off, len, ret, strerror(errno),
     255                                 tdb->map_size));
     256                        return -1;
     257                }
     258#endif
    155259        }
    156260        if (cv) {
     
    165269  do an unlocked scan of the hash table heads to find the next non-zero head. The value
    166270  will then be confirmed with the lock held
    167 */             
     271*/
    168272static void tdb_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
    169273{
    170274        uint32_t h = *chain;
    171275        if (tdb->map_ptr) {
    172                 for (;h < tdb->header.hash_size;h++) {
     276                for (;h < tdb->hash_size;h++) {
    173277                        if (0 != *(uint32_t *)(TDB_HASH_TOP(h) + (unsigned char *)tdb->map_ptr)) {
    174278                                break;
     
    177281        } else {
    178282                uint32_t off=0;
    179                 for (;h < tdb->header.hash_size;h++) {
     283                for (;h < tdb->hash_size;h++) {
    180284                        if (tdb_ofs_read(tdb, TDB_HASH_TOP(h), &off) != 0 || off != 0) {
    181285                                break;
     
    205309}
    206310
    207 void tdb_mmap(struct tdb_context *tdb)
     311/* If mmap isn't coherent, *everyone* must always mmap. */
     312static bool should_mmap(const struct tdb_context *tdb)
     313{
     314#ifdef HAVE_INCOHERENT_MMAP
     315        return true;
     316#else
     317        return !(tdb->flags & TDB_NOMMAP);
     318#endif
     319}
     320
     321int tdb_mmap(struct tdb_context *tdb)
    208322{
    209323        if (tdb->flags & TDB_INTERNAL)
    210                 return;
     324                return 0;
    211325
    212326#ifdef HAVE_MMAP
    213         if (!(tdb->flags & TDB_NOMMAP)) {
    214                 tdb->map_ptr = mmap(NULL, tdb->map_size,
    215                                     PROT_READ|(tdb->read_only? 0:PROT_WRITE),
    216                                     MAP_SHARED|MAP_FILE, tdb->fd, 0);
     327        if (should_mmap(tdb)) {
     328                tdb->map_ptr = mmap(NULL, tdb->map_size,
     329                                    PROT_READ|(tdb->read_only? 0:PROT_WRITE),
     330                                    MAP_SHARED|MAP_FILE, tdb->fd,
     331                                    tdb->hdr_ofs);
    217332
    218333                /*
     
    222337                if (tdb->map_ptr == MAP_FAILED) {
    223338                        tdb->map_ptr = NULL;
    224                         TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n",
     339                        TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %u (%s)\n",
    225340                                 tdb->map_size, strerror(errno)));
     341#ifdef HAVE_INCOHERENT_MMAP
     342                        tdb->ecode = TDB_ERR_IO;
     343                        return -1;
     344#endif
    226345                }
    227346        } else {
     
    231350        tdb->map_ptr = NULL;
    232351#endif
     352        return 0;
    233353}
    234354
     
    238358{
    239359        char buf[8192];
     360        tdb_off_t new_size;
    240361
    241362        if (tdb->read_only || tdb->traverse_read) {
     
    244365        }
    245366
    246         if (ftruncate(tdb->fd, size+addition) == -1) {
     367        if (!tdb_add_off_t(size, addition, &new_size)) {
     368                tdb->ecode = TDB_ERR_OOM;
     369                TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
     370                        "overflow detected current size[%u] addition[%u]!\n",
     371                        (unsigned)size, (unsigned)addition));
     372                errno = ENOSPC;
     373                return -1;
     374        }
     375
     376        if (tdb_ftruncate(tdb, new_size) == -1) {
    247377                char b = 0;
    248                 ssize_t written = pwrite(tdb->fd,  &b, 1, (size+addition) - 1);
     378                ssize_t written = tdb_pwrite(tdb, &b, 1, new_size - 1);
    249379                if (written == 0) {
    250380                        /* try once more, potentially revealing errno */
    251                         written = pwrite(tdb->fd,  &b, 1, (size+addition) - 1);
     381                        written = tdb_pwrite(tdb, &b, 1, new_size - 1);
    252382                }
    253383                if (written == 0) {
     
    256386                }
    257387                if (written != 1) {
    258                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n",
    259                                  size+addition, strerror(errno)));
     388                        tdb->ecode = TDB_ERR_OOM;
     389                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %u failed (%s)\n",
     390                                 (unsigned)new_size, strerror(errno)));
    260391                        return -1;
    261392                }
     
    268399        while (addition) {
    269400                size_t n = addition>sizeof(buf)?sizeof(buf):addition;
    270                 ssize_t written = pwrite(tdb->fd, buf, n, size);
     401                ssize_t written = tdb_pwrite(tdb, buf, n, size);
    271402                if (written == 0) {
    272403                        /* prevent infinite loops: try _once_ more */
    273                         written = pwrite(tdb->fd, buf, n, size);
     404                        written = tdb_pwrite(tdb, buf, n, size);
    274405                }
    275406                if (written == 0) {
    276407                        /* give up, trying to provide a useful errno */
     408                        tdb->ecode = TDB_ERR_OOM;
    277409                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
    278410                                "returned 0 twice: giving up!\n"));
    279411                        errno = ENOSPC;
    280412                        return -1;
    281                 } else if (written == -1) {
     413                }
     414                if (written == -1) {
     415                        tdb->ecode = TDB_ERR_OOM;
    282416                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
    283                                  "%d bytes failed (%s)\n", (int)n,
     417                                 "%u bytes failed (%s)\n", (int)n,
    284418                                 strerror(errno)));
    285419                        return -1;
    286                 } else if (written != n) {
     420                }
     421                if (written != n) {
    287422                        TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
    288                                  "only %d of %d bytes - retrying\n", (int)written,
    289                                  (int)n));
     423                                 "only %zu of %zi bytes - retrying\n", written,
     424                                 n));
    290425                }
    291426                addition -= written;
     
    295430}
    296431
     432
     433/* You need 'size', this tells you how much you should expand by. */
     434tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size)
     435{
     436        tdb_off_t new_size, top_size, increment;
     437        tdb_off_t max_size = UINT32_MAX - map_size;
     438
     439        if (size > max_size) {
     440                /*
     441                 * We can't round up anymore, just give back
     442                 * what we're asked for.
     443                 *
     444                 * The caller has to take care of the ENOSPC handling.
     445                 */
     446                return size;
     447        }
     448
     449        /* limit size in order to avoid using up huge amounts of memory for
     450         * in memory tdbs if an oddball huge record creeps in */
     451        if (size > 100 * 1024) {
     452                increment = size * 2;
     453        } else {
     454                increment = size * 100;
     455        }
     456        if (increment < size) {
     457                goto overflow;
     458        }
     459
     460        if (!tdb_add_off_t(map_size, increment, &top_size)) {
     461                goto overflow;
     462        }
     463
     464        /* always make room for at least top_size more records, and at
     465           least 25% more space. if the DB is smaller than 100MiB,
     466           otherwise grow it by 10% only. */
     467        if (map_size > 100 * 1024 * 1024) {
     468                new_size = map_size * 1.10;
     469        } else {
     470                new_size = map_size * 1.25;
     471        }
     472        if (new_size < map_size) {
     473                goto overflow;
     474        }
     475
     476        /* Round the database up to a multiple of the page size */
     477        new_size = MAX(top_size, new_size);
     478
     479        if (new_size + page_size < new_size) {
     480                /* There's a "+" in TDB_ALIGN that might overflow... */
     481                goto overflow;
     482        }
     483
     484        return TDB_ALIGN(new_size, page_size) - map_size;
     485
     486overflow:
     487        /*
     488         * Somewhere in between we went over 4GB. Make one big jump to
     489         * exactly 4GB database size.
     490         */
     491        return max_size;
     492}
    297493
    298494/* expand the database at least size bytes by expanding the underlying
     
    301497{
    302498        struct tdb_record rec;
    303         tdb_off_t offset, new_size, top_size, map_size;
     499        tdb_off_t offset;
     500        tdb_off_t new_size;
    304501
    305502        if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
     
    309506
    310507        /* must know about any previous expansions by another process */
    311         tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
    312 
    313         /* limit size in order to avoid using up huge amounts of memory for
    314          * in memory tdbs if an oddball huge record creeps in */
    315         if (size > 100 * 1024) {
    316                 top_size = tdb->map_size + size * 2;
    317         } else {
    318                 top_size = tdb->map_size + size * 100;
    319         }
    320 
    321         /* always make room for at least top_size more records, and at
    322            least 25% more space. if the DB is smaller than 100MiB,
    323            otherwise grow it by 10% only. */
    324         if (tdb->map_size > 100 * 1024 * 1024) {
    325                 map_size = tdb->map_size * 1.10;
    326         } else {
    327                 map_size = tdb->map_size * 1.25;
    328         }
    329 
    330         /* Round the database up to a multiple of the page size */
    331         new_size = MAX(top_size, map_size);
    332         size = TDB_ALIGN(new_size, tdb->page_size) - tdb->map_size;
    333 
    334         if (!(tdb->flags & TDB_INTERNAL))
    335                 tdb_munmap(tdb);
     508        tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1);
    336509
    337510        /*
    338          * We must ensure the file is unmapped before doing this
    339          * to ensure consistency with systems like OpenBSD where
    340          * writes and mmaps are not consistent.
     511         * Note: that we don't care about tdb->hdr_ofs != 0 here
     512         *
     513         * The 4GB limitation is just related to tdb->map_size
     514         * and the offset calculation in the records.
     515         *
     516         * The file on disk can be up to 4GB + tdb->hdr_ofs
    341517         */
    342 
    343         /* expand the file itself */
    344         if (!(tdb->flags & TDB_INTERNAL)) {
    345                 if (tdb->methods->tdb_expand_file(tdb, tdb->map_size, size) != 0)
    346                         goto fail;
    347         }
    348 
    349         tdb->map_size += size;
    350 
    351         if (tdb->flags & TDB_INTERNAL) {
    352                 char *new_map_ptr = (char *)realloc(tdb->map_ptr,
    353                                                     tdb->map_size);
    354                 if (!new_map_ptr) {
    355                         tdb->map_size -= size;
    356                         goto fail;
    357                 }
    358                 tdb->map_ptr = new_map_ptr;
    359         } else {
    360                 /*
    361                  * We must ensure the file is remapped before adding the space
    362                  * to ensure consistency with systems like OpenBSD where
    363                  * writes and mmaps are not consistent.
    364                  */
    365 
    366                 /* We're ok if the mmap fails as we'll fallback to read/write */
    367                 tdb_mmap(tdb);
     518        size = tdb_expand_adjust(tdb->map_size, size, tdb->page_size);
     519
     520        if (!tdb_add_off_t(tdb->map_size, size, &new_size)) {
     521                tdb->ecode = TDB_ERR_OOM;
     522                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_expand "
     523                        "overflow detected current map_size[%u] size[%u]!\n",
     524                        (unsigned)tdb->map_size, (unsigned)size));
     525                goto fail;
    368526        }
    369527
    370528        /* form a new freelist record */
     529        offset = tdb->map_size;
    371530        memset(&rec,'\0',sizeof(rec));
    372531        rec.rec_len = size - sizeof(rec);
    373532
     533        if (tdb->flags & TDB_INTERNAL) {
     534                char *new_map_ptr;
     535
     536                new_map_ptr = (char *)realloc(tdb->map_ptr, new_size);
     537                if (!new_map_ptr) {
     538                        tdb->ecode = TDB_ERR_OOM;
     539                        goto fail;
     540                }
     541                tdb->map_ptr = new_map_ptr;
     542                tdb->map_size = new_size;
     543        } else {
     544                int ret;
     545
     546                /*
     547                 * expand the file itself
     548                 */
     549                ret = tdb->methods->tdb_expand_file(tdb, tdb->map_size, size);
     550                if (ret != 0) {
     551                        goto fail;
     552                }
     553
     554                /* Explicitly remap: if we're in a transaction, this won't
     555                 * happen automatically! */
     556                tdb_munmap(tdb);
     557                tdb->map_size = new_size;
     558                if (tdb_mmap(tdb) != 0) {
     559                        goto fail;
     560                }
     561        }
     562
    374563        /* link it into the free list */
    375         offset = tdb->map_size - size;
    376564        if (tdb_free(tdb, offset, &rec) == -1)
    377565                goto fail;
     
    407595                /* Ensure ecode is set for log fn. */
    408596                tdb->ecode = TDB_ERR_OOM;
    409                 TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%d (%s)\n",
     597                TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_alloc_read malloc failed len=%u (%s)\n",
    410598                           len, strerror(errno)));
    411599                return NULL;
     
    436624                 * parser directly at the mmap area.
    437625                 */
    438                 if (tdb->methods->tdb_oob(tdb, offset+len, 0) != 0) {
     626                if (tdb->methods->tdb_oob(tdb, offset, len, 0) != 0) {
    439627                        return -1;
    440628                }
     
    460648                /* Ensure ecode is set for log fn. */
    461649                tdb->ecode = TDB_ERR_CORRUPT;
    462                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%d\n", rec->magic, offset));
    463                 return -1;
    464         }
    465         return tdb->methods->tdb_oob(tdb, rec->next+sizeof(*rec), 0);
     650                TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_rec_read bad magic 0x%x at offset=%u\n", rec->magic, offset));
     651                return -1;
     652        }
     653        return tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 0);
    466654}
    467655
  • vendor/current/lib/tdb/common/lock.c

    r986 r988  
    1  /* 
     1 /*
    22   Unix SMB/CIFS implementation.
    33
     
    3737{
    3838        struct flock fl;
     39        int cmd;
     40
     41#ifdef USE_TDB_MUTEX_LOCKING
     42        {
     43                int ret;
     44                if (tdb_mutex_lock(tdb, rw, off, len, waitflag, &ret)) {
     45                        return ret;
     46                }
     47        }
     48#endif
    3949
    4050        fl.l_type = rw;
     
    4454        fl.l_pid = 0;
    4555
    46         if (waitflag)
    47                 return fcntl(tdb->fd, F_SETLKW, &fl);
    48         else
    49                 return fcntl(tdb->fd, F_SETLK, &fl);
     56        cmd = waitflag ? F_SETLKW : F_SETLK;
     57
     58        return fcntl(tdb->fd, cmd, &fl);
    5059}
    5160
     
    111120#endif
    112121
     122#ifdef USE_TDB_MUTEX_LOCKING
     123        {
     124                int ret;
     125                if (tdb_mutex_unlock(tdb, rw, off, len, &ret)) {
     126                        return ret;
     127                }
     128        }
     129#endif
     130
    113131        fl.l_type = F_UNLCK;
    114132        fl.l_whence = SEEK_SET;
     
    127145
    128146/* a byte range locking function - return 0 on success
    129    this functions locks/unlocks 1 byte at the specified offset.
     147   this functions locks/unlocks "len" byte at the specified offset.
    130148
    131149   On error, errno is also set so that errors are passed back properly
    132    through tdb_open(). 
     150   through tdb_open().
    133151
    134152   note that a len of zero means lock to end of file
     
    170188                 * locks. */
    171189                if (!(flags & TDB_LOCK_PROBE) && errno != EAGAIN) {
    172                         TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d flags=%d len=%d\n",
    173                                  tdb->fd, offset, rw_type, flags, (int)len));
     190                        TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brlock failed (fd=%d) at offset %u rw_type=%d flags=%d len=%zu\n",
     191                                 tdb->fd, offset, rw_type, flags, len));
    174192                }
    175193                return -1;
     
    192210
    193211        if (ret == -1) {
    194                 TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brunlock failed (fd=%d) at offset %d rw_type=%d len=%d\n",
    195                          tdb->fd, offset, rw_type, (int)len));
     212                TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_brunlock failed (fd=%d) at offset %u rw_type=%u len=%zu\n",
     213                         tdb->fd, offset, rw_type, len));
    196214        }
    197215        return ret;
     
    199217
    200218/*
    201   upgrade a read lock to a write lock. This needs to be handled in a
    202   special way as some OSes (such as solaris) have too conservative
    203   deadlock detection and claim a deadlock when progress can be
    204   made. For those OSes we may loop for a while. 
     219 * Do a tdb_brlock in a loop. Some OSes (such as solaris) have too
     220 * conservative deadlock detection and claim a deadlock when progress can be
     221 * made. For those OSes we may loop for a while.
     222 */
     223
     224static int tdb_brlock_retry(struct tdb_context *tdb,
     225                            int rw_type, tdb_off_t offset, size_t len,
     226                            enum tdb_lock_flags flags)
     227{
     228        int count = 1000;
     229
     230        while (count--) {
     231                struct timeval tv;
     232                int ret;
     233
     234                ret = tdb_brlock(tdb, rw_type, offset, len, flags);
     235                if (ret == 0) {
     236                        return 0;
     237                }
     238                if (errno != EDEADLK) {
     239                        break;
     240                }
     241                /* sleep for as short a time as we can - more portable than usleep() */
     242                tv.tv_sec = 0;
     243                tv.tv_usec = 1;
     244                select(0, NULL, NULL, NULL, &tv);
     245        }
     246        return -1;
     247}
     248
     249/*
     250  upgrade a read lock to a write lock.
    205251*/
    206252int tdb_allrecord_upgrade(struct tdb_context *tdb)
    207253{
    208         int count = 1000;
     254        int ret;
    209255
    210256        if (tdb->allrecord_lock.count != 1) {
     
    221267        }
    222268
    223         while (count--) {
    224                 struct timeval tv;
    225                 if (tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
    226                                TDB_LOCK_WAIT|TDB_LOCK_PROBE) == 0) {
    227                         tdb->allrecord_lock.ltype = F_WRLCK;
    228                         tdb->allrecord_lock.off = 0;
    229                         return 0;
    230                 }
    231                 if (errno != EDEADLK) {
    232                         break;
    233                 }
    234                 /* sleep for as short a time as we can - more portable than usleep() */
    235                 tv.tv_sec = 0;
    236                 tv.tv_usec = 1;
    237                 select(0, NULL, NULL, NULL, &tv);
    238         }
     269        if (tdb_have_mutexes(tdb)) {
     270                ret = tdb_mutex_allrecord_upgrade(tdb);
     271                if (ret == -1) {
     272                        goto fail;
     273                }
     274                ret = tdb_brlock_retry(tdb, F_WRLCK, lock_offset(tdb->hash_size),
     275                                       0, TDB_LOCK_WAIT|TDB_LOCK_PROBE);
     276                if (ret == -1) {
     277                        tdb_mutex_allrecord_downgrade(tdb);
     278                }
     279        } else {
     280                ret = tdb_brlock_retry(tdb, F_WRLCK, FREELIST_TOP, 0,
     281                                       TDB_LOCK_WAIT|TDB_LOCK_PROBE);
     282        }
     283
     284        if (ret == 0) {
     285                tdb->allrecord_lock.ltype = F_WRLCK;
     286                tdb->allrecord_lock.off = 0;
     287                return 0;
     288        }
     289fail:
    239290        TDB_LOG((tdb, TDB_DEBUG_TRACE,"tdb_allrecord_upgrade failed\n"));
    240291        return -1;
     
    260311        struct tdb_lock_type *new_lck;
    261312
    262         if (offset >= lock_offset(tdb->header.hash_size)) {
     313        if (offset >= lock_offset(tdb->hash_size)) {
    263314                tdb->ecode = TDB_ERR_LOCK;
    264315                TDB_LOG((tdb, TDB_DEBUG_ERROR,"tdb_lock: invalid offset %u for ltype=%d\n",
     
    279330        }
    280331
    281         new_lck = (struct tdb_lock_type *)realloc(
    282                 tdb->lockrecs,
    283                 sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1));
    284         if (new_lck == NULL) {
    285                 errno = ENOMEM;
    286                 return -1;
    287         }
    288         tdb->lockrecs = new_lck;
     332        if (tdb->num_lockrecs == tdb->lockrecs_array_length) {
     333                new_lck = (struct tdb_lock_type *)realloc(
     334                        tdb->lockrecs,
     335                        sizeof(*tdb->lockrecs) * (tdb->num_lockrecs+1));
     336                if (new_lck == NULL) {
     337                        errno = ENOMEM;
     338                        return -1;
     339                }
     340                tdb->lockrecs_array_length = tdb->num_lockrecs+1;
     341                tdb->lockrecs = new_lck;
     342        }
    289343
    290344        /* Since fcntl locks don't nest, we do a lock for the first one,
     
    294348        }
    295349
    296         tdb->lockrecs[tdb->num_lockrecs].off = offset;
    297         tdb->lockrecs[tdb->num_lockrecs].count = 1;
    298         tdb->lockrecs[tdb->num_lockrecs].ltype = ltype;
     350        new_lck = &tdb->lockrecs[tdb->num_lockrecs];
     351
     352        new_lck->off = offset;
     353        new_lck->count = 1;
     354        new_lck->ltype = ltype;
    299355        tdb->num_lockrecs++;
    300356
     
    335391}
    336392
     393/*
     394 * A allrecord lock allows us to avoid per chain locks. Check if the allrecord
     395 * lock is strong enough.
     396 */
     397static int tdb_lock_covered_by_allrecord_lock(struct tdb_context *tdb,
     398                                              int ltype)
     399{
     400        if (ltype == F_RDLCK) {
     401                /*
     402                 * The allrecord_lock is equal (F_RDLCK) or stronger
     403                 * (F_WRLCK). Pass.
     404                 */
     405                return 0;
     406        }
     407
     408        if (tdb->allrecord_lock.ltype == F_RDLCK) {
     409                /*
     410                 * We ask for ltype==F_WRLCK, but the allrecord_lock
     411                 * is too weak. We can't upgrade here, so fail.
     412                 */
     413                tdb->ecode = TDB_ERR_LOCK;
     414                return -1;
     415        }
     416
     417        /*
     418         * Asking for F_WRLCK, allrecord is F_WRLCK as well. Pass.
     419         */
     420        return 0;
     421}
     422
    337423static int tdb_lock_list(struct tdb_context *tdb, int list, int ltype,
    338424                         enum tdb_lock_flags waitflag)
     
    341427        bool check = false;
    342428
    343         /* a allrecord lock allows us to avoid per chain locks */
    344         if (tdb->allrecord_lock.count &&
    345             (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) {
    346                 return 0;
    347         }
    348 
    349429        if (tdb->allrecord_lock.count) {
    350                 tdb->ecode = TDB_ERR_LOCK;
    351                 ret = -1;
    352         } else {
    353                 /* Only check when we grab first data lock. */
    354                 check = !have_data_locks(tdb);
    355                 ret = tdb_nest_lock(tdb, lock_offset(list), ltype, waitflag);
    356 
    357                 if (ret == 0 && check && tdb_needs_recovery(tdb)) {
    358                         tdb_nest_unlock(tdb, lock_offset(list), ltype, false);
    359 
    360                         if (tdb_lock_and_recover(tdb) == -1) {
    361                                 return -1;
    362                         }
    363                         return tdb_lock_list(tdb, list, ltype, waitflag);
    364                 }
     430                return tdb_lock_covered_by_allrecord_lock(tdb, ltype);
     431        }
     432
     433        /*
     434         * Check for recoveries: Someone might have kill -9'ed a process
     435         * during a commit.
     436         */
     437        check = !have_data_locks(tdb);
     438        ret = tdb_nest_lock(tdb, lock_offset(list), ltype, waitflag);
     439
     440        if (ret == 0 && check && tdb_needs_recovery(tdb)) {
     441                tdb_nest_unlock(tdb, lock_offset(list), ltype, false);
     442
     443                if (tdb_lock_and_recover(tdb) == -1) {
     444                        return -1;
     445                }
     446                return tdb_lock_list(tdb, list, ltype, waitflag);
    365447        }
    366448        return ret;
     
    381463
    382464/* lock a list in the database. list -1 is the alloc list. non-blocking lock */
    383 int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype)
     465_PUBLIC_ int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype)
    384466{
    385467        return tdb_lock_list(tdb, list, ltype, TDB_LOCK_NOWAIT);
     
    397479
    398480        /* Sanity checks */
    399         if (offset >= lock_offset(tdb->header.hash_size)) {
    400                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: offset %u invalid (%d)\n", offset, tdb->header.hash_size));
     481        if (offset >= lock_offset(tdb->hash_size)) {
     482                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: offset %u invalid (%d)\n", offset, tdb->hash_size));
    401483                return ret;
    402484        }
     
    437519         */
    438520
    439         if (tdb->num_lockrecs == 0) {
    440                 SAFE_FREE(tdb->lockrecs);
    441         }
    442 
    443521        if (ret)
    444                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n")); 
    445         return ret;
    446 }
    447 
    448 int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
     522                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlock: An error occurred unlocking!\n"));
     523        return ret;
     524}
     525
     526_PUBLIC_ int tdb_unlock(struct tdb_context *tdb, int list, int ltype)
    449527{
    450528        /* a global lock allows us to avoid per chain locks */
    451         if (tdb->allrecord_lock.count &&
    452             (ltype == tdb->allrecord_lock.ltype || ltype == F_RDLCK)) {
    453                 return 0;
    454         }
    455 
    456529        if (tdb->allrecord_lock.count) {
    457                 tdb->ecode = TDB_ERR_LOCK;
    458                 return -1;
     530                return tdb_lock_covered_by_allrecord_lock(tdb, ltype);
    459531        }
    460532
     
    554626                       enum tdb_lock_flags flags, bool upgradable)
    555627{
     628        int ret;
     629
    556630        switch (tdb_allrecord_check(tdb, ltype, flags, upgradable)) {
    557631        case -1:
     
    563637        /* We cover two kinds of locks:
    564638         * 1) Normal chain locks.  Taken for almost all operations.
    565          * 3) Individual records locks.  Taken after normal or free
     639         * 2) Individual records locks.  Taken after normal or free
    566640         *    chain locks.
    567641         *
    568642         * It is (1) which cause the starvation problem, so we're only
    569643         * gradual for that. */
    570         if (tdb_chainlock_gradual(tdb, ltype, flags, FREELIST_TOP,
    571                                   tdb->header.hash_size * 4) == -1) {
     644
     645        if (tdb_have_mutexes(tdb)) {
     646                ret = tdb_mutex_allrecord_lock(tdb, ltype, flags);
     647        } else {
     648                ret = tdb_chainlock_gradual(tdb, ltype, flags, FREELIST_TOP,
     649                                            tdb->hash_size * 4);
     650        }
     651
     652        if (ret == -1) {
    572653                return -1;
    573654        }
    574655
    575656        /* Grab individual record locks. */
    576         if (tdb_brlock(tdb, ltype, lock_offset(tdb->header.hash_size), 0,
     657        if (tdb_brlock(tdb, ltype, lock_offset(tdb->hash_size), 0,
    577658                       flags) == -1) {
    578                 tdb_brunlock(tdb, ltype, FREELIST_TOP,
    579                              tdb->header.hash_size * 4);
     659                if (tdb_have_mutexes(tdb)) {
     660                        tdb_mutex_allrecord_unlock(tdb);
     661                } else {
     662                        tdb_brunlock(tdb, ltype, FREELIST_TOP,
     663                                     tdb->hash_size * 4);
     664                }
    580665                return -1;
    581666        }
     
    633718        }
    634719
    635         if (!mark_lock && tdb_brunlock(tdb, ltype, FREELIST_TOP, 0)) {
    636                 TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed (%s)\n", strerror(errno)));
    637                 return -1;
     720        if (!mark_lock) {
     721                int ret;
     722
     723                if (tdb_have_mutexes(tdb)) {
     724                        ret = tdb_mutex_allrecord_unlock(tdb);
     725                        if (ret == 0) {
     726                                ret = tdb_brunlock(tdb, ltype,
     727                                                   lock_offset(tdb->hash_size),
     728                                                   0);
     729                        }
     730                } else {
     731                        ret = tdb_brunlock(tdb, ltype, FREELIST_TOP, 0);
     732                }
     733
     734                if (ret != 0) {
     735                        TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_unlockall failed "
     736                                 "(%s)\n", strerror(errno)));
     737                        return -1;
     738                }
    638739        }
    639740
     
    756857        tdb_trace_1rec(tdb, "tdb_chainunlock_read", key);
    757858        return tdb_unlock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
     859}
     860
     861_PUBLIC_ int tdb_chainlock_read_nonblock(struct tdb_context *tdb, TDB_DATA key)
     862{
     863        int ret = tdb_lock_nonblock(tdb, BUCKET(tdb->hash_fn(&key)), F_RDLCK);
     864        tdb_trace_1rec_ret(tdb, "tdb_chainlock_read_nonblock", key, ret);
     865        return ret;
    758866}
    759867
     
    841949
    842950        if (tdb->allrecord_lock.count != 0) {
    843                 tdb_brunlock(tdb, tdb->allrecord_lock.ltype, FREELIST_TOP, 0);
     951                tdb_allrecord_unlock(tdb, tdb->allrecord_lock.ltype, false);
    844952                tdb->allrecord_lock.count = 0;
    845953        }
     
    856964        }
    857965        tdb->num_lockrecs = active;
    858         if (tdb->num_lockrecs == 0) {
    859                 SAFE_FREE(tdb->lockrecs);
    860         }
    861 }
     966}
     967
     968/* Following functions are added specifically to support CTDB. */
     969
     970/* Don't do actual fcntl locking, just mark tdb locked */
     971int tdb_transaction_write_lock_mark(struct tdb_context *tdb);
     972_PUBLIC_ int tdb_transaction_write_lock_mark(struct tdb_context *tdb)
     973{
     974        return tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_MARK_ONLY);
     975}
     976
     977/* Don't do actual fcntl unlocking, just mark tdb unlocked */
     978int tdb_transaction_write_lock_unmark(struct tdb_context *tdb);
     979_PUBLIC_ int tdb_transaction_write_lock_unmark(struct tdb_context *tdb)
     980{
     981        return tdb_nest_unlock(tdb, TRANSACTION_LOCK, F_WRLCK, true);
     982}
  • vendor/current/lib/tdb/common/open.c

    r914 r988  
    1  /* 
     1 /*
    22   Unix SMB/CIFS implementation.
    33
     
    5252
    5353/* initialise a new database with a specified hash size */
    54 static int tdb_new_database(struct tdb_context *tdb, int hash_size)
     54static int tdb_new_database(struct tdb_context *tdb, struct tdb_header *header,
     55                            int hash_size)
    5556{
    5657        struct tdb_header *newdb;
     
    7677                newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC;
    7778
     79        /*
     80         * We create a tdb with TDB_FEATURE_FLAG_MUTEX support,
     81         * the flag combination and runtime feature checks
     82         * are done by the caller already.
     83         */
     84        if (tdb->flags & TDB_MUTEX_LOCKING) {
     85                newdb->feature_flags |= TDB_FEATURE_FLAG_MUTEX;
     86        }
     87
     88        /*
     89         * If we have any features we add the FEATURE_FLAG_MAGIC, overwriting the
     90         * TDB_HASH_RWLOCK_MAGIC above.
     91         */
     92        if (newdb->feature_flags != 0) {
     93                newdb->rwlocks = TDB_FEATURE_FLAG_MAGIC;
     94        }
     95
     96        /*
     97         * It's required for some following code pathes
     98         * to have the fields on 'tdb' up-to-date.
     99         *
     100         * E.g. tdb_mutex_size() requires it
     101         */
     102        tdb->feature_flags = newdb->feature_flags;
     103        tdb->hash_size = newdb->hash_size;
     104
    78105        if (tdb->flags & TDB_INTERNAL) {
    79106                tdb->map_size = size;
    80107                tdb->map_ptr = (char *)newdb;
    81                 memcpy(&tdb->header, newdb, sizeof(tdb->header));
     108                memcpy(header, newdb, sizeof(*header));
    82109                /* Convert the `ondisk' version if asked. */
    83110                CONVERT(*newdb);
     
    90117                goto fail;
    91118
     119        if (newdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) {
     120                newdb->mutex_size = tdb_mutex_size(tdb);
     121                tdb->hdr_ofs = newdb->mutex_size;
     122        }
     123
    92124        /* This creates an endian-converted header, as if read from disk */
    93125        CONVERT(*newdb);
    94         memcpy(&tdb->header, newdb, sizeof(tdb->header));
     126        memcpy(header, newdb, sizeof(*header));
    95127        /* Don't endian-convert the magic food! */
    96128        memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
    97         /* we still have "ret == -1" here */
    98         if (tdb_write_all(tdb->fd, newdb, size))
    99                 ret = 0;
    100 
     129
     130        if (!tdb_write_all(tdb->fd, newdb, size))
     131                goto fail;
     132
     133        if (newdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) {
     134
     135                /*
     136                 * Now we init the mutex area
     137                 * followed by a second header.
     138                 */
     139
     140                ret = ftruncate(
     141                        tdb->fd,
     142                        newdb->mutex_size + sizeof(struct tdb_header));
     143                if (ret == -1) {
     144                        goto fail;
     145                }
     146                ret = tdb_mutex_init(tdb);
     147                if (ret == -1) {
     148                        goto fail;
     149                }
     150
     151                /*
     152                 * Write a second header behind the mutexes. That's the area
     153                 * that will be mmapp'ed.
     154                 */
     155                ret = lseek(tdb->fd, newdb->mutex_size, SEEK_SET);
     156                if (ret == -1) {
     157                        goto fail;
     158                }
     159                if (!tdb_write_all(tdb->fd, newdb, size)) {
     160                        goto fail;
     161                }
     162        }
     163
     164        ret = 0;
    101165  fail:
    102166        SAFE_FREE(newdb);
     
    120184}
    121185
    122 /* open the database, creating it if necessary 
     186/* open the database, creating it if necessary
    123187
    124188   The open_flags and mode are passed straight to the open call on the
     
    126190   is advisory, use zero for a default value.
    127191
    128    Return is NULL on error, in which case errno is also set.  Don't 
     192   Return is NULL on error, in which case errno is also set.  Don't
    129193   try to call tdb_error or tdb_errname, just do strerror(errno).
    130194
     
    143207
    144208static bool check_header_hash(struct tdb_context *tdb,
     209                              struct tdb_header *header,
    145210                              bool default_hash, uint32_t *m1, uint32_t *m2)
    146211{
    147212        tdb_header_hash(tdb, m1, m2);
    148         if (tdb->header.magic1_hash == *m1 &&
    149             tdb->header.magic2_hash == *m2) {
     213        if (header->magic1_hash == *m1 &&
     214            header->magic2_hash == *m2) {
    150215                return true;
    151216        }
     
    160225        else
    161226                tdb->hash_fn = tdb_old_hash;
    162         return check_header_hash(tdb, false, m1, m2);
     227        return check_header_hash(tdb, header, false, m1, m2);
     228}
     229
     230static bool tdb_mutex_open_ok(struct tdb_context *tdb,
     231                              const struct tdb_header *header)
     232{
     233        int locked;
     234
     235        if (tdb->flags & TDB_NOLOCK) {
     236                /*
     237                 * We don't look at locks, so it does not matter to have a
     238                 * compatible mutex implementation. Allow the open.
     239                 */
     240                return true;
     241        }
     242
     243        locked = tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK,
     244                               TDB_LOCK_NOWAIT|TDB_LOCK_PROBE);
     245
     246        if ((locked == -1) && (tdb->ecode == TDB_ERR_LOCK)) {
     247                /*
     248                 * CLEAR_IF_FIRST still active. The tdb was created on this
     249                 * host, so we can assume the mutex implementation is
     250                 * compatible. Important for tools like tdbdump on a still
     251                 * open locking.tdb.
     252                 */
     253                goto check_local_settings;
     254        }
     255
     256        /*
     257         * We got the CLEAR_IF_FIRST lock. That means the database was
     258         * potentially copied from somewhere else. The mutex implementation
     259         * might be incompatible.
     260         */
     261
     262        if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) {
     263                /*
     264                 * Should not happen
     265                 */
     266                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_mutex_open_ok: "
     267                         "failed to release ACTIVE_LOCK on %s: %s\n",
     268                         tdb->name, strerror(errno)));
     269                return false;
     270        }
     271
     272check_local_settings:
     273
     274        if (!(tdb->flags & TDB_MUTEX_LOCKING)) {
     275                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_mutex_open_ok[%s]: "
     276                         "Can use mutexes only with "
     277                         "MUTEX_LOCKING or NOLOCK\n",
     278                         tdb->name));
     279                return false;
     280        }
     281
     282        if (tdb_mutex_size(tdb) != header->mutex_size) {
     283                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_mutex_open_ok[%s]: "
     284                         "Mutex size changed from %u to %u\n.",
     285                         tdb->name,
     286                         (unsigned int)header->mutex_size,
     287                         (unsigned int)tdb_mutex_size(tdb)));
     288                return false;
     289        }
     290
     291        return true;
    163292}
    164293
     
    168297                                tdb_hash_func hash_fn)
    169298{
     299        int orig_errno = errno;
     300        struct tdb_header header;
    170301        struct tdb_context *tdb;
    171302        struct stat st;
     
    176307        const char *hash_alg;
    177308        uint32_t magic1, magic2;
     309        int ret;
     310
     311        ZERO_STRUCT(header);
    178312
    179313        if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
     
    183317        }
    184318        tdb_io_init(tdb);
     319
     320        if (tdb_flags & TDB_INTERNAL) {
     321                tdb_flags |= TDB_INCOMPATIBLE_HASH;
     322        }
     323        if (tdb_flags & TDB_MUTEX_LOCKING) {
     324                tdb_flags |= TDB_INCOMPATIBLE_HASH;
     325        }
     326
    185327        tdb->fd = -1;
    186328#ifdef TDB_TRACE
     
    210352        }
    211353
    212         /* now make a copy of the name, as the caller memory might went away */
     354        /* now make a copy of the name, as the caller memory might go away */
    213355        if (!(tdb->name = (char *)strdup(name))) {
    214356                /*
     
    258400                /* read only databases don't do locking or clear if first */
    259401                tdb->flags |= TDB_NOLOCK;
    260                 tdb->flags &= ~TDB_CLEAR_IF_FIRST;
     402                tdb->flags &= ~(TDB_CLEAR_IF_FIRST|TDB_MUTEX_LOCKING);
    261403        }
    262404
     
    270412        }
    271413
     414        if (tdb->flags & TDB_MUTEX_LOCKING) {
     415                /*
     416                 * Here we catch bugs in the callers,
     417                 * the runtime check for existing tdb's comes later.
     418                 */
     419
     420                if (!(tdb->flags & TDB_CLEAR_IF_FIRST)) {
     421                        TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
     422                                "invalid flags for %s - TDB_MUTEX_LOCKING "
     423                                "requires TDB_CLEAR_IF_FIRST\n", name));
     424                        errno = EINVAL;
     425                        goto fail;
     426                }
     427
     428                if (tdb->flags & TDB_INTERNAL) {
     429                        TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
     430                                "invalid flags for %s - TDB_MUTEX_LOCKING and "
     431                                "TDB_INTERNAL are not allowed together\n", name));
     432                        errno = EINVAL;
     433                        goto fail;
     434                }
     435
     436                if (tdb->flags & TDB_NOMMAP) {
     437                        TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
     438                                "invalid flags for %s - TDB_MUTEX_LOCKING and "
     439                                "TDB_NOMMAP are not allowed together\n", name));
     440                        errno = EINVAL;
     441                        goto fail;
     442                }
     443
     444                if (tdb->read_only) {
     445                        TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
     446                                "invalid flags for %s - TDB_MUTEX_LOCKING "
     447                                "not allowed read only\n", name));
     448                        errno = EINVAL;
     449                        goto fail;
     450                }
     451
     452                /*
     453                 * The callers should have called
     454                 * tdb_runtime_check_for_robust_mutexes()
     455                 * before using TDB_MUTEX_LOCKING!
     456                 *
     457                 * This makes sure the caller understands
     458                 * that the locking may behave a bit differently
     459                 * than with pure fcntl locking. E.g. multiple
     460                 * read locks are not supported.
     461                 */
     462                if (!tdb_runtime_check_for_robust_mutexes()) {
     463                        TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
     464                                "invalid flags for %s - TDB_MUTEX_LOCKING "
     465                                "requires support for robust_mutexes\n",
     466                                name));
     467                        errno = ENOSYS;
     468                        goto fail;
     469                }
     470        }
     471
    272472        if (getenv("TDB_NO_FSYNC")) {
    273473                tdb->flags |= TDB_NOSYNC;
     
    286486                tdb->flags |= (TDB_NOLOCK | TDB_NOMMAP);
    287487                tdb->flags &= ~TDB_CLEAR_IF_FIRST;
    288                 if (tdb_new_database(tdb, hash_size) != 0) {
     488                if (tdb_new_database(tdb, &header, hash_size) != 0) {
    289489                        TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: tdb_new_database failed!"));
    290490                        goto fail;
    291491                }
     492                tdb->hash_size = hash_size;
    292493                goto internal;
    293494        }
     
    314515            (!tdb->read_only) &&
    315516            (locked = (tdb_nest_lock(tdb, ACTIVE_LOCK, F_WRLCK, TDB_LOCK_NOWAIT|TDB_LOCK_PROBE) == 0))) {
    316                 int ret;
    317517                ret = tdb_brlock(tdb, F_WRLCK, FREELIST_TOP, 0,
    318                                 TDB_LOCK_WAIT);
     518                                 TDB_LOCK_WAIT);
    319519                if (ret == -1) {
    320520                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
    321                                 "tdb_brlock failed for %s: %s\n",
    322                                 name, strerror(errno)));
    323                         goto fail;
    324                 }
    325                 ret = tdb_new_database(tdb, hash_size);
     521                                 "tdb_brlock failed for %s: %s\n",
     522                                 name, strerror(errno)));
     523                        goto fail;
     524                }
     525                ret = tdb_new_database(tdb, &header, hash_size);
    326526                if (ret == -1) {
    327527                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
    328                                 "tdb_new_database failed for %s: %s\n",
    329                                 name, strerror(errno)));
     528                                 "tdb_new_database failed for %s: %s\n",
     529                                 name, strerror(errno)));
    330530                        tdb_unlockall(tdb);
    331531                        goto fail;
     
    334534                if (ret == -1) {
    335535                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
    336                                 "tdb_unlockall failed for %s: %s\n",
    337                                 name, strerror(errno)));
     536                                 "tdb_unlockall failed for %s: %s\n",
     537                                 name, strerror(errno)));
    338538                        goto fail;
    339539                }
     
    341541                if (ret == -1) {
    342542                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
    343                                 "lseek failed for %s: %s\n",
    344                                 name, strerror(errno)));
     543                                 "lseek failed for %s: %s\n",
     544                                 name, strerror(errno)));
    345545                        goto fail;
    346546                }
     
    348548
    349549        errno = 0;
    350         if (read(tdb->fd, &tdb->header, sizeof(tdb->header)) != sizeof(tdb->header)
    351             || strcmp(tdb->header.magic_food, TDB_MAGIC_FOOD) != 0) {
    352                 if (!(open_flags & O_CREAT) || tdb_new_database(tdb, hash_size) == -1) {
     550        if (read(tdb->fd, &header, sizeof(header)) != sizeof(header)
     551            || strcmp(header.magic_food, TDB_MAGIC_FOOD) != 0) {
     552                if (!(open_flags & O_CREAT) ||
     553                    tdb_new_database(tdb, &header, hash_size) == -1) {
    353554                        if (errno == 0) {
    354555                                errno = EIO; /* ie bad format or something */
     
    357558                }
    358559                rev = (tdb->flags & TDB_CONVERT);
    359         } else if (tdb->header.version != TDB_VERSION
    360                    && !(rev = (tdb->header.version==TDB_BYTEREV(TDB_VERSION)))) {
     560        } else if (header.version != TDB_VERSION
     561                   && !(rev = (header.version==TDB_BYTEREV(TDB_VERSION)))) {
    361562                /* wrong version */
    362563                errno = EIO;
    363564                goto fail;
    364565        }
    365         vp = (unsigned char *)&tdb->header.version;
     566        vp = (unsigned char *)&header.version;
    366567        vertest = (((uint32_t)vp[0]) << 24) | (((uint32_t)vp[1]) << 16) |
    367568                  (((uint32_t)vp[2]) << 8) | (uint32_t)vp[3];
     
    371572        else {
    372573                tdb->flags |= TDB_CONVERT;
    373                 tdb_convert(&tdb->header, sizeof(tdb->header));
    374         }
    375         if (fstat(tdb->fd, &st) == -1)
    376                 goto fail;
    377 
    378         if (tdb->header.rwlocks != 0 &&
    379             tdb->header.rwlocks != TDB_HASH_RWLOCK_MAGIC) {
     574                tdb_convert(&header, sizeof(header));
     575        }
     576
     577        /*
     578         * We only use st.st_dev and st.st_ino from the raw fstat()
     579         * call, everything else needs to use tdb_fstat() in order
     580         * to skip tdb->hdr_ofs!
     581         */
     582        if (fstat(tdb->fd, &st) == -1) {
     583                goto fail;
     584        }
     585        tdb->device = st.st_dev;
     586        tdb->inode = st.st_ino;
     587        ZERO_STRUCT(st);
     588
     589        if (header.rwlocks != 0 &&
     590            header.rwlocks != TDB_FEATURE_FLAG_MAGIC &&
     591            header.rwlocks != TDB_HASH_RWLOCK_MAGIC) {
    380592                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
    381                 goto fail;
    382         }
    383 
    384         if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) {
     593                errno = ENOSYS;
     594                goto fail;
     595        }
     596
     597        if (header.hash_size == 0) {
     598                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: invalid database: 0 hash_size\n"));
     599                errno = ENOSYS;
     600                goto fail;
     601        }
     602
     603        tdb->hash_size = header.hash_size;
     604
     605        if (header.rwlocks == TDB_FEATURE_FLAG_MAGIC) {
     606                tdb->feature_flags = header.feature_flags;
     607        }
     608
     609        if (tdb->feature_flags & ~TDB_SUPPORTED_FEATURE_FLAGS) {
     610                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: unsupported "
     611                         "features in tdb %s: 0x%08x (supported: 0x%08x)\n",
     612                         name, (unsigned)tdb->feature_flags,
     613                         (unsigned)TDB_SUPPORTED_FEATURE_FLAGS));
     614                errno = ENOSYS;
     615                goto fail;
     616        }
     617
     618        if (tdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) {
     619                if (!tdb_mutex_open_ok(tdb, &header)) {
     620                        errno = EINVAL;
     621                        goto fail;
     622                }
     623
     624                /*
     625                 * We need to remember the hdr_ofs
     626                 * also for the TDB_NOLOCK case
     627                 * if the current library doesn't support
     628                 * mutex locking.
     629                 */
     630                tdb->hdr_ofs = header.mutex_size;
     631        }
     632
     633        if ((header.magic1_hash == 0) && (header.magic2_hash == 0)) {
    385634                /* older TDB without magic hash references */
    386635                tdb->hash_fn = tdb_old_hash;
    387         } else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) {
     636        } else if (!check_header_hash(tdb, &header, !hash_fn,
     637                                      &magic1, &magic2)) {
    388638                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
    389639                         "%s was not created with %s hash function we are using\n"
     
    391641                         "magic2_hash[0x%08X %s 0x%08X]\n",
    392642                         name, hash_alg,
    393                          tdb->header.magic1_hash,
    394                          (tdb->header.magic1_hash == magic1) ? "==" : "!=",
     643                         header.magic1_hash,
     644                         (header.magic1_hash == magic1) ? "==" : "!=",
    395645                         magic1,
    396                          tdb->header.magic2_hash,
    397                          (tdb->header.magic2_hash == magic2) ? "==" : "!=",
     646                         header.magic2_hash,
     647                         (header.magic2_hash == magic2) ? "==" : "!=",
    398648                         magic2));
    399649                errno = EINVAL;
     
    402652
    403653        /* Is it already in the open list?  If so, fail. */
    404         if (tdb_already_open(st.st_dev, st.st_ino)) {
     654        if (tdb_already_open(tdb->device, tdb->inode)) {
    405655                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
    406656                         "%s (%d,%d) is already open in this process\n",
    407                          name, (int)st.st_dev, (int)st.st_ino));
     657                         name, (int)tdb->device, (int)tdb->inode));
    408658                errno = EBUSY;
    409659                goto fail;
    410660        }
    411661
    412         tdb->map_size = st.st_size;
    413         tdb->device = st.st_dev;
    414         tdb->inode = st.st_ino;
    415         tdb_mmap(tdb);
     662        /*
     663         * We had tdb_mmap(tdb) here before,
     664         * but we need to use tdb_fstat(),
     665         * which is triggered from tdb_oob() before calling tdb_mmap().
     666         * As this skips tdb->hdr_ofs.
     667         */
     668        tdb->map_size = 0;
     669        ret = tdb->methods->tdb_oob(tdb, 0, 1, 0);
     670        if (ret == -1) {
     671                errno = EIO;
     672                goto fail;
     673        }
     674
     675        if (tdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) {
     676                if (!(tdb->flags & TDB_NOLOCK)) {
     677                        ret = tdb_mutex_mmap(tdb);
     678                        if (ret != 0) {
     679                                goto fail;
     680                        }
     681                }
     682        }
     683
    416684        if (locked) {
    417685                if (tdb_nest_unlock(tdb, ACTIVE_LOCK, F_WRLCK, false) == -1) {
     
    465733        tdb->next = tdbs;
    466734        tdbs = tdb;
     735        errno = orig_errno;
    467736        return tdb;
    468737
     
    523792                        tdb_munmap(tdb);
    524793        }
     794
     795        tdb_mutex_munmap(tdb);
     796
    525797        SAFE_FREE(tdb->name);
    526798        if (tdb->fd != -1) {
     
    594866                goto fail;
    595867        }
     868        /*
     869         * We only use st.st_dev and st.st_ino from the raw fstat()
     870         * call, everything else needs to use tdb_fstat() in order
     871         * to skip tdb->hdr_ofs!
     872         */
    596873        if (fstat(tdb->fd, &st) != 0) {
    597874                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_reopen: fstat failed (%s)\n", strerror(errno)));
     
    602879                goto fail;
    603880        }
    604         tdb_mmap(tdb);
     881        ZERO_STRUCT(st);
     882
     883        /*
     884         * We had tdb_mmap(tdb) here before,
     885         * but we need to use tdb_fstat(),
     886         * which is triggered from tdb_oob() before calling tdb_mmap().
     887         * As this skips tdb->hdr_ofs.
     888         */
     889        tdb->map_size = 0;
     890        if (tdb->methods->tdb_oob(tdb, 0, 1, 0) != 0) {
     891                goto fail;
     892        }
    605893#endif /* fake pread or pwrite */
    606894
     
    608896        tdb->num_lockrecs = 0;
    609897        SAFE_FREE(tdb->lockrecs);
     898        tdb->lockrecs_array_length = 0;
    610899
    611900        if (active_lock && tdb_nest_lock(tdb, ACTIVE_LOCK, F_RDLCK, TDB_LOCK_WAIT) == -1) {
  • vendor/current/lib/tdb/common/summary.c

    r986 r988  
    1  /* 
     1 /*
    22   Trivial Database: human-readable summary code
    33   Copyright (C) Rusty Russell 2010
    4    
     4
    55   This library is free software; you can redistribute it and/or
    66   modify it under the terms of the GNU Lesser General Public
     
    1919
    2020#define SUMMARY_FORMAT \
    21         "Size of file/data: %u/%zu\n" \
     21        "Size of file/data: %llu/%zu\n" \
     22        "Header offset/logical size: %zu/%zu\n" \
    2223        "Number of records: %zu\n" \
     24        "Incompatible hash: %s\n" \
     25        "Active/supported feature flags: 0x%08x/0x%08x\n" \
     26        "Robust mutexes locking: %s\n" \
    2327        "Smallest/average/largest keys: %zu/%zu/%zu\n" \
    2428        "Smallest/average/largest data: %zu/%zu/%zu\n" \
     
    8791_PUBLIC_ char *tdb_summary(struct tdb_context *tdb)
    8892{
     93        off_t file_size;
    8994        tdb_off_t off, rec_off;
    90         struct tally freet, keys, data, dead, extra, hash, uncoal;
     95        struct tally freet, keys, data, dead, extra, hashval, uncoal;
    9196        struct tdb_record rec;
    9297        char *ret = NULL;
    9398        bool locked;
    94         size_t len, unc = 0;
     99        size_t unc = 0;
     100        int len;
    95101        struct tdb_record recovery;
    96102
     
    114120        tally_init(&dead);
    115121        tally_init(&extra);
    116         tally_init(&hash);
     122        tally_init(&hashval);
    117123        tally_init(&uncoal);
    118124
    119         for (off = TDB_DATA_START(tdb->header.hash_size);
     125        for (off = TDB_DATA_START(tdb->hash_size);
    120126             off < tdb->map_size - 1;
    121127             off += sizeof(rec) + rec.rec_len) {
     
    152158                default:
    153159                        TDB_LOG((tdb, TDB_DEBUG_ERROR,
    154                                  "Unexpected record magic 0x%x at offset %d\n",
     160                                 "Unexpected record magic 0x%x at offset %u\n",
    155161                                 rec.magic, off));
    156162                        goto unlock;
     
    160166                tally_add(&uncoal, unc - 1);
    161167
    162         for (off = 0; off < tdb->header.hash_size; off++)
    163                 tally_add(&hash, get_hash_length(tdb, off));
    164 
    165         /* 20 is max length of a %zu. */
    166         len = strlen(SUMMARY_FORMAT) + 35*20 + 1;
    167         ret = (char *)malloc(len);
    168         if (!ret)
    169                 goto unlock;
    170 
    171         snprintf(ret, len, SUMMARY_FORMAT,
    172                  tdb->map_size, keys.total+data.total,
     168        for (off = 0; off < tdb->hash_size; off++)
     169                tally_add(&hashval, get_hash_length(tdb, off));
     170
     171        file_size = tdb->hdr_ofs + tdb->map_size;
     172
     173        len = asprintf(&ret, SUMMARY_FORMAT,
     174                 (unsigned long long)file_size, keys.total+data.total,
     175                 (size_t)tdb->hdr_ofs, (size_t)tdb->map_size,
    173176                 keys.num,
     177                 (tdb->hash_fn == tdb_jenkins_hash)?"yes":"no",
     178                 (unsigned)tdb->feature_flags, TDB_SUPPORTED_FEATURE_FLAGS,
     179                 (tdb->feature_flags & TDB_FEATURE_FLAG_MUTEX)?"yes":"no",
    174180                 keys.min, tally_mean(&keys), keys.max,
    175181                 data.min, tally_mean(&data), data.max,
     
    179185                 freet.num,
    180186                 freet.min, tally_mean(&freet), freet.max,
    181                  hash.num,
    182                  hash.min, tally_mean(&hash), hash.max,
     187                 hashval.num,
     188                 hashval.min, tally_mean(&hashval), hashval.max,
    183189                 uncoal.total,
    184190                 uncoal.min, tally_mean(&uncoal), uncoal.max,
    185                  keys.total * 100.0 / tdb->map_size,
    186                  data.total * 100.0 / tdb->map_size,
    187                  extra.total * 100.0 / tdb->map_size,
    188                  freet.total * 100.0 / tdb->map_size,
    189                  dead.total * 100.0 / tdb->map_size,
     191                 keys.total * 100.0 / file_size,
     192                 data.total * 100.0 / file_size,
     193                 extra.total * 100.0 / file_size,
     194                 freet.total * 100.0 / file_size,
     195                 dead.total * 100.0 / file_size,
    190196                 (keys.num + freet.num + dead.num)
    191197                 * (sizeof(struct tdb_record) + sizeof(uint32_t))
    192                  * 100.0 / tdb->map_size,
    193                  tdb->header.hash_size * sizeof(tdb_off_t)
    194                  * 100.0 / tdb->map_size);
     198                 * 100.0 / file_size,
     199                 tdb->hash_size * sizeof(tdb_off_t)
     200                 * 100.0 / file_size);
     201        if (len == -1) {
     202                goto unlock;
     203        }
    195204
    196205unlock:
  • vendor/current/lib/tdb/common/tdb.c

    r986 r988  
    1  /* 
     1 /*
    22   Unix SMB/CIFS implementation.
    33
     
    125125static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
    126126
     127static int tdb_update_hash_cmp(TDB_DATA key, TDB_DATA data, void *private_data)
     128{
     129        TDB_DATA *dbuf = (TDB_DATA *)private_data;
     130
     131        if (dbuf->dsize != data.dsize) {
     132                return -1;
     133        }
     134        if (memcmp(dbuf->dptr, data.dptr, data.dsize) != 0) {
     135                return -1;
     136        }
     137        return 0;
     138}
     139
    127140/* update an entry in place - this only works if the new data size
    128141   is <= the old data size and the key exists.
     
    140153        /* it could be an exact duplicate of what is there - this is
    141154         * surprisingly common (eg. with a ldb re-index). */
    142         if (rec.key_len == key.dsize && 
     155        if (rec.key_len == key.dsize &&
    143156            rec.data_len == dbuf.dsize &&
    144             rec.full_hash == hash) {
    145                 TDB_DATA data = _tdb_fetch(tdb, key);
    146                 if (data.dsize == dbuf.dsize &&
    147                     memcmp(data.dptr, dbuf.dptr, data.dsize) == 0) {
    148                         if (data.dptr) {
    149                                 free(data.dptr);
    150                         }
    151                         return 0;
    152                 }
    153                 if (data.dptr) {
    154                         free(data.dptr);
    155                 }
     157            rec.full_hash == hash &&
     158            tdb_parse_record(tdb, key, tdb_update_hash_cmp, &dbuf) == 0) {
     159                return 0;
    156160        }
    157161
     
    255259}
    256260
    257 /* check if an entry in the database exists 
     261/* check if an entry in the database exists
    258262
    259263   note that 1 is returned if the key is found and 0 is returned if not found
     
    342346 * Purge all DEAD records from a hash chain
    343347 */
    344 static int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
     348int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
    345349{
    346350        int res = -1;
     
    348352        tdb_off_t rec_ptr;
    349353
    350         if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
     354        if (tdb_lock_nonblock(tdb, -1, F_WRLCK) == -1) {
     355                /*
     356                 * Don't block the freelist if not strictly necessary
     357                 */
    351358                return -1;
    352359        }
     
    384391        int ret;
    385392
     393        rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, &rec);
     394        if (rec_ptr == 0) {
     395                return -1;
     396        }
     397
    386398        if (tdb->max_dead_records != 0) {
     399
     400                uint32_t magic = TDB_DEAD_MAGIC;
    387401
    388402                /*
     
    390404                 * tdb's with a very high create/delete rate like locking.tdb.
    391405                 */
    392 
    393                 if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
    394                         return -1;
    395406
    396407                if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) {
     
    402413                }
    403414
    404                 if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) {
    405                         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
    406                         return -1;
    407                 }
    408 
    409415                /*
    410416                 * Just mark the record as dead.
    411417                 */
    412                 rec.magic = TDB_DEAD_MAGIC;
    413                 ret = tdb_rec_write(tdb, rec_ptr, &rec);
     418                ret = tdb_ofs_write(
     419                        tdb, rec_ptr + offsetof(struct tdb_record, magic),
     420                        &magic);
    414421        }
    415422        else {
    416                 if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK,
    417                                                    &rec)))
    418                         return -1;
    419 
    420423                ret = tdb_do_delete(tdb, rec_ptr, &rec);
    421424        }
     
    425428        }
    426429
    427         if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0)
     430        if (tdb_unlock(tdb, BUCKET(hash), F_WRLCK) != 0)
    428431                TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n"));
    429432        return ret;
     
    443446 * See if we have a dead record around with enough space
    444447 */
    445 static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
    446                                struct tdb_record *r, tdb_len_t length)
    447 {
    448         tdb_off_t rec_ptr;
     448tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
     449                        struct tdb_record *r, tdb_len_t length,
     450                        tdb_off_t *p_last_ptr)
     451{
     452        tdb_off_t rec_ptr, last_ptr;
     453        tdb_off_t best_rec_ptr = 0;
     454        tdb_off_t best_last_ptr = 0;
     455        struct tdb_record best = { .rec_len = UINT32_MAX };
     456
     457        length += sizeof(tdb_off_t); /* tailer */
     458
     459        last_ptr = TDB_HASH_TOP(hash);
    449460
    450461        /* read in the hash top */
    451         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
     462        if (tdb_ofs_read(tdb, last_ptr, &rec_ptr) == -1)
    452463                return 0;
    453464
     
    457468                        return 0;
    458469
    459                 if (TDB_DEAD(r) && r->rec_len >= length) {
    460                         /*
    461                          * First fit for simple coding, TODO: change to best
    462                          * fit
    463                          */
    464                         return rec_ptr;
    465                 }
     470                if (TDB_DEAD(r) && (r->rec_len >= length) &&
     471                    (r->rec_len < best.rec_len)) {
     472                        best_rec_ptr = rec_ptr;
     473                        best_last_ptr = last_ptr;
     474                        best = *r;
     475                }
     476                last_ptr = rec_ptr;
    466477                rec_ptr = r->next;
    467478        }
    468         return 0;
     479
     480        if (best.rec_len == UINT32_MAX) {
     481                return 0;
     482        }
     483
     484        *r = best;
     485        *p_last_ptr = best_last_ptr;
     486        return best_rec_ptr;
    469487}
    470488
     
    474492        struct tdb_record rec;
    475493        tdb_off_t rec_ptr;
    476         char *p = NULL;
    477494        int ret = -1;
    478495
     
    495512                }
    496513        }
    497         /* reset the error code potentially set by the tdb_update() */
     514        /* reset the error code potentially set by the tdb_update_hash() */
    498515        tdb->ecode = TDB_SUCCESS;
    499516
     
    504521                tdb_delete_hash(tdb, key, hash);
    505522
    506         /* Copy key+value *before* allocating free space in case malloc
    507            fails and we are left with a dead spot in the tdb. */
    508 
    509         if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
    510                 tdb->ecode = TDB_ERR_OOM;
    511                 goto fail;
    512         }
    513 
    514         memcpy(p, key.dptr, key.dsize);
    515         if (dbuf.dsize)
    516                 memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
    517 
    518         if (tdb->max_dead_records != 0) {
    519                 /*
    520                  * Allow for some dead records per hash chain, look if we can
    521                  * find one that can hold the new record. We need enough space
    522                  * for key, data and tailer. If we find one, we don't have to
    523                  * consult the central freelist.
    524                  */
    525                 rec_ptr = tdb_find_dead(
    526                         tdb, hash, &rec,
    527                         key.dsize + dbuf.dsize + sizeof(tdb_off_t));
    528 
    529                 if (rec_ptr != 0) {
    530                         rec.key_len = key.dsize;
    531                         rec.data_len = dbuf.dsize;
    532                         rec.full_hash = hash;
    533                         rec.magic = TDB_MAGIC;
    534                         if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
    535                             || tdb->methods->tdb_write(
    536                                     tdb, rec_ptr + sizeof(rec),
    537                                     p, key.dsize + dbuf.dsize) == -1) {
    538                                 goto fail;
    539                         }
    540                         goto done;
    541                 }
    542         }
    543 
    544         /*
    545          * We have to allocate some space from the freelist, so this means we
    546          * have to lock it. Use the chance to purge all the DEAD records from
    547          * the hash chain under the freelist lock.
    548          */
    549 
    550         if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
    551                 goto fail;
    552         }
    553 
    554         if ((tdb->max_dead_records != 0)
    555             && (tdb_purge_dead(tdb, hash) == -1)) {
    556                 tdb_unlock(tdb, -1, F_WRLCK);
    557                 goto fail;
    558         }
    559 
    560523        /* we have to allocate some space */
    561         rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec);
    562 
    563         tdb_unlock(tdb, -1, F_WRLCK);
     524        rec_ptr = tdb_allocate(tdb, hash, key.dsize + dbuf.dsize, &rec);
    564525
    565526        if (rec_ptr == 0) {
     
    578539        /* write out and point the top of the hash chain at it */
    579540        if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
    580             || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
     541            || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec),
     542                                       key.dptr, key.dsize) == -1
     543            || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec)+key.dsize,
     544                                       dbuf.dptr, dbuf.dsize) == -1
    581545            || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
    582546                /* Need to tdb_unallocate() here */
     
    590554                tdb_increment_seqnum(tdb);
    591555        }
    592 
    593         SAFE_FREE(p);
    594556        return ret;
    595557}
     
    719681_PUBLIC_ int tdb_hash_size(struct tdb_context *tdb)
    720682{
    721         return tdb->header.hash_size;
     683        return tdb->hash_size;
    722684}
    723685
     
    762724        }
    763725
     726        if ((flags & TDB_NOLOCK) &&
     727            (tdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) &&
     728            (tdb->mutexes == NULL)) {
     729                tdb->ecode = TDB_ERR_LOCK;
     730                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_remove_flags: "
     731                         "Can not remove NOLOCK flag on mutexed databases"));
     732                return;
     733        }
     734
    764735        if (flags & TDB_ALLOW_NESTING) {
    765736                tdb->flags |= TDB_DISALLOW_NESTING;
     
    783754
    784755/*
    785   add a region of the file to the freelist. Length is the size of the region in bytes, 
     756  add a region of the file to the freelist. Length is the size of the region in bytes,
    786757  which includes the free list header that needs to be added
    787758 */
     
    795766        if (length + offset > tdb->map_size) {
    796767                TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n"));
    797                 return -1;             
     768                return -1;
    798769        }
    799770        memset(&rec,'\0',sizeof(rec));
     
    841812                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery record\n"));
    842813                        return -1;
    843                 }       
     814                }
    844815                recovery_size = rec.rec_len + sizeof(rec);
    845816        }
    846817
    847818        /* wipe the hashes */
    848         for (i=0;i<tdb->header.hash_size;i++) {
     819        for (i=0;i<tdb->hash_size;i++) {
    849820                if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) {
    850821                        TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i));
     
    859830        }
    860831
    861         /* add all the rest of the file to the freelist, possibly leaving a gap 
     832        /* add all the rest of the file to the freelist, possibly leaving a gap
    862833           for the recovery area */
    863834        if (recovery_size == 0) {
    864835                /* the simple case - the whole file can be used as a freelist */
    865                 data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size));
    866                 if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
     836                data_len = (tdb->map_size - TDB_DATA_START(tdb->hash_size));
     837                if (tdb_free_region(tdb, TDB_DATA_START(tdb->hash_size), data_len) != 0) {
    867838                        goto failed;
    868839                }
    869840        } else {
    870841                /* we need to add two freelist entries - one on either
    871                    side of the recovery area 
     842                   side of the recovery area
    872843
    873844                   Note that we cannot shift the recovery area during
     
    876847                   corruption
    877848                */
    878                 data_len = (recovery_head - TDB_DATA_START(tdb->header.hash_size));
    879                 if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
     849                data_len = (recovery_head - TDB_DATA_START(tdb->hash_size));
     850                if (tdb_free_region(tdb, TDB_DATA_START(tdb->hash_size), data_len) != 0) {
    880851                        goto failed;
    881852                }
     
    887858        }
    888859
     860        tdb_increment_seqnum_nonblock(tdb);
     861
    889862        if (tdb_unlockall(tdb) != 0) {
    890863                TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n"));
     
    946919                tdb_transaction_cancel(tdb);
    947920                tdb_close(tmp_db);
    948                 return -1;             
     921                return -1;
    949922        }
    950923
     
    970943                tdb_transaction_cancel(tdb);
    971944                tdb_close(tmp_db);
    972                 return -1;             
     945                return -1;
    973946        }
    974947
     
    1004977}
    1005978
     979bool tdb_add_off_t(tdb_off_t a, tdb_off_t b, tdb_off_t *pret)
     980{
     981        tdb_off_t ret = a + b;
     982
     983        if ((ret < a) || (ret < b)) {
     984                return false;
     985        }
     986        *pret = ret;
     987        return true;
     988}
     989
    1006990#ifdef TDB_TRACE
    1007991static void tdb_trace_write(struct tdb_context *tdb, const char *str)
    1008992{
    1009         if (!tdb_write_alltdb->tracefd, str, strlen(str)) {
     993        if (!tdb_write_all(tdb->tracefd, str, strlen(str))) {
    1010994                close(tdb->tracefd);
    1011995                tdb->tracefd = -1;
  • vendor/current/lib/tdb/common/tdb_private.h

    r986 r988  
    1  /*
     1#ifndef TDB_PRIVATE_H
     2#define TDB_PRIVATE_H
     3 /*
    24   Unix SMB/CIFS implementation.
    35
     
    5254#define TDB_RECOVERY_INVALID_MAGIC (0x0)
    5355#define TDB_HASH_RWLOCK_MAGIC (0xbad1a51U)
     56#define TDB_FEATURE_FLAG_MAGIC (0xbad1a52U)
    5457#define TDB_ALIGNMENT 4
    5558#define DEFAULT_HASH_SIZE 131
     
    6063#define TDB_BAD_MAGIC(r) ((r)->magic != TDB_MAGIC && !TDB_DEAD(r))
    6164#define TDB_HASH_TOP(hash) (FREELIST_TOP + (BUCKET(hash)+1)*sizeof(tdb_off_t))
    62 #define TDB_HASHTABLE_SIZE(tdb) ((tdb->header.hash_size+1)*sizeof(tdb_off_t))
     65#define TDB_HASHTABLE_SIZE(tdb) ((tdb->hash_size+1)*sizeof(tdb_off_t))
    6366#define TDB_DATA_START(hash_size) (TDB_HASH_TOP(hash_size-1) + sizeof(tdb_off_t))
    6467#define TDB_RECOVERY_HEAD offsetof(struct tdb_header, recovery_start)
     
    6669#define TDB_PAD_BYTE 0x42
    6770#define TDB_PAD_U32  0x42424242
     71
     72#define TDB_FEATURE_FLAG_MUTEX 0x00000001
     73
     74#define TDB_SUPPORTED_FEATURE_FLAGS ( \
     75        TDB_FEATURE_FLAG_MUTEX | \
     76        0)
    6877
    6978/* NB assumes there is a local variable called "tdb" that is the
     
    113122#endif
    114123
    115 #define BUCKET(hash) ((hash) % tdb->header.hash_size)
     124#define BUCKET(hash) ((hash) % tdb->hash_size)
    116125
    117126#define DOCONV() (tdb->flags & TDB_CONVERT)
     
    151160        uint32_t magic1_hash; /* hash of TDB_MAGIC_FOOD. */
    152161        uint32_t magic2_hash; /* hash of TDB_MAGIC. */
    153         tdb_off_t reserved[27];
     162        uint32_t feature_flags;
     163        tdb_len_t mutex_size; /* set if TDB_FEATURE_FLAG_MUTEX is set */
     164        tdb_off_t reserved[25];
    154165};
    155166
     
    181192        int (*tdb_write)(struct tdb_context *, tdb_off_t, const void *, tdb_len_t);
    182193        void (*next_hash_chain)(struct tdb_context *, uint32_t *);
    183         int (*tdb_oob)(struct tdb_context *, tdb_off_t , int );
     194        int (*tdb_oob)(struct tdb_context *, tdb_off_t , tdb_len_t, int );
    184195        int (*tdb_expand_file)(struct tdb_context *, tdb_off_t , tdb_off_t );
    185196};
     197
     198struct tdb_mutexes;
    186199
    187200struct tdb_context {
     
    196209        int num_lockrecs;
    197210        struct tdb_lock_type *lockrecs; /* only real locks, all with count>0 */
     211        int lockrecs_array_length;
     212
     213        tdb_off_t hdr_ofs; /* this is 0 or header.mutex_size */
     214        struct tdb_mutexes *mutexes; /* mmap of the mutex area */
     215
    198216        enum TDB_ERROR ecode; /* error code for last tdb error */
    199         struct tdb_header header; /* a cached copy of the header */
     217        uint32_t hash_size;
     218        uint32_t feature_flags;
    200219        uint32_t flags; /* the flags passed to tdb_open */
    201220        struct tdb_traverse_lock travlocks; /* current traversal locks */
     
    221240*/
    222241int tdb_munmap(struct tdb_context *tdb);
    223 void tdb_mmap(struct tdb_context *tdb);
     242int tdb_mmap(struct tdb_context *tdb);
    224243int tdb_lock(struct tdb_context *tdb, int list, int ltype);
    225244int tdb_lock_nonblock(struct tdb_context *tdb, int list, int ltype);
     
    253272void *tdb_convert(void *buf, uint32_t size);
    254273int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec);
    255 tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct tdb_record *rec);
     274tdb_off_t tdb_allocate(struct tdb_context *tdb, int hash, tdb_len_t length,
     275                       struct tdb_record *rec);
    256276int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
    257277int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d);
     
    270290tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
    271291                           struct tdb_record *rec);
     292tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
     293                        struct tdb_record *r, tdb_len_t length,
     294                        tdb_off_t *p_last_ptr);
     295int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash);
    272296void tdb_io_init(struct tdb_context *tdb);
    273297int tdb_expand(struct tdb_context *tdb, tdb_off_t size);
     298tdb_off_t tdb_expand_adjust(tdb_off_t map_size, tdb_off_t size, int page_size);
    274299int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off,
    275300                      struct tdb_record *rec);
     
    280305unsigned int tdb_old_hash(TDB_DATA *key);
    281306size_t tdb_dead_space(struct tdb_context *tdb, tdb_off_t off);
     307bool tdb_add_off_t(tdb_off_t a, tdb_off_t b, tdb_off_t *pret);
     308
     309/* tdb_off_t and tdb_len_t right now are both uint32_t */
     310#define tdb_add_len_t tdb_add_off_t
     311
     312size_t tdb_mutex_size(struct tdb_context *tdb);
     313bool tdb_have_mutexes(struct tdb_context *tdb);
     314int tdb_mutex_init(struct tdb_context *tdb);
     315int tdb_mutex_mmap(struct tdb_context *tdb);
     316int tdb_mutex_munmap(struct tdb_context *tdb);
     317bool tdb_mutex_lock(struct tdb_context *tdb, int rw, off_t off, off_t len,
     318                    bool waitflag, int *pret);
     319bool tdb_mutex_unlock(struct tdb_context *tdb, int rw, off_t off, off_t len,
     320                      int *pret);
     321int tdb_mutex_allrecord_lock(struct tdb_context *tdb, int ltype,
     322                             enum tdb_lock_flags flags);
     323int tdb_mutex_allrecord_unlock(struct tdb_context *tdb);
     324int tdb_mutex_allrecord_upgrade(struct tdb_context *tdb);
     325void tdb_mutex_allrecord_downgrade(struct tdb_context *tdb);
     326
     327#endif /* TDB_PRIVATE_H */
  • vendor/current/lib/tdb/common/transaction.c

    r986 r988  
    1  /* 
     1 /*
    22   Unix SMB/CIFS implementation.
    33
     
    8383
    8484  - if TDB_NOSYNC is passed to flags in tdb_open then transactions are
    85     still available, but no transaction recovery area is used and no
    86     fsync/msync calls are made.
     85    still available, but no fsync/msync calls are made.  This means we
     86    are still proof against a process dying during transaction commit,
     87    but not against machine reboot.
    8788
    8889  - if TDB_ALLOW_NESTING is passed to flags in tdb open, or added using
     
    148149  of transaction elements, then if not do a real read
    149150*/
    150 static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf, 
     151static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
    151152                            tdb_len_t len, int cv)
    152153{
     
    195196
    196197fail:
    197         TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: failed at off=%d len=%d\n", off, len));
     198        TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: failed at off=%u len=%u\n", off, len));
    198199        tdb->ecode = TDB_ERR_IO;
    199200        tdb->transaction->transaction_error = 1;
     
    205206  write while in a transaction
    206207*/
    207 static int transaction_write(struct tdb_context *tdb, tdb_off_t off, 
     208static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
    208209                             const void *buf, tdb_len_t len)
    209210{
     
    249250                uint8_t **new_blocks;
    250251                /* expand the blocks array */
    251                 if (tdb->transaction->blocks == NULL) {
    252                         new_blocks = (uint8_t **)malloc(
    253                                 (blk+1)*sizeof(uint8_t *));
    254                 } else {
    255                         new_blocks = (uint8_t **)realloc(
    256                                 tdb->transaction->blocks,
    257                                 (blk+1)*sizeof(uint8_t *));
    258                 }
     252                new_blocks = (uint8_t **)realloc(tdb->transaction->blocks,
     253                                                 (blk+1)*sizeof(uint8_t *));
    259254                if (new_blocks == NULL) {
    260255                        tdb->ecode = TDB_ERR_OOM;
    261256                        goto fail;
    262257                }
    263                 memset(&new_blocks[tdb->transaction->num_blocks], 0, 
     258                memset(&new_blocks[tdb->transaction->num_blocks], 0,
    264259                       (1+(blk - tdb->transaction->num_blocks))*sizeof(uint8_t *));
    265260                tdb->transaction->blocks = new_blocks;
     
    274269                        tdb->ecode = TDB_ERR_OOM;
    275270                        tdb->transaction->transaction_error = 1;
    276                         return -1;                     
     271                        return -1;
    277272                }
    278273                if (tdb->transaction->old_map_size > blk * tdb->transaction->block_size) {
     
    281276                                len2 = tdb->transaction->old_map_size - (blk * tdb->transaction->block_size);
    282277                        }
    283                         if (tdb->transaction->io_methods->tdb_read(tdb, blk * tdb->transaction->block_size, 
    284                                                                    tdb->transaction->blocks[blk], 
     278                        if (tdb->transaction->io_methods->tdb_read(tdb, blk * tdb->transaction->block_size,
     279                                                                   tdb->transaction->blocks[blk],
    285280                                                                   len2, 0) != 0) {
    286                                 SAFE_FREE(tdb->transaction->blocks[blk]);                               
     281                                SAFE_FREE(tdb->transaction->blocks[blk]);
    287282                                tdb->ecode = TDB_ERR_IO;
    288283                                goto fail;
     
    290285                        if (blk == tdb->transaction->num_blocks-1) {
    291286                                tdb->transaction->last_block_size = len2;
    292                         }                       
     287                        }
    293288                }
    294289        }
     
    309304
    310305fail:
    311         TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%d len=%d\n",
     306        TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%u len=%u\n",
    312307                 (blk*tdb->transaction->block_size) + off, len));
    313308        tdb->transaction->transaction_error = 1;
     
    317312
    318313/*
    319   write while in a transaction - this varient never expands the transaction blocks, it only
     314  write while in a transaction - this variant never expands the transaction blocks, it only
    320315  updates existing blocks. This means it cannot change the recovery size
    321316*/
    322 static int transaction_write_existing(struct tdb_context *tdb, tdb_off_t off, 
     317static int transaction_write_existing(struct tdb_context *tdb, tdb_off_t off,
    323318                                      const void *buf, tdb_len_t len)
    324319{
     
    371366{
    372367        uint32_t h = *chain;
    373         for (;h < tdb->header.hash_size;h++) {
     368        for (;h < tdb->hash_size;h++) {
    374369                /* the +1 takes account of the freelist */
    375370                if (0 != tdb->transaction->hash_heads[h+1]) {
     
    383378  out of bounds check during a transaction
    384379*/
    385 static int transaction_oob(struct tdb_context *tdb, tdb_off_t len, int probe)
    386 {
    387         if (len <= tdb->map_size) {
     380static int transaction_oob(struct tdb_context *tdb, tdb_off_t off,
     381                           tdb_len_t len, int probe)
     382{
     383        if (off + len >= off && off + len <= tdb->map_size) {
    388384                return 0;
    389385        }
     
    395391  transaction version of tdb_expand().
    396392*/
    397 static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size, 
     393static int transaction_expand_file(struct tdb_context *tdb, tdb_off_t size,
    398394                                   tdb_off_t addition)
    399395{
     
    426422{
    427423        /* some sanity checks */
    428         if (tdb->read_only || (tdb->flags & TDB_INTERNAL) || tdb->traverse_read) {
     424        if (tdb->read_only || (tdb->flags & TDB_INTERNAL)
     425            || tdb->traverse_read) {
    429426                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: cannot start a transaction on a read-only or internal db\n"));
    430427                tdb->ecode = TDB_ERR_EINVAL;
     
    439436                }
    440437                tdb->transaction->nesting++;
    441                 TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n", 
     438                TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_start: nesting %d\n",
    442439                         tdb->transaction->nesting));
    443440                return 0;
     
    494491           traverse can be fast */
    495492        tdb->transaction->hash_heads = (uint32_t *)
    496                 calloc(tdb->header.hash_size+1, sizeof(uint32_t));
     493                calloc(tdb->hash_size+1, sizeof(uint32_t));
    497494        if (tdb->transaction->hash_heads == NULL) {
    498495                tdb->ecode = TDB_ERR_OOM;
     
    508505        /* make sure we know about any file expansions already done by
    509506           anyone else */
    510         tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
     507        tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1);
    511508        tdb->transaction->old_map_size = tdb->map_size;
    512509
     
    544541*/
    545542static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length)
    546 {       
     543{
    547544        if (tdb->flags & TDB_NOSYNC) {
    548545                return 0;
     
    561558        if (tdb->map_ptr) {
    562559                tdb_off_t moffset = offset & ~(tdb->page_size-1);
    563                 if (msync(moffset + (char *)tdb->map_ptr, 
     560                if (msync(moffset + (char *)tdb->map_ptr,
    564561                          length + (offset - moffset), MS_SYNC) != 0) {
    565562                        tdb->ecode = TDB_ERR_IO;
     
    575572
    576573static int _tdb_transaction_cancel(struct tdb_context *tdb)
    577 {       
     574{
    578575        int i, ret = 0;
    579576
     
    587584                tdb->transaction->nesting--;
    588585                return 0;
    589         }               
     586        }
    590587
    591588        tdb->map_size = tdb->transaction->old_map_size;
     
    635632  work out how much space the linearised recovery data will consume
    636633*/
    637 static tdb_len_t tdb_recovery_size(struct tdb_context *tdb)
     634static bool tdb_recovery_size(struct tdb_context *tdb, tdb_len_t *result)
    638635{
    639636        tdb_len_t recovery_size = 0;
     
    642639        recovery_size = sizeof(uint32_t);
    643640        for (i=0;i<tdb->transaction->num_blocks;i++) {
     641                tdb_len_t block_size;
    644642                if (i * tdb->transaction->block_size >= tdb->transaction->old_map_size) {
    645643                        break;
     
    648646                        continue;
    649647                }
    650                 recovery_size += 2*sizeof(tdb_off_t);
     648                if (!tdb_add_len_t(recovery_size, 2*sizeof(tdb_off_t),
     649                                   &recovery_size)) {
     650                        return false;
     651                }
    651652                if (i == tdb->transaction->num_blocks-1) {
    652                         recovery_size += tdb->transaction->last_block_size;
     653                        block_size = tdb->transaction->last_block_size;
    653654                } else {
    654                         recovery_size += tdb->transaction->block_size;
    655                 }
    656         }       
    657 
    658         return recovery_size;
     655                        block_size =  tdb->transaction->block_size;
     656                }
     657                if (!tdb_add_len_t(recovery_size, block_size,
     658                                   &recovery_size)) {
     659                        return false;
     660                }
     661        }
     662
     663        *result = recovery_size;
     664        return true;
    659665}
    660666
     
    691697  large enough
    692698*/
    693 static int tdb_recovery_allocate(struct tdb_context *tdb, 
     699static int tdb_recovery_allocate(struct tdb_context *tdb,
    694700                                 tdb_len_t *recovery_size,
    695701                                 tdb_off_t *recovery_offset,
     
    698704        struct tdb_record rec;
    699705        const struct tdb_methods *methods = tdb->transaction->io_methods;
    700         tdb_off_t recovery_head;
     706        tdb_off_t recovery_head, new_end;
    701707
    702708        if (tdb_recovery_area(tdb, methods, &recovery_head, &rec) == -1) {
     
    705711        }
    706712
    707         *recovery_size = tdb_recovery_size(tdb);
    708 
     713        if (!tdb_recovery_size(tdb, recovery_size)) {
     714                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: "
     715                         "overflow recovery size\n"));
     716                return -1;
     717        }
     718
     719        /* Existing recovery area? */
    709720        if (recovery_head != 0 && *recovery_size <= rec.rec_len) {
    710721                /* it fits in the existing area */
     
    714725        }
    715726
    716         /* we need to free up the old recovery area, then allocate a
    717            new one at the end of the file. Note that we cannot use
    718            tdb_allocate() to allocate the new one as that might return
    719            us an area that is being currently used (as of the start of
    720            the transaction) */
    721         if (recovery_head != 0) {
    722                 if (tdb_free(tdb, recovery_head, &rec) == -1) {
    723                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to free previous recovery area\n"));
    724                         return -1;
    725                 }
    726         }
    727 
    728         /* the tdb_free() call might have increased the recovery size */
    729         *recovery_size = tdb_recovery_size(tdb);
    730 
    731         /* round up to a multiple of page size */
    732         *recovery_max_size = TDB_ALIGN(sizeof(rec) + *recovery_size, tdb->page_size) - sizeof(rec);
    733         *recovery_offset = tdb->map_size;
    734         recovery_head = *recovery_offset;
    735 
    736         if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
    737                                      (tdb->map_size - tdb->transaction->old_map_size) +
    738                                      sizeof(rec) + *recovery_max_size) == -1) {
     727        /* If recovery area in middle of file, we need a new one. */
     728        if (recovery_head == 0
     729            || recovery_head + sizeof(rec) + rec.rec_len != tdb->map_size) {
     730                /* we need to free up the old recovery area, then allocate a
     731                   new one at the end of the file. Note that we cannot use
     732                   tdb_allocate() to allocate the new one as that might return
     733                   us an area that is being currently used (as of the start of
     734                   the transaction) */
     735                if (recovery_head) {
     736                        if (tdb_free(tdb, recovery_head, &rec) == -1) {
     737                                TDB_LOG((tdb, TDB_DEBUG_FATAL,
     738                                         "tdb_recovery_allocate: failed to"
     739                                         " free previous recovery area\n"));
     740                                return -1;
     741                        }
     742
     743                        /* the tdb_free() call might have increased
     744                         * the recovery size */
     745                        if (!tdb_recovery_size(tdb, recovery_size)) {
     746                                TDB_LOG((tdb, TDB_DEBUG_FATAL,
     747                                         "tdb_recovery_allocate: "
     748                                         "overflow recovery size\n"));
     749                                return -1;
     750                        }
     751                }
     752
     753                /* New head will be at end of file. */
     754                recovery_head = tdb->map_size;
     755        }
     756
     757        /* Now we know where it will be. */
     758        *recovery_offset = recovery_head;
     759
     760        /* Expand by more than we need, so we don't do it often. */
     761        *recovery_max_size = tdb_expand_adjust(tdb->map_size,
     762                                               *recovery_size,
     763                                               tdb->page_size)
     764                - sizeof(rec);
     765
     766        if (!tdb_add_off_t(recovery_head, sizeof(rec), &new_end) ||
     767            !tdb_add_off_t(new_end, *recovery_max_size, &new_end)) {
     768                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: "
     769                         "overflow recovery area\n"));
     770                return -1;
     771        }
     772
     773        if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
     774                                     new_end - tdb->transaction->old_map_size)
     775            == -1) {
    739776                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to create recovery area\n"));
    740777                return -1;
     
    742779
    743780        /* remap the file (if using mmap) */
    744         methods->tdb_oob(tdb, tdb->map_size + 1, 1);
     781        methods->tdb_oob(tdb, tdb->map_size, 1, 1);
    745782
    746783        /* we have to reset the old map size so that we don't try to expand the file
     
    751788           as the magic ptr in the recovery record has not been set */
    752789        CONVERT(recovery_head);
    753         if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD, 
     790        if (methods->tdb_write(tdb, TDB_RECOVERY_HEAD,
    754791                               &recovery_head, sizeof(tdb_off_t)) == -1) {
    755792                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
     
    768805  setup the recovery data that will be used on a crash during commit
    769806*/
    770 static int transaction_setup_recovery(struct tdb_context *tdb, 
     807static int transaction_setup_recovery(struct tdb_context *tdb,
    771808                                      tdb_off_t *magic_offset)
    772809{
     
    783820          check that the recovery area has enough space
    784821        */
    785         if (tdb_recovery_allocate(tdb, &recovery_size, 
     822        if (tdb_recovery_allocate(tdb, &recovery_size,
    786823                                  &recovery_offset, &recovery_max_size) == -1) {
    787824                return -1;
     
    901938
    902939static int _tdb_transaction_prepare_commit(struct tdb_context *tdb)
    903 {       
     940{
    904941        const struct tdb_methods *methods;
    905942
     
    926963        if (tdb->transaction->nesting != 0) {
    927964                return 0;
    928         }               
     965        }
    929966
    930967        /* check for a null transaction */
     
    959996        }
    960997
    961         if (!(tdb->flags & TDB_NOSYNC)) {
    962                 /* write the recovery data to the end of the file */
    963                 if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) {
    964                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n"));
    965                         _tdb_transaction_cancel(tdb);
    966                         return -1;
    967                 }
     998        /* write the recovery data to the end of the file */
     999        if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) {
     1000                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n"));
     1001                _tdb_transaction_cancel(tdb);
     1002                return -1;
    9681003        }
    9691004
     
    9721007        /* expand the file to the new size if needed */
    9731008        if (tdb->map_size != tdb->transaction->old_map_size) {
    974                 if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size, 
    975                                              tdb->map_size - 
     1009                if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size,
     1010                                             tdb->map_size -
    9761011                                             tdb->transaction->old_map_size) == -1) {
    9771012                        tdb->ecode = TDB_ERR_IO;
     
    9811016                }
    9821017                tdb->map_size = tdb->transaction->old_map_size;
    983                 methods->tdb_oob(tdb, tdb->map_size + 1, 1);
     1018                methods->tdb_oob(tdb, tdb->map_size, 1, 1);
    9841019        }
    9851020
     
    10851120                           run the crash recovery code */
    10861121                        tdb->methods = methods;
    1087                         tdb_transaction_recover(tdb); 
     1122                        tdb_transaction_recover(tdb);
    10881123
    10891124                        _tdb_transaction_cancel(tdb);
     
    10931128                }
    10941129                SAFE_FREE(tdb->transaction->blocks[i]);
    1095         } 
     1130        }
    10961131
    10971132        /* Do this before we drop lock or blocks. */
     
    11601195
    11611196        /* read the recovery record */
    1162         if (tdb->methods->tdb_read(tdb, recovery_head, &rec, 
     1197        if (tdb->methods->tdb_read(tdb, recovery_head, &rec,
    11631198                                   sizeof(rec), DOCONV()) == -1) {
    1164                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery record\n"));           
     1199                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery record\n"));
    11651200                tdb->ecode = TDB_ERR_IO;
    11661201                return -1;
     
    11821217        data = (unsigned char *)malloc(rec.data_len);
    11831218        if (data == NULL) {
    1184                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to allocate recovery data\n"));         
     1219                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to allocate recovery data\n"));
    11851220                tdb->ecode = TDB_ERR_OOM;
    11861221                return -1;
     
    11901225        if (tdb->methods->tdb_read(tdb, recovery_head + sizeof(rec), data,
    11911226                                   rec.data_len, 0) == -1) {
    1192                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery data\n"));             
     1227                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to read recovery data\n"));
    11931228                tdb->ecode = TDB_ERR_IO;
    11941229                return -1;
     
    12071242                if (tdb->methods->tdb_write(tdb, ofs, p+8, len) == -1) {
    12081243                        free(data);
    1209                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to recover %d bytes at offset %d\n", len, ofs));
     1244                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to recover %u bytes at offset %u\n", len, ofs));
    12101245                        tdb->ecode = TDB_ERR_IO;
    12111246                        return -1;
     
    12271262                        TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery head\n"));
    12281263                        tdb->ecode = TDB_ERR_IO;
    1229                         return -1;                     
     1264                        return -1;
    12301265                }
    12311266        }
     
    12361271                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_recover: failed to remove recovery magic\n"));
    12371272                tdb->ecode = TDB_ERR_IO;
    1238                 return -1;                     
     1273                return -1;
    12391274        }
    12401275
     
    12451280        }
    12461281
    1247         TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_recover: recovered %d byte database\n",
     1282        TDB_LOG((tdb, TDB_DEBUG_TRACE, "tdb_transaction_recover: recovered %u byte database\n",
    12481283                 recovery_eof));
    12491284
  • vendor/current/lib/tdb/common/traverse.c

    r986 r988  
    1  /* 
     1 /*
    22   Unix SMB/CIFS implementation.
    33
     
    3838
    3939        /* Lock each chain from the start one. */
    40         for (; tlock->hash < tdb->header.hash_size; tlock->hash++) {
     40        for (; tlock->hash < tdb->hash_size; tlock->hash++) {
    4141                if (!tlock->off && tlock->hash != 0) {
    4242                        /* this is an optimisation for the common case where
     
    6969                        */
    7070                        tdb->methods->next_hash_chain(tdb, &tlock->hash);
    71                         if (tlock->hash == tdb->header.hash_size) {
     71                        if (tlock->hash == tdb->hash_size) {
    7272                                continue;
    7373                        }
     
    118118                        current = tlock->off;
    119119                        tlock->off = rec->next;
    120                         if (!(tdb->read_only || tdb->traverse_read) && 
     120                        if (!(tdb->read_only || tdb->traverse_read) &&
    121121                            tdb_do_delete(tdb, current, rec) != 0)
    122122                                goto fail;
     
    141141   a non-zero return value from fn() indicates that the traversal should stop
    142142  */
    143 static int tdb_traverse_internal(struct tdb_context *tdb, 
     143static int tdb_traverse_internal(struct tdb_context *tdb,
    144144                                 tdb_traverse_func fn, void *private_data,
    145145                                 struct tdb_traverse_lock *tl)
     
    150150        tdb_off_t off;
    151151
    152         /* This was in the initializaton, above, but the IRIX compiler
     152        /* This was in the initialization, above, but the IRIX compiler
    153153         * did not like it.  crh
    154154         */
     
    166166                count++;
    167167                /* now read the full record */
    168                 key.dptr = tdb_alloc_read(tdb, tl->off + sizeof(rec), 
     168                key.dptr = tdb_alloc_read(tdb, tl->off + sizeof(rec),
    169169                                          rec.key_len + rec.data_len);
    170170                if (!key.dptr) {
     
    211211
    212212/*
    213   a write style traverse - temporarily marks the db read only
     213  a read style traverse - temporarily marks the db read only
    214214*/
    215 _PUBLIC_ int tdb_traverse_read(struct tdb_context *tdb, 
     215_PUBLIC_ int tdb_traverse_read(struct tdb_context *tdb,
    216216                      tdb_traverse_func fn, void *private_data)
    217217{
     
    240240
    241241  WARNING: The data buffer given to the callback fn does NOT meet the
    242   alignment restrictions malloc gives you.
     242  alignment guarantees malloc gives you.
    243243*/
    244 _PUBLIC_ int tdb_traverse(struct tdb_context *tdb, 
     244_PUBLIC_ int tdb_traverse(struct tdb_context *tdb,
    245245                 tdb_traverse_func fn, void *private_data)
    246246{
    247247        struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK };
     248        enum tdb_lock_flags lock_flags;
    248249        int ret;
    249250
     
    252253        }
    253254
    254         if (tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_WAIT)) {
     255        lock_flags = TDB_LOCK_WAIT;
     256
     257        if (tdb->allrecord_lock.count != 0) {
     258                /*
     259                 * This avoids a deadlock between tdb_lockall() and
     260                 * tdb_traverse(). See
     261                 * https://bugzilla.samba.org/show_bug.cgi?id=11381
     262                 */
     263                lock_flags = TDB_LOCK_NOWAIT;
     264        }
     265
     266        if (tdb_transaction_lock(tdb, F_WRLCK, lock_flags)) {
    255267                return -1;
    256268        }
  • vendor/current/lib/tdb/docs/README

    r986 r988  
    6565   possible tdb_flags are:
    6666    TDB_CLEAR_IF_FIRST - clear database if we are the only one with it open
    67     TDB_INTERNAL - don't use a file, instaed store the data in
     67    TDB_INTERNAL - don't use a file, instead store the data in
    6868                   memory. The filename is ignored in this case.
    6969    TDB_NOLOCK - don't do any locking
  • vendor/current/lib/tdb/doxy.config

    r986 r988  
    660660# for example use the pattern */test/*
    661661
    662 EXCLUDE_PATTERNS       = */.git/* \
    663                          */.svn/* \
    664                          */cmake/* \
    665                          */build/*
     662EXCLUDE_PATTERNS       = */.git/*
    666663
    667664# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
  • vendor/current/lib/tdb/include/tdb.h

    r986 r988  
    3232
    3333#include <signal.h>
     34#include <stdbool.h>
    3435
    3536/**
     
    8182#define TDB_DISALLOW_NESTING 1024 /** Disallow transactions to nest */
    8283#define TDB_INCOMPATIBLE_HASH 2048 /** Better hashing: can't be opened by tdb < 1.2.6. */
     84#define TDB_MUTEX_LOCKING 4096 /** optimized locking using robust mutexes if supported,
     85                                   only with tdb >= 1.3.0 and TDB_CLEAR_IF_FIRST
     86                                   after checking tdb_runtime_check_for_robust_mutexes() */
    8387
    8488/** The tdb error codes */
     
    133137 *                         TDB_CLEAR_IF_FIRST - Clear database if we are the
    134138 *                                              only one with it open\n
    135  *                         TDB_INTERNAL - Don't use a file, instaed store the
     139 *                         TDB_INTERNAL - Don't use a file, instead store the
    136140 *                                        data in memory. The filename is
    137141 *                                        ignored in this case.\n
     
    144148 *                         TDB_ALLOW_NESTING - Allow transactions to nest.\n
    145149 *                         TDB_DISALLOW_NESTING - Disallow transactions to nest.\n
     150 *                         TDB_INCOMPATIBLE_HASH - Better hashing: can't be opened by tdb < 1.2.6.\n
     151 *                         TDB_MUTEX_LOCKING - Optimized locking using robust mutexes if supported,
     152 *                                             can't be opened by tdb < 1.3.0.
     153 *                                             Only valid in combination with TDB_CLEAR_IF_FIRST
     154 *                                             after checking tdb_runtime_check_for_robust_mutexes()\n
    146155 *
    147156 * @param[in]  open_flags Flags for the open(2) function.
     
    169178 *                         TDB_CLEAR_IF_FIRST - Clear database if we are the
    170179 *                                              only one with it open\n
    171  *                         TDB_INTERNAL - Don't use a file, instaed store the
     180 *                         TDB_INTERNAL - Don't use a file, instead store the
    172181 *                                        data in memory. The filename is
    173182 *                                        ignored in this case.\n
     
    180189 *                         TDB_ALLOW_NESTING - Allow transactions to nest.\n
    181190 *                         TDB_DISALLOW_NESTING - Disallow transactions to nest.\n
     191 *                         TDB_INCOMPATIBLE_HASH - Better hashing: can't be opened by tdb < 1.2.6.\n
     192 *                         TDB_MUTEX_LOCKING - Optimized locking using robust mutexes if supported,
     193 *                                             can't be opened by tdb < 1.3.0.
     194 *                                             Only valid in combination with TDB_CLEAR_IF_FIRST
     195 *                                             after checking tdb_runtime_check_for_robust_mutexes()\n
    182196 *
    183197 * @param[in]  open_flags Flags for the open(2) function.
     
    213227 * pointer from our parent and to re-establish locks.
    214228 *
    215  * @param[in]  tdb      The database to reopen.
     229 * @param[in]  tdb      The database to reopen. It will be free'd on error!
    216230 *
    217231 * @return              0 on success, -1 on error.
     232 *
     233 * @note Don't call tdb_error() after this function cause the tdb context will
     234 *       be freed on error.
    218235 */
    219236int tdb_reopen(struct tdb_context *tdb);
     
    362379 * @brief Close a database.
    363380 *
    364  * @param[in]  tdb      The database to close.
     381 * @param[in]  tdb      The database to close. The context will be free'd.
    365382 *
    366383 * @return              0 for success, -1 on error.
     384 *
     385 * @note Don't call tdb_error() after this function cause the tdb context will
     386 *       be freed on error.
    367387 */
    368388int tdb_close(struct tdb_context *tdb);
     
    397417 * @brief Traverse the entire database.
    398418 *
    399  * While travering the function fn(tdb, key, data, state) is called on each
     419 * While traversing the function fn(tdb, key, data, state) is called on each
    400420 * element. If fn is NULL then it is not called. A non-zero return value from
    401421 * fn() indicates that the traversal should stop. Traversal callbacks may not
     
    772792 *
    773793 * This only works if the tdb has been opened using the TDB_SEQNUM flag or
    774  * enabled useing tdb_enable_seqnum().
     794 * enabled using tdb_enable_seqnum().
    775795 *
    776796 * @param[in]  tdb      The database to increment the sequence number.
     
    814834              int (*check) (TDB_DATA key, TDB_DATA data, void *private_data),
    815835              void *private_data);
     836
     837/**
     838 * @brief Dump all possible records in a corrupt database.
     839 *
     840 * This is the only way to get data out of a database where tdb_check() fails.
     841 * It will call walk() with anything which looks like a database record; this
     842 * may well include invalid, incomplete or duplicate records.
     843 *
     844 * @param[in]  tdb      The database to check.
     845 *
     846 * @param[in]  walk     The walk function to use.
     847 *
     848 * @param[in]  private_data the private data to pass to the walk function.
     849 *
     850 * @return              0 on success, -1 on error with error code set.
     851 *
     852 * @see tdb_error()
     853 * @see tdb_errorstr()
     854 */
     855int tdb_rescue(struct tdb_context *tdb,
     856               void (*walk) (TDB_DATA key, TDB_DATA data, void *private_data),
     857               void *private_data);
     858
     859/**
     860 * @brief Check if support for TDB_MUTEX_LOCKING is available at runtime.
     861 *
     862 * On some systems the API for pthread_mutexattr_setrobust() is not available.
     863 * On other systems there are some bugs in the interaction between glibc and
     864 * the linux kernel.
     865 *
     866 * This function provides a runtime check if robust mutexes are really
     867 * available.
     868 *
     869 * This needs to be called and return true before TDB_MUTEX_LOCKING
     870 * can be used at runtime.
     871 *
     872 * @note This calls fork(), but the SIGCHILD handling should be transparent.
     873 *
     874 * @return              true if supported, false otherwise.
     875 *
     876 * @see TDB_MUTEX_LOCKING
     877 */
     878bool tdb_runtime_check_for_robust_mutexes(void);
    816879
    817880/* @} ******************************************************************/
     
    822885int tdb_chainunlock(struct tdb_context *tdb, TDB_DATA key);
    823886int tdb_chainlock_read(struct tdb_context *tdb, TDB_DATA key);
     887int tdb_chainlock_read_nonblock(struct tdb_context *tdb, TDB_DATA key);
    824888int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key);
    825889int tdb_chainlock_mark(struct tdb_context *tdb, TDB_DATA key);
  • vendor/current/lib/tdb/man/tdbbackup.8.xml

    r740 r988  
    22<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
    33<refentry id="tdbbackup.8">
     4<refentryinfo><date>2015-04-25</date></refentryinfo>
    45
    56<refmeta>
     
    2324                <arg choice="opt">-v</arg>
    2425                <arg choice="opt">-h</arg>
     26                <arg choice="opt">-l</arg>
    2527        </cmdsynopsis>
    2628</refsynopsisdiv>
     
    3436        <para><command>tdbbackup</command> is a tool that may be used to backup samba .tdb
    3537        files. This tool may also be used to verify the integrity of the .tdb files prior
    36         to samba startup or during normal operation. If it finds file damage and it finds 
    37         a prior backup the backup file will be restored. 
     38        to samba startup or during normal operation. If it finds file damage and it finds
     39        a prior backup the backup file will be restored.
    3840        </para>
    3941</refsect1>
     
    5557                <term>-s suffix</term>
    5658                <listitem><para>
    57                 The <command>-s</command> option allows the adminisistrator to specify a file
     59                The <command>-s</command> option allows the administrator to specify a file
    5860                backup extension. This way it is possible to keep a history of tdb backup
    5961                files by using a new suffix for each backup.
     
    6466                <term>-v</term>
    6567                <listitem><para>
    66                 The <command>-v</command> will check the database for damages (currupt data)
     68                The <command>-v</command> will check the database for damages (corrupt data)
    6769                which if detected causes the backup to be restored.
     70                </para></listitem>
     71                </varlistentry>
     72
     73                <varlistentry>
     74                <term>-l</term>
     75                <listitem><para>
     76                This options disables any locking, by passing TDB_NOLOCK
     77                to tdb_open_ex(). Only use this for database files which
     78                are not used by any other process! And also only if it is otherwise not
     79                possible to open the database, e.g. databases which were created with
     80                mutex locking.
    6881                </para></listitem>
    6982                </varlistentry>
     
    129142        Samba is now developed by the Samba Team as an Open Source project similar to the way
    130143        the Linux kernel is developed.
    131         </para> 
     144        </para>
    132145
    133146        <para>The tdbbackup man page was written by John H Terpstra.</para>
  • vendor/current/lib/tdb/man/tdbdump.8.xml

    r740 r988  
    22<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
    33<refentry id="tdbdump.8">
     4<refentryinfo><date>2015-04-25</date></refentryinfo>
    45
    56<refmeta>
     
    2021        <cmdsynopsis>
    2122                <command>tdbdump</command>
     23                <arg choice="opt">-k <replaceable>keyname</replaceable></arg>
     24                <arg choice="opt">-e</arg>
     25                <arg choice="opt">-h</arg>
    2226                <arg choice="req">filename</arg>
    2327        </cmdsynopsis>
     
    3034        <manvolnum>1</manvolnum></citerefentry> suite.</para>
    3135
    32         <para><command>tdbdump</command> is a very simple utility that 'dumps' the 
    33                 contents of a TDB (Trivial DataBase) file to standard output in a 
     36        <para><command>tdbdump</command> is a very simple utility that 'dumps' the
     37                contents of a TDB (Trivial DataBase) file to standard output in a
    3438                human-readable format.
    3539        </para>
    3640
    37         <para>This tool can be used when debugging problems with TDB files. It is 
     41        <para>This tool can be used when debugging problems with TDB files. It is
    3842                intended for those who are somewhat familiar with Samba internals.
    3943        </para>
    4044</refsect1>
    4145
     46<refsect1>
     47        <title>OPTIONS</title>
     48
     49        <variablelist>
     50
     51                <varlistentry>
     52                <term>-h</term>
     53                <listitem><para>
     54                Get help information.
     55                </para></listitem>
     56                </varlistentry>
     57
     58                <varlistentry>
     59                <term>-k <replaceable>keyname</replaceable></term>
     60                <listitem><para>
     61                The <command>-k</command> option restricts dumping to a single key, if found.
     62                </para> </listitem>
     63                </varlistentry>
     64
     65                <varlistentry>
     66                <term>-e</term>
     67                <listitem><para>
     68                The <command>-e</command> tries to dump out from a corrupt database.  Naturally, such a dump is unreliable, at best.
     69                </para></listitem>
     70                </varlistentry>
     71
     72        </variablelist>
     73</refsect1>
    4274
    4375<refsect1>
     
    5486        Samba is now developed by the Samba Team as an Open Source project similar to the way
    5587        the Linux kernel is developed.
    56         </para> 
     88        </para>
    5789
    5890        <para>The tdbdump man page was written by Jelmer Vernooij.</para>
  • vendor/current/lib/tdb/man/tdbrestore.8.xml

    r740 r988  
    22<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
    33<refentry id="tdbrestore.8">
     4<refentryinfo><date>2015-04-25</date></refentryinfo>
    45
    56<refmeta>
  • vendor/current/lib/tdb/man/tdbtool.8.xml

    r740 r988  
    22<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
    33<refentry id="tdbtool.8">
     4<refentryinfo><date>2015-04-25</date></refentryinfo>
    45
    56<refmeta>
     
    89        <refmiscinfo class="source">Samba</refmiscinfo>
    910        <refmiscinfo class="manual">System Administration tools</refmiscinfo>
    10         <refmiscinfo class="version">3.6</refmiscinfo>
     11        <refmiscinfo class="version">4.0</refmiscinfo>
    1112</refmeta>
    1213
     
    2526        <cmdsynopsis>
    2627                <command>tdbtool</command>
     28                <arg choice="opt">-l</arg>
    2729                <arg choice="plain">
    2830                <replaceable>TDBFILE</replaceable>
     
    4951</refsect1>
    5052
     53<refsect1>
     54        <title>OPTIONS</title>
     55
     56        <variablelist>
     57
     58                <varlistentry>
     59                <term>-l</term>
     60                <listitem><para>
     61                This options disables any locking, by passing TDB_NOLOCK
     62                to tdb_open_ex(). Only use this for database files which
     63                are not used by any other process! And also only if it is otherwise not
     64                possible to open the database, e.g. databases which were created with
     65                mutex locking.
     66                </para></listitem>
     67                </varlistentry>
     68
     69        </variablelist>
     70</refsect1>
     71
     72
    5173
    5274<refsect1>
     
    123145                <replaceable>TDBFILE</replaceable>
    124146                </term>
    125                 <listitem><para>Move a record from the 
     147                <listitem><para>Move a record from the
    126148                current database into <replaceable>TDBFILE</replaceable>.
    127149                </para></listitem>
     
    197219                </term>
    198220                <listitem><para>Check the integrity of the current database.
     221                </para></listitem>
     222                </varlistentry>
     223
     224                <varlistentry>
     225                <term>
     226                <option>repack</option>
     227                </term>
     228                <listitem><para>Repack a database using a temporary file to remove fragmentation.
    199229                </para></listitem>
    200230                </varlistentry>
     
    221251<refsect1>
    222252        <title>VERSION</title>
    223         <para>This man page is correct for version 3.0.25 of the Samba suite.</para>
     253        <para>This man page is correct for version 3.6 of the Samba suite.</para>
    224254</refsect1>
    225255
  • vendor/current/lib/tdb/pytdb.c

    r986 r988  
    2929#include "system/filesys.h"
    3030
    31 #ifndef Py_RETURN_NONE
    32 #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
    33 #endif
    34 
    3531/* Include tdb headers */
    3632#include <tdb.h>
     33
     34#if PY_MAJOR_VERSION >= 3
     35#define PyStr_FromString PyUnicode_FromString
     36#define PyStr_FromFormat PyUnicode_FromFormat
     37#define PyInt_FromLong PyLong_FromLong
     38#define PyInt_Check PyLong_Check
     39#define PyInt_AsLong PyLong_AsLong
     40#define Py_TPFLAGS_HAVE_ITER 0
     41#else
     42#define PyStr_FromString PyString_FromString
     43#define PyStr_FromFormat PyString_FromFormat
     44#endif
    3745
    3846typedef struct {
     
    4250} PyTdbObject;
    4351
    44 staticforward PyTypeObject PyTdb;
     52static PyTypeObject PyTdb;
    4553
    4654static void PyErr_SetTDBError(TDB_CONTEXT *tdb)
     
    5058}
    5159
    52 static TDB_DATA PyString_AsTDB_DATA(PyObject *data)
     60static TDB_DATA PyBytes_AsTDB_DATA(PyObject *data)
    5361{
    5462        TDB_DATA ret;
    55         ret.dptr = (unsigned char *)PyString_AsString(data);
    56         ret.dsize = PyString_Size(data);
     63        ret.dptr = (unsigned char *)PyBytes_AsString(data);
     64        ret.dsize = PyBytes_Size(data);
    5765        return ret;
    5866}
    5967
    60 static PyObject *PyString_FromTDB_DATA(TDB_DATA data)
     68static PyObject *PyBytes_FromTDB_DATA(TDB_DATA data)
    6169{
    6270        if (data.dptr == NULL && data.dsize == 0) {
    6371                Py_RETURN_NONE;
    6472        } else {
    65                 PyObject *ret = PyString_FromStringAndSize((const char *)data.dptr,
    66                                                                                                    data.dsize);
     73                PyObject *ret = PyBytes_FromStringAndSize((const char *)data.dptr,
     74                                                                                                  data.dsize);
    6775                free(data.dptr);
    6876                return ret;
     
    7684        }
    7785
     86#define PyErr_TDB_RAISE_IF_CLOSED(self) \
     87        if (self->closed) {                                             \
     88                PyErr_SetObject(PyExc_RuntimeError,                             \
     89                                Py_BuildValue("(i,s)", TDB_ERR_IO, "Database is already closed")); \
     90                return NULL;                                            \
     91        }
     92
     93#define PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self) \
     94        if (self->closed) {                                             \
     95                PyErr_SetObject(PyExc_RuntimeError,                             \
     96                                Py_BuildValue("(i,s)", TDB_ERR_IO, "Database is already closed")); \
     97                return -1;                                              \
     98        }
     99
    78100static PyObject *py_tdb_open(PyTypeObject *type, PyObject *args, PyObject *kwargs)
    79101{
     
    82104        TDB_CONTEXT *ctx;
    83105        PyTdbObject *ret;
    84         const char *kwnames[] = { "name", "hash_size", "tdb_flags", "flags", "mode", NULL };
    85 
    86         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|siiii", (char **)kwnames, &name, &hash_size, &tdb_flags, &flags, &mode))
     106        const char *_kwnames[] = { "name", "hash_size", "tdb_flags", "flags", "mode", NULL };
     107        char **kwnames = discard_const_p(char *, _kwnames);
     108
     109        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|siiii", kwnames, &name, &hash_size, &tdb_flags, &flags, &mode))
    87110                return NULL;
    88111
     
    110133static PyObject *obj_transaction_cancel(PyTdbObject *self)
    111134{
    112         int ret = tdb_transaction_cancel(self->ctx);
     135        int ret;
     136
     137        PyErr_TDB_RAISE_IF_CLOSED(self);
     138
     139        ret = tdb_transaction_cancel(self->ctx);
    113140        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
    114141        Py_RETURN_NONE;
     
    117144static PyObject *obj_transaction_commit(PyTdbObject *self)
    118145{
    119         int ret = tdb_transaction_commit(self->ctx);
     146        int ret;
     147        PyErr_TDB_RAISE_IF_CLOSED(self);
     148        ret = tdb_transaction_commit(self->ctx);
    120149        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
    121150        Py_RETURN_NONE;
     
    124153static PyObject *obj_transaction_prepare_commit(PyTdbObject *self)
    125154{
    126         int ret = tdb_transaction_prepare_commit(self->ctx);
     155        int ret;
     156        PyErr_TDB_RAISE_IF_CLOSED(self);
     157        ret = tdb_transaction_prepare_commit(self->ctx);
    127158        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
    128159        Py_RETURN_NONE;
     
    131162static PyObject *obj_transaction_start(PyTdbObject *self)
    132163{
    133         int ret = tdb_transaction_start(self->ctx);
     164        int ret;
     165        PyErr_TDB_RAISE_IF_CLOSED(self);
     166        ret = tdb_transaction_start(self->ctx);
    134167        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
    135168        Py_RETURN_NONE;
     
    138171static PyObject *obj_reopen(PyTdbObject *self)
    139172{
    140         int ret = tdb_reopen(self->ctx);
    141         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     173        int ret;
     174        PyErr_TDB_RAISE_IF_CLOSED(self);
     175        ret = tdb_reopen(self->ctx);
     176        if (ret != 0) {
     177                self->closed = true;
     178                PyErr_SetObject(PyExc_RuntimeError,
     179                                Py_BuildValue("(i,s)",
     180                                              TDB_ERR_IO,
     181                                              "Failed to reopen database"));
     182                return NULL;
     183        }
    142184        Py_RETURN_NONE;
    143185}
     
    145187static PyObject *obj_lockall(PyTdbObject *self)
    146188{
    147         int ret = tdb_lockall(self->ctx);
     189        int ret;
     190        PyErr_TDB_RAISE_IF_CLOSED(self);
     191        ret = tdb_lockall(self->ctx);
    148192        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
    149193        Py_RETURN_NONE;
     
    152196static PyObject *obj_unlockall(PyTdbObject *self)
    153197{
    154         int ret = tdb_unlockall(self->ctx);
     198        int ret;
     199        PyErr_TDB_RAISE_IF_CLOSED(self);
     200        ret = tdb_unlockall(self->ctx);
    155201        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
    156202        Py_RETURN_NONE;
     
    159205static PyObject *obj_lockall_read(PyTdbObject *self)
    160206{
    161         int ret = tdb_lockall_read(self->ctx);
     207        int ret;
     208        PyErr_TDB_RAISE_IF_CLOSED(self);
     209        ret = tdb_lockall_read(self->ctx);
    162210        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
    163211        Py_RETURN_NONE;
     
    178226        ret = tdb_close(self->ctx);
    179227        self->closed = true;
    180         PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     228        if (ret != 0) {
     229                PyErr_SetObject(PyExc_RuntimeError,
     230                                Py_BuildValue("(i,s)",
     231                                              TDB_ERR_IO,
     232                                              "Failed to close database"));
     233                return NULL;
     234        }
    181235        Py_RETURN_NONE;
    182236}
     
    186240        TDB_DATA key;
    187241        PyObject *py_key;
     242
     243        PyErr_TDB_RAISE_IF_CLOSED(self);
     244
    188245        if (!PyArg_ParseTuple(args, "O", &py_key))
    189246                return NULL;
    190247
    191         key = PyString_AsTDB_DATA(py_key);
    192 
    193         return PyString_FromTDB_DATA(tdb_fetch(self->ctx, key));
     248        key = PyBytes_AsTDB_DATA(py_key);
     249        if (!key.dptr)
     250                return NULL;
     251
     252        return PyBytes_FromTDB_DATA(tdb_fetch(self->ctx, key));
    194253}
    195254
     
    199258        PyObject *py_key, *py_data;
    200259        int ret;
     260
     261        PyErr_TDB_RAISE_IF_CLOSED(self);
     262
    201263        if (!PyArg_ParseTuple(args, "OO", &py_key, &py_data))
    202264                return NULL;
    203265
    204         key = PyString_AsTDB_DATA(py_key);
    205         data = PyString_AsTDB_DATA(py_data);
     266        key = PyBytes_AsTDB_DATA(py_key);
     267        if (!key.dptr)
     268                return NULL;
     269        data = PyBytes_AsTDB_DATA(py_data);
     270        if (!data.dptr)
     271                return NULL;
    206272
    207273        ret = tdb_append(self->ctx, key, data);
     
    212278static PyObject *obj_firstkey(PyTdbObject *self)
    213279{
    214         return PyString_FromTDB_DATA(tdb_firstkey(self->ctx));
     280        PyErr_TDB_RAISE_IF_CLOSED(self);
     281
     282        return PyBytes_FromTDB_DATA(tdb_firstkey(self->ctx));
    215283}
    216284
     
    219287        TDB_DATA key;
    220288        PyObject *py_key;
     289        PyErr_TDB_RAISE_IF_CLOSED(self);
     290
    221291        if (!PyArg_ParseTuple(args, "O", &py_key))
    222292                return NULL;
    223293
    224         key = PyString_AsTDB_DATA(py_key);
     294        key = PyBytes_AsTDB_DATA(py_key);
     295        if (!key.dptr)
     296                return NULL;
    225297       
    226         return PyString_FromTDB_DATA(tdb_nextkey(self->ctx, key));
     298        return PyBytes_FromTDB_DATA(tdb_nextkey(self->ctx, key));
    227299}
    228300
     
    232304        PyObject *py_key;
    233305        int ret;
     306        PyErr_TDB_RAISE_IF_CLOSED(self);
     307
    234308        if (!PyArg_ParseTuple(args, "O", &py_key))
    235309                return NULL;
    236310
    237         key = PyString_AsTDB_DATA(py_key);
     311        key = PyBytes_AsTDB_DATA(py_key);
     312        if (!key.dptr)
     313                return NULL;
    238314        ret = tdb_delete(self->ctx, key);
    239315        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
     
    241317}
    242318
     319static int obj_contains(PyTdbObject *self, PyObject *py_key)
     320{
     321        TDB_DATA key;
     322        int ret;
     323        PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
     324
     325        key = PyBytes_AsTDB_DATA(py_key);
     326        if (!key.dptr) {
     327                PyErr_BadArgument();
     328                return -1;
     329        }
     330        ret = tdb_exists(self->ctx, key);
     331        if (ret)
     332                return 1;
     333        return 0;
     334}
     335
     336#if PY_MAJOR_VERSION < 3
    243337static PyObject *obj_has_key(PyTdbObject *self, PyObject *args)
    244338{
    245         TDB_DATA key;
    246339        int ret;
    247340        PyObject *py_key;
     341        PyErr_TDB_RAISE_IF_CLOSED(self);
     342
    248343        if (!PyArg_ParseTuple(args, "O", &py_key))
    249344                return NULL;
    250345
    251         key = PyString_AsTDB_DATA(py_key);
    252         ret = tdb_exists(self->ctx, key);
    253         if (ret != TDB_ERR_NOEXIST) {
    254                 PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
    255         }
    256 
    257         return (ret == TDB_ERR_NOEXIST)?Py_False:Py_True;
    258 }
     346        ret = obj_contains(self, py_key);
     347        if (ret == -1)
     348                return NULL;
     349        if (ret)
     350                Py_RETURN_TRUE;
     351        Py_RETURN_FALSE;
     352
     353}
     354#endif
    259355
    260356static PyObject *obj_store(PyTdbObject *self, PyObject *args)
     
    265361        PyObject *py_key, *py_value;
    266362
     363        PyErr_TDB_RAISE_IF_CLOSED(self);
     364
    267365        if (!PyArg_ParseTuple(args, "OO|i", &py_key, &py_value, &flag))
    268366                return NULL;
    269367
    270         key = PyString_AsTDB_DATA(py_key);
    271         value = PyString_AsTDB_DATA(py_value);
     368        key = PyBytes_AsTDB_DATA(py_key);
     369        if (!key.dptr)
     370                return NULL;
     371        value = PyBytes_AsTDB_DATA(py_value);
     372        if (!value.dptr)
     373                return NULL;
    272374
    273375        ret = tdb_store(self->ctx, key, value, flag);
     
    280382        unsigned flags;
    281383
     384        PyErr_TDB_RAISE_IF_CLOSED(self);
     385
    282386        if (!PyArg_ParseTuple(args, "I", &flags))
    283387                return NULL;
     
    290394{
    291395        unsigned flags;
     396
     397        PyErr_TDB_RAISE_IF_CLOSED(self);
    292398
    293399        if (!PyArg_ParseTuple(args, "I", &flags))
     
    312418        current = self->current;
    313419        self->current = tdb_nextkey(self->iteratee->ctx, self->current);
    314         ret = PyString_FromTDB_DATA(current);
     420        ret = PyBytes_FromTDB_DATA(current);
    315421        return ret;
    316422}
     
    335441        PyTdbIteratorObject *ret;       
    336442
     443        PyErr_TDB_RAISE_IF_CLOSED(self);
     444
    337445        ret = PyObject_New(PyTdbIteratorObject, &PyTdbIterator);
    338446        if (!ret)
     
    346454static PyObject *obj_clear(PyTdbObject *self)
    347455{
    348         int ret = tdb_wipe_all(self->ctx);
     456        int ret;
     457        PyErr_TDB_RAISE_IF_CLOSED(self);
     458        ret = tdb_wipe_all(self->ctx);
    349459        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
    350460        Py_RETURN_NONE;
     
    353463static PyObject *obj_repack(PyTdbObject *self)
    354464{
    355         int ret = tdb_repack(self->ctx);
     465        int ret;
     466        PyErr_TDB_RAISE_IF_CLOSED(self);
     467        ret = tdb_repack(self->ctx);
    356468        PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
    357469        Py_RETURN_NONE;
     
    360472static PyObject *obj_enable_seqnum(PyTdbObject *self)
    361473{
     474        PyErr_TDB_RAISE_IF_CLOSED(self);
    362475        tdb_enable_seqnum(self->ctx);
    363476        Py_RETURN_NONE;
     
    366479static PyObject *obj_increment_seqnum_nonblock(PyTdbObject *self)
    367480{
     481        PyErr_TDB_RAISE_IF_CLOSED(self);
    368482        tdb_increment_seqnum_nonblock(self->ctx);
    369483        Py_RETURN_NONE;
     
    395509        { "firstkey", (PyCFunction)obj_firstkey, METH_NOARGS, "S.firstkey() -> data\n"
    396510                "Return the first key in this database." },
    397         { "nextkey", (PyCFunction)obj_nextkey, METH_NOARGS, "S.nextkey(key) -> data\n"
     511        { "nextkey", (PyCFunction)obj_nextkey, METH_VARARGS, "S.nextkey(key) -> data\n"
    398512                "Return the next key in this database." },
    399513        { "delete", (PyCFunction)obj_delete, METH_VARARGS, "S.delete(key) -> None\n"
    400514                "Delete an entry." },
     515#if PY_MAJOR_VERSION < 3
    401516        { "has_key", (PyCFunction)obj_has_key, METH_VARARGS, "S.has_key(key) -> None\n"
    402517                "Check whether key exists in this database." },
     518#endif
    403519        { "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, flag=REPLACE) -> None"
    404520                "Store data." },
    405521        { "add_flags", (PyCFunction)obj_add_flags, METH_VARARGS, "S.add_flags(flags) -> None" },
    406522        { "remove_flags", (PyCFunction)obj_remove_flags, METH_VARARGS, "S.remove_flags(flags) -> None" },
     523#if PY_MAJOR_VERSION >= 3
     524        { "keys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" },
     525#else
    407526        { "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" },
     527#endif
    408528        { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n"
    409529                "Wipe the entire database." },
     
    419539static PyObject *obj_get_hash_size(PyTdbObject *self, void *closure)
    420540{
     541        PyErr_TDB_RAISE_IF_CLOSED(self);
    421542        return PyInt_FromLong(tdb_hash_size(self->ctx));
    422543}
     
    424545static int obj_set_max_dead(PyTdbObject *self, PyObject *max_dead, void *closure)
    425546{
     547        PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
    426548        if (!PyInt_Check(max_dead))
    427549                return -1;
     
    432554static PyObject *obj_get_map_size(PyTdbObject *self, void *closure)
    433555{
     556        PyErr_TDB_RAISE_IF_CLOSED(self);
    434557        return PyInt_FromLong(tdb_map_size(self->ctx));
    435558}
     
    437560static PyObject *obj_get_freelist_size(PyTdbObject *self, void *closure)
    438561{
     562        PyErr_TDB_RAISE_IF_CLOSED(self);
    439563        return PyInt_FromLong(tdb_freelist_size(self->ctx));
    440564}
     
    442566static PyObject *obj_get_flags(PyTdbObject *self, void *closure)
    443567{
     568        PyErr_TDB_RAISE_IF_CLOSED(self);
    444569        return PyInt_FromLong(tdb_get_flags(self->ctx));
    445570}
     
    447572static PyObject *obj_get_filename(PyTdbObject *self, void *closure)
    448573{
    449         return PyString_FromString(tdb_name(self->ctx));
     574        PyErr_TDB_RAISE_IF_CLOSED(self);
     575        return PyBytes_FromString(tdb_name(self->ctx));
    450576}
    451577
    452578static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure)
    453579{
     580        PyErr_TDB_RAISE_IF_CLOSED(self);
    454581        return PyInt_FromLong(tdb_get_seqnum(self->ctx));
    455582}
    456583
     584static PyObject *obj_get_text(PyTdbObject *self, void *closure)
     585{
     586        PyObject *mod, *cls, *inst;
     587        mod = PyImport_ImportModule("_tdb_text");
     588        if (mod == NULL)
     589                return NULL;
     590        cls = PyObject_GetAttrString(mod, "TdbTextWrapper");
     591        if (cls == NULL) {
     592                Py_DECREF(mod);
     593                return NULL;
     594        }
     595        inst = PyObject_CallFunction(cls, discard_const_p(char, "O"), self);
     596        Py_DECREF(mod);
     597        Py_DECREF(cls);
     598        return inst;
     599}
    457600
    458601static PyGetSetDef tdb_object_getsetters[] = {
    459         { (char *)"hash_size", (getter)obj_get_hash_size, NULL, NULL },
    460         { (char *)"map_size", (getter)obj_get_map_size, NULL, NULL },
    461         { (char *)"freelist_size", (getter)obj_get_freelist_size, NULL, NULL },
    462         { (char *)"flags", (getter)obj_get_flags, NULL, NULL },
    463         { (char *)"max_dead", NULL, (setter)obj_set_max_dead, NULL },
    464         { (char *)"filename", (getter)obj_get_filename, NULL, (char *)"The filename of this TDB file."},
    465         { (char *)"seqnum", (getter)obj_get_seqnum, NULL, NULL },
     602        { discard_const_p(char, "hash_size"),
     603          (getter)obj_get_hash_size, NULL, NULL },
     604        { discard_const_p(char, "map_size"),
     605          (getter)obj_get_map_size, NULL, NULL },
     606        { discard_const_p(char, "freelist_size"),
     607          (getter)obj_get_freelist_size, NULL, NULL },
     608        { discard_const_p(char, "flags"),
     609          (getter)obj_get_flags, NULL, NULL },
     610        { discard_const_p(char, "max_dead"),
     611          NULL, (setter)obj_set_max_dead, NULL },
     612        { discard_const_p(char, "filename"),
     613          (getter)obj_get_filename, NULL,
     614          discard_const_p(char, "The filename of this TDB file.") },
     615        { discard_const_p(char, "seqnum"),
     616          (getter)obj_get_seqnum, NULL, NULL },
     617        { discard_const_p(char, "text"),
     618          (getter)obj_get_text, NULL, NULL },
    466619        { NULL }
    467620};
     
    469622static PyObject *tdb_object_repr(PyTdbObject *self)
    470623{
     624        PyErr_TDB_RAISE_IF_CLOSED(self);
    471625        if (tdb_get_flags(self->ctx) & TDB_INTERNAL) {
    472                 return PyString_FromString("Tdb(<internal>)");
     626                return PyStr_FromString("Tdb(<internal>)");
    473627        } else {
    474                 return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx));
     628                return PyStr_FromFormat("Tdb('%s')", tdb_name(self->ctx));
    475629        }
    476630}
     
    480634        if (!self->closed)
    481635                tdb_close(self->ctx);
    482         self->ob_type->tp_free(self);
     636        Py_TYPE(self)->tp_free(self);
    483637}
    484638
     
    486640{
    487641        TDB_DATA tkey, val;
    488         if (!PyString_Check(key)) {
    489                 PyErr_SetString(PyExc_TypeError, "Expected string as key");
    490                 return NULL;
    491         }
    492 
    493         tkey.dptr = (unsigned char *)PyString_AsString(key);
    494         tkey.dsize = PyString_Size(key);
     642        PyErr_TDB_RAISE_IF_CLOSED(self);
     643        if (!PyBytes_Check(key)) {
     644                PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
     645                return NULL;
     646        }
     647
     648        tkey.dptr = (unsigned char *)PyBytes_AsString(key);
     649        tkey.dsize = PyBytes_Size(key);
    495650
    496651        val = tdb_fetch(self->ctx, tkey);
    497652        if (val.dptr == NULL) {
    498                 PyErr_SetString(PyExc_KeyError, "No such TDB entry");
     653                /*
     654                 * if the key doesn't exist raise KeyError(key) to be
     655                 * consistent with python dict
     656                 */
     657                PyErr_SetObject(PyExc_KeyError, key);
    499658                return NULL;
    500659        } else {
    501                 return PyString_FromTDB_DATA(val);
     660                return PyBytes_FromTDB_DATA(val);
    502661        }
    503662}
     
    507666        TDB_DATA tkey, tval;
    508667        int ret;
    509         if (!PyString_Check(key)) {
    510                 PyErr_SetString(PyExc_TypeError, "Expected string as key");
     668        PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
     669        if (!PyBytes_Check(key)) {
     670                PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
    511671                return -1;
    512672        }
    513673
    514         tkey = PyString_AsTDB_DATA(key);
     674        tkey = PyBytes_AsTDB_DATA(key);
    515675
    516676        if (value == NULL) {
    517677                ret = tdb_delete(self->ctx, tkey);
    518678        } else {
    519                 if (!PyString_Check(value)) {
     679                if (!PyBytes_Check(value)) {
    520680                        PyErr_SetString(PyExc_TypeError, "Expected string as value");
    521681                        return -1;
    522682                }
    523683
    524                 tval = PyString_AsTDB_DATA(value);
     684                tval = PyBytes_AsTDB_DATA(value);
    525685
    526686                ret = tdb_store(self->ctx, tkey, tval, TDB_REPLACE);
     
    539699        .mp_ass_subscript = (objobjargproc)obj_setitem,
    540700};
     701static PySequenceMethods tdb_object_seq = {
     702        .sq_contains = (objobjproc)obj_contains,
     703};
    541704static PyTypeObject PyTdb = {
    542         .tp_name = "Tdb",
     705        .tp_name = "tdb.Tdb",
    543706        .tp_basicsize = sizeof(PyTdbObject),
    544707        .tp_methods = tdb_object_methods,
     
    549712        .tp_dealloc = (destructor)tdb_object_dealloc,
    550713        .tp_as_mapping = &tdb_object_mapping,
     714        .tp_as_sequence = &tdb_object_seq,
    551715        .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_ITER,
    552716        .tp_iter = (getiterfunc)tdb_object_iter,
     
    559723};
    560724
     725#define MODULE_DOC "simple key-value database that supports multiple writers."
     726
     727#if PY_MAJOR_VERSION >= 3
     728static struct PyModuleDef moduledef = {
     729    PyModuleDef_HEAD_INIT,
     730    .m_name = "tdb",
     731    .m_doc = MODULE_DOC,
     732    .m_size = -1,
     733    .m_methods = tdb_methods,
     734};
     735#endif
     736
     737PyObject* module_init(void);
     738PyObject* module_init(void)
     739{
     740        PyObject *m;
     741
     742        if (PyType_Ready(&PyTdb) < 0)
     743                return NULL;
     744
     745        if (PyType_Ready(&PyTdbIterator) < 0)
     746                return NULL;
     747
     748#if PY_MAJOR_VERSION >= 3
     749        m = PyModule_Create(&moduledef);
     750#else
     751        m = Py_InitModule3("tdb", tdb_methods, MODULE_DOC);
     752#endif
     753        if (m == NULL)
     754                return NULL;
     755
     756        PyModule_AddIntConstant(m, "REPLACE", TDB_REPLACE);
     757        PyModule_AddIntConstant(m, "INSERT", TDB_INSERT);
     758        PyModule_AddIntConstant(m, "MODIFY", TDB_MODIFY);
     759
     760        PyModule_AddIntConstant(m, "DEFAULT", TDB_DEFAULT);
     761        PyModule_AddIntConstant(m, "CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST);
     762        PyModule_AddIntConstant(m, "INTERNAL", TDB_INTERNAL);
     763        PyModule_AddIntConstant(m, "NOLOCK", TDB_NOLOCK);
     764        PyModule_AddIntConstant(m, "NOMMAP", TDB_NOMMAP);
     765        PyModule_AddIntConstant(m, "CONVERT", TDB_CONVERT);
     766        PyModule_AddIntConstant(m, "BIGENDIAN", TDB_BIGENDIAN);
     767        PyModule_AddIntConstant(m, "NOSYNC", TDB_NOSYNC);
     768        PyModule_AddIntConstant(m, "SEQNUM", TDB_SEQNUM);
     769        PyModule_AddIntConstant(m, "VOLATILE", TDB_VOLATILE);
     770        PyModule_AddIntConstant(m, "ALLOW_NESTING", TDB_ALLOW_NESTING);
     771        PyModule_AddIntConstant(m, "DISALLOW_NESTING", TDB_DISALLOW_NESTING);
     772        PyModule_AddIntConstant(m, "INCOMPATIBLE_HASH", TDB_INCOMPATIBLE_HASH);
     773
     774        PyModule_AddStringConstant(m, "__docformat__", "restructuredText");
     775
     776        PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
     777
     778        Py_INCREF(&PyTdb);
     779        PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb);
     780
     781        Py_INCREF(&PyTdbIterator);
     782
     783    return m;
     784}
     785
     786
     787#if PY_MAJOR_VERSION >= 3
     788PyMODINIT_FUNC PyInit_tdb(void);
     789PyMODINIT_FUNC PyInit_tdb(void)
     790{
     791    return module_init();
     792}
     793#else
    561794void inittdb(void);
    562795void inittdb(void)
    563796{
    564         PyObject *m;
    565 
    566         if (PyType_Ready(&PyTdb) < 0)
    567                 return;
    568 
    569         if (PyType_Ready(&PyTdbIterator) < 0)
    570                 return;
    571 
    572         m = Py_InitModule3("tdb", tdb_methods, "TDB is a simple key-value database similar to GDBM that supports multiple writers.");
    573         if (m == NULL)
    574                 return;
    575 
    576         PyModule_AddObject(m, "REPLACE", PyInt_FromLong(TDB_REPLACE));
    577         PyModule_AddObject(m, "INSERT", PyInt_FromLong(TDB_INSERT));
    578         PyModule_AddObject(m, "MODIFY", PyInt_FromLong(TDB_MODIFY));
    579 
    580         PyModule_AddObject(m, "DEFAULT", PyInt_FromLong(TDB_DEFAULT));
    581         PyModule_AddObject(m, "CLEAR_IF_FIRST", PyInt_FromLong(TDB_CLEAR_IF_FIRST));
    582         PyModule_AddObject(m, "INTERNAL", PyInt_FromLong(TDB_INTERNAL));
    583         PyModule_AddObject(m, "NOLOCK", PyInt_FromLong(TDB_NOLOCK));
    584         PyModule_AddObject(m, "NOMMAP", PyInt_FromLong(TDB_NOMMAP));
    585         PyModule_AddObject(m, "CONVERT", PyInt_FromLong(TDB_CONVERT));
    586         PyModule_AddObject(m, "BIGENDIAN", PyInt_FromLong(TDB_BIGENDIAN));
    587         PyModule_AddObject(m, "NOSYNC", PyInt_FromLong(TDB_NOSYNC));
    588         PyModule_AddObject(m, "SEQNUM", PyInt_FromLong(TDB_SEQNUM));
    589         PyModule_AddObject(m, "VOLATILE", PyInt_FromLong(TDB_VOLATILE));
    590         PyModule_AddObject(m, "ALLOW_NESTING", PyInt_FromLong(TDB_ALLOW_NESTING));
    591         PyModule_AddObject(m, "DISALLOW_NESTING", PyInt_FromLong(TDB_DISALLOW_NESTING));
    592         PyModule_AddObject(m, "INCOMPATIBLE_HASH", PyInt_FromLong(TDB_INCOMPATIBLE_HASH));
    593 
    594         PyModule_AddObject(m, "__docformat__", PyString_FromString("restructuredText"));
    595 
    596         PyModule_AddObject(m, "__version__", PyString_FromString(PACKAGE_VERSION));
    597 
    598         Py_INCREF(&PyTdb);
    599         PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb);
    600 
    601         Py_INCREF(&PyTdbIterator);
    602 }
     797    module_init();
     798}
     799#endif
  • vendor/current/lib/tdb/python/tests/simple.py

    r986 r988  
    77# Published under the GNU LGPLv3 or later
    88
     9import sys
     10import os
     11import tempfile
     12from unittest import TestCase
     13
    914import tdb
    10 from unittest import TestCase
    11 import os, tempfile
    1215
    1316
    1417class OpenTdbTests(TestCase):
    1518
    16     def test_nonexistant_read(self):
    17         self.assertRaises(IOError, tdb.Tdb, "/some/nonexistant/file", 0,
     19    def test_nonexistent_read(self):
     20        self.assertRaises(IOError, tdb.Tdb, "/some/nonexistent/file", 0,
    1821                tdb.DEFAULT, os.O_RDWR)
    1922
     
    2225    def test_double_close(self):
    2326        self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
    24                 os.O_CREAT|os.O_RDWR)
     27                           os.O_CREAT|os.O_RDWR)
    2528        self.assertNotEqual(None, self.tdb)
    2629
     
    2932        self.tdb.close()
    3033
     34        # Check that further operations do not crash python
     35        self.assertRaises(RuntimeError, lambda: self.tdb.transaction_start())
     36
     37        self.assertRaises(RuntimeError, lambda: self.tdb["bar"])
     38
    3139
    3240class InternalTdbTests(TestCase):
     
    3745        # repr used to crash on internal db
    3846        self.assertEquals(repr(self.tdb), "Tdb(<internal>)")
     47
     48
     49class CommonTdbTests(TestCase):
     50    """Tests common to both the text & bytes interfaces"""
     51
     52    use_text = False
     53
     54    def setUp(self):
     55        super(CommonTdbTests, self).setUp()
     56        self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
     57                           os.O_CREAT|os.O_RDWR)
     58        self.assertNotEqual(None, self.tdb)
     59        if self.use_text:
     60            self.tdb = self.tdb.text
     61
     62    def test_lockall(self):
     63        self.tdb.lock_all()
     64
     65    def test_max_dead(self):
     66        self.tdb.max_dead = 20
     67
     68    def test_unlockall(self):
     69        self.tdb.lock_all()
     70        self.tdb.unlock_all()
     71
     72    def test_lockall_read(self):
     73        self.tdb.read_lock_all()
     74        self.tdb.read_unlock_all()
     75
     76    def test_reopen(self):
     77        self.tdb.reopen()
     78
     79    def test_hash_size(self):
     80        self.tdb.hash_size
     81
     82    def test_map_size(self):
     83        self.tdb.map_size
     84
     85    def test_freelist_size(self):
     86        self.tdb.freelist_size
     87
     88    def test_name(self):
     89        self.tdb.filename
     90
     91    def test_add_flags(self):
     92        self.tdb.add_flags(tdb.NOMMAP)
     93        self.tdb.remove_flags(tdb.NOMMAP)
     94
     95
     96class TextCommonTdbTests(CommonTdbTests):
     97
     98    use_text = True
    3999
    40100
     
    44104        super(SimpleTdbTests, self).setUp()
    45105        self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
    46                 os.O_CREAT|os.O_RDWR)
     106                           os.O_CREAT|os.O_RDWR)
    47107        self.assertNotEqual(None, self.tdb)
    48 
    49     def tearDown(self):
    50         del self.tdb
    51108
    52109    def test_repr(self):
    53110        self.assertTrue(repr(self.tdb).startswith("Tdb('"))
    54111
    55     def test_lockall(self):
    56         self.tdb.lock_all()
    57 
    58     def test_max_dead(self):
    59         self.tdb.max_dead = 20
    60 
    61     def test_unlockall(self):
    62         self.tdb.lock_all()
    63         self.tdb.unlock_all()
    64 
    65     def test_lockall_read(self):
    66         self.tdb.read_lock_all()
    67         self.tdb.read_unlock_all()
    68 
    69     def test_reopen(self):
     112    def test_store(self):
     113        self.tdb.store(b"bar", b"bla")
     114        self.assertEquals(b"bla", self.tdb.get(b"bar"))
     115
     116    def test_getitem(self):
     117        self.tdb[b"bar"] = b"foo"
    70118        self.tdb.reopen()
    71 
    72     def test_store(self):
    73         self.tdb.store("bar", "bla")
    74         self.assertEquals("bla", self.tdb.get("bar"))
    75 
    76     def test_getitem(self):
    77         self.tdb["bar"] = "foo"
    78         self.tdb.reopen()
    79         self.assertEquals("foo", self.tdb["bar"])
     119        self.assertEquals(b"foo", self.tdb[b"bar"])
    80120
    81121    def test_delete(self):
    82         self.tdb["bar"] = "foo"
    83         del self.tdb["bar"]
    84         self.assertRaises(KeyError, lambda: self.tdb["bar"])
    85    
     122        self.tdb[b"bar"] = b"foo"
     123        del self.tdb[b"bar"]
     124        self.assertRaises(KeyError, lambda: self.tdb[b"bar"])
     125
    86126    def test_contains(self):
    87         self.tdb["bla"] = "bloe"
    88         self.assertTrue("bla" in self.tdb)
     127        self.tdb[b"bla"] = b"bloe"
     128        self.assertTrue(b"bla" in self.tdb)
     129        self.assertFalse(b"qwertyuiop" in self.tdb)
     130        if sys.version_info < (3, 0):
     131            self.assertTrue(self.tdb.has_key(b"bla"))
     132            self.assertFalse(self.tdb.has_key(b"qwertyuiop"))
    89133
    90134    def test_keyerror(self):
    91         self.assertRaises(KeyError, lambda: self.tdb["bla"])
    92 
    93     def test_hash_size(self):
    94         self.tdb.hash_size
    95 
    96     def test_map_size(self):
    97         self.tdb.map_size
    98 
    99     def test_freelist_size(self):
    100         self.tdb.freelist_size
    101 
    102     def test_name(self):
    103         self.tdb.filename
     135        self.assertRaises(KeyError, lambda: self.tdb[b"bla"])
    104136
    105137    def test_iterator(self):
    106         self.tdb["bla"] = "1"
    107         self.tdb["brainslug"] = "2"
    108         self.assertEquals(["bla", "brainslug"], list(self.tdb))
     138        self.tdb[b"bla"] = b"1"
     139        self.tdb[b"brainslug"] = b"2"
     140        l = list(self.tdb)
     141        l.sort()
     142        self.assertEquals([b"bla", b"brainslug"], l)
    109143
    110144    def test_transaction_cancel(self):
    111         self.tdb["bloe"] = "2"
    112         self.tdb.transaction_start()
    113         self.tdb["bloe"] = "1"
     145        self.tdb[b"bloe"] = b"2"
     146        self.tdb.transaction_start()
     147        self.tdb[b"bloe"] = b"1"
    114148        self.tdb.transaction_cancel()
    115         self.assertEquals("2", self.tdb["bloe"])
     149        self.assertEquals(b"2", self.tdb[b"bloe"])
    116150
    117151    def test_transaction_commit(self):
    118         self.tdb["bloe"] = "2"
    119         self.tdb.transaction_start()
    120         self.tdb["bloe"] = "1"
     152        self.tdb[b"bloe"] = b"2"
     153        self.tdb.transaction_start()
     154        self.tdb[b"bloe"] = b"1"
    121155        self.tdb.transaction_commit()
    122         self.assertEquals("1", self.tdb["bloe"])
     156        self.assertEquals(b"1", self.tdb[b"bloe"])
    123157
    124158    def test_transaction_prepare_commit(self):
    125         self.tdb["bloe"] = "2"
    126         self.tdb.transaction_start()
    127         self.tdb["bloe"] = "1"
     159        self.tdb[b"bloe"] = b"2"
     160        self.tdb.transaction_start()
     161        self.tdb[b"bloe"] = b"1"
    128162        self.tdb.transaction_prepare_commit()
    129163        self.tdb.transaction_commit()
    130         self.assertEquals("1", self.tdb["bloe"])
     164        self.assertEquals(b"1", self.tdb[b"bloe"])
    131165
    132166    def test_iterkeys(self):
    133         self.tdb["bloe"] = "2"
    134         self.tdb["bla"] = "25"
    135         i = self.tdb.iterkeys()
    136         self.assertEquals(set(["bloe", "bla"]), set([i.next(), i.next()]))
     167        self.tdb[b"bloe"] = b"2"
     168        self.tdb[b"bla"] = b"25"
     169        if sys.version_info >= (3, 0):
     170            i = self.tdb.keys()
     171        else:
     172            i = self.tdb.iterkeys()
     173        self.assertEquals(set([b"bloe", b"bla"]), set([next(i), next(i)]))
    137174
    138175    def test_clear(self):
    139         self.tdb["bloe"] = "2"
    140         self.tdb["bla"] = "25"
     176        self.tdb[b"bloe"] = b"2"
     177        self.tdb[b"bla"] = b"25"
    141178        self.assertEquals(2, len(list(self.tdb)))
    142179        self.tdb.clear()
     
    144181
    145182    def test_repack(self):
    146         self.tdb["foo"] = "abc"
    147         self.tdb["bar"] = "def"
    148         del self.tdb["foo"]
     183        self.tdb[b"foo"] = b"abc"
     184        self.tdb[b"bar"] = b"def"
     185        del self.tdb[b"foo"]
    149186        self.tdb.repack()
    150187
     
    158195    def test_len(self):
    159196        self.assertEquals(0, len(list(self.tdb)))
    160         self.tdb["entry"] = "value"
     197        self.tdb[b"entry"] = b"value"
    161198        self.assertEquals(1, len(list(self.tdb)))
    162199
    163     def test_add_flags(self):
    164         self.tdb.add_flags(tdb.NOMMAP)
    165         self.tdb.remove_flags(tdb.NOMMAP)
     200
     201class TdbTextTests(TestCase):
     202
     203    def setUp(self):
     204        super(TdbTextTests, self).setUp()
     205        self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
     206                           os.O_CREAT|os.O_RDWR)
     207        self.assertNotEqual(None, self.tdb)
     208
     209    def test_repr(self):
     210        self.assertTrue(repr(self.tdb).startswith("Tdb('"))
     211
     212    def test_store(self):
     213        self.tdb.text.store("bar", "bla")
     214        self.assertEquals("bla", self.tdb.text.get("bar"))
     215
     216    def test_getitem(self):
     217        self.tdb.text["bar"] = "foo"
     218        self.tdb.reopen()
     219        self.assertEquals("foo", self.tdb.text["bar"])
     220
     221    def test_delete(self):
     222        self.tdb.text["bar"] = "foo"
     223        del self.tdb.text["bar"]
     224        self.assertRaises(KeyError, lambda: self.tdb.text["bar"])
     225
     226    def test_contains(self):
     227        self.tdb.text["bla"] = "bloe"
     228        self.assertTrue("bla" in self.tdb.text)
     229        self.assertFalse("qwertyuiop" in self.tdb.text)
     230        if sys.version_info < (3, 0):
     231            self.assertTrue(self.tdb.text.has_key("bla"))
     232            self.assertFalse(self.tdb.text.has_key("qwertyuiop"))
     233
     234    def test_keyerror(self):
     235        self.assertRaises(KeyError, lambda: self.tdb.text["bla"])
     236
     237    def test_iterator(self):
     238        self.tdb.text["bla"] = "1"
     239        self.tdb.text["brainslug"] = "2"
     240        l = list(self.tdb.text)
     241        l.sort()
     242        self.assertEquals(["bla", "brainslug"], l)
     243
     244    def test_transaction_cancel(self):
     245        self.tdb.text["bloe"] = "2"
     246        self.tdb.transaction_start()
     247        self.tdb.text["bloe"] = "1"
     248        self.tdb.transaction_cancel()
     249        self.assertEquals("2", self.tdb.text["bloe"])
     250
     251    def test_transaction_commit(self):
     252        self.tdb.text["bloe"] = "2"
     253        self.tdb.transaction_start()
     254        self.tdb.text["bloe"] = "1"
     255        self.tdb.transaction_commit()
     256        self.assertEquals("1", self.tdb.text["bloe"])
     257
     258    def test_transaction_prepare_commit(self):
     259        self.tdb.text["bloe"] = "2"
     260        self.tdb.transaction_start()
     261        self.tdb.text["bloe"] = "1"
     262        self.tdb.transaction_prepare_commit()
     263        self.tdb.transaction_commit()
     264        self.assertEquals("1", self.tdb.text["bloe"])
     265
     266    def test_iterkeys(self):
     267        self.tdb.text["bloe"] = "2"
     268        self.tdb.text["bla"] = "25"
     269        if sys.version_info >= (3, 0):
     270            i = self.tdb.text.keys()
     271        else:
     272            i = self.tdb.text.iterkeys()
     273        self.assertEquals(set(["bloe", "bla"]), set([next(i), next(i)]))
     274
     275    def test_clear(self):
     276        self.tdb.text["bloe"] = "2"
     277        self.tdb.text["bla"] = "25"
     278        self.assertEquals(2, len(list(self.tdb)))
     279        self.tdb.clear()
     280        self.assertEquals(0, len(list(self.tdb)))
     281
     282    def test_repack(self):
     283        self.tdb.text["foo"] = "abc"
     284        self.tdb.text["bar"] = "def"
     285        del self.tdb.text["foo"]
     286        self.tdb.repack()
     287
     288    def test_len(self):
     289        self.assertEquals(0, len(list(self.tdb.text)))
     290        self.tdb.text["entry"] = "value"
     291        self.assertEquals(1, len(list(self.tdb.text)))
     292
     293    def test_text_and_binary(self):
     294        text = u'\xfa\u0148\xef\xe7\xf8\xf0\xea'
     295        bytestr = text.encode('utf-8')
     296        self.tdb[b"entry"] = bytestr
     297        self.tdb.text[u"entry2"] = text
     298        self.assertEquals(self.tdb.text["entry"], text)
     299        self.assertEquals(self.tdb[b"entry2"], bytestr)
     300        assert self.tdb.text.raw == self.tdb
    166301
    167302
  • vendor/current/lib/tdb/tools/tdbbackup.c

    r986 r988  
    1 /* 
     1/*
    22   Unix SMB/CIFS implementation.
    33   low level tdb backup and restore utility
     
    88   the Free Software Foundation; either version 3 of the License, or
    99   (at your option) any later version.
    10    
     10
    1111   This program is distributed in the hope that it will be useful,
    1212   but WITHOUT ANY WARRANTY; without even the implied warranty of
    1313   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1414   GNU General Public License for more details.
    15    
     15
    1616   You should have received a copy of the GNU General Public License
    1717   along with this program.  If not, see <http://www.gnu.org/licenses/>.
     
    6262{
    6363        va_list ap;
    64    
     64
    6565        va_start(ap, format);
    6666        vfprintf(stdout, format, ap);
     
    105105  this function is also used for restore
    106106*/
    107 static int backup_tdb(const char *old_name, const char *new_name, int hash_size)
     107static int backup_tdb(const char *old_name, const char *new_name,
     108                      int hash_size, int nolock)
    108109{
    109110        TDB_CONTEXT *tdb;
     
    123124
    124125        /* open the old tdb */
    125         tdb = tdb_open_ex(old_name, 0, 0,
     126        tdb = tdb_open_ex(old_name, 0,
     127                          TDB_DEFAULT | (nolock ? TDB_NOLOCK : 0),
    126128                          O_RDWR, 0, &log_ctx, NULL);
    127129        if (!tdb) {
     
    133135        /* create the new tdb */
    134136        unlink(tmp_name);
    135         tdb_new = tdb_open_ex(tmp_name, 
    136                               hash_size ? hash_size : tdb_hash_size(tdb), 
    137                               TDB_DEFAULT, 
    138                               O_RDWR|O_CREAT|O_EXCL, st.st_mode & 0777, 
     137        tdb_new = tdb_open_ex(tmp_name,
     138                              hash_size ? hash_size : tdb_hash_size(tdb),
     139                              TDB_DEFAULT,
     140                              O_RDWR|O_CREAT|O_EXCL, st.st_mode & 0777,
    139141                              &log_ctx, NULL);
    140142        if (!tdb_new) {
     
    193195        /* close the new tdb and re-open read-only */
    194196        tdb_close(tdb_new);
    195         tdb_new = tdb_open_ex(tmp_name, 
     197        tdb_new = tdb_open_ex(tmp_name,
    196198                              0,
    197                               TDB_DEFAULT, 
     199                              TDB_DEFAULT,
    198200                              O_RDONLY, 0,
    199201                              &log_ctx, NULL);
     
    205207                return 1;
    206208        }
    207        
     209
    208210        /* traverse the new tdb to confirm */
    209211        count2 = tdb_traverse(tdb_new, test_fn, NULL);
     
    238240
    239241        /* open the tdb */
    240         tdb = tdb_open_ex(fname, 0, 0, 
     242        tdb = tdb_open_ex(fname, 0, 0,
    241243                          O_RDONLY, 0, &log_ctx, NULL);
    242244
     
    250252        if (count < 0) {
    251253                printf("restoring %s\n", fname);
    252                 return backup_tdb(bak_name, fname, 0);
     254                return backup_tdb(bak_name, fname, 0, 0);
    253255        }
    254256
     
    280282        printf("   -v            verify mode (restore if corrupt)\n");
    281283        printf("   -n hashsize   set the new hash size for the backup\n");
    282 }
    283                
     284        printf("   -l            open without locking to back up mutex dbs\n");
     285}
    284286
    285287 int main(int argc, char *argv[])
     
    290292        int verify = 0;
    291293        int hashsize = 0;
     294        int nolock = 0;
    292295        const char *suffix = ".bak";
    293296
    294297        log_ctx.log_fn = tdb_log;
    295298
    296         while ((c = getopt(argc, argv, "vhs:n:")) != -1) {
     299        while ((c = getopt(argc, argv, "vhs:n:l")) != -1) {
    297300                switch (c) {
    298301                case 'h':
     
    308311                        hashsize = atoi(optarg);
    309312                        break;
     313                case 'l':
     314                        nolock = 1;
     315                        break;
    310316                }
    311317        }
     
    331337                } else {
    332338                        if (file_newer(fname, bak_name) &&
    333                             backup_tdb(fname, bak_name, hashsize) != 0) {
     339                            backup_tdb(fname, bak_name, hashsize,
     340                                       nolock) != 0) {
    334341                                ret = 1;
    335342                        }
  • vendor/current/lib/tdb/tools/tdbdump.c

    r414 r988  
    1 /* 
     1/*
    22   Unix SMB/CIFS implementation.
    33   simple tdb dump util
     
    88   the Free Software Foundation; either version 3 of the License, or
    99   (at your option) any later version.
    10    
     10
    1111   This program is distributed in the hope that it will be useful,
    1212   but WITHOUT ANY WARRANTY; without even the implied warranty of
    1313   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1414   GNU General Public License for more details.
    15    
     15
    1616   You should have received a copy of the GNU General Public License
    1717   along with this program.  If not, see <http://www.gnu.org/licenses/>.
     
    5252}
    5353
    54 static int dump_tdb(const char *fname, const char *keyname)
     54static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
     55                       const char *fmt, ...)
     56{
     57        va_list ap;
     58        const char *name = tdb_name(tdb);
     59        const char *prefix = "";
     60
     61        if (!name)
     62                name = "unnamed";
     63
     64        switch (level) {
     65        case TDB_DEBUG_ERROR:
     66                prefix = "ERROR: ";
     67                break;
     68        case TDB_DEBUG_WARNING:
     69                prefix = "WARNING: ";
     70                break;
     71        case TDB_DEBUG_TRACE:
     72                return;
     73
     74        default:
     75        case TDB_DEBUG_FATAL:
     76                prefix = "FATAL: ";
     77                break;
     78        }
     79
     80        va_start(ap, fmt);
     81        fprintf(stderr, "tdb(%s): %s", name, prefix);
     82        vfprintf(stderr, fmt, ap);
     83        va_end(ap);
     84}
     85
     86static void emergency_walk(TDB_DATA key, TDB_DATA dbuf, void *keyname)
     87{
     88        if (keyname) {
     89                if (key.dsize != strlen(keyname))
     90                        return;
     91                if (memcmp(key.dptr, keyname, key.dsize) != 0)
     92                        return;
     93        }
     94        traverse_fn(NULL, key, dbuf, NULL);
     95}
     96
     97static int dump_tdb(const char *fname, const char *keyname, bool emergency)
    5598{
    5699        TDB_CONTEXT *tdb;
    57100        TDB_DATA key, value;
    58        
    59         tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
     101        struct tdb_logging_context logfn = { log_stderr };
     102        int tdb_flags = TDB_DEFAULT;
     103
     104        /*
     105         * Note: that O_RDONLY implies TDB_NOLOCK, but we want to make it
     106         * explicit as it's important when working on databases which were
     107         * created with mutex locking.
     108         */
     109        tdb_flags |= TDB_NOLOCK;
     110
     111        tdb = tdb_open_ex(fname, 0, tdb_flags, O_RDONLY, 0, &logfn, NULL);
    60112        if (!tdb) {
    61113                printf("Failed to open %s\n", fname);
     
    63115        }
    64116
     117        if (emergency) {
     118                return tdb_rescue(tdb, emergency_walk, discard_const(keyname)) == 0;
     119        }
    65120        if (!keyname) {
    66                 tdb_traverse(tdb, traverse_fn, NULL);
     121                return tdb_traverse(tdb, traverse_fn, NULL) == -1 ? 1 : 0;
    67122        } else {
    68123                key.dptr = discard_const_p(uint8_t, keyname);
     
    85140        printf( "   -h          this help message\n");
    86141        printf( "   -k keyname  dumps value of keyname\n");
     142        printf( "   -e          emergency dump, for corrupt databases\n");
    87143}
    88144
     
    90146{
    91147        char *fname, *keyname=NULL;
     148        bool emergency = false;
    92149        int c;
    93150
     
    97154        }
    98155
    99         while ((c = getopt( argc, argv, "hk:")) != -1) {
     156        while ((c = getopt( argc, argv, "hk:e")) != -1) {
    100157                switch (c) {
    101158                case 'h':
     
    104161                case 'k':
    105162                        keyname = optarg;
     163                        break;
     164                case 'e':
     165                        emergency = true;
    106166                        break;
    107167                default:
     
    113173        fname = argv[optind];
    114174
    115         return dump_tdb(fname, keyname);
     175        return dump_tdb(fname, keyname, emergency);
    116176}
  • vendor/current/lib/tdb/tools/tdbrestore.c

    r986 r988  
    1818*/
    1919
     20#include "replace.h"
    2021#include <assert.h>
    21 #include "replace.h"
    2222#include "system/locale.h"
    2323#include "system/time.h"
     
    2525#include "system/wait.h"
    2626#include "tdb.h"
    27 
    28 #define debug_fprintf(file, fmt, ...) do {/*nothing*/} while (0)
    2927
    3028static int read_linehead(FILE *f)
     
    171169                goto fail;
    172170        }
    173         if (tdb_store(tdb, key, data, TDB_INSERT) == -1) {
     171        if (tdb_store(tdb, key, data, TDB_INSERT) != 0) {
    174172                fprintf(stderr, "TDB error: %s\n", tdb_errorstr(tdb));
    175173                goto fail;
     
    207205                return 1;
    208206        }
    209         fprintf(stderr, "EOF\n");
    210207        return 0;
    211208}
  • vendor/current/lib/tdb/tools/tdbtest.c

    r986 r988  
    2525{
    2626        gettimeofday(&tp2,NULL);
    27         return((tp2.tv_sec - tp1.tv_sec) + 
     27        return((tp2.tv_sec - tp1.tv_sec) +
    2828               (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
    2929}
     
    4141{
    4242        va_list ap;
    43    
     43
    4444        va_start(ap, format);
    4545        vfprintf(stdout, format, ap);
     
    190190        char tdata[] = "test";
    191191        TDB_DATA key, data;
    192        
     192
    193193        for (i = 0; i < 5; i++) {
    194194                snprintf(keys[i],2, "%d", i);
    195195                key.dptr = keys[i];
    196196                key.dsize = 2;
    197                
     197
    198198                data.dptr = tdata;
    199199                data.dsize = 4;
    200                
     200
    201201                if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
    202202                        fatal("tdb_store failed");
     
    249249        db = tdb_open(test_tdb, 0, TDB_CLEAR_IF_FIRST,
    250250                      O_RDWR | O_CREAT | O_TRUNC, 0600);
    251         gdbm = gdbm_open(test_gdbm, 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST, 
     251        gdbm = gdbm_open(test_gdbm, 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST,
    252252                         0600, NULL);
    253253
  • vendor/current/lib/tdb/tools/tdbtool.c

    r986 r988  
    1 /* 
     1/*
    22   Unix SMB/CIFS implementation.
    33   Samba database functions
     
    1111   the Free Software Foundation; either version 3 of the License, or
    1212   (at your option) any later version.
    13    
     13
    1414   This program is distributed in the hope that it will be useful,
    1515   but WITHOUT ANY WARRANTY; without even the implied warranty of
    1616   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1717   GNU General Public License for more details.
    18    
     18
    1919   You should have received a copy of the GNU General Public License
    2020   along with this program.  If not, see <http://www.gnu.org/licenses/>.
     
    3737char cmdline[1024];
    3838static int disable_mmap;
     39static int disable_lock;
    3940
    4041enum commands {
     
    5556        CMD_LIST_HASH_FREE,
    5657        CMD_LIST_FREE,
     58        CMD_FREELIST_SIZE,
    5759        CMD_INFO,
    5860        CMD_MMAP,
     
    6264        CMD_SYSTEM,
    6365        CMD_CHECK,
     66        CMD_REPACK,
    6467        CMD_QUIT,
    6568        CMD_HELP
     
    8891        {"list",        CMD_LIST_HASH_FREE},
    8992        {"free",        CMD_LIST_FREE},
     93        {"freelist_size",       CMD_FREELIST_SIZE},
    9094        {"info",        CMD_INFO},
    9195        {"speed",       CMD_SPEED},
     
    99103        {"q",           CMD_QUIT},
    100104        {"!",           CMD_SYSTEM},
     105        {"repack",      CMD_REPACK},
    101106        {NULL,          CMD_HELP}
    102107};
     
    112117{
    113118        gettimeofday(&tp2,NULL);
    114         return((tp2.tv_sec - tp1.tv_sec) + 
     119        return((tp2.tv_sec - tp1.tv_sec) +
    115120               (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
     121}
     122
     123#ifdef PRINTF_ATTRIBUTE
     124static void tdb_log_open(struct tdb_context *tdb, enum tdb_debug_level level,
     125                         const char *format, ...) PRINTF_ATTRIBUTE(3,4);
     126#endif
     127static void tdb_log_open(struct tdb_context *tdb, enum tdb_debug_level level,
     128                         const char *format, ...)
     129{
     130        const char *mutex_msg =
     131                "Can use mutexes only with MUTEX_LOCKING or NOLOCK\n";
     132        char *p;
     133        va_list ap;
     134
     135        p = strstr(format, mutex_msg);
     136        if (p != NULL) {
     137                /*
     138                 * Yes, this is a hack, but we don't want to see this
     139                 * message on first open, but we want to see
     140                 * everything else.
     141                 */
     142                return;
     143        }
     144
     145        va_start(ap, format);
     146        vfprintf(stderr, format, ap);
     147        va_end(ap);
    116148}
    117149
     
    159191                i++;
    160192                if (i%8 == 0) printf(" ");
    161                 if (i%16 == 0) {     
     193                if (i%16 == 0) {
    162194                        print_asc(&buf[i-16],8); printf(" ");
    163195                        print_asc(&buf[i-8],8); printf("\n");
     
    167199        if (i%16) {
    168200                int n;
    169                
     201
    170202                n = 16 - (i%16);
    171203                printf(" ");
    172204                if (n>8) printf(" ");
    173205                while (n--) printf("   ");
    174                
     206
    175207                n = i%16;
    176208                if (n > 8) n = 8;
    177209                print_asc(&buf[i-(i%16)],n); printf(" ");
    178210                n = (i%16) - n;
    179                 if (n>0) print_asc(&buf[i-n],n); 
    180                 printf("\n");   
     211                if (n>0) print_asc(&buf[i-n],n);
     212                printf("\n");
    181213        }
    182214}
     
    203235"  list                 : print the database hash table and freelist\n"
    204236"  free                 : print the database freelist\n"
     237"  freelist_size        : print the number of records in the freelist\n"
    205238"  check                : check the integrity of an opened database\n"
     239"  repack               : repack the database\n"
    206240"  speed                : perform speed tests on the database\n"
    207241"  ! command            : execute system command\n"
     
    220254static void create_tdb(const char *tdbname)
    221255{
    222         struct tdb_logging_context log_ctx;
     256        struct tdb_logging_context log_ctx = { NULL, NULL};
    223257        log_ctx.log_fn = tdb_log;
    224258
    225259        if (tdb) tdb_close(tdb);
    226         tdb = tdb_open_ex(tdbname, 0, TDB_CLEAR_IF_FIRST | (disable_mmap?TDB_NOMMAP:0),
     260        tdb = tdb_open_ex(tdbname, 0,
     261                          TDB_CLEAR_IF_FIRST |
     262                          (disable_mmap?TDB_NOMMAP:0) |
     263                          (disable_lock?TDB_NOLOCK:0),
    227264                          O_RDWR | O_CREAT | O_TRUNC, 0600, &log_ctx, NULL);
    228265        if (!tdb) {
     
    233270static void open_tdb(const char *tdbname)
    234271{
    235         struct tdb_logging_context log_ctx;
     272        struct tdb_logging_context log_ctx = { NULL, NULL };
     273        log_ctx.log_fn = tdb_log_open;
     274
     275        if (tdb) tdb_close(tdb);
     276        tdb = tdb_open_ex(tdbname, 0,
     277                          (disable_mmap?TDB_NOMMAP:0) |
     278                          (disable_lock?TDB_NOLOCK:0),
     279                          O_RDWR, 0600,
     280                          &log_ctx, NULL);
     281
    236282        log_ctx.log_fn = tdb_log;
    237 
    238         if (tdb) tdb_close(tdb);
    239         tdb = tdb_open_ex(tdbname, 0, disable_mmap?TDB_NOMMAP:0, O_RDWR, 0600,
    240                           &log_ctx, NULL);
     283        if (tdb != NULL) {
     284                tdb_set_logging_function(tdb, &log_ctx);
     285        }
     286
     287        if ((tdb == NULL) && (errno == EINVAL)) {
     288                /*
     289                 * Retry NOLOCK and readonly. There we want to see all
     290                 * error messages.
     291                 */
     292                tdb = tdb_open_ex(tdbname, 0,
     293                                  (disable_mmap?TDB_NOMMAP:0) |TDB_NOLOCK,
     294                                  O_RDONLY, 0600,
     295                                  &log_ctx, NULL);
     296        }
     297
    241298        if (!tdb) {
    242299                printf("Could not open %s: %s\n", tdbname, strerror(errno));
     
    258315        dbuf.dsize = datalen;
    259316
    260         if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) {
     317        if (tdb_store(tdb, key, dbuf, TDB_INSERT) != 0) {
    261318                terror("insert failed");
    262319        }
     
    285342        print_rec(tdb, key, dbuf, NULL);
    286343
    287         if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
     344        if (tdb_store(tdb, key, dbuf, TDB_REPLACE) != 0) {
    288345                terror("store failed");
    289346        }
     
    307364            return;
    308365        }
    309        
     366
    310367        print_rec(tdb, key, dbuf, NULL);
    311        
     368
    312369        free( dbuf.dptr );
    313        
     370
    314371        return;
    315372}
     
    355412                return;
    356413        }
    357        
     414
    358415        print_rec(tdb, key, dbuf, NULL);
    359        
     416
    360417        dst_tdb = tdb_open(tdbname, 0, 0, O_RDWR, 0600);
    361418        if ( !dst_tdb ) {
     
    363420                return;
    364421        }
    365        
    366         if ( tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) == -1 ) {
     422
     423        if (tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) != 0) {
    367424                terror("failed to move record");
    368425        }
    369426        else
    370427                printf("record moved\n");
    371        
     428
    372429        tdb_close( dst_tdb );
    373        
     430
    374431        return;
    375432}
     
    448505        _start_timer();
    449506        do {
    450                 long int r = random();
    451                 TDB_DATA key, dbuf;
     507                TDB_DATA key;
    452508                key.dptr = discard_const_p(uint8_t, str);
    453509                key.dsize = strlen((char *)key.dptr);
    454                 dbuf.dptr = (uint8_t *) &r;
    455                 dbuf.dsize = sizeof(r);
    456510                tdb_fetch(tdb, key);
    457511                t = _end_timer();
     
    521575        TDB_DATA dbuf;
    522576        *pkey = tdb_firstkey(the_tdb);
    523        
     577
    524578        dbuf = tdb_fetch(the_tdb, *pkey);
    525579        if (!dbuf.dptr) terror("fetch failed");
     
    533587        TDB_DATA dbuf;
    534588        *pkey = tdb_nextkey(the_tdb, *pkey);
    535        
     589
    536590        dbuf = tdb_fetch(the_tdb, *pkey);
    537         if (!dbuf.dptr) 
     591        if (!dbuf.dptr)
    538592                terror("fetch failed");
    539593        else
     
    612666                        tdb_transaction_commit(tdb);
    613667                        return 0;
     668                case CMD_REPACK:
     669                        bIterate = 0;
     670                        tdb_repack(tdb);
     671                        return 0;
    614672                case CMD_TRANSACTION_CANCEL:
    615673                        bIterate = 0;
     
    656714                        tdb_printfreelist(tdb);
    657715                        return 0;
     716                case CMD_FREELIST_SIZE: {
     717                        int size;
     718
     719                        size = tdb_freelist_size(tdb);
     720                        if (size < 0) {
     721                                printf("Error getting freelist size.\n");
     722                        } else {
     723                                printf("freelist size: %d\n", size);
     724                        }
     725
     726                        return 0;
     727                }
    658728                case CMD_INFO:
    659729                        info_tdb();
     
    694764}
    695765
    696 static char *convert_string(char *instring, size_t *sizep)
     766static char *tdb_convert_string(char *instring, size_t *sizep)
    697767{
    698768        size_t length = 0;
     
    732802        arg2 = NULL;
    733803        arg2len = 0;
     804
     805        if (argv[1] && (strcmp(argv[1], "-l") == 0)) {
     806                disable_lock = 1;
     807                argv[1] = argv[0];
     808                argv += 1;
     809                argc -= 1;
     810        }
    734811
    735812        if (argv[1]) {
     
    760837                                }
    761838                        }
    762                         if (arg1) arg1 = convert_string(arg1,&arg1len);
    763                         if (arg2) arg2 = convert_string(arg2,&arg2len);
     839                        if (arg1) arg1 = tdb_convert_string(arg1,&arg1len);
     840                        if (arg2) arg2 = tdb_convert_string(arg2,&arg2len);
    764841                        if (do_command()) break;
    765842                }
    766843                break;
    767844        case 5:
    768                 arg2 = convert_string(argv[4],&arg2len);
     845                arg2 = tdb_convert_string(argv[4],&arg2len);
    769846        case 4:
    770                 arg1 = convert_string(argv[3],&arg1len);
     847                arg1 = tdb_convert_string(argv[3],&arg1len);
    771848        case 3:
    772849                cmdname = argv[2];
  • vendor/current/lib/tdb/tools/tdbtorture.c

    r986 r988  
    11/* this tests tdb by doing lots of ops from several simultaneous
    2    writers - that stresses the locking code. 
     2   writers - that stresses the locking code.
    33*/
    44
     
    3434static int loopnum;
    3535static int count_pipe;
     36static bool mutex = false;
    3637static struct tdb_logging_context log_ctx;
    3738
     
    6061                free(ptr);
    6162        }
    62 #endif 
     63#endif
    6364}
    6465
     
    217218static void usage(void)
    218219{
    219         printf("Usage: tdbtorture [-t] [-k] [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
     220        printf("Usage: tdbtorture [-t] [-k] [-m] [-n NUM_PROCS] [-l NUM_LOOPS] [-s SEED] [-H HASH_SIZE]\n");
    220221        exit(0);
    221222}
     
    231232static int run_child(const char *filename, int i, int seed, unsigned num_loops, unsigned start)
    232233{
    233         db = tdb_open_ex(filename, hash_size, TDB_DEFAULT,
     234        int tdb_flags = TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH;
     235
     236        if (mutex) {
     237                tdb_flags |= TDB_MUTEX_LOCKING;
     238        }
     239
     240        db = tdb_open_ex(filename, hash_size, tdb_flags,
    234241                         O_RDWR | O_CREAT, 0600, &log_ctx, NULL);
    235242        if (!db) {
     
    303310        log_ctx.log_fn = tdb_log;
    304311
    305         while ((c = getopt(argc, argv, "n:l:s:H:thk")) != -1) {
     312        while ((c = getopt(argc, argv, "n:l:s:H:thkm")) != -1) {
    306313                switch (c) {
    307314                case 'n':
     
    323330                        kill_random = 1;
    324331                        break;
     332                case 'm':
     333                        mutex = tdb_runtime_check_for_robust_mutexes();
     334                        if (!mutex) {
     335                                printf("tdb_runtime_check_for_robust_mutexes() returned false\n");
     336                                exit(1);
     337                        }
     338                        break;
    325339                default:
    326340                        usage();
     
    335349                seed = (getpid() + time(NULL)) & 0x7FFFFFFF;
    336350        }
     351
     352        printf("Testing with %d processes, %d loops, %d hash_size, seed=%d%s\n",
     353               num_procs, num_loops, hash_size, seed,
     354               (always_transaction ? " (all within transactions)" : ""));
    337355
    338356        if (num_procs == 1 && !kill_random) {
     
    343361
    344362        pids = (pid_t *)calloc(sizeof(pid_t), num_procs);
     363        if (pids == NULL) {
     364                perror("Unable to allocate memory for pids");
     365                exit(1);
     366        }
    345367        done = (int *)calloc(sizeof(int), num_procs);
     368        if (done == NULL) {
     369                perror("Unable to allocate memory for done");
     370                exit(1);
     371        }
    346372
    347373        if (pipe(pfds) != 0) {
     
    354380                if ((pids[i]=fork()) == 0) {
    355381                        close(pfds[0]);
    356                         if (i == 0) {
    357                                 printf("Testing with %d processes, %d loops, %d hash_size, seed=%d%s\n",
    358                                        num_procs, num_loops, hash_size, seed, always_transaction ? " (all within transactions)" : "");
    359                         }
    360382                        exit(run_child(test_tdb, i, seed, num_loops, 0));
    361383                }
     
    436458done:
    437459        if (error_count == 0) {
    438                 db = tdb_open_ex(test_tdb, hash_size, TDB_DEFAULT,
     460                int tdb_flags = TDB_DEFAULT;
     461
     462                if (mutex) {
     463                        tdb_flags |= TDB_NOLOCK;
     464                }
     465
     466                db = tdb_open_ex(test_tdb, hash_size, tdb_flags,
    439467                                 O_RDWR, 0, &log_ctx, NULL);
    440468                if (!db) {
    441                         fatal("db open failed");
     469                        fatal("db open failed\n");
     470                        exit(1);
    442471                }
    443472                if (tdb_check(db, NULL, NULL) == -1) {
    444                         printf("db check failed");
     473                        printf("db check failed\n");
    445474                        exit(1);
    446475                }
  • vendor/current/lib/tdb/wscript

    r986 r988  
    22
    33APPNAME = 'tdb'
    4 VERSION = '1.2.9'
     4VERSION = '1.3.8'
    55
    66blddir = 'bin'
     
    1111srcdir = '.'
    1212while not os.path.exists(srcdir+'/buildtools') and len(srcdir.split('/')) < 5:
    13     srcdir = '../' + srcdir
     13    srcdir = srcdir + '/..'
    1414sys.path.insert(0, srcdir + '/buildtools/wafsamba')
    1515
    1616import wafsamba, samba_dist, Options, Logs
    1717
    18 samba_dist.DIST_DIRS('lib/tdb:. lib/replace:lib/replace buildtools:buildtools')
     18samba_dist.DIST_DIRS('lib/tdb:. lib/replace:lib/replace buildtools:buildtools third_party/waf:third_party/waf')
     19
     20tdb1_unit_tests = [
     21    'run-3G-file',
     22    'run-bad-tdb-header',
     23    'run',
     24    'run-check',
     25    'run-corrupt',
     26    'run-die-during-transaction',
     27    'run-endian',
     28    'run-incompatible',
     29    'run-nested-transactions',
     30    'run-nested-traverse',
     31    'run-no-lock-during-traverse',
     32    'run-oldhash',
     33    'run-open-during-transaction',
     34    'run-readonly-check',
     35    'run-rescue',
     36    'run-rescue-find_entry',
     37    'run-rwlock-check',
     38    'run-summary',
     39    'run-transaction-expand',
     40    'run-traverse-in-transaction',
     41    'run-wronghash-fail',
     42    'run-zero-append',
     43    'run-marklock-deadlock',
     44    'run-allrecord-traverse-deadlock',
     45    'run-mutex-openflags2',
     46    'run-mutex-trylock',
     47    'run-mutex-allrecord-bench',
     48    'run-mutex-allrecord-trylock',
     49    'run-mutex-allrecord-block',
     50    'run-mutex-transaction1',
     51    'run-mutex-die',
     52    'run-mutex1',
     53]
    1954
    2055def set_options(opt):
     
    2257    opt.PRIVATE_EXTENSION_DEFAULT('tdb', noextension='tdb')
    2358    opt.RECURSE('lib/replace')
     59    opt.add_option('--disable-tdb-mutex-locking',
     60                   help=("Disable the use of pthread robust mutexes"),
     61                   action="store_true", dest='disable_tdb_mutex_locking',
     62                   default=False)
    2463    if opt.IN_LAUNCH_DIR():
    2564        opt.add_option('--disable-python',
     
    2968
    3069def configure(conf):
     70    conf.env.disable_tdb_mutex_locking = getattr(Options.options,
     71                                                 'disable_tdb_mutex_locking',
     72                                                 False)
     73    if not conf.env.disable_tdb_mutex_locking:
     74        conf.env.replace_add_global_pthread = True
    3175    conf.RECURSE('lib/replace')
    3276
    3377    conf.env.standalone_tdb = conf.IN_LAUNCH_DIR()
     78    conf.env.building_tdb = True
    3479
    3580    if not conf.env.standalone_tdb:
    36         if conf.CHECK_BUNDLED_SYSTEM('tdb', minversion=VERSION,
     81        if conf.CHECK_BUNDLED_SYSTEM_PKG('tdb', minversion=VERSION,
    3782                                     implied_deps='replace'):
    3883            conf.define('USING_SYSTEM_TDB', 1)
     84            conf.env.building_tdb = False
    3985            if conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytdb', 'tdb', minversion=VERSION):
    4086                conf.define('USING_SYSTEM_PYTDB', 1)
     
    4288    conf.env.disable_python = getattr(Options.options, 'disable_python', False)
    4389
     90    if (conf.CONFIG_SET('HAVE_ROBUST_MUTEXES') and
     91        conf.env.building_tdb and
     92        not conf.env.disable_tdb_mutex_locking):
     93        conf.define('USE_TDB_MUTEX_LOCKING', 1)
     94
    4495    conf.CHECK_XSLTPROC_MANPAGES()
    4596
    4697    if not conf.env.disable_python:
    4798        # also disable if we don't have the python libs installed
    48         conf.check_tool('python')
     99        conf.SAMBA_CHECK_PYTHON(mandatory=False)
    49100        conf.check_python_version((2,4,2))
    50101        conf.SAMBA_CHECK_PYTHON_HEADERS(mandatory=False)
     
    55106    conf.SAMBA_CONFIG_H()
    56107
     108    conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
     109
    57110def build(bld):
    58111    bld.RECURSE('lib/replace')
    59112
    60     COMMON_SRC = bld.SUBDIR('common',
    61                             '''check.c error.c tdb.c traverse.c
    62                             freelistcheck.c lock.c dump.c freelist.c
    63                             io.c open.c transaction.c hash.c summary.c''')
     113    COMMON_FILES='''check.c error.c tdb.c traverse.c
     114                    freelistcheck.c lock.c dump.c freelist.c
     115                    io.c open.c transaction.c hash.c summary.c rescue.c
     116                    mutex.c'''
     117
     118    COMMON_SRC = bld.SUBDIR('common', COMMON_FILES)
    64119
    65120    if bld.env.standalone_tdb:
    66121        bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
    67         bld.PKG_CONFIG_FILES('tdb.pc', vnum=VERSION)
    68122        private_library = False
    69123    else:
     
    71125
    72126    if not bld.CONFIG_SET('USING_SYSTEM_TDB'):
     127
     128        tdb_deps = 'replace'
     129
     130        if bld.CONFIG_SET('USE_TDB_MUTEX_LOCKING'):
     131            tdb_deps += ' pthread'
     132
    73133        bld.SAMBA_LIBRARY('tdb',
    74134                          COMMON_SRC,
    75                           deps='replace',
     135                          deps=tdb_deps,
    76136                          includes='include',
    77137                          abi_directory='ABI',
     
    79139                          hide_symbols=True,
    80140                          vnum=VERSION,
    81                           public_headers='include/tdb.h',
     141                          public_headers=('' if private_library else 'include/tdb.h'),
    82142                          public_headers_install=not private_library,
     143                          pc_files='tdb.pc',
    83144                          private_library=private_library)
    84145
     
    90151        bld.SAMBA_BINARY('tdbrestore',
    91152                         'tools/tdbrestore.c',
    92                          'tdb', manpages='manpages/tdbrestore.8')
     153                         'tdb', manpages='man/tdbrestore.8')
    93154
    94155        bld.SAMBA_BINARY('tdbdump',
    95156                         'tools/tdbdump.c',
    96                          'tdb', manpages='manpages/tdbdump.8')
     157                         'tdb', manpages='man/tdbdump.8')
    97158
    98159        bld.SAMBA_BINARY('tdbbackup',
    99160                         'tools/tdbbackup.c',
    100161                         'tdb',
    101                          manpages='manpages/tdbbackup.8')
     162                         manpages='man/tdbbackup.8')
    102163
    103164        bld.SAMBA_BINARY('tdbtool',
    104165                         'tools/tdbtool.c',
    105                          'tdb', manpages='manpages/tdbtool.8')
     166                         'tdb', manpages='man/tdbtool.8')
     167
     168        if bld.env.standalone_tdb:
     169            # FIXME: This hardcoded list is stupid, stupid, stupid.
     170            bld.SAMBA_SUBSYSTEM('tdb-test-helpers',
     171                                'test/external-agent.c test/lock-tracking.c test/logging.c',
     172                                tdb_deps,
     173                                includes='include')
     174
     175            for t in tdb1_unit_tests:
     176                b = "tdb1-" + t
     177                s = "test/" + t + ".c"
     178                bld.SAMBA_BINARY(b, s, 'replace tdb-test-helpers',
     179                                 includes='include', install=False)
    106180
    107181    if not bld.CONFIG_SET('USING_SYSTEM_PYTDB'):
    108         bld.SAMBA_PYTHON('pytdb',
    109                          'pytdb.c',
    110                          deps='tdb',
    111                          enabled=not bld.env.disable_python,
    112                          realname='tdb.so',
    113                          cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
    114 
    115 
    116 
    117 def test(ctx):
     182        for env in bld.gen_python_environments(['PKGCONFIGDIR']):
     183            bld.SAMBA_PYTHON('pytdb',
     184                             'pytdb.c',
     185                             deps='tdb',
     186                             enabled=not bld.env.disable_python,
     187                             realname='tdb.so',
     188                             cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
     189
     190        if not bld.env.disable_python:
     191            for env in bld.gen_python_environments(['PKGCONFIGDIR']):
     192                bld.SAMBA_SCRIPT('_tdb_text.py',
     193                                 pattern='_tdb_text.py',
     194                                 installdir='python')
     195
     196                bld.INSTALL_FILES('${PYTHONARCHDIR}', '_tdb_text.py')
     197
     198def testonly(ctx):
    118199    '''run tdb testsuite'''
    119200    import Utils, samba_utils, shutil
     201    ecode = 0
     202
    120203    test_prefix = "%s/st" % (Utils.g_module.blddir)
    121204    shutil.rmtree(test_prefix, ignore_errors=True)
    122205    os.makedirs(test_prefix)
    123206    os.environ['TEST_DATA_PREFIX'] = test_prefix
    124     cmd = os.path.join(Utils.g_module.blddir, 'tdbtorture')
    125     ret = samba_utils.RUN_COMMAND(cmd)
    126     print("testsuite returned %d" % ret)
    127     sys.exit(ret)
     207
     208    env = samba_utils.LOAD_ENVIRONMENT()
     209    # FIXME: This is horrible :(
     210    if env.building_tdb:
     211        # Create scratch directory for tests.
     212        testdir = os.path.join(test_prefix, 'tdb-tests')
     213        samba_utils.mkdir_p(testdir)
     214        # Symlink back to source dir so it can find tests in test/
     215        link = os.path.join(testdir, 'test')
     216        if not os.path.exists(link):
     217            os.symlink(os.path.abspath(os.path.join(env.cwd, 'test')), link)
     218
     219        for t in tdb1_unit_tests:
     220            f = "tdb1-" + t
     221            cmd = "cd " + testdir + " && " + os.path.abspath(os.path.join(Utils.g_module.blddir, f)) + " > test-output 2>&1"
     222            print("..." + f)
     223            ret = samba_utils.RUN_COMMAND(cmd)
     224            if ret != 0:
     225                print("%s failed:" % f)
     226                samba_utils.RUN_COMMAND("cat " + os.path.join(testdir, 'test-output'))
     227                ecode = ret
     228                break
     229
     230    if ecode == 0:
     231        cmd = os.path.join(Utils.g_module.blddir, 'tdbtorture')
     232        ret = samba_utils.RUN_COMMAND(cmd)
     233        print("testsuite returned %d" % ret)
     234        if ret != 0:
     235            ecode = ret
     236
     237    pyret = samba_utils.RUN_PYTHON_TESTS(['python/tests/simple.py'])
     238    print("python testsuite returned %d" % pyret)
     239    sys.exit(ecode or pyret)
     240
     241# WAF doesn't build the unit tests for this, maybe because they don't link with tdb?
     242# This forces it
     243def test(ctx):
     244    import Scripting
     245    Scripting.commands.append('build')
     246    Scripting.commands.append('testonly')
    128247
    129248def dist():
Note: See TracChangeset for help on using the changeset viewer.