VirtualBox

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

Last change on this file was 93071, checked in by vboxsync, 2 years ago

os2/VBoxSF: Fixed off by one check in vboxSfOs2MakeEmptyEaListEx. Fixed problem with missing FEAList length when called from vboxSfOs2ReadDirEntries. ticketref:19453

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 88.4 KB
Line 
1/** $Id: VBoxSF.cpp 93071 2021-12-24 00:12:04Z vboxsync $ */
2/** @file
3 * VBoxSF - OS/2 Shared Folders, the FS and FSD level IFS EPs
4 */
5
6/*
7 * Copyright (c) 2007 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/assert.h>
40#include <iprt/ctype.h>
41#include <iprt/err.h>
42#include <iprt/mem.h>
43#include <iprt/path.h>
44
45#include <iprt/asm.h>
46#include <iprt/asm-amd64-x86.h>
47
48
49/*********************************************************************************************************************************
50* Defined Constants And Macros *
51*********************************************************************************************************************************/
52/** Max folder name length, including terminator.
53 * Easier to deal with stack buffers if we put a reasonable limit on the. */
54#define VBOXSFOS2_MAX_FOLDER_NAME 64
55
56
57/*********************************************************************************************************************************
58* Global Variables *
59*********************************************************************************************************************************/
60/** VMMDEV_HVF_XXX (set during init). */
61uint32_t g_fHostFeatures = 0;
62/** The shared mutex protecting folders list, drives and the connection. */
63MutexLock_t g_MtxFolders;
64/** The shared folder service client structure. */
65VBGLSFCLIENT g_SfClient;
66/** Set if g_SfClient is valid, clear if not. */
67bool g_fIsConnectedToService = false;
68/** List of active folder (PVBOXSFFOLDER). */
69RTLISTANCHOR g_FolderHead;
70/** This is incremented everytime g_FolderHead is modified. */
71uint32_t volatile g_uFolderRevision;
72/** Folders mapped on drive letters. Pointers include a reference. */
73PVBOXSFFOLDER g_apDriveFolders[26];
74
75
76
77/**
78 * Generic IPRT -> OS/2 status code converter.
79 *
80 * @returns OS/2 status code.
81 * @param vrc IPRT/VBox status code.
82 * @param rcDefault The OS/2 status code to return when there
83 * is no translation.
84 */
85APIRET vboxSfOs2ConvertStatusToOs2(int vrc, APIRET rcDefault)
86{
87 switch (vrc)
88 {
89 default: return rcDefault;
90
91 case VERR_FILE_NOT_FOUND: return ERROR_FILE_NOT_FOUND;
92 case VERR_PATH_NOT_FOUND: return ERROR_PATH_NOT_FOUND;
93 case VERR_SHARING_VIOLATION: return ERROR_SHARING_VIOLATION;
94 case VERR_ACCESS_DENIED: return ERROR_ACCESS_DENIED;
95 case VERR_ALREADY_EXISTS: return ERROR_ACCESS_DENIED;
96 case VERR_WRITE_PROTECT: return ERROR_WRITE_PROTECT;
97 case VERR_IS_A_DIRECTORY: return ERROR_DIRECTORY;
98 case VERR_DISK_FULL: return ERROR_DISK_FULL;
99 case VINF_SUCCESS: return NO_ERROR;
100 }
101}
102
103
104/**
105 * Gets the delta for the local timezone, in minutes.
106 *
107 * We need to do this once for each API call rather than over and over again for
108 * each date/time conversion, so as not to create an update race.
109 *
110 * @returns Delta in minutes. Current thinking is that positive means timezone
111 * is west of UTC, while negative is east of it.
112 */
113int16_t vboxSfOs2GetLocalTimeDelta(void)
114{
115 GINFOSEG volatile *pGis = (GINFOSEG volatile *)&KernSISData;
116 if (pGis)
117 {
118 uint16_t cDelta = pGis->timezone;
119 if (cDelta != 0 && cDelta != 0xffff)
120 return (int16_t)cDelta;
121 }
122 return 0;
123}
124
125
126/**
127 * Helper for converting from IPRT timespec format to OS/2 DATE/TIME.
128 *
129 * @param pDosDate The output DOS date.
130 * @param pDosTime The output DOS time.
131 * @param SrcTimeSpec The IPRT input timestamp.
132 * @param cMinLocalTimeDelta The timezone delta in minutes.
133 */
134void vboxSfOs2DateTimeFromTimeSpec(FDATE *pDosDate, FTIME *pDosTime, RTTIMESPEC SrcTimeSpec, int16_t cMinLocalTimeDelta)
135{
136 if (cMinLocalTimeDelta != 0)
137 RTTimeSpecAddSeconds(&SrcTimeSpec, -cMinLocalTimeDelta * 60);
138
139 RTTIME Time;
140 if ( RTTimeSpecGetNano(&SrcTimeSpec) >= RTTIME_OFFSET_DOS_TIME
141 && RTTimeExplode(&Time, &SrcTimeSpec))
142 {
143 pDosDate->year = Time.i32Year - 1980;
144 pDosDate->month = Time.u8Month;
145 pDosDate->day = Time.u8MonthDay;
146 pDosTime->hours = Time.u8Hour;
147 pDosTime->minutes = Time.u8Minute;
148 pDosTime->twosecs = Time.u8Second / 2;
149 }
150 else
151 {
152 pDosDate->year = 0;
153 pDosDate->month = 1;
154 pDosDate->day = 1;
155 pDosTime->hours = 0;
156 pDosTime->minutes = 0;
157 pDosTime->twosecs = 0;
158 }
159}
160
161
162/**
163 * Helper for converting from OS/2 DATE/TIME to IPRT timespec format.
164 *
165 * @returns pDstTimeSpec on success, NULL if invalid input.
166 * @param DosDate The input DOS date.
167 * @param DosTime The input DOS time.
168 * @param cMinLocalTimeDelta The timezone delta in minutes.
169 * @param pDstTimeSpec The IPRT output timestamp.
170 */
171PRTTIMESPEC vboxSfOs2DateTimeToTimeSpec(FDATE DosDate, FTIME DosTime, int16_t cMinLocalTimeDelta, PRTTIMESPEC pDstTimeSpec)
172{
173 RTTIME Time;
174 Time.i32Year = DosDate.year + 1980;
175 Time.u8Month = DosDate.month;
176 Time.u8WeekDay = UINT8_MAX;
177 Time.u16YearDay = 0;
178 Time.u8MonthDay = DosDate.day;
179 Time.u8Hour = DosTime.hours;
180 Time.u8Minute = DosTime.minutes;
181 Time.u8Second = DosTime.twosecs * 2;
182 Time.u32Nanosecond = 0;
183 Time.fFlags = RTTIME_FLAGS_TYPE_LOCAL;
184 Time.offUTC = -cMinLocalTimeDelta;
185 if (RTTimeLocalNormalize(&Time))
186 return RTTimeImplode(pDstTimeSpec, &Time);
187 return NULL;
188}
189
190
191/*********************************************************************************************************************************
192* Shared Folder String Buffer Management *
193*********************************************************************************************************************************/
194
195/**
196 * Allocates a SHFLSTRING buffer (UTF-16).
197 *
198 * @returns Pointer to a SHFLSTRING buffer, NULL if out of memory.
199 * @param cwcLength The desired string buffer length in UTF-16 units
200 * (excluding terminator).
201 */
202PSHFLSTRING vboxSfOs2StrAlloc(size_t cwcLength)
203{
204 AssertReturn(cwcLength <= 0x1000, NULL);
205 uint16_t cb = (uint16_t)cwcLength + 1;
206 cb *= sizeof(RTUTF16);
207
208 PSHFLSTRING pStr = (PSHFLSTRING)VbglR0PhysHeapAlloc(SHFLSTRING_HEADER_SIZE + cb);
209 if (pStr)
210 {
211 pStr->u16Size = cb;
212 pStr->u16Length = 0;
213 pStr->String.utf16[0] = '\0';
214 return pStr;
215 }
216 return NULL;
217}
218
219
220/**
221 * Duplicates a shared folders string buffer (UTF-16).
222 *
223 * @returns Pointer to a SHFLSTRING buffer containing the copy.
224 * NULL if out of memory or the string is too long.
225 * @param pSrc The string to clone.
226 */
227PSHFLSTRING vboxSfOs2StrDup(PCSHFLSTRING pSrc)
228{
229 PSHFLSTRING pDst = (PSHFLSTRING)VbglR0PhysHeapAlloc(SHFLSTRING_HEADER_SIZE + pSrc->u16Length + sizeof(RTUTF16));
230 if (pDst)
231 {
232 pDst->u16Size = pSrc->u16Length + (uint16_t)sizeof(RTUTF16);
233 pDst->u16Length = pSrc->u16Length;
234 memcpy(&pDst->String, &pSrc->String, pSrc->u16Length);
235 pDst->String.utf16[pSrc->u16Length / sizeof(RTUTF16)] = '\0';
236 return pDst;
237 }
238 return NULL;
239}
240
241
242/**
243 * Frees a SHLFSTRING buffer.
244 *
245 * @param pStr The buffer to free.
246 */
247void vboxSfOs2StrFree(PSHFLSTRING pStr)
248{
249 if (pStr)
250 VbglR0PhysHeapFree(pStr);
251}
252
253
254
255/*********************************************************************************************************************************
256* Folders, Paths and Service Connection. *
257*********************************************************************************************************************************/
258
259/**
260 * Ensures that we're connected to the host service.
261 *
262 * @returns VBox status code.
263 * @remarks Caller owns g_MtxFolder exclusively!
264 */
265static int vboxSfOs2EnsureConnected(void)
266{
267 if (g_fIsConnectedToService)
268 return VINF_SUCCESS;
269
270 int rc = VbglR0SfConnect(&g_SfClient);
271 if (RT_SUCCESS(rc))
272 g_fIsConnectedToService = true;
273 else
274 LogRel(("VbglR0SfConnect failed: %Rrc\n", rc));
275 return rc;
276}
277
278
279/**
280 * Destroys a folder when the reference count has reached zero.
281 *
282 * @param pFolder The folder to destroy.
283 */
284static void vboxSfOs2DestroyFolder(PVBOXSFFOLDER pFolder)
285{
286 /* Note! We won't get there while the folder is on the list. */
287 LogRel(("vboxSfOs2ReleaseFolder: Destroying %p [%s]\n", pFolder, pFolder->szName));
288 VbglR0SfHostReqUnmapFolderSimple(pFolder->idHostRoot);
289 RT_ZERO(pFolder);
290 RTMemFree(pFolder);
291}
292
293
294/**
295 * Releases a reference to a folder.
296 *
297 * @param pFolder The folder to release.
298 */
299void vboxSfOs2ReleaseFolder(PVBOXSFFOLDER pFolder)
300{
301 if (pFolder)
302 {
303 uint32_t cRefs = ASMAtomicDecU32(&pFolder->cRefs);
304 AssertMsg(cRefs < _64K, ("%#x\n", cRefs));
305 if (!cRefs)
306 vboxSfOs2DestroyFolder(pFolder);
307 }
308}
309
310
311/**
312 * Retain a reference to a folder.
313 *
314 * @param pFolder The folder to release.
315 */
316void vboxSfOs2RetainFolder(PVBOXSFFOLDER pFolder)
317{
318 uint32_t cRefs = ASMAtomicIncU32(&pFolder->cRefs);
319 AssertMsg(cRefs < _64K, ("%#x\n", cRefs));
320}
321
322
323/**
324 * Locates and retains a folder structure.
325 *
326 * @returns Folder matching the name, NULL of not found.
327 * @remarks Caller owns g_MtxFolder.
328 */
329static PVBOXSFFOLDER vboxSfOs2FindAndRetainFolder(const char *pachName, size_t cchName)
330{
331 PVBOXSFFOLDER pCur;
332 RTListForEach(&g_FolderHead, pCur, VBOXSFFOLDER, ListEntry)
333 {
334 if ( pCur->cchName == cchName
335 && RTStrNICmpAscii(pCur->szName, pachName, cchName) == 0)
336 {
337 uint32_t cRefs = ASMAtomicIncU32(&pCur->cRefs);
338 AssertMsg(cRefs < _64K, ("%#x\n", cRefs));
339 return pCur;
340 }
341 }
342 return NULL;
343}
344
345
346/**
347 * Maps a folder, linking it into the list of folders.
348 *
349 * One reference is retained for the caller, which must pass it on or release
350 * it. The list also have a reference to it.
351 *
352 * @returns VBox status code.
353 * @param pName The name of the folder to map - ASCII (not UTF-16!).
354 * Must be large enough to hold UTF-16 expansion of the
355 * string, will do so upon return.
356 * @param pszTag Folder tag (for the VBoxService automounter). Optional.
357 * @param ppFolder Where to return the folder structure on success.
358 *
359 * @remarks Caller owns g_MtxFolder exclusively!
360 */
361static int vboxSfOs2MapFolder(PSHFLSTRING pName, const char *pszTag, PVBOXSFFOLDER *ppFolder)
362{
363 int rc;
364 size_t const cbTag = pszTag ? strlen(pszTag) + 1 : NULL;
365 PVBOXSFFOLDER pNew = (PVBOXSFFOLDER)RTMemAlloc(RT_UOFFSETOF_DYN(VBOXSFFOLDER, szName[pName->u16Length + 1 + cbTag]));
366 if (pNew != NULL)
367 {
368 pNew->u32Magic = VBOXSFFOLDER_MAGIC;
369 pNew->cRefs = 2; /* (List reference + the returned reference.) */
370 pNew->cOpenFiles = 0;
371 pNew->cOpenSearches = 0;
372 pNew->cDrives = 0;
373 pNew->idHostRoot = SHFL_ROOT_NIL;
374 pNew->hVpb = 0;
375 pNew->cbNameAndTag = pName->u16Length + (uint16_t)cbTag;
376 pNew->cchName = (uint8_t)pName->u16Length;
377 pNew->cchName = (uint8_t)pName->u16Length;
378 memcpy(pNew->szName, pName->String.utf8, pName->u16Length);
379 pNew->szName[pName->u16Length] = '\0';
380 if (cbTag)
381 memcpy(&pNew->szName[pName->u16Length + 1], pszTag, cbTag);
382
383 /* Expand the folder name to UTF-16. */
384 uint8_t off = pNew->cchName;
385 uint8_t volatile const *pbSrc = &pName->String.utf8[0];
386 RTUTF16 volatile *pwcDst = &pName->String.utf16[0];
387 do
388 pwcDst[off] = pbSrc[off];
389 while (off-- > 0);
390 pName->u16Length *= sizeof(RTUTF16);
391 Assert(pName->u16Length + sizeof(RTUTF16) <= pName->u16Size);
392
393 /* Try do the mapping.*/
394 VBOXSFMAPFOLDERWITHBUFREQ *pReq = (VBOXSFMAPFOLDERWITHBUFREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
395 if (pReq)
396 {
397 rc = VbglR0SfHostReqMapFolderWithBuf(pReq, pName, RTPATH_DELIMITER, false /*fCaseSensitive*/);
398 if (RT_SUCCESS(rc))
399 {
400 pNew->idHostRoot = pReq->Parms.id32Root.u.value32;
401
402 RTListAppend(&g_FolderHead, &pNew->ListEntry);
403 ASMAtomicIncU32(&g_uFolderRevision);
404 LogRel(("vboxSfOs2MapFolder: %p - %s\n", pNew, pNew->szName));
405
406 *ppFolder = pNew;
407 pNew = NULL;
408 }
409 else
410 LogRel(("vboxSfOs2MapFolder: VbglR0SfHostReqMapFolderWithBuf(,%s,) -> %Rrc\n", pNew->szName, rc));
411 VbglR0PhysHeapFree(pReq);
412 }
413 else
414 LogRel(("vboxSfOs2MapFolder: Out of physical heap :-(\n"));
415 RTMemFree(pNew);
416 }
417 else
418 {
419 LogRel(("vboxSfOs2MapFolder: Out of memory :-(\n"));
420 rc = VERR_NO_MEMORY;
421 }
422 return rc;
423}
424
425
426/**
427 * Worker for vboxSfOs2UncPrefixLength.
428 */
429DECLINLINE(size_t) vboxSfOs2CountLeadingSlashes(const char *pszPath)
430{
431 size_t cchSlashes = 0;
432 char ch;
433 while ((ch = *pszPath) == '\\' || ch == '/')
434 cchSlashes++, pszPath++;
435 return cchSlashes;
436}
437
438
439/**
440 * Checks for a VBox UNC prefix (server + slashes) and determins its length when
441 * found.
442 *
443 * @returns Length of VBoxSF UNC prefix, 0 if not VBoxSF UNC prefix.
444 * @param pszPath The possible UNC path.
445 */
446DECLINLINE(size_t) vboxSfOs2UncPrefixLength(const char *pszPath)
447{
448 char ch;
449 if ( ((ch = pszPath[0]) == '\\' || ch == '/')
450 && ((ch = pszPath[1]) == '\\' || ch == '/')
451 && ((ch = pszPath[2]) == 'V' || ch == 'v')
452 && ((ch = pszPath[3]) == 'B' || ch == 'b')
453 && ((ch = pszPath[4]) == 'O' || ch == 'o')
454 && ((ch = pszPath[5]) == 'X' || ch == 'x')
455 && ((ch = pszPath[6]) == 'S' || ch == 's')
456 )
457 {
458 /* \\VBoxSf\ */
459 if ( ((ch = pszPath[7]) == 'F' || ch == 'f')
460 && ((ch = pszPath[8]) == '\\' || ch == '/') )
461 return vboxSfOs2CountLeadingSlashes(&pszPath[9]) + 9;
462
463 /* \\VBoxSvr\ */
464 if ( ((ch = pszPath[7]) == 'V' || ch == 'v')
465 && ((ch = pszPath[8]) == 'R' || ch == 'r')
466 && ((ch = pszPath[9]) == '\\' || ch == '/') )
467 return vboxSfOs2CountLeadingSlashes(&pszPath[10]) + 10;
468
469 /* \\VBoxSrv\ */
470 if ( ((ch = pszPath[7]) == 'R' || ch == 'r')
471 && ((ch = pszPath[8]) == 'V' || ch == 'v')
472 && ((ch = pszPath[9]) == '\\' || ch == '/') )
473 return vboxSfOs2CountLeadingSlashes(&pszPath[10]) + 10;
474 }
475
476 return 0;
477}
478
479
480/**
481 * Converts a path to UTF-16 and puts it in a VBGL friendly buffer.
482 *
483 * @returns OS/2 status code
484 * @param pszFolderPath The path to convert.
485 * @param ppStr Where to return the pointer to the buffer. Free
486 * using vboxSfOs2FreePath.
487 */
488APIRET vboxSfOs2ConvertPath(const char *pszFolderPath, PSHFLSTRING *ppStr)
489{
490 /*
491 * Skip unnecessary leading slashes.
492 */
493 char ch = *pszFolderPath;
494 if (ch == '\\' || ch == '/')
495 while ((ch = pszFolderPath[1]) == '\\' || ch == '/')
496 pszFolderPath++;
497
498 /*
499 * Since the KEE unicode conversion routines does not seem to know of
500 * surrogate pairs, we will get a very good output size estimate by
501 * using strlen() on the input.
502 */
503 size_t cchSrc = strlen(pszFolderPath);
504 PSHFLSTRING pDst = vboxSfOs2StrAlloc(cchSrc + 4 /*fudge*/);
505 if (pDst)
506 {
507 APIRET rc = SafeKernStrToUcs(NULL, &pDst->String.utf16[0], (char *)pszFolderPath, cchSrc + 4, cchSrc);
508 if (rc == NO_ERROR)
509 {
510 pDst->u16Length = (uint16_t)RTUtf16Len(pDst->String.utf16) * (uint16_t)sizeof(RTUTF16);
511 Assert(pDst->u16Length < pDst->u16Size);
512 pDst->u16Size = pDst->u16Length + (uint16_t)sizeof(RTUTF16); /* (limit how much is copied to the host) */
513 *ppStr = pDst;
514 return NO_ERROR;
515 }
516 VbglR0PhysHeapFree(pDst);
517
518 /*
519 * This shouldn't happen, but just in case we try again with twice
520 * the buffer size.
521 */
522 if (rc == 0x20412 /*ULS_BUFFERFULL*/)
523 {
524 pDst = vboxSfOs2StrAlloc((cchSrc + 16) * 2);
525 if (pDst)
526 {
527 rc = SafeKernStrToUcs(NULL, pDst->String.utf16, (char *)pszFolderPath, (cchSrc + 16) * 2, cchSrc);
528 if (rc == NO_ERROR)
529 {
530 pDst->u16Length = (uint16_t)RTUtf16Len(pDst->String.utf16) * (uint16_t)sizeof(RTUTF16);
531 Assert(pDst->u16Length < pDst->u16Size);
532 pDst->u16Size = pDst->u16Length + (uint16_t)sizeof(RTUTF16);
533 *ppStr = pDst;
534 return NO_ERROR;
535 }
536 VbglR0PhysHeapFree(pDst);
537 LogRel(("vboxSfOs2ConvertPath: SafeKernStrToUcs returns %#x for %.*Rhxs\n", rc, cchSrc, pszFolderPath));
538 }
539 }
540 else
541 LogRel(("vboxSfOs2ConvertPath: SafeKernStrToUcs returns %#x for %.*Rhxs\n", rc, cchSrc, pszFolderPath));
542 }
543
544 LogRel(("vboxSfOs2ConvertPath: Out of memory - cchSrc=%#x\n", cchSrc));
545 *ppStr = NULL;
546 return ERROR_NOT_ENOUGH_MEMORY;
547}
548
549
550/**
551 * Converts a path to UTF-16 and puts it in a VBGL friendly buffer within a
552 * larger buffer.
553 *
554 * @returns OS/2 status code
555 * @param pszFolderPath The path to convert.
556 * @param offStrInBuf The offset of the SHLFSTRING in the return buffer.
557 * This first part of the buffer is zeroed.
558 * @param ppvBuf Where to return the pointer to the buffer. Free
559 * using vboxSfOs2FreePath.
560 */
561APIRET vboxSfOs2ConvertPathEx(const char *pszFolderPath, uint32_t offStrInBuf, void **ppvBuf)
562{
563 /*
564 * Skip unnecessary leading slashes.
565 */
566 char ch = *pszFolderPath;
567 if (ch == '\\' || ch == '/')
568 while ((ch = pszFolderPath[1]) == '\\' || ch == '/')
569 pszFolderPath++;
570
571 /*
572 * Since the KEE unicode conversion routines does not seem to know of
573 * surrogate pairs, we will get a very good output size estimate by
574 * using strlen() on the input.
575 */
576 size_t cchSrc = strlen(pszFolderPath);
577 void *pvBuf = VbglR0PhysHeapAlloc(offStrInBuf + SHFLSTRING_HEADER_SIZE + (cchSrc + 4) * sizeof(RTUTF16));
578 if (pvBuf)
579 {
580 RT_BZERO(pvBuf, offStrInBuf);
581 PSHFLSTRING pDst = (PSHFLSTRING)((uint8_t *)pvBuf + offStrInBuf);
582
583 APIRET rc = SafeKernStrToUcs(NULL, &pDst->String.utf16[0], (char *)pszFolderPath, cchSrc + 4, cchSrc);
584 if (rc == NO_ERROR)
585 {
586 pDst->u16Length = (uint16_t)RTUtf16Len(pDst->String.utf16) * (uint16_t)sizeof(RTUTF16);
587 Assert(pDst->u16Length < (cchSrc + 4) * sizeof(RTUTF16));
588 pDst->u16Size = pDst->u16Length + (uint16_t)sizeof(RTUTF16); /* (limit how much is copied to the host) */
589 *ppvBuf = pvBuf;
590 return NO_ERROR;
591 }
592 VbglR0PhysHeapFree(pvBuf);
593
594 /*
595 * This shouldn't happen, but just in case we try again with twice
596 * the buffer size.
597 */
598 if (rc == 0x20412 /*ULS_BUFFERFULL*/)
599 {
600 pvBuf = VbglR0PhysHeapAlloc(offStrInBuf + SHFLSTRING_HEADER_SIZE + (cchSrc + 16) * sizeof(RTUTF16) * 2);
601 if (pvBuf)
602 {
603 RT_BZERO(pvBuf, offStrInBuf);
604 pDst = (PSHFLSTRING)((uint8_t *)pvBuf + offStrInBuf);
605
606 rc = SafeKernStrToUcs(NULL, pDst->String.utf16, (char *)pszFolderPath, (cchSrc + 16) * 2, cchSrc);
607 if (rc == NO_ERROR)
608 {
609 pDst->u16Length = (uint16_t)RTUtf16Len(pDst->String.utf16) * (uint16_t)sizeof(RTUTF16);
610 Assert(pDst->u16Length < (cchSrc + 16) * 2 * sizeof(RTUTF16));
611 pDst->u16Size = pDst->u16Length + (uint16_t)sizeof(RTUTF16);
612 *ppvBuf = pvBuf;
613 return NO_ERROR;
614 }
615 VbglR0PhysHeapFree(pDst);
616 LogRel(("vboxSfOs2ConvertPath: SafeKernStrToUcs returns %#x for %.*Rhxs\n", rc, cchSrc, pszFolderPath));
617 }
618 }
619 else
620 LogRel(("vboxSfOs2ConvertPath: SafeKernStrToUcs returns %#x for %.*Rhxs\n", rc, cchSrc, pszFolderPath));
621 }
622
623 LogRel(("vboxSfOs2ConvertPath: Out of memory - cchSrc=%#x offStrInBuf=%#x\n", cchSrc, offStrInBuf));
624 *ppvBuf = NULL;
625 return ERROR_NOT_ENOUGH_MEMORY;
626}
627
628
629/**
630 * Counterpart to vboxSfOs2ResolvePath.
631 *
632 * @param pStrPath The path to free.
633 * @param pFolder The folder to release.
634 */
635void vboxSfOs2ReleasePathAndFolder(PSHFLSTRING pStrPath, PVBOXSFFOLDER pFolder)
636{
637 if (pStrPath)
638 VbglR0PhysHeapFree(pStrPath);
639 if (pFolder)
640 {
641 uint32_t cRefs = ASMAtomicDecU32(&pFolder->cRefs);
642 Assert(cRefs < _64K);
643 if (!cRefs)
644 vboxSfOs2DestroyFolder(pFolder);
645 }
646}
647
648
649/**
650 * Worker for vboxSfOs2ResolvePath() for dynamically mapping folders for UNC
651 * paths.
652 *
653 * @returns OS/2 status code.
654 * @param pachFolderName The folder to map. Not necessarily zero terminated
655 * at the end of the folder name!
656 * @param cchFolderName The length of the folder name.
657 * @param uRevBefore The previous folder list revision.
658 * @param ppFolder Where to return the pointer to the retained folder.
659 */
660DECL_NO_INLINE(static, int) vboxSfOs2AttachUncAndRetain(const char *pachFolderName, size_t cchFolderName,
661 uint32_t uRevBefore, PVBOXSFFOLDER *ppFolder)
662{
663 KernRequestExclusiveMutex(&g_MtxFolders);
664
665 /*
666 * Check if someone raced us to it.
667 */
668 if (uRevBefore != g_uFolderRevision)
669 {
670 PVBOXSFFOLDER pFolder = vboxSfOs2FindAndRetainFolder(pachFolderName, cchFolderName);
671 if (pFolder)
672 {
673 KernReleaseExclusiveMutex(&g_MtxFolders);
674 *ppFolder = pFolder;
675 return NO_ERROR;
676 }
677 }
678
679 int rc = vboxSfOs2EnsureConnected();
680 if (RT_SUCCESS(rc))
681 {
682 /*
683 * Copy the name into the buffer format that Vbgl desires.
684 */
685 PSHFLSTRING pStrName = vboxSfOs2StrAlloc(cchFolderName);
686 if (pStrName)
687 {
688 memcpy(pStrName->String.ach, pachFolderName, cchFolderName);
689 pStrName->String.ach[cchFolderName] = '\0';
690 pStrName->u16Length = (uint16_t)cchFolderName;
691
692 /*
693 * Do the attaching.
694 */
695 rc = vboxSfOs2MapFolder(pStrName, NULL, ppFolder);
696 vboxSfOs2StrFree(pStrName);
697 if (RT_SUCCESS(rc))
698 {
699 KernReleaseExclusiveMutex(&g_MtxFolders);
700 LogRel(("vboxSfOs2AttachUncAndRetain: Successfully attached '%s' (as UNC).\n", (*ppFolder)->szName));
701 return NO_ERROR;
702 }
703
704 if (rc == VERR_NO_MEMORY)
705 rc = ERROR_NOT_ENOUGH_MEMORY;
706 else
707 rc = ERROR_PATH_NOT_FOUND;
708 }
709 else
710 rc = ERROR_NOT_ENOUGH_MEMORY;
711 }
712 else
713 rc = ERROR_PATH_NOT_FOUND;
714
715 KernReleaseExclusiveMutex(&g_MtxFolders);
716 return rc;
717}
718
719
720/**
721 * Resolves the given path to a folder structure and folder relative string.
722 *
723 * @returns OS/2 status code.
724 * @param pszPath The path to resolve.
725 * @param pCdFsd The IFS dependent CWD structure if present.
726 * @param offCurDirEnd The offset into @a pszPath of the CWD. -1 if not
727 * CWD relative path.
728 * @param ppFolder Where to return the referenced pointer to the folder
729 * structure. Call vboxSfOs2ReleaseFolder() when done.
730 * @param ppStrFolderPath Where to return a buffer holding the folder relative
731 * path component. Free using vboxSfOs2FreePath().
732 */
733APIRET vboxSfOs2ResolvePath(const char *pszPath, PVBOXSFCD pCdFsd, LONG offCurDirEnd,
734 PVBOXSFFOLDER *ppFolder, PSHFLSTRING *ppStrFolderPath)
735{
736 APIRET rc;
737
738 /*
739 * UNC path? Reject the prefix to be on the safe side.
740 */
741 char ch = pszPath[0];
742 if (ch == '\\' || ch == '/')
743 {
744 size_t cchPrefix = vboxSfOs2UncPrefixLength(pszPath);
745 if (cchPrefix > 0)
746 {
747 /* Find the length of the folder name (share). */
748 const char *pszFolderName = &pszPath[cchPrefix];
749 size_t cchFolderName = 0;
750 while ((ch = pszFolderName[cchFolderName]) != '\0' && ch != '\\' && ch != '/')
751 {
752 if ((uint8_t)ch >= 0x20 && (uint8_t)ch <= 0x7f && ch != ':')
753 cchFolderName++;
754 else
755 {
756 LogRel(("vboxSfOs2ResolvePath: Invalid share name (@%u): %.*Rhxs\n",
757 cchPrefix + cchFolderName, strlen(pszPath), pszPath));
758 return ERROR_INVALID_NAME;
759 }
760 }
761 if (cchFolderName >= VBOXSFOS2_MAX_FOLDER_NAME)
762 {
763 LogRel(("vboxSfOs2ResolvePath: Folder name is too long: %u, max %u (%s)\n",
764 cchFolderName, VBOXSFOS2_MAX_FOLDER_NAME, pszPath));
765 return ERROR_FILENAME_EXCED_RANGE;
766 }
767
768 /*
769 * Look for the share.
770 */
771 KernRequestSharedMutex(&g_MtxFolders);
772 PVBOXSFFOLDER pFolder = *ppFolder = vboxSfOs2FindAndRetainFolder(pszFolderName, cchFolderName);
773 if (pFolder)
774 {
775 vboxSfOs2RetainFolder(pFolder);
776 KernReleaseSharedMutex(&g_MtxFolders);
777 }
778 else
779 {
780 uint32_t const uRevBefore = g_uFolderRevision;
781 KernReleaseSharedMutex(&g_MtxFolders);
782 rc = vboxSfOs2AttachUncAndRetain(pszFolderName, cchFolderName, uRevBefore, ppFolder);
783 if (rc == NO_ERROR)
784 pFolder = *ppFolder;
785 else
786 return rc;
787 }
788
789 /*
790 * Convert the path and put it in a Vbgl compatible buffer..
791 */
792 rc = vboxSfOs2ConvertPath(&pszFolderName[cchFolderName], ppStrFolderPath);
793 if (rc == NO_ERROR)
794 return rc;
795
796 vboxSfOs2ReleaseFolder(pFolder);
797 *ppFolder = NULL;
798 return rc;
799 }
800
801 LogRel(("vboxSfOs2ResolvePath: Unexpected path: %s\n", pszPath));
802 return ERROR_PATH_NOT_FOUND;
803 }
804
805 /*
806 * Drive letter?
807 */
808 ch &= ~0x20; /* upper case */
809 if ( ch >= 'A'
810 && ch <= 'Z'
811 && pszPath[1] == ':')
812 {
813 unsigned iDrive = ch - 'A';
814 ch = pszPath[2];
815 if (ch == '\\' || ch == '/')
816 {
817 KernRequestSharedMutex(&g_MtxFolders);
818 PVBOXSFFOLDER pFolder = *ppFolder = g_apDriveFolders[iDrive];
819 if (pFolder)
820 {
821 vboxSfOs2RetainFolder(pFolder);
822 KernReleaseSharedMutex(&g_MtxFolders);
823
824 /*
825 * Convert the path and put it in a Vbgl compatible buffer..
826 */
827 rc = vboxSfOs2ConvertPath(&pszPath[3], ppStrFolderPath);
828 if (rc == NO_ERROR)
829 return rc;
830
831 vboxSfOs2ReleaseFolder(pFolder);
832 *ppFolder = NULL;
833 return rc;
834 }
835 KernReleaseSharedMutex(&g_MtxFolders);
836 LogRel(("vboxSfOs2ResolvePath: No folder mapped on '%s'. Detach race?\n", pszPath));
837 return ERROR_PATH_NOT_FOUND;
838 }
839 LogRel(("vboxSfOs2ResolvePath: No root slash: '%s'\n", pszPath));
840 return ERROR_PATH_NOT_FOUND;
841 }
842 LogRel(("vboxSfOs2ResolvePath: Unexpected path: %s\n", pszPath));
843 RT_NOREF_PV(pCdFsd); RT_NOREF_PV(offCurDirEnd);
844 return ERROR_PATH_NOT_FOUND;
845}
846
847
848/**
849 * Resolves the given path to a folder structure and folder relative string,
850 * the latter placed within a larger request buffer.
851 *
852 * @returns OS/2 status code.
853 * @param pszPath The path to resolve.
854 * @param pCdFsd The IFS dependent CWD structure if present.
855 * @param offCurDirEnd The offset into @a pszPath of the CWD. -1 if not
856 * CWD relative path.
857 * @param offStrInBuf The offset of the SHLFSTRING in the return buffer.
858 * This first part of the buffer is zeroed.
859 * @param ppFolder Where to return the referenced pointer to the folder
860 * structure. Call vboxSfOs2ReleaseFolder() when done.
861 * @param ppvBuf Where to return the Pointer to the buffer. Free
862 * using VbglR0PhysHeapFree.
863 */
864APIRET vboxSfOs2ResolvePathEx(const char *pszPath, PVBOXSFCD pCdFsd, LONG offCurDirEnd, uint32_t offStrInBuf,
865 PVBOXSFFOLDER *ppFolder, void **ppvBuf)
866{
867 APIRET rc;
868
869 /*
870 * UNC path? Reject the prefix to be on the safe side.
871 */
872 char ch = pszPath[0];
873 if (ch == '\\' || ch == '/')
874 {
875 size_t cchPrefix = vboxSfOs2UncPrefixLength(pszPath);
876 if (cchPrefix > 0)
877 {
878 /* Find the length of the folder name (share). */
879 const char *pszFolderName = &pszPath[cchPrefix];
880 size_t cchFolderName = 0;
881 while ((ch = pszFolderName[cchFolderName]) != '\0' && ch != '\\' && ch != '/')
882 {
883 if ((uint8_t)ch >= 0x20 && (uint8_t)ch <= 0x7f && ch != ':')
884 cchFolderName++;
885 else
886 {
887 LogRel(("vboxSfOs2ResolvePath: Invalid share name (@%u): %.*Rhxs\n",
888 cchPrefix + cchFolderName, strlen(pszPath), pszPath));
889 return ERROR_INVALID_NAME;
890 }
891 }
892 if (cchFolderName >= VBOXSFOS2_MAX_FOLDER_NAME)
893 {
894 LogRel(("vboxSfOs2ResolvePath: Folder name is too long: %u, max %u (%s)\n",
895 cchFolderName, VBOXSFOS2_MAX_FOLDER_NAME, pszPath));
896 return ERROR_FILENAME_EXCED_RANGE;
897 }
898
899 /*
900 * Look for the share.
901 */
902 KernRequestSharedMutex(&g_MtxFolders);
903 PVBOXSFFOLDER pFolder = *ppFolder = vboxSfOs2FindAndRetainFolder(pszFolderName, cchFolderName);
904 if (pFolder)
905 {
906 vboxSfOs2RetainFolder(pFolder);
907 KernReleaseSharedMutex(&g_MtxFolders);
908 }
909 else
910 {
911 uint32_t const uRevBefore = g_uFolderRevision;
912 KernReleaseSharedMutex(&g_MtxFolders);
913 rc = vboxSfOs2AttachUncAndRetain(pszFolderName, cchFolderName, uRevBefore, ppFolder);
914 if (rc == NO_ERROR)
915 pFolder = *ppFolder;
916 else
917 return rc;
918 }
919
920 /*
921 * Convert the path and put it in a Vbgl compatible buffer..
922 */
923 rc = vboxSfOs2ConvertPathEx(&pszFolderName[cchFolderName], offStrInBuf, ppvBuf);
924 if (rc == NO_ERROR)
925 return rc;
926
927 vboxSfOs2ReleaseFolder(pFolder);
928 *ppFolder = NULL;
929 return rc;
930 }
931
932 LogRel(("vboxSfOs2ResolvePath: Unexpected path: %s\n", pszPath));
933 return ERROR_PATH_NOT_FOUND;
934 }
935
936 /*
937 * Drive letter?
938 */
939 ch &= ~0x20; /* upper case */
940 if ( ch >= 'A'
941 && ch <= 'Z'
942 && pszPath[1] == ':')
943 {
944 unsigned iDrive = ch - 'A';
945 ch = pszPath[2];
946 if (ch == '\\' || ch == '/')
947 {
948 KernRequestSharedMutex(&g_MtxFolders);
949 PVBOXSFFOLDER pFolder = *ppFolder = g_apDriveFolders[iDrive];
950 if (pFolder)
951 {
952 vboxSfOs2RetainFolder(pFolder);
953 KernReleaseSharedMutex(&g_MtxFolders);
954
955 /*
956 * Convert the path and put it in a Vbgl compatible buffer..
957 */
958 rc = vboxSfOs2ConvertPathEx(&pszPath[3], offStrInBuf, ppvBuf);
959 if (rc == NO_ERROR)
960 return rc;
961
962 vboxSfOs2ReleaseFolder(pFolder);
963 *ppFolder = NULL;
964 return rc;
965 }
966 KernReleaseSharedMutex(&g_MtxFolders);
967 LogRel(("vboxSfOs2ResolvePath: No folder mapped on '%s'. Detach race?\n", pszPath));
968 return ERROR_PATH_NOT_FOUND;
969 }
970 LogRel(("vboxSfOs2ResolvePath: No root slash: '%s'\n", pszPath));
971 return ERROR_PATH_NOT_FOUND;
972 }
973 LogRel(("vboxSfOs2ResolvePath: Unexpected path: %s\n", pszPath));
974 RT_NOREF_PV(pCdFsd); RT_NOREF_PV(offCurDirEnd);
975 return ERROR_PATH_NOT_FOUND;
976}
977
978
979DECLASM(void)
980FS32_EXIT(ULONG uid, ULONG pid, ULONG pdb)
981{
982 LogFlow(("FS32_EXIT: uid=%u pid=%u pdb=%#x\n", uid, pid, pdb));
983 NOREF(uid); NOREF(pid); NOREF(pdb);
984}
985
986
987DECLASM(APIRET)
988FS32_SHUTDOWN(ULONG uType, ULONG uReserved)
989{
990 LogFlow(("FS32_SHUTDOWN: type=%u uReserved=%u\n", uType, uReserved));
991 NOREF(uType); NOREF(uReserved);
992 return NO_ERROR;
993}
994
995
996/**
997 * FS32_ATTACH worker: FS_ATTACH
998 */
999static APIRET vboxSfOs2Attach(PCSZ pszDev, PVBOXSFVP pVpFsd, PVBOXSFCD pCdFsd, PBYTE pszParam, PUSHORT pcbParam,
1000 PSHFLSTRING *ppCleanup)
1001{
1002 /*
1003 * Check out the parameters, copying the pszParam into a suitable string buffer.
1004 */
1005 if (pszDev == NULL || !*pszDev || !RT_C_IS_ALPHA(pszDev[0]) || pszDev[1] != ':' || pszDev[2] != '\0')
1006 {
1007 LogRel(("vboxSfOs2Attach: Invalid pszDev value:%p:{%s}\n", pszDev, pszDev));
1008 return ERROR_INVALID_PARAMETER;
1009 }
1010 unsigned const iDrive = (pszDev[0] & ~0x20) - 'A';
1011
1012 if (pszParam == NULL || pcbParam == NULL)
1013 {
1014 LogRel(("vboxSfOs2Attach: NULL parameter buffer or buffer length\n"));
1015 return ERROR_INVALID_PARAMETER;
1016 }
1017
1018 PSHFLSTRING pStrName = *ppCleanup = vboxSfOs2StrAlloc(VBOXSFOS2_MAX_FOLDER_NAME - 1);
1019 pStrName->u16Length = *pcbParam;
1020 if (pStrName->u16Length < 1 || pStrName->u16Length > VBOXSFOS2_MAX_FOLDER_NAME)
1021 {
1022 LogRel(("vboxSfOs2Attach: Parameter buffer length is out of bounds: %u (min: 1, max " RT_XSTR(VBOXSFOS2_MAX_FOLDER_NAME) ")\n",
1023 pStrName->u16Length));
1024 return ERROR_INVALID_PARAMETER;
1025 }
1026
1027 int rc = KernCopyIn(pStrName->String.utf8, pszParam, pStrName->u16Length);
1028 if (rc != NO_ERROR)
1029 return rc;
1030
1031 pStrName->u16Length -= 1;
1032 if (pStrName->String.utf8[pStrName->u16Length] != '\0')
1033 {
1034 LogRel(("vboxSfOs2Attach: Parameter not null terminated\n"));
1035 return ERROR_INVALID_PARAMETER;
1036 }
1037
1038 /* Make sure it's only ascii and contains not weird stuff.
1039 Note! There could be a 2nd tag string, so identify that one. */
1040 const char *pszTag = NULL;
1041 unsigned off = pStrName->u16Length;
1042 while (off-- > 0)
1043 {
1044 char const ch = pStrName->String.utf8[off];
1045 if (ch < 0x20 || ch >= 0x7f || ch == ':' || ch == '\\' || ch == '/')
1046 {
1047 if (ch == '\0' && !pszTag && off + 1 < pStrName->u16Length && off > 0)
1048 {
1049 pszTag = &pStrName->String.ach[off + 1];
1050 pStrName->u16Length = (uint16_t)off;
1051 }
1052 else
1053 {
1054 LogRel(("vboxSfOs2Attach: Malformed folder name: %.*Rhxs (off %#x)\n", pStrName->u16Length, pStrName->String.utf8, off));
1055 return ERROR_INVALID_PARAMETER;
1056 }
1057 }
1058 }
1059
1060 /* Is there a tag following the name? */
1061
1062 if (!pVpFsd)
1063 {
1064 LogRel(("vboxSfOs2Attach: pVpFsd is NULL\n"));
1065 return ERROR_INVALID_PARAMETER;
1066 }
1067
1068 /*
1069 * Look for the folder to see if we're already using it. Map it if needed.
1070 */
1071 KernRequestExclusiveMutex(&g_MtxFolders);
1072 if (g_apDriveFolders[iDrive] == NULL)
1073 {
1074
1075 PVBOXSFFOLDER pFolder = vboxSfOs2FindAndRetainFolder(pStrName->String.ach, pStrName->u16Length);
1076 if (!pFolder)
1077 {
1078 rc = vboxSfOs2EnsureConnected();
1079 if (RT_SUCCESS(rc))
1080 rc = vboxSfOs2MapFolder(pStrName, pszTag, &pFolder);
1081 }
1082 if (pFolder && RT_SUCCESS(rc))
1083 {
1084 pFolder->cDrives += 1;
1085 g_apDriveFolders[iDrive] = pFolder;
1086
1087 pVpFsd->u32Magic = VBOXSFVP_MAGIC;
1088 pVpFsd->pFolder = pFolder;
1089
1090 KernReleaseExclusiveMutex(&g_MtxFolders);
1091
1092 LogRel(("vboxSfOs2Attach: Successfully attached '%s' to '%s'.\n", pFolder->szName, pszDev));
1093 return NO_ERROR;
1094 }
1095
1096 KernReleaseExclusiveMutex(&g_MtxFolders);
1097 return ERROR_FILE_NOT_FOUND;
1098 }
1099 KernReleaseExclusiveMutex(&g_MtxFolders);
1100
1101 LogRel(("vboxSfOs2Attach: Already got a folder on '%s'!\n", pszDev));
1102 RT_NOREF(pCdFsd);
1103 return ERROR_BUSY_DRIVE;
1104}
1105
1106
1107/**
1108 * FS32_ATTACH worker: FS_DETACH
1109 */
1110static APIRET vboxSfOs2Detach(PCSZ pszDev, PVBOXSFVP pVpFsd, PVBOXSFCD pCdFsd, PBYTE pszParam, PUSHORT pcbParam)
1111{
1112 /*
1113 * Validate the volume data and assocated folder.
1114 */
1115 AssertPtrReturn(pVpFsd, ERROR_SYS_INTERNAL);
1116 AssertReturn(pVpFsd->u32Magic == VBOXSFVP_MAGIC, ERROR_SYS_INTERNAL);
1117 PVBOXSFFOLDER pFolder = pVpFsd->pFolder;
1118 AssertPtrReturn(pFolder, ERROR_SYS_INTERNAL);
1119 AssertReturn(pFolder->u32Magic == VBOXSFFOLDER_MAGIC, ERROR_SYS_INTERNAL);
1120
1121 uint8_t idxDrive = UINT8_MAX;
1122 if ( pszDev
1123 && RT_C_IS_ALPHA(*pszDev))
1124 idxDrive = (*pszDev & ~0x20) - 'A';
1125
1126 /*
1127 * Can we detach it?
1128 */
1129 APIRET rc;
1130 KernRequestExclusiveMutex(&g_MtxFolders);
1131 if ( pFolder->cOpenFiles == 0
1132 && pFolder->cOpenSearches == 0)
1133 {
1134 /*
1135 * Check that we've got the right folder/drive combo.
1136 */
1137 if ( idxDrive < RT_ELEMENTS(g_apDriveFolders)
1138 && g_apDriveFolders[idxDrive] == pFolder)
1139 {
1140 g_apDriveFolders[idxDrive] = NULL;
1141 uint8_t cDrives = --pFolder->cDrives;
1142 AssertMsg(cDrives < 30, ("%#x\n", cDrives));
1143
1144 uint32_t cRefs = ASMAtomicDecU32(&pFolder->cRefs);
1145 AssertMsg(cRefs < _32K, ("%#x\n", cRefs));
1146 if (cRefs)
1147 {
1148 /* If there are now zero drives, unlink it from the list and release
1149 the list reference. This should almost always drop end up with us
1150 destroying the folder.*/
1151 if (cDrives == 0)
1152 {
1153 RTListNodeRemove(&pFolder->ListEntry);
1154 cRefs = ASMAtomicDecU32(&pFolder->cRefs);
1155 AssertMsg(cRefs < _32K, ("%#x\n", cRefs));
1156 if (!cRefs)
1157 vboxSfOs2DestroyFolder(pFolder);
1158 }
1159 }
1160 else
1161 {
1162 LogRel(("vboxSfOs2Detach: cRefs=0?!?\n"));
1163 vboxSfOs2DestroyFolder(pFolder);
1164 }
1165 rc = NO_ERROR;
1166 }
1167 else
1168 {
1169 LogRel(("vboxSfOs2Detach: g_apDriveFolders[%#x]=%p pFolder=%p\n",
1170 idxDrive, idxDrive < RT_ELEMENTS(g_apDriveFolders) ? g_apDriveFolders[idxDrive] : NULL, pFolder));
1171 rc = ERROR_NOT_SUPPORTED;
1172 }
1173 }
1174 else
1175 rc = ERROR_BUSY_DRIVE;
1176 KernReleaseExclusiveMutex(&g_MtxFolders);
1177
1178 RT_NOREF(pszDev, pVpFsd, pCdFsd, pszParam, pcbParam);
1179 return rc;
1180}
1181
1182
1183/**
1184 * FS32_ATTACH worker: FSA_ATTACH_INFO
1185 */
1186static APIRET vboxSfOs2QueryAttachInfo(PCSZ pszDev, PVBOXSFVP pVpFsd, PVBOXSFCD pCdFsd, PBYTE pbData, PUSHORT pcbParam)
1187{
1188 /*
1189 * Userland calls the kernel with a FSQBUFFER buffer, the kernel
1190 * fills in the first part of us and hands us &FSQBUFFER::cbFSAData
1191 * to do the rest. We could return the share name here, for instance.
1192 */
1193 APIRET rc;
1194 USHORT cbParam = *pcbParam;
1195 if ( pszDev == NULL
1196 || (pszDev[0] != '\\' && pszDev[0] != '/'))
1197 {
1198 /* Validate the volume data and assocated folder. */
1199 AssertPtrReturn(pVpFsd, ERROR_SYS_INTERNAL);
1200 AssertReturn(pVpFsd->u32Magic == VBOXSFVP_MAGIC, ERROR_SYS_INTERNAL);
1201 PVBOXSFFOLDER pFolder = pVpFsd->pFolder;
1202 AssertPtrReturn(pFolder, ERROR_SYS_INTERNAL);
1203 AssertReturn(pFolder->u32Magic == VBOXSFFOLDER_MAGIC, ERROR_SYS_INTERNAL);
1204
1205 /* Try copy out the data. */
1206 if (cbParam >= sizeof(USHORT) + pFolder->cbNameAndTag)
1207 {
1208 *pcbParam = (uint16_t)sizeof(USHORT) + pFolder->cbNameAndTag;
1209 cbParam = pFolder->cchName + 1;
1210 rc = KernCopyOut(pbData, &cbParam, sizeof(cbParam));
1211 if (rc == NO_ERROR)
1212 rc = KernCopyOut(pbData + sizeof(USHORT), pFolder->szName, pFolder->cbNameAndTag);
1213 }
1214 else
1215 rc = ERROR_BUFFER_OVERFLOW;
1216 }
1217 else
1218 {
1219 /* Looks like a device query, so return zero bytes. */
1220 if (cbParam >= sizeof(USHORT))
1221 {
1222 *pcbParam = sizeof(USHORT);
1223 cbParam = 0;
1224 rc = KernCopyOut(pbData, &cbParam, sizeof(cbParam));
1225 }
1226 else
1227 rc = ERROR_BUFFER_OVERFLOW;
1228 }
1229
1230 RT_NOREF(pCdFsd);
1231 return rc;
1232}
1233
1234
1235DECLASM(APIRET)
1236FS32_ATTACH(ULONG fFlags, PCSZ pszDev, PVBOXSFVP pVpFsd, PVBOXSFCD pCdFsd, PBYTE pszParam, PUSHORT pcbParam)
1237{
1238 LogFlow(("FS32_ATTACH: fFlags=%#x pszDev=%p:{%s} pVpFsd=%p pCdFsd=%p pszParam=%p pcbParam=%p\n",
1239 fFlags, pszDev, pszDev, pVpFsd, pCdFsd, pszParam, pcbParam));
1240 APIRET rc;
1241 if (pVpFsd)
1242 {
1243 PSHFLSTRING pCleanup = NULL;
1244
1245 if (fFlags == FS_ATTACH)
1246 rc = vboxSfOs2Attach(pszDev, pVpFsd, pCdFsd, pszParam, pcbParam, &pCleanup);
1247 else if (fFlags == FSA_DETACH)
1248 rc = vboxSfOs2Detach(pszDev, pVpFsd, pCdFsd, pszParam, pcbParam);
1249 else if (fFlags == FSA_ATTACH_INFO)
1250 rc = vboxSfOs2QueryAttachInfo(pszDev, pVpFsd, pCdFsd, pszParam, pcbParam);
1251 else
1252 {
1253 LogRel(("FS32_ATTACH: Unsupported fFlags value: %#x\n", fFlags));
1254 rc = ERROR_NOT_SUPPORTED;
1255 }
1256
1257 if (pCleanup)
1258 vboxSfOs2StrFree(pCleanup);
1259 }
1260 else
1261 rc = ERROR_NOT_SUPPORTED; /* We don't support device attaching. */
1262 LogFlow(("FS32_ATTACH: returns %u\n", rc));
1263 return rc;
1264}
1265
1266
1267DECLASM(APIRET)
1268FS32_VERIFYUNCNAME(ULONG uType, PCSZ pszName)
1269{
1270 LogFlow(("FS32_VERIFYUNCNAME: uType=%#x pszName=%p:{%s}\n", uType, pszName, pszName));
1271 RT_NOREF(uType); /* pass 1 or pass 2 doesn't matter to us, we've only got one 'server'. */
1272
1273 if (vboxSfOs2UncPrefixLength(pszName) > 0)
1274 return NO_ERROR;
1275 return ERROR_NOT_SUPPORTED;
1276}
1277
1278
1279DECLASM(APIRET)
1280FS32_FLUSHBUF(USHORT hVPB, ULONG fFlags)
1281{
1282 NOREF(hVPB); NOREF(fFlags);
1283 return NO_ERROR;
1284}
1285
1286
1287DECLASM(APIRET)
1288FS32_FSINFO(ULONG fFlags, USHORT hVpb, PBYTE pbData, ULONG cbData, ULONG uLevel)
1289{
1290 LogFlow(("FS32_FSINFO: fFlags=%#x hVpb=%#x pbData=%p cbData=%#x uLevel=%p\n", fFlags, hVpb, pbData, cbData, uLevel));
1291
1292 /*
1293 * Resolve hVpb and do parameter validation.
1294 */
1295 PVPFSI pVpFsi = NULL;
1296 PVBOXSFVP pVpFsd = Fsh32GetVolParams(hVpb, &pVpFsi);
1297 Log(("FS32_FSINFO: hVpb=%#x -> pVpFsd=%p pVpFsi=%p\n", hVpb, pVpFsd, pVpFsi));
1298
1299 AssertPtrReturn(pVpFsd, ERROR_SYS_INTERNAL);
1300 AssertReturn(pVpFsd->u32Magic == VBOXSFVP_MAGIC, ERROR_SYS_INTERNAL);
1301 PVBOXSFFOLDER pFolder = pVpFsd->pFolder; /** @todo need to retain it behind locks. */
1302 AssertPtrReturn(pFolder, ERROR_SYS_INTERNAL);
1303 AssertReturn(pFolder->u32Magic == VBOXSFFOLDER_MAGIC, ERROR_SYS_INTERNAL);
1304
1305 APIRET rc;
1306
1307 /*
1308 * Queries.
1309 */
1310 if (fFlags == INFO_RETREIVE)
1311 {
1312 /* Check that buffer/level matches up. */
1313 switch (uLevel)
1314 {
1315 case FSIL_ALLOC:
1316 if (cbData >= sizeof(FSALLOCATE))
1317 break;
1318 LogFlow(("FS32_FSINOF: cbData=%u < sizeof(FSALLOCATE) -> ERROR_BUFFER_OVERFLOW\n", cbData));
1319 return ERROR_BUFFER_OVERFLOW;
1320
1321 case FSIL_VOLSER:
1322 if (cbData >= sizeof(FSINFO))
1323 break;
1324 LogFlow(("FS32_FSINOF: cbData=%u < sizeof(FSINFO) -> ERROR_BUFFER_OVERFLOW\n", cbData));
1325 return ERROR_BUFFER_OVERFLOW;
1326
1327 default:
1328 LogRel(("FS32_FSINFO: Unsupported info level %u!\n", uLevel));
1329 return ERROR_INVALID_LEVEL;
1330 }
1331
1332 /* Work buffer union to keep it to a single allocation and no stack. */
1333 union FsInfoBufs
1334 {
1335 struct
1336 {
1337 VBOXSFCREATEREQ Req;
1338 uint8_t PathStringSpace[4 * sizeof(RTUTF16)];
1339 } Open;
1340 struct
1341 {
1342 VBOXSFVOLINFOREQ Req;
1343 union
1344 {
1345 FSALLOCATE Alloc;
1346 FSINFO FsInfo;
1347 };
1348 } Info;
1349 VBOXSFCLOSEREQ Close;
1350 } *pu = (union FsInfoBufs *)VbglR0PhysHeapAlloc(sizeof(*pu));
1351 if (!pu)
1352 return ERROR_NOT_ENOUGH_MEMORY;
1353
1354 /*
1355 * To get the info we need to open the root of the folder.
1356 */
1357 RT_ZERO(pu->Open.Req);
1358 pu->Open.Req.CreateParms.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACT_OPEN_IF_EXISTS
1359 | SHFL_CF_ACCESS_READ | SHFL_CF_ACCESS_ATTR_READ | SHFL_CF_ACCESS_DENYNONE;
1360 pu->Open.Req.StrPath.u16Size = 3 * sizeof(RTUTF16);
1361 pu->Open.Req.StrPath.u16Length = 2 * sizeof(RTUTF16);
1362 pu->Open.Req.StrPath.String.utf16[0] = '\\';
1363 pu->Open.Req.StrPath.String.utf16[1] = '.';
1364 pu->Open.Req.StrPath.String.utf16[2] = '\0';
1365
1366 int vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, &pu->Open.Req);
1367 LogFlow(("FS32_FSINFO: VbglR0SfHostReqCreate -> %Rrc Result=%d Handle=%#RX64\n",
1368 vrc, pu->Open.Req.CreateParms.Result, pu->Open.Req.CreateParms.Handle));
1369 if ( RT_SUCCESS(vrc)
1370 && pu->Open.Req.CreateParms.Handle != SHFL_HANDLE_NIL)
1371 {
1372 SHFLHANDLE volatile hHandle = pu->Open.Req.CreateParms.Handle;
1373
1374 RT_ZERO(pu->Info.Req);
1375 vrc = VbglR0SfHostReqQueryVolInfo(pFolder->idHostRoot, &pu->Info.Req, hHandle);
1376 if (RT_SUCCESS(vrc))
1377 {
1378 /*
1379 * Construct and copy out the requested info.
1380 */
1381 if (uLevel == FSIL_ALLOC)
1382 {
1383 pu->Info.Alloc.idFileSystem = 0; /* unknown */
1384 uint32_t const cbSector = RT_MAX(pu->Info.Req.VolInfo.ulBytesPerSector, 1);
1385 pu->Info.Alloc.cSectorUnit = pu->Info.Req.VolInfo.ulBytesPerAllocationUnit / cbSector;
1386 pu->Info.Alloc.cUnit = (uint32_t)(pu->Info.Req.VolInfo.ullTotalAllocationBytes / cbSector);
1387 pu->Info.Alloc.cUnitAvail = (uint32_t)(pu->Info.Req.VolInfo.ullAvailableAllocationBytes / cbSector);
1388 pu->Info.Alloc.cbSector = (uint16_t)pu->Info.Req.VolInfo.ulBytesPerSector;
1389 rc = KernCopyOut(pbData, &pu->Info.Alloc, sizeof(pu->Info.Alloc));
1390 }
1391 else
1392 {
1393 RT_ZERO(pu->Info.FsInfo);
1394 pu->Info.FsInfo.vol.cch = (uint8_t)RT_MIN(pFolder->cchName, sizeof(pu->Info.FsInfo.vol.szVolLabel) - 1);
1395 memcpy(pu->Info.FsInfo.vol.szVolLabel, pFolder->szName, pu->Info.FsInfo.vol.cch);
1396 *(uint32_t *)&pu->Info.FsInfo.fdateCreation = pu->Info.Req.VolInfo.ulSerial;
1397 rc = KernCopyOut(pbData, &pu->Info.FsInfo, sizeof(pu->Info.FsInfo));
1398 }
1399 }
1400 else
1401 {
1402 LogRel(("FS32_FSINFO: VbglR0SfHostReqQueryVolInfo failed: %Rrc\n", vrc));
1403 rc = ERROR_GEN_FAILURE;
1404 }
1405
1406 vrc = VbglR0SfHostReqClose(pFolder->idHostRoot, &pu->Close, hHandle);
1407 AssertRC(vrc);
1408 }
1409 else
1410 rc = ERROR_GEN_FAILURE;
1411
1412 VbglR0PhysHeapFree(pu);
1413 }
1414 /*
1415 * We don't allow setting anything.
1416 */
1417 else if (fFlags == INFO_SET)
1418 {
1419 LogRel(("FS32_FSINFO: Attempting to set volume info (uLevel=%u, cbData=%#x) -> ERROR_ACCESS_DENIED\n", uLevel, cbData));
1420 rc = ERROR_ACCESS_DENIED;
1421 }
1422 else
1423 {
1424 LogRel(("FS32_FSINFO: Unknown flags: %#x\n", fFlags));
1425 rc = ERROR_SYS_INTERNAL;
1426 }
1427
1428 LogFlow(("FS32_FSINFO: returns %#x\n", rc));
1429 return rc;
1430}
1431
1432
1433DECLASM(APIRET)
1434FS32_FSCTL(union argdat *pArgData, ULONG iArgType, ULONG uFunction,
1435 PVOID pvParm, USHORT cbParm, PUSHORT pcbParmIO,
1436 PVOID pvData, USHORT cbData, PUSHORT pcbDataIO)
1437{
1438 LogFlow(("FS32_FSCTL: pArgData=%p iArgType=%#x uFunction=%#x pvParam=%p cbParam=%#x pcbParmIO=%p pvData=%p cbData=%#x pcbDataIO=%p\n",
1439 pArgData, iArgType, uFunction, pvParm, cbParm, pcbParmIO, pvData, cbData, pcbDataIO));
1440 NOREF(pArgData); NOREF(iArgType); NOREF(uFunction); NOREF(pvParm); NOREF(cbParm); NOREF(pcbParmIO);
1441 NOREF(pvData); NOREF(cbData); NOREF(pcbDataIO);
1442 return ERROR_NOT_SUPPORTED;
1443}
1444
1445
1446DECLASM(APIRET)
1447FS32_PROCESSNAME(PSZ pszName)
1448{
1449 LogFlow(("FS32_PROCESSNAME: '%s'\n", pszName));
1450 NOREF(pszName);
1451 return NO_ERROR;
1452}
1453
1454
1455DECLASM(APIRET)
1456FS32_CHDIR(ULONG fFlags, PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszDir, LONG offCurDirEnd)
1457{
1458 LogFlow(("FS32_CHDIR: fFlags=%#x pCdFsi=%p:{%#x,%s} pCdFsd=%p pszDir=%p:{%s} offCurDirEnd=%d\n",
1459 fFlags, pCdFsi, pCdFsi ? pCdFsi->cdi_hVPB : 0xffff, pCdFsi ? pCdFsi->cdi_curdir : "", pCdFsd, pszDir, pszDir, offCurDirEnd));
1460
1461 /*
1462 * We do not keep any information about open directory, just verify
1463 * them before they are CD'ed into and when asked to revalidate them.
1464 * If there were any path walking benefits, we could consider opening the
1465 * directory and keeping it open, but there isn't, so we don't do that.
1466 */
1467 APIRET rc = NO_ERROR;
1468 if ( fFlags == CD_EXPLICIT
1469 || fFlags == CD_VERIFY)
1470 {
1471 if (fFlags == CD_VERIFY)
1472 pszDir = pCdFsi->cdi_curdir;
1473
1474 PVBOXSFFOLDER pFolder;
1475 VBOXSFCREATEREQ *pReq;
1476 rc = vboxSfOs2ResolvePathEx(pszDir, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath),
1477 &pFolder, (void **)&pReq);
1478 if (rc == NO_ERROR)
1479 {
1480 pReq->CreateParms.CreateFlags = SHFL_CF_LOOKUP;
1481
1482 int vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
1483 LogFlow(("FS32_CHDIR: VbglR0SfHostReqCreate -> %Rrc Result=%d fMode=%#x\n",
1484 vrc, pReq->CreateParms.Result, pReq->CreateParms.Info.Attr.fMode));
1485 if (RT_SUCCESS(vrc))
1486 {
1487 switch (pReq->CreateParms.Result)
1488 {
1489 case SHFL_FILE_EXISTS:
1490 if (RTFS_IS_DIRECTORY(pReq->CreateParms.Info.Attr.fMode))
1491 rc = NO_ERROR;
1492 else
1493 rc = ERROR_ACCESS_DENIED;
1494 break;
1495
1496 case SHFL_PATH_NOT_FOUND:
1497 rc = ERROR_PATH_NOT_FOUND;
1498 break;
1499
1500 default:
1501 case SHFL_FILE_NOT_FOUND:
1502 rc = ERROR_FILE_NOT_FOUND;
1503 break;
1504 }
1505 }
1506 else
1507 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_PATH_NOT_FOUND);
1508 }
1509
1510 VbglR0PhysHeapFree(pReq);
1511 vboxSfOs2ReleaseFolder(pFolder);
1512 }
1513 else if (fFlags == CD_FREE)
1514 {
1515 /* nothing to do here. */
1516 }
1517 else
1518 {
1519 LogRel(("FS32_CHDIR: Unexpected fFlags value: %#x\n", fFlags));
1520 rc = ERROR_NOT_SUPPORTED;
1521 }
1522
1523 LogFlow(("FS32_CHDIR: returns %u\n", rc));
1524 return rc;
1525}
1526
1527
1528DECLASM(APIRET)
1529FS32_MKDIR(PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszDir, LONG offCurDirEnd, PEAOP pEaOp, ULONG fFlags)
1530{
1531 LogFlow(("FS32_MKDIR: pCdFsi=%p pCdFsd=%p pszDir=%p:{%s} pEAOp=%p fFlags=%#x\n", pCdFsi, pCdFsd, pszDir, pszDir, offCurDirEnd, pEaOp, fFlags));
1532 RT_NOREF(fFlags);
1533
1534 /*
1535 * We don't do EAs.
1536 */
1537 APIRET rc;
1538 if (pEaOp == NULL)
1539 rc = NO_ERROR;
1540 else
1541 rc = vboxSfOs2CheckEaOpForCreation(pEaOp);
1542 if (rc == NO_ERROR)
1543 {
1544 /*
1545 * Resolve the path.
1546 */
1547 PVBOXSFFOLDER pFolder;
1548 VBOXSFCREATEREQ *pReq;
1549 rc = vboxSfOs2ResolvePathEx(pszDir, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath),
1550 &pFolder, (void **)&pReq);
1551 if (rc == NO_ERROR)
1552 {
1553 /*
1554 * The silly interface for creating directories amounts an open call that
1555 * fails if it exists and we get a file handle back that needs closing. Sigh.
1556 */
1557 pReq->CreateParms.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW | SHFL_CF_ACT_FAIL_IF_EXISTS
1558 | SHFL_CF_ACCESS_READ | SHFL_CF_ACCESS_DENYNONE;
1559
1560 int vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
1561 LogFlow(("FS32_MKDIR: VbglR0SfHostReqCreate -> %Rrc Result=%d fMode=%#x\n",
1562 vrc, pReq->CreateParms.Result, pReq->CreateParms.Info.Attr.fMode));
1563 if (RT_SUCCESS(vrc))
1564 {
1565 switch (pReq->CreateParms.Result)
1566 {
1567 case SHFL_FILE_CREATED:
1568 if (pReq->CreateParms.Handle != SHFL_HANDLE_NIL)
1569 {
1570 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
1571 vrc = VbglR0SfHostReqClose(pFolder->idHostRoot, (VBOXSFCLOSEREQ *)pReq, pReq->CreateParms.Handle);
1572 AssertRC(vrc);
1573 }
1574 rc = NO_ERROR;
1575 break;
1576
1577 case SHFL_FILE_EXISTS:
1578 rc = ERROR_ACCESS_DENIED;
1579 break;
1580
1581 case SHFL_PATH_NOT_FOUND:
1582 rc = ERROR_PATH_NOT_FOUND;
1583 break;
1584
1585 default:
1586 case SHFL_FILE_NOT_FOUND:
1587 rc = ERROR_FILE_NOT_FOUND;
1588 break;
1589 }
1590 }
1591 else if (vrc == VERR_ALREADY_EXISTS)
1592 rc = ERROR_ACCESS_DENIED;
1593 else
1594 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_FILE_NOT_FOUND);
1595
1596 VbglR0PhysHeapFree(pReq);
1597 vboxSfOs2ReleaseFolder(pFolder);
1598 }
1599 }
1600 else
1601 Log(("FS32_MKDIR: EA trouble %p: %u%s\n", pEaOp, rc, rc == ERROR_EAS_NOT_SUPPORTED ? " (ERROR_EAS_NOT_SUPPORTED)" : ""));
1602
1603 RT_NOREF_PV(pCdFsi);
1604 LogFlow(("FS32_MMDIR: returns %u\n", rc));
1605 return rc;
1606}
1607
1608
1609DECLASM(APIRET)
1610FS32_RMDIR(PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszDir, LONG offCurDirEnd)
1611{
1612 LogFlow(("FS32_RMDIR: pCdFsi=%p pCdFsd=%p pszDir=%p:{%s} offCurDirEnd=%d\n", pCdFsi, pCdFsd, pszDir, pszDir, offCurDirEnd));
1613
1614 /*
1615 * Resolve the path.
1616 */
1617 PVBOXSFFOLDER pFolder;
1618 VBOXSFREMOVEREQ *pReq;
1619 APIRET rc = vboxSfOs2ResolvePathEx(pszDir, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath),
1620 &pFolder, (void **)&pReq);
1621 if (rc == NO_ERROR)
1622 {
1623 int vrc = VbglR0SfHostReqRemove(pFolder->idHostRoot, pReq, SHFL_REMOVE_DIR);
1624 LogFlow(("FS32_RMDIR: VbglR0SfHostReqRemove -> %Rrc\n", vrc));
1625 if (RT_SUCCESS(vrc))
1626 rc = NO_ERROR;
1627 else
1628 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_ACCESS_DENIED);
1629
1630 VbglR0PhysHeapFree(pReq);
1631 vboxSfOs2ReleaseFolder(pFolder);
1632 }
1633
1634 RT_NOREF_PV(pCdFsi);
1635 LogFlow(("FS32_RMDIR: returns %u\n", rc));
1636 return rc;
1637}
1638
1639
1640DECLASM(APIRET)
1641FS32_COPY(ULONG fFlags, PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszSrc, LONG offSrcCurDirEnd,
1642 PCSZ pszDst, LONG offDstCurDirEnd, ULONG uNameType)
1643{
1644 LogFlow(("FS32_COPY: fFlags=%#x pCdFsi=%p pCdFsd=%p pszSrc=%p:{%s} offSrcCurDirEnd=%d pszDst=%p:{%s} offDstCurDirEnd=%d uNameType=%#x\n",
1645 fFlags, pCdFsi, pCdFsd, pszSrc, pszSrc, offSrcCurDirEnd, pszDst, pszDst, offDstCurDirEnd, uNameType));
1646 NOREF(fFlags); NOREF(pCdFsi); NOREF(pCdFsd); NOREF(pszSrc); NOREF(offSrcCurDirEnd);
1647 NOREF(pszDst); NOREF(offDstCurDirEnd); NOREF(uNameType);
1648
1649 /* Let DOSCALL1.DLL do the work for us till we get a host side function for doing this. */
1650 return ERROR_CANNOT_COPY;
1651}
1652
1653
1654DECLASM(APIRET)
1655FS32_MOVE(PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszSrc, LONG offSrcCurDirEnd, PCSZ pszDst, LONG offDstCurDirEnd, ULONG uNameType)
1656{
1657 LogFlow(("FS32_MOVE: pCdFsi=%p pCdFsd=%p pszSrc=%p:{%s} offSrcCurDirEnd=%d pszDst=%p:{%s} offDstcurDirEnd=%d uNameType=%#x\n",
1658 pCdFsi, pCdFsd, pszSrc, pszSrc, offSrcCurDirEnd, pszDst, pszDst, offDstCurDirEnd, uNameType));
1659
1660 /*
1661 * Resolve the source and destination paths and check that they
1662 * refer to the same folder.
1663 */
1664 PVBOXSFFOLDER pSrcFolder;
1665 PSHFLSTRING pSrcFolderPath;
1666 APIRET rc = vboxSfOs2ResolvePath(pszSrc, pCdFsd, offSrcCurDirEnd, &pSrcFolder, &pSrcFolderPath);
1667 if (rc == NO_ERROR)
1668 {
1669 PVBOXSFFOLDER pDstFolder;
1670 VBOXSFRENAMEWITHSRCBUFREQ *pReq;
1671 rc = vboxSfOs2ResolvePathEx(pszDst, pCdFsd, offDstCurDirEnd, RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath),
1672 &pDstFolder, (void **)&pReq);
1673 if (rc == NO_ERROR)
1674 {
1675 if (pSrcFolder == pDstFolder)
1676 {
1677 /*
1678 * Do the renaming.
1679 * Note! Requires 6.0.0beta2+ or 5.2.24+ host for renaming files.
1680 */
1681 int vrc = VbglR0SfHostReqRenameWithSrcBuf(pSrcFolder->idHostRoot, pReq, pSrcFolderPath,
1682 SHFL_RENAME_FILE | SHFL_RENAME_DIR);
1683 if (RT_SUCCESS(vrc))
1684 rc = NO_ERROR;
1685 else
1686 {
1687 Log(("FS32_MOVE: VbglR0SfHostReqRenameWithSrcBuf failed: %Rrc\n", rc));
1688 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_ACCESS_DENIED);
1689 }
1690 }
1691 else
1692 {
1693 Log(("FS32_MOVE: source folder '%s' != destiation folder '%s'\n", pszSrc, pszDst));
1694 rc = ERROR_NOT_SAME_DEVICE;
1695 }
1696 VbglR0PhysHeapFree(pReq);
1697 vboxSfOs2ReleaseFolder(pDstFolder);
1698 }
1699 vboxSfOs2ReleasePathAndFolder(pSrcFolderPath, pSrcFolder);
1700 }
1701
1702 RT_NOREF_PV(pCdFsi); RT_NOREF_PV(uNameType);
1703 return rc;
1704}
1705
1706
1707DECLASM(APIRET)
1708FS32_DELETE(PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszFile, LONG offCurDirEnd)
1709{
1710 LogFlow(("FS32_DELETE: pCdFsi=%p pCdFsd=%p pszFile=%p:{%s} offCurDirEnd=%d\n", pCdFsi, pCdFsd, pszFile, pszFile, offCurDirEnd));
1711
1712 /*
1713 * Resolve the path.
1714 */
1715 PVBOXSFFOLDER pFolder;
1716 VBOXSFREMOVEREQ *pReq;
1717 APIRET rc = vboxSfOs2ResolvePathEx(pszFile, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath),
1718 &pFolder, (void **)&pReq);
1719 if (rc == NO_ERROR)
1720 {
1721 int vrc = VbglR0SfHostReqRemove(pFolder->idHostRoot, pReq, SHFL_REMOVE_FILE);
1722 LogFlow(("FS32_DELETE: VbglR0SfHostReqRemove -> %Rrc\n", vrc));
1723 if (RT_SUCCESS(vrc))
1724 rc = NO_ERROR;
1725 else
1726 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_ACCESS_DENIED);
1727
1728 VbglR0PhysHeapFree(pReq);
1729 vboxSfOs2ReleaseFolder(pFolder);
1730 }
1731
1732 RT_NOREF_PV(pCdFsi);
1733 LogFlow(("FS32_DELETE: returns %u\n", rc));
1734 return rc;
1735}
1736
1737
1738
1739/**
1740 * Worker for FS32_PATHINFO that handles file stat setting.
1741 *
1742 * @returns OS/2 status code
1743 * @param pFolder The folder.
1744 * @param hHostFile The host file handle.
1745 * @param fAttribs The attributes to set.
1746 * @param pTimestamps Pointer to the timestamps. NULL if none should be
1747 * modified.
1748 * @param pObjInfoBuf Buffer to use when setting the attributes (host
1749 * will return current info upon successful
1750 * return). This must life on the phys heap.
1751 * @param offObjInfoInAlloc Offset of pObjInfoBuf in the phys heap
1752 * allocation where it lives.
1753 */
1754APIRET vboxSfOs2SetInfoCommonWorker(PVBOXSFFOLDER pFolder, SHFLHANDLE hHostFile, ULONG fAttribs,
1755 PFILESTATUS pTimestamps, PSHFLFSOBJINFO pObjInfoBuf, uint32_t offObjInfoInAlloc)
1756{
1757 /*
1758 * Validate the data a little and convert it to host speak.
1759 * When the date part is zero, the timestamp should not be updated.
1760 */
1761 RT_ZERO(*pObjInfoBuf);
1762 uint16_t cDelta = vboxSfOs2GetLocalTimeDelta();
1763
1764 /** @todo should we validate attributes? */
1765 pObjInfoBuf->Attr.fMode = (fAttribs << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_OS2;
1766 if (pObjInfoBuf->Attr.fMode == 0)
1767 pObjInfoBuf->Attr.fMode |= RTFS_DOS_NT_NORMAL;
1768
1769 if (pTimestamps)
1770 {
1771 if ( *(uint16_t *)&pTimestamps->fdateCreation != 0
1772 && !vboxSfOs2DateTimeToTimeSpec(pTimestamps->fdateCreation, pTimestamps->ftimeCreation, cDelta, &pObjInfoBuf->BirthTime))
1773 {
1774 LogRel(("vboxSfOs2SetInfoCommonWorker: Bad creation timestamp: %u-%u-%u %u:%u:%u\n",
1775 pTimestamps->fdateCreation.year + 1980, pTimestamps->fdateCreation.month, pTimestamps->fdateCreation.day,
1776 pTimestamps->ftimeCreation.hours, pTimestamps->ftimeCreation.minutes, pTimestamps->ftimeCreation.twosecs * 2));
1777 return ERROR_INVALID_PARAMETER;
1778 }
1779 if ( *(uint16_t *)&pTimestamps->fdateLastAccess != 0
1780 && !vboxSfOs2DateTimeToTimeSpec(pTimestamps->fdateLastAccess, pTimestamps->ftimeLastAccess, cDelta, &pObjInfoBuf->AccessTime))
1781 {
1782 LogRel(("vboxSfOs2SetInfoCommonWorker: Bad last access timestamp: %u-%u-%u %u:%u:%u\n",
1783 pTimestamps->fdateLastAccess.year + 1980, pTimestamps->fdateLastAccess.month, pTimestamps->fdateLastAccess.day,
1784 pTimestamps->ftimeLastAccess.hours, pTimestamps->ftimeLastAccess.minutes, pTimestamps->ftimeLastAccess.twosecs * 2));
1785 return ERROR_INVALID_PARAMETER;
1786 }
1787 if ( *(uint16_t *)&pTimestamps->fdateLastWrite != 0
1788 && !vboxSfOs2DateTimeToTimeSpec(pTimestamps->fdateLastWrite, pTimestamps->ftimeLastWrite, cDelta, &pObjInfoBuf->ModificationTime))
1789 {
1790 LogRel(("vboxSfOs2SetInfoCommonWorker: Bad last access timestamp: %u-%u-%u %u:%u:%u\n",
1791 pTimestamps->fdateLastWrite.year + 1980, pTimestamps->fdateLastWrite.month, pTimestamps->fdateLastWrite.day,
1792 pTimestamps->ftimeLastWrite.hours, pTimestamps->ftimeLastWrite.minutes, pTimestamps->ftimeLastWrite.twosecs * 2));
1793 return ERROR_INVALID_PARAMETER;
1794 }
1795 }
1796
1797 /*
1798 * Call the host to do the updating.
1799 */
1800 VBOXSFOBJINFOWITHBUFREQ *pReq = (VBOXSFOBJINFOWITHBUFREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
1801 if (pReq)
1802 {
1803 int vrc = VbglR0SfHostReqSetObjInfoWithBuf(pFolder->idHostRoot, pReq, hHostFile, pObjInfoBuf, offObjInfoInAlloc);
1804 LogFlow(("vboxSfOs2SetFileInfo: VbglR0SfHostReqSetObjInfoWithBuf -> %Rrc\n", vrc));
1805
1806 VbglR0PhysHeapFree(pReq);
1807 if (RT_SUCCESS(vrc))
1808 return NO_ERROR;
1809 return vboxSfOs2ConvertStatusToOs2(vrc, ERROR_ACCESS_DENIED);
1810 }
1811 return ERROR_NOT_ENOUGH_MEMORY;
1812}
1813
1814
1815/**
1816 * Worker for FS32_FILEATTRIBUTE and FS32_PATHINFO that handles setting stuff.
1817 *
1818 * @returns OS/2 status code.
1819 * @param pFolder The folder.
1820 * @param pReq Open/create request buffer with path.
1821 * @param fAttribs New file attributes.
1822 * @param pTimestamps New timestamps. May be NULL.
1823 */
1824static APIRET vboxSfOs2SetPathInfoWorker(PVBOXSFFOLDER pFolder, VBOXSFCREATEREQ *pReq, ULONG fAttribs, PFILESTATUS pTimestamps)
1825
1826{
1827 /*
1828 * In order to do anything we need to open the object.
1829 */
1830 APIRET rc;
1831 pReq->CreateParms.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW
1832 | SHFL_CF_ACCESS_ATTR_READWRITE | SHFL_CF_ACCESS_DENYNONE | SHFL_CF_ACCESS_NONE;
1833
1834 int vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
1835 LogFlow(("vboxSfOs2SetPathInfoWorker: VbglR0SfHostReqCreate -> %Rrc Result=%d Handle=%#RX64 fMode=%#x\n",
1836 vrc, pReq->CreateParms.Result, pReq->CreateParms.Handle, pReq->CreateParms.Info.Attr.fMode));
1837 if ( vrc == VERR_IS_A_DIRECTORY
1838 || ( RT_SUCCESS(vrc)
1839 && pReq->CreateParms.Handle == SHFL_HANDLE_NIL
1840 && RTFS_IS_DIRECTORY(pReq->CreateParms.Info.Attr.fMode)))
1841 {
1842 RT_ZERO(pReq->CreateParms);
1843 pReq->CreateParms.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW
1844 | SHFL_CF_ACCESS_ATTR_READWRITE | SHFL_CF_ACCESS_DENYNONE | SHFL_CF_ACCESS_NONE;
1845 vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
1846 LogFlow(("vboxSfOs2SetPathInfoWorker: VbglR0SfHostReqCreate#2 -> %Rrc Result=%d Handle=%#RX64 fMode=%#x\n",
1847 vrc, pReq->CreateParms.Result, pReq->CreateParms.Handle, pReq->CreateParms.Info.Attr.fMode));
1848 }
1849 if (RT_SUCCESS(vrc))
1850 {
1851 switch (pReq->CreateParms.Result)
1852 {
1853 case SHFL_FILE_EXISTS:
1854 if (pReq->CreateParms.Handle != SHFL_HANDLE_NIL)
1855 {
1856 /*
1857 * Join up with FS32_FILEINFO to do the actual setting.
1858 */
1859 rc = vboxSfOs2SetInfoCommonWorker(pFolder, pReq->CreateParms.Handle, fAttribs, pTimestamps,
1860 &pReq->CreateParms.Info, RT_UOFFSETOF(VBOXSFCREATEREQ, CreateParms.Info));
1861
1862 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
1863 vrc = VbglR0SfHostReqClose(pFolder->idHostRoot, (VBOXSFCLOSEREQ *)pReq, pReq->CreateParms.Handle);
1864 AssertRC(vrc);
1865 }
1866 else
1867 {
1868 LogRel(("vboxSfOs2SetPathInfoWorker: No handle! fMode=%#x\n", pReq->CreateParms.Info.Attr.fMode));
1869 rc = ERROR_SYS_INTERNAL;
1870 }
1871 break;
1872
1873 case SHFL_PATH_NOT_FOUND:
1874 rc = ERROR_PATH_NOT_FOUND;
1875 break;
1876
1877 default:
1878 case SHFL_FILE_NOT_FOUND:
1879 rc = ERROR_FILE_NOT_FOUND;
1880 break;
1881 }
1882 }
1883 else
1884 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_FILE_NOT_FOUND);
1885 return rc;
1886}
1887
1888
1889DECLASM(APIRET)
1890FS32_FILEATTRIBUTE(ULONG fFlags, PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszName, LONG offCurDirEnd, PUSHORT pfAttr)
1891{
1892 LogFlow(("FS32_FILEATTRIBUTE: fFlags=%#x pCdFsi=%p:{%#x,%s} pCdFsd=%p pszName=%p:{%s} offCurDirEnd=%d pfAttr=%p={%#x}\n",
1893 fFlags, pCdFsi, pCdFsi->cdi_hVPB, pCdFsi->cdi_curdir, pCdFsd, pszName, pszName, offCurDirEnd, pfAttr, *pfAttr));
1894 RT_NOREF(pCdFsi, offCurDirEnd);
1895
1896 APIRET rc;
1897 if ( fFlags == FA_RETRIEVE
1898 || fFlags == FA_SET)
1899 {
1900 /* Both setting and querying needs to make a create request. */
1901 PVBOXSFFOLDER pFolder;
1902 VBOXSFCREATEREQ *pReq;
1903 rc = vboxSfOs2ResolvePathEx(pszName, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath),
1904 &pFolder, (void **)&pReq);
1905 if (rc == NO_ERROR)
1906 {
1907 if (fFlags == FA_RETRIEVE)
1908 {
1909 /*
1910 * Query it.
1911 */
1912 pReq->CreateParms.CreateFlags = SHFL_CF_LOOKUP;
1913
1914 int vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
1915 LogFlow(("FS32_FILEATTRIBUTE: VbglR0SfHostReqCreate -> %Rrc Result=%d fMode=%#x\n",
1916 vrc, pReq->CreateParms.Result, pReq->CreateParms.Info.Attr.fMode));
1917 if (RT_SUCCESS(vrc))
1918 {
1919 switch (pReq->CreateParms.Result)
1920 {
1921 case SHFL_FILE_EXISTS:
1922 *pfAttr = (uint16_t)((pReq->CreateParms.Info.Attr.fMode & RTFS_DOS_MASK_OS2) >> RTFS_DOS_SHIFT);
1923 rc = NO_ERROR;
1924 break;
1925
1926 case SHFL_PATH_NOT_FOUND:
1927 rc = ERROR_PATH_NOT_FOUND;
1928 break;
1929
1930 default:
1931 case SHFL_FILE_NOT_FOUND:
1932 rc = ERROR_FILE_NOT_FOUND;
1933 break;
1934 }
1935 }
1936 else
1937 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_FILE_NOT_FOUND);
1938 }
1939 else
1940 {
1941 /*
1942 * Set the info. Join paths with FS32_PATHINFO.
1943 */
1944 rc = vboxSfOs2SetPathInfoWorker(pFolder, pReq, *pfAttr, NULL);
1945 }
1946 VbglR0PhysHeapFree(pReq);
1947 vboxSfOs2ReleaseFolder(pFolder);
1948 }
1949 }
1950 else
1951 {
1952 LogRel(("FS32_FILEATTRIBUTE: Unknwon flag value: %#x\n", fFlags));
1953 rc = ERROR_NOT_SUPPORTED;
1954 }
1955 LogFlow(("FS32_FILEATTRIBUTE: returns %u\n", rc));
1956 return rc;
1957}
1958
1959
1960/**
1961 * Creates an empty full EA list given a GEALIST and info level.
1962 *
1963 * @returns OS/2 status code.
1964 * @param pEaOp Kernel copy of the EA request with flattened pointers.
1965 * @param uLevel The info level being queried.
1966 * @param cbFullEasLeft The size of the full EA buffer, ~(ULONG)0 if it
1967 * should be read in from pEaOp->fpFEAList->cbList.
1968 * @param pcbWritten Where to return the length of the resulting list. Optional.
1969 * @param poffError User buffer address of EAOP.oError for reporting GEALIST issues.
1970 */
1971APIRET vboxSfOs2MakeEmptyEaListEx(PEAOP pEaOp, ULONG uLevel, ULONG cbFullEasLeft, uint32_t *pcbWritten, ULONG *poffError)
1972{
1973 ULONG cbDstList;
1974 APIRET rc;
1975
1976 /*
1977 * Levels 8 and 5 are simple.
1978 */
1979 if ( pEaOp->fpGEAList == NULL
1980 || uLevel == FI_LVL_EAS_FULL_8
1981 || uLevel == FI_LVL_EAS_FULL_5)
1982 {
1983 Log2(("vboxSfOs2MakeEmptyEaList: #1\n"));
1984 cbDstList = RT_UOFFSET_AFTER(FEALIST, cbList);
1985 rc = NO_ERROR;
1986 }
1987 /*
1988 * For levels 3 and 4 we have to do work when a request list is present.
1989 */
1990 else
1991 {
1992 ULONG cbGetEasLeft = 0;
1993 rc = KernCopyIn(&cbGetEasLeft, &pEaOp->fpGEAList->cbList, sizeof(pEaOp->fpGEAList->cbList));
1994 if (rc == NO_ERROR && cbFullEasLeft == ~(ULONG)0)
1995 rc = KernCopyIn(&cbFullEasLeft, &pEaOp->fpFEAList->cbList, sizeof(cbFullEasLeft));
1996 if ( rc == NO_ERROR
1997 && cbGetEasLeft >= sizeof(pEaOp->fpGEAList->cbList)
1998 && cbFullEasLeft >= sizeof(pEaOp->fpFEAList->cbList))
1999 {
2000 cbGetEasLeft -= sizeof(pEaOp->fpGEAList->cbList);
2001 cbFullEasLeft -= sizeof(pEaOp->fpFEAList->cbList);
2002
2003 char *pszNameBuf = (char *)RTMemAlloc(256 + 1);
2004 if (!pszNameBuf)
2005 return ERROR_NOT_ENOUGH_MEMORY;
2006 /* Start of no-return zone. */
2007
2008 uint8_t const *pbSrc = (uint8_t const *)&pEaOp->fpGEAList->list[0]; /* user buffer! */
2009 uint8_t *pbDst = (uint8_t *)&pEaOp->fpFEAList->list[0]; /* user buffer! */
2010 Log2(("vboxSfOs2MakeEmptyEaList: %p LB %#x -> %p LB %#x...\n", pbSrc, cbGetEasLeft, pbDst, cbFullEasLeft));
2011 while (cbGetEasLeft > 0)
2012 {
2013 /*
2014 * pbSrc: GEA: BYTE cbName; char szName[];
2015 */
2016 /* Get name length (we call it cchName instead of cbName since
2017 it does not include the zero terminator). */
2018 uint8_t cchName = 0;
2019 rc = KernCopyIn(&cchName, pbSrc, sizeof(cchName));
2020 Log3(("vboxSfOs2MakeEmptyEaList: cchName=%#x rc=%u\n", cchName, rc));
2021 if (rc != NO_ERROR)
2022 break;
2023 pbSrc++;
2024 cbGetEasLeft--;
2025 if (cchName + 1U > cbGetEasLeft)
2026 {
2027 cbDstList = pbSrc - 1 - (uint8_t *)pEaOp->fpGEAList;
2028 rc = KernCopyOut(poffError, &cbDstList, sizeof(pEaOp->oError));
2029 if (rc == NO_ERROR)
2030 rc = ERROR_EA_LIST_INCONSISTENT;
2031 Log(("vboxSfOs2MakeEmptyEaList: ERROR_EA_LIST_INCONSISTENT\n"));
2032 break;
2033 }
2034
2035 /* Copy in name. */
2036 rc = KernCopyIn(pszNameBuf, pbSrc, cchName + 1);
2037 if (rc != NO_ERROR)
2038 break;
2039 Log3(("vboxSfOs2MakeEmptyEaList: szName: %.*Rhxs\n", cchName + 1, pszNameBuf));
2040 if ((char *)memchr(pszNameBuf, '\0', cchName + 1) != &pszNameBuf[cchName])
2041 {
2042 cbDstList = pbSrc - 1 - (uint8_t *)pEaOp->fpGEAList;
2043 rc = KernCopyOut(poffError, &cbDstList, sizeof(pEaOp->oError));
2044 if (rc == NO_ERROR)
2045 rc = ERROR_INVALID_EA_NAME;
2046 Log(("vboxSfOs2MakeEmptyEaList: ERROR_INVALID_EA_NAME\n"));
2047 break;
2048 }
2049
2050 /* Skip input. */
2051 cbGetEasLeft -= cchName + 1;
2052 pbSrc += cchName + 1;
2053
2054 /*
2055 * Construct and emit output.
2056 * Note! We should technically skip duplicates here, but who cares...
2057 */
2058 if (cchName > 0)
2059 {
2060 FEA Result;
2061 if (sizeof(Result) + cchName + 1 <= cbFullEasLeft)
2062 cbFullEasLeft -= sizeof(Result) + cchName + 1;
2063 else
2064 {
2065 Log(("vboxSfOs2MakeEmptyEaList: ERROR_BUFFER_OVERFLOW (%#x vs %#x)\n", sizeof(Result) + cchName + 1, cbFullEasLeft));
2066 rc = ERROR_BUFFER_OVERFLOW;
2067 break;
2068 }
2069
2070 Result.fEA = 0;
2071 Result.cbName = cchName;
2072 Result.cbValue = 0;
2073 rc = KernCopyOut(pbDst, &Result, sizeof(Result));
2074 if (rc != NO_ERROR)
2075 break;
2076 pbDst += sizeof(Result);
2077
2078 rc = KernCopyOut(pbDst, pszNameBuf, cchName + 1);
2079 if (rc != NO_ERROR)
2080 break;
2081 pbDst += cchName + 1;
2082 }
2083 } /* (while more GEAs) */
2084
2085 /* End of no-return zone. */
2086 RTMemFree(pszNameBuf);
2087
2088 cbDstList = (uintptr_t)pbDst - (uintptr_t)pEaOp->fpFEAList;
2089 }
2090 else
2091 {
2092 if (rc == NO_ERROR)
2093 rc = ERROR_BUFFER_OVERFLOW;
2094 cbDstList = 0; /* oh, shut up. */
2095 }
2096
2097 }
2098
2099 /* Set the list length. */
2100 if (rc == NO_ERROR)
2101 rc = KernCopyOut(&pEaOp->fpFEAList->cbList, &cbDstList, sizeof(pEaOp->fpFEAList->cbList));
2102
2103 if (pcbWritten)
2104 *pcbWritten = cbDstList;
2105
2106 Log(("vboxSfOs2MakeEmptyEaList: return %u (cbDstList=%#x)\n", rc, cbDstList));
2107 return rc;
2108}
2109
2110
2111
2112/**
2113 * Creates an empty full EA list given a GEALIST and info level.
2114 *
2115 * @returns OS/2 status code.
2116 * @param pEaOp The EA request. User buffer.
2117 * @param uLevel The info level being queried.
2118 */
2119DECL_NO_INLINE(RT_NOTHING, APIRET)
2120vboxSfOs2MakeEmptyEaList(PEAOP pEaOp, ULONG uLevel)
2121{
2122 /*
2123 * Copy the user request into memory, do pointer conversion, and
2124 * join extended function version.
2125 */
2126 EAOP EaOp = { NULL, NULL, 0 };
2127 APIRET rc = KernCopyIn(&EaOp, pEaOp, sizeof(EaOp));
2128 if (rc == NO_ERROR)
2129 {
2130 Log2(("vboxSfOs2MakeEmptyEaList: #0: %p %p %#x\n", EaOp.fpGEAList, EaOp.fpFEAList, EaOp.oError));
2131 EaOp.fpFEAList = (PFEALIST)KernSelToFlat((uintptr_t)EaOp.fpFEAList);
2132 if ( uLevel != FI_LVL_EAS_FULL
2133 && uLevel != FI_LVL_EAS_FULL_5
2134 && uLevel != FI_LVL_EAS_FULL_8)
2135 EaOp.fpGEAList = (PGEALIST)KernSelToFlat((uintptr_t)EaOp.fpGEAList);
2136 else
2137 EaOp.fpGEAList = NULL;
2138 Log2(("vboxSfOs2MakeEmptyEaList: #0b: %p %p\n", EaOp.fpGEAList, EaOp.fpFEAList));
2139
2140 rc = vboxSfOs2MakeEmptyEaListEx(&EaOp, uLevel, ~(ULONG)0, NULL, &pEaOp->oError);
2141 }
2142 return rc;
2143}
2144
2145
2146/**
2147 * Corrects the case of the given path.
2148 *
2149 * @returns OS/2 status code
2150 * @param pFolder The folder.
2151 * @param pReq Open/create request buffer with folder path.
2152 * @param pszPath The original path for figuring the drive letter or
2153 * UNC part of the path.
2154 * @param pbData Where to return the data (user address).
2155 * @param cbData The maximum amount of data we can return.
2156 */
2157static APIRET vboxSfOs2QueryCorrectCase(PVBOXSFFOLDER pFolder, VBOXSFCREATEREQ *pReq, const char *pszPath,
2158 PBYTE pbData, ULONG cbData)
2159{
2160 RT_NOREF(pFolder, pReq);
2161 APIRET rc;
2162 size_t cchPath = RTStrNLen(pszPath, CCHMAXPATH + 1);
2163 if (cchPath <= CCHMAXPATH)
2164 {
2165 if (cbData > cchPath)
2166 {
2167 /** @todo implement this properly on the host side! */
2168 rc = KernCopyOut(pbData, pszPath, cbData + 1);
2169 LogFlow(("vboxSfOs2QueryCorrectCase: returns %u\n", rc));
2170 }
2171 else
2172 {
2173 LogFlow(("vboxSfOs2QueryCorrectCase: returns %u (ERROR_INSUFFICIENT_BUFFER) - cchPath=%#x cbData=%#x\n",
2174 ERROR_INSUFFICIENT_BUFFER, cchPath, cbData));
2175 rc = ERROR_INSUFFICIENT_BUFFER;
2176 }
2177 }
2178 else
2179 {
2180 LogFlow(("vboxSfOs2QueryCorrectCase: returns %u (ERROR_FILENAME_EXCED_RANGE)\n", ERROR_FILENAME_EXCED_RANGE));
2181 rc = ERROR_FILENAME_EXCED_RANGE;
2182 }
2183 return rc;
2184}
2185
2186
2187/**
2188 * Copy out file status info.
2189 *
2190 * @returns OS/2 status code.
2191 * @param pbDst User address to put the status info at.
2192 * @param cbDst The size of the structure to produce.
2193 * @param uLevel The info level of the structure to produce.
2194 * @param pSrc The shared folder FS object info source structure.
2195 * @note Careful with stack, thus no-inlining.
2196 */
2197DECL_NO_INLINE(RT_NOTHING, APIRET)
2198vboxSfOs2FileStatusFromObjInfo(PBYTE pbDst, ULONG cbDst, ULONG uLevel, SHFLFSOBJINFO const *pSrc)
2199{
2200 union
2201 {
2202 FILESTATUS Fst;
2203 FILESTATUS2 Fst2;
2204 FILESTATUS3L Fst3L;
2205 FILESTATUS4L Fst4L;
2206 } uTmp;
2207
2208 int16_t cMinLocalTimeDelta = vboxSfOs2GetLocalTimeDelta();
2209 vboxSfOs2DateTimeFromTimeSpec(&uTmp.Fst.fdateCreation, &uTmp.Fst.ftimeCreation, pSrc->BirthTime, cMinLocalTimeDelta);
2210 vboxSfOs2DateTimeFromTimeSpec(&uTmp.Fst.fdateLastAccess, &uTmp.Fst.ftimeLastAccess, pSrc->AccessTime, cMinLocalTimeDelta);
2211 vboxSfOs2DateTimeFromTimeSpec(&uTmp.Fst.fdateLastWrite, &uTmp.Fst.ftimeLastWrite, pSrc->ModificationTime, cMinLocalTimeDelta);
2212 if (uLevel < FI_LVL_STANDARD_64)
2213 {
2214 uTmp.Fst.cbFile = (uint32_t)RT_MIN(pSrc->cbObject, UINT32_MAX);
2215 uTmp.Fst.cbFileAlloc = (uint32_t)RT_MIN(pSrc->cbAllocated, UINT32_MAX);
2216 uTmp.Fst.attrFile = (uint16_t)((pSrc->Attr.fMode & RTFS_DOS_MASK_OS2) >> RTFS_DOS_SHIFT);
2217 if (uLevel == FI_LVL_STANDARD_EASIZE)
2218 uTmp.Fst2.cbList = 0;
2219 }
2220 else
2221 {
2222 uTmp.Fst3L.cbFile = pSrc->cbObject;
2223 uTmp.Fst3L.cbFileAlloc = pSrc->cbAllocated;
2224 uTmp.Fst3L.attrFile = (pSrc->Attr.fMode & RTFS_DOS_MASK_OS2) >> RTFS_DOS_SHIFT;
2225 uTmp.Fst4L.cbList = 0;
2226 }
2227
2228 return KernCopyOut(pbDst, &uTmp, cbDst);
2229}
2230
2231
2232
2233/**
2234 * Worker for FS32_PATHINFO that handles file stat queries.
2235 *
2236 * @returns OS/2 status code
2237 * @param pFolder The folder.
2238 * @param pReq Open/create request buffer with folder path.
2239 * @param uLevel The information level.
2240 * @param pbData Where to return the data (user address).
2241 * @param cbData The amount of data to produce.
2242 */
2243static APIRET vboxSfOs2QueryPathInfo(PVBOXSFFOLDER pFolder, VBOXSFCREATEREQ *pReq, ULONG uLevel, PBYTE pbData, ULONG cbData)
2244{
2245 APIRET rc;
2246 pReq->CreateParms.CreateFlags = SHFL_CF_LOOKUP;
2247
2248 int vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
2249 LogFlow(("FS32_PATHINFO: VbglR0SfHostReqCreate -> %Rrc Result=%d fMode=%#x\n",
2250 vrc, pReq->CreateParms.Result, pReq->CreateParms.Info.Attr.fMode));
2251 if (RT_SUCCESS(vrc))
2252 {
2253 switch (pReq->CreateParms.Result)
2254 {
2255 case SHFL_FILE_EXISTS:
2256 switch (uLevel)
2257 {
2258 /*
2259 * Produce the desired file stat data.
2260 */
2261 case FI_LVL_STANDARD:
2262 case FI_LVL_STANDARD_EASIZE:
2263 case FI_LVL_STANDARD_64:
2264 case FI_LVL_STANDARD_EASIZE_64:
2265 rc = vboxSfOs2FileStatusFromObjInfo(pbData, cbData, uLevel, &pReq->CreateParms.Info);
2266 break;
2267
2268 /*
2269 * We don't do EAs and we "just" need to return no-EAs.
2270 * However, that's not as easy as you might think.
2271 */
2272 case FI_LVL_EAS_FROM_LIST:
2273 case FI_LVL_EAS_FULL:
2274 case FI_LVL_EAS_FULL_5:
2275 case FI_LVL_EAS_FULL_8:
2276 rc = vboxSfOs2MakeEmptyEaList((PEAOP)pbData, uLevel);
2277 break;
2278
2279 default:
2280 AssertFailed();
2281 rc = ERROR_GEN_FAILURE;
2282 break;
2283 }
2284 break;
2285
2286 case SHFL_PATH_NOT_FOUND:
2287 rc = ERROR_PATH_NOT_FOUND;
2288 break;
2289
2290 default:
2291 case SHFL_FILE_NOT_FOUND:
2292 rc = ERROR_FILE_NOT_FOUND;
2293 break;
2294 }
2295 }
2296 else
2297 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_FILE_NOT_FOUND);
2298 return rc;
2299}
2300
2301
2302DECLASM(APIRET)
2303FS32_PATHINFO(USHORT fFlags, PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszPath, LONG offCurDirEnd,
2304 ULONG uLevel, PBYTE pbData, ULONG cbData)
2305{
2306 LogFlow(("FS32_PATHINFO: fFlags=%#x pCdFsi=%p:{%#x,%s} pCdFsd=%p pszPath=%p:{%s} offCurDirEnd=%d uLevel=%u pbData=%p cbData=%#x\n",
2307 fFlags, pCdFsi, pCdFsi->cdi_hVPB, pCdFsi->cdi_curdir, pCdFsd, pszPath, pszPath, offCurDirEnd, uLevel, pbData, cbData));
2308
2309 /*
2310 * Check the level.
2311 *
2312 * Note! You would think this is FIL_STANDARD, FIL_QUERYEASIZE,
2313 * FIL_QUERYEASFROMLISTL and such. However, there are several levels
2314 * (4/14, 6/16, 7/17, 8/18) that are not defined in os2.h and then
2315 * there and FIL_QUERYFULLNAME that is used very between the kernel
2316 * and the FSD so the kernel can implement DosEnumAttributes.
2317 *
2318 * Note! DOSCALL1.DLL has code for converting FILESTATUS to FILESTATUS3
2319 * and FILESTATUS2 to FILESTATUS4 as needed. We don't need to do this.
2320 * It also has weird code for doubling the FILESTATUS2.cbList value
2321 * for no apparent reason.
2322 */
2323 ULONG cbMinData;
2324 switch (uLevel)
2325 {
2326 case FI_LVL_STANDARD:
2327 cbMinData = sizeof(FILESTATUS);
2328 AssertCompileSize(FILESTATUS, 0x16);
2329 break;
2330 case FI_LVL_STANDARD_64:
2331 cbMinData = sizeof(FILESTATUS3L);
2332 AssertCompileSize(FILESTATUS3L, 0x20); /* cbFile and cbFileAlloc are misaligned. */
2333 break;
2334 case FI_LVL_STANDARD_EASIZE:
2335 cbMinData = sizeof(FILESTATUS2);
2336 AssertCompileSize(FILESTATUS2, 0x1a);
2337 break;
2338 case FI_LVL_STANDARD_EASIZE_64:
2339 cbMinData = sizeof(FILESTATUS4L);
2340 AssertCompileSize(FILESTATUS4L, 0x24); /* cbFile and cbFileAlloc are misaligned. */
2341 break;
2342 case FI_LVL_EAS_FROM_LIST:
2343 case FI_LVL_EAS_FULL:
2344 case FI_LVL_EAS_FULL_5:
2345 case FI_LVL_EAS_FULL_8:
2346 cbMinData = sizeof(EAOP);
2347 break;
2348 case FI_LVL_VERIFY_PATH:
2349 case FI_LVL_CASE_CORRECT_PATH:
2350 cbMinData = 1;
2351 break;
2352 default:
2353 LogRel(("FS32_PATHINFO: Unsupported info level %u!\n", uLevel));
2354 return ERROR_INVALID_LEVEL;
2355 }
2356 if (cbData < cbMinData || pbData == NULL)
2357 {
2358 Log(("FS32_PATHINFO: ERROR_BUFFER_OVERFLOW (cbMinData=%#x, cbData=%#x, pszPath=%s)\n", cbMinData, cbData, pszPath));
2359 return ERROR_BUFFER_OVERFLOW;
2360 }
2361
2362 /*
2363 * Resolve the path to a folder and folder path.
2364 */
2365 PVBOXSFFOLDER pFolder;
2366 VBOXSFCREATEREQ *pReq;
2367 int rc = vboxSfOs2ResolvePathEx(pszPath, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath),
2368 &pFolder, (void **)&pReq);
2369 if (rc == NO_ERROR)
2370 {
2371 /*
2372 * Query information.
2373 */
2374 if (fFlags == PI_RETRIEVE)
2375 {
2376 if ( uLevel != FI_LVL_VERIFY_PATH
2377 && uLevel != FI_LVL_CASE_CORRECT_PATH)
2378 rc = vboxSfOs2QueryPathInfo(pFolder, pReq, uLevel, pbData, cbMinData);
2379 else if (uLevel == FI_LVL_VERIFY_PATH)
2380 rc = NO_ERROR; /* vboxSfOs2ResolvePath should've taken care of this already */
2381 else
2382 rc = vboxSfOs2QueryCorrectCase(pFolder, pReq, pszPath, pbData, cbData);
2383 }
2384 /*
2385 * Update information.
2386 */
2387 else if ( fFlags == PI_SET
2388 || fFlags == (PI_SET | PI_WRITE_THRU))
2389 {
2390 if ( uLevel == FI_LVL_STANDARD
2391 || uLevel == FI_LVL_STANDARD_64)
2392 {
2393 /* Read in the data and join paths with FS32_FILEATTRIBUTE: */
2394 PFILESTATUS pDataCopy = (PFILESTATUS)VbglR0PhysHeapAlloc(cbMinData);
2395 if (pDataCopy)
2396 {
2397 rc = KernCopyIn(pDataCopy, pbData, cbMinData);
2398 if (rc == NO_ERROR)
2399 rc = vboxSfOs2SetPathInfoWorker(pFolder, pReq,
2400 uLevel == FI_LVL_STANDARD
2401 ? (ULONG)pDataCopy->attrFile
2402 : ((PFILESTATUS3L)pDataCopy)->attrFile,
2403 (PFILESTATUS)pDataCopy);
2404 VbglR0PhysHeapFree(pDataCopy);
2405 }
2406 else
2407 rc = ERROR_NOT_ENOUGH_MEMORY;
2408 }
2409 else if (uLevel == FI_LVL_STANDARD_EASIZE)
2410 rc = ERROR_EAS_NOT_SUPPORTED;
2411 else
2412 rc = ERROR_INVALID_LEVEL;
2413 }
2414 else
2415 {
2416 LogRel(("FS32_PATHINFO: Unknown flags value: %#x (path: %s)\n", fFlags, pszPath));
2417 rc = ERROR_INVALID_PARAMETER;
2418 }
2419 VbglR0PhysHeapFree(pReq);
2420 vboxSfOs2ReleaseFolder(pFolder);
2421 }
2422 RT_NOREF_PV(pCdFsi);
2423 return rc;
2424}
2425
2426
2427DECLASM(APIRET)
2428FS32_MOUNT(USHORT fFlags, PVPFSI pvpfsi, PVBOXSFVP pVpFsd, USHORT hVPB, PCSZ pszBoot)
2429{
2430 NOREF(fFlags); NOREF(pvpfsi); NOREF(pVpFsd); NOREF(hVPB); NOREF(pszBoot);
2431 return ERROR_NOT_SUPPORTED;
2432}
2433
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use