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) {
|
typedef struct { FILE *fp; int offset; } TarStream;
|
||||||
mtar_t *tar = dmt_malloc( sizeof(*tar) );
|
|
||||||
|
|
||||||
/* Try to init tar */
|
static int tar_stream_read(mtar_t *tar, void *data, unsigned size) {
|
||||||
int err = mtar_open(tar, path, "r");
|
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) {
|
if (err) {
|
||||||
dmt_free(tar);
|
int offset;
|
||||||
return FILESYSTEM_EFAILURE;
|
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 */
|
/* Init mount */
|
||||||
@@ -262,6 +328,12 @@ static int tar_mount(Mount *mnt, const char *path) {
|
|||||||
|
|
||||||
/* Return ok */
|
/* Return ok */
|
||||||
return FILESYSTEM_ESUCCESS;
|
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 "mouse.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "palette.h"
|
#include "palette.h"
|
||||||
|
#include "package.h"
|
||||||
|
|
||||||
|
|
||||||
static lua_State *L;
|
static lua_State *L;
|
||||||
@@ -45,6 +46,11 @@ int luaopen_love(lua_State *L);
|
|||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
/* Handle package command */
|
||||||
|
if ( package_run(argc, argv) == PACKAGE_ESUCCESS ) {
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
/* Init everything */
|
/* Init everything */
|
||||||
atexit(deinit);
|
atexit(deinit);
|
||||||
vga_init();
|
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