~ubuntu-branches/ubuntu/utopic/tdb/utopic-proposed

« back to all changes in this revision

Viewing changes to common/check.c

  • Committer: Bazaar Package Importer
  • Author(s): Jelmer Vernooij
  • Date: 2010-10-04 21:55:48 UTC
  • mfrom: (1.1.12 upstream) (3.2.5 sid)
  • Revision ID: james.westby@ubuntu.com-20101004215548-43p3vge27fml13jz
Tags: 1.2.7-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
static bool tdb_check_header(struct tdb_context *tdb, tdb_off_t *recovery)
29
29
{
30
30
        struct tdb_header hdr;
 
31
        uint32_t h1, h2;
31
32
 
32
 
        if (tdb->methods->tdb_read(tdb, 0, &hdr, sizeof(hdr), DOCONV()) == -1)
 
33
        if (tdb->methods->tdb_read(tdb, 0, &hdr, sizeof(hdr), 0) == -1)
33
34
                return false;
34
35
        if (strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0)
35
36
                goto corrupt;
38
39
        if (hdr.version != TDB_VERSION)
39
40
                goto corrupt;
40
41
 
41
 
        if (hdr.rwlocks != 0)
 
42
        if (hdr.rwlocks != 0 && hdr.rwlocks != TDB_HASH_RWLOCK_MAGIC)
 
43
                goto corrupt;
 
44
 
 
45
        tdb_header_hash(tdb, &h1, &h2);
 
46
        if (hdr.magic1_hash && hdr.magic2_hash &&
 
47
            (hdr.magic1_hash != h1 || hdr.magic2_hash != h2))
42
48
                goto corrupt;
43
49
 
44
50
        if (hdr.hash_size == 0)
301
307
        return true;
302
308
}
303
309
 
 
310
/* Slow, but should be very rare. */
 
311
static size_t dead_space(struct tdb_context *tdb, tdb_off_t off)
 
312
{
 
313
        size_t len;
 
314
 
 
315
        for (len = 0; off + len < tdb->map_size; len++) {
 
316
                char c;
 
317
                if (tdb->methods->tdb_read(tdb, off, &c, 1, 0))
 
318
                        return 0;
 
319
                if (c != 0 && c != 0x42)
 
320
                        break;
 
321
        }
 
322
        return len;
 
323
}
 
324
 
304
325
int tdb_check(struct tdb_context *tdb,
305
326
              int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
306
327
              void *private_data)
310
331
        tdb_off_t off, recovery_start;
311
332
        struct tdb_record rec;
312
333
        bool found_recovery = false;
 
334
        tdb_len_t dead;
 
335
        bool locked;
313
336
 
314
 
        if (tdb_lockall(tdb) == -1)
315
 
                return -1;
 
337
        /* Read-only databases use no locking at all: it's best-effort.
 
338
         * We may have a write lock already, so skip that case too. */
 
339
        if (tdb->read_only || tdb->allrecord_lock.count != 0) {
 
340
                locked = false;
 
341
        } else {
 
342
                if (tdb_lockall_read(tdb) == -1)
 
343
                        return -1;
 
344
                locked = true;
 
345
        }
316
346
 
317
347
        /* Make sure we know true size of the underlying file. */
318
348
        tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);
369
399
                        if (!tdb_check_free_record(tdb, off, &rec, hashes))
370
400
                                goto free;
371
401
                        break;
 
402
                /* If we crash after ftruncate, we can get zeroes or fill. */
 
403
                case TDB_RECOVERY_INVALID_MAGIC:
 
404
                case 0x42424242:
 
405
                        if (recovery_start == off) {
 
406
                                found_recovery = true;
 
407
                                break;
 
408
                        }
 
409
                        dead = dead_space(tdb, off);
 
410
                        if (dead < sizeof(rec))
 
411
                                goto corrupt;
 
412
 
 
413
                        TDB_LOG((tdb, TDB_DEBUG_ERROR,
 
414
                                 "Dead space at %d-%d (of %u)\n",
 
415
                                 off, off + dead, tdb->map_size));
 
416
                        rec.rec_len = dead - sizeof(rec);
 
417
                        break;
372
418
                case TDB_RECOVERY_MAGIC:
373
 
                case 0: /* Used for invalid (or in-progress) recovery area. */
374
419
                        if (recovery_start != off) {
375
420
                                TDB_LOG((tdb, TDB_DEBUG_ERROR,
376
421
                                         "Unexpected recovery record at offset %d\n",
379
424
                        }
380
425
                        found_recovery = true;
381
426
                        break;
382
 
                default:
 
427
                default: ;
 
428
                corrupt:
383
429
                        tdb->ecode = TDB_ERR_CORRUPT;
384
430
                        TDB_LOG((tdb, TDB_DEBUG_ERROR,
385
431
                                 "Bad magic 0x%x at offset %d\n",
405
451
        /* We must have found recovery area if there was one. */
406
452
        if (recovery_start != 0 && !found_recovery) {
407
453
                TDB_LOG((tdb, TDB_DEBUG_ERROR,
408
 
                         "Expected %s recovery area, got %s\n",
409
 
                         recovery_start ? "a" : "no",
410
 
                         found_recovery ? "one" : "none"));
 
454
                         "Expected a recovery area at %u\n",
 
455
                         recovery_start));
411
456
                goto free;
412
457
        }
413
458
 
414
459
        free(hashes);
415
 
        tdb_unlockall(tdb);
 
460
        if (locked) {
 
461
                tdb_unlockall_read(tdb);
 
462
        }
416
463
        return 0;
417
464
 
418
465
free:
419
466
        free(hashes);
420
467
unlock:
421
 
        tdb_unlockall(tdb);
 
468
        if (locked) {
 
469
                tdb_unlockall_read(tdb);
 
470
        }
422
471
        return -1;
423
472
}