VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedFolders/testcase/tstShflCase.cpp@ 100429

Last change on this file since 100429 was 99775, checked in by vboxsync, 21 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.0 KB
Line 
1/** @file
2 * Testcase for shared folder case conversion code.
3 */
4
5/*
6 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
24 * SPDX-License-Identifier: GPL-3.0-only
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP LOG_GROUP_MISC
32#define LOG_ENABLED
33#include <VBox/shflsvc.h>
34#include <VBox/log.h>
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/file.h>
38#include <iprt/fs.h>
39#include <iprt/dir.h>
40#include <iprt/initterm.h>
41#include <iprt/mem.h>
42#include <iprt/path.h>
43#include <iprt/string.h>
44#include <iprt/uni.h>
45#include <stdio.h>
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51/* Override slash for non-windows hosts. */
52#undef RTPATH_DELIMITER
53#define RTPATH_DELIMITER '\\'
54
55/* Use our own RTPath and RTDir methods. */
56#define RTPathQueryInfo rtPathQueryInfo
57#define RTDirOpenFiltered rtDirOpenFiltered
58#define RTDirClose rtDirClose
59#define RTDirReadEx rtDirReadEx
60
61
62/*********************************************************************************************************************************
63* Global Variables *
64*********************************************************************************************************************************/
65static int iDirList = 0;
66static int iDirFile = 0;
67
68static const char *g_apszDirs[] =
69{
70 "c:",
71 "c:\\test dir",
72 "c:\\test dir\\SUBDIR",
73};
74
75static const char *g_apszDirsC[] =
76{
77 ".",
78 "..",
79 "test dir"
80};
81
82static const char *g_apszTestdirEntries[] =
83{
84 ".",
85 "..",
86 "SUBDIR",
87 "a.bat",
88 "aTestJe.bat",
89 "aTestje.bat",
90 "b.bat",
91 "c.bat",
92 "d.bat",
93 "e.bat",
94 "f.bat",
95 "g.bat",
96 "h.bat",
97 "x.bat",
98 "z.bat",
99};
100
101static const char *g_apszSUBDIREntries[] =
102{
103 ".",
104 "..",
105 "a.bat",
106 "aTestJe.bat",
107 "aTestje.bat",
108 "b.bat",
109 "c.bat",
110 "d.bat",
111 "e.bat",
112 "f.bat",
113 "g.bat",
114 "h.bat",
115 "x.bat",
116 "z.bat",
117};
118
119static int rtDirOpenFiltered(RTDIR *phDir, const char *pszPath, RTDIRFILTER enmFilter, uint32_t fFlags)
120{
121 RT_NOREF2(enmFilter, fFlags);
122 if (!strcmp(pszPath, "c:\\*"))
123 iDirList = 1;
124 else if (!strcmp(pszPath, "c:\\test dir\\*"))
125 iDirList = 2;
126 else if (!strcmp(pszPath, "c:\\test dir\\SUBDIR\\*"))
127 iDirList = 3;
128 else
129 AssertFailed();
130
131 *phDir = (RTDIR)1;
132 return VINF_SUCCESS;
133}
134
135static int rtDirClose(RTDIR hDir)
136{
137 RT_NOREF1(hDir);
138 iDirFile = 0;
139 return VINF_SUCCESS;
140}
141
142static int rtDirReadEx(RTDIR hDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
143{
144 RT_NOREF4(hDir, pcbDirEntry, enmAdditionalAttribs, fFlags);
145 switch (iDirList)
146 {
147 case 1:
148 if (iDirFile == RT_ELEMENTS(g_apszDirsC))
149 return VERR_NO_MORE_FILES;
150 pDirEntry->cbName = (uint16_t)strlen(g_apszDirsC[iDirFile]);
151 strcpy(pDirEntry->szName, g_apszDirsC[iDirFile++]);
152 break;
153 case 2:
154 if (iDirFile == RT_ELEMENTS(g_apszTestdirEntries))
155 return VERR_NO_MORE_FILES;
156 pDirEntry->cbName = (uint16_t)strlen(g_apszTestdirEntries[iDirFile]);
157 strcpy(pDirEntry->szName, g_apszTestdirEntries[iDirFile++]);
158 break;
159 case 3:
160 if (iDirFile == RT_ELEMENTS(g_apszSUBDIREntries))
161 return VERR_NO_MORE_FILES;
162 pDirEntry->cbName = (uint16_t)strlen(g_apszSUBDIREntries[iDirFile]);
163 strcpy(pDirEntry->szName, g_apszSUBDIREntries[iDirFile++]);
164 break;
165 }
166 return VINF_SUCCESS;
167}
168
169static int rtPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
170{
171 RT_NOREF2(pObjInfo, enmAdditionalAttribs);
172 int cMax;
173
174 /* first try g_apszDirs */
175 for (unsigned int i=0;i<RT_ELEMENTS(g_apszDirs);i++)
176 {
177 if(!strcmp(pszPath, g_apszDirs[i]))
178 return VINF_SUCCESS;
179 }
180
181 const char **papszDirList;
182 switch (iDirList)
183 {
184 case 1:
185 cMax = RT_ELEMENTS(g_apszDirsC);
186 papszDirList = g_apszDirsC;
187 break;
188 case 2:
189 cMax = RT_ELEMENTS(g_apszTestdirEntries);
190 papszDirList = g_apszTestdirEntries;
191 break;
192 case 3:
193 cMax = RT_ELEMENTS(g_apszSUBDIREntries);
194 papszDirList = g_apszSUBDIREntries;
195 break;
196 default:
197 return VERR_FILE_NOT_FOUND;
198 }
199 for (int i = 0; i < cMax; i++)
200 {
201 if (!strcmp(pszPath, papszDirList[i]))
202 return VINF_SUCCESS;
203 }
204 return VERR_FILE_NOT_FOUND;
205}
206
207static int vbsfCorrectCasing(char *pszFullPath, char *pszStartComponent)
208{
209 PRTDIRENTRYEX pDirEntry = NULL;
210 uint32_t cbDirEntry;
211 size_t cbComponent;
212 int rc = VERR_FILE_NOT_FOUND;
213 RTDIR hSearch = NIL_RTDIR;
214 char szWildCard[4];
215
216 Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent));
217
218 cbComponent = strlen(pszStartComponent);
219
220 cbDirEntry = 4096;
221 pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
222 if (pDirEntry == 0)
223 {
224 AssertFailed();
225 return VERR_NO_MEMORY;
226 }
227
228 /** @todo this is quite inefficient, especially for directories with many files */
229 Assert(pszFullPath < pszStartComponent-1);
230 Assert(*(pszStartComponent-1) == RTPATH_DELIMITER);
231 *(pszStartComponent-1) = 0;
232 strcpy(pDirEntry->szName, pszFullPath);
233 szWildCard[0] = RTPATH_DELIMITER;
234 szWildCard[1] = '*';
235 szWildCard[2] = 0;
236 strcat(pDirEntry->szName, szWildCard);
237
238 rc = RTDirOpenFiltered(&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT, 0 /*fFlags*/);
239 *(pszStartComponent-1) = RTPATH_DELIMITER;
240 if (RT_FAILURE(rc))
241 goto end;
242
243 for(;;)
244 {
245 size_t cbDirEntrySize = cbDirEntry;
246
247 rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
248 if (rc == VERR_NO_MORE_FILES)
249 break;
250
251 if (VINF_SUCCESS != rc && rc != VWRN_NO_DIRENT_INFO)
252 {
253 AssertFailed();
254 if (rc != VERR_NO_TRANSLATION)
255 break;
256 else
257 continue;
258 }
259
260 Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0]));
261 if ( pDirEntry->cbName == cbComponent
262 && !RTStrICmp(pszStartComponent, &pDirEntry->szName[0]))
263 {
264 Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent));
265 strcpy(pszStartComponent, &pDirEntry->szName[0]);
266 rc = VINF_SUCCESS;
267 break;
268 }
269 }
270 if (RT_FAILURE(rc))
271 Log(("vbsfCorrectCasing %s failed with %d\n", pszStartComponent, rc));
272
273end:
274 if (pDirEntry)
275 RTMemFree(pDirEntry);
276
277 if (hSearch)
278 RTDirClose(hSearch);
279 return rc;
280}
281
282
283
284static int testCase(char *pszFullPath, bool fWildCard = false)
285{
286 int rc;
287 RTFSOBJINFO info;
288 char *pszWildCardComponent = NULL;
289
290 if (fWildCard)
291 {
292 /* strip off the last path component, that contains the wildcard(s) */
293 size_t len = strlen(pszFullPath);
294 char *src = pszFullPath + len - 1;
295
296 while(src > pszFullPath)
297 {
298 if (*src == RTPATH_DELIMITER)
299 break;
300 src--;
301 }
302 if (*src == RTPATH_DELIMITER)
303 {
304 bool fHaveWildcards = false;
305 char *temp = src;
306
307 while(*temp)
308 {
309 char uc = *temp;
310 /** @todo should depend on the guest OS */
311 if (uc == '*' || uc == '?' || uc == '>' || uc == '<' || uc == '"')
312 {
313 fHaveWildcards = true;
314 break;
315 }
316 temp++;
317 }
318
319 if (fHaveWildcards)
320 {
321 pszWildCardComponent = src;
322 *pszWildCardComponent = 0;
323 }
324 }
325 }
326
327 rc = RTPathQueryInfo(pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
328 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
329 {
330 size_t len = strlen(pszFullPath);
331 char *src = pszFullPath + len - 1;
332
333 Log(("Handle case insensitive guest fs on top of host case sensitive fs for %s\n", pszFullPath));
334
335 /* Find partial path that's valid */
336 while(src > pszFullPath)
337 {
338 if (*src == RTPATH_DELIMITER)
339 {
340 *src = 0;
341 rc = RTPathQueryInfo (pszFullPath, &info, RTFSOBJATTRADD_NOTHING);
342 *src = RTPATH_DELIMITER;
343 if (rc == VINF_SUCCESS)
344 {
345#ifdef DEBUG
346 *src = 0;
347 Log(("Found valid partial path %s\n", pszFullPath));
348 *src = RTPATH_DELIMITER;
349#endif
350 break;
351 }
352 }
353
354 src--;
355 }
356 Assert(*src == RTPATH_DELIMITER && RT_SUCCESS(rc));
357 if ( *src == RTPATH_DELIMITER
358 && RT_SUCCESS(rc))
359 {
360 src++;
361 for(;;)
362 {
363 char *end = src;
364 bool fEndOfString = true;
365
366 while(*end)
367 {
368 if (*end == RTPATH_DELIMITER)
369 break;
370 end++;
371 }
372
373 if (*end == RTPATH_DELIMITER)
374 {
375 fEndOfString = false;
376 *end = 0;
377 rc = RTPathQueryInfo(src, &info, RTFSOBJATTRADD_NOTHING);
378 Assert(rc == VINF_SUCCESS || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND);
379 }
380 else
381 if (end == src)
382 rc = VINF_SUCCESS; /* trailing delimiter */
383 else
384 rc = VERR_FILE_NOT_FOUND;
385
386 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
387 {
388 /* path component is invalid; try to correct the casing */
389 rc = vbsfCorrectCasing(pszFullPath, src);
390 if (RT_FAILURE(rc))
391 {
392 if (!fEndOfString)
393 *end = RTPATH_DELIMITER;
394 break;
395 }
396 }
397
398 if (fEndOfString)
399 break;
400
401 *end = RTPATH_DELIMITER;
402 src = end + 1;
403 }
404 if (RT_FAILURE(rc))
405 Log(("Unable to find suitable component rc=%d\n", rc));
406 }
407 else
408 rc = VERR_FILE_NOT_FOUND;
409
410 }
411 if (pszWildCardComponent)
412 *pszWildCardComponent = RTPATH_DELIMITER;
413
414 if (RT_SUCCESS(rc))
415 Log(("New valid path %s\n", pszFullPath));
416 else
417 Log(("Old invalid path %s\n", pszFullPath));
418 return rc;
419}
420
421
422int main()
423{
424 char szTest[128];
425
426 RTR3InitExeNoArguments(0);
427 RTLogFlush(NULL);
428 RTLogDestinations(NULL, "stdout");
429 RTLogGroupSettings(NULL, "misc=~0");
430 RTLogFlags(NULL, "unbuffered");
431
432 strcpy(szTest, "c:\\test Dir\\z.bAt");
433 testCase(szTest);
434 strcpy(szTest, "c:\\test dir\\z.bAt");
435 testCase(szTest);
436 strcpy(szTest, "c:\\test dir\\SUBDIR\\z.bAt");
437 testCase(szTest);
438 strcpy(szTest, "c:\\test dir\\SUBDiR\\atestje.bat");
439 testCase(szTest);
440 strcpy(szTest, "c:\\TEST dir\\subDiR\\aTestje.baT");
441 testCase(szTest);
442 strcpy(szTest, "c:\\TEST dir\\subDiR\\*");
443 testCase(szTest, true);
444 strcpy(szTest, "c:\\TEST dir\\subDiR\\");
445 testCase(szTest ,true);
446 strcpy(szTest, "c:\\test dir\\SUBDIR\\");
447 testCase(szTest);
448 strcpy(szTest, "c:\\test dir\\invalid\\SUBDIR\\test.bat");
449 testCase(szTest);
450 return 0;
451}
452
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