VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServiceUtils.cpp@ 76553

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

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.8 KB
Line 
1/* $Id: VBoxServiceUtils.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBoxServiceUtils - Some utility functions.
4 */
5
6/*
7 * Copyright (C) 2009-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#ifdef RT_OS_WINDOWS
23# include <iprt/win/windows.h>
24# include <iprt/param.h>
25# include <iprt/path.h>
26#endif
27#include <iprt/assert.h>
28#include <iprt/mem.h>
29#include <iprt/string.h>
30
31#include <VBox/VBoxGuestLib.h>
32#include "VBoxServiceInternal.h"
33
34
35#ifdef VBOX_WITH_GUEST_PROPS
36
37/**
38 * Reads a guest property.
39 *
40 * @returns VBox status code, fully bitched.
41 *
42 * @param u32ClientId The HGCM client ID for the guest property session.
43 * @param pszPropName The property name.
44 * @param ppszValue Where to return the value. This is always set
45 * to NULL. Free it using RTStrFree(). Optional.
46 * @param ppszFlags Where to return the value flags. Free it
47 * using RTStrFree(). Optional.
48 * @param puTimestamp Where to return the timestamp. This is only set
49 * on success. Optional.
50 */
51int VGSvcReadProp(uint32_t u32ClientId, const char *pszPropName, char **ppszValue, char **ppszFlags, uint64_t *puTimestamp)
52{
53 AssertPtrReturn(pszPropName, VERR_INVALID_POINTER);
54
55 uint32_t cbBuf = _1K;
56 void *pvBuf = NULL;
57 int rc = VINF_SUCCESS; /* MSC can't figure out the loop */
58
59 if (ppszValue)
60 *ppszValue = NULL;
61
62 for (unsigned cTries = 0; cTries < 10; cTries++)
63 {
64 /*
65 * (Re-)Allocate the buffer and try read the property.
66 */
67 RTMemFree(pvBuf);
68 pvBuf = RTMemAlloc(cbBuf);
69 if (!pvBuf)
70 {
71 VGSvcError("Guest Property: Failed to allocate %zu bytes\n", cbBuf);
72 rc = VERR_NO_MEMORY;
73 break;
74 }
75 char *pszValue;
76 char *pszFlags;
77 uint64_t uTimestamp;
78 rc = VbglR3GuestPropRead(u32ClientId, pszPropName, pvBuf, cbBuf, &pszValue, &uTimestamp, &pszFlags, NULL);
79 if (RT_FAILURE(rc))
80 {
81 if (rc == VERR_BUFFER_OVERFLOW)
82 {
83 /* try again with a bigger buffer. */
84 cbBuf *= 2;
85 continue;
86 }
87 if (rc == VERR_NOT_FOUND)
88 VGSvcVerbose(2, "Guest Property: %s not found\n", pszPropName);
89 else
90 VGSvcError("Guest Property: Failed to query '%s': %Rrc\n", pszPropName, rc);
91 break;
92 }
93
94 VGSvcVerbose(2, "Guest Property: Read '%s' = '%s', timestamp %RU64n\n", pszPropName, pszValue, uTimestamp);
95 if (ppszValue)
96 {
97 *ppszValue = RTStrDup(pszValue);
98 if (!*ppszValue)
99 {
100 VGSvcError("Guest Property: RTStrDup failed for '%s'\n", pszValue);
101 rc = VERR_NO_MEMORY;
102 break;
103 }
104 }
105
106 if (puTimestamp)
107 *puTimestamp = uTimestamp;
108 if (ppszFlags)
109 *ppszFlags = RTStrDup(pszFlags);
110 break; /* done */
111 }
112
113 if (pvBuf)
114 RTMemFree(pvBuf);
115 return rc;
116}
117
118
119/**
120 * Reads a guest property as a 32-bit value.
121 *
122 * @returns VBox status code, fully bitched.
123 *
124 * @param u32ClientId The HGCM client ID for the guest property session.
125 * @param pszPropName The property name.
126 * @param pu32 Where to store the 32-bit value.
127 *
128 */
129int VGSvcReadPropUInt32(uint32_t u32ClientId, const char *pszPropName, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max)
130{
131 char *pszValue;
132 int rc = VGSvcReadProp(u32ClientId, pszPropName, &pszValue, NULL /* ppszFlags */, NULL /* puTimestamp */);
133 if (RT_SUCCESS(rc))
134 {
135 char *pszNext;
136 rc = RTStrToUInt32Ex(pszValue, &pszNext, 0, pu32);
137 if ( RT_SUCCESS(rc)
138 && (*pu32 < u32Min || *pu32 > u32Max))
139 rc = VGSvcError("The guest property value %s = %RU32 is out of range [%RU32..%RU32].\n",
140 pszPropName, *pu32, u32Min, u32Max);
141 RTStrFree(pszValue);
142 }
143 return rc;
144}
145
146/**
147 * Checks if @a pszPropName exists.
148 *
149 * @returns VBox status code.
150 * @retval VINF_SUCCESS if it exists.
151 * @retval VERR_NOT_FOUND if not found.
152 *
153 * @param u32ClientId The HGCM client ID for the guest property session.
154 * @param pszPropName The property name.
155 */
156int VGSvcCheckPropExist(uint32_t u32ClientId, const char *pszPropName)
157{
158 return VGSvcReadProp(u32ClientId, pszPropName, NULL /*ppszValue*/, NULL /* ppszFlags */, NULL /* puTimestamp */);
159}
160
161
162/**
163 * Reads a guest property from the host side.
164 *
165 * @returns IPRT status code, fully bitched.
166 * @param u32ClientId The HGCM client ID for the guest property session.
167 * @param pszPropName The property name.
168 * @param fReadOnly Whether or not this property needs to be read only
169 * by the guest side. Otherwise VERR_ACCESS_DENIED will
170 * be returned.
171 * @param ppszValue Where to return the value. This is always set
172 * to NULL. Free it using RTStrFree().
173 * @param ppszFlags Where to return the value flags. Free it
174 * using RTStrFree(). Optional.
175 * @param puTimestamp Where to return the timestamp. This is only set
176 * on success. Optional.
177 */
178int VGSvcReadHostProp(uint32_t u32ClientId, const char *pszPropName, bool fReadOnly,
179 char **ppszValue, char **ppszFlags, uint64_t *puTimestamp)
180{
181 AssertPtrReturn(ppszValue, VERR_INVALID_PARAMETER);
182
183 char *pszValue = NULL;
184 char *pszFlags = NULL;
185 int rc = VGSvcReadProp(u32ClientId, pszPropName, &pszValue, &pszFlags, puTimestamp);
186 if (RT_SUCCESS(rc))
187 {
188 /* Check security bits. */
189 if ( fReadOnly /* Do we except a guest read-only property */
190 && !RTStrStr(pszFlags, "RDONLYGUEST"))
191 {
192 /* If we want a property which is read-only on the guest
193 * and it is *not* marked as such, deny access! */
194 rc = VERR_ACCESS_DENIED;
195 }
196
197 if (RT_SUCCESS(rc))
198 {
199 *ppszValue = pszValue;
200
201 if (ppszFlags)
202 *ppszFlags = pszFlags;
203 else if (pszFlags)
204 RTStrFree(pszFlags);
205 }
206 else
207 {
208 if (pszValue)
209 RTStrFree(pszValue);
210 if (pszFlags)
211 RTStrFree(pszFlags);
212 }
213 }
214
215 return rc;
216}
217
218
219/**
220 * Wrapper around VbglR3GuestPropWriteValue that does value formatting and
221 * logging.
222 *
223 * @returns VBox status code. Errors will be logged.
224 *
225 * @param u32ClientId The HGCM client ID for the guest property session.
226 * @param pszName The property name.
227 * @param pszValueFormat The property format string. If this is NULL then
228 * the property will be deleted (if possible).
229 * @param ... Format arguments.
230 */
231int VGSvcWritePropF(uint32_t u32ClientId, const char *pszName, const char *pszValueFormat, ...)
232{
233 AssertPtr(pszName);
234 int rc;
235 if (pszValueFormat != NULL)
236 {
237 va_list va;
238 va_start(va, pszValueFormat);
239 VGSvcVerbose(3, "Writing guest property '%s' = '%N'\n", pszName, pszValueFormat, &va);
240 va_end(va);
241
242 va_start(va, pszValueFormat);
243 rc = VbglR3GuestPropWriteValueV(u32ClientId, pszName, pszValueFormat, va);
244 va_end(va);
245
246 if (RT_FAILURE(rc))
247 VGSvcError("Error writing guest property '%s' (rc=%Rrc)\n", pszName, rc);
248 }
249 else
250 {
251 VGSvcVerbose(3, "Deleting guest property '%s'\n", pszName);
252 rc = VbglR3GuestPropWriteValue(u32ClientId, pszName, NULL);
253 if (RT_FAILURE(rc))
254 VGSvcError("Error deleting guest property '%s' (rc=%Rrc)\n", pszName, rc);
255 }
256 return rc;
257}
258
259#endif /* VBOX_WITH_GUEST_PROPS */
260#ifdef RT_OS_WINDOWS
261
262/**
263 * Helper for vgsvcUtilGetFileVersion and attempts to read and parse
264 * FileVersion.
265 *
266 * @returns Success indicator.
267 */
268static bool vgsvcUtilGetFileVersionOwn(LPSTR pVerData, PDWORD pdwMajor, PDWORD pdwMinor, PDWORD pdwBuildNumber,
269 PDWORD pdwRevisionNumber)
270{
271 UINT cchStrValue = 0;
272 LPTSTR pStrValue = NULL;
273 if (!VerQueryValueA(pVerData, "\\StringFileInfo\\040904b0\\FileVersion", (LPVOID *)&pStrValue, &cchStrValue))
274 return false;
275
276 /** @todo r=bird: get rid of this. Avoid sscanf like the plague! */
277 if (sscanf(pStrValue, "%ld.%ld.%ld.%ld", pdwMajor, pdwMinor, pdwBuildNumber, pdwRevisionNumber) != 4)
278 return false;
279
280 return true;
281}
282
283
284/**
285 * Worker for VGSvcUtilWinGetFileVersionString.
286 *
287 * @returns VBox status code.
288 * @param pszFilename ASCII & ANSI & UTF-8 compliant name.
289 * @param pdwMajor Where to return the major version number.
290 * @param pdwMinor Where to return the minor version number.
291 * @param pdwBuildNumber Where to return the build number.
292 * @param pdwRevisionNumber Where to return the revision number.
293 */
294static int vgsvcUtilGetFileVersion(const char *pszFilename, PDWORD pdwMajor, PDWORD pdwMinor, PDWORD pdwBuildNumber,
295 PDWORD pdwRevisionNumber)
296{
297 int rc;
298
299 *pdwMajor = *pdwMinor = *pdwBuildNumber = *pdwRevisionNumber = 0;
300
301 /*
302 * Get the file version info.
303 */
304 DWORD dwHandleIgnored;
305 DWORD cbVerData = GetFileVersionInfoSizeA(pszFilename, &dwHandleIgnored);
306 if (cbVerData)
307 {
308 LPTSTR pVerData = (LPTSTR)RTMemTmpAllocZ(cbVerData);
309 if (pVerData)
310 {
311 if (GetFileVersionInfoA(pszFilename, dwHandleIgnored, cbVerData, pVerData))
312 {
313 /*
314 * Try query and parse the FileVersion string our selves first
315 * since this will give us the correct revision number when
316 * it goes beyond the range of an uint16_t / WORD.
317 */
318 if (vgsvcUtilGetFileVersionOwn(pVerData, pdwMajor, pdwMinor, pdwBuildNumber, pdwRevisionNumber))
319 rc = VINF_SUCCESS;
320 else
321 {
322 /* Fall back on VS_FIXEDFILEINFO */
323 UINT cbFileInfoIgnored = 0;
324 VS_FIXEDFILEINFO *pFileInfo = NULL;
325 if (VerQueryValue(pVerData, "\\", (LPVOID *)&pFileInfo, &cbFileInfoIgnored))
326 {
327 *pdwMajor = HIWORD(pFileInfo->dwFileVersionMS);
328 *pdwMinor = LOWORD(pFileInfo->dwFileVersionMS);
329 *pdwBuildNumber = HIWORD(pFileInfo->dwFileVersionLS);
330 *pdwRevisionNumber = LOWORD(pFileInfo->dwFileVersionLS);
331 rc = VINF_SUCCESS;
332 }
333 else
334 {
335 rc = RTErrConvertFromWin32(GetLastError());
336 VGSvcVerbose(3, "No file version value for file '%s' available! (%d / rc=%Rrc)\n",
337 pszFilename, GetLastError(), rc);
338 }
339 }
340 }
341 else
342 {
343 rc = RTErrConvertFromWin32(GetLastError());
344 VGSvcVerbose(0, "GetFileVersionInfo(%s) -> %u / %Rrc\n", pszFilename, GetLastError(), rc);
345 }
346
347 RTMemTmpFree(pVerData);
348 }
349 else
350 {
351 VGSvcVerbose(0, "Failed to allocate %u byte for file version info for '%s'\n", cbVerData, pszFilename);
352 rc = VERR_NO_TMP_MEMORY;
353 }
354 }
355 else
356 {
357 rc = RTErrConvertFromWin32(GetLastError());
358 VGSvcVerbose(3, "GetFileVersionInfoSize(%s) -> %u / %Rrc\n", pszFilename, GetLastError(), rc);
359 }
360 return rc;
361}
362
363
364/**
365 * Gets a re-formatted version string from the VS_FIXEDFILEINFO table.
366 *
367 * @returns VBox status code. The output buffer is always valid and the status
368 * code can safely be ignored.
369 *
370 * @param pszPath The base path.
371 * @param pszFilename The filename.
372 * @param pszVersion Where to return the version string.
373 * @param cbVersion The size of the version string buffer. This MUST be
374 * at least 2 bytes!
375 */
376int VGSvcUtilWinGetFileVersionString(const char *pszPath, const char *pszFilename, char *pszVersion, size_t cbVersion)
377{
378 /*
379 * We will ALWAYS return with a valid output buffer.
380 */
381 AssertReturn(cbVersion >= 2, VERR_BUFFER_OVERFLOW);
382 pszVersion[0] = '-';
383 pszVersion[1] = '\0';
384
385 /*
386 * Create the path and query the bits.
387 */
388 char szFullPath[RTPATH_MAX];
389 int rc = RTPathJoin(szFullPath, sizeof(szFullPath), pszPath, pszFilename);
390 if (RT_SUCCESS(rc))
391 {
392 DWORD dwMajor, dwMinor, dwBuild, dwRev;
393 rc = vgsvcUtilGetFileVersion(szFullPath, &dwMajor, &dwMinor, &dwBuild, &dwRev);
394 if (RT_SUCCESS(rc))
395 RTStrPrintf(pszVersion, cbVersion, "%u.%u.%ur%u", dwMajor, dwMinor, dwBuild, dwRev);
396 }
397 return rc;
398}
399
400#endif /* RT_OS_WINDOWS */
401
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use