#include "urlib.h" #include "urlib.c" #include #include #include #include #include #include #include "liblzf/lzf_d.c" /* some simple? dynamic memory management for paths might save ltos of ram */ static u_handle pack_handle; static u_handle lock_handle; static char tmppath[MAX_PATH]; static int exe_argc; static const char *exe_argv[MAX_ARGC]; static char exe_args[MAX_ARGS]; /* actual arguments strings copied here */ static unsigned int exe_argo; static void tmpdir (const char *dir) { static int cnt; for (;;) { // #ifdef _WIN32 // sprintf (tmppath, "%s/%x_%x.tmp", dir, (unsigned int)GetCurrentProcessId (), ++cnt); // #else sprintf (tmppath, "%s/t-%x_%x.tmp", dir, (unsigned int)getpid () , ++cnt); // #endif if (!u_mkdir (tmppath)) return; } } static void systemv (const char *const argv[]) { #ifdef _WIN32 _spawnv (P_WAIT, argv [0], argv); #else pid_t pid = fork (); if (pid < 0) u_fatal ("fork failure"); if (!pid) { execv (argv [0], (void *)argv); _exit (124); } int status; waitpid (pid, &status, 0); #endif } static void deltree (const char *path) { #ifdef _WIN32 char buf[MAX_PATH * 2 + 64]; const char *argv[] = { getenv ("COMSPEC"), "/c", "rd", "/s", "/q", buf, 0 }; sprintf (buf, "\"%s\"", path); #else const char *argv[] = { "/bin/rm", "-rf", path, 0 }; #endif systemv (argv); } static char *pack_base, *pack_end; static struct u_pack_hdr *pack_cur; static char *scratch; static unsigned int scratch_size; #define PACK_NAME ((char *)(pack_cur + 1)) #define PACK_DATA (PACK_NAME + u_16 (pack_cur->namelen) + 1) #define PACK_VALID pack_cur->type static void pack_next (void) { unsigned int d = u_32 (pack_cur->datalen); pack_cur = (struct u_pack_hdr *)(PACK_DATA + d); } static void pack_unmap (void) { if (pack_base) { u_munmap (pack_base, pack_end - pack_base); pack_base = 0; } if (scratch) { u_free (scratch, scratch_size); scratch = 0; } } static int pack_map (void) { char *addr; unsigned int size; #ifdef _WIN32 BY_HANDLE_FILE_INFORMATION fi; if (!GetFileInformationByHandle (pack_handle, &fi)) return 0; size = fi.nFileSizeLow; #else size = lseek (pack_handle, 0, SEEK_END); #endif addr = u_mmap (pack_handle, size); if (!addr) return 0; pack_unmap (); pack_base = addr; pack_end = pack_base + size; struct u_pack_tail *tail; tail = (void *)(pack_end - sizeof (*tail)); if (memcmp (tail->magic, TAIL_MAGIC, sizeof (TAIL_MAGIC) - 1)) return 0; pack_cur = (struct u_pack_hdr *)(pack_end - u_32 (tail->size)); scratch = u_malloc (scratch_size = u_32 (tail->max_filesize)); if (!scratch) return 0; return 1; } static void exe_info (void) { if (!pack_map ()) u_fatal ("unable to locate packfile in executable - executable corrupted?"); if (pack_cur->type != T_META) u_fatal ("unable to locate executable metadata - executable corrupted?"); strcpy (exe_id, PACK_NAME); } static void load (void) { if (u_chdir (exe_dir)) u_fatal ("unable to change to application data directory"); u_handle h = u_open ("override"); if (u_valid (h)) { u_handle oh = pack_handle; pack_handle = h; if (!pack_map ()) { pack_handle = oh; oh = h; } u_close (oh); } if (pack_cur->type != T_META) u_fatal ("unable to locate override metadata"); strcpy (exe_ver, PACK_DATA); u_set_exe_info (); pack_next (); for (;;) { if (pack_cur->type == T_ENV) u_setenv (PACK_NAME, PACK_DATA); else if (pack_cur->type == T_ARG) { int len = u_16 (pack_cur->namelen) + 1; exe_argv [exe_argc++] = exe_args + exe_argo; memcpy (exe_args + exe_argo, PACK_NAME, len); exe_argo += len; } else break; pack_next (); } done_env_arg: strcat (strcpy (tmppath, execdir), ".lck"); lock_handle = u_lock (tmppath, 0, 1); if (!lock_handle) u_fatal ("unable to lock application instance"); if (access (execdir, F_OK)) { // does not exist yet, so unpack and move tmpdir (exe_dir); if (u_chdir (tmppath)) u_fatal ("unable to change to new instance directory"); for (;;) { switch (pack_cur->type) { case T_DIR: u_mkdir (PACK_NAME); break; case T_FILE: { u_handle h = u_creat (PACK_NAME, pack_cur->flags & F_EXEC); unsigned int dlen, len = u_32 (pack_cur->datalen); char *data = PACK_DATA; if (pack_cur->flags & F_LZF) if (dlen = lzf_decompress (data, len, scratch, scratch_size)) { data = scratch; len = dlen; } else u_fatal ("unable to uncompress file data - pack corrupted?"); if (!u_valid (h)) u_fatal ("unable to unpack file from packfile - disk full?"); if (u_write (h, data, len) != len) u_fatal ("unable to unpack file from packfile - disk full?"); u_fsync (h); u_close (h); } break; case T_NULL: goto done; } pack_next (); } done: if (u_chdir (datadir)) u_fatal ("unable to change to data directory"); u_sync (); if (u_rename (tmppath, execdir)) deltree (tmppath); // if move fails, delete new, assume other process created it independently } pack_unmap (); u_close (pack_handle); if (u_chdir (execdir)) u_fatal ("unable to change to application instance directory"); u_setenv ("URLADER_VERSION", URLADER_VERSION); #if 0 // yes, this is overkill u_setenv ("SHLIB_PATH" , execdir); // hpux u_setenv ("LIBPATH" , execdir); // aix u_setenv ("LD_LIBRARY_PATH" , execdir); // most elf systems u_setenv ("LD_LIBRARY_PATH_32", execdir); // solaris u_setenv ("LD_LIBRARY_PATH_64", execdir); // solaris u_setenv ("LD_LIBRARYN32_PATH", execdir); // irix u_setenv ("LD_LIBRARY64_PATH" , execdir); // irix u_setenv ("DYLD_LIBRARY_PATH" , execdir); // os sucks from apple #endif } static void execute (void) { exe_argv [exe_argc] = 0; systemv (exe_argv); } static void doit (void) { u_set_datadir (); u_mkdir (datadir); exe_info (); u_set_exe_info (); load (); execute (); } #ifdef _WIN32 int APIENTRY WinMain (HINSTANCE hI, HINSTANCE hP, LPSTR argv, int command_show) { if (!GetModuleFileName (hI, tmppath, sizeof (tmppath))) u_fatal ("unable to find executable pack"); pack_handle = u_open (tmppath); if (!u_valid (pack_handle)) u_fatal ("unable to open executable pack"); if (!GetCurrentDirectory (sizeof (currdir), currdir)) strcpy (currdir, "."); return 0; } #else int main (int argc, char *argv[]) { pack_handle = u_open (argv [0]); if (!u_valid (pack_handle)) u_fatal ("unable to open executable pack"); if (!getcwd (currdir, sizeof (currdir))) strcpy (currdir, "."); #if 0 if (gethostname (tmppath, sizeof (tmppath))) strcpy (tmppath, "default"); u_append (datadir, tmppath); #endif doit (); return 0; } #endif