VirtualBox

source: vbox/trunk/src/VBox/Additions/os2/VBoxSF/VBoxSFFind.cpp@ 75573

Last change on this file since 75573 was 75461, checked in by vboxsync, 6 years ago

os2/VBoxSF: warnings / gcc.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 34.2 KB
Line 
1/** $Id: VBoxSFFind.cpp 75461 2018-11-14 19:51:23Z vboxsync $ */
2/** @file
3 * VBoxSF - OS/2 Shared Folders, Find File IFS EPs.
4 */
5
6/*
7 * Copyright (c) 2007-2018 knut st. osmundsen <[email protected]>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#define LOG_GROUP LOG_GROUP_DEFAULT
36#include "VBoxSFInternal.h"
37
38#include <VBox/log.h>
39#include <iprt/asm.h>
40#include <iprt/assert.h>
41#include <iprt/mem.h>
42#include <iprt/path.h>
43#include <iprt/err.h>
44
45
46
47/**
48 * Checks if the given name is 8-dot-3 compatible.
49 *
50 * @returns true if compatible, false if not.
51 * @param pszName The name to inspect (UTF-8).
52 * @param cchName The length of the name.
53 * @param pwszTmp Buffer for test conversions.
54 * @param cwcTmp The size of the buffer.
55 */
56static bool vboxSfOs2IsUtf8Name8dot3(const char *pszName, size_t cchName, PRTUTF16 pwszTmp, size_t cwcTmp)
57{
58 /* Reject names that must be too long when using maximum UTF-8 encoding. */
59 if (cchName > (8 + 1 + 3) * 4)
60 return false;
61
62 /* First char cannot be a dot. */
63 if (*pszName == '.' || !*pszName)
64 return false;
65
66 /*
67 * To basic checks on code point level before doing full conversion.
68 */
69 const char *pszCursor = pszName;
70 for (uint32_t cuc = 0; ; cuc++)
71 {
72 RTUNICP uCp;
73 RTStrGetCpEx(&pszCursor, &uCp);
74 if (uCp == '.')
75 {
76 for (cuc = 0; ; cuc++)
77 {
78 RTStrGetCpEx(&pszCursor, &uCp);
79 if (!uCp)
80 break;
81 if (uCp == '.')
82 return false;
83 if (cuc >= 3)
84 return false;
85 }
86 break;
87 }
88 if (!uCp)
89 break;
90 if (cuc >= 8)
91 return false;
92 }
93
94 /*
95 * Convert to UTF-16 and then to native codepage.
96 */
97 size_t cwcActual = cwcTmp;
98 int rc = RTStrToUtf16Ex(pszName, cchName, &pwszTmp, cwcTmp, &cwcActual);
99 if (RT_SUCCESS(rc))
100 {
101 char *pszTmp = (char *)&pwszTmp[cwcActual + 1];
102 rc = KernStrFromUcs(NULL, pszTmp, pwszTmp, (cwcTmp - cwcActual - 1) * sizeof(RTUTF16), cwcActual);
103 if (rc != NO_ERROR)
104 {
105 LogRel(("vboxSfOs2IsUtf8Name8dot3: KernStrFromUcs failed: %d\n", rc));
106 return false;
107 }
108
109 /*
110 * Redo the check.
111 * Note! This could be bogus if a DBCS leadin sequence collides with '.'.
112 */
113 for (uint32_t cch = 0; ; cch++)
114 {
115 char ch = *pszTmp++;
116 if (ch == '.')
117 break;
118 if (ch == '\0')
119 return true;
120 if (cch >= 8)
121 return false;
122 }
123 for (uint32_t cch = 0; ; cch++)
124 {
125 char ch = *pszTmp++;
126 if (ch == '\0')
127 return true;
128 if (ch != '.')
129 return false;
130 if (cch >= 3)
131 return false;
132 }
133 }
134 else
135 LogRel(("vboxSfOs2IsUtf8Name8dot3: RTStrToUtf16Ex failed: %Rrc\n", rc));
136 return false;
137}
138
139
140/**
141 * @returns Updated pbDst on success, NULL on failure.
142 */
143static uint8_t *vboxSfOs2CopyUtf8Name(uint8_t *pbDst, PRTUTF16 pwszTmp, size_t cwcTmp, const char *pszSrc, size_t cchSrc)
144{
145 /* Convert UTF-8 to UTF-16: */
146 int rc = RTStrToUtf16Ex(pszSrc, cchSrc, &pwszTmp, cwcTmp, &cwcTmp);
147 if (RT_SUCCESS(rc))
148 {
149 char *pszDst = (char *)(pbDst + 1);
150 rc = KernStrFromUcs(NULL, pszDst, pwszTmp, CCHMAXPATHCOMP, cwcTmp);
151 if (rc == NO_ERROR)
152 {
153 size_t cchDst = strlen(pszDst);
154 *pbDst++ = (uint8_t)cchDst;
155 pbDst += cchDst;
156 *pbDst++ = '\0';
157 return pbDst;
158 }
159 LogRel(("vboxSfOs2CopyUtf8Name: KernStrFromUcs failed: %d\n", rc));
160 }
161 else
162 LogRel(("vboxSfOs2CopyUtf8Name: RTStrToUtf16Ex failed: %Rrc\n", rc));
163 return NULL;
164}
165
166
167/**
168 * @returns Updated pbDst on success, NULL on failure.
169 */
170static uint8_t *vboxSfOs2CopyUtf8NameAndUpperCase(uint8_t *pbDst, PRTUTF16 pwszTmp, size_t cwcTmp, const char *pszSrc, size_t cchSrc)
171{
172 /* Convert UTF-8 to UTF-16: */
173 int rc = RTStrToUtf16Ex(pszSrc, cchSrc, &pwszTmp, cwcTmp, &cwcTmp);
174 if (RT_SUCCESS(rc))
175 {
176 char *pszDst = (char *)(pbDst + 1);
177 rc = KernStrFromUcs(NULL, pszDst, RTUtf16ToUpper(pwszTmp), CCHMAXPATHCOMP, cwcTmp);
178 if (rc == NO_ERROR)
179 {
180 size_t cchDst = strlen(pszDst);
181 *pbDst++ = (uint8_t)cchDst;
182 pbDst += cchDst;
183 *pbDst++ = '\0';
184 return pbDst;
185 }
186 LogRel(("vboxSfOs2CopyUtf8NameAndUpperCase: KernStrFromUcs failed: %d\n", rc));
187 }
188 else
189 LogRel(("vboxSfOs2CopyUtf8NameAndUpperCase: RTStrToUtf16Ex failed: %Rrc\n", rc));
190 return NULL;
191}
192
193
194/**
195 * @returns Updated pbDst on success, NULL on failure.
196 */
197static uint8_t *vboxSfOs2CopyUtf16NameAndUpperCase(uint8_t *pbDst, PRTUTF16 pwszSrc, size_t cwcSrc)
198{
199 char *pszDst = (char *)(pbDst + 1);
200 APIRET rc = KernStrFromUcs(NULL, pszDst, RTUtf16ToUpper(pwszSrc), CCHMAXPATHCOMP, cwcSrc);
201 if (rc == NO_ERROR)
202 {
203 size_t cchDst = strlen(pszDst);
204 *pbDst++ = (uint8_t)cchDst;
205 pbDst += cchDst;
206 *pbDst++ = '\0';
207 return pbDst;
208 }
209 LogRel(("vboxSfOs2CopyUtf16NameAndUpperCase: KernStrFromUcs failed: %#x\n", rc));
210 return NULL;
211}
212
213
214
215/**
216 * Worker for FS32_FINDFIRST, FS32_FINDNEXT and FS32_FINDFROMNAME.
217 *
218 * @returns OS/2 status code.
219 * @param pFolder The folder we're working on.
220 * @param pFsFsd The search handle data.
221 * @param pDataBuf The search data buffer (some handle data there too).
222 * @param uLevel The info level to return.
223 * @param fFlags Position flag.
224 * @param pbData The output buffer.
225 * @param cbData The size of the output buffer.
226 * @param cMaxMatches The maximum number of matches to return.
227 * @param pcMatches Where to set the number of returned matches.
228 */
229static APIRET vboxSfOs2ReadDirEntries(PVBOXSFFOLDER pFolder, PVBOXSFFS pFsFsd, PVBOXSFFSBUF pDataBuf, ULONG uLevel, ULONG fFlags,
230 PBYTE pbData, ULONG cbData, USHORT cMaxMatches, PUSHORT pcMatches)
231{
232 APIRET rc = NO_ERROR;
233
234 /*
235 * If we're doing EAs, the buffer starts with an EAOP structure.
236 */
237 EAOP EaOp;
238 PEAOP pEaOpUser = NULL; /* Shut up gcc */
239 switch (uLevel)
240 {
241 case FI_LVL_EAS_FROM_LIST:
242 case FI_LVL_EAS_FROM_LIST_64:
243 case FI_LVL_EAS_FULL:
244 case FI_LVL_EAS_FULL_5:
245 case FI_LVL_EAS_FULL_8:
246 if (cbData >= sizeof(EaOp))
247 {
248 rc = KernCopyIn(&EaOp, pbData, sizeof(EaOp));
249 if (rc == NO_ERROR)
250 {
251 EaOp.fpGEAList = (PGEALIST)KernSelToFlat((uintptr_t)EaOp.fpGEAList);
252 EaOp.fpFEAList = NULL;
253
254 pEaOpUser = (PEAOP)pbData;
255 pbData += sizeof(*pEaOpUser);
256 cbData -= sizeof(*pEaOpUser);
257 break;
258 }
259 }
260 else
261 rc = ERROR_BUFFER_OVERFLOW;
262 Log(("vboxSfOs2ReadDirEntries: Failed to read EAOP: %u\n", rc));
263 return rc;
264 }
265
266 /*
267 * Do the reading.
268 */
269 USHORT cMatches;
270 for (cMatches = 0; cMatches < cMaxMatches;)
271 {
272 /*
273 * Do we need to fetch more directory entries?
274 */
275 PSHFLDIRINFO pEntry = pDataBuf->pEntry;
276 if ( pDataBuf->cEntriesLeft == 0
277 || pEntry == NULL /* paranoia */)
278 {
279 pDataBuf->pEntry = pEntry = (PSHFLDIRINFO)(pDataBuf + 1);
280 pDataBuf->cbValid = pDataBuf->cbBuf - sizeof(*pDataBuf);
281 int vrc = VbglR0SfDirInfo(&g_SfClient, &pFolder->hHostFolder, pFsFsd->hHostDir, pDataBuf->pFilter,
282 cMaxMatches == 1 ? SHFL_LIST_RETURN_ONE : 0, 0 /*index*/, &pDataBuf->cbValid,
283 pEntry, &pDataBuf->cEntriesLeft);
284 if (RT_SUCCESS(vrc))
285 {
286 AssertReturn(pDataBuf->cbValid >= RT_UOFFSETOF(SHFLDIRINFO, name.String), ERROR_SYS_INTERNAL);
287 AssertReturn(pDataBuf->cbValid >= RT_UOFFSETOF(SHFLDIRINFO, name.String) + pEntry->name.u16Size, ERROR_SYS_INTERNAL);
288 Log4(("vboxSfOs2ReadDirEntries: VbglR0SfDirInfo returned %#x matches in %#x bytes\n", pDataBuf->cEntriesLeft, pDataBuf->cbValid));
289 }
290 else
291 {
292 if (vrc == VERR_NO_MORE_FILES)
293 Log(("vboxSfOs2ReadDirEntries: VbglR0SfDirInfo failed %Rrc (%d,%d)\n", vrc, pDataBuf->cEntriesLeft, pDataBuf->cbValid));
294 else
295 Log4(("vboxSfOs2ReadDirEntries: VbglR0SfDirInfo returned VERR_NO_MORE_FILES (%d,%d)\n", pDataBuf->cEntriesLeft, pDataBuf->cbValid));
296 pDataBuf->pEntry = NULL;
297 pDataBuf->cEntriesLeft = 0;
298 if (cMatches == 0)
299 {
300 if (vrc == VERR_NO_MORE_FILES)
301 rc = ERROR_NO_MORE_FILES;
302 else
303 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_GEN_FAILURE);
304 }
305 break;
306 }
307 }
308
309 /*
310 * Do matching and stuff the return buffer.
311 */
312 if ( !((pEntry->Info.Attr.fMode >> RTFS_DOS_SHIFT) & pDataBuf->fExcludedAttribs)
313 && ((pEntry->Info.Attr.fMode >> RTFS_DOS_SHIFT) & pDataBuf->fMustHaveAttribs) == pDataBuf->fMustHaveAttribs
314 && ( pDataBuf->fLongFilenames
315 || pEntry->cucShortName
316 || vboxSfOs2IsUtf8Name8dot3((char *)pEntry->name.String.utf8, pEntry->name.u16Length,
317 pDataBuf->wszTmp, sizeof(pDataBuf->wszTmp))))
318 {
319 /*
320 * We stages all but FEAs (level 3, 4, 13 and 14).
321 */
322 PBYTE const pbUserBufStart = pbData; /* In case we need to skip a bad name. */
323 uint8_t *pbToCopy = pDataBuf->abStaging;
324 uint8_t *pbDst = pbToCopy;
325
326 /* Position (originally used for FS32_FINDFROMNAME 'position', but since reused
327 for FILEFINDBUF3::oNextEntryOffset and FILEFINDBUF4::oNextEntryOffset): */
328 if (fFlags & FF_GETPOS)
329 {
330 *(uint32_t *)pbDst = pFsFsd->offLastFile + 1;
331 pbDst += sizeof(uint32_t);
332 }
333
334 /* Dates: Creation, Access, Write */
335 vboxSfOs2DateTimeFromTimeSpec((FDATE *)pbDst, (FTIME *)(pbDst + 2), pEntry->Info.BirthTime, pDataBuf->cMinLocalTimeDelta);
336 pbDst += sizeof(FDATE) + sizeof(FTIME);
337 vboxSfOs2DateTimeFromTimeSpec((FDATE *)pbDst, (FTIME *)(pbDst + 2), pEntry->Info.AccessTime, pDataBuf->cMinLocalTimeDelta);
338 pbDst += sizeof(FDATE) + sizeof(FTIME);
339 vboxSfOs2DateTimeFromTimeSpec((FDATE *)pbDst, (FTIME *)(pbDst + 2), pEntry->Info.ModificationTime, pDataBuf->cMinLocalTimeDelta);
340 pbDst += sizeof(FDATE) + sizeof(FTIME);
341
342 /* File size, allocation size, attributes: */
343 if (uLevel >= FI_LVL_STANDARD_64)
344 {
345 *(uint64_t *)pbDst = pEntry->Info.cbObject;
346 pbDst += sizeof(uint64_t);
347 *(uint64_t *)pbDst = pEntry->Info.cbAllocated;
348 pbDst += sizeof(uint64_t);
349 *(uint32_t *)pbDst = (pEntry->Info.Attr.fMode & RTFS_DOS_MASK_OS2) >> RTFS_DOS_SHIFT;
350 pbDst += sizeof(uint32_t);
351 }
352 else
353 {
354 *(uint32_t *)pbDst = (uint32_t)RT_MIN(pEntry->Info.cbObject, _2G - 1);
355 pbDst += sizeof(uint32_t);
356 *(uint32_t *)pbDst = (uint32_t)RT_MIN(pEntry->Info.cbAllocated, _2G - 1);
357 pbDst += sizeof(uint32_t);
358 *(uint16_t *)pbDst = (uint16_t)((pEntry->Info.Attr.fMode & RTFS_DOS_MASK_OS2) >> RTFS_DOS_SHIFT);
359 pbDst += sizeof(uint16_t); /* (Curious: Who is expanding this to 32-bits for 32-bit callers? */
360 }
361
362 /* Extra EA related fields: */
363 if ( uLevel == FI_LVL_STANDARD
364 || uLevel == FI_LVL_STANDARD_64)
365 { /* nothing */ }
366 else if ( uLevel == FI_LVL_STANDARD_EASIZE
367 || uLevel == FI_LVL_STANDARD_EASIZE_64)
368 {
369 /* EA size: */
370 *(uint32_t *)pbDst = 0;
371 pbDst += sizeof(uint32_t);
372 }
373 else
374 {
375 /* Empty FEALIST - flush pending data first: */
376 uint32_t cbToCopy = pbDst - pbToCopy;
377 if (cbToCopy < cbData)
378 {
379 rc = KernCopyOut(pbData, pbToCopy, cbToCopy);
380 if (rc == NO_ERROR)
381 {
382 pbData += cbToCopy;
383 cbData -= cbToCopy;
384 pbDst = pbToCopy;
385
386 uint32_t cbWritten = 0;
387 EaOp.fpFEAList = (PFEALIST)pbData;
388 rc = vboxSfOs2MakeEmptyEaListEx(&EaOp, uLevel, &cbWritten, &pEaOpUser->oError);
389 if (rc == NO_ERROR)
390 {
391 cbData -= cbWritten;
392 pbData += cbWritten;
393 }
394 }
395 }
396 else
397 rc = ERROR_BUFFER_OVERFLOW;
398 if (rc != NO_ERROR)
399 break;
400 }
401
402 /* The length prefixed filename. */
403 if (pDataBuf->fLongFilenames)
404 pbDst = vboxSfOs2CopyUtf8Name(pbDst, pDataBuf->wszTmp, sizeof(pDataBuf->wszTmp),
405 (char *)pEntry->name.String.utf8, pEntry->name.u16Length);
406 else if (pEntry->cucShortName == 0)
407 pbDst = vboxSfOs2CopyUtf8NameAndUpperCase(pbDst, pDataBuf->wszTmp, sizeof(pDataBuf->wszTmp),
408 (char *)pEntry->name.String.utf8, pEntry->name.u16Length);
409 else
410 pbDst = vboxSfOs2CopyUtf16NameAndUpperCase(pbDst, pEntry->uszShortName, pEntry->cucShortName);
411 if (pbDst)
412 {
413 /*
414 * Copy out the staged data.
415 */
416 uint32_t cbToCopy = pbDst - pbToCopy;
417 if (cbToCopy <= cbData)
418 {
419 rc = KernCopyOut(pbData, pbToCopy, cbToCopy);
420 if (rc == NO_ERROR)
421 {
422 Log4(("vboxSfOs2ReadDirEntries: match #%u LB %#x: '%s'\n", cMatches, cbToCopy, pEntry->name.String.utf8));
423 Log4(("%.*Rhxd\n", cbToCopy, pbToCopy));
424
425 pbData += cbToCopy;
426 cbData -= cbToCopy;
427 pbDst = pbToCopy;
428
429 cMatches++;
430 pFsFsd->offLastFile++;
431 }
432 else
433 break;
434 }
435 else
436 {
437 rc = ERROR_BUFFER_OVERFLOW;
438 break;
439 }
440 }
441 else
442 {
443 /* Name conversion issue, just skip the entry. */
444 Log3(("vboxSfOs2ReadDirEntries: Skipping '%s' due to name conversion issue.\n", pEntry->name.String.utf8));
445 cbData -= pbUserBufStart - pbData;
446 pbData = pbUserBufStart;
447 }
448 }
449 else
450 Log3(("vboxSfOs2ReadDirEntries: fMode=%#x filter out by %#x/%#x; '%s'\n",
451 pEntry->Info.Attr.fMode, pDataBuf->fMustHaveAttribs, pDataBuf->fExcludedAttribs, pEntry->name.String.utf8));
452
453 /*
454 * Advance to the next directory entry from the host.
455 */
456 if (pDataBuf->cEntriesLeft-- > 1)
457 {
458 pDataBuf->pEntry = pEntry = (PSHFLDIRINFO)&pEntry->name.String.utf8[pEntry->name.u16Size];
459 uintptr_t offEntry = (uintptr_t)pEntry - (uintptr_t)(pDataBuf + 1);
460 AssertMsgReturn(offEntry + RT_UOFFSETOF(SHFLDIRINFO, name.String) <= pDataBuf->cbValid,
461 ("offEntry=%#x cbValid=%#x\n", offEntry, pDataBuf->cbValid), ERROR_SYS_INTERNAL);
462 AssertMsgReturn(offEntry + RT_UOFFSETOF(SHFLDIRINFO, name.String) + pEntry->name.u16Size <= pDataBuf->cbValid,
463 ("offEntry=%#x cbValid=%#x\n", offEntry, pDataBuf->cbValid), ERROR_SYS_INTERNAL);
464 }
465 else
466 pDataBuf->pEntry = NULL;
467 }
468
469 *pcMatches = cMatches;
470
471 /* Ignore buffer overflows if we've got matches to return. */
472 if (rc == ERROR_BUFFER_OVERFLOW && cMatches > 0)
473 rc = NO_ERROR;
474 return rc;
475}
476
477
478DECLASM(APIRET)
479FS32_FINDFIRST(PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszPath, LONG offCurDirEnd, ULONG fAttribs,
480 PFSFSI pFsFsi, PVBOXSFFS pFsFsd, PBYTE pbData, ULONG cbData, PUSHORT pcMatches, ULONG uLevel, ULONG fFlags)
481{
482 LogFlow(("pCdFsi=%p pCdFsd=%p pszPath=%p:{%s} offCurDirEnd=%d fAttribs=%#x pFsFsi=%p pFsFsd=%p pbData=%p cbData=%#x pcMatches=%p:{%#x} uLevel=%#x fFlags=%#x\n",
483 pCdFsi, pCdFsd, pszPath, pszPath, offCurDirEnd, fAttribs, pFsFsi, pFsFsd, pbData, cbData, pcMatches, *pcMatches, uLevel, fFlags));
484 USHORT const cMaxMatches = *pcMatches;
485 *pcMatches = 0;
486
487 /*
488 * Input validation.
489 */
490 switch (uLevel)
491 {
492 case FI_LVL_STANDARD:
493 case FI_LVL_STANDARD_64:
494 case FI_LVL_STANDARD_EASIZE:
495 case FI_LVL_STANDARD_EASIZE_64:
496 break;
497
498 case FI_LVL_EAS_FROM_LIST:
499 case FI_LVL_EAS_FROM_LIST_64:
500 if (cbData < sizeof(EAOP))
501 {
502 Log(("FS32_FINDFIRST: Buffer smaller than EAOP: %#x\n", cbData));
503 return ERROR_BUFFER_OVERFLOW;
504 }
505 break;
506
507 default:
508 LogRel(("FS32_FINDFIRST: Unsupported info level %u!\n", uLevel));
509 return ERROR_INVALID_LEVEL;
510 }
511
512 /*
513 * Resolve path to a folder and folder relative path.
514 */
515 PVBOXSFFOLDER pFolder;
516 PSHFLSTRING pStrFolderPath;
517 RT_NOREF(pCdFsi);
518 APIRET rc = vboxSfOs2ResolvePath(pszPath, pCdFsd, offCurDirEnd, &pFolder, &pStrFolderPath);
519 LogFlow(("FS32_FINDFIRST: vboxSfOs2ResolvePath: -> %u pFolder=%p\n", rc, pFolder));
520 if (rc == NO_ERROR)
521 {
522 /*
523 * Look for a wildcard filter at the end of the path, saving it all for
524 * later in NT filter speak if present.
525 */
526 PSHFLSTRING pFilter = NULL;
527 char *pszFilter = RTPathFilename((char *)pStrFolderPath->String.utf8);
528 if ( pszFilter
529 && ( strchr(pszFilter, '*') != NULL
530 || strchr(pszFilter, '?') != NULL))
531 {
532 if (strcmp(pszFilter, "*.*") == 0)
533 {
534 /* All files, no filtering needed. Just drop the filter expression from the directory path. */
535 *pszFilter = '\0';
536 pStrFolderPath->u16Length = (uint16_t)((uint8_t *)pszFilter - &pStrFolderPath->String.utf8[0]);
537 }
538 else
539 {
540 /* Duplicate the whole path. */
541 pFilter = vboxSfOs2StrDup(pStrFolderPath->String.ach, pStrFolderPath->u16Length);
542 if (pFilter)
543 {
544 /* Drop filter from directory path. */
545 *pszFilter = '\0';
546 pStrFolderPath->u16Length = (uint16_t)((uint8_t *)pszFilter - &pStrFolderPath->String.utf8[0]);
547
548 /* Convert filter part of the copy to NT speak. */
549 pszFilter = (char *)&pFilter->String.utf8[(uint8_t *)pszFilter - &pStrFolderPath->String.utf8[0]];
550 for (;;)
551 {
552 char ch = *pszFilter;
553 if (ch == '?')
554 *pszFilter = '>'; /* The DOS question mark: Matches one char, but dots and end-of-name eats them. */
555 else if (ch == '.')
556 {
557 char ch2 = pszFilter[1];
558 if (ch2 == '*' || ch2 == '?')
559 *pszFilter = '"'; /* The DOS dot: Matches a dot or end-of-name. */
560 }
561 else if (ch == '*')
562 {
563 if (pszFilter[1] == '.')
564 *pszFilter = '<'; /* The DOS star: Matches zero or more chars except the DOS dot.*/
565 }
566 else if (ch == '\0')
567 break;
568 pszFilter++;
569 }
570 }
571 else
572 rc = ERROR_NOT_ENOUGH_MEMORY;
573 }
574 }
575 /*
576 * When no wildcard is specified, we're supposed to return a single entry
577 * with the name in the final component. Exception is the root, where we
578 * always list the whole thing.
579 *
580 * Not sure if we'll ever see a trailing slash here (pszFilter == NULL),
581 * but if we do we should accept it only for the root.
582 */
583 else if (pszFilter)
584 {
585 pFilter = pStrFolderPath;
586 pStrFolderPath = vboxSfOs2StrDup(pFilter->String.ach, pszFilter - pFilter->String.ach);
587 if (!pStrFolderPath)
588 rc = ERROR_NOT_ENOUGH_MEMORY;
589 }
590 else if (!pszFilter && pStrFolderPath->u16Length > 1)
591 {
592 LogFlow(("FS32_FINDFIRST: Trailing slash (%s)\n", pStrFolderPath->String.utf8));
593 rc = ERROR_PATH_NOT_FOUND;
594 }
595 else
596 LogFlow(("FS32_FINDFIRST: Root dir (%s)\n", pStrFolderPath->String.utf8));
597
598 /*
599 * Make sure we've got a buffer for keeping unused search results.
600 */
601 PVBOXSFFSBUF pDataBuf = NULL;
602 if (rc == NO_ERROR)
603 {
604 pDataBuf = (PVBOXSFFSBUF)RTMemAlloc(cMaxMatches == 1 ? VBOXSFFSBUF_MIN_SIZE : _16K - ALLOC_HDR_SIZE);
605 if (pDataBuf)
606 pDataBuf->cbBuf = cMaxMatches == 1 ? VBOXSFFSBUF_MIN_SIZE : _16K - ALLOC_HDR_SIZE;
607 else
608 {
609 pDataBuf = (PVBOXSFFSBUF)RTMemAlloc(VBOXSFFSBUF_MIN_SIZE);
610 if (pDataBuf)
611 pDataBuf->cbBuf = VBOXSFFSBUF_MIN_SIZE;
612 else
613 rc = ERROR_NOT_ENOUGH_MEMORY;
614 }
615 }
616 if (rc == NO_ERROR)
617 {
618 /*
619 * Now, try open the directory for reading.
620 * We pre-use the data buffer for parameter passin to avoid
621 * wasting any stack space.
622 */
623 PSHFLCREATEPARMS pParams = (PSHFLCREATEPARMS)(pDataBuf + 1);
624 RT_ZERO(*pParams);
625 pParams->CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACT_OPEN_IF_EXISTS
626 | SHFL_CF_ACCESS_READ | SHFL_CF_ACCESS_ATTR_READ | SHFL_CF_ACCESS_DENYNONE;
627 int vrc = VbglR0SfCreate(&g_SfClient, &pFolder->hHostFolder, pStrFolderPath, pParams);
628 LogFlow(("FS32_FINDFIRST: VbglR0SfCreate(%s) -> %Rrc Result=%d fMode=%#x hHandle=%#RX64\n",
629 pStrFolderPath->String.ach, vrc, pParams->Result, pParams->Info.Attr.fMode, pParams->Handle));
630 if (RT_SUCCESS(vrc))
631 {
632 switch (pParams->Result)
633 {
634 case SHFL_FILE_EXISTS:
635 if (pParams->Handle != SHFL_HANDLE_NIL)
636 {
637 /*
638 * Initialize the structures.
639 */
640 pFsFsd->hHostDir = pParams->Handle;
641 pFsFsd->u32Magic = VBOXSFFS_MAGIC;
642 pFsFsd->pFolder = pFolder;
643 pFsFsd->pBuf = pDataBuf;
644 pFsFsd->offLastFile = 0;
645 pDataBuf->u32Magic = VBOXSFFSBUF_MAGIC;
646 pDataBuf->cbValid = 0;
647 pDataBuf->cEntriesLeft = 0;
648 pDataBuf->pEntry = NULL;
649 pDataBuf->pFilter = pFilter;
650 pDataBuf->fMustHaveAttribs = (uint8_t)((fAttribs >> 8) & (RTFS_DOS_MASK_OS2 >> RTFS_DOS_SHIFT));
651 pDataBuf->fExcludedAttribs = (uint8_t)(~fAttribs
652 & ( (RTFS_DOS_MASK_OS2 & ~(RTFS_DOS_ARCHIVED | RTFS_DOS_READONLY)
653 >> RTFS_DOS_SHIFT)));
654 pDataBuf->fLongFilenames = RT_BOOL(fAttribs & FF_ATTR_LONG_FILENAME);
655 pDataBuf->cMinLocalTimeDelta = vboxSfOs2GetLocalTimeDelta();
656
657 rc = vboxSfOs2ReadDirEntries(pFolder, pFsFsd, pDataBuf, uLevel, fFlags,
658 pbData, cbData, cMaxMatches ? cMaxMatches : UINT16_MAX, pcMatches);
659 if (rc == NO_ERROR)
660 {
661 uint32_t cRefs = ASMAtomicIncU32(&pFolder->cOpenSearches);
662 Assert(cRefs < _4K); RT_NOREF(cRefs);
663
664 /* We keep these on success: */
665 if (pFilter == pStrFolderPath)
666 pStrFolderPath = NULL;
667 pFilter = NULL;
668 pDataBuf = NULL;
669 pFolder = NULL;
670 }
671 else
672 {
673 vrc = VbglR0SfClose(&g_SfClient, &pFolder->hHostFolder, pFsFsd->hHostDir);
674 AssertRC(vrc);
675 pFsFsd->u32Magic = ~VBOXSFFS_MAGIC;
676 pDataBuf->u32Magic = ~VBOXSFFSBUF_MAGIC;
677 pFsFsd->pFolder = NULL;
678 pFsFsd->hHostDir = NULL;
679 }
680 }
681 else
682 {
683 LogFlow(("FS32_FINDFIRST: VbglR0SfCreate returns NIL handle for '%s'\n", pStrFolderPath->String.utf8));
684 rc = ERROR_PATH_NOT_FOUND;
685 }
686 break;
687
688 case SHFL_PATH_NOT_FOUND:
689 rc = ERROR_PATH_NOT_FOUND;
690 break;
691
692 default:
693 case SHFL_FILE_NOT_FOUND:
694 rc = ERROR_FILE_NOT_FOUND;
695 break;
696 }
697 }
698 else
699 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_GEN_FAILURE);
700 }
701
702 RTMemFree(pDataBuf);
703 if (pFilter != pStrFolderPath)
704 vboxSfOs2StrFree(pFilter);
705 vboxSfOs2ReleasePathAndFolder(pStrFolderPath, pFolder);
706 }
707
708 RT_NOREF_PV(pFsFsi);
709 LogFlow(("FS32_FINDFIRST: returns %u\n", rc));
710 return rc;
711}
712
713
714DECLASM(APIRET)
715FS32_FINDFROMNAME(PFSFSI pFsFsi, PVBOXSFFS pFsFsd, PBYTE pbData, ULONG cbData, PUSHORT pcMatches,
716 ULONG uLevel, ULONG uPosition, PCSZ pszName, ULONG fFlags)
717{
718 LogFlow(("FS32_FINDFROMNAME: pFsFsi=%p pFsFsd=%p pbData=%p cbData=%#x pcMatches=%p:{%#x} uLevel=%#x uPosition=%#x pszName=%p:{%s} fFlags=%#x\n",
719 pFsFsi, pFsFsd, pbData, cbData, pcMatches, *pcMatches, uLevel, uPosition, pszName, pszName, fFlags));
720
721 /*
722 * Input validation.
723 */
724 USHORT const cMaxMatches = *pcMatches;
725 *pcMatches = 0;
726 AssertReturn(pFsFsd->u32Magic == VBOXSFFS_MAGIC, ERROR_SYS_INTERNAL);
727 PVBOXSFFOLDER pFolder = pFsFsd->pFolder;
728 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
729 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
730 Assert(pFolder->cOpenSearches > 0);
731 PVBOXSFFSBUF pDataBuf = pFsFsd->pBuf;
732 AssertReturn(pDataBuf, ERROR_SYS_INTERNAL);
733 Assert(pDataBuf->u32Magic == VBOXSFFSBUF_MAGIC);
734
735 switch (uLevel)
736 {
737 case FI_LVL_STANDARD:
738 case FI_LVL_STANDARD_64:
739 case FI_LVL_STANDARD_EASIZE:
740 case FI_LVL_STANDARD_EASIZE_64:
741 break;
742
743 case FI_LVL_EAS_FROM_LIST:
744 case FI_LVL_EAS_FROM_LIST_64:
745 Log(("FS32_FINDFIRST: FI_LVL_EAS_FROM_LIST[_64] -> ERROR_EAS_NOT_SUPPORTED\n"));
746 return ERROR_EAS_NOT_SUPPORTED;
747
748 default:
749 LogRel(("FS32_FINDFIRST: Unsupported info level %u!\n", uLevel));
750 return ERROR_INVALID_LEVEL;
751 }
752
753 /*
754 * Check if we're just continuing. This is usually the case.
755 */
756 APIRET rc;
757 if (uPosition == pFsFsd->offLastFile)
758 rc = vboxSfOs2ReadDirEntries(pFolder, pFsFsd, pDataBuf, uLevel, fFlags, pbData, cbData,
759 cMaxMatches ? cMaxMatches : UINT16_MAX, pcMatches);
760 else
761 {
762 Log(("TODO: uPosition differs: %#x, expected %#x (%s)\n", uPosition, pFsFsd->offLastFile, pszName));
763 rc = vboxSfOs2ReadDirEntries(pFolder, pFsFsd, pDataBuf, uLevel, fFlags, pbData, cbData,
764 cMaxMatches ? cMaxMatches : UINT16_MAX, pcMatches);
765 }
766
767 RT_NOREF(pFsFsi, pszName);
768 LogFlow(("FS32_FINDFROMNAME: returns %u (*pcMatches=%#x)\n", rc, *pcMatches));
769 return rc;
770}
771
772
773DECLASM(APIRET)
774FS32_FINDNEXT(PFSFSI pFsFsi, PVBOXSFFS pFsFsd, PBYTE pbData, ULONG cbData, PUSHORT pcMatches, ULONG uLevel, ULONG fFlags)
775{
776 LogFlow(("FS32_FINDNEXT: pFsFsi=%p pFsFsd=%p pbData=%p cbData=%#x pcMatches=%p:{%#x} uLevel=%#x fFlags=%#x\n",
777 pFsFsi, pFsFsd, pbData, cbData, pcMatches, *pcMatches, uLevel, fFlags));
778
779 /*
780 * Input validation.
781 */
782 USHORT const cMaxMatches = *pcMatches;
783 *pcMatches = 0;
784 AssertReturn(pFsFsd->u32Magic == VBOXSFFS_MAGIC, ERROR_SYS_INTERNAL);
785 PVBOXSFFOLDER pFolder = pFsFsd->pFolder;
786 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
787 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
788 Assert(pFolder->cOpenSearches > 0);
789 PVBOXSFFSBUF pDataBuf = pFsFsd->pBuf;
790 AssertReturn(pDataBuf, ERROR_SYS_INTERNAL);
791 Assert(pDataBuf->u32Magic == VBOXSFFSBUF_MAGIC);
792
793 switch (uLevel)
794 {
795 case FI_LVL_STANDARD:
796 case FI_LVL_STANDARD_64:
797 case FI_LVL_STANDARD_EASIZE:
798 case FI_LVL_STANDARD_EASIZE_64:
799 break;
800
801 case FI_LVL_EAS_FROM_LIST:
802 case FI_LVL_EAS_FROM_LIST_64:
803 Log(("FS32_FINDFIRST: FI_LVL_EAS_FROM_LIST[_64] -> ERROR_EAS_NOT_SUPPORTED\n"));
804 return ERROR_EAS_NOT_SUPPORTED;
805
806 default:
807 LogRel(("FS32_FINDFIRST: Unsupported info level %u!\n", uLevel));
808 return ERROR_INVALID_LEVEL;
809 }
810
811 /*
812 * Read more.
813 */
814 APIRET rc = vboxSfOs2ReadDirEntries(pFolder, pFsFsd, pDataBuf, uLevel, fFlags, pbData, cbData,
815 cMaxMatches ? cMaxMatches : UINT16_MAX, pcMatches);
816
817 NOREF(pFsFsi);
818 LogFlow(("FS32_FINDNEXT: returns %u (*pcMatches=%#x)\n", rc, *pcMatches));
819 return rc;
820}
821
822
823DECLASM(APIRET)
824FS32_FINDCLOSE(PFSFSI pFsFsi, PVBOXSFFS pFsFsd)
825{
826 /*
827 * Input validation.
828 */
829 AssertReturn(pFsFsd->u32Magic == VBOXSFFS_MAGIC, ERROR_SYS_INTERNAL);
830 PVBOXSFFOLDER pFolder = pFsFsd->pFolder;
831 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
832 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
833 Assert(pFolder->cOpenSearches > 0);
834 PVBOXSFFSBUF pDataBuf = pFsFsd->pBuf;
835 AssertReturn(pDataBuf, ERROR_SYS_INTERNAL);
836 Assert(pDataBuf->u32Magic == VBOXSFFSBUF_MAGIC);
837
838 /*
839 * Close it.
840 */
841 if (pFsFsd->hHostDir != SHFL_HANDLE_NIL)
842 {
843 int vrc = VbglR0SfClose(&g_SfClient, &pFolder->hHostFolder, pFsFsd->hHostDir);
844 AssertRC(vrc);
845 }
846
847 pFsFsd->u32Magic = ~VBOXSFFS_MAGIC;
848 pFsFsd->hHostDir = SHFL_HANDLE_NIL;
849 pFsFsd->pFolder = NULL;
850 pFsFsd->pBuf = NULL;
851 vboxSfOs2StrFree(pDataBuf->pFilter);
852 pDataBuf->pFilter = NULL;
853 pDataBuf->u32Magic = ~VBOXSFFSBUF_MAGIC;
854 pDataBuf->cbBuf = 0;
855 RTMemFree(pDataBuf);
856
857 uint32_t cRefs = ASMAtomicDecU32(&pFolder->cOpenSearches);
858 Assert(cRefs < _4K); RT_NOREF(cRefs);
859 vboxSfOs2ReleaseFolder(pFolder);
860
861 RT_NOREF(pFsFsi);
862 LogFlow(("FS32_FINDCLOSE: returns NO_ERROR\n"));
863 return NO_ERROR;
864}
865
866
867
868
869
870DECLASM(APIRET)
871FS32_FINDNOTIFYFIRST(PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszPath, LONG offCurDirEnd, ULONG fAttribs,
872 PUSHORT phHandle, PBYTE pbData, ULONG cbData, PUSHORT pcMatches,
873 ULONG uLevel, ULONG fFlags)
874{
875 RT_NOREF(pCdFsi, pCdFsd, pszPath, offCurDirEnd, fAttribs, phHandle, pbData, cbData, pcMatches, uLevel, fFlags);
876 return ERROR_NOT_SUPPORTED;
877}
878
879
880DECLASM(APIRET)
881FS32_FINDNOTIFYNEXT(ULONG hHandle, PBYTE pbData, ULONG cbData, PUSHORT pcMatchs, ULONG uLevel, ULONG cMsTimeout)
882{
883 RT_NOREF(hHandle, pbData, cbData, pcMatchs, uLevel, cMsTimeout);
884 return ERROR_NOT_SUPPORTED;
885}
886
887
888DECLASM(APIRET)
889FS32_FINDNOTIFYCLOSE(ULONG hHandle)
890{
891 NOREF(hHandle);
892 return ERROR_NOT_SUPPORTED;
893}
894
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