VirtualBox

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

Last change on this file since 69564 was 69230, checked in by vboxsync, 7 years ago

Storage: scm updates

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

© 2023 Oracle
ContactPrivacy policyTerms of Use