VirtualBox

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

Last change on this file since 77758 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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