VirtualBox

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

Last change on this file since 57329 was 56719, checked in by vboxsync, 9 years ago

tstVMREQ: mac fix (no raw-mode)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 96.1 KB
Line 
1/* $Id: CFGM.cpp 56719 2015-07-01 05:06:06Z vboxsync $ */
2/** @file
3 * CFGM - Configuration Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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 leaves 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 * VMMDev.
1188 */
1189 rc = CFGMR3InsertNode(pDevices, "VMMDev", &pDev);
1190 UPDATERC();
1191 rc = CFGMR3InsertNode(pDev, "0", &pInst);
1192 UPDATERC();
1193 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
1194 UPDATERC();
1195 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
1196 UPDATERC();
1197 rc = CFGMR3InsertInteger(pCfg, "RamSize", 128U * _1M);
1198 UPDATERC();
1199
1200
1201 /*
1202 * ...
1203 */
1204
1205#undef UPDATERC
1206 return rcAll;
1207}
1208
1209
1210
1211
1212/**
1213 * Resolves a path reference to a child node.
1214 *
1215 * @returns VBox status code.
1216 * @param pNode Which node to search for pszName in.
1217 * @param pszPath Path to the child node.
1218 * @param ppChild Where to store the pointer to the child node.
1219 */
1220static int cfgmR3ResolveNode(PCFGMNODE pNode, const char *pszPath, PCFGMNODE *ppChild)
1221{
1222 *ppChild = NULL;
1223 if (!pNode)
1224 return VERR_CFGM_NO_PARENT;
1225 PCFGMNODE pChild = NULL;
1226 for (;;)
1227 {
1228 /* skip leading slashes. */
1229 while (*pszPath == '/')
1230 pszPath++;
1231
1232 /* End of path? */
1233 if (!*pszPath)
1234 {
1235 if (!pChild)
1236 return VERR_CFGM_INVALID_CHILD_PATH;
1237 *ppChild = pChild;
1238 return VINF_SUCCESS;
1239 }
1240
1241 /* find end of component. */
1242 const char *pszNext = strchr(pszPath, '/');
1243 if (!pszNext)
1244 pszNext = strchr(pszPath, '\0');
1245 RTUINT cchName = pszNext - pszPath;
1246
1247 /* search child list. */
1248 pChild = pNode->pFirstChild;
1249 for ( ; pChild; pChild = pChild->pNext)
1250 if (pChild->cchName == cchName)
1251 {
1252 int iDiff = memcmp(pszPath, pChild->szName, cchName);
1253 if (iDiff <= 0)
1254 {
1255 if (iDiff != 0)
1256 pChild = NULL;
1257 break;
1258 }
1259 }
1260 if (!pChild)
1261 return VERR_CFGM_CHILD_NOT_FOUND;
1262
1263 /* next iteration */
1264 pNode = pChild;
1265 pszPath = pszNext;
1266 }
1267
1268 /* won't get here */
1269}
1270
1271
1272/**
1273 * Resolves a path reference to a child node.
1274 *
1275 * @returns VBox status code.
1276 * @param pNode Which node to search for pszName in.
1277 * @param pszName Name of a byte string value.
1278 * @param ppLeaf Where to store the pointer to the leaf node.
1279 */
1280static int cfgmR3ResolveLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1281{
1282 *ppLeaf = NULL;
1283 if (!pNode)
1284 return VERR_CFGM_NO_PARENT;
1285
1286 size_t cchName = strlen(pszName);
1287 PCFGMLEAF pLeaf = pNode->pFirstLeaf;
1288 while (pLeaf)
1289 {
1290 if (cchName == pLeaf->cchName)
1291 {
1292 int iDiff = memcmp(pszName, pLeaf->szName, cchName);
1293 if (iDiff <= 0)
1294 {
1295 if (iDiff != 0)
1296 break;
1297 *ppLeaf = pLeaf;
1298 return VINF_SUCCESS;
1299 }
1300 }
1301
1302 /* next */
1303 pLeaf = pLeaf->pNext;
1304 }
1305 return VERR_CFGM_VALUE_NOT_FOUND;
1306}
1307
1308
1309
1310/**
1311 * Creates a CFGM tree.
1312 *
1313 * This is intended for creating device/driver configs can be
1314 * passed around and later attached to the main tree in the
1315 * correct location.
1316 *
1317 * @returns Pointer to the root node, NULL on error (out of memory or invalid
1318 * VM handle).
1319 * @param pUVM The user mode VM handle. For testcase (and other
1320 * purposes, NULL can be used. However, the resulting
1321 * tree cannot be inserted into a tree that has a
1322 * non-NULL value. Using NULL can be usedful for
1323 * testcases and similar, non VMM uses.
1324 */
1325VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PUVM pUVM)
1326{
1327 if (pUVM)
1328 {
1329 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
1330 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
1331 }
1332
1333 PCFGMNODE pNew;
1334 if (pUVM)
1335 pNew = (PCFGMNODE)MMR3HeapAllocU(pUVM, MM_TAG_CFGM, sizeof(*pNew));
1336 else
1337 pNew = (PCFGMNODE)RTMemAlloc(sizeof(*pNew));
1338 if (pNew)
1339 {
1340 pNew->pPrev = NULL;
1341 pNew->pNext = NULL;
1342 pNew->pParent = NULL;
1343 pNew->pFirstChild = NULL;
1344 pNew->pFirstLeaf = NULL;
1345 pNew->pVM = pUVM ? pUVM->pVM : NULL;
1346 pNew->fRestrictedRoot = false;
1347 pNew->cchName = 0;
1348 pNew->szName[0] = 0;
1349 }
1350 return pNew;
1351}
1352
1353
1354/**
1355 * Duplicates a CFGM sub-tree or a full tree.
1356 *
1357 * @returns Pointer to the root node. NULL if we run out of memory or the
1358 * input parameter is NULL.
1359 * @param pRoot The root of the tree to duplicate.
1360 * @param ppCopy Where to return the root of the duplicate.
1361 */
1362VMMR3DECL(int) CFGMR3DuplicateSubTree(PCFGMNODE pRoot, PCFGMNODE *ppCopy)
1363{
1364 AssertPtrReturn(pRoot, VERR_INVALID_POINTER);
1365
1366 /*
1367 * Create a new tree.
1368 */
1369 PCFGMNODE pNewRoot = CFGMR3CreateTree(pRoot->pVM ? pRoot->pVM->pUVM : NULL);
1370 if (!pNewRoot)
1371 return VERR_NO_MEMORY;
1372
1373 /*
1374 * Duplicate the content.
1375 */
1376 int rc = VINF_SUCCESS;
1377 PCFGMNODE pSrcCur = pRoot;
1378 PCFGMNODE pDstCur = pNewRoot;
1379 for (;;)
1380 {
1381 if ( !pDstCur->pFirstChild
1382 && !pDstCur->pFirstLeaf)
1383 {
1384 /*
1385 * Values first.
1386 */
1387 /** @todo this isn't the most efficient way to do it. */
1388 for (PCFGMLEAF pLeaf = pSrcCur->pFirstLeaf; pLeaf && RT_SUCCESS(rc); pLeaf = pLeaf->pNext)
1389 rc = CFGMR3InsertValue(pDstCur, pLeaf);
1390
1391 /*
1392 * Insert immediate child nodes.
1393 */
1394 /** @todo this isn't the most efficient way to do it. */
1395 for (PCFGMNODE pChild = pSrcCur->pFirstChild; pChild && RT_SUCCESS(rc); pChild = pChild->pNext)
1396 rc = CFGMR3InsertNode(pDstCur, pChild->szName, NULL);
1397
1398 AssertLogRelRCBreak(rc);
1399 }
1400
1401 /*
1402 * Deep copy of the children.
1403 */
1404 if (pSrcCur->pFirstChild)
1405 {
1406 Assert(pDstCur->pFirstChild && !strcmp(pDstCur->pFirstChild->szName, pSrcCur->pFirstChild->szName));
1407 pSrcCur = pSrcCur->pFirstChild;
1408 pDstCur = pDstCur->pFirstChild;
1409 }
1410 /*
1411 * If it's the root node, we're done.
1412 */
1413 else if (pSrcCur == pRoot)
1414 break;
1415 else
1416 {
1417 /*
1418 * Upon reaching the end of a sibling list, we must ascend and
1419 * resume the sibiling walk on an previous level.
1420 */
1421 if (!pSrcCur->pNext)
1422 {
1423 do
1424 {
1425 pSrcCur = pSrcCur->pParent;
1426 pDstCur = pDstCur->pParent;
1427 } while (!pSrcCur->pNext && pSrcCur != pRoot);
1428 if (pSrcCur == pRoot)
1429 break;
1430 }
1431
1432 /*
1433 * Next sibling.
1434 */
1435 Assert(pDstCur->pNext && !strcmp(pDstCur->pNext->szName, pSrcCur->pNext->szName));
1436 pSrcCur = pSrcCur->pNext;
1437 pDstCur = pDstCur->pNext;
1438 }
1439 }
1440
1441 if (RT_FAILURE(rc))
1442 {
1443 CFGMR3RemoveNode(pNewRoot);
1444 return rc;
1445 }
1446
1447 *ppCopy = pNewRoot;
1448 return VINF_SUCCESS;
1449}
1450
1451
1452/**
1453 * Insert subtree.
1454 *
1455 * This function inserts (no duplication) a tree created by CFGMR3CreateTree()
1456 * into the main tree.
1457 *
1458 * The root node of the inserted subtree will need to be reallocated, which
1459 * effectually means that the passed in pSubTree handle becomes invalid
1460 * upon successful return. Use the value returned in ppChild instead
1461 * of pSubTree.
1462 *
1463 * @returns VBox status code.
1464 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1465 * @param pNode Parent node.
1466 * @param pszName Name or path of the new child node.
1467 * @param pSubTree The subtree to insert. Must be returned by CFGMR3CreateTree().
1468 * @param ppChild Where to store the address of the new child node. (optional)
1469 */
1470VMMR3DECL(int) CFGMR3InsertSubTree(PCFGMNODE pNode, const char *pszName, PCFGMNODE pSubTree, PCFGMNODE *ppChild)
1471{
1472 /*
1473 * Validate input.
1474 */
1475 AssertPtrReturn(pNode, VERR_INVALID_POINTER);
1476 AssertPtrReturn(pSubTree, VERR_INVALID_POINTER);
1477 AssertReturn(pNode != pSubTree, VERR_INVALID_PARAMETER);
1478 AssertReturn(!pSubTree->pParent, VERR_INVALID_PARAMETER);
1479 AssertReturn(pNode->pVM == pSubTree->pVM, VERR_INVALID_PARAMETER);
1480 Assert(!pSubTree->pNext);
1481 Assert(!pSubTree->pPrev);
1482
1483 /*
1484 * Use CFGMR3InsertNode to create a new node and then
1485 * re-attach the children and leaves of the subtree to it.
1486 */
1487 PCFGMNODE pNewChild;
1488 int rc = CFGMR3InsertNode(pNode, pszName, &pNewChild);
1489 if (RT_SUCCESS(rc))
1490 {
1491 Assert(!pNewChild->pFirstChild);
1492 Assert(!pNewChild->pFirstLeaf);
1493
1494 pNewChild->pFirstChild = pSubTree->pFirstChild;
1495 pNewChild->pFirstLeaf = pSubTree->pFirstLeaf;
1496 for (PCFGMNODE pChild = pNewChild->pFirstChild; pChild; pChild = pChild->pNext)
1497 pChild->pParent = pNewChild;
1498
1499 if (ppChild)
1500 *ppChild = pNewChild;
1501
1502 /* free the old subtree root */
1503 cfgmR3FreeNodeOnly(pSubTree);
1504 }
1505 return rc;
1506}
1507
1508
1509/**
1510 * Replaces a (sub-)tree with new one.
1511 *
1512 * This function removes the exiting (sub-)tree, completely freeing it in the
1513 * process, and inserts (no duplication) the specified tree. The tree can
1514 * either be created by CFGMR3CreateTree or CFGMR3DuplicateSubTree.
1515 *
1516 * @returns VBox status code.
1517 * @param pRoot The sub-tree to replace. This node will remain valid
1518 * after the call.
1519 * @param pNewRoot The tree to replace @a pRoot with. This not will
1520 * become invalid after a successful call.
1521 */
1522VMMR3DECL(int) CFGMR3ReplaceSubTree(PCFGMNODE pRoot, PCFGMNODE pNewRoot)
1523{
1524 /*
1525 * Validate input.
1526 */
1527 AssertPtrReturn(pRoot, VERR_INVALID_POINTER);
1528 AssertPtrReturn(pNewRoot, VERR_INVALID_POINTER);
1529 AssertReturn(pRoot != pNewRoot, VERR_INVALID_PARAMETER);
1530 AssertReturn(!pNewRoot->pParent, VERR_INVALID_PARAMETER);
1531 AssertReturn(pNewRoot->pVM == pRoot->pVM, VERR_INVALID_PARAMETER);
1532 AssertReturn(!pNewRoot->pNext, VERR_INVALID_PARAMETER);
1533 AssertReturn(!pNewRoot->pPrev, VERR_INVALID_PARAMETER);
1534
1535 /*
1536 * Free the current properties fo pRoot.
1537 */
1538 while (pRoot->pFirstChild)
1539 CFGMR3RemoveNode(pRoot->pFirstChild);
1540
1541 while (pRoot->pFirstLeaf)
1542 cfgmR3RemoveLeaf(pRoot, pRoot->pFirstLeaf);
1543
1544 /*
1545 * Copy all the properties from the new root to the current one.
1546 */
1547 pRoot->pFirstLeaf = pNewRoot->pFirstLeaf;
1548 pRoot->pFirstChild = pNewRoot->pFirstChild;
1549 for (PCFGMNODE pChild = pRoot->pFirstChild; pChild; pChild = pChild->pNext)
1550 pChild->pParent = pRoot;
1551
1552 cfgmR3FreeNodeOnly(pNewRoot);
1553
1554 return VINF_SUCCESS;
1555}
1556
1557
1558/**
1559 * Copies all values and keys from one tree onto another.
1560 *
1561 * The flags control what happens to keys and values with the same name
1562 * existing in both source and destination.
1563 *
1564 * @returns VBox status code.
1565 * @param pDstTree The destination tree.
1566 * @param pSrcTree The source tree.
1567 * @param fFlags Copy flags, see CFGM_COPY_FLAGS_XXX.
1568 */
1569VMMR3DECL(int) CFGMR3CopyTree(PCFGMNODE pDstTree, PCFGMNODE pSrcTree, uint32_t fFlags)
1570{
1571 /*
1572 * Input validation.
1573 */
1574 AssertPtrReturn(pSrcTree, VERR_INVALID_POINTER);
1575 AssertPtrReturn(pDstTree, VERR_INVALID_POINTER);
1576 AssertReturn(pDstTree != pSrcTree, VERR_INVALID_PARAMETER);
1577 AssertReturn(!(fFlags & ~(CFGM_COPY_FLAGS_VALUE_DISP_MASK | CFGM_COPY_FLAGS_KEY_DISP_MASK)), VERR_INVALID_PARAMETER);
1578 AssertReturn( (fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_0
1579 && (fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_1,
1580 VERR_INVALID_PARAMETER);
1581 AssertReturn((fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) != CFGM_COPY_FLAGS_RESERVED_KEY_DISP,
1582 VERR_INVALID_PARAMETER);
1583
1584 /*
1585 * Copy the values.
1586 */
1587 int rc;
1588 for (PCFGMLEAF pValue = CFGMR3GetFirstValue(pSrcTree); pValue; pValue = CFGMR3GetNextValue(pValue))
1589 {
1590 rc = CFGMR3InsertValue(pDstTree, pValue);
1591 if (rc == VERR_CFGM_LEAF_EXISTS)
1592 {
1593 if ((fFlags & CFGM_COPY_FLAGS_VALUE_DISP_MASK) == CFGM_COPY_FLAGS_REPLACE_VALUES)
1594 {
1595 rc = CFGMR3RemoveValue(pDstTree, pValue->szName);
1596 if (RT_FAILURE(rc))
1597 break;
1598 rc = CFGMR3InsertValue(pDstTree, pValue);
1599 }
1600 else
1601 rc = VINF_SUCCESS;
1602 }
1603 AssertRCReturn(rc, rc);
1604 }
1605
1606 /*
1607 * Copy/merge the keys - merging results in recursion.
1608 */
1609 for (PCFGMNODE pSrcChild = CFGMR3GetFirstChild(pSrcTree); pSrcChild; pSrcChild = CFGMR3GetNextChild(pSrcChild))
1610 {
1611 PCFGMNODE pDstChild = CFGMR3GetChild(pDstTree, pSrcChild->szName);
1612 if ( pDstChild
1613 && (fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) == CFGM_COPY_FLAGS_REPLACE_KEYS)
1614 {
1615 CFGMR3RemoveNode(pDstChild);
1616 pDstChild = NULL;
1617 }
1618 if (!pDstChild)
1619 {
1620 PCFGMNODE pChildCopy;
1621 rc = CFGMR3DuplicateSubTree(pSrcChild, &pChildCopy);
1622 AssertRCReturn(rc, rc);
1623 rc = CFGMR3InsertSubTree(pDstTree, pSrcChild->szName, pChildCopy, NULL);
1624 AssertRCReturnStmt(rc, CFGMR3RemoveNode(pChildCopy), rc);
1625 }
1626 else if ((fFlags & CFGM_COPY_FLAGS_KEY_DISP_MASK) == CFGM_COPY_FLAGS_MERGE_KEYS)
1627 {
1628 rc = CFGMR3CopyTree(pDstChild, pSrcChild, fFlags);
1629 AssertRCReturn(rc, rc);
1630 }
1631 }
1632
1633 return VINF_SUCCESS;
1634}
1635
1636
1637
1638/**
1639 * Compares two names.
1640 *
1641 * @returns Similar to memcpy.
1642 * @param pszName1 The first name.
1643 * @param cchName1 The length of the first name.
1644 * @param pszName2 The second name.
1645 * @param cchName2 The length of the second name.
1646 */
1647DECLINLINE(int) cfgmR3CompareNames(const char *pszName1, size_t cchName1, const char *pszName2, size_t cchName2)
1648{
1649 int iDiff;
1650 if (cchName1 <= cchName2)
1651 {
1652 iDiff = memcmp(pszName1, pszName2, cchName1);
1653 if (!iDiff && cchName1 < cchName2)
1654 iDiff = -1;
1655 }
1656 else
1657 {
1658 iDiff = memcmp(pszName1, pszName2, cchName2);
1659 if (!iDiff)
1660 iDiff = 1;
1661 }
1662 return iDiff;
1663}
1664
1665
1666/**
1667 * Insert a node.
1668 *
1669 * @returns VBox status code.
1670 * @returns VERR_CFGM_NODE_EXISTS if the final child node name component exists.
1671 * @param pNode Parent node.
1672 * @param pszName Name or path of the new child node.
1673 * @param ppChild Where to store the address of the new child node. (optional)
1674 */
1675VMMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild)
1676{
1677 int rc;
1678 if (pNode)
1679 {
1680 /*
1681 * If given a path we have to deal with it component by component.
1682 */
1683 while (*pszName == '/')
1684 pszName++;
1685 if (strchr(pszName, '/'))
1686 {
1687 char *pszDup = RTStrDup(pszName);
1688 if (pszDup)
1689 {
1690 char *psz = pszDup;
1691 for (;;)
1692 {
1693 /* Terminate at '/' and find the next component. */
1694 char *pszNext = strchr(psz, '/');
1695 if (pszNext)
1696 {
1697 *pszNext++ = '\0';
1698 while (*pszNext == '/')
1699 pszNext++;
1700 if (*pszNext == '\0')
1701 pszNext = NULL;
1702 }
1703
1704 /* does it exist? */
1705 PCFGMNODE pChild = CFGMR3GetChild(pNode, psz);
1706 if (!pChild)
1707 {
1708 /* no, insert it */
1709 rc = CFGMR3InsertNode(pNode, psz, &pChild);
1710 if (RT_FAILURE(rc))
1711 break;
1712 if (!pszNext)
1713 {
1714 if (ppChild)
1715 *ppChild = pChild;
1716 break;
1717 }
1718
1719 }
1720 /* if last component fail */
1721 else if (!pszNext)
1722 {
1723 rc = VERR_CFGM_NODE_EXISTS;
1724 break;
1725 }
1726
1727 /* next */
1728 pNode = pChild;
1729 psz = pszNext;
1730 }
1731 RTStrFree(pszDup);
1732 }
1733 else
1734 rc = VERR_NO_TMP_MEMORY;
1735 }
1736 /*
1737 * Not multicomponent, just make sure it's a non-zero name.
1738 */
1739 else if (*pszName)
1740 {
1741 /*
1742 * Check if already exists and find last node in chain.
1743 */
1744 size_t cchName = strlen(pszName);
1745 PCFGMNODE pPrev = NULL;
1746 PCFGMNODE pNext = pNode->pFirstChild;
1747 if (pNext)
1748 {
1749 for ( ; pNext; pPrev = pNext, pNext = pNext->pNext)
1750 {
1751 int iDiff = cfgmR3CompareNames(pszName, cchName, pNext->szName, pNext->cchName);
1752 if (iDiff <= 0)
1753 {
1754 if (!iDiff)
1755 return VERR_CFGM_NODE_EXISTS;
1756 break;
1757 }
1758 }
1759 }
1760
1761 /*
1762 * Allocate and init node.
1763 */
1764 PCFGMNODE pNew = (PCFGMNODE)cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1765 if (pNew)
1766 {
1767 pNew->pParent = pNode;
1768 pNew->pFirstChild = NULL;
1769 pNew->pFirstLeaf = NULL;
1770 pNew->pVM = pNode->pVM;
1771 pNew->fRestrictedRoot = false;
1772 pNew->cchName = cchName;
1773 memcpy(pNew->szName, pszName, cchName + 1);
1774
1775 /*
1776 * Insert into child list.
1777 */
1778 pNew->pPrev = pPrev;
1779 if (pPrev)
1780 pPrev->pNext = pNew;
1781 else
1782 pNode->pFirstChild = pNew;
1783 pNew->pNext = pNext;
1784 if (pNext)
1785 pNext->pPrev = pNew;
1786
1787 if (ppChild)
1788 *ppChild = pNew;
1789 rc = VINF_SUCCESS;
1790 }
1791 else
1792 rc = VERR_NO_MEMORY;
1793 }
1794 else
1795 {
1796 rc = VERR_CFGM_INVALID_NODE_PATH;
1797 AssertMsgFailed(("Invalid path %s\n", pszName));
1798 }
1799 }
1800 else
1801 {
1802 rc = VERR_CFGM_NO_PARENT;
1803 AssertMsgFailed(("No parent! path %s\n", pszName));
1804 }
1805
1806 return rc;
1807}
1808
1809
1810/**
1811 * Insert a node, format string name.
1812 *
1813 * @returns VBox status code.
1814 * @param pNode Parent node.
1815 * @param ppChild Where to store the address of the new child node. (optional)
1816 * @param pszNameFormat Name of or path the new child node.
1817 * @param ... Name format arguments.
1818 */
1819VMMR3DECL(int) CFGMR3InsertNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...)
1820{
1821 va_list Args;
1822 va_start(Args, pszNameFormat);
1823 int rc = CFGMR3InsertNodeFV(pNode, ppChild, pszNameFormat, Args);
1824 va_end(Args);
1825 return rc;
1826}
1827
1828
1829/**
1830 * Insert a node, format string name.
1831 *
1832 * @returns VBox status code.
1833 * @param pNode Parent node.
1834 * @param ppChild Where to store the address of the new child node. (optional)
1835 * @param pszNameFormat Name or path of the new child node.
1836 * @param Args Name format arguments.
1837 */
1838VMMR3DECL(int) CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, va_list Args)
1839{
1840 int rc;
1841 char *pszName;
1842 RTStrAPrintfV(&pszName, pszNameFormat, Args);
1843 if (pszName)
1844 {
1845 rc = CFGMR3InsertNode(pNode, pszName, ppChild);
1846 RTStrFree(pszName);
1847 }
1848 else
1849 rc = VERR_NO_MEMORY;
1850 return rc;
1851}
1852
1853
1854/**
1855 * Marks the node as the root of a restricted subtree, i.e. the end of
1856 * a CFGMR3GetParent() journey.
1857 *
1858 * @param pNode The node to mark.
1859 */
1860VMMR3DECL(void) CFGMR3SetRestrictedRoot(PCFGMNODE pNode)
1861{
1862 if (pNode)
1863 pNode->fRestrictedRoot = true;
1864}
1865
1866
1867/**
1868 * Insert a node.
1869 *
1870 * @returns VBox status code.
1871 * @param pNode Parent node.
1872 * @param pszName Name of the new child node.
1873 * @param ppLeaf Where to store the new leaf.
1874 * The caller must fill in the enmType and Value fields!
1875 */
1876static int cfgmR3InsertLeaf(PCFGMNODE pNode, const char *pszName, PCFGMLEAF *ppLeaf)
1877{
1878 int rc;
1879 if (*pszName)
1880 {
1881 if (pNode)
1882 {
1883 /*
1884 * Check if already exists and find last node in chain.
1885 */
1886 size_t cchName = strlen(pszName);
1887 PCFGMLEAF pPrev = NULL;
1888 PCFGMLEAF pNext = pNode->pFirstLeaf;
1889 if (pNext)
1890 {
1891 for ( ; pNext; pPrev = pNext, pNext = pNext->pNext)
1892 {
1893 int iDiff = cfgmR3CompareNames(pszName, cchName, pNext->szName, pNext->cchName);
1894 if (iDiff <= 0)
1895 {
1896 if (!iDiff)
1897 return VERR_CFGM_LEAF_EXISTS;
1898 break;
1899 }
1900 }
1901 }
1902
1903 /*
1904 * Allocate and init node.
1905 */
1906 PCFGMLEAF pNew = (PCFGMLEAF)cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM, sizeof(*pNew) + cchName);
1907 if (pNew)
1908 {
1909 pNew->cchName = cchName;
1910 memcpy(pNew->szName, pszName, cchName + 1);
1911
1912 /*
1913 * Insert into child list.
1914 */
1915 pNew->pPrev = pPrev;
1916 if (pPrev)
1917 pPrev->pNext = pNew;
1918 else
1919 pNode->pFirstLeaf = pNew;
1920 pNew->pNext = pNext;
1921 if (pNext)
1922 pNext->pPrev = pNew;
1923
1924 *ppLeaf = pNew;
1925 rc = VINF_SUCCESS;
1926 }
1927 else
1928 rc = VERR_NO_MEMORY;
1929 }
1930 else
1931 rc = VERR_CFGM_NO_PARENT;
1932 }
1933 else
1934 rc = VERR_CFGM_INVALID_CHILD_PATH;
1935 return rc;
1936}
1937
1938
1939/**
1940 * Removes a node.
1941 *
1942 * @param pNode The node to remove.
1943 */
1944VMMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode)
1945{
1946 if (pNode)
1947 {
1948 /*
1949 * Free children.
1950 */
1951 while (pNode->pFirstChild)
1952 CFGMR3RemoveNode(pNode->pFirstChild);
1953
1954 /*
1955 * Free leaves.
1956 */
1957 while (pNode->pFirstLeaf)
1958 cfgmR3RemoveLeaf(pNode, pNode->pFirstLeaf);
1959
1960 /*
1961 * Unlink ourselves.
1962 */
1963 if (pNode->pPrev)
1964 pNode->pPrev->pNext = pNode->pNext;
1965 else
1966 {
1967 if (pNode->pParent)
1968 pNode->pParent->pFirstChild = pNode->pNext;
1969 else if ( pNode->pVM /* might be a different tree */
1970 && pNode == pNode->pVM->cfgm.s.pRoot)
1971 pNode->pVM->cfgm.s.pRoot = NULL;
1972 }
1973 if (pNode->pNext)
1974 pNode->pNext->pPrev = pNode->pPrev;
1975
1976 /*
1977 * Free ourselves.
1978 */
1979 cfgmR3FreeNodeOnly(pNode);
1980 }
1981}
1982
1983
1984/**
1985 * Removes a leaf.
1986 *
1987 * @param pNode Parent node.
1988 * @param pLeaf Leaf to remove.
1989 */
1990static void cfgmR3RemoveLeaf(PCFGMNODE pNode, PCFGMLEAF pLeaf)
1991{
1992 if (pNode && pLeaf)
1993 {
1994 /*
1995 * Unlink.
1996 */
1997 if (pLeaf->pPrev)
1998 pLeaf->pPrev->pNext = pLeaf->pNext;
1999 else
2000 pNode->pFirstLeaf = pLeaf->pNext;
2001 if (pLeaf->pNext)
2002 pLeaf->pNext->pPrev = pLeaf->pPrev;
2003
2004 /*
2005 * Free value and node.
2006 */
2007 cfgmR3FreeValue(pNode->pVM, pLeaf);
2008 pLeaf->pNext = NULL;
2009 pLeaf->pPrev = NULL;
2010 cfgmR3MemFree(pNode->pVM, pLeaf);
2011 }
2012}
2013
2014
2015/**
2016 * Frees whatever resources the leaf value is owning.
2017 *
2018 * Use this before assigning a new value to a leaf.
2019 * The caller must either free the leaf or assign a new value to it.
2020 *
2021 * @param pVM Used to select the heap.
2022 * @param pLeaf Pointer to the leaf which value should be free.
2023 */
2024static void cfgmR3FreeValue(PVM pVM, PCFGMLEAF pLeaf)
2025{
2026 if (pLeaf)
2027 {
2028 switch (pLeaf->enmType)
2029 {
2030 case CFGMVALUETYPE_BYTES:
2031 cfgmR3MemFree(pVM, pLeaf->Value.Bytes.pau8);
2032 pLeaf->Value.Bytes.pau8 = NULL;
2033 pLeaf->Value.Bytes.cb = 0;
2034 break;
2035
2036 case CFGMVALUETYPE_STRING:
2037 cfgmR3StrFree(pVM, pLeaf->Value.String.psz);
2038 pLeaf->Value.String.psz = NULL;
2039 pLeaf->Value.String.cb = 0;
2040 break;
2041
2042 case CFGMVALUETYPE_INTEGER:
2043 break;
2044 }
2045 pLeaf->enmType = (CFGMVALUETYPE)0;
2046 }
2047}
2048
2049/**
2050 * Destroys a tree created with CFGMR3CreateTree or CFGMR3DuplicateSubTree.
2051 *
2052 * @returns VBox status code.
2053 * @param pRoot The root node of the tree.
2054 */
2055VMMR3DECL(int) CFGMR3DestroyTree(PCFGMNODE pRoot)
2056{
2057 if (!pRoot)
2058 return VINF_SUCCESS;
2059 AssertReturn(!pRoot->pParent, VERR_INVALID_PARAMETER);
2060 AssertReturn(!pRoot->pVM || pRoot != pRoot->pVM->cfgm.s.pRoot, VERR_ACCESS_DENIED);
2061
2062 CFGMR3RemoveNode(pRoot);
2063 return VINF_SUCCESS;
2064}
2065
2066
2067/**
2068 * Inserts a new integer value.
2069 *
2070 * @returns VBox status code.
2071 * @param pNode Parent node.
2072 * @param pszName Value name.
2073 * @param u64Integer The value.
2074 */
2075VMMR3DECL(int) CFGMR3InsertInteger(PCFGMNODE pNode, const char *pszName, uint64_t u64Integer)
2076{
2077 PCFGMLEAF pLeaf;
2078 int rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2079 if (RT_SUCCESS(rc))
2080 {
2081 pLeaf->enmType = CFGMVALUETYPE_INTEGER;
2082 pLeaf->Value.Integer.u64 = u64Integer;
2083 }
2084 return rc;
2085}
2086
2087
2088/**
2089 * Inserts a new string value. This variant expects that the caller know the length
2090 * of the string already so we can avoid calling strlen() here.
2091 *
2092 * @returns VBox status code.
2093 * @param pNode Parent node.
2094 * @param pszName Value name.
2095 * @param pszString The value. Must not be NULL.
2096 * @param cchString The length of the string excluding the
2097 * terminator.
2098 */
2099VMMR3DECL(int) CFGMR3InsertStringN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString)
2100{
2101 Assert(RTStrNLen(pszString, cchString) == cchString);
2102
2103 int rc;
2104 if (pNode)
2105 {
2106 /*
2107 * Allocate string object first.
2108 */
2109 char *pszStringCopy = (char *)cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cchString + 1);
2110 if (pszStringCopy)
2111 {
2112 memcpy(pszStringCopy, pszString, cchString);
2113 pszStringCopy[cchString] = '\0';
2114
2115 /*
2116 * Create value leaf and set it to string type.
2117 */
2118 PCFGMLEAF pLeaf;
2119 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2120 if (RT_SUCCESS(rc))
2121 {
2122 pLeaf->enmType = CFGMVALUETYPE_STRING;
2123 pLeaf->Value.String.psz = pszStringCopy;
2124 pLeaf->Value.String.cb = cchString + 1;
2125 }
2126 else
2127 cfgmR3StrFree(pNode->pVM, pszStringCopy);
2128 }
2129 else
2130 rc = VERR_NO_MEMORY;
2131 }
2132 else
2133 rc = VERR_CFGM_NO_PARENT;
2134
2135 return rc;
2136}
2137
2138
2139/**
2140 * Inserts a new string value. Calls strlen(pszString) internally; if you know the
2141 * length of the string, CFGMR3InsertStringLengthKnown() is faster.
2142 *
2143 * @returns VBox status code.
2144 * @param pNode Parent node.
2145 * @param pszName Value name.
2146 * @param pszString The value.
2147 */
2148VMMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString)
2149{
2150 return CFGMR3InsertStringN(pNode, pszName, pszString, strlen(pszString));
2151}
2152
2153
2154/**
2155 * Same as CFGMR3InsertString except the string value given in RTStrPrintfV
2156 * fashion.
2157 *
2158 * @returns VBox status code.
2159 * @param pNode Parent node.
2160 * @param pszName Value name.
2161 * @param pszFormat The value given as a format string.
2162 * @param va Argument to pszFormat.
2163 */
2164VMMR3DECL(int) CFGMR3InsertStringFV(PCFGMNODE pNode, const char *pszName, const char *pszFormat, va_list va)
2165{
2166 int rc;
2167 if (pNode)
2168 {
2169 /*
2170 * Allocate string object first.
2171 */
2172 char *pszString;
2173 if (!pNode->pVM)
2174 pszString = RTStrAPrintf2(pszFormat, va);
2175 else
2176 pszString = MMR3HeapAPrintfVU(pNode->pVM->pUVM, MM_TAG_CFGM_STRING, pszFormat, va);
2177 if (pszString)
2178 {
2179 /*
2180 * Create value leaf and set it to string type.
2181 */
2182 PCFGMLEAF pLeaf;
2183 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2184 if (RT_SUCCESS(rc))
2185 {
2186 pLeaf->enmType = CFGMVALUETYPE_STRING;
2187 pLeaf->Value.String.psz = pszString;
2188 pLeaf->Value.String.cb = strlen(pszString) + 1;
2189 }
2190 else
2191 cfgmR3StrFree(pNode->pVM, pszString);
2192 }
2193 else
2194 rc = VERR_NO_MEMORY;
2195 }
2196 else
2197 rc = VERR_CFGM_NO_PARENT;
2198
2199 return rc;
2200}
2201
2202
2203/**
2204 * Same as CFGMR3InsertString except the string value given in RTStrPrintf
2205 * fashion.
2206 *
2207 * @returns VBox status code.
2208 * @param pNode Parent node.
2209 * @param pszName Value name.
2210 * @param pszFormat The value given as a format string.
2211 * @param ... Argument to pszFormat.
2212 */
2213VMMR3DECL(int) CFGMR3InsertStringF(PCFGMNODE pNode, const char *pszName, const char *pszFormat, ...)
2214{
2215 va_list va;
2216 va_start(va, pszFormat);
2217 int rc = CFGMR3InsertStringFV(pNode, pszName, pszFormat, va);
2218 va_end(va);
2219 return rc;
2220}
2221
2222
2223/**
2224 * Same as CFGMR3InsertString except the string value given as a UTF-16 string.
2225 *
2226 * @returns VBox status code.
2227 * @param pNode Parent node.
2228 * @param pszName Value name.
2229 * @param pwszValue The string value (UTF-16).
2230 */
2231VMMR3DECL(int) CFGMR3InsertStringW(PCFGMNODE pNode, const char *pszName, PCRTUTF16 pwszValue)
2232{
2233 char *pszValue;
2234 int rc = RTUtf16ToUtf8(pwszValue, &pszValue);
2235 if (RT_SUCCESS(rc))
2236 {
2237 rc = CFGMR3InsertString(pNode, pszName, pszValue);
2238 RTStrFree(pszValue);
2239 }
2240 return rc;
2241}
2242
2243
2244/**
2245 * Inserts a new integer value.
2246 *
2247 * @returns VBox status code.
2248 * @param pNode Parent node.
2249 * @param pszName Value name.
2250 * @param pvBytes The value.
2251 * @param cbBytes The value size.
2252 */
2253VMMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const void *pvBytes, size_t cbBytes)
2254{
2255 int rc;
2256 if (pNode)
2257 {
2258 if (cbBytes == (RTUINT)cbBytes)
2259 {
2260 /*
2261 * Allocate string object first.
2262 */
2263 void *pvCopy = cfgmR3MemAlloc(pNode->pVM, MM_TAG_CFGM_STRING, cbBytes);
2264 if (pvCopy || !cbBytes)
2265 {
2266 memcpy(pvCopy, pvBytes, cbBytes);
2267
2268 /*
2269 * Create value leaf and set it to string type.
2270 */
2271 PCFGMLEAF pLeaf;
2272 rc = cfgmR3InsertLeaf(pNode, pszName, &pLeaf);
2273 if (RT_SUCCESS(rc))
2274 {
2275 pLeaf->enmType = CFGMVALUETYPE_BYTES;
2276 pLeaf->Value.Bytes.cb = cbBytes;
2277 pLeaf->Value.Bytes.pau8 = (uint8_t *)pvCopy;
2278 }
2279 else
2280 cfgmR3MemFree(pNode->pVM, pvCopy);
2281 }
2282 else
2283 rc = VERR_NO_MEMORY;
2284 }
2285 else
2286 rc = VERR_OUT_OF_RANGE;
2287 }
2288 else
2289 rc = VERR_CFGM_NO_PARENT;
2290
2291 return rc;
2292}
2293
2294
2295/**
2296 * Make a copy of the specified value under the given node.
2297 *
2298 * @returns VBox status code.
2299 * @param pNode Parent node.
2300 * @param pValue The value to copy and insert.
2301 */
2302VMMR3DECL(int) CFGMR3InsertValue(PCFGMNODE pNode, PCFGMLEAF pValue)
2303{
2304 int rc;
2305 switch (pValue->enmType)
2306 {
2307 case CFGMVALUETYPE_INTEGER:
2308 rc = CFGMR3InsertInteger(pNode, pValue->szName, pValue->Value.Integer.u64);
2309 break;
2310
2311 case CFGMVALUETYPE_BYTES:
2312 rc = CFGMR3InsertBytes(pNode, pValue->szName, pValue->Value.Bytes.pau8, pValue->Value.Bytes.cb);
2313 break;
2314
2315 case CFGMVALUETYPE_STRING:
2316 rc = CFGMR3InsertStringN(pNode, pValue->szName, pValue->Value.String.psz, pValue->Value.String.cb - 1);
2317 break;
2318
2319 default:
2320 rc = VERR_CFGM_IPE_1;
2321 AssertMsgFailed(("Invalid value type %d\n", pValue->enmType));
2322 break;
2323 }
2324 return rc;
2325}
2326
2327
2328/**
2329 * Remove a value.
2330 *
2331 * @returns VBox status code.
2332 * @param pNode Parent node.
2333 * @param pszName Name of the new child node.
2334 */
2335VMMR3DECL(int) CFGMR3RemoveValue(PCFGMNODE pNode, const char *pszName)
2336{
2337 PCFGMLEAF pLeaf;
2338 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
2339 if (RT_SUCCESS(rc))
2340 cfgmR3RemoveLeaf(pNode, pLeaf);
2341 return rc;
2342}
2343
2344
2345
2346/*
2347 * -+- helper apis -+-
2348 */
2349
2350
2351/**
2352 * Query unsigned 64-bit integer value.
2353 *
2354 * @returns VBox status code.
2355 * @param pNode Which node to search for pszName in.
2356 * @param pszName Name of an integer value.
2357 * @param pu64 Where to store the integer value.
2358 */
2359VMMR3DECL(int) CFGMR3QueryU64(PCFGMNODE pNode, const char *pszName, uint64_t *pu64)
2360{
2361 return CFGMR3QueryInteger(pNode, pszName, pu64);
2362}
2363
2364
2365/**
2366 * Query unsigned 64-bit integer value with default.
2367 *
2368 * @returns VBox status code.
2369 * @param pNode Which node to search for pszName in.
2370 * @param pszName Name of an integer value.
2371 * @param pu64 Where to store the integer value. Set to default on failure.
2372 * @param u64Def The default value.
2373 */
2374VMMR3DECL(int) CFGMR3QueryU64Def(PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)
2375{
2376 return CFGMR3QueryIntegerDef(pNode, pszName, pu64, u64Def);
2377}
2378
2379
2380/**
2381 * Query signed 64-bit integer value.
2382 *
2383 * @returns VBox status code.
2384 * @param pNode Which node to search for pszName in.
2385 * @param pszName Name of an integer value.
2386 * @param pi64 Where to store the value.
2387 */
2388VMMR3DECL(int) CFGMR3QueryS64(PCFGMNODE pNode, const char *pszName, int64_t *pi64)
2389{
2390 uint64_t u64;
2391 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2392 if (RT_SUCCESS(rc))
2393 *pi64 = (int64_t)u64;
2394 return rc;
2395}
2396
2397
2398/**
2399 * Query signed 64-bit integer value with default.
2400 *
2401 * @returns VBox status code.
2402 * @param pNode Which node to search for pszName in.
2403 * @param pszName Name of an integer value.
2404 * @param pi64 Where to store the value. Set to default on failure.
2405 * @param i64Def The default value.
2406 */
2407VMMR3DECL(int) CFGMR3QueryS64Def(PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)
2408{
2409 uint64_t u64;
2410 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i64Def);
2411 *pi64 = (int64_t)u64;
2412 return rc;
2413}
2414
2415
2416/**
2417 * Query unsigned 32-bit integer value.
2418 *
2419 * @returns VBox status code.
2420 * @param pNode Which node to search for pszName in.
2421 * @param pszName Name of an integer value.
2422 * @param pu32 Where to store the value.
2423 */
2424VMMR3DECL(int) CFGMR3QueryU32(PCFGMNODE pNode, const char *pszName, uint32_t *pu32)
2425{
2426 uint64_t u64;
2427 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2428 if (RT_SUCCESS(rc))
2429 {
2430 if (!(u64 & UINT64_C(0xffffffff00000000)))
2431 *pu32 = (uint32_t)u64;
2432 else
2433 rc = VERR_CFGM_INTEGER_TOO_BIG;
2434 }
2435 return rc;
2436}
2437
2438
2439/**
2440 * Query unsigned 32-bit integer value with default.
2441 *
2442 * @returns VBox status code.
2443 * @param pNode Which node to search for pszName in.
2444 * @param pszName Name of an integer value.
2445 * @param pu32 Where to store the value. Set to default on failure.
2446 * @param u32Def The default value.
2447 */
2448VMMR3DECL(int) CFGMR3QueryU32Def(PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)
2449{
2450 uint64_t u64;
2451 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u32Def);
2452 if (RT_SUCCESS(rc))
2453 {
2454 if (!(u64 & UINT64_C(0xffffffff00000000)))
2455 *pu32 = (uint32_t)u64;
2456 else
2457 rc = VERR_CFGM_INTEGER_TOO_BIG;
2458 }
2459 if (RT_FAILURE(rc))
2460 *pu32 = u32Def;
2461 return rc;
2462}
2463
2464
2465/**
2466 * Query signed 32-bit integer value.
2467 *
2468 * @returns VBox status code.
2469 * @param pNode Which node to search for pszName in.
2470 * @param pszName Name of an integer value.
2471 * @param pi32 Where to store the value.
2472 */
2473VMMR3DECL(int) CFGMR3QueryS32(PCFGMNODE pNode, const char *pszName, int32_t *pi32)
2474{
2475 uint64_t u64;
2476 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2477 if (RT_SUCCESS(rc))
2478 {
2479 if ( !(u64 & UINT64_C(0xffffffff80000000))
2480 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
2481 *pi32 = (int32_t)u64;
2482 else
2483 rc = VERR_CFGM_INTEGER_TOO_BIG;
2484 }
2485 return rc;
2486}
2487
2488
2489/**
2490 * Query signed 32-bit integer value with default.
2491 *
2492 * @returns VBox status code.
2493 * @param pNode Which node to search for pszName in.
2494 * @param pszName Name of an integer value.
2495 * @param pi32 Where to store the value. Set to default on failure.
2496 * @param i32Def The default value.
2497 */
2498VMMR3DECL(int) CFGMR3QueryS32Def(PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)
2499{
2500 uint64_t u64;
2501 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i32Def);
2502 if (RT_SUCCESS(rc))
2503 {
2504 if ( !(u64 & UINT64_C(0xffffffff80000000))
2505 || (u64 & UINT64_C(0xffffffff80000000)) == UINT64_C(0xffffffff80000000))
2506 *pi32 = (int32_t)u64;
2507 else
2508 rc = VERR_CFGM_INTEGER_TOO_BIG;
2509 }
2510 if (RT_FAILURE(rc))
2511 *pi32 = i32Def;
2512 return rc;
2513}
2514
2515
2516/**
2517 * Query unsigned 16-bit integer value.
2518 *
2519 * @returns VBox status code.
2520 * @param pNode Which node to search for pszName in.
2521 * @param pszName Name of an integer value.
2522 * @param pu16 Where to store the value.
2523 */
2524VMMR3DECL(int) CFGMR3QueryU16(PCFGMNODE pNode, const char *pszName, uint16_t *pu16)
2525{
2526 uint64_t u64;
2527 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2528 if (RT_SUCCESS(rc))
2529 {
2530 if (!(u64 & UINT64_C(0xffffffffffff0000)))
2531 *pu16 = (int16_t)u64;
2532 else
2533 rc = VERR_CFGM_INTEGER_TOO_BIG;
2534 }
2535 return rc;
2536}
2537
2538
2539/**
2540 * Query unsigned 16-bit integer value with default.
2541 *
2542 * @returns VBox status code.
2543 * @param pNode Which node to search for pszName in.
2544 * @param pszName Name of an integer value.
2545 * @param pu16 Where to store the value. Set to default on failure.
2546 * @param i16Def The default value.
2547 */
2548VMMR3DECL(int) CFGMR3QueryU16Def(PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)
2549{
2550 uint64_t u64;
2551 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u16Def);
2552 if (RT_SUCCESS(rc))
2553 {
2554 if (!(u64 & UINT64_C(0xffffffffffff0000)))
2555 *pu16 = (int16_t)u64;
2556 else
2557 rc = VERR_CFGM_INTEGER_TOO_BIG;
2558 }
2559 if (RT_FAILURE(rc))
2560 *pu16 = u16Def;
2561 return rc;
2562}
2563
2564
2565/**
2566 * Query signed 16-bit integer value.
2567 *
2568 * @returns VBox status code.
2569 * @param pNode Which node to search for pszName in.
2570 * @param pszName Name of an integer value.
2571 * @param pi16 Where to store the value.
2572 */
2573VMMR3DECL(int) CFGMR3QueryS16(PCFGMNODE pNode, const char *pszName, int16_t *pi16)
2574{
2575 uint64_t u64;
2576 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2577 if (RT_SUCCESS(rc))
2578 {
2579 if ( !(u64 & UINT64_C(0xffffffffffff8000))
2580 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
2581 *pi16 = (int16_t)u64;
2582 else
2583 rc = VERR_CFGM_INTEGER_TOO_BIG;
2584 }
2585 return rc;
2586}
2587
2588
2589/**
2590 * Query signed 16-bit integer value with default.
2591 *
2592 * @returns VBox status code.
2593 * @param pNode Which node to search for pszName in.
2594 * @param pszName Name of an integer value.
2595 * @param pi16 Where to store the value. Set to default on failure.
2596 * @param i16Def The default value.
2597 */
2598VMMR3DECL(int) CFGMR3QueryS16Def(PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)
2599{
2600 uint64_t u64;
2601 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i16Def);
2602 if (RT_SUCCESS(rc))
2603 {
2604 if ( !(u64 & UINT64_C(0xffffffffffff8000))
2605 || (u64 & UINT64_C(0xffffffffffff8000)) == UINT64_C(0xffffffffffff8000))
2606 *pi16 = (int16_t)u64;
2607 else
2608 rc = VERR_CFGM_INTEGER_TOO_BIG;
2609 }
2610 if (RT_FAILURE(rc))
2611 *pi16 = i16Def;
2612 return rc;
2613}
2614
2615
2616/**
2617 * Query unsigned 8-bit integer value.
2618 *
2619 * @returns VBox status code.
2620 * @param pNode Which node to search for pszName in.
2621 * @param pszName Name of an integer value.
2622 * @param pu8 Where to store the value.
2623 */
2624VMMR3DECL(int) CFGMR3QueryU8(PCFGMNODE pNode, const char *pszName, uint8_t *pu8)
2625{
2626 uint64_t u64;
2627 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2628 if (RT_SUCCESS(rc))
2629 {
2630 if (!(u64 & UINT64_C(0xffffffffffffff00)))
2631 *pu8 = (uint8_t)u64;
2632 else
2633 rc = VERR_CFGM_INTEGER_TOO_BIG;
2634 }
2635 return rc;
2636}
2637
2638
2639/**
2640 * Query unsigned 8-bit integer value with default.
2641 *
2642 * @returns VBox status code.
2643 * @param pNode Which node to search for pszName in.
2644 * @param pszName Name of an integer value.
2645 * @param pu8 Where to store the value. Set to default on failure.
2646 * @param u8Def The default value.
2647 */
2648VMMR3DECL(int) CFGMR3QueryU8Def(PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)
2649{
2650 uint64_t u64;
2651 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, u8Def);
2652 if (RT_SUCCESS(rc))
2653 {
2654 if (!(u64 & UINT64_C(0xffffffffffffff00)))
2655 *pu8 = (uint8_t)u64;
2656 else
2657 rc = VERR_CFGM_INTEGER_TOO_BIG;
2658 }
2659 if (RT_FAILURE(rc))
2660 *pu8 = u8Def;
2661 return rc;
2662}
2663
2664
2665/**
2666 * Query signed 8-bit integer value.
2667 *
2668 * @returns VBox status code.
2669 * @param pNode Which node to search for pszName in.
2670 * @param pszName Name of an integer value.
2671 * @param pi8 Where to store the value.
2672 */
2673VMMR3DECL(int) CFGMR3QueryS8(PCFGMNODE pNode, const char *pszName, int8_t *pi8)
2674{
2675 uint64_t u64;
2676 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2677 if (RT_SUCCESS(rc))
2678 {
2679 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2680 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2681 *pi8 = (int8_t)u64;
2682 else
2683 rc = VERR_CFGM_INTEGER_TOO_BIG;
2684 }
2685 return rc;
2686}
2687
2688
2689/**
2690 * Query signed 8-bit integer value with default.
2691 *
2692 * @returns VBox status code.
2693 * @param pNode Which node to search for pszName in.
2694 * @param pszName Name of an integer value.
2695 * @param pi8 Where to store the value. Set to default on failure.
2696 * @param i8Def The default value.
2697 */
2698VMMR3DECL(int) CFGMR3QueryS8Def(PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)
2699{
2700 uint64_t u64;
2701 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, i8Def);
2702 if (RT_SUCCESS(rc))
2703 {
2704 if ( !(u64 & UINT64_C(0xffffffffffffff80))
2705 || (u64 & UINT64_C(0xffffffffffffff80)) == UINT64_C(0xffffffffffffff80))
2706 *pi8 = (int8_t)u64;
2707 else
2708 rc = VERR_CFGM_INTEGER_TOO_BIG;
2709 }
2710 if (RT_FAILURE(rc))
2711 *pi8 = i8Def;
2712 return rc;
2713}
2714
2715
2716/**
2717 * Query boolean integer value.
2718 *
2719 * @returns VBox status code.
2720 * @param pNode Which node to search for pszName in.
2721 * @param pszName Name of an integer value.
2722 * @param pf Where to store the value.
2723 * @remark This function will interpret any non-zero value as true.
2724 */
2725VMMR3DECL(int) CFGMR3QueryBool(PCFGMNODE pNode, const char *pszName, bool *pf)
2726{
2727 uint64_t u64;
2728 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2729 if (RT_SUCCESS(rc))
2730 *pf = u64 ? true : false;
2731 return rc;
2732}
2733
2734
2735/**
2736 * Query boolean integer value with default.
2737 *
2738 * @returns VBox status code.
2739 * @param pNode Which node to search for pszName in.
2740 * @param pszName Name of an integer value.
2741 * @param pf Where to store the value. Set to default on failure.
2742 * @param fDef The default value.
2743 * @remark This function will interpret any non-zero value as true.
2744 */
2745VMMR3DECL(int) CFGMR3QueryBoolDef(PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)
2746{
2747 uint64_t u64;
2748 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, fDef);
2749 *pf = u64 ? true : false;
2750 return rc;
2751}
2752
2753
2754/**
2755 * Query I/O port address value.
2756 *
2757 * @returns VBox status code.
2758 * @param pNode Which node to search for pszName in.
2759 * @param pszName Name of an integer value.
2760 * @param pPort Where to store the value.
2761 */
2762VMMR3DECL(int) CFGMR3QueryPort(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)
2763{
2764 AssertCompileSize(RTIOPORT, 2);
2765 return CFGMR3QueryU16(pNode, pszName, pPort);
2766}
2767
2768
2769/**
2770 * Query I/O port address value with default.
2771 *
2772 * @returns VBox status code.
2773 * @param pNode Which node to search for pszName in.
2774 * @param pszName Name of an integer value.
2775 * @param pPort Where to store the value. Set to default on failure.
2776 * @param PortDef The default value.
2777 */
2778VMMR3DECL(int) CFGMR3QueryPortDef(PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)
2779{
2780 AssertCompileSize(RTIOPORT, 2);
2781 return CFGMR3QueryU16Def(pNode, pszName, pPort, PortDef);
2782}
2783
2784
2785/**
2786 * Query unsigned int address value.
2787 *
2788 * @returns VBox status code.
2789 * @param pNode Which node to search for pszName in.
2790 * @param pszName Name of an integer value.
2791 * @param pu Where to store the value.
2792 */
2793VMMR3DECL(int) CFGMR3QueryUInt(PCFGMNODE pNode, const char *pszName, unsigned int *pu)
2794{
2795 AssertCompileSize(unsigned int, 4);
2796 return CFGMR3QueryU32(pNode, pszName, (uint32_t *)pu);
2797}
2798
2799
2800/**
2801 * Query unsigned int address value with default.
2802 *
2803 * @returns VBox status code.
2804 * @param pNode Which node to search for pszName in.
2805 * @param pszName Name of an integer value.
2806 * @param pu Where to store the value. Set to default on failure.
2807 * @param uDef The default value.
2808 */
2809VMMR3DECL(int) CFGMR3QueryUIntDef(PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)
2810{
2811 AssertCompileSize(unsigned int, 4);
2812 return CFGMR3QueryU32Def(pNode, pszName, (uint32_t *)pu, uDef);
2813}
2814
2815
2816/**
2817 * Query signed int address value.
2818 *
2819 * @returns VBox status code.
2820 * @param pNode Which node to search for pszName in.
2821 * @param pszName Name of an integer value.
2822 * @param pi Where to store the value.
2823 */
2824VMMR3DECL(int) CFGMR3QuerySInt(PCFGMNODE pNode, const char *pszName, signed int *pi)
2825{
2826 AssertCompileSize(signed int, 4);
2827 return CFGMR3QueryS32(pNode, pszName, (int32_t *)pi);
2828}
2829
2830
2831/**
2832 * Query unsigned int address value with default.
2833 *
2834 * @returns VBox status code.
2835 * @param pNode Which node to search for pszName in.
2836 * @param pszName Name of an integer value.
2837 * @param pi Where to store the value. Set to default on failure.
2838 * @param iDef The default value.
2839 */
2840VMMR3DECL(int) CFGMR3QuerySIntDef(PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)
2841{
2842 AssertCompileSize(signed int, 4);
2843 return CFGMR3QueryS32Def(pNode, pszName, (int32_t *)pi, iDef);
2844}
2845
2846
2847/**
2848 * Query pointer integer value.
2849 *
2850 * @returns VBox status code.
2851 * @param pNode Which node to search for pszName in.
2852 * @param pszName Name of an integer value.
2853 * @param ppv Where to store the value.
2854 */
2855VMMR3DECL(int) CFGMR3QueryPtr(PCFGMNODE pNode, const char *pszName, void **ppv)
2856{
2857 uint64_t u64;
2858 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2859 if (RT_SUCCESS(rc))
2860 {
2861 uintptr_t u = (uintptr_t)u64;
2862 if (u64 == u)
2863 *ppv = (void *)u;
2864 else
2865 rc = VERR_CFGM_INTEGER_TOO_BIG;
2866 }
2867 return rc;
2868}
2869
2870
2871/**
2872 * Query pointer integer value with default.
2873 *
2874 * @returns VBox status code.
2875 * @param pNode Which node to search for pszName in.
2876 * @param pszName Name of an integer value.
2877 * @param ppv Where to store the value. Set to default on failure.
2878 * @param pvDef The default value.
2879 */
2880VMMR3DECL(int) CFGMR3QueryPtrDef(PCFGMNODE pNode, const char *pszName, void **ppv, void *pvDef)
2881{
2882 uint64_t u64;
2883 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, (uintptr_t)pvDef);
2884 if (RT_SUCCESS(rc))
2885 {
2886 uintptr_t u = (uintptr_t)u64;
2887 if (u64 == u)
2888 *ppv = (void *)u;
2889 else
2890 rc = VERR_CFGM_INTEGER_TOO_BIG;
2891 }
2892 if (RT_FAILURE(rc))
2893 *ppv = pvDef;
2894 return rc;
2895}
2896
2897
2898/**
2899 * Query Guest Context pointer integer value.
2900 *
2901 * @returns VBox status code.
2902 * @param pNode Which node to search for pszName in.
2903 * @param pszName Name of an integer value.
2904 * @param pGCPtr Where to store the value.
2905 */
2906VMMR3DECL(int) CFGMR3QueryGCPtr(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)
2907{
2908 uint64_t u64;
2909 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2910 if (RT_SUCCESS(rc))
2911 {
2912 RTGCPTR u = (RTGCPTR)u64;
2913 if (u64 == u)
2914 *pGCPtr = u;
2915 else
2916 rc = VERR_CFGM_INTEGER_TOO_BIG;
2917 }
2918 return rc;
2919}
2920
2921
2922/**
2923 * Query Guest Context pointer integer value with default.
2924 *
2925 * @returns VBox status code.
2926 * @param pNode Which node to search for pszName in.
2927 * @param pszName Name of an integer value.
2928 * @param pGCPtr Where to store the value. Set to default on failure.
2929 * @param GCPtrDef The default value.
2930 */
2931VMMR3DECL(int) CFGMR3QueryGCPtrDef(PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)
2932{
2933 uint64_t u64;
2934 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2935 if (RT_SUCCESS(rc))
2936 {
2937 RTGCPTR u = (RTGCPTR)u64;
2938 if (u64 == u)
2939 *pGCPtr = u;
2940 else
2941 rc = VERR_CFGM_INTEGER_TOO_BIG;
2942 }
2943 if (RT_FAILURE(rc))
2944 *pGCPtr = GCPtrDef;
2945 return rc;
2946}
2947
2948
2949/**
2950 * Query Guest Context unsigned pointer value.
2951 *
2952 * @returns VBox status code.
2953 * @param pNode Which node to search for pszName in.
2954 * @param pszName Name of an integer value.
2955 * @param pGCPtr Where to store the value.
2956 */
2957VMMR3DECL(int) CFGMR3QueryGCPtrU(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)
2958{
2959 uint64_t u64;
2960 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
2961 if (RT_SUCCESS(rc))
2962 {
2963 RTGCUINTPTR u = (RTGCUINTPTR)u64;
2964 if (u64 == u)
2965 *pGCPtr = u;
2966 else
2967 rc = VERR_CFGM_INTEGER_TOO_BIG;
2968 }
2969 return rc;
2970}
2971
2972
2973/**
2974 * Query Guest Context unsigned pointer value with default.
2975 *
2976 * @returns VBox status code.
2977 * @param pNode Which node to search for pszName in.
2978 * @param pszName Name of an integer value.
2979 * @param pGCPtr Where to store the value. Set to default on failure.
2980 * @param GCPtrDef The default value.
2981 */
2982VMMR3DECL(int) CFGMR3QueryGCPtrUDef(PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)
2983{
2984 uint64_t u64;
2985 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
2986 if (RT_SUCCESS(rc))
2987 {
2988 RTGCUINTPTR u = (RTGCUINTPTR)u64;
2989 if (u64 == u)
2990 *pGCPtr = u;
2991 else
2992 rc = VERR_CFGM_INTEGER_TOO_BIG;
2993 }
2994 if (RT_FAILURE(rc))
2995 *pGCPtr = GCPtrDef;
2996 return rc;
2997}
2998
2999
3000/**
3001 * Query Guest Context signed pointer value.
3002 *
3003 * @returns VBox status code.
3004 * @param pNode Which node to search for pszName in.
3005 * @param pszName Name of an integer value.
3006 * @param pGCPtr Where to store the value.
3007 */
3008VMMR3DECL(int) CFGMR3QueryGCPtrS(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)
3009{
3010 uint64_t u64;
3011 int rc = CFGMR3QueryInteger(pNode, pszName, &u64);
3012 if (RT_SUCCESS(rc))
3013 {
3014 RTGCINTPTR u = (RTGCINTPTR)u64;
3015 if (u64 == (uint64_t)u)
3016 *pGCPtr = u;
3017 else
3018 rc = VERR_CFGM_INTEGER_TOO_BIG;
3019 }
3020 return rc;
3021}
3022
3023
3024/**
3025 * Query Guest Context signed pointer value with default.
3026 *
3027 * @returns VBox status code.
3028 * @param pNode Which node to search for pszName in.
3029 * @param pszName Name of an integer value.
3030 * @param pGCPtr Where to store the value. Set to default on failure.
3031 * @param GCPtrDef The default value.
3032 */
3033VMMR3DECL(int) CFGMR3QueryGCPtrSDef(PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)
3034{
3035 uint64_t u64;
3036 int rc = CFGMR3QueryIntegerDef(pNode, pszName, &u64, GCPtrDef);
3037 if (RT_SUCCESS(rc))
3038 {
3039 RTGCINTPTR u = (RTGCINTPTR)u64;
3040 if (u64 == (uint64_t)u)
3041 *pGCPtr = u;
3042 else
3043 rc = VERR_CFGM_INTEGER_TOO_BIG;
3044 }
3045 if (RT_FAILURE(rc))
3046 *pGCPtr = GCPtrDef;
3047 return rc;
3048}
3049
3050
3051/**
3052 * Query zero terminated character value storing it in a
3053 * buffer allocated from the MM heap.
3054 *
3055 * @returns VBox status code.
3056 * @param pNode Which node to search for pszName in.
3057 * @param pszName Value name. This value must be of zero terminated character string type.
3058 * @param ppszString Where to store the string pointer.
3059 * Free this using MMR3HeapFree() (or RTStrFree if not
3060 * associated with a pUVM - see CFGMR3CreateTree).
3061 */
3062VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
3063{
3064 size_t cbString;
3065 int rc = CFGMR3QuerySize(pNode, pszName, &cbString);
3066 if (RT_SUCCESS(rc))
3067 {
3068 char *pszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbString);
3069 if (pszString)
3070 {
3071 rc = CFGMR3QueryString(pNode, pszName, pszString, cbString);
3072 if (RT_SUCCESS(rc))
3073 *ppszString = pszString;
3074 else
3075 cfgmR3StrFree(pNode->pVM, pszString);
3076 }
3077 else
3078 rc = VERR_NO_MEMORY;
3079 }
3080 return rc;
3081}
3082
3083
3084/**
3085 * Query zero terminated character value storing it in a
3086 * buffer allocated from the MM heap.
3087 *
3088 * @returns VBox status code.
3089 * @param pNode Which node to search for pszName in. This cannot be
3090 * NULL if @a pszDef is not NULL, because we need
3091 * somewhere way to get to the VM in order to call
3092 * MMR3HeapStrDup.
3093 * @param pszName Value name. This value must be of zero terminated character string type.
3094 * @param ppszString Where to store the string pointer. Not set on failure.
3095 * Free this using MMR3HeapFree() (or RTStrFree if not
3096 * associated with a pUVM - see CFGMR3CreateTree).
3097 * @param pszDef The default return value. This can be NULL.
3098 */
3099VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)
3100{
3101 Assert(pNode || !pszDef); /* We need pVM if we need to duplicate the string later. */
3102
3103 /*
3104 * (Don't call CFGMR3QuerySize and CFGMR3QueryStringDef here as the latter
3105 * cannot handle pszDef being NULL.)
3106 */
3107 PCFGMLEAF pLeaf;
3108 int rc = cfgmR3ResolveLeaf(pNode, pszName, &pLeaf);
3109 if (RT_SUCCESS(rc))
3110 {
3111 if (pLeaf->enmType == CFGMVALUETYPE_STRING)
3112 {
3113 size_t const cbSrc = pLeaf->Value.String.cb;
3114 char *pszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbSrc);
3115 if (pszString)
3116 {
3117 memcpy(pszString, pLeaf->Value.String.psz, cbSrc);
3118 *ppszString = pszString;
3119 }
3120 else
3121 rc = VERR_NO_MEMORY;
3122 }
3123 else
3124 rc = VERR_CFGM_NOT_STRING;
3125 }
3126 if (RT_FAILURE(rc))
3127 {
3128 if (!pszDef)
3129 *ppszString = NULL;
3130 else
3131 {
3132 size_t const cbDef = strlen(pszDef) + 1;
3133 *ppszString = cfgmR3StrAlloc(pNode->pVM, MM_TAG_CFGM_USER, cbDef);
3134 memcpy(*ppszString, pszDef, cbDef);
3135 }
3136 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
3137 rc = VINF_SUCCESS;
3138 }
3139
3140 return rc;
3141}
3142
3143
3144/**
3145 * Dumps the configuration (sub)tree to the release log.
3146 *
3147 * @param pRoot The root node of the dump.
3148 */
3149VMMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot)
3150{
3151 bool fOldBuffered = RTLogRelSetBuffering(true /*fBuffered*/);
3152 LogRel(("************************* CFGM dump *************************\n"));
3153 cfgmR3Dump(pRoot, 0, DBGFR3InfoLogRelHlp());
3154 LogRel(("********************* End of CFGM dump **********************\n"));
3155 RTLogRelSetBuffering(fOldBuffered);
3156}
3157
3158
3159/**
3160 * Info handler, internal version.
3161 *
3162 * @param pVM Pointer to the VM.
3163 * @param pHlp Callback functions for doing output.
3164 * @param pszArgs Argument string. Optional and specific to the handler.
3165 */
3166static DECLCALLBACK(void) cfgmR3Info(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
3167{
3168 /*
3169 * Figure where to start.
3170 */
3171 PCFGMNODE pRoot = pVM->cfgm.s.pRoot;
3172 if (pszArgs && *pszArgs)
3173 {
3174 int rc = cfgmR3ResolveNode(pRoot, pszArgs, &pRoot);
3175 if (RT_FAILURE(rc))
3176 {
3177 pHlp->pfnPrintf(pHlp, "Failed to resolve CFGM path '%s', %Rrc", pszArgs, rc);
3178 return;
3179 }
3180 }
3181
3182 /*
3183 * Dump the specified tree.
3184 */
3185 pHlp->pfnPrintf(pHlp, "pRoot=%p:{", pRoot);
3186 cfgmR3DumpPath(pRoot, pHlp);
3187 pHlp->pfnPrintf(pHlp, "}\n");
3188 cfgmR3Dump(pRoot, 0, pHlp);
3189}
3190
3191
3192/**
3193 * Recursively prints a path name.
3194 */
3195static void cfgmR3DumpPath(PCFGMNODE pNode, PCDBGFINFOHLP pHlp)
3196{
3197 if (pNode->pParent)
3198 cfgmR3DumpPath(pNode->pParent, pHlp);
3199 pHlp->pfnPrintf(pHlp, "%s/", pNode->szName);
3200}
3201
3202
3203/**
3204 * Dumps a branch of a tree.
3205 */
3206static void cfgmR3Dump(PCFGMNODE pRoot, unsigned iLevel, PCDBGFINFOHLP pHlp)
3207{
3208 /*
3209 * Path.
3210 */
3211 pHlp->pfnPrintf(pHlp, "[");
3212 cfgmR3DumpPath(pRoot, pHlp);
3213 pHlp->pfnPrintf(pHlp, "] (level %d)%s\n", iLevel, pRoot->fRestrictedRoot ? " (restricted root)" : "");
3214
3215 /*
3216 * Values.
3217 */
3218 PCFGMLEAF pLeaf;
3219 size_t cchMax = 0;
3220 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
3221 cchMax = RT_MAX(cchMax, pLeaf->cchName);
3222 for (pLeaf = CFGMR3GetFirstValue(pRoot); pLeaf; pLeaf = CFGMR3GetNextValue(pLeaf))
3223 {
3224 switch (CFGMR3GetValueType(pLeaf))
3225 {
3226 case CFGMVALUETYPE_INTEGER:
3227 {
3228 pHlp->pfnPrintf(pHlp, " %-*s <integer> = %#018llx (%'lld", (int)cchMax, pLeaf->szName, pLeaf->Value.Integer.u64, pLeaf->Value.Integer.u64);
3229 if ( ( pLeaf->cchName >= 4
3230 && !RTStrCmp(&pLeaf->szName[pLeaf->cchName - 4], "Size"))
3231 || ( pLeaf->cchName >= 2
3232 && !RTStrNCmp(pLeaf->szName, "cb", 2)) )
3233 {
3234 if (pLeaf->Value.Integer.u64 > _2G)
3235 pHlp->pfnPrintf(pHlp, ", %'lld GB", pLeaf->Value.Integer.u64 / _1G);
3236 else if (pLeaf->Value.Integer.u64 > _2M)
3237 pHlp->pfnPrintf(pHlp, ", %'lld MB", pLeaf->Value.Integer.u64 / _1M);
3238 else if (pLeaf->Value.Integer.u64 > _2K)
3239 pHlp->pfnPrintf(pHlp, ", %'lld KB", pLeaf->Value.Integer.u64 / _1K);
3240 }
3241 pHlp->pfnPrintf(pHlp, ")\n");
3242 break;
3243 }
3244
3245 case CFGMVALUETYPE_STRING:
3246 pHlp->pfnPrintf(pHlp, " %-*s <string> = \"%s\" (cb=%zu)\n", (int)cchMax, pLeaf->szName, pLeaf->Value.String.psz, pLeaf->Value.String.cb);
3247 break;
3248
3249 case CFGMVALUETYPE_BYTES:
3250 pHlp->pfnPrintf(pHlp, " %-*s <bytes> = \"%.*Rhxs\" (cb=%zu)\n", (int)cchMax, pLeaf->szName, pLeaf->Value.Bytes.cb, pLeaf->Value.Bytes.pau8, pLeaf->Value.Bytes.cb);
3251 break;
3252
3253 default:
3254 AssertMsgFailed(("bad leaf!\n"));
3255 break;
3256 }
3257 }
3258 pHlp->pfnPrintf(pHlp, "\n");
3259
3260 /*
3261 * Children.
3262 */
3263 for (PCFGMNODE pChild = CFGMR3GetFirstChild(pRoot); pChild; pChild = CFGMR3GetNextChild(pChild))
3264 {
3265 Assert(pChild->pNext != pChild);
3266 Assert(pChild->pPrev != pChild);
3267 Assert(pChild->pPrev != pChild->pNext || !pChild->pPrev);
3268 Assert(pChild->pFirstChild != pChild);
3269 Assert(pChild->pParent == pRoot);
3270 cfgmR3Dump(pChild, iLevel + 1, pHlp);
3271 }
3272}
3273
Note: See TracBrowser for help on using the repository browser.

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