1 /**************************************************************************
3 Copyright (c) 2005-13 Simon Peter
4 Copyright (c) 2007 Alexander Larsson
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 **************************************************************************/
28 #include <sys/types.h>
40 /* ======================================================== Start helper functions for icon extraction */
42 Constructs the name of the thumbnail image for $HOME/.thumbnails for the executable that is itself
43 See http://people.freedesktop.org/~vuntz/thumbnail-spec-cache/
45 http://www.google.com/codesearch#n76pnUnMG18/trunk/blender/imbuf/intern/thumbs.c&q=.thumbnails/normal%20lang:c%20md5&type=cs
54 #define URI_MAX FILE_MAX*3 + 8
56 /* --- begin of adapted code from glib ---
57 * The following code is adapted from function g_escape_uri_string from the gnome glib
58 * Source: http://svn.gnome.org/viewcvs/glib/trunk/glib/gconvert.c?view=markup
59 * released under the Gnu General Public License.
60 * NOTE THIS DOESN'T WORK PROPERLY FOR öäüß - FIXME
64 UNSAFE_ALL
= 0x1, /* Escape all unsafe characters */
65 UNSAFE_ALLOW_PLUS
= 0x2, /* Allows '+' */
66 UNSAFE_PATH
= 0x8, /* Allows '/', '&', '=', ':', '@', '+', '$' and ',' */
67 UNSAFE_HOST
= 0x10, /* Allows '/' and ':' and '@' */
68 UNSAFE_SLASHES
= 0x20 /* Allows all characters except for '/' and '%' */
71 static const unsigned char acceptable
[96] = {
72 /* A table of the ASCII chars from space (32) to DEL (127) */
73 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
74 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
75 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
76 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
77 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
78 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20
81 static const char hex
[17] = "0123456789abcdef";
83 void escape_uri_string (const char *string
, char* escaped_string
, int len
,UnsafeCharacterSet mask
)
85 #define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask))
90 UnsafeCharacterSet use_mask
;
93 for (q
= escaped_string
, p
= string
; (*p
!= '\0') && len
; p
++) {
94 c
= (unsigned char) *p
;
97 if (!ACCEPTABLE (c
)) {
98 *q
++ = '%'; /* means hex coming */
109 void to_hex_char(char* hexbytes
, const unsigned char* bytes
, int len
)
111 const unsigned char *p
;
114 for (q
= hexbytes
, p
= bytes
; len
; p
++) {
115 const unsigned char c
= (unsigned char) *p
;
122 /* --- end of adapted code from glib --- */
124 static int uri_from_filename( const char *dir
, char *newuri
)
127 sprintf (uri
, "file://%s", dir
);
128 char newstring
[URI_MAX
];
129 strncpy(newstring
, uri
, URI_MAX
);
130 newstring
[URI_MAX
- 1] = 0;
132 escape_uri_string(newstring
, newuri
, FILE_MAX
*3+8, UNSAFE_PATH
);
137 static void thumbname_from_uri(const char* uri
, char* thumb
)
140 unsigned char digest
[16];
141 md5_buffer( uri
, strlen(uri
), digest
);
143 to_hex_char(hexdigest
, digest
, 16);
144 hexdigest
[32] = '\0';
145 sprintf(thumb
, "%s.png", hexdigest
);
149 /* ======================================================== End helper functions for icon extraction */
151 extern int ext2_main(int argc
, char *argv
[], void (*mounted
) (void));
152 extern void ext2_quit(void);
154 static pid_t fuse_pid
;
155 static int keepalive_pipe
[2];
158 write_pipe_thread (void *arg
)
162 // sprintf(stderr, "Called write_pipe_thread");
163 memset (c
, 'x', sizeof (c
));
165 /* Write until we block, on broken pipe, exit */
166 res
= write (keepalive_pipe
[1], c
, sizeof (c
));
168 kill (fuse_pid
, SIGHUP
);
176 run_when_fuse_fs_mounted (void)
179 // sprintf(stderr, "Called run_when_fuse_fs_mounted");
184 res
= pthread_create(&thread
, NULL
, write_pipe_thread
, keepalive_pipe
);
187 char* getArg(int argc
, char *argv
[],char chr
)
190 for (i
=1; i
<argc
; ++i
)
191 if ((argv
[i
][0]=='-') && (argv
[i
][1]==chr
))
192 return &(argv
[i
][2]);
198 main (int argc
, char *argv
[])
201 char mount_dir
[] = "/tmp/.mount_XXXXXX"; /* create mountpoint */
202 char filename
[100]; /* enough for mount_dir + "/AppRun" */
207 // We are using glib anyway for fuseiso, so we can use it here too to make our life easier
208 char *xdg_cache_home
;
209 char thumbnails_medium_dir
[FILE_MAX
];
210 xdg_cache_home
= (getenv("XDG_CACHE_HOME") == NULL
211 ? g_build_filename(g_get_home_dir(), ".cache", NULL
)
212 : g_strdup(getenv("XDG_CACHE_HOME")));
213 sprintf(thumbnails_medium_dir
, "%s/thumbnails/normal/", xdg_cache_home
);
214 /* printf("%s\n", thumbnails_medium_dir); */
216 if (mkdtemp(mount_dir
) == NULL
) {
220 if (pipe (keepalive_pipe
) == -1) {
221 perror ("pipe error: ");
227 perror ("fork error: ");
236 /* close read pipe */
237 close (keepalive_pipe
[0]);
240 char *dir
= realpath( "/proc/self/exe", NULL
);
243 child_argv
[1] = mount_dir
;
244 child_argv
[2] = "-o";
245 child_argv
[3] = "ro";
246 child_argv
[4] = NULL
;
248 ext2_main (4, child_argv
, NULL
);
250 /* in parent, child is $pid */
253 /* close write pipe */
254 close (keepalive_pipe
[1]);
256 /* Pause until mounted */
257 read (keepalive_pipe
[0], &c
, 1);
260 dir_fd
= open (mount_dir
, O_RDONLY
);
262 // perror ("open dir error: ");
263 printf("Could not mount AppImage\n");
264 printf("Please see https://github.com/probonopd/AppImageKit/wiki/FUSE\n");
268 res
= dup2 (dir_fd
, 1023);
270 perror ("dup2 error: ");
275 strcpy (filename
, mount_dir
);
276 strcat (filename
, "/AppRun");
278 real_argv
= malloc (sizeof (char *) * (argc
+ 1));
279 for (i
= 0; i
< argc
; i
++) {
280 real_argv
[i
] = argv
[i
];
286 /* ======================================================== Start icon extraction */
289 char fullpath
[FILE_MAX
];
290 length
= readlink("/proc/self/exe", fullpath
, sizeof(fullpath
));
291 fullpath
[length
] = '\0';
292 /* printf("%s\n", fullpath); */
293 char theuri
[URI_MAX
];
294 uri_from_filename(fullpath
, theuri
);
295 /* printf("%s\n", theuri); */
296 char path_to_thumbnail
[URI_MAX
];
297 char thumbname
[URI_MAX
];
298 thumbname_from_uri(theuri
, thumbname
);
299 sprintf(path_to_thumbnail
, "%s%s", thumbnails_medium_dir
, thumbname
);
304 char diricon
[FILE_MAX
];
305 sprintf (diricon
, "%s/.DirIcon", mount_dir
);
307 /* open source file */
308 if((from
= fopen(diricon
, "rb"))==NULL
) {
309 printf("Cannot open %s\n", diricon
);
313 /* open destination file */
314 char mkcmd
[FILE_MAX
];
315 char iconsdir
[FILE_MAX
];
317 sprintf(mkcmd
, "mkdir -p '%s'", thumbnails_medium_dir
);
319 if((to
= fopen(path_to_thumbnail
, "wb"))==NULL
) {
320 printf("Cannot open %s for writing\n", path_to_thumbnail
);
328 printf("Error reading source file\n");
331 if(!feof(from
)) fputc(ch
, to
);
333 printf("Error writing destination file\n");
338 if(fclose(from
)==EOF
) {
339 printf("Error closing source file\n");
343 if(fclose(to
)==EOF
) {
344 printf("Error closing destination file\n");
349 /* If called with --icon, then do not run the main app, just print print a message and exit after extracting the icon */
351 arg
=getArg(argc
,argv
,'-');
352 if (arg
&& strcmp(arg
,"icon")==0) {
353 printf("Written %s\n", path_to_thumbnail
);
357 /* ======================================================== End icon extraction */
359 /* Setting some environment variables that the app "inside" might use */
360 setenv( "APPIMAGE", fullpath
, 0 );
361 setenv( "APPDIR", mount_dir
, 0 );
362 execv (filename
, real_argv
);
363 /* Error if we continue here */
364 perror ("execv error: ");