08141383e3dcd04f3f3d00554a0dc485212ecea1
[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 }