VirtualBox

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

Last change on this file since 46786 was 46781, checked in by vboxsync, 12 years ago

CFGM: Made the CFGMR3CreateTree usable with pUVM == NULL for testing purposes.

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

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