Merge pull request #3477 from cesanta/mem

Make packed fs always available, and manually settable
This commit is contained in:
Sergio R. Caprile authored and GitHub committed 2026-04-01 14:36:58 -03:00
commit ae5a2263ac
83 files changed
+289 -8052

No files matched your search

+2 -3
View File
@@ -1,6 +1,6 @@
SRCS = mongoose.c unit_test.c packed_fs.c
HDRS = $(wildcard ../src/*.h) $(wildcard ../src/drivers/*.h)
DEFS ?= -DMG_MAX_HTTP_HEADERS=7 -DMG_ENABLE_LINES -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_SSI=1 -DMG_ENABLE_ASSERT=1
DEFS ?= -DMG_MAX_HTTP_HEADERS=7 -DMG_ENABLE_LINES -DMG_ENABLE_SSI=1 -DMG_ENABLE_ASSERT=1
WARN ?= -pedantic -W -Wall -Werror -Wshadow -Wdouble-promotion -fno-common -Wconversion -Wundef
OPTS ?= -O3 -g3
INCS ?= -Isrc -I.
@@ -172,7 +172,7 @@ valgrind: Makefile mongoose.h $(SRCS)
$(VALGRIND_RUN) ./unit_test
misra:
cppcheck --addon=misra -DMG_ARCH=MG_ARCH_UNIX -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_SSI=1 mongoose.c >/tmp/x 2>&1
cppcheck --addon=misra -DMG_ARCH=MG_ARCH_UNIX -DMG_ENABLE_SSI=1 mongoose.c >/tmp/x 2>&1
cppcheck --addon=misra -DMG_ARCH=MG_ARCH_CUSTOM -DMG_ENABLE_LINES=1 -DTLS=MG_TLS_BUILTIN -DMG_ENABLE_TCPIP=1 mongoose.c >>/tmp/x 2>&1
cppcheck --addon=misra --clang -DMG_ENABLE_LINES=1 -DTLS=MG_TLS_BUILTIN -DMG_ENABLE_TCPIP=1 mongoose.c >>/tmp/x 2>&1
cppcheck --addon=misra --clang -DMG_ENABLE_LINES=1 -DMG_ENABLE_SSI=1 mongoose.c >>/tmp/x 2>&1
@@ -285,4 +285,3 @@ tutorials_embedded:
@for X in $(TUTORIALS_EMBEDDED); do test -f $$X/Makefile || continue; $(MAKE) -C $$X build || exit 1; done
clean_tutorials_embedded:
for X in $(TUTORIALS_EMBEDDED); do test -f $$X/Makefile || continue; $(MAKE) -C $$X clean || exit 1; done
-59
View File
@@ -1,59 +0,0 @@
#pragma once
// Build environment. Possible options are at https://github.com/cesanta/mongoose/blob/master/src/arch.h
// #define MG_ARCH MG_ARCH_CUSTOM
// Choice of the network stack. By default, use an external BSD-compatible stack
// #define MG_ENABLE_FREERTOS_TCP 0 // Amazon FreeRTOS-TCP
// #define MG_ENABLE_LWIP 0 // lWIP
// #define MG_ENABLE_TCPIP 0 // Mongoose built-in
// #define MG_ENABLE_RL 0 // ARM MDK
// #define MG_ENABLE_POLL 0 // Only for BSD stack. Use poll()
// #define MG_ENABLE_EPOLL 0 // Only for Linux/BSD stack. Use epoll()
// #define MG_ENABLE_WINSOCK 1 // Only for Windows stack. Use Winsock
// #define MG_ENABLE_SOCKET !MG_ENABLE_TCPIP
// #define MG_SOCK_LISTEN_BACKLOG_SIZE 3 // Only for socket-based stacks
// Only for built-in network stack, MG_ENABLE_TCPIP == 1
// #define MG_ENABLE_TCPIP_DRIVER_INIT 1 // enabled built-in driver for
// #define MG_SET_MAC_ADDRESS(mac) // set MAC address for built-in driver
// #define MG_SET_WIFI_CONFIG(data)
// #define MG_ENABLE_TCPIP_PRINT_DEBUG_STATS 0
// Choose a driver for built-in network stack, MG_ENABLE_TCPIP == 1
// #define MG_ENABLE_DRIVER_STM32H 0
// #define MG_ENABLE_DRIVER_STM32F 0
// #define MG_ENABLE_DRIVER_IMXRT 0
// #define MG_ENABLE_DRIVER_CMSIS 0
// #define MG_ENABLE_DRIVER_RA 0
// #define MG_ENABLE_DRIVER_RW612 0
// #define MG_ENABLE_DRIVER_SAME54 0
// #define MG_ENABLE_DRIVER_MCXN 0
// #define MG_ENABLE_DRIVER_TM4C 0
// #define MG_ENABLE_DRIVER_TMS570 0
// #define MG_ENABLE_DRIVER_XMC7 0
// #define MG_ENABLE_DRIVER_XMC 0
// Filesystem support
// #define MG_ENABLE_PACKED_FS 0 // Enable packed filesystem support
// #define MG_ENABLE_FATFS 0 // Enable FATFS support, mg_fs_packed
// #define MG_ENABLE_POSIX_FS 0 // Enable POSIX filesystem support, mg_fs_posix
// #define MG_PATH_MAX 128 // Maximum path length
// #define MG_DIRSEP '/' // Directory separator
// Misc options
// #define MG_ENABLE_LOG 1 // Enable logging
// #define MG_TLS MG_TLS_NONE // MG_TLS_NONE, MG_TLS_MBED, MG_TLS_OPENSSL, MG_TLS_CUSTOM
// #define MG_ENABLE_IPV6 0 // Enable IPv6 support
// #define MG_IPV6_V6ONLY 0 // IPv6 socket binds only to V6, not V4 address
// #define MG_ENABLE_CUSTOM_CALLOC 0 // Set to 1 to let user define mg_calloc() and mg_free()
// #define MG_ENABLE_CUSTOM_RANDOM 0 // Set to 1 to let user define mg_random()
// #define MG_ENABLE_CUSTOM_MILLIS 0 // Set to 1 to let user define mg_millis()
// #define MG_ENABLE_SSI 0 // Enable SSI support
// #define MG_ENABLE_DIRLIST 0 // Enable directory listing
// #define MG_IO_SIZE 512 // Granularity of the send/recv IO buffer growth
// #define MG_MAX_RECV_SIZE (3UL * 1024UL * 1024UL) // Maximum recv IO buffer size
// #define MG_DATA_SIZE 32 // struct mg_connection :: data size
// #define MG_MAX_HTTP_HEADERS 30 // Maximum number of HTTP headers
// #define MG_HTTP_INDEX "index.html" // Default HTTP index file
// #define MG_ENABLE_LINES 0 // Show unamalgamated line numbers
+3 -33
View File
@@ -2,7 +2,7 @@
// All rights reserved.
// This program is used to pack arbitrary data into a C binary. It takes
// a list of files as an input, and produces a .c data file that contains
// a list of files as an input, and produc es a .c data file that contains
// contents of all these files as a collection of byte arrays.
//
// Usage:
@@ -24,35 +24,12 @@
#include <string.h>
#include <sys/stat.h>
static const char *code =
"static int scmp(const char *a, const char *b) {\n"
" while (*a && (*a == *b)) a++, b++;\n"
" return *(const unsigned char *) a - *(const unsigned char *) b;\n"
"}\n"
"const char *mg_unlist(size_t no) {\n"
" return packed_files[no].name;\n"
"}\n"
"const char *mg_unpack(const char *name, size_t *size, time_t *mtime) {\n"
" const struct packed_file *p;\n"
" for (p = packed_files; p->name != NULL; p++) {\n"
" if (scmp(p->name, name) != 0) continue;\n"
" if (size != NULL) *size = p->size - 1;\n"
" if (mtime != NULL) *mtime = p->mtime;\n"
" return (const char *) p->data;\n"
" }\n"
" return NULL;\n"
"}\n";
int main(int argc, char *argv[]) {
int i, j, ch;
const char *strip_prefix = "";
printf("%s", "#include \"mongoose.h\"\n");
printf("%s", "\n");
printf("%s", "#if defined(__cplusplus)\nextern \"C\" {\n#endif\n");
printf("%s", "const char *mg_unlist(size_t no);\n");
printf("%s", "const char *mg_unpack(const char *, size_t *, time_t *);\n");
printf("%s", "#if defined(__cplusplus)\n}\n#endif\n\n");
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-s") == 0) {
@@ -79,18 +56,12 @@ int main(int argc, char *argv[]) {
}
// Append zero byte at the end, to make text files appear in memory
// as nul-terminated strings.
// printf(" 0 // %.*s\n", (int) sizeof(ascii), ascii);
printf(" 0 // %.*s\n};\n", j, ascii);
fclose(fp);
}
}
printf("%s", "\nstatic const struct packed_file {\n");
printf("%s", " const char *name;\n");
printf("%s", " const unsigned char *data;\n");
printf("%s", " size_t size;\n");
printf("%s", " time_t mtime;\n");
printf("%s", "} packed_files[] = {\n");
printf("%s", "\nconst struct mg_mem_file mg_packed_files[] = {\n");
for (i = 1; i < argc; i++) {
struct stat st;
@@ -102,12 +73,11 @@ int main(int argc, char *argv[]) {
}
stat(argv[i], &st);
if (strncmp(name, strip_prefix, n) == 0) name += n;
printf(" {\"/%s\", v%d, sizeof(v%d), %lu},\n", name, i, i,
printf(" {\"/%s\", v%d, sizeof(v%d) - 1, %lu},\n", name, i, i,
(unsigned long) st.st_mtime);
}
printf("%s", " {NULL, NULL, 0, 0}\n");
printf("%s", "};\n\n");
printf("%s", code);
return EXIT_SUCCESS;
}
+38 -98
View File
@@ -1,103 +1,43 @@
// Copyright (c) 2013-2024 Cesanta Software Limited
const Pack = async function(files) {
let out = `// DO NOT EDIT. This file is generated
#include "mongoose.h"
#if defined(__cplusplus)
extern "C" {
#endif
const char *mg_unlist(size_t no);
const char *mg_unpack(const char *, size_t *, time_t *);
#if defined(__cplusplus)
}
#endif
`;
//const str2bytes = str => new TextEncoder().encode(str);
let no = 1;
for (const f of files) {
let byteArray = new TextEncoder().encode(f.data);
if (f.zip) {
const cs = new CompressionStream('gzip');
const writer = cs.writable.getWriter();
writer.write(byteArray);
writer.close();
const resp = new Response(cs.readable);
const arr = await resp.arrayBuffer();
byteArray = new Uint8Array(arr);
}
const bytes = Array.from(byteArray);
// console.log(f.path, bytes);
out += `
static const unsigned char v${no}[] = {`;
// concat(0) appends trailing 0, in order to make any file an asciz string
out += bytes.concat(0).join(',');
out +=`};`;
no++;
}
out += `
static const struct packed_file {
const char *name;
const unsigned char *data;
size_t size;
time_t mtime;
} packed_files[] = {`;
no = 1;
for (const f of files) {
out += `
{"/${f.path}${f.zip ? '.gz' : ''}", v${no}, sizeof(v${no}), 0},`;
no++;
}
out +=`
{NULL, NULL, 0, 0}
};
`;
out += `
static int scmp(const char *a, const char *b) {
while (*a && (*a == *b)) a++, b++;
return *(const unsigned char *) a - *(const unsigned char *) b;
}
const char *mg_unlist(size_t no) {
return packed_files[no].name;
}
const char *mg_unpack(const char *name, size_t *size, time_t *mtime) {
const struct packed_file *p;
for (p = packed_files; p->name != NULL; p++) {
if (scmp(p->name, name) != 0) continue;
if (size != NULL) *size = p->size - 1;
if (mtime != NULL) *mtime = p->mtime;
return (const char *) p->data;
}
return NULL;
};
`;
return out;
};
// Script entry point
// Copyright (c) 2024 Cesanta Software Limited
//
// Utility that generates packed filesystem C file compatible with the
// Mongoose Network Library, https://github.com/cesanta/mongoose
//
// Usage:
// node pack.js FILE[:DESTINATION[:gzip]] ...
const fs = require('fs');
const path = require('path');
const [, , ...args] = process.argv;
const zlib = require('zlib');
const argv = process.argv.slice(2);
const files = args.map(f => ({
path: f,
data: fs.readFileSync(f, 'utf8'),
zip: !!f.match(/web_root\/.+/),
}));
// Convert each command-line arguments into [ DATA_ARRAY, STRUCT_INITIALIZER ]
const entries = argv.map(function(filename, i) {
const parts = filename.split(':');
const stat = fs.statSync(parts[0]);
const data = fs.readFileSync(parts[0], null);
let bytes = Array.from(data);
let destination = (parts[1] || parts[0]).replace(/^\.+[\/\\]*/, '');
if (parts[2] == 'gzip') {
bytes = Array.from(zlib.gzipSync(data));
destination += '.gz';
}
(async () => {
const text = await Pack(files);
process.stdout.write(text);
})();
// concat(0) appends trailing 0, in order to make any file an asciz string
return [
`static const unsigned char v${i}[] = {${bytes.concat(0).join(',')}};`,
` {"/${destination}", v${i}, sizeof(v${i}) - 1, ${parseInt(stat.mtimeMs / 1000)}}`,
];
});
process.stdout.write(`// DO NOT EDIT. This file is generated using this command:
// ${process.argv.join(' ')}
#include "mongoose.h"
${entries.map(x => x[0]).join('\n\n')}
const struct mg_mem_file mg_packed_files[] = {
${entries.map(x => x[1]).join(',\n')},
{NULL, NULL, 0, 0}
};
`);
+1
View File
@@ -3211,6 +3211,7 @@ static void eh7(struct mg_connection *c, int ev, void *ev_data) {
memset(&sopts, 0, sizeof(sopts));
sopts.root_dir = "/";
sopts.fs = &mg_fs_packed;
mg_mem_files = mg_packed_files;
mg_http_serve_dir(c, hm, &sopts);
}
}