1 /* $Id: cdb_init.c,v 1.12 2008-11-06 18:07:04 mjt Exp $
2  * cdb_init, cdb_free and cdb_read routines
3  *
4  * This file is a part of tinycdb package by Michael Tokarev, mjt@corpit.ru.
5  * Public domain.
6  */
7 
8 #include "cdb.h"
9 
10 unsigned
cdb_hash(const void * buf,unsigned len)11 cdb_hash(const void *buf, unsigned len)
12 {
13 	register const unsigned char *p = (const unsigned char *) buf;
14 	register const unsigned char *end = p + len;
15 	register unsigned hash = 5381; /* start value */
16 	while (p < end)
17 		hash = (hash + (hash << 5)) ^ *p++;
18 	return hash;
19 }
20 
21 int
cdb_init(struct cdb * cdbp,int fd)22 cdb_init(struct cdb *cdbp, int fd)
23 {
24 	struct stat st;
25 	unsigned char *mem;
26 	unsigned fsize, dend;
27 #ifdef _WIN32
28 	HANDLE hFile, hMapping;
29 #endif
30 
31 	/* get file size */
32 	if (fstat (fd, &st) < 0)
33 		return -1;
34 	/* trivial sanity check: at least toc should be here */
35 	if (st.st_size < 2048)
36 		return errno = EPROTO, -1;
37 	fsize = (unsigned) (st.st_size & 0xffffffffu);
38 	/* memory-map file */
39 #ifdef _WIN32
40 	hFile = (HANDLE) _get_osfhandle(fd);
41 	if (hFile == (HANDLE) -1)
42 	return -1;
43 	hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
44 	if (!hMapping)
45 	return -1;
46 	mem = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
47 	CloseHandle(hMapping);
48 	if (!mem)
49 	return -1;
50 #else
51 	mem = (unsigned char*) mmap (NULL, fsize, PROT_READ, MAP_SHARED, fd, 0);
52 	if (mem == MAP_FAILED)
53 		return -1;
54 #endif /* _WIN32 */
55 
56 	cdbp->cdb_fd = fd;
57 	cdbp->cdb_fsize = fsize;
58 	cdbp->cdb_mem = mem;
59 	cdbp->mtime = st.st_mtime;
60 
61 	cdbp->cdb_vpos = cdbp->cdb_vlen = 0;
62 	cdbp->cdb_kpos = cdbp->cdb_klen = 0;
63 	dend = cdb_unpack (mem);
64 	if (dend < 2048)
65 		dend = 2048;
66 	else if (dend >= fsize)
67 		dend = fsize;
68 	cdbp->cdb_dend = dend;
69 
70 	return 0;
71 }
72 
73 void
cdb_free(struct cdb * cdbp)74 cdb_free(struct cdb *cdbp)
75 {
76 	if (cdbp->cdb_mem) {
77 #ifdef _WIN32
78 		UnmapViewOfFile((void*) cdbp->cdb_mem);
79 #else
80 		munmap ((void*) cdbp->cdb_mem, cdbp->cdb_fsize);
81 #endif /* _WIN32 */
82 		cdbp->cdb_mem = NULL;
83 	}
84 	cdbp->cdb_fsize = 0;
85 
86 	if (cdbp->loop) {
87 		ev_stat_stop (cdbp->loop, &cdbp->stat_ev);
88 	}
89 }
90 
91 const void *
cdb_get(const struct cdb * cdbp,unsigned len,unsigned pos)92 cdb_get(const struct cdb *cdbp, unsigned len, unsigned pos)
93 {
94 	if (pos > cdbp->cdb_fsize || cdbp->cdb_fsize - pos < len) {
95 		errno = EPROTO;
96 		return NULL;
97 	}
98 	return cdbp->cdb_mem + pos;
99 }
100 
101 int
cdb_read(const struct cdb * cdbp,void * buf,unsigned len,unsigned pos)102 cdb_read(const struct cdb *cdbp, void *buf, unsigned len, unsigned pos)
103 {
104 	const void *data = cdb_get (cdbp, len, pos);
105 	if (!data)
106 		return -1;
107 	memcpy (buf, data, len);
108 	return 0;
109 }
110 
111 static void
cdb_timer_callback(EV_P_ ev_stat * w,int revents)112 cdb_timer_callback (EV_P_ ev_stat *w, int revents)
113 {
114 	struct cdb *cdbp = w->data;
115 	gint nfd;
116 
117 	/* Check cdb file for modifications */
118 	if ((nfd = open (cdbp->filename, O_RDONLY)) != -1) {
119 		if (cdbp->cdb_mem) {
120 #ifdef _WIN32
121 			UnmapViewOfFile((void*) cdbp->cdb_mem);
122 #else
123 			munmap ((void*) cdbp->cdb_mem, cdbp->cdb_fsize);
124 #endif /* _WIN32 */
125 			cdbp->cdb_mem = NULL;
126 		}
127 		(void)close (cdbp->cdb_fd);
128 		cdbp->cdb_fsize = 0;
129 		(void)cdb_init (cdbp, nfd);
130 	}
131 }
132 
133 void
cdb_add_timer(struct cdb * cdbp,EV_P_ ev_tstamp seconds)134 cdb_add_timer (struct cdb *cdbp, EV_P_ ev_tstamp seconds)
135 {
136 	cdbp->loop = loop;
137 	ev_stat_init (&cdbp->stat_ev, cdb_timer_callback, cdbp->filename, seconds);
138 	cdbp->stat_ev.data = cdbp;
139 	ev_stat_start (EV_A_ &cdbp->stat_ev);
140 }
141