VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/ResourceStoreImpl.cpp

Last change on this file was 100042, checked in by vboxsync, 11 months ago

Main: Start simple ResourceStore implementation similar to NvramStore but without all the file loading and saving as it will contain only resources created on the fly when the VM is created, bugref:10467 [doxygen fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1/* $Id: ResourceStoreImpl.cpp 100042 2023-06-01 18:26:07Z vboxsync $ */
2/** @file
3 * VirtualBox COM resource store class implementation
4 */
5
6/*
7 * Copyright (C) 2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_RESOURCESTORE
29#include "LoggingNew.h"
30
31#include "ResourceStoreImpl.h"
32#include "ConsoleImpl.h"
33#include "VirtualBoxImpl.h"
34
35#include "AutoCaller.h"
36
37#include <VBox/com/array.h>
38#include <VBox/vmm/pdmdrv.h>
39#include <VBox/err.h>
40
41#include <iprt/cpp/utils.h>
42#include <iprt/file.h>
43#include <iprt/vfs.h>
44
45
46// defines
47////////////////////////////////////////////////////////////////////////////////
48
49
50// globals
51////////////////////////////////////////////////////////////////////////////////
52
53/**
54 * Resource store driver instance data.
55 */
56typedef struct DRVMAINRESOURCESTORE
57{
58 /** Pointer to the keyboard object. */
59 ResourceStore *pResourceStore;
60 /** Pointer to the driver instance structure. */
61 PPDMDRVINS pDrvIns;
62 /** Our VFS connector interface. */
63 PDMIVFSCONNECTOR IVfs;
64} DRVMAINRESOURCESTORE, *PDRVMAINRESOURCESTORE;
65
66/** The resource store map keyed by namespace/entity. */
67typedef std::map<Utf8Str, RTVFSFILE> ResourceStoreMap;
68/** The resource store map iterator. */
69typedef std::map<Utf8Str, RTVFSFILE>::iterator ResourceStoreIter;
70
71struct BackupableResourceStoreData
72{
73 BackupableResourceStoreData()
74 { }
75
76 /** The resource store. */
77 ResourceStoreMap mapResources;
78};
79
80/////////////////////////////////////////////////////////////////////////////
81// ResourceStore::Data structure
82/////////////////////////////////////////////////////////////////////////////
83
84struct ResourceStore::Data
85{
86 Data()
87 : pParent(NULL)
88 { }
89
90 /** The Console owning this resource store. */
91 Console * const pParent;
92 /** Number of references held to this resource store from the various devices/drivers. */
93 volatile uint32_t cRefs;
94
95 Backupable<BackupableResourceStoreData> bd;
96};
97
98// constructor / destructor
99////////////////////////////////////////////////////////////////////////////////
100
101DEFINE_EMPTY_CTOR_DTOR(ResourceStore)
102
103HRESULT ResourceStore::FinalConstruct()
104{
105 return BaseFinalConstruct();
106}
107
108void ResourceStore::FinalRelease()
109{
110 uninit();
111 BaseFinalRelease();
112}
113
114
115// public initializer/uninitializer for internal purposes only
116/////////////////////////////////////////////////////////////////////////////
117
118/**
119 * Initializes the resource store object.
120 *
121 * @returns COM result indicator
122 * @param aParent Handle of our parent object
123 */
124HRESULT ResourceStore::init(Console *aParent)
125{
126 LogFlowThisFunc(("aParent=%p\n", aParent));
127
128 ComAssertRet(aParent, E_INVALIDARG);
129
130 /* Enclose the state transition NotReady->InInit->Ready */
131 AutoInitSpan autoInitSpan(this);
132 AssertReturn(autoInitSpan.isOk(), E_FAIL);
133
134 m = new Data();
135
136 unconst(m->pParent) = aParent;
137
138 m->bd.allocate();
139
140 /* Confirm a successful initialization */
141 autoInitSpan.setSucceeded();
142
143 return S_OK;
144}
145
146
147/**
148 * Uninitializes the instance and sets the ready flag to FALSE.
149 * Called either from FinalRelease() or by the parent when it gets destroyed.
150 */
151void ResourceStore::uninit()
152{
153 LogFlowThisFuncEnter();
154
155 /* Enclose the state transition Ready->InUninit->NotReady */
156 AutoUninitSpan autoUninitSpan(this);
157 if (autoUninitSpan.uninitDone())
158 return;
159
160 unconst(m->pParent) = NULL;
161
162 /* Delete the store content. */
163 ResourceStoreIter it = m->bd->mapResources.begin();
164 while (it != m->bd->mapResources.end())
165 {
166 RTVfsFileRelease(it->second);
167 it++;
168 }
169
170 m->bd->mapResources.clear();
171 m->bd.free();
172
173 delete m;
174 m = NULL;
175
176 LogFlowThisFuncLeave();
177}
178
179
180/**
181 * Adds the given item to the store under the namespace and path.
182 *
183 * @returns VBox status code.
184 * @param pszNamespace The namespace of the item.
185 * @param pszPath The path to the item.
186 * @param hVfsFile The item data as a VFS file handle, a reference is retained on success.
187 */
188int ResourceStore::i_addItem(const char *pszNamespace, const char *pszPath, RTVFSFILE hVfsFile)
189{
190 Utf8Str strKey;
191 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
192 AssertRCReturn(vrc, vrc);
193
194 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
195 try
196 {
197 RTVfsFileRetain(hVfsFile);
198 m->bd->mapResources[strKey] = hVfsFile;
199 }
200 catch (...)
201 {
202 AssertLogRelFailed();
203 vrc = VERR_UNEXPECTED_EXCEPTION;
204 }
205
206 return vrc;
207}
208
209
210//
211// private methods
212//
213/*static*/
214DECLCALLBACK(int) ResourceStore::i_resourceStoreQuerySize(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
215 uint64_t *pcb)
216{
217 PDRVMAINRESOURCESTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINRESOURCESTORE, IVfs);
218
219 Utf8Str strKey;
220 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
221 AssertRCReturn(vrc, vrc);
222
223 AutoReadLock rlock(pThis->pResourceStore COMMA_LOCKVAL_SRC_POS);
224 ResourceStoreIter it = pThis->pResourceStore->m->bd->mapResources.find(strKey);
225 if (it != pThis->pResourceStore->m->bd->mapResources.end())
226 {
227 RTVFSFILE hVfsFile = it->second;
228 return RTVfsFileQuerySize(hVfsFile, pcb);
229 }
230
231 return VERR_NOT_FOUND;
232}
233
234
235/*static*/
236DECLCALLBACK(int) ResourceStore::i_resourceStoreReadAll(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
237 void *pvBuf, size_t cbRead)
238{
239 PDRVMAINRESOURCESTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINRESOURCESTORE, IVfs);
240
241 Utf8Str strKey;
242 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
243 AssertRCReturn(vrc, vrc);
244
245 AutoReadLock rlock(pThis->pResourceStore COMMA_LOCKVAL_SRC_POS);
246 ResourceStoreIter it = pThis->pResourceStore->m->bd->mapResources.find(strKey);
247 if (it != pThis->pResourceStore->m->bd->mapResources.end())
248 {
249 RTVFSFILE hVfsFile = it->second;
250
251 vrc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
252 AssertLogRelRC(vrc);
253
254 return RTVfsFileRead(hVfsFile, pvBuf, cbRead, NULL /*pcbRead*/);
255 }
256
257 return VERR_NOT_FOUND;
258}
259
260
261/*static*/
262DECLCALLBACK(int) ResourceStore::i_resourceStoreWriteAll(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
263 const void *pvBuf, size_t cbWrite)
264{
265 PDRVMAINRESOURCESTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINRESOURCESTORE, IVfs);
266
267 Utf8Str strKey;
268 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
269 AssertRCReturn(vrc, vrc);
270
271 AutoWriteLock wlock(pThis->pResourceStore COMMA_LOCKVAL_SRC_POS);
272
273 ResourceStoreIter it = pThis->pResourceStore->m->bd->mapResources.find(strKey);
274 if (it != pThis->pResourceStore->m->bd->mapResources.end())
275 {
276 RTVFSFILE hVfsFile = it->second;
277
278 vrc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
279 AssertLogRelRC(vrc);
280 vrc = RTVfsFileSetSize(hVfsFile, cbWrite, RTVFSFILE_SIZE_F_NORMAL);
281 if (RT_SUCCESS(vrc))
282 vrc = RTVfsFileWrite(hVfsFile, pvBuf, cbWrite, NULL /*pcbWritten*/);
283 }
284 else
285 {
286 /* Create a new entry. */
287 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
288 vrc = RTVfsFileFromBuffer(RTFILE_O_READ | RTFILE_O_WRITE, pvBuf, cbWrite, &hVfsFile);
289 if (RT_SUCCESS(vrc))
290 {
291 try
292 {
293 pThis->pResourceStore->m->bd->mapResources[strKey] = hVfsFile;
294 }
295 catch (...)
296 {
297 AssertLogRelFailed();
298 RTVfsFileRelease(hVfsFile);
299 vrc = VERR_UNEXPECTED_EXCEPTION;
300 }
301 }
302 }
303
304 return vrc;
305}
306
307
308/*static*/
309DECLCALLBACK(int) ResourceStore::i_resourceStoreDelete(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath)
310{
311 PDRVMAINRESOURCESTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINRESOURCESTORE, IVfs);
312
313 Utf8Str strKey;
314 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
315 AssertRCReturn(vrc, vrc);
316
317 AutoWriteLock wlock(pThis->pResourceStore COMMA_LOCKVAL_SRC_POS);
318 ResourceStoreIter it = pThis->pResourceStore->m->bd->mapResources.find(strKey);
319 if (it != pThis->pResourceStore->m->bd->mapResources.end())
320 {
321 RTVFSFILE hVfsFile = it->second;
322 pThis->pResourceStore->m->bd->mapResources.erase(it);
323 RTVfsFileRelease(hVfsFile);
324 return VINF_SUCCESS;
325 }
326
327 return VERR_NOT_FOUND;
328}
329
330
331/**
332 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
333 */
334DECLCALLBACK(void *) ResourceStore::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
335{
336 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
337 PDRVMAINRESOURCESTORE pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINRESOURCESTORE);
338
339 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
340 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVFSCONNECTOR, &pDrv->IVfs);
341 return NULL;
342}
343
344
345/**
346 * Destruct a resource store driver instance.
347 *
348 * @param pDrvIns The driver instance data.
349 */
350DECLCALLBACK(void) ResourceStore::i_drvDestruct(PPDMDRVINS pDrvIns)
351{
352 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
353 PDRVMAINRESOURCESTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINRESOURCESTORE);
354 LogFlow(("ResourceStore::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
355
356 if (pThis->pResourceStore)
357 {
358 ASMAtomicDecU32(&pThis->pResourceStore->m->cRefs);
359 pThis->pResourceStore = NULL;
360 }
361}
362
363
364/**
365 * Construct a resource store driver instance.
366 *
367 * @copydoc FNPDMDRVCONSTRUCT
368 */
369DECLCALLBACK(int) ResourceStore::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
370{
371 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
372 RT_NOREF(fFlags, pCfg);
373 PDRVMAINRESOURCESTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINRESOURCESTORE);
374 LogFlow(("ResourceStore::drvConstruct: iInstance=%d\n", pDrvIns->iInstance));
375
376 /*
377 * Validate configuration.
378 */
379 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "", "");
380 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
381 ("Configuration error: Not possible to attach anything to this driver!\n"),
382 VERR_PDM_DRVINS_NO_ATTACH);
383
384 /*
385 * IBase.
386 */
387 pDrvIns->IBase.pfnQueryInterface = ResourceStore::i_drvQueryInterface;
388
389 pThis->IVfs.pfnQuerySize = ResourceStore::i_resourceStoreQuerySize;
390 pThis->IVfs.pfnReadAll = ResourceStore::i_resourceStoreReadAll;
391 pThis->IVfs.pfnWriteAll = ResourceStore::i_resourceStoreWriteAll;
392 pThis->IVfs.pfnDelete = ResourceStore::i_resourceStoreDelete;
393
394 /*
395 * Get the resource store object pointer.
396 */
397 com::Guid uuid(COM_IIDOF(IResourceStore));
398 pThis->pResourceStore = (ResourceStore *)PDMDrvHlpQueryGenericUserObject(pDrvIns, uuid.raw());
399 if (!pThis->pResourceStore)
400 {
401 AssertMsgFailed(("Configuration error: No/bad resource store object!\n"));
402 return VERR_NOT_FOUND;
403 }
404
405 ASMAtomicIncU32(&pThis->pResourceStore->m->cRefs);
406 return VINF_SUCCESS;
407}
408
409
410/**
411 * Resource store driver registration record.
412 */
413const PDMDRVREG ResourceStore::DrvReg =
414{
415 /* u32Version */
416 PDM_DRVREG_VERSION,
417 /* szName */
418 "ResourceStore",
419 /* szRCMod */
420 "",
421 /* szR0Mod */
422 "",
423 /* pszDescription */
424 "Main resource store driver (Main as in the API).",
425 /* fFlags */
426 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
427 /* fClass. */
428 PDM_DRVREG_CLASS_STATUS,
429 /* cMaxInstances */
430 ~0U,
431 /* cbInstance */
432 sizeof(DRVMAINRESOURCESTORE),
433 /* pfnConstruct */
434 ResourceStore::i_drvConstruct,
435 /* pfnDestruct */
436 ResourceStore::i_drvDestruct,
437 /* pfnRelocate */
438 NULL,
439 /* pfnIOCtl */
440 NULL,
441 /* pfnPowerOn */
442 NULL,
443 /* pfnReset */
444 NULL,
445 /* pfnSuspend */
446 NULL,
447 /* pfnResume */
448 NULL,
449 /* pfnAttach */
450 NULL,
451 /* pfnDetach */
452 NULL,
453 /* pfnPowerOff */
454 NULL,
455 /* pfnSoftReset */
456 NULL,
457 /* u32EndVersion */
458 PDM_DRVREG_VERSION
459};
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use