VirtualBox

source: vbox/trunk/src/VBox/Main/ExtPackUtil.cpp@ 34277

Last change on this file since 34277 was 34244, checked in by vboxsync, 14 years ago

Main,Config.kmk,VBoxManage,ExtPacks: Moved the VRDE bits from IVirtualBox to the extension packs; changed ISystemProperties and IVRDEServer to talk about VRDE extension packs instead of VRDE libraries.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.4 KB
Line 
1/* $Id: ExtPackUtil.cpp 34244 2010-11-22 14:31:02Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Extension Pack Utilities and definitions, VBoxC, VBoxSVC, ++.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * Oracle Corporation confidential
10 * All rights reserved
11 */
12
13
14/*******************************************************************************
15* Header Files *
16*******************************************************************************/
17#include "include/ExtPackUtil.h"
18
19#include <iprt/ctype.h>
20#include <iprt/dir.h>
21#include <iprt/file.h>
22#include <iprt/param.h>
23#include <iprt/path.h>
24#include <iprt/string.h>
25#include <iprt/cpp/xml.h>
26
27#include <VBox/log.h>
28
29
30/**
31 * Worker for VBoxExtPackLoadDesc that loads the plug-in descriptors.
32 *
33 * @returns Same as VBoxExtPackLoadDesc.
34 * @param pVBoxExtPackElm
35 * @param pcPlugIns Where to return the number of plug-ins in the
36 * array.
37 * @param paPlugIns Where to return the plug-in descriptor array.
38 * (RTMemFree it even on failure)
39 */
40static iprt::MiniString *
41vboxExtPackLoadPlugInDescs(const xml::ElementNode *pVBoxExtPackElm,
42 uint32_t *pcPlugIns, PVBOXEXTPACKPLUGINDESC *paPlugIns)
43{
44 *pcPlugIns = 0;
45 *paPlugIns = NULL;
46
47 /** @todo plug-ins */
48 NOREF(pVBoxExtPackElm);
49
50 return NULL;
51}
52
53/**
54 * Reads the extension pack descriptor.
55 *
56 * @returns NULL on success, pointer to an error message on failure (caller
57 * deletes it).
58 * @param a_pszDir The directory containing the description file.
59 * @param a_pExtPackDesc Where to store the extension pack descriptor.
60 * @param a_pObjInfo Where to store the object info for the file (unix
61 * attribs). Optional.
62 */
63iprt::MiniString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo)
64{
65 /*
66 * Clear the descriptor.
67 */
68 a_pExtPackDesc->strName.setNull();
69 a_pExtPackDesc->strDescription.setNull();
70 a_pExtPackDesc->strVersion.setNull();
71 a_pExtPackDesc->uRevision = 0;
72 a_pExtPackDesc->strMainModule.setNull();
73 a_pExtPackDesc->strVrdeModule.setNull();
74 a_pExtPackDesc->cPlugIns = 0;
75 a_pExtPackDesc->paPlugIns = NULL;
76
77 /*
78 * Validate, open and parse the XML file.
79 */
80 char szFilePath[RTPATH_MAX];
81 int vrc = RTPathJoin(szFilePath, sizeof(szFilePath), a_pszDir, VBOX_EXTPACK_DESCRIPTION_NAME);
82 if (RT_FAILURE(vrc))
83 return new iprt::MiniString("RTPathJoin failed with %Rrc", vrc);
84
85 RTFSOBJINFO ObjInfo;
86 vrc = RTPathQueryInfoEx(szFilePath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
87 if (RT_FAILURE(vrc))
88 return &(new iprt::MiniString())->printf("RTPathQueryInfoEx failed with %Rrc", vrc);
89 if (a_pObjInfo)
90 *a_pObjInfo = ObjInfo;
91 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
92 {
93 if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
94 return new iprt::MiniString("The XML file is symlinked, that is not allowed");
95 return &(new iprt::MiniString)->printf("The XML file is not a file (fMode=%#x)", ObjInfo.Attr.fMode);
96 }
97
98 xml::Document Doc;
99 xml::XmlFileParser Parser;
100 try
101 {
102 Parser.read(szFilePath, Doc);
103 }
104 catch (xml::XmlError Err)
105 {
106 return new iprt::MiniString(Err.what());
107 }
108
109 /*
110 * Get the main element and check its version.
111 */
112 const xml::ElementNode *pVBoxExtPackElm = Doc.getRootElement();
113 if ( !pVBoxExtPackElm
114 || strcmp(pVBoxExtPackElm->getName(), "VirtualBoxExtensionPack") != 0)
115 return new iprt::MiniString("No VirtualBoxExtensionPack element");
116
117 iprt::MiniString strFormatVersion;
118 if (!pVBoxExtPackElm->getAttributeValue("version", strFormatVersion))
119 return new iprt::MiniString("Missing format version");
120 if (!strFormatVersion.equals("1.0"))
121 return &(new iprt::MiniString("Unsupported format version: "))->append(strFormatVersion);
122
123 /*
124 * Read and validate mandatory bits.
125 */
126 const xml::ElementNode *pNameElm = pVBoxExtPackElm->findChildElement("Name");
127 if (!pNameElm)
128 return new iprt::MiniString("The 'Name' element is missing");
129 const char *pszName = pNameElm->getValue();
130 if (!VBoxExtPackIsValidName(pszName))
131 return &(new iprt::MiniString("Invalid name: "))->append(pszName);
132
133 const xml::ElementNode *pDescElm = pVBoxExtPackElm->findChildElement("Description");
134 if (!pDescElm)
135 return new iprt::MiniString("The 'Description' element is missing");
136 const char *pszDesc = pDescElm->getValue();
137 if (!pszDesc || *pszDesc == '\0')
138 return new iprt::MiniString("The 'Description' element is empty");
139 if (strpbrk(pszDesc, "\n\r\t\v\b") != NULL)
140 return new iprt::MiniString("The 'Description' must not contain control characters");
141
142 const xml::ElementNode *pVersionElm = pVBoxExtPackElm->findChildElement("Version");
143 if (!pVersionElm)
144 return new iprt::MiniString("The 'Version' element is missing");
145 const char *pszVersion = pVersionElm->getValue();
146 if (!pszVersion || *pszVersion == '\0')
147 return new iprt::MiniString("The 'Version' element is empty");
148 if (!VBoxExtPackIsValidVersionString(pszVersion))
149 return &(new iprt::MiniString("Invalid version string: "))->append(pszVersion);
150
151 uint32_t uRevision;
152 if (!pVersionElm->getAttributeValue("revision", uRevision))
153 uRevision = 0;
154
155 const xml::ElementNode *pMainModuleElm = pVBoxExtPackElm->findChildElement("MainModule");
156 if (!pMainModuleElm)
157 return new iprt::MiniString("The 'MainModule' element is missing");
158 const char *pszMainModule = pMainModuleElm->getValue();
159 if (!pszMainModule || *pszMainModule == '\0')
160 return new iprt::MiniString("The 'MainModule' element is empty");
161 if (!VBoxExtPackIsValidModuleString(pszMainModule))
162 return &(new iprt::MiniString("Invalid main module string: "))->append(pszMainModule);
163
164 /*
165 * The VRDE module, optional.
166 * Accept both none and empty as tokens of no VRDE module.
167 */
168 const char *pszVrdeModule = NULL;
169 const xml::ElementNode *pVrdeModuleElm = pVBoxExtPackElm->findChildElement("VRDEModule");
170 if (pVrdeModuleElm)
171 {
172 pszVrdeModule = pVrdeModuleElm->getValue();
173 if (!pszVrdeModule || *pszVrdeModule == '\0')
174 pszVrdeModule = NULL;
175 else if (!VBoxExtPackIsValidModuleString(pszVrdeModule))
176 return &(new iprt::MiniString("Invalid VRDE module string: "))->append(pszVrdeModule);
177 }
178
179 /*
180 * Parse plug-in descriptions.
181 */
182 uint32_t cPlugIns = 0;
183 PVBOXEXTPACKPLUGINDESC paPlugIns = NULL;
184 iprt::MiniString *pstrRet = vboxExtPackLoadPlugInDescs(pVBoxExtPackElm, &cPlugIns, &paPlugIns);
185 if (pstrRet)
186 {
187 RTMemFree(paPlugIns);
188 return pstrRet;
189 }
190
191 /*
192 * Everything seems fine, fill in the return values and return successfully.
193 */
194 a_pExtPackDesc->strName = pszName;
195 a_pExtPackDesc->strDescription = pszDesc;
196 a_pExtPackDesc->strVersion = pszVersion;
197 a_pExtPackDesc->uRevision = uRevision;
198 a_pExtPackDesc->strMainModule = pszMainModule;
199 a_pExtPackDesc->strVrdeModule = pszVrdeModule;
200 a_pExtPackDesc->cPlugIns = cPlugIns;
201 a_pExtPackDesc->paPlugIns = paPlugIns;
202
203 return NULL;
204}
205
206
207/**
208 * Frees all resources associated with a extension pack descriptor.
209 *
210 * @param a_pExtPackDesc The extension pack descriptor which members
211 * should be freed.
212 */
213void VBoxExtPackFreeDesc(PVBOXEXTPACKDESC a_pExtPackDesc)
214{
215 if (!a_pExtPackDesc)
216 return;
217
218 a_pExtPackDesc->strName.setNull();
219 a_pExtPackDesc->strDescription.setNull();
220 a_pExtPackDesc->strVersion.setNull();
221 a_pExtPackDesc->uRevision = 0;
222 a_pExtPackDesc->strMainModule.setNull();
223 a_pExtPackDesc->strVrdeModule.setNull();
224 a_pExtPackDesc->cPlugIns = 0;
225 RTMemFree(a_pExtPackDesc->paPlugIns);
226 a_pExtPackDesc->paPlugIns = NULL;
227}
228
229
230/**
231 * Extract the extension pack name from the tarball path.
232 *
233 * @returns String containing the name on success, the caller must delete it.
234 * NULL if no valid name was found or if we ran out of memory.
235 * @param pszTarball The path to the tarball.
236 */
237iprt::MiniString *VBoxExtPackExtractNameFromTarballPath(const char *pszTarball)
238{
239 /*
240 * Skip ahead to the filename part and count the number of characters
241 * that matches the criteria for a extension pack name.
242 */
243 const char *pszSrc = RTPathFilename(pszTarball);
244 if (!pszSrc)
245 return NULL;
246
247 size_t off = 0;
248 while (RT_C_IS_ALNUM(pszSrc[off]) || pszSrc[off] == ' ')
249 off++;
250
251 /*
252 * Check min and max name limits.
253 */
254 if ( off > VBOX_EXTPACK_NAME_MIN_LEN
255 || off < VBOX_EXTPACK_NAME_MIN_LEN)
256 return NULL;
257
258 /*
259 * Make a duplicate of the name and return it.
260 */
261 iprt::MiniString *pStrRet = new iprt::MiniString(pszSrc, off);
262 Assert(VBoxExtPackIsValidName(pStrRet->c_str()));
263 return pStrRet;
264}
265
266
267/**
268 * Validates the extension pack name.
269 *
270 * @returns true if valid, false if not.
271 * @param pszName The name to validate.
272 * @sa VBoxExtPackExtractNameFromTarballPath
273 */
274bool VBoxExtPackIsValidName(const char *pszName)
275{
276 if (!pszName)
277 return false;
278
279 /*
280 * Check the characters making up the name, only english alphabet
281 * characters, decimal digits and spaces are allowed.
282 */
283 size_t off = 0;
284 while (pszName[off])
285 {
286 if (!RT_C_IS_ALNUM(pszName[off]) && pszName[off] != ' ')
287 return false;
288 off++;
289 }
290
291 /*
292 * Check min and max name limits.
293 */
294 if ( off > VBOX_EXTPACK_NAME_MAX_LEN
295 || off < VBOX_EXTPACK_NAME_MIN_LEN)
296 return false;
297
298 return true;
299}
300
301/**
302 * Validates the extension pack version string.
303 *
304 * @returns true if valid, false if not.
305 * @param pszVersion The version string to validate.
306 */
307bool VBoxExtPackIsValidVersionString(const char *pszVersion)
308{
309 if (!pszVersion || *pszVersion == '\0')
310 return false;
311
312 /* 1.x.y.z... */
313 for (;;)
314 {
315 if (!RT_C_IS_DIGIT(*pszVersion))
316 return false;
317 do
318 pszVersion++;
319 while (RT_C_IS_DIGIT(*pszVersion));
320 if (*pszVersion != '.')
321 break;
322 pszVersion++;
323 }
324
325 /* upper case string + numbers indicating the build type */
326 if (*pszVersion == '-' || *pszVersion == '_')
327 {
328 do
329 pszVersion++;
330 while ( RT_C_IS_DIGIT(*pszVersion)
331 || RT_C_IS_UPPER(*pszVersion)
332 || *pszVersion == '-'
333 || *pszVersion == '_');
334 }
335
336 /* revision or nothing */
337 if (*pszVersion != '\0')
338 {
339 if (*pszVersion != 'r')
340 return false;
341 do
342 pszVersion++;
343 while (RT_C_IS_DIGIT(*pszVersion));
344 }
345
346 return *pszVersion == '\0';
347}
348
349/**
350 * Validates an extension pack module string.
351 *
352 * @returns true if valid, false if not.
353 * @param pszModule The module string to validate.
354 */
355bool VBoxExtPackIsValidModuleString(const char *pszModule)
356{
357 if (!pszModule || *pszModule == '\0')
358 return false;
359
360 /* Restricted charset, no extensions (dots). */
361 while ( RT_C_IS_ALNUM(*pszModule)
362 || *pszModule == '-'
363 || *pszModule == '_')
364 pszModule++;
365
366 return *pszModule == '\0';
367}
368
Note: See TracBrowser for help on using the repository browser.

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