VirtualBox

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

Last change on this file since 69111 was 67455, checked in by vboxsync, 7 years ago

Storage: Hacked up a virtual image format around the IPRT ISO maker API. (untsted)

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