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