aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/cdb/cdb_init.c
blob: bfc6dd0c2a3b0908bb7d8c5917ece290a4f9989f (plain)
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* $Id: cdb_init.c,v 1.12 2008-11-06 18:07:04 mjt Exp $
 * cdb_init, cdb_free and cdb_read routines
 *
 * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
 * Public domain.
 */

#include "cdb.h"

unsigned
cdb_hash(const void *buf, unsigned len)
{
	register const unsigned char *p = (const unsigned char *) buf;
	register const unsigned char *end = p + len;
	register unsigned hash = 5381; /* start value */
	while (p < end)
		hash = (hash + (hash << 5)) ^ *p++;
	return hash;
}

int
cdb_init(struct cdb *cdbp, int fd)
{
	struct stat st;
	unsigned char *mem;
	unsigned fsize, dend;
#ifdef _WIN32
	HANDLE hFile, hMapping;
#endif

	/* get file size */
	if (fstat (fd, &st) < 0)
		return -1;
	/* trivial sanity check: at least toc should be here */
	if (st.st_size < 2048)
		return errno = EPROTO, -1;
	fsize = (unsigned) (st.st_size & 0xffffffffu);
	/* memory-map file */
#ifdef _WIN32
	hFile = (HANDLE) _get_osfhandle(fd);
	if (hFile == (HANDLE) -1)
	return -1;
	hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
	if (!hMapping)
	return -1;
	mem = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
	CloseHandle(hMapping);
	if (!mem)
	return -1;
#else
	mem = (unsigned char*) mmap (NULL, fsize, PROT_READ, MAP_SHARED, fd, 0);
	if (mem == MAP_FAILED)
		return -1;
#endif /* _WIN32 */

	cdbp->cdb_fd = fd;
	cdbp->cdb_fsize = fsize;
	cdbp->cdb_mem = mem;
	cdbp->mtime = st.st_mtime;

	cdbp->cdb_vpos = cdbp->cdb_vlen = 0;
	cdbp->cdb_kpos = cdbp->cdb_klen = 0;
	dend = cdb_unpack (mem);
	if (dend < 2048)
		dend = 2048;
	else if (dend >= fsize)
		dend = fsize;
	cdbp->cdb_dend = dend;

	return 0;
}

void
cdb_free(struct cdb *cdbp)
{
	if (cdbp->cdb_mem) {
#ifdef _WIN32
		UnmapViewOfFile((void*) cdbp->cdb_mem);
#else
		munmap ((void*) cdbp->cdb_mem, cdbp->cdb_fsize);
#endif /* _WIN32 */
		cdbp->cdb_mem = NULL;
	}
	cdbp->cdb_fsize = 0;

	if (cdbp->loop) {
		ev_stat_stop (cdbp->loop, &cdbp->stat_ev);
	}
}

const void *
cdb_get(const struct cdb *cdbp, unsigned len, unsigned pos)
{
	if (pos > cdbp->cdb_fsize || cdbp->cdb_fsize - pos < len) {
		errno = EPROTO;
		return NULL;
	}
	return cdbp->cdb_mem + pos;
}

int
cdb_read(const struct cdb *cdbp, void *buf, unsigned len, unsigned pos)
{
	const void *data = cdb_get (cdbp, len, pos);
	if (!data)
		return -1;
	memcpy (buf, data, len);
	return 0;
}

static void
cdb_timer_callback (EV_P_ ev_stat *w, int revents)
{
	struct cdb *cdbp = w->data;
	gint nfd;

	/* Check cdb file for modifications */
	if ((nfd = open (cdbp->filename, O_RDONLY)) != -1) {
		if (cdbp->cdb_mem) {
#ifdef _WIN32
			UnmapViewOfFile((void*) cdbp->cdb_mem);
#else
			munmap ((void*) cdbp->cdb_mem, cdbp->cdb_fsize);
#endif /* _WIN32 */
			cdbp->cdb_mem = NULL;
		}
		(void)close (cdbp->cdb_fd);
		cdbp->cdb_fsize = 0;
		(void)cdb_init (cdbp, nfd);
	}
}

void
cdb_add_timer (struct cdb *cdbp, EV_P_ ev_tstamp seconds)
{
	cdbp->loop = loop;
	ev_stat_init (&cdbp->stat_ev, cdb_timer_callback, cdbp->filename, seconds);
	cdbp->stat_ev.data = cdbp;
	ev_stat_start (EV_A_ &cdbp->stat_ev);
}