wix-on-linux/fake-msi.c
2017-05-18 06:57:18 +01:00

215 lines
6.3 KiB
C

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <uchar.h>
#include <err.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "memory.h"
#include "fake-lib.h"
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,
MsiMainCtx **out_ctx)
{
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 MsiDatabaseImportW(MsiMainCtx *ctx, const char16_t *folder,
const char16_t *file)
{
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;
}
typedef struct MsiView {
MsiTypePrefix t;
FILE *fp;
char *targetdir;
MsiMainCtx *ctx;
} MsiView;
uint32_t MsiDatabaseOpenViewW(MsiMainCtx *ctx, const char16_t *query,
MsiView **outview)
{
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(MsiView *view, void *params)
{
assert(view->t.type == VIEW);
return 0;
}
typedef struct MsiRecord {
MsiTypePrefix t;
char *name, *data;
} MsiRecord;
MsiRecord *MsiCreateRecord(uint32_t nparams)
{
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(MsiRecord *rec, uint32_t field, char16_t *value)
{
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(MsiRecord *rec, uint32_t field, char16_t *path)
{
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(MsiView *view, uint32_t mode, MsiRecord *rec)
{
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("-a", (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 MsiCloseHandle(MsiTypePrefix *t)
{
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;
}