/** * Loads a plugins cache file. * * This function will load the plugin cache if present and valid. This cache * will in turn be queried by AllocateAllPlugins() to see if it needs to * actually load the dynamically loadable module. * This allows us to only fully load plugins when they are actually used. */ size_t CacheLoad( vlc_object_t *p_this, const char *dir, module_cache_t **r ) { char *psz_filename; FILE *file; int i_size, i_read; char p_cachestring[sizeof(CACHE_STRING)]; size_t i_cache; int32_t i_marker; assert( dir != NULL ); *r = NULL; if( asprintf( &psz_filename, "%s"DIR_SEP CACHE_NAME, dir ) == -1 ) return 0; msg_Dbg( p_this, "loading plugins cache file %s", psz_filename ); file = vlc_fopen( psz_filename, "rb" ); if( !file ) { msg_Warn( p_this, "cannot read %s: %s", psz_filename, vlc_strerror_c(errno) ); free( psz_filename ); return 0; } free( psz_filename ); /* Check the file is a plugins cache */ i_size = sizeof(CACHE_STRING) - 1; i_read = fread( p_cachestring, 1, i_size, file ); if( i_read != i_size || memcmp( p_cachestring, CACHE_STRING, i_size ) ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache" ); fclose( file ); return 0; } #ifdef DISTRO_VERSION /* Check for distribution specific version */ char p_distrostring[sizeof( DISTRO_VERSION )]; i_size = sizeof( DISTRO_VERSION ) - 1; i_read = fread( p_distrostring, 1, i_size, file ); if( i_read != i_size || memcmp( p_distrostring, DISTRO_VERSION, i_size ) ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache" ); fclose( file ); return 0; } #endif /* Check Sub-version number */ i_read = fread( &i_marker, 1, sizeof(i_marker), file ); if( i_read != sizeof(i_marker) || i_marker != CACHE_SUBVERSION_NUM ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache " "(corrupted header)" ); fclose( file ); return 0; } /* Check header marker */ i_read = fread( &i_marker, 1, sizeof(i_marker), file ); if( i_read != sizeof(i_marker) || i_marker != ftell( file ) - (int)sizeof(i_marker) ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache " "(corrupted header)" ); fclose( file ); return 0; } if (fread( &i_cache, 1, sizeof(i_cache), file ) != sizeof(i_cache) ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache " "(file too short)" ); fclose( file ); return 0; } module_cache_t *cache = NULL; for (size_t count = 0; count < i_cache;) { module_t *module; int i_submodules; module = vlc_module_create (NULL); /* Load additional infos */ LOAD_STRING(module->psz_shortname); LOAD_STRING(module->psz_longname); LOAD_STRING(module->psz_help); LOAD_IMMEDIATE(module->i_shortcuts); if (module->i_shortcuts > MODULE_SHORTCUT_MAX) goto error; else { module->pp_shortcuts = xmalloc (sizeof (*module->pp_shortcuts) * module->i_shortcuts); for (unsigned j = 0; j < module->i_shortcuts; j++) LOAD_STRING(module->pp_shortcuts[j]); } LOAD_STRING(module->psz_capability); LOAD_IMMEDIATE(module->i_score); LOAD_IMMEDIATE(module->b_unloadable); /* Config stuff */ if (CacheLoadModuleConfig (module, file) != VLC_SUCCESS) goto error; LOAD_STRING(module->domain); if (module->domain != NULL) vlc_bindtextdomain (module->domain); LOAD_IMMEDIATE( i_submodules ); while( i_submodules-- ) { module_t *submodule = vlc_module_create (module); free (submodule->pp_shortcuts); LOAD_STRING(submodule->psz_shortname); LOAD_STRING(submodule->psz_longname); LOAD_IMMEDIATE(submodule->i_shortcuts); if (submodule->i_shortcuts > MODULE_SHORTCUT_MAX) goto error; else { submodule->pp_shortcuts = xmalloc (sizeof (*submodule->pp_shortcuts) * submodule->i_shortcuts); for (unsigned j = 0; j < submodule->i_shortcuts; j++) LOAD_STRING(submodule->pp_shortcuts[j]); } LOAD_STRING(submodule->psz_capability); LOAD_IMMEDIATE(submodule->i_score); } char *path; struct stat st; /* Load common info */ LOAD_STRING(path); if (path == NULL) goto error; LOAD_IMMEDIATE(st.st_mtime); LOAD_IMMEDIATE(st.st_size); CacheAdd (&cache, &count, path, &st, module); free (path); /* TODO: deal with errors */ } fclose( file ); *r = cache; return i_cache; error: msg_Warn( p_this, "plugins cache not loaded (corrupted)" ); /* TODO: cleanup */ fclose( file ); return 0; }
/** * Callback for the plugin descriptor functions. */ static int vlc_plugin_setter (void *plugin, void *tgt, int propid, ...) { module_t **pprimary = plugin; module_t *module = tgt; module_config_t *item = tgt; va_list ap; int ret = 0; va_start (ap, propid); switch (propid) { case VLC_MODULE_CREATE: { module = *pprimary; module_t *submodule = vlc_module_create (module); if (unlikely(submodule == NULL)) { ret = -1; break; } *(va_arg (ap, module_t **)) = submodule; if (*pprimary == NULL) { *pprimary = submodule; break; } /* Inheritance. Ugly!! */ submodule->pp_shortcuts = xmalloc (sizeof ( *submodule->pp_shortcuts )); submodule->pp_shortcuts[0] = strdup_null (module->pp_shortcuts[0]); submodule->i_shortcuts = 1; /* object name */ submodule->psz_shortname = strdup_null (module->psz_shortname); submodule->psz_longname = strdup_null (module->psz_longname); submodule->psz_capability = strdup_null (module->psz_capability); break; } case VLC_CONFIG_CREATE: { int type = va_arg (ap, int); module_config_t **pp = va_arg (ap, module_config_t **); item = vlc_config_create (*pprimary, type); if (unlikely(item == NULL)) { ret = -1; break; } *pp = item; break; } case VLC_MODULE_SHORTCUT: { unsigned i_shortcuts = va_arg (ap, unsigned); unsigned index = module->i_shortcuts; /* The cache loader accept only a small number of shortcuts */ assert(i_shortcuts + index <= MODULE_SHORTCUT_MAX); const char *const *tab = va_arg (ap, const char *const *); char **pp = realloc (module->pp_shortcuts, sizeof (pp[0]) * (index + i_shortcuts)); if (unlikely(pp == NULL)) { ret = -1; break; } module->pp_shortcuts = pp; module->i_shortcuts = index + i_shortcuts; pp += index; for (unsigned i = 0; i < i_shortcuts; i++) pp[i] = strdup (tab[i]); break; } case VLC_MODULE_CAPABILITY: free (module->psz_capability); module->psz_capability = strdup (va_arg (ap, char *)); break; case VLC_MODULE_SCORE: module->i_score = va_arg (ap, int); break; case VLC_MODULE_CB_OPEN: module->pf_activate = va_arg (ap, void *); break; case VLC_MODULE_CB_CLOSE: module->pf_deactivate = va_arg (ap, void *); break; case VLC_MODULE_NO_UNLOAD: assert (module->parent == NULL); module->b_unloadable = false; break; case VLC_MODULE_NAME: { const char *value = va_arg (ap, const char *); assert (module->i_shortcuts == 0); module->pp_shortcuts = malloc( sizeof( *module->pp_shortcuts ) ); module->pp_shortcuts[0] = strdup (value); module->i_shortcuts = 1; assert (module->psz_longname == NULL); module->psz_longname = strdup (value); break; } case VLC_MODULE_SHORTNAME: assert (module->psz_shortname == NULL || module->parent != NULL); free (module->psz_shortname); module->psz_shortname = strdup (va_arg (ap, char *)); break; case VLC_MODULE_DESCRIPTION: // TODO: do not set this in VLC_MODULE_NAME free (module->psz_longname); module->psz_longname = strdup (va_arg (ap, char *)); break; case VLC_MODULE_HELP: assert (module->parent == NULL); assert (module->psz_help == NULL); module->psz_help = strdup (va_arg (ap, char *)); break; case VLC_MODULE_TEXTDOMAIN: assert (module->parent == NULL); assert (module->domain == NULL); module->domain = strdup (va_arg (ap, char *)); break; case VLC_CONFIG_NAME: { const char *name = va_arg (ap, const char *); assert (name != NULL); item->psz_name = strdup (name); break; } case VLC_CONFIG_VALUE: { if (IsConfigIntegerType (item->i_type) || !CONFIG_ITEM(item->i_type)) { item->orig.i = item->value.i = va_arg (ap, int64_t); } else if (IsConfigFloatType (item->i_type)) { item->orig.f = item->value.f = va_arg (ap, double); } else if (IsConfigStringType (item->i_type)) { const char *value = va_arg (ap, const char *); item->value.psz = value ? strdup (value) : NULL; item->orig.psz = value ? strdup (value) : NULL; } break; }
/** * Loads a plugins cache file. * * This function will load the plugin cache if present and valid. This cache * will in turn be queried by AllocateAllPlugins() to see if it needs to * actually load the dynamically loadable module. * This allows us to only fully load plugins when they are actually used. */ size_t CacheLoad( vlc_object_t *p_this, const char *dir, module_cache_t ***r ) { char *psz_filename; FILE *file; int i_size, i_read; char p_cachestring[sizeof(CACHE_STRING)]; size_t i_cache; int32_t i_file_size, i_marker; assert( dir != NULL ); *r = NULL; if( asprintf( &psz_filename, "%s"DIR_SEP CACHE_NAME, dir ) == -1 ) return 0; msg_Dbg( p_this, "loading plugins cache file %s", psz_filename ); file = vlc_fopen( psz_filename, "rb" ); if( !file ) { msg_Warn( p_this, "cannot read %s (%m)", psz_filename ); free( psz_filename ); return 0; } free( psz_filename ); /* Check the file size */ i_read = fread( &i_file_size, 1, sizeof(i_file_size), file ); if( i_read != sizeof(i_file_size) ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache " "(too short)" ); fclose( file ); return 0; } fseek( file, 0, SEEK_END ); if( ftell( file ) != i_file_size ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache " "(corrupted size)" ); fclose( file ); return 0; } fseek( file, sizeof(i_file_size), SEEK_SET ); /* Check the file is a plugins cache */ i_size = sizeof(CACHE_STRING) - 1; i_read = fread( p_cachestring, 1, i_size, file ); if( i_read != i_size || memcmp( p_cachestring, CACHE_STRING, i_size ) ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache" ); fclose( file ); return 0; } #ifdef DISTRO_VERSION /* Check for distribution specific version */ char p_distrostring[sizeof( DISTRO_VERSION )]; i_size = sizeof( DISTRO_VERSION ) - 1; i_read = fread( p_distrostring, 1, i_size, file ); if( i_read != i_size || memcmp( p_distrostring, DISTRO_VERSION, i_size ) ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache" ); fclose( file ); return 0; } #endif /* Check Sub-version number */ i_read = fread( &i_marker, 1, sizeof(i_marker), file ); if( i_read != sizeof(i_marker) || i_marker != CACHE_SUBVERSION_NUM ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache " "(corrupted header)" ); fclose( file ); return 0; } /* Check header marker */ i_read = fread( &i_marker, 1, sizeof(i_marker), file ); if( i_read != sizeof(i_marker) || i_marker != ftell( file ) - (int)sizeof(i_marker) ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache " "(corrupted header)" ); fclose( file ); return 0; } if (fread( &i_cache, 1, sizeof(i_cache), file ) != sizeof(i_cache) ) { msg_Warn( p_this, "This doesn't look like a valid plugins cache " "(file too short)" ); fclose( file ); return 0; } module_cache_t **pp_cache = malloc( i_cache * sizeof(*pp_cache) ); if( pp_cache == NULL ) i_cache = 0; /* don't load anything */ #define LOAD_IMMEDIATE(a) \ if( fread( (void *)&a, sizeof(char), sizeof(a), file ) != sizeof(a) ) goto error #define LOAD_STRING(a) \ { \ a = NULL; \ if( ( fread( &i_size, sizeof(i_size), 1, file ) != 1 ) \ || ( i_size > 16384 ) ) \ goto error; \ if( i_size ) { \ char *psz = xmalloc( i_size ); \ if( fread( psz, i_size, 1, file ) != 1 ) { \ free( psz ); \ goto error; \ } \ if( psz[i_size-1] ) { \ free( psz ); \ goto error; \ } \ a = psz; \ } \ } for( size_t i = 0; i < i_cache; i++ ) { uint16_t i_size; int i_submodules; pp_cache[i] = xmalloc( sizeof(module_cache_t) ); /* Load common info */ LOAD_STRING( pp_cache[i]->path ); LOAD_IMMEDIATE( pp_cache[i]->mtime ); LOAD_IMMEDIATE( pp_cache[i]->size ); pp_cache[i]->p_module = vlc_module_create(); /* Load additional infos */ free( pp_cache[i]->p_module->psz_object_name ); LOAD_STRING( pp_cache[i]->p_module->psz_object_name ); LOAD_STRING( pp_cache[i]->p_module->psz_shortname ); LOAD_STRING( pp_cache[i]->p_module->psz_longname ); LOAD_STRING( pp_cache[i]->p_module->psz_help ); LOAD_IMMEDIATE( pp_cache[i]->p_module->i_shortcuts ); if( pp_cache[i]->p_module->i_shortcuts > MODULE_SHORTCUT_MAX ) goto error; else if( pp_cache[i]->p_module->i_shortcuts == 0 ) pp_cache[i]->p_module->pp_shortcuts = NULL; else { pp_cache[i]->p_module->pp_shortcuts = xmalloc( sizeof( char ** ) * pp_cache[i]->p_module->i_shortcuts ); for( unsigned j = 0; j < pp_cache[i]->p_module->i_shortcuts; j++ ) LOAD_STRING( pp_cache[i]->p_module->pp_shortcuts[j] ); } LOAD_STRING( pp_cache[i]->p_module->psz_capability ); LOAD_IMMEDIATE( pp_cache[i]->p_module->i_score ); LOAD_IMMEDIATE( pp_cache[i]->p_module->b_unloadable ); /* Config stuff */ if( CacheLoadConfig( pp_cache[i]->p_module, file ) != VLC_SUCCESS ) goto error; LOAD_STRING( pp_cache[i]->p_module->psz_filename ); LOAD_STRING( pp_cache[i]->p_module->domain ); if( pp_cache[i]->p_module->domain != NULL ) vlc_bindtextdomain( pp_cache[i]->p_module->domain ); LOAD_IMMEDIATE( i_submodules ); while( i_submodules-- ) { module_t *p_module = vlc_submodule_create( pp_cache[i]->p_module ); free( p_module->psz_object_name ); free( p_module->pp_shortcuts ); LOAD_STRING( p_module->psz_object_name ); LOAD_STRING( p_module->psz_shortname ); LOAD_STRING( p_module->psz_longname ); LOAD_STRING( p_module->psz_help ); LOAD_IMMEDIATE( p_module->i_shortcuts ); if( p_module->i_shortcuts > MODULE_SHORTCUT_MAX ) goto error; else if( p_module->i_shortcuts == 0 ) p_module->pp_shortcuts = NULL; else { p_module->pp_shortcuts = xmalloc( sizeof( char ** ) * p_module->i_shortcuts ); for( unsigned j = 0; j < p_module->i_shortcuts; j++ ) LOAD_STRING( p_module->pp_shortcuts[j] ); } LOAD_STRING( p_module->psz_capability ); LOAD_IMMEDIATE( p_module->i_score ); LOAD_IMMEDIATE( p_module->b_unloadable ); LOAD_STRING( p_module->domain ); } } fclose( file ); *r = pp_cache; return i_cache; error: msg_Warn( p_this, "plugins cache not loaded (corrupted)" ); /* TODO: cleanup */ fclose( file ); return 0; }
static module_t *CacheLoadModule (FILE *file) { module_t *module = vlc_module_create (NULL); if (unlikely(module == NULL)) return NULL; /* Load additional infos */ LOAD_STRING(module->psz_shortname); LOAD_STRING(module->psz_longname); LOAD_STRING(module->psz_help); LOAD_IMMEDIATE(module->i_shortcuts); if (module->i_shortcuts > MODULE_SHORTCUT_MAX) goto error; else { module->pp_shortcuts = xmalloc (sizeof (*module->pp_shortcuts) * module->i_shortcuts); for (unsigned j = 0; j < module->i_shortcuts; j++) LOAD_STRING(module->pp_shortcuts[j]); } LOAD_STRING(module->psz_capability); LOAD_IMMEDIATE(module->i_score); LOAD_IMMEDIATE(module->b_unloadable); /* Config stuff */ if (CacheLoadModuleConfig (module, file) != VLC_SUCCESS) goto error; LOAD_STRING(module->domain); if (module->domain != NULL) vlc_bindtextdomain (module->domain); uint32_t submodules; LOAD_IMMEDIATE(submodules); for (; submodules > 0; submodules--) { module_t *submodule = vlc_module_create (module); free (submodule->pp_shortcuts); LOAD_STRING(submodule->psz_shortname); LOAD_STRING(submodule->psz_longname); LOAD_IMMEDIATE(submodule->i_shortcuts); if (submodule->i_shortcuts > MODULE_SHORTCUT_MAX) goto error; else { submodule->pp_shortcuts = xmalloc (sizeof (*submodule->pp_shortcuts) * submodule->i_shortcuts); for (unsigned j = 0; j < submodule->i_shortcuts; j++) LOAD_STRING(submodule->pp_shortcuts[j]); } LOAD_STRING(submodule->psz_capability); LOAD_IMMEDIATE(submodule->i_score); } return module; error: vlc_module_destroy(module); return NULL; }