VirtualBox

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

Last change on this file since 84175 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • 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 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * VD - Virtual disk container implementation, plugin related bits.
4 */
5
6/*
7 * Copyright (C) 2017-2020 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.

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