luci-0.11: merge r9399-r9402 and r9412
[project/luci.git] / libs / lmo / src / lmo_core.c
1 /*
2 * lmo - Lua Machine Objects - Base functions
3 *
4 * Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include "lmo.h"
20
21 extern char _lmo_error[1024];
22
23 static int lmo_read32( int fd, uint32_t *val )
24 {
25 if( read(fd, val, 4) < 4 )
26 return -1;
27
28 *val = ntohl(*val);
29
30 return 4;
31 }
32
33 static char * error(const char *message, int add_errno)
34 {
35 memset(_lmo_error, 0, sizeof(_lmo_error));
36
37 if( add_errno )
38 snprintf(_lmo_error, sizeof(_lmo_error),
39 "%s: %s", message, strerror(errno));
40 else
41 snprintf(_lmo_error, sizeof(_lmo_error), "%s", message);
42
43 return NULL;
44 }
45
46 const char * lmo_error(void)
47 {
48 return _lmo_error;
49 }
50
51 lmo_archive_t * lmo_open(const char *file)
52 {
53 int in = -1;
54 uint32_t idx_offset = 0;
55 uint32_t i;
56 struct stat s;
57
58 lmo_archive_t *ar = NULL;
59 lmo_entry_t *head = NULL;
60 lmo_entry_t *entry = NULL;
61
62 if( stat(file, &s) == -1 )
63 {
64 error("Can not stat file", 1);
65 goto cleanup;
66 }
67
68 if( (in = open(file, O_RDONLY)) == -1 )
69 {
70 error("Can not open file", 1);
71 goto cleanup;
72 }
73
74 if( lseek(in, -sizeof(uint32_t), SEEK_END) == -1 )
75 {
76 error("Can not seek to eof", 1);
77 goto cleanup;
78 }
79
80 if( lmo_read32(in, &idx_offset) != 4 )
81 {
82 error("Unexpected EOF while reading index offset", 0);
83 goto cleanup;
84 }
85
86 if( lseek(in, (off_t)idx_offset, SEEK_SET) == -1 )
87 {
88 error("Can not seek to index offset", 1);
89 goto cleanup;
90 }
91
92 if( (ar = (lmo_archive_t *) malloc(sizeof(lmo_archive_t))) != NULL )
93 {
94 ar->fd = in;
95 ar->length = idx_offset;
96
97 fcntl(ar->fd, F_SETFD, fcntl(ar->fd, F_GETFD) | FD_CLOEXEC);
98
99 for( i = idx_offset;
100 i < (s.st_size - sizeof(uint32_t));
101 i += (4 * sizeof(uint32_t))
102 ) {
103 if( (entry = (lmo_entry_t *) malloc(sizeof(lmo_entry_t))) != NULL )
104 {
105 if( (lmo_read32(ar->fd, &entry->key_id) == 4) &&
106 (lmo_read32(ar->fd, &entry->val_id) == 4) &&
107 (lmo_read32(ar->fd, &entry->offset) == 4) &&
108 (lmo_read32(ar->fd, &entry->length) == 4)
109 ) {
110 entry->next = head;
111 head = entry;
112 }
113 else
114 {
115 error("Unexpected EOF while reading index entry", 0);
116 goto cleanup;
117 }
118 }
119 else
120 {
121 error("Out of memory", 0);
122 goto cleanup;
123 }
124 }
125
126 ar->index = head;
127
128 if( lseek(ar->fd, 0, SEEK_SET) == -1 )
129 {
130 error("Can not seek to start", 1);
131 goto cleanup;
132 }
133
134 if( (ar->mmap = mmap(NULL, ar->length, PROT_READ, MAP_PRIVATE, ar->fd, 0)) == MAP_FAILED )
135 {
136 error("Failed to memory map archive contents", 1);
137 goto cleanup;
138 }
139
140 return ar;
141 }
142 else
143 {
144 error("Out of memory", 0);
145 goto cleanup;
146 }
147
148
149 cleanup:
150
151 if( in > -1 )
152 close(in);
153
154 if( head != NULL )
155 {
156 entry = head;
157
158 while( entry != NULL )
159 {
160 head = entry->next;
161 free(entry);
162 entry = head;
163 }
164
165 head = entry = NULL;
166 }
167
168 if( ar != NULL )
169 {
170 if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) )
171 munmap(ar->mmap, ar->length);
172
173 free(ar);
174 ar = NULL;
175 }
176
177 return NULL;
178 }
179
180 void lmo_close(lmo_archive_t *ar)
181 {
182 lmo_entry_t *head = NULL;
183 lmo_entry_t *entry = NULL;
184
185 if( ar != NULL )
186 {
187 entry = ar->index;
188
189 while( entry != NULL )
190 {
191 head = entry->next;
192 free(entry);
193 entry = head;
194 }
195
196 head = entry = NULL;
197
198 if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) )
199 munmap(ar->mmap, ar->length);
200
201 close(ar->fd);
202 free(ar);
203
204 ar = NULL;
205 }
206 }
207
208 int lmo_lookup(lmo_archive_t *ar, const char *key, char *dest, int len)
209 {
210 uint32_t look_key = sfh_hash(key, strlen(key));
211 int copy_len = -1;
212 lmo_entry_t *entry;
213
214 if( !ar )
215 return copy_len;
216
217 entry = ar->index;
218
219 while( entry != NULL )
220 {
221 if( entry->key_id == look_key )
222 {
223 copy_len = ((len - 1) > entry->length) ? entry->length : (len - 1);
224 memcpy(dest, &ar->mmap[entry->offset], copy_len);
225 dest[copy_len] = '\0';
226
227 break;
228 }
229
230 entry = entry->next;
231 }
232
233 return copy_len;
234 }