VirtualBox

source: vbox/trunk/src/VBox/Storage/VDPlugin.cpp@ 82781

Last change on this file since 82781 was 79965, checked in by vboxsync, 5 years ago

Storage: Added a desired format parameter to VDGetFormat() so Main can pass along the device type. Bumped the RAW backend down after the CUE and VISO to prevent (impossible) mixups of tiny files. Extended rawProbe() to look for a valid ISO-9660/UDF descriptor sequence on the image if the caller doesn't say it should be a floppy or hdd, only if that fail go by the extension. Note! the pfnProbe callback should probably get a score return parameter to indicate how confient the backend is about the probe result, as this would prevent the RAW backend from accidentally grabbing images which belongs to a plug-in. bugref:9151

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.5 KB
Line 
1/* $Id: VDPlugin.cpp 79965 2019-07-24 20:32:32Z vboxsync $ */
2/** @file
3 * VD - Virtual disk container implementation, plugin related bits.
4 */
5
6/*
7 * Copyright (C) 2017-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_VD
23#include <VBox/err.h>
24#include <VBox/sup.h>
25#include <VBox/log.h>
26#include <VBox/vd-plugin.h>
27
28#include <iprt/dir.h>
29#include <iprt/ldr.h>
30#include <iprt/mem.h>
31#include <iprt/path.h>
32
33#include "VDInternal.h"
34#include "VDBackends.h"
35
36
37/*********************************************************************************************************************************
38* Structures and Typedefs *
39*********************************************************************************************************************************/
40
41/**
42 * Plugin structure.
43 */
44typedef struct VDPLUGIN
45{
46 /** Pointer to the next plugin structure. */
47 RTLISTNODE NodePlugin;
48 /** Handle of loaded plugin library. */
49 RTLDRMOD hPlugin;
50 /** Filename of the loaded plugin. */
51 char *pszFilename;
52} VDPLUGIN;
53/** Pointer to a plugin structure. */
54typedef VDPLUGIN *PVDPLUGIN;
55
56
57/*********************************************************************************************************************************
58* Defined Constants And Macros *
59*********************************************************************************************************************************/
60
61
62/*********************************************************************************************************************************
63* Global Variables *
64*********************************************************************************************************************************/
65
66#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
67/** Head of loaded plugin list. */
68static RTLISTANCHOR g_ListPluginsLoaded;
69#endif
70
71/** Number of image backends supported. */
72static unsigned g_cBackends = 0;
73/** Array of pointers to the image backends. */
74static PCVDIMAGEBACKEND *g_apBackends = NULL;
75#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
76/** Array of handles to the corresponding plugin. */
77static RTLDRMOD *g_ahBackendPlugins = NULL;
78#endif
79/**
80 * Builtin image backends.
81 *
82 * @note As long as the pfnProb() calls aren't scored, the ordering influences
83 * which backend take precedence. In particular, the RAW backend should
84 * be thowards the end of the list.
85 */
86static PCVDIMAGEBACKEND aStaticBackends[] =
87{
88 &g_VmdkBackend,
89 &g_VDIBackend,
90 &g_VhdBackend,
91 &g_ParallelsBackend,
92 &g_DmgBackend,
93 &g_QedBackend,
94 &g_QCowBackend,
95 &g_VhdxBackend,
96 &g_CueBackend,
97 &g_VBoxIsoMakerBackend,
98 &g_RawBackend,
99 &g_ISCSIBackend
100};
101
102/** Number of supported cache backends. */
103static unsigned g_cCacheBackends = 0;
104/** Array of pointers to the cache backends. */
105static PCVDCACHEBACKEND *g_apCacheBackends = NULL;
106#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
107/** Array of handles to the corresponding plugin.
108 *
109 * @todo r=bird: This looks rather pointless.
110 */
111static RTLDRMOD *g_ahCacheBackendPlugins = NULL;
112#endif
113/** Builtin cache backends. */
114static PCVDCACHEBACKEND aStaticCacheBackends[] =
115{
116 &g_VciCacheBackend
117};
118
119/** Number of supported filter backends. */
120static unsigned g_cFilterBackends = 0;
121/** Array of pointers to the filters backends. */
122static PCVDFILTERBACKEND *g_apFilterBackends = NULL;
123#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
124/** Array of handles to the corresponding plugin. */
125static PRTLDRMOD g_pahFilterBackendPlugins = NULL;
126#endif
127
128
129/*********************************************************************************************************************************
130* Internal Functions *
131*********************************************************************************************************************************/
132
133/**
134 * Add an array of image format backends from the given plugin to the list of known
135 * image formats.
136 *
137 * @returns VBox status code.
138 * @param hPlugin The plugin handle the backends belong to, can be NIL_RTLDRMOD
139 * for compiled in backends.
140 * @param ppBackends The array of image backend descriptors to add.
141 * @param cBackends Number of descriptors in the array.
142 */
143static int vdAddBackends(RTLDRMOD hPlugin, PCVDIMAGEBACKEND *ppBackends, unsigned cBackends)
144{
145 PCVDIMAGEBACKEND *pTmp = (PCVDIMAGEBACKEND *)RTMemRealloc(g_apBackends,
146 (g_cBackends + cBackends) * sizeof(PCVDIMAGEBACKEND));
147 if (RT_UNLIKELY(!pTmp))
148 return VERR_NO_MEMORY;
149 g_apBackends = pTmp;
150 memcpy(&g_apBackends[g_cBackends], ppBackends, cBackends * sizeof(PCVDIMAGEBACKEND));
151
152#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
153 RTLDRMOD *pTmpPlugins = (RTLDRMOD*)RTMemRealloc(g_ahBackendPlugins,
154 (g_cBackends + cBackends) * sizeof(RTLDRMOD));
155 if (RT_UNLIKELY(!pTmpPlugins))
156 return VERR_NO_MEMORY;
157 g_ahBackendPlugins = pTmpPlugins;
158 for (unsigned i = g_cBackends; i < g_cBackends + cBackends; i++)
159 g_ahBackendPlugins[i] = hPlugin;
160#else
161 RT_NOREF(hPlugin);
162#endif
163
164 g_cBackends += cBackends;
165 return VINF_SUCCESS;
166}
167
168
169/**
170 * Add an array of cache format backends from the given plugin to the list of known
171 * cache formats.
172 *
173 * @returns VBox status code.
174 * @param hPlugin The plugin handle the backends belong to, can be NIL_RTLDRMOD
175 * for compiled in backends.
176 * @param ppBackends The array of cache backend descriptors to add.
177 * @param cBackends Number of descriptors in the array.
178 */
179static int vdAddCacheBackends(RTLDRMOD hPlugin, PCVDCACHEBACKEND *ppBackends, unsigned cBackends)
180{
181 PCVDCACHEBACKEND *pTmp = (PCVDCACHEBACKEND*)RTMemReallocTag(g_apCacheBackends,
182 (g_cCacheBackends + cBackends) * sizeof(PCVDCACHEBACKEND),
183 "may-leak:vdAddCacheBackend");
184 if (RT_UNLIKELY(!pTmp))
185 return VERR_NO_MEMORY;
186 g_apCacheBackends = pTmp;
187 memcpy(&g_apCacheBackends[g_cCacheBackends], ppBackends, cBackends * sizeof(PCVDCACHEBACKEND));
188
189#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
190 RTLDRMOD *pTmpPlugins = (RTLDRMOD*)RTMemReallocTag(g_ahCacheBackendPlugins,
191 (g_cCacheBackends + cBackends) * sizeof(RTLDRMOD),
192 "may-leak:vdAddCacheBackend");
193 if (RT_UNLIKELY(!pTmpPlugins))
194 return VERR_NO_MEMORY;
195 g_ahCacheBackendPlugins = pTmpPlugins;
196 for (unsigned i = g_cCacheBackends; i < g_cCacheBackends + cBackends; i++)
197 g_ahCacheBackendPlugins[i] = hPlugin;
198#else
199 RT_NOREF(hPlugin);
200#endif
201
202 g_cCacheBackends += cBackends;
203 return VINF_SUCCESS;
204}
205
206#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
207/**
208 * Add a single image format backend to the list of known image formats.
209 *
210 * @returns VBox status code.
211 * @param hPlugin The plugin handle the backend belongs to, can be NIL_RTLDRMOD
212 * for compiled in backends.
213 * @param pBackend The image backend descriptors to add.
214 */
215DECLINLINE(int) vdAddBackend(RTLDRMOD hPlugin, PCVDIMAGEBACKEND pBackend)
216{
217 return vdAddBackends(hPlugin, &pBackend, 1);
218}
219
220
221/**
222 * Add a single cache format backend to the list of known cache formats.
223 *
224 * @returns VBox status code.
225 * @param hPlugin The plugin handle the backend belongs to, can be NIL_RTLDRMOD
226 * for compiled in backends.
227 * @param pBackend The cache backend descriptors to add.
228 */
229DECLINLINE(int) vdAddCacheBackend(RTLDRMOD hPlugin, PCVDCACHEBACKEND pBackend)
230{
231 return vdAddCacheBackends(hPlugin, &pBackend, 1);
232}
233
234
235/**
236 * Add several filter backends.
237 *
238 * @returns VBox status code.
239 * @param hPlugin Plugin handle to add.
240 * @param ppBackends Array of filter backends to add.
241 * @param cBackends Number of backends to add.
242 */
243static int vdAddFilterBackends(RTLDRMOD hPlugin, PCVDFILTERBACKEND *ppBackends, unsigned cBackends)
244{
245 PCVDFILTERBACKEND *pTmp = (PCVDFILTERBACKEND *)RTMemRealloc(g_apFilterBackends,
246 (g_cFilterBackends + cBackends) * sizeof(PCVDFILTERBACKEND));
247 if (RT_UNLIKELY(!pTmp))
248 return VERR_NO_MEMORY;
249 g_apFilterBackends = pTmp;
250
251#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
252 PRTLDRMOD pTmpPlugins = (PRTLDRMOD)RTMemRealloc(g_pahFilterBackendPlugins,
253 (g_cFilterBackends + cBackends) * sizeof(RTLDRMOD));
254 if (RT_UNLIKELY(!pTmpPlugins))
255 return VERR_NO_MEMORY;
256
257 g_pahFilterBackendPlugins = pTmpPlugins;
258 memcpy(&g_apFilterBackends[g_cFilterBackends], ppBackends, cBackends * sizeof(PCVDFILTERBACKEND));
259 for (unsigned i = g_cFilterBackends; i < g_cFilterBackends + cBackends; i++)
260 g_pahFilterBackendPlugins[i] = hPlugin;
261#else
262 RT_NOREF(hPlugin);
263#endif
264
265 g_cFilterBackends += cBackends;
266 return VINF_SUCCESS;
267}
268
269
270/**
271 * Add a single filter backend to the list of supported filters.
272 *
273 * @returns VBox status code.
274 * @param hPlugin Plugin handle to add.
275 * @param pBackend The backend to add.
276 */
277DECLINLINE(int) vdAddFilterBackend(RTLDRMOD hPlugin, PCVDFILTERBACKEND pBackend)
278{
279 return vdAddFilterBackends(hPlugin, &pBackend, 1);
280}
281
282/**
283 * @interface_method_impl{VDBACKENDREGISTER,pfnRegisterImage}
284 */
285static DECLCALLBACK(int) vdPluginRegisterImage(void *pvUser, PCVDIMAGEBACKEND pBackend)
286{
287 int rc = VINF_SUCCESS;
288
289 if (VD_VERSION_ARE_COMPATIBLE(VD_IMGBACKEND_VERSION, pBackend->u32Version))
290 vdAddBackend((RTLDRMOD)pvUser, pBackend);
291 else
292 {
293 LogFunc(("ignored plugin: pBackend->u32Version=%u rc=%Rrc\n", pBackend->u32Version, rc));
294 rc = VERR_IGNORED;
295 }
296
297 return rc;
298}
299
300/**
301 * @interface_method_impl{VDBACKENDREGISTER,pfnRegisterCache}
302 */
303static DECLCALLBACK(int) vdPluginRegisterCache(void *pvUser, PCVDCACHEBACKEND pBackend)
304{
305 int rc = VINF_SUCCESS;
306
307 if (VD_VERSION_ARE_COMPATIBLE(VD_CACHEBACKEND_VERSION, pBackend->u32Version))
308 vdAddCacheBackend((RTLDRMOD)pvUser, pBackend);
309 else
310 {
311 LogFunc(("ignored plugin: pBackend->u32Version=%u rc=%Rrc\n", pBackend->u32Version, rc));
312 rc = VERR_IGNORED;
313 }
314
315 return rc;
316}
317
318/**
319 * @interface_method_impl{VDBACKENDREGISTER,pfnRegisterFilter}
320 */
321static DECLCALLBACK(int) vdPluginRegisterFilter(void *pvUser, PCVDFILTERBACKEND pBackend)
322{
323 int rc = VINF_SUCCESS;
324
325 if (VD_VERSION_ARE_COMPATIBLE(VD_FLTBACKEND_VERSION, pBackend->u32Version))
326 vdAddFilterBackend((RTLDRMOD)pvUser, pBackend);
327 else
328 {
329 LogFunc(("ignored plugin: pBackend->u32Version=%u rc=%Rrc\n", pBackend->u32Version, rc));
330 rc = VERR_IGNORED;
331 }
332
333 return rc;
334}
335
336/**
337 * Checks whether the given plugin filename was already loaded.
338 *
339 * @returns Pointer to already loaded plugin, NULL if not found.
340 * @param pszFilename The filename to check.
341 */
342static PVDPLUGIN vdPluginFind(const char *pszFilename)
343{
344 PVDPLUGIN pIt;
345 RTListForEach(&g_ListPluginsLoaded, pIt, VDPLUGIN, NodePlugin)
346 {
347 if (!RTStrCmp(pIt->pszFilename, pszFilename))
348 return pIt;
349 }
350
351 return NULL;
352}
353
354/**
355 * Adds a plugin to the list of loaded plugins.
356 *
357 * @returns VBox status code.
358 * @param hPlugin Plugin handle to add.
359 * @param pszFilename The associated filename, used for finding duplicates.
360 */
361static int vdAddPlugin(RTLDRMOD hPlugin, const char *pszFilename)
362{
363 int rc = VINF_SUCCESS;
364 PVDPLUGIN pPlugin = (PVDPLUGIN)RTMemAllocZ(sizeof(VDPLUGIN));
365
366 if (pPlugin)
367 {
368 pPlugin->hPlugin = hPlugin;
369 pPlugin->pszFilename = RTStrDup(pszFilename);
370 if (pPlugin->pszFilename)
371 RTListAppend(&g_ListPluginsLoaded, &pPlugin->NodePlugin);
372 else
373 {
374 RTMemFree(pPlugin);
375 rc = VERR_NO_MEMORY;
376 }
377 }
378 else
379 rc = VERR_NO_MEMORY;
380
381 return rc;
382}
383
384/**
385 * Removes a single plugin given by the filename.
386 *
387 * @returns VBox status code.
388 * @param pszFilename The plugin filename to remove.
389 */
390static int vdRemovePlugin(const char *pszFilename)
391{
392 /* Find plugin to be removed from the list. */
393 PVDPLUGIN pIt = vdPluginFind(pszFilename);
394 if (!pIt)
395 return VINF_SUCCESS;
396
397 /** @todo r=klaus: need to add a plugin entry point for unregistering the
398 * backends. Only if this doesn't exist (or fails to work) we should fall
399 * back to the following uncoordinated backend cleanup. */
400 for (unsigned i = 0; i < g_cBackends; i++)
401 {
402 while (i < g_cBackends && g_ahBackendPlugins[i] == pIt->hPlugin)
403 {
404 memmove(&g_apBackends[i], &g_apBackends[i + 1], (g_cBackends - i - 1) * sizeof(PCVDIMAGEBACKEND));
405 memmove(&g_ahBackendPlugins[i], &g_ahBackendPlugins[i + 1], (g_cBackends - i - 1) * sizeof(RTLDRMOD));
406 /** @todo for now skip reallocating, doesn't save much */
407 g_cBackends--;
408 }
409 }
410 for (unsigned i = 0; i < g_cCacheBackends; i++)
411 {
412 while (i < g_cCacheBackends && g_ahCacheBackendPlugins[i] == pIt->hPlugin)
413 {
414 memmove(&g_apCacheBackends[i], &g_apCacheBackends[i + 1], (g_cCacheBackends - i - 1) * sizeof(PCVDCACHEBACKEND));
415 memmove(&g_ahCacheBackendPlugins[i], &g_ahCacheBackendPlugins[i + 1], (g_cCacheBackends - i - 1) * sizeof(RTLDRMOD));
416 /** @todo for now skip reallocating, doesn't save much */
417 g_cCacheBackends--;
418 }
419 }
420 for (unsigned i = 0; i < g_cFilterBackends; i++)
421 {
422 while (i < g_cFilterBackends && g_pahFilterBackendPlugins[i] == pIt->hPlugin)
423 {
424 memmove(&g_apFilterBackends[i], &g_apFilterBackends[i + 1], (g_cFilterBackends - i - 1) * sizeof(PCVDFILTERBACKEND));
425 memmove(&g_pahFilterBackendPlugins[i], &g_pahFilterBackendPlugins[i + 1], (g_cFilterBackends - i - 1) * sizeof(RTLDRMOD));
426 /** @todo for now skip reallocating, doesn't save much */
427 g_cFilterBackends--;
428 }
429 }
430
431 /* Remove the plugin node now, all traces of it are gone. */
432 RTListNodeRemove(&pIt->NodePlugin);
433 RTLdrClose(pIt->hPlugin);
434 RTStrFree(pIt->pszFilename);
435 RTMemFree(pIt);
436
437 return VINF_SUCCESS;
438}
439
440#endif /* VBOX_HDD_NO_DYNAMIC_BACKENDS*/
441
442/**
443 * Returns the number of known image format backends.
444 *
445 * @returns Number of image formats known.
446 */
447DECLHIDDEN(uint32_t) vdGetImageBackendCount(void)
448{
449 return g_cBackends;
450}
451
452
453/**
454 * Queries a image backend descriptor by the index.
455 *
456 * @returns VBox status code.
457 * @param idx The index of the backend to query.
458 * @param ppBackend Where to store the pointer to the backend descriptor on success.
459 */
460DECLHIDDEN(int) vdQueryImageBackend(uint32_t idx, PCVDIMAGEBACKEND *ppBackend)
461{
462 if (idx >= g_cBackends)
463 return VERR_OUT_OF_RANGE;
464
465 *ppBackend = g_apBackends[idx];
466 return VINF_SUCCESS;
467}
468
469
470/**
471 * Returns the image backend descriptor matching the given identifier if known.
472 *
473 * @returns VBox status code.
474 * @param pszBackend The backend identifier to look for.
475 * @param ppBackend Where to store the pointer to the backend descriptor on success.
476 */
477DECLHIDDEN(int) vdFindImageBackend(const char *pszBackend, PCVDIMAGEBACKEND *ppBackend)
478{
479 int rc = VINF_SUCCESS;
480 PCVDIMAGEBACKEND pBackend = NULL;
481
482 if (!g_apBackends)
483 VDInit();
484
485 for (unsigned i = 0; i < g_cBackends; i++)
486 {
487 if (!RTStrICmp(pszBackend, g_apBackends[i]->pszBackendName))
488 {
489 pBackend = g_apBackends[i];
490 break;
491 }
492 }
493 *ppBackend = pBackend;
494 return rc;
495}
496
497/**
498 * Returns the number of known cache format backends.
499 *
500 * @returns Number of image formats known.
501 */
502DECLHIDDEN(uint32_t) vdGetCacheBackendCount(void)
503{
504 return g_cCacheBackends;
505}
506
507
508/**
509 * Queries a cache backend descriptor by the index.
510 *
511 * @returns VBox status code.
512 * @param idx The index of the backend to query.
513 * @param ppBackend Where to store the pointer to the backend descriptor on success.
514 */
515DECLHIDDEN(int) vdQueryCacheBackend(uint32_t idx, PCVDCACHEBACKEND *ppBackend)
516{
517 if (idx >= g_cCacheBackends)
518 return VERR_OUT_OF_RANGE;
519
520 *ppBackend = g_apCacheBackends[idx];
521 return VINF_SUCCESS;
522}
523
524
525/**
526 * Returns the cache backend descriptor matching the given identifier if known.
527 *
528 * @returns VBox status code.
529 * @param pszBackend The backend identifier to look for.
530 * @param ppBackend Where to store the pointer to the backend descriptor on success.
531 */
532DECLHIDDEN(int) vdFindCacheBackend(const char *pszBackend, PCVDCACHEBACKEND *ppBackend)
533{
534 int rc = VINF_SUCCESS;
535 PCVDCACHEBACKEND pBackend = NULL;
536
537 if (!g_apCacheBackends)
538 VDInit();
539
540 for (unsigned i = 0; i < g_cCacheBackends; i++)
541 {
542 if (!RTStrICmp(pszBackend, g_apCacheBackends[i]->pszBackendName))
543 {
544 pBackend = g_apCacheBackends[i];
545 break;
546 }
547 }
548 *ppBackend = pBackend;
549 return rc;
550}
551
552
553/**
554 * Returns the number of known filter backends.
555 *
556 * @returns Number of image formats known.
557 */
558DECLHIDDEN(uint32_t) vdGetFilterBackendCount(void)
559{
560 return g_cFilterBackends;
561}
562
563
564/**
565 * Queries a filter backend descriptor by the index.
566 *
567 * @returns VBox status code.
568 * @param idx The index of the backend to query.
569 * @param ppBackend Where to store the pointer to the backend descriptor on success.
570 */
571DECLHIDDEN(int) vdQueryFilterBackend(uint32_t idx, PCVDFILTERBACKEND *ppBackend)
572{
573 if (idx >= g_cFilterBackends)
574 return VERR_OUT_OF_RANGE;
575
576 *ppBackend = g_apFilterBackends[idx];
577 return VINF_SUCCESS;
578}
579
580
581/**
582 * Returns the filter backend descriptor matching the given identifier if known.
583 *
584 * @returns VBox status code.
585 * @param pszFilter The filter identifier to look for.
586 * @param ppBackend Where to store the pointer to the backend descriptor on success.
587 */
588DECLHIDDEN(int) vdFindFilterBackend(const char *pszFilter, PCVDFILTERBACKEND *ppBackend)
589{
590 int rc = VINF_SUCCESS;
591 PCVDFILTERBACKEND pBackend = NULL;
592
593 for (unsigned i = 0; i < g_cFilterBackends; i++)
594 {
595 if (!RTStrICmp(pszFilter, g_apFilterBackends[i]->pszBackendName))
596 {
597 pBackend = g_apFilterBackends[i];
598 break;
599 }
600 }
601 *ppBackend = pBackend;
602 return rc;
603}
604
605
606/**
607 * Worker for VDPluginLoadFromFilename() and vdPluginLoadFromPath().
608 *
609 * @returns VBox status code.
610 * @param pszFilename The plugin filename to load.
611 */
612DECLHIDDEN(int) vdPluginLoadFromFilename(const char *pszFilename)
613{
614#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
615 /* Plugin loaded? Nothing to do. */
616 if (vdPluginFind(pszFilename))
617 return VINF_SUCCESS;
618
619 RTLDRMOD hPlugin = NIL_RTLDRMOD;
620 int rc = SUPR3HardenedLdrLoadPlugIn(pszFilename, &hPlugin, NULL);
621 if (RT_SUCCESS(rc))
622 {
623 VDBACKENDREGISTER BackendRegister;
624 PFNVDPLUGINLOAD pfnVDPluginLoad = NULL;
625
626 BackendRegister.u32Version = VD_BACKENDREG_CB_VERSION;
627 BackendRegister.pfnRegisterImage = vdPluginRegisterImage;
628 BackendRegister.pfnRegisterCache = vdPluginRegisterCache;
629 BackendRegister.pfnRegisterFilter = vdPluginRegisterFilter;
630
631 rc = RTLdrGetSymbol(hPlugin, VD_PLUGIN_LOAD_NAME, (void**)&pfnVDPluginLoad);
632 if (RT_FAILURE(rc) || !pfnVDPluginLoad)
633 {
634 LogFunc(("error resolving the entry point %s in plugin %s, rc=%Rrc, pfnVDPluginLoad=%#p\n",
635 VD_PLUGIN_LOAD_NAME, pszFilename, rc, pfnVDPluginLoad));
636 if (RT_SUCCESS(rc))
637 rc = VERR_SYMBOL_NOT_FOUND;
638 }
639
640 if (RT_SUCCESS(rc))
641 {
642 /* Get the function table. */
643 rc = pfnVDPluginLoad(hPlugin, &BackendRegister);
644 }
645 else
646 LogFunc(("ignored plugin '%s': rc=%Rrc\n", pszFilename, rc));
647
648 /* Create a plugin entry on success. */
649 if (RT_SUCCESS(rc))
650 vdAddPlugin(hPlugin, pszFilename);
651 else
652 RTLdrClose(hPlugin);
653 }
654
655 return rc;
656#else
657 RT_NOREF1(pszFilename);
658 return VERR_NOT_IMPLEMENTED;
659#endif
660}
661
662/**
663 * Worker for VDPluginLoadFromPath() and vdLoadDynamicBackends().
664 *
665 * @returns VBox status code.
666 * @param pszPath The path to load plugins from.
667 */
668DECLHIDDEN(int) vdPluginLoadFromPath(const char *pszPath)
669{
670#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
671 /* To get all entries with VBoxHDD as prefix. */
672 char *pszPluginFilter = RTPathJoinA(pszPath, VD_PLUGIN_PREFIX "*");
673 if (!pszPluginFilter)
674 return VERR_NO_STR_MEMORY;
675
676 PRTDIRENTRYEX pPluginDirEntry = NULL;
677 RTDIR hPluginDir;
678 size_t cbPluginDirEntry = sizeof(RTDIRENTRYEX);
679 int rc = RTDirOpenFiltered(&hPluginDir, pszPluginFilter, RTDIRFILTER_WINNT, 0 /*fFlags*/);
680 if (RT_SUCCESS(rc))
681 {
682 pPluginDirEntry = (PRTDIRENTRYEX)RTMemAllocZ(sizeof(RTDIRENTRYEX));
683 if (pPluginDirEntry)
684 {
685 while ( (rc = RTDirReadEx(hPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK))
686 != VERR_NO_MORE_FILES)
687 {
688 char *pszPluginPath = NULL;
689
690 if (rc == VERR_BUFFER_OVERFLOW)
691 {
692 /* allocate new buffer. */
693 RTMemFree(pPluginDirEntry);
694 pPluginDirEntry = (PRTDIRENTRYEX)RTMemAllocZ(cbPluginDirEntry);
695 if (!pPluginDirEntry)
696 {
697 rc = VERR_NO_MEMORY;
698 break;
699 }
700 /* Retry. */
701 rc = RTDirReadEx(hPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
702 if (RT_FAILURE(rc))
703 break;
704 }
705 else if (RT_FAILURE(rc))
706 break;
707
708 /* We got the new entry. */
709 if (!RTFS_IS_FILE(pPluginDirEntry->Info.Attr.fMode))
710 continue;
711
712 /* Prepend the path to the libraries. */
713 pszPluginPath = RTPathJoinA(pszPath, pPluginDirEntry->szName);
714 if (!pszPluginPath)
715 {
716 rc = VERR_NO_STR_MEMORY;
717 break;
718 }
719
720 rc = vdPluginLoadFromFilename(pszPluginPath);
721 RTStrFree(pszPluginPath);
722 }
723
724 RTMemFree(pPluginDirEntry);
725 }
726 else
727 rc = VERR_NO_MEMORY;
728
729 RTDirClose(hPluginDir);
730 }
731 else
732 {
733 /* On Windows the above immediately signals that there are no
734 * files matching, while on other platforms enumerating the
735 * files below fails. Either way: no plugins. */
736 }
737
738 if (rc == VERR_NO_MORE_FILES)
739 rc = VINF_SUCCESS;
740 RTStrFree(pszPluginFilter);
741 return rc;
742#else
743 RT_NOREF1(pszPath);
744 return VERR_NOT_IMPLEMENTED;
745#endif
746}
747
748#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
749/**
750 * internal: scans plugin directory and loads found plugins.
751 */
752static int vdLoadDynamicBackends(void)
753{
754 /*
755 * Enumerate plugin backends from the application directory where the other
756 * shared libraries are.
757 */
758 char szPath[RTPATH_MAX];
759 int rc = RTPathAppPrivateArch(szPath, sizeof(szPath));
760 if (RT_FAILURE(rc))
761 return rc;
762
763 return vdPluginLoadFromPath(szPath);
764}
765#endif
766
767/**
768 * Worker for VDPluginUnloadFromFilename() and vdPluginUnloadFromPath().
769 *
770 * @returns VBox status code.
771 * @param pszFilename The plugin filename to unload.
772 */
773DECLHIDDEN(int) vdPluginUnloadFromFilename(const char *pszFilename)
774{
775#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
776 return vdRemovePlugin(pszFilename);
777#else
778 RT_NOREF1(pszFilename);
779 return VERR_NOT_IMPLEMENTED;
780#endif
781}
782
783/**
784 * Worker for VDPluginUnloadFromPath().
785 *
786 * @returns VBox status code.
787 * @param pszPath The path to unload plugins from.
788 */
789DECLHIDDEN(int) vdPluginUnloadFromPath(const char *pszPath)
790{
791#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
792 /* To get all entries with VBoxHDD as prefix. */
793 char *pszPluginFilter = RTPathJoinA(pszPath, VD_PLUGIN_PREFIX "*");
794 if (!pszPluginFilter)
795 return VERR_NO_STR_MEMORY;
796
797 PRTDIRENTRYEX pPluginDirEntry = NULL;
798 RTDIR hPluginDir;
799 size_t cbPluginDirEntry = sizeof(RTDIRENTRYEX);
800 int rc = RTDirOpenFiltered(&hPluginDir, pszPluginFilter, RTDIRFILTER_WINNT, 0 /*fFlags*/);
801 if (RT_SUCCESS(rc))
802 {
803 pPluginDirEntry = (PRTDIRENTRYEX)RTMemAllocZ(sizeof(RTDIRENTRYEX));
804 if (pPluginDirEntry)
805 {
806 while ((rc = RTDirReadEx(hPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK)) != VERR_NO_MORE_FILES)
807 {
808 char *pszPluginPath = NULL;
809
810 if (rc == VERR_BUFFER_OVERFLOW)
811 {
812 /* allocate new buffer. */
813 RTMemFree(pPluginDirEntry);
814 pPluginDirEntry = (PRTDIRENTRYEX)RTMemAllocZ(cbPluginDirEntry);
815 if (!pPluginDirEntry)
816 {
817 rc = VERR_NO_MEMORY;
818 break;
819 }
820 /* Retry. */
821 rc = RTDirReadEx(hPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
822 if (RT_FAILURE(rc))
823 break;
824 }
825 else if (RT_FAILURE(rc))
826 break;
827
828 /* We got the new entry. */
829 if (!RTFS_IS_FILE(pPluginDirEntry->Info.Attr.fMode))
830 continue;
831
832 /* Prepend the path to the libraries. */
833 pszPluginPath = RTPathJoinA(pszPath, pPluginDirEntry->szName);
834 if (!pszPluginPath)
835 {
836 rc = VERR_NO_STR_MEMORY;
837 break;
838 }
839
840 rc = vdPluginUnloadFromFilename(pszPluginPath);
841 RTStrFree(pszPluginPath);
842 }
843
844 RTMemFree(pPluginDirEntry);
845 }
846 else
847 rc = VERR_NO_MEMORY;
848
849 RTDirClose(hPluginDir);
850 }
851 else
852 {
853 /* On Windows the above immediately signals that there are no
854 * files matching, while on other platforms enumerating the
855 * files below fails. Either way: no plugins. */
856 }
857
858 if (rc == VERR_NO_MORE_FILES)
859 rc = VINF_SUCCESS;
860 RTStrFree(pszPluginFilter);
861 return rc;
862#else
863 RT_NOREF1(pszPath);
864 return VERR_NOT_IMPLEMENTED;
865#endif
866}
867
868
869/**
870 * Initializes the plugin state to be able to load further plugins and populates
871 * the backend lists with the compiled in backends.
872 *
873 * @returns VBox status code.
874 */
875DECLHIDDEN(int) vdPluginInit(void)
876{
877 int rc = vdAddBackends(NIL_RTLDRMOD, aStaticBackends, RT_ELEMENTS(aStaticBackends));
878 if (RT_SUCCESS(rc))
879 {
880 rc = vdAddCacheBackends(NIL_RTLDRMOD, aStaticCacheBackends, RT_ELEMENTS(aStaticCacheBackends));
881#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
882 if (RT_SUCCESS(rc))
883 {
884 RTListInit(&g_ListPluginsLoaded);
885 rc = vdLoadDynamicBackends();
886 }
887#endif
888 }
889
890 return rc;
891}
892
893
894/**
895 * Tears down the plugin related state.
896 *
897 * @returns VBox status code.
898 */
899DECLHIDDEN(int) vdPluginTerm(void)
900{
901 if (!g_apBackends)
902 return VERR_INTERNAL_ERROR;
903
904#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
905 if (g_pahFilterBackendPlugins)
906 RTMemFree(g_pahFilterBackendPlugins);
907#endif
908 if (g_apFilterBackends)
909 RTMemFree(g_apFilterBackends);
910#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
911 if (g_ahCacheBackendPlugins)
912 RTMemFree(g_ahCacheBackendPlugins);
913#endif
914 if (g_apCacheBackends)
915 RTMemFree(g_apCacheBackends);
916 RTMemFree(g_apBackends);
917
918 g_cBackends = 0;
919 g_apBackends = NULL;
920
921 /* Clear the supported cache backends. */
922 g_cCacheBackends = 0;
923 g_apCacheBackends = NULL;
924#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
925 g_ahCacheBackendPlugins = NULL;
926#endif
927
928 /* Clear the supported filter backends. */
929 g_cFilterBackends = 0;
930 g_apFilterBackends = NULL;
931#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
932 g_pahFilterBackendPlugins = NULL;
933#endif
934
935#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
936 PVDPLUGIN pPlugin, pPluginNext;
937 RTListForEachSafe(&g_ListPluginsLoaded, pPlugin, pPluginNext, VDPLUGIN, NodePlugin)
938 {
939 RTLdrClose(pPlugin->hPlugin);
940 RTStrFree(pPlugin->pszFilename);
941 RTListNodeRemove(&pPlugin->NodePlugin);
942 RTMemFree(pPlugin);
943 }
944#endif
945
946 return VINF_SUCCESS;
947}
948
949
950/**
951 * Returns whether the plugin related state is initialized.
952 *
953 * @returns true if the plugin state is initialized and plugins can be loaded,
954 * false otherwise.
955 */
956DECLHIDDEN(bool) vdPluginIsInitialized(void)
957{
958 return g_apBackends != NULL;
959}
960
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use