1 /******************************* LICENCE **************************************
2 * Any code in this file may be redistributed or modified under the terms of
3 * the GNU General Public Licence as published by the Free Software
4 * Foundation; version 2 of the licence.
5 ****************************** END LICENCE ***********************************/
6 
7 /******************************************************************************
8 * Author:
9 * Andrew Smith, http://littlesvr.ca/misc/contactandrew.php
10 *
11 * Contributors:
12 *
13 ******************************************************************************/
14 
15 #include <gtk/gtk.h>
16 #include <gdk/gdkkeysyms.h>
17 #include <libintl.h>
18 #include <errno.h>
19 #include <signal.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 
23 #include "isomaster.h"
24 #include "bk/bkIoWrappers.h"
25 
26 #include <sys/wait.h>
27 
28 #define MAX_RANDOM_BASE_NAME_LEN 26
29 #define RANDOM_STR_NAME_LEN 6
30 
31 /* milliseconds */
32 #define TIMEOUT_TIME 50
33 
34 /* files that I created in the temp dir for editing */
35 TempFileCreated* GBLtempFilesList = NULL;
36 
37 extern GtkWidget* GBLfsTreeView;
38 extern char* GBLfsCurrentDir;
39 extern bool GBLisoPaneActive;
40 extern GtkWidget* GBLisoTreeView;
41 extern char* GBLisoCurrentDir;
42 extern VolInfo GBLvolInfo;
43 extern GtkWidget* GBLmainWindow;
44 extern bool GBLisoChangesProbable;
45 extern AppSettings GBLappSettings;
46 
47 static bool GBLeditFailed;
48 static bool GBLviewFailed;
49 
50 /******************************************************************************
51 * addToTempFilesList()
52 * Appends a node to the front of the list.
53 * */
addToTempFilesList(const char * pathAndName)54 void addToTempFilesList(const char* pathAndName)
55 {
56     TempFileCreated* newNode;
57 
58     newNode = malloc(sizeof(TempFileCreated));
59     if(newNode == NULL)
60         fatalError("newNode = malloc(sizeof(TempFileCreated)) failed\n");
61 
62     newNode->pathAndName = malloc(strlen(pathAndName) + 1);
63     if(newNode == NULL)
64         fatalError("newNode.pathAndName = malloc(strlen(pathAndName) + 1) failed\n");
65 
66     strcpy(newNode->pathAndName, pathAndName);
67 
68     newNode->next = GBLtempFilesList;
69 
70     GBLtempFilesList = newNode;
71 }
72 
checkEditFailed(gpointer data)73 gboolean checkEditFailed(gpointer data)
74 {
75     if(GBLeditFailed)
76     {
77         GtkWidget* warningDialog;
78         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
79                                                GTK_DIALOG_DESTROY_WITH_PARENT,
80                                                GTK_MESSAGE_ERROR,
81                                                GTK_BUTTONS_CLOSE,
82                                                _("Edit failed, please check Options/Editor"));
83         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
84         gtk_dialog_run(GTK_DIALOG(warningDialog));
85         gtk_widget_destroy(warningDialog);
86 
87         return FALSE;
88     }
89     else
90         return TRUE;
91 }
92 
checkViewFailed(gpointer data)93 gboolean checkViewFailed(gpointer data)
94 {
95     if(GBLviewFailed)
96     {
97         GtkWidget* warningDialog;
98         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
99                                                GTK_DIALOG_DESTROY_WITH_PARENT,
100                                                GTK_MESSAGE_ERROR,
101                                                GTK_BUTTONS_CLOSE,
102                                                _("View failed, please check Options/Viewer"));
103         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
104         gtk_dialog_run(GTK_DIALOG(warningDialog));
105         gtk_widget_destroy(warningDialog);
106 
107         return FALSE;
108     }
109     else
110         return TRUE;
111 }
112 
copyFsToFs(const char * src,const char * dest)113 bool copyFsToFs(const char* src, const char* dest)
114 {
115     BkStatStruct statStruct;
116     int srcFile;
117     int destFile;
118     int rc;
119     const int blockSize = 102400;
120     int count;
121     int numBlocks;
122     int sizeLastBlock;
123     char buffer[blockSize];
124 
125     rc = bkStat(src, &statStruct);
126     if(rc != 0)
127         return false;
128 
129     srcFile = open(src, O_RDONLY);
130     if(srcFile <= 0)
131         return false;
132 
133     destFile = open(dest, O_WRONLY | O_CREAT | O_EXCL, 0600);
134     if(destFile <= 0)
135     {
136         bkClose(srcFile);
137         return false;
138     }
139 
140     numBlocks = statStruct.st_size / blockSize;
141     sizeLastBlock = statStruct.st_size % blockSize;
142 
143     for(count = 0; count < numBlocks; count++)
144     {
145         rc = bkRead(srcFile, buffer, blockSize);
146         if(rc != blockSize)
147         {
148             bkClose(srcFile);
149             bkClose(destFile);
150             return false;
151         }
152 
153         rc = bkWrite(destFile, buffer, blockSize);
154         if(rc != blockSize)
155         {
156             bkClose(srcFile);
157             bkClose(destFile);
158             return false;
159         }
160     }
161 
162     if(sizeLastBlock > 0)
163     {
164         rc = bkRead(srcFile, buffer, sizeLastBlock);
165         if(rc != sizeLastBlock)
166         {
167             bkClose(srcFile);
168             bkClose(destFile);
169             return false;
170         }
171         rc = bkWrite(destFile, buffer, sizeLastBlock);
172         if(rc != sizeLastBlock)
173         {
174             bkClose(srcFile);
175             bkClose(destFile);
176             return false;
177         }
178     }
179 
180     bkClose(srcFile);
181     bkClose(destFile);
182 
183     return true;
184 }
185 
deleteTempFiles(void)186 void deleteTempFiles(void)
187 {
188     TempFileCreated* next;
189 
190     while(GBLtempFilesList != NULL)
191     {
192         next = GBLtempFilesList->next;
193 
194         unlink(GBLtempFilesList->pathAndName);
195 
196         free(GBLtempFilesList->pathAndName);
197         free(GBLtempFilesList);
198 
199         GBLtempFilesList = next;
200     }
201 }
202 
editSelectedBtnCbk(GtkMenuItem * menuitem,gpointer data)203 void editSelectedBtnCbk(GtkMenuItem *menuitem, gpointer data)
204 {
205     GtkTreeSelection* selection;
206     static guint timeoutTag = 0;
207 
208     gboolean fsViewHasFocus;
209     gboolean isoViewHasFocus;
210 
211     g_object_get(GBLfsTreeView, "is-focus", &fsViewHasFocus, NULL);
212     g_object_get(GBLisoTreeView, "is-focus", &isoViewHasFocus, NULL);
213 
214     if(fsViewHasFocus)
215     {
216         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLfsTreeView));
217 
218         /* kill the previous timeout function (if any) */
219         if(timeoutTag != 0)
220             g_source_remove(timeoutTag);
221 
222         GBLeditFailed = false;
223 
224         /* a timeout that will keep checking whether GBLviewFailed */
225         timeoutTag = g_timeout_add(TIMEOUT_TIME, checkViewFailed, NULL);
226 
227         gtk_tree_selection_selected_foreach(selection, editSelectedFsRowCbk, NULL);
228     }
229     else if(isoViewHasFocus)
230     {
231         /* do nothing if no image open */
232         if(!GBLisoPaneActive)
233             return;
234 
235         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
236 
237         /* kill the previous timeout function (if any) */
238         if(timeoutTag != 0)
239             g_source_remove(timeoutTag);
240 
241         GBLeditFailed = false;
242 
243         /* a timeout that will keep checking whether GBLeditFailed */
244         timeoutTag = g_timeout_add(TIMEOUT_TIME, checkEditFailed, NULL);
245 
246         gtk_tree_selection_selected_foreach(selection, editSelectedIsoRowCbk, NULL);
247 
248         /* can't put this in the callback because gtk complains */
249         //refreshIsoView();
250     }
251 }
252 
editSelectedFsRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)253 void editSelectedFsRowCbk(GtkTreeModel* model, GtkTreePath* path,
254                           GtkTreeIter* iterator, gpointer data)
255 {
256     int fileType;
257     char* itemName;
258     char* randomizedItemName;
259     char* pathAndNameOnFs;
260     char* pathAndNameInTempDir;
261     GtkWidget* warningDialog;
262     bool copiedOk;
263 
264     gtk_tree_model_get(model, iterator, COLUMN_HIDDEN_TYPE, &fileType,
265                                         COLUMN_FILENAME, &itemName, -1);
266     if(fileType != FILE_TYPE_REGULAR)
267     {
268         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
269                                                GTK_DIALOG_DESTROY_WITH_PARENT,
270                                                GTK_MESSAGE_ERROR,
271                                                GTK_BUTTONS_CLOSE,
272                                                _("'%s' is not a regular file"),
273                                                itemName);
274         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
275         gtk_dialog_run(GTK_DIALOG(warningDialog));
276         gtk_widget_destroy(warningDialog);
277 
278         g_free(itemName);
279         return;
280     }
281 
282     /* create full path and name for the file on the fs */
283     pathAndNameOnFs = malloc(strlen(GBLfsCurrentDir) + strlen(itemName) + 1);
284     if(pathAndNameOnFs == NULL)
285         fatalError("malloc(strlen(GBLfsCurrentDir) + strlen(itemName) + 1) failed");
286     strcpy(pathAndNameOnFs, GBLfsCurrentDir);
287     strcat(pathAndNameOnFs, itemName);
288 
289     /* create full path and name for the extracted file */
290     randomizedItemName = makeRandomFilename(itemName);
291     pathAndNameInTempDir = malloc(strlen(GBLappSettings.tempDir) +
292                                   strlen(randomizedItemName) + 2);
293     if(pathAndNameInTempDir == NULL)
294         fatalError("malloc(strlen(GBLappSettings.tempDir) + "
295                    "strlen(randomizedItemName) + 2) failed");
296     strcpy(pathAndNameInTempDir, GBLappSettings.tempDir);
297 
298     strcat(pathAndNameInTempDir, "/"); /* doesn't hurt even if not needed */
299 
300     strcat(pathAndNameInTempDir, randomizedItemName);
301 
302     /* disable warnings, so user isn't confused with 'continue' buttons */
303     bool(*savedWarningCbk)(const char*) = GBLvolInfo.warningCbk;
304     GBLvolInfo.warningCbk = NULL;
305 
306     /* copy the file to the temporary directory */
307     copiedOk = copyFsToFs(pathAndNameOnFs, pathAndNameInTempDir);
308     if(!copiedOk)
309     {
310         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
311                                                GTK_DIALOG_DESTROY_WITH_PARENT,
312                                                GTK_MESSAGE_ERROR,
313                                                GTK_BUTTONS_CLOSE,
314                                                "Failed to copy '%s' to '%s'",
315                                                pathAndNameOnFs,
316                                                pathAndNameInTempDir);
317         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
318         gtk_dialog_run(GTK_DIALOG(warningDialog));
319         gtk_widget_destroy(warningDialog);
320 
321         g_free(itemName);
322         free(randomizedItemName);
323         free(pathAndNameOnFs);
324         free(pathAndNameInTempDir);
325         GBLvolInfo.warningCbk = savedWarningCbk;
326         return;
327     }
328 
329     addToTempFilesList(pathAndNameInTempDir);
330 
331     /* start the viewer */
332     if(!fork())
333     {
334         execlp(GBLappSettings.editor, "editor", pathAndNameInTempDir, NULL);
335 
336         kill(getppid(), SIGUSR2);
337 
338         exit(1);
339     }
340 
341     g_free(itemName);
342     free(randomizedItemName);
343     free(pathAndNameOnFs);
344     free(pathAndNameInTempDir);
345     GBLvolInfo.warningCbk = savedWarningCbk;
346 }
347 
editSelectedIsoRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)348 void editSelectedIsoRowCbk(GtkTreeModel* model, GtkTreePath* path,
349                            GtkTreeIter* iterator, gpointer data)
350 {
351     int fileType;
352     char* itemName;
353     char* randomizedItemName;
354     char* pathAndNameOnFs; /* to extract to and add from */
355     char* pathAndNameOnIso; /* to delete from iso */
356     int rc;
357     GtkWidget* warningDialog;
358 
359     gtk_tree_model_get(model, iterator, COLUMN_HIDDEN_TYPE, &fileType,
360                                         COLUMN_FILENAME, &itemName, -1);
361 
362     if(fileType != FILE_TYPE_REGULAR)
363     {
364         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
365                                                GTK_DIALOG_DESTROY_WITH_PARENT,
366                                                GTK_MESSAGE_ERROR,
367                                                GTK_BUTTONS_CLOSE,
368                                                _("'%s' is not a regular file"),
369                                                itemName);
370         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
371         gtk_dialog_run(GTK_DIALOG(warningDialog));
372         gtk_widget_destroy(warningDialog);
373 
374         g_free(itemName);
375         return;
376     }
377 
378     /* create full path and name for the file on the iso */
379     pathAndNameOnIso = malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
380     if(pathAndNameOnIso == NULL)
381         fatalError("malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed");
382     strcpy(pathAndNameOnIso, GBLisoCurrentDir);
383     strcat(pathAndNameOnIso, itemName);
384 
385     /* create full path and name for the extracted file */
386     randomizedItemName = makeRandomFilename(itemName);
387     pathAndNameOnFs = malloc(strlen(GBLappSettings.tempDir) +
388                              strlen(randomizedItemName) + 2);
389     if(pathAndNameOnFs == NULL)
390         fatalError("malloc(strlen(GBLappSettings.tempDir) + "
391                    "strlen(randomizedItemName) + 2) failed");
392     strcpy(pathAndNameOnFs, GBLappSettings.tempDir);
393 
394     strcat(pathAndNameOnFs, "/"); /* doesn't hurt even if not needed */
395 
396     strcat(pathAndNameOnFs, randomizedItemName);
397 
398     /* disable warnings, so user isn't confused with 'continue' buttons */
399     bool(*savedWarningCbk)(const char*) = GBLvolInfo.warningCbk;
400     GBLvolInfo.warningCbk = NULL;
401 
402     /* extract the file to the temporary directory */
403     rc = bk_extract_as(&GBLvolInfo, pathAndNameOnIso,
404                        GBLappSettings.tempDir,
405                        randomizedItemName, false, activityProgressUpdaterCbk);
406     if(rc <= 0)
407     {
408         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
409                                                GTK_DIALOG_DESTROY_WITH_PARENT,
410                                                GTK_MESSAGE_ERROR,
411                                                GTK_BUTTONS_CLOSE,
412                                                _("Failed to extract '%s': '%s'"),
413                                                pathAndNameOnIso,
414                                                bk_get_error_string(rc));
415         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
416         gtk_dialog_run(GTK_DIALOG(warningDialog));
417         gtk_widget_destroy(warningDialog);
418 
419         g_free(itemName);
420         free(randomizedItemName);
421         free(pathAndNameOnFs);
422         free(pathAndNameOnIso);
423         GBLvolInfo.warningCbk = savedWarningCbk;
424         return;
425     }
426 
427     addToTempFilesList(pathAndNameOnFs);
428 
429     /* start the editor */
430     if(!fork())
431     {
432         execlp(GBLappSettings.editor, "editor", pathAndNameOnFs, NULL);
433 
434         kill(getppid(), SIGUSR1);
435 
436         exit(1);
437     }
438 
439     /* delete the file from the iso */
440     rc = bk_delete(&GBLvolInfo, pathAndNameOnIso);
441     if(rc <= 0)
442     {
443         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
444                                                GTK_DIALOG_DESTROY_WITH_PARENT,
445                                                GTK_MESSAGE_ERROR,
446                                                GTK_BUTTONS_CLOSE,
447                                                _("Failed to delete '%s': '%s'"),
448                                                pathAndNameOnIso,
449                                                bk_get_error_string(rc));
450         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
451         gtk_dialog_run(GTK_DIALOG(warningDialog));
452         gtk_widget_destroy(warningDialog);
453 
454         g_free(itemName);
455         free(randomizedItemName);
456         free(pathAndNameOnFs);
457         free(pathAndNameOnIso);
458         GBLvolInfo.warningCbk = savedWarningCbk;
459         return;
460     }
461 
462     GBLisoChangesProbable = true;
463 
464     /* add the file back fom tmp */
465     rc = bk_add_as(&GBLvolInfo, pathAndNameOnFs, GBLisoCurrentDir, itemName,
466                    activityProgressUpdaterCbk);
467     if(rc <= 0)
468     {
469         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
470                                                GTK_DIALOG_DESTROY_WITH_PARENT,
471                                                GTK_MESSAGE_ERROR,
472                                                GTK_BUTTONS_CLOSE,
473                                                _("Failed to add '%s': '%s'"),
474                                                pathAndNameOnFs,
475                                                bk_get_error_string(rc));
476         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
477         gtk_dialog_run(GTK_DIALOG(warningDialog));
478         gtk_widget_destroy(warningDialog);
479     }
480 
481     g_free(itemName);
482     free(randomizedItemName);
483     free(pathAndNameOnFs);
484     free(pathAndNameOnIso);
485     GBLvolInfo.warningCbk = savedWarningCbk;
486 }
487 
488 /* caller must free the string returned */
makeRandomFilename(const char * sourceName)489 char* makeRandomFilename(const char* sourceName)
490 {
491     int sourceNameLen;
492     char* newName;
493     char randomStr[RANDOM_STR_NAME_LEN];
494     int numRandomCharsFilled;
495 
496     if(strlen(sourceName) > MAX_RANDOM_BASE_NAME_LEN)
497         sourceNameLen = MAX_RANDOM_BASE_NAME_LEN;
498     else
499         sourceNameLen = strlen(sourceName);
500 
501     newName = malloc(sourceNameLen + RANDOM_STR_NAME_LEN + 2);
502     if(newName == NULL)
503         fatalError("newName = malloc(sourceNameLen + RANDOM_STR_NAME_LEN + 2) failed\n");
504 
505     numRandomCharsFilled = 0;
506     while(numRandomCharsFilled < RANDOM_STR_NAME_LEN)
507     {
508         char oneRandomChar;
509         bool gotGoodChar;
510 
511 #ifdef HAVE_ARC4RANDOM
512         oneRandomChar = arc4random_uniform('Z'-'A'+1) + 'A';
513 #else
514         gotGoodChar = false;
515         while(!gotGoodChar)
516         {
517             oneRandomChar = random();
518             if(64 < oneRandomChar && oneRandomChar < 91)
519             {
520                 gotGoodChar = true;
521             }
522         }
523 #endif
524 
525         randomStr[numRandomCharsFilled] = oneRandomChar;
526 
527         numRandomCharsFilled++;
528     }
529 
530     strncpy(newName, randomStr, RANDOM_STR_NAME_LEN);
531     newName[RANDOM_STR_NAME_LEN] = '\0';
532     strcat(newName, "-");
533     strncat(newName, sourceName, sourceNameLen);
534     newName[RANDOM_STR_NAME_LEN + sourceNameLen + 1] = '\0';
535 
536     return newName;
537 }
538 
viewSelectedBtnCbk(GtkMenuItem * menuitem,gpointer data)539 void viewSelectedBtnCbk(GtkMenuItem *menuitem, gpointer data)
540 {
541     GtkTreeSelection* selection;
542     static guint timeoutTag = 0;
543 
544     gboolean fsViewHasFocus;
545     gboolean isoViewHasFocus;
546 
547     g_object_get(GBLfsTreeView, "is-focus", &fsViewHasFocus, NULL);
548     g_object_get(GBLisoTreeView, "is-focus", &isoViewHasFocus, NULL);
549 
550     if(fsViewHasFocus)
551     {
552         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLfsTreeView));
553 
554         /* kill the previous timeout function (if any) */
555         if(timeoutTag != 0)
556             g_source_remove(timeoutTag);
557 
558         GBLviewFailed = false;
559 
560         /* a timeout that will keep checking whether GBLviewFailed */
561         timeoutTag = g_timeout_add(TIMEOUT_TIME, checkViewFailed, NULL);
562 
563         gtk_tree_selection_selected_foreach(selection, viewSelectedFsRowCbk, NULL);
564     }
565     else if(isoViewHasFocus)
566     {
567         /* do nothing if no image open */
568         if(!GBLisoPaneActive)
569             return;
570 
571         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(GBLisoTreeView));
572 
573         /* kill the previous timeout function (if any) */
574         if(timeoutTag != 0)
575             g_source_remove(timeoutTag);
576 
577         GBLviewFailed = false;
578 
579         /* a timeout that will keep checking whether GBLviewFailed */
580         timeoutTag = g_timeout_add(TIMEOUT_TIME, checkViewFailed, NULL);
581 
582         gtk_tree_selection_selected_foreach(selection, viewSelectedIsoRowCbk, NULL);
583     }
584 }
585 
viewSelectedFsRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)586 void viewSelectedFsRowCbk(GtkTreeModel* model, GtkTreePath* path,
587                           GtkTreeIter* iterator, gpointer data)
588 {
589     int fileType;
590     char* itemName;
591     char* randomizedItemName;
592     char* pathAndNameOnFs;
593     char* pathAndNameInTempDir;
594     GtkWidget* warningDialog;
595     bool copiedOk;
596 
597     gtk_tree_model_get(model, iterator, COLUMN_HIDDEN_TYPE, &fileType,
598                                         COLUMN_FILENAME, &itemName, -1);
599     if(fileType != FILE_TYPE_REGULAR)
600     {
601         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
602                                                GTK_DIALOG_DESTROY_WITH_PARENT,
603                                                GTK_MESSAGE_ERROR,
604                                                GTK_BUTTONS_CLOSE,
605                                                _("'%s' is not a regular file"),
606                                                itemName);
607         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
608         gtk_dialog_run(GTK_DIALOG(warningDialog));
609         gtk_widget_destroy(warningDialog);
610 
611         g_free(itemName);
612         return;
613     }
614 
615     /* create full path and name for the file on the fs */
616     pathAndNameOnFs = malloc(strlen(GBLfsCurrentDir) + strlen(itemName) + 1);
617     if(pathAndNameOnFs == NULL)
618         fatalError("malloc(strlen(GBLfsCurrentDir) + strlen(itemName) + 1) failed");
619     strcpy(pathAndNameOnFs, GBLfsCurrentDir);
620     strcat(pathAndNameOnFs, itemName);
621 
622     /* create full path and name for the extracted file */
623     randomizedItemName = makeRandomFilename(itemName);
624     pathAndNameInTempDir = malloc(strlen(GBLappSettings.tempDir) +
625                                   strlen(randomizedItemName) + 2);
626     if(pathAndNameInTempDir == NULL)
627         fatalError("malloc(strlen(GBLappSettings.tempDir) + "
628                    "strlen(randomizedItemName) + 2) failed");
629     strcpy(pathAndNameInTempDir, GBLappSettings.tempDir);
630 
631     strcat(pathAndNameInTempDir, "/"); /* doesn't hurt even if not needed */
632 
633     strcat(pathAndNameInTempDir, randomizedItemName);
634 
635     /* disable warnings, so user isn't confused with 'continue' buttons */
636     bool(*savedWarningCbk)(const char*) = GBLvolInfo.warningCbk;
637     GBLvolInfo.warningCbk = NULL;
638 
639     /* copy the file to the temporary directory */
640     copiedOk = copyFsToFs(pathAndNameOnFs, pathAndNameInTempDir);
641     if(!copiedOk)
642     {
643         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
644                                                GTK_DIALOG_DESTROY_WITH_PARENT,
645                                                GTK_MESSAGE_ERROR,
646                                                GTK_BUTTONS_CLOSE,
647                                                "Failed to copy '%s' to '%s'",
648                                                pathAndNameOnFs,
649                                                pathAndNameInTempDir);
650         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
651         gtk_dialog_run(GTK_DIALOG(warningDialog));
652         gtk_widget_destroy(warningDialog);
653 
654         g_free(itemName);
655         free(randomizedItemName);
656         free(pathAndNameOnFs);
657         free(pathAndNameInTempDir);
658         GBLvolInfo.warningCbk = savedWarningCbk;
659         return;
660     }
661 
662     addToTempFilesList(pathAndNameInTempDir);
663 
664     /* start the viewer */
665     if(!fork())
666     {
667         execlp(GBLappSettings.viewer, "viewer", pathAndNameInTempDir, NULL);
668 
669         kill(getppid(), SIGUSR2);
670 
671         exit(1);
672     }
673 
674     g_free(itemName);
675     free(randomizedItemName);
676     free(pathAndNameOnFs);
677     free(pathAndNameInTempDir);
678     GBLvolInfo.warningCbk = savedWarningCbk;
679 }
680 
viewSelectedIsoRowCbk(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iterator,gpointer data)681 void viewSelectedIsoRowCbk(GtkTreeModel* model, GtkTreePath* path,
682                         GtkTreeIter* iterator, gpointer data)
683 {
684     int fileType;
685     char* itemName;
686     char* randomizedItemName;
687     char* pathAndNameOnFs; /* to extract to and add from */
688     char* pathAndNameOnIso; /* to delete from iso */
689     int rc;
690     GtkWidget* warningDialog;
691 
692     gtk_tree_model_get(model, iterator, COLUMN_HIDDEN_TYPE, &fileType,
693                                         COLUMN_FILENAME, &itemName, -1);
694     if(fileType != FILE_TYPE_REGULAR)
695     {
696         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
697                                                GTK_DIALOG_DESTROY_WITH_PARENT,
698                                                GTK_MESSAGE_ERROR,
699                                                GTK_BUTTONS_CLOSE,
700                                                _("'%s' is not a regular file"),
701                                                itemName);
702         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
703         gtk_dialog_run(GTK_DIALOG(warningDialog));
704         gtk_widget_destroy(warningDialog);
705 
706         g_free(itemName);
707         return;
708     }
709 
710     /* create full path and name for the file on the iso */
711     pathAndNameOnIso = malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1);
712     if(pathAndNameOnIso == NULL)
713         fatalError("malloc(strlen(GBLisoCurrentDir) + strlen(itemName) + 1) failed");
714     strcpy(pathAndNameOnIso, GBLisoCurrentDir);
715     strcat(pathAndNameOnIso, itemName);
716 
717     /* create full path and name for the extracted file */
718     randomizedItemName = makeRandomFilename(itemName);
719     pathAndNameOnFs = malloc(strlen(GBLappSettings.tempDir) +
720                              strlen(randomizedItemName) + 2);
721     if(pathAndNameOnFs == NULL)
722         fatalError("malloc(strlen(GBLappSettings.tempDir) + "
723                    "strlen(randomizedItemName) + 2) failed");
724     strcpy(pathAndNameOnFs, GBLappSettings.tempDir);
725 
726     strcat(pathAndNameOnFs, "/"); /* doesn't hurt even if not needed */
727 
728     strcat(pathAndNameOnFs, randomizedItemName);
729 
730     /* disable warnings, so user isn't confused with 'continue' buttons */
731     bool(*savedWarningCbk)(const char*) = GBLvolInfo.warningCbk;
732     GBLvolInfo.warningCbk = NULL;
733 
734     /* extract the file to the temporary directory */
735     rc = bk_extract_as(&GBLvolInfo, pathAndNameOnIso,
736                        GBLappSettings.tempDir,
737                        randomizedItemName, false, activityProgressUpdaterCbk);
738     if(rc <= 0)
739     {
740         warningDialog = gtk_message_dialog_new(GTK_WINDOW(GBLmainWindow),
741                                                GTK_DIALOG_DESTROY_WITH_PARENT,
742                                                GTK_MESSAGE_ERROR,
743                                                GTK_BUTTONS_CLOSE,
744                                                _("Failed to extract '%s': '%s'"),
745                                                pathAndNameOnIso,
746                                                bk_get_error_string(rc));
747         gtk_window_set_modal(GTK_WINDOW(warningDialog), TRUE);
748         gtk_dialog_run(GTK_DIALOG(warningDialog));
749         gtk_widget_destroy(warningDialog);
750 
751         g_free(itemName);
752         free(randomizedItemName);
753         free(pathAndNameOnFs);
754         free(pathAndNameOnIso);
755         GBLvolInfo.warningCbk = savedWarningCbk;
756         return;
757     }
758 
759     addToTempFilesList(pathAndNameOnFs);
760 
761     /* start the viewer */
762     if(!fork())
763     {
764         execlp(GBLappSettings.viewer, "viewer", pathAndNameOnFs, NULL);
765 
766         kill(getppid(), SIGUSR2);
767 
768         exit(1);
769     }
770 
771     g_free(itemName);
772     free(randomizedItemName);
773     free(pathAndNameOnFs);
774     free(pathAndNameOnIso);
775     GBLvolInfo.warningCbk = savedWarningCbk;
776 }
777 
sigusr1(int signum)778 void sigusr1(int signum)
779 {
780     GBLeditFailed = true;
781 }
782 
sigusr2(int signum)783 void sigusr2(int signum)
784 {
785     GBLviewFailed = true;
786 }
787