VirtualBox

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

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

os2/VBoxSF: Use UTF-16 for talking to the host, fits better with conversions APIs in kernel. Experimenting with using single request buffers for open/create. [fix]

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