VirtualBox

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

Last change on this file since 84044 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use