Line data Source code
1 : #include "../common/tdb_private.h"
2 : #include "../common/io.c"
3 : #include "../common/tdb.c"
4 : #include "../common/lock.c"
5 : #include "../common/freelist.c"
6 : #include "../common/traverse.c"
7 : #include "../common/transaction.c"
8 : #include "../common/error.c"
9 : #include "../common/open.c"
10 : #include "../common/check.c"
11 : #include "../common/hash.c"
12 : #include "../common/mutex.c"
13 : #include "tap-interface.h"
14 : #include <stdlib.h>
15 : #include "logging.h"
16 :
17 315638 : static int check(TDB_DATA key, TDB_DATA data, void *private)
18 : {
19 315638 : unsigned int *sizes = private;
20 :
21 315638 : if (key.dsize > strlen("hello"))
22 0 : return -1;
23 315638 : if (memcmp(key.dptr, "hello", key.dsize) != 0)
24 0 : return -1;
25 :
26 315638 : if (data.dsize != strlen("world"))
27 28 : return -1;
28 315610 : if (memcmp(data.dptr, "world", data.dsize) != 0)
29 400 : return -1;
30 :
31 315210 : sizes[0] += key.dsize;
32 315210 : sizes[1] += data.dsize;
33 315210 : return 0;
34 : }
35 :
36 131072 : static void tdb_flip_bit(struct tdb_context *tdb, unsigned int bit)
37 : {
38 131072 : unsigned int off = bit / CHAR_BIT;
39 131072 : unsigned char mask = (1 << (bit % CHAR_BIT));
40 :
41 131072 : if (tdb->map_ptr)
42 65536 : ((unsigned char *)tdb->map_ptr)[off] ^= mask;
43 : else {
44 : unsigned char c;
45 65536 : if (pread(tdb->fd, &c, 1, off) != 1) {
46 0 : fprintf(stderr, "pread: %s\n", strerror(errno));
47 0 : exit(1);
48 : }
49 65536 : c ^= mask;
50 65536 : if (pwrite(tdb->fd, &c, 1, off) != 1) {
51 0 : fprintf(stderr, "pwrite: %s\n", strerror(errno));
52 0 : exit(1);
53 : }
54 : }
55 131072 : }
56 :
57 2 : static void check_test(struct tdb_context *tdb)
58 : {
59 : TDB_DATA key, data;
60 : unsigned int i, verifiable, corrupt, sizes[2], dsize, ksize;
61 :
62 2 : ok1(tdb_check(tdb, NULL, NULL) == 0);
63 :
64 2 : key.dptr = discard_const_p(uint8_t, "hello");
65 2 : data.dsize = strlen("world");
66 2 : data.dptr = discard_const_p(uint8_t, "world");
67 :
68 : /* Key and data size respectively. */
69 2 : dsize = ksize = 0;
70 :
71 : /* 5 keys in hash size 2 means we'll have multichains. */
72 12 : for (key.dsize = 1; key.dsize <= 5; key.dsize++) {
73 10 : ksize += key.dsize;
74 10 : dsize += data.dsize;
75 10 : if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
76 0 : abort();
77 : }
78 :
79 : /* This is how many bytes we expect to be verifiable. */
80 : /* From the file header. */
81 2 : verifiable = strlen(TDB_MAGIC_FOOD) + 1
82 : + 2 * sizeof(uint32_t) + 2 * sizeof(tdb_off_t)
83 : + 2 * sizeof(uint32_t);
84 : /* From the free list chain and hash chains. */
85 2 : verifiable += 3 * sizeof(tdb_off_t);
86 : /* From the record headers & tailer */
87 2 : verifiable += 5 * (sizeof(struct tdb_record) + sizeof(uint32_t));
88 : /* The free block: we ignore datalen, keylen, full_hash. */
89 2 : verifiable += sizeof(struct tdb_record) - 3*sizeof(uint32_t) +
90 : sizeof(uint32_t);
91 : /* Our check function verifies the key and data. */
92 2 : verifiable += ksize + dsize;
93 :
94 : /* Flip one bit at a time, make sure it detects verifiable bytes. */
95 65538 : for (i = 0, corrupt = 0; i < tdb->map_size * CHAR_BIT; i++) {
96 65536 : tdb_flip_bit(tdb, i);
97 65536 : memset(sizes, 0, sizeof(sizes));
98 65536 : if (tdb_check(tdb, check, sizes) != 0)
99 3872 : corrupt++;
100 61664 : else if (sizes[0] != ksize || sizes[1] != dsize)
101 0 : corrupt++;
102 65536 : tdb_flip_bit(tdb, i);
103 : }
104 2 : ok(corrupt == verifiable * CHAR_BIT, "corrupt %u should be %u",
105 : corrupt, verifiable * CHAR_BIT);
106 2 : }
107 :
108 1 : int main(int argc, char *argv[])
109 : {
110 : struct tdb_context *tdb;
111 :
112 : plan_tests(4);
113 : /* This should use mmap. */
114 1 : tdb = tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST,
115 : O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
116 :
117 1 : if (!tdb)
118 0 : abort();
119 1 : check_test(tdb);
120 1 : tdb_close(tdb);
121 :
122 : /* This should not. */
123 1 : tdb = tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST|TDB_NOMMAP,
124 : O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL);
125 :
126 1 : if (!tdb)
127 0 : abort();
128 1 : check_test(tdb);
129 1 : tdb_close(tdb);
130 :
131 1 : return exit_status();
132 : }
|