SpriteHTTPD - embedded HTTP server with read-only filesystem and templating, originally developed for ESP8266, now stand-alone and POSIX compatible.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
spritehttpd/fstool/parsing.c

165 lines
4.3 KiB

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <zlib.h>
#include "parsing.h"
#include "espfs.h"
static off_t espfs_parse_filesize = -1;
static int espfs_parse_fd = -1;
size_t decompressGzip(const uint8_t *in, size_t insize, int outfd)
{
#define OUTBUF_LEN 10240
uint8_t outbuf[OUTBUF_LEN];
z_stream stream;
int zresult;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.next_in = in;
stream.avail_in = (uInt) insize;
stream.next_out = outbuf;
stream.avail_out = OUTBUF_LEN;
// 31 -> 15 window bits + 16 for gzip
zresult = inflateInit2(&stream, 31);
if (zresult != Z_OK) {
fprintf(stderr, "InflateInit2 failed with code %d\n", zresult);
exit(1);
}
while (1) {
stream.avail_out = OUTBUF_LEN;
stream.next_out = outbuf;
fprintf(stderr, "inflate chunk\n");
zresult = inflate(&stream, Z_FINISH);
if (zresult == Z_BUF_ERROR || zresult == Z_OK || zresult == Z_STREAM_END) {
size_t have = OUTBUF_LEN - stream.avail_out;
fprintf(stderr, "inflated: %d\n", (int) have);
if ((ssize_t)have != write(outfd, outbuf, have)) {
perror("Write output");
exit(1);
}
if (zresult == Z_STREAM_END) {
fprintf(stderr, "Z_STREAM_END\n");
break;
}
} else {
fprintf(stderr, "gzip error: %d\n", zresult);
exit(1);
}
}
zresult = inflateEnd(&stream);
if (zresult != Z_OK) {
fprintf(stderr, "InflateEnd failed with code %d\n", zresult);
exit(1);
}
fprintf(stderr, "Total decoded = %d\n", (int) stream.total_out);
return stream.total_out;
}
/**
* Parse an image file and show the files contained.
* This is a simple sanity test.
*
* @param[in] imagefile - image file to parse
* @param[in] extractfile - name of the file to extract
* @param outfd - output FD when extracting
*/
void parseEspfsImage(const char *imagefile, const char *extractfile, int outfd)
{
int rv;
fprintf(stderr, "Parsing: %s\n", imagefile);
FILE *f = fopen(imagefile, "r");
if (!f) {
perror(imagefile);
exit(1);
}
int fd = fileno(f);
espfs_parse_filesize = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
espfs_parse_fd = fd;
rv = espFsInit();
if (rv != 0) {
fprintf(stderr, "Fail to init FS\n");
exit(1);
}
if (extractfile) {
EspFsFile *efile = espFsOpen(extractfile);
EspFsHeader hdr;
if (!efile) {
fprintf(stderr, "Fail to open file %s from image\n", extractfile);
exit(1);
}
rv = espFsFileReadHeader(efile, &hdr);
if (rv != 0) {
fprintf(stderr, "Fail to read file header\n");
exit(1);
}
bool isGzip = hdr.flags & FLAG_GZIP;
size_t expected_readlen = isGzip ? hdr.fileLenComp : hdr.fileLenDecomp;
uint8_t *buff = malloc(expected_readlen);
size_t lenRead = espFsRead(efile, buff, expected_readlen);
if (lenRead != expected_readlen) {
fprintf(stderr, "Fail to read raw file from espfs image - read len %d", (int) lenRead);
exit(1);
}
if (isGzip) {
fprintf(stderr, "[EspFS] File is gzipped!");
decompressGzip(buff, lenRead, outfd);
} else {
write(outfd, buff, lenRead);
}
fsync(outfd);
exit(0);
}
/* Walk the image */
EspFsWalk walk;
espFsWalkInit(&walk);
EspFsHeader header;
uint32_t offset;
char namebuf[1024];
while (espFsWalkNext(&walk, &header, namebuf, 1024, &offset)) {
fprintf(stderr, "at %04x: \"%s\", flags: %02x, comp: %s, compLen: %d, plainLen: %d\n", offset, namebuf, header.flags,
header.compression == 1 ? "HS" : "None", header.fileLenComp, header.fileLenDecomp);
}
fclose(f);
}
int httpdPlatEspfsRead(void *dest, size_t offset, size_t len)
{
// fprintf(stderr, "FS read @ %d, len %d\n", offset, (int) len);
if ((off_t) (offset + len) > espfs_parse_filesize) {
fprintf(stderr, "Read out fo range!\n");
return -1;
}
lseek(espfs_parse_fd, (off_t) offset, SEEK_SET);
read(espfs_parse_fd, dest, len);
return 0;
}