uhttpd: only enable Lua runtime if a handler was specified
[project/luci.git] / contrib / lar / lar.c
1 /*
2  * lar - Lua Archive Library
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
20 #include "lar.h"
21
22 static int lar_read32( int fd, uint32_t *val )
23 {
24         uint8_t buffer[5];
25
26         if( read(fd, buffer, 4) < 4 )
27                 LAR_DIE("Unexpected EOF while reading data");
28
29         buffer[4] = 0;
30         *val = ntohl(*((uint32_t *) buffer));
31
32         return 0;
33 }
34
35 static int lar_read16( int fd, uint16_t *val )
36 {
37         uint8_t buffer[3];
38
39         if( read(fd, buffer, 2) < 2 )
40                 LAR_DIE("Unexpected EOF while reading data");
41
42         buffer[2] = 0;
43         *val = ntohs(*((uint16_t *) buffer));
44
45         return 0;
46 }
47
48 static void lar_md5( char *md5, const char *data, int len )
49 {
50         md5_state_t state;
51
52         md5_init(&state);
53         md5_append(&state, (const md5_byte_t *)data, len);
54         md5_finish(&state, (md5_byte_t *)md5);
55 }
56
57 static int lar_read_filenames( lar_archive *ar )
58 {
59         int i;
60         int j;
61         char *filelist;
62         size_t pgof;
63         size_t pgsz = getpagesize();
64         lar_index *idx_ptr;
65         lar_index *idx_filelist = ar->index;
66
67         while(idx_filelist)
68         {
69                 if( idx_filelist->type == LAR_TYPE_FILELIST )
70                         break;
71
72                 idx_filelist = idx_filelist->next;
73         }
74
75         if( idx_filelist != NULL )
76         {
77                 pgof = ( idx_filelist->offset % pgsz );
78
79                 filelist = mmap(
80                         0, idx_filelist->length + pgof, PROT_READ, MAP_PRIVATE,
81                         ar->fd, idx_filelist->offset - pgof
82                 );
83
84                 if( filelist == MAP_FAILED )
85                         LAR_DIE("Failed to mmap() file list");
86
87
88                 idx_ptr = ar->index;
89                 i = pgof;
90
91                 while(idx_ptr)
92                 {
93                         if( idx_ptr->type == LAR_TYPE_REGULAR )
94                         {
95                                 j = strlen(&filelist[i]) + 1;
96
97                                 if( (j >= LAR_FNAME_BUFFER) ||
98                                     ((i+j) > (idx_filelist->length+pgof)) )
99                                                 LAR_DIE("Filename exceeds maximum allowed length");
100
101                                 idx_ptr->filename = (char *)malloc(j);
102                                 memcpy(idx_ptr->filename, &filelist[i], j);
103
104                                 i += j;
105                         }
106
107                         idx_ptr = idx_ptr->next;
108                 }
109
110                 munmap(filelist, idx_filelist->length + pgof);
111
112                 return 1;
113         }
114
115         return 0;
116 }
117
118 lar_index * lar_get_index( lar_archive *ar )
119 {
120         uint32_t i;
121         uint32_t idx_offset;
122         uint32_t idx_length;
123         lar_index *idx_map;
124         lar_index *idx_ptr;
125
126         if( lseek(ar->fd, -(sizeof(idx_offset)), SEEK_END) == -1 )
127                 LAR_DIE("Unable to seek to end of archive");
128
129         lar_read32(ar->fd, &idx_offset);
130         idx_length = ( ar->length - idx_offset - sizeof(idx_offset) );
131
132         if( lseek(ar->fd, idx_offset, SEEK_SET) == -1 )
133                 LAR_DIE("Unable to seek to archive index");
134
135
136         idx_map = NULL;
137
138         for( i = 0; i < idx_length; i += (sizeof(lar_index) - 2 * sizeof(char *)) )
139         {
140                 idx_ptr = (lar_index *)malloc(sizeof(lar_index));
141                 idx_ptr->filename = NULL;
142
143                 lar_read32(ar->fd, &idx_ptr->offset);
144                 lar_read32(ar->fd, &idx_ptr->length);
145                 lar_read16(ar->fd, &idx_ptr->type);
146                 lar_read16(ar->fd, &idx_ptr->flags);
147
148                 if(read(ar->fd,&idx_ptr->id,sizeof(idx_ptr->id)) < sizeof(idx_ptr->id))
149                         LAR_DIE("Unexpected EOF while reading member id");
150
151                 idx_ptr->next = idx_map;
152                 idx_map = idx_ptr;
153         }
154
155         return idx_map;
156 }
157
158 lar_member * lar_mmap_member( lar_archive *ar, lar_index *idx_ptr )
159 {
160         lar_member *member;
161         size_t pgsz = getpagesize();
162         size_t pgof = ( idx_ptr->offset % pgsz );
163
164         char *memberdata = mmap(
165                 0, idx_ptr->length + pgof, PROT_READ, MAP_PRIVATE,
166                 ar->fd, idx_ptr->offset - pgof
167         );
168
169         if( memberdata == MAP_FAILED )
170                 LAR_DIE("Failed to mmap() member data");
171
172         member = (lar_member *)malloc(sizeof(lar_member));
173         member->type   = idx_ptr->type;
174         member->flags  = idx_ptr->flags;
175         member->length = idx_ptr->length;
176         member->data   = &memberdata[pgof];
177
178         member->mmap   = memberdata;
179         member->mlen   = idx_ptr->length + pgof;
180
181         return member;
182 }
183
184 lar_member * lar_open_member( lar_archive *ar, const char *name )
185 {
186         lar_index *idx_ptr = ar->index;
187         char mbid[sizeof(idx_ptr->id)];
188
189         lar_md5(mbid, name, strlen(name));
190
191         while(idx_ptr)
192         {
193                 if( !strncmp(mbid, idx_ptr->id, sizeof(mbid)) )
194                         return lar_mmap_member(ar, idx_ptr);
195
196                 idx_ptr = idx_ptr->next;
197         }
198
199         return NULL;
200 }
201
202 int lar_close_member( lar_member *member )
203 {
204         int stat = munmap(member->mmap, member->mlen);
205         free(member);
206         member = NULL;
207
208         return stat;
209 }
210
211 lar_archive * lar_open( const char *filename )
212 {
213         int fd;
214         struct stat as;
215         lar_archive *ar;
216
217         if( stat(filename, &as) == -1 )
218                 return NULL;
219
220         if( !(as.st_mode & S_IFREG) )
221                 return NULL;
222
223         if( (fd = open(filename, O_RDONLY)) != -1 )
224         {
225                 ar = (lar_archive *)malloc(sizeof(lar_archive));
226                 ar->fd       = fd;
227                 ar->length   = as.st_size;
228                 ar->index    = lar_get_index(ar);
229                 strncpy(ar->filename, filename, sizeof(ar->filename));
230
231                 ar->has_filenames = lar_read_filenames(ar);
232
233                 return ar;
234         }
235
236         return NULL;
237 }
238
239 int lar_close( lar_archive *ar )
240 {
241         lar_index *idx_head;
242         lar_index *idx_next;
243
244         close(ar->fd);
245
246         idx_head = ar->index;
247         do {
248                 idx_next = idx_head->next;
249                 free(idx_head->filename);
250                 free(idx_head);
251         } while( (idx_head = idx_next) != NULL );
252
253         free(ar);
254         ar = NULL;
255
256         return 0;
257 }
258
259 lar_archive * lar_find_archive( const char *package, const char *path, int pkg )
260 {
261         uint32_t i;
262         uint32_t j;
263         uint32_t seg = 1;
264         uint32_t len = 0;
265         uint32_t pln = 0;
266         char sep = ( pkg ? '.' : '/' );
267         struct stat s;
268         LAR_FNAME(buffer);
269
270         if( path )
271         {
272                 for( pln = 0; path[pln] != '\0'; pln++ )
273                         if( pln >= (sizeof(buffer) - 5) )
274                                 LAR_DIE("Library path exceeds maximum allowed length");
275
276                 memcpy(buffer, path, pln);
277         }
278
279         if( buffer[pln-1] != '/' )
280                 buffer[pln++] = '/';
281
282         for( len = 0; package[len] != '\0'; len++ )
283         {
284                 if( len >= (sizeof(buffer) - 5 - pln) )
285                         LAR_DIE("Package name exceeds maximum allowed length");
286
287                 if( package[len] == sep ) seg++;
288         }
289
290         while( seg > 0 )
291         {
292                 for( i = 0, j = 1; (i < len) && (j <= seg); i++ )
293                 {
294                         if( package[i] == sep ) {
295                                 if( j < seg ) j++; else break;
296                         }
297
298                         buffer[pln+i] = ( package[i] == sep ) ? LAR_DIRSEP : package[i];
299                 }
300
301                 strcpy(&buffer[pln+i], ".lar");
302
303                 if( (stat(buffer, &s) > -1) && (s.st_mode & S_IFREG) )
304                         return lar_open(buffer);
305
306                 seg--;
307         }
308
309         return NULL;
310 }
311
312 lar_member * lar_find_member( lar_archive *ar, const char *package )
313 {
314         int len;
315         LAR_FNAME(buffer);
316
317         for( len = 0; package[len] != '\0'; len++ )
318         {
319                 if( len >= (sizeof(buffer) - 5) )
320                         LAR_DIE("Package name exceeds maximum allowed length");
321
322                 buffer[len] = ( package[len] == '.' ) ? '/' : package[len];
323         }
324
325         strcpy(&buffer[len], ".lua");
326
327         return lar_open_member(ar, buffer);
328 }