X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fconfig%2Ffile.c;h=9b779ab1b420ed9372435da63dcd57bac6d75d10;hb=55c960749e8f91763e720ac610d5dd56f90fcde1;hp=f170bbec401c9ff333744adf5d184c1bb0558537;hpb=7d5bf1ea1baaaad1dbd494312b725e18b00c1de9;p=vlc diff --git a/src/config/file.c b/src/config/file.c index f170bbec40..9b779ab1b4 100644 --- a/src/config/file.c +++ b/src/config/file.c @@ -16,29 +16,31 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU 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 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 -#include "../libvlc.h" -#include "vlc_charset.h" -#include "vlc_keys.h" - #include /* errno */ #include #include +#include +#include #ifdef __APPLE__ # include #else #include #endif +#include +#include "../libvlc.h" +#include "vlc_charset.h" +#include "vlc_keys.h" + #include "configuration.h" #include "modules/modules.h" @@ -52,30 +54,29 @@ static inline char *strdupnull (const char *src) /** * 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 = config_GetPsz( obj, "config" ); + if( psz_file == NULL ) + { + char *psz_dir = config_GetUserConfDir(); - 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 = utf8_fopen( psz_filename, "rt" ); if( p_stream == NULL && errno != ENOENT ) { msg_Err( p_obj, "cannot open config file (%s): %m", @@ -83,7 +84,7 @@ static FILE *config_OpenConfigFile( vlc_object_t *p_obj, const char *mode ) } #if !( defined(WIN32) || defined(__APPLE__) || defined(SYS_BEOS) ) - else if( p_stream == NULL && errno == ENOENT && mode[0] == 'r' ) + else if( p_stream == NULL && errno == ENOENT ) { /* This is the fallback for pre XDG Base Directory * Specification configs */ @@ -91,7 +92,7 @@ static FILE *config_OpenConfigFile( vlc_object_t *p_obj, const char *mode ) if( asprintf( &psz_old, "%s" DIR_SEP CONFIG_DIR DIR_SEP CONFIG_FILE, config_GetHomeDir() ) != -1 ) { - p_stream = utf8_fopen( psz_old, mode ); + p_stream = utf8_fopen( psz_old, "rt" ); if( p_stream ) { /* Old config file found. We want to write it at the @@ -121,11 +122,7 @@ static FILE *config_OpenConfigFile( vlc_object_t *p_obj, const char *mode ) } } #endif - else if( p_stream != NULL ) - { - libvlc_priv (p_obj->p_libvlc)->psz_configfile = psz_filename; - } - + free( psz_filename ); return p_stream; } @@ -157,16 +154,12 @@ static int strtoi (const char *str) *****************************************************************************/ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name ) { - 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); @@ -263,6 +256,7 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name ) /* We found it */ errno = 0; + vlc_mutex_lock( p_item->p_lock ); switch( p_item->i_type ) { case CONFIG_ITEM_BOOL: @@ -292,19 +286,15 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name ) 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; } - + vlc_mutex_unlock( p_item->p_lock ); break; } } @@ -322,8 +312,6 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name ) uselocale (baseloc); freelocale (loc); } - - vlc_mutex_unlock( &priv->config_lock ); return 0; } @@ -391,6 +379,17 @@ config_Write (FILE *file, const char *type, const char *desc, } +static int config_PrepareDir (vlc_object_t *obj) +{ + char *psz_configdir = config_GetUserConfDir (); + if (psz_configdir == NULL) /* XXX: This should never happen */ + return -1; + + int ret = config_CreateDir (obj, psz_configdir); + free (psz_configdir); + return ret; +} + /***************************************************************************** * config_SaveConfigFile: Save a module's config options. ***************************************************************************** @@ -413,48 +412,35 @@ config_Write (FILE *file, const char *type, const char *desc, static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, bool b_autosave ) { - 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; - int i_sizebuf = 0; - char *p_bigbuffer, *p_index; + unsigned long i_sizebuf = 0; + char *p_bigbuffer = NULL, *p_index; bool b_backup; int i_index; - /* Acquire config file lock */ - vlc_mutex_lock( &priv->config_lock ); - - if( libvlc_priv (p_this->p_libvlc)->psz_configfile == NULL ) + if( config_PrepareDir( p_this ) ) { - 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; - } - - config_CreateDir( p_this, psz_configdir ); - free( psz_configdir ); + msg_Err( p_this, "no configuration directory" ); + goto error; } - file = config_OpenConfigFile( p_this, "rt" ); + file = config_OpenConfigFile( p_this ); if( file != NULL ) { /* look for file size */ fseek( file, 0L, SEEK_END ); i_sizebuf = ftell( file ); fseek( file, 0L, SEEK_SET ); + if( i_sizebuf >= LONG_MAX ) + i_sizebuf = 0; } 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 */ @@ -462,7 +448,7 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, /* backup file into memory, we only need to backup the sections we won't * save later on */ - b_backup = 0; + b_backup = false; while( file && fgets( p_line, 1024, file ) ) { if( (p_line[0] == '[') && (p_index2 = strchr(p_line,']'))) @@ -495,11 +481,11 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, #endif *p_index2 = ']'; - b_backup = 1; + b_backup = true; } else { - b_backup = 0; + b_backup = false; } } @@ -512,20 +498,52 @@ 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, +#ifdef UNDER_CE + GetCurrentProcessId () +#else + getpid () +#endif + ) == -1) { + temporary = NULL; module_list_free (list); - free( p_bigbuffer ); - vlc_mutex_unlock( &priv->config_lock ); - return -1; + goto error; + } + + /* The temporary configuration file is per-PID. Therefore SaveConfigFile() + * should be serialized against itself within a given process. */ + static vlc_mutex_t lock = VLC_STATIC_MUTEX; + vlc_mutex_lock (&lock); + + int fd = utf8_open (temporary, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR); + if (fd == -1) + { + vlc_mutex_unlock (&lock); + module_list_free (list); + goto error; + } + file = fdopen (fd, "wt"); + if (file == NULL) + { + close (fd); + vlc_mutex_unlock (&lock); + module_list_free (list); + goto error; } fprintf( file, "\xEF\xBB\xBF###\n### " COPYRIGHT_MESSAGE "\n###\n\n" @@ -561,15 +579,17 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, 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 */ || p_item->b_removed /* ignore deprecated option */ || p_item->b_unsaveable) /* ignore volatile option */ continue; + vlc_mutex_lock (p_item->p_lock); + + /* 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 (IsConfigIntegerType (p_item->i_type)) { int val = b_retain ? p_item->saved.i : p_item->value.i; @@ -636,6 +656,7 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, if (!b_retain) p_item->b_dirty = false; + vlc_mutex_unlock (p_item->p_lock); } } @@ -652,24 +673,49 @@ 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... */ + utf8_rename (temporary, permanent); + /* (...then synchronize the directory, err, TODO...) */ + /* ...and finally close the file */ + vlc_mutex_unlock (&lock); +#endif + fclose (file); +#ifdef WIN32 + /* Windows cannot remove open files nor overwrite existing ones */ + utf8_unlink (permanent); + utf8_rename (temporary, permanent); + vlc_mutex_unlock (&lock); +#endif + free (temporary); + free (permanent); return 0; + +error: + if( file ) + fclose( file ); + free (temporary); + free (permanent); + free( p_bigbuffer ); + return -1; } int config_AutoSaveConfigFile( vlc_object_t *p_this ) { - libvlc_priv_t *priv = libvlc_priv (p_this->p_libvlc); size_t i_index; - bool done; + bool save = false; 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++ ) + for( i_index = 0; list[i_index] && !save; i_index++ ) { module_t *p_parser = list[i_index]; module_config_t *p_item, *p_end; @@ -677,18 +723,17 @@ int config_AutoSaveConfigFile( vlc_object_t *p_this ) 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 < p_end && !save; p_item++ ) { - if( p_item->b_autosave && p_item->b_dirty ) break; + vlc_mutex_lock (p_item->p_lock); + save = p_item->b_autosave && p_item->b_dirty; + vlc_mutex_unlock (p_item->p_lock); } - if( p_item < p_end ) break; } - done = list[i_index] == NULL; module_list_free (list); - vlc_mutex_unlock( &priv->config_lock ); - return done ? VLC_SUCCESS : SaveConfigFile( p_this, NULL, true ); + return save ? VLC_SUCCESS : SaveConfigFile( p_this, NULL, true ); } int __config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name ) @@ -696,39 +741,14 @@ int __config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name ) return SaveConfigFile( p_this, psz_module_name, false ); } -/** - * 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; -} - int ConfigStringToKey( const char *psz_key ) { int i_key = 0; - unsigned int i; + size_t 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++ ) + for( i = 0; i < vlc_num_modifiers; ++i ) { if( !strncasecmp( vlc_modifiers[i].psz_key_string, psz_key, strlen( vlc_modifiers[i].psz_key_string ) ) ) @@ -739,7 +759,7 @@ int ConfigStringToKey( const char *psz_key ) psz_key = psz_parser + 1; psz_parser = strchr( psz_key, '-' ); } - for( i = 0; i < sizeof(vlc_keys) / sizeof( key_descriptor_t ); i++ ) + for( i = 0; i < vlc_num_keys; ++i ) { if( !strcasecmp( vlc_keys[i].psz_key_string, psz_key ) ) { @@ -752,7 +772,10 @@ int ConfigStringToKey( const char *psz_key ) char *ConfigKeyToString( int i_key ) { - char *psz_key = malloc( 100 ); + // Worst case appears to be 45 characters: + // "Command-Meta-Ctrl-Shift-Alt-Browser Favorites" + enum { keylen=64 }; + char *psz_key = malloc( keylen ); char *p; size_t index; @@ -763,20 +786,20 @@ char *ConfigKeyToString( int i_key ) *psz_key = '\0'; p = psz_key; - for( index = 0; index < (sizeof(vlc_modifiers) / sizeof(key_descriptor_t)); - index++ ) + for( index = 0; index < vlc_num_modifiers; ++index ) { if( i_key & vlc_modifiers[index].i_key_code ) { - p += sprintf( p, "%s-", vlc_modifiers[index].psz_key_string ); + p += snprintf( p, keylen-(psz_key-p), "%s-", + vlc_modifiers[index].psz_key_string ); } } - for( index = 0; index < (sizeof(vlc_keys) / sizeof( key_descriptor_t)); - index++) + for( index = 0; index < vlc_num_keys; ++index ) { if( (int)( i_key & ~KEY_MODIFIER ) == vlc_keys[index].i_key_code ) { - p += sprintf( p, "%s", vlc_keys[index].psz_key_string ); + p += snprintf( p, keylen-(psz_key-p), "%s", + vlc_keys[index].psz_key_string ); break; } }