1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "storage/store.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int failures;
#define CHECK(value) \
do \
{ \
if (!(value)) \
{ \
fprintf(stderr, "CHECK failed at line %d: %s\n", __LINE__, #value); \
failures++; \
} \
} \
while (0)
int
wmain(void)
{
wchar_t temporary[MAX_PATH], directory[MAX_PATH], log_path[MAX_PATH];
tiny_store_t *store = NULL, *second = NULL;
tiny_message_t input, first, second_message;
tiny_store_status_t status;
HANDLE log;
HANDLE blocker;
tiny_rebuild_report_t report;
LARGE_INTEGER position;
unsigned char byte;
DWORD count;
CHECK(GetTempPathW(MAX_PATH, temporary) > 0);
CHECK(GetTempFileNameW(temporary, L"tcm", 0, directory) > 0);
DeleteFileW(directory);
CHECK(CreateDirectoryW(directory, NULL) != 0);
status = tiny_store_open(&store, directory);
CHECK(status == TINY_STORE_OK);
CHECK(tiny_store_open(&second, directory) == TINY_STORE_BUSY);
tiny_message_init(&input);
tiny_message_init(&first);
tiny_message_init(&second_message);
input.session_id = _strdup("unit");
input.content = _strdup("first");
input.role = TINY_ROLE_USER;
CHECK(tiny_store_write(store, &input, &first) == TINY_STORE_OK);
free(input.content);
input.content = _strdup("second");
CHECK(tiny_store_write(store, &input, &second_message) == TINY_STORE_OK);
CHECK(strcmp(first.message_id, second_message.message_id) < 0);
tiny_message_free(&input);
tiny_message_free(&first);
tiny_message_free(&second_message);
tiny_store_close(store);
store = NULL;
CHECK(tiny_store_open(&store, directory) == TINY_STORE_OK);
CHECK(tiny_store_entry_count(store) == 2);
swprintf_s(log_path, MAX_PATH, L"%s\\active.tmp", directory);
blocker = CreateFileW(
log_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
CHECK(blocker != INVALID_HANDLE_VALUE);
CHECK(tiny_store_rebuild(store, &report) == TINY_STORE_IO_ERROR);
CHECK(tiny_store_entry_count(store) == 2);
CloseHandle(blocker);
DeleteFileW(log_path);
tiny_store_close(store);
store = NULL;
swprintf_s(log_path, MAX_PATH, L"%s\\active.log", directory);
log = CreateFileW(
log_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
CHECK(log != INVALID_HANDLE_VALUE);
position.QuadPart = -1;
CHECK(SetFilePointerEx(log, position, NULL, FILE_END) != 0);
CHECK(ReadFile(log, &byte, 1, &count, NULL) != 0 && count == 1);
byte ^= 0x5a;
position.QuadPart = -1;
CHECK(SetFilePointerEx(log, position, NULL, FILE_CURRENT) != 0);
CHECK(WriteFile(log, &byte, 1, &count, NULL) != 0 && count == 1);
CloseHandle(log);
CHECK(tiny_store_open(&store, directory) == TINY_STORE_CORRUPT);
DeleteFileW(log_path);
swprintf_s(log_path, MAX_PATH, L"%s\\active.tmp", directory);
DeleteFileW(log_path);
swprintf_s(log_path, MAX_PATH, L"%s\\store.lock", directory);
DeleteFileW(log_path);
swprintf_s(log_path, MAX_PATH, L"%s\\snapshot.bin", directory);
DeleteFileW(log_path);
RemoveDirectoryW(directory);
return failures == 0 ? 0 : 1;
}
|