1 |
root |
1.1 |
#ifndef URLADER |
2 |
|
|
# define URLADER "urlader" |
3 |
|
|
#endif |
4 |
|
|
#define URLADER_VERSION "1.0" |
5 |
|
|
|
6 |
|
|
#include <stdio.h> |
7 |
|
|
#include <stdlib.h> |
8 |
|
|
#include <unistd.h> |
9 |
|
|
#include <errno.h> |
10 |
|
|
#include <string.h> |
11 |
|
|
#include <time.h> |
12 |
|
|
#include <fcntl.h> |
13 |
|
|
|
14 |
root |
1.2 |
#include "liblzf/lzf_d.c" |
15 |
root |
1.1 |
|
16 |
|
|
#define TAIL_MAGIC "SCHMORPPACK0" |
17 |
|
|
|
18 |
|
|
#ifdef _WIN32 |
19 |
|
|
|
20 |
|
|
#include <windows.h> |
21 |
|
|
//#include <winbase.h> |
22 |
|
|
#include <shlobj.h> |
23 |
|
|
#include <shlwapi.h> |
24 |
|
|
#include <wininet.h> |
25 |
|
|
|
26 |
|
|
static DWORD dword; |
27 |
|
|
|
28 |
|
|
#define u_handle HANDLE |
29 |
|
|
#define u_setenv(name,value) SetEnvironmentVariable (name, value) |
30 |
|
|
#define u_mkdir(path) !CreateDirectory (path, NULL) |
31 |
|
|
#define u_chdir(path) !SetCurrentDirectory (path) |
32 |
|
|
#define u_rename(fr,to) !MoveFile (fr, to) |
33 |
|
|
#define u_open(path) CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) |
34 |
|
|
#define u_creat(path,exec) CreateFile (path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) |
35 |
|
|
#define u_close(handle) CloseHandle (handle) |
36 |
|
|
#define u_append(path,add) PathAppend (path, add) |
37 |
|
|
#define u_write(handle,data,len) (WriteFile (handle, data, len, &dword, 0) ? dword : -1) |
38 |
root |
1.3 |
#define u_sync() // use transacted I/O? |
39 |
root |
1.1 |
|
40 |
|
|
#else |
41 |
|
|
|
42 |
|
|
#include <sys/mman.h> |
43 |
|
|
#include <sys/types.h> |
44 |
|
|
#include <pwd.h> |
45 |
|
|
|
46 |
|
|
#ifdef PATH_MAX |
47 |
|
|
#define MAX_PATH (PATH_MAX < 4096 ? 4096 : PATH_MAX) |
48 |
|
|
#else |
49 |
|
|
#define MAX_PATH 4096 |
50 |
|
|
#endif |
51 |
|
|
|
52 |
|
|
#define u_handle int |
53 |
|
|
#define u_setenv(name,value) setenv (name, value, 1) |
54 |
|
|
#define u_mkdir(path) mkdir (path, 0777) |
55 |
|
|
#define u_chdir(path) chdir (path) |
56 |
|
|
#define u_rename(fr,to) rename (fr, to) |
57 |
|
|
#define u_open(path) open (path, O_RDONLY) + 1 |
58 |
|
|
#define u_creat(path,exec) open (path, O_WRONLY | O_CREAT | O_TRUNC, (exec) ? 0777 : 0666) + 1 |
59 |
|
|
#define u_close(handle) close (handle - 1) |
60 |
|
|
#define u_append(path,add) strcat (strcat (path, "/"), add) |
61 |
|
|
#define u_write(handle,data,len) write ((handle) - 1, data, len) |
62 |
root |
1.3 |
#define u_sync() sync () |
63 |
root |
1.1 |
|
64 |
|
|
#endif |
65 |
|
|
|
66 |
|
|
#define u_16(ptr) (((ptr)[0] << 8) | (ptr)[1]) |
67 |
|
|
#define u_32(ptr) (((ptr)[0] << 24) | ((ptr)[1] << 16) | ((ptr)[2] << 8) | (ptr)[3]) |
68 |
|
|
|
69 |
|
|
static u_handle pack_handle; |
70 |
|
|
static char tmppath[MAX_PATH]; |
71 |
|
|
static char currdir[MAX_PATH]; |
72 |
|
|
static char datadir[MAX_PATH]; // %AppData%/urlader |
73 |
|
|
static char exe_dir[MAX_PATH]; // %AppData%/urlader/EXE_ID |
74 |
|
|
static char execdir[MAX_PATH]; // %AppData%/urlader/EXE_ID/EXE_VER |
75 |
|
|
static char exe_id[MAX_PATH]; |
76 |
|
|
static char exe_ver[MAX_PATH]; |
77 |
|
|
|
78 |
|
|
static int exe_argc; |
79 |
|
|
static const char *exe_argv[32]; |
80 |
|
|
|
81 |
|
|
static void |
82 |
|
|
fatal (const char *msg) |
83 |
|
|
{ |
84 |
|
|
#ifdef _WIN32 |
85 |
|
|
MessageBox (0, msg, URLADER, 0); |
86 |
|
|
#else |
87 |
|
|
fprintf (stderr, "%s: %s\n", URLADER, msg); |
88 |
|
|
#endif |
89 |
|
|
|
90 |
|
|
_exit (1); |
91 |
|
|
} |
92 |
|
|
|
93 |
|
|
static void |
94 |
|
|
tmpdir (const char *dir) |
95 |
|
|
{ |
96 |
|
|
static int cnt; |
97 |
|
|
|
98 |
|
|
for (;;) |
99 |
|
|
{ |
100 |
|
|
// #ifdef _WIN32 |
101 |
|
|
// sprintf (tmppath, "%s/%x_%x.tmp", dir, (unsigned int)GetCurrentProcessId (), ++cnt); |
102 |
|
|
// #else |
103 |
|
|
sprintf (tmppath, "%s/t-%x_%x.tmp", dir, (unsigned int)getpid () , ++cnt); |
104 |
|
|
// #endif |
105 |
|
|
|
106 |
|
|
if (!u_mkdir (tmppath)) |
107 |
|
|
return; |
108 |
|
|
} |
109 |
|
|
} |
110 |
|
|
|
111 |
|
|
static void |
112 |
root |
1.2 |
systemv (const char *const argv[], int dowait) |
113 |
root |
1.1 |
{ |
114 |
|
|
#ifdef _WIN32 |
115 |
|
|
_spawnv (P_WAIT, argv [0], argv); |
116 |
|
|
#else |
117 |
root |
1.2 |
pid_t pid = dowait ? fork () : 0; |
118 |
root |
1.1 |
|
119 |
|
|
if (pid < 0) |
120 |
|
|
fatal ("fork failure"); |
121 |
|
|
|
122 |
|
|
if (!pid) |
123 |
|
|
{ |
124 |
|
|
execv (argv [0], (void *)argv); |
125 |
|
|
_exit (124); |
126 |
|
|
} |
127 |
|
|
|
128 |
|
|
int status; |
129 |
|
|
waitpid (pid, &status, 0); |
130 |
|
|
#endif |
131 |
|
|
} |
132 |
|
|
|
133 |
|
|
static void |
134 |
|
|
deltree (const char *path) |
135 |
|
|
{ |
136 |
|
|
#ifdef _WIN32 |
137 |
|
|
char buf[MAX_PATH * 2 + 64]; |
138 |
|
|
const char *argv[] = { getenv ("COMSPEC"), "/c", "rd", "/s", "/q", buf, 0 }; |
139 |
|
|
sprintf (buf, "\"%s\"", path); |
140 |
|
|
#else |
141 |
|
|
const char *argv[] = { "/bin/rm", "-rf", path, 0 }; |
142 |
|
|
#endif |
143 |
root |
1.2 |
systemv (argv, 1); |
144 |
root |
1.1 |
} |
145 |
|
|
|
146 |
|
|
enum |
147 |
|
|
{ |
148 |
|
|
T_NULL, // 5 |
149 |
|
|
T_META, // 1 : exe_id, exe_ver |
150 |
|
|
T_ARG, // 2 : arg |
151 |
|
|
T_ENV, // 3 : name, value |
152 |
|
|
T_DIR, // 4+: path |
153 |
|
|
T_FILE, // 4+: path, data |
154 |
|
|
T_NUM |
155 |
|
|
}; |
156 |
|
|
|
157 |
|
|
enum |
158 |
|
|
{ |
159 |
|
|
F_EXEC = 1, |
160 |
|
|
F_LZF = 2, |
161 |
|
|
F_NULL = 0 |
162 |
|
|
}; |
163 |
|
|
|
164 |
|
|
struct hdr |
165 |
|
|
{ |
166 |
|
|
unsigned char type; |
167 |
|
|
unsigned char flags; |
168 |
|
|
unsigned char namelen[2]; |
169 |
|
|
unsigned char datalen[4]; |
170 |
|
|
}; |
171 |
|
|
|
172 |
|
|
struct tail { |
173 |
|
|
unsigned char max_filesize[4]; |
174 |
|
|
unsigned char size[4]; |
175 |
|
|
char magic[12]; |
176 |
|
|
}; |
177 |
|
|
|
178 |
|
|
static char *pack_base, *pack_end; |
179 |
|
|
static struct hdr *pack_cur; |
180 |
root |
1.2 |
static char *scratch; |
181 |
|
|
static unsigned int scratch_len; |
182 |
root |
1.1 |
|
183 |
|
|
#define PACK_NAME ((char *)(pack_cur + 1)) |
184 |
|
|
#define PACK_DATA (PACK_NAME + u_16 (pack_cur->namelen) + 1) |
185 |
|
|
#define PACK_VALID pack_cur->type |
186 |
|
|
|
187 |
|
|
static void |
188 |
|
|
pack_next (void) |
189 |
|
|
{ |
190 |
|
|
unsigned int d = u_32 (pack_cur->datalen); |
191 |
|
|
|
192 |
|
|
pack_cur = (struct hdr *)(PACK_DATA + d); |
193 |
|
|
} |
194 |
|
|
|
195 |
|
|
static void |
196 |
|
|
pack_unmap (void) |
197 |
|
|
{ |
198 |
|
|
if (!pack_base) |
199 |
|
|
return; |
200 |
|
|
|
201 |
root |
1.2 |
free (scratch); |
202 |
|
|
|
203 |
root |
1.1 |
#ifdef _WIN32 |
204 |
|
|
UnmapViewOfFile (pack_base); |
205 |
|
|
#else |
206 |
|
|
munmap (pack_base, pack_end - pack_base); |
207 |
|
|
#endif |
208 |
|
|
} |
209 |
|
|
|
210 |
|
|
static int |
211 |
|
|
pack_map (void) |
212 |
|
|
{ |
213 |
|
|
#ifdef _WIN32 |
214 |
|
|
BY_HANDLE_FILE_INFORMATION fi; |
215 |
|
|
|
216 |
|
|
if (!GetFileInformationByHandle (pack_handle, &fi)) |
217 |
|
|
return 0; |
218 |
|
|
|
219 |
|
|
if (fi.nFileSizeHigh) // too big |
220 |
|
|
return 0; |
221 |
|
|
|
222 |
|
|
HANDLE handle = CreateFileMapping (pack_handle, 0, PAGE_READONLY, 0, fi.nFileSizeLow, NULL); |
223 |
|
|
|
224 |
|
|
if (!handle) |
225 |
|
|
return 0; |
226 |
|
|
|
227 |
|
|
pack_unmap (); |
228 |
|
|
|
229 |
|
|
pack_base = MapViewOfFile (handle, FILE_MAP_READ, 0, 0, fi.nFileSizeLow); |
230 |
|
|
|
231 |
|
|
CloseHandle (handle); |
232 |
|
|
|
233 |
|
|
pack_end = pack_base + fi.nFileSizeLow; |
234 |
|
|
#else |
235 |
|
|
off_t len = lseek (pack_handle - 1, 0, SEEK_END); |
236 |
|
|
|
237 |
|
|
pack_unmap (); |
238 |
|
|
|
239 |
|
|
pack_base = mmap (0, len, PROT_READ, MAP_SHARED, pack_handle - 1, 0); |
240 |
|
|
if (pack_base == (void *)-1) |
241 |
|
|
pack_base = 0; |
242 |
|
|
|
243 |
|
|
pack_end = pack_base + len; |
244 |
|
|
#endif |
245 |
|
|
|
246 |
|
|
if (!pack_base) |
247 |
|
|
return 0; |
248 |
|
|
|
249 |
|
|
struct tail *tail; |
250 |
|
|
|
251 |
|
|
tail = (void *)(pack_end - sizeof (*tail)); |
252 |
|
|
|
253 |
|
|
if (memcmp (tail->magic, TAIL_MAGIC, sizeof (TAIL_MAGIC) - 1)) |
254 |
|
|
return 0; |
255 |
|
|
|
256 |
|
|
pack_cur = (struct hdr *)(pack_end - u_32 (tail->size)); |
257 |
|
|
|
258 |
root |
1.2 |
free (scratch); |
259 |
|
|
scratch = malloc (scratch_len = u_32 (tail->max_filesize)); |
260 |
|
|
|
261 |
root |
1.1 |
return 1; |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
static void |
265 |
|
|
exe_info (void) |
266 |
|
|
{ |
267 |
|
|
if (!pack_map ()) |
268 |
|
|
fatal ("unable to locate packfile in executable - executable corrupted?"); |
269 |
|
|
|
270 |
|
|
if (pack_cur->type != T_META) |
271 |
|
|
fatal ("unable to locate executable metadata - executable corrupted?"); |
272 |
|
|
|
273 |
|
|
strcpy (exe_id, PACK_NAME); |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
static void |
277 |
|
|
load (void) |
278 |
|
|
{ |
279 |
|
|
u_mkdir (datadir); |
280 |
|
|
|
281 |
|
|
strcpy (exe_dir, datadir); |
282 |
|
|
u_append (exe_dir, exe_id); |
283 |
|
|
u_mkdir (exe_dir); |
284 |
|
|
|
285 |
|
|
if (u_chdir (exe_dir)) |
286 |
|
|
fatal ("unable to change to application data directory"); |
287 |
|
|
|
288 |
|
|
u_handle h = u_open ("override"); |
289 |
|
|
if (h) |
290 |
|
|
{ |
291 |
|
|
u_handle oh = pack_handle; |
292 |
|
|
|
293 |
|
|
pack_handle = h; |
294 |
|
|
if (!pack_map ()) |
295 |
|
|
{ |
296 |
|
|
pack_handle = oh; |
297 |
|
|
oh = h; |
298 |
|
|
} |
299 |
|
|
|
300 |
|
|
u_close (oh); |
301 |
|
|
} |
302 |
|
|
|
303 |
|
|
if (pack_cur->type != T_META) |
304 |
|
|
fatal ("unable to locate override metadata"); |
305 |
|
|
|
306 |
|
|
strcpy (exe_ver, PACK_DATA); |
307 |
|
|
pack_next (); |
308 |
|
|
|
309 |
|
|
while (pack_cur->type == T_ARG) |
310 |
|
|
{ |
311 |
|
|
exe_argv [exe_argc++] = strdup (PACK_NAME); |
312 |
|
|
pack_next (); |
313 |
|
|
} |
314 |
|
|
|
315 |
|
|
while (pack_cur->type == T_ENV) |
316 |
|
|
{ |
317 |
|
|
u_setenv (PACK_NAME, PACK_DATA); |
318 |
|
|
pack_next (); |
319 |
|
|
} |
320 |
|
|
|
321 |
|
|
strcpy (execdir, exe_dir); |
322 |
|
|
u_append (execdir, "i-"); |
323 |
|
|
strcat (execdir, exe_ver); |
324 |
|
|
|
325 |
|
|
if (access (execdir, F_OK)) |
326 |
|
|
{ |
327 |
|
|
// does not exist yet, so unpack and move |
328 |
|
|
tmpdir (exe_dir); |
329 |
|
|
|
330 |
|
|
if (u_chdir (tmppath)) |
331 |
|
|
fatal ("unable to change to new instance directory"); |
332 |
|
|
|
333 |
|
|
for (;;) |
334 |
|
|
{ |
335 |
|
|
switch (pack_cur->type) |
336 |
|
|
{ |
337 |
|
|
case T_DIR: |
338 |
|
|
u_mkdir (PACK_NAME); |
339 |
|
|
break; |
340 |
|
|
|
341 |
|
|
case T_FILE: |
342 |
|
|
{ |
343 |
|
|
u_handle h = u_creat (PACK_NAME, pack_cur->flags & F_EXEC); |
344 |
root |
1.2 |
unsigned int dlen, len = u_32 (pack_cur->datalen); |
345 |
|
|
char *data = PACK_DATA; |
346 |
|
|
|
347 |
|
|
if (pack_cur->flags & F_LZF) |
348 |
|
|
if (dlen = lzf_decompress (data, len, scratch, scratch_len)) |
349 |
|
|
{ |
350 |
|
|
data = scratch; |
351 |
|
|
len = dlen; |
352 |
|
|
} |
353 |
|
|
else |
354 |
|
|
fatal ("unable to uncompress file data - pack corrupted?"); |
355 |
root |
1.1 |
|
356 |
|
|
if (!h) |
357 |
|
|
fatal ("unable to unpack file from packfile - disk full?"); |
358 |
|
|
|
359 |
root |
1.2 |
if (u_write (h, data, len) != len) |
360 |
root |
1.1 |
fatal ("unable to unpack file from packfile - disk full?"); |
361 |
|
|
|
362 |
|
|
u_close (h); |
363 |
|
|
} |
364 |
|
|
break; |
365 |
|
|
|
366 |
|
|
case T_NULL: |
367 |
|
|
goto done; |
368 |
|
|
} |
369 |
|
|
|
370 |
|
|
pack_next (); |
371 |
|
|
} |
372 |
|
|
|
373 |
|
|
done: |
374 |
|
|
if (u_chdir (datadir)) |
375 |
|
|
fatal ("unable to change to data directory"); |
376 |
|
|
|
377 |
root |
1.3 |
u_sync (); |
378 |
|
|
|
379 |
root |
1.1 |
if (u_rename (tmppath, execdir)) |
380 |
|
|
deltree (tmppath); // if move fails, delete new, assume other process created it independently |
381 |
|
|
} |
382 |
|
|
|
383 |
|
|
pack_unmap (); |
384 |
|
|
u_close (pack_handle); |
385 |
|
|
|
386 |
root |
1.2 |
if (u_chdir (execdir)) |
387 |
|
|
fatal ("unable to change to application instance directory"); |
388 |
|
|
|
389 |
root |
1.1 |
u_setenv ("URLADER_VERSION", URLADER_VERSION); |
390 |
|
|
u_setenv ("URLADER_DATADIR", datadir); |
391 |
|
|
u_setenv ("URLADER_EXECDIR", execdir); |
392 |
|
|
u_setenv ("URLADER_EXE_ID" , exe_id); |
393 |
|
|
u_setenv ("URLADER_EXE_DIR", exe_dir); |
394 |
|
|
u_setenv ("URLADER_EXE_VER", exe_ver); |
395 |
|
|
|
396 |
|
|
// yes, this is overkill |
397 |
|
|
u_setenv ("SHLIB_PATH" , execdir); // hpux |
398 |
|
|
u_setenv ("LIBPATH" , execdir); // aix |
399 |
|
|
u_setenv ("LD_LIBRARY_PATH" , execdir); // most elf systems |
400 |
|
|
u_setenv ("LD_LIBRARY_PATH_32", execdir); // solaris |
401 |
|
|
u_setenv ("LD_LIBRARY_PATH_64", execdir); // solaris |
402 |
|
|
u_setenv ("LD_LIBRARYN32_PATH", execdir); // irix |
403 |
|
|
u_setenv ("LD_LIBRARY64_PATH" , execdir); // irix |
404 |
|
|
u_setenv ("DYLD_LIBRARY_PATH" , execdir); // os sucks from apple |
405 |
|
|
} |
406 |
|
|
|
407 |
root |
1.2 |
static void |
408 |
|
|
execute (void) |
409 |
|
|
{ |
410 |
|
|
exe_argv [exe_argc] = 0; |
411 |
|
|
systemv (exe_argv, 0); |
412 |
|
|
} |
413 |
|
|
|
414 |
root |
1.1 |
#ifdef _WIN32 |
415 |
|
|
|
416 |
|
|
int APIENTRY |
417 |
|
|
WinMain (HINSTANCE hI, HINSTANCE hP, LPSTR argv, int command_show) |
418 |
|
|
{ |
419 |
|
|
if (!GetModuleFileName (hI, tmppath, sizeof (tmppath))) |
420 |
|
|
fatal ("unable to find executable pack"); |
421 |
|
|
|
422 |
|
|
if (!(pack_handle = u_open (tmppath))) |
423 |
|
|
fatal ("unable to open executable pack"); |
424 |
|
|
|
425 |
|
|
exe_info (); |
426 |
|
|
|
427 |
|
|
if (!GetCurrentDirectory (sizeof (currdir), currdir)) |
428 |
|
|
strcpy (currdir, "."); |
429 |
|
|
|
430 |
|
|
if (SHGetFolderPath (0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, datadir) != S_OK) |
431 |
|
|
fatal ("unable to find application data directory"); |
432 |
|
|
|
433 |
|
|
u_mkdir (datadir); |
434 |
|
|
u_append (datadir, URLADER); |
435 |
|
|
|
436 |
|
|
load (); |
437 |
|
|
execute (); |
438 |
|
|
|
439 |
|
|
return 0; |
440 |
|
|
} |
441 |
|
|
|
442 |
|
|
#else |
443 |
|
|
|
444 |
|
|
int |
445 |
|
|
main (int argc, char *argv[]) |
446 |
|
|
{ |
447 |
|
|
char *home = getenv ("HOME"); |
448 |
|
|
|
449 |
|
|
// we assume fd 0 and 2 are "normal" |
450 |
|
|
|
451 |
|
|
if (!(pack_handle = u_open (argv [0]))) |
452 |
|
|
fatal ("unable to open executable pack"); |
453 |
|
|
|
454 |
|
|
exe_info (); |
455 |
|
|
|
456 |
|
|
if (!home) |
457 |
|
|
{ |
458 |
|
|
struct passwd *pw; |
459 |
|
|
|
460 |
|
|
if ((pw = getpwuid (getuid ()))) |
461 |
|
|
home = pw->pw_dir; |
462 |
|
|
else |
463 |
|
|
home = "/tmp"; |
464 |
|
|
} |
465 |
|
|
|
466 |
|
|
if (!getcwd (currdir, sizeof (currdir))) |
467 |
|
|
strcpy (currdir, "."); |
468 |
|
|
|
469 |
|
|
u_mkdir (home); |
470 |
|
|
sprintf (datadir, "%s/.%s", home, URLADER); |
471 |
|
|
u_mkdir (datadir); |
472 |
|
|
|
473 |
|
|
if (gethostname (tmppath, sizeof (tmppath))) |
474 |
|
|
strcpy (tmppath, "default"); |
475 |
|
|
|
476 |
|
|
u_append (datadir, tmppath); |
477 |
|
|
|
478 |
|
|
load (); |
479 |
|
|
execute (); |
480 |
|
|
|
481 |
|
|
return 0; |
482 |
|
|
} |
483 |
|
|
|
484 |
|
|
#endif |
485 |
|
|
|