libs/lmo: jffs2 does not support mmap() with MAP_SHARED, use MAP_PRIVATE instead...
[project/luci.git] / libs / lmo / src / lmo_core.c
1 /*
2  * lmo - Lua Machine Objects - Base functions
3  *
4  *   Copyright (C) 2009 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         uint8_t buffer[5];
26
27         if( read(fd, buffer, 4) < 4 )
28                 return -1;
29
30         buffer[4] = 0;
31         *val = ntohl(*((uint32_t *) buffer));
32
33         return 4;
34 }
35
36 static char * error(const char *message, int add_errno)
37 {
38         memset(_lmo_error, 0, sizeof(_lmo_error));
39
40         if( add_errno )
41                 snprintf(_lmo_error, sizeof(_lmo_error),
42                         "%s: %s", message, strerror(errno));
43         else
44                 snprintf(_lmo_error, sizeof(_lmo_error), "%s", message);
45
46         return NULL;
47 }
48
49 const char * lmo_error(void)
50 {
51         return _lmo_error;
52 }
53
54 lmo_archive_t * lmo_open(const char *file)
55 {
56         int in = -1;
57         uint32_t idx_offset = 0;
58         uint32_t i;
59         struct stat s;
60
61         lmo_archive_t *ar    = NULL;
62         lmo_entry_t   *head  = NULL;
63         lmo_entry_t   *entry = NULL;
64
65         if( stat(file, &s) == -1 )
66         {
67                 error("Can not stat file", 1);
68                 goto cleanup;
69         }
70
71         if( (in = open(file, O_RDONLY)) == -1 )
72         {
73                 error("Can not open file", 1);
74                 goto cleanup;
75         }
76
77         if( lseek(in, -sizeof(uint32_t), SEEK_END) == -1 )
78         {
79                 error("Can not seek to eof", 1);
80                 goto cleanup;
81         }
82
83         if( lmo_read32(in, &idx_offset) != 4 )
84         {
85                 error("Unexpected EOF while reading index offset", 0);
86                 goto cleanup;
87         }
88
89         if( lseek(in, idx_offset, SEEK_SET) == -1 )
90         {
91                 error("Can not seek to index offset", 1);
92                 goto cleanup;
93         }
94
95         if( (ar = (lmo_archive_t *) malloc(sizeof(lmo_archive_t))) != NULL )
96         {
97                 ar->fd     = in;
98                 ar->length = idx_offset;
99
100                 for( i = idx_offset;
101                      i < (s.st_size - sizeof(uint32_t));
102                      i += (4 * sizeof(uint32_t))
103                 ) {
104                         if( (entry = (lmo_entry_t *) malloc(sizeof(lmo_entry_t))) != NULL )
105                         {
106                                 if( (lmo_read32(ar->fd, &entry->key_id) == 4) &&
107                                     (lmo_read32(ar->fd, &entry->val_id) == 4) &&
108                                     (lmo_read32(ar->fd, &entry->offset) == 4) &&
109                                     (lmo_read32(ar->fd, &entry->length) == 4)
110                                 ) {
111                                         entry->next = head;
112                                         head = entry;
113                                 }
114                                 else
115                                 {
116                                         error("Unexpected EOF while reading index entry", 0);
117                                         goto cleanup;
118                                 }
119                         }
120                         else
121                         {
122                                 error("Out of memory", 0);
123                                 goto cleanup;
124                         }
125                 }
126
127                 ar->index = head;
128
129                 if( lseek(ar->fd, 0, SEEK_SET) == -1 )
130                 {
131                         error("Can not seek to start", 1);
132                         goto cleanup;
133                 }
134
135                 if( (ar->mmap = mmap(NULL, ar->length, PROT_READ, MAP_PRIVATE, ar->fd, 0)) == MAP_FAILED )
136                 {
137                         error("Failed to memory map archive contents", 1);
138                         goto cleanup;
139                 }
140
141                 return ar;
142         }
143         else
144         {
145                 error("Out of memory", 0);
146                 goto cleanup;
147         }
148
149
150         cleanup:
151
152         if( in > -1 )
153                 close(in);
154
155         if( head != NULL )
156         {
157                 entry = head;
158
159                 while( entry != NULL )
160                 {
161                         head = entry->next;
162                         free(entry);
163                         entry = head;
164                 }
165
166                 head = entry = NULL;
167         }
168
169         if( ar != NULL )
170         {
171                 if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) )
172                         munmap(ar->mmap, ar->length);
173
174                 free(ar);
175                 ar = NULL;
176         }
177
178         return NULL;
179 }
180
181 void lmo_close(lmo_archive_t *ar)
182 {
183         lmo_entry_t *head  = NULL;
184         lmo_entry_t *entry = NULL;
185
186         if( ar != NULL )
187         {
188                 entry = ar->index;
189
190                 while( entry != NULL )
191                 {
192                         head = entry->next;
193                         free(entry);
194                         entry = head;
195                 }
196
197                 head = entry = NULL;
198
199                 if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) )
200                         munmap(ar->mmap, ar->length);
201
202                 close(ar->fd);
203                 free(ar);
204
205                 ar = NULL;
206         }
207 }
208
209 int lmo_lookup(lmo_archive_t *ar, const char *key, char *dest, int len)
210 {
211         uint32_t look_key = sfh_hash(key, strlen(key));
212         int copy_len = -1;
213
214         lmo_entry_t *entry = ar->index;
215
216         while( entry != NULL )
217         {
218                 if( entry->key_id == look_key )
219                 {
220                         copy_len = (len > entry->length) ? entry->length : len;
221                         memcpy(dest, &ar->mmap[entry->offset], copy_len);
222
223                         break;
224                 }
225
226                 entry = entry->next;
227         }
228
229         return copy_len;
230 }
231