/* * lmo - Lua Machine Objects - Base functions * * Copyright (C) 2009-2010 Jo-Philipp Wich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "lmo.h" extern char _lmo_error[1024]; static int lmo_read32( int fd, uint32_t *val ) { if( read(fd, val, 4) < 4 ) return -1; *val = ntohl(*val); return 4; } static char * error(const char *message, int add_errno) { memset(_lmo_error, 0, sizeof(_lmo_error)); if( add_errno ) snprintf(_lmo_error, sizeof(_lmo_error), "%s: %s", message, strerror(errno)); else snprintf(_lmo_error, sizeof(_lmo_error), "%s", message); return NULL; } const char * lmo_error(void) { return _lmo_error; } lmo_archive_t * lmo_open(const char *file) { int in = -1; uint32_t idx_offset = 0; uint32_t i; struct stat s; lmo_archive_t *ar = NULL; lmo_entry_t *head = NULL; lmo_entry_t *entry = NULL; if( stat(file, &s) == -1 ) { error("Can not stat file", 1); goto cleanup; } if( (in = open(file, O_RDONLY)) == -1 ) { error("Can not open file", 1); goto cleanup; } if( lseek(in, -sizeof(uint32_t), SEEK_END) == -1 ) { error("Can not seek to eof", 1); goto cleanup; } if( lmo_read32(in, &idx_offset) != 4 ) { error("Unexpected EOF while reading index offset", 0); goto cleanup; } if( lseek(in, (off_t)idx_offset, SEEK_SET) == -1 ) { error("Can not seek to index offset", 1); goto cleanup; } if( (ar = (lmo_archive_t *) malloc(sizeof(lmo_archive_t))) != NULL ) { ar->fd = in; ar->length = idx_offset; fcntl(ar->fd, F_SETFD, fcntl(ar->fd, F_GETFD) | FD_CLOEXEC); for( i = idx_offset; i < (s.st_size - sizeof(uint32_t)); i += (4 * sizeof(uint32_t)) ) { if( (entry = (lmo_entry_t *) malloc(sizeof(lmo_entry_t))) != NULL ) { if( (lmo_read32(ar->fd, &entry->key_id) == 4) && (lmo_read32(ar->fd, &entry->val_id) == 4) && (lmo_read32(ar->fd, &entry->offset) == 4) && (lmo_read32(ar->fd, &entry->length) == 4) ) { entry->next = head; head = entry; } else { error("Unexpected EOF while reading index entry", 0); goto cleanup; } } else { error("Out of memory", 0); goto cleanup; } } ar->index = head; if( lseek(ar->fd, 0, SEEK_SET) == -1 ) { error("Can not seek to start", 1); goto cleanup; } if( (ar->mmap = mmap(NULL, ar->length, PROT_READ, MAP_PRIVATE, ar->fd, 0)) == MAP_FAILED ) { error("Failed to memory map archive contents", 1); goto cleanup; } return ar; } else { error("Out of memory", 0); goto cleanup; } cleanup: if( in > -1 ) close(in); if( head != NULL ) { entry = head; while( entry != NULL ) { head = entry->next; free(entry); entry = head; } head = entry = NULL; } if( ar != NULL ) { if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) ) munmap(ar->mmap, ar->length); free(ar); ar = NULL; } return NULL; } void lmo_close(lmo_archive_t *ar) { lmo_entry_t *head = NULL; lmo_entry_t *entry = NULL; if( ar != NULL ) { entry = ar->index; while( entry != NULL ) { head = entry->next; free(entry); entry = head; } head = entry = NULL; if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) ) munmap(ar->mmap, ar->length); close(ar->fd); free(ar); ar = NULL; } } int lmo_lookup(lmo_archive_t *ar, const char *key, char *dest, int len) { uint32_t look_key = sfh_hash(key, strlen(key)); int copy_len = -1; lmo_entry_t *entry; if( !ar ) return copy_len; entry = ar->index; while( entry != NULL ) { if( entry->key_id == look_key ) { copy_len = ((len - 1) > entry->length) ? entry->length : (len - 1); memcpy(dest, &ar->mmap[entry->offset], copy_len); dest[copy_len] = '\0'; break; } entry = entry->next; } return copy_len; }