Added packaging functionality, added packaged exe support to filesystem

Adds package.c and package.h. Adds support for the `--pack` argument for
packing a project directory into an exe or tar file.
This commit is contained in:
rxi
2016-10-01 00:35:22 +01:00
parent 0506b3b0ca
commit cb61fa1ecd
4 changed files with 310 additions and 6 deletions

View File

@@ -242,14 +242,80 @@ static void* tar_read(Mount *mnt, const char *filename, int *size) {
}
static int tar_mount(Mount *mnt, const char *path) {
mtar_t *tar = dmt_malloc( sizeof(*tar) );
typedef struct { FILE *fp; int offset; } TarStream;
/* Try to init tar */
int err = mtar_open(tar, path, "r");
static int tar_stream_read(mtar_t *tar, void *data, unsigned size) {
TarStream *t = tar->stream;
unsigned res = fread(data, 1, size, t->fp);
return (res == size) ? MTAR_ESUCCESS : MTAR_EREADFAIL;
}
static int tar_stream_seek(mtar_t *tar, unsigned offset) {
TarStream *t = tar->stream;
int res = fseek(t->fp, t->offset + offset, SEEK_SET);
return (res == 0) ? MTAR_ESUCCESS : MTAR_ESEEKFAIL;
}
static int tar_stream_close(mtar_t *tar) {
TarStream *t = tar->stream;
fclose(t->fp);
dmt_free(t);
return MTAR_ESUCCESS;
}
static int tar_mount(Mount *mnt, const char *path) {
FILE *fp = NULL;
TarStream *stream = NULL;
mtar_t *tar = NULL;
/* Try to open file */
fp = fopen(path, "rb");
if (!fp) {
goto fail;
}
/* Init tar stream */
stream = dmt_calloc(1, sizeof(*stream));
if (!stream) {
goto fail;
}
stream->fp = fp;
/* Init tar */
tar = dmt_calloc(1, sizeof(*tar));
if (!tar) {
goto fail;
}
tar->read = tar_stream_read;
tar->seek = tar_stream_seek;
tar->close = tar_stream_close;
tar->stream = stream;
/* Check start of file for valid tar header */
mtar_header_t h;
int err = mtar_read_header(tar, &h);
/* If checking the start of the file failed then check the end of file for a
* "TAR\0" tag and offset, this would have been added when packaging (see
* `package.c`) to indicate the offset of the tar archive's beginning from the
* file's end */
if (err) {
dmt_free(tar);
return FILESYSTEM_EFAILURE;
int offset;
char buf[4] = "";
fseek(fp, -8, SEEK_END);
fread(buf, 1, 4, fp);
fread(&offset, 1, 4, fp);
if ( !memcmp(buf, "TAR\0", 4) ) {
fseek(fp, -offset, SEEK_END);
stream->offset = ftell(fp);
}
mtar_rewind(tar);
err = mtar_read_header(tar, &h);
if (err) {
goto fail;
}
}
/* Init mount */
@@ -262,6 +328,12 @@ static int tar_mount(Mount *mnt, const char *path) {
/* Return ok */
return FILESYSTEM_ESUCCESS;
fail:
if (fp) fclose(fp);
dmt_free(tar);
dmt_free(stream);
return FILESYSTEM_EFAILURE;
}

View File

@@ -19,6 +19,7 @@
#include "mouse.h"
#include "image.h"
#include "palette.h"
#include "package.h"
static lua_State *L;
@@ -45,6 +46,11 @@ int luaopen_love(lua_State *L);
int main(int argc, char **argv) {
/* Handle package command */
if ( package_run(argc, argv) == PACKAGE_ESUCCESS ) {
exit(EXIT_SUCCESS);
}
/* Init everything */
atexit(deinit);
vga_init();

207
src/package.c Normal file
View File

@@ -0,0 +1,207 @@
/**
* Copyright (c) 2016 rxi
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <stdarg.h>
#include "lib/microtar/microtar.h"
#include "package.h"
static void error(const char *fmt, ...) {
va_list argp;
printf("Package error: ");
va_start(argp, fmt);
vprintf(fmt, argp);
va_end(argp);
printf("\n");
exit(EXIT_FAILURE);
}
static int tar_stream_write(mtar_t *tar, const void *data, unsigned size) {
unsigned res = fwrite(data, 1, size, tar->stream);
if (res != size) {
error("failed when writing to output file");
}
return MTAR_ESUCCESS;
}
static void concat(char *dst, int dstsz, ...) {
const char *s;
va_list argp;
int i = 0;
va_start(argp, dstsz);
while ( (s = va_arg(argp, const char*)) ) {
while (*s) {
dst[i++] = *s++;
if (i == dstsz) {
error("string length exceeds destination buffer");
}
}
}
dst[i] = '\0';
va_end(argp);
}
static
void concat_path(char *dst, int dstsz, const char *dir, const char *filename) {
int dirlen = strlen(dir);
if ( dir[dirlen - 1] == '/' || *dir == '\0' ) {
concat(dst, dstsz, dir, filename, NULL);
} else {
concat(dst, dstsz, dir, "/", filename, NULL);
}
}
static void write_file(mtar_t *tar, const char *inname, const char *outname) {
FILE *fp = fopen(inname, "rb");
if (!fp) {
error("couldn't open input file '%s'", inname);
}
/* Get size */
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
fseek(fp, 0, SEEK_SET);
/* Write header */
mtar_header_t h;
memset(&h, 0, sizeof(h));
concat(h.name, sizeof(h.name), outname, NULL);
h.size = size;
h.mode = 0664;
mtar_write_header(tar, &h);
/* Write file */
int chr;
while ( (chr = fgetc(fp)) != EOF ) {
unsigned char byte = chr;
mtar_write_data(tar, &byte, 1);
}
/* Close file and return ok */
fclose(fp);
}
static void write_dir(mtar_t *tar, const char *indir, const char *outdir) {
char inbuf[256];
char outbuf[256];
struct dirent *ep;
DIR *dir = opendir(indir);
if (!dir) {
error("couldn't open input dir '%s'", indir);
}
/* Write dir */
mtar_header_t h;
memset(&h, 0, sizeof(h));
concat(h.name, sizeof(h.name), outdir, NULL);
h.type = MTAR_TDIR;
h.mode = 0664;
mtar_write_header(tar, &h);
/* Write files */
while ( (ep = readdir(dir)) ) {
/* Skip `.` and `..` */
if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..")) {
continue;
}
/* Get full input name and full output name */
concat_path(inbuf, sizeof(inbuf), indir, ep->d_name);
concat_path(outbuf, sizeof(outbuf), outdir, ep->d_name);
/* Write */
DIR *d = opendir(inbuf);
if (d) {
closedir(d);
write_dir(tar, inbuf, outbuf);
} else {
write_file(tar, inbuf, outbuf);
}
}
closedir(dir);
}
void package_make(const char *indir, const char *outfile, const char *exefile, int type) {
/* Open file */
FILE *fp = fopen(outfile, "wb");
if (!fp) {
error("couldn't open output file");
}
/* Copy .exe to file if exe type is set */
if (type == PACKAGE_TEXE) {
FILE *exefp = fopen(exefile, "rb");
if (!exefp) {
error("couldn't open .exe file");
}
int chr;
while ( (chr = fgetc(exefp)) != EOF ) {
fputc(chr, fp);
}
fclose(exefp);
}
/* Get start of file (used for offset) */
int start = ftell(fp);
/* Init tar writer */
mtar_t tar;
memset(&tar, 0, sizeof(tar));
tar.write = tar_stream_write;
tar.stream = fp;
/* Write package data to file and finalize tar */
write_dir(&tar, indir, "");
mtar_finalize(&tar);
/* Write "TAR\0" and offset int so we can find the .tar if it was appended
* onto the end of the .exe */
int offset = ftell(fp) - start + 8;
fwrite("TAR\0", 1, 4, fp);
fwrite(&offset, 1, 4, fp);
/* Done */
fclose(fp);
}
int package_run(int argc, char **argv) {
/* Check for `--pack` argument; return failure if it isn't present */
if (argc < 2) {
return PACKAGE_EFAILURE;
}
if ( strcmp(argv[1], "--pack") != 0 && strcmp(argv[1], "--PACK") != 0 ) {
return PACKAGE_EFAILURE;
}
/* Check arguments */
if (argc < 4) {
error("expected arguments: %s DIRNAME OUTFILE", argv[1]);
}
/* Set package type based on file extension */
int type = PACKAGE_TTAR;
if ( strstr(argv[3], ".exe") || strstr(argv[3], ".EXE") ) {
type = PACKAGE_TEXE;
}
/* Make package and return success*/
package_make(argv[2], argv[3], argv[0], type);
return PACKAGE_ESUCCESS;
}

19
src/package.h Normal file
View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2016 rxi
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the MIT license. See LICENSE for details.
*/
enum {
PACKAGE_TTAR,
PACKAGE_TEXE
};
enum {
PACKAGE_ESUCCESS = 0,
PACKAGE_EFAILURE = -1
};
void package_make(const char *indir, const char *outfile, const char *exefile, int type);
int package_run(int argc, char **argv);