VirtualBox

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

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

scm --update-copyright-year

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