VirtualBox

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

Last change on this file since 67000 was 66380, checked in by vboxsync, 8 years ago

Storage/VD: build fix

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