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 }