#include "urlib.c" #include #include #include #include #include #include #include "liblzf/lzf_d.c" #include "urlib.h" /* 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 char currdir[MAX_PATH]; static char datadir[MAX_PATH]; // %AppData%/urlader static char exe_dir[MAX_PATH]; // %AppData%/urlader/EXE_ID static char execdir[MAX_PATH]; // %AppData%/urlader/EXE_ID/EXE_VER static char exe_id[MAX_PATH]; static char exe_ver[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 fatal (const char *msg) { #ifdef _WIN32 MessageBox (0, msg, URLADER, 0); #else write (2, URLADER ": ", sizeof (URLADER ": ") - 1); write (2, msg, strlen (msg)); write (2, "\n", 1); #endif _exit (1); } 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) 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 ()) fatal ("unable to locate packfile in executable - executable corrupted?"); if (pack_cur->type != U_T_META) fatal ("unable to locate executable metadata - executable corrupted?"); strcpy (exe_id, PACK_NAME); } static void load (void) { u_mkdir (datadir); strcpy (exe_dir, datadir); u_append (exe_dir, exe_id); u_mkdir (exe_dir); if (u_chdir (exe_dir)) 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 != U_T_META) fatal ("unable to locate override metadata"); strcpy (exe_ver, PACK_DATA); pack_next (); for (;;) { if (pack_cur->type == U_T_ENV) u_setenv (PACK_NAME, PACK_DATA); else if (pack_cur->type == U_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: strcpy (execdir, exe_dir); u_append (execdir, "i-"); strcat (execdir, exe_ver); strcat (strcpy (tmppath, execdir), ".lck"); lock_handle = u_lock (tmppath, 0, 1); if (!lock_handle) 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)) fatal ("unable to change to new instance directory"); for (;;) { switch (pack_cur->type) { case U_T_DIR: u_mkdir (PACK_NAME); break; case U_T_FILE: { u_handle h = u_creat (PACK_NAME, pack_cur->flags & U_F_EXEC); unsigned int dlen, len = u_32 (pack_cur->datalen); char *data = PACK_DATA; if (pack_cur->flags & U_F_LZF) if (dlen = lzf_decompress (data, len, scratch, scratch_size)) { data = scratch; len = dlen; } else fatal ("unable to uncompress file data - pack corrupted?"); if (!u_valid (h)) fatal ("unable to unpack file from packfile - disk full?"); if (u_write (h, data, len) != len) fatal ("unable to unpack file from packfile - disk full?"); u_fsync (h); u_close (h); } break; case U_T_NULL: goto done; } pack_next (); } done: if (u_chdir (datadir)) 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)) fatal ("unable to change to application instance directory"); u_setenv ("URLADER_VERSION", URLADER_VERSION); u_setenv ("URLADER_DATADIR", datadir); u_setenv ("URLADER_EXECDIR", execdir); u_setenv ("URLADER_EXE_ID" , exe_id); u_setenv ("URLADER_EXE_DIR", exe_dir); u_setenv ("URLADER_EXE_VER", exe_ver); #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); } #ifdef _WIN32 int APIENTRY WinMain (HINSTANCE hI, HINSTANCE hP, LPSTR argv, int command_show) { if (!GetModuleFileName (hI, tmppath, sizeof (tmppath))) fatal ("unable to find executable pack"); pack_handle = u_open (tmppath); if (!u_valid (pack_handle)) fatal ("unable to open executable pack"); exe_info (); if (!GetCurrentDirectory (sizeof (currdir), currdir)) strcpy (currdir, "."); if (SHGetFolderPath (0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, datadir) != S_OK) fatal ("unable to find application data directory"); u_mkdir (datadir); u_append (datadir, URLADER); load (); execute (); return 0; } #else int main (int argc, char *argv[]) { char *home = getenv ("HOME"); pack_handle = u_open (argv [0]); if (!u_valid (pack_handle)) fatal ("unable to open executable pack"); exe_info (); if (!home) { struct passwd *pw; if ((pw = getpwuid (getuid ()))) home = pw->pw_dir; else home = "/tmp"; } if (!getcwd (currdir, sizeof (currdir))) strcpy (currdir, "."); u_mkdir (home); //strcat (strcat (strcpy (datadir, home), "/."), URLADER); sprintf (datadir, "%s/.%s", home, URLADER); u_mkdir (datadir); #if 0 if (gethostname (tmppath, sizeof (tmppath))) strcpy (tmppath, "default"); u_append (datadir, tmppath); #endif load (); execute (); return 0; } #endif