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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
207
src/package.c
Normal 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
19
src/package.h
Normal 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);
|
||||
Reference in New Issue
Block a user