VirtualBox

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

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

ExtPack: Fixes to IExtPack (QueryInterface can't be used for getting stuff from the ext pack, designed the plug-in interfaces). Bugfixes making 'VBoxManage list extpack' work when building with VBOX_WITH_EXTPACK_PUEL=1.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.5 KB
Line 
1/* $Id: ExtPackUtil.cpp 34073 2010-11-15 15:38:20Z 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 * Reads the extension pack descriptor.
32 *
33 * @returns NULL on success, pointer to an error message on failure (caller
34 * deletes it).
35 * @param a_pszDir The directory containing the description file.
36 * @param a_pExtPackDesc Where to store the extension pack descriptor.
37 * @param a_pObjInfo Where to store the object info for the file (unix
38 * attribs). Optional.
39 */
40iprt::MiniString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo)
41{
42 /*
43 * Clear the descriptor.
44 */
45 a_pExtPackDesc->strName.setNull();
46 a_pExtPackDesc->strDescription.setNull();
47 a_pExtPackDesc->strVersion.setNull();
48 a_pExtPackDesc->uRevision = 0;
49 a_pExtPackDesc->strMainModule.setNull();
50 a_pExtPackDesc->cPlugIns = 0;
51 a_pExtPackDesc->paPlugIns = NULL;
52
53 /*
54 * Validate, open and parse the XML file.
55 */
56 char szFilePath[RTPATH_MAX];
57 int vrc = RTPathJoin(szFilePath, sizeof(szFilePath), a_pszDir, VBOX_EXTPACK_DESCRIPTION_NAME);
58 if (RT_FAILURE(vrc))
59 return new iprt::MiniString("RTPathJoin failed with %Rrc", vrc);
60
61 RTFSOBJINFO ObjInfo;
62 vrc = RTPathQueryInfoEx(szFilePath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
63 if (RT_FAILURE(vrc))
64 return &(new iprt::MiniString())->printf("RTPathQueryInfoEx failed with %Rrc", vrc);
65 if (a_pObjInfo)
66 *a_pObjInfo = ObjInfo;
67 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
68 {
69 if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
70 return new iprt::MiniString("The XML file is symlinked, that is not allowed");
71 return &(new iprt::MiniString)->printf("The XML file is not a file (fMode=%#x)", ObjInfo.Attr.fMode);
72 }
73
74 xml::Document Doc;
75 xml::XmlFileParser Parser;
76 try
77 {
78 Parser.read(szFilePath, Doc);
79 }
80 catch (xml::XmlError Err)
81 {
82 return new iprt::MiniString(Err.what());
83 }
84
85 /*
86 * Get the main element and check its version.
87 */
88 const xml::ElementNode *pVBoxExtPackElm = Doc.getRootElement();
89 if ( !pVBoxExtPackElm
90 || strcmp(pVBoxExtPackElm->getName(), "VirtualBoxExtensionPack") != 0)
91 return new iprt::MiniString("No VirtualBoxExtensionPack element");
92
93 iprt::MiniString strFormatVersion;
94 if (!pVBoxExtPackElm->getAttributeValue("version", strFormatVersion))
95 return new iprt::MiniString("Missing format version");
96 if (!strFormatVersion.equals("1.0"))
97 return &(new iprt::MiniString("Unsupported format version: "))->append(strFormatVersion);
98
99 /*
100 * Read and validate the name.
101 */
102 const xml::ElementNode *pNameElm = pVBoxExtPackElm->findChildElement("Name");
103 if (!pNameElm)
104 return new iprt::MiniString("The 'Name' element is missing");
105 const char *pszName = pNameElm->getValue();
106 if (!VBoxExtPackIsValidName(pszName))
107 return &(new iprt::MiniString("Invalid name: "))->append(pszName);
108
109 const xml::ElementNode *pDescElm = pVBoxExtPackElm->findChildElement("Description");
110 if (!pDescElm)
111 return new iprt::MiniString("The 'Description' element is missing");
112 const char *pszDesc = pDescElm->getValue();
113 if (!pszDesc || *pszDesc == '\0')
114 return new iprt::MiniString("The 'Description' element is empty");
115 if (strpbrk(pszDesc, "\n\r\t\v\b") != NULL)
116 return new iprt::MiniString("The 'Description' must not contain control characters");
117
118 const xml::ElementNode *pVersionElm = pVBoxExtPackElm->findChildElement("Version");
119 if (!pVersionElm)
120 return new iprt::MiniString("The 'Version' element is missing");
121 const char *pszVersion = pVersionElm->getValue();
122 if (!pszVersion || *pszVersion == '\0')
123 return new iprt::MiniString("The 'Version' element is empty");
124 if (!VBoxExtPackIsValidVersionString(pszVersion))
125 return &(new iprt::MiniString("Invalid version string: "))->append(pszVersion);
126
127 uint32_t uRevision;
128 if (!pVersionElm->getAttributeValue("revision", uRevision))
129 uRevision = 0;
130
131 const xml::ElementNode *pMainModuleElm = pVBoxExtPackElm->findChildElement("MainModule");
132 if (!pMainModuleElm)
133 return new iprt::MiniString("The 'MainModule' element is missing");
134 const char *pszMainModule = pMainModuleElm->getValue();
135 if (!pszMainModule || *pszMainModule == '\0')
136 return new iprt::MiniString("The 'MainModule' element is empty");
137 if (!VBoxExtPackIsValidMainModuleString(pszMainModule))
138 return &(new iprt::MiniString("Invalid main module string: "))->append(pszMainModule);
139
140 /*
141 * Everything seems fine, fill in the return values and return successfully.
142 */
143 a_pExtPackDesc->strName = pszName;
144 a_pExtPackDesc->strDescription = pszDesc;
145 a_pExtPackDesc->strVersion = pszVersion;
146 a_pExtPackDesc->uRevision = uRevision;
147 a_pExtPackDesc->strMainModule = pszMainModule;
148
149 return NULL;
150}
151
152
153/**
154 * Frees all resources associated with a extension pack descriptor.
155 *
156 * @param a_pExtPackDesc The extension pack descriptor to free.
157 */
158void VBoxExtPackFreeDesc(PVBOXEXTPACKDESC a_pExtPackDesc)
159{
160 if (!a_pExtPackDesc)
161 return;
162
163 a_pExtPackDesc->strName.setNull();
164 a_pExtPackDesc->strDescription.setNull();
165 a_pExtPackDesc->strVersion.setNull();
166 a_pExtPackDesc->uRevision = 0;
167 a_pExtPackDesc->strMainModule.setNull();
168 a_pExtPackDesc->cPlugIns = 0;
169 RTMemFree(a_pExtPackDesc->paPlugIns);
170 a_pExtPackDesc->paPlugIns = NULL;
171}
172
173
174/**
175 * Extract the extension pack name from the tarball path.
176 *
177 * @returns String containing the name on success, the caller must delete it.
178 * NULL if no valid name was found or if we ran out of memory.
179 * @param pszTarball The path to the tarball.
180 */
181iprt::MiniString *VBoxExtPackExtractNameFromTarballPath(const char *pszTarball)
182{
183 /*
184 * Skip ahead to the filename part and count the number of characters
185 * that matches the criteria for a extension pack name.
186 */
187 const char *pszSrc = RTPathFilename(pszTarball);
188 if (!pszSrc)
189 return NULL;
190
191 size_t off = 0;
192 while (RT_C_IS_ALNUM(pszSrc[off]) || pszSrc[off] == ' ')
193 off++;
194
195 /*
196 * Check min and max name limits.
197 */
198 if ( off > VBOX_EXTPACK_NAME_MIN_LEN
199 || off < VBOX_EXTPACK_NAME_MIN_LEN)
200 return NULL;
201
202 /*
203 * Make a duplicate of the name and return it.
204 */
205 iprt::MiniString *pStrRet = new iprt::MiniString(pszSrc, off);
206 Assert(VBoxExtPackIsValidName(pStrRet->c_str()));
207 return pStrRet;
208}
209
210
211/**
212 * Validates the extension pack name.
213 *
214 * @returns true if valid, false if not.
215 * @param pszName The name to validate.
216 * @sa VBoxExtPackExtractNameFromTarballPath
217 */
218bool VBoxExtPackIsValidName(const char *pszName)
219{
220 if (!pszName)
221 return false;
222
223 /*
224 * Check the characters making up the name, only english alphabet
225 * characters, decimal digits and spaces are allowed.
226 */
227 size_t off = 0;
228 while (pszName[off])
229 {
230 if (!RT_C_IS_ALNUM(pszName[off]) && !pszName[off] == ' ')
231 return false;
232 off++;
233 }
234
235 /*
236 * Check min and max name limits.
237 */
238 if ( off > VBOX_EXTPACK_NAME_MAX_LEN
239 || off < VBOX_EXTPACK_NAME_MIN_LEN)
240 return false;
241
242 return true;
243}
244
245/**
246 * Validates the extension pack version string.
247 *
248 * @returns true if valid, false if not.
249 * @param pszVersion The version string to validate.
250 */
251bool VBoxExtPackIsValidVersionString(const char *pszVersion)
252{
253 if (!pszVersion || *pszVersion == '\0')
254 return false;
255
256 /* 1.x.y.z... */
257 for (;;)
258 {
259 if (!RT_C_IS_DIGIT(*pszVersion))
260 return false;
261 do
262 pszVersion++;
263 while (RT_C_IS_DIGIT(*pszVersion));
264 if (*pszVersion != '.')
265 break;
266 pszVersion++;
267 }
268
269 /* upper case string + numbers indicating the build type */
270 if (*pszVersion == '-' || *pszVersion == '_')
271 {
272 do
273 pszVersion++;
274 while ( RT_C_IS_DIGIT(*pszVersion)
275 || RT_C_IS_UPPER(*pszVersion)
276 || *pszVersion == '-'
277 || *pszVersion == '_');
278 }
279
280 /* revision or nothing */
281 if (*pszVersion != '\0')
282 {
283 if (*pszVersion != 'r')
284 return false;
285 do
286 pszVersion++;
287 while (RT_C_IS_DIGIT(*pszVersion));
288 }
289
290 return *pszVersion == '\0';
291}
292
293/**
294 * Validates the extension pack main module string.
295 *
296 * @returns true if valid, false if not.
297 * @param pszMainModule The main module string to validate.
298 */
299bool VBoxExtPackIsValidMainModuleString(const char *pszMainModule)
300{
301 if (!pszMainModule || *pszMainModule == '\0')
302 return false;
303
304 /* Restricted charset, no extensions (dots). */
305 while ( RT_C_IS_ALNUM(*pszMainModule)
306 || *pszMainModule == '-'
307 || *pszMainModule == '_')
308 pszMainModule++;
309
310 return *pszMainModule == '\0';
311}
312
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