VirtualBox

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

Last change on this file since 77661 was 77661, checked in by vboxsync, 5 years ago

os2/vboxsf: Supply RTFS_DOS_NT_NORMAL if fMode is zero, or the host will make no changes (resetting readonly bit not possible). Fake case correction or the icsdebug won't display sources (among other things). Detect reads beyond EOF and skip updating sfi_sizel and timestamps. Both FS32_READ and FS32_WRITE had one or three instances of 'rc' variable shadowing.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 87.8 KB
Line 
1/** $Id: VBoxSF.cpp 77661 2019-03-11 21:14:16Z 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 {
1540 /*
1541 * Resolve the path.
1542 */
1543 PVBOXSFFOLDER pFolder;
1544 VBOXSFCREATEREQ *pReq;
1545 rc = vboxSfOs2ResolvePathEx(pszDir, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath),
1546 &pFolder, (void **)&pReq);
1547 if (rc == NO_ERROR)
1548 {
1549 /*
1550 * The silly interface for creating directories amounts an open call that
1551 * fails if it exists and we get a file handle back that needs closing. Sigh.
1552 */
1553 pReq->CreateParms.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW | SHFL_CF_ACT_FAIL_IF_EXISTS
1554 | SHFL_CF_ACCESS_READ | SHFL_CF_ACCESS_DENYNONE;
1555
1556 int vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
1557 LogFlow(("FS32_MKDIR: VbglR0SfHostReqCreate -> %Rrc Result=%d fMode=%#x\n",
1558 vrc, pReq->CreateParms.Result, pReq->CreateParms.Info.Attr.fMode));
1559 if (RT_SUCCESS(vrc))
1560 {
1561 switch (pReq->CreateParms.Result)
1562 {
1563 case SHFL_FILE_CREATED:
1564 if (pReq->CreateParms.Handle != SHFL_HANDLE_NIL)
1565 {
1566 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
1567 vrc = VbglR0SfHostReqClose(pFolder->idHostRoot, (VBOXSFCLOSEREQ *)pReq, pReq->CreateParms.Handle);
1568 AssertRC(vrc);
1569 }
1570 rc = NO_ERROR;
1571 break;
1572
1573 case SHFL_FILE_EXISTS:
1574 rc = ERROR_ACCESS_DENIED;
1575 break;
1576
1577 case SHFL_PATH_NOT_FOUND:
1578 rc = ERROR_PATH_NOT_FOUND;
1579 break;
1580
1581 default:
1582 case SHFL_FILE_NOT_FOUND:
1583 rc = ERROR_FILE_NOT_FOUND;
1584 break;
1585 }
1586 }
1587 else if (vrc == VERR_ALREADY_EXISTS)
1588 rc = ERROR_ACCESS_DENIED;
1589 else
1590 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_FILE_NOT_FOUND);
1591
1592 VbglR0PhysHeapFree(pReq);
1593 vboxSfOs2ReleaseFolder(pFolder);
1594 }
1595 }
1596 else
1597 {
1598 Log(("FS32_MKDIR: EAs not supported\n"));
1599 rc = ERROR_EAS_NOT_SUPPORTED;
1600 }
1601
1602 RT_NOREF_PV(pCdFsi);
1603 LogFlow(("FS32_MMDIR: returns %u\n", rc));
1604 return rc;
1605}
1606
1607
1608DECLASM(APIRET)
1609FS32_RMDIR(PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszDir, LONG offCurDirEnd)
1610{
1611 LogFlow(("FS32_RMDIR: pCdFsi=%p pCdFsd=%p pszDir=%p:{%s} offCurDirEnd=%d\n", pCdFsi, pCdFsd, pszDir, pszDir, offCurDirEnd));
1612
1613 /*
1614 * Resolve the path.
1615 */
1616 PVBOXSFFOLDER pFolder;
1617 VBOXSFREMOVEREQ *pReq;
1618 APIRET rc = vboxSfOs2ResolvePathEx(pszDir, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath),
1619 &pFolder, (void **)&pReq);
1620 if (rc == NO_ERROR)
1621 {
1622 int vrc = VbglR0SfHostReqRemove(pFolder->idHostRoot, pReq, SHFL_REMOVE_DIR);
1623 LogFlow(("FS32_RMDIR: VbglR0SfHostReqRemove -> %Rrc\n", vrc));
1624 if (RT_SUCCESS(vrc))
1625 rc = NO_ERROR;
1626 else
1627 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_ACCESS_DENIED);
1628
1629 VbglR0PhysHeapFree(pReq);
1630 vboxSfOs2ReleaseFolder(pFolder);
1631 }
1632
1633 RT_NOREF_PV(pCdFsi);
1634 LogFlow(("FS32_RMDIR: returns %u\n", rc));
1635 return rc;
1636}
1637
1638
1639DECLASM(APIRET)
1640FS32_COPY(ULONG fFlags, PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszSrc, LONG offSrcCurDirEnd,
1641 PCSZ pszDst, LONG offDstCurDirEnd, ULONG uNameType)
1642{
1643 LogFlow(("FS32_COPY: fFlags=%#x pCdFsi=%p pCdFsd=%p pszSrc=%p:{%s} offSrcCurDirEnd=%d pszDst=%p:{%s} offDstCurDirEnd=%d uNameType=%#x\n",
1644 fFlags, pCdFsi, pCdFsd, pszSrc, pszSrc, offSrcCurDirEnd, pszDst, pszDst, offDstCurDirEnd, uNameType));
1645 NOREF(fFlags); NOREF(pCdFsi); NOREF(pCdFsd); NOREF(pszSrc); NOREF(offSrcCurDirEnd);
1646 NOREF(pszDst); NOREF(offDstCurDirEnd); NOREF(uNameType);
1647
1648 /* Let DOSCALL1.DLL do the work for us till we get a host side function for doing this. */
1649 return ERROR_CANNOT_COPY;
1650}
1651
1652
1653DECLASM(APIRET)
1654FS32_MOVE(PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszSrc, LONG offSrcCurDirEnd, PCSZ pszDst, LONG offDstCurDirEnd, ULONG uNameType)
1655{
1656 LogFlow(("FS32_MOVE: pCdFsi=%p pCdFsd=%p pszSrc=%p:{%s} offSrcCurDirEnd=%d pszDst=%p:{%s} offDstcurDirEnd=%d uNameType=%#x\n",
1657 pCdFsi, pCdFsd, pszSrc, pszSrc, offSrcCurDirEnd, pszDst, pszDst, offDstCurDirEnd, uNameType));
1658
1659 /*
1660 * Resolve the source and destination paths and check that they
1661 * refer to the same folder.
1662 */
1663 PVBOXSFFOLDER pSrcFolder;
1664 PSHFLSTRING pSrcFolderPath;
1665 APIRET rc = vboxSfOs2ResolvePath(pszSrc, pCdFsd, offSrcCurDirEnd, &pSrcFolder, &pSrcFolderPath);
1666 if (rc == NO_ERROR)
1667 {
1668 PVBOXSFFOLDER pDstFolder;
1669 VBOXSFRENAMEWITHSRCBUFREQ *pReq;
1670 rc = vboxSfOs2ResolvePathEx(pszDst, pCdFsd, offDstCurDirEnd, RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath),
1671 &pDstFolder, (void **)&pReq);
1672 if (rc == NO_ERROR)
1673 {
1674 if (pSrcFolder == pDstFolder)
1675 {
1676 /*
1677 * Do the renaming.
1678 * Note! Requires 6.0.0beta2+ or 5.2.24+ host for renaming files.
1679 */
1680 int vrc = VbglR0SfHostReqRenameWithSrcBuf(pSrcFolder->idHostRoot, pReq, pSrcFolderPath,
1681 SHFL_RENAME_FILE | SHFL_RENAME_DIR);
1682 if (RT_SUCCESS(vrc))
1683 rc = NO_ERROR;
1684 else
1685 {
1686 Log(("FS32_MOVE: VbglR0SfHostReqRenameWithSrcBuf failed: %Rrc\n", rc));
1687 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_ACCESS_DENIED);
1688 }
1689 }
1690 else
1691 {
1692 Log(("FS32_MOVE: source folder '%s' != destiation folder '%s'\n", pszSrc, pszDst));
1693 rc = ERROR_NOT_SAME_DEVICE;
1694 }
1695 VbglR0PhysHeapFree(pReq);
1696 vboxSfOs2ReleaseFolder(pDstFolder);
1697 }
1698 vboxSfOs2ReleasePathAndFolder(pSrcFolderPath, pSrcFolder);
1699 }
1700
1701 RT_NOREF_PV(pCdFsi); RT_NOREF_PV(uNameType);
1702 return rc;
1703}
1704
1705
1706DECLASM(APIRET)
1707FS32_DELETE(PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszFile, LONG offCurDirEnd)
1708{
1709 LogFlow(("FS32_DELETE: pCdFsi=%p pCdFsd=%p pszFile=%p:{%s} offCurDirEnd=%d\n", pCdFsi, pCdFsd, pszFile, pszFile, offCurDirEnd));
1710
1711 /*
1712 * Resolve the path.
1713 */
1714 PVBOXSFFOLDER pFolder;
1715 VBOXSFREMOVEREQ *pReq;
1716 APIRET rc = vboxSfOs2ResolvePathEx(pszFile, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath),
1717 &pFolder, (void **)&pReq);
1718 if (rc == NO_ERROR)
1719 {
1720 int vrc = VbglR0SfHostReqRemove(pFolder->idHostRoot, pReq, SHFL_REMOVE_FILE);
1721 LogFlow(("FS32_DELETE: VbglR0SfHostReqRemove -> %Rrc\n", vrc));
1722 if (RT_SUCCESS(vrc))
1723 rc = NO_ERROR;
1724 else
1725 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_ACCESS_DENIED);
1726
1727 VbglR0PhysHeapFree(pReq);
1728 vboxSfOs2ReleaseFolder(pFolder);
1729 }
1730
1731 RT_NOREF_PV(pCdFsi);
1732 LogFlow(("FS32_DELETE: returns %u\n", rc));
1733 return rc;
1734}
1735
1736
1737
1738/**
1739 * Worker for FS32_PATHINFO that handles file stat setting.
1740 *
1741 * @returns OS/2 status code
1742 * @param pFolder The folder.
1743 * @param hHostFile The host file handle.
1744 * @param fAttribs The attributes to set.
1745 * @param pTimestamps Pointer to the timestamps. NULL if none should be
1746 * modified.
1747 * @param pObjInfoBuf Buffer to use when setting the attributes (host
1748 * will return current info upon successful
1749 * return). This must life on the phys heap.
1750 * @param offObjInfoInAlloc Offset of pObjInfoBuf in the phys heap
1751 * allocation where it lives.
1752 */
1753APIRET vboxSfOs2SetInfoCommonWorker(PVBOXSFFOLDER pFolder, SHFLHANDLE hHostFile, ULONG fAttribs,
1754 PFILESTATUS pTimestamps, PSHFLFSOBJINFO pObjInfoBuf, uint32_t offObjInfoInAlloc)
1755{
1756 /*
1757 * Validate the data a little and convert it to host speak.
1758 * When the date part is zero, the timestamp should not be updated.
1759 */
1760 RT_ZERO(*pObjInfoBuf);
1761 uint16_t cDelta = vboxSfOs2GetLocalTimeDelta();
1762
1763 /** @todo should we validate attributes? */
1764 pObjInfoBuf->Attr.fMode = (fAttribs << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_OS2;
1765 if (pObjInfoBuf->Attr.fMode == 0)
1766 pObjInfoBuf->Attr.fMode |= RTFS_DOS_NT_NORMAL;
1767
1768 if (pTimestamps)
1769 {
1770 if ( *(uint16_t *)&pTimestamps->fdateCreation != 0
1771 && !vboxSfOs2DateTimeToTimeSpec(pTimestamps->fdateCreation, pTimestamps->ftimeCreation, cDelta, &pObjInfoBuf->BirthTime))
1772 {
1773 LogRel(("vboxSfOs2SetInfoCommonWorker: Bad creation timestamp: %u-%u-%u %u:%u:%u\n",
1774 pTimestamps->fdateCreation.year + 1980, pTimestamps->fdateCreation.month, pTimestamps->fdateCreation.day,
1775 pTimestamps->ftimeCreation.hours, pTimestamps->ftimeCreation.minutes, pTimestamps->ftimeCreation.twosecs * 2));
1776 return ERROR_INVALID_PARAMETER;
1777 }
1778 if ( *(uint16_t *)&pTimestamps->fdateLastAccess != 0
1779 && !vboxSfOs2DateTimeToTimeSpec(pTimestamps->fdateLastAccess, pTimestamps->ftimeLastAccess, cDelta, &pObjInfoBuf->AccessTime))
1780 {
1781 LogRel(("vboxSfOs2SetInfoCommonWorker: Bad last access timestamp: %u-%u-%u %u:%u:%u\n",
1782 pTimestamps->fdateLastAccess.year + 1980, pTimestamps->fdateLastAccess.month, pTimestamps->fdateLastAccess.day,
1783 pTimestamps->ftimeLastAccess.hours, pTimestamps->ftimeLastAccess.minutes, pTimestamps->ftimeLastAccess.twosecs * 2));
1784 return ERROR_INVALID_PARAMETER;
1785 }
1786 if ( *(uint16_t *)&pTimestamps->fdateLastWrite != 0
1787 && !vboxSfOs2DateTimeToTimeSpec(pTimestamps->fdateLastWrite, pTimestamps->ftimeLastWrite, cDelta, &pObjInfoBuf->ModificationTime))
1788 {
1789 LogRel(("vboxSfOs2SetInfoCommonWorker: Bad last access timestamp: %u-%u-%u %u:%u:%u\n",
1790 pTimestamps->fdateLastWrite.year + 1980, pTimestamps->fdateLastWrite.month, pTimestamps->fdateLastWrite.day,
1791 pTimestamps->ftimeLastWrite.hours, pTimestamps->ftimeLastWrite.minutes, pTimestamps->ftimeLastWrite.twosecs * 2));
1792 return ERROR_INVALID_PARAMETER;
1793 }
1794 }
1795
1796 /*
1797 * Call the host to do the updating.
1798 */
1799 VBOXSFOBJINFOWITHBUFREQ *pReq = (VBOXSFOBJINFOWITHBUFREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
1800 if (pReq)
1801 {
1802 int vrc = VbglR0SfHostReqSetObjInfoWithBuf(pFolder->idHostRoot, pReq, hHostFile, pObjInfoBuf, offObjInfoInAlloc);
1803 LogFlow(("vboxSfOs2SetFileInfo: VbglR0SfHostReqSetObjInfoWithBuf -> %Rrc\n", vrc));
1804
1805 VbglR0PhysHeapFree(pReq);
1806 if (RT_SUCCESS(vrc))
1807 return NO_ERROR;
1808 return vboxSfOs2ConvertStatusToOs2(vrc, ERROR_ACCESS_DENIED);
1809 }
1810 return ERROR_NOT_ENOUGH_MEMORY;
1811}
1812
1813
1814/**
1815 * Worker for FS32_FILEATTRIBUTE and FS32_PATHINFO that handles setting stuff.
1816 *
1817 * @returns OS/2 status code.
1818 * @param pFolder The folder.
1819 * @param pReq Open/create request buffer with path.
1820 * @param fAttribs New file attributes.
1821 * @param pTimestamps New timestamps. May be NULL.
1822 */
1823static APIRET vboxSfOs2SetPathInfoWorker(PVBOXSFFOLDER pFolder, VBOXSFCREATEREQ *pReq, ULONG fAttribs, PFILESTATUS pTimestamps)
1824
1825{
1826 /*
1827 * In order to do anything we need to open the object.
1828 */
1829 APIRET rc;
1830 pReq->CreateParms.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW
1831 | SHFL_CF_ACCESS_ATTR_READWRITE | SHFL_CF_ACCESS_DENYNONE | SHFL_CF_ACCESS_NONE;
1832
1833 int vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
1834 LogFlow(("vboxSfOs2SetPathInfoWorker: VbglR0SfHostReqCreate -> %Rrc Result=%d Handle=%#RX64 fMode=%#x\n",
1835 vrc, pReq->CreateParms.Result, pReq->CreateParms.Handle, pReq->CreateParms.Info.Attr.fMode));
1836 if ( vrc == VERR_IS_A_DIRECTORY
1837 || ( RT_SUCCESS(vrc)
1838 && pReq->CreateParms.Handle == SHFL_HANDLE_NIL
1839 && RTFS_IS_DIRECTORY(pReq->CreateParms.Info.Attr.fMode)))
1840 {
1841 RT_ZERO(pReq->CreateParms);
1842 pReq->CreateParms.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW
1843 | SHFL_CF_ACCESS_ATTR_READWRITE | SHFL_CF_ACCESS_DENYNONE | SHFL_CF_ACCESS_NONE;
1844 vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
1845 LogFlow(("vboxSfOs2SetPathInfoWorker: VbglR0SfHostReqCreate#2 -> %Rrc Result=%d Handle=%#RX64 fMode=%#x\n",
1846 vrc, pReq->CreateParms.Result, pReq->CreateParms.Handle, pReq->CreateParms.Info.Attr.fMode));
1847 }
1848 if (RT_SUCCESS(vrc))
1849 {
1850 switch (pReq->CreateParms.Result)
1851 {
1852 case SHFL_FILE_EXISTS:
1853 if (pReq->CreateParms.Handle != SHFL_HANDLE_NIL)
1854 {
1855 /*
1856 * Join up with FS32_FILEINFO to do the actual setting.
1857 */
1858 rc = vboxSfOs2SetInfoCommonWorker(pFolder, pReq->CreateParms.Handle, fAttribs, pTimestamps,
1859 &pReq->CreateParms.Info, RT_UOFFSETOF(VBOXSFCREATEREQ, CreateParms.Info));
1860
1861 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
1862 vrc = VbglR0SfHostReqClose(pFolder->idHostRoot, (VBOXSFCLOSEREQ *)pReq, pReq->CreateParms.Handle);
1863 AssertRC(vrc);
1864 }
1865 else
1866 {
1867 LogRel(("vboxSfOs2SetPathInfoWorker: No handle! fMode=%#x\n", pReq->CreateParms.Info.Attr.fMode));
1868 rc = ERROR_SYS_INTERNAL;
1869 }
1870 break;
1871
1872 case SHFL_PATH_NOT_FOUND:
1873 rc = ERROR_PATH_NOT_FOUND;
1874 break;
1875
1876 default:
1877 case SHFL_FILE_NOT_FOUND:
1878 rc = ERROR_FILE_NOT_FOUND;
1879 break;
1880 }
1881 }
1882 else
1883 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_FILE_NOT_FOUND);
1884 return rc;
1885}
1886
1887
1888DECLASM(APIRET)
1889FS32_FILEATTRIBUTE(ULONG fFlags, PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszName, LONG offCurDirEnd, PUSHORT pfAttr)
1890{
1891 LogFlow(("FS32_FILEATTRIBUTE: fFlags=%#x pCdFsi=%p:{%#x,%s} pCdFsd=%p pszName=%p:{%s} offCurDirEnd=%d pfAttr=%p={%#x}\n",
1892 fFlags, pCdFsi, pCdFsi->cdi_hVPB, pCdFsi->cdi_curdir, pCdFsd, pszName, pszName, offCurDirEnd, pfAttr, *pfAttr));
1893 RT_NOREF(pCdFsi, offCurDirEnd);
1894
1895 APIRET rc;
1896 if ( fFlags == FA_RETRIEVE
1897 || fFlags == FA_SET)
1898 {
1899 /* Both setting and querying needs to make a create request. */
1900 PVBOXSFFOLDER pFolder;
1901 VBOXSFCREATEREQ *pReq;
1902 rc = vboxSfOs2ResolvePathEx(pszName, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath),
1903 &pFolder, (void **)&pReq);
1904 if (rc == NO_ERROR)
1905 {
1906 if (fFlags == FA_RETRIEVE)
1907 {
1908 /*
1909 * Query it.
1910 */
1911 pReq->CreateParms.CreateFlags = SHFL_CF_LOOKUP;
1912
1913 int vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
1914 LogFlow(("FS32_FILEATTRIBUTE: VbglR0SfHostReqCreate -> %Rrc Result=%d fMode=%#x\n",
1915 vrc, pReq->CreateParms.Result, pReq->CreateParms.Info.Attr.fMode));
1916 if (RT_SUCCESS(vrc))
1917 {
1918 switch (pReq->CreateParms.Result)
1919 {
1920 case SHFL_FILE_EXISTS:
1921 *pfAttr = (uint16_t)((pReq->CreateParms.Info.Attr.fMode & RTFS_DOS_MASK_OS2) >> RTFS_DOS_SHIFT);
1922 rc = NO_ERROR;
1923 break;
1924
1925 case SHFL_PATH_NOT_FOUND:
1926 rc = ERROR_PATH_NOT_FOUND;
1927 break;
1928
1929 default:
1930 case SHFL_FILE_NOT_FOUND:
1931 rc = ERROR_FILE_NOT_FOUND;
1932 break;
1933 }
1934 }
1935 else
1936 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_FILE_NOT_FOUND);
1937 }
1938 else
1939 {
1940 /*
1941 * Set the info. Join paths with FS32_PATHINFO.
1942 */
1943 rc = vboxSfOs2SetPathInfoWorker(pFolder, pReq, *pfAttr, NULL);
1944 }
1945 VbglR0PhysHeapFree(pReq);
1946 vboxSfOs2ReleaseFolder(pFolder);
1947 }
1948 }
1949 else
1950 {
1951 LogRel(("FS32_FILEATTRIBUTE: Unknwon flag value: %#x\n", fFlags));
1952 rc = ERROR_NOT_SUPPORTED;
1953 }
1954 LogFlow(("FS32_FILEATTRIBUTE: returns %u\n", rc));
1955 return rc;
1956}
1957
1958
1959/**
1960 * Creates an empty full EA list given a GEALIST and info level.
1961 *
1962 * @returns OS/2 status code.
1963 * @param pEaOp Kernel copy of the EA request with flattened pointers.
1964 * @param uLevel The info level being queried.
1965 * @param pcbWritten Where to return the length of the resulting list. Optional.
1966 * @param poffError User buffer address of EAOP.oError for reporting GEALIST issues.
1967 */
1968APIRET vboxSfOs2MakeEmptyEaListEx(PEAOP pEaOp, ULONG uLevel, uint32_t *pcbWritten, ULONG *poffError)
1969{
1970 ULONG cbDstList;
1971 APIRET rc;
1972
1973 /*
1974 * Levels 8 and 5 are simple.
1975 */
1976 if ( pEaOp->fpGEAList == NULL
1977 || uLevel == FI_LVL_EAS_FULL_8
1978 || uLevel == FI_LVL_EAS_FULL_5)
1979 {
1980 Log2(("vboxSfOs2MakeEmptyEaList: #1\n"));
1981 cbDstList = RT_UOFFSET_AFTER(FEALIST, cbList);
1982 rc = NO_ERROR;
1983 }
1984 /*
1985 * For levels 3 and 4 we have to do work when a request list is present.
1986 */
1987 else
1988 {
1989 ULONG cbGetEasLeft = 0;
1990 rc = KernCopyIn(&cbGetEasLeft, &pEaOp->fpGEAList->cbList, sizeof(pEaOp->fpGEAList->cbList));
1991 ULONG cbFullEasLeft = 0;
1992 if (rc == NO_ERROR)
1993 rc = KernCopyIn(&cbFullEasLeft, &pEaOp->fpFEAList->cbList, sizeof(cbFullEasLeft));
1994 if ( rc == NO_ERROR
1995 && cbGetEasLeft >= sizeof(pEaOp->fpGEAList->cbList)
1996 && cbFullEasLeft >= sizeof(pEaOp->fpFEAList->cbList))
1997 {
1998 cbGetEasLeft -= sizeof(pEaOp->fpGEAList->cbList);
1999 cbFullEasLeft -= sizeof(pEaOp->fpFEAList->cbList);
2000
2001 char *pszNameBuf = (char *)RTMemAlloc(256 + 1);
2002 if (!pszNameBuf)
2003 return ERROR_NOT_ENOUGH_MEMORY;
2004 /* Start of no-return zone. */
2005
2006 uint8_t const *pbSrc = (uint8_t const *)&pEaOp->fpGEAList->list[0]; /* user buffer! */
2007 uint8_t *pbDst = (uint8_t *)&pEaOp->fpFEAList->list[0]; /* user buffer! */
2008 Log2(("vboxSfOs2MakeEmptyEaList: %p LB %#x -> %p LB %#x...\n", pbSrc, cbGetEasLeft, pbDst, cbFullEasLeft));
2009 while (cbGetEasLeft > 0)
2010 {
2011 /*
2012 * pbSrc: GEA: BYTE cbName; char szName[];
2013 */
2014 /* Get name length. */
2015 uint8_t cbName = 0;
2016 rc = KernCopyIn(&cbName, pbSrc, sizeof(cbName));
2017 Log3(("vboxSfOs2MakeEmptyEaList: cbName=%#x rc=%u\n", cbName, rc));
2018 if (rc != NO_ERROR)
2019 break;
2020 pbSrc++;
2021 cbGetEasLeft--;
2022 if (cbName + 1U > cbGetEasLeft)
2023 {
2024 cbDstList = pbSrc - 1 - (uint8_t *)pEaOp->fpGEAList;
2025 rc = KernCopyOut(poffError, &cbDstList, sizeof(pEaOp->oError));
2026 if (rc == NO_ERROR)
2027 rc = ERROR_EA_LIST_INCONSISTENT;
2028 Log(("vboxSfOs2MakeEmptyEaList: ERROR_EA_LIST_INCONSISTENT\n"));
2029 break;
2030 }
2031
2032 /* Copy in name. */
2033 rc = KernCopyIn(pszNameBuf, pbSrc, cbName + 1);
2034 if (rc != NO_ERROR)
2035 break;
2036 Log3(("vboxSfOs2MakeEmptyEaList: szName: %.*Rhxs\n", cbName + 1, pszNameBuf));
2037 if ((char *)memchr(pszNameBuf, '\0', cbName) != &pszNameBuf[cbName])
2038 {
2039 cbDstList = pbSrc - 1 - (uint8_t *)pEaOp->fpGEAList;
2040 rc = KernCopyOut(poffError, &cbDstList, sizeof(pEaOp->oError));
2041 if (rc == NO_ERROR)
2042 rc = ERROR_INVALID_EA_NAME;
2043 Log(("vboxSfOs2MakeEmptyEaList: ERROR_INVALID_EA_NAME\n"));
2044 break;
2045 }
2046
2047 /* Skip input. */
2048 cbGetEasLeft -= cbName + 1;
2049 pbSrc += cbName + 1;
2050
2051 /*
2052 * Construct and emit output.
2053 * Note! We should technically skip duplicates here, but who cares...
2054 */
2055 if (cbName > 0)
2056 {
2057 FEA Result;
2058 if (sizeof(Result) + cbName + 1 > cbFullEasLeft)
2059 {
2060 Log(("vboxSfOs2MakeEmptyEaList: ERROR_BUFFER_OVERFLOW (%#x vs %#x)\n", sizeof(Result) + cbName + 1, cbFullEasLeft));
2061 rc = ERROR_BUFFER_OVERFLOW;
2062 break;
2063 }
2064 cbFullEasLeft -= sizeof(Result) + cbName + 1;
2065
2066 Result.fEA = 0;
2067 Result.cbName = cbName;
2068 Result.cbValue = 0;
2069 rc = KernCopyOut(pbDst, &Result, sizeof(Result));
2070 if (rc != NO_ERROR)
2071 break;
2072 pbDst += sizeof(Result);
2073
2074 rc = KernCopyOut(pbDst, pszNameBuf, cbName + 1);
2075 if (rc != NO_ERROR)
2076 break;
2077 pbDst += cbName + 1;
2078 }
2079 } /* (while more GEAs) */
2080
2081 /* End of no-return zone. */
2082 RTMemFree(pszNameBuf);
2083
2084 cbDstList = (uintptr_t)pbDst - (uintptr_t)pEaOp->fpFEAList;
2085 }
2086 else
2087 {
2088 if (rc == NO_ERROR)
2089 rc = ERROR_BUFFER_OVERFLOW;
2090 cbDstList = 0; /* oh, shut up. */
2091 }
2092
2093 }
2094
2095 /* Set the list length. */
2096 if (rc == NO_ERROR)
2097 rc = KernCopyOut(&pEaOp->fpFEAList->cbList, &cbDstList, sizeof(pEaOp->fpFEAList->cbList));
2098
2099 if (pcbWritten)
2100 *pcbWritten = cbDstList;
2101
2102 Log(("vboxSfOs2MakeEmptyEaList: return %u (cbDstList=%#x)\n", rc, cbDstList));
2103 return rc;
2104}
2105
2106
2107
2108/**
2109 * Creates an empty full EA list given a GEALIST and info level.
2110 *
2111 * @returns OS/2 status code.
2112 * @param pEaOp The EA request. User buffer.
2113 * @param uLevel The info level being queried.
2114 */
2115DECL_NO_INLINE(RT_NOTHING, APIRET)
2116vboxSfOs2MakeEmptyEaList(PEAOP pEaOp, ULONG uLevel)
2117{
2118 /*
2119 * Copy the user request into memory, do pointer conversion, and
2120 * join extended function version.
2121 */
2122 EAOP EaOp = { NULL, NULL, 0 };
2123 APIRET rc = KernCopyIn(&EaOp, pEaOp, sizeof(EaOp));
2124 if (rc == NO_ERROR)
2125 {
2126 Log2(("vboxSfOs2MakeEmptyEaList: #0: %p %p %#x\n", EaOp.fpGEAList, EaOp.fpFEAList, EaOp.oError));
2127 EaOp.fpFEAList = (PFEALIST)KernSelToFlat((uintptr_t)EaOp.fpFEAList);
2128 EaOp.fpGEAList = (PGEALIST)KernSelToFlat((uintptr_t)EaOp.fpGEAList);
2129 Log2(("vboxSfOs2MakeEmptyEaList: #0b: %p %p\n", EaOp.fpGEAList, EaOp.fpFEAList));
2130
2131 rc = vboxSfOs2MakeEmptyEaListEx(&EaOp, uLevel, NULL, &pEaOp->oError);
2132 }
2133 return rc;
2134}
2135
2136
2137/**
2138 * Corrects the case of the given path.
2139 *
2140 * @returns OS/2 status code
2141 * @param pFolder The folder.
2142 * @param pReq Open/create request buffer with folder path.
2143 * @param pszPath The original path for figuring the drive letter or
2144 * UNC part of the path.
2145 * @param pbData Where to return the data (user address).
2146 * @param cbData The maximum amount of data we can return.
2147 */
2148static APIRET vboxSfOs2QueryCorrectCase(PVBOXSFFOLDER pFolder, VBOXSFCREATEREQ *pReq, const char *pszPath,
2149 PBYTE pbData, ULONG cbData)
2150{
2151 RT_NOREF(pFolder, pReq);
2152 APIRET rc;
2153 size_t cchPath = RTStrNLen(pszPath, CCHMAXPATH + 1);
2154 if (cchPath <= CCHMAXPATH)
2155 {
2156 if (cbData > cchPath)
2157 {
2158 /** @todo implement this properly on the host side! */
2159 rc = KernCopyOut(pbData, pszPath, cbData + 1);
2160 LogFlow(("vboxSfOs2QueryCorrectCase: returns %u\n", rc));
2161 }
2162 else
2163 {
2164 LogFlow(("vboxSfOs2QueryCorrectCase: returns %u (ERROR_INSUFFICIENT_BUFFER) - cchPath=%#x cbData=%#x\n",
2165 ERROR_INSUFFICIENT_BUFFER, cchPath, cbData));
2166 rc = ERROR_INSUFFICIENT_BUFFER;
2167 }
2168 }
2169 else
2170 {
2171 LogFlow(("vboxSfOs2QueryCorrectCase: returns %u (ERROR_FILENAME_EXCED_RANGE)\n", ERROR_FILENAME_EXCED_RANGE));
2172 rc = ERROR_FILENAME_EXCED_RANGE;
2173 }
2174 return rc;
2175}
2176
2177
2178/**
2179 * Copy out file status info.
2180 *
2181 * @returns OS/2 status code.
2182 * @param pbDst User address to put the status info at.
2183 * @param cbDst The size of the structure to produce.
2184 * @param uLevel The info level of the structure to produce.
2185 * @param pSrc The shared folder FS object info source structure.
2186 * @note Careful with stack, thus no-inlining.
2187 */
2188DECL_NO_INLINE(RT_NOTHING, APIRET)
2189vboxSfOs2FileStatusFromObjInfo(PBYTE pbDst, ULONG cbDst, ULONG uLevel, SHFLFSOBJINFO const *pSrc)
2190{
2191 union
2192 {
2193 FILESTATUS Fst;
2194 FILESTATUS2 Fst2;
2195 FILESTATUS3L Fst3L;
2196 FILESTATUS4L Fst4L;
2197 } uTmp;
2198
2199 int16_t cMinLocalTimeDelta = vboxSfOs2GetLocalTimeDelta();
2200 vboxSfOs2DateTimeFromTimeSpec(&uTmp.Fst.fdateCreation, &uTmp.Fst.ftimeCreation, pSrc->BirthTime, cMinLocalTimeDelta);
2201 vboxSfOs2DateTimeFromTimeSpec(&uTmp.Fst.fdateLastAccess, &uTmp.Fst.ftimeLastAccess, pSrc->AccessTime, cMinLocalTimeDelta);
2202 vboxSfOs2DateTimeFromTimeSpec(&uTmp.Fst.fdateLastWrite, &uTmp.Fst.ftimeLastWrite, pSrc->ModificationTime, cMinLocalTimeDelta);
2203 if (uLevel < FI_LVL_STANDARD_64)
2204 {
2205 uTmp.Fst.cbFile = (uint32_t)RT_MIN(pSrc->cbObject, UINT32_MAX);
2206 uTmp.Fst.cbFileAlloc = (uint32_t)RT_MIN(pSrc->cbAllocated, UINT32_MAX);
2207 uTmp.Fst.attrFile = (uint16_t)((pSrc->Attr.fMode & RTFS_DOS_MASK_OS2) >> RTFS_DOS_SHIFT);
2208 if (uLevel == FI_LVL_STANDARD_EASIZE)
2209 uTmp.Fst2.cbList = 0;
2210 }
2211 else
2212 {
2213 uTmp.Fst3L.cbFile = pSrc->cbObject;
2214 uTmp.Fst3L.cbFileAlloc = pSrc->cbAllocated;
2215 uTmp.Fst3L.attrFile = (pSrc->Attr.fMode & RTFS_DOS_MASK_OS2) >> RTFS_DOS_SHIFT;
2216 uTmp.Fst4L.cbList = 0;
2217 }
2218
2219 return KernCopyOut(pbDst, &uTmp, cbDst);
2220}
2221
2222
2223
2224/**
2225 * Worker for FS32_PATHINFO that handles file stat queries.
2226 *
2227 * @returns OS/2 status code
2228 * @param pFolder The folder.
2229 * @param pReq Open/create request buffer with folder path.
2230 * @param uLevel The information level.
2231 * @param pbData Where to return the data (user address).
2232 * @param cbData The amount of data to produce.
2233 */
2234static APIRET vboxSfOs2QueryPathInfo(PVBOXSFFOLDER pFolder, VBOXSFCREATEREQ *pReq, ULONG uLevel, PBYTE pbData, ULONG cbData)
2235{
2236 APIRET rc;
2237 pReq->CreateParms.CreateFlags = SHFL_CF_LOOKUP;
2238
2239 int vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
2240 LogFlow(("FS32_PATHINFO: VbglR0SfHostReqCreate -> %Rrc Result=%d fMode=%#x\n",
2241 vrc, pReq->CreateParms.Result, pReq->CreateParms.Info.Attr.fMode));
2242 if (RT_SUCCESS(vrc))
2243 {
2244 switch (pReq->CreateParms.Result)
2245 {
2246 case SHFL_FILE_EXISTS:
2247 switch (uLevel)
2248 {
2249 /*
2250 * Produce the desired file stat data.
2251 */
2252 case FI_LVL_STANDARD:
2253 case FI_LVL_STANDARD_EASIZE:
2254 case FI_LVL_STANDARD_64:
2255 case FI_LVL_STANDARD_EASIZE_64:
2256 rc = vboxSfOs2FileStatusFromObjInfo(pbData, cbData, uLevel, &pReq->CreateParms.Info);
2257 break;
2258
2259 /*
2260 * We don't do EAs and we "just" need to return no-EAs.
2261 * However, that's not as easy as you might think.
2262 */
2263 case FI_LVL_EAS_FROM_LIST:
2264 case FI_LVL_EAS_FULL:
2265 case FI_LVL_EAS_FULL_5:
2266 case FI_LVL_EAS_FULL_8:
2267 rc = vboxSfOs2MakeEmptyEaList((PEAOP)pbData, uLevel);
2268 break;
2269
2270 default:
2271 AssertFailed();
2272 rc = ERROR_GEN_FAILURE;
2273 break;
2274 }
2275 break;
2276
2277 case SHFL_PATH_NOT_FOUND:
2278 rc = ERROR_PATH_NOT_FOUND;
2279 break;
2280
2281 default:
2282 case SHFL_FILE_NOT_FOUND:
2283 rc = ERROR_FILE_NOT_FOUND;
2284 break;
2285 }
2286 }
2287 else
2288 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_FILE_NOT_FOUND);
2289 return rc;
2290}
2291
2292
2293DECLASM(APIRET)
2294FS32_PATHINFO(USHORT fFlags, PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszPath, LONG offCurDirEnd,
2295 ULONG uLevel, PBYTE pbData, ULONG cbData)
2296{
2297 LogFlow(("FS32_PATHINFO: fFlags=%#x pCdFsi=%p:{%#x,%s} pCdFsd=%p pszPath=%p:{%s} offCurDirEnd=%d uLevel=%u pbData=%p cbData=%#x\n",
2298 fFlags, pCdFsi, pCdFsi->cdi_hVPB, pCdFsi->cdi_curdir, pCdFsd, pszPath, pszPath, offCurDirEnd, uLevel, pbData, cbData));
2299
2300 /*
2301 * Check the level.
2302 *
2303 * Note! You would think this is FIL_STANDARD, FIL_QUERYEASIZE,
2304 * FIL_QUERYEASFROMLISTL and such. However, there are several levels
2305 * (4/14, 6/16, 7/17, 8/18) that are not defined in os2.h and then
2306 * there and FIL_QUERYFULLNAME that is used very between the kernel
2307 * and the FSD so the kernel can implement DosEnumAttributes.
2308 *
2309 * Note! DOSCALL1.DLL has code for converting FILESTATUS to FILESTATUS3
2310 * and FILESTATUS2 to FILESTATUS4 as needed. We don't need to do this.
2311 * It also has weird code for doubling the FILESTATUS2.cbList value
2312 * for no apparent reason.
2313 */
2314 ULONG cbMinData;
2315 switch (uLevel)
2316 {
2317 case FI_LVL_STANDARD:
2318 cbMinData = sizeof(FILESTATUS);
2319 AssertCompileSize(FILESTATUS, 0x16);
2320 break;
2321 case FI_LVL_STANDARD_64:
2322 cbMinData = sizeof(FILESTATUS3L);
2323 AssertCompileSize(FILESTATUS3L, 0x20); /* cbFile and cbFileAlloc are misaligned. */
2324 break;
2325 case FI_LVL_STANDARD_EASIZE:
2326 cbMinData = sizeof(FILESTATUS2);
2327 AssertCompileSize(FILESTATUS2, 0x1a);
2328 break;
2329 case FI_LVL_STANDARD_EASIZE_64:
2330 cbMinData = sizeof(FILESTATUS4L);
2331 AssertCompileSize(FILESTATUS4L, 0x24); /* cbFile and cbFileAlloc are misaligned. */
2332 break;
2333 case FI_LVL_EAS_FROM_LIST:
2334 case FI_LVL_EAS_FULL:
2335 case FI_LVL_EAS_FULL_5:
2336 case FI_LVL_EAS_FULL_8:
2337 cbMinData = sizeof(EAOP);
2338 break;
2339 case FI_LVL_VERIFY_PATH:
2340 case FI_LVL_CASE_CORRECT_PATH:
2341 cbMinData = 1;
2342 break;
2343 default:
2344 LogRel(("FS32_PATHINFO: Unsupported info level %u!\n", uLevel));
2345 return ERROR_INVALID_LEVEL;
2346 }
2347 if (cbData < cbMinData || pbData == NULL)
2348 {
2349 Log(("FS32_PATHINFO: ERROR_BUFFER_OVERFLOW (cbMinData=%#x, cbData=%#x, pszPath=%s)\n", cbMinData, cbData, pszPath));
2350 return ERROR_BUFFER_OVERFLOW;
2351 }
2352
2353 /*
2354 * Resolve the path to a folder and folder path.
2355 */
2356 PVBOXSFFOLDER pFolder;
2357 VBOXSFCREATEREQ *pReq;
2358 int rc = vboxSfOs2ResolvePathEx(pszPath, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath),
2359 &pFolder, (void **)&pReq);
2360 if (rc == NO_ERROR)
2361 {
2362 /*
2363 * Query information.
2364 */
2365 if (fFlags == PI_RETRIEVE)
2366 {
2367 if ( uLevel != FI_LVL_VERIFY_PATH
2368 && uLevel != FI_LVL_CASE_CORRECT_PATH)
2369 rc = vboxSfOs2QueryPathInfo(pFolder, pReq, uLevel, pbData, cbMinData);
2370 else if (uLevel == FI_LVL_VERIFY_PATH)
2371 rc = NO_ERROR; /* vboxSfOs2ResolvePath should've taken care of this already */
2372 else
2373 rc = vboxSfOs2QueryCorrectCase(pFolder, pReq, pszPath, pbData, cbData);
2374 }
2375 /*
2376 * Update information.
2377 */
2378 else if ( fFlags == PI_SET
2379 || fFlags == (PI_SET | PI_WRITE_THRU))
2380 {
2381 if ( uLevel == FI_LVL_STANDARD
2382 || uLevel == FI_LVL_STANDARD_64)
2383 {
2384 /* Read in the data and join paths with FS32_FILEATTRIBUTE: */
2385 PFILESTATUS pDataCopy = (PFILESTATUS)VbglR0PhysHeapAlloc(cbMinData);
2386 if (pDataCopy)
2387 {
2388 rc = KernCopyIn(pDataCopy, pbData, cbMinData);
2389 if (rc == NO_ERROR)
2390 rc = vboxSfOs2SetPathInfoWorker(pFolder, pReq,
2391 uLevel == FI_LVL_STANDARD
2392 ? (ULONG)pDataCopy->attrFile
2393 : ((PFILESTATUS3L)pDataCopy)->attrFile,
2394 (PFILESTATUS)pDataCopy);
2395 VbglR0PhysHeapFree(pDataCopy);
2396 }
2397 else
2398 rc = ERROR_NOT_ENOUGH_MEMORY;
2399 }
2400 else if (uLevel == FI_LVL_STANDARD_EASIZE)
2401 rc = ERROR_EAS_NOT_SUPPORTED;
2402 else
2403 rc = ERROR_INVALID_LEVEL;
2404 }
2405 else
2406 {
2407 LogRel(("FS32_PATHINFO: Unknown flags value: %#x (path: %s)\n", fFlags, pszPath));
2408 rc = ERROR_INVALID_PARAMETER;
2409 }
2410 VbglR0PhysHeapFree(pReq);
2411 vboxSfOs2ReleaseFolder(pFolder);
2412 }
2413 RT_NOREF_PV(pCdFsi);
2414 return rc;
2415}
2416
2417
2418DECLASM(APIRET)
2419FS32_MOUNT(USHORT fFlags, PVPFSI pvpfsi, PVBOXSFVP pVpFsd, USHORT hVPB, PCSZ pszBoot)
2420{
2421 NOREF(fFlags); NOREF(pvpfsi); NOREF(pVpFsd); NOREF(hVPB); NOREF(pszBoot);
2422 return ERROR_NOT_SUPPORTED;
2423}
2424
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use