diff -r 008c75a5e08d -r 8e4bf84a7bb8 librazor/uri-io.c --- a/librazor/uri-io.c Mon Jul 04 10:48:18 2016 +0100 +++ b/librazor/uri-io.c Thu Jul 07 11:04:10 2016 +0100 @@ -38,6 +38,10 @@ #if HAVE_SYS_MMAN_H #include #endif +#if HAVE_LIBARCHIVE +#include +#include +#endif #include #include "razor.h" @@ -51,6 +55,130 @@ #define strcmp0(s1, s2) ((s1) && (s2) ? strcmp(s1, s2) : \ (s1) ? 1 : (s2) ? -1 : 0) +#if HAVE_LIBARCHIVE +static void * +razor_archive_get_file_contents(const char *filename, int fd, const char *path, + size_t *length, struct razor_error **error) +{ + int r; + void *addr; + const void *buf; + size_t size; + off_t offset; + struct archive *a; + struct archive_entry *entry; + + a = archive_read_new(); + archive_read_support_compression_all(a); + archive_read_support_format_all(a); + + r = archive_read_open_fd(a, fd, 10240); + + if (r) { + razor_set_error(error, RAZOR_POSIX_ERROR, archive_errno(a), + filename, archive_error_string(a)); + archive_read_finish(a); + return NULL; + } + + for (;;) { + r = archive_read_next_header(a, &entry); + if (r == ARCHIVE_EOF) + break; + else if (r < ARCHIVE_WARN) { + razor_set_error(error, RAZOR_POSIX_ERROR, + archive_errno(a), filename, + archive_error_string(a)); + archive_read_close(a); + archive_read_finish(a); + return NULL; + } + + /* + * TODO: Unicode support. Might need to wait for libarchive v4. + */ + if (!strcmp(archive_entry_pathname(entry), path)) { + addr = malloc(archive_entry_size(entry)); + if (!addr) { + archive_read_close(a); + archive_read_finish(a); + razor_set_error(error, RAZOR_POSIX_ERROR, + ENOMEM, NULL, + "Not enough memory"); + return NULL; + } + + for(;;) { + r = archive_read_data_block(a, &buf, &size, + &offset); + if (r == ARCHIVE_EOF) + break; + if (r < ARCHIVE_OK) { + razor_set_error(error, RAZOR_POSIX_ERROR, + archive_errno(a), path, + archive_error_string(a)); + free(addr); + addr = NULL; + break; + } + memcpy((char *)addr + offset, buf, size); + } + + archive_read_close(a); + archive_read_finish(a); + + return addr; + } + } + + archive_read_close(a); + archive_read_finish(a); + + razor_set_error(error, RAZOR_POSIX_ERROR, ENOENT, path, + "No such file or directory in archive"); + + return NULL; +} + +static void * +razor_file_get_contents_archive(const char *filename, size_t *length, + struct razor_error **error) +{ + int fd; + char *path, *slash, *s; + void *addr; + + path = strdup(filename); + slash = strrchr(path, '/'); + + while (slash) { + *slash = '\0'; + fd = open(path, O_RDONLY | O_BINARY); + if (fd >= 0) { + addr = razor_archive_get_file_contents(path, fd, + slash + 1, + length, error); + free(path); + close(fd); + return addr; + } else if (errno != ENOTDIR) { + free(path); + razor_set_error_posix(error, filename); + return NULL; + } + s = strrchr(path, '/'); + *slash = '/'; + slash = s; + } + + /* Impossible */ + free(path); + razor_set_error(error, RAZOR_POSIX_ERROR, ENOTDIR, filename, + strerror(ENOTDIR)); + return NULL; +} +#endif + #define OPEN_FILE_USED (1U<<0) #define OPEN_FILE_MMAPPED (1U<<1) @@ -68,24 +196,33 @@ int fd; struct stat st; void *addr = NULL; - size_t nb; + size_t nb, size; ssize_t res; struct open_file *of, *ofend; fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) { +#if HAVE_LIBARCHIVE + if (errno != ENOTDIR) { + razor_set_error_posix(error, filename); + return NULL; + } + addr = razor_file_get_contents_archive(filename, &size, error); + if (!addr) + return NULL; +#else razor_set_error_posix(error, filename); return NULL; +#endif + } else { + if (fstat(fd, &st) < 0) { + razor_set_error_posix(error, filename); + close(fd); + return NULL; + } + size = st.st_size; } - if (fstat(fd, &st) < 0) { - razor_set_error_posix(error, filename); - close(fd); - return NULL; - } - - *length = st.st_size; - ofend = open_files.data + open_files.size; for (of = open_files.data; of < ofend; of++) if (!(of->flags & OPEN_FILE_USED)) @@ -96,21 +233,21 @@ } #if HAVE_SYS_MMAN_H - if (!private) { - addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (!addr && !private) { + addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) addr = NULL; else of->flags = OPEN_FILE_USED | OPEN_FILE_MMAPPED; } #endif /* HAVE_SYS_MMAN_H */ + if (!addr) { - addr = malloc(st.st_size); + addr = malloc(size); if (addr) { - of->flags = OPEN_FILE_USED; nb = 0; - while(nb < st.st_size) { - res = read(fd, addr + nb, st.st_size - nb); + while(nb < size) { + res = read(fd, addr + nb, size - nb); if (res <= 0) { razor_set_error_posix(error, filename); free(addr); @@ -119,14 +256,21 @@ } nb += res; } + if (addr) + of->flags = OPEN_FILE_USED; } else razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, "Not enough memory"); } - close(fd); + + if (fd >= 0) + close(fd); of->addr = addr; - of->length = st.st_size; + of->length = size; + + if (addr) + *length = size; return addr; } @@ -659,7 +803,8 @@ return fallback; } -int razor_uri_mkdir(const char *uri, mode_t mode, struct razor_error **error) +RAZOR_EXPORT int +razor_uri_mkdir(const char *uri, mode_t mode, struct razor_error **error) { int retval; char *path; @@ -700,7 +845,8 @@ return retval; } -int razor_uri_unlink(const char *uri, struct razor_error **error) +RAZOR_EXPORT int +razor_uri_unlink(const char *uri, struct razor_error **error) { int retval; char *path; @@ -741,8 +887,9 @@ return retval; } -int razor_uri_open(const char *uri, int flags, mode_t mode, - struct razor_error **error) +RAZOR_EXPORT int +razor_uri_open(const char *uri, int flags, mode_t mode, + struct razor_error **error) { int retval; char *path; @@ -783,8 +930,9 @@ return retval; } -int razor_uri_move(const char *src_uri, const char *dst_uri, - struct razor_error **error) +RAZOR_EXPORT int +razor_uri_move(const char *src_uri, const char *dst_uri, + struct razor_error **error) { int retval; char *src_path, *dst_path; @@ -851,8 +999,9 @@ return retval; } -void *razor_uri_get_contents(const char *uri, size_t *length, int private, - struct razor_error **error) +RAZOR_EXPORT void * +razor_uri_get_contents(const char *uri, size_t *length, int private, + struct razor_error **error) { void *retval; char *path; @@ -897,7 +1046,7 @@ return retval; } -int razor_uri_free_contents(void *addr, size_t length) +RAZOR_EXPORT int razor_uri_free_contents(void *addr, size_t length) { int retval, of; struct razor_uri_vtable_entry *entry, *eend; @@ -925,7 +1074,8 @@ return retval; } -int razor_uri_is_directory(const char *uri, struct razor_error **error) +RAZOR_EXPORT int +razor_uri_is_directory(const char *uri, struct razor_error **error) { int retval; char *path; @@ -966,8 +1116,9 @@ return retval; } -char *razor_uri_mkdtemp_near(const char *uri, const char *template, - struct razor_error **error) +RAZOR_EXPORT char * +razor_uri_mkdtemp_near(const char *uri, const char *template, + struct razor_error **error) { char *retval, *s; char *path; @@ -1011,7 +1162,8 @@ return retval; } -void *razor_uri_opendir(const char *uri, struct razor_error **error) +RAZOR_EXPORT void * +razor_uri_opendir(const char *uri, struct razor_error **error) { void *retval; char *path; @@ -1055,7 +1207,7 @@ return retval; } -char *razor_uri_readdir(void *dir, struct razor_error **error) +RAZOR_EXPORT char *razor_uri_readdir(void *dir, struct razor_error **error) { int od; char *retval; @@ -1086,7 +1238,7 @@ return retval; } -int razor_uri_closedir(void *dir, struct razor_error **error) +RAZOR_EXPORT int razor_uri_closedir(void *dir, struct razor_error **error) { int od; int retval;