VirtualBox

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

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

SharedFolders,os2/VBoxSF: Continued hacking on replacements for VbglR0SfXxxx using OS/2 as testbed. Some simple read+write optimizations. bugref:9172

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