aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fake-lib.c43
-rw-r--r--fake-lib.h3
-rw-r--r--fake-msi.c190
-rw-r--r--fake-winterop.c3
4 files changed, 190 insertions, 49 deletions
diff --git a/fake-lib.c b/fake-lib.c
index 9255005..2207ce3 100644
--- a/fake-lib.c
+++ b/fake-lib.c
@@ -28,6 +28,25 @@ char *ascii(const char16_t *wstr, bool translate_slashes)
28 return ret; 28 return ret;
29} 29}
30 30
31void 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
31void system_argv(const char *cmd, ...) 50void 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
74void c16cpy(char16_t *out, uint32_t *outsize, char *s) 79void 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
99void *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
94char *dupcat(const char *str, ...) 107char *dupcat(const char *str, ...)
95{ 108{
96 va_list ap; 109 va_list ap;
diff --git a/fake-lib.h b/fake-lib.h
index 65fed63..c95169a 100644
--- a/fake-lib.h
+++ b/fake-lib.h
@@ -1,9 +1,12 @@
1char *ascii(const char16_t *wstr, bool translate_slashes); 1char *ascii(const char16_t *wstr, bool translate_slashes);
2void system_argv(const char *cmd, ...); 2void system_argv(const char *cmd, ...);
3void system_argv_array(char **args);
3void c16cpy(char16_t *out, uint32_t *outsize, char *s); 4void c16cpy(char16_t *out, uint32_t *outsize, char *s);
4void *smalloc(size_t size); 5void *smalloc(size_t size);
6void *srealloc(void *ptr, size_t size);
5char *dupcat(const char *str, ...); 7char *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)
diff --git a/fake-msi.c b/fake-msi.c
index 59e0a4b..3f82f74 100644
--- a/fake-msi.c
+++ b/fake-msi.c
@@ -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
29typedef struct MsiTypePrefix {
30 enum { MAIN, VIEW, RECORD } type;
31} MsiTypePrefix;
32
33typedef struct MsiMainCtx {
34 MsiTypePrefix t;
35
36 char *tempdir;
37 char *outfile;
38
39 char **args;
40 int nargs, argsize;
41} MsiMainCtx;
42
43
28uint32_t MsiOpenDatabaseW(const char16_t *filename, 44uint32_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
39uint32_t MsiCloseHandle(void *handle) 71uint32_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
45uint32_t MsiDatabaseImportW(void *handle, const char16_t *folder, 88typedef struct MsiView {
46 const char16_t *file) 89 MsiTypePrefix t;
90
91 FILE *fp;
92 char *targetdir;
93 MsiMainCtx *ctx;
94} MsiView;
95
96uint32_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
53uint32_t MsiDatabaseOpenViewW(void *handle, const char16_t *query, 128uint32_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
61uint32_t MsiViewExecute(void *handle, void *params) 134typedef struct MsiRecord {
135 MsiTypePrefix t;
136
137 char *name, *data;
138} MsiRecord;
139
140MsiRecord *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
67void *MsiCreateRecord(uint32_t nparams) 151uint32_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
73uint32_t MsiRecordSetStringW(void *handle, uint32_t field, char16_t *value) 160uint32_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
80uint32_t MsiRecordSetStreamW(void *handle, uint32_t field, char16_t *path) 169uint32_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
87uint32_t MsiViewModify(void *vhandle, uint32_t mode, void *rechandle) 191uint32_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
94uint32_t MsiDatabaseCommit(void *handle) 201uint32_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;