1 #include "tdb2-source.h"
2 #include <ccan/tap/tap.h>
5 #include "tdb1-logging.h"
7 static int check(TDB_DATA key
, TDB_DATA data
, void *private)
9 unsigned int *sizes
= private;
11 if (key
.dsize
> strlen("hello"))
13 if (memcmp(key
.dptr
, "hello", key
.dsize
) != 0)
16 if (data
.dsize
!= strlen("world"))
18 if (memcmp(data
.dptr
, "world", data
.dsize
) != 0)
21 sizes
[0] += key
.dsize
;
22 sizes
[1] += data
.dsize
;
26 static void tdb1_flip_bit(struct tdb1_context
*tdb
, unsigned int bit
)
28 unsigned int off
= bit
/ CHAR_BIT
;
29 unsigned char mask
= (1 << (bit
% CHAR_BIT
));
32 ((unsigned char *)tdb
->map_ptr
)[off
] ^= mask
;
35 if (pread(tdb
->fd
, &c
, 1, off
) != 1)
38 if (pwrite(tdb
->fd
, &c
, 1, off
) != 1)
43 static void check_test(struct tdb1_context
*tdb
)
46 unsigned int i
, verifiable
, corrupt
, sizes
[2], dsize
, ksize
;
48 ok1(tdb1_check(tdb
, NULL
, NULL
) == 0);
50 key
.dptr
= (void *)"hello";
51 data
.dsize
= strlen("world");
52 data
.dptr
= (void *)"world";
54 /* Key and data size respectively. */
57 /* 5 keys in hash size 2 means we'll have multichains. */
58 for (key
.dsize
= 1; key
.dsize
<= 5; key
.dsize
++) {
61 if (tdb1_store(tdb
, key
, data
, TDB_INSERT
) != 0)
65 /* This is how many bytes we expect to be verifiable. */
66 /* From the file header. */
67 verifiable
= strlen(TDB_MAGIC_FOOD
) + 1
68 + 2 * sizeof(uint32_t) + 2 * sizeof(tdb1_off_t
)
69 + 2 * sizeof(uint32_t);
70 /* From the free list chain and hash chains. */
71 verifiable
+= 3 * sizeof(tdb1_off_t
);
72 /* From the record headers & tailer */
73 verifiable
+= 5 * (sizeof(struct tdb1_record
) + sizeof(uint32_t));
74 /* The free block: we ignore datalen, keylen, full_hash. */
75 verifiable
+= sizeof(struct tdb1_record
) - 3*sizeof(uint32_t) +
77 /* Our check function verifies the key and data. */
78 verifiable
+= ksize
+ dsize
;
80 /* Flip one bit at a time, make sure it detects verifiable bytes. */
81 for (i
= 0, corrupt
= 0; i
< tdb
->map_size
* CHAR_BIT
; i
++) {
82 tdb1_flip_bit(tdb
, i
);
83 memset(sizes
, 0, sizeof(sizes
));
84 if (tdb1_check(tdb
, check
, sizes
) != 0)
86 else if (sizes
[0] != ksize
|| sizes
[1] != dsize
)
88 tdb1_flip_bit(tdb
, i
);
90 ok(corrupt
== verifiable
* CHAR_BIT
, "corrupt %u should be %u",
91 corrupt
, verifiable
* CHAR_BIT
);
94 int main(int argc
, char *argv
[])
96 struct tdb1_context
*tdb
;
99 /* This should use mmap. */
100 tdb
= tdb1_open_ex("run-corrupt.tdb", 2, TDB1_CLEAR_IF_FIRST
,
101 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &taplogctx
, NULL
);
108 /* This should not. */
109 tdb
= tdb1_open_ex("run-corrupt.tdb", 2, TDB1_CLEAR_IF_FIRST
|TDB1_NOMMAP
,
110 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &taplogctx
, NULL
);
117 return exit_status();