Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/src/modules/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 18 kB image not shown  

Quelle  cache.c   Sprache: C

 

/*****************************************************************************
 * cache.c: Plugins cache
 *****************************************************************************
 * Copyright (C) 2001-2007 VLC authors and VideoLAN
 *
 * Authors: Sam Hocevar <sam@zoy.org>
 *          Ethan C. Baldridge <BaldridgeE@cadmus.com>
 *          Hans-Peter Jansen <hpj@urpla.net>
 *          Gildas Bazin <gbazin@videolan.org>
 *
 * 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 Lesser General Public License for more details.
 *
 * 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 <stdalign.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <assert.h>

#include <vlc_common.h>
#include <vlc_block.h>
#include "../libvlc.h"

#include <vlc_plugin.h>
#include <errno.h>

#include "config/configuration.h"

#include <vlc_fs.h>

#include "modules/modules.h"


/*****************************************************************************
 * Local prototypes
 *****************************************************************************/

#ifdef HAVE_DYNAMIC_PLUGINS
/* Sub-version number
 * (only used to avoid breakage in dev version when cache structure changes) */

#define CACHE_SUBVERSION_NUM 36

/* Cache filename */
#define CACHE_NAME "plugins.dat"
/* Magic for the cache filename */
#define CACHE_STRING "cache "PACKAGE_NAME" "PACKAGE_VERSION


static int vlc_cache_load_immediate(void *out, block_t *in, size_t size)
{
    if (in->i_buffer < size)
        return -1;

    memcpy(out, in->p_buffer, size);
    in->p_buffer += size;
    in->i_buffer -= size;
    return 0;
}

static int vlc_cache_load_bool(bool *out, block_t *in)
{
    unsigned char b;

    if (vlc_cache_load_immediate(&b, in, 1) || b > 1)
        return -1;

    *out = b;
    return 0;
}

static int vlc_cache_load_array(const void **p, size_t size, size_t n,
                                block_t *file)
{
    if (n == 0)
    {
        *p = NULL;
        return 0;
    }

    if (unlikely(size * n < size))
        return -1;

    size *= n;

    if (file->i_buffer < size)
        return -1;

    *p = file->p_buffer;
    file->p_buffer += size;
    file->i_buffer -= size;
    return 0;
}

static int vlc_cache_load_string(const char **restrict p, block_t *file)
{
    uint16_t size;

    if (vlc_cache_load_immediate(&size, file, sizeof (size)) || size > 16384)
        return -1;

    if (size == 0)
    {
        *p = NULL;
        return 0;
    }

    const char *str = (char *)file->p_buffer;

    if (file->i_buffer < size || str[size - 1] != '\0')
        return -1;

    file->p_buffer += size;
    file->i_buffer -= size;
    *p = str;
    return 0;
}

static int vlc_cache_load_align(size_t align, block_t *file)
{
    assert(align > 0);

    size_t skip = (-(uintptr_t)file->p_buffer) % align;
    if (skip == 0)
        return 0;

    assert(skip < align);

    if (file->i_buffer < skip)
        return -1;

    file->p_buffer += skip;
    file->i_buffer -= skip;
    assert((((uintptr_t)file->p_buffer) % align) == 0);
    return 0;
}

#define LOAD_IMMEDIATE(a) \
    if (vlc_cache_load_immediate(&(a), file, sizeof (a))) \
        goto error
#define LOAD_FLAG(a) \
    do \
    { \
        bool b; \
        if (vlc_cache_load_bool(&b, file)) \
            goto error; \
        (a) = b; \
    } while (0)
#define LOAD_ARRAY(a,n) \
    do \
    { \
        const void *base; \
        if (vlc_cache_load_array(&base, sizeof (*(a)), (n), file)) \
            goto error; \
        (a) = base; \
    } while (0)
#define LOAD_STRING(a) \
    if (vlc_cache_load_string(&(a), file)) \
        goto error
#define LOAD_ALIGNOF(t) \
    if (vlc_cache_load_align(alignof(t), file)) \
        goto error

static int vlc_cache_load_config(struct vlc_param *param, block_t *file)
{
    module_config_t *cfg = ¶m->item;

    LOAD_IMMEDIATE (cfg->i_type);
    LOAD_IMMEDIATE (param->shortname);
    LOAD_FLAG (param->internal);
    LOAD_FLAG (param->unsaved);
    LOAD_FLAG (param->safe);
    LOAD_FLAG (param->obsolete);
    LOAD_STRING (cfg->psz_type);
    LOAD_STRING (cfg->psz_name);
    LOAD_STRING (cfg->psz_text);
    LOAD_STRING (cfg->psz_longtext);
    LOAD_IMMEDIATE (cfg->list_count);

    if (IsConfigStringType (cfg->i_type))
    {
        const char *psz;
        LOAD_STRING(psz);
        cfg->orig.psz = (char *)psz;
        atomic_init(¶m->value.str, NULL);
        vlc_param_SetString(param, psz);

        if (cfg->list_count)
            cfg->list.psz = xmalloc (cfg->list_count * sizeof (char *));
        for (unsigned i = 0; i < cfg->list_count; i++)
        {
            LOAD_STRING (cfg->list.psz[i]);
            if (cfg->list.psz[i] == NULL /* NULL -> empty string */
             && (cfg->list.psz[i] = calloc (1, 1)) == NULL)
                goto error;
        }
    }
    else
    {
        LOAD_IMMEDIATE (cfg->orig);
        LOAD_IMMEDIATE (cfg->min);
        LOAD_IMMEDIATE (cfg->max);
        if (IsConfigFloatType(cfg->i_type))
            atomic_store_explicit(¶m->value.f, cfg->orig.f,
                                  memory_order_relaxed);
        else
            atomic_store_explicit(¶m->value.i, cfg->orig.i,
                                  memory_order_relaxed);
        cfg->value = cfg->orig;

        if (cfg->list_count)
        {
            LOAD_ALIGNOF(int);
        }

        LOAD_ARRAY(cfg->list.i, cfg->list_count);
    }

    cfg->list_text = xmalloc (cfg->list_count * sizeof (char *));
    for (unsigned i = 0; i < cfg->list_count; i++)
    {
        LOAD_STRING (cfg->list_text[i]);
        if (cfg->list_text[i] == NULL /* NULL -> empty string */
         && (cfg->list_text[i] = calloc (1, 1)) == NULL)
            goto error;
    }

    return 0;
error:
    return -1; /* FIXME: leaks */
}

static int vlc_cache_load_plugin_config(vlc_plugin_t *plugin, block_t *file)
{
    uint16_t lines;

    /* Calculate the structure length */
    LOAD_IMMEDIATE (lines);

    /* Allocate memory */
    if (lines)
    {
        plugin->conf.params = calloc(lines, sizeof (struct vlc_param));
        if (unlikely(plugin->conf.params == NULL))
        {
            plugin->conf.size = 0;
            return -1;
        }
    }
    else
        plugin->conf.params = NULL;

    plugin->conf.size = lines;

    /* Do the duplication job */
    for (size_t i = 0; i < lines; i++)
    {
        struct vlc_param *param = plugin->conf.params + i;
        module_config_t *item = ¶m->item;

        if (vlc_cache_load_config(param, file))
            return -1;

        if (CONFIG_ITEM(item->i_type))
        {
            plugin->conf.count++;
            if (item->i_type == CONFIG_ITEM_BOOL)
                plugin->conf.booleans++;
        }
        param->owner = plugin;
    }

    return 0;
error:
    return -1; /* FIXME: leaks */
}

static int vlc_cache_load_module(vlc_plugin_t *plugin, block_t *file)
{
    module_t *module = vlc_module_create(plugin);
    if (unlikely(module == NULL))
        return -1;

    LOAD_STRING(module->psz_shortname);
    LOAD_STRING(module->psz_longname);
    LOAD_STRING(module->psz_help);
    LOAD_STRING(module->psz_help_html);

    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->activate_name);
    LOAD_STRING(module->deactivate_name);
    LOAD_STRING(module->psz_capability);
    LOAD_IMMEDIATE(module->i_score);
    return 0;
error:
    return -1;
}

static vlc_plugin_t *vlc_cache_load_plugin(block_t *file)
{
    vlc_plugin_t *plugin = vlc_plugin_create();
    if (unlikely(plugin == NULL))
        return NULL;

    uint32_t modules;
    LOAD_IMMEDIATE(modules);

    for (size_t i = 0; i < modules; i++)
        if (vlc_cache_load_module(plugin, file))
            goto error;

    if (vlc_cache_load_plugin_config(plugin, file))
        goto error;

    LOAD_STRING(plugin->textdomain);

    const char *path;
    LOAD_STRING(path);
    if (path == NULL)
        goto error;

    plugin->path = strdup(path);
    if (unlikely(plugin->path == NULL))
        goto error;

    LOAD_FLAG(plugin->unloadable);
    LOAD_IMMEDIATE(plugin->mtime);
    LOAD_IMMEDIATE(plugin->size);

    if (plugin->textdomain != NULL)
        vlc_bindtextdomain(plugin->textdomain);

    return plugin;

error:
    vlc_plugin_destroy(plugin);
    return NULL;
}

/**
 * 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.
 */

vlc_plugin_t *vlc_cache_load(libvlc_int_t *p_this, const char *dir,
                             block_t **backingp)
{
    char *psz_filename;

    assert( dir != NULL );

    if( asprintf( &psz_filename, "%s"DIR_SEP CACHE_NAME, dir ) == -1 )
        return NULL;

    msg_Dbg( p_this, "loading plugins cache file %s", psz_filename );

    block_t *file = block_FilePath(psz_filename, false);
    if (file == NULL)
        msg_Warn(p_this, "cannot read %s: %s", psz_filename,
                 vlc_strerror_c(errno));
    free(psz_filename);
    if (file == NULL)
        return NULL;

    /* Check the file is a plugins cache */
    char cachestr[sizeof (CACHE_STRING) - 1];

    if (vlc_cache_load_immediate(cachestr, file, sizeof (cachestr))
     || memcmp(cachestr, CACHE_STRING, sizeof (cachestr)))
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache" );
        block_Release(file);
        return NULL;
    }

#ifdef DISTRO_VERSION
    /* Check for distribution specific version */
    char distrostr[sizeof (DISTRO_VERSION) - 1];

    if (vlc_cache_load_immediate(distrostr, file, sizeof (distrostr))
     || memcmp(distrostr, DISTRO_VERSION, sizeof (distrostr)))
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache" );
        block_Release(file);
        return NULL;
    }
#endif

    /* Check sub-version number */
    uint32_t marker;

    if (vlc_cache_load_immediate(&marker, file, sizeof (marker))
     || marker != CACHE_SUBVERSION_NUM)
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(corrupted header)" );
        block_Release(file);
        return NULL;
    }

    /* Check header marker */
    if (vlc_cache_load_immediate(&marker, file, sizeof (marker))
#ifdef DISTRO_VERSION
     || marker != (sizeof (cachestr) + sizeof (distrostr) + sizeof (marker))
#else
     || marker != (sizeof (cachestr) + sizeof (marker))
#endif
        )
    {
        msg_Warn( p_this, "This doesn't look like a valid plugins cache "
                  "(corrupted header)" );
        block_Release(file);
        return NULL;
    }

    vlc_plugin_t *cache = NULL;

    while (file->i_buffer > 0)
    {
        vlc_plugin_t *plugin = vlc_cache_load_plugin(file);
        if (plugin == NULL)
            goto error;

        if (unlikely(asprintf(&plugin->abspath, "%s" DIR_SEP "%s", dir,
                              plugin->path) == -1))
        {
            plugin->abspath = NULL;
            vlc_plugin_destroy(plugin);
            goto error;
        }

        plugin->next = cache;
        cache = plugin;
    }

    file->p_next = *backingp;
    *backingp = file;
    return cache;

error:
    msg_Warn( p_this, "plugins cache not loaded (corrupted)" );

    /* TODO: cleanup */
    block_Release(file);
    return NULL;
}

#define SAVE_IMMEDIATE( a ) \
    if (fwrite (&(a), sizeof(a), 1, file) != 1) \
        goto error
#define SAVE_FLAG(a) \
    do { \
        char b = (a); \
        SAVE_IMMEDIATE(b); \
    } while (0)

static int CacheSaveString (FILE *file, const char *str)
{
    uint16_t size = (str != NULL) ? (strlen (str) + 1) : 0;

    SAVE_IMMEDIATE (size);
    if (size != 0 && fwrite(str, 1, size, file) != size)
    {
error:
        return -1;
    }
    return 0;
}

#define SAVE_STRING( a ) \
    if (CacheSaveString (file, (a))) \
        goto error

static int CacheSaveAlign(FILE *file, size_t align)
{
    assert(align > 0);

    size_t skip = (-ftell(file)) % align;
    if (skip == 0)
        return 0;

    assert(((ftell(file) + skip) % align) == 0);
    return fseek(file, skip, SEEK_CUR);
}

#define SAVE_ALIGNOF(t) \
    if (CacheSaveAlign(file, alignof (t))) \
        goto error

static int CacheSaveConfig(FILE *file, const struct vlc_param *param)
{
    const module_config_t *cfg = ¶m->item;

    SAVE_IMMEDIATE (cfg->i_type);
    SAVE_IMMEDIATE (param->shortname);
    SAVE_FLAG (param->internal);
    SAVE_FLAG (param->unsaved);
    SAVE_FLAG (param->safe);
    SAVE_FLAG (param->obsolete);
    SAVE_STRING (cfg->psz_type);
    SAVE_STRING (cfg->psz_name);
    SAVE_STRING (cfg->psz_text);
    SAVE_STRING (cfg->psz_longtext);
    SAVE_IMMEDIATE (cfg->list_count);

    if (IsConfigStringType (cfg->i_type))
    {
        SAVE_STRING (cfg->orig.psz);

        for (unsigned i = 0; i < cfg->list_count; i++)
            SAVE_STRING (cfg->list.psz[i]);
    }
    else
    {
        SAVE_IMMEDIATE (cfg->orig);
        SAVE_IMMEDIATE (cfg->min);
        SAVE_IMMEDIATE (cfg->max);

        if (cfg->list_count > 0)
        {
            SAVE_ALIGNOF(int);
        }

        for (unsigned i = 0; i < cfg->list_count; i++)
             SAVE_IMMEDIATE (cfg->list.i[i]);
    }
    for (unsigned i = 0; i < cfg->list_count; i++)
        SAVE_STRING (cfg->list_text[i]);

    return 0;
error:
    return -1;
}

static int CacheSaveModuleConfig(FILE *file, const vlc_plugin_t *plugin)
{
    uint16_t lines = plugin->conf.size;

    SAVE_IMMEDIATE (lines);

    for (size_t i = 0; i < lines; i++)
        if (CacheSaveConfig(file, plugin->conf.params + i))
           goto error;

    return 0;
error:
    return -1;
}

static int CacheSaveModule(FILE *file, const module_t *module)
{
    SAVE_STRING(module->psz_shortname);
    SAVE_STRING(module->psz_longname);
    SAVE_STRING(module->psz_help);
    SAVE_STRING(module->psz_help_html);
    SAVE_IMMEDIATE(module->i_shortcuts);

    for (size_t j = 0; j < module->i_shortcuts; j++)
         SAVE_STRING(module->pp_shortcuts[j]);

    SAVE_STRING(module->activate_name);
    SAVE_STRING(module->deactivate_name);
    SAVE_STRING(module->psz_capability);
    SAVE_IMMEDIATE(module->i_score);
    return 0;
error:
    return -1;
}

static int CacheSaveBank(FILE *file, vlc_plugin_t *const *cache, size_t n)
{
    uint32_t i_file_size = 0;

    /* Contains version number */
    if (fputs (CACHE_STRING, file) == EOF)
        goto error;
#ifdef DISTRO_VERSION
    /* Allow binary maintainer to pass a string to detect new binary version*/
    if (fputs( DISTRO_VERSION, file ) == EOF)
        goto error;
#endif
    /* Sub-version number (to avoid breakage in the dev version when cache
     * structure changes) */

    i_file_size = CACHE_SUBVERSION_NUM;
    if (fwrite (&i_file_size, sizeof (i_file_size), 1, file) != 1 )
        goto error;

    /* Header marker */
    i_file_size = ftell( file );
    if (fwrite (&i_file_size, sizeof (i_file_size), 1, file) != 1)
        goto error;

    for (size_t i = 0; i < n; i++)
    {
        const vlc_plugin_t *plugin = cache[i];
        uint32_t count = plugin->modules_count;

        SAVE_IMMEDIATE(count);

        for (module_t *module = plugin->module;
             module != NULL;
             module = module->next)
            if (CacheSaveModule(file, module))
                goto error;

        /* Config stuff */
        if (CacheSaveModuleConfig(file, plugin))
            goto error;

        /* Save common info */
        SAVE_STRING(plugin->textdomain);
        SAVE_STRING(plugin->path);
        SAVE_FLAG(plugin->unloadable);
        SAVE_IMMEDIATE(plugin->mtime);
        SAVE_IMMEDIATE(plugin->size);
    }

    if (fflush (file)) /* flush libc buffers */
        goto error;
    return 0; /* success! */

error:
    return -1;
}

/**
 * Saves a module cache to disk, and release cache data from memory.
 */

void CacheSave(libvlc_int_t *p_this, const char *dir,
               vlc_plugin_t *const *entries, size_t n)
{
    char *filename = NULL, *tmpname = NULL;

    if (asprintf (&filename, "%s"DIR_SEP CACHE_NAME, dir ) == -1)
        return;

    if (asprintf (&tmpname, "%s.%"PRIu32, filename, (uint32_t)getpid ()) == -1)
    {
        free (filename);
        return;
    }
    msg_Dbg (p_this, "saving plugins cache %s", filename);

    FILE *file = vlc_fopen (tmpname, "wb");
    if (file == NULL)
    {
        if (errno != EACCES && errno != ENOENT)
            msg_Warn (p_this, "cannot create %s: %s", tmpname,
                      vlc_strerror_c(errno));
        goto out;
    }

    if (CacheSaveBank(file, entries, n))
    {
        msg_Warn (p_this, "cannot write %s: %s", tmpname,
                  vlc_strerror_c(errno));
        clearerr (file);
        fclose (file);
        vlc_unlink (tmpname);
        goto out;
    }

#if !defined( _WIN32 ) && !defined( __OS2__ )
    vlc_rename (tmpname, filename); /* atomically replace old cache */
    fclose (file);
#else
    vlc_unlink (filename);
    fclose (file);
    vlc_rename (tmpname, filename);
#endif
out:
    free (filename);
    free (tmpname);
}

/**
 * Looks up a plugin file in a table of cached plugins.
 */

vlc_plugin_t *vlc_cache_lookup(vlc_plugin_t **cache, const char *path)
{
    vlc_plugin_t **pp = cache, *plugin;

    while ((plugin = *pp) != NULL)
    {
        if (plugin->path != NULL && !strcmp(plugin->path, path))
        {
            *pp = plugin->next;
            plugin->next = NULL;
            return plugin;
        }

        pp = &plugin->next;
    }

    return NULL;
}
#endif /* HAVE_DYNAMIC_PLUGINS */

Messung
CHZG
839410092

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.