VirtualBox

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

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

CFGM: Added CFGMR3Exists for TM.

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