VirtualBox

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

Last change on this file since 94369 was 94369, checked in by vboxsync, 3 years ago

VMM,CFGM: Drop CFGMR3QueryPtr and CFGMR3QueryPtrDef, bugref:10053

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

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