[vlc-devel] commit: Replace the configuration file atomically ( Rémi Denis-Courmont )

git version control git at videolan.org
Wed May 6 19:27:13 CEST 2009


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Wed May  6 19:44:42 2009 +0300| [e61b137f927a5a563634af8c59e69fbfdd7a3671] | committer: Rémi Denis-Courmont 

Replace the configuration file atomically

Another VLC instance could get a corrupt configuration otherwise.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=e61b137f927a5a563634af8c59e69fbfdd7a3671
---

 src/config/file.c |   79 +++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 61 insertions(+), 18 deletions(-)

diff --git a/src/config/file.c b/src/config/file.c
index 1f99e35..caf8a09 100644
--- a/src/config/file.c
+++ b/src/config/file.c
@@ -33,6 +33,7 @@
 #include <errno.h>                                                  /* errno */
 #include <assert.h>
 #include <limits.h>
+#include <fcntl.h>
 #ifdef __APPLE__
 #   include <xlocale.h>
 #else
@@ -420,10 +421,11 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
 {
     libvlc_priv_t *priv = libvlc_priv (p_this->p_libvlc);
     module_t *p_parser;
-    FILE *file;
+    FILE *file = NULL;
+    char *permanent = NULL, *temporary = NULL;
     char p_line[1024], *p_index2;
     unsigned long i_sizebuf = 0;
-    char *p_bigbuffer, *p_index;
+    char *p_bigbuffer = NULL, *p_index;
     bool b_backup;
     int i_index;
 
@@ -433,8 +435,7 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
     if( config_PrepareDir( p_this ) )
     {
         msg_Err( p_this, "no configuration directory" );
-        vlc_mutex_unlock( &priv->config_lock );
-        return -1;
+        goto error;
     }
 
     file = config_OpenConfigFile( p_this, "rt" );
@@ -450,11 +451,7 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
 
     p_bigbuffer = p_index = malloc( i_sizebuf+1 );
     if( !p_bigbuffer )
-    {
-        if( file ) fclose( file );
-        vlc_mutex_unlock( &priv->config_lock );
-        return -1;
-    }
+        goto error;
     p_bigbuffer[0] = 0;
 
     /* List all available modules */
@@ -512,20 +509,39 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
             p_index += strlen( p_line );
         }
     }
-    if( file ) fclose( file );
-
+    if( file )
+        fclose( file );
+    file = NULL;
 
     /*
      * Save module config in file
      */
+    permanent = config_GetConfigFile (p_this);
+    if (!permanent)
+    {
+        module_list_free (list);
+        goto error;
+    }
 
-    file = config_OpenConfigFile (p_this, "wt");
-    if( !file )
+    if (asprintf (&temporary, "%s.%u", permanent, getpid ()) == -1)
     {
+        temporary = NULL;
         module_list_free (list);
-        free( p_bigbuffer );
-        vlc_mutex_unlock( &priv->config_lock );
-        return -1;
+        goto error;
+    }
+
+    int fd = utf8_open (temporary, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
+    if (fd == -1)
+    {
+        module_list_free (list);
+        goto error;
+    }
+    file = fdopen (fd, "wt");
+    if (file == NULL)
+    {
+        close (fd);
+        module_list_free (list);
+        goto error;
     }
 
     fprintf( file, "\xEF\xBB\xBF###\n###  " COPYRIGHT_MESSAGE "\n###\n\n"
@@ -652,10 +668,37 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
     fputs( p_bigbuffer, file );
     free( p_bigbuffer );
 
-    fclose( file );
-    vlc_mutex_unlock( &priv->config_lock );
+    /*
+     * Flush to disk and replace atomically
+     */
+    fflush (file); /* Flush from run-time */
+#ifndef WIN32
+    fdatasync (fd); /* Flush from OS */
+    /* Atomically replace the file... */
+    rename (temporary, permanent);
+    /* (...then synchronize the directory, err, TODO...) */
+    /* ...and finally close the file */
+#endif
+    vlc_mutex_unlock (&priv->config_lock);
+    fclose (file);
+#ifdef WIN32
+    /* Windows cannot remove open files nor overwrite existing ones */
+    remove (permanent);
+    rename (temporary, permanent);
+#endif
 
+    free (temporary);
+    free (permanent);
     return 0;
+
+error:
+    if( file )
+        fclose( file );
+    vlc_mutex_unlock( &priv->config_lock );
+    free (temporary);
+    free (permanent);
+    free( p_bigbuffer );
+    return -1;
 }
 
 int config_AutoSaveConfigFile( vlc_object_t *p_this )




More information about the vlc-devel mailing list