VirtualBox

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

Last change on this file since 50653 was 46793, checked in by vboxsync, 11 years ago

typo

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

© 2023 Oracle
ContactPrivacy policyTerms of Use