VirtualBox

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

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

err.h build fixes. bugref:9344

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