VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServicePropCache.cpp@ 29743

Last change on this file since 29743 was 29040, checked in by vboxsync, 15 years ago

VBoxService/PropCache: Finished some todos, IPRT: Added VINF_NO_CHANGE.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.9 KB
Line 
1/* $Id: VBoxServicePropCache.cpp 29040 2010-05-04 20:09:03Z vboxsync $ */
2/** @file
3 * VBoxServicePropCache - Guest property cache.
4 */
5
6/*
7 * Copyright (C) 2010 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
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <iprt/assert.h>
23#include <iprt/list.h>
24#include <iprt/mem.h>
25#include <iprt/string.h>
26
27#include <VBox/VBoxGuestLib.h>
28#include "VBoxServiceInternal.h"
29#include "VBoxServiceUtils.h"
30#include "VBoxServicePropCache.h"
31
32
33/** Internal functions, not for public use. */
34PVBOXSERVICEVEPROPCACHEENTRY vboxServicePropCacheFindInternal(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, uint32_t uFlags);
35PVBOXSERVICEVEPROPCACHEENTRY vboxServicePropCacheInsertEntryInternal(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName);
36
37
38/** @todo Docs */
39PVBOXSERVICEVEPROPCACHEENTRY vboxServicePropCacheFindInternal(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, uint32_t uFlags)
40{
41 AssertPtr(pCache);
42 AssertPtr(pszName);
43 /** @todo This is a O(n) lookup, maybe improve this later to O(1) using a
44 * map.
45 * r=bird: Use a string space (RTstrSpace*). That is O(log n) in its current
46 * implementation (AVL tree). However, this is not important at the
47 * moment. */
48 PVBOXSERVICEVEPROPCACHEENTRY pNodeIt, pNode = NULL;
49 if (RT_SUCCESS(RTCritSectEnter(&pCache->CritSect)))
50 {
51 RTListForEach(&pCache->ListEntries, pNodeIt, VBOXSERVICEVEPROPCACHEENTRY, Node)
52 {
53 if (strcmp(pNodeIt->pszName, pszName) == 0)
54 {
55 pNode = pNodeIt;
56 break;
57 }
58 }
59 RTCritSectLeave(&pCache->CritSect);
60 }
61 return pNode;
62}
63
64
65/** @todo Docs */
66PVBOXSERVICEVEPROPCACHEENTRY vboxServicePropCacheInsertEntryInternal(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName)
67{
68 AssertPtr(pszName);
69 PVBOXSERVICEVEPROPCACHEENTRY pNode = (PVBOXSERVICEVEPROPCACHEENTRY)RTMemAlloc(sizeof(VBOXSERVICEVEPROPCACHEENTRY));
70 if (pNode)
71 {
72 pNode->pszName = RTStrDup(pszName);
73 pNode->pszValue = NULL;
74 pNode->fFlags = 0;
75 pNode->pszValueReset = NULL;
76
77 int rc = RTCritSectEnter(&pCache->CritSect);
78 if (RT_SUCCESS(rc))
79 {
80 /*rc =*/ RTListAppend(&pCache->ListEntries, &pNode->Node);
81 rc = RTCritSectLeave(&pCache->CritSect);
82 }
83 }
84 return pNode;
85}
86
87
88/**
89 * Creates a property cache.
90 *
91 * @returns IPRT status code.
92 * @param pCache Pointer to the cache.
93 * @param uClientId The HGCM handle of to the guest property service.
94 */
95int VBoxServicePropCacheCreate(PVBOXSERVICEVEPROPCACHE pCache, uint32_t uClientId)
96{
97 AssertPtr(pCache);
98 /** @todo Prevent init the cache twice!
99 * r=bird: Use a magic. */
100 RTListInit(&pCache->ListEntries);
101 pCache->uClientID = uClientId;
102 return RTCritSectInit(&pCache->CritSect);
103}
104
105
106/** @todo Docs */
107int VBoxServicePropCacheUpdateEntry(PVBOXSERVICEVEPROPCACHE pCache,
108 const char *pszName, uint32_t fFlags, const char *pszValueReset)
109{
110 AssertPtr(pCache);
111 AssertPtr(pszName);
112 PVBOXSERVICEVEPROPCACHEENTRY pNode = vboxServicePropCacheFindInternal(pCache, pszName, 0);
113 if (pNode == NULL)
114 pNode = vboxServicePropCacheInsertEntryInternal(pCache, pszName);
115
116 int rc;
117 if (pNode != NULL)
118 {
119 rc = RTCritSectEnter(&pCache->CritSect);
120 if (RT_SUCCESS(rc))
121 {
122 pNode->fFlags = fFlags;
123 if (pszValueReset)
124 {
125 if (pNode->pszValueReset)
126 RTStrFree(pNode->pszValueReset);
127 pNode->pszValueReset = RTStrDup(pszValueReset);
128 }
129 rc = RTCritSectLeave(&pCache->CritSect);
130 }
131 }
132 else
133 rc = VERR_NO_MEMORY;
134 return rc;
135}
136
137
138/**
139 * Updates the local guest property cache and writes it to HGCM if outdated.
140 *
141 * @returns VBox status code. Errors will be logged.
142 *
143 * @param pCache The property cache.
144 * @param pszName The property name.
145 * @param pszValueFormat The property format string. If this is NULL then
146 * the property will be deleted (if possible).
147 * @param ... Format arguments.
148 */
149int VBoxServicePropCacheUpdate(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, const char *pszValueFormat, ...)
150{
151 char *pszValue = NULL;
152 int rc;
153 if (pszValueFormat)
154 {
155 va_list va;
156 va_start(va, pszValueFormat);
157 RTStrAPrintfV(&pszValue, pszValueFormat, va);
158 va_end(va);
159 }
160 rc = VBoxServicePropCacheUpdateEx(pCache, pszName, 0 /* Not used */, NULL /* Not used */, pszValue);
161 if (pszValue)
162 RTStrFree(pszValue);
163 return rc;
164}
165
166
167/**
168 * Updates the local guest property cache and writes it to HGCM if outdated.
169 *
170 * @returns VBox status code. Errors will be logged.
171 *
172 * @param pCache The property cache.
173 * @param pszName The property name.
174 * @param pszValueFormat The property format string. If this is NULL then
175 * the property will be deleted (if possible).
176 * @param ... Format arguments.
177 */
178int VBoxServicePropCacheUpdateEx(PVBOXSERVICEVEPROPCACHE pCache, const char *pszName, uint32_t fFlags,
179 const char *pszValueReset, const char *pszValueFormat, ...)
180{
181 AssertPtr(pCache);
182 Assert(pCache->uClientID);
183 AssertPtr(pszName);
184
185 /*
186 * Format the value first.
187 */
188 char *pszValue = NULL;
189 if (pszValueFormat)
190 {
191 va_list va;
192 va_start(va, pszValueFormat);
193 RTStrAPrintfV(&pszValue, pszValueFormat, va);
194 va_end(va);
195 if (!pszValue)
196 return VERR_NO_STR_MEMORY;
197 }
198
199 PVBOXSERVICEVEPROPCACHEENTRY pNode = vboxServicePropCacheFindInternal(pCache, pszName, 0);
200
201 /* Lock the cache. */
202 int rc = RTCritSectEnter(&pCache->CritSect);
203 if (RT_SUCCESS(rc))
204 {
205 if (pNode == NULL)
206 pNode = vboxServicePropCacheInsertEntryInternal(pCache, pszName);
207
208 AssertPtr(pNode);
209 if (pszValue) /* Do we have a value to check for? */
210 {
211 bool fUpdate = false;
212 /* Always update this property, no matter what? */
213 if (pNode->fFlags & VBOXSERVICEPROPCACHEFLAG_ALWAYS_UPDATE)
214 fUpdate = true;
215 /* Did the value change so we have to update? */
216 else if (pNode->pszValue && strcmp(pNode->pszValue, pszValue) != 0)
217 fUpdate = true;
218 /* No value stored at the moment but we have a value now? */
219 else if (pNode->pszValue == NULL)
220 fUpdate = true;
221
222 if (fUpdate)
223 {
224 /* Write the update. */
225 rc = VBoxServiceWritePropF(pCache->uClientID, pNode->pszName, pszValue);
226 RTStrFree(pNode->pszValue);
227 pNode->pszValue = RTStrDup(pszValue);
228 }
229 else
230 rc = VINF_NO_CHANGE; /* No update needed. */
231 }
232 else
233 {
234 /* No value specified. Deletion (or no action required). */
235 if (pNode->pszValue) /* Did we have a value before? Then the value needs to be deleted. */
236 {
237 /* Delete property (but do not remove from cache) if not deleted yet. */
238 RTStrFree(pNode->pszValue);
239 pNode->pszValue = NULL;
240 rc = VBoxServiceWritePropF(pCache->uClientID, pNode->pszName, NULL);
241 }
242 else
243 rc = VINF_NO_CHANGE; /* No update needed. */
244 }
245
246 /* Update rest of the fields. */
247 if (pszValueReset)
248 {
249 if (pNode->pszValueReset)
250 RTStrFree(pNode->pszValueReset);
251 pNode->pszValueReset = RTStrDup(pszValueReset);
252 }
253 if (fFlags)
254 pNode->fFlags = fFlags;
255
256 /* Release cache. */
257 int rc2 = RTCritSectLeave(&pCache->CritSect);
258 if (RT_SUCCESS(rc))
259 rc2 = rc;
260 }
261
262 /* Delete temp stuff. */
263 RTStrFree(pszValue);
264
265 return rc;
266}
267
268
269/**
270 * Reset all temporary properties and destroy the cache.
271 *
272 * @param pCache The property cache.
273 */
274void VBoxServicePropCacheDestroy(PVBOXSERVICEVEPROPCACHE pCache)
275{
276 AssertPtr(pCache);
277 Assert(pCache->uClientID);
278
279 /* Lock the cache. */
280 int rc = RTCritSectEnter(&pCache->CritSect);
281 if (RT_SUCCESS(rc))
282 {
283 PVBOXSERVICEVEPROPCACHEENTRY pNode = RTListNodeGetFirst(&pCache->ListEntries, VBOXSERVICEVEPROPCACHEENTRY, Node);
284 while (pNode)
285 {
286 if ((pNode->fFlags & VBOXSERVICEPROPCACHEFLAG_TEMPORARY) == 0)
287 VBoxServiceWritePropF(pCache->uClientID, pNode->pszName, pNode->pszValueReset);
288
289 AssertPtr(pNode->pszName);
290 RTStrFree(pNode->pszName);
291 RTStrFree(pNode->pszValue);
292 RTStrFree(pNode->pszValueReset);
293 pNode->fFlags = 0;
294
295 PVBOXSERVICEVEPROPCACHEENTRY pNext = RTListNodeGetNext(&pNode->Node, VBOXSERVICEVEPROPCACHEENTRY, Node);
296 RTListNodeRemove(&pNode->Node);
297 RTMemFree(pNode);
298
299 if (pNext && RTListNodeIsLast(&pCache->ListEntries, &pNext->Node))
300 break;
301 pNode = pNext;
302 }
303 RTCritSectLeave(&pCache->CritSect);
304 }
305
306 /* Destroy critical section. */
307 RTCritSectDelete(&pCache->CritSect);
308}
309
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