/*****************************************************************************
* file.c: configuration file handling
*****************************************************************************
- * Copyright (C) 2001-2007 the VideoLAN team
+ * Copyright (C) 2001-2007 VLC authors and VideoLAN
* $Id$
*
* Authors: Gildas Bazin <gbazin@videolan.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
-#include <vlc_common.h>
-#include "../libvlc.h"
-#include "vlc_charset.h"
-#include "vlc_keys.h"
-
#include <errno.h> /* errno */
#include <assert.h>
#include <limits.h>
+#include <fcntl.h>
+#include <sys/stat.h>
#ifdef __APPLE__
# include <xlocale.h>
-#else
+#elif defined(HAVE_USELOCALE)
#include <locale.h>
#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <vlc_common.h>
+#include "../libvlc.h"
+#include <vlc_charset.h>
+#include <vlc_fs.h>
+#include <vlc_keys.h>
+#include <vlc_modules.h>
+#include <vlc_plugin.h>
#include "configuration.h"
#include "modules/modules.h"
-static char *ConfigKeyToString( int );
-
static inline char *strdupnull (const char *src)
{
return src ? strdup (src) : NULL;
/**
* Get the user's configuration file
*/
-static char *config_GetConfigFile( void )
+static char *config_GetConfigFile( vlc_object_t *obj )
{
- char *psz_dir = config_GetUserConfDir();
- char *psz_configfile;
+ char *psz_file = var_CreateGetNonEmptyString( obj, "config" );
+ var_Destroy( obj, "config" );
+ if( psz_file == NULL )
+ {
+ char *psz_dir = config_GetUserDir( VLC_CONFIG_DIR );
- if( asprintf( &psz_configfile, "%s" DIR_SEP CONFIG_FILE, psz_dir ) == -1 )
- psz_configfile = NULL;
- free( psz_dir );
- return psz_configfile;
+ if( asprintf( &psz_file, "%s" DIR_SEP CONFIG_FILE, psz_dir ) == -1 )
+ psz_file = NULL;
+ free( psz_dir );
+ }
+ return psz_file;
}
-static FILE *config_OpenConfigFile( vlc_object_t *p_obj, const char *mode )
+static FILE *config_OpenConfigFile( vlc_object_t *p_obj )
{
- char *psz_filename = libvlc_priv (p_obj->p_libvlc)->psz_configfile;
- FILE *p_stream;
-
- if( !psz_filename )
- {
- psz_filename = config_GetConfigFile();
- }
+ char *psz_filename = config_GetConfigFile( p_obj );
+ if( psz_filename == NULL )
+ return NULL;
msg_Dbg( p_obj, "opening config file (%s)", psz_filename );
- p_stream = utf8_fopen( psz_filename, mode );
+ FILE *p_stream = vlc_fopen( psz_filename, "rt" );
if( p_stream == NULL && errno != ENOENT )
{
msg_Err( p_obj, "cannot open config file (%s): %m",
psz_filename );
}
-#if !( defined(WIN32) || defined(__APPLE__) || defined(SYS_BEOS) )
- else if( p_stream == NULL && errno == ENOENT && mode[0] == 'r' )
+#if !( defined(WIN32) || defined(__APPLE__) || defined(__OS2__) )
+ else if( p_stream == NULL && errno == ENOENT )
{
/* This is the fallback for pre XDG Base Directory
* Specification configs */
+ char *home = config_GetUserDir(VLC_HOME_DIR);
char *psz_old;
- if( asprintf( &psz_old, "%s" DIR_SEP CONFIG_DIR DIR_SEP CONFIG_FILE,
- config_GetHomeDir() ) != -1 )
+
+ if( home != NULL
+ && asprintf( &psz_old, "%s/.vlc/" CONFIG_FILE,
+ home ) != -1 )
{
- p_stream = utf8_fopen( psz_old, mode );
+ p_stream = vlc_fopen( psz_old, "rt" );
if( p_stream )
{
/* Old config file found. We want to write it at the
msg_Info( p_obj->p_libvlc, "Found old config file at %s. "
"VLC will now use %s.", psz_old, psz_filename );
char *psz_readme;
- if( asprintf(&psz_readme,"%s"DIR_SEP CONFIG_DIR DIR_SEP"README",
- config_GetHomeDir() ) != -1 )
+ if( asprintf(&psz_readme,"%s/.vlc/README",
+ home ) != -1 )
{
- FILE *p_readme = utf8_fopen( psz_readme, "wt" );
+ FILE *p_readme = vlc_fopen( psz_readme, "wt" );
if( p_readme )
{
fprintf( p_readme, "The VLC media player "
}
free( psz_readme );
}
+ /* Remove the old configuration file so that --reset-config
+ * can work properly. Fortunately, Linux allows removing
+ * open files - with most filesystems. */
+ unlink( psz_old );
}
free( psz_old );
}
+ free( home );
}
#endif
- else if( p_stream != NULL )
- {
- libvlc_priv (p_obj->p_libvlc)->psz_configfile = psz_filename;
- }
-
+ free( psz_filename );
return p_stream;
}
-static int strtoi (const char *str)
+static int64_t strtoi (const char *str)
{
char *end;
- long l;
+ long long l;
errno = 0;
- l = strtol (str, &end, 0);
+ l = strtoll (str, &end, 0);
if (!errno)
{
- if ((l > INT_MAX) || (l < INT_MIN))
+#if (LLONG_MAX > 0x7fffffffffffffffLL)
+ if (l > 0x7fffffffffffffffLL
+ || l < -0x8000000000000000LL)
errno = ERANGE;
+#endif
if (*end)
errno = EINVAL;
}
- return (int)l;
+ return l;
}
-
+#undef config_LoadConfigFile
/*****************************************************************************
* config_LoadConfigFile: loads the configuration file.
*****************************************************************************
* This function is called to load the config options stored in the config
* file.
*****************************************************************************/
-int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
+int config_LoadConfigFile( vlc_object_t *p_this )
{
- libvlc_priv_t *priv = libvlc_priv (p_this->p_libvlc);
FILE *file;
- file = config_OpenConfigFile (p_this, "rt");
+ file = config_OpenConfigFile (p_this);
if (file == NULL)
return VLC_EGENERIC;
- /* Acquire config file lock */
- vlc_mutex_lock( &priv->config_lock );
-
- /* Look for the selected module, if NULL then save everything */
- module_t **list = module_list_get (NULL);
-
/* Look for UTF-8 Byte Order Mark */
char * (*convert) (const char *) = strdupnull;
char bom[3];
rewind (file); /* no BOM, rewind */
}
- module_t *module = NULL;
- char line[1024], section[1022];
- section[0] = '\0';
+ char *line = NULL;
+ size_t bufsize;
+ ssize_t linelen;
/* Ensure consistent number formatting... */
locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
locale_t baseloc = uselocale (loc);
- while (fgets (line, 1024, file) != NULL)
+ vlc_rwlock_wrlock (&config_lock);
+ while ((linelen = getline (&line, &bufsize, file)) != -1)
{
- /* Ignore comments and empty lines */
- switch (line[0])
- {
- case '#':
- case '\n':
- case '\0':
- continue;
- }
-
- if (line[0] == '[')
- {
- char *ptr = strchr (line, ']');
- if (ptr == NULL)
- continue; /* syntax error; */
- *ptr = '\0';
-
- /* New section ( = a given module) */
- strcpy (section, line + 1);
- module = NULL;
-
- if ((psz_module_name == NULL)
- || (strcmp (psz_module_name, section) == 0))
- {
- for (int i = 0; list[i]; i++)
- {
- module_t *m = list[i];
-
- if ((strcmp (section, m->psz_object_name) == 0)
- && (m->i_config_items > 0)) /* ignore config-less modules */
- {
- module = m;
- if (psz_module_name != NULL)
- msg_Dbg (p_this,
- "loading config for module \"%s\"",
- section);
- break;
- }
- }
- }
+ line[linelen - 1] = '\0'; /* trim newline */
+ /* Ignore comments, section and empty lines */
+ if (memchr ("#[", line[0], 3) != NULL)
continue;
- }
-
- if (module == NULL)
- continue; /* no need to parse if there is no matching module */
-
- char *ptr = strchr (line, '\n');
- if (ptr != NULL)
- *ptr = '\0';
/* look for option name */
const char *psz_option_name = line;
- ptr = strchr (line, '=');
+ char *ptr = strchr (line, '=');
if (ptr == NULL)
continue; /* syntax error */
-
*ptr = '\0';
- const char *psz_option_value = ptr + 1;
-
- /* try to match this option with one of the module's options */
- for (size_t i = 0; i < module->confsize; i++)
- {
- module_config_t *p_item = module->p_config + i;
-
- if ((p_item->i_type & CONFIG_HINT)
- || strcmp (p_item->psz_name, psz_option_name))
- continue;
- /* We found it */
- errno = 0;
+ module_config_t *item = config_FindConfig (p_this, psz_option_name);
+ if (item == NULL)
+ continue;
- switch( p_item->i_type )
+ const char *psz_option_value = ptr + 1;
+ switch (CONFIG_CLASS(item->i_type))
+ {
+ case CONFIG_ITEM_BOOL:
+ case CONFIG_ITEM_INTEGER:
{
- case CONFIG_ITEM_BOOL:
- case CONFIG_ITEM_INTEGER:
- {
- long l = strtoi (psz_option_value);
- if (errno)
- msg_Warn (p_this, "Integer value (%s) for %s: %m",
- psz_option_value, psz_option_name);
- else
- p_item->saved.i = p_item->value.i = (int)l;
- break;
- }
-
- case CONFIG_ITEM_FLOAT:
- if( !*psz_option_value )
- break; /* ignore empty option */
- p_item->value.f = (float)atof (psz_option_value);
- p_item->saved.f = p_item->value.f;
- break;
-
- case CONFIG_ITEM_KEY:
- if( !*psz_option_value )
- break; /* ignore empty option */
- p_item->value.i = ConfigStringToKey(psz_option_value);
- p_item->saved.i = p_item->value.i;
- break;
-
- default:
- vlc_mutex_lock( p_item->p_lock );
-
- /* free old string */
- free( (char*) p_item->value.psz );
- free( (char*) p_item->saved.psz );
-
- p_item->value.psz = convert (psz_option_value);
- p_item->saved.psz = strdupnull (p_item->value.psz);
-
- vlc_mutex_unlock( p_item->p_lock );
- break;
+ int64_t l;
+
+ errno = 0;
+ l = strtoi (psz_option_value);
+ if ((l > item->max.i) || (l < item->min.i))
+ errno = ERANGE;
+ if (errno)
+ msg_Warn (p_this, "Integer value (%s) for %s: %m",
+ psz_option_value, psz_option_name);
+ else
+ item->value.i = l;
+ break;
}
- break;
+ case CONFIG_ITEM_FLOAT:
+ if (!*psz_option_value)
+ break; /* ignore empty option */
+ item->value.f = (float)atof (psz_option_value);
+ break;
+
+ default:
+ free ((char *)item->value.psz);
+ item->value.psz = convert (psz_option_value);
+ break;
}
}
+ vlc_rwlock_unlock (&config_lock);
+ free (line);
if (ferror (file))
{
}
fclose (file);
- module_list_free (list);
if (loc != (locale_t)0)
{
uselocale (baseloc);
freelocale (loc);
}
-
- vlc_mutex_unlock( &priv->config_lock );
return 0;
}
{
if( !psz_dirname || !*psz_dirname ) return -1;
- if( utf8_mkdir( psz_dirname, 0700 ) == 0 )
+ if( vlc_mkdir( psz_dirname, 0700 ) == 0 )
return 0;
switch( errno )
*psz_end = '\0';
if( config_CreateDir( p_this, psz_parent ) == 0 )
{
- if( !utf8_mkdir( psz_dirname, 0700 ) )
+ if( !vlc_mkdir( psz_dirname, 0700 ) )
return 0;
}
}
}
}
- msg_Err( p_this, "could not create %s: %m", psz_dirname );
+ msg_Warn( p_this, "could not create %s: %m", psz_dirname );
return -1;
}
static int
-config_Write (FILE *file, const char *type, const char *desc,
+config_Write (FILE *file, const char *desc, const char *type,
bool comment, const char *name, const char *fmt, ...)
{
va_list ap;
}
-/*****************************************************************************
- * config_SaveConfigFile: Save a module's config options.
- *****************************************************************************
- * This will save the specified module's config options to the config file.
- * If psz_module_name is NULL then we save all the modules config options.
- * It's no use to save the config options that kept their default values, so
- * we'll try to be a bit clever here.
- *
- * When we save we mustn't delete the config options of the modules that
- * haven't been loaded. So we cannot just create a new config file with the
- * config structures we've got in memory.
- * I don't really know how to deal with this nicely, so I will use a completly
- * dumb method ;-)
- * I will load the config file in memory, but skipping all the sections of the
- * modules we want to save. Then I will create a brand new file, dump the file
- * loaded in memory and then append the sections of the modules we want to
- * save.
- * Really stupid no ?
- *****************************************************************************/
-static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
- bool b_autosave )
+static int config_PrepareDir (vlc_object_t *obj)
{
- libvlc_priv_t *priv = libvlc_priv (p_this->p_libvlc);
- module_t *p_parser;
- FILE *file;
- char p_line[1024], *p_index2;
- int i_sizebuf = 0;
- char *p_bigbuffer, *p_index;
- bool b_backup;
- int i_index;
-
- /* Acquire config file lock */
- vlc_mutex_lock( &priv->config_lock );
+ char *psz_configdir = config_GetUserDir (VLC_CONFIG_DIR);
+ if (psz_configdir == NULL)
+ return -1;
- if( libvlc_priv (p_this->p_libvlc)->psz_configfile == NULL )
- {
- char *psz_configdir = config_GetUserConfDir();
- if( !psz_configdir ) /* XXX: This should never happen */
- {
- msg_Err( p_this, "no configuration directory defined" );
- vlc_mutex_unlock( &priv->config_lock );
- return -1;
- }
+ int ret = config_CreateDir (obj, psz_configdir);
+ free (psz_configdir);
+ return ret;
+}
- config_CreateDir( p_this, psz_configdir );
- free( psz_configdir );
- }
+#undef config_SaveConfigFile
+/**
+ * Saves the in-memory configuration into a file.
+ * @return 0 on success, -1 on error.
+ */
+int config_SaveConfigFile (vlc_object_t *p_this)
+{
- file = config_OpenConfigFile( p_this, "rt" );
- if( file != NULL )
+ if( config_PrepareDir( p_this ) )
{
- /* look for file size */
- fseek( file, 0L, SEEK_END );
- i_sizebuf = ftell( file );
- fseek( file, 0L, SEEK_SET );
+ msg_Err( p_this, "no configuration directory" );
+ return -1;
}
- p_bigbuffer = p_index = malloc( i_sizebuf+1 );
- if( !p_bigbuffer )
+ /*
+ * Save module config in file
+ */
+ char *temporary;
+ char *permanent = config_GetConfigFile (p_this);
+ if (permanent == NULL)
+ return -1;
+ if (asprintf (&temporary, "%s.%u", permanent, getpid ()) == -1)
{
- if( file ) fclose( file );
- vlc_mutex_unlock( &priv->config_lock );
+ free (permanent);
return -1;
}
- p_bigbuffer[0] = 0;
-
- /* List all available modules */
- module_t **list = module_list_get (NULL);
-
- /* backup file into memory, we only need to backup the sections we won't
- * save later on */
- b_backup = 0;
- while( file && fgets( p_line, 1024, file ) )
+ else
{
- if( (p_line[0] == '[') && (p_index2 = strchr(p_line,']')))
- {
-
- /* we found a section, check if we need to do a backup */
- for( i_index = 0; (p_parser = list[i_index]) != NULL; i_index++ )
- {
- if( ((p_index2 - &p_line[1])
- == (int)strlen(p_parser->psz_object_name) )
- && !memcmp( &p_line[1], p_parser->psz_object_name,
- strlen(p_parser->psz_object_name) ) )
- {
- if( !psz_module_name )
- break;
- else if( !strcmp( psz_module_name,
- p_parser->psz_object_name ) )
- break;
- }
- }
-
- if( list[i_index] == NULL )
- {
- /* we don't have this section in our list so we need to back
- * it up */
- *p_index2 = 0;
-#if 0
- msg_Dbg( p_this, "backing up config for unknown module \"%s\"",
- &p_line[1] );
-#endif
- *p_index2 = ']';
+ struct stat st;
- b_backup = 1;
- }
- else
- {
- b_backup = 0;
- }
- }
-
- /* save line if requested and line is valid (doesn't begin with a
- * space, tab, or eol) */
- if( b_backup && (p_line[0] != '\n') && (p_line[0] != ' ')
- && (p_line[0] != '\t') )
+ /* Some users make vlcrc read-only to prevent changes.
+ * The atomic replacement scheme breaks this "feature",
+ * so we check for read-only by hand. */
+ if (stat (permanent, &st) == 0 && !(st.st_mode & S_IWUSR))
{
- strcpy( p_index, p_line );
- p_index += strlen( p_line );
+ msg_Err (p_this, "configuration file is read-only");
+ goto error;
}
}
- if( file ) fclose( file );
+ /* Configuration lock must be taken before vlcrc serializer below. */
+ vlc_rwlock_rdlock (&config_lock);
- /*
- * Save module config in file
- */
+ /* The temporary configuration file is per-PID. Therefore this function
+ * should be serialized against itself within a given process. */
+ static vlc_mutex_t lock = VLC_STATIC_MUTEX;
+ vlc_mutex_lock (&lock);
- file = config_OpenConfigFile (p_this, "wt");
- if( !file )
+ int fd = vlc_open (temporary, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
+ if (fd == -1)
{
- module_list_free (list);
- free( p_bigbuffer );
- vlc_mutex_unlock( &priv->config_lock );
- return -1;
+ vlc_rwlock_unlock (&config_lock);
+ vlc_mutex_unlock (&lock);
+ goto error;
+ }
+ FILE *file = fdopen (fd, "wt");
+ if (file == NULL)
+ {
+ msg_Err (p_this, "cannot create configuration file: %m");
+ vlc_rwlock_unlock (&config_lock);
+ close (fd);
+ vlc_mutex_unlock (&lock);
+ goto error;
}
- fprintf( file, "\xEF\xBB\xBF###\n### " COPYRIGHT_MESSAGE "\n###\n\n"
- "###\n### lines beginning with a '#' character are comments\n###\n\n" );
+ fprintf( file,
+ "\xEF\xBB\xBF###\n"
+ "### "PACKAGE_NAME" "PACKAGE_VERSION"\n"
+ "###\n"
+ "\n"
+ "###\n"
+ "### lines beginning with a '#' character are comments\n"
+ "###\n"
+ "\n" );
/* Ensure consistent number formatting... */
locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
locale_t baseloc = uselocale (loc);
+ /* We would take the config lock here. But this would cause a lock
+ * inversion with the serializer above and config_AutoSaveConfigFile().
+ vlc_rwlock_rdlock (&config_lock);*/
+
/* Look for the selected module, if NULL then save everything */
- for( i_index = 0; (p_parser = list[i_index]) != NULL; i_index++ )
+ module_t **list = module_list_get (NULL);
+ module_t *p_parser;
+ for (int i = 0; (p_parser = list[i]) != NULL; i++)
{
module_config_t *p_item, *p_end;
- if( psz_module_name && strcmp( psz_module_name,
- p_parser->psz_object_name ) )
- continue;
-
if( !p_parser->i_config_items )
continue;
- if( psz_module_name )
- msg_Dbg( p_this, "saving config for module \"%s\"",
- p_parser->psz_object_name );
-
- fprintf( file, "[%s]", p_parser->psz_object_name );
+ fprintf( file, "[%s]", module_get_object (p_parser) );
if( p_parser->psz_longname )
fprintf( file, " # %s\n\n", p_parser->psz_longname );
else
p_item < p_end;
p_item++ )
{
- /* Do not save the new value in the configuration file
- * if doing an autosave, and the item is not an "autosaved" one. */
- bool b_retain = b_autosave && !p_item->b_autosave;
-
- if ((p_item->i_type & CONFIG_HINT) /* ignore hint */
+ if (!CONFIG_ITEM(p_item->i_type) /* ignore hint */
|| p_item->b_removed /* ignore deprecated option */
|| p_item->b_unsaveable) /* ignore volatile option */
continue;
if (IsConfigIntegerType (p_item->i_type))
{
- int val = b_retain ? p_item->saved.i : p_item->value.i;
- if (p_item->i_type == CONFIG_ITEM_KEY)
- {
- char *psz_key = ConfigKeyToString (val);
- config_Write (file, p_item->psz_text, N_("key"),
- val == p_item->orig.i,
- p_item->psz_name, "%s",
- psz_key ? psz_key : "");
- free (psz_key);
- }
- else
- config_Write (file, p_item->psz_text,
- (p_item->i_type == CONFIG_ITEM_BOOL)
- ? N_("boolean") : N_("integer"),
- val == p_item->orig.i,
- p_item->psz_name, "%d", val);
- p_item->saved.i = val;
+ int64_t val = p_item->value.i;
+ config_Write (file, p_item->psz_text,
+ (CONFIG_CLASS(p_item->i_type) == CONFIG_ITEM_BOOL)
+ ? N_("boolean") : N_("integer"),
+ val == p_item->orig.i,
+ p_item->psz_name, "%"PRId64, val);
}
else
if (IsConfigFloatType (p_item->i_type))
{
- float val = b_retain ? p_item->saved.f : p_item->value.f;
+ float val = p_item->value.f;
config_Write (file, p_item->psz_text, N_("float"),
val == p_item->orig.f,
p_item->psz_name, "%f", val);
- p_item->saved.f = val;
}
else
{
- const char *psz_value = b_retain ? p_item->saved.psz
- : p_item->value.psz;
+ const char *psz_value = p_item->value.psz;
bool modified;
assert (IsConfigStringType (p_item->i_type));
- if (b_retain && (psz_value == NULL)) /* FIXME: hack */
- psz_value = p_item->orig.psz;
-
- modified =
- (psz_value != NULL)
- ? ((p_item->orig.psz != NULL)
- ? (strcmp (psz_value, p_item->orig.psz) != 0)
- : true)
- : (p_item->orig.psz != NULL);
-
+ modified = !!strcmp (psz_value ? psz_value : "",
+ p_item->orig.psz ? p_item->orig.psz : "");
config_Write (file, p_item->psz_text, N_("string"),
!modified, p_item->psz_name, "%s",
psz_value ? psz_value : "");
-
- if ( !b_retain )
- {
-
- free ((char *)p_item->saved.psz);
- if( (psz_value && p_item->orig.psz &&
- strcmp( psz_value, p_item->orig.psz )) ||
- !psz_value || !p_item->orig.psz)
- p_item->saved.psz = strdupnull (psz_value);
- else
- p_item->saved.psz = NULL;
- }
}
-
- if (!b_retain)
- p_item->b_dirty = false;
}
}
+ vlc_rwlock_unlock (&config_lock);
module_list_free (list);
if (loc != (locale_t)0)
}
/*
- * Restore old settings from the config in file
+ * Flush to disk and replace atomically
*/
- fputs( p_bigbuffer, file );
- free( p_bigbuffer );
-
- fclose( file );
- vlc_mutex_unlock( &priv->config_lock );
-
- return 0;
-}
-
-int config_AutoSaveConfigFile( vlc_object_t *p_this )
-{
- libvlc_priv_t *priv = libvlc_priv (p_this->p_libvlc);
- size_t i_index;
- bool done;
-
- assert( p_this );
-
- /* Check if there's anything to save */
- vlc_mutex_lock( &priv->config_lock );
- module_t **list = module_list_get (NULL);
- for( i_index = 0; list[i_index]; i_index++ )
+ fflush (file); /* Flush from run-time */
+ if (ferror (file))
{
- module_t *p_parser = list[i_index];
- module_config_t *p_item, *p_end;
-
- if( !p_parser->i_config_items ) continue;
-
- for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize;
- p_item < p_end;
- p_item++ )
- {
- if( p_item->b_autosave && p_item->b_dirty ) break;
- }
- if( p_item < p_end ) break;
+ vlc_unlink (temporary);
+ vlc_mutex_unlock (&lock);
+ msg_Err (p_this, "cannot write configuration file");
+ fclose (file);
+ goto error;
}
- done = list[i_index] == NULL;
- module_list_free (list);
- vlc_mutex_unlock( &priv->config_lock );
-
- return done ? VLC_SUCCESS : SaveConfigFile( p_this, NULL, true );
-}
+#if defined(__APPLE__) || defined(__ANDROID__)
+ fsync (fd); /* Flush from OS */
+#else
+ fdatasync (fd); /* Flush from OS */
+#endif
+#if defined (WIN32) || defined (__OS2__)
+ /* Windows cannot (re)move open files nor overwrite existing ones */
+ fclose (file);
+ vlc_unlink (permanent);
+#endif
+ /* Atomically replace the file... */
+ if (vlc_rename (temporary, permanent))
+ vlc_unlink (temporary);
+ /* (...then synchronize the directory, err, TODO...) */
+ /* ...and finally close the file */
+ vlc_mutex_unlock (&lock);
+#if !defined (WIN32) && !defined (__OS2__)
+ fclose (file);
+#endif
-int __config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name )
-{
- return SaveConfigFile( p_this, psz_module_name, false );
-}
+ free (temporary);
+ free (permanent);
+ return 0;
-/**
- * Get the user's configuration file when given with the --config option
- */
-char *config_GetCustomConfigFile( libvlc_int_t *p_libvlc )
-{
- char *psz_configfile = config_GetPsz( p_libvlc, "config" );
- if( psz_configfile != NULL )
- {
- if( psz_configfile[0] == '~' && psz_configfile[1] == '/' )
- {
- /* This is incomplete: we should also support the ~cmassiot/ syntax */
- char *psz_buf;
- if( asprintf( &psz_buf, "%s/%s", config_GetHomeDir(),
- psz_configfile + 2 ) == -1 )
- {
- free( psz_configfile );
- return NULL;
- }
- free( psz_configfile );
- psz_configfile = psz_buf;
- }
- }
- return psz_configfile;
+error:
+ free (temporary);
+ free (permanent);
+ return -1;
}
-int ConfigStringToKey( const char *psz_key )
+int config_AutoSaveConfigFile( vlc_object_t *p_this )
{
- int i_key = 0;
- unsigned int i;
- const char *psz_parser = strchr( psz_key, '-' );
- while( psz_parser && psz_parser != psz_key )
- {
- for( i = 0; i < sizeof(vlc_modifiers) / sizeof(key_descriptor_t); i++ )
- {
- if( !strncasecmp( vlc_modifiers[i].psz_key_string, psz_key,
- strlen( vlc_modifiers[i].psz_key_string ) ) )
- {
- i_key |= vlc_modifiers[i].i_key_code;
- }
- }
- psz_key = psz_parser + 1;
- psz_parser = strchr( psz_key, '-' );
- }
- for( i = 0; i < sizeof(vlc_keys) / sizeof( key_descriptor_t ); i++ )
- {
- if( !strcasecmp( vlc_keys[i].psz_key_string, psz_key ) )
- {
- i_key |= vlc_keys[i].i_key_code;
- break;
- }
- }
- return i_key;
-}
+ int ret = 0;
-char *ConfigKeyToString( int i_key )
-{
- char *psz_key = malloc( 100 );
- char *p;
- size_t index;
+ assert( p_this );
- if ( !psz_key )
+ vlc_rwlock_rdlock (&config_lock);
+ if (config_dirty)
{
- return NULL;
+ /* Note: this will get the read lock recursively. Ok. */
+ ret = config_SaveConfigFile (p_this);
+ config_dirty = (ret != 0);
}
- *psz_key = '\0';
- p = psz_key;
+ vlc_rwlock_unlock (&config_lock);
- for( index = 0; index < (sizeof(vlc_modifiers) / sizeof(key_descriptor_t));
- index++ )
- {
- if( i_key & vlc_modifiers[index].i_key_code )
- {
- p += sprintf( p, "%s-", vlc_modifiers[index].psz_key_string );
- }
- }
- for( index = 0; index < (sizeof(vlc_keys) / sizeof( key_descriptor_t));
- index++)
- {
- if( (int)( i_key & ~KEY_MODIFIER ) == vlc_keys[index].i_key_code )
- {
- p += sprintf( p, "%s", vlc_keys[index].psz_key_string );
- break;
- }
- }
- return psz_key;
+ return ret;
}
-