[file-roller] avoid tarbombs when using extract here



commit 265cb90c4c17e638033b723c9bf39e490740cd4e
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sun May 8 16:42:59 2016 +0200

    avoid tarbombs when using extract here
    
    [bug #766071]

 src/fr-window.c |  186 +++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 145 insertions(+), 41 deletions(-)
---
diff --git a/src/fr-window.c b/src/fr-window.c
index e33f26e..29813f2 100644
--- a/src/fr-window.c
+++ b/src/fr-window.c
@@ -124,6 +124,7 @@ typedef struct {
        gboolean     junk_paths;
        char        *password;
        gboolean     ask_to_open_destination;
+       gboolean     avoid_tarbombs;
 } ExtractData;
 
 
@@ -6421,7 +6422,8 @@ extract_data_new (FrWindow    *window,
                  gboolean     skip_older,
                  FrOverwrite  overwrite,
                  gboolean     junk_paths,
-                 gboolean     ask_to_open_destination)
+                 gboolean     ask_to_open_destination,
+                 gboolean     avoid_tarbombs)
 {
        ExtractData *edata;
 
@@ -6435,6 +6437,7 @@ extract_data_new (FrWindow    *window,
        if (base_dir != NULL)
                edata->base_dir = g_strdup (base_dir);
        edata->ask_to_open_destination = ask_to_open_destination;
+       edata->avoid_tarbombs = avoid_tarbombs;
 
        return edata;
 }
@@ -6807,33 +6810,13 @@ archive_is_encrypted (FrWindow *window,
 }
 
 
-void
-fr_window_archive_extract (FrWindow    *window,
-                          GList       *file_list,
-                          GFile       *destination,
-                          const char  *base_dir,
-                          gboolean     skip_older,
-                          FrOverwrite  overwrite,
-                          gboolean     junk_paths,
-                          gboolean     ask_to_open_destination)
+/* ask some questions to the user before calling _fr_window_archive_extract_from_edata */
+static void
+_fr_window_archive_extract_from_edata_maybe (FrWindow    *window,
+                                            ExtractData *edata)
 {
-       ExtractData *edata;
-       gboolean     do_not_extract = FALSE;
-       GError      *error = NULL;
-
-       edata = extract_data_new (window,
-                                 file_list,
-                                 destination,
-                                 base_dir,
-                                 skip_older,
-                                 overwrite,
-                                 junk_paths,
-                                 ask_to_open_destination);
-
-       fr_window_set_current_action (window,
-                                           FR_BATCH_ACTION_EXTRACT,
-                                           edata,
-                                           (GFreeFunc) extract_data_free);
+       gboolean  do_not_extract = FALSE;
+       GError   *error = NULL;
 
        if (archive_is_encrypted (window, edata->file_list) && (window->priv->password == NULL)) {
                dlg_ask_password (window);
@@ -6846,7 +6829,7 @@ fr_window_archive_extract (FrWindow    *window,
                if (edata->overwrite == FR_OVERWRITE_ASK)
                        edata->overwrite = FR_OVERWRITE_YES;
 
-               if (! ForceDirectoryCreation) {
+               if (! ForceDirectoryCreation && ! edata->avoid_tarbombs) {
                        GtkWidget *d;
                        int        r;
                        char      *folder_name;
@@ -6931,26 +6914,144 @@ fr_window_archive_extract (FrWindow    *window,
 }
 
 
+void
+fr_window_archive_extract (FrWindow    *window,
+                          GList       *file_list,
+                          GFile       *destination,
+                          const char  *base_dir,
+                          gboolean     skip_older,
+                          FrOverwrite  overwrite,
+                          gboolean     junk_paths,
+                          gboolean     ask_to_open_destination)
+{
+       ExtractData *edata;
+
+       edata = extract_data_new (window,
+                                 file_list,
+                                 destination,
+                                 base_dir,
+                                 skip_older,
+                                 overwrite,
+                                 junk_paths,
+                                 ask_to_open_destination,
+                                 FALSE);
+
+       fr_window_set_current_action (window,
+                                     FR_BATCH_ACTION_EXTRACT,
+                                     edata,
+                                     (GFreeFunc) extract_data_free);
+
+       _fr_window_archive_extract_from_edata_maybe (window, edata);
+}
+
+
 /* -- fr_window_archive_extract_here -- */
 
 
+#define MIN_TOPLEVEL_ITEMS_FOR_A_TARBOMB 2
+
+
+static gboolean
+_archive_extraction_generates_a_tarbomb (FrArchive *archive)
+{
+       gboolean    tarbomb = FALSE;
+       GHashTable *names_hash;
+       int         n_toplevel_items, i;
+
+       names_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+       n_toplevel_items = 0;
+       for (i = 0; ! tarbomb && (i < archive->files->len); i++) {
+               FileData *fdata = g_ptr_array_index (archive->files, i);
+               char     *second_separator;
+               char     *name = NULL;
+               gboolean  name_created;
+
+               if ((fdata->full_path == NULL) || (fdata->full_path[0] == '\0'))
+                       continue;
+
+               second_separator = strchr (fdata->full_path + 1 /* skip the first separator */, '/');
+               if (second_separator != NULL) {
+                       name = g_strndup (fdata->full_path, second_separator - fdata->full_path);
+                       name_created = TRUE;
+               }
+               else {
+                       name = fdata->full_path;
+                       name_created = FALSE;
+               }
+
+               if (g_hash_table_lookup (names_hash, name) == NULL) {
+                       g_hash_table_insert (names_hash, name_created ? name : g_strdup (name), 
GINT_TO_POINTER (1));
+                       n_toplevel_items++;
+                       if (n_toplevel_items >= MIN_TOPLEVEL_ITEMS_FOR_A_TARBOMB)
+                               tarbomb = TRUE;
+               }
+               else if (name_created)
+                       g_free (name);
+       }
+       g_hash_table_destroy (names_hash);
+
+       return tarbomb;
+}
+
+
+static GFile *
+_get_destination_to_avoid_tarbomb (GFile *file)
+{
+       GFile      *directory;
+       char       *name;
+       const char *ext;
+       char       *new_name;
+       GFile      *destination;
+
+       directory = g_file_get_parent (file);
+       name = g_file_get_basename (file);
+       ext = get_archive_filename_extension (name);
+       if (ext == NULL)
+               /* if no extension is present add a suffix to the name... */
+               new_name = g_strconcat (name, "_FILES", NULL);
+       else
+               /* ...else use the name without the extension */
+               new_name = g_strndup (name, strlen (name) - strlen (ext));
+       destination = g_file_get_child (directory, new_name);
+
+       g_free (new_name);
+       g_free (name);
+       g_object_unref (directory);
+
+       return destination;
+}
+
+
 void
 fr_window_archive_extract_here (FrWindow   *window,
                                gboolean    skip_older,
                                gboolean    overwrite,
                                gboolean    junk_paths)
 {
-       GFile *destination;
+       GFile       *destination;
+       ExtractData *edata;
 
-       destination = g_file_get_parent (fr_archive_get_file (window->archive));
-       fr_window_archive_extract (window,
-                                  NULL,
-                                  destination,
-                                  NULL,
-                                  skip_older,
-                                  overwrite,
-                                  junk_paths,
-                                  _fr_window_get_ask_to_open_destination (window));
+       if (_archive_extraction_generates_a_tarbomb (window->archive))
+               destination = _get_destination_to_avoid_tarbomb (fr_archive_get_file (window->archive));
+       else
+               destination = g_file_get_parent (fr_archive_get_file (window->archive));
+
+       edata = extract_data_new (window,
+                                 NULL,
+                                 destination,
+                                 NULL,
+                                 skip_older,
+                                 overwrite,
+                                 junk_paths,
+                                 _fr_window_get_ask_to_open_destination (window),
+                                 TRUE);
+
+       fr_window_set_current_action (window,
+                                     FR_BATCH_ACTION_EXTRACT,
+                                     edata,
+                                     (GFreeFunc) extract_data_free);
+
+       _fr_window_archive_extract_from_edata_maybe (window, edata);
 
        g_object_unref (destination);
 }
@@ -9704,7 +9805,8 @@ fr_window_batch__extract_here (FrWindow *window,
                                                         FALSE,
                                                         FR_OVERWRITE_ASK,
                                                         FALSE,
-                                                        _fr_window_get_ask_to_open_destination (window)),
+                                                        _fr_window_get_ask_to_open_destination (window),
+                                                        TRUE),
                                       (GFreeFunc) extract_data_free);
        fr_window_batch_append_action (window,
                                       FR_BATCH_ACTION_CLOSE,
@@ -9735,7 +9837,8 @@ fr_window_batch__extract (FrWindow  *window,
                                                                 FALSE,
                                                                 FR_OVERWRITE_ASK,
                                                                 FALSE,
-                                                                _fr_window_get_ask_to_open_destination 
(window)),
+                                                                _fr_window_get_ask_to_open_destination 
(window),
+                                                                FALSE),
                                               (GFreeFunc) extract_data_free);
        else
                fr_window_batch_append_action (window,
@@ -9811,7 +9914,8 @@ fr_window_extract_archive_and_continue (FrWindow      *window,
                                                                          skip_older,
                                                                          FR_OVERWRITE_ASK,
                                                                          junk_paths,
-                                                                         
_fr_window_get_ask_to_open_destination (window)),
+                                                                         
_fr_window_get_ask_to_open_destination (window),
+                                                                         FALSE),
                                                        (GFreeFunc) extract_data_free);
                fr_window_batch_resume (window);
        }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]