1 #define _XOPEN_SOURCE 500
2 #include "../common/tdb_private.h"
3 #include "../common/io.c"
4 #include "../common/tdb.c"
5 #include "../common/lock.c"
6 #include "../common/freelist.c"
7 #include "../common/traverse.c"
8 #include "../common/transaction.c"
9 #include "../common/error.c"
10 #include "../common/open.c"
11 #include "../common/check.c"
12 #include "../common/hash.c"
13 #include "tap-interface.h"
18 static int check(TDB_DATA key
, TDB_DATA data
, void *private)
20 unsigned int *sizes
= private;
22 if (key
.dsize
> strlen("hello"))
24 if (memcmp(key
.dptr
, "hello", key
.dsize
) != 0)
27 if (data
.dsize
!= strlen("world"))
29 if (memcmp(data
.dptr
, "world", data
.dsize
) != 0)
32 sizes
[0] += key
.dsize
;
33 sizes
[1] += data
.dsize
;
37 static void tdb_flip_bit(struct tdb_context
*tdb
, unsigned int bit
)
39 unsigned int off
= bit
/ CHAR_BIT
;
40 unsigned char mask
= (1 << (bit
% CHAR_BIT
));
43 ((unsigned char *)tdb
->map_ptr
)[off
] ^= mask
;
46 if (pread(tdb
->fd
, &c
, 1, off
) != 1)
49 if (pwrite(tdb
->fd
, &c
, 1, off
) != 1)
54 static void check_test(struct tdb_context
*tdb
)
57 unsigned int i
, verifiable
, corrupt
, sizes
[2], dsize
, ksize
;
59 ok1(tdb_check(tdb
, NULL
, NULL
) == 0);
61 key
.dptr
= (void *)"hello";
62 data
.dsize
= strlen("world");
63 data
.dptr
= (void *)"world";
65 /* Key and data size respectively. */
68 /* 5 keys in hash size 2 means we'll have multichains. */
69 for (key
.dsize
= 1; key
.dsize
<= 5; key
.dsize
++) {
72 if (tdb_store(tdb
, key
, data
, TDB_INSERT
) != 0)
76 /* This is how many bytes we expect to be verifiable. */
77 /* From the file header. */
78 verifiable
= strlen(TDB_MAGIC_FOOD
) + 1
79 + 2 * sizeof(uint32_t) + 2 * sizeof(tdb_off_t
)
80 + 2 * sizeof(uint32_t);
81 /* From the free list chain and hash chains. */
82 verifiable
+= 3 * sizeof(tdb_off_t
);
83 /* From the record headers & tailer */
84 verifiable
+= 5 * (sizeof(struct tdb_record
) + sizeof(uint32_t));
85 /* The free block: we ignore datalen, keylen, full_hash. */
86 verifiable
+= sizeof(struct tdb_record
) - 3*sizeof(uint32_t) +
88 /* Our check function verifies the key and data. */
89 verifiable
+= ksize
+ dsize
;
91 /* Flip one bit at a time, make sure it detects verifiable bytes. */
92 for (i
= 0, corrupt
= 0; i
< tdb
->map_size
* CHAR_BIT
; i
++) {
94 memset(sizes
, 0, sizeof(sizes
));
95 if (tdb_check(tdb
, check
, sizes
) != 0)
97 else if (sizes
[0] != ksize
|| sizes
[1] != dsize
)
101 ok(corrupt
== verifiable
* CHAR_BIT
, "corrupt %u should be %u",
102 corrupt
, verifiable
* CHAR_BIT
);
105 int main(int argc
, char *argv
[])
107 struct tdb_context
*tdb
;
110 /* This should use mmap. */
111 tdb
= tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST
,
112 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &taplogctx
, NULL
);
119 /* This should not. */
120 tdb
= tdb_open_ex("run-corrupt.tdb", 2, TDB_CLEAR_IF_FIRST
|TDB_NOMMAP
,
121 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &taplogctx
, NULL
);
128 return exit_status();