diff options
| author | Simon Tatham <anakin@pobox.com> | 2017-05-15 20:04:18 +0100 |
|---|---|---|
| committer | Simon Tatham <anakin@pobox.com> | 2017-05-15 20:04:18 +0100 |
| commit | 29795aed5b2c81c264eab087e480d204ec7df8f8 (patch) | |
| tree | d3349d53478a998b1354d6ca4a9c32819f1592e5 | |
| parent | b19fd4ee7798a4948f5f47fafd89d67576a4642a (diff) | |
| download | wix-on-linux-29795aed5b2c81c264eab087e480d204ec7df8f8.tar.gz wix-on-linux-29795aed5b2c81c264eab087e480d204ec7df8f8.tar.bz2 wix-on-linux-29795aed5b2c81c264eab087e480d204ec7df8f8.zip | |
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.
| -rw-r--r-- | fake-lib.c | 43 | ||||
| -rw-r--r-- | fake-lib.h | 3 | ||||
| -rw-r--r-- | fake-msi.c | 190 | ||||
| -rw-r--r-- | fake-winterop.c | 3 |
4 files changed, 190 insertions, 49 deletions
| @@ -28,6 +28,25 @@ char *ascii(const char16_t *wstr, bool translate_slashes) | |||
| 28 | return ret; | 28 | return ret; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | void system_argv_array(char **args) | ||
| 32 | { | ||
| 33 | pid_t pid = fork(); | ||
| 34 | if (pid < 0) | ||
| 35 | err(1, "fork"); | ||
| 36 | |||
| 37 | if (pid == 0) { | ||
| 38 | execvp(args[0], args); | ||
| 39 | warn("execvp"); | ||
| 40 | _exit(127); | ||
| 41 | } | ||
| 42 | |||
| 43 | int status; | ||
| 44 | if (waitpid(pid, &status, 0) != pid) | ||
| 45 | err(1, "waitpid"); | ||
| 46 | if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0)) | ||
| 47 | errx(1, "subcommand failed"); | ||
| 48 | } | ||
| 49 | |||
| 31 | void system_argv(const char *cmd, ...) | 50 | void system_argv(const char *cmd, ...) |
| 32 | { | 51 | { |
| 33 | int nargs, nchars; | 52 | int nargs, nchars; |
| @@ -54,21 +73,7 @@ void system_argv(const char *cmd, ...) | |||
| 54 | va_end(ap); | 73 | va_end(ap); |
| 55 | *argp++ = NULL; | 74 | *argp++ = NULL; |
| 56 | 75 | ||
| 57 | pid_t pid = fork(); | 76 | system_argv_array(args); |
| 58 | if (pid < 0) | ||
| 59 | err(1, "fork"); | ||
| 60 | |||
| 61 | if (pid == 0) { | ||
| 62 | execvp(args[0], args); | ||
| 63 | warn("execvp"); | ||
| 64 | _exit(127); | ||
| 65 | } | ||
| 66 | |||
| 67 | int status; | ||
| 68 | if (waitpid(pid, &status, 0) != pid) | ||
| 69 | err(1, "waitpid"); | ||
| 70 | if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0)) | ||
| 71 | errx(1, "subcommand failed"); | ||
| 72 | } | 77 | } |
| 73 | 78 | ||
| 74 | void c16cpy(char16_t *out, uint32_t *outsize, char *s) | 79 | void c16cpy(char16_t *out, uint32_t *outsize, char *s) |
| @@ -91,6 +96,14 @@ void *smalloc(size_t size) | |||
| 91 | return toret; | 96 | return toret; |
| 92 | } | 97 | } |
| 93 | 98 | ||
| 99 | void *srealloc(void *ptr, size_t size) | ||
| 100 | { | ||
| 101 | void *toret = realloc(ptr, size); | ||
| 102 | if (!toret) | ||
| 103 | errx(1, "out of memory"); | ||
| 104 | return toret; | ||
| 105 | } | ||
| 106 | |||
| 94 | char *dupcat(const char *str, ...) | 107 | char *dupcat(const char *str, ...) |
| 95 | { | 108 | { |
| 96 | va_list ap; | 109 | va_list ap; |
| @@ -1,9 +1,12 @@ | |||
| 1 | char *ascii(const char16_t *wstr, bool translate_slashes); | 1 | char *ascii(const char16_t *wstr, bool translate_slashes); |
| 2 | void system_argv(const char *cmd, ...); | 2 | void system_argv(const char *cmd, ...); |
| 3 | void system_argv_array(char **args); | ||
| 3 | void c16cpy(char16_t *out, uint32_t *outsize, char *s); | 4 | void c16cpy(char16_t *out, uint32_t *outsize, char *s); |
| 4 | void *smalloc(size_t size); | 5 | void *smalloc(size_t size); |
| 6 | void *srealloc(void *ptr, size_t size); | ||
| 5 | char *dupcat(const char *str, ...); | 7 | char *dupcat(const char *str, ...); |
| 6 | 8 | ||
| 7 | #define snew(type) ((type *)smalloc(sizeof(type))) | 9 | #define snew(type) ((type *)smalloc(sizeof(type))) |
| 8 | #define snewn(n,type) ((type *)smalloc((n)*sizeof(type))) | 10 | #define snewn(n,type) ((type *)smalloc((n)*sizeof(type))) |
| 11 | #define sresize(ptr,n,type) ((type *)srealloc(ptr,(n)*sizeof(type))) | ||
| 9 | #define sfree(ptr) free(ptr) | 12 | #define sfree(ptr) free(ptr) |
| @@ -1,3 +1,4 @@ | |||
| 1 | #include <assert.h> | ||
| 1 | #include <stdio.h> | 2 | #include <stdio.h> |
| 2 | #include <stdlib.h> | 3 | #include <stdlib.h> |
| 3 | #include <stdint.h> | 4 | #include <stdint.h> |
| @@ -25,74 +26,199 @@ uint32_t MsiGetFileVersionW(const char16_t *filename, | |||
| 25 | return 0; | 26 | return 0; |
| 26 | } | 27 | } |
| 27 | 28 | ||
| 29 | typedef struct MsiTypePrefix { | ||
| 30 | enum { MAIN, VIEW, RECORD } type; | ||
| 31 | } MsiTypePrefix; | ||
| 32 | |||
| 33 | typedef struct MsiMainCtx { | ||
| 34 | MsiTypePrefix t; | ||
| 35 | |||
| 36 | char *tempdir; | ||
| 37 | char *outfile; | ||
| 38 | |||
| 39 | char **args; | ||
| 40 | int nargs, argsize; | ||
| 41 | } MsiMainCtx; | ||
| 42 | |||
| 43 | |||
| 28 | uint32_t MsiOpenDatabaseW(const char16_t *filename, | 44 | uint32_t MsiOpenDatabaseW(const char16_t *filename, |
| 29 | const char16_t *persist, | 45 | const char16_t *persist, |
| 30 | void **handle) | 46 | MsiMainCtx **out_ctx) |
| 31 | { | 47 | { |
| 32 | char *file = ascii(filename, true); | 48 | MsiMainCtx *ctx = snew(MsiMainCtx); |
| 33 | warnx("FIXME: MsiOpenDatabaseW(%s,%p)", file, persist); | 49 | ctx->t.type = MAIN; |
| 34 | close(open(file, O_WRONLY | O_CREAT, 0666)); | 50 | ctx->outfile = ascii(filename, true); |
| 35 | *handle = (void *)1; | 51 | close(open(ctx->outfile, O_CREAT | O_WRONLY, 0666)); |
| 52 | ctx->outfile = realpath(ctx->outfile, NULL); | ||
| 53 | unlink(ctx->outfile); | ||
| 54 | ctx->tempdir = dupcat(ctx->outfile, "-msiXXXXXX", (const char *)NULL); | ||
| 55 | if (!mkdtemp(ctx->tempdir)) | ||
| 56 | err(1, "%s: mkdtemp", ctx->tempdir); | ||
| 57 | ctx->nargs = 0; | ||
| 58 | ctx->argsize = 16; | ||
| 59 | ctx->args = snewn(ctx->argsize, char *); | ||
| 60 | ctx->args[ctx->nargs++] = dupcat("sh", (const char *)NULL); | ||
| 61 | ctx->args[ctx->nargs++] = dupcat("-c", (const char *)NULL); | ||
| 62 | ctx->args[ctx->nargs++] = dupcat("cd \"$0\" && \"$@\"", | ||
| 63 | (const char *)NULL); | ||
| 64 | ctx->args[ctx->nargs++] = dupcat(ctx->tempdir, (const char *)NULL); | ||
| 65 | ctx->args[ctx->nargs++] = dupcat("msibuild", (const char *)NULL); | ||
| 66 | ctx->args[ctx->nargs++] = dupcat(ctx->outfile, (const char *)NULL); | ||
| 67 | *out_ctx = ctx; | ||
| 36 | return 0; | 68 | return 0; |
| 37 | } | 69 | } |
| 38 | 70 | ||
| 39 | uint32_t MsiCloseHandle(void *handle) | 71 | uint32_t MsiDatabaseImportW(MsiMainCtx *ctx, const char16_t *folder, |
| 72 | const char16_t *file) | ||
| 40 | { | 73 | { |
| 41 | warnx("FIXME: MsiCloseHandle(%p)", handle); | 74 | assert(ctx->t.type == MAIN); |
| 75 | system_argv("sh", "-c", "cd \"$0\" && cp \"$1\" \"$2\"", | ||
| 76 | ascii(folder, true), ascii(file, true), ctx->tempdir, | ||
| 77 | (const char *)NULL); | ||
| 78 | if (ctx->nargs + 2 >= ctx->argsize) { | ||
| 79 | ctx->argsize = ctx->nargs * 5 / 4 + 16; | ||
| 80 | ctx->args = sresize(ctx->args, ctx->argsize, char *); | ||
| 81 | } | ||
| 82 | ctx->args[ctx->nargs++] = dupcat("-i", (const char *)NULL); | ||
| 83 | ctx->args[ctx->nargs++] = dupcat(ctx->tempdir, "/", ascii(file, true), | ||
| 84 | (const char *)NULL); | ||
| 42 | return 0; | 85 | return 0; |
| 43 | } | 86 | } |
| 44 | 87 | ||
| 45 | uint32_t MsiDatabaseImportW(void *handle, const char16_t *folder, | 88 | typedef struct MsiView { |
| 46 | const char16_t *file) | 89 | MsiTypePrefix t; |
| 90 | |||
| 91 | FILE *fp; | ||
| 92 | char *targetdir; | ||
| 93 | MsiMainCtx *ctx; | ||
| 94 | } MsiView; | ||
| 95 | |||
| 96 | uint32_t MsiDatabaseOpenViewW(MsiMainCtx *ctx, const char16_t *query, | ||
| 97 | MsiView **outview) | ||
| 47 | { | 98 | { |
| 48 | warnx("FIXME: MsiDatabaseImport(%p,%s,%s)", handle, ascii(folder, true), | 99 | assert(ctx->t.type == MAIN); |
| 49 | ascii(file, true)); | 100 | MsiView *view = snew(MsiView); |
| 101 | view->t.type = VIEW; | ||
| 102 | view->ctx = ctx; | ||
| 103 | char *cquery = ascii(query, false); | ||
| 104 | if (!strcmp(cquery, "SELECT `Name`, `Data` FROM `_Streams`")) | ||
| 105 | view->fp = NULL; /* special case */ | ||
| 106 | else { | ||
| 107 | if (!strcmp(cquery, "SELECT `Name`, `Data` FROM `Binary`")) { | ||
| 108 | view->fp = fopen(dupcat(ctx->tempdir, "/", "Binary.idt", | ||
| 109 | (const char *)NULL), "a"); | ||
| 110 | view->targetdir = dupcat(ctx->tempdir, "/", "Binary", | ||
| 111 | (const char *)NULL); | ||
| 112 | } else if (!strcmp(cquery, "SELECT `Name`, `Data` FROM `Icon`")) { | ||
| 113 | view->fp = fopen(dupcat(ctx->tempdir, "/", "Icon.idt", | ||
| 114 | (const char *)NULL), "a"); | ||
| 115 | view->targetdir = dupcat(ctx->tempdir, "/", "Icon", | ||
| 116 | (const char *)NULL); | ||
| 117 | } else | ||
| 118 | errx(1, "unrecognised query: %s", cquery); | ||
| 119 | if (!view->fp) | ||
| 120 | err(1, "open"); | ||
| 121 | if (mkdir(view->targetdir, 0777) < 0) | ||
| 122 | err(1, "%s: mkdir", view->targetdir); | ||
| 123 | } | ||
| 124 | *outview = view; | ||
| 50 | return 0; | 125 | return 0; |
| 51 | } | 126 | } |
| 52 | 127 | ||
| 53 | uint32_t MsiDatabaseOpenViewW(void *handle, const char16_t *query, | 128 | uint32_t MsiViewExecute(MsiView *view, void *params) |
| 54 | void **outhandle) | ||
| 55 | { | 129 | { |
| 56 | warnx("FIXME: MsiDatabaseOpenView(%p,%s)", handle, ascii(query, false)); | 130 | assert(view->t.type == VIEW); |
| 57 | *outhandle = (void *)2; | ||
| 58 | return 0; | 131 | return 0; |
| 59 | } | 132 | } |
| 60 | 133 | ||
| 61 | uint32_t MsiViewExecute(void *handle, void *params) | 134 | typedef struct MsiRecord { |
| 135 | MsiTypePrefix t; | ||
| 136 | |||
| 137 | char *name, *data; | ||
| 138 | } MsiRecord; | ||
| 139 | |||
| 140 | MsiRecord *MsiCreateRecord(uint32_t nparams) | ||
| 62 | { | 141 | { |
| 63 | warnx("FIXME: MsiViewExecute(%p)", handle); | 142 | MsiRecord *rec = snew(MsiRecord); |
| 64 | return 0; | 143 | rec->t.type = RECORD; |
| 144 | |||
| 145 | if (nparams != 2) | ||
| 146 | errx(1, "bad MsiCreateRecord param count %u", (unsigned)nparams); | ||
| 147 | rec->name = rec->data = NULL; | ||
| 148 | return rec; | ||
| 65 | } | 149 | } |
| 66 | 150 | ||
| 67 | void *MsiCreateRecord(uint32_t nparams) | 151 | uint32_t MsiRecordSetStringW(MsiRecord *rec, uint32_t field, char16_t *value) |
| 68 | { | 152 | { |
| 69 | warnx("FIXME: MsiCreateRecord(%u)", (unsigned)nparams); | 153 | assert(rec->t.type == RECORD); |
| 70 | return (void *)3; | 154 | if (field != 1) |
| 155 | errx(1, "bad MsiRecordSetString param index %u", (unsigned)field); | ||
| 156 | rec->name = ascii(value, false); | ||
| 157 | return 0; | ||
| 71 | } | 158 | } |
| 72 | 159 | ||
| 73 | uint32_t MsiRecordSetStringW(void *handle, uint32_t field, char16_t *value) | 160 | uint32_t MsiRecordSetStreamW(MsiRecord *rec, uint32_t field, char16_t *path) |
| 74 | { | 161 | { |
| 75 | warnx("FIXME: MsiRecordSetString(%p,%u,%s)", handle, (unsigned)field, | 162 | assert(rec->t.type == RECORD); |
| 76 | ascii(value, false)); | 163 | if (field != 2) |
| 164 | errx(1, "bad MsiRecordSetStream param index %u", (unsigned)field); | ||
| 165 | rec->data = ascii(path, true); | ||
| 77 | return 0; | 166 | return 0; |
| 78 | } | 167 | } |
| 79 | 168 | ||
| 80 | uint32_t MsiRecordSetStreamW(void *handle, uint32_t field, char16_t *path) | 169 | uint32_t MsiViewModify(MsiView *view, uint32_t mode, MsiRecord *rec) |
| 81 | { | 170 | { |
| 82 | warnx("FIXME: MsiRecordSetStream(%p,%u,%s)", handle, (unsigned)field, | 171 | assert(view->t.type == VIEW); |
| 83 | ascii(path, true)); | 172 | assert(rec->t.type == RECORD); |
| 173 | if (view->fp) { | ||
| 174 | system_argv("sh", "-c", "cp \"$0\" \"$1\"/\"$2\"", | ||
| 175 | rec->data, view->targetdir, rec->name, | ||
| 176 | (const char *)NULL); | ||
| 177 | fprintf(view->fp, "%s\t%s\r\n", rec->name, rec->name); | ||
| 178 | } else { | ||
| 179 | MsiMainCtx *ctx = view->ctx; | ||
| 180 | if (ctx->nargs + 3 >= ctx->argsize) { | ||
| 181 | ctx->argsize = ctx->nargs * 5 / 4 + 16; | ||
| 182 | ctx->args = sresize(ctx->args, ctx->argsize, char *); | ||
| 183 | } | ||
| 184 | ctx->args[ctx->nargs++] = dupcat("-s", (const char *)NULL); | ||
| 185 | ctx->args[ctx->nargs++] = dupcat(rec->name, (const char *)NULL); | ||
| 186 | ctx->args[ctx->nargs++] = dupcat(rec->data, (const char *)NULL); | ||
| 187 | } | ||
| 84 | return 0; | 188 | return 0; |
| 85 | } | 189 | } |
| 86 | 190 | ||
| 87 | uint32_t MsiViewModify(void *vhandle, uint32_t mode, void *rechandle) | 191 | uint32_t MsiCloseHandle(MsiTypePrefix *t) |
| 88 | { | 192 | { |
| 89 | warnx("FIXME: MsiViewModify(%p,%u,%p)", | 193 | if (t->type == VIEW) { |
| 90 | vhandle, (unsigned)mode, rechandle); | 194 | MsiView *view = (MsiView *)t; |
| 195 | if (view->fp) | ||
| 196 | fclose(view->fp); | ||
| 197 | } | ||
| 91 | return 0; | 198 | return 0; |
| 92 | } | 199 | } |
| 93 | 200 | ||
| 94 | uint32_t MsiDatabaseCommit(void *handle) | 201 | uint32_t MsiDatabaseCommit(MsiMainCtx *ctx) |
| 95 | { | 202 | { |
| 96 | warnx("FIXME: MsiDatabaseCommit(%p)", handle); | 203 | assert(ctx->t.type == MAIN); |
| 204 | printf("commit:"); | ||
| 205 | for (int i = 0; i < ctx->nargs; i++) { | ||
| 206 | printf(" '"); | ||
| 207 | for (const char *p = ctx->args[i]; *p; p++) { | ||
| 208 | if (*p == '\'') | ||
| 209 | printf("'\\''"); | ||
| 210 | else | ||
| 211 | putchar(*p); | ||
| 212 | } | ||
| 213 | printf("'"); | ||
| 214 | } | ||
| 215 | printf("\n"); | ||
| 216 | |||
| 217 | if (ctx->nargs + 1 >= ctx->argsize) { | ||
| 218 | ctx->argsize = ctx->nargs * 5 / 4 + 16; | ||
| 219 | ctx->args = sresize(ctx->args, ctx->argsize, char *); | ||
| 220 | } | ||
| 221 | ctx->args[ctx->nargs++] = NULL; | ||
| 222 | system_argv_array(ctx->args); | ||
| 97 | return 0; | 223 | return 0; |
| 98 | } | 224 | } |
diff --git a/fake-winterop.c b/fake-winterop.c index d792553..c302f12 100644 --- a/fake-winterop.c +++ b/fake-winterop.c | |||
| @@ -40,8 +40,7 @@ uint32_t CreateCabBegin(const char16_t *wzCab, const char16_t *wzCabDir, | |||
| 40 | ctx->outdir = ascii(wzCabDir, true); | 40 | ctx->outdir = ascii(wzCabDir, true); |
| 41 | ctx->outfile = dupcat(ctx->outdir, "/", | 41 | ctx->outfile = dupcat(ctx->outdir, "/", |
| 42 | ascii(wzCab, true), (const char *)NULL); | 42 | ascii(wzCab, true), (const char *)NULL); |
| 43 | ctx->tempdir = snewn(20 + strlen(ctx->outdir), char); | 43 | ctx->tempdir = dupcat(ctx->outdir, "/cabXXXXXX", (const char *)NULL); |
| 44 | sprintf(ctx->tempdir, "%s/cabXXXXXX", ctx->outdir); | ||
| 45 | if (!mkdtemp(ctx->tempdir)) | 44 | if (!mkdtemp(ctx->tempdir)) |
| 46 | err(1, "mkdtemp"); | 45 | err(1, "mkdtemp"); |
| 47 | *out_ctx = ctx; | 46 | *out_ctx = ctx; |
