File indexing completed on 2024-12-22 05:26:49
0001 /* 0002 SPDX-FileCopyrightText: 2004-16 Simon Peter 0003 SPDX-FileCopyrightText: 2007 Alexander Larsson 0004 0005 All Rights Reserved. 0006 0007 SPDX-License-Identifier: MIT 0008 */ 0009 0010 #include <sys/types.h> 0011 #include <sys/stat.h> 0012 #include <fcntl.h> 0013 #include <stdio.h> 0014 #include <stdlib.h> 0015 #include <signal.h> 0016 #include <string.h> 0017 #include <unistd.h> 0018 #include <pthread.h> 0019 #include <errno.h> 0020 0021 0022 /* ======================================================== Start helper functions for icon extraction */ 0023 /* 0024 Constructs the name of the thumbnail image for $HOME/.thumbnails for the executable that is itself 0025 See http://people.freedesktop.org/~vuntz/thumbnail-spec-cache/ 0026 Partly borrowed from 0027 http://www.google.com/codesearch#n76pnUnMG18/trunk/blender/imbuf/intern/thumbs.c&q=.thumbnails/normal%20lang:c%20md5&type=cs 0028 */ 0029 0030 #include "md5.h" 0031 #include "md5.c" 0032 #include <ctype.h> 0033 #include <time.h> 0034 0035 #define FILE_MAX 240 0036 #define URI_MAX FILE_MAX*3 + 8 0037 0038 /* --- begin of adapted code from glib --- 0039 * The following code is adapted from function g_escape_uri_string from the gnome glib 0040 * Source: http://svn.gnome.org/viewcvs/glib/trunk/glib/gconvert.c?view=markup 0041 * released under the Gnu General Public License. 0042 * NOTE THIS DOESN'T WORK PROPERLY FOR öäüß - FIXME 0043 */ 0044 0045 typedef enum { 0046 UNSAFE_ALL = 0x1, /* Escape all unsafe characters */ 0047 UNSAFE_ALLOW_PLUS = 0x2, /* Allows '+' */ 0048 UNSAFE_PATH = 0x8, /* Allows '/', '&', '=', ':', '@', '+', '$' and ',' */ 0049 UNSAFE_HOST = 0x10, /* Allows '/' and ':' and '@' */ 0050 UNSAFE_SLASHES = 0x20 /* Allows all characters except for '/' and '%' */ 0051 } UnsafeCharacterSet; 0052 0053 static const unsigned char acceptable[96] = { 0054 /* A table of the ASCII chars from space (32) to DEL (127) */ 0055 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C, 0056 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20, 0057 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, 0058 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F, 0059 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, 0060 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20 0061 }; 0062 0063 static const char hex[17] = "0123456789abcdef"; 0064 0065 void escape_uri_string (const char *string, char* escaped_string, int len,UnsafeCharacterSet mask) 0066 { 0067 #define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask)) 0068 0069 const char *p; 0070 char *q; 0071 int c; 0072 UnsafeCharacterSet use_mask; 0073 use_mask = mask; 0074 0075 for (q = escaped_string, p = string; (*p != '\0') && len; p++) { 0076 c = (unsigned char) *p; 0077 len--; 0078 0079 if (!ACCEPTABLE (c)) { 0080 *q++ = '%'; /* means hex coming */ 0081 *q++ = hex[c >> 4]; 0082 *q++ = hex[c & 15]; 0083 } else { 0084 *q++ = *p; 0085 } 0086 } 0087 0088 *q = '\0'; 0089 } 0090 0091 void to_hex_char(char* hexbytes, const unsigned char* bytes, int len) 0092 { 0093 const unsigned char *p; 0094 char *q; 0095 0096 for (q = hexbytes, p = bytes; len; p++) { 0097 const unsigned char c = (unsigned char) *p; 0098 len--; 0099 *q++ = hex[c >> 4]; 0100 *q++ = hex[c & 15]; 0101 } 0102 } 0103 0104 /* --- end of adapted code from glib --- */ 0105 0106 static int uri_from_filename( const char *dir, char *newuri ) 0107 { 0108 char uri[URI_MAX]; 0109 sprintf (uri, "file://%s", dir); 0110 char newstring[URI_MAX]; 0111 strncpy(newstring, uri, URI_MAX); 0112 newstring[URI_MAX - 1] = 0; 0113 unsigned int i = 0; 0114 escape_uri_string(newstring, newuri, FILE_MAX*3+8, UNSAFE_PATH); 0115 return 1; 0116 } 0117 0118 0119 static void thumbname_from_uri(const char* uri, char* thumb) 0120 { 0121 char hexdigest[33]; 0122 unsigned char digest[16]; 0123 md5_buffer( uri, strlen(uri), digest); 0124 hexdigest[0] = '\0'; 0125 to_hex_char(hexdigest, digest, 16); 0126 hexdigest[32] = '\0'; 0127 sprintf(thumb, "%s.png", hexdigest); 0128 0129 } 0130 0131 /* ======================================================== End helper functions for icon extraction */ 0132 0133 extern int ext2_main(int argc, char *argv[], void (*mounted) (void)); 0134 extern void ext2_quit(void); 0135 0136 static pid_t fuse_pid; 0137 static int keepalive_pipe[2]; 0138 0139 static void * 0140 write_pipe_thread (void *arg) 0141 { 0142 char c[32]; 0143 int res; 0144 // sprintf(stderr, "Called write_pipe_thread"); 0145 memset (c, 'x', sizeof (c)); 0146 while (1) { 0147 /* Write until we block, on broken pipe, exit */ 0148 res = write (keepalive_pipe[1], c, sizeof (c)); 0149 if (res == -1) { 0150 kill (fuse_pid, SIGHUP); 0151 break; 0152 } 0153 } 0154 return NULL; 0155 } 0156 0157 void 0158 run_when_fuse_fs_mounted (void) 0159 { 0160 0161 // sprintf(stderr, "Called run_when_fuse_fs_mounted"); 0162 pthread_t thread; 0163 int res; 0164 0165 fuse_pid = getpid(); 0166 res = pthread_create(&thread, NULL, write_pipe_thread, keepalive_pipe); 0167 } 0168 0169 char* getArg(int argc, char *argv[],char chr) 0170 { 0171 int i; 0172 for (i=1; i<argc; ++i) 0173 if ((argv[i][0]=='-') && (argv[i][1]==chr)) 0174 return &(argv[i][2]); 0175 return NULL; 0176 } 0177 0178 0179 int 0180 main (int argc, char *argv[]) 0181 { 0182 int dir_fd, res; 0183 char mount_dir[] = "/tmp/.mount_XXXXXX"; /* create mountpoint */ 0184 char filename[100]; /* enough for mount_dir + "/AppRun" */ 0185 pid_t pid; 0186 char **real_argv; 0187 int i; 0188 0189 // We are using glib anyway for fuseiso, so we can use it here too to make our life easier 0190 char *xdg_cache_home; 0191 char thumbnails_medium_dir[FILE_MAX]; 0192 xdg_cache_home = (getenv("XDG_CACHE_HOME") == NULL 0193 ? g_build_filename(g_get_home_dir(), ".cache", NULL) 0194 : g_strdup(getenv("XDG_CACHE_HOME"))); 0195 sprintf(thumbnails_medium_dir, "%s/thumbnails/normal/", xdg_cache_home); 0196 /* printf("%s\n", thumbnails_medium_dir); */ 0197 0198 if (mkdtemp(mount_dir) == NULL) { 0199 exit (1); 0200 } 0201 0202 if (pipe (keepalive_pipe) == -1) { 0203 perror ("pipe error: "); 0204 exit (1); 0205 } 0206 0207 pid = fork (); 0208 if (pid == -1) { 0209 perror ("fork error: "); 0210 exit (1); 0211 } 0212 0213 if (pid == 0) { 0214 /* in child */ 0215 0216 char *child_argv[5]; 0217 0218 /* close read pipe */ 0219 close (keepalive_pipe[0]); 0220 0221 0222 char *dir = realpath( "/proc/self/exe", NULL ); 0223 0224 child_argv[0] = dir; 0225 child_argv[1] = mount_dir; 0226 child_argv[2] = "-o"; 0227 child_argv[3] = "ro"; 0228 child_argv[4] = NULL; 0229 0230 ext2_main (4, child_argv, NULL); 0231 } else { 0232 /* in parent, child is $pid */ 0233 int c; 0234 0235 /* close write pipe */ 0236 close (keepalive_pipe[1]); 0237 0238 /* Pause until mounted */ 0239 read (keepalive_pipe[0], &c, 1); 0240 0241 0242 dir_fd = open (mount_dir, O_RDONLY); 0243 if (dir_fd == -1) { 0244 // perror ("open dir error: "); 0245 printf("Could not mount AppImage\n"); 0246 printf("Please see https://github.com/probonopd/AppImageKit/wiki/FUSE\n"); 0247 exit (1); 0248 } 0249 0250 res = dup2 (dir_fd, 1023); 0251 if (res == -1) { 0252 perror ("dup2 error: "); 0253 exit (1); 0254 } 0255 close (dir_fd); 0256 0257 strcpy (filename, mount_dir); 0258 strcat (filename, "/AppRun"); 0259 0260 real_argv = malloc (sizeof (char *) * (argc + 1)); 0261 for (i = 0; i < argc; i++) { 0262 real_argv[i] = argv[i]; 0263 } 0264 real_argv[i] = NULL; 0265 0266 0267 0268 /* ======================================================== Start icon extraction */ 0269 0270 int length; 0271 char fullpath[FILE_MAX]; 0272 length = readlink("/proc/self/exe", fullpath, sizeof(fullpath)); 0273 fullpath[length] = '\0'; 0274 /* printf("%s\n", fullpath); */ 0275 char theuri[URI_MAX]; 0276 uri_from_filename(fullpath, theuri); 0277 /* printf("%s\n", theuri); */ 0278 char path_to_thumbnail[URI_MAX]; 0279 char thumbname[URI_MAX]; 0280 thumbname_from_uri(theuri, thumbname); 0281 sprintf(path_to_thumbnail, "%s%s", thumbnails_medium_dir, thumbname); 0282 0283 FILE *from, *to; 0284 char ch; 0285 0286 char diricon[FILE_MAX]; 0287 sprintf (diricon, "%s/.DirIcon", mount_dir); 0288 0289 /* open source file */ 0290 if((from = fopen(diricon, "rb"))==NULL) { 0291 printf("Cannot open %s\n", diricon); 0292 exit(1); 0293 } 0294 0295 /* open destination file */ 0296 char mkcmd[FILE_MAX]; 0297 char iconsdir[FILE_MAX]; 0298 0299 sprintf(mkcmd, "mkdir -p '%s'", thumbnails_medium_dir); 0300 system(mkcmd); 0301 if((to = fopen(path_to_thumbnail, "wb"))==NULL) { 0302 printf("Cannot open %s for writing\n", path_to_thumbnail); 0303 0304 } else { 0305 0306 /* copy the file */ 0307 while(!feof(from)) { 0308 ch = fgetc(from); 0309 if(ferror(from)) { 0310 printf("Error reading source file\n"); 0311 exit(1); 0312 } 0313 if(!feof(from)) fputc(ch, to); 0314 if(ferror(to)) { 0315 printf("Error writing destination file\n"); 0316 exit(1); 0317 } 0318 } 0319 0320 if(fclose(from)==EOF) { 0321 printf("Error closing source file\n"); 0322 exit(1); 0323 } 0324 0325 if(fclose(to)==EOF) { 0326 printf("Error closing destination file\n"); 0327 exit(1); 0328 } 0329 } 0330 0331 /* If called with --icon, then do not run the main app, just print print a message and exit after extracting the icon */ 0332 char * arg; 0333 arg=getArg(argc,argv,'-'); 0334 if (arg && strcmp(arg,"icon")==0) { 0335 printf("Written %s\n", path_to_thumbnail); 0336 exit(0); 0337 } 0338 0339 /* ======================================================== End icon extraction */ 0340 0341 /* Setting some environment variables that the app "inside" might use */ 0342 setenv( "APPIMAGE", fullpath, 1 ); 0343 setenv( "APPDIR", mount_dir, 1 ); 0344 0345 /* Original working directory */ 0346 char cwd[1024]; 0347 if (getcwd(cwd, sizeof(cwd)) != NULL) { 0348 setenv( "OWD", cwd, 1 ); 0349 } 0350 0351 execv (filename, real_argv); 0352 /* Error if we continue here */ 0353 perror ("execv error: "); 0354 exit (1); 0355 } 0356 0357 return 0; 0358 }