We now get as far as building a non-empty MSI file!
But I haven't tested it yet, so it's probably got a zillion things wrong inside it.
This commit is contained in:
parent
b19fd4ee77
commit
29795aed5b
4 changed files with 192 additions and 51 deletions
43
fake-lib.c
43
fake-lib.c
|
@ -28,6 +28,25 @@ char *ascii(const char16_t *wstr, bool translate_slashes)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void system_argv_array(char **args)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
err(1, "fork");
|
||||
|
||||
if (pid == 0) {
|
||||
execvp(args[0], args);
|
||||
warn("execvp");
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
int status;
|
||||
if (waitpid(pid, &status, 0) != pid)
|
||||
err(1, "waitpid");
|
||||
if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0))
|
||||
errx(1, "subcommand failed");
|
||||
}
|
||||
|
||||
void system_argv(const char *cmd, ...)
|
||||
{
|
||||
int nargs, nchars;
|
||||
|
@ -54,21 +73,7 @@ void system_argv(const char *cmd, ...)
|
|||
va_end(ap);
|
||||
*argp++ = NULL;
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
err(1, "fork");
|
||||
|
||||
if (pid == 0) {
|
||||
execvp(args[0], args);
|
||||
warn("execvp");
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
int status;
|
||||
if (waitpid(pid, &status, 0) != pid)
|
||||
err(1, "waitpid");
|
||||
if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0))
|
||||
errx(1, "subcommand failed");
|
||||
system_argv_array(args);
|
||||
}
|
||||
|
||||
void c16cpy(char16_t *out, uint32_t *outsize, char *s)
|
||||
|
@ -91,6 +96,14 @@ void *smalloc(size_t size)
|
|||
return toret;
|
||||
}
|
||||
|
||||
void *srealloc(void *ptr, size_t size)
|
||||
{
|
||||
void *toret = realloc(ptr, size);
|
||||
if (!toret)
|
||||
errx(1, "out of memory");
|
||||
return toret;
|
||||
}
|
||||
|
||||
char *dupcat(const char *str, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
char *ascii(const char16_t *wstr, bool translate_slashes);
|
||||
void system_argv(const char *cmd, ...);
|
||||
void system_argv_array(char **args);
|
||||
void c16cpy(char16_t *out, uint32_t *outsize, char *s);
|
||||
void *smalloc(size_t size);
|
||||
void *srealloc(void *ptr, size_t size);
|
||||
char *dupcat(const char *str, ...);
|
||||
|
||||
#define snew(type) ((type *)smalloc(sizeof(type)))
|
||||
#define snewn(n,type) ((type *)smalloc((n)*sizeof(type)))
|
||||
#define sresize(ptr,n,type) ((type *)srealloc(ptr,(n)*sizeof(type)))
|
||||
#define sfree(ptr) free(ptr)
|
||||
|
|
194
fake-msi.c
194
fake-msi.c
|
@ -1,3 +1,4 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
@ -25,74 +26,199 @@ uint32_t MsiGetFileVersionW(const char16_t *filename,
|
|||
return 0;
|
||||
}
|
||||
|
||||
typedef struct MsiTypePrefix {
|
||||
enum { MAIN, VIEW, RECORD } type;
|
||||
} MsiTypePrefix;
|
||||
|
||||
typedef struct MsiMainCtx {
|
||||
MsiTypePrefix t;
|
||||
|
||||
char *tempdir;
|
||||
char *outfile;
|
||||
|
||||
char **args;
|
||||
int nargs, argsize;
|
||||
} MsiMainCtx;
|
||||
|
||||
|
||||
uint32_t MsiOpenDatabaseW(const char16_t *filename,
|
||||
const char16_t *persist,
|
||||
void **handle)
|
||||
MsiMainCtx **out_ctx)
|
||||
{
|
||||
char *file = ascii(filename, true);
|
||||
warnx("FIXME: MsiOpenDatabaseW(%s,%p)", file, persist);
|
||||
close(open(file, O_WRONLY | O_CREAT, 0666));
|
||||
*handle = (void *)1;
|
||||
MsiMainCtx *ctx = snew(MsiMainCtx);
|
||||
ctx->t.type = MAIN;
|
||||
ctx->outfile = ascii(filename, true);
|
||||
close(open(ctx->outfile, O_CREAT | O_WRONLY, 0666));
|
||||
ctx->outfile = realpath(ctx->outfile, NULL);
|
||||
unlink(ctx->outfile);
|
||||
ctx->tempdir = dupcat(ctx->outfile, "-msiXXXXXX", (const char *)NULL);
|
||||
if (!mkdtemp(ctx->tempdir))
|
||||
err(1, "%s: mkdtemp", ctx->tempdir);
|
||||
ctx->nargs = 0;
|
||||
ctx->argsize = 16;
|
||||
ctx->args = snewn(ctx->argsize, char *);
|
||||
ctx->args[ctx->nargs++] = dupcat("sh", (const char *)NULL);
|
||||
ctx->args[ctx->nargs++] = dupcat("-c", (const char *)NULL);
|
||||
ctx->args[ctx->nargs++] = dupcat("cd \"$0\" && \"$@\"",
|
||||
(const char *)NULL);
|
||||
ctx->args[ctx->nargs++] = dupcat(ctx->tempdir, (const char *)NULL);
|
||||
ctx->args[ctx->nargs++] = dupcat("msibuild", (const char *)NULL);
|
||||
ctx->args[ctx->nargs++] = dupcat(ctx->outfile, (const char *)NULL);
|
||||
*out_ctx = ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiCloseHandle(void *handle)
|
||||
{
|
||||
warnx("FIXME: MsiCloseHandle(%p)", handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiDatabaseImportW(void *handle, const char16_t *folder,
|
||||
uint32_t MsiDatabaseImportW(MsiMainCtx *ctx, const char16_t *folder,
|
||||
const char16_t *file)
|
||||
{
|
||||
warnx("FIXME: MsiDatabaseImport(%p,%s,%s)", handle, ascii(folder, true),
|
||||
ascii(file, true));
|
||||
assert(ctx->t.type == MAIN);
|
||||
system_argv("sh", "-c", "cd \"$0\" && cp \"$1\" \"$2\"",
|
||||
ascii(folder, true), ascii(file, true), ctx->tempdir,
|
||||
(const char *)NULL);
|
||||
if (ctx->nargs + 2 >= ctx->argsize) {
|
||||
ctx->argsize = ctx->nargs * 5 / 4 + 16;
|
||||
ctx->args = sresize(ctx->args, ctx->argsize, char *);
|
||||
}
|
||||
ctx->args[ctx->nargs++] = dupcat("-i", (const char *)NULL);
|
||||
ctx->args[ctx->nargs++] = dupcat(ctx->tempdir, "/", ascii(file, true),
|
||||
(const char *)NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiDatabaseOpenViewW(void *handle, const char16_t *query,
|
||||
void **outhandle)
|
||||
typedef struct MsiView {
|
||||
MsiTypePrefix t;
|
||||
|
||||
FILE *fp;
|
||||
char *targetdir;
|
||||
MsiMainCtx *ctx;
|
||||
} MsiView;
|
||||
|
||||
uint32_t MsiDatabaseOpenViewW(MsiMainCtx *ctx, const char16_t *query,
|
||||
MsiView **outview)
|
||||
{
|
||||
warnx("FIXME: MsiDatabaseOpenView(%p,%s)", handle, ascii(query, false));
|
||||
*outhandle = (void *)2;
|
||||
assert(ctx->t.type == MAIN);
|
||||
MsiView *view = snew(MsiView);
|
||||
view->t.type = VIEW;
|
||||
view->ctx = ctx;
|
||||
char *cquery = ascii(query, false);
|
||||
if (!strcmp(cquery, "SELECT `Name`, `Data` FROM `_Streams`"))
|
||||
view->fp = NULL; /* special case */
|
||||
else {
|
||||
if (!strcmp(cquery, "SELECT `Name`, `Data` FROM `Binary`")) {
|
||||
view->fp = fopen(dupcat(ctx->tempdir, "/", "Binary.idt",
|
||||
(const char *)NULL), "a");
|
||||
view->targetdir = dupcat(ctx->tempdir, "/", "Binary",
|
||||
(const char *)NULL);
|
||||
} else if (!strcmp(cquery, "SELECT `Name`, `Data` FROM `Icon`")) {
|
||||
view->fp = fopen(dupcat(ctx->tempdir, "/", "Icon.idt",
|
||||
(const char *)NULL), "a");
|
||||
view->targetdir = dupcat(ctx->tempdir, "/", "Icon",
|
||||
(const char *)NULL);
|
||||
} else
|
||||
errx(1, "unrecognised query: %s", cquery);
|
||||
if (!view->fp)
|
||||
err(1, "open");
|
||||
if (mkdir(view->targetdir, 0777) < 0)
|
||||
err(1, "%s: mkdir", view->targetdir);
|
||||
}
|
||||
*outview = view;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiViewExecute(void *handle, void *params)
|
||||
uint32_t MsiViewExecute(MsiView *view, void *params)
|
||||
{
|
||||
warnx("FIXME: MsiViewExecute(%p)", handle);
|
||||
assert(view->t.type == VIEW);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *MsiCreateRecord(uint32_t nparams)
|
||||
typedef struct MsiRecord {
|
||||
MsiTypePrefix t;
|
||||
|
||||
char *name, *data;
|
||||
} MsiRecord;
|
||||
|
||||
MsiRecord *MsiCreateRecord(uint32_t nparams)
|
||||
{
|
||||
warnx("FIXME: MsiCreateRecord(%u)", (unsigned)nparams);
|
||||
return (void *)3;
|
||||
MsiRecord *rec = snew(MsiRecord);
|
||||
rec->t.type = RECORD;
|
||||
|
||||
if (nparams != 2)
|
||||
errx(1, "bad MsiCreateRecord param count %u", (unsigned)nparams);
|
||||
rec->name = rec->data = NULL;
|
||||
return rec;
|
||||
}
|
||||
|
||||
uint32_t MsiRecordSetStringW(void *handle, uint32_t field, char16_t *value)
|
||||
uint32_t MsiRecordSetStringW(MsiRecord *rec, uint32_t field, char16_t *value)
|
||||
{
|
||||
warnx("FIXME: MsiRecordSetString(%p,%u,%s)", handle, (unsigned)field,
|
||||
ascii(value, false));
|
||||
assert(rec->t.type == RECORD);
|
||||
if (field != 1)
|
||||
errx(1, "bad MsiRecordSetString param index %u", (unsigned)field);
|
||||
rec->name = ascii(value, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiRecordSetStreamW(void *handle, uint32_t field, char16_t *path)
|
||||
uint32_t MsiRecordSetStreamW(MsiRecord *rec, uint32_t field, char16_t *path)
|
||||
{
|
||||
warnx("FIXME: MsiRecordSetStream(%p,%u,%s)", handle, (unsigned)field,
|
||||
ascii(path, true));
|
||||
assert(rec->t.type == RECORD);
|
||||
if (field != 2)
|
||||
errx(1, "bad MsiRecordSetStream param index %u", (unsigned)field);
|
||||
rec->data = ascii(path, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiViewModify(void *vhandle, uint32_t mode, void *rechandle)
|
||||
uint32_t MsiViewModify(MsiView *view, uint32_t mode, MsiRecord *rec)
|
||||
{
|
||||
warnx("FIXME: MsiViewModify(%p,%u,%p)",
|
||||
vhandle, (unsigned)mode, rechandle);
|
||||
assert(view->t.type == VIEW);
|
||||
assert(rec->t.type == RECORD);
|
||||
if (view->fp) {
|
||||
system_argv("sh", "-c", "cp \"$0\" \"$1\"/\"$2\"",
|
||||
rec->data, view->targetdir, rec->name,
|
||||
(const char *)NULL);
|
||||
fprintf(view->fp, "%s\t%s\r\n", rec->name, rec->name);
|
||||
} else {
|
||||
MsiMainCtx *ctx = view->ctx;
|
||||
if (ctx->nargs + 3 >= ctx->argsize) {
|
||||
ctx->argsize = ctx->nargs * 5 / 4 + 16;
|
||||
ctx->args = sresize(ctx->args, ctx->argsize, char *);
|
||||
}
|
||||
ctx->args[ctx->nargs++] = dupcat("-s", (const char *)NULL);
|
||||
ctx->args[ctx->nargs++] = dupcat(rec->name, (const char *)NULL);
|
||||
ctx->args[ctx->nargs++] = dupcat(rec->data, (const char *)NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiDatabaseCommit(void *handle)
|
||||
uint32_t MsiCloseHandle(MsiTypePrefix *t)
|
||||
{
|
||||
warnx("FIXME: MsiDatabaseCommit(%p)", handle);
|
||||
if (t->type == VIEW) {
|
||||
MsiView *view = (MsiView *)t;
|
||||
if (view->fp)
|
||||
fclose(view->fp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t MsiDatabaseCommit(MsiMainCtx *ctx)
|
||||
{
|
||||
assert(ctx->t.type == MAIN);
|
||||
printf("commit:");
|
||||
for (int i = 0; i < ctx->nargs; i++) {
|
||||
printf(" '");
|
||||
for (const char *p = ctx->args[i]; *p; p++) {
|
||||
if (*p == '\'')
|
||||
printf("'\\''");
|
||||
else
|
||||
putchar(*p);
|
||||
}
|
||||
printf("'");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (ctx->nargs + 1 >= ctx->argsize) {
|
||||
ctx->argsize = ctx->nargs * 5 / 4 + 16;
|
||||
ctx->args = sresize(ctx->args, ctx->argsize, char *);
|
||||
}
|
||||
ctx->args[ctx->nargs++] = NULL;
|
||||
system_argv_array(ctx->args);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -40,8 +40,7 @@ uint32_t CreateCabBegin(const char16_t *wzCab, const char16_t *wzCabDir,
|
|||
ctx->outdir = ascii(wzCabDir, true);
|
||||
ctx->outfile = dupcat(ctx->outdir, "/",
|
||||
ascii(wzCab, true), (const char *)NULL);
|
||||
ctx->tempdir = snewn(20 + strlen(ctx->outdir), char);
|
||||
sprintf(ctx->tempdir, "%s/cabXXXXXX", ctx->outdir);
|
||||
ctx->tempdir = dupcat(ctx->outdir, "/cabXXXXXX", (const char *)NULL);
|
||||
if (!mkdtemp(ctx->tempdir))
|
||||
err(1, "mkdtemp");
|
||||
*out_ctx = ctx;
|
||||
|
|
Loading…
Add table
Reference in a new issue