X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fconfig%2Ffile.c;h=305bbf8d731ee79d344b40724a1e0b34d36a22a1;hb=12ade3e3bc975d5426ba4af155b7372c31093b31;hp=5d0f3772a3995b32a1f72ddc16558cb4c691258e;hpb=9142f0c610d9eea3ed0224cb4bf9fa19087222d7;p=vlc diff --git a/src/config/file.c b/src/config/file.c index 5d0f3772a3..305bbf8d73 100644 --- a/src/config/file.c +++ b/src/config/file.c @@ -32,14 +32,16 @@ #include #ifdef __APPLE__ # include -#else +#elif defined(HAVE_USELOCALE) #include #endif #include #include "../libvlc.h" -#include "vlc_charset.h" -#include "vlc_keys.h" +#include +#include +#include +#include #include "configuration.h" #include "modules/modules.h" @@ -54,7 +56,8 @@ static inline char *strdupnull (const char *src) */ static char *config_GetConfigFile( vlc_object_t *obj ) { - char *psz_file = config_GetPsz( obj, "config" ); + char *psz_file = var_CreateGetNonEmptyString( obj, "config" ); + var_Destroy( obj, "config" ); if( psz_file == NULL ) { char *psz_dir = config_GetUserDir( VLC_CONFIG_DIR ); @@ -74,7 +77,7 @@ static FILE *config_OpenConfigFile( vlc_object_t *p_obj ) msg_Dbg( p_obj, "opening config file (%s)", psz_filename ); - FILE *p_stream = utf8_fopen( psz_filename, "rt" ); + FILE *p_stream = vlc_fopen( psz_filename, "rt" ); if( p_stream == NULL && errno != ENOENT ) { msg_Err( p_obj, "cannot open config file (%s): %m", @@ -93,7 +96,7 @@ static FILE *config_OpenConfigFile( vlc_object_t *p_obj ) && asprintf( &psz_old, "%s/.vlc/" CONFIG_FILE, home ) != -1 ) { - p_stream = utf8_fopen( psz_old, "rt" ); + p_stream = vlc_fopen( psz_old, "rt" ); if( p_stream ) { /* Old config file found. We want to write it at the @@ -104,7 +107,7 @@ static FILE *config_OpenConfigFile( vlc_object_t *p_obj ) 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 " @@ -118,6 +121,10 @@ static FILE *config_OpenConfigFile( vlc_object_t *p_obj ) } 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 ); } @@ -129,32 +136,35 @@ static FILE *config_OpenConfigFile( vlc_object_t *p_obj ) } -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, const char *psz_module_name ) { FILE *file; @@ -184,6 +194,7 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name ) locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL); locale_t baseloc = uselocale (loc); + vlc_rwlock_wrlock (&config_lock); while (fgets (line, 1024, file) != NULL) { /* Ignore comments and empty lines */ @@ -258,18 +269,19 @@ 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: case CONFIG_ITEM_INTEGER: { - long l = strtoi (psz_option_value); + int64_t l = strtoi (psz_option_value); + if ((l > p_item->max.i) || (l < p_item->min.i)) + errno = ERANGE; 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; + p_item->saved.i = p_item->value.i = l; break; } @@ -296,10 +308,10 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name ) p_item->saved.psz = strdupnull (p_item->value.psz); break; } - vlc_mutex_unlock( p_item->p_lock ); break; } } + vlc_rwlock_unlock (&config_lock); if (ferror (file)) { @@ -324,7 +336,7 @@ int config_CreateDir( vlc_object_t *p_this, const char *psz_dirname ) { 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 ) @@ -344,14 +356,14 @@ int config_CreateDir( vlc_object_t *p_this, const char *psz_dirname ) *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; } @@ -426,7 +438,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" ); - goto error; + return -1; } file = config_OpenConfigFile( p_this ); @@ -527,14 +539,18 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, goto error; } + /* Configuration lock must be taken before vlcrc serializer below. */ + vlc_rwlock_rdlock (&config_lock); + /* 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); + int fd = vlc_open (temporary, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR); if (fd == -1) { + vlc_rwlock_unlock (&config_lock); vlc_mutex_unlock (&lock); module_list_free (list); goto error; @@ -542,19 +558,32 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, 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); module_list_free (list); 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++ ) { @@ -586,15 +615,13 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, || 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; + int64_t val = b_retain ? p_item->saved.i : p_item->value.i; if (p_item->i_type == CONFIG_ITEM_KEY) { char *psz_key = ConfigKeyToString (val); @@ -609,7 +636,7 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, (p_item->i_type == CONFIG_ITEM_BOOL) ? N_("boolean") : N_("integer"), val == p_item->orig.i, - p_item->psz_name, "%d", val); + p_item->psz_name, "%"PRId64, val); p_item->saved.i = val; } else @@ -658,9 +685,9 @@ 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); } } + vlc_rwlock_unlock (&config_lock); module_list_free (list); if (loc != (locale_t)0) @@ -679,11 +706,23 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, * Flush to disk and replace atomically */ fflush (file); /* Flush from run-time */ + if (ferror (file)) + { + vlc_unlink (temporary); + vlc_mutex_unlock (&lock); + msg_Err (p_this, "cannot write configuration file"); + clearerr (file); + goto error; + } #ifndef WIN32 +#ifdef __APPLE__ + fsync (fd); /* Flush from OS */ +#else fdatasync (fd); /* Flush from OS */ +#endif /* Atomically replace the file... */ - if (utf8_rename (temporary, permanent)) - utf8_unlink (temporary); + if (vlc_rename (temporary, permanent)) + vlc_unlink (temporary); /* (...then synchronize the directory, err, TODO...) */ /* ...and finally close the file */ vlc_mutex_unlock (&lock); @@ -691,9 +730,9 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, fclose (file); #ifdef WIN32 /* Windows cannot remove open files nor overwrite existing ones */ - utf8_unlink (permanent); - if (utf8_rename (temporary, permanent)) - utf8_unlink (temporary); + vlc_unlink (permanent); + if (vlc_rename (temporary, permanent)) + vlc_unlink (temporary); vlc_mutex_unlock (&lock); #endif @@ -712,14 +751,15 @@ error: int config_AutoSaveConfigFile( vlc_object_t *p_this ) { - size_t i_index; + int ret = VLC_SUCCESS; bool save = false; assert( p_this ); /* Check if there's anything to save */ module_t **list = module_list_get (NULL); - for( i_index = 0; list[i_index] && !save; i_index++ ) + vlc_rwlock_rdlock (&config_lock); + for (size_t i_index = 0; list[i_index] && !save; i_index++) { module_t *p_parser = list[i_index]; module_config_t *p_item, *p_end; @@ -730,17 +770,21 @@ int config_AutoSaveConfigFile( vlc_object_t *p_this ) p_item < p_end && !save; p_item++ ) { - vlc_mutex_lock (p_item->p_lock); save = p_item->b_autosave && p_item->b_dirty; - vlc_mutex_unlock (p_item->p_lock); } } - module_list_free (list); - return save ? VLC_SUCCESS : SaveConfigFile( p_this, NULL, true ); + if (save) + /* Note: this will get the read lock recursively. Ok. */ + ret = SaveConfigFile (p_this, NULL, true); + vlc_rwlock_unlock (&config_lock); + + module_list_free (list); + return ret; } -int __config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name ) +#undef config_SaveConfigFile +int config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name ) { return SaveConfigFile( p_this, psz_module_name, false ); }