VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/CFGM.cpp@ 58008

Last change on this file since 58008 was 57358, checked in by vboxsync, 10 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 96.4 KB
Line 
1/* $Id: CFGM.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * CFGM - Configuration Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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/** @page pg_cfgm CFGM - The Configuration Manager
19 *
20 * The configuration manager is a directory containing the VM configuration at
21 * run time. It works in a manner similar to the windows registry - it's like a
22 * file system hierarchy, but the files (values) live in a separate name space
23 * and can include the path separators.
24 *
25 * The configuration is normally created via a callback passed to VMR3Create()
26 * via the pfnCFGMConstructor parameter. To make testcase writing a bit simpler,
27 * we allow the callback to be NULL, in which case a simple default
28 * configuration will be created by CFGMR3ConstructDefaultTree(). The
29 * Console::configConstructor() method in Main/ConsoleImpl2.cpp creates the
30 * configuration from the XML.
31 *
32 * Devices, drivers, services and other PDM stuff are given their own subtree
33 * where they are protected from accessing information of any parents. This is
34 * is implemented via the CFGMR3SetRestrictedRoot() API.
35 *
36 * Data validation beyond the basic primitives is left to the caller. The caller
37 * is in a better position to know the proper validation rules of the individual
38 * properties.
39 *
40 * @see grp_cfgm
41 *
42 *
43 * @section sec_cfgm_primitives Data Primitives
44 *
45 * CFGM supports the following data primitives:
46 * - Integers. Representation is unsigned 64-bit. Boolean, unsigned and
47 * small integers, and pointers are all represented using this primitive.
48 * - Zero terminated character strings. These are of course UTF-8.
49 * - Variable length byte strings. This can be used to get/put binary
50 * objects like for instance RTMAC.
51 *
52 */
53
54
55/*********************************************************************************************************************************
56* Header Files *
57*********************************************************************************************************************************/
58#define LOG_GROUP LOG_GROUP_CFGM
59#include <VBox/vmm/cfgm.h>
60#include <VBox/vmm/dbgf.h>
61#include <VBox/vmm/mm.h>
62#include "CFGMInternal.h"
63#include <VBox/vmm/vm.h>
64#include <VBox/vmm/uvm.h>
65#include <VBox/err.h>
66
67#include <VBox/log.h>
68#include <iprt/assert.h>
69#include <iprt/mem.h>
70#include <iprt/param.h>
71#include <iprt/string.h>
72#include <iprt/uuid.h>
73
74
75/*********************************************************************************************************************************
76* Internal Functions *
77*********************************************************************************************************************************/
78static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp);
79static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp);
80static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
81static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild);
82static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf);
83static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf);
84static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf);
85static void cfgmR3FreeValue(PVM pVM, PCFGMLEAF pLeaf);
86
87
88/**
89 * Allocator wrapper.
90 *
91 * @returns Pointer to the allocated memory, NULL on failure.
92 * @param pVM The VM handle, if tree associated with one.
93 * @param enmTag The allocation tag.
94 * @param cb The size of the allocation.
95 */
96static void *cfgmR3MemAlloc(PVM pVM, MMTAG enmTag, size_t cb)
97{
98 if (pVM)
99 return MMR3HeapAlloc(pVM, enmTag, cb);
100 return RTMemAlloc(cb);
101}
102
103
104/**
105 * Free wrapper.
106 *
107 * @returns Pointer to the allocated memory, NULL on failure.
108 * @param pVM The VM handle, if tree associated with one.
109 * @param pv The memory block to free.
110 */
111static void cfgmR3MemFree(PVM pVM, void *pv)
112{
113 if (pVM)
114 MMR3HeapFree(pv);
115 else
116 RTMemFree(pv);
117}
118
119
120/**
121 * String allocator wrapper.
122 *
123 * @returns Pointer to the allocated memory, NULL on failure.
124 * @param pVM The VM handle, if tree associated with one.
125 * @param enmTag The allocation tag.
126 * @param cbString The size of the allocation, terminator included.
127 */
128static char *cfgmR3StrAlloc(PVM pVM, MMTAG enmTag, size_t cbString)
129{
130 if (pVM)
131 return (char *)MMR3HeapAlloc(pVM, enmTag, cbString);
132 return (char *)RTStrAlloc(cbString);
133}
134
135
136/**
137 * String free wrapper.
138 *
139 * @returns Pointer to the allocated memory, NULL on failure.
140 * @param pVM The VM handle, if tree associated with one.
141 * @param pszString The memory block to free.
142 */
143static void cfgmR3StrFree(PVM pVM, char *pszString)
144{
145 if (pVM)
146 MMR3HeapFree(pszString);
147 else
148 RTStrFree(pszString);
149}
150
151
152/**
153 * Frees one node, leaving any children or leaves to the caller.
154 *
155 * @param pNode The node structure to free.
156 */
157static void cfgmR3FreeNodeOnly(PCFGMNODE pNode)
158{
159 pNode->pFirstLeaf = NULL;
160 pNode->pFirstChild = NULL;
161 pNode->pNext = NULL;
162 pNode->pPrev = NULL;
163 if (!pNode->pVM)
164 RTMemFree(pNode);
165 else
166 {
167 pNode->pVM = NULL;
168 MMR3HeapFree(pNode);
169 }
170}
171
172
173
174
175/**
176 * Constructs the configuration for the VM.
177 *
178 * @returns VBox status code.
179 * @param pVM Pointer to VM which configuration has not yet been loaded.
180 * @param pfnCFGMConstructor Pointer to callback function for constructing the VM configuration tree.
181 * This is called in the EM.
182 * @param pvUser The user argument passed to pfnCFGMConstructor.
183 * @thread EMT.
184 * @internal
185 */
186VMMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUser)
187{
188 LogFlow(("CFGMR3Init: pfnCFGMConstructor=%p pvUser=%p\n", pfnCFGMConstructor, pvUser));
189
190 /*
191 * Init data members.
192 */
193 pVM->cfgm.s.pRoot = NULL;
194
195 /*
196 * Register DBGF into item.
197 */
198 int rc = DBGFR3InfoRegisterInternal(pVM, "cfgm", "Dumps a part of the CFGM tree. The argument indicates where to start.",
199 cfgmR3Info);
200 AssertRCReturn(rc,rc);
201
202 /*
203 * Root Node.
204 */
205 PCFGMNODE pRoot = (PCFGMNODE)MMR3HeapAllocZ(pVM, MM_TAG_CFGM, sizeof(*pRoot));
206 if (!pRoot)
207 return VERR_NO_MEMORY;
208 pRoot->pVM = pVM;
209 pRoot->cchName = 0;
210 pVM->cfgm.s.pRoot = pRoot;
211
212 /*
213 * Call the constructor if specified, if not use the default one.
214 */
215 if (pfnCFGMConstructor)
216 rc = pfnCFGMConstructor(pVM->pUVM, pVM, pvUser);
217 else
218 rc = CFGMR3ConstructDefaultTree(pVM);
219 if (RT_SUCCESS(rc))
220 {
221 Log(("CFGMR3Init: Successfully constructed the configuration\n"));
222 CFGMR3Dump(CFGMR3GetRoot(pVM));
223 }
224 else
225 AssertMsgFailed(("Constructor failed with rc=%Rrc pfnCFGMConstructor=%p\n", rc, pfnCFGMConstructor));
226
227 return rc;
228}
229
230
231/**
232 * Terminates the configuration manager.
233 *
234 * @returns VBox status code.
235 * @param pVM Pointer to the VM.
236 * @internal
237 */
238VMMR3DECL(int) CFGMR3Term(PVM pVM)
239{
240 CFGMR3RemoveNode(pVM->cfgm.s.pRoot);
241 pVM->cfgm.s.pRoot = NULL;
242 return 0;
243}
244
245
246/**
247 * Gets the root node for the VM.
248 *
249 * @returns Pointer to root node.
250 * @param pVM Pointer to the VM.
251 */
252VMMR3DECL(PCFGMNODE) CFGMR3GetRoot(PVM pVM)
253{
254 return pVM->cfgm.s.pRoot;
255}
256
257
258/**
259 * Gets the root node for the VM.
260 *
261 * @returns Pointer to root node.
262 * @param pVM Pointer to the VM.
263 */
264VMMR3DECL(PCFGMNODE) CFGMR3GetRootU(PUVM pUVM)
265{
266 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
267 PVM pVM = pUVM->pVM;
268 AssertReturn(pVM, NULL);
269 return pVM->cfgm.s.pRoot;
270}
271
272
273/**
274 * Gets the parent of a CFGM node.
275 *
276 * @returns Pointer to the parent node.
277 * @returns NULL if pNode is Root or pNode is the start of a
278 * restricted subtree (use CFGMr3GetParentEx() for that).
279 *
280 * @param pNode The node which parent we query.
281 */
282VMMR3DECL(PCFGMNODE) CFGMR3GetParent(PCFGMNODE pNode)
283{
284 if (pNode && !pNode->fRestrictedRoot)
285 return pNode->pParent;
286 return NULL;
287}
288
289
290/**
291 * Gets the parent of a CFGM node.
292 *
293 * @returns Pointer to the parent node.
294 * @returns NULL if pNode is Root or pVM is not correct.
295 *
296 * @param pVM The VM handle, used as token that the caller is trusted.
297 * @param pNode The node which parent we query.
298 */
299VMMR3DECL(PCFGMNODE) CFGMR3GetParentEx(PVM pVM, PCFGMNODE pNode)
300{
301 if (pNode && pNode->pVM == pVM)
302 return pNode->pParent;
303 return NULL;
304}
305
306
307/**
308 * Query a child node.
309 *
310 * @returns Pointer to the specified node.
311 * @returns NULL if node was not found or pNode is NULL.
312 * @param pNode Node pszPath is relative to.
313 * @param pszPath Path to the child node or pNode.
314 * It's good style to end this with '/'.
315 */
316VMMR3DECL(PCFGMNODE) CFGMR3GetChild(PCFGMNODE pNode, const char *pszPath)
317{
318 PCFGMNODE pChild;
319 int rc = cfgmR3ResolveNode(pNode, pszPath, &pChild);
320 if (RT_SUCCESS(rc))
321 return pChild;
322 return NULL;
323}
324
325
326/**
327 * Query a child node by a format string.
328 *
329 * @returns Pointer to the specified node.
330 * @returns NULL if node was not found or pNode is NULL.
331 * @param pNode Node pszPath is relative to.
332 * @param pszPathFormat Path to the child node or pNode.
333 * It's good style to end this with '/'.
334 * @param ... Arguments to pszPathFormat.
335 */
336VMMR3DECL(PCFGMNODE) CFGMR3GetChildF(PCFGMNODE pNode, const char *pszPathFormat, ...)
337{
338 va_list Args;
339 va_start(Args, pszPathFormat);
340 PCFGMNODE pRet = CFGMR3GetChildFV(pNode, pszPathFormat, Args);
341 va_end(Args);
342 return pRet;
343}
344
345
346/**
347 * Query a child node by a format string.
348 *
349 * @returns Pointer to the specified node.
350 * @returns NULL if node was not found or pNode is NULL.
351 * @param pNode Node pszPath is relative to.
352 * @param pszPathFormat Path to the child node or pNode.
353 * It's good style to end this with '/'.
354 * @param Args Arguments to pszPathFormat.
355 */
356VMMR3DECL(PCFGMNODE) CFGMR3GetChildFV(PCFGMNODE pNode, const char *pszPathFormat, va_list Args)
357{
358 char *pszPath;
359 RTStrAPrintfV(&pszPath, pszPathFormat, Args);
360 if (pszPath)
361 {
362 PCFGMNODE pChild;
363 int rc = cfgmR3ResolveNode(pNode, pszPath, &pChild);
364 RTStrFree(pszPath);
365 if (RT_SUCCESS(rc))
366 return pChild;
367 }
368 return NULL;
369}
370
371
372/**
373 * Gets the first child node.
374 * Use this to start an enumeration of child nodes.
375 *
376 * @returns Pointer to the first child.
377 * @returns NULL if no children.
378 * @param pNode Node to enumerate children for.
379 */
380VMMR3DECL(PCFGMNODE) CFGMR3GetFirstChild(PCFGMNODE pNode)
381{
382 return pNode ? pNode->pFirstChild : NULL;
383}
384
385
386/**
387 * Gets the next sibling node.
388 * Use this to continue an enumeration.
389 *
390 * @returns Pointer to the first child.
391 * @returns NULL if no children.
392 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
393 * or successive calls to this function.
394 */
395VMMR3DECL(PCFGMNODE) CFGMR3GetNextChild(PCFGMNODE pCur)
396{
397 return pCur ? pCur->pNext : NULL;
398}
399
400
401/**
402 * Gets the name of the current node.
403 * (Needed for enumeration.)
404 *
405 * @returns VBox status code.
406 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
407 * or successive calls to CFGMR3GetNextChild().
408 * @param pszName Where to store the node name.
409 * @param cchName Size of the buffer pointed to by pszName (with terminator).
410 */
411VMMR3DECL(int) CFGMR3GetName(PCFGMNODE pCur, char *pszName, size_t cchName)
412{
413 int rc;
414 if (pCur)
415 {
416 if (cchName > pCur->cchName)
417 {
418 rc = VINF_SUCCESS;
419 memcpy(pszName, pCur->szName, pCur->cchName + 1);
420 }
421 else
422 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
423 }
424 else
425 rc = VERR_CFGM_NO_NODE;
426 return rc;
427}
428
429
430/**
431 * Gets the length of the current node's name.
432 * (Needed for enumeration.)
433 *
434 * @returns Node name length in bytes including the terminating null char.
435 * @returns 0 if pCur is NULL.
436 * @param pCur Node to returned by a call to CFGMR3GetFirstChild()
437 * or successive calls to CFGMR3GetNextChild().
438 */
439VMMR3DECL(size_t) CFGMR3GetNameLen(PCFGMNODE pCur)
440{
441 return pCur ? pCur->cchName + 1 : 0;
442}
443
444
445/**
446 * Validates that the child nodes are within a set of valid names.
447 *
448 * @returns true if all names are found in pszzAllowed.
449 * @returns false if not.
450 * @param pNode The node which children should be examined.
451 * @param pszzValid List of valid names separated by '\\0' and ending with
452 * a double '\\0'.
453 *
454 * @deprecated Use CFGMR3ValidateConfig.
455 */
456VMMR3DECL(bool) CFGMR3AreChildrenValid(PCFGMNODE pNode, const char *pszzValid)
457{
458 if (pNode)
459 {
460 for (PCFGMNODE pChild = pNode->pFirstChild; pChild; pChild = pChild->pNext)
461 {
462 /* search pszzValid for the name */
463 const char *psz = pszzValid;
464 while (*psz)
465 {
466 size_t cch = strlen(psz);
467 if ( cch == pChild->cchName
468 && !memcmp(psz, pChild->szName, cch))
469 break;
470
471 /* next */
472 psz += cch + 1;
473 }
474
475 /* if at end of pszzValid we didn't find it => failure */
476 if (!*psz)
477 {
478 AssertMsgFailed(("Couldn't find '%s' in the valid values\n", pChild->szName));
479 return false;
480 }
481 }
482 }
483
484 /* all ok. */
485 return true;
486}
487
488
489/**
490 * Gets the first value of a node.
491 * Use this to start an enumeration of values.
492 *
493 * @returns Pointer to the first value.
494 * @param pCur The node (Key) which values to enumerate.
495 */
496VMMR3DECL(PCFGMLEAF) CFGMR3GetFirstValue(PCFGMNODE pCur)
497{
498 return pCur ? pCur->pFirstLeaf : NULL;
499}
500
501/**
502 * Gets the next value in enumeration.
503 *
504 * @returns Pointer to the next value.
505 * @param pCur The current value as returned by this function or CFGMR3GetFirstValue().
506 */
507VMMR3DECL(PCFGMLEAF) CFGMR3GetNextValue(PCFGMLEAF pCur)
508{
509 return pCur ? pCur->pNext : NULL;
510}
511
512/**
513 * Get the value name.
514 * (Needed for enumeration.)
515 *
516 * @returns VBox status code.
517 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
518 * or successive calls to CFGMR3GetNextValue().
519 * @param pszName Where to store the value name.
520 * @param cchName Size of the buffer pointed to by pszName (with terminator).
521 */
522VMMR3DECL(int) CFGMR3GetValueName(PCFGMLEAF pCur, char *pszName, size_t cchName)
523{
524 int rc;
525 if (pCur)
526 {
527 if (cchName > pCur->cchName)
528 {
529 rc = VINF_SUCCESS;
530 memcpy(pszName, pCur->szName, pCur->cchName + 1);
531 }
532 else
533 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
534 }
535 else
536 rc = VERR_CFGM_NO_NODE;
537 return rc;
538}
539
540
541/**
542 * Gets the length of the current node's name.
543 * (Needed for enumeration.)
544 *
545 * @returns Value name length in bytes including the terminating null char.
546 * @returns 0 if pCur is NULL.
547 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
548 * or successive calls to CFGMR3GetNextValue().
549 */
550VMMR3DECL(size_t) CFGMR3GetValueNameLen(PCFGMLEAF pCur)
551{
552 return pCur ? pCur->cchName + 1 : 0;
553}
554
555
556/**
557 * Gets the value type.
558 * (For enumeration.)
559 *
560 * @returns VBox status code.
561 * @param pCur Value returned by a call to CFGMR3GetFirstValue()
562 * or successive calls to CFGMR3GetNextValue().
563 */
564VMMR3DECL(CFGMVALUETYPE) CFGMR3GetValueType(PCFGMLEAF pCur)
565{
566 Assert(pCur);
567 return pCur->enmType;
568}
569
570
571/**
572 * Validates that the values are within a set of valid names.
573 *
574 * @returns true if all names are found in pszzAllowed.
575 * @returns false if not.
576 * @param pNode The node which values should be examined.
577 * @param pszzValid List of valid names separated by '\\0' and ending with
578 * a double '\\0'.
579 * @deprecated Use CFGMR3ValidateConfig.
580 */
581VMMR3DECL(bool) CFGMR3AreValuesValid(PCFGMNODE pNode, const char *pszzValid)
582{
583 if (pNode)
584 {
585 for (PCFGMLEAF pLeaf = pNode->pFirstLeaf; pLeaf; pLeaf = pLeaf->pNext)
586 {
587 /* search pszzValid for the name */
588 const char *psz = pszzValid;
589 while (*psz)
590 {
591 size_t cch = strlen(psz);
592 if ( cch == pLeaf->cchName
593 && !memcmp(psz, pLeaf->szName, cch))
594 break;
595
596 /* next */
597 psz += cch + 1;
598 }
599
600 /* if at end of pszzValid we didn't find it => failure */
601 if (!*psz)
602 {
603 AssertMsgFailed(("Couldn't find '%s' in the valid values\n", pLeaf->szName));
604 return false;
605 }
606 }
607 }
608
609 /* all ok. */
610 return true;
611}
612
613
614/**
615 * Checks if the given value exists.
616 *
617 * @returns true if it exists, false if not.
618 * @param pNode Which node to search for pszName in.
619 * @param pszName The name of the value we seek.
620 */
621VMMR3DECL(bool) CFGMR3Exists(PCFGMNODE pNode, const char *pszName)
622{
623 PCFGMLEAF pLeaf;
624 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
625 return RT_SUCCESS_NP(rc);
626}
627
628
629/**
630 * Query value type.
631 *
632 * @returns VBox status code.
633 * @param pNode Which node to search for pszName in.
634 * @param pszName Name of an integer value.
635 * @param penmType Where to store the type.
636 */
637VMMR3DECL(int) CFGMR3QueryType(PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)
638{
639 PCFGMLEAF pLeaf;
640 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
641 if (RT_SUCCESS(rc))
642 {
643 if (penmType)
644 *penmType = pLeaf->enmType;
645 }
646 return rc;
647}
648
649
650/**
651 * Query value size.
652 * This works on all types of values.
653 *
654 * @returns VBox status code.
655 * @param pNode Which node to search for pszName in.
656 * @param pszName Name of an integer value.
657 * @param pcb Where to store the value size.
658 */
659VMMR3DECL(int) CFGMR3QuerySize(PCFGMNODE pNode, const char *pszName, size_t *pcb)
660{
661 PCFGMLEAF pLeaf;
662 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
663 if (RT_SUCCESS(rc))
664 {
665 switch (pLeaf->enmType)
666 {
667 case CFGMVALUETYPE_INTEGER:
668 *pcb = sizeof(pLeaf->Value.Integer.u64);
669 break;
670
671 case CFGMVALUETYPE_STRING:
672 *pcb = pLeaf->Value.String.cb;
673 break;
674
675 case CFGMVALUETYPE_BYTES:
676 *pcb = pLeaf->Value.Bytes.cb;
677 break;
678
679 default:
680 rc = VERR_CFGM_IPE_1;
681 AssertMsgFailed(("Invalid value type %d\n", pLeaf->enmType));
682 break;
683 }
684 }
685 return rc;
686}
687
688
689/**
690 * Query integer value.
691 *
692 * @returns VBox status code.
693 * @param pNode Which node to search for pszName in.
694 * @param pszName Name of an integer value.
695 * @param pu64 Where to store the integer value.
696 */
697VMMR3DECL(int) CFGMR3QueryInteger(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
698{
699 PCFGMLEAF pLeaf;
700 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
701 if (RT_SUCCESS(rc))
702 {
703 if (pLeaf->enmType == CFGMVALUETYPE_INTEGER)
704 *pu64 = pLeaf->Value.Integer.u64;
705 else
706 rc = VERR_CFGM_NOT_INTEGER;
707 }
708 return rc;
709}
710
711
712/**
713 * Query integer value with default.
714 *
715 * @returns VBox status code.
716 * @param pNode Which node to search for pszName in.
717 * @param pszName Name of an integer value.
718 * @param pu64 Where to store the integer value. This is set to the default on failure.
719 * @param u64Def The default value. This is always set.
720 */
721VMMR3DECL(int) CFGMR3QueryIntegerDef(PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)
722{
723 PCFGMLEAF pLeaf;
724 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
725 if (RT_SUCCESS(rc))
726 {
727 if (pLeaf->enmType == CFGMVALUETYPE_INTEGER)
728 *pu64 = pLeaf->Value.Integer.u64;
729 else
730 rc = VERR_CFGM_NOT_INTEGER;
731 }
732
733 if (RT_FAILURE(rc))
734 {
735 *pu64 = u64Def;
736 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
737 rc = VINF_SUCCESS;
738 }
739
740 return rc;
741}
742
743
744/**
745 * Query zero terminated character value.
746 *
747 * @returns VBox status code.
748 * @param pNode Which node to search for pszName in.
749 * @param pszName Name of a zero terminate character value.
750 * @param pszString Where to store the string.
751 * @param cchString Size of the string buffer. (Includes terminator.)
752 */
753VMMR3DECL(int) CFGMR3QueryString(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)
754{
755 PCFGMLEAF pLeaf;
756 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
757 if (RT_SUCCESS(rc))
758 {
759 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
760 {
761 size_t cbSrc = pLeaf->Value.String.cb;
762 if (cchString >= cbSrc)
763 {
764 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
765 memset(pszString + cbSrc, 0, cchString - cbSrc);
766 }
767 else
768 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
769 }
770 else
771 rc = VERR_CFGM_NOT_STRING;
772 }
773 return rc;
774}
775
776
777/**
778 * Query zero terminated character value with default.
779 *
780 * @returns VBox status code.
781 * @param pNode Which node to search for pszName in.
782 * @param pszName Name of a zero terminate character value.
783 * @param pszString Where to store the string. This will not be set on overflow error.
784 * @param cchString Size of the string buffer. (Includes terminator.)
785 * @param pszDef The default value.
786 */
787VMMR3DECL(int) CFGMR3QueryStringDef(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)
788{
789 PCFGMLEAF pLeaf;
790 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
791 if (RT_SUCCESS(rc))
792 {
793 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
794 {
795 size_t cbSrc = pLeaf->Value.String.cb;
796 if (cchString >= cbSrc)
797 {
798 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
799 memset(pszString + cbSrc, 0, cchString - cbSrc);
800 }
801 else
802 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
803 }
804 else
805 rc = VERR_CFGM_NOT_STRING;
806 }
807
808 if (RT_FAILURE(rc) && rc != VERR_CFGM_NOT_ENOUGH_SPACE)
809 {
810 size_t cchDef = strlen(pszDef);
811 if (cchString > cchDef)
812 {
813 memcpy(pszString, pszDef, cchDef);
814 memset(pszString + cchDef, 0, cchString - cchDef);
815 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
816 rc = VINF_SUCCESS;
817 }
818 else if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
819 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
820 }
821
822 return rc;
823}
824
825
826/**
827 * Query byte string value.
828 *
829 * @returns VBox status code.
830 * @param pNode Which node to search for pszName in.
831 * @param pszName Name of a byte string value.
832 * @param pvData Where to store the binary data.
833 * @param cbData Size of buffer pvData points too.
834 */
835VMMR3DECL(int) CFGMR3QueryBytes(PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)
836{
837 PCFGMLEAF pLeaf;
838 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
839 if (RT_SUCCESS(rc))
840 {
841 if (pLeaf->enmType == CFGMVALUETYPE_BYTES)
842 {
843 if (cbData >= pLeaf->Value.Bytes.cb)
844 {
845 memcpy(pvData, pLeaf->Value.Bytes.pau8, pLeaf->Value.Bytes.cb);
846 memset((char *)pvData + pLeaf->Value.Bytes.cb, 0, cbData - pLeaf->Value.Bytes.cb);
847 }
848 else
849 rc = VERR_CFGM_NOT_ENOUGH_SPACE;
850 }
851 else
852 rc = VERR_CFGM_NOT_BYTES;
853 }
854 return rc;
855}
856
857
858/**
859 * Validate one level of a configuration node.
860 *
861 * This replaces the CFGMR3AreChildrenValid and CFGMR3AreValuesValid APIs.
862 *
863 * @returns VBox status code.
864 *
865 * When an error is returned, both VMSetError and AssertLogRelMsgFailed
866 * have been called. So, all the caller needs to do is to propagate
867 * the error status up to PDM.
868 *
869 * @param pNode The node to validate.
870 * @param pszNode The node path, always ends with a slash. Use
871 * "/" for the root config node.
872 * @param pszValidValues Patterns describing the valid value names. See
873 * RTStrSimplePatternMultiMatch for details on the
874 * pattern syntax.
875 * @param pszValidNodes Patterns describing the valid node (key) names.
876 * See RTStrSimplePatternMultiMatch for details on
877 * the pattern syntax.
878 * @param pszWho Who is calling.
879 * @param uInstance The instance number of the caller.
880 */
881VMMR3DECL(int) CFGMR3ValidateConfig(PCFGMNODE pNode, const char *pszNode,
882 const char *pszValidValues, const char *pszValidNodes,
883 const char *pszWho, uint32_t uInstance)
884{
885 /* Input validation. */
886 AssertPtrNullReturn(pNode, VERR_INVALID_POINTER);
887 AssertPtrReturn(pszNode, VERR_INVALID_POINTER);
888 Assert(*pszNode && pszNode[strlen(pszNode) - 1] == '/');
889 AssertPtrReturn(pszValidValues, VERR_INVALID_POINTER);
890 AssertPtrReturn(pszValidNodes, VERR_INVALID_POINTER);
891 AssertPtrReturn(pszWho, VERR_INVALID_POINTER);
892
893 if (pNode)
894 {
895 /*
896 * Enumerate the leaves and check them against pszValidValues.
897 */
898 for (PCFGMLEAF pLeaf = pNode->pFirstLeaf; pLeaf; pLeaf = pLeaf->pNext)
899 {
900 if (!RTStrSimplePatternMultiMatch(pszValidValues, RTSTR_MAX,
901 pLeaf->szName, pLeaf->cchName,
902 NULL))
903 {
904 AssertLogRelMsgFailed(("%s/%u: Value '%s%s' didn't match '%s'\n",
905 pszWho, uInstance, pszNode, pLeaf->szName, pszValidValues));
906 return VMSetError(pNode->pVM, VERR_CFGM_CONFIG_UNKNOWN_VALUE, RT_SRC_POS,
907 N_("Unknown configuration value '%s%s' found in the configuration of %s instance #%u"),
908 pszNode, pLeaf->szName, pszWho, uInstance);
909 }
910
911 }
912
913 /*
914 * Enumerate the child nodes and check them against pszValidNodes.
915 */
916 for (PCFGMNODE pChild = pNode->pFirstChild; pChild; pChild = pChild->pNext)
917 {
918 if (!RTStrSimplePatternMultiMatch(pszValidNodes, RTSTR_MAX,
919 pChild->szName, pChild->cchName,
920 NULL))
921 {
922 AssertLogRelMsgFailed(("%s/%u: Node '%s%s' didn't match '%s'\n",
923 pszWho, uInstance, pszNode, pChild->szName, pszValidNodes));
924 return VMSetError(pNode->pVM, VERR_CFGM_CONFIG_UNKNOWN_NODE, RT_SRC_POS,
925 N_("Unknown configuration node '%s%s' found in the configuration of %s instance #%u"),
926 pszNode, pChild->szName, pszWho, uInstance);
927 }
928 }
929 }
930
931 /* All is well. */
932 return VINF_SUCCESS;
933}
934
935
936
937/**
938 * Populates the CFGM tree with the default configuration.
939 *
940 * This assumes an empty tree and is intended for testcases and such that only
941 * need to do very small adjustments to the config.
942 *
943 * @returns VBox status code.
944 * @param pVM Pointer to the VM.
945 * @internal
946 */
947VMMR3DECL(int) CFGMR3ConstructDefaultTree(PVM pVM)
948{
949 int rc;
950 int rcAll = VINF_SUCCESS;
951#define UPDATERC() do { if (RT_FAILURE(rc) && RT_SUCCESS(rcAll)) rcAll = rc; } while (0)
952
953 PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
954 AssertReturn(pRoot, VERR_WRONG_ORDER);
955
956 /*
957 * Create VM default values.
958 */
959 rc = CFGMR3InsertString(pRoot, "Name", "Default VM");
960 UPDATERC();
961 rc = CFGMR3InsertInteger(pRoot, "RamSize", 128U * _1M);
962 UPDATERC();
963 rc = CFGMR3InsertInteger(pRoot, "RamHoleSize", 512U * _1M);
964 UPDATERC();
965 rc = CFGMR3InsertInteger(pRoot, "TimerMillies", 10);
966 UPDATERC();
967 rc = CFGMR3InsertInteger(pRoot, "RawR3Enabled", 1);
968 UPDATERC();
969 /** @todo CFGM Defaults: RawR0, PATMEnabled and CASMEnabled needs attention later. */
970 rc = CFGMR3InsertInteger(pRoot, "RawR0Enabled", 1);
971 UPDATERC();
972 rc = CFGMR3InsertInteger(pRoot, "PATMEnabled", 1);
973 UPDATERC();
974 rc = CFGMR3InsertInteger(pRoot, "CSAMEnabled", 1);
975 UPDATERC();
976
977 /*
978 * PDM.
979 */
980 PCFGMNODE pPdm;
981 rc = CFGMR3InsertNode(pRoot, "PDM", &pPdm);
982 UPDATERC();
983 PCFGMNODE pDevices = NULL;
984 rc = CFGMR3InsertNode(pPdm, "Devices", &pDevices);
985 UPDATERC();
986 rc = CFGMR3InsertInteger(pDevices, "LoadBuiltin", 1); /* boolean */
987 UPDATERC();
988 PCFGMNODE pDrivers = NULL;
989 rc = CFGMR3InsertNode(pPdm, "Drivers", &pDrivers);
990 UPDATERC();
991 rc = CFGMR3InsertInteger(pDrivers, "LoadBuiltin", 1); /* boolean */
992 UPDATERC();
993
994
995 /*
996 * Devices
997 */
998 pDevices = NULL;
999 rc = CFGMR3InsertNode(pRoot, "Devices", &pDevices);
1000 UPDATERC();
1001 /* device */
1002 PCFGMNODE pDev = NULL;
1003 PCFGMNODE pInst = NULL;
1004 PCFGMNODE pCfg = NULL;
1005#if 0
1006 PCFGMNODE pLunL0 = NULL;
1007 PCFGMNODE pLunL1 = NULL;
1008#endif
1009
1010 /*
1011 * PC Arch.
1012 */
1013 rc = CFGMR3InsertNode(pDevices, "pcarch", &pDev);
1014 UPDATERC();
1015 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1016 UPDATERC();
1017 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1018 UPDATERC();
1019 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1020 UPDATERC();
1021
1022 /*
1023 * PC Bios.
1024 */
1025 rc = CFGMR3InsertNode(pDevices, "pcbios", &pDev);
1026 UPDATERC();
1027 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1028 UPDATERC();
1029 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1030 UPDATERC();
1031 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1032 UPDATERC();
1033 rc = CFGMR3InsertInteger(pCfg, "RamSize", 128U * _1M);
1034 UPDATERC();
1035 rc = CFGMR3InsertInteger(pCfg, "RamHoleSize", 512U * _1M);
1036 UPDATERC();
1037 rc = CFGMR3InsertString(pCfg, "BootDevice0", "IDE");
1038 UPDATERC();
1039 rc = CFGMR3InsertString(pCfg, "BootDevice1", "NONE");
1040 UPDATERC();
1041 rc = CFGMR3InsertString(pCfg, "BootDevice2", "NONE");
1042 UPDATERC();
1043 rc = CFGMR3InsertString(pCfg, "BootDevice3", "NONE");
1044 UPDATERC();
1045 rc = CFGMR3InsertString(pCfg, "HardDiskDevice", "piix3ide");
1046 UPDATERC();
1047 rc = CFGMR3InsertString(pCfg, "FloppyDevice", "");
1048 UPDATERC();
1049 RTUUID Uuid;
1050 RTUuidClear(&Uuid);
1051 rc = CFGMR3InsertBytes(pCfg, "UUID", &Uuid, sizeof(Uuid));
1052 UPDATERC();
1053
1054 /*
1055 * PCI bus.
1056 */
1057 rc = CFGMR3InsertNode(pDevices, "pci", &pDev); /* piix3 */
1058 UPDATERC();
1059 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1060 UPDATERC();
1061 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1062 UPDATERC();
1063 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1064 UPDATERC();
1065
1066 /*
1067 * PS/2 keyboard & mouse
1068 */
1069 rc = CFGMR3InsertNode(pDevices, "pckbd", &pDev);
1070 UPDATERC();
1071 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1072 UPDATERC();
1073 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1074 UPDATERC();
1075#if 0
1076 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
1077 UPDATERC();
1078 rc = CFGMR3InsertString(pLunL0, "Driver", "KeyboardQueue");
1079 UPDATERC();
1080 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
1081 UPDATERC();
1082 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 64);
1083 UPDATERC();
1084 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
1085 UPDATERC();
1086 rc = CFGMR3InsertString(pLunL1, "Driver", "MainKeyboard");
1087 UPDATERC();
1088 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
1089 UPDATERC();
1090#endif
1091#if 0
1092 rc = CFGMR3InsertNode(pInst, "LUN#1", &pLunL0);
1093 UPDATERC();
1094 rc = CFGMR3InsertString(pLunL0, "Driver", "MouseQueue");
1095 UPDATERC();
1096 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg);
1097 UPDATERC();
1098 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 128);
1099 UPDATERC();
1100 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1);
1101 UPDATERC();
1102 rc = CFGMR3InsertString(pLunL1, "Driver", "MainMouse");
1103 UPDATERC();
1104 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg);
1105 UPDATERC();
1106#endif
1107
1108 /*
1109 * i8254 Programmable Interval Timer And Dummy Speaker
1110 */
1111 rc = CFGMR3InsertNode(pDevices, "i8254", &pDev);
1112 UPDATERC();
1113 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1114 UPDATERC();
1115#ifdef DEBUG
1116 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1117 UPDATERC();
1118#endif
1119 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1120 UPDATERC();
1121
1122 /*
1123 * i8259 Programmable Interrupt Controller.
1124 */
1125 rc = CFGMR3InsertNode(pDevices, "i8259", &pDev);
1126 UPDATERC();
1127 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1128 UPDATERC();
1129 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1130 UPDATERC();
1131 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1132 UPDATERC();
1133
1134 /*
1135 * RTC MC146818.
1136 */
1137 rc = CFGMR3InsertNode(pDevices, "mc146818", &pDev);
1138 UPDATERC();
1139 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1140 UPDATERC();
1141 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1142 UPDATERC();
1143
1144 /*
1145 * VGA.
1146 */
1147 rc = CFGMR3InsertNode(pDevices, "vga", &pDev);
1148 UPDATERC();
1149 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1150 UPDATERC();
1151 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1152 UPDATERC();
1153 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1154 UPDATERC();
1155 rc = CFGMR3InsertInteger(pCfg, "VRamSize", 4 * _1M);
1156 UPDATERC();
1157
1158 /* Bios logo. */
1159 rc = CFGMR3InsertInteger(pCfg, "FadeIn", 1);
1160 UPDATERC();
1161 rc = CFGMR3InsertInteger(pCfg, "FadeOut", 1);
1162 UPDATERC();
1163 rc = CFGMR3InsertInteger(pCfg, "LogoTime", 0);
1164 UPDATERC();
1165 rc = CFGMR3InsertString(pCfg, "LogoFile", "");
1166 UPDATERC();
1167
1168#if 0
1169 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0);
1170 UPDATERC();
1171 rc = CFGMR3InsertString(pLunL0, "Driver", "MainDisplay");
1172 UPDATERC();
1173#endif
1174
1175 /*
1176 * IDE controller.
1177 */
1178 rc = CFGMR3InsertNode(pDevices, "piix3ide", &pDev); /* piix3 */
1179 UPDATERC();
1180 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1181 UPDATERC();
1182 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1183 UPDATERC();
1184 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1185 UPDATERC();
1186
1187 /*
1188 * VMMDev.
1189 */
1190 rc = CFGMR3InsertNode(pDevices, "VMMDev", &pDev);
1191 UPDATERC();
1192 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1193 UPDATERC();
1194 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1195 UPDATERC();
1196 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1197 UPDATERC();
1198 rc = CFGMR3InsertInteger(pCfg, "RamSize", 128U * _1M);
1199 UPDATERC();
1200
1201
1202 /*
1203 * ...
1204 */
1205
1206#undef UPDATERC
1207 return rcAll;
1208}
1209
1210
1211
1212
1213/**
1214 * Resolves a path reference to a child node.
1215 *
1216 * @returns VBox status code.
1217 * @param pNode Which node to search for pszName in.
1218 * @param pszPath Path to the child node.
1219 * @param ppChild Where to store the pointer to the child node.
1220 */
1221static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild)
1222{
1223 *ppChild = NULL;
1224 if (!pNode)
1225 return VERR_CFGM_NO_PARENT;
1226 PCFGMNODE pChild = NULL;
1227 for (;;)
1228 {
1229 /* skip leading slashes. */
1230 while (*pszPath == '/')
1231 pszPath++;
1232
1233 /* End of path? */
1234 if (!*pszPath)
1235 {
1236 if (!pChild)
1237 return VERR_CFGM_INVALID_CHILD_PATH;
1238 *ppChild = pChild;
1239 return VINF_SUCCESS;
1240 }
1241
1242 /* find end of component. */
1243 const char *pszNext = strchr(pszPath, '/');
1244 if (!pszNext)
1245 pszNext = strchr(pszPath, '\0');
1246 RTUINT cchName = pszNext - pszPath;
1247
1248 /* search child list. */
1249 pChild = pNode->pFirstChild;
1250 for ( ; pChild; pChild = pChild->pNext)
1251 if (pChild->cchName == cchName)
1252 {
1253 int iDiff = memcmp(pszPath, pChild->szName, cchName);
1254 if (iDiff <= 0)
1255 {
1256 if (iDiff != 0)
1257 pChild = NULL;
1258 break;
1259 }
1260 }
1261 if (!pChild)
1262 return VERR_CFGM_CHILD_NOT_FOUND;
1263
1264 /* next iteration */
1265 pNode = pChild;
1266 pszPath = pszNext;
1267 }
1268
1269 /* won't get here */
1270}
1271
1272
1273/**
1274 * Resolves a path reference to a child node.
1275 *
1276 * @returns VBox status code.
1277 * @param pNode Which node to search for pszName in.
1278 * @param pszName Name of a byte string value.
1279 * @param ppLeaf Where to store the pointer to the leaf node.
1280 */
1281static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1282{
1283 *ppLeaf = NULL;
1284 if (!pNode)
1285 return VERR_CFGM_NO_PARENT;
1286
1287 size_t cchName = strlen(pszName);
1288 PCFGMLEAF pLeaf = pNode->pFirstLeaf;
1289 while (pLeaf)
1290 {
1291 if (cchName == pLeaf->cchName)
1292 {
1293 int iDiff = memcmp(pszName, pLeaf->szName, cchName);
1294 if (iDiff <= 0)
1295 {
1296 if (iDiff != 0)
1297 break;
1298 *ppLeaf = pLeaf;
1299 return VINF_SUCCESS;
1300 }
1301 }
1302
1303 /* next */
1304 pLeaf = pLeaf->pNext;
1305 }
1306 return VERR_CFGM_VALUE_NOT_FOUND;
1307}
1308
1309
1310
1311/**
1312 * Creates a CFGM tree.
1313 *
1314 * This is intended for creating device/driver configs can be
1315 * passed around and later attached to the main tree in the
1316 * correct location.
1317 *
1318 * @returns Pointer to the root node, NULL on error (out of memory or invalid
1319 * VM handle).
1320 * @param pUVM The user mode VM handle. For testcase (and other
1321 * purposes, NULL can be used. However, the resulting
1322 * tree cannot be inserted into a tree that has a
1323 * non-NULL value. Using NULL can be usedful for
1324 * testcases and similar, non VMM uses.
1325 */
1326VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PUVM pUVM)
1327{
1328 if (pUVM)
1329 {
1330 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
1331 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
1332 }
1333
1334 PCFGMNODE pNew;
1335 if (pUVM)
1336 pNew = (PCFGMNODE)MMR3HeapAllocU(pUVM, MM_TAG_CFGM, sizeof(*pNew));
1337 else
1338 pNew = (PCFGMNODE)RTMemAlloc(sizeof(*pNew));
1339 if (pNew)
1340 {
1341 pNew->pPrev = NULL;
1342 pNew->pNext = NULL;
1343 pNew->pParent = NULL;
1344 pNew->pFirstChild = NULL;
1345 pNew->pFirstLeaf = NULL;
1346 pNew->pVM = pUVM ? pUVM->pVM : NULL;
1347 pNew->fRestrictedRoot = false;
1348 pNew->cchName = 0;
1349 pNew->szName[0] = 0;
1350 }
1351 return pNew;
1352}
1353
1354
1355/**
1356 * Duplicates a CFGM sub-tree or a full tree.
1357 *
1358 * @returns Pointer to the root node. NULL if we run out of memory or the
1359 * input parameter is NULL.
1360 * @param pRoot The root of the tree to duplicate.
1361 * @param ppCopy Where to return the root of the duplicate.
1362 */
1363VMMR3DECL(int) CFGMR3DuplicateSubTree(PCFGMNODE pRoot, PCFGMNODE *ppCopy)
1364{
1365 AssertPtrReturn(pRoot, VERR_INVALID_POINTER);
1366
1367 /*
1368 * Create a new tree.
1369 */
1370 PCFGMNODE pNewRoot = CFGMR3CreateTree(pRoot->pVM ? pRoot->pVM->pUVM : NULL);
1371 if (!pNewRoot)
1372 return VERR_NO_MEMORY;
1373
1374 /*
1375 * Duplicate the content.
1376 */
1377 int rc = VINF_SUCCESS;
1378 PCFGMNODE pSrcCur = pRoot;
1379 PCFGMNODE pDstCur = pNewRoot;
1380 for (;;)
1381 {
1382 if ( !pDstCur->pFirstChild
1383 && !pDstCur->pFirstLeaf)
1384 {
1385 /*
1386 * Values first.
1387 */
1388 /** @todo this isn't the most efficient way to do it. */
1389 for (PCFGMLEAF pLeaf = pSrcCur->pFirstLeaf; pLeaf && RT_SUCCESS(rc); pLeaf = pLeaf->pNext)
1390 rc = CFGMR3InsertValue(pDstCur, pLeaf);
1391
1392 /*
1393 * Insert immediate child nodes.
1394 */
1395 /** @todo this isn't the most efficient way to do it. */
1396 for (PCFGMNODE pChild = pSrcCur->pFirstChild; pChild && RT_SUCCESS(rc); pChild = pChild->pNext)
1397 rc = CFGMR3InsertNode(pDstCur, pChild->szName, NULL);
1398
1399 AssertLogRelRCBreak(rc);
1400 }
1401
1402 /*
1403 * Deep copy of the children.
1404 */
1405 if (pSrcCur->pFirstChild)
1406 {
1407 Assert(pDstCur->pFirstChild && !strcmp(pDstCur->pFirstChild->szName, pSrcCur->pFirstChild->szName));
1408 pSrcCur = pSrcCur->pFirstChild;
1409 pDstCur = pDstCur->pFirstChild;
1410 }
1411 /*
1412 * If it's the root node, we're done.
1413 */
1414 else if (pSrcCur == pRoot)
1415 break;
1416 else
1417 {
1418 /*
1419 * Upon reaching the end of a sibling list, we must ascend and
1420 * resume the sibiling walk on an previous level.
1421 */
1422 if (!pSrcCur->pNext)
1423 {
1424 do
1425 {
1426 pSrcCur = pSrcCur->pParent;
1427 pDstCur = pDstCur->pParent;
1428 } while (!pSrcCur->pNext && pSrcCur != pRoot);
1429 if (pSrcCur == pRoot)
1430 break;
1431 }
1432
1433 /*
1434 * Next sibling.
1435 */
1436 Assert(pDstCur->pNext && !strcmp(pDstCur->pNext->szName, pSrcCur->pNext->szName));
1437 pSrcCur = pSrcCur->pNext;
1438 pDstCur = pDstCur->pNext;
1439 }
1440 }
1441
1442 if (RT_FAILURE(rc))
1443 {
1444 CFGMR3RemoveNode(pNewRoot);
1445 return rc;
1446 }
1447
1448 *ppCopy = pNewRoot;
1449 return VINF_SUCCESS;
1450}
1451
1452
1453/**
1454 * Insert subtree.
1455 *
1456 * This function inserts (no duplication) a tree created by CFGMR3CreateTree()
1457 * into the main tree.
1458 *
1459 * The root node of the inserted subtree will need to be reallocated, which
1460 * effectually means that the passed in pSubTree handle becomes invalid
1461 * upon successful return. Use the value returned in ppChild instead
1462 * of pSubTree.
1463 *
1464 * @returns VBox status code.
1465 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1466 * @param pNode Parent node.
1467 * @param pszName Name or path of the new child node.
1468 * @param pSubTree The subtree to insert. Must be returned by CFGMR3CreateTree().
1469 * @param ppChild Where to store the address of the new child node. (optional)
1470 */
1471VMMR3DECL(int) CFGMR3InsertSubTree(PCFGMNODE pNode, const char *pszName, PCFGMNODE pSubTree, PCFGMNODE *ppChild)
1472{
1473 /*
1474 * Validate input.
1475 */
1476 AssertPtrReturn(pNode, VERR_INVALID_POINTER);
1477 AssertPtrReturn(pSubTree, VERR_INVALID_POINTER);
1478 AssertReturn(pNode != pSubTree, VERR_INVALID_PARAMETER);
1479 AssertReturn(!pSubTree->pParent, VERR_INVALID_PARAMETER);
1480 AssertReturn(pNode->pVM == pSubTree->pVM, VERR_INVALID_PARAMETER);
1481 Assert(!pSubTree->pNext);
1482 Assert(!pSubTree->pPrev);
1483
1484 /*
1485 * Use CFGMR3InsertNode to create a new node and then
1486 * re-attach the children and leaves of the subtree to it.
1487 */
1488 PCFGMNODE pNewChild;
1489 int rc = CFGMR3InsertNode(pNode, pszName, &pNewChild);
1490 if (RT_SUCCESS(rc))
1491 {
1492 Assert(!pNewChild->pFirstChild);
1493 Assert(!pNewChild->pFirstLeaf);
1494
1495 pNewChild->pFirstChild = pSubTree->pFirstChild;
1496 pNewChild->pFirstLeaf = pSubTree->pFirstLeaf;
1497 for (PCFGMNODE pChild = pNewChild->pFirstChild; pChild; pChild = pChild->pNext)
1498 pChild->pParent = pNewChild;
1499
1500 if (ppChild)
1501 *ppChild = pNewChild;
1502
1503 /* free the old subtree root */
1504 cfgmR3FreeNodeOnly(pSubTree);
1505 }
1506 return rc;
1507}
1508
1509
1510/**
1511 * Replaces a (sub-)tree with new one.
1512 *
1513 * This function removes the exiting (sub-)tree, completely freeing it in the
1514 * process, and inserts (no duplication) the specified tree. The tree can
1515 * either be created by CFGMR3CreateTree or CFGMR3DuplicateSubTree.
1516 *
1517 * @returns VBox status code.
1518 * @param pRoot The sub-tree to replace. This node will remain valid
1519 * after the call.
1520 * @param pNewRoot The tree to replace @a pRoot with. This not will
1521 * become invalid after a successful call.
1522 */
1523VMMR3DECL(int) CFGMR3ReplaceSubTree(PCFGMNODE pRoot, PCFGMNODE pNewRoot)
1524{
1525 /*
1526 * Validate input.
1527 */
1528 AssertPtrReturn(pRoot, VERR_INVALID_POINTER);
1529 AssertPtrReturn(pNewRoot, VERR_INVALID_POINTER);
1530 AssertReturn(pRoot != pNewRoot, VERR_INVALID_PARAMETER);
1531 AssertReturn(!pNewRoot->pParent, VERR_INVALID_PARAMETER);
1532 AssertReturn(pNewRoot->pVM == pRoot->pVM, VERR_INVALID_PARAMETER);
1533 AssertReturn(!pNewRoot->pNext, VERR_INVALID_PARAMETER);
1534 AssertReturn(!pNewRoot->pPrev, VERR_INVALID_PARAMETER);
1535
1536 /*
1537 * Free the current properties fo pRoot.
1538 */
1539 while (pRoot->pFirstChild)
1540 CFGMR3RemoveNode(pRoot->pFirstChild);
1541
1542 while (pRoot->pFirstLeaf)
1543 cfgmR3RemoveLeaf(pRoot, pRoot->pFirstLeaf);
1544
1545 /*
1546 * Copy all the properties from the new root to the current one.
1547 */
1548 pRoot->pFirstLeaf = pNewRoot->pFirstLeaf;
1549 pRoot->pFirstChild = pNewRoot->pFirstChild;
1550 for (PCFGMNODE pChild = pRoot->pFirstChild; pChild; pChild = pChild->pNext)
1551 pChild->pParent = pRoot;
1552
1553 cfgmR3FreeNodeOnly(pNewRoot);
1554
1555 return VINF_SUCCESS;
1556}
1557
1558
1559/**
1560 * Copies all values and keys from one tree onto another.
1561 *
1562 * The flags control what happens to keys and values with the same name
1563 * existing in both source and destination.
1564 *
1565 * @returns VBox status code.
1566 * @param pDstTree The destination tree.
1567 * @param pSrcTree The source tree.
1568 * @param fFlags Copy flags, see CFGM_COPY_FLAGS_XXX.
1569 */
1570VMMR3DECL(int) CFGMR3CopyTree(PCFGMNODE pDstTree, PCFGMNODE pSrcTree, uint32_t fFlags)
1571{
1572 /*
1573 * Input validation.
1574 */
1575 AssertPtrReturn(pSrcTree, VERR_INVALID_POINTER);
1576 AssertPtrReturn(pDstTree, VERR_INVALID_POINTER);
1577 AssertReturn(pDstTree != pSrcTree, VERR_INVALID_PARAMETER);
1578 AssertReturn(!(fFlags & ~(CFGM_COPY_FLAGS_VALUE_DISP_MASK | CFGM_COPY_FLAGS_KEY_DISP_MASK)), VERR_INVALID_PARAMETER);
1579 AssertReturn( (fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_0
1580 && (fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_1,
1581 VERR_INVALID_PARAMETER);
1582 AssertReturn((fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_KEY_DISP,
1583 VERR_INVALID_PARAMETER);
1584
1585 /*
1586 * Copy the values.
1587 */
1588 int rc;
1589 for (PCFGMLEAF pValue = CFGMR3GetFirstValue(pSrcTree); pValue; pValue = CFGMR3GetNextValue(pValue))
1590 {
1591 rc = CFGMR3InsertValue(pDstTree, pValue);
1592 if (rc == VERR_CFGM_LEAF_EXISTS)
1593 {
1594 if ((fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) == CFGM_COPY_FLAGS_REPLACE_VALUES)
1595 {
1596 rc = CFGMR3RemoveValue(pDstTree, pValue->szName);
1597 if (RT_FAILURE(rc))
1598 break;
1599 rc = CFGMR3InsertValue(pDstTree, pValue);
1600 }
1601 else
1602 rc = VINF_SUCCESS;
1603 }
1604 AssertRCReturn(rc, rc);
1605 }
1606
1607 /*
1608 * Copy/merge the keys - merging results in recursion.
1609 */
1610 for (PCFGMNODE pSrcChild = CFGMR3GetFirstChild(pSrcTree); pSrcChild; pSrcChild = CFGMR3GetNextChild(pSrcChild))
1611 {
1612 PCFGMNODE pDstChild = CFGMR3GetChild(pDstTree, pSrcChild->szName);
1613 if ( pDstChild
1614 && (fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) == CFGM_COPY_FLAGS_REPLACE_KEYS)
1615 {
1616 CFGMR3RemoveNode(pDstChild);
1617 pDstChild = NULL;
1618 }
1619 if (!pDstChild)
1620 {
1621 PCFGMNODE pChildCopy;
1622 rc = CFGMR3DuplicateSubTree(pSrcChild, &pChildCopy);
1623 AssertRCReturn(rc, rc);
1624 rc = CFGMR3InsertSubTree(pDstTree, pSrcChild->szName, pChildCopy, NULL);
1625 AssertRCReturnStmt(rc, CFGMR3RemoveNode(pChildCopy), rc);
1626 }
1627 else if ((fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) == CFGM_COPY_FLAGS_MERGE_KEYS)
1628 {
1629 rc = CFGMR3CopyTree(pDstChild, pSrcChild, fFlags);
1630 AssertRCReturn(rc, rc);
1631 }
1632 }
1633
1634 return VINF_SUCCESS;
1635}
1636
1637
1638
1639/**
1640 * Compares two names.
1641 *
1642 * @returns Similar to memcpy.
1643 * @param pszName1 The first name.
1644 * @param cchName1 The length of the first name.
1645 * @param pszName2 The second name.
1646 * @param cchName2 The length of the second name.
1647 */
1648DECLINLINE(int) cfgmR3CompareNames(const char *pszName1, size_t cchName1, const char *pszName2, size_t cchName2)
1649{
1650 int iDiff;
1651 if (cchName1 <= cchName2)
1652 {
1653 iDiff = memcmp(pszName1, pszName2, cchName1);
1654 if (!iDiff && cchName1 < cchName2)
1655 iDiff = -1;
1656 }
1657 else
1658 {
1659 iDiff = memcmp(pszName1, pszName2, cchName2);
1660 if (!iDiff)
1661 iDiff = 1;
1662 }
1663 return iDiff;
1664}
1665
1666
1667/**
1668 * Insert a node.
1669 *
1670 * @returns VBox status code.
1671 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1672 * @param pNode Parent node.
1673 * @param pszName Name or path of the new child node.
1674 * @param ppChild Where to store the address of the new child node. (optional)
1675 */
1676VMMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild)
1677{
1678 int rc;
1679 if (pNode)
1680 {
1681 /*
1682 * If given a path we have to deal with it component by component.
1683 */
1684 while (*pszName == '/')
1685 pszName++;
1686 if (strchr(pszName, '/'))
1687 {
1688 char *pszDup = RTStrDup(pszName);
1689 if (pszDup)
1690 {
1691 char *psz = pszDup;
1692 for (;;)
1693 {
1694 /* Terminate at '/' and find the next component. */
1695 char *pszNext = strchr(psz, '/');
1696 if (pszNext)
1697 {
1698 *pszNext++ = '\0';
1699 while (*pszNext == '/')
1700 pszNext++;
1701 if (*pszNext == '\0')
1702 pszNext = NULL;
1703 }
1704
1705 /* does it exist? */
1706 PCFGMNODE pChild = CFGMR3GetChild(pNode, psz);
1707 if (!pChild)
1708 {
1709 /* no, insert it */
1710 rc = CFGMR3InsertNode(pNode, psz, &pChild);
1711 if (RT_FAILURE(rc))
1712 break;
1713 if (!pszNext)
1714 {
1715 if (ppChild)
1716 *ppChild = pChild;
1717 break;
1718 }
1719
1720 }
1721 /* if last component fail */
1722 else if (!pszNext)
1723 {
1724 rc = VERR_CFGM_NODE_EXISTS;
1725 break;
1726 }
1727
1728 /* next */
1729 pNode = pChild;
1730 psz = pszNext;
1731 }
1732 RTStrFree(pszDup);
1733 }
1734 else
1735 rc = VERR_NO_TMP_MEMORY;
1736 }
1737 /*
1738 * Not multicomponent, just make sure it's a non-zero name.
1739 */
1740 else if (*pszName)
1741 {
1742 /*
1743 * Check if already exists and find last node in chain.
1744 */
1745 size_t cchName = strlen(pszName);
1746 PCFGMNODE pPrev = NULL;
1747 PCFGMNODE pNext = pNode->pFirstChild;
1748 if (pNext)
1749 {
1750 for ( ; pNext; pPrev = pNext, pNext = pNext->pNext)
1751 {
1752 int iDiff = cfgmR3CompareNames(pszName, cchName, pNext->szName, pNext->cchName);
1753 if (iDiff <= 0)
1754 {
1755 if (!iDiff)
1756 return VERR_CFGM_NODE_EXISTS;
1757 break;
1758 }
1759 }
1760 }
1761
1762 /*
1763 * Allocate and init node.
1764 */
1765 PCFGMNODE pNew = (PCFGMNODE)cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1766 if (pNew)
1767 {
1768 pNew->pParent = pNode;
1769 pNew->pFirstChild = NULL;
1770 pNew->pFirstLeaf = NULL;
1771 pNew->pVM = pNode->pVM;
1772 pNew->fRestrictedRoot = false;
1773 pNew->cchName = cchName;
1774 memcpy(pNew->szName, pszName, cchName + 1);
1775
1776 /*
1777 * Insert into child list.
1778 */
1779 pNew->pPrev = pPrev;
1780 if (pPrev)
1781 pPrev->pNext = pNew;
1782 else
1783 pNode->pFirstChild = pNew;
1784 pNew->pNext = pNext;
1785 if (pNext)
1786 pNext->pPrev = pNew;
1787
1788 if (ppChild)
1789 *ppChild = pNew;
1790 rc = VINF_SUCCESS;
1791 }
1792 else
1793 rc = VERR_NO_MEMORY;
1794 }
1795 else
1796 {
1797 rc = VERR_CFGM_INVALID_NODE_PATH;
1798 AssertMsgFailed(("Invalid path %s\n", pszName));
1799 }
1800 }
1801 else
1802 {
1803 rc = VERR_CFGM_NO_PARENT;
1804 AssertMsgFailed(("No parent! path %s\n", pszName));
1805 }
1806
1807 return rc;
1808}
1809
1810
1811/**
1812 * Insert a node, format string name.
1813 *
1814 * @returns VBox status code.
1815 * @param pNode Parent node.
1816 * @param ppChild Where to store the address of the new child node. (optional)
1817 * @param pszNameFormat Name of or path the new child node.
1818 * @param ... Name format arguments.
1819 */
1820VMMR3DECL(int) CFGMR3InsertNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...)
1821{
1822 va_list Args;
1823 va_start(Args, pszNameFormat);
1824 int rc = CFGMR3InsertNodeFV(pNode, ppChild, pszNameFormat, Args);
1825 va_end(Args);
1826 return rc;
1827}
1828
1829
1830/**
1831 * Insert a node, format string name.
1832 *
1833 * @returns VBox status code.
1834 * @param pNode Parent node.
1835 * @param ppChild Where to store the address of the new child node. (optional)
1836 * @param pszNameFormat Name or path of the new child node.
1837 * @param Args Name format arguments.
1838 */
1839VMMR3DECL(int) CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, va_list Args)
1840{
1841 int rc;
1842 char *pszName;
1843 RTStrAPrintfV(&pszName, pszNameFormat, Args);
1844 if (pszName)
1845 {
1846 rc = CFGMR3InsertNode(pNode, pszName, ppChild);
1847 RTStrFree(pszName);
1848 }
1849 else
1850 rc = VERR_NO_MEMORY;
1851 return rc;
1852}
1853
1854
1855/**
1856 * Marks the node as the root of a restricted subtree, i.e. the end of
1857 * a CFGMR3GetParent() journey.
1858 *
1859 * @param pNode The node to mark.
1860 */
1861VMMR3DECL(void) CFGMR3SetRestrictedRoot(PCFGMNODE pNode)
1862{
1863 if (pNode)
1864 pNode->fRestrictedRoot = true;
1865}
1866
1867
1868/**
1869 * Insert a node.
1870 *
1871 * @returns VBox status code.
1872 * @param pNode Parent node.
1873 * @param pszName Name of the new child node.
1874 * @param ppLeaf Where to store the new leaf.
1875 * The caller must fill in the enmType and Value fields!
1876 */
1877static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1878{
1879 int rc;
1880 if (*pszName)
1881 {
1882 if (pNode)
1883 {
1884 /*
1885 * Check if already exists and find last node in chain.
1886 */
1887 size_t cchName = strlen(pszName);
1888 PCFGMLEAF pPrev = NULL;
1889 PCFGMLEAF pNext = pNode->pFirstLeaf;
1890 if (pNext)
1891 {
1892 for ( ; pNext; pPrev = pNext, pNext = pNext->pNext)
1893 {
1894 int iDiff = cfgmR3CompareNames(pszName, cchName, pNext->szName, pNext->cchName);
1895 if (iDiff <= 0)
1896 {
1897 if (!iDiff)
1898 return VERR_CFGM_LEAF_EXISTS;
1899 break;
1900 }
1901 }
1902 }
1903
1904 /*
1905 * Allocate and init node.
1906 */
1907 PCFGMLEAF pNew = (PCFGMLEAF)cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1908 if (pNew)
1909 {
1910 pNew->cchName = cchName;
1911 memcpy(pNew->szName, pszName, cchName + 1);
1912
1913 /*
1914 * Insert into child list.
1915 */
1916 pNew->pPrev = pPrev;
1917 if (pPrev)
1918 pPrev->pNext = pNew;
1919 else
1920 pNode->pFirstLeaf = pNew;
1921 pNew->pNext = pNext;
1922 if (pNext)
1923 pNext->pPrev = pNew;
1924
1925 *ppLeaf = pNew;
1926 rc = VINF_SUCCESS;
1927 }
1928 else
1929 rc = VERR_NO_MEMORY;
1930 }
1931 else
1932 rc = VERR_CFGM_NO_PARENT;
1933 }
1934 else
1935 rc = VERR_CFGM_INVALID_CHILD_PATH;
1936 return rc;
1937}
1938
1939
1940/**
1941 * Removes a node.
1942 *
1943 * @param pNode The node to remove.
1944 */
1945VMMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode)
1946{
1947 if (pNode)
1948 {
1949 /*
1950 * Free children.
1951 */
1952 while (pNode->pFirstChild)
1953 CFGMR3RemoveNode(pNode->pFirstChild);
1954
1955 /*
1956 * Free leaves.
1957 */
1958 while (pNode->pFirstLeaf)
1959 cfgmR3RemoveLeaf(pNode, pNode->pFirstLeaf);
1960
1961 /*
1962 * Unlink ourselves.
1963 */
1964 if (pNode->pPrev)
1965 pNode->pPrev->pNext = pNode->pNext;
1966 else
1967 {
1968 if (pNode->pParent)
1969 pNode->pParent->pFirstChild = pNode->pNext;
1970 else if ( pNode->pVM /* might be a different tree */
1971 && pNode == pNode->pVM->cfgm.s.pRoot)
1972 pNode->pVM->cfgm.s.pRoot = NULL;
1973 }
1974 if (pNode->pNext)
1975 pNode->pNext->pPrev = pNode->pPrev;
1976
1977 /*
1978 * Free ourselves.
1979 */
1980 cfgmR3FreeNodeOnly(pNode);
1981 }
1982}
1983
1984
1985/**
1986 * Removes a leaf.
1987 *
1988 * @param pNode Parent node.
1989 * @param pLeaf Leaf to remove.
1990 */
1991static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf)
1992{
1993 if (pNode && pLeaf)
1994 {
1995 /*
1996 * Unlink.
1997 */
1998 if (pLeaf->pPrev)
1999 pLeaf->pPrev->pNext = pLeaf->pNext;
2000 else
2001 pNode->pFirstLeaf = pLeaf->pNext;
2002 if (pLeaf->pNext)
2003 pLeaf->pNext->pPrev = pLeaf->pPrev;
2004
2005 /*
2006 * Free value and node.
2007 */
2008 cfgmR3FreeValue(pNode->pVM, pLeaf);
2009 pLeaf->pNext = NULL;
2010 pLeaf->pPrev = NULL;
2011 cfgmR3MemFree(pNode->pVM, pLeaf);
2012 }
2013}
2014
2015
2016/**
2017 * Frees whatever resources the leaf value is owning.
2018 *
2019 * Use this before assigning a new value to a leaf.
2020 * The caller must either free the leaf or assign a new value to it.
2021 *
2022 * @param pVM Used to select the heap.
2023 * @param pLeaf Pointer to the leaf which value should be free.
2024 */
2025static void cfgmR3FreeValue(PVM pVM, PCFGMLEAF pLeaf)
2026{
2027 if (pLeaf)
2028 {
2029 switch (pLeaf->enmType)
2030 {
2031 case CFGMVALUETYPE_BYTES:
2032 cfgmR3MemFree(pVM, pLeaf->Value.Bytes.pau8);
2033 pLeaf->Value.Bytes.pau8 = NULL;
2034 pLeaf->Value.Bytes.cb = 0;
2035 break;
2036
2037 case CFGMVALUETYPE_STRING:
2038 cfgmR3StrFree(pVM, pLeaf->Value.String.psz);
2039 pLeaf->Value.String.psz = NULL;
2040 pLeaf->Value.String.cb = 0;
2041 break;
2042
2043 case CFGMVALUETYPE_INTEGER:
2044 break;
2045 }
2046 pLeaf->enmType = (CFGMVALUETYPE)0;
2047 }
2048}
2049
2050/**
2051 * Destroys a tree created with CFGMR3CreateTree or CFGMR3DuplicateSubTree.
2052 *
2053 * @returns VBox status code.
2054 * @param pRoot The root node of the tree.
2055 */
2056VMMR3DECL(int) CFGMR3DestroyTree(PCFGMNODE pRoot)
2057{
2058 if (!pRoot)
2059 return VINF_SUCCESS;
2060 AssertReturn(!pRoot->pParent, VERR_INVALID_PARAMETER);
2061 AssertReturn(!pRoot->pVM || pRoot != pRoot->pVM->cfgm.s.pRoot, VERR_ACCESS_DENIED);
2062
2063 CFGMR3RemoveNode(pRoot);
2064 return VINF_SUCCESS;
2065}
2066
2067
2068/**
2069 * Inserts a new integer value.
2070 *
2071 * @returns VBox status code.
2072 * @param pNode Parent node.
2073 * @param pszName Value name.
2074 * @param u64Integer The value.
2075 */
2076VMMR3DECL(int) CFGMR3InsertInteger(PCFGMNODE pNode, const char *pszName, uint64_t u64Integer)
2077{
2078 PCFGMLEAF pLeaf;
2079 int rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2080 if (RT_SUCCESS(rc))
2081 {
2082 pLeaf->enmType = CFGMVALUETYPE_INTEGER;
2083 pLeaf->Value.Integer.u64 = u64Integer;
2084 }
2085 return rc;
2086}
2087
2088
2089/**
2090 * Inserts a new string value. This variant expects that the caller know the length
2091 * of the string already so we can avoid calling strlen() here.
2092 *
2093 * @returns VBox status code.
2094 * @param pNode Parent node.
2095 * @param pszName Value name.
2096 * @param pszString The value. Must not be NULL.
2097 * @param cchString The length of the string excluding the
2098 * terminator.
2099 */
2100VMMR3DECL(int) CFGMR3InsertStringN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString)
2101{
2102 Assert(RTStrNLen(pszString, cchString) == cchString);
2103
2104 int rc;
2105 if (pNode)
2106 {
2107 /*
2108 * Allocate string object first.
2109 */
2110 char *pszStringCopy = (char *)cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cchString + 1);
2111 if (pszStringCopy)
2112 {
2113 memcpy(pszStringCopy, pszString, cchString);
2114 pszStringCopy[cchString] = '\0';
2115
2116 /*
2117 * Create value leaf and set it to string type.
2118 */
2119 PCFGMLEAF pLeaf;
2120 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2121 if (RT_SUCCESS(rc))
2122 {
2123 pLeaf->enmType = CFGMVALUETYPE_STRING;
2124 pLeaf->Value.String.psz = pszStringCopy;
2125 pLeaf->Value.String.cb = cchString + 1;
2126 }
2127 else
2128 cfgmR3StrFree(pNode->pVM, pszStringCopy);
2129 }
2130 else
2131 rc = VERR_NO_MEMORY;
2132 }
2133 else
2134 rc = VERR_CFGM_NO_PARENT;
2135
2136 return rc;
2137}
2138
2139
2140/**
2141 * Inserts a new string value. Calls strlen(pszString) internally; if you know the
2142 * length of the string, CFGMR3InsertStringLengthKnown() is faster.
2143 *
2144 * @returns VBox status code.
2145 * @param pNode Parent node.
2146 * @param pszName Value name.
2147 * @param pszString The value.
2148 */
2149VMMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString)
2150{
2151 return CFGMR3InsertStringN(pNode, pszName, pszString, strlen(pszString));
2152}
2153
2154
2155/**
2156 * Same as CFGMR3InsertString except the string value given in RTStrPrintfV
2157 * fashion.
2158 *
2159 * @returns VBox status code.
2160 * @param pNode Parent node.
2161 * @param pszName Value name.
2162 * @param pszFormat The value given as a format string.
2163 * @param va Argument to pszFormat.
2164 */
2165VMMR3DECL(int) CFGMR3InsertStringFV(PCFGMNODE pNode, const char *pszName, const char *pszFormat, va_list va)
2166{
2167 int rc;
2168 if (pNode)
2169 {
2170 /*
2171 * Allocate string object first.
2172 */
2173 char *pszString;
2174 if (!pNode->pVM)
2175 pszString = RTStrAPrintf2(pszFormat, va);
2176 else
2177 pszString = MMR3HeapAPrintfVU(pNode->pVM->pUVM, MM_TAG_CFGM_STRING, pszFormat, va);
2178 if (pszString)
2179 {
2180 /*
2181 * Create value leaf and set it to string type.
2182 */
2183 PCFGMLEAF pLeaf;
2184 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2185 if (RT_SUCCESS(rc))
2186 {
2187 pLeaf->enmType = CFGMVALUETYPE_STRING;
2188 pLeaf->Value.String.psz = pszString;
2189 pLeaf->Value.String.cb = strlen(pszString) + 1;
2190 }
2191 else
2192 cfgmR3StrFree(pNode->pVM, pszString);
2193 }
2194 else
2195 rc = VERR_NO_MEMORY;
2196 }
2197 else
2198 rc = VERR_CFGM_NO_PARENT;
2199
2200 return rc;
2201}
2202
2203
2204/**
2205 * Same as CFGMR3InsertString except the string value given in RTStrPrintf
2206 * fashion.
2207 *
2208 * @returns VBox status code.
2209 * @param pNode Parent node.
2210 * @param pszName Value name.
2211 * @param pszFormat The value given as a format string.
2212 * @param ... Argument to pszFormat.
2213 */
2214VMMR3DECL(int) CFGMR3InsertStringF(PCFGMNODE pNode, const char *pszName, const char *pszFormat, ...)
2215{
2216 va_list va;
2217 va_start(va, pszFormat);
2218 int rc = CFGMR3InsertStringFV(pNode, pszName, pszFormat, va);
2219 va_end(va);
2220 return rc;
2221}
2222
2223
2224/**
2225 * Same as CFGMR3InsertString except the string value given as a UTF-16 string.
2226 *
2227 * @returns VBox status code.
2228 * @param pNode Parent node.
2229 * @param pszName Value name.
2230 * @param pwszValue The string value (UTF-16).
2231 */
2232VMMR3DECL(int) CFGMR3InsertStringW(PCFGMNODE pNode, const char *pszName, PCRTUTF16 pwszValue)
2233{
2234 char *pszValue;
2235 int rc = RTUtf16ToUtf8(pwszValue, &pszValue);
2236 if (RT_SUCCESS(rc))
2237 {
2238 rc = CFGMR3InsertString(pNode, pszName, pszValue);
2239 RTStrFree(pszValue);
2240 }
2241 return rc;
2242}
2243
2244
2245/**
2246 * Inserts a new integer value.
2247 *
2248 * @returns VBox status code.
2249 * @param pNode Parent node.
2250 * @param pszName Value name.
2251 * @param pvBytes The value.
2252 * @param cbBytes The value size.
2253 */
2254VMMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const void *pvBytes, size_t cbBytes)
2255{
2256 int rc;
2257 if (pNode)
2258 {
2259 if (cbBytes == (RTUINT)cbBytes)
2260 {
2261 /*
2262 * Allocate string object first.
2263 */
2264 void *pvCopy = cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cbBytes);
2265 if (pvCopy || !cbBytes)
2266 {
2267 memcpy(pvCopy, pvBytes, cbBytes);
2268
2269 /*
2270 * Create value leaf and set it to string type.
2271 */
2272 PCFGMLEAF pLeaf;
2273 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2274 if (RT_SUCCESS(rc))
2275 {
2276 pLeaf->enmType = CFGMVALUETYPE_BYTES;
2277 pLeaf->Value.Bytes.cb = cbBytes;
2278 pLeaf->Value.Bytes.pau8 = (uint8_t *)pvCopy;
2279 }
2280 else
2281 cfgmR3MemFree(pNode->pVM, pvCopy);
2282 }
2283 else
2284 rc = VERR_NO_MEMORY;
2285 }
2286 else
2287 rc = VERR_OUT_OF_RANGE;
2288 }
2289 else
2290 rc = VERR_CFGM_NO_PARENT;
2291
2292 return rc;
2293}
2294
2295
2296/**
2297 * Make a copy of the specified value under the given node.
2298 *
2299 * @returns VBox status code.
2300 * @param pNode Parent node.
2301 * @param pValue The value to copy and insert.
2302 */
2303VMMR3DECL(int) CFGMR3InsertValue(PCFGMNODE pNode, PCFGMLEAF pValue)
2304{
2305 int rc;
2306 switch (pValue->enmType)
2307 {
2308 case CFGMVALUETYPE_INTEGER:
2309 rc = CFGMR3InsertInteger(pNode, pValue->szName, pValue->Value.Integer.u64);
2310 break;
2311
2312 case CFGMVALUETYPE_BYTES:
2313 rc = CFGMR3InsertBytes(pNode, pValue->szName, pValue->Value.Bytes.pau8, pValue->Value.Bytes.cb);
2314 break;
2315
2316 case CFGMVALUETYPE_STRING:
2317 rc = CFGMR3InsertStringN(pNode, pValue->szName, pValue->Value.String.psz, pValue->Value.String.cb - 1);
2318 break;
2319
2320 default:
2321 rc = VERR_CFGM_IPE_1;
2322 AssertMsgFailed(("Invalid value type %d\n", pValue->enmType));
2323 break;
2324 }
2325 return rc;
2326}
2327
2328
2329/**
2330 * Remove a value.
2331 *
2332 * @returns VBox status code.
2333 * @param pNode Parent node.
2334 * @param pszName Name of the new child node.
2335 */
2336VMMR3DECL(int) CFGMR3RemoveValue(PCFGMNODE pNode, const char *pszName)
2337{
2338 PCFGMLEAF pLeaf;
2339 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
2340 if (RT_SUCCESS(rc))
2341 cfgmR3RemoveLeaf(pNode, pLeaf);
2342 return rc;
2343}
2344
2345
2346
2347/*
2348 * -+- helper apis -+-
2349 */
2350
2351
2352/**
2353 * Query unsigned 64-bit integer value.
2354 *
2355 * @returns VBox status code.
2356 * @param pNode Which node to search for pszName in.
2357 * @param pszName Name of an integer value.
2358 * @param pu64 Where to store the integer value.
2359 */
2360VMMR3DECL(int) CFGMR3QueryU64(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
2361{
2362 return CFGMR3QueryInteger(pNode, pszName, pu64);
2363}
2364
2365
2366/**
2367 * Query unsigned 64-bit integer value with default.
2368 *
2369 * @returns VBox status code.
2370 * @param pNode Which node to search for pszName in.
2371 * @param pszName Name of an integer value.
2372 * @param pu64 Where to store the integer value. Set to default on failure.
2373 * @param u64Def The default value.
2374 */
2375VMMR3DECL(int) CFGMR3QueryU64Def(PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)
2376{
2377 return CFGMR3QueryIntegerDef(pNode, pszName, pu64, u64Def);
2378}
2379
2380
2381/**
2382 * Query signed 64-bit integer value.
2383 *
2384 * @returns VBox status code.
2385 * @param pNode Which node to search for pszName in.
2386 * @param pszName Name of an integer value.
2387 * @param pi64 Where to store the value.
2388 */
2389VMMR3DECL(int) CFGMR3QueryS64(PCFGMNODE pNode, const char *pszName, int64_t *pi64)
2390{
2391 uint64_t u64;
2392 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2393 if (RT_SUCCESS(rc))
2394 *pi64 = (int64_t)u64;
2395 return rc;
2396}
2397
2398
2399/**
2400 * Query signed 64-bit integer value with default.
2401 *
2402 * @returns VBox status code.
2403 * @param pNode Which node to search for pszName in.
2404 * @param pszName Name of an integer value.
2405 * @param pi64 Where to store the value. Set to default on failure.
2406 * @param i64Def The default value.
2407 */
2408VMMR3DECL(int) CFGMR3QueryS64Def(PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)
2409{
2410 uint64_t u64;
2411 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i64Def);
2412 *pi64 = (int64_t)u64;
2413 return rc;
2414}
2415
2416
2417/**
2418 * Query unsigned 32-bit integer value.
2419 *
2420 * @returns VBox status code.
2421 * @param pNode Which node to search for pszName in.
2422 * @param pszName Name of an integer value.
2423 * @param pu32 Where to store the value.
2424 */
2425VMMR3DECL(int) CFGMR3QueryU32(PCFGMNODE pNode, const char *pszName, uint32_t *pu32)
2426{
2427 uint64_t u64;
2428 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2429 if (RT_SUCCESS(rc))
2430 {
2431 if (!(u64 & UINT64_C(0xffffffff00000000)))
2432 *pu32 = (uint32_t)u64;
2433 else
2434 rc = VERR_CFGM_INTEGER_TOO_BIG;
2435 }
2436 return rc;
2437}
2438
2439
2440/**
2441 * Query unsigned 32-bit integer value with default.
2442 *
2443 * @returns VBox status code.
2444 * @param pNode Which node to search for pszName in.
2445 * @param pszName Name of an integer value.
2446 * @param pu32 Where to store the value. Set to default on failure.
2447 * @param u32Def The default value.
2448 */
2449VMMR3DECL(int) CFGMR3QueryU32Def(PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)
2450{
2451 uint64_t u64;
2452 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u32Def);
2453 if (RT_SUCCESS(rc))
2454 {
2455 if (!(u64 & UINT64_C(0xffffffff00000000)))
2456 *pu32 = (uint32_t)u64;
2457 else
2458 rc = VERR_CFGM_INTEGER_TOO_BIG;
2459 }
2460 if (RT_FAILURE(rc))
2461 *pu32 = u32Def;
2462 return rc;
2463}
2464
2465
2466/**
2467 * Query signed 32-bit integer value.
2468 *
2469 * @returns VBox status code.
2470 * @param pNode Which node to search for pszName in.
2471 * @param pszName Name of an integer value.
2472 * @param pi32 Where to store the value.
2473 */
2474VMMR3DECL(int) CFGMR3QueryS32(PCFGMNODE pNode, const char *pszName, int32_t *pi32)
2475{
2476 uint64_t u64;
2477 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2478 if (RT_SUCCESS(rc))
2479 {
2480 if ( !(u64 & UINT64_C(0xffffffff80000000))
2481 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
2482 *pi32 = (int32_t)u64;
2483 else
2484 rc = VERR_CFGM_INTEGER_TOO_BIG;
2485 }
2486 return rc;
2487}
2488
2489
2490/**
2491 * Query signed 32-bit integer value with default.
2492 *
2493 * @returns VBox status code.
2494 * @param pNode Which node to search for pszName in.
2495 * @param pszName Name of an integer value.
2496 * @param pi32 Where to store the value. Set to default on failure.
2497 * @param i32Def The default value.
2498 */
2499VMMR3DECL(int) CFGMR3QueryS32Def(PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)
2500{
2501 uint64_t u64;
2502 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i32Def);
2503 if (RT_SUCCESS(rc))
2504 {
2505 if ( !(u64 & UINT64_C(0xffffffff80000000))
2506 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
2507 *pi32 = (int32_t)u64;
2508 else
2509 rc = VERR_CFGM_INTEGER_TOO_BIG;
2510 }
2511 if (RT_FAILURE(rc))
2512 *pi32 = i32Def;
2513 return rc;
2514}
2515
2516
2517/**
2518 * Query unsigned 16-bit integer value.
2519 *
2520 * @returns VBox status code.
2521 * @param pNode Which node to search for pszName in.
2522 * @param pszName Name of an integer value.
2523 * @param pu16 Where to store the value.
2524 */
2525VMMR3DECL(int) CFGMR3QueryU16(PCFGMNODE pNode, const char *pszName, uint16_t *pu16)
2526{
2527 uint64_t u64;
2528 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2529 if (RT_SUCCESS(rc))
2530 {
2531 if (!(u64 & UINT64_C(0xffffffffffff0000)))
2532 *pu16 = (int16_t)u64;
2533 else
2534 rc = VERR_CFGM_INTEGER_TOO_BIG;
2535 }
2536 return rc;
2537}
2538
2539
2540/**
2541 * Query unsigned 16-bit integer value with default.
2542 *
2543 * @returns VBox status code.
2544 * @param pNode Which node to search for pszName in.
2545 * @param pszName Name of an integer value.
2546 * @param pu16 Where to store the value. Set to default on failure.
2547 * @param i16Def The default value.
2548 */
2549VMMR3DECL(int) CFGMR3QueryU16Def(PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)
2550{
2551 uint64_t u64;
2552 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u16Def);
2553 if (RT_SUCCESS(rc))
2554 {
2555 if (!(u64 & UINT64_C(0xffffffffffff0000)))
2556 *pu16 = (int16_t)u64;
2557 else
2558 rc = VERR_CFGM_INTEGER_TOO_BIG;
2559 }
2560 if (RT_FAILURE(rc))
2561 *pu16 = u16Def;
2562 return rc;
2563}
2564
2565
2566/**
2567 * Query signed 16-bit integer value.
2568 *
2569 * @returns VBox status code.
2570 * @param pNode Which node to search for pszName in.
2571 * @param pszName Name of an integer value.
2572 * @param pi16 Where to store the value.
2573 */
2574VMMR3DECL(int) CFGMR3QueryS16(PCFGMNODE pNode, const char *pszName, int16_t *pi16)
2575{
2576 uint64_t u64;
2577 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2578 if (RT_SUCCESS(rc))
2579 {
2580 if ( !(u64 & UINT64_C(0xffffffffffff8000))
2581 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
2582 *pi16 = (int16_t)u64;
2583 else
2584 rc = VERR_CFGM_INTEGER_TOO_BIG;
2585 }
2586 return rc;
2587}
2588
2589
2590/**
2591 * Query signed 16-bit integer value with default.
2592 *
2593 * @returns VBox status code.
2594 * @param pNode Which node to search for pszName in.
2595 * @param pszName Name of an integer value.
2596 * @param pi16 Where to store the value. Set to default on failure.
2597 * @param i16Def The default value.
2598 */
2599VMMR3DECL(int) CFGMR3QueryS16Def(PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)
2600{
2601 uint64_t u64;
2602 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i16Def);
2603 if (RT_SUCCESS(rc))
2604 {
2605 if ( !(u64 & UINT64_C(0xffffffffffff8000))
2606 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
2607 *pi16 = (int16_t)u64;
2608 else
2609 rc = VERR_CFGM_INTEGER_TOO_BIG;
2610 }
2611 if (RT_FAILURE(rc))
2612 *pi16 = i16Def;
2613 return rc;
2614}
2615
2616
2617/**
2618 * Query unsigned 8-bit integer value.
2619 *
2620 * @returns VBox status code.
2621 * @param pNode Which node to search for pszName in.
2622 * @param pszName Name of an integer value.
2623 * @param pu8 Where to store the value.
2624 */
2625VMMR3DECL(int) CFGMR3QueryU8(PCFGMNODE pNode, const char *pszName, uint8_t *pu8)
2626{
2627 uint64_t u64;
2628 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2629 if (RT_SUCCESS(rc))
2630 {
2631 if (!(u64 & UINT64_C(0xffffffffffffff00)))
2632 *pu8 = (uint8_t)u64;
2633 else
2634 rc = VERR_CFGM_INTEGER_TOO_BIG;
2635 }
2636 return rc;
2637}
2638
2639
2640/**
2641 * Query unsigned 8-bit integer value with default.
2642 *
2643 * @returns VBox status code.
2644 * @param pNode Which node to search for pszName in.
2645 * @param pszName Name of an integer value.
2646 * @param pu8 Where to store the value. Set to default on failure.
2647 * @param u8Def The default value.
2648 */
2649VMMR3DECL(int) CFGMR3QueryU8Def(PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)
2650{
2651 uint64_t u64;
2652 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u8Def);
2653 if (RT_SUCCESS(rc))
2654 {
2655 if (!(u64 & UINT64_C(0xffffffffffffff00)))
2656 *pu8 = (uint8_t)u64;
2657 else
2658 rc = VERR_CFGM_INTEGER_TOO_BIG;
2659 }
2660 if (RT_FAILURE(rc))
2661 *pu8 = u8Def;
2662 return rc;
2663}
2664
2665
2666/**
2667 * Query signed 8-bit integer value.
2668 *
2669 * @returns VBox status code.
2670 * @param pNode Which node to search for pszName in.
2671 * @param pszName Name of an integer value.
2672 * @param pi8 Where to store the value.
2673 */
2674VMMR3DECL(int) CFGMR3QueryS8(PCFGMNODE pNode, const char *pszName, int8_t *pi8)
2675{
2676 uint64_t u64;
2677 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2678 if (RT_SUCCESS(rc))
2679 {
2680 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2681 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2682 *pi8 = (int8_t)u64;
2683 else
2684 rc = VERR_CFGM_INTEGER_TOO_BIG;
2685 }
2686 return rc;
2687}
2688
2689
2690/**
2691 * Query signed 8-bit integer value with default.
2692 *
2693 * @returns VBox status code.
2694 * @param pNode Which node to search for pszName in.
2695 * @param pszName Name of an integer value.
2696 * @param pi8 Where to store the value. Set to default on failure.
2697 * @param i8Def The default value.
2698 */
2699VMMR3DECL(int) CFGMR3QueryS8Def(PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)
2700{
2701 uint64_t u64;
2702 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i8Def);
2703 if (RT_SUCCESS(rc))
2704 {
2705 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2706 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2707 *pi8 = (int8_t)u64;
2708 else
2709 rc = VERR_CFGM_INTEGER_TOO_BIG;
2710 }
2711 if (RT_FAILURE(rc))
2712 *pi8 = i8Def;
2713 return rc;
2714}
2715
2716
2717/**
2718 * Query boolean integer value.
2719 *
2720 * @returns VBox status code.
2721 * @param pNode Which node to search for pszName in.
2722 * @param pszName Name of an integer value.
2723 * @param pf Where to store the value.
2724 * @remark This function will interpret any non-zero value as true.
2725 */
2726VMMR3DECL(int) CFGMR3QueryBool(PCFGMNODE pNode, const char *pszName, bool *pf)
2727{
2728 uint64_t u64;
2729 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2730 if (RT_SUCCESS(rc))
2731 *pf = u64 ? true : false;
2732 return rc;
2733}
2734
2735
2736/**
2737 * Query boolean integer value with default.
2738 *
2739 * @returns VBox status code.
2740 * @param pNode Which node to search for pszName in.
2741 * @param pszName Name of an integer value.
2742 * @param pf Where to store the value. Set to default on failure.
2743 * @param fDef The default value.
2744 * @remark This function will interpret any non-zero value as true.
2745 */
2746VMMR3DECL(int) CFGMR3QueryBoolDef(PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)
2747{
2748 uint64_t u64;
2749 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, fDef);
2750 *pf = u64 ? true : false;
2751 return rc;
2752}
2753
2754
2755/**
2756 * Query I/O port address value.
2757 *
2758 * @returns VBox status code.
2759 * @param pNode Which node to search for pszName in.
2760 * @param pszName Name of an integer value.
2761 * @param pPort Where to store the value.
2762 */
2763VMMR3DECL(int) CFGMR3QueryPort(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)
2764{
2765 AssertCompileSize(RTIOPORT, 2);
2766 return CFGMR3QueryU16(pNode, pszName, pPort);
2767}
2768
2769
2770/**
2771 * Query I/O port address value with default.
2772 *
2773 * @returns VBox status code.
2774 * @param pNode Which node to search for pszName in.
2775 * @param pszName Name of an integer value.
2776 * @param pPort Where to store the value. Set to default on failure.
2777 * @param PortDef The default value.
2778 */
2779VMMR3DECL(int) CFGMR3QueryPortDef(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)
2780{
2781 AssertCompileSize(RTIOPORT, 2);
2782 return CFGMR3QueryU16Def(pNode, pszName, pPort, PortDef);
2783}
2784
2785
2786/**
2787 * Query unsigned int address value.
2788 *
2789 * @returns VBox status code.
2790 * @param pNode Which node to search for pszName in.
2791 * @param pszName Name of an integer value.
2792 * @param pu Where to store the value.
2793 */
2794VMMR3DECL(int) CFGMR3QueryUInt(PCFGMNODE pNode, const char *pszName, unsigned int *pu)
2795{
2796 AssertCompileSize(unsigned int, 4);
2797 return CFGMR3QueryU32(pNode, pszName, (uint32_t *)pu);
2798}
2799
2800
2801/**
2802 * Query unsigned int address value with default.
2803 *
2804 * @returns VBox status code.
2805 * @param pNode Which node to search for pszName in.
2806 * @param pszName Name of an integer value.
2807 * @param pu Where to store the value. Set to default on failure.
2808 * @param uDef The default value.
2809 */
2810VMMR3DECL(int) CFGMR3QueryUIntDef(PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)
2811{
2812 AssertCompileSize(unsigned int, 4);
2813 return CFGMR3QueryU32Def(pNode, pszName, (uint32_t *)pu, uDef);
2814}
2815
2816
2817/**
2818 * Query signed int address value.
2819 *
2820 * @returns VBox status code.
2821 * @param pNode Which node to search for pszName in.
2822 * @param pszName Name of an integer value.
2823 * @param pi Where to store the value.
2824 */
2825VMMR3DECL(int) CFGMR3QuerySInt(PCFGMNODE pNode, const char *pszName, signed int *pi)
2826{
2827 AssertCompileSize(signed int, 4);
2828 return CFGMR3QueryS32(pNode, pszName, (int32_t *)pi);
2829}
2830
2831
2832/**
2833 * Query unsigned int address value with default.
2834 *
2835 * @returns VBox status code.
2836 * @param pNode Which node to search for pszName in.
2837 * @param pszName Name of an integer value.
2838 * @param pi Where to store the value. Set to default on failure.
2839 * @param iDef The default value.
2840 */
2841VMMR3DECL(int) CFGMR3QuerySIntDef(PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)
2842{
2843 AssertCompileSize(signed int, 4);
2844 return CFGMR3QueryS32Def(pNode, pszName, (int32_t *)pi, iDef);
2845}
2846
2847
2848/**
2849 * Query pointer integer value.
2850 *
2851 * @returns VBox status code.
2852 * @param pNode Which node to search for pszName in.
2853 * @param pszName Name of an integer value.
2854 * @param ppv Where to store the value.
2855 */
2856VMMR3DECL(int) CFGMR3QueryPtr(PCFGMNODE pNode, const char *pszName, void **ppv)
2857{
2858 uint64_t u64;
2859 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2860 if (RT_SUCCESS(rc))
2861 {
2862 uintptr_t u = (uintptr_t)u64;
2863 if (u64 == u)
2864 *ppv = (void *)u;
2865 else
2866 rc = VERR_CFGM_INTEGER_TOO_BIG;
2867 }
2868 return rc;
2869}
2870
2871
2872/**
2873 * Query pointer integer value with default.
2874 *
2875 * @returns VBox status code.
2876 * @param pNode Which node to search for pszName in.
2877 * @param pszName Name of an integer value.
2878 * @param ppv Where to store the value. Set to default on failure.
2879 * @param pvDef The default value.
2880 */
2881VMMR3DECL(int) CFGMR3QueryPtrDef(PCFGMNODE pNode, const char *pszName, void **ppv, void *pvDef)
2882{
2883 uint64_t u64;
2884 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, (uintptr_t)pvDef);
2885 if (RT_SUCCESS(rc))
2886 {
2887 uintptr_t u = (uintptr_t)u64;
2888 if (u64 == u)
2889 *ppv = (void *)u;
2890 else
2891 rc = VERR_CFGM_INTEGER_TOO_BIG;
2892 }
2893 if (RT_FAILURE(rc))
2894 *ppv = pvDef;
2895 return rc;
2896}
2897
2898
2899/**
2900 * Query Guest Context pointer integer value.
2901 *
2902 * @returns VBox status code.
2903 * @param pNode Which node to search for pszName in.
2904 * @param pszName Name of an integer value.
2905 * @param pGCPtr Where to store the value.
2906 */
2907VMMR3DECL(int) CFGMR3QueryGCPtr(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)
2908{
2909 uint64_t u64;
2910 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2911 if (RT_SUCCESS(rc))
2912 {
2913 RTGCPTR u = (RTGCPTR)u64;
2914 if (u64 == u)
2915 *pGCPtr = u;
2916 else
2917 rc = VERR_CFGM_INTEGER_TOO_BIG;
2918 }
2919 return rc;
2920}
2921
2922
2923/**
2924 * Query Guest Context pointer integer value with default.
2925 *
2926 * @returns VBox status code.
2927 * @param pNode Which node to search for pszName in.
2928 * @param pszName Name of an integer value.
2929 * @param pGCPtr Where to store the value. Set to default on failure.
2930 * @param GCPtrDef The default value.
2931 */
2932VMMR3DECL(int) CFGMR3QueryGCPtrDef(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)
2933{
2934 uint64_t u64;
2935 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2936 if (RT_SUCCESS(rc))
2937 {
2938 RTGCPTR u = (RTGCPTR)u64;
2939 if (u64 == u)
2940 *pGCPtr = u;
2941 else
2942 rc = VERR_CFGM_INTEGER_TOO_BIG;
2943 }
2944 if (RT_FAILURE(rc))
2945 *pGCPtr = GCPtrDef;
2946 return rc;
2947}
2948
2949
2950/**
2951 * Query Guest Context unsigned pointer value.
2952 *
2953 * @returns VBox status code.
2954 * @param pNode Which node to search for pszName in.
2955 * @param pszName Name of an integer value.
2956 * @param pGCPtr Where to store the value.
2957 */
2958VMMR3DECL(int) CFGMR3QueryGCPtrU(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)
2959{
2960 uint64_t u64;
2961 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2962 if (RT_SUCCESS(rc))
2963 {
2964 RTGCUINTPTR u = (RTGCUINTPTR)u64;
2965 if (u64 == u)
2966 *pGCPtr = u;
2967 else
2968 rc = VERR_CFGM_INTEGER_TOO_BIG;
2969 }
2970 return rc;
2971}
2972
2973
2974/**
2975 * Query Guest Context unsigned pointer value with default.
2976 *
2977 * @returns VBox status code.
2978 * @param pNode Which node to search for pszName in.
2979 * @param pszName Name of an integer value.
2980 * @param pGCPtr Where to store the value. Set to default on failure.
2981 * @param GCPtrDef The default value.
2982 */
2983VMMR3DECL(int) CFGMR3QueryGCPtrUDef(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)
2984{
2985 uint64_t u64;
2986 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2987 if (RT_SUCCESS(rc))
2988 {
2989 RTGCUINTPTR u = (RTGCUINTPTR)u64;
2990 if (u64 == u)
2991 *pGCPtr = u;
2992 else
2993 rc = VERR_CFGM_INTEGER_TOO_BIG;
2994 }
2995 if (RT_FAILURE(rc))
2996 *pGCPtr = GCPtrDef;
2997 return rc;
2998}
2999
3000
3001/**
3002 * Query Guest Context signed pointer value.
3003 *
3004 * @returns VBox status code.
3005 * @param pNode Which node to search for pszName in.
3006 * @param pszName Name of an integer value.
3007 * @param pGCPtr Where to store the value.
3008 */
3009VMMR3DECL(int) CFGMR3QueryGCPtrS(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)
3010{
3011 uint64_t u64;
3012 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
3013 if (RT_SUCCESS(rc))
3014 {
3015 RTGCINTPTR u = (RTGCINTPTR)u64;
3016 if (u64 == (uint64_t)u)
3017 *pGCPtr = u;
3018 else
3019 rc = VERR_CFGM_INTEGER_TOO_BIG;
3020 }
3021 return rc;
3022}
3023
3024
3025/**
3026 * Query Guest Context signed pointer value with default.
3027 *
3028 * @returns VBox status code.
3029 * @param pNode Which node to search for pszName in.
3030 * @param pszName Name of an integer value.
3031 * @param pGCPtr Where to store the value. Set to default on failure.
3032 * @param GCPtrDef The default value.
3033 */
3034VMMR3DECL(int) CFGMR3QueryGCPtrSDef(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)
3035{
3036 uint64_t u64;
3037 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
3038 if (RT_SUCCESS(rc))
3039 {
3040 RTGCINTPTR u = (RTGCINTPTR)u64;
3041 if (u64 == (uint64_t)u)
3042 *pGCPtr = u;
3043 else
3044 rc = VERR_CFGM_INTEGER_TOO_BIG;
3045 }
3046 if (RT_FAILURE(rc))
3047 *pGCPtr = GCPtrDef;
3048 return rc;
3049}
3050
3051
3052/**
3053 * Query zero terminated character value storing it in a
3054 * buffer allocated from the MM heap.
3055 *
3056 * @returns VBox status code.
3057 * @param pNode Which node to search for pszName in.
3058 * @param pszName Value name. This value must be of zero terminated character string type.
3059 * @param ppszString Where to store the string pointer.
3060 * Free this using MMR3HeapFree() (or RTStrFree if not
3061 * associated with a pUVM - see CFGMR3CreateTree).
3062 */
3063VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
3064{
3065 size_t cbString;
3066 int rc = CFGMR3QuerySize(pNode, pszName, &cbString);
3067 if (RT_SUCCESS(rc))
3068 {
3069 char *pszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbString);
3070 if (pszString)
3071 {
3072 rc = CFGMR3QueryString(pNode, pszName, pszString, cbString);
3073 if (RT_SUCCESS(rc))
3074 *ppszString = pszString;
3075 else
3076 cfgmR3StrFree(pNode->pVM, pszString);
3077 }
3078 else
3079 rc = VERR_NO_MEMORY;
3080 }
3081 return rc;
3082}
3083
3084
3085/**
3086 * Query zero terminated character value storing it in a
3087 * buffer allocated from the MM heap.
3088 *
3089 * @returns VBox status code.
3090 * @param pNode Which node to search for pszName in. This cannot be
3091 * NULL if @a pszDef is not NULL, because we need
3092 * somewhere way to get to the VM in order to call
3093 * MMR3HeapStrDup.
3094 * @param pszName Value name. This value must be of zero terminated character string type.
3095 * @param ppszString Where to store the string pointer. Not set on failure.
3096 * Free this using MMR3HeapFree() (or RTStrFree if not
3097 * associated with a pUVM - see CFGMR3CreateTree).
3098 * @param pszDef The default return value. This can be NULL.
3099 */
3100VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)
3101{
3102 Assert(pNode || !pszDef); /* We need pVM if we need to duplicate the string later. */
3103
3104 /*
3105 * (Don't call CFGMR3QuerySize and CFGMR3QueryStringDef here as the latter
3106 * cannot handle pszDef being NULL.)
3107 */
3108 PCFGMLEAF pLeaf;
3109 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
3110 if (RT_SUCCESS(rc))
3111 {
3112 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
3113 {
3114 size_t const cbSrc = pLeaf->Value.String.cb;
3115 char *pszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbSrc);
3116 if (pszString)
3117 {
3118 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
3119 *ppszString = pszString;
3120 }
3121 else
3122 rc = VERR_NO_MEMORY;
3123 }
3124 else
3125 rc = VERR_CFGM_NOT_STRING;
3126 }
3127 if (RT_FAILURE(rc))
3128 {
3129 if (!pszDef)
3130 *ppszString = NULL;
3131 else
3132 {
3133 size_t const cbDef = strlen(pszDef) + 1;
3134 *ppszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbDef);
3135 memcpy(*ppszString, pszDef, cbDef);
3136 }
3137 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
3138 rc = VINF_SUCCESS;
3139 }
3140
3141 return rc;
3142}
3143
3144
3145/**
3146 * Dumps the configuration (sub)tree to the release log.
3147 *
3148 * @param pRoot The root node of the dump.
3149 */
3150VMMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot)
3151{
3152 bool fOldBuffered = RTLogRelSetBuffering(true /*fBuffered*/);
3153 LogRel(("************************* CFGM dump *************************\n"));
3154 cfgmR3Dump(pRoot, 0, DBGFR3InfoLogRelHlp());
3155 LogRel(("********************* End of CFGM dump **********************\n"));
3156 RTLogRelSetBuffering(fOldBuffered);
3157}
3158
3159
3160/**
3161 * Info handler, internal version.
3162 *
3163 * @param pVM Pointer to the VM.
3164 * @param pHlp Callback functions for doing output.
3165 * @param pszArgs Argument string. Optional and specific to the handler.
3166 */
3167static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
3168{
3169 /*
3170 * Figure where to start.
3171 */
3172 PCFGMNODE pRoot = pVM->cfgm.s.pRoot;
3173 if (pszArgs && *pszArgs)
3174 {
3175 int rc = cfgmR3ResolveNode(pRoot, pszArgs, &pRoot);
3176 if (RT_FAILURE(rc))
3177 {
3178 pHlp->pfnPrintf(pHlp, "Failed to resolve CFGM path '%s', %Rrc", pszArgs, rc);
3179 return;
3180 }
3181 }
3182
3183 /*
3184 * Dump the specified tree.
3185 */
3186 pHlp->pfnPrintf(pHlp, "pRoot=%p:{", pRoot);
3187 cfgmR3DumpPath(pRoot, pHlp);
3188 pHlp->pfnPrintf(pHlp, "}\n");
3189 cfgmR3Dump(pRoot, 0, pHlp);
3190}
3191
3192
3193/**
3194 * Recursively prints a path name.
3195 */
3196static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp)
3197{
3198 if (pNode->pParent)
3199 cfgmR3DumpPath(pNode->pParent, pHlp);
3200 pHlp->pfnPrintf(pHlp, "%s/", pNode->szName);
3201}
3202
3203
3204/**
3205 * Dumps a branch of a tree.
3206 */
3207static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp)
3208{
3209 /*
3210 * Path.
3211 */
3212 pHlp->pfnPrintf(pHlp, "[");
3213 cfgmR3DumpPath(pRoot, pHlp);
3214 pHlp->pfnPrintf(pHlp, "] (level %d)%s\n", iLevel, pRoot->fRestrictedRoot ? " (restricted root)" : "");
3215
3216 /*
3217 * Values.
3218 */
3219 PCFGMLEAF pLeaf;
3220 size_t cchMax = 0;
3221 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
3222 cchMax = RT_MAX(cchMax, pLeaf->cchName);
3223 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
3224 {
3225 switch (CFGMR3GetValueType(pLeaf))
3226 {
3227 case CFGMVALUETYPE_INTEGER:
3228 {
3229 pHlp->pfnPrintf(pHlp, " %-*s <integer> = %#018llx (%'lld", (int)cchMax, pLeaf->szName, pLeaf->Value.Integer.u64, pLeaf->Value.Integer.u64);
3230 if ( ( pLeaf->cchName >= 4
3231 && !RTStrCmp(&pLeaf->szName[pLeaf->cchName - 4], "Size"))
3232 || ( pLeaf->cchName >= 2
3233 && !RTStrNCmp(pLeaf->szName, "cb", 2)) )
3234 {
3235 if (pLeaf->Value.Integer.u64 > _2G)
3236 pHlp->pfnPrintf(pHlp, ", %'lld GB", pLeaf->Value.Integer.u64 / _1G);
3237 else if (pLeaf->Value.Integer.u64 > _2M)
3238 pHlp->pfnPrintf(pHlp, ", %'lld MB", pLeaf->Value.Integer.u64 / _1M);
3239 else if (pLeaf->Value.Integer.u64 > _2K)
3240 pHlp->pfnPrintf(pHlp, ", %'lld KB", pLeaf->Value.Integer.u64 / _1K);
3241 }
3242 pHlp->pfnPrintf(pHlp, ")\n");
3243 break;
3244 }
3245
3246 case CFGMVALUETYPE_STRING:
3247 pHlp->pfnPrintf(pHlp, " %-*s <string> = \"%s\" (cb=%zu)\n", (int)cchMax, pLeaf->szName, pLeaf->Value.String.psz, pLeaf->Value.String.cb);
3248 break;
3249
3250 case CFGMVALUETYPE_BYTES:
3251 pHlp->pfnPrintf(pHlp, " %-*s <bytes> = \"%.*Rhxs\" (cb=%zu)\n", (int)cchMax, pLeaf->szName, pLeaf->Value.Bytes.cb, pLeaf->Value.Bytes.pau8, pLeaf->Value.Bytes.cb);
3252 break;
3253
3254 default:
3255 AssertMsgFailed(("bad leaf!\n"));
3256 break;
3257 }
3258 }
3259 pHlp->pfnPrintf(pHlp, "\n");
3260
3261 /*
3262 * Children.
3263 */
3264 for (PCFGMNODE pChild = CFGMR3GetFirstChild(pRoot); pChild; pChild = CFGMR3GetNextChild(pChild))
3265 {
3266 Assert(pChild->pNext != pChild);
3267 Assert(pChild->pPrev != pChild);
3268 Assert(pChild->pPrev != pChild->pNext || !pChild->pPrev);
3269 Assert(pChild->pFirstChild != pChild);
3270 Assert(pChild->pParent == pRoot);
3271 cfgmR3Dump(pChild, iLevel + 1, pHlp);
3272 }
3273}
3274
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette