[gnome-desktop] thumbnail: Split off running the script



commit c1956f35bd1a9170e433d116f36e63d58b6ff826
Author: Bastien Nocera <hadess hadess net>
Date:   Thu Jul 20 20:51:09 2017 +0200

    thumbnail: Split off running the script
    
    Move most of the script command generation to a separate file, making
    the function return a GBytes from a successful thumbnailer run, so as to
    avoid having to clean up temporary files from the thumbnailer run.
    
    Note that it changes a few subtle things which shouldn't be a problem in
    practice, but, as a corner case, might have been used by applications:
    
    - Thumbnailers must output PNG images. pixbuf_new_from_bytes() could
    have been made more complicated to handle all images, and then we would
    restrict the thumbnailer output format separately, but it makes no sense
    to write complicated code to remove it in the next commit.
    - URIs which have no backing path are not supported. This will likely
    cause problems for thumbnailing remote shares on OSes which lack
    gvfsd-fuse. Support could be re-added in the future.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=774497

 libgnome-desktop/Makefile.am                      |    4 +-
 libgnome-desktop/gnome-desktop-thumbnail-script.c |  244 +++++++++++++++++++++
 libgnome-desktop/gnome-desktop-thumbnail-script.h |   38 ++++
 libgnome-desktop/gnome-desktop-thumbnail.c        |  185 +++-------------
 4 files changed, 321 insertions(+), 150 deletions(-)
---
diff --git a/libgnome-desktop/Makefile.am b/libgnome-desktop/Makefile.am
index 9c4da15..a60aac8 100644
--- a/libgnome-desktop/Makefile.am
+++ b/libgnome-desktop/Makefile.am
@@ -42,7 +42,9 @@ libgnome_desktop_3_la_SOURCES =       \
        gnome-datetime-source.c         \
        gnome-rr-private.h              \
        default-input-sources.h         \
-       meta-xrandr-shared.h
+       meta-xrandr-shared.h            \
+       gnome-desktop-thumbnail-script.c\
+       gnome-desktop-thumbnail-script.h
 
 dbus_xrandr_built_sources = meta-dbus-xrandr.c meta-dbus-xrandr.h
 
diff --git a/libgnome-desktop/gnome-desktop-thumbnail-script.c 
b/libgnome-desktop/gnome-desktop-thumbnail-script.c
new file mode 100644
index 0000000..87319bc
--- /dev/null
+++ b/libgnome-desktop/gnome-desktop-thumbnail-script.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2002, 2017 Red Hat, Inc.
+ * Copyright (C) 2010 Carlos Garcia Campos <carlosgc gnome org>
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors: Alexander Larsson <alexl redhat com>
+ *          Carlos Garcia Campos <carlosgc gnome org>
+ *          Bastien Nocera <hadess hadess net>
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+#include <glib/gstdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "gnome-desktop-thumbnail-script.h"
+
+typedef struct {
+  char *infile;
+  char *outfile;
+} ScriptExec;
+
+static char *
+expand_thumbnailing_elem (const char *elem,
+                         const int   size,
+                         const char *inuri,
+                         const char *outfile,
+                         gboolean   *got_input,
+                         gboolean   *got_output)
+{
+  GString *str;
+  const char *p, *last;
+  char *localfile;
+
+  str = g_string_new (NULL);
+
+  last = elem;
+  while ((p = strchr (last, '%')) != NULL)
+    {
+      g_string_append_len (str, last, p - last);
+      p++;
+
+      switch (*p) {
+      case 'u':
+       g_string_append (str, inuri);
+       *got_input = TRUE;
+       p++;
+       break;
+      case 'i':
+       localfile = g_filename_from_uri (inuri, NULL, NULL);
+       if (localfile)
+         {
+           g_string_append (str, localfile);
+           *got_input = TRUE;
+           g_free (localfile);
+         }
+       p++;
+       break;
+      case 'o':
+       g_string_append (str, outfile);
+       *got_output = TRUE;
+       p++;
+       break;
+      case 's':
+       g_string_append_printf (str, "%d", size);
+       p++;
+       break;
+      case '%':
+       g_string_append_c (str, '%');
+       p++;
+       break;
+      case 0:
+      default:
+       break;
+      }
+      last = p;
+    }
+  g_string_append (str, last);
+
+  return g_string_free (str, FALSE);
+}
+
+static char **
+expand_thumbnailing_script (const char  *cmd,
+                           ScriptExec  *script,
+                           int          size,
+                           GError     **error)
+{
+  GPtrArray *array;
+  g_auto(GStrv) cmd_elems = NULL;
+  guint i;
+  gboolean got_in, got_out;
+  g_autofree char *sandboxed_path = NULL;
+
+  if (!g_shell_parse_argv (cmd, NULL, &cmd_elems, error))
+    return NULL;
+
+  array = g_ptr_array_new_with_free_func (g_free);
+
+  got_in = got_out = FALSE;
+  for (i = 0; cmd_elems[i] != NULL; i++)
+    {
+      char *expanded;
+
+      expanded = expand_thumbnailing_elem (cmd_elems[i],
+                                          size,
+                                          script->infile,
+                                          script->outfile,
+                                          &got_in,
+                                          &got_out);
+
+      g_ptr_array_add (array, expanded);
+    }
+
+  if (!got_in)
+    {
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                          "Input file could not be set");
+      goto bail;
+    }
+  else if (!got_out)
+    {
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                          "Output file could not be set");
+      goto bail;
+    }
+
+  g_ptr_array_add (array, NULL);
+
+  return (char **) g_ptr_array_free (array, FALSE);
+
+bail:
+  g_ptr_array_free (array, TRUE);
+  return NULL;
+}
+
+static void
+script_exec_free (ScriptExec *exec)
+{
+  g_free (exec->infile);
+  if (exec->outfile)
+    {
+      g_unlink (exec->outfile);
+      g_free (exec->outfile);
+    }
+  g_free (exec);
+}
+
+static ScriptExec *
+script_exec_new (const char *uri)
+{
+  ScriptExec *exec;
+  g_autoptr(GFile) file = NULL;
+  int fd;
+  g_autofree char *tmpname = NULL;
+
+  exec = g_new0 (ScriptExec, 1);
+  file = g_file_new_for_uri (uri);
+
+  exec->infile = g_file_get_path (file);
+  if (!exec->infile)
+    goto bail;
+
+  fd = g_file_open_tmp (".gnome_desktop_thumbnail.XXXXXX", &tmpname, NULL);
+  if (fd == -1)
+    goto bail;
+  close (fd);
+  exec->outfile = g_steal_pointer (&tmpname);
+
+  return exec;
+
+bail:
+  script_exec_free (exec);
+  return NULL;
+}
+
+GBytes *
+gnome_desktop_thumbnail_script_exec (const char  *cmd,
+                                    int          size,
+                                    const char  *uri,
+                                    GError     **error)
+{
+  g_autofree char *error_out = NULL;
+  g_auto(GStrv) expanded_script = NULL;
+  int exit_status;
+  gboolean ret;
+  GBytes *image = NULL;
+  ScriptExec *exec;
+
+  exec = script_exec_new (uri);
+  expanded_script = expand_thumbnailing_script (cmd, exec, size, error);
+  if (expanded_script == NULL)
+    goto out;
+
+#if 0
+  guint i;
+
+  g_print ("About to launch script: ");
+  for (i = 0; expanded_script[i]; i++)
+    g_print ("%s ", expanded_script[i]);
+  g_print ("\n");
+#endif
+
+  ret = g_spawn_sync (NULL, expanded_script, NULL, G_SPAWN_SEARCH_PATH,
+                     NULL, NULL, NULL, &error_out,
+                     &exit_status, error);
+  if (ret && g_spawn_check_exit_status (exit_status, error))
+    {
+      char *contents;
+      gsize length;
+
+      if (g_file_get_contents (exec->outfile, &contents, &length, error))
+        image = g_bytes_new_take (contents, length);
+    }
+  else
+    {
+      g_debug ("Failed to launch script: %s", !ret ? (*error)->message : error_out);
+    }
+
+out:
+  script_exec_free (exec);
+  return image;
+}
+
diff --git a/libgnome-desktop/gnome-desktop-thumbnail-script.h 
b/libgnome-desktop/gnome-desktop-thumbnail-script.h
new file mode 100644
index 0000000..cbd6bbf
--- /dev/null
+++ b/libgnome-desktop/gnome-desktop-thumbnail-script.h
@@ -0,0 +1,38 @@
+/*
+ * gnome-thumbnail.h: Utilities for handling thumbnails
+ *
+ * Copyright (C) 2002, 2017 Red Hat, Inc.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors: Alexander Larsson <alexl redhat com>
+ *          Bastien Nocera <hadess hadess net>
+ */
+
+#ifndef GNOME_DESKTOP_THUMBNAIL_SCRIPT_H
+#define GNOME_DESKTOP_THUMBNAIL_SCRIPT_H
+
+#include <glib.h>
+
+GBytes *
+gnome_desktop_thumbnail_script_exec (const char  *cmd,
+                                    int          size,
+                                    const char  *uri,
+                                    GError     **error);
+
+#endif /* GNOME_DESKTOP_THUMBNAIL_SCRIPT_H */
diff --git a/libgnome-desktop/gnome-desktop-thumbnail.c b/libgnome-desktop/gnome-desktop-thumbnail.c
index 617160d..73751f6 100644
--- a/libgnome-desktop/gnome-desktop-thumbnail.c
+++ b/libgnome-desktop/gnome-desktop-thumbnail.c
@@ -127,9 +127,12 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <string.h>
 #include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 #define GNOME_DESKTOP_USE_UNSTABLE_API
 #include "gnome-desktop-thumbnail.h"
+#include "gnome-desktop-thumbnail-script.h"
 
 static void
 thumbnailers_directory_changed (GFileMonitor                 *monitor,
@@ -929,120 +932,6 @@ gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDesktopThumbnailFactory *fac
   return FALSE;
 }
 
-static char *
-expand_thumbnailing_elem (const char *elem,
-                         const int   size,
-                         const char *inuri,
-                         const char *outfile,
-                         gboolean   *got_input,
-                         gboolean   *got_output)
-{
-  GString *str;
-  const char *p, *last;
-  char *localfile;
-
-  str = g_string_new (NULL);
-
-  last = elem;
-  while ((p = strchr (last, '%')) != NULL)
-    {
-      g_string_append_len (str, last, p - last);
-      p++;
-
-      switch (*p) {
-      case 'u':
-       g_string_append (str, inuri);
-       *got_input = TRUE;
-       p++;
-       break;
-      case 'i':
-       localfile = g_filename_from_uri (inuri, NULL, NULL);
-       if (localfile)
-         {
-           g_string_append (str, localfile);
-           *got_input = TRUE;
-           g_free (localfile);
-         }
-       p++;
-       break;
-      case 'o':
-       g_string_append (str, outfile);
-       *got_output = TRUE;
-       p++;
-       break;
-      case 's':
-       g_string_append_printf (str, "%d", size);
-       p++;
-       break;
-      case '%':
-       g_string_append_c (str, '%');
-       p++;
-       break;
-      case 0:
-      default:
-       break;
-      }
-      last = p;
-    }
-  g_string_append (str, last);
-
-  return g_string_free (str, FALSE);
-}
-
-static char **
-expand_thumbnailing_script (const char  *script,
-                           const int    size,
-                           const char  *inuri,
-                           const char  *outfile,
-                           GError     **error)
-{
-  GPtrArray *array;
-  char **script_elems;
-  guint i;
-  gboolean got_in, got_out;
-
-  if (!g_shell_parse_argv (script, NULL, &script_elems, error))
-    return NULL;
-
-  array = g_ptr_array_new_with_free_func (g_free);
-
-  got_in = got_out = FALSE;
-  for (i = 0; script_elems[i] != NULL; i++)
-    {
-      char *expanded;
-
-      expanded = expand_thumbnailing_elem (script_elems[i],
-                                          size,
-                                          inuri,
-                                          outfile,
-                                          &got_in,
-                                          &got_out);
-
-      g_ptr_array_add (array, expanded);
-    }
-
-  if (!got_in)
-    {
-      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                          "Input file could not be set");
-      goto bail;
-    }
-  else if (!got_out)
-    {
-      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                          "Output file could not be set");
-      goto bail;
-    }
-
-  g_ptr_array_add (array, NULL);
-
-  return (char **) g_ptr_array_free (array, FALSE);
-
-bail:
-  g_ptr_array_free (array, TRUE);
-  return NULL;
-}
-
 static GdkPixbuf *
 get_preview_thumbnail (const char *uri,
                        int         size)
@@ -1099,6 +988,30 @@ get_preview_thumbnail (const char *uri,
     return pixbuf;
 }
 
+static GdkPixbuf *
+pixbuf_new_from_bytes (GBytes  *bytes,
+                      GError **error)
+{
+  g_autoptr(GdkPixbufLoader) loader = NULL;
+
+  loader = gdk_pixbuf_loader_new_with_mime_type ("image/png", error);
+  if (!loader)
+    return NULL;
+
+  if (!gdk_pixbuf_loader_write (loader,
+                               g_bytes_get_data (bytes, NULL),
+                               g_bytes_get_size (bytes),
+                               error))
+    {
+      return NULL;
+    }
+
+  if (!gdk_pixbuf_loader_close (loader, error))
+    return NULL;
+
+  return g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader));
+}
+
 /**
  * gnome_desktop_thumbnail_factory_generate_thumbnail:
  * @factory: a #GnomeDesktopThumbnailFactory
@@ -1122,8 +1035,6 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
   GdkPixbuf *pixbuf;
   char *script;
   int size;
-  int exit_status;
-  char *tmpname;
 
   g_return_val_if_fail (uri != NULL, NULL);
   g_return_val_if_fail (mime_type != NULL, NULL);
@@ -1154,42 +1065,18 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
 
   if (script)
     {
-      int fd;
-
-      fd = g_file_open_tmp (".gnome_desktop_thumbnail.XXXXXX", &tmpname, NULL);
-
-      if (fd != -1)
-       {
-         char **expanded_script;
-         GError *error = NULL;
-
-         close (fd);
-
-         expanded_script = expand_thumbnailing_script (script, size, uri, tmpname, &error);
-         if (expanded_script == NULL)
-           {
-             g_warning ("Failed to expand script '%s': %s", script, error->message);
-             g_error_free (error);
-           }
-         else
-           {
-             gboolean ret;
+      GBytes *data;
 
-             ret = g_spawn_sync (NULL, expanded_script, NULL, G_SPAWN_SEARCH_PATH,
-                                 NULL, NULL, NULL, NULL, &exit_status, NULL);
-             if (ret && exit_status == 0)
-               pixbuf = gdk_pixbuf_new_from_file (tmpname, NULL);
-
-             g_strfreev (expanded_script);
-           }
-
-         g_unlink (tmpname);
-         g_free (tmpname);
-       }
-
-      g_free (script);
+      data = gnome_desktop_thumbnail_script_exec (script, size, uri, NULL);
+      if (data)
+        {
+          pixbuf = pixbuf_new_from_bytes (data, NULL);
+          g_bytes_unref (data);
+        }
     }
 
+  g_free (script);
+
   return pixbuf;
 }
 


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