baseparse: support reverse playback
[platform/upstream/gstreamer.git] / gst / gstregistrybinary.c
index 5bbb824..1a58837 100644 (file)
@@ -61,6 +61,7 @@
 #include <gst/gstenumtypes.h>
 #include <gst/gstpadtemplate.h>
 
+#include <gst/gstregistrychunks.h>
 #include <gst/gstregistrybinary.h>
 
 #include <glib/gstdio.h>        /* for g_stat(), g_mapped_file(), ... */
 
 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
 
-/* count string length, but return -1 if we hit the eof */
-static gint
-_strnlen (const gchar * str, gint maxlen)
-{
-  gint len = 0;
-
-  if (len == maxlen)
-    return -1;
-
-  while (*str++ != '\0') {
-    len++;
-    if (len == maxlen)
-      return -1;
-  }
-  return len;
-}
-
 /* reading macros */
-
 #define unpack_element(inptr, outptr, element, endptr, error_label) G_STMT_START{ \
   if (inptr + sizeof(element) >= endptr) \
     goto error_label; \
@@ -96,22 +79,6 @@ _strnlen (const gchar * str, gint maxlen)
   inptr += sizeof (element); \
 }G_STMT_END
 
-#define unpack_const_string(inptr, outptr, endptr, error_label) G_STMT_START{\
-  gint _len = _strnlen (inptr, (endptr-inptr)) + 1; \
-  if (_len == -1) \
-    goto error_label; \
-  outptr = g_intern_string ((const gchar *)inptr); \
-  inptr += _len; \
-}G_STMT_END
-
-#define unpack_string(inptr, outptr, endptr, error_label)  G_STMT_START{\
-  gint _len = _strnlen (inptr, (endptr-inptr)) + 1; \
-  if (_len == -1) \
-    goto error_label; \
-  outptr = g_memdup ((gconstpointer)inptr, _len); \
-  inptr += _len; \
-}G_STMT_END
-
 #define ALIGNMENT            (sizeof (void *))
 #define alignment(_address)  (gsize)_address%ALIGNMENT
 #define align(_ptr)          _ptr += (( alignment(_ptr) == 0) ? 0 : ALIGNMENT-alignment(_ptr))
@@ -134,15 +101,14 @@ typedef struct BinaryRegistryCache
 static BinaryRegistryCache *
 gst_registry_binary_cache_init (GstRegistry * registry, const char *location)
 {
-  BinaryRegistryCache *cache = g_new0 (BinaryRegistryCache, 1);
+  BinaryRegistryCache *cache = g_slice_new0 (BinaryRegistryCache);
   cache->location = location;
   return cache;
 }
 
 static int
-gst_registry_binary_cache_write (GstRegistry * registry,
-    BinaryRegistryCache * cache, unsigned long offset,
-    const void *data, int length)
+gst_registry_binary_cache_write (BinaryRegistryCache * cache,
+    unsigned long offset, const void *data, int length)
 {
   cache->len = MAX (offset + length, cache->len);
   cache->mem = g_realloc (cache->mem, cache->len);
@@ -153,8 +119,7 @@ gst_registry_binary_cache_write (GstRegistry * registry,
 }
 
 static gboolean
-gst_registry_binary_cache_finish (GstRegistry * registry,
-    BinaryRegistryCache * cache, gboolean success)
+gst_registry_binary_cache_finish (BinaryRegistryCache * cache, gboolean success)
 {
   gboolean ret = TRUE;
   GError *error = NULL;
@@ -171,14 +136,26 @@ gst_registry_binary_cache_finish (GstRegistry * registry,
 
     if (!g_file_set_contents (cache->location, (const gchar *) cache->mem,
             cache->len, &error)) {
-      GST_ERROR ("Failed to write to cache file: %s", error->message);
+      /* Probably the directory didn't exist; create it */
+      gchar *dir;
+      dir = g_path_get_dirname (cache->location);
+      g_mkdir_with_parents (dir, 0777);
+      g_free (dir);
+
       g_error_free (error);
-      ret = FALSE;
+      error = NULL;
+
+      if (!g_file_set_contents (cache->location, (const gchar *) cache->mem,
+              cache->len, &error)) {
+        GST_ERROR ("Failed to write to cache file: %s", error->message);
+        g_error_free (error);
+        ret = FALSE;
+      }
     }
   }
 
   g_free (cache->mem);
-  g_free (cache);
+  g_slice_free (BinaryRegistryCache, cache);
   return ret;
 }
 
@@ -188,55 +165,68 @@ typedef struct BinaryRegistryCache
   const char *location;
   char *tmp_location;
   unsigned long currentoffset;
+  int cache_fd;
 } BinaryRegistryCache;
 
 static BinaryRegistryCache *
 gst_registry_binary_cache_init (GstRegistry * registry, const char *location)
 {
-  BinaryRegistryCache *cache = g_new0 (BinaryRegistryCache, 1);
+  BinaryRegistryCache *cache = g_slice_new0 (BinaryRegistryCache);
 
   cache->location = location;
   cache->tmp_location = g_strconcat (location, ".tmpXXXXXX", NULL);
-  registry->cache_file = g_mkstemp (cache->tmp_location);
-  if (registry->cache_file == -1) {
+  cache->cache_fd = g_mkstemp (cache->tmp_location);
+  if (cache->cache_fd == -1) {
+    int ret;
+    GStatBuf statbuf;
     gchar *dir;
 
     /* oops, I bet the directory doesn't exist */
     dir = g_path_get_dirname (location);
     g_mkdir_with_parents (dir, 0777);
+
+    ret = g_stat (dir, &statbuf);
+    if (ret != -1 && (statbuf.st_mode & 0700) != 0700) {
+      g_chmod (dir, 0700);
+    }
+
     g_free (dir);
 
     /* the previous g_mkstemp call overwrote the XXXXXX placeholder ... */
     g_free (cache->tmp_location);
     cache->tmp_location = g_strconcat (location, ".tmpXXXXXX", NULL);
-    registry->cache_file = g_mkstemp (cache->tmp_location);
+    cache->cache_fd = g_mkstemp (cache->tmp_location);
 
-    if (registry->cache_file == -1) {
+    if (cache->cache_fd == -1) {
       GST_DEBUG ("g_mkstemp() failed: %s", g_strerror (errno));
       g_free (cache->tmp_location);
-      g_free (cache);
+      g_slice_free (BinaryRegistryCache, cache);
       return NULL;
     }
+
+    ret = g_stat (cache->tmp_location, &statbuf);
+    if (ret != -1 && (statbuf.st_mode & 0600) != 0600) {
+      g_chmod (cache->tmp_location, 0600);
+    }
   }
 
   return cache;
 }
 
 static int
-gst_registry_binary_cache_write (GstRegistry * registry,
-    BinaryRegistryCache * cache, unsigned long offset,
-    const void *data, int length)
+gst_registry_binary_cache_write (BinaryRegistryCache * cache,
+    unsigned long offset, const void *data, int length)
 {
   long written;
   if (offset != cache->currentoffset) {
-    if (lseek (registry->cache_file, offset, SEEK_SET) != 0) {
+    if (lseek (cache->cache_fd, offset, SEEK_SET) != 0) {
       GST_ERROR ("Seeking to new offset failed");
       return FALSE;
     }
     cache->currentoffset = offset;
   }
 
-  written = write (registry->cache_file, data, length);
+  written = write (cache->cache_fd, data, length);
   if (written != length) {
     GST_ERROR ("Failed to write to cache file");
   }
@@ -246,24 +236,25 @@ gst_registry_binary_cache_write (GstRegistry * registry,
 }
 
 static gboolean
-gst_registry_binary_cache_finish (GstRegistry * registry,
-    BinaryRegistryCache * cache, gboolean success)
+gst_registry_binary_cache_finish (BinaryRegistryCache * cache, gboolean success)
 {
   /* only fsync if we're actually going to use and rename the file below */
-  if (success && fsync (registry->cache_file) < 0)
+  if (success && fsync (cache->cache_fd) < 0)
     goto fsync_failed;
 
-  if (close (registry->cache_file) < 0)
+  if (close (cache->cache_fd) < 0)
     goto close_failed;
 
   if (success) {
     /* Only do the rename if we wrote the entire file successfully */
-    if (g_rename (cache->tmp_location, cache->location) < 0)
+    if (g_rename (cache->tmp_location, cache->location) < 0) {
+      GST_ERROR ("g_rename() failed: %s", g_strerror (errno));
       goto rename_failed;
+    }
   }
 
   g_free (cache->tmp_location);
-  g_free (cache);
+  g_slice_free (BinaryRegistryCache, cache);
   GST_INFO ("Wrote binary registry cache");
   return TRUE;
 
@@ -272,7 +263,7 @@ fail_after_close:
   {
     g_unlink (cache->tmp_location);
     g_free (cache->tmp_location);
-    g_free (cache);
+    g_slice_free (BinaryRegistryCache, cache);
     return FALSE;
   }
 fsync_failed:
@@ -301,17 +292,16 @@ rename_failed:
  * Returns: %TRUE for success
  */
 inline static gboolean
-gst_registry_binary_write_chunk (GstRegistry * registry,
-    BinaryRegistryCache * cache, const void *mem,
-    const gssize size, unsigned long *file_position, gboolean align)
+gst_registry_binary_write_chunk (BinaryRegistryCache * cache,
+    GstRegistryChunk * chunk, unsigned long *file_position)
 {
   gchar padder[ALIGNMENT] = { 0, };
   int padsize = 0;
 
   /* Padding to insert the struct that requiere word alignment */
-  if ((align) && (alignment (*file_position) != 0)) {
+  if ((chunk->align) && (alignment (*file_position) != 0)) {
     padsize = ALIGNMENT - alignment (*file_position);
-    if (gst_registry_binary_cache_write (registry, cache, *file_position,
+    if (gst_registry_binary_cache_write (cache, *file_position,
             padder, padsize) != padsize) {
       GST_ERROR ("Failed to write binary registry padder");
       return FALSE;
@@ -319,13 +309,13 @@ gst_registry_binary_write_chunk (GstRegistry * registry,
     *file_position += padsize;
   }
 
-  if (gst_registry_binary_cache_write (registry, cache, *file_position,
-          mem, size) != size) {
+  if (gst_registry_binary_cache_write (cache, *file_position,
+          chunk->data, chunk->size) != chunk->size) {
     GST_ERROR ("Failed to write binary registry element");
     return FALSE;
   }
 
-  *file_position += size;
+  *file_position += chunk->size;
 
   return TRUE;
 }
@@ -353,358 +343,13 @@ gst_registry_binary_initialize_magic (GstBinaryRegistryMagic * m)
   return TRUE;
 }
 
-
-/*
- * gst_registry_binary_save_const_string:
- *
- * Store a const string in a binary chunk.
- *
- * Returns: %TRUE for success
- */
-inline static gboolean
-gst_registry_binary_save_const_string (GList ** list, const gchar * str)
-{
-  GstBinaryChunk *chunk;
-
-  if (G_UNLIKELY (str == NULL)) {
-    GST_ERROR ("unexpected NULL string in plugin or plugin feature data");
-    str = "";
-  }
-
-  chunk = g_malloc (sizeof (GstBinaryChunk));
-  chunk->data = (gpointer) str;
-  chunk->size = strlen ((gchar *) chunk->data) + 1;
-  chunk->flags = GST_BINARY_REGISTRY_FLAG_CONST;
-  chunk->align = FALSE;
-  *list = g_list_prepend (*list, chunk);
-  return TRUE;
-}
-
-/*
- * gst_registry_binary_save_string:
- *
- * Store a string in a binary chunk.
- *
- * Returns: %TRUE for success
- */
-inline static gboolean
-gst_registry_binary_save_string (GList ** list, gchar * str)
-{
-  GstBinaryChunk *chunk;
-
-  chunk = g_malloc (sizeof (GstBinaryChunk));
-  chunk->data = str;
-  chunk->size = strlen ((gchar *) chunk->data) + 1;
-  chunk->flags = GST_BINARY_REGISTRY_FLAG_NONE;
-  chunk->align = FALSE;
-  *list = g_list_prepend (*list, chunk);
-  return TRUE;
-}
-
-
-/*
- * gst_registry_binary_save_data:
- *
- * Store some data in a binary chunk.
- *
- * Returns: the initialized chunk
- */
-inline static GstBinaryChunk *
-gst_registry_binary_make_data (gpointer data, gulong size)
-{
-  GstBinaryChunk *chunk;
-
-  chunk = g_malloc (sizeof (GstBinaryChunk));
-  chunk->data = data;
-  chunk->size = size;
-  chunk->flags = GST_BINARY_REGISTRY_FLAG_NONE;
-  chunk->align = TRUE;
-  return chunk;
-}
-
-
-/*
- * gst_registry_binary_save_pad_template:
- *
- * Store pad_templates in binary chunks.
- *
- * Returns: %TRUE for success
- */
-static gboolean
-gst_registry_binary_save_pad_template (GList ** list,
-    GstStaticPadTemplate * template)
-{
-  GstBinaryPadTemplate *pt;
-  GstBinaryChunk *chk;
-
-  pt = g_malloc0 (sizeof (GstBinaryPadTemplate));
-  chk = gst_registry_binary_make_data (pt, sizeof (GstBinaryPadTemplate));
-
-  pt->presence = template->presence;
-  pt->direction = template->direction;
-
-  /* pack pad template strings */
-  gst_registry_binary_save_const_string (list,
-      (gchar *) (template->static_caps.string));
-  gst_registry_binary_save_const_string (list, template->name_template);
-
-  *list = g_list_prepend (*list, chk);
-
-  return TRUE;
-}
-
-
-/*
- * gst_registry_binary_save_feature:
- *
- * Store features in binary chunks.
- *
- * Returns: %TRUE for success
- */
-static gboolean
-gst_registry_binary_save_feature (GList ** list, GstPluginFeature * feature)
-{
-  const gchar *type_name = g_type_name (G_OBJECT_TYPE (feature));
-  GstBinaryPluginFeature *pf = NULL;
-  GstBinaryChunk *chk = NULL;
-  GList *walk;
-
-  if (!type_name) {
-    GST_ERROR ("NULL feature type_name, aborting.");
-    return FALSE;
-  }
-
-  if (GST_IS_ELEMENT_FACTORY (feature)) {
-    GstBinaryElementFactory *ef;
-    GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
-
-    ef = g_malloc0 (sizeof (GstBinaryElementFactory));
-    chk = gst_registry_binary_make_data (ef, sizeof (GstBinaryElementFactory));
-    ef->npadtemplates = ef->ninterfaces = ef->nuriprotocols = 0;
-    pf = (GstBinaryPluginFeature *) ef;
-
-    /* save interfaces */
-    for (walk = factory->interfaces; walk;
-        walk = g_list_next (walk), ef->ninterfaces++) {
-      gst_registry_binary_save_const_string (list, (gchar *) walk->data);
-    }
-    GST_DEBUG ("Saved %d Interfaces", ef->ninterfaces);
-    /* save uritypes */
-    if (GST_URI_TYPE_IS_VALID (factory->uri_type)) {
-      if (factory->uri_protocols && *factory->uri_protocols) {
-        GstBinaryChunk *subchk;
-        gchar **protocol;
-
-        subchk =
-            gst_registry_binary_make_data (&factory->uri_type,
-            sizeof (factory->uri_type));
-        subchk->flags = GST_BINARY_REGISTRY_FLAG_CONST;
-
-        protocol = factory->uri_protocols;
-        while (*protocol) {
-          gst_registry_binary_save_const_string (list, *protocol++);
-          ef->nuriprotocols++;
-        }
-        *list = g_list_prepend (*list, subchk);
-        GST_DEBUG ("Saved %d UriTypes", ef->nuriprotocols);
-      } else {
-        g_warning ("GStreamer feature '%s' is URI handler but does not provide"
-            " any protocols it can handle", feature->name);
-      }
-    }
-
-    /* save pad-templates */
-    for (walk = factory->staticpadtemplates; walk;
-        walk = g_list_next (walk), ef->npadtemplates++) {
-      GstStaticPadTemplate *template = walk->data;
-
-      if (!gst_registry_binary_save_pad_template (list, template)) {
-        GST_ERROR ("Can't fill pad template, aborting.");
-        goto fail;
-      }
-    }
-
-    /* pack element factory strings */
-    gst_registry_binary_save_const_string (list, factory->details.author);
-    gst_registry_binary_save_const_string (list, factory->details.description);
-    gst_registry_binary_save_const_string (list, factory->details.klass);
-    gst_registry_binary_save_const_string (list, factory->details.longname);
-  } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
-    GstBinaryTypeFindFactory *tff;
-    GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
-
-    tff = g_malloc0 (sizeof (GstBinaryTypeFindFactory));
-    chk =
-        gst_registry_binary_make_data (tff, sizeof (GstBinaryTypeFindFactory));
-    tff->nextensions = 0;
-    pf = (GstBinaryPluginFeature *) tff;
-
-    /* save extensions */
-    if (factory->extensions) {
-      while (factory->extensions[tff->nextensions]) {
-        gst_registry_binary_save_const_string (list,
-            factory->extensions[tff->nextensions++]);
-      }
-    }
-    /* save caps */
-    if (factory->caps) {
-      GstCaps *copy = gst_caps_copy (factory->caps);
-      gchar *str;
-
-      /* we copy the caps here so we can simplify them
-       * before saving. This is a lot faster when loading
-       * them later on */
-      gst_caps_do_simplify (copy);
-      str = gst_caps_to_string (copy);
-      gst_caps_unref (copy);
-      gst_registry_binary_save_string (list, str);
-    } else {
-      gst_registry_binary_save_const_string (list, "");
-    }
-
-  } else if (GST_IS_INDEX_FACTORY (feature)) {
-    GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
-
-    pf = g_malloc0 (sizeof (GstBinaryPluginFeature));
-    chk = gst_registry_binary_make_data (pf, sizeof (GstBinaryPluginFeature));
-    pf->rank = feature->rank;
-
-    /* pack element factory strings */
-    gst_registry_binary_save_const_string (list, factory->longdesc);
-  } else {
-    GST_WARNING ("unhandled feature type '%s'", type_name);
-  }
-
-  if (pf) {
-    pf->rank = feature->rank;
-    *list = g_list_prepend (*list, chk);
-
-    /* pack plugin feature strings */
-    gst_registry_binary_save_const_string (list, feature->name);
-    gst_registry_binary_save_const_string (list, (gchar *) type_name);
-
-    return TRUE;
-  }
-
-  /* Errors */
-fail:
-  g_free (chk);
-  g_free (pf);
-  return FALSE;
-}
-
-static gboolean
-gst_registry_binary_save_plugin_dep (GList ** list, GstPluginDep * dep)
-{
-  GstBinaryDep *ed;
-  GstBinaryChunk *chk;
-  gchar **s;
-
-  ed = g_new0 (GstBinaryDep, 1);
-  chk = gst_registry_binary_make_data (ed, sizeof (GstBinaryDep));
-
-  ed->flags = dep->flags;
-  ed->n_env_vars = 0;
-  ed->n_paths = 0;
-  ed->n_names = 0;
-
-  ed->env_hash = dep->env_hash;
-  ed->stat_hash = dep->stat_hash;
-
-  for (s = dep->env_vars; s != NULL && *s != NULL; ++s, ++ed->n_env_vars)
-    gst_registry_binary_save_string (list, g_strdup (*s));
-
-  for (s = dep->paths; s != NULL && *s != NULL; ++s, ++ed->n_paths)
-    gst_registry_binary_save_string (list, g_strdup (*s));
-
-  for (s = dep->names; s != NULL && *s != NULL; ++s, ++ed->n_names)
-    gst_registry_binary_save_string (list, g_strdup (*s));
-
-  *list = g_list_prepend (*list, chk);
-
-  GST_LOG ("Saved external plugin dependency");
-  return TRUE;
-}
-
-/*
- * gst_registry_binary_save_plugin:
- *
- * Adapt a GstPlugin to our GstBinaryPluginElement structure, and write it to
- * the registry file.
- */
-static gboolean
-gst_registry_binary_save_plugin (GList ** list, GstRegistry * registry,
-    GstPlugin * plugin)
-{
-  GstBinaryPluginElement *pe;
-  GstBinaryChunk *chk;
-  GList *plugin_features = NULL;
-  GList *walk;
-
-  pe = g_malloc0 (sizeof (GstBinaryPluginElement));
-  chk = gst_registry_binary_make_data (pe, sizeof (GstBinaryPluginElement));
-
-  pe->file_size = plugin->file_size;
-  pe->file_mtime = plugin->file_mtime;
-  pe->n_deps = 0;
-  pe->nfeatures = 0;
-
-  /* pack external deps */
-  for (walk = plugin->priv->deps; walk != NULL; walk = walk->next) {
-    if (!gst_registry_binary_save_plugin_dep (list, walk->data)) {
-      GST_ERROR ("Could not save external plugin dependency, aborting.");
-      goto fail;
-    }
-    ++pe->n_deps;
-  }
-
-  /* pack plugin features */
-  plugin_features =
-      gst_registry_get_feature_list_by_plugin (registry, plugin->desc.name);
-  for (walk = plugin_features; walk; walk = g_list_next (walk), pe->nfeatures++) {
-    GstPluginFeature *feature = GST_PLUGIN_FEATURE (walk->data);
-
-    if (!gst_registry_binary_save_feature (list, feature)) {
-      GST_ERROR ("Can't fill plugin feature, aborting.");
-      goto fail;
-    }
-  }
-  GST_DEBUG ("Save plugin '%s' with %d feature(s)", plugin->desc.name,
-      pe->nfeatures);
-
-  gst_plugin_feature_list_free (plugin_features);
-
-  /* pack plugin element strings */
-  gst_registry_binary_save_const_string (list, plugin->desc.origin);
-  gst_registry_binary_save_const_string (list, plugin->desc.package);
-  gst_registry_binary_save_const_string (list, plugin->desc.source);
-  gst_registry_binary_save_const_string (list, plugin->desc.license);
-  gst_registry_binary_save_const_string (list, plugin->desc.version);
-  gst_registry_binary_save_const_string (list, plugin->filename);
-  gst_registry_binary_save_const_string (list, plugin->desc.description);
-  gst_registry_binary_save_const_string (list, plugin->desc.name);
-
-  *list = g_list_prepend (*list, chk);
-
-  GST_DEBUG ("Found %d features in plugin \"%s\"", pe->nfeatures,
-      plugin->desc.name);
-  return TRUE;
-
-  /* Errors */
-fail:
-  gst_plugin_feature_list_free (plugin_features);
-  g_free (chk);
-  g_free (pe);
-  return FALSE;
-}
-
 /**
  * gst_registry_binary_write_cache:
  * @registry: a #GstRegistry
  * @location: a filename
  *
  * Write the @registry to a cache to file at given @location.
- * 
+ *
  * Returns: %TRUE on success.
  */
 gboolean
@@ -731,7 +376,7 @@ gst_registry_binary_write_cache (GstRegistry * registry, const char *location)
       continue;
 
     if (plugin->flags & GST_PLUGIN_FLAG_CACHED) {
-      struct stat statbuf;
+      GStatBuf statbuf;
 
       if (g_stat (plugin->filename, &statbuf) < 0 ||
           plugin->file_mtime != statbuf.st_mtime ||
@@ -739,12 +384,15 @@ gst_registry_binary_write_cache (GstRegistry * registry, const char *location)
         continue;
     }
 
-    if (!gst_registry_binary_save_plugin (&to_write, registry, plugin)) {
+    if (!_priv_gst_registry_chunks_save_plugin (&to_write, registry, plugin)) {
       GST_ERROR ("Can't write binary plugin information for \"%s\"",
           plugin->filename);
     }
   }
 
+  _priv_gst_registry_chunks_save_global_header (&to_write, registry,
+      priv_gst_plugin_loading_get_whitelist_hash ());
+
   GST_INFO ("Writing binary registry cache");
 
   cache = gst_registry_binary_cache_init (registry, location);
@@ -752,7 +400,7 @@ gst_registry_binary_write_cache (GstRegistry * registry, const char *location)
     goto fail_free_list;
 
   /* write magic */
-  if (gst_registry_binary_cache_write (registry, cache, file_position,
+  if (gst_registry_binary_cache_write (cache, file_position,
           &magic, sizeof (GstBinaryRegistryMagic)) !=
       sizeof (GstBinaryRegistryMagic)) {
     GST_ERROR ("Failed to write binary registry magic");
@@ -762,24 +410,19 @@ gst_registry_binary_write_cache (GstRegistry * registry, const char *location)
 
   /* write out data chunks */
   for (walk = to_write; walk; walk = g_list_next (walk)) {
-    GstBinaryChunk *cur = walk->data;
-
-    if (!gst_registry_binary_write_chunk (registry, cache, cur->data, cur->size,
-            &file_position, cur->align)) {
-      if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
-        g_free (cur->data);
-      g_free (cur);
-      walk->data = NULL;
-      goto fail_free_list;
-    }
-    if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
-      g_free (cur->data);
-    g_free (cur);
+    GstRegistryChunk *cur = walk->data;
+    gboolean res;
+
+    res = gst_registry_binary_write_chunk (cache, cur, &file_position);
+
+    _priv_gst_registry_chunk_free (cur);
     walk->data = NULL;
+    if (!res)
+      goto fail_free_list;
   }
   g_list_free (to_write);
 
-  if (!gst_registry_binary_cache_finish (registry, cache, TRUE))
+  if (!gst_registry_binary_cache_finish (cache, TRUE))
     return FALSE;
 
   return TRUE;
@@ -788,16 +431,15 @@ gst_registry_binary_write_cache (GstRegistry * registry, const char *location)
 fail_free_list:
   {
     for (walk = to_write; walk; walk = g_list_next (walk)) {
-      GstBinaryChunk *cur = walk->data;
+      GstRegistryChunk *cur = walk->data;
 
-      if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
-        g_free (cur->data);
-      g_free (cur);
+      if (cur)
+        _priv_gst_registry_chunk_free (cur);
     }
     g_list_free (to_write);
 
     if (cache)
-      (void) gst_registry_binary_cache_finish (registry, cache, FALSE);
+      (void) gst_registry_binary_cache_finish (cache, FALSE);
     /* fall through */
   }
 fail:
@@ -851,336 +493,6 @@ fail:
   return -1;
 }
 
-
-/*
- * gst_registry_binary_load_pad_template:
- *
- * Make a new GstStaticPadTemplate from current GstBinaryPadTemplate structure
- *
- * Returns: new GstStaticPadTemplate
- */
-static gboolean
-gst_registry_binary_load_pad_template (GstElementFactory * factory, gchar ** in,
-    gchar * end)
-{
-  GstBinaryPadTemplate *pt;
-  GstStaticPadTemplate *template;
-
-  align (*in);
-  GST_DEBUG ("Reading/casting for GstBinaryPadTemplate at address %p", *in);
-  unpack_element (*in, pt, GstBinaryPadTemplate, end, fail);
-
-  template = g_new0 (GstStaticPadTemplate, 1);
-  template->presence = pt->presence;
-  template->direction = pt->direction;
-
-  /* unpack pad template strings */
-  unpack_const_string (*in, template->name_template, end, fail);
-  unpack_string (*in, template->static_caps.string, end, fail);
-
-  __gst_element_factory_add_static_pad_template (factory, template);
-  GST_DEBUG ("Added pad_template %s", template->name_template);
-
-  return TRUE;
-
-fail:
-  GST_INFO ("Reading pad template failed");
-  return FALSE;
-}
-
-
-/*
- * gst_registry_binary_load_feature:
- *
- * Make a new GstPluginFeature from current binary plugin feature structure
- *
- * Returns: new GstPluginFeature
- */
-static gboolean
-gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
-    gchar * end, const gchar * plugin_name)
-{
-  GstBinaryPluginFeature *pf = NULL;
-  GstPluginFeature *feature = NULL;
-  gchar *type_name = NULL, *str;
-  GType type;
-  guint i;
-
-  /* unpack plugin feature strings */
-  unpack_string (*in, type_name, end, fail);
-
-  if (!type_name) {
-    GST_ERROR ("No feature type name");
-    return FALSE;
-  }
-
-  GST_DEBUG ("Plugin '%s' feature typename : '%s'", plugin_name, type_name);
-
-  if (!(type = g_type_from_name (type_name))) {
-    GST_ERROR ("Unknown type from typename '%s' for plugin '%s'", type_name,
-        plugin_name);
-    g_free (type_name);
-    return FALSE;
-  }
-  if ((feature = g_object_new (type, NULL)) == NULL) {
-    GST_ERROR ("Can't create feature from type");
-    g_free (type_name);
-    return FALSE;
-  }
-
-  if (!GST_IS_PLUGIN_FEATURE (feature)) {
-    GST_ERROR ("typename : '%s' is not a plugin feature", type_name);
-    goto fail;
-  }
-
-  /* unpack more plugin feature strings */
-  unpack_string (*in, feature->name, end, fail);
-
-  if (GST_IS_ELEMENT_FACTORY (feature)) {
-    GstBinaryElementFactory *ef;
-    GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
-
-    align (*in);
-    GST_LOG ("Reading/casting for GstBinaryElementFactory at address %p", *in);
-    unpack_element (*in, ef, GstBinaryElementFactory, end, fail);
-    pf = (GstBinaryPluginFeature *) ef;
-
-    /* unpack element factory strings */
-    unpack_string (*in, factory->details.longname, end, fail);
-    unpack_string (*in, factory->details.klass, end, fail);
-    unpack_string (*in, factory->details.description, end, fail);
-    unpack_string (*in, factory->details.author, end, fail);
-    GST_DEBUG ("Element factory : '%s' with npadtemplates=%d",
-        factory->details.longname, ef->npadtemplates);
-
-    /* load pad templates */
-    for (i = 0; i < ef->npadtemplates; i++) {
-      if (!gst_registry_binary_load_pad_template (factory, in, end)) {
-        GST_ERROR ("Error while loading binary pad template");
-        goto fail;
-      }
-    }
-
-    /* load uritypes */
-    if (ef->nuriprotocols) {
-      GST_DEBUG ("Reading %d UriTypes at address %p", ef->nuriprotocols, *in);
-
-      align (*in);
-      factory->uri_type = *((guint *) * in);
-      *in += sizeof (factory->uri_type);
-      /*unpack_element(*in, &factory->uri_type, factory->uri_type, end, fail); */
-
-      factory->uri_protocols = g_new0 (gchar *, ef->nuriprotocols + 1);
-      for (i = 0; i < ef->nuriprotocols; i++) {
-        unpack_string (*in, str, end, fail);
-        factory->uri_protocols[i] = str;
-      }
-    }
-    /* load interfaces */
-    GST_DEBUG ("Reading %d Interfaces at address %p", ef->ninterfaces, *in);
-    for (i = 0; i < ef->ninterfaces; i++) {
-      unpack_string (*in, str, end, fail);
-      __gst_element_factory_add_interface (factory, str);
-      g_free (str);
-    }
-  } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
-    GstBinaryTypeFindFactory *tff;
-    GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
-
-    align (*in);
-    GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
-    unpack_element (*in, tff, GstBinaryTypeFindFactory, end, fail);
-    pf = (GstBinaryPluginFeature *) tff;
-
-    /* load caps */
-    unpack_string (*in, str, end, fail);
-    factory->caps = (str && *str) ? gst_caps_from_string (str) : NULL;
-    g_free (str);
-    /* load extensions */
-    if (tff->nextensions) {
-      GST_DEBUG ("Reading %d Typefind extensions at address %p",
-          tff->nextensions, *in);
-      factory->extensions = g_new0 (gchar *, tff->nextensions + 1);
-      for (i = 0; i < tff->nextensions; i++) {
-        unpack_string (*in, str, end, fail);
-        factory->extensions[i] = str;
-      }
-    }
-  } else if (GST_IS_INDEX_FACTORY (feature)) {
-    GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
-
-    align (*in);
-    GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
-    unpack_element (*in, pf, GstBinaryPluginFeature, end, fail);
-
-    /* unpack index factory strings */
-    unpack_string (*in, factory->longdesc, end, fail);
-  } else {
-    GST_WARNING ("unhandled factory type : %s", G_OBJECT_TYPE_NAME (feature));
-    goto fail;
-  }
-
-  feature->rank = pf->rank;
-
-  /* should already be the interned string, but better make sure */
-  feature->plugin_name = g_intern_string (plugin_name);
-
-  gst_registry_add_feature (registry, feature);
-  GST_DEBUG ("Added feature %s", feature->name);
-
-  g_free (type_name);
-  return TRUE;
-
-  /* Errors */
-fail:
-  GST_INFO ("Reading plugin feature failed");
-  g_free (type_name);
-  if (GST_IS_OBJECT (feature))
-    gst_object_unref (feature);
-  else
-    g_object_unref (feature);
-  return FALSE;
-}
-
-static gchar **
-gst_registry_binary_load_plugin_dep_strv (gchar ** in, gchar * end, guint n)
-{
-  gchar **arr;
-
-  if (n == 0)
-    return NULL;
-
-  arr = g_new0 (gchar *, n + 1);
-  while (n > 0) {
-    unpack_string (*in, arr[n - 1], end, fail);
-    --n;
-  }
-  return arr;
-fail:
-  GST_INFO ("Reading plugin dependency strings failed");
-  return NULL;
-}
-
-static gboolean
-gst_registry_binary_load_plugin_dep (GstPlugin * plugin, gchar ** in,
-    gchar * end)
-{
-  GstPluginDep *dep;
-  GstBinaryDep *d;
-  gchar **s;
-
-  align (*in);
-  GST_LOG_OBJECT (plugin, "Unpacking GstBinaryDep from %p", *in);
-  unpack_element (*in, d, GstBinaryDep, end, fail);
-
-  dep = g_new0 (GstPluginDep, 1);
-
-  dep->env_hash = d->env_hash;
-  dep->stat_hash = d->stat_hash;
-
-  dep->flags = d->flags;
-
-  dep->names = gst_registry_binary_load_plugin_dep_strv (in, end, d->n_names);
-  dep->paths = gst_registry_binary_load_plugin_dep_strv (in, end, d->n_paths);
-  dep->env_vars =
-      gst_registry_binary_load_plugin_dep_strv (in, end, d->n_env_vars);
-
-  plugin->priv->deps = g_list_append (plugin->priv->deps, dep);
-
-  GST_DEBUG_OBJECT (plugin, "Loaded external plugin dependency from registry: "
-      "env_hash: %08x, stat_hash: %08x", dep->env_hash, dep->stat_hash);
-  for (s = dep->env_vars; s != NULL && *s != NULL; ++s)
-    GST_LOG_OBJECT (plugin, " evar: %s", *s);
-  for (s = dep->paths; s != NULL && *s != NULL; ++s)
-    GST_LOG_OBJECT (plugin, " path: %s", *s);
-  for (s = dep->names; s != NULL && *s != NULL; ++s)
-    GST_LOG_OBJECT (plugin, " name: %s", *s);
-
-  return TRUE;
-fail:
-  GST_INFO ("Reading plugin dependency failed");
-  return FALSE;
-}
-
-/*
- * gst_registry_binary_load_plugin:
- *
- * Make a new GstPlugin from current GstBinaryPluginElement structure
- * and save it to the GstRegistry. Return an offset to the next
- * GstBinaryPluginElement structure.
- */
-static gboolean
-gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in,
-    gchar * end)
-{
-  GstBinaryPluginElement *pe;
-  GstPlugin *plugin = NULL;
-  guint i;
-
-  align (*in);
-  GST_LOG ("Reading/casting for GstBinaryPluginElement at address %p", *in);
-  unpack_element (*in, pe, GstBinaryPluginElement, end, fail);
-
-  plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
-
-  /* TODO: also set GST_PLUGIN_FLAG_CONST */
-  plugin->flags |= GST_PLUGIN_FLAG_CACHED;
-  plugin->file_mtime = pe->file_mtime;
-  plugin->file_size = pe->file_size;
-
-  /* unpack plugin element strings */
-  unpack_const_string (*in, plugin->desc.name, end, fail);
-  unpack_string (*in, plugin->desc.description, end, fail);
-  unpack_string (*in, plugin->filename, end, fail);
-  unpack_const_string (*in, plugin->desc.version, end, fail);
-  unpack_const_string (*in, plugin->desc.license, end, fail);
-  unpack_const_string (*in, plugin->desc.source, end, fail);
-  unpack_const_string (*in, plugin->desc.package, end, fail);
-  unpack_const_string (*in, plugin->desc.origin, end, fail);
-  GST_LOG ("read strings for name='%s'", plugin->desc.name);
-  GST_LOG ("  desc.description='%s'", plugin->desc.description);
-  GST_LOG ("  filename='%s'", plugin->filename);
-  GST_LOG ("  desc.version='%s'", plugin->desc.version);
-  GST_LOG ("  desc.license='%s'", plugin->desc.license);
-  GST_LOG ("  desc.source='%s'", plugin->desc.source);
-  GST_LOG ("  desc.package='%s'", plugin->desc.package);
-  GST_LOG ("  desc.origin='%s'", plugin->desc.origin);
-
-  plugin->basename = g_path_get_basename (plugin->filename);
-
-  /* Takes ownership of plugin */
-  gst_registry_add_plugin (registry, plugin);
-  GST_DEBUG ("Added plugin '%s' plugin with %d features from binary registry",
-      plugin->desc.name, pe->nfeatures);
-
-  /* Load plugin features */
-  for (i = 0; i < pe->nfeatures; i++) {
-    if (!gst_registry_binary_load_feature (registry, in, end,
-            plugin->desc.name)) {
-      GST_ERROR ("Error while loading binary feature");
-      gst_registry_remove_plugin (registry, plugin);
-      goto fail;
-    }
-  }
-
-  /* Load external plugin dependencies */
-  for (i = 0; i < pe->n_deps; ++i) {
-    if (!gst_registry_binary_load_plugin_dep (plugin, in, end)) {
-      GST_ERROR_OBJECT (plugin, "Could not read external plugin dependency");
-      gst_registry_remove_plugin (registry, plugin);
-      goto fail;
-    }
-  }
-
-  return TRUE;
-
-  /* Errors */
-fail:
-  GST_INFO ("Reading plugin failed");
-  return FALSE;
-}
-
-
 /**
  * gst_registry_binary_read_cache:
  * @registry: a #GstRegistry
@@ -1199,6 +511,7 @@ gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
   gsize size;
   GError *err = NULL;
   gboolean res = FALSE;
+  guint32 filter_env_hash = 0;
   gint check_magic_result;
 #ifndef GST_DISABLE_GST_DEBUG
   GTimer *timer = NULL;
@@ -1215,10 +528,14 @@ gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
 #endif
 
   mapped = g_mapped_file_new (location, FALSE, &err);
-  if (err != NULL) {
+  if (G_UNLIKELY (err != NULL)) {
     GST_INFO ("Unable to mmap file %s : %s", location, err->message);
     g_error_free (err);
     err = NULL;
+  }
+
+  if (mapped == NULL) {
+    /* Error mmap-ing the cache, try a plain memory read */
 
     g_file_get_contents (location, &contents, &size, &err);
     if (err != NULL) {
@@ -1230,24 +547,22 @@ gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
       return FALSE;
     }
   } else {
-    if ((contents = g_mapped_file_get_contents (mapped)) == NULL) {
-      GST_ERROR ("Can't load file %s : %s", location, g_strerror (errno));
-      goto Error;
-    }
-    /* check length for header */
+    /* This can't fail if g_mapped_file_new() succeeded */
+    contents = g_mapped_file_get_contents (mapped);
     size = g_mapped_file_get_length (mapped);
   }
 
   /* in is a cursor pointer, we initialize it with the begin of registry and is updated on each read */
   in = contents;
   GST_DEBUG ("File data at address %p", in);
-  if (size < sizeof (GstBinaryRegistryMagic)) {
-    GST_ERROR ("No or broken registry header");
+  if (G_UNLIKELY (size < sizeof (GstBinaryRegistryMagic))) {
+    GST_ERROR ("No or broken registry header for file at %s", location);
     goto Error;
   }
 
   /* check if header is valid */
-  if ((check_magic_result = gst_registry_binary_check_magic (&in, size)) < 0) {
+  if (G_UNLIKELY ((check_magic_result =
+              gst_registry_binary_check_magic (&in, size)) < 0)) {
 
     if (check_magic_result == -1)
       GST_ERROR
@@ -1256,27 +571,41 @@ gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
     goto Error;
   }
 
+  if (!_priv_gst_registry_chunks_load_global_header (registry, &in,
+          contents + size, &filter_env_hash)) {
+    GST_ERROR ("Couldn't read global header chunk");
+    goto Error;
+  }
+
+  if (filter_env_hash != priv_gst_plugin_loading_get_whitelist_hash ()) {
+    GST_INFO_OBJECT (registry, "Plugin loading filter environment changed, "
+        "ignoring plugin cache to force update with new filter environment");
+    goto done;
+  }
+
   /* check if there are plugins in the file */
-  if (!(((gsize) in + sizeof (GstBinaryPluginElement)) <
-          (gsize) contents + size)) {
+  if (G_UNLIKELY (!(((gsize) in + sizeof (GstRegistryChunkPluginElement)) <
+              (gsize) contents + size))) {
     GST_INFO ("No binary plugins structure to read");
     /* empty file, this is not an error */
   } else {
     gchar *end = contents + size;
-    /* read as long as we still have space for a GstBinaryPluginElement */
+    /* read as long as we still have space for a GstRegistryChunkPluginElement */
     for (;
-        ((gsize) in + sizeof (GstBinaryPluginElement)) <
+        ((gsize) in + sizeof (GstRegistryChunkPluginElement)) <
         (gsize) contents + size;) {
       GST_DEBUG ("reading binary registry %" G_GSIZE_FORMAT "(%x)/%"
           G_GSIZE_FORMAT, (gsize) in - (gsize) contents,
           (guint) ((gsize) in - (gsize) contents), size);
-      if (!gst_registry_binary_load_plugin (registry, &in, end)) {
+      if (!_priv_gst_registry_chunks_load_plugin (registry, &in, end, NULL)) {
         GST_ERROR ("Problem while reading binary registry %s", location);
         goto Error;
       }
     }
   }
 
+done:
+
 #ifndef GST_DISABLE_GST_DEBUG
   g_timer_stop (timer);
   seconds = g_timer_elapsed (timer, NULL);
@@ -1292,24 +621,33 @@ Error:
   g_timer_destroy (timer);
 #endif
   if (mapped) {
-    g_mapped_file_free (mapped);
+    g_mapped_file_unref (mapped);
   } else {
     g_free (contents);
   }
   return res;
 }
 
-
-/* FIXME 0.11: these are here for backwards compatibility */
-
+#ifndef GST_REMOVE_DEPRECATED
+#ifdef GST_DISABLE_DEPRECATED
+gboolean
+gst_registry_xml_read_cache (GstRegistry * registry, const char *location);
+#endif
+/* FIXME 0.11: these symbols are here for backwards compatibility and should
+ * be removed or made private */
 gboolean
 gst_registry_xml_read_cache (GstRegistry * registry, const char *location)
 {
   return FALSE;
 }
 
+#ifdef GST_DISABLE_DEPRECATED
+gboolean
+gst_registry_xml_write_cache (GstRegistry * registry, const char *location);
+#endif
 gboolean
 gst_registry_xml_write_cache (GstRegistry * registry, const char *location)
 {
   return FALSE;
 }
+#endif /* GST_REMOVE_DEPRECATED */