1 #include "tdb2-source.h"
2 #include "tap-interface.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 tdb_context
*tdb
, unsigned int bit
)
28 unsigned int off
= bit
/ CHAR_BIT
;
29 unsigned char mask
= (1 << (bit
% CHAR_BIT
));
31 if (tdb
->file
->map_ptr
)
32 ((unsigned char *)tdb
->file
->map_ptr
)[off
] ^= mask
;
35 if (pread(tdb
->file
->fd
, &c
, 1, off
) != 1)
38 if (pwrite(tdb
->file
->fd
, &c
, 1, off
) != 1)
43 static void check_test(struct tdb_context
*tdb
)
46 unsigned int i
, verifiable
, corrupt
, sizes
[2], dsize
, ksize
;
48 ok1(tdb_check(tdb
, NULL
, NULL
) == TDB_SUCCESS
);
50 key
= tdb_mkdata("hello", strlen("hello"));
51 data
= tdb_mkdata("world", strlen("world"));
53 /* Key and data size respectively. */
56 /* 5 keys in hash size 2 means we'll have multichains. */
57 for (key
.dsize
= 1; key
.dsize
<= 5; key
.dsize
++) {
60 if (tdb_store(tdb
, key
, data
, TDB_INSERT
) != TDB_SUCCESS
)
64 /* This is how many bytes we expect to be verifiable. */
65 /* From the file header. */
66 verifiable
= strlen(TDB_MAGIC_FOOD
) + 1
67 + 2 * sizeof(uint32_t) + 2 * sizeof(tdb1_off_t
)
68 + 2 * sizeof(uint32_t);
69 /* From the free list chain and hash chains. */
70 verifiable
+= 3 * sizeof(tdb1_off_t
);
71 /* From the record headers & tailer */
72 verifiable
+= 5 * (sizeof(struct tdb1_record
) + sizeof(uint32_t));
73 /* The free block: we ignore datalen, keylen, full_hash. */
74 verifiable
+= sizeof(struct tdb1_record
) - 3*sizeof(uint32_t) +
76 /* Our check function verifies the key and data. */
77 verifiable
+= ksize
+ dsize
;
79 /* Flip one bit at a time, make sure it detects verifiable bytes. */
80 for (i
= 0, corrupt
= 0; i
< tdb
->file
->map_size
* CHAR_BIT
; i
++) {
81 tdb1_flip_bit(tdb
, i
);
82 memset(sizes
, 0, sizeof(sizes
));
83 if (tdb_check(tdb
, check
, sizes
) == TDB_ERR_CORRUPT
)
85 else if (sizes
[0] != ksize
|| sizes
[1] != dsize
)
87 tdb1_flip_bit(tdb
, i
);
89 ok(corrupt
== verifiable
* CHAR_BIT
, "corrupt %u should be %u",
90 corrupt
, verifiable
* CHAR_BIT
);
93 int main(int argc
, char *argv
[])
95 struct tdb_context
*tdb
;
96 union tdb_attribute hsize
;
98 hsize
.base
.attr
= TDB_ATTRIBUTE_TDB1_HASHSIZE
;
99 hsize
.base
.next
= &tap_log_attr
;
100 hsize
.tdb1_hashsize
.hsize
= 2;
103 /* This should use mmap. */
104 tdb
= tdb_open("run-corrupt.tdb1", TDB_VERSION1
,
105 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &hsize
);
112 /* This should not. */
113 tdb
= tdb_open("run-corrupt.tdb1", TDB_VERSION1
|TDB_NOMMAP
,
114 O_CREAT
|O_TRUNC
|O_RDWR
, 0600, &hsize
);
121 return exit_status();