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 "tap-interface.h"
16 static int check(TDB_DATA key
, TDB_DATA data
, void *private)
18 unsigned int *sizes
= private;
20 if (key
.dsize
> strlen("hello"))
22 if (memcmp(key
.dptr
, "hello", key
.dsize
) != 0)
25 if (data
.dsize
!= strlen("world"))
27 if (memcmp(data
.dptr
, "world", data
.dsize
) != 0)
30 sizes
[0] += key
.dsize
;
31 sizes
[1] += data
.dsize
;
35 static void tdb_flip_bit(struct tdb_context
*tdb
, unsigned int bit
)
37 unsigned int off
= bit
/ CHAR_BIT
;
38 unsigned char mask
= (1 << (bit
% CHAR_BIT
));
41 ((unsigned char *)tdb
->map_ptr
)[off
] ^= mask
;
44 if (pread(tdb
->fd
, &c
, 1, off
) != 1) {
45 fprintf(stderr
, "pread: %s\n", strerror(errno
));
49 if (pwrite(tdb
->fd
, &c
, 1, off
) != 1) {
50 fprintf(stderr
, "pwrite: %s\n", strerror(errno
));
56 static void check_test(struct tdb_context
*tdb
)
59 unsigned int i
, verifiable
, corrupt
, sizes
[2], dsize
, ksize
;
61 ok1(tdb_check(tdb
, NULL
, NULL
) == 0);
63 key
.dptr
= discard_const_p(uint8_t, "hello");
64 data
.dsize
= strlen("world");
65 data
.dptr
= discard_const_p(uint8_t, "world");
67 /* Key and data size respectively. */
70 /* 5 keys in hash size 2 means we'll have multichains. */
71 for (key
.dsize
= 1; key
.dsize
<= 5; key
.dsize
++) {
74 if (tdb_store(tdb
, key
, data
, TDB_INSERT
) != 0)
78 /* This is how many bytes we expect to be verifiable. */
79 /* From the file header. */
80 verifiable
= strlen(TDB_MAGIC_FOOD
) + 1
81 + 2 * sizeof(uint32_t) + 2 * sizeof(tdb_off_t
)
82 + 2 * sizeof(uint32_t);
83 /* From the free list chain and hash chains. */
84 verifiable
+= 3 * sizeof(tdb_off_t
);
85 /* From the record headers & tailer */
86 verifiable
+= 5 * (sizeof(struct tdb_record
) + sizeof(uint32_t));
87 /* The free block: we ignore datalen, keylen, full_hash. */
88 verifiable
+= sizeof(struct tdb_record
) - 3*sizeof(uint32_t) +
90 /* Our check function verifies the key and data. */
91 verifiable
+= ksize
+ dsize
;
93 /* Flip one bit at a time, make sure it detects verifiable bytes. */
94 for (i
= 0, corrupt
= 0; i
< tdb
->map_size
* CHAR_BIT
; i
++) {
96 memset(sizes
, 0, sizeof(sizes
));
97 if (tdb_check(tdb
, check
, sizes
) != 0)
99 else if (sizes
[0] != ksize
|| sizes
[1] != dsize
)
101 tdb_flip_bit(tdb
, i
);
103 ok(corrupt
== verifiable
* CHAR_BIT
, "corrupt %u should be %u",
104 corrupt
, verifiable
* CHAR_BIT
);
107 int main(int argc
, char *argv
[])
109 struct tdb_context
*tdb
;
112 /* This should use mmap. */
113 tdb
= tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST
,
114 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &taplogctx
, NULL
);
121 /* This should not. */
122 tdb
= tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST
|TDB_NOMMAP
,
123 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &taplogctx
, NULL
);
130 return exit_status();