contrib/lar:
[project/luci.git] / contrib / lar / larlib.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 "lua.h"
21 #include "lualib.h"
22 #include "lauxlib.h"
23 #include "lar.h"
24
25 typedef struct {
26 int fd;
27 char *data;
28 size_t length;
29 } mmap_handle;
30
31 static int larlib_perror( lua_State *L, const char *message )
32 {
33 lua_pushnil(L);
34 lua_pushstring(L, message);
35
36 return 2;
37 }
38
39 int larlib_open( lua_State *L )
40 {
41 lar_archive *ar, **udata;
42 const char *filename = luaL_checkstring( L, 1 );
43
44 if( filename != NULL && (ar = lar_open(filename)) != NULL )
45 {
46 if( (udata = lua_newuserdata(L, sizeof(lar_archive *))) != NULL )
47 {
48 *udata = ar;
49 luaL_getmetatable(L, "lar.archive");
50 lua_setmetatable(L, -2);
51 }
52 else
53 {
54 return luaL_error(L, "Out of memory");
55 }
56 }
57 else
58 {
59 return larlib_perror(L, "Archive not found");
60 }
61
62 return 1;
63 }
64
65 int larlib_find( lua_State *L )
66 {
67 const char *filename = luaL_checkstring( L, 1 );
68 const char *basepath = luaL_optstring( L, 2, "./" );
69 int is_pkg = strstr(filename, "/") ? 0 : 1;
70 lar_archive *ar, **udata;
71
72 if( ((ar = lar_find_archive(filename, basepath, is_pkg)) != NULL) ||
73 ((ar = lar_find_archive(filename, LUA_LDIR, is_pkg)) != NULL) ||
74 ((ar = lar_find_archive(filename, LUA_CDIR, is_pkg)) != NULL) )
75 {
76 if( (udata = lua_newuserdata(L, sizeof(lar_archive *))) != NULL )
77 {
78 *udata = ar;
79 luaL_getmetatable(L, "lar.archive");
80 lua_setmetatable(L, -2);
81 }
82 else
83 {
84 return luaL_error(L, "Out of memory");
85 }
86 }
87 else
88 {
89 return larlib_perror(L, "Archive not found");
90 }
91
92 return 1;
93 }
94
95 int larlib_md5( lua_State *L )
96 {
97 int i;
98 char md5[16], md5_hex[33];
99 const char *data = luaL_checkstring( L, 1 );
100 md5_state_t state;
101
102 md5_init(&state);
103 md5_append(&state, (const md5_byte_t *)data, strlen(data));
104 md5_finish(&state, (md5_byte_t *)md5);
105
106 for( i = 0; i < 16; i++ )
107 sprintf(&md5_hex[i*2], "%02x", (unsigned char)md5[i]);
108
109 lua_pushstring(L, md5_hex);
110 return 1;
111 }
112
113 int larlib_md5_file( lua_State *L )
114 {
115 int i, fd, len;
116 char md5[16], md5_hex[33], buffer[1024];
117 const char *filename = luaL_checkstring( L, 1 );
118 md5_state_t state;
119
120 if( (fd = open(filename, O_RDONLY)) != -1 )
121 {
122 md5_init(&state);
123
124 while( (len = read(fd, buffer, 1024)) > 0 )
125 md5_append(&state, (const md5_byte_t *)buffer, len);
126
127 md5_finish(&state, (md5_byte_t *)md5);
128
129 for( i = 0; i < 16; i++ )
130 sprintf(&md5_hex[i*2], "%02x", (unsigned char)md5[i]);
131
132 close(fd);
133 lua_pushstring(L, md5_hex);
134 }
135 else
136 {
137 return larlib_perror(L, strerror(errno));
138 }
139
140 return 1;
141 }
142
143 static int larlib_mkpath( const char *name, const char *path, char *buffer )
144 {
145 int nlen = strlen(name);
146 int plen = strlen(path);
147
148 if( (nlen + plen + 1) <= 1024 )
149 {
150 strcpy(buffer, path);
151
152 if( buffer[plen-1] != '/' )
153 buffer[plen++] = '/';
154
155 strcpy(&buffer[plen], name);
156 buffer[plen + nlen] = '\0';
157
158 return 0;
159 }
160
161 return 1;
162 }
163
164 static int larlib__gc( lua_State *L )
165 {
166 lar_archive **archive = luaL_checkudata( L, 1, "lar.archive" );
167
168 if( *archive )
169 lar_close(*archive);
170
171 *archive = NULL;
172 return 0;
173 }
174
175
176 static int larlib_member__open( lua_State *L, lar_member *mb )
177 {
178 lar_archive **archive = NULL;
179 const char *filename = NULL;
180 lar_member **udata;
181
182 if( mb == NULL )
183 {
184 *archive = luaL_checkudata( L, 1, "lar.archive" );
185 filename = luaL_checkstring( L, 2 );
186 }
187
188 if( mb != NULL || (mb = lar_open_member(*archive, filename)) != NULL )
189 {
190 if( (udata = lua_newuserdata(L, sizeof(lar_member *))) != NULL )
191 {
192 *udata = mb;
193 luaL_getmetatable(L, "lar.member");
194 lua_setmetatable(L, -2);
195 }
196 else
197 {
198 return luaL_error(L, "Out of memory");
199 }
200 }
201 else
202 {
203 return larlib_perror(L, "Member not found in archive");
204 }
205
206 return 1;
207 }
208
209 int larlib_member_open( lua_State *L )
210 {
211 return larlib_member__open( L, NULL );
212 }
213
214 int larlib_member_find( lua_State *L )
215 {
216 lar_archive **archive = luaL_checkudata( L, 1, "lar.archive" );
217 const char *package = luaL_checkstring( L, 2 );
218 lar_member *mb, **udata;
219
220 if( (mb = lar_find_member(*archive, package)) != NULL )
221 {
222 if( (udata = lua_newuserdata(L, sizeof(lar_member *))) != NULL )
223 {
224 *udata = mb;
225 luaL_getmetatable(L, "lar.member");
226 lua_setmetatable(L, -2);
227 }
228 else
229 {
230 return luaL_error(L, "Out of memory");
231 }
232 }
233 else
234 {
235 return larlib_perror(L, "Member not found in archive");
236 }
237
238 return 1;
239 }
240
241 int larlib_member_size( lua_State *L )
242 {
243 lar_member **member = luaL_checkudata( L, 1, "lar.member" );
244 lua_pushnumber(L, (*member)->length);
245 return 1;
246 }
247
248 int larlib_member_type( lua_State *L )
249 {
250 lar_member **member = luaL_checkudata( L, 1, "lar.member" );
251 lua_pushnumber(L, (*member)->type);
252 return 1;
253 }
254
255 int larlib_member_flags( lua_State *L )
256 {
257 lar_member **member = luaL_checkudata( L, 1, "lar.member" );
258 lua_pushnumber(L, (*member)->flags);
259 return 1;
260 }
261
262 int larlib_member_read( lua_State *L )
263 {
264 lar_member **member = luaL_checkudata( L, 1, "lar.member" );
265 int start = luaL_checknumber( L, 2 );
266 int length = luaL_optnumber( L, 3, (*member)->length );
267 char *stringcopy;
268
269 if( (start >= 0) && (start < (*member)->length) && (length > 0) )
270 {
271 if( (start + length) >= (*member)->length )
272 length = (*member)->length - start;
273
274 if( (stringcopy = (char *)malloc(length + 1)) != NULL )
275 {
276 memcpy(stringcopy, &(*member)->data[start], length);
277 stringcopy[length] = '\0';
278 lua_pushstring(L, stringcopy);
279 free(stringcopy);
280 }
281 else
282 {
283 return luaL_error(L, "Out of memory");
284 }
285 }
286 else
287 {
288 return larlib_perror(L, "Invalid argument");
289 }
290
291 return 1;
292 }
293
294 int larlib_member_data( lua_State *L )
295 {
296 lar_member **member = luaL_checkudata( L, 1, "lar.member" );
297 lua_pushstring(L, (*member)->data);
298 return 1;
299 }
300
301 int larlib_member_load( lua_State *L )
302 {
303 lar_member **member = luaL_checkudata( L, 1, "lar.member" );
304 int status = luaL_loadbuffer( L, (*member)->data, (*member)->length,
305 "=(lar member)" );
306
307 if( status )
308 {
309 lua_pushnil(L);
310 lua_insert(L, -2);
311 return 2;
312 }
313
314 return 1;
315 }
316
317 static int larlib_member__gc( lua_State *L )
318 {
319 lar_member **member = luaL_checkudata( L, 1, "lar.member" );
320
321 if( *member )
322 lar_close_member(*member);
323
324 *member = NULL;
325 return 0;
326 }
327
328
329 static int larlib_mmfile__open( lua_State *L, const char *filename )
330 {
331 struct stat s;
332 mmap_handle *fh, **udata;
333
334 if( filename == NULL )
335 filename = (const char *)luaL_checkstring( L, 1 );
336
337 if( (fh = (mmap_handle *)malloc(sizeof(mmap_handle))) == NULL )
338 return larlib_perror(L, "Out of memory");
339
340 if( stat(filename, &s) > -1 && (fh->fd = open(filename, O_RDONLY)) > -1 )
341 {
342 fh->length = s.st_size;
343 fh->data = mmap( 0, s.st_size, PROT_READ, MAP_PRIVATE, fh->fd, 0 );
344
345 if( fh->data == MAP_FAILED )
346 return larlib_perror(L, "Failed to mmap() file");
347
348 if( (udata = lua_newuserdata(L, sizeof(char *))) != NULL )
349 {
350 *udata = fh;
351 luaL_getmetatable(L, "lar.mmfile");
352 lua_setmetatable(L, -2);
353 }
354 else
355 {
356 return larlib_perror(L, "Out of memory");
357 }
358 }
359 else
360 {
361 return larlib_perror(L, strerror(errno));
362 }
363
364 return 1;
365 }
366
367 int larlib_mmfile_open( lua_State *L )
368 {
369 return larlib_mmfile__open(L, NULL);
370 }
371
372 int larlib_mmfile_size( lua_State *L )
373 {
374 mmap_handle **fh = luaL_checkudata( L, 1, "lar.mmfile" );
375 lua_pushnumber(L, (*fh)->length);
376 return 1;
377 }
378
379 int larlib_mmfile_read( lua_State *L )
380 {
381 mmap_handle **fh = luaL_checkudata( L, 1, "lar.mmfile" );
382 int start = luaL_checknumber( L, 2 );
383 int length = luaL_optnumber( L, 3, (*fh)->length );
384 char *stringcopy;
385
386 if( (start >= 0) && (start < (*fh)->length) && (length > 0) )
387 {
388 if( (start + length) >= (*fh)->length )
389 length = (*fh)->length - start;
390
391 if( (stringcopy = (char *)malloc(length + 1)) != NULL )
392 {
393 memcpy(stringcopy, &(*fh)->data[start], length);
394 stringcopy[length] = '\0';
395 lua_pushstring(L, stringcopy);
396 free(stringcopy);
397 }
398 else
399 {
400 return luaL_error(L, "Out of memory");
401 }
402 }
403 else
404 {
405 return larlib_perror(L, "Invalid argument");
406 }
407
408 return 1;
409 }
410
411 int larlib_mmfile_data( lua_State *L )
412 {
413 mmap_handle **fh = luaL_checkudata( L, 1, "lar.mmfile" );
414 lua_pushstring(L, (*fh)->data);
415 return 1;
416 }
417
418 int larlib_mmfile_load( lua_State *L )
419 {
420 mmap_handle **fh = luaL_checkudata( L, 1, "lar.mmfile" );
421 int status = luaL_loadbuffer(L, (*fh)->data, (*fh)->length, "=(mmap file)");
422
423 if( status )
424 {
425 lua_pushnil(L);
426 lua_insert(L, -2);
427 return 2;
428 }
429
430 return 1;
431 }
432
433 static int larlib_mmfile__gc( lua_State *L )
434 {
435 mmap_handle **fh = luaL_checkudata( L, 1, "lar.mmfile" );
436
437 if( *fh )
438 {
439 close((*fh)->fd);
440 munmap((*fh)->data, (*fh)->length);
441 free(*fh);
442 *fh = NULL;
443 }
444
445 return 0;
446 }
447
448
449 int larlib_findfile( lua_State *L )
450 {
451 int i;
452 const char *filename = luaL_checkstring( L, 1 );
453 const char *basepath = luaL_optstring( L, 2, "./" );
454 char filepath[1024];
455 struct stat s;
456 lar_archive *ar;
457 lar_member *mb;
458
459 const char *searchpath[3] = { basepath, LUA_LDIR, LUA_CDIR };
460
461 for( i = 0; i < 3; i++ )
462 if( !larlib_mkpath(filename, searchpath[i], filepath) )
463 if( stat(filepath, &s) > -1 && (s.st_mode & S_IFREG) )
464 return larlib_mmfile__open( L, filepath );
465
466 for( i = 0; i < 3; i++ )
467 if( (ar = lar_find_archive(filename, searchpath[i], 0)) != NULL )
468 if( (mb = lar_open_member(ar, filename)) != NULL )
469 return larlib_member__open( L, mb );
470
471 return larlib_perror(L, "File not found");
472 }
473
474
475 static const luaL_reg LAR_REG[] = {
476 { "open", larlib_open },
477 { "find", larlib_find },
478 { "md5", larlib_md5 },
479 { "md5_file", larlib_md5_file },
480 { "mmap", larlib_mmfile_open },
481 { "findfile", larlib_findfile },
482 { NULL, NULL }
483 };
484
485 static const luaL_reg LAR_ARCHIVE_REG[] = {
486 { "member", larlib_member_open },
487 { "find", larlib_member_find },
488 { "__gc", larlib__gc },
489 { NULL, NULL }
490 };
491
492 static const luaL_reg LAR_MEMBER_REG[] = {
493 { "size", larlib_member_size },
494 { "type", larlib_member_type },
495 { "flags", larlib_member_flags },
496 { "read", larlib_member_read },
497 { "data", larlib_member_data },
498 { "load", larlib_member_load },
499 { "__gc", larlib_member__gc },
500 { NULL, NULL }
501 };
502
503 static const luaL_reg LAR_MMFILE_REG[] = {
504 { "size", larlib_mmfile_size },
505 { "read", larlib_mmfile_read },
506 { "data", larlib_mmfile_data },
507 { "load", larlib_mmfile_load },
508 { "__gc", larlib_mmfile__gc },
509 { NULL, NULL }
510 };
511
512
513 LUALIB_API int luaopen_larlib( lua_State *L )
514 {
515 luaL_newmetatable(L, "lar");
516 luaL_register(L, NULL, LAR_REG);
517 lua_pushvalue(L, -1);
518 lua_setfield(L, -2, "__index");
519 lua_setglobal(L, "lar");
520
521 luaL_newmetatable(L, "lar.archive");
522 luaL_register(L, NULL, LAR_ARCHIVE_REG);
523 lua_pushvalue(L, -1);
524 lua_setfield(L, -2, "__index");
525 lua_setglobal(L, "lar.archive");
526
527 luaL_newmetatable(L, "lar.member");
528 luaL_register(L, NULL, LAR_MEMBER_REG);
529 lua_pushvalue(L, -1);
530 lua_setfield(L, -2, "__index");
531 lua_setglobal(L, "lar.member");
532
533 luaL_newmetatable(L, "lar.mmfile");
534 luaL_register(L, NULL, LAR_MMFILE_REG);
535 lua_pushvalue(L, -1);
536 lua_setfield(L, -2, "__index");
537 lua_setglobal(L, "lar.mmfile");
538
539 return 1;
540 }