VirtualBox

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

Last change on this file since 78296 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use