Contribs: detect sidplay2 with pkg-config
[vlc.git] / src / modules / cache.c
bloba9ce8efa9fc06ac1a333a10af9a5f00571afbaca
1 /*****************************************************************************
2 * cache.c: Plugins cache
3 *****************************************************************************
4 * Copyright (C) 2001-2007 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Sam Hocevar <sam@zoy.org>
8 * Ethan C. Baldridge <BaldridgeE@cadmus.com>
9 * Hans-Peter Jansen <hpj@urpla.net>
10 * Gildas Bazin <gbazin@videolan.org>
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <stdalign.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <assert.h>
40 #include <vlc_common.h>
41 #include <vlc_block.h>
42 #include "libvlc.h"
44 #include <vlc_plugin.h>
45 #include <errno.h>
47 #include "config/configuration.h"
49 #include <vlc_fs.h>
51 #include "modules/modules.h"
54 /*****************************************************************************
55 * Local prototypes
56 *****************************************************************************/
57 #ifdef HAVE_DYNAMIC_PLUGINS
58 /* Sub-version number
59 * (only used to avoid breakage in dev version when cache structure changes) */
60 #define CACHE_SUBVERSION_NUM 34
62 /* Cache filename */
63 #define CACHE_NAME "plugins.dat"
64 /* Magic for the cache filename */
65 #define CACHE_STRING "cache "PACKAGE_NAME" "PACKAGE_VERSION
68 static int vlc_cache_load_immediate(void *out, block_t *in, size_t size)
70 if (in->i_buffer < size)
71 return -1;
73 memcpy(out, in->p_buffer, size);
74 in->p_buffer += size;
75 in->i_buffer -= size;
76 return 0;
79 static int vlc_cache_load_bool(bool *out, block_t *in)
81 unsigned char b;
83 if (vlc_cache_load_immediate(&b, in, 1) || b > 1)
84 return -1;
86 *out = b;
87 return 0;
90 static int vlc_cache_load_array(const void **p, size_t size, size_t n,
91 block_t *file)
93 if (n == 0)
95 *p = NULL;
96 return 0;
99 if (unlikely(size * n < size))
100 return -1;
102 size *= n;
104 if (file->i_buffer < size)
105 return -1;
107 *p = file->p_buffer;
108 file->p_buffer += size;
109 file->i_buffer -= size;
110 return 0;
113 static int vlc_cache_load_string(const char **restrict p, block_t *file)
115 uint16_t size;
117 if (vlc_cache_load_immediate(&size, file, sizeof (size)) || size > 16384)
118 return -1;
120 if (size == 0)
122 *p = NULL;
123 return 0;
126 const char *str = (char *)file->p_buffer;
128 if (file->i_buffer < size || str[size - 1] != '\0')
129 return -1;
131 file->p_buffer += size;
132 file->i_buffer -= size;
133 *p = str;
134 return 0;
137 static int vlc_cache_load_align(size_t align, block_t *file)
139 assert(align > 0);
141 size_t skip = (-(uintptr_t)file->p_buffer) % align;
142 if (skip == 0)
143 return 0;
145 assert(skip < align);
147 if (file->i_buffer < skip)
148 return -1;
150 file->p_buffer += skip;
151 file->i_buffer -= skip;
152 assert((((uintptr_t)file->p_buffer) % align) == 0);
153 return 0;
156 #define LOAD_IMMEDIATE(a) \
157 if (vlc_cache_load_immediate(&(a), file, sizeof (a))) \
158 goto error
159 #define LOAD_FLAG(a) \
160 do \
162 bool b; \
163 if (vlc_cache_load_bool(&b, file)) \
164 goto error; \
165 (a) = b; \
166 } while (0)
167 #define LOAD_ARRAY(a,n) \
168 do \
170 const void *base; \
171 if (vlc_cache_load_array(&base, sizeof (*(a)), (n), file)) \
172 goto error; \
173 (a) = base; \
174 } while (0)
175 #define LOAD_STRING(a) \
176 if (vlc_cache_load_string(&(a), file)) \
177 goto error
178 #define LOAD_ALIGNOF(t) \
179 if (vlc_cache_load_align(alignof(t), file)) \
180 goto error
182 static int vlc_cache_load_config(module_config_t *cfg, block_t *file)
184 LOAD_IMMEDIATE (cfg->i_type);
185 LOAD_IMMEDIATE (cfg->i_short);
186 LOAD_FLAG (cfg->b_advanced);
187 LOAD_FLAG (cfg->b_internal);
188 LOAD_FLAG (cfg->b_unsaveable);
189 LOAD_FLAG (cfg->b_safe);
190 LOAD_FLAG (cfg->b_removed);
191 LOAD_STRING (cfg->psz_type);
192 LOAD_STRING (cfg->psz_name);
193 LOAD_STRING (cfg->psz_text);
194 LOAD_STRING (cfg->psz_longtext);
195 LOAD_IMMEDIATE (cfg->list_count);
197 if (IsConfigStringType (cfg->i_type))
199 const char *psz;
200 LOAD_STRING(psz);
201 cfg->orig.psz = (char *)psz;
202 cfg->value.psz = (psz != NULL) ? strdup (cfg->orig.psz) : NULL;
204 if (cfg->list_count)
205 cfg->list.psz = xmalloc (cfg->list_count * sizeof (char *));
206 else
207 LOAD_STRING(cfg->list_cb_name);
208 for (unsigned i = 0; i < cfg->list_count; i++)
210 LOAD_STRING (cfg->list.psz[i]);
211 if (cfg->list.psz[i] == NULL /* NULL -> empty string */
212 && (cfg->list.psz[i] = calloc (1, 1)) == NULL)
213 goto error;
216 else
218 LOAD_IMMEDIATE (cfg->orig);
219 LOAD_IMMEDIATE (cfg->min);
220 LOAD_IMMEDIATE (cfg->max);
221 cfg->value = cfg->orig;
223 if (cfg->list_count)
225 LOAD_ALIGNOF(*cfg->list.i);
227 else
228 LOAD_STRING(cfg->list_cb_name);
230 LOAD_ARRAY(cfg->list.i, cfg->list_count);
233 cfg->list_text = xmalloc (cfg->list_count * sizeof (char *));
234 for (unsigned i = 0; i < cfg->list_count; i++)
236 LOAD_STRING (cfg->list_text[i]);
237 if (cfg->list_text[i] == NULL /* NULL -> empty string */
238 && (cfg->list_text[i] = calloc (1, 1)) == NULL)
239 goto error;
242 return 0;
243 error:
244 return -1; /* FIXME: leaks */
247 static int vlc_cache_load_plugin_config(vlc_plugin_t *plugin, block_t *file)
249 uint16_t lines;
251 /* Calculate the structure length */
252 LOAD_IMMEDIATE (lines);
254 /* Allocate memory */
255 if (lines)
257 plugin->conf.items = calloc(sizeof (module_config_t), lines);
258 if (unlikely(plugin->conf.items == NULL))
260 plugin->conf.size = 0;
261 return -1;
264 else
265 plugin->conf.items = NULL;
267 plugin->conf.size = lines;
269 /* Do the duplication job */
270 for (size_t i = 0; i < lines; i++)
272 module_config_t *item = plugin->conf.items + i;
274 if (vlc_cache_load_config(item, file))
275 return -1;
277 if (CONFIG_ITEM(item->i_type))
279 plugin->conf.count++;
280 if (item->i_type == CONFIG_ITEM_BOOL)
281 plugin->conf.booleans++;
283 item->owner = plugin;
286 return 0;
287 error:
288 return -1; /* FIXME: leaks */
291 static int vlc_cache_load_module(vlc_plugin_t *plugin, block_t *file)
293 module_t *module = vlc_module_create(plugin);
294 if (unlikely(module == NULL))
295 return -1;
297 LOAD_STRING(module->psz_shortname);
298 LOAD_STRING(module->psz_longname);
299 LOAD_STRING(module->psz_help);
301 LOAD_IMMEDIATE(module->i_shortcuts);
302 if (module->i_shortcuts > MODULE_SHORTCUT_MAX)
303 goto error;
304 else
306 module->pp_shortcuts =
307 xmalloc (sizeof (*module->pp_shortcuts) * module->i_shortcuts);
308 for (unsigned j = 0; j < module->i_shortcuts; j++)
309 LOAD_STRING(module->pp_shortcuts[j]);
312 LOAD_STRING(module->activate_name);
313 LOAD_STRING(module->deactivate_name);
314 LOAD_STRING(module->psz_capability);
315 LOAD_IMMEDIATE(module->i_score);
316 return 0;
317 error:
318 return -1;
321 static vlc_plugin_t *vlc_cache_load_plugin(block_t *file)
323 vlc_plugin_t *plugin = vlc_plugin_create();
324 if (unlikely(plugin == NULL))
325 return NULL;
327 uint32_t modules;
328 LOAD_IMMEDIATE(modules);
330 for (size_t i = 0; i < modules; i++)
331 if (vlc_cache_load_module(plugin, file))
332 goto error;
334 if (vlc_cache_load_plugin_config(plugin, file))
335 goto error;
337 LOAD_STRING(plugin->textdomain);
339 const char *path;
340 LOAD_STRING(path);
341 if (path == NULL)
342 goto error;
344 plugin->path = strdup(path);
345 if (unlikely(plugin->path == NULL))
346 goto error;
348 LOAD_FLAG(plugin->unloadable);
349 LOAD_IMMEDIATE(plugin->mtime);
350 LOAD_IMMEDIATE(plugin->size);
352 if (plugin->textdomain != NULL)
353 vlc_bindtextdomain(plugin->textdomain);
355 return plugin;
357 error:
358 vlc_plugin_destroy(plugin);
359 return NULL;
363 * Loads a plugins cache file.
365 * This function will load the plugin cache if present and valid. This cache
366 * will in turn be queried by AllocateAllPlugins() to see if it needs to
367 * actually load the dynamically loadable module.
368 * This allows us to only fully load plugins when they are actually used.
370 vlc_plugin_t *vlc_cache_load(vlc_object_t *p_this, const char *dir,
371 block_t **backingp)
373 char *psz_filename;
375 assert( dir != NULL );
377 if( asprintf( &psz_filename, "%s"DIR_SEP CACHE_NAME, dir ) == -1 )
378 return 0;
380 msg_Dbg( p_this, "loading plugins cache file %s", psz_filename );
382 block_t *file = block_FilePath(psz_filename, false);
383 if (file == NULL)
384 msg_Warn(p_this, "cannot read %s: %s", psz_filename,
385 vlc_strerror_c(errno));
386 free(psz_filename);
387 if (file == NULL)
388 return 0;
390 /* Check the file is a plugins cache */
391 char cachestr[sizeof (CACHE_STRING) - 1];
393 if (vlc_cache_load_immediate(cachestr, file, sizeof (cachestr))
394 || memcmp(cachestr, CACHE_STRING, sizeof (cachestr)))
396 msg_Warn( p_this, "This doesn't look like a valid plugins cache" );
397 block_Release(file);
398 return 0;
401 #ifdef DISTRO_VERSION
402 /* Check for distribution specific version */
403 char distrostr[sizeof (DISTRO_VERSION) - 1];
405 if (vlc_cache_load_immediate(distrostr, file, sizeof (distrostr))
406 || memcmp(distrostr, DISTRO_VERSION, sizeof (distrostr)))
408 msg_Warn( p_this, "This doesn't look like a valid plugins cache" );
409 block_Release(file);
410 return 0;
412 #endif
414 /* Check sub-version number */
415 uint32_t marker;
417 if (vlc_cache_load_immediate(&marker, file, sizeof (marker))
418 || marker != CACHE_SUBVERSION_NUM)
420 msg_Warn( p_this, "This doesn't look like a valid plugins cache "
421 "(corrupted header)" );
422 block_Release(file);
423 return 0;
426 /* Check header marker */
427 if (vlc_cache_load_immediate(&marker, file, sizeof (marker))
428 #ifdef DISTRO_VERSION
429 || marker != (sizeof (cachestr) + sizeof (distrostr) + sizeof (marker))
430 #else
431 || marker != (sizeof (cachestr) + sizeof (marker))
432 #endif
435 msg_Warn( p_this, "This doesn't look like a valid plugins cache "
436 "(corrupted header)" );
437 block_Release(file);
438 return 0;
441 vlc_plugin_t *cache = NULL;
443 while (file->i_buffer > 0)
445 vlc_plugin_t *plugin = vlc_cache_load_plugin(file);
446 if (plugin == NULL)
447 goto error;
449 if (unlikely(asprintf(&plugin->abspath, "%s" DIR_SEP "%s", dir,
450 plugin->path) == -1))
452 plugin->abspath = NULL;
453 vlc_plugin_destroy(plugin);
454 goto error;
457 plugin->next = cache;
458 cache = plugin;
461 file->p_next = *backingp;
462 *backingp = file;
463 return cache;
465 error:
466 msg_Warn( p_this, "plugins cache not loaded (corrupted)" );
468 /* TODO: cleanup */
469 block_Release(file);
470 return NULL;
473 #define SAVE_IMMEDIATE( a ) \
474 if (fwrite (&(a), sizeof(a), 1, file) != 1) \
475 goto error
476 #define SAVE_FLAG(a) \
477 do { \
478 char b = (a); \
479 SAVE_IMMEDIATE(b); \
480 } while (0)
482 static int CacheSaveString (FILE *file, const char *str)
484 uint16_t size = (str != NULL) ? (strlen (str) + 1) : 0;
486 SAVE_IMMEDIATE (size);
487 if (size != 0 && fwrite(str, 1, size, file) != size)
489 error:
490 return -1;
492 return 0;
495 #define SAVE_STRING( a ) \
496 if (CacheSaveString (file, (a))) \
497 goto error
499 static int CacheSaveAlign(FILE *file, size_t align)
501 assert(align > 0);
503 size_t skip = (-ftell(file)) % align;
504 if (skip == 0)
505 return 0;
507 assert(((ftell(file) + skip) % align) == 0);
508 return fseek(file, skip, SEEK_CUR);
511 #define SAVE_ALIGNOF(t) \
512 if (CacheSaveAlign(file, alignof (t))) \
513 goto error
515 static int CacheSaveConfig (FILE *file, const module_config_t *cfg)
517 SAVE_IMMEDIATE (cfg->i_type);
518 SAVE_IMMEDIATE (cfg->i_short);
519 SAVE_FLAG (cfg->b_advanced);
520 SAVE_FLAG (cfg->b_internal);
521 SAVE_FLAG (cfg->b_unsaveable);
522 SAVE_FLAG (cfg->b_safe);
523 SAVE_FLAG (cfg->b_removed);
524 SAVE_STRING (cfg->psz_type);
525 SAVE_STRING (cfg->psz_name);
526 SAVE_STRING (cfg->psz_text);
527 SAVE_STRING (cfg->psz_longtext);
528 SAVE_IMMEDIATE (cfg->list_count);
530 if (IsConfigStringType (cfg->i_type))
532 SAVE_STRING (cfg->orig.psz);
533 if (cfg->list_count == 0)
534 SAVE_STRING(cfg->list_cb_name);
536 for (unsigned i = 0; i < cfg->list_count; i++)
537 SAVE_STRING (cfg->list.psz[i]);
539 else
541 SAVE_IMMEDIATE (cfg->orig);
542 SAVE_IMMEDIATE (cfg->min);
543 SAVE_IMMEDIATE (cfg->max);
545 if (cfg->list_count > 0)
547 SAVE_ALIGNOF(*cfg->list.i);
549 else
550 SAVE_STRING(cfg->list_cb_name);
552 for (unsigned i = 0; i < cfg->list_count; i++)
553 SAVE_IMMEDIATE (cfg->list.i[i]);
555 for (unsigned i = 0; i < cfg->list_count; i++)
556 SAVE_STRING (cfg->list_text[i]);
558 return 0;
559 error:
560 return -1;
563 static int CacheSaveModuleConfig(FILE *file, const vlc_plugin_t *plugin)
565 uint16_t lines = plugin->conf.size;
567 SAVE_IMMEDIATE (lines);
569 for (size_t i = 0; i < lines; i++)
570 if (CacheSaveConfig(file, plugin->conf.items + i))
571 goto error;
573 return 0;
574 error:
575 return -1;
578 static int CacheSaveModule(FILE *file, const module_t *module)
580 SAVE_STRING(module->psz_shortname);
581 SAVE_STRING(module->psz_longname);
582 SAVE_STRING(module->psz_help);
583 SAVE_IMMEDIATE(module->i_shortcuts);
585 for (size_t j = 0; j < module->i_shortcuts; j++)
586 SAVE_STRING(module->pp_shortcuts[j]);
588 SAVE_STRING(module->activate_name);
589 SAVE_STRING(module->deactivate_name);
590 SAVE_STRING(module->psz_capability);
591 SAVE_IMMEDIATE(module->i_score);
592 return 0;
593 error:
594 return -1;
597 static int CacheSaveBank(FILE *file, vlc_plugin_t *const *cache, size_t n)
599 uint32_t i_file_size = 0;
601 /* Contains version number */
602 if (fputs (CACHE_STRING, file) == EOF)
603 goto error;
604 #ifdef DISTRO_VERSION
605 /* Allow binary maintaner to pass a string to detect new binary version*/
606 if (fputs( DISTRO_VERSION, file ) == EOF)
607 goto error;
608 #endif
609 /* Sub-version number (to avoid breakage in the dev version when cache
610 * structure changes) */
611 i_file_size = CACHE_SUBVERSION_NUM;
612 if (fwrite (&i_file_size, sizeof (i_file_size), 1, file) != 1 )
613 goto error;
615 /* Header marker */
616 i_file_size = ftell( file );
617 if (fwrite (&i_file_size, sizeof (i_file_size), 1, file) != 1)
618 goto error;
620 for (size_t i = 0; i < n; i++)
622 const vlc_plugin_t *plugin = cache[i];
623 uint32_t count = plugin->modules_count;
625 SAVE_IMMEDIATE(count);
627 for (module_t *module = plugin->module;
628 module != NULL;
629 module = module->next)
630 if (CacheSaveModule(file, module))
631 goto error;
633 /* Config stuff */
634 if (CacheSaveModuleConfig(file, plugin))
635 goto error;
637 /* Save common info */
638 SAVE_STRING(plugin->textdomain);
639 SAVE_STRING(plugin->path);
640 SAVE_FLAG(plugin->unloadable);
641 SAVE_IMMEDIATE(plugin->mtime);
642 SAVE_IMMEDIATE(plugin->size);
645 if (fflush (file)) /* flush libc buffers */
646 goto error;
647 return 0; /* success! */
649 error:
650 return -1;
654 * Saves a module cache to disk, and release cache data from memory.
656 void CacheSave(vlc_object_t *p_this, const char *dir,
657 vlc_plugin_t *const *entries, size_t n)
659 char *filename = NULL, *tmpname = NULL;
661 if (asprintf (&filename, "%s"DIR_SEP CACHE_NAME, dir ) == -1)
662 goto out;
664 if (asprintf (&tmpname, "%s.%"PRIu32, filename, (uint32_t)getpid ()) == -1)
665 goto out;
666 msg_Dbg (p_this, "saving plugins cache %s", filename);
668 FILE *file = vlc_fopen (tmpname, "wb");
669 if (file == NULL)
671 if (errno != EACCES && errno != ENOENT)
672 msg_Warn (p_this, "cannot create %s: %s", tmpname,
673 vlc_strerror_c(errno));
674 goto out;
677 if (CacheSaveBank(file, entries, n))
679 msg_Warn (p_this, "cannot write %s: %s", tmpname,
680 vlc_strerror_c(errno));
681 clearerr (file);
682 fclose (file);
683 vlc_unlink (tmpname);
684 goto out;
687 #if !defined( _WIN32 ) && !defined( __OS2__ )
688 vlc_rename (tmpname, filename); /* atomically replace old cache */
689 fclose (file);
690 #else
691 vlc_unlink (filename);
692 fclose (file);
693 vlc_rename (tmpname, filename);
694 #endif
695 out:
696 free (filename);
697 free (tmpname);
701 * Looks up a plugin file in a table of cached plugins.
703 vlc_plugin_t *vlc_cache_lookup(vlc_plugin_t **cache, const char *path)
705 vlc_plugin_t **pp = cache, *plugin;
707 while ((plugin = *pp) != NULL)
709 if (plugin->path != NULL && !strcmp(plugin->path, path))
711 *pp = plugin->next;
712 plugin->next = NULL;
713 return plugin;
716 pp = &plugin->next;
719 return NULL;
721 #endif /* HAVE_DYNAMIC_PLUGINS */