VirtualBox

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

Last change on this file since 72118 was 69968, checked in by vboxsync, 7 years ago

VDPlugin: Free g_ahCacheBackendPlugins on shutdown; don't use memcpy to shuffle array members, use memmov.

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