VirtualBox

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

Last change on this file since 100038 was 100038, checked in by vboxsync, 18 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

  • 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 100038 2023-06-01 18:18:08Z 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 * @returns VBox status code.
349 * @param pDrvIns The driver instance data.
350 */
351DECLCALLBACK(void) ResourceStore::i_drvDestruct(PPDMDRVINS pDrvIns)
352{
353 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
354 PDRVMAINRESOURCESTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINRESOURCESTORE);
355 LogFlow(("ResourceStore::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
356
357 if (pThis->pResourceStore)
358 {
359 ASMAtomicDecU32(&pThis->pResourceStore->m->cRefs);
360 pThis->pResourceStore = NULL;
361 }
362}
363
364
365/**
366 * Construct a resource store driver instance.
367 *
368 * @copydoc FNPDMDRVCONSTRUCT
369 */
370DECLCALLBACK(int) ResourceStore::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
371{
372 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
373 RT_NOREF(fFlags, pCfg);
374 PDRVMAINRESOURCESTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINRESOURCESTORE);
375 LogFlow(("ResourceStore::drvConstruct: iInstance=%d\n", pDrvIns->iInstance));
376
377 /*
378 * Validate configuration.
379 */
380 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "", "");
381 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
382 ("Configuration error: Not possible to attach anything to this driver!\n"),
383 VERR_PDM_DRVINS_NO_ATTACH);
384
385 /*
386 * IBase.
387 */
388 pDrvIns->IBase.pfnQueryInterface = ResourceStore::i_drvQueryInterface;
389
390 pThis->IVfs.pfnQuerySize = ResourceStore::i_resourceStoreQuerySize;
391 pThis->IVfs.pfnReadAll = ResourceStore::i_resourceStoreReadAll;
392 pThis->IVfs.pfnWriteAll = ResourceStore::i_resourceStoreWriteAll;
393 pThis->IVfs.pfnDelete = ResourceStore::i_resourceStoreDelete;
394
395 /*
396 * Get the resource store object pointer.
397 */
398 com::Guid uuid(COM_IIDOF(IResourceStore));
399 pThis->pResourceStore = (ResourceStore *)PDMDrvHlpQueryGenericUserObject(pDrvIns, uuid.raw());
400 if (!pThis->pResourceStore)
401 {
402 AssertMsgFailed(("Configuration error: No/bad resource store object!\n"));
403 return VERR_NOT_FOUND;
404 }
405
406 ASMAtomicIncU32(&pThis->pResourceStore->m->cRefs);
407 return VINF_SUCCESS;
408}
409
410
411/**
412 * Resource store driver registration record.
413 */
414const PDMDRVREG ResourceStore::DrvReg =
415{
416 /* u32Version */
417 PDM_DRVREG_VERSION,
418 /* szName */
419 "ResourceStore",
420 /* szRCMod */
421 "",
422 /* szR0Mod */
423 "",
424 /* pszDescription */
425 "Main resource store driver (Main as in the API).",
426 /* fFlags */
427 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
428 /* fClass. */
429 PDM_DRVREG_CLASS_STATUS,
430 /* cMaxInstances */
431 ~0U,
432 /* cbInstance */
433 sizeof(DRVMAINRESOURCESTORE),
434 /* pfnConstruct */
435 ResourceStore::i_drvConstruct,
436 /* pfnDestruct */
437 ResourceStore::i_drvDestruct,
438 /* pfnRelocate */
439 NULL,
440 /* pfnIOCtl */
441 NULL,
442 /* pfnPowerOn */
443 NULL,
444 /* pfnReset */
445 NULL,
446 /* pfnSuspend */
447 NULL,
448 /* pfnResume */
449 NULL,
450 /* pfnAttach */
451 NULL,
452 /* pfnDetach */
453 NULL,
454 /* pfnPowerOff */
455 NULL,
456 /* pfnSoftReset */
457 NULL,
458 /* u32EndVersion */
459 PDM_DRVREG_VERSION
460};
Note: See TracBrowser for help on using the repository browser.

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