VirtualBox

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

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

Made CFGMR3RemoveNode work in standalone mode.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 94.8 KB
Line 
1/* $Id: CFGM.cpp 46791 2013-06-26 09:20:37Z 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->pVM /* might be a different tree */
1943 && pNode == pNode->pVM->cfgm.s.pRoot)
1944 pNode->pVM->cfgm.s.pRoot = NULL;
1945 }
1946 if (pNode->pNext)
1947 pNode->pNext->pPrev = pNode->pPrev;
1948
1949 /*
1950 * Free ourselves.
1951 */
1952 cfgmR3FreeNodeOnly(pNode);
1953 }
1954}
1955
1956
1957/**
1958 * Removes a leaf.
1959 *
1960 * @param pNode Parent node.
1961 * @param pLeaf Leaf to remove.
1962 */
1963static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf)
1964{
1965 if (pNode && pLeaf)
1966 {
1967 /*
1968 * Unlink.
1969 */
1970 if (pLeaf->pPrev)
1971 pLeaf->pPrev->pNext = pLeaf->pNext;
1972 else
1973 pNode->pFirstLeaf = pLeaf->pNext;
1974 if (pLeaf->pNext)
1975 pLeaf->pNext->pPrev = pLeaf->pPrev;
1976
1977 /*
1978 * Free value and node.
1979 */
1980 cfgmR3FreeValue(pNode->pVM, pLeaf);
1981 pLeaf->pNext = NULL;
1982 pLeaf->pPrev = NULL;
1983 cfgmR3MemFree(pNode->pVM, pLeaf);
1984 }
1985}
1986
1987
1988/**
1989 * Frees whatever resources the leaf value is owning.
1990 *
1991 * Use this before assigning a new value to a leaf.
1992 * The caller must either free the leaf or assign a new value to it.
1993 *
1994 * @param pVM Used to select the heap.
1995 * @param pLeaf Pointer to the leaf which value should be free.
1996 */
1997static void cfgmR3FreeValue(PVM pVM, PCFGMLEAF pLeaf)
1998{
1999 if (pLeaf)
2000 {
2001 switch (pLeaf->enmType)
2002 {
2003 case CFGMVALUETYPE_BYTES:
2004 cfgmR3MemFree(pVM, pLeaf->Value.Bytes.pau8);
2005 pLeaf->Value.Bytes.pau8 = NULL;
2006 pLeaf->Value.Bytes.cb = 0;
2007 break;
2008
2009 case CFGMVALUETYPE_STRING:
2010 cfgmR3StrFree(pVM, pLeaf->Value.String.psz);
2011 pLeaf->Value.String.psz = NULL;
2012 pLeaf->Value.String.cb = 0;
2013 break;
2014
2015 case CFGMVALUETYPE_INTEGER:
2016 break;
2017 }
2018 pLeaf->enmType = (CFGMVALUETYPE)0;
2019 }
2020}
2021
2022
2023/**
2024 * Inserts a new integer value.
2025 *
2026 * @returns VBox status code.
2027 * @param pNode Parent node.
2028 * @param pszName Value name.
2029 * @param u64Integer The value.
2030 */
2031VMMR3DECL(int) CFGMR3InsertInteger(PCFGMNODE pNode, const char *pszName, uint64_t u64Integer)
2032{
2033 PCFGMLEAF pLeaf;
2034 int rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2035 if (RT_SUCCESS(rc))
2036 {
2037 pLeaf->enmType = CFGMVALUETYPE_INTEGER;
2038 pLeaf->Value.Integer.u64 = u64Integer;
2039 }
2040 return rc;
2041}
2042
2043
2044/**
2045 * Inserts a new string value. This variant expects that the caller know the length
2046 * of the string already so we can avoid calling strlen() here.
2047 *
2048 * @returns VBox status code.
2049 * @param pNode Parent node.
2050 * @param pszName Value name.
2051 * @param pszString The value. Must not be NULL.
2052 * @param cchString The length of the string excluding the
2053 * terminator.
2054 */
2055VMMR3DECL(int) CFGMR3InsertStringN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString)
2056{
2057 Assert(RTStrNLen(pszString, cchString) == cchString);
2058
2059 int rc;
2060 if (pNode)
2061 {
2062 /*
2063 * Allocate string object first.
2064 */
2065 char *pszStringCopy = (char *)cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cchString + 1);
2066 if (pszStringCopy)
2067 {
2068 memcpy(pszStringCopy, pszString, cchString);
2069 pszStringCopy[cchString] = '\0';
2070
2071 /*
2072 * Create value leaf and set it to string type.
2073 */
2074 PCFGMLEAF pLeaf;
2075 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2076 if (RT_SUCCESS(rc))
2077 {
2078 pLeaf->enmType = CFGMVALUETYPE_STRING;
2079 pLeaf->Value.String.psz = pszStringCopy;
2080 pLeaf->Value.String.cb = cchString + 1;
2081 }
2082 else
2083 cfgmR3StrFree(pNode->pVM, pszStringCopy);
2084 }
2085 else
2086 rc = VERR_NO_MEMORY;
2087 }
2088 else
2089 rc = VERR_CFGM_NO_PARENT;
2090
2091 return rc;
2092}
2093
2094
2095/**
2096 * Inserts a new string value. Calls strlen(pszString) internally; if you know the
2097 * length of the string, CFGMR3InsertStringLengthKnown() is faster.
2098 *
2099 * @returns VBox status code.
2100 * @param pNode Parent node.
2101 * @param pszName Value name.
2102 * @param pszString The value.
2103 */
2104VMMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString)
2105{
2106 return CFGMR3InsertStringN(pNode, pszName, pszString, strlen(pszString));
2107}
2108
2109
2110/**
2111 * Same as CFGMR3InsertString except the string value given in RTStrPrintfV
2112 * fashion.
2113 *
2114 * @returns VBox status code.
2115 * @param pNode Parent node.
2116 * @param pszName Value name.
2117 * @param pszFormat The value given as a format string.
2118 * @param va Argument to pszFormat.
2119 */
2120VMMR3DECL(int) CFGMR3InsertStringFV(PCFGMNODE pNode, const char *pszName, const char *pszFormat, va_list va)
2121{
2122 int rc;
2123 if (pNode)
2124 {
2125 /*
2126 * Allocate string object first.
2127 */
2128 char *pszString;
2129 if (!pNode->pVM)
2130 pszString = RTStrAPrintf2(pszFormat, va);
2131 else
2132 pszString = MMR3HeapAPrintfVU(pNode->pVM->pUVM, MM_TAG_CFGM_STRING, pszFormat, va);
2133 if (pszString)
2134 {
2135 /*
2136 * Create value leaf and set it to string type.
2137 */
2138 PCFGMLEAF pLeaf;
2139 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2140 if (RT_SUCCESS(rc))
2141 {
2142 pLeaf->enmType = CFGMVALUETYPE_STRING;
2143 pLeaf->Value.String.psz = pszString;
2144 pLeaf->Value.String.cb = strlen(pszString) + 1;
2145 }
2146 else
2147 cfgmR3StrFree(pNode->pVM, pszString);
2148 }
2149 else
2150 rc = VERR_NO_MEMORY;
2151 }
2152 else
2153 rc = VERR_CFGM_NO_PARENT;
2154
2155 return rc;
2156}
2157
2158
2159/**
2160 * Same as CFGMR3InsertString except the string value given in RTStrPrintf
2161 * fashion.
2162 *
2163 * @returns VBox status code.
2164 * @param pNode Parent node.
2165 * @param pszName Value name.
2166 * @param pszFormat The value given as a format string.
2167 * @param ... Argument to pszFormat.
2168 */
2169VMMR3DECL(int) CFGMR3InsertStringF(PCFGMNODE pNode, const char *pszName, const char *pszFormat, ...)
2170{
2171 va_list va;
2172 va_start(va, pszFormat);
2173 int rc = CFGMR3InsertStringFV(pNode, pszName, pszFormat, va);
2174 va_end(va);
2175 return rc;
2176}
2177
2178
2179/**
2180 * Same as CFGMR3InsertString except the string value given as a UTF-16 string.
2181 *
2182 * @returns VBox status code.
2183 * @param pNode Parent node.
2184 * @param pszName Value name.
2185 * @param pwszValue The string value (UTF-16).
2186 */
2187VMMR3DECL(int) CFGMR3InsertStringW(PCFGMNODE pNode, const char *pszName, PCRTUTF16 pwszValue)
2188{
2189 char *pszValue;
2190 int rc = RTUtf16ToUtf8(pwszValue, &pszValue);
2191 if (RT_SUCCESS(rc))
2192 {
2193 rc = CFGMR3InsertString(pNode, pszName, pszValue);
2194 RTStrFree(pszValue);
2195 }
2196 return rc;
2197}
2198
2199
2200/**
2201 * Inserts a new integer value.
2202 *
2203 * @returns VBox status code.
2204 * @param pNode Parent node.
2205 * @param pszName Value name.
2206 * @param pvBytes The value.
2207 * @param cbBytes The value size.
2208 */
2209VMMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const void *pvBytes, size_t cbBytes)
2210{
2211 int rc;
2212 if (pNode)
2213 {
2214 if (cbBytes == (RTUINT)cbBytes)
2215 {
2216 /*
2217 * Allocate string object first.
2218 */
2219 void *pvCopy = cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cbBytes);
2220 if (pvCopy || !cbBytes)
2221 {
2222 memcpy(pvCopy, pvBytes, cbBytes);
2223
2224 /*
2225 * Create value leaf and set it to string type.
2226 */
2227 PCFGMLEAF pLeaf;
2228 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2229 if (RT_SUCCESS(rc))
2230 {
2231 pLeaf->enmType = CFGMVALUETYPE_BYTES;
2232 pLeaf->Value.Bytes.cb = cbBytes;
2233 pLeaf->Value.Bytes.pau8 = (uint8_t *)pvCopy;
2234 }
2235 else
2236 cfgmR3MemFree(pNode->pVM, pvCopy);
2237 }
2238 else
2239 rc = VERR_NO_MEMORY;
2240 }
2241 else
2242 rc = VERR_OUT_OF_RANGE;
2243 }
2244 else
2245 rc = VERR_CFGM_NO_PARENT;
2246
2247 return rc;
2248}
2249
2250
2251/**
2252 * Make a copy of the specified value under the given node.
2253 *
2254 * @returns VBox status code.
2255 * @param pNode Parent node.
2256 * @param pValue The value to copy and insert.
2257 */
2258VMMR3DECL(int) CFGMR3InsertValue(PCFGMNODE pNode, PCFGMLEAF pValue)
2259{
2260 int rc;
2261 switch (pValue->enmType)
2262 {
2263 case CFGMVALUETYPE_INTEGER:
2264 rc = CFGMR3InsertInteger(pNode, pValue->szName, pValue->Value.Integer.u64);
2265 break;
2266
2267 case CFGMVALUETYPE_BYTES:
2268 rc = CFGMR3InsertBytes(pNode, pValue->szName, pValue->Value.Bytes.pau8, pValue->Value.Bytes.cb);
2269 break;
2270
2271 case CFGMVALUETYPE_STRING:
2272 rc = CFGMR3InsertStringN(pNode, pValue->szName, pValue->Value.String.psz, pValue->Value.String.cb - 1);
2273 break;
2274
2275 default:
2276 rc = VERR_CFGM_IPE_1;
2277 AssertMsgFailed(("Invalid value type %d\n", pValue->enmType));
2278 break;
2279 }
2280 return rc;
2281}
2282
2283
2284/**
2285 * Remove a value.
2286 *
2287 * @returns VBox status code.
2288 * @param pNode Parent node.
2289 * @param pszName Name of the new child node.
2290 */
2291VMMR3DECL(int) CFGMR3RemoveValue(PCFGMNODE pNode, const char *pszName)
2292{
2293 PCFGMLEAF pLeaf;
2294 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
2295 if (RT_SUCCESS(rc))
2296 cfgmR3RemoveLeaf(pNode, pLeaf);
2297 return rc;
2298}
2299
2300
2301
2302/*
2303 * -+- helper apis -+-
2304 */
2305
2306
2307/**
2308 * Query unsigned 64-bit integer value.
2309 *
2310 * @returns VBox status code.
2311 * @param pNode Which node to search for pszName in.
2312 * @param pszName Name of an integer value.
2313 * @param pu64 Where to store the integer value.
2314 */
2315VMMR3DECL(int) CFGMR3QueryU64(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
2316{
2317 return CFGMR3QueryInteger(pNode, pszName, pu64);
2318}
2319
2320
2321/**
2322 * Query unsigned 64-bit integer value with default.
2323 *
2324 * @returns VBox status code.
2325 * @param pNode Which node to search for pszName in.
2326 * @param pszName Name of an integer value.
2327 * @param pu64 Where to store the integer value. Set to default on failure.
2328 * @param u64Def The default value.
2329 */
2330VMMR3DECL(int) CFGMR3QueryU64Def(PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)
2331{
2332 return CFGMR3QueryIntegerDef(pNode, pszName, pu64, u64Def);
2333}
2334
2335
2336/**
2337 * Query signed 64-bit integer value.
2338 *
2339 * @returns VBox status code.
2340 * @param pNode Which node to search for pszName in.
2341 * @param pszName Name of an integer value.
2342 * @param pi64 Where to store the value.
2343 */
2344VMMR3DECL(int) CFGMR3QueryS64(PCFGMNODE pNode, const char *pszName, int64_t *pi64)
2345{
2346 uint64_t u64;
2347 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2348 if (RT_SUCCESS(rc))
2349 *pi64 = (int64_t)u64;
2350 return rc;
2351}
2352
2353
2354/**
2355 * Query signed 64-bit integer value with default.
2356 *
2357 * @returns VBox status code.
2358 * @param pNode Which node to search for pszName in.
2359 * @param pszName Name of an integer value.
2360 * @param pi64 Where to store the value. Set to default on failure.
2361 * @param i64Def The default value.
2362 */
2363VMMR3DECL(int) CFGMR3QueryS64Def(PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)
2364{
2365 uint64_t u64;
2366 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i64Def);
2367 *pi64 = (int64_t)u64;
2368 return rc;
2369}
2370
2371
2372/**
2373 * Query unsigned 32-bit integer value.
2374 *
2375 * @returns VBox status code.
2376 * @param pNode Which node to search for pszName in.
2377 * @param pszName Name of an integer value.
2378 * @param pu32 Where to store the value.
2379 */
2380VMMR3DECL(int) CFGMR3QueryU32(PCFGMNODE pNode, const char *pszName, uint32_t *pu32)
2381{
2382 uint64_t u64;
2383 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2384 if (RT_SUCCESS(rc))
2385 {
2386 if (!(u64 & UINT64_C(0xffffffff00000000)))
2387 *pu32 = (uint32_t)u64;
2388 else
2389 rc = VERR_CFGM_INTEGER_TOO_BIG;
2390 }
2391 return rc;
2392}
2393
2394
2395/**
2396 * Query unsigned 32-bit integer value with default.
2397 *
2398 * @returns VBox status code.
2399 * @param pNode Which node to search for pszName in.
2400 * @param pszName Name of an integer value.
2401 * @param pu32 Where to store the value. Set to default on failure.
2402 * @param u32Def The default value.
2403 */
2404VMMR3DECL(int) CFGMR3QueryU32Def(PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)
2405{
2406 uint64_t u64;
2407 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u32Def);
2408 if (RT_SUCCESS(rc))
2409 {
2410 if (!(u64 & UINT64_C(0xffffffff00000000)))
2411 *pu32 = (uint32_t)u64;
2412 else
2413 rc = VERR_CFGM_INTEGER_TOO_BIG;
2414 }
2415 if (RT_FAILURE(rc))
2416 *pu32 = u32Def;
2417 return rc;
2418}
2419
2420
2421/**
2422 * Query signed 32-bit integer value.
2423 *
2424 * @returns VBox status code.
2425 * @param pNode Which node to search for pszName in.
2426 * @param pszName Name of an integer value.
2427 * @param pi32 Where to store the value.
2428 */
2429VMMR3DECL(int) CFGMR3QueryS32(PCFGMNODE pNode, const char *pszName, int32_t *pi32)
2430{
2431 uint64_t u64;
2432 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2433 if (RT_SUCCESS(rc))
2434 {
2435 if ( !(u64 & UINT64_C(0xffffffff80000000))
2436 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
2437 *pi32 = (int32_t)u64;
2438 else
2439 rc = VERR_CFGM_INTEGER_TOO_BIG;
2440 }
2441 return rc;
2442}
2443
2444
2445/**
2446 * Query signed 32-bit integer value with default.
2447 *
2448 * @returns VBox status code.
2449 * @param pNode Which node to search for pszName in.
2450 * @param pszName Name of an integer value.
2451 * @param pi32 Where to store the value. Set to default on failure.
2452 * @param i32Def The default value.
2453 */
2454VMMR3DECL(int) CFGMR3QueryS32Def(PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)
2455{
2456 uint64_t u64;
2457 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i32Def);
2458 if (RT_SUCCESS(rc))
2459 {
2460 if ( !(u64 & UINT64_C(0xffffffff80000000))
2461 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
2462 *pi32 = (int32_t)u64;
2463 else
2464 rc = VERR_CFGM_INTEGER_TOO_BIG;
2465 }
2466 if (RT_FAILURE(rc))
2467 *pi32 = i32Def;
2468 return rc;
2469}
2470
2471
2472/**
2473 * Query unsigned 16-bit integer value.
2474 *
2475 * @returns VBox status code.
2476 * @param pNode Which node to search for pszName in.
2477 * @param pszName Name of an integer value.
2478 * @param pu16 Where to store the value.
2479 */
2480VMMR3DECL(int) CFGMR3QueryU16(PCFGMNODE pNode, const char *pszName, uint16_t *pu16)
2481{
2482 uint64_t u64;
2483 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2484 if (RT_SUCCESS(rc))
2485 {
2486 if (!(u64 & UINT64_C(0xffffffffffff0000)))
2487 *pu16 = (int16_t)u64;
2488 else
2489 rc = VERR_CFGM_INTEGER_TOO_BIG;
2490 }
2491 return rc;
2492}
2493
2494
2495/**
2496 * Query unsigned 16-bit integer value with default.
2497 *
2498 * @returns VBox status code.
2499 * @param pNode Which node to search for pszName in.
2500 * @param pszName Name of an integer value.
2501 * @param pu16 Where to store the value. Set to default on failure.
2502 * @param i16Def The default value.
2503 */
2504VMMR3DECL(int) CFGMR3QueryU16Def(PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)
2505{
2506 uint64_t u64;
2507 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u16Def);
2508 if (RT_SUCCESS(rc))
2509 {
2510 if (!(u64 & UINT64_C(0xffffffffffff0000)))
2511 *pu16 = (int16_t)u64;
2512 else
2513 rc = VERR_CFGM_INTEGER_TOO_BIG;
2514 }
2515 if (RT_FAILURE(rc))
2516 *pu16 = u16Def;
2517 return rc;
2518}
2519
2520
2521/**
2522 * Query signed 16-bit integer value.
2523 *
2524 * @returns VBox status code.
2525 * @param pNode Which node to search for pszName in.
2526 * @param pszName Name of an integer value.
2527 * @param pi16 Where to store the value.
2528 */
2529VMMR3DECL(int) CFGMR3QueryS16(PCFGMNODE pNode, const char *pszName, int16_t *pi16)
2530{
2531 uint64_t u64;
2532 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2533 if (RT_SUCCESS(rc))
2534 {
2535 if ( !(u64 & UINT64_C(0xffffffffffff8000))
2536 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
2537 *pi16 = (int16_t)u64;
2538 else
2539 rc = VERR_CFGM_INTEGER_TOO_BIG;
2540 }
2541 return rc;
2542}
2543
2544
2545/**
2546 * Query signed 16-bit integer value with default.
2547 *
2548 * @returns VBox status code.
2549 * @param pNode Which node to search for pszName in.
2550 * @param pszName Name of an integer value.
2551 * @param pi16 Where to store the value. Set to default on failure.
2552 * @param i16Def The default value.
2553 */
2554VMMR3DECL(int) CFGMR3QueryS16Def(PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)
2555{
2556 uint64_t u64;
2557 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i16Def);
2558 if (RT_SUCCESS(rc))
2559 {
2560 if ( !(u64 & UINT64_C(0xffffffffffff8000))
2561 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
2562 *pi16 = (int16_t)u64;
2563 else
2564 rc = VERR_CFGM_INTEGER_TOO_BIG;
2565 }
2566 if (RT_FAILURE(rc))
2567 *pi16 = i16Def;
2568 return rc;
2569}
2570
2571
2572/**
2573 * Query unsigned 8-bit integer value.
2574 *
2575 * @returns VBox status code.
2576 * @param pNode Which node to search for pszName in.
2577 * @param pszName Name of an integer value.
2578 * @param pu8 Where to store the value.
2579 */
2580VMMR3DECL(int) CFGMR3QueryU8(PCFGMNODE pNode, const char *pszName, uint8_t *pu8)
2581{
2582 uint64_t u64;
2583 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2584 if (RT_SUCCESS(rc))
2585 {
2586 if (!(u64 & UINT64_C(0xffffffffffffff00)))
2587 *pu8 = (uint8_t)u64;
2588 else
2589 rc = VERR_CFGM_INTEGER_TOO_BIG;
2590 }
2591 return rc;
2592}
2593
2594
2595/**
2596 * Query unsigned 8-bit integer value with default.
2597 *
2598 * @returns VBox status code.
2599 * @param pNode Which node to search for pszName in.
2600 * @param pszName Name of an integer value.
2601 * @param pu8 Where to store the value. Set to default on failure.
2602 * @param u8Def The default value.
2603 */
2604VMMR3DECL(int) CFGMR3QueryU8Def(PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)
2605{
2606 uint64_t u64;
2607 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u8Def);
2608 if (RT_SUCCESS(rc))
2609 {
2610 if (!(u64 & UINT64_C(0xffffffffffffff00)))
2611 *pu8 = (uint8_t)u64;
2612 else
2613 rc = VERR_CFGM_INTEGER_TOO_BIG;
2614 }
2615 if (RT_FAILURE(rc))
2616 *pu8 = u8Def;
2617 return rc;
2618}
2619
2620
2621/**
2622 * Query signed 8-bit integer value.
2623 *
2624 * @returns VBox status code.
2625 * @param pNode Which node to search for pszName in.
2626 * @param pszName Name of an integer value.
2627 * @param pi8 Where to store the value.
2628 */
2629VMMR3DECL(int) CFGMR3QueryS8(PCFGMNODE pNode, const char *pszName, int8_t *pi8)
2630{
2631 uint64_t u64;
2632 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2633 if (RT_SUCCESS(rc))
2634 {
2635 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2636 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2637 *pi8 = (int8_t)u64;
2638 else
2639 rc = VERR_CFGM_INTEGER_TOO_BIG;
2640 }
2641 return rc;
2642}
2643
2644
2645/**
2646 * Query signed 8-bit integer value with default.
2647 *
2648 * @returns VBox status code.
2649 * @param pNode Which node to search for pszName in.
2650 * @param pszName Name of an integer value.
2651 * @param pi8 Where to store the value. Set to default on failure.
2652 * @param i8Def The default value.
2653 */
2654VMMR3DECL(int) CFGMR3QueryS8Def(PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)
2655{
2656 uint64_t u64;
2657 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i8Def);
2658 if (RT_SUCCESS(rc))
2659 {
2660 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2661 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2662 *pi8 = (int8_t)u64;
2663 else
2664 rc = VERR_CFGM_INTEGER_TOO_BIG;
2665 }
2666 if (RT_FAILURE(rc))
2667 *pi8 = i8Def;
2668 return rc;
2669}
2670
2671
2672/**
2673 * Query boolean integer value.
2674 *
2675 * @returns VBox status code.
2676 * @param pNode Which node to search for pszName in.
2677 * @param pszName Name of an integer value.
2678 * @param pf Where to store the value.
2679 * @remark This function will interpret any non-zero value as true.
2680 */
2681VMMR3DECL(int) CFGMR3QueryBool(PCFGMNODE pNode, const char *pszName, bool *pf)
2682{
2683 uint64_t u64;
2684 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2685 if (RT_SUCCESS(rc))
2686 *pf = u64 ? true : false;
2687 return rc;
2688}
2689
2690
2691/**
2692 * Query boolean integer value with default.
2693 *
2694 * @returns VBox status code.
2695 * @param pNode Which node to search for pszName in.
2696 * @param pszName Name of an integer value.
2697 * @param pf Where to store the value. Set to default on failure.
2698 * @param fDef The default value.
2699 * @remark This function will interpret any non-zero value as true.
2700 */
2701VMMR3DECL(int) CFGMR3QueryBoolDef(PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)
2702{
2703 uint64_t u64;
2704 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, fDef);
2705 *pf = u64 ? true : false;
2706 return rc;
2707}
2708
2709
2710/**
2711 * Query I/O port address value.
2712 *
2713 * @returns VBox status code.
2714 * @param pNode Which node to search for pszName in.
2715 * @param pszName Name of an integer value.
2716 * @param pPort Where to store the value.
2717 */
2718VMMR3DECL(int) CFGMR3QueryPort(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)
2719{
2720 AssertCompileSize(RTIOPORT, 2);
2721 return CFGMR3QueryU16(pNode, pszName, pPort);
2722}
2723
2724
2725/**
2726 * Query I/O port address value with default.
2727 *
2728 * @returns VBox status code.
2729 * @param pNode Which node to search for pszName in.
2730 * @param pszName Name of an integer value.
2731 * @param pPort Where to store the value. Set to default on failure.
2732 * @param PortDef The default value.
2733 */
2734VMMR3DECL(int) CFGMR3QueryPortDef(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)
2735{
2736 AssertCompileSize(RTIOPORT, 2);
2737 return CFGMR3QueryU16Def(pNode, pszName, pPort, PortDef);
2738}
2739
2740
2741/**
2742 * Query unsigned int address value.
2743 *
2744 * @returns VBox status code.
2745 * @param pNode Which node to search for pszName in.
2746 * @param pszName Name of an integer value.
2747 * @param pu Where to store the value.
2748 */
2749VMMR3DECL(int) CFGMR3QueryUInt(PCFGMNODE pNode, const char *pszName, unsigned int *pu)
2750{
2751 AssertCompileSize(unsigned int, 4);
2752 return CFGMR3QueryU32(pNode, pszName, (uint32_t *)pu);
2753}
2754
2755
2756/**
2757 * Query unsigned int address value with default.
2758 *
2759 * @returns VBox status code.
2760 * @param pNode Which node to search for pszName in.
2761 * @param pszName Name of an integer value.
2762 * @param pu Where to store the value. Set to default on failure.
2763 * @param uDef The default value.
2764 */
2765VMMR3DECL(int) CFGMR3QueryUIntDef(PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)
2766{
2767 AssertCompileSize(unsigned int, 4);
2768 return CFGMR3QueryU32Def(pNode, pszName, (uint32_t *)pu, uDef);
2769}
2770
2771
2772/**
2773 * Query signed int address value.
2774 *
2775 * @returns VBox status code.
2776 * @param pNode Which node to search for pszName in.
2777 * @param pszName Name of an integer value.
2778 * @param pi Where to store the value.
2779 */
2780VMMR3DECL(int) CFGMR3QuerySInt(PCFGMNODE pNode, const char *pszName, signed int *pi)
2781{
2782 AssertCompileSize(signed int, 4);
2783 return CFGMR3QueryS32(pNode, pszName, (int32_t *)pi);
2784}
2785
2786
2787/**
2788 * Query unsigned int address value with default.
2789 *
2790 * @returns VBox status code.
2791 * @param pNode Which node to search for pszName in.
2792 * @param pszName Name of an integer value.
2793 * @param pi Where to store the value. Set to default on failure.
2794 * @param iDef The default value.
2795 */
2796VMMR3DECL(int) CFGMR3QuerySIntDef(PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)
2797{
2798 AssertCompileSize(signed int, 4);
2799 return CFGMR3QueryS32Def(pNode, pszName, (int32_t *)pi, iDef);
2800}
2801
2802
2803/**
2804 * Query pointer integer value.
2805 *
2806 * @returns VBox status code.
2807 * @param pNode Which node to search for pszName in.
2808 * @param pszName Name of an integer value.
2809 * @param ppv Where to store the value.
2810 */
2811VMMR3DECL(int) CFGMR3QueryPtr(PCFGMNODE pNode, const char *pszName, void **ppv)
2812{
2813 uint64_t u64;
2814 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2815 if (RT_SUCCESS(rc))
2816 {
2817 uintptr_t u = (uintptr_t)u64;
2818 if (u64 == u)
2819 *ppv = (void *)u;
2820 else
2821 rc = VERR_CFGM_INTEGER_TOO_BIG;
2822 }
2823 return rc;
2824}
2825
2826
2827/**
2828 * Query pointer integer value with default.
2829 *
2830 * @returns VBox status code.
2831 * @param pNode Which node to search for pszName in.
2832 * @param pszName Name of an integer value.
2833 * @param ppv Where to store the value. Set to default on failure.
2834 * @param pvDef The default value.
2835 */
2836VMMR3DECL(int) CFGMR3QueryPtrDef(PCFGMNODE pNode, const char *pszName, void **ppv, void *pvDef)
2837{
2838 uint64_t u64;
2839 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, (uintptr_t)pvDef);
2840 if (RT_SUCCESS(rc))
2841 {
2842 uintptr_t u = (uintptr_t)u64;
2843 if (u64 == u)
2844 *ppv = (void *)u;
2845 else
2846 rc = VERR_CFGM_INTEGER_TOO_BIG;
2847 }
2848 if (RT_FAILURE(rc))
2849 *ppv = pvDef;
2850 return rc;
2851}
2852
2853
2854/**
2855 * Query Guest Context pointer integer value.
2856 *
2857 * @returns VBox status code.
2858 * @param pNode Which node to search for pszName in.
2859 * @param pszName Name of an integer value.
2860 * @param pGCPtr Where to store the value.
2861 */
2862VMMR3DECL(int) CFGMR3QueryGCPtr(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)
2863{
2864 uint64_t u64;
2865 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2866 if (RT_SUCCESS(rc))
2867 {
2868 RTGCPTR u = (RTGCPTR)u64;
2869 if (u64 == u)
2870 *pGCPtr = u;
2871 else
2872 rc = VERR_CFGM_INTEGER_TOO_BIG;
2873 }
2874 return rc;
2875}
2876
2877
2878/**
2879 * Query Guest Context pointer integer value with default.
2880 *
2881 * @returns VBox status code.
2882 * @param pNode Which node to search for pszName in.
2883 * @param pszName Name of an integer value.
2884 * @param pGCPtr Where to store the value. Set to default on failure.
2885 * @param GCPtrDef The default value.
2886 */
2887VMMR3DECL(int) CFGMR3QueryGCPtrDef(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)
2888{
2889 uint64_t u64;
2890 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2891 if (RT_SUCCESS(rc))
2892 {
2893 RTGCPTR u = (RTGCPTR)u64;
2894 if (u64 == u)
2895 *pGCPtr = u;
2896 else
2897 rc = VERR_CFGM_INTEGER_TOO_BIG;
2898 }
2899 if (RT_FAILURE(rc))
2900 *pGCPtr = GCPtrDef;
2901 return rc;
2902}
2903
2904
2905/**
2906 * Query Guest Context unsigned pointer value.
2907 *
2908 * @returns VBox status code.
2909 * @param pNode Which node to search for pszName in.
2910 * @param pszName Name of an integer value.
2911 * @param pGCPtr Where to store the value.
2912 */
2913VMMR3DECL(int) CFGMR3QueryGCPtrU(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)
2914{
2915 uint64_t u64;
2916 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2917 if (RT_SUCCESS(rc))
2918 {
2919 RTGCUINTPTR u = (RTGCUINTPTR)u64;
2920 if (u64 == u)
2921 *pGCPtr = u;
2922 else
2923 rc = VERR_CFGM_INTEGER_TOO_BIG;
2924 }
2925 return rc;
2926}
2927
2928
2929/**
2930 * Query Guest Context unsigned pointer value with default.
2931 *
2932 * @returns VBox status code.
2933 * @param pNode Which node to search for pszName in.
2934 * @param pszName Name of an integer value.
2935 * @param pGCPtr Where to store the value. Set to default on failure.
2936 * @param GCPtrDef The default value.
2937 */
2938VMMR3DECL(int) CFGMR3QueryGCPtrUDef(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)
2939{
2940 uint64_t u64;
2941 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2942 if (RT_SUCCESS(rc))
2943 {
2944 RTGCUINTPTR u = (RTGCUINTPTR)u64;
2945 if (u64 == u)
2946 *pGCPtr = u;
2947 else
2948 rc = VERR_CFGM_INTEGER_TOO_BIG;
2949 }
2950 if (RT_FAILURE(rc))
2951 *pGCPtr = GCPtrDef;
2952 return rc;
2953}
2954
2955
2956/**
2957 * Query Guest Context signed pointer value.
2958 *
2959 * @returns VBox status code.
2960 * @param pNode Which node to search for pszName in.
2961 * @param pszName Name of an integer value.
2962 * @param pGCPtr Where to store the value.
2963 */
2964VMMR3DECL(int) CFGMR3QueryGCPtrS(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)
2965{
2966 uint64_t u64;
2967 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2968 if (RT_SUCCESS(rc))
2969 {
2970 RTGCINTPTR u = (RTGCINTPTR)u64;
2971 if (u64 == (uint64_t)u)
2972 *pGCPtr = u;
2973 else
2974 rc = VERR_CFGM_INTEGER_TOO_BIG;
2975 }
2976 return rc;
2977}
2978
2979
2980/**
2981 * Query Guest Context signed pointer value with default.
2982 *
2983 * @returns VBox status code.
2984 * @param pNode Which node to search for pszName in.
2985 * @param pszName Name of an integer value.
2986 * @param pGCPtr Where to store the value. Set to default on failure.
2987 * @param GCPtrDef The default value.
2988 */
2989VMMR3DECL(int) CFGMR3QueryGCPtrSDef(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)
2990{
2991 uint64_t u64;
2992 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2993 if (RT_SUCCESS(rc))
2994 {
2995 RTGCINTPTR u = (RTGCINTPTR)u64;
2996 if (u64 == (uint64_t)u)
2997 *pGCPtr = u;
2998 else
2999 rc = VERR_CFGM_INTEGER_TOO_BIG;
3000 }
3001 if (RT_FAILURE(rc))
3002 *pGCPtr = GCPtrDef;
3003 return rc;
3004}
3005
3006
3007/**
3008 * Query zero terminated character value storing it in a
3009 * buffer allocated from the MM heap.
3010 *
3011 * @returns VBox status code.
3012 * @param pNode Which node to search for pszName in.
3013 * @param pszName Value name. This value must be of zero terminated character string type.
3014 * @param ppszString Where to store the string pointer.
3015 * Free this using MMR3HeapFree() (or RTStrFree if not
3016 * associated with a pUVM - see CFGMR3CreateTree).
3017 */
3018VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
3019{
3020 size_t cbString;
3021 int rc = CFGMR3QuerySize(pNode, pszName, &cbString);
3022 if (RT_SUCCESS(rc))
3023 {
3024 char *pszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbString);
3025 if (pszString)
3026 {
3027 rc = CFGMR3QueryString(pNode, pszName, pszString, cbString);
3028 if (RT_SUCCESS(rc))
3029 *ppszString = pszString;
3030 else
3031 cfgmR3StrFree(pNode->pVM, pszString);
3032 }
3033 else
3034 rc = VERR_NO_MEMORY;
3035 }
3036 return rc;
3037}
3038
3039
3040/**
3041 * Query zero terminated character value storing it in a
3042 * buffer allocated from the MM heap.
3043 *
3044 * @returns VBox status code.
3045 * @param pNode Which node to search for pszName in. This cannot be
3046 * NULL if @a pszDef is not NULL, because we need
3047 * somewhere way to get to the VM in order to call
3048 * MMR3HeapStrDup.
3049 * @param pszName Value name. This value must be of zero terminated character string type.
3050 * @param ppszString Where to store the string pointer. Not set on failure.
3051 * Free this using MMR3HeapFree() (or RTStrFree if not
3052 * associated with a pUVM - see CFGMR3CreateTree).
3053 * @param pszDef The default return value. This can be NULL.
3054 */
3055VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)
3056{
3057 Assert(pNode || !pszDef); /* We need pVM if we need to duplicate the string later. */
3058
3059 /*
3060 * (Don't call CFGMR3QuerySize and CFGMR3QueryStringDef here as the latter
3061 * cannot handle pszDef being NULL.)
3062 */
3063 PCFGMLEAF pLeaf;
3064 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
3065 if (RT_SUCCESS(rc))
3066 {
3067 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
3068 {
3069 size_t const cbSrc = pLeaf->Value.String.cb;
3070 char *pszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbSrc);
3071 if (pszString)
3072 {
3073 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
3074 *ppszString = pszString;
3075 }
3076 else
3077 rc = VERR_NO_MEMORY;
3078 }
3079 else
3080 rc = VERR_CFGM_NOT_STRING;
3081 }
3082 if (RT_FAILURE(rc))
3083 {
3084 if (!pszDef)
3085 *ppszString = NULL;
3086 else
3087 {
3088 size_t const cbDef = strlen(pszDef) + 1;
3089 *ppszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbDef);
3090 memcpy(*ppszString, pszDef, cbDef);
3091 }
3092 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
3093 rc = VINF_SUCCESS;
3094 }
3095
3096 return rc;
3097}
3098
3099
3100/**
3101 * Dumps the configuration (sub)tree to the release log.
3102 *
3103 * @param pRoot The root node of the dump.
3104 */
3105VMMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot)
3106{
3107 bool fOldBuffered = RTLogRelSetBuffering(true /*fBuffered*/);
3108 LogRel(("************************* CFGM dump *************************\n"));
3109 cfgmR3Dump(pRoot, 0, DBGFR3InfoLogRelHlp());
3110 LogRel(("********************* End of CFGM dump **********************\n"));
3111 RTLogRelSetBuffering(fOldBuffered);
3112}
3113
3114
3115/**
3116 * Info handler, internal version.
3117 *
3118 * @param pVM Pointer to the VM.
3119 * @param pHlp Callback functions for doing output.
3120 * @param pszArgs Argument string. Optional and specific to the handler.
3121 */
3122static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
3123{
3124 /*
3125 * Figure where to start.
3126 */
3127 PCFGMNODE pRoot = pVM->cfgm.s.pRoot;
3128 if (pszArgs && *pszArgs)
3129 {
3130 int rc = cfgmR3ResolveNode(pRoot, pszArgs, &pRoot);
3131 if (RT_FAILURE(rc))
3132 {
3133 pHlp->pfnPrintf(pHlp, "Failed to resolve CFGM path '%s', %Rrc", pszArgs, rc);
3134 return;
3135 }
3136 }
3137
3138 /*
3139 * Dump the specified tree.
3140 */
3141 pHlp->pfnPrintf(pHlp, "pRoot=%p:{", pRoot);
3142 cfgmR3DumpPath(pRoot, pHlp);
3143 pHlp->pfnPrintf(pHlp, "}\n");
3144 cfgmR3Dump(pRoot, 0, pHlp);
3145}
3146
3147
3148/**
3149 * Recursively prints a path name.
3150 */
3151static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp)
3152{
3153 if (pNode->pParent)
3154 cfgmR3DumpPath(pNode->pParent, pHlp);
3155 pHlp->pfnPrintf(pHlp, "%s/", pNode->szName);
3156}
3157
3158
3159/**
3160 * Dumps a branch of a tree.
3161 */
3162static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp)
3163{
3164 /*
3165 * Path.
3166 */
3167 pHlp->pfnPrintf(pHlp, "[");
3168 cfgmR3DumpPath(pRoot, pHlp);
3169 pHlp->pfnPrintf(pHlp, "] (level %d)%s\n", iLevel, pRoot->fRestrictedRoot ? " (restricted root)" : "");
3170
3171 /*
3172 * Values.
3173 */
3174 PCFGMLEAF pLeaf;
3175 size_t cchMax = 0;
3176 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
3177 cchMax = RT_MAX(cchMax, pLeaf->cchName);
3178 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
3179 {
3180 switch (CFGMR3GetValueType(pLeaf))
3181 {
3182 case CFGMVALUETYPE_INTEGER:
3183 {
3184 pHlp->pfnPrintf(pHlp, " %-*s <integer> = %#018llx (%'lld", (int)cchMax, pLeaf->szName, pLeaf->Value.Integer.u64, pLeaf->Value.Integer.u64);
3185 if ( ( pLeaf->cchName >= 4
3186 && !RTStrCmp(&pLeaf->szName[pLeaf->cchName - 4], "Size"))
3187 || ( pLeaf->cchName >= 2
3188 && !RTStrNCmp(pLeaf->szName, "cb", 2)) )
3189 {
3190 if (pLeaf->Value.Integer.u64 > _2G)
3191 pHlp->pfnPrintf(pHlp, ", %'lld GB", pLeaf->Value.Integer.u64 / _1G);
3192 else if (pLeaf->Value.Integer.u64 > _2M)
3193 pHlp->pfnPrintf(pHlp, ", %'lld MB", pLeaf->Value.Integer.u64 / _1M);
3194 else if (pLeaf->Value.Integer.u64 > _2K)
3195 pHlp->pfnPrintf(pHlp, ", %'lld KB", pLeaf->Value.Integer.u64 / _1K);
3196 }
3197 pHlp->pfnPrintf(pHlp, ")\n");
3198 break;
3199 }
3200
3201 case CFGMVALUETYPE_STRING:
3202 pHlp->pfnPrintf(pHlp, " %-*s <string> = \"%s\" (cb=%zu)\n", (int)cchMax, pLeaf->szName, pLeaf->Value.String.psz, pLeaf->Value.String.cb);
3203 break;
3204
3205 case CFGMVALUETYPE_BYTES:
3206 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);
3207 break;
3208
3209 default:
3210 AssertMsgFailed(("bad leaf!\n"));
3211 break;
3212 }
3213 }
3214 pHlp->pfnPrintf(pHlp, "\n");
3215
3216 /*
3217 * Children.
3218 */
3219 for (PCFGMNODE pChild = CFGMR3GetFirstChild(pRoot); pChild; pChild = CFGMR3GetNextChild(pChild))
3220 {
3221 Assert(pChild->pNext != pChild);
3222 Assert(pChild->pPrev != pChild);
3223 Assert(pChild->pPrev != pChild->pNext || !pChild->pPrev);
3224 Assert(pChild->pFirstChild != pChild);
3225 Assert(pChild->pParent == pRoot);
3226 cfgmR3Dump(pChild, iLevel + 1, pHlp);
3227 }
3228}
3229
Note: See TracBrowser for help on using the repository browser.

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