1 |
#include "urlib.c" |
2 |
|
3 |
#include <stdio.h> |
4 |
#include <stdlib.h> |
5 |
#include <unistd.h> |
6 |
#include <errno.h> |
7 |
#include <string.h> |
8 |
#include <time.h> |
9 |
|
10 |
#include "liblzf/lzf_d.c" |
11 |
|
12 |
#include "urlib.h" |
13 |
|
14 |
/* some simple? dynamic memory management for paths might save ltos of ram */ |
15 |
static u_handle pack_handle; |
16 |
static u_handle lock_handle; |
17 |
static char tmppath[MAX_PATH]; |
18 |
static char currdir[MAX_PATH]; |
19 |
static char datadir[MAX_PATH]; // %AppData%/urlader |
20 |
static char exe_dir[MAX_PATH]; // %AppData%/urlader/EXE_ID |
21 |
static char execdir[MAX_PATH]; // %AppData%/urlader/EXE_ID/EXE_VER |
22 |
static char exe_id[MAX_PATH]; |
23 |
static char exe_ver[MAX_PATH]; |
24 |
|
25 |
static int exe_argc; |
26 |
static const char *exe_argv[MAX_ARGC]; |
27 |
static char exe_args[MAX_ARGS]; /* actual arguments strings copied here */ |
28 |
static unsigned int exe_argo; |
29 |
|
30 |
static void |
31 |
fatal (const char *msg) |
32 |
{ |
33 |
#ifdef _WIN32 |
34 |
MessageBox (0, msg, URLADER, 0); |
35 |
#else |
36 |
write (2, URLADER ": ", sizeof (URLADER ": ") - 1); |
37 |
write (2, msg, strlen (msg)); |
38 |
write (2, "\n", 1); |
39 |
#endif |
40 |
|
41 |
_exit (1); |
42 |
} |
43 |
|
44 |
static void |
45 |
tmpdir (const char *dir) |
46 |
{ |
47 |
static int cnt; |
48 |
|
49 |
for (;;) |
50 |
{ |
51 |
// #ifdef _WIN32 |
52 |
// sprintf (tmppath, "%s/%x_%x.tmp", dir, (unsigned int)GetCurrentProcessId (), ++cnt); |
53 |
// #else |
54 |
sprintf (tmppath, "%s/t-%x_%x.tmp", dir, (unsigned int)getpid () , ++cnt); |
55 |
// #endif |
56 |
|
57 |
if (!u_mkdir (tmppath)) |
58 |
return; |
59 |
} |
60 |
} |
61 |
|
62 |
static void |
63 |
systemv (const char *const argv[]) |
64 |
{ |
65 |
#ifdef _WIN32 |
66 |
_spawnv (P_WAIT, argv [0], argv); |
67 |
#else |
68 |
pid_t pid = fork (); |
69 |
|
70 |
if (pid < 0) |
71 |
fatal ("fork failure"); |
72 |
|
73 |
if (!pid) |
74 |
{ |
75 |
execv (argv [0], (void *)argv); |
76 |
_exit (124); |
77 |
} |
78 |
|
79 |
int status; |
80 |
waitpid (pid, &status, 0); |
81 |
#endif |
82 |
} |
83 |
|
84 |
static void |
85 |
deltree (const char *path) |
86 |
{ |
87 |
#ifdef _WIN32 |
88 |
char buf[MAX_PATH * 2 + 64]; |
89 |
const char *argv[] = { getenv ("COMSPEC"), "/c", "rd", "/s", "/q", buf, 0 }; |
90 |
sprintf (buf, "\"%s\"", path); |
91 |
#else |
92 |
const char *argv[] = { "/bin/rm", "-rf", path, 0 }; |
93 |
#endif |
94 |
systemv (argv); |
95 |
} |
96 |
|
97 |
static char *pack_base, *pack_end; |
98 |
static struct u_pack_hdr *pack_cur; |
99 |
static char *scratch; |
100 |
static unsigned int scratch_size; |
101 |
|
102 |
#define PACK_NAME ((char *)(pack_cur + 1)) |
103 |
#define PACK_DATA (PACK_NAME + u_16 (pack_cur->namelen) + 1) |
104 |
#define PACK_VALID pack_cur->type |
105 |
|
106 |
static void |
107 |
pack_next (void) |
108 |
{ |
109 |
unsigned int d = u_32 (pack_cur->datalen); |
110 |
|
111 |
pack_cur = (struct u_pack_hdr *)(PACK_DATA + d); |
112 |
} |
113 |
|
114 |
static void |
115 |
pack_unmap (void) |
116 |
{ |
117 |
if (pack_base) |
118 |
{ |
119 |
u_munmap (pack_base, pack_end - pack_base); |
120 |
pack_base = 0; |
121 |
} |
122 |
|
123 |
if (scratch) |
124 |
{ |
125 |
u_free (scratch, scratch_size); |
126 |
scratch = 0; |
127 |
} |
128 |
} |
129 |
|
130 |
static int |
131 |
pack_map (void) |
132 |
{ |
133 |
char *addr; |
134 |
unsigned int size; |
135 |
|
136 |
#ifdef _WIN32 |
137 |
BY_HANDLE_FILE_INFORMATION fi; |
138 |
|
139 |
if (!GetFileInformationByHandle (pack_handle, &fi)) |
140 |
return 0; |
141 |
|
142 |
size = fi.nFileSizeLow; |
143 |
#else |
144 |
size = lseek (pack_handle, 0, SEEK_END); |
145 |
#endif |
146 |
|
147 |
addr = u_mmap (pack_handle, size); |
148 |
if (!addr) |
149 |
return 0; |
150 |
|
151 |
pack_unmap (); |
152 |
|
153 |
pack_base = addr; |
154 |
pack_end = pack_base + size; |
155 |
|
156 |
struct u_pack_tail *tail; |
157 |
|
158 |
tail = (void *)(pack_end - sizeof (*tail)); |
159 |
|
160 |
if (memcmp (tail->magic, TAIL_MAGIC, sizeof (TAIL_MAGIC) - 1)) |
161 |
return 0; |
162 |
|
163 |
pack_cur = (struct u_pack_hdr *)(pack_end - u_32 (tail->size)); |
164 |
|
165 |
scratch = u_malloc (scratch_size = u_32 (tail->max_filesize)); |
166 |
if (!scratch) |
167 |
return 0; |
168 |
|
169 |
return 1; |
170 |
} |
171 |
|
172 |
static void |
173 |
exe_info (void) |
174 |
{ |
175 |
if (!pack_map ()) |
176 |
fatal ("unable to locate packfile in executable - executable corrupted?"); |
177 |
|
178 |
if (pack_cur->type != U_T_META) |
179 |
fatal ("unable to locate executable metadata - executable corrupted?"); |
180 |
|
181 |
strcpy (exe_id, PACK_NAME); |
182 |
} |
183 |
|
184 |
static void |
185 |
load (void) |
186 |
{ |
187 |
u_mkdir (datadir); |
188 |
|
189 |
strcpy (exe_dir, datadir); |
190 |
u_append (exe_dir, exe_id); |
191 |
u_mkdir (exe_dir); |
192 |
|
193 |
if (u_chdir (exe_dir)) |
194 |
fatal ("unable to change to application data directory"); |
195 |
|
196 |
u_handle h = u_open ("override"); |
197 |
if (u_valid (h)) |
198 |
{ |
199 |
u_handle oh = pack_handle; |
200 |
|
201 |
pack_handle = h; |
202 |
if (!pack_map ()) |
203 |
{ |
204 |
pack_handle = oh; |
205 |
oh = h; |
206 |
} |
207 |
|
208 |
u_close (oh); |
209 |
} |
210 |
|
211 |
if (pack_cur->type != U_T_META) |
212 |
fatal ("unable to locate override metadata"); |
213 |
|
214 |
strcpy (exe_ver, PACK_DATA); |
215 |
pack_next (); |
216 |
|
217 |
for (;;) |
218 |
{ |
219 |
if (pack_cur->type == U_T_ENV) |
220 |
u_setenv (PACK_NAME, PACK_DATA); |
221 |
else if (pack_cur->type == U_T_ARG) |
222 |
{ |
223 |
int len = u_16 (pack_cur->namelen) + 1; |
224 |
exe_argv [exe_argc++] = exe_args + exe_argo; |
225 |
memcpy (exe_args + exe_argo, PACK_NAME, len); |
226 |
exe_argo += len; |
227 |
} |
228 |
else |
229 |
break; |
230 |
|
231 |
pack_next (); |
232 |
} |
233 |
|
234 |
done_env_arg: |
235 |
strcpy (execdir, exe_dir); |
236 |
u_append (execdir, "i-"); |
237 |
strcat (execdir, exe_ver); |
238 |
|
239 |
strcat (strcpy (tmppath, execdir), ".lck"); |
240 |
lock_handle = u_lock (tmppath, 0, 1); |
241 |
if (!lock_handle) |
242 |
fatal ("unable to lock application instance"); |
243 |
|
244 |
if (access (execdir, F_OK)) |
245 |
{ |
246 |
// does not exist yet, so unpack and move |
247 |
tmpdir (exe_dir); |
248 |
|
249 |
if (u_chdir (tmppath)) |
250 |
fatal ("unable to change to new instance directory"); |
251 |
|
252 |
for (;;) |
253 |
{ |
254 |
switch (pack_cur->type) |
255 |
{ |
256 |
case U_T_DIR: |
257 |
u_mkdir (PACK_NAME); |
258 |
break; |
259 |
|
260 |
case U_T_FILE: |
261 |
{ |
262 |
u_handle h = u_creat (PACK_NAME, pack_cur->flags & U_F_EXEC); |
263 |
unsigned int dlen, len = u_32 (pack_cur->datalen); |
264 |
char *data = PACK_DATA; |
265 |
|
266 |
if (pack_cur->flags & U_F_LZF) |
267 |
if (dlen = lzf_decompress (data, len, scratch, scratch_size)) |
268 |
{ |
269 |
data = scratch; |
270 |
len = dlen; |
271 |
} |
272 |
else |
273 |
fatal ("unable to uncompress file data - pack corrupted?"); |
274 |
|
275 |
if (!u_valid (h)) |
276 |
fatal ("unable to unpack file from packfile - disk full?"); |
277 |
|
278 |
if (u_write (h, data, len) != len) |
279 |
fatal ("unable to unpack file from packfile - disk full?"); |
280 |
|
281 |
u_fsync (h); |
282 |
u_close (h); |
283 |
} |
284 |
break; |
285 |
|
286 |
case U_T_NULL: |
287 |
goto done; |
288 |
} |
289 |
|
290 |
pack_next (); |
291 |
} |
292 |
|
293 |
done: |
294 |
if (u_chdir (datadir)) |
295 |
fatal ("unable to change to data directory"); |
296 |
|
297 |
u_sync (); |
298 |
|
299 |
if (u_rename (tmppath, execdir)) |
300 |
deltree (tmppath); // if move fails, delete new, assume other process created it independently |
301 |
} |
302 |
|
303 |
pack_unmap (); |
304 |
u_close (pack_handle); |
305 |
|
306 |
if (u_chdir (execdir)) |
307 |
fatal ("unable to change to application instance directory"); |
308 |
|
309 |
u_setenv ("URLADER_VERSION", URLADER_VERSION); |
310 |
u_setenv ("URLADER_DATADIR", datadir); |
311 |
u_setenv ("URLADER_EXECDIR", execdir); |
312 |
u_setenv ("URLADER_EXE_ID" , exe_id); |
313 |
u_setenv ("URLADER_EXE_DIR", exe_dir); |
314 |
u_setenv ("URLADER_EXE_VER", exe_ver); |
315 |
|
316 |
#if 0 |
317 |
// yes, this is overkill |
318 |
u_setenv ("SHLIB_PATH" , execdir); // hpux |
319 |
u_setenv ("LIBPATH" , execdir); // aix |
320 |
u_setenv ("LD_LIBRARY_PATH" , execdir); // most elf systems |
321 |
u_setenv ("LD_LIBRARY_PATH_32", execdir); // solaris |
322 |
u_setenv ("LD_LIBRARY_PATH_64", execdir); // solaris |
323 |
u_setenv ("LD_LIBRARYN32_PATH", execdir); // irix |
324 |
u_setenv ("LD_LIBRARY64_PATH" , execdir); // irix |
325 |
u_setenv ("DYLD_LIBRARY_PATH" , execdir); // os sucks from apple |
326 |
#endif |
327 |
} |
328 |
|
329 |
static void |
330 |
execute (void) |
331 |
{ |
332 |
exe_argv [exe_argc] = 0; |
333 |
systemv (exe_argv); |
334 |
} |
335 |
|
336 |
#ifdef _WIN32 |
337 |
|
338 |
int APIENTRY |
339 |
WinMain (HINSTANCE hI, HINSTANCE hP, LPSTR argv, int command_show) |
340 |
{ |
341 |
if (!GetModuleFileName (hI, tmppath, sizeof (tmppath))) |
342 |
fatal ("unable to find executable pack"); |
343 |
|
344 |
pack_handle = u_open (tmppath); |
345 |
if (!u_valid (pack_handle)) |
346 |
fatal ("unable to open executable pack"); |
347 |
|
348 |
exe_info (); |
349 |
|
350 |
if (!GetCurrentDirectory (sizeof (currdir), currdir)) |
351 |
strcpy (currdir, "."); |
352 |
|
353 |
if (SHGetFolderPath (0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, datadir) != S_OK) |
354 |
fatal ("unable to find application data directory"); |
355 |
|
356 |
u_mkdir (datadir); |
357 |
u_append (datadir, URLADER); |
358 |
|
359 |
load (); |
360 |
execute (); |
361 |
|
362 |
return 0; |
363 |
} |
364 |
|
365 |
#else |
366 |
|
367 |
int |
368 |
main (int argc, char *argv[]) |
369 |
{ |
370 |
char *home = getenv ("HOME"); |
371 |
|
372 |
pack_handle = u_open (argv [0]); |
373 |
if (!u_valid (pack_handle)) |
374 |
fatal ("unable to open executable pack"); |
375 |
|
376 |
exe_info (); |
377 |
|
378 |
if (!home) |
379 |
{ |
380 |
struct passwd *pw; |
381 |
|
382 |
if ((pw = getpwuid (getuid ()))) |
383 |
home = pw->pw_dir; |
384 |
else |
385 |
home = "/tmp"; |
386 |
} |
387 |
|
388 |
if (!getcwd (currdir, sizeof (currdir))) |
389 |
strcpy (currdir, "."); |
390 |
|
391 |
u_mkdir (home); |
392 |
//strcat (strcat (strcpy (datadir, home), "/."), URLADER); |
393 |
sprintf (datadir, "%s/.%s", home, URLADER); |
394 |
u_mkdir (datadir); |
395 |
|
396 |
#if 0 |
397 |
if (gethostname (tmppath, sizeof (tmppath))) |
398 |
strcpy (tmppath, "default"); |
399 |
|
400 |
u_append (datadir, tmppath); |
401 |
#endif |
402 |
|
403 |
load (); |
404 |
execute (); |
405 |
|
406 |
return 0; |
407 |
} |
408 |
|
409 |
#endif |
410 |
|