gst/: Rewrite registry-saving to avoid race conditions and check for failed writes.

Original commit message from CVS:
* gst/gstregistry.h:
* gst/gstregistryxml.c: (gst_registry_save),
(gst_registry_save_escaped), (gst_registry_xml_save_caps),
(gst_registry_xml_save_pad_template),
(gst_registry_xml_save_feature), (gst_registry_xml_save_plugin),
(gst_registry_xml_write_cache):
Rewrite registry-saving to avoid race conditions and check for
failed writes.
This commit is contained in:
Michael Smith 2006-03-08 12:57:37 +00:00
parent 21a646d674
commit 81cc6d92ba
4 changed files with 170 additions and 68 deletions

View file

@ -1,3 +1,14 @@
2006-03-08 Michael Smith <msmith@fluendo.com>
* gst/gstregistry.h:
* gst/gstregistryxml.c: (gst_registry_save),
(gst_registry_save_escaped), (gst_registry_xml_save_caps),
(gst_registry_xml_save_pad_template),
(gst_registry_xml_save_feature), (gst_registry_xml_save_plugin),
(gst_registry_xml_write_cache):
Rewrite registry-saving to avoid race conditions and check for
failed writes.
2006-03-08 Wim Taymans <wim@fluendo.com> 2006-03-08 Wim Taymans <wim@fluendo.com>
* libs/gst/base/gstbasetransform.c: * libs/gst/base/gstbasetransform.c:

2
common

@ -1 +1 @@
Subproject commit c09cd18d328f740ac532377fa5605b0f712cc6fd Subproject commit d576cc6779aa9555121d4c78ab69cc620fae3e2b

View file

@ -54,8 +54,8 @@ struct _GstRegistry {
GList *paths; GList *paths;
/* FIXME move elsewhere */ /* FIXME move these elsewhere */
FILE *cache_file; int cache_file;
/*< private >*/ /*< private >*/
gpointer _gst_reserved[GST_PADDING]; gpointer _gst_reserved[GST_PADDING];

View file

@ -56,17 +56,32 @@
#define CLASS(registry) GST_XML_REGISTRY_CLASS (G_OBJECT_GET_CLASS (registry)) #define CLASS(registry) GST_XML_REGISTRY_CLASS (G_OBJECT_GET_CLASS (registry))
static gboolean static gboolean
gst_registry_xml_save (GstRegistry * registry, gchar * format, ...) gst_registry_save (GstRegistry * registry, gchar * format, ...)
{ {
va_list var_args; va_list var_args;
size_t written, len;
gboolean ret;
char *str;
va_start (var_args, format); va_start (var_args, format);
str = g_strdup_vprintf (format, var_args);
vfprintf (registry->cache_file, format, var_args);
va_end (var_args); va_end (var_args);
return TRUE; len = strlen (str);
written = write (registry->cache_file, str, len);
if (len == written)
ret = TRUE;
else {
ret = FALSE;
GST_ERROR ("Failed to write registry to temporary file: %s",
g_strerror (errno));
}
g_free (str);
return ret;
} }
static void static void
@ -527,15 +542,21 @@ gst_registry_xml_read_cache (GstRegistry * registry, const char *location)
/* /*
* Save * Save
*/ */
#define PUT_ESCAPED(prefix,tag,value) \ static gboolean
G_STMT_START{ \ gst_registry_save_escaped (GstRegistry * registry, char *prefix, char *tag,
const gchar *toconv = value; \ char *value)
if (toconv) { \ {
gchar *v = g_markup_escape_text (toconv, strlen (toconv)); \ gboolean ret = TRUE;
gst_registry_xml_save (registry, prefix "<%s>%s</%s>\n", tag, v, tag); \
g_free (v); \ if (value) {
} \ gchar *v = g_markup_escape_text (value, strlen (value));
}G_STMT_END
ret = gst_registry_save (registry, "%s<%s>%s</%s>\n", prefix, tag, v, tag);
g_free (v);
}
return ret;
}
static gboolean static gboolean
@ -545,14 +566,15 @@ gst_registry_xml_save_caps (GstRegistry * registry, const GstCaps * caps)
* faster when loading them later on */ * faster when loading them later on */
char *s; char *s;
GstCaps *copy = gst_caps_copy (caps); GstCaps *copy = gst_caps_copy (caps);
gboolean ret;
gst_caps_do_simplify (copy); gst_caps_do_simplify (copy);
s = gst_caps_to_string (copy); s = gst_caps_to_string (copy);
gst_caps_unref (copy); gst_caps_unref (copy);
PUT_ESCAPED (" ", "caps", s); ret = gst_registry_save_escaped (registry, " ", "caps", s);
g_free (s); g_free (s);
return TRUE; return ret;
} }
static gboolean static gboolean
@ -561,9 +583,14 @@ gst_registry_xml_save_pad_template (GstRegistry * registry,
{ {
gchar *presence; gchar *presence;
PUT_ESCAPED (" ", "nametemplate", template->name_template); if (!gst_registry_save_escaped (registry, " ", "nametemplate",
gst_registry_xml_save (registry, " <direction>%s</direction>\n", template->name_template))
(template->direction == GST_PAD_SINK ? "sink" : "src")); return FALSE;
if (!gst_registry_save (registry,
" <direction>%s</direction>\n",
(template->direction == GST_PAD_SINK ? "sink" : "src")))
return FALSE;
switch (template->presence) { switch (template->presence) {
case GST_PAD_ALWAYS: case GST_PAD_ALWAYS:
@ -579,11 +606,13 @@ gst_registry_xml_save_pad_template (GstRegistry * registry,
presence = "unknown"; presence = "unknown";
break; break;
} }
gst_registry_xml_save (registry, " <presence>%s</presence>\n", presence); if (!gst_registry_save (registry, " <presence>%s</presence>\n", presence))
return FALSE;
if (template->static_caps.string) { if (template->static_caps.string) {
gst_registry_xml_save (registry, " <caps>%s</caps>\n", if (!gst_registry_save (registry, " <caps>%s</caps>\n",
template->static_caps.string); template->static_caps.string))
return FALSE;
} }
return TRUE; return TRUE;
} }
@ -592,50 +621,68 @@ static gboolean
gst_registry_xml_save_feature (GstRegistry * registry, gst_registry_xml_save_feature (GstRegistry * registry,
GstPluginFeature * feature) GstPluginFeature * feature)
{ {
PUT_ESCAPED (" ", "name", feature->name); if (!gst_registry_save_escaped (registry, " ", "name", feature->name))
return FALSE;
if (feature->rank > 0) { if (feature->rank > 0) {
gint rank = feature->rank; gint rank = feature->rank;
gst_registry_xml_save (registry, " <rank>%d</rank>\n", rank); if (!gst_registry_save (registry, " <rank>%d</rank>\n", rank))
return FALSE;
} }
if (GST_IS_ELEMENT_FACTORY (feature)) { if (GST_IS_ELEMENT_FACTORY (feature)) {
GstElementFactory *factory = GST_ELEMENT_FACTORY (feature); GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
GList *walk; GList *walk;
PUT_ESCAPED (" ", "longname", factory->details.longname); if (!gst_registry_save_escaped (registry, " ", "longname",
PUT_ESCAPED (" ", "class", factory->details.klass); factory->details.longname))
PUT_ESCAPED (" ", "description", factory->details.description); return FALSE;
PUT_ESCAPED (" ", "author", factory->details.author); if (!gst_registry_save_escaped (registry, " ", "class",
factory->details.klass))
return FALSE;
if (!gst_registry_save_escaped (registry, " ", "description",
factory->details.description))
return FALSE;
if (!gst_registry_save_escaped (registry, " ", "author",
factory->details.author))
return FALSE;
walk = factory->staticpadtemplates; walk = factory->staticpadtemplates;
while (walk) { while (walk) {
GstStaticPadTemplate *template = walk->data; GstStaticPadTemplate *template = walk->data;
gst_registry_xml_save (registry, " <padtemplate>\n"); if (!gst_registry_save (registry, " <padtemplate>\n"))
gst_registry_xml_save_pad_template (registry, template); return FALSE;
gst_registry_xml_save (registry, " </padtemplate>\n"); if (!gst_registry_xml_save_pad_template (registry, template))
return FALSE;
if (!gst_registry_save (registry, " </padtemplate>\n"))
return FALSE;
walk = g_list_next (walk); walk = g_list_next (walk);
} }
walk = factory->interfaces; walk = factory->interfaces;
while (walk) { while (walk) {
PUT_ESCAPED (" ", "interface", (gchar *) walk->data); if (!gst_registry_save_escaped (registry, " ", "interface",
(gchar *) walk->data))
return FALSE;
walk = g_list_next (walk); walk = g_list_next (walk);
} }
if (GST_URI_TYPE_IS_VALID (factory->uri_type)) { if (GST_URI_TYPE_IS_VALID (factory->uri_type)) {
gchar **protocol; gchar **protocol;
PUT_ESCAPED (" ", "uri_type", if (!gst_registry_save_escaped (registry, " ", "uri_type",
factory->uri_type == GST_URI_SINK ? "sink" : "source"); factory->uri_type == GST_URI_SINK ? "sink" : "source"))
return FALSE;
g_assert (factory->uri_protocols); g_assert (factory->uri_protocols);
protocol = factory->uri_protocols; protocol = factory->uri_protocols;
while (*protocol) { while (*protocol) {
PUT_ESCAPED (" ", "uri_protocol", *protocol); if (!gst_registry_save_escaped (registry, " ", "uri_protocol",
*protocol))
return FALSE;
protocol++; protocol++;
} }
} }
@ -644,16 +691,21 @@ gst_registry_xml_save_feature (GstRegistry * registry,
gint i = 0; gint i = 0;
if (factory->caps) { if (factory->caps) {
gst_registry_xml_save_caps (registry, factory->caps); if (!gst_registry_xml_save_caps (registry, factory->caps))
return FALSE;
} }
if (factory->extensions) { if (factory->extensions) {
while (factory->extensions[i]) { while (factory->extensions[i]) {
PUT_ESCAPED (" ", "extension", factory->extensions[i]); if (!gst_registry_save_escaped (registry, " ", "extension",
factory->extensions[i]))
return FALSE;
i++; i++;
} }
} }
} else if (GST_IS_INDEX_FACTORY (feature)) { } else if (GST_IS_INDEX_FACTORY (feature)) {
PUT_ESCAPED (" ", "longdesc", GST_INDEX_FACTORY (feature)->longdesc); if (!gst_registry_save_escaped (registry, " ", "longdesc",
GST_INDEX_FACTORY (feature)->longdesc))
return FALSE;
} }
return TRUE; return TRUE;
} }
@ -665,33 +717,58 @@ gst_registry_xml_save_plugin (GstRegistry * registry, GstPlugin * plugin)
GList *walk; GList *walk;
char s[100]; char s[100];
PUT_ESCAPED (" ", "name", plugin->desc.name); if (!gst_registry_save_escaped (registry, " ", "name", plugin->desc.name))
PUT_ESCAPED (" ", "description", plugin->desc.description); return FALSE;
PUT_ESCAPED (" ", "filename", plugin->filename); if (!gst_registry_save_escaped (registry, " ", "description",
plugin->desc.description))
return FALSE;
if (!gst_registry_save_escaped (registry, " ", "filename", plugin->filename))
return FALSE;
sprintf (s, "%d", (int) plugin->file_size); sprintf (s, "%d", (int) plugin->file_size);
PUT_ESCAPED (" ", "size", s); if (!gst_registry_save_escaped (registry, " ", "size", s))
return FALSE;
sprintf (s, "%d", (int) plugin->file_mtime); sprintf (s, "%d", (int) plugin->file_mtime);
PUT_ESCAPED (" ", "m32p", s); if (!gst_registry_save_escaped (registry, " ", "m32p", s))
PUT_ESCAPED (" ", "version", plugin->desc.version); return FALSE;
PUT_ESCAPED (" ", "license", plugin->desc.license);
PUT_ESCAPED (" ", "source", plugin->desc.source); if (!gst_registry_save_escaped (registry, " ", "version",
PUT_ESCAPED (" ", "package", plugin->desc.package); plugin->desc.version))
PUT_ESCAPED (" ", "origin", plugin->desc.origin); return FALSE;
if (!gst_registry_save_escaped (registry, " ", "license",
plugin->desc.license))
return FALSE;
if (!gst_registry_save_escaped (registry, " ", "source", plugin->desc.source))
return FALSE;
if (!gst_registry_save_escaped (registry, " ", "package",
plugin->desc.package))
return FALSE;
if (!gst_registry_save_escaped (registry, " ", "origin", plugin->desc.origin))
return FALSE;
list = gst_registry_get_feature_list_by_plugin (registry, plugin->desc.name); list = gst_registry_get_feature_list_by_plugin (registry, plugin->desc.name);
for (walk = list; walk; walk = g_list_next (walk)) { for (walk = list; walk; walk = g_list_next (walk)) {
GstPluginFeature *feature = GST_PLUGIN_FEATURE (walk->data); GstPluginFeature *feature = GST_PLUGIN_FEATURE (walk->data);
gst_registry_xml_save (registry, " <feature typename=\"%s\">\n", if (!gst_registry_save (registry,
g_type_name (G_OBJECT_TYPE (feature))); " <feature typename=\"%s\">\n",
gst_registry_xml_save_feature (registry, feature); g_type_name (G_OBJECT_TYPE (feature))))
gst_registry_xml_save (registry, " </feature>\n"); goto fail;
if (!gst_registry_xml_save_feature (registry, feature))
goto fail;
if (!gst_registry_save (registry, " </feature>\n"))
goto fail;
} }
gst_plugin_feature_list_free (list); gst_plugin_feature_list_free (list);
return TRUE; return TRUE;
fail:
gst_plugin_feature_list_free (list);
return FALSE;
} }
/** /**
@ -712,9 +789,9 @@ gst_registry_xml_write_cache (GstRegistry * registry, const char *location)
g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE); g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
tmp_location = g_strconcat (location, ".tmp", NULL); tmp_location = g_strconcat (location, ".tmpXXXXXX", NULL);
registry->cache_file = fopen (tmp_location, "w"); registry->cache_file = g_mkstemp (tmp_location);
if (registry->cache_file == NULL) { if (registry->cache_file == -1) {
char *dir; char *dir;
/* oops, I bet the directory doesn't exist */ /* oops, I bet the directory doesn't exist */
@ -722,14 +799,17 @@ gst_registry_xml_write_cache (GstRegistry * registry, const char *location)
g_mkdir_with_parents (dir, 0777); g_mkdir_with_parents (dir, 0777);
g_free (dir); g_free (dir);
registry->cache_file = fopen (tmp_location, "w"); registry->cache_file = g_mkstemp (tmp_location);
} }
if (registry->cache_file == NULL) { if (registry->cache_file == -1) {
g_free (tmp_location);
return FALSE; return FALSE;
} }
gst_registry_xml_save (registry, "<?xml version=\"1.0\"?>\n"); if (!gst_registry_save (registry, "<?xml version=\"1.0\"?>\n"))
gst_registry_xml_save (registry, "<GST-PluginRegistry>\n"); goto fail;
if (!gst_registry_save (registry, "<GST-PluginRegistry>\n"))
goto fail;
for (walk = g_list_last (registry->plugins); walk; for (walk = g_list_last (registry->plugins); walk;
@ -752,13 +832,17 @@ gst_registry_xml_write_cache (GstRegistry * registry, const char *location)
} }
} }
gst_registry_xml_save (registry, "<plugin>\n"); if (!gst_registry_save (registry, "<plugin>\n"))
gst_registry_xml_save_plugin (registry, plugin); goto fail;
gst_registry_xml_save (registry, "</plugin>\n"); if (!gst_registry_xml_save_plugin (registry, plugin))
goto fail;
if (!gst_registry_save (registry, "</plugin>\n"))
goto fail;
} }
gst_registry_xml_save (registry, "</GST-PluginRegistry>\n"); if (!gst_registry_save (registry, "</GST-PluginRegistry>\n"))
goto fail;
fclose (registry->cache_file); close (registry->cache_file);
if (g_file_test (tmp_location, G_FILE_TEST_EXISTS)) { if (g_file_test (tmp_location, G_FILE_TEST_EXISTS)) {
#ifdef WIN32 #ifdef WIN32
@ -766,7 +850,14 @@ gst_registry_xml_write_cache (GstRegistry * registry, const char *location)
#endif #endif
rename (tmp_location, location); rename (tmp_location, location);
} }
g_free (tmp_location); g_free (tmp_location);
return TRUE; return TRUE;
fail:
close (registry->cache_file);
g_free (tmp_location);
return FALSE;
} }