From 299075c930a96bfea70996a4adeba3e3df7b1efb Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Mon, 26 Jul 2021 09:05:34 +0100 Subject: [PATCH] Add test for fopen_packed() --- Makefile | 27 +++++++++------- examples/complete/Makefile | 6 ++-- examples/complete/pack.c | 2 +- mongoose.c | 65 ++++++++++++++++++++++++++++++++++++-- src/fs.c | 65 ++++++++++++++++++++++++++++++++++++-- test/unit_test.c | 13 ++++++++ 6 files changed, 158 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index 95c8b39d..fcb1c408 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SRCS = $(wildcard src/*.c) +SRCS = mongoose.c test/unit_test.c test/packed_fs.c HDRS = $(wildcard src/*.h) DEFS ?= -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_DIRECTORY_LISTING=1 -DMG_ENABLE_SSI=1 WARN ?= -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion @@ -13,7 +13,6 @@ MINGW = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) docker.io/mdashnet/mingw GCC = docker run --rm -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/cc2 ARM = docker run -v $(CDIR):$(CDIR) -w $(CDIR) mdashnet/armgcc VCFLAGS = /nologo /W3 /O2 /I. $(DEFS) $(TFLAGS) -CLANG ?= clang # /usr/local/opt/llvm\@9/bin/clang IPV6 ?= 1 ASAN_OPTIONS ?= EXAMPLES := $(wildcard examples/*) @@ -38,26 +37,30 @@ all: mg_prefix test test++ ex vc98 vc2017 mingw mingw++ linux linux++ infer fuzz ex: @for X in $(EXAMPLES); do $(MAKE) -C $$X $(EXAMPLE_TARGET) || break; done +test/packed_fs.c: + $(CC) $(CFLAGS) examples/complete/pack.c -o pack + ./pack Makefile > $@ + # Check that all external (exported) symbols have "mg_" prefix mg_prefix: mongoose.c mongoose.h - $(CLANG) mongoose.c $(CFLAGS) -c -o /tmp/x.o && nm /tmp/x.o | grep ' T' | grep -v 'mg_' ; test $$? = 1 + $(CC) mongoose.c $(CFLAGS) -c -o /tmp/x.o && nm /tmp/x.o | grep ' T' | grep -v 'mg_' ; test $$? = 1 # C++ build -test++: CLANG = g++ +test++: CC = g++ test++: WARN += -Wno-shadow -Wno-missing-field-initializers -Wno-deprecated test++: test # Make sure we can build from an unamalgamated sources -unamalgamated: $(SRCS) $(HDRS) Makefile - $(CLANG) src/*.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test +unamalgamated: $(HDRS) Makefile + $(CC) src/*.c test/unit_test.c $(CFLAGS) $(LDFLAGS) -g -o unit_test fuzz: mongoose.c mongoose.h Makefile test/fuzz.c - $(CLANG) mongoose.c test/fuzz.c $(CFLAGS) -DMG_ENABLE_LINES -DMG_ENABLE_LOG=0 -fsanitize=fuzzer,signed-integer-overflow,address $(LDFLAGS) -g -o fuzzer + $(CC) mongoose.c test/fuzz.c $(CFLAGS) -DMG_ENABLE_LINES -DMG_ENABLE_LOG=0 -fsanitize=fuzzer,signed-integer-overflow,address $(LDFLAGS) -g -o fuzzer $(DEBUGGER) ./fuzzer -# make CLANG=/usr/local/opt/llvm\@8/bin/clang ASAN_OPTIONS=detect_leaks=1 +# make CC=/usr/local/opt/llvm\@8/bin/clang ASAN_OPTIONS=detect_leaks=1 test: CFLAGS += -DMG_ENABLE_IPV6=$(IPV6) -fsanitize=address#,undefined -test: mongoose.c mongoose.h Makefile test/unit_test.c - $(CLANG) mongoose.c test/unit_test.c $(CFLAGS) -coverage $(LDFLAGS) -g -o unit_test +test: mongoose.h Makefile $(SRCS) + $(CC) $(SRCS) $(CFLAGS) -coverage $(LDFLAGS) -g -o unit_test ASAN_OPTIONS=$(ASAN_OPTIONS) $(DEBUGGER) ./unit_test coverage: test @@ -114,7 +117,7 @@ uninstall: arm: Makefile mongoose.c mongoose.h test/unit_test.c $(ARM) arm-none-eabi-gcc mongoose.c -c -Itest -DMG_ARCH=MG_ARCH_CUSTOM $(OPTS) $(WARN) $(INCS) -DMG_MAX_HTTP_HEADERS=5 -DMG_ENABLE_LINES -DMG_ENABLE_DIRECTORY_LISTING=0 -DMG_ENABLE_SSI=1 -mongoose.c: $(SRCS) Makefile +mongoose.c: Makefile (cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/private.h src/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@ mongoose.h: $(HDRS) Makefile @@ -122,4 +125,4 @@ mongoose.h: $(HDRS) Makefile clean: EXAMPLE_TARGET = clean clean: ex - rm -rf $(PROG) *.o *.dSYM unit_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* + rm -rf $(PROG) *.o *.dSYM unit_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* test/packed_fs.c pack diff --git a/examples/complete/Makefile b/examples/complete/Makefile index a7096825..87defa1c 100644 --- a/examples/complete/Makefile +++ b/examples/complete/Makefile @@ -1,5 +1,5 @@ PROG ?= example -SOURCES ?= ../../mongoose.c main.c mjson.c fs.c +SOURCES ?= ../../mongoose.c main.c mjson.c packed_fs.c CFLAGS ?= -I../.. $(EXTRA) FILES_TO_EMBED ?= $(wildcard web_root/*.js) $(wildcard web_root/*.css) $(wildcard web_root/*.html) $(wildcard web_root/images/*.png) $(wildcard images/*.jpg) @@ -8,14 +8,14 @@ all: $(PROG) $(PROG): $(CC) pack.c -o pack - ./pack $(FILES_TO_EMBED) > fs.c + ./pack $(FILES_TO_EMBED) > packed_fs.c $(CC) -W -Wall -Wextra -Os -g3 $(CFLAGS) -o $(PROG) $(SOURCES) ROOT ?= $(realpath $(CURDIR)/../..) DOCKER ?= docker run -it --rm -e Tmp=. -e WINEDEBUG=-all -v $(ROOT):$(ROOT) -w $(CURDIR) mdashnet/vc98 wine windows: $(DOCKER) cl.exe /nologo $(CFLAGS) pack.c /Fepack.exe - $(DOCKER) cmd /c 'pack.exe $(FILES_TO_EMBED) > fs.c' + $(DOCKER) cmd /c 'pack.exe $(FILES_TO_EMBED) > packed_fs.c' $(DOCKER) cl.exe /nologo /O2 $(CFLAGS) $(SOURCES) ws2_32.lib /Fe$(PROG).exe $(DOCKER) $(PROG).exe diff --git a/examples/complete/pack.c b/examples/complete/pack.c index c2561f42..0113484a 100644 --- a/examples/complete/pack.c +++ b/examples/complete/pack.c @@ -50,7 +50,7 @@ int main(int argc, char *argv[]) { printf(" // %.*s\n", j, ascii); j = 0; } - ascii[j] = (ch >= ' ' && ch <= '~' && ch != '\\') ? ch : '.'; + ascii[j] = (char) ((ch >= ' ' && ch <= '~' && ch != '\\') ? ch : '.'); printf(" %3u,", ch); } // Append zero byte at the end, to make text files appear in memory diff --git a/mongoose.c b/mongoose.c index 3c2cc43a..5bf8ff1d 100644 --- a/mongoose.c +++ b/mongoose.c @@ -411,8 +411,69 @@ void mg_error(struct mg_connection *c, const char *fmt, ...) { #endif -// FILE *fopen_packed(const char *path, const char *mode) { -//} +struct packed_file { + const char *data; + size_t size; + size_t pos; +}; + +const char *unpack(const char *, size_t *) WEAK; +const char *unpack(const char *path, size_t *size) { + (void) path, (void) size; + return NULL; +} + +#if defined(__linux__) +ssize_t packed_read(void *cookie, char *buf, size_t size) { + struct packed_file *fp = (struct packed_file *) cookie; + if (size > fp->size - fp->pos) size = fp->size - fp->pos; + memcpy(buf, &fp->data[fp->pos], size); + fp->pos += size; + return (ssize_t) size; +} + +ssize_t packed_write(void *cookie, const char *buf, size_t size) { + (void) cookie, (void) buf, (void) size; + return -1; +} + +int packed_seek(void *cookie, off64_t *offset, int whence) { + struct packed_file *fp = (struct packed_file *) cookie; + if (whence == SEEK_SET) fp->pos = (size_t) *offset; + if (whence == SEEK_END) fp->pos = (size_t)((off64_t) fp->size + *offset); + if (whence == SEEK_CUR) fp->pos = (size_t)((off64_t) fp->pos + *offset); + if (fp->pos > fp->size) fp->pos = fp->size; + *offset = (off64_t) fp->pos; + return 0; +} + +int packed_close(void *cookie) { + free(cookie); + return 0; +} + +FILE *fopen_packed(const char *path, const char *mode) { + cookie_io_functions_t funcs = { + .read = packed_read, + .write = packed_write, + .seek = packed_seek, + .close = packed_close, + }; + struct packed_file *cookie = NULL; + size_t size = 0; + const char *data = unpack(path, &size); + if (data == NULL) return NULL; + if ((cookie = calloc(1, sizeof(*cookie))) == NULL) return NULL; + cookie->data = data; + cookie->size = size; + return fopencookie(cookie, mode, funcs); +} +#else +FILE *fopen_packed(const char *path, const char *mode) { + (void) path, (void) mode; + return NULL; +} +#endif #ifdef MG_ENABLE_LINES #line 1 "src/http.c" diff --git a/src/fs.c b/src/fs.c index fe0122fb..5dac29cd 100644 --- a/src/fs.c +++ b/src/fs.c @@ -1,4 +1,65 @@ #include "fs.h" -// FILE *fopen_packed(const char *path, const char *mode) { -//} +struct packed_file { + const char *data; + size_t size; + size_t pos; +}; + +const char *unpack(const char *, size_t *) WEAK; +const char *unpack(const char *path, size_t *size) { + (void) path, (void) size; + return NULL; +} + +#if defined(__linux__) && defined(GCC) +ssize_t packed_read(void *cookie, char *buf, size_t size) { + struct packed_file *fp = (struct packed_file *) cookie; + if (size > fp->size - fp->pos) size = fp->size - fp->pos; + memcpy(buf, &fp->data[fp->pos], size); + fp->pos += size; + return (ssize_t) size; +} + +ssize_t packed_write(void *cookie, const char *buf, size_t size) { + (void) cookie, (void) buf, (void) size; + return -1; +} + +int packed_seek(void *cookie, off64_t *offset, int whence) { + struct packed_file *fp = (struct packed_file *) cookie; + if (whence == SEEK_SET) fp->pos = (size_t) *offset; + if (whence == SEEK_END) fp->pos = (size_t)((off64_t) fp->size + *offset); + if (whence == SEEK_CUR) fp->pos = (size_t)((off64_t) fp->pos + *offset); + if (fp->pos > fp->size) fp->pos = fp->size; + *offset = (off64_t) fp->pos; + return 0; +} + +int packed_close(void *cookie) { + free(cookie); + return 0; +} + +FILE *fopen_packed(const char *path, const char *mode) { + cookie_io_functions_t funcs = { + .read = packed_read, + .write = packed_write, + .seek = packed_seek, + .close = packed_close, + }; + struct packed_file *cookie = NULL; + size_t size = 0; + const char *data = unpack(path, &size); + if (data == NULL) return NULL; + if ((cookie = calloc(1, sizeof(*cookie))) == NULL) return NULL; + cookie->data = data; + cookie->size = size; + return fopencookie(cookie, mode, funcs); +} +#else +FILE *fopen_packed(const char *path, const char *mode) { + (void) path, (void) mode; + return NULL; +} +#endif diff --git a/test/unit_test.c b/test/unit_test.c index efdd5f2f..0280a4ec 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -1335,8 +1335,21 @@ static void test_multipart(void) { ASSERT(mg_http_next_multipart(mg_str(s), ofs, &part) == 0); } +static void test_packed(void) { + FILE *fp = fopen_packed("Makefile", "r"); +#if defined(__linux__) && defined(GCC) + ASSERT(fp != NULL); + fseek(fp, 0, SEEK_END); + ASSERT(ftell(fp) > 0); + fclose(fp); +#else + ASSERT(fp == NULL); +#endif +} + int main(void) { mg_log_set("3"); + test_packed(); test_crc32(); test_multipart(); test_http_chunked();