[gdk-pixbuf] windows: rework loaders cache relocation support



commit 6ef31828dd5f58491fb7a20e5258cb0c3f42b170
Author: Christoph Reiter <creiter src gnome org>
Date:   Tue Dec 13 20:43:10 2016 +0100

    windows: rework loaders cache relocation support
    
    Relocation works by recognizing paths in the loaders cache
    which start with the built time prefix and extract the relative
    path from that.
    
    This leads to the following problem when updating the cache:
    
    In case the package is build on another machine one has to
    either match the build directory layout or adjust the
    cache by hand for the resulting cache to stay relocatable.
    
    This commonly occurs with msys2 where mostly pre-build packages
    are used which are built on another machine and the cache gets
    generated at install time. Another case is updating the cache
    in a separate deployment environment.
    
    This patch takes the package installation directory as a base
    and writes relative paths into the cache when relocation
    is enabled. When loading the cache a relative path is made
    absolute by prepending the package base again.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=776081

 gdk-pixbuf/gdk-pixbuf-io.c |   43 ++++++++---------------
 gdk-pixbuf/queryloaders.c  |   79 +++++++++++++++++++++++++++++++++++++-------
 2 files changed, 82 insertions(+), 40 deletions(-)
---
diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c
index 021b4c7..75fa26a 100644
--- a/gdk-pixbuf/gdk-pixbuf-io.c
+++ b/gdk-pixbuf/gdk-pixbuf-io.c
@@ -347,34 +347,24 @@ get_libdir (void)
 #undef GDK_PIXBUF_LIBDIR
 #define GDK_PIXBUF_LIBDIR get_libdir()
 
-static void
-correct_prefix (gchar **path)
+#endif  /* GDK_PIXBUF_RELOCATABLE */
+
+/* In case we have a relative module path in the loaders cache
+ * prepend the toplevel dir */
+static gchar *
+build_module_path (const gchar *path)
 {
-  if (strncmp (*path, GDK_PIXBUF_PREFIX "/", strlen (GDK_PIXBUF_PREFIX "/")) == 0 ||
-      strncmp (*path, GDK_PIXBUF_PREFIX "\\", strlen (GDK_PIXBUF_PREFIX "\\")) == 0)
-    {
-          gchar *tem = NULL;
-      if (g_str_has_suffix (*path, ".libs"))
-        {
-          /* We are being run from inside the build tree, and shouldn't mess about. */
-          return;
+#ifdef GDK_PIXBUF_RELOCATABLE
+        if (g_path_is_absolute (path)) {
+                return g_strdup (path);
+        } else {
+                return g_build_filename (gdk_pixbuf_get_toplevel (), path, NULL);
         }
-
-      /* This is an entry put there by gdk-pixbuf-query-loaders on the
-       * packager's system. On Windows a prebuilt gdk-pixbuf package can be
-       * installed in a random location. The loaders.cache file
-       * distributed in such a package contains paths from the package
-       * builder's machine. Replace the build-time prefix with the
-       * installation prefix on this machine.
-       */
-      tem = *path;
-      *path = g_strconcat (gdk_pixbuf_get_toplevel (), tem + strlen (GDK_PIXBUF_PREFIX), NULL);
-      g_free (tem);
-    }
+#else
+        return g_strdup (path);
+#endif
 }
 
-#endif  /* GDK_PIXBUF_RELOCATABLE */
-
 static gchar *
 gdk_pixbuf_get_module_file (void)
 {
@@ -512,9 +502,6 @@ gdk_pixbuf_io_init (void)
                                 /* Blank line marking the end of a module
                                  */
                         if (module && *p != '#') {
-#ifdef GDK_PIXBUF_RELOCATABLE
-                                correct_prefix (&module->module_path);
-#endif
                                 file_formats = g_slist_prepend (file_formats, module);
                                 module = NULL;
                         }
@@ -536,7 +523,7 @@ gdk_pixbuf_io_init (void)
                                            filename, line_buf);
                                 have_error = TRUE;
                         }
-                        module->module_path = g_strdup (tmp_buf->str);
+                        module->module_path = build_module_path (tmp_buf->str);
                 }
                 else if (!module->module_name) {
                         module->info = g_new0 (GdkPixbufFormat, 1);
diff --git a/gdk-pixbuf/queryloaders.c b/gdk-pixbuf/queryloaders.c
index 2b025b8..7728caf 100644
--- a/gdk-pixbuf/queryloaders.c
+++ b/gdk-pixbuf/queryloaders.c
@@ -116,14 +116,80 @@ loader_sanity_check (const char *path, GdkPixbufFormat *info, GdkPixbufModule *v
         return 0;
 }
 
+#ifdef GDK_PIXBUF_RELOCATABLE
+
+/* Based on gdk_pixbuf_get_toplevel () */
+static gchar *
+get_toplevel (void)
+{
+        static gchar *toplevel = NULL;
+
+        if (toplevel == NULL) {
+#if defined (G_OS_WIN32)
+                toplevel = g_win32_get_package_installation_directory_of_module (NULL);
+#elif defined(OS_DARWIN)
+                char pathbuf[PATH_MAX + 1];
+                uint32_t  bufsize = sizeof (pathbuf);
+                gchar *bin_dir;
+
+                _NSGetExecutablePath (pathbuf, &bufsize);
+                bin_dir = g_dirname (pathbuf);
+                toplevel = g_build_path (G_DIR_SEPARATOR_S, bin_dir, "..", NULL);
+                g_free (bin_dir);
+#elif defined (OS_LINUX) || defined (__MINGW32__)
+                gchar *exe_path, *bin_dir;
+
+                exe_path = g_file_read_link ("/proc/self/exe", NULL);
+                bin_dir = g_dirname (exe_path);
+                toplevel = g_build_path (G_DIR_SEPARATOR_S, bin_dir, "..", NULL);
+                g_free (exe_path);
+                g_free (bin_dir);
+#else
+#error "Relocations not supported for this platform"
+#endif
+        }
+        return toplevel;
+}
+
+/* Returns the relative path or NULL; transfer full */
+static gchar *
+get_relative_path (const gchar *parent, const gchar *descendant)
+{
+        GFile *parent_file, *descendant_file;
+        char *relative_path;
+
+        parent_file = g_file_new_for_path (parent);
+        descendant_file = g_file_new_for_path (descendant);
+        relative_path = g_file_get_relative_path (parent_file, descendant_file);
+        g_object_unref (parent_file);
+        g_object_unref (descendant_file);
+
+        return relative_path;
+}
+
+#endif  /* GDK_PIXBUF_RELOCATABLE */
+
 static void
 write_loader_info (GString *contents, const char *path, GdkPixbufFormat *info)
 {
         const GdkPixbufModulePattern *pattern;
         char **mime;
         char **ext;
+        gchar *module_path = NULL, *escaped_path;
+
+#ifdef GDK_PIXBUF_RELOCATABLE
+        module_path = get_relative_path (get_toplevel (), path);
+#endif
+
+        if (module_path == NULL) {
+                module_path = g_strdup (path);
+        }
+
+        escaped_path = g_strescape (module_path, "");
+        g_string_append_printf (contents, "\"%s\"\n", escaped_path);
+        g_free (module_path);
+        g_free (escaped_path);
 
-        g_string_append_printf (contents, "\"%s\"\n", path);
         g_string_append_printf (contents, "\"%s\" %u \"%s\" \"%s\" \"%s\"\n",
                   info->name,
                   info->flags,
@@ -213,17 +279,6 @@ query_module (GString *contents, const char *dir, const char *file)
 #ifdef G_OS_WIN32
 
 static char *
-get_toplevel (void)
-{
-  static char *toplevel = NULL;
-
-  if (toplevel == NULL)
-          toplevel = g_win32_get_package_installation_directory_of_module (NULL);
-
-  return toplevel;
-}
-
-static char *
 get_libdir (void)
 {
   static char *libdir = NULL;


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