VirtualBox

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

Last change on this file since 95085 was 93512, checked in by vboxsync, 3 years ago

Storage/VDPlugIn: Don't disable VBOX_HDD_NO_DYNAMIC_BACKENDS on non-x86 platforms. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.4 KB
Line 
1/* $Id: VDPlugin.cpp 93512 2022-01-31 20:48:00Z vboxsync $ */
2/** @file
3 * VD - Virtual disk container implementation, plugin related bits.
4 */
5
6/*
7 * Copyright (C) 2017-2022 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 * Plugin structure.
42 */
43typedef struct VDPLUGIN
44{
45 /** Pointer to the next plugin structure. */
46 RTLISTNODE NodePlugin;
47 /** Handle of loaded plugin library. */
48 RTLDRMOD hPlugin;
49 /** Filename of the loaded plugin. */
50 char *pszFilename;
51} VDPLUGIN;
52/** Pointer to a plugin structure. */
53typedef VDPLUGIN *PVDPLUGIN;
54
55
56/*********************************************************************************************************************************
57* Global Variables *
58*********************************************************************************************************************************/
59#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
60/** Head of loaded plugin list. */
61static RTLISTANCHOR g_ListPluginsLoaded;
62#endif
63
64/** Number of image backends supported. */
65static unsigned g_cBackends = 0;
66/** Array of pointers to the image backends. */
67static PCVDIMAGEBACKEND *g_apBackends = NULL;
68#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
69/** Array of handles to the corresponding plugin. */
70static RTLDRMOD *g_ahBackendPlugins = NULL;
71#endif
72/**
73 * Builtin image backends.
74 *
75 * @note As long as the pfnProb() calls aren't scored, the ordering influences
76 * which backend take precedence. In particular, the RAW backend should
77 * be thowards the end of the list.
78 */
79static PCVDIMAGEBACKEND aStaticBackends[] =
80{
81 &g_VmdkBackend,
82 &g_VDIBackend,
83 &g_VhdBackend,
84 &g_ParallelsBackend,
85 &g_DmgBackend,
86 &g_QedBackend,
87 &g_QCowBackend,
88 &g_VhdxBackend,
89 &g_CueBackend,
90 &g_VBoxIsoMakerBackend,
91 &g_RawBackend,
92 &g_ISCSIBackend
93};
94
95/** Number of supported cache backends. */
96static unsigned g_cCacheBackends = 0;
97/** Array of pointers to the cache backends. */
98static PCVDCACHEBACKEND *g_apCacheBackends = NULL;
99#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
100/** Array of handles to the corresponding plugin.
101 *
102 * @todo r=bird: This looks rather pointless.
103 */
104static RTLDRMOD *g_ahCacheBackendPlugins = NULL;
105#endif
106/** Builtin cache backends. */
107static PCVDCACHEBACKEND aStaticCacheBackends[] =
108{
109 &g_VciCacheBackend
110};
111
112/** Number of supported filter backends. */
113static unsigned g_cFilterBackends = 0;
114/** Array of pointers to the filters backends. */
115static PCVDFILTERBACKEND *g_apFilterBackends = NULL;
116#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
117/** Array of handles to the corresponding plugin. */
118static PRTLDRMOD g_pahFilterBackendPlugins = NULL;
119#endif
120
121
122/*********************************************************************************************************************************
123* Internal Functions *
124*********************************************************************************************************************************/
125
126/**
127 * Add an array of image format backends from the given plugin to the list of known
128 * image formats.
129 *
130 * @returns VBox status code.
131 * @param hPlugin The plugin handle the backends belong to, can be NIL_RTLDRMOD
132 * for compiled in backends.
133 * @param ppBackends The array of image backend descriptors to add.
134 * @param cBackends Number of descriptors in the array.
135 */
136static int vdAddBackends(RTLDRMOD hPlugin, PCVDIMAGEBACKEND *ppBackends, unsigned cBackends)
137{
138 PCVDIMAGEBACKEND *pTmp = (PCVDIMAGEBACKEND *)RTMemRealloc(g_apBackends,
139 (g_cBackends + cBackends) * sizeof(PCVDIMAGEBACKEND));
140 if (RT_UNLIKELY(!pTmp))
141 return VERR_NO_MEMORY;
142 g_apBackends = pTmp;
143 memcpy(&g_apBackends[g_cBackends], ppBackends, cBackends * sizeof(PCVDIMAGEBACKEND));
144
145#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
146 RTLDRMOD *pTmpPlugins = (RTLDRMOD*)RTMemRealloc(g_ahBackendPlugins,
147 (g_cBackends + cBackends) * sizeof(RTLDRMOD));
148 if (RT_UNLIKELY(!pTmpPlugins))
149 return VERR_NO_MEMORY;
150 g_ahBackendPlugins = pTmpPlugins;
151 for (unsigned i = g_cBackends; i < g_cBackends + cBackends; i++)
152 g_ahBackendPlugins[i] = hPlugin;
153#else
154 RT_NOREF(hPlugin);
155#endif
156
157 g_cBackends += cBackends;
158 return VINF_SUCCESS;
159}
160
161
162/**
163 * Add an array of cache format backends from the given plugin to the list of known
164 * cache formats.
165 *
166 * @returns VBox status code.
167 * @param hPlugin The plugin handle the backends belong to, can be NIL_RTLDRMOD
168 * for compiled in backends.
169 * @param ppBackends The array of cache backend descriptors to add.
170 * @param cBackends Number of descriptors in the array.
171 */
172static int vdAddCacheBackends(RTLDRMOD hPlugin, PCVDCACHEBACKEND *ppBackends, unsigned cBackends)
173{
174 PCVDCACHEBACKEND *pTmp = (PCVDCACHEBACKEND*)RTMemReallocTag(g_apCacheBackends,
175 (g_cCacheBackends + cBackends) * sizeof(PCVDCACHEBACKEND),
176 "may-leak:vdAddCacheBackend");
177 if (RT_UNLIKELY(!pTmp))
178 return VERR_NO_MEMORY;
179 g_apCacheBackends = pTmp;
180 memcpy(&g_apCacheBackends[g_cCacheBackends], ppBackends, cBackends * sizeof(PCVDCACHEBACKEND));
181
182#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
183 RTLDRMOD *pTmpPlugins = (RTLDRMOD*)RTMemReallocTag(g_ahCacheBackendPlugins,
184 (g_cCacheBackends + cBackends) * sizeof(RTLDRMOD),
185 "may-leak:vdAddCacheBackend");
186 if (RT_UNLIKELY(!pTmpPlugins))
187 return VERR_NO_MEMORY;
188 g_ahCacheBackendPlugins = pTmpPlugins;
189 for (unsigned i = g_cCacheBackends; i < g_cCacheBackends + cBackends; i++)
190 g_ahCacheBackendPlugins[i] = hPlugin;
191#else
192 RT_NOREF(hPlugin);
193#endif
194
195 g_cCacheBackends += cBackends;
196 return VINF_SUCCESS;
197}
198
199#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
200/**
201 * Add a single image format backend to the list of known image formats.
202 *
203 * @returns VBox status code.
204 * @param hPlugin The plugin handle the backend belongs to, can be NIL_RTLDRMOD
205 * for compiled in backends.
206 * @param pBackend The image backend descriptors to add.
207 */
208DECLINLINE(int) vdAddBackend(RTLDRMOD hPlugin, PCVDIMAGEBACKEND pBackend)
209{
210 return vdAddBackends(hPlugin, &pBackend, 1);
211}
212
213
214/**
215 * Add a single cache format backend to the list of known cache formats.
216 *
217 * @returns VBox status code.
218 * @param hPlugin The plugin handle the backend belongs to, can be NIL_RTLDRMOD
219 * for compiled in backends.
220 * @param pBackend The cache backend descriptors to add.
221 */
222DECLINLINE(int) vdAddCacheBackend(RTLDRMOD hPlugin, PCVDCACHEBACKEND pBackend)
223{
224 return vdAddCacheBackends(hPlugin, &pBackend, 1);
225}
226
227
228/**
229 * Add several filter backends.
230 *
231 * @returns VBox status code.
232 * @param hPlugin Plugin handle to add.
233 * @param ppBackends Array of filter backends to add.
234 * @param cBackends Number of backends to add.
235 */
236static int vdAddFilterBackends(RTLDRMOD hPlugin, PCVDFILTERBACKEND *ppBackends, unsigned cBackends)
237{
238 PCVDFILTERBACKEND *pTmp = (PCVDFILTERBACKEND *)RTMemRealloc(g_apFilterBackends,
239 (g_cFilterBackends + cBackends) * sizeof(PCVDFILTERBACKEND));
240 if (RT_UNLIKELY(!pTmp))
241 return VERR_NO_MEMORY;
242 g_apFilterBackends = pTmp;
243
244#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
245 PRTLDRMOD pTmpPlugins = (PRTLDRMOD)RTMemRealloc(g_pahFilterBackendPlugins,
246 (g_cFilterBackends + cBackends) * sizeof(RTLDRMOD));
247 if (RT_UNLIKELY(!pTmpPlugins))
248 return VERR_NO_MEMORY;
249
250 g_pahFilterBackendPlugins = pTmpPlugins;
251 memcpy(&g_apFilterBackends[g_cFilterBackends], ppBackends, cBackends * sizeof(PCVDFILTERBACKEND));
252 for (unsigned i = g_cFilterBackends; i < g_cFilterBackends + cBackends; i++)
253 g_pahFilterBackendPlugins[i] = hPlugin;
254#else
255 RT_NOREF(hPlugin);
256#endif
257
258 g_cFilterBackends += cBackends;
259 return VINF_SUCCESS;
260}
261
262
263/**
264 * Add a single filter backend to the list of supported filters.
265 *
266 * @returns VBox status code.
267 * @param hPlugin Plugin handle to add.
268 * @param pBackend The backend to add.
269 */
270DECLINLINE(int) vdAddFilterBackend(RTLDRMOD hPlugin, PCVDFILTERBACKEND pBackend)
271{
272 return vdAddFilterBackends(hPlugin, &pBackend, 1);
273}
274
275/**
276 * @interface_method_impl{VDBACKENDREGISTER,pfnRegisterImage}
277 */
278static DECLCALLBACK(int) vdPluginRegisterImage(void *pvUser, PCVDIMAGEBACKEND pBackend)
279{
280 int rc = VINF_SUCCESS;
281
282 if (VD_VERSION_ARE_COMPATIBLE(VD_IMGBACKEND_VERSION, pBackend->u32Version))
283 vdAddBackend((RTLDRMOD)pvUser, pBackend);
284 else
285 {
286 LogFunc(("ignored plugin: pBackend->u32Version=%u rc=%Rrc\n", pBackend->u32Version, rc));
287 rc = VERR_IGNORED;
288 }
289
290 return rc;
291}
292
293/**
294 * @interface_method_impl{VDBACKENDREGISTER,pfnRegisterCache}
295 */
296static DECLCALLBACK(int) vdPluginRegisterCache(void *pvUser, PCVDCACHEBACKEND pBackend)
297{
298 int rc = VINF_SUCCESS;
299
300 if (VD_VERSION_ARE_COMPATIBLE(VD_CACHEBACKEND_VERSION, pBackend->u32Version))
301 vdAddCacheBackend((RTLDRMOD)pvUser, pBackend);
302 else
303 {
304 LogFunc(("ignored plugin: pBackend->u32Version=%u rc=%Rrc\n", pBackend->u32Version, rc));
305 rc = VERR_IGNORED;
306 }
307
308 return rc;
309}
310
311/**
312 * @interface_method_impl{VDBACKENDREGISTER,pfnRegisterFilter}
313 */
314static DECLCALLBACK(int) vdPluginRegisterFilter(void *pvUser, PCVDFILTERBACKEND pBackend)
315{
316 int rc = VINF_SUCCESS;
317
318 if (VD_VERSION_ARE_COMPATIBLE(VD_FLTBACKEND_VERSION, pBackend->u32Version))
319 vdAddFilterBackend((RTLDRMOD)pvUser, pBackend);
320 else
321 {
322 LogFunc(("ignored plugin: pBackend->u32Version=%u rc=%Rrc\n", pBackend->u32Version, rc));
323 rc = VERR_IGNORED;
324 }
325
326 return rc;
327}
328
329/**
330 * Checks whether the given plugin filename was already loaded.
331 *
332 * @returns Pointer to already loaded plugin, NULL if not found.
333 * @param pszFilename The filename to check.
334 */
335static PVDPLUGIN vdPluginFind(const char *pszFilename)
336{
337 PVDPLUGIN pIt;
338 RTListForEach(&g_ListPluginsLoaded, pIt, VDPLUGIN, NodePlugin)
339 {
340 if (!RTStrCmp(pIt->pszFilename, pszFilename))
341 return pIt;
342 }
343
344 return NULL;
345}
346
347/**
348 * Adds a plugin to the list of loaded plugins.
349 *
350 * @returns VBox status code.
351 * @param hPlugin Plugin handle to add.
352 * @param pszFilename The associated filename, used for finding duplicates.
353 */
354static int vdAddPlugin(RTLDRMOD hPlugin, const char *pszFilename)
355{
356 int rc = VINF_SUCCESS;
357 PVDPLUGIN pPlugin = (PVDPLUGIN)RTMemAllocZ(sizeof(VDPLUGIN));
358
359 if (pPlugin)
360 {
361 pPlugin->hPlugin = hPlugin;
362 pPlugin->pszFilename = RTStrDup(pszFilename);
363 if (pPlugin->pszFilename)
364 RTListAppend(&g_ListPluginsLoaded, &pPlugin->NodePlugin);
365 else
366 {
367 RTMemFree(pPlugin);
368 rc = VERR_NO_MEMORY;
369 }
370 }
371 else
372 rc = VERR_NO_MEMORY;
373
374 return rc;
375}
376
377/**
378 * Removes a single plugin given by the filename.
379 *
380 * @returns VBox status code.
381 * @param pszFilename The plugin filename to remove.
382 */
383static int vdRemovePlugin(const char *pszFilename)
384{
385 /* Find plugin to be removed from the list. */
386 PVDPLUGIN pIt = vdPluginFind(pszFilename);
387 if (!pIt)
388 return VINF_SUCCESS;
389
390 /** @todo r=klaus: need to add a plugin entry point for unregistering the
391 * backends. Only if this doesn't exist (or fails to work) we should fall
392 * back to the following uncoordinated backend cleanup. */
393 for (unsigned i = 0; i < g_cBackends; i++)
394 {
395 while (i < g_cBackends && g_ahBackendPlugins[i] == pIt->hPlugin)
396 {
397 memmove(&g_apBackends[i], &g_apBackends[i + 1], (g_cBackends - i - 1) * sizeof(PCVDIMAGEBACKEND));
398 memmove(&g_ahBackendPlugins[i], &g_ahBackendPlugins[i + 1], (g_cBackends - i - 1) * sizeof(RTLDRMOD));
399 /** @todo for now skip reallocating, doesn't save much */
400 g_cBackends--;
401 }
402 }
403 for (unsigned i = 0; i < g_cCacheBackends; i++)
404 {
405 while (i < g_cCacheBackends && g_ahCacheBackendPlugins[i] == pIt->hPlugin)
406 {
407 memmove(&g_apCacheBackends[i], &g_apCacheBackends[i + 1], (g_cCacheBackends - i - 1) * sizeof(PCVDCACHEBACKEND));
408 memmove(&g_ahCacheBackendPlugins[i], &g_ahCacheBackendPlugins[i + 1], (g_cCacheBackends - i - 1) * sizeof(RTLDRMOD));
409 /** @todo for now skip reallocating, doesn't save much */
410 g_cCacheBackends--;
411 }
412 }
413 for (unsigned i = 0; i < g_cFilterBackends; i++)
414 {
415 while (i < g_cFilterBackends && g_pahFilterBackendPlugins[i] == pIt->hPlugin)
416 {
417 memmove(&g_apFilterBackends[i], &g_apFilterBackends[i + 1], (g_cFilterBackends - i - 1) * sizeof(PCVDFILTERBACKEND));
418 memmove(&g_pahFilterBackendPlugins[i], &g_pahFilterBackendPlugins[i + 1], (g_cFilterBackends - i - 1) * sizeof(RTLDRMOD));
419 /** @todo for now skip reallocating, doesn't save much */
420 g_cFilterBackends--;
421 }
422 }
423
424 /* Remove the plugin node now, all traces of it are gone. */
425 RTListNodeRemove(&pIt->NodePlugin);
426 RTLdrClose(pIt->hPlugin);
427 RTStrFree(pIt->pszFilename);
428 RTMemFree(pIt);
429
430 return VINF_SUCCESS;
431}
432
433#endif /* VBOX_HDD_NO_DYNAMIC_BACKENDS*/
434
435/**
436 * Returns the number of known image format backends.
437 *
438 * @returns Number of image formats known.
439 */
440DECLHIDDEN(uint32_t) vdGetImageBackendCount(void)
441{
442 return g_cBackends;
443}
444
445
446/**
447 * Queries a image backend descriptor by the index.
448 *
449 * @returns VBox status code.
450 * @param idx The index of the backend to query.
451 * @param ppBackend Where to store the pointer to the backend descriptor on success.
452 */
453DECLHIDDEN(int) vdQueryImageBackend(uint32_t idx, PCVDIMAGEBACKEND *ppBackend)
454{
455 if (idx >= g_cBackends)
456 return VERR_OUT_OF_RANGE;
457
458 *ppBackend = g_apBackends[idx];
459 return VINF_SUCCESS;
460}
461
462
463/**
464 * Returns the image backend descriptor matching the given identifier if known.
465 *
466 * @returns VBox status code.
467 * @param pszBackend The backend identifier to look for.
468 * @param ppBackend Where to store the pointer to the backend descriptor on success.
469 */
470DECLHIDDEN(int) vdFindImageBackend(const char *pszBackend, PCVDIMAGEBACKEND *ppBackend)
471{
472 int rc = VERR_NOT_FOUND;
473 PCVDIMAGEBACKEND pBackend = NULL;
474
475 if (!g_apBackends)
476 VDInit();
477
478 for (unsigned i = 0; i < g_cBackends; i++)
479 {
480 if (!RTStrICmp(pszBackend, g_apBackends[i]->pszBackendName))
481 {
482 pBackend = g_apBackends[i];
483 rc = VINF_SUCCESS;
484 break;
485 }
486 }
487 *ppBackend = pBackend;
488 return rc;
489}
490
491/**
492 * Returns the number of known cache format backends.
493 *
494 * @returns Number of image formats known.
495 */
496DECLHIDDEN(uint32_t) vdGetCacheBackendCount(void)
497{
498 return g_cCacheBackends;
499}
500
501
502/**
503 * Queries a cache backend descriptor by the index.
504 *
505 * @returns VBox status code.
506 * @param idx The index of the backend to query.
507 * @param ppBackend Where to store the pointer to the backend descriptor on success.
508 */
509DECLHIDDEN(int) vdQueryCacheBackend(uint32_t idx, PCVDCACHEBACKEND *ppBackend)
510{
511 if (idx >= g_cCacheBackends)
512 return VERR_OUT_OF_RANGE;
513
514 *ppBackend = g_apCacheBackends[idx];
515 return VINF_SUCCESS;
516}
517
518
519/**
520 * Returns the cache backend descriptor matching the given identifier if known.
521 *
522 * @returns VBox status code.
523 * @param pszBackend The backend identifier to look for.
524 * @param ppBackend Where to store the pointer to the backend descriptor on success.
525 */
526DECLHIDDEN(int) vdFindCacheBackend(const char *pszBackend, PCVDCACHEBACKEND *ppBackend)
527{
528 int rc = VERR_NOT_FOUND;
529 PCVDCACHEBACKEND pBackend = NULL;
530
531 if (!g_apCacheBackends)
532 VDInit();
533
534 for (unsigned i = 0; i < g_cCacheBackends; i++)
535 {
536 if (!RTStrICmp(pszBackend, g_apCacheBackends[i]->pszBackendName))
537 {
538 pBackend = g_apCacheBackends[i];
539 rc = VINF_SUCCESS;
540 break;
541 }
542 }
543 *ppBackend = pBackend;
544 return rc;
545}
546
547
548/**
549 * Returns the number of known filter backends.
550 *
551 * @returns Number of image formats known.
552 */
553DECLHIDDEN(uint32_t) vdGetFilterBackendCount(void)
554{
555 return g_cFilterBackends;
556}
557
558
559/**
560 * Queries a filter backend descriptor by the index.
561 *
562 * @returns VBox status code.
563 * @param idx The index of the backend to query.
564 * @param ppBackend Where to store the pointer to the backend descriptor on success.
565 */
566DECLHIDDEN(int) vdQueryFilterBackend(uint32_t idx, PCVDFILTERBACKEND *ppBackend)
567{
568 if (idx >= g_cFilterBackends)
569 return VERR_OUT_OF_RANGE;
570
571 *ppBackend = g_apFilterBackends[idx];
572 return VINF_SUCCESS;
573}
574
575
576/**
577 * Returns the filter backend descriptor matching the given identifier if known.
578 *
579 * @returns VBox status code.
580 * @param pszFilter The filter identifier to look for.
581 * @param ppBackend Where to store the pointer to the backend descriptor on success.
582 */
583DECLHIDDEN(int) vdFindFilterBackend(const char *pszFilter, PCVDFILTERBACKEND *ppBackend)
584{
585 int rc = VERR_NOT_FOUND;
586 PCVDFILTERBACKEND pBackend = NULL;
587
588 for (unsigned i = 0; i < g_cFilterBackends; i++)
589 {
590 if (!RTStrICmp(pszFilter, g_apFilterBackends[i]->pszBackendName))
591 {
592 pBackend = g_apFilterBackends[i];
593 rc = VINF_SUCCESS;
594 break;
595 }
596 }
597 *ppBackend = pBackend;
598 return rc;
599}
600
601
602/**
603 * Worker for VDPluginLoadFromFilename() and vdPluginLoadFromPath().
604 *
605 * @returns VBox status code.
606 * @param pszFilename The plugin filename to load.
607 */
608DECLHIDDEN(int) vdPluginLoadFromFilename(const char *pszFilename)
609{
610#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
611 /* Plugin loaded? Nothing to do. */
612 if (vdPluginFind(pszFilename))
613 {
614 LogFlowFunc(("Plugin '%s' already loaded\n", pszFilename));
615 return VINF_SUCCESS;
616 }
617
618 RTLDRMOD hPlugin = NIL_RTLDRMOD;
619 int rc = SUPR3HardenedLdrLoadPlugIn(pszFilename, &hPlugin, NULL);
620 LogFlowFunc(("SUPR3HardenedLdrLoadPlugIn('%s') -> %Rrc\n", pszFilename, rc));
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.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette