VirtualBox

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

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

os2/VBoxSF: FS32_OPENCREATE should fail on directories. Corrected attribute filtering calculations in FS32_FINDFIRST (caused COPY *.* to see directories, causing previous issue). FS32_FINDFROMNAME & FS32_FINDNEXT should not fail if FI_LVL_EAS_FROM_LIST[_64] are requested, we can handle it (FS32_FINDFIRST lets them thru) and WPS needs it for browsing shared folders.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 66.4 KB
Line 
1/** $Id: VBoxSFFile.cpp 79710 2019-07-12 05:10:42Z vboxsync $ */
2/** @file
3 * VBoxSF - OS/2 Shared Folders, the file level IFS EPs.
4 */
5
6/*
7 * Copyright (c) 2007-2018 knut st. osmundsen <bird-src-spam@anduin.net>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#define LOG_GROUP LOG_GROUP_DEFAULT
36#include "VBoxSFInternal.h"
37
38#include <VBox/log.h>
39#include <iprt/asm.h>
40#include <iprt/assert.h>
41#include <iprt/err.h>
42#include <iprt/mem.h>
43
44
45/*********************************************************************************************************************************
46* Structures and Typedefs *
47*********************************************************************************************************************************/
48/** A preallocated buffer. */
49typedef struct
50{
51 RTCCPHYS PhysAddr;
52 void *pvBuf;
53 bool volatile fBusy;
54} VBOXSFOS2BUF;
55
56
57/*********************************************************************************************************************************
58* Global Variables *
59*********************************************************************************************************************************/
60/** Buffer spinlock. */
61static SpinLock_t g_BufferLock;
62/** 64KB buffers. */
63static VBOXSFOS2BUF g_aBigBuffers[4];
64
65
66
67/**
68 * Initialize file buffers.
69 */
70void vboxSfOs2InitFileBuffers(void)
71{
72 KernAllocSpinLock(&g_BufferLock);
73
74 for (uint32_t i = 0; i < RT_ELEMENTS(g_aBigBuffers); i++)
75 {
76 g_aBigBuffers[i].pvBuf = RTMemContAlloc(&g_aBigBuffers[i].PhysAddr, _64K);
77 g_aBigBuffers[i].fBusy = g_aBigBuffers[i].pvBuf == NULL;
78 }
79}
80
81
82/**
83 * Allocates a big buffer.
84 * @returns Pointer to buffer on success, NULL on failure.
85 * @param pPhysAddr The physical address of the buffer.
86 */
87DECLINLINE(void *) vboxSfOs2AllocBigBuffer(RTGCPHYS *pPhysAddr)
88{
89 KernAcquireSpinLock(&g_BufferLock);
90 for (uint32_t i = 0; i < RT_ELEMENTS(g_aBigBuffers); i++)
91 if (!g_aBigBuffers[i].fBusy)
92 {
93 g_aBigBuffers[i].fBusy = true;
94 KernReleaseSpinLock(&g_BufferLock);
95
96 *pPhysAddr = g_aBigBuffers[i].PhysAddr;
97 return g_aBigBuffers[i].pvBuf;
98 }
99 KernReleaseSpinLock(&g_BufferLock);
100 *pPhysAddr = NIL_RTGCPHYS;
101 return NULL;
102}
103
104
105/**
106 * Frees a big buffer.
107 * @param pvBuf The address of the buffer to be freed.
108 */
109DECLINLINE(void) vboxSfOs2FreeBigBuffer(void *pvBuf)
110{
111 Assert(pvBuf);
112 KernAcquireSpinLock(&g_BufferLock);
113 for (uint32_t i = 0; i < RT_ELEMENTS(g_aBigBuffers); i++)
114 if (g_aBigBuffers[i].pvBuf == pvBuf)
115 {
116 Assert(g_aBigBuffers[i].fBusy);
117 g_aBigBuffers[i].fBusy = false;
118 KernReleaseSpinLock(&g_BufferLock);
119 return;
120 }
121 KernReleaseSpinLock(&g_BufferLock);
122 AssertFailed();
123}
124
125
126/**
127 * Checks a EA buffer intended for file or directory creation.
128 *
129 * @retval NO_ERROR if empty list.
130 * @retval ERROR_EAS_NOT_SUPPORTED not empty.
131 * @retval ERROR_PROTECTION_VIOLATION if the address is invalid.
132 *
133 * @param pEaOp The EA buffer to check out.
134 */
135DECL_NO_INLINE(RT_NOTHING, APIRET) vboxSfOs2CheckEaOpForCreation(EAOP const *pEaOp)
136{
137 EAOP EaOp = { NULL, NULL, 0 };
138 APIRET rc = KernCopyIn(&EaOp, pEaOp, sizeof(EaOp));
139 Log(("vboxSfOs2CheckEasForCreation: %p: rc=%u %#x %#x %#x\n", pEaOp, rc, EaOp.fpFEAList, EaOp.fpGEAList, EaOp.oError));
140 if (rc == NO_ERROR)
141 {
142 EaOp.fpFEAList = (PFEALIST)KernSelToFlat((uintptr_t)EaOp.fpFEAList);
143 if (EaOp.fpFEAList)
144 {
145 FEALIST FeaList = { 0, {0, 0, 0} };
146 rc = KernCopyIn(&FeaList, EaOp.fpFEAList, sizeof(FeaList));
147 Log(("vboxSfOs2CheckEasForCreation: FeaList %p: rc=%u: %#x {%#x %#x %#x}\n",
148 EaOp.fpFEAList, rc, FeaList.cbList, FeaList.list[0].cbName, FeaList.list[0].cbValue, FeaList.list[0].fEA));
149 if (rc != NO_ERROR)
150 {
151 rc = KernCopyIn(&FeaList, EaOp.fpFEAList, sizeof(FeaList.cbList));
152 Log(("vboxSfOs2CheckEasForCreation: FeaList %p: rc=%u: %#x\n", EaOp.fpFEAList, rc, FeaList.cbList));
153 }
154 if (rc == NO_ERROR && FeaList.cbList > sizeof(FeaList.cbList))
155 rc = ERROR_EAS_NOT_SUPPORTED;
156 }
157 }
158 return rc;
159}
160
161
162DECLASM(APIRET)
163FS32_OPENCREATE(PCDFSI pCdFsi, PVBOXSFCD pCdFsd, PCSZ pszName, LONG offCurDirEnd,
164 PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, ULONG fOpenMode, USHORT fOpenFlags,
165 PUSHORT puAction, ULONG fAttribs, EAOP const *pEaOp, PUSHORT pfGenFlag)
166{
167 LogFlow(("FS32_OPENCREATE: pCdFsi=%p pCdFsd=%p pszName=%p:{%s} offCurDirEnd=%d pSfFsi=%p pSfFsd=%p fOpenMode=%#x fOpenFlags=%#x puAction=%p fAttribs=%#x pEaOp=%p pfGenFlag=%p\n",
168 pCdFsi, pCdFsd, pszName, pszName, offCurDirEnd, pSfFsi, pSfFsd, fOpenMode, fOpenFlags, puAction, fAttribs, pEaOp, pfGenFlag));
169 RT_NOREF(pfGenFlag, pCdFsi);
170
171 /*
172 * Validate and convert parameters.
173 */
174 /* No EAs. We may need to put in some effort to determin the absense of EAs,
175 because CMD.exe likes to supply them when opening the source file of a
176 copy operation. */
177 if (!pEaOp)
178 { /* likely */ }
179 else
180 {
181 switch (fOpenFlags & 0x13)
182 {
183 case OPEN_ACTION_FAIL_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW: /* 0x00 */
184 case OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW: /* 0x01 */
185 LogFlow(("FS32_OPENCREATE: Ignoring EAOP for non-create/replace action (%u).\n",
186 vboxSfOs2CheckEaOpForCreation(pEaOp)));
187 break;
188
189 case OPEN_ACTION_FAIL_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW: /* 0x10 */
190 case OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW: /* 0x11 */ /** @todo */
191 case OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW: /* 0x02 */
192 case OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW: /* 0x12 */
193 {
194 APIRET rc = vboxSfOs2CheckEaOpForCreation(pEaOp);
195 if (rc == NO_ERROR)
196 {
197 Log(("FS32_OPENCREATE: Ignoring empty EAOP.\n"));
198 break;
199 }
200 Log(("FS32_OPENCREATE: Returns %u%s [%p];\n",
201 rc, rc == ERROR_EAS_NOT_SUPPORTED ? " (ERROR_EAS_NOT_SUPPORTED)" : "", pEaOp));
202 return rc;
203 }
204
205 default:
206 LogRel(("FS32_OPENCREATE: Invalid file open flags: %#x\n", fOpenFlags));
207 return VERR_INVALID_PARAMETER;
208 }
209 }
210
211 /* No direct access. */
212 if (!(fOpenMode & OPEN_FLAGS_DASD))
213 { /* likely */ }
214 else
215 {
216 LogRel(("FS32_OPENCREATE: Returns ERROR_ACCESS_DENIED [DASD];\n"));
217 return ERROR_ACCESS_DENIED;
218 }
219
220 /*
221 * Allocate request buffer and resovle the path to folder and folder relative path.
222 */
223 PVBOXSFFOLDER pFolder;
224 VBOXSFCREATEREQ *pReq;
225 APIRET rc = vboxSfOs2ResolvePathEx(pszName, pCdFsd, offCurDirEnd, RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath),
226 &pFolder, (void **)&pReq);
227 LogFlow(("FS32_OPENCREATE: vboxSfOs2ResolvePath: -> %u pFolder=%p\n", rc, pFolder));
228 if (rc == NO_ERROR)
229 { /* likely */ }
230 else
231 return rc;
232
233 /*
234 * Continue validating and converting parameters.
235 */
236 /* access: */
237 if (fOpenMode & OPEN_ACCESS_READWRITE)
238 pReq->CreateParms.CreateFlags = SHFL_CF_ACCESS_READWRITE | SHFL_CF_ACCESS_ATTR_READWRITE;
239 else if (fOpenMode & OPEN_ACCESS_WRITEONLY)
240 pReq->CreateParms.CreateFlags = SHFL_CF_ACCESS_WRITE | SHFL_CF_ACCESS_ATTR_WRITE;
241 else
242 pReq->CreateParms.CreateFlags = SHFL_CF_ACCESS_READ | SHFL_CF_ACCESS_ATTR_READ; /* read or/and exec */
243
244 /* Sharing: */
245 switch (fOpenMode & (OPEN_SHARE_DENYNONE | OPEN_SHARE_DENYREADWRITE | OPEN_SHARE_DENYREAD | OPEN_SHARE_DENYWRITE))
246 {
247 case OPEN_SHARE_DENYNONE: pReq->CreateParms.CreateFlags |= SHFL_CF_ACCESS_DENYNONE; break;
248 case OPEN_SHARE_DENYWRITE: pReq->CreateParms.CreateFlags |= SHFL_CF_ACCESS_DENYWRITE; break;
249 case OPEN_SHARE_DENYREAD: pReq->CreateParms.CreateFlags |= SHFL_CF_ACCESS_DENYREAD; break;
250 case OPEN_SHARE_DENYREADWRITE: pReq->CreateParms.CreateFlags |= SHFL_CF_ACCESS_DENYALL; break;
251 case 0: pReq->CreateParms.CreateFlags |= SHFL_CF_ACCESS_DENYWRITE; break; /* compatibility */
252 default:
253 LogRel(("FS32_OPENCREATE: Invalid file sharing mode: %#x\n", fOpenMode));
254 VbglR0PhysHeapFree(pReq);
255 return VERR_INVALID_PARAMETER;
256
257 }
258
259 /* How to open the file: */
260 switch (fOpenFlags & 0x13)
261 {
262 case OPEN_ACTION_FAIL_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW: /* 0x00 */
263 pReq->CreateParms.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW;
264 break;
265 case OPEN_ACTION_FAIL_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW: /* 0x10 */
266 pReq->CreateParms.CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
267 break;
268 case OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW: /* 0x01 */
269 pReq->CreateParms.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW;
270 break;
271 case OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW: /* 0x11 */
272 pReq->CreateParms.CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
273 break;
274 case OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW: /* 0x02 */
275 pReq->CreateParms.CreateFlags |= SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW;
276 break;
277 case OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW: /* 0x12 */
278 pReq->CreateParms.CreateFlags |= SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
279 break;
280 default:
281 LogRel(("FS32_OPENCREATE: Invalid file open flags: %#x\n", fOpenFlags));
282 VbglR0PhysHeapFree(pReq);
283 return VERR_INVALID_PARAMETER;
284 }
285
286 /* Misc: cache, etc? There seems to be no API for that. */
287
288 /* Attributes: */
289 pReq->CreateParms.Info.Attr.fMode = ((uint32_t)fAttribs << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_OS2;
290
291 /* Initial size: */
292 if (pSfFsi->sfi_sizel > 0)
293 pReq->CreateParms.Info.cbObject = pSfFsi->sfi_sizel;
294
295 /*
296 * Try open the file.
297 */
298 int vrc = VbglR0SfHostReqCreate(pFolder->idHostRoot, pReq);
299 LogFlow(("FS32_OPENCREATE: VbglR0SfHostReqCreate -> %Rrc Result=%d fMode=%#x\n",
300 vrc, pReq->CreateParms.Result, pReq->CreateParms.Info.Attr.fMode));
301 if (RT_SUCCESS(vrc))
302 {
303 switch (pReq->CreateParms.Result)
304 {
305 case SHFL_FILE_EXISTS:
306 if (pReq->CreateParms.Handle == SHFL_HANDLE_NIL)
307 {
308 rc = ERROR_OPEN_FAILED; //ERROR_FILE_EXISTS;
309 break;
310 }
311 if (RTFS_IS_DIRECTORY(pReq->CreateParms.Info.Attr.fMode))
312 {
313 LogFlow(("FS32_OPENCREATE: directory, closing and returning ERROR_ACCESS_DENIED!\n"));
314 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
315 VbglR0SfHostReqClose(pFolder->idHostRoot, (VBOXSFCLOSEREQ *)pReq, pReq->CreateParms.Handle);
316 rc = ERROR_ACCESS_DENIED;
317 break;
318 }
319 RT_FALL_THRU();
320 case SHFL_FILE_CREATED:
321 case SHFL_FILE_REPLACED:
322 if ( pReq->CreateParms.Info.cbObject < _2G
323 || (fOpenMode & OPEN_FLAGS_LARGEFILE))
324 {
325 pSfFsd->u32Magic = VBOXSFSYFI_MAGIC;
326 pSfFsd->pSelf = pSfFsd;
327 pSfFsd->hHostFile = pReq->CreateParms.Handle;
328 pSfFsd->pFolder = pFolder;
329
330 uint32_t cOpenFiles = ASMAtomicIncU32(&pFolder->cOpenFiles);
331 Assert(cOpenFiles < _32K);
332 pFolder = NULL; /* Reference now taken by pSfFsd->pFolder. */
333
334 pSfFsi->sfi_sizel = pReq->CreateParms.Info.cbObject;
335 pSfFsi->sfi_type = STYPE_FILE;
336 pSfFsi->sfi_DOSattr = (uint8_t)((pReq->CreateParms.Info.Attr.fMode & RTFS_DOS_MASK_OS2) >> RTFS_DOS_SHIFT);
337 int16_t cMinLocalTimeDelta = vboxSfOs2GetLocalTimeDelta();
338 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_cdate, &pSfFsi->sfi_ctime, pReq->CreateParms.Info.BirthTime, cMinLocalTimeDelta);
339 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_adate, &pSfFsi->sfi_atime, pReq->CreateParms.Info.AccessTime, cMinLocalTimeDelta);
340 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_mdate, &pSfFsi->sfi_mtime, pReq->CreateParms.Info.ModificationTime, cMinLocalTimeDelta);
341 if (pReq->CreateParms.Result == SHFL_FILE_CREATED)
342 pSfFsi->sfi_tstamp |= ST_PCREAT | ST_SCREAT | ST_PWRITE | ST_SWRITE | ST_PREAD | ST_SREAD;
343
344 *puAction = pReq->CreateParms.Result == SHFL_FILE_CREATED ? FILE_CREATED
345 : pReq->CreateParms.Result == SHFL_FILE_EXISTS ? FILE_EXISTED
346 : FILE_TRUNCATED;
347
348 Log(("FS32_OPENCREATE: hHandle=%#RX64 for '%s'\n", pSfFsd->hHostFile, pszName));
349 rc = NO_ERROR;
350 }
351 else
352 {
353 LogRel(("FS32_OPENCREATE: cbObject=%#RX64 no OPEN_FLAGS_LARGEFILE (%s)\n", pReq->CreateParms.Info.cbObject, pszName));
354 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
355 VbglR0SfHostReqClose(pFolder->idHostRoot, (VBOXSFCLOSEREQ *)pReq, pReq->CreateParms.Handle);
356 rc = ERROR_ACCESS_DENIED;
357 }
358 break;
359
360 case SHFL_PATH_NOT_FOUND:
361 rc = ERROR_PATH_NOT_FOUND;
362 break;
363
364 default:
365 case SHFL_FILE_NOT_FOUND:
366 rc = ERROR_OPEN_FAILED;
367 break;
368 }
369 }
370 else if (vrc == VERR_ALREADY_EXISTS)
371 rc = ERROR_ACCESS_DENIED;
372 else if (vrc == VERR_FILE_NOT_FOUND)
373 rc = ERROR_OPEN_FAILED;
374 else
375 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_PATH_NOT_FOUND);
376 VbglR0PhysHeapFree(pReq);
377 vboxSfOs2ReleaseFolder(pFolder);
378 LogFlow(("FS32_OPENCREATE: returns %u\n", rc));
379 return rc;
380}
381
382
383DECLASM(APIRET)
384FS32_CLOSE(ULONG uType, ULONG fIoFlags, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd)
385{
386 LogFlow(("FS32_CLOSE: uType=%#x fIoFlags=%#x pSfFsi=%p pSfFsd=%p:{%#x, %#llx}\n",
387 uType, fIoFlags, pSfFsi, pSfFsd, pSfFsd->u32Magic, pSfFsd->hHostFile));
388
389 /*
390 * Validate input.
391 */
392 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
393 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
394 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
395 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
396 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
397 Assert(pFolder->cOpenFiles > 0);
398
399 /*
400 * We only care for when the system is done truly with the file
401 * and we can close it.
402 */
403 if (uType != FS_CL_FORSYS)
404 return NO_ERROR;
405
406 /** @todo flush file if fIoFlags says so? */
407 RT_NOREF(fIoFlags);
408
409 int vrc = VbglR0SfHostReqCloseSimple(pFolder->idHostRoot, pSfFsd->hHostFile);
410 AssertRC(vrc);
411
412 pSfFsd->hHostFile = SHFL_HANDLE_NIL;
413 pSfFsd->pSelf = NULL;
414 pSfFsd->u32Magic = ~VBOXSFSYFI_MAGIC;
415 pSfFsd->pFolder = NULL;
416
417 ASMAtomicDecU32(&pFolder->cOpenFiles);
418 vboxSfOs2ReleaseFolder(pFolder);
419
420 RT_NOREF(pSfFsi);
421 LogFlow(("FS32_CLOSE: returns NO_ERROR\n"));
422 return NO_ERROR;
423}
424
425
426DECLASM(APIRET)
427FS32_COMMIT(ULONG uType, ULONG fIoFlags, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd)
428{
429 LogFlow(("FS32_COMMIT: uType=%#x fIoFlags=%#x pSfFsi=%p pSfFsd=%p:{%#x}\n", uType, fIoFlags, pSfFsi, pSfFsd, pSfFsd->u32Magic));
430
431 /*
432 * Validate input.
433 */
434 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
435 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
436 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
437 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
438 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
439 Assert(pFolder->cOpenFiles > 0);
440 RT_NOREF(pFolder);
441
442 /*
443 * We only need to flush writable files.
444 */
445 if ( (pSfFsi->sfi_mode & SFMODE_OPEN_ACCESS) == SFMODE_OPEN_WRITEONLY
446 || (pSfFsi->sfi_mode & SFMODE_OPEN_ACCESS) == SFMODE_OPEN_READWRITE)
447 {
448 int vrc = VbglR0SfHostReqFlushSimple(pFolder->idHostRoot, pSfFsd->hHostFile);
449 if (RT_FAILURE(vrc))
450 {
451 LogRel(("FS32_COMMIT: VbglR0SfHostReqFlushSimple failed: %Rrc\n", vrc));
452 return ERROR_FLUSHBUF_FAILED;
453 }
454 }
455
456 NOREF(uType); NOREF(fIoFlags); NOREF(pSfFsi);
457 LogFlow(("FS32_COMMIT: returns NO_ERROR\n"));
458 return NO_ERROR;
459}
460
461
462extern "C" APIRET APIENTRY
463FS32_CHGFILEPTRL(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, LONGLONG off, ULONG uMethod, ULONG fIoFlags)
464{
465 LogFlow(("FS32_CHGFILEPTRL: pSfFsi=%p pSfFsd=%p off=%RI64 (%#RX64) uMethod=%u fIoFlags=%#x\n",
466 pSfFsi, pSfFsd, off, off, uMethod, fIoFlags));
467
468 /*
469 * Validate input.
470 */
471 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
472 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
473 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
474 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
475 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
476 Assert(pFolder->cOpenFiles > 0);
477
478 /*
479 * Calc absolute offset.
480 */
481 int64_t offNew;
482 switch (uMethod)
483 {
484 case CFP_RELBEGIN:
485 if (off >= 0)
486 {
487 offNew = off;
488 break;
489 }
490 Log(("FS32_CHGFILEPTRL: Negative seek (BEGIN): %RI64\n", off));
491 return ERROR_NEGATIVE_SEEK;
492
493 case CFP_RELCUR:
494 offNew = pSfFsi->sfi_positionl + off;
495 if (offNew >= 0)
496 break;
497 Log(("FS32_CHGFILEPTRL: Negative seek (RELCUR): %RU64 + %RI64\n", pSfFsi->sfi_positionl, off));
498 return ERROR_NEGATIVE_SEEK;
499
500 case CFP_RELEND:
501 {
502 /* Have to consult the host to get the current file size. */
503 VBOXSFOBJINFOREQ *pReq = (VBOXSFOBJINFOREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
504 if (pReq)
505 RT_ZERO(*pReq);
506 else
507 return ERROR_NOT_ENOUGH_MEMORY;
508
509 int vrc = VbglR0SfHostReqQueryObjInfo(pFolder->idHostRoot, pReq, pSfFsd->hHostFile);
510 if (RT_SUCCESS(vrc))
511 {
512 if (pSfFsi->sfi_mode & SFMODE_LARGE_FILE)
513 pSfFsi->sfi_sizel = pReq->ObjInfo.cbObject;
514 else
515 pSfFsi->sfi_sizel = RT_MIN(pReq->ObjInfo.cbObject, _2G - 1);
516 }
517 else
518 LogRel(("FS32_CHGFILEPTRL/CFP_RELEND: VbglR0SfFsInfo failed: %Rrc\n", vrc));
519
520 VbglR0PhysHeapFree(pReq);
521
522 offNew = pSfFsi->sfi_sizel + off;
523 if (offNew >= 0)
524 break;
525 Log(("FS32_CHGFILEPTRL: Negative seek (CFP_RELEND): %RI64 + %RI64\n", pSfFsi->sfi_sizel, off));
526 return ERROR_NEGATIVE_SEEK;
527 }
528
529
530 default:
531 LogRel(("FS32_CHGFILEPTRL: Unknown seek method: %#x\n", uMethod));
532 return ERROR_INVALID_FUNCTION;
533 }
534
535 /*
536 * Commit the seek.
537 */
538 pSfFsi->sfi_positionl = offNew;
539 LogFlow(("FS32_CHGFILEPTRL: returns; sfi_positionl=%RI64\n", offNew));
540 RT_NOREF_PV(fIoFlags);
541 return NO_ERROR;
542}
543
544
545/** Forwards the call to FS32_CHGFILEPTRL. */
546DECLASM(APIRET)
547FS32_CHGFILEPTR(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, LONG off, ULONG uMethod, ULONG fIoFlags)
548{
549 return FS32_CHGFILEPTRL(pSfFsi, pSfFsd, off, uMethod, fIoFlags);
550}
551
552
553/**
554 * Worker for FS32_PATHINFO that handles file stat setting.
555 *
556 * @returns OS/2 status code
557 * @param pFolder The folder.
558 * @param pSfFsi The file system independent file structure. We'll
559 * update the timestamps and size here.
560 * @param pSfFsd Out file data.
561 * @param uLevel The information level.
562 * @param pbData The stat data to set.
563 * @param cbData The uLevel specific input size.
564 */
565static APIRET
566vboxSfOs2SetFileInfo(PVBOXSFFOLDER pFolder, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, ULONG uLevel, PBYTE pbData, ULONG cbData)
567{
568 APIRET rc;
569
570 /*
571 * Data buffer both for caching user data and for issuing the
572 * change request to the host.
573 */
574 struct SetFileInfoBuf
575 {
576 union
577 {
578 FILESTATUS Lvl1;
579 FILESTATUS3L Lvl1L;
580 };
581 SHFLFSOBJINFO ObjInfo;
582 } *pBuf = (struct SetFileInfoBuf *)VbglR0PhysHeapAlloc(sizeof(*pBuf));
583 if (pBuf)
584 {
585 /* Copy in the data. */
586 rc = KernCopyIn(&pBuf->Lvl1, pbData, cbData);
587 if (rc == NO_ERROR)
588 {
589 /*
590 * Join paths with FS32_PATHINFO and FS32_FILEATTRIBUTE.
591 */
592 rc = vboxSfOs2SetInfoCommonWorker(pFolder, pSfFsd->hHostFile,
593 uLevel == FI_LVL_STANDARD ? pBuf->Lvl1.attrFile : pBuf->Lvl1L.attrFile,
594 &pBuf->Lvl1, &pBuf->ObjInfo, RT_UOFFSETOF(struct SetFileInfoBuf, ObjInfo));
595 if (rc == NO_ERROR)
596 {
597 /*
598 * Update the timestamps in the independent file data with what
599 * the host returned:
600 */
601 pSfFsi->sfi_tstamp |= ST_PCREAT | ST_PWRITE | ST_PREAD;
602 pSfFsi->sfi_tstamp &= ~(ST_SCREAT | ST_SWRITE| ST_SREAD);
603 uint16_t cDelta = vboxSfOs2GetLocalTimeDelta();
604 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_cdate, &pSfFsi->sfi_ctime, pBuf->ObjInfo.BirthTime, cDelta);
605 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_adate, &pSfFsi->sfi_atime, pBuf->ObjInfo.AccessTime, cDelta);
606 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_mdate, &pSfFsi->sfi_mtime, pBuf->ObjInfo.ModificationTime, cDelta);
607
608 /* And the size field as we're at it: */
609 pSfFsi->sfi_sizel = pBuf->ObjInfo.cbObject;
610 }
611 else
612 rc = ERROR_INVALID_PARAMETER;
613 }
614
615 VbglR0PhysHeapFree(pBuf);
616 }
617 else
618 rc = ERROR_NOT_ENOUGH_MEMORY;
619 return rc;
620}
621
622
623#if 0
624
625DECLVBGL(int) VbglR0SfFastPhysFsInfo(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile,
626 uint32_t flags, uint32_t *pcbBuffer, PSHFLDIRINFO pBuffer)
627{
628 struct FsInfoReq
629 {
630 VBGLIOCIDCHGCMFASTCALL Hdr;
631 VMMDevHGCMCall Call;
632 VBoxSFParmInformation Parms;
633 HGCMPageListInfo PgLst;
634 RTGCPHYS64 PageTwo;
635 } *pReq;
636 AssertCompileMemberOffset(struct FsInfoReq, Call, 52);
637 AssertCompileMemberOffset(struct FsInfoReq, Parms, 0x60);
638
639 pReq = (struct FsInfoReq *)VbglR0PhysHeapAlloc(sizeof(*pReq));
640 if (!pReq)
641 return VERR_NO_MEMORY;
642
643 VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, pClient->idClient,
644 SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, sizeof(*pReq));
645#if 0
646 VBGLREQHDR_INIT_EX(&pReq->Hdr.Hdr, sizeof(*pReq), sizeof(*pReq));
647 pReq->Hdr.GCPhysReq = VbglR0PhysHeapGetPhysAddr(pReq) + sizeof(pReq->Hdr);
648 pReq->Hdr.fInterruptible = false;
649
650 pReq->Call.header.header.size = sizeof(*pReq) - sizeof(pReq->Hdr);
651 pReq->Call.header.header.version = VBGLREQHDR_VERSION;
652 pReq->Call.header.header.requestType= VMMDevReq_HGCMCall32;
653 pReq->Call.header.header.rc = VERR_INTERNAL_ERROR;
654 pReq->Call.header.header.reserved1 = 0;
655 pReq->Call.header.header.fRequestor = VMMDEV_REQUESTOR_KERNEL | VMMDEV_REQUESTOR_USR_DRV_OTHER
656 | VMMDEV_REQUESTOR_CON_DONT_KNOW | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN;
657 pReq->Call.header.fu32Flags = 0;
658 pReq->Call.header.result = VERR_INTERNAL_ERROR;
659 pReq->Call.u32ClientID = pClient->idClient;
660 pReq->Call.u32Function = SHFL_FN_INFORMATION;
661 pReq->Call.cParms = SHFL_CPARMS_INFORMATION;
662#endif
663 uint32_t const cbBuffer = *pcbBuffer;
664 pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit;
665 pReq->Parms.id32Root.u.value32 = pMap->root;
666 pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit;
667 pReq->Parms.u64Handle.u.value64 = hFile;
668 pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit;
669 pReq->Parms.f32Flags.u.value32 = flags;
670 pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit;
671 pReq->Parms.cb32.u.value32 = cbBuffer;
672 pReq->Parms.pInfo.type = VMMDevHGCMParmType_PageList;
673 pReq->Parms.pInfo.u.PageList.size = cbBuffer;
674 pReq->Parms.pInfo.u.PageList.offset = RT_UOFFSETOF(struct FsInfoReq, PgLst) - RT_UOFFSETOF(struct FsInfoReq, Call);
675
676 Assert(cbBuffer < _1K);
677 pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
678 pReq->PgLst.cPages = cbBuffer <= (PAGE_SIZE - ((uintptr_t)pBuffer & PAGE_OFFSET_MASK)) ? 1 : 2;
679 pReq->PgLst.offFirstPage = (uint16_t)((uintptr_t)pBuffer & PAGE_OFFSET_MASK);
680 pReq->PgLst.aPages[0] = VbglR0PhysHeapGetPhysAddr(pBuffer) & ~(RTGCPHYS64)PAGE_OFFSET_MASK;
681 if (pReq->PgLst.cPages == 1)
682 pReq->PageTwo = NIL_RTGCPHYS64;
683 else
684 pReq->PageTwo = pReq->PgLst.aPages[0] + PAGE_SIZE;
685
686 int rc = VbglR0HGCMFastCall(pClient->handle, &pReq->Hdr, sizeof(*pReq));
687 if (RT_SUCCESS(rc))
688 {
689 rc = pReq->Call.header.result;
690 *pcbBuffer = pReq->Parms.cb32.u.value32;
691 }
692 VbglR0PhysHeapFree(pReq);
693 return rc;
694}
695
696
697DECLVBGL(int) VbglR0SfPhysFsInfo(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile,
698 uint32_t flags, uint32_t *pcbBuffer, PSHFLDIRINFO pBuffer)
699{
700 uint32_t const cbBuffer = *pcbBuffer;
701
702 struct
703 {
704 VBoxSFInformation Core;
705 HGCMPageListInfo PgLst;
706 RTGCPHYS64 PageTwo;
707 } Req;
708
709 VBGL_HGCM_HDR_INIT_EX(&Req.Core.callInfo, pClient->idClient, SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, sizeof(Req));
710 Req.Core.callInfo.fInterruptible = false;
711
712 Req.Core.root.type = VMMDevHGCMParmType_32bit;
713 Req.Core.root.u.value32 = pMap->root;
714
715 Req.Core.handle.type = VMMDevHGCMParmType_64bit;
716 Req.Core.handle.u.value64 = hFile;
717 Req.Core.flags.type = VMMDevHGCMParmType_32bit;
718 Req.Core.flags.u.value32 = flags;
719 Req.Core.cb.type = VMMDevHGCMParmType_32bit;
720 Req.Core.cb.u.value32 = cbBuffer;
721 Req.Core.info.type = VMMDevHGCMParmType_PageList;
722 Req.Core.info.u.PageList.size = cbBuffer;
723 Req.Core.info.u.PageList.offset = sizeof(Req.Core);
724
725 Assert(cbBuffer < _1K);
726 Req.PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
727 Req.PgLst.cPages = cbBuffer <= (PAGE_SIZE - ((uintptr_t)pBuffer & PAGE_OFFSET_MASK)) ? 1 : 2;
728 Req.PgLst.offFirstPage = (uint16_t)((uintptr_t)pBuffer & PAGE_OFFSET_MASK);
729 Req.PgLst.aPages[0] = VbglR0PhysHeapGetPhysAddr(pBuffer) & ~(RTGCPHYS64)PAGE_OFFSET_MASK;
730 if (Req.PgLst.cPages == 1)
731 Req.PageTwo = NIL_RTGCPHYS64;
732 else
733 Req.PageTwo = Req.PgLst.aPages[0] + PAGE_SIZE;
734
735 int rc = VbglR0HGCMCallRaw(pClient->handle, &Req.Core.callInfo, sizeof(Req));
736 //Log(("VBOXSF: VbglR0SfFsInfo: VbglR0HGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.Hdr.rc));
737 if (RT_SUCCESS(rc))
738 {
739 rc = Req.Core.callInfo.Hdr.rc;
740 *pcbBuffer = Req.Core.cb.u.value32;
741 }
742 return rc;
743}
744
745#endif
746
747
748/**
749 * Worker for FS32_PATHINFO that handles file stat queries.
750 *
751 * @returns OS/2 status code
752 * @param pFolder The folder.
753 * @param pSfFsi The file system independent file structure. We'll
754 * update the timestamps and size here.
755 * @param pSfFsd Out file data.
756 * @param uLevel The information level.
757 * @param pbData Where to return the data (user address).
758 * @param cbData The amount of data to produce.
759 */
760static APIRET
761vboxSfOs2QueryFileInfo(PVBOXSFFOLDER pFolder, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, ULONG uLevel, PBYTE pbData, ULONG cbData)
762{
763 /*
764 * Performance notes (@bugref{9172}):
765 *
766 * This function was used for some performance hacking in an attempt at
767 * squeezing more performance out of the HGCM and shared folders code.
768 *
769 * 0. Skip calling the host and returning zeros:
770 * 906 ns / 3653 ticks
771 *
772 * This is comparable to JFS (859 ns) and HPFS (1107 ns) and give an
773 * idea what we're up against compared to a "local" file system.
774 *
775 * Host build of r126639 with strict VBoxGuest.sys and VBoxSF.ifs
776 * circa r126775, just for establishing some actual base line for (2, 3, +):
777 * (a) 39095 ns / 156757 ticks - VbglR0SfFsInfo.
778 * (b) 35074 ns / 140880 ticks - VbglR0SfPhysFsInfo.
779 *
780 * 1. Having shortcircuted the host side processing by faking a success when
781 * VMMDevHGCM.cpp is about to do pThis->pHGCMDrv->pfnCall, then measuring
782 * various guest side changes in the request and request submission path:
783 *
784 * - Saved by page lists vs virtul address for buffers:
785 * 4095 ns / 16253 ticks / %35.
786 *
787 * Suspect this is due to expensive memory locking on the guest side and
788 * the host doing extra virtual address conversion.
789 *
790 * - Saved by no repackaging the HGCM requests:
791 * 450 ns / 1941 ticks / 5.8%.
792 *
793 * - Embedding the SHFLFSOBJINFO into the buffer may save a little as well:
794 * 286 ns / 1086 ticks / 3.9%.
795 *
796 * Raw data:
797 * 11843 ns / 47469 ticks - VbglR0SfFsInfo.
798 * 7748 ns / 31216 ticks - VbglR0SfPhysFsInfo.
799 * 7298 ns / 29275 ticks - VbglR0SfFastPhysFsInfo.
800 * 7012 ns / 28189 ticks - Embedded buffer.
801 *
802 * 2. Interrupt acknowledgement in VBoxGuest goes to ring-3, which is wasteful.
803 * Played around with handling VMMDevReq_AcknowledgeEvents requests in
804 * ring-0, but since it just returns a 32-bit mask of pending events it was
805 * more natural to implement it as a 32-bit IN operation.
806 *
807 * Saves 4217 ns / 17048 ticks / 13%.
808 *
809 * Raw data:
810 * 32027 ns / 128506 ticks - ring-3 VMMDevReq_AcknowledgeEvents.
811 * 27810 ns / 111458 ticks - fast ring-0 ACK.
812 *
813 * 3. Use single release & auto resetting event semaphore in HGCMThread.
814 *
815 * Saves 922 ns / 3406 ticks / 3.4%.
816 *
817 * Raw data:
818 * 27472 ns / 110237 ticks - RTSEMEVENTMULTI
819 * 26550 ns / 106831 ticks - RTSEMEVENT
820 *
821 * Gain since 0a: 12545 ns / 49926 ticks / 32%
822 * Gain since 0b: 8524 ns / 34049 ticks / 24%
823 *
824 * 4. Try handle VINF_EM_HALT from HMR0 in ring-0, avoiding 4 context switches
825 * and a EM reschduling.
826 *
827 * Saves 1216 ns / 4734 ticks / 4.8%.
828 *
829 * Raw data:
830 * 25595 ns / 102768 ticks - no ring-0 HLT.
831 * 24379 ns / 98034 ticks - ring-0 HLT (42 spins)
832 *
833 * Gain since 0a: 14716 ns / 58723 ticks / 38%
834 * Gain since 0b: 10695 ns / 42846 ticks / 30%
835 *
836 */
837#if 0
838 APIRET rc;
839 PSHFLFSOBJINFO pObjInfo = (PSHFLFSOBJINFO)VbglR0PhysHeapAlloc(sizeof(*pObjInfo));
840 if (pObjInfo)
841 {
842 RT_ZERO(*pObjInfo);
843 uint32_t cbObjInfo = sizeof(*pObjInfo);
844
845 int vrc = VbglR0SfFsInfo(&g_SfClient, &pFolder->hHostFolder, pSfFsd->hHostFile,
846 SHFL_INFO_FILE | SHFL_INFO_GET, &cbObjInfo, (PSHFLDIRINFO)pObjInfo);
847 if (RT_SUCCESS(vrc))
848 {
849 rc = vboxSfOs2FileStatusFromObjInfo(pbData, cbData, uLevel, pObjInfo);
850 if (rc == NO_ERROR)
851 {
852 /* Update the timestamps in the independent file data: */
853 int16_t cMinLocalTimeDelta = vboxSfOs2GetLocalTimeDelta();
854 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_cdate, &pSfFsi->sfi_ctime, pObjInfo->BirthTime, cMinLocalTimeDelta);
855 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_adate, &pSfFsi->sfi_atime, pObjInfo->AccessTime, cMinLocalTimeDelta);
856 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_mdate, &pSfFsi->sfi_mtime, pObjInfo->ModificationTime, cMinLocalTimeDelta);
857
858 /* And the size field as we're at it: */
859 pSfFsi->sfi_sizel = pObjInfo->cbObject;
860 }
861 }
862 else
863 {
864 Log(("vboxSfOs2QueryFileInfo: VbglR0SfFsInfo failed: %Rrc\n", vrc));
865 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_GEN_FAILURE);
866 }
867 VbglR0PhysHeapFree(pObjInfo);
868 }
869 else
870 rc = ERROR_NOT_ENOUGH_MEMORY;
871#elif 0
872 APIRET rc;
873 struct MyEmbReq
874 {
875 VBGLIOCIDCHGCMFASTCALL Hdr;
876 VMMDevHGCMCall Call;
877 VBoxSFParmInformation Parms;
878 SHFLFSOBJINFO ObjInfo;
879 } *pReq = (struct MyEmbReq *)VbglR0PhysHeapAlloc(sizeof(*pReq));
880 if (pReq)
881 {
882 RT_ZERO(pReq->ObjInfo);
883
884 VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
885 SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, sizeof(*pReq));
886 pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit;
887 pReq->Parms.id32Root.u.value32 = pFolder->idHostRoot;
888 pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit;
889 pReq->Parms.u64Handle.u.value64 = pSfFsd->hHostFile;
890 pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit;
891 pReq->Parms.f32Flags.u.value32 = SHFL_INFO_FILE | SHFL_INFO_GET;
892 pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit;
893 pReq->Parms.cb32.u.value32 = sizeof(pReq->ObjInfo);
894 pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded;
895 pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->ObjInfo);
896 pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(struct MyEmbReq, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL);
897 pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
898
899 int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
900 if (RT_SUCCESS(vrc))
901 vrc = pReq->Call.header.result;
902 if (RT_SUCCESS(vrc))
903 {
904 rc = vboxSfOs2FileStatusFromObjInfo(pbData, cbData, uLevel, &pReq->ObjInfo);
905 if (rc == NO_ERROR)
906 {
907 /* Update the timestamps in the independent file data: */
908 int16_t cMinLocalTimeDelta = vboxSfOs2GetLocalTimeDelta();
909 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_cdate, &pSfFsi->sfi_ctime, pReq->ObjInfo.BirthTime, cMinLocalTimeDelta);
910 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_adate, &pSfFsi->sfi_atime, pReq->ObjInfo.AccessTime, cMinLocalTimeDelta);
911 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_mdate, &pSfFsi->sfi_mtime, pReq->ObjInfo.ModificationTime, cMinLocalTimeDelta);
912
913 /* And the size field as we're at it: */
914 pSfFsi->sfi_sizel = pReq->ObjInfo.cbObject;
915 }
916 }
917 else
918 {
919 Log(("vboxSfOs2QueryFileInfo: VbglR0SfFsInfo failed: %Rrc\n", vrc));
920 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_GEN_FAILURE);
921 }
922
923 VbglR0PhysHeapFree(pReq);
924 }
925 else
926 rc = ERROR_NOT_ENOUGH_MEMORY;
927#else /* clean version of the above. */
928 APIRET rc;
929 VBOXSFOBJINFOREQ *pReq = (VBOXSFOBJINFOREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
930 if (pReq)
931 {
932 int vrc = VbglR0SfHostReqQueryObjInfo(pFolder->idHostRoot, pReq, pSfFsd->hHostFile);
933 if (RT_SUCCESS(vrc))
934 {
935 rc = vboxSfOs2FileStatusFromObjInfo(pbData, cbData, uLevel, &pReq->ObjInfo);
936 if (rc == NO_ERROR)
937 {
938 /* Update the timestamps in the independent file data: */
939 int16_t cMinLocalTimeDelta = vboxSfOs2GetLocalTimeDelta();
940 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_cdate, &pSfFsi->sfi_ctime, pReq->ObjInfo.BirthTime, cMinLocalTimeDelta);
941 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_adate, &pSfFsi->sfi_atime, pReq->ObjInfo.AccessTime, cMinLocalTimeDelta);
942 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_mdate, &pSfFsi->sfi_mtime, pReq->ObjInfo.ModificationTime, cMinLocalTimeDelta);
943
944 /* And the size field as we're at it: */
945 pSfFsi->sfi_sizel = pReq->ObjInfo.cbObject;
946 }
947 }
948 else
949 {
950 Log(("vboxSfOs2QueryFileInfo: VbglR0SfHostReqQueryObjInfo failed: %Rrc\n", vrc));
951 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_GEN_FAILURE);
952 }
953
954 VbglR0PhysHeapFree(pReq);
955 }
956 else
957 rc = ERROR_NOT_ENOUGH_MEMORY;
958#endif
959 return rc;
960}
961
962
963DECLASM(APIRET)
964FS32_FILEINFO(ULONG fFlags, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, ULONG uLevel,
965 PBYTE pbData, ULONG cbData, ULONG fIoFlags)
966{
967 LogFlow(("FS32_FILEINFO: fFlags=%#x pSfFsi=%p pSfFsd=%p uLevel=%p pbData=%p cbData=%#x fIoFlags=%#x\n",
968 fFlags, pSfFsi, pSfFsd, uLevel, pbData, cbData, fIoFlags));
969
970 /*
971 * Validate input.
972 */
973 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
974 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
975 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
976 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
977 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
978 Assert(pFolder->cOpenFiles > 0);
979
980 /*
981 * Check the level.
982 * Note! See notes in FS32_PATHINFO.
983 */
984 ULONG cbMinData;
985 switch (uLevel)
986 {
987 case FI_LVL_STANDARD:
988 cbMinData = sizeof(FILESTATUS);
989 AssertCompileSize(FILESTATUS, 0x16);
990 break;
991 case FI_LVL_STANDARD_64:
992 cbMinData = sizeof(FILESTATUS3L);
993 AssertCompileSize(FILESTATUS3L, 0x20); /* cbFile and cbFileAlloc are misaligned. */
994 break;
995 case FI_LVL_STANDARD_EASIZE:
996 cbMinData = sizeof(FILESTATUS2);
997 AssertCompileSize(FILESTATUS2, 0x1a);
998 break;
999 case FI_LVL_STANDARD_EASIZE_64:
1000 cbMinData = sizeof(FILESTATUS4L);
1001 AssertCompileSize(FILESTATUS4L, 0x24); /* cbFile and cbFileAlloc are misaligned. */
1002 break;
1003 case FI_LVL_EAS_FROM_LIST:
1004 case FI_LVL_EAS_FULL:
1005 case FI_LVL_EAS_FULL_5:
1006 case FI_LVL_EAS_FULL_8:
1007 cbMinData = sizeof(EAOP);
1008 break;
1009 default:
1010 LogRel(("FS32_PATHINFO: Unsupported info level %u!\n", uLevel));
1011 return ERROR_INVALID_LEVEL;
1012 }
1013 if (cbData < cbMinData || pbData == NULL)
1014 {
1015 Log(("FS32_FILEINFO: ERROR_BUFFER_OVERFLOW (cbMinData=%#x, cbData=%#x)\n", cbMinData, cbData));
1016 return ERROR_BUFFER_OVERFLOW;
1017 }
1018
1019 /*
1020 * Query information.
1021 */
1022 APIRET rc;
1023 if (fFlags == FI_RETRIEVE)
1024 {
1025 switch (uLevel)
1026 {
1027 case FI_LVL_STANDARD:
1028 case FI_LVL_STANDARD_EASIZE:
1029 case FI_LVL_STANDARD_64:
1030 case FI_LVL_STANDARD_EASIZE_64:
1031 rc = vboxSfOs2QueryFileInfo(pFolder, pSfFsi, pSfFsd, uLevel, pbData, cbMinData);
1032 break;
1033
1034 /*
1035 * We don't do EAs and we "just" need to return no-EAs.
1036 * However, that's not as easy as you might think.
1037 */
1038 case FI_LVL_EAS_FROM_LIST:
1039 case FI_LVL_EAS_FULL:
1040 case FI_LVL_EAS_FULL_5:
1041 case FI_LVL_EAS_FULL_8:
1042 rc = vboxSfOs2MakeEmptyEaList((PEAOP)pbData, uLevel);
1043 break;
1044
1045 default:
1046 AssertFailed();
1047 rc = ERROR_GEN_FAILURE;
1048 break;
1049 }
1050 }
1051 /*
1052 * Update information.
1053 */
1054 else if (fFlags == FI_SET)
1055 {
1056 switch (uLevel)
1057 {
1058 case FI_LVL_STANDARD:
1059 case FI_LVL_STANDARD_64:
1060 rc = vboxSfOs2SetFileInfo(pFolder, pSfFsi, pSfFsd, uLevel, pbData, cbMinData);
1061 break;
1062
1063 case FI_LVL_STANDARD_EASIZE:
1064 rc = ERROR_EAS_NOT_SUPPORTED;
1065 break;
1066
1067 case FI_LVL_STANDARD_EASIZE_64:
1068 case FI_LVL_EAS_FROM_LIST:
1069 case FI_LVL_EAS_FULL:
1070 case FI_LVL_EAS_FULL_5:
1071 case FI_LVL_EAS_FULL_8:
1072 rc = ERROR_INVALID_LEVEL;
1073 break;
1074
1075 default:
1076 AssertFailed();
1077 rc = ERROR_GEN_FAILURE;
1078 break;
1079 }
1080 }
1081 else
1082 {
1083 LogRel(("FS32_FILEINFO: Unknown flags value: %#x\n", fFlags));
1084 rc = ERROR_INVALID_PARAMETER;
1085 }
1086 RT_NOREF_PV(fIoFlags);
1087 return rc;
1088}
1089
1090
1091DECLASM(APIRET)
1092FS32_NEWSIZEL(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, LONGLONG cbFile, ULONG fIoFlags)
1093{
1094 LogFlow(("FS32_NEWSIZEL: pSfFsi=%p pSfFsd=%p cbFile=%RI64 (%#RX64) fIoFlags=%#x\n", pSfFsi, pSfFsd, cbFile, cbFile, fIoFlags));
1095
1096 /*
1097 * Validate input.
1098 */
1099 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1100 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1101 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1102 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1103 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1104 Assert(pFolder->cOpenFiles > 0);
1105 if (cbFile < 0)
1106 {
1107 LogRel(("FS32_NEWSIZEL: Negative size: %RI64\n", cbFile));
1108 return ERROR_INVALID_PARAMETER;
1109 }
1110
1111 /*
1112 * This should only be possible on a file that is writable.
1113 */
1114 APIRET rc;
1115 if ( (pSfFsi->sfi_mode & SFMODE_OPEN_ACCESS) == SFMODE_OPEN_WRITEONLY
1116 || (pSfFsi->sfi_mode & SFMODE_OPEN_ACCESS) == SFMODE_OPEN_READWRITE)
1117 {
1118 /*
1119 * Call the host.
1120 */
1121 int vrc = VbglR0SfHostReqSetFileSizeSimple(pFolder->idHostRoot, pSfFsd->hHostFile, cbFile);
1122 if (RT_SUCCESS(vrc))
1123 {
1124 pSfFsi->sfi_sizel = cbFile;
1125 rc = NO_ERROR;
1126 }
1127 else
1128 {
1129 LogRel(("FS32_NEWSIZEL: VbglR0SfFsInfo failed: %Rrc\n", vrc));
1130 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_GEN_FAILURE);
1131 }
1132 }
1133 else
1134 rc = ERROR_ACCESS_DENIED;
1135
1136 RT_NOREF(fIoFlags);
1137 LogFlow(("FS32_NEWSIZEL: returns %u\n", rc));
1138 return rc;
1139}
1140
1141
1142/**
1143 * Convert KernVMLock page list to HGCM page list.
1144 *
1145 * The trouble is that it combine pages.
1146 */
1147static void vboxSfOs2ConvertPageList(KernPageList_t volatile *paSrc, RTGCPHYS64 volatile *paDst, ULONG cSrc, uint32_t cDst)
1148{
1149 LogFlow(("vboxSfOs2ConvertPageList: %d vs %d\n", cSrc, cDst));
1150
1151 /* If the list have identical length, the job is easy. */
1152 if (cSrc == cDst)
1153 for (uint32_t i = 0; i < cSrc; i++)
1154 paDst[i] &= ~(uint32_t)PAGE_OFFSET_MASK;
1155 else
1156 {
1157 Assert(cSrc <= cDst);
1158 Assert(cSrc > 0);
1159
1160 /*
1161 * We have fewer source entries than destiation pages, so something needs
1162 * expanding. The fact that the first and last pages might be partial ones
1163 * makes this more interesting. We have to do it backwards, of course.
1164 */
1165
1166 /* Deal with the partial page stuff first. */
1167 paSrc[0].Size += paSrc[0].Addr & PAGE_OFFSET_MASK;
1168 paSrc[0].Addr &= ~(ULONG)PAGE_OFFSET_MASK;
1169 paSrc[cSrc - 1].Size = RT_ALIGN_32(paSrc[cSrc - 1].Size, PAGE_SIZE);
1170
1171 /* The go do work on the conversion. */
1172 uint32_t iDst = cDst;
1173 uint32_t iSrc = cSrc;
1174 while (iSrc-- > 0)
1175 {
1176 ULONG cbSrc = paSrc[iSrc].Size;
1177 ULONG uAddrSrc = paSrc[iSrc].Addr + cbSrc;
1178 Assert(!(cbSrc & PAGE_OFFSET_MASK));
1179 Assert(!(uAddrSrc & PAGE_OFFSET_MASK));
1180 while (cbSrc > 0)
1181 {
1182 uAddrSrc -= PAGE_SIZE;
1183 Assert(iDst > 0);
1184 paDst[--iDst] = uAddrSrc;
1185 cbSrc -= PAGE_SIZE;
1186 }
1187 }
1188 Assert(iDst == 0);
1189 }
1190}
1191
1192
1193/**
1194 * Helper for FS32_READ.
1195 *
1196 * @note Must not called if reading beyond the end of the file, as we would give
1197 * sfi_sizel an incorrect value then.
1198 */
1199DECLINLINE(uint32_t) vboxSfOs2ReadFinalize(PSFFSI pSfFsi, uint64_t offRead, uint32_t cbActual)
1200{
1201 pSfFsi->sfi_positionl = offRead + cbActual;
1202 if ((uint64_t)pSfFsi->sfi_sizel < offRead + cbActual)
1203 pSfFsi->sfi_sizel = offRead + cbActual;
1204 pSfFsi->sfi_tstamp |= ST_SREAD | ST_PREAD;
1205 return cbActual;
1206}
1207
1208
1209extern "C" APIRET APIENTRY
1210FS32_READ(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, PVOID pvData, PULONG pcb, ULONG fIoFlags)
1211{
1212 LogFlow(("FS32_READ: pSfFsi=%p pSfFsd=%p pvData=%p pcb=%p:{%#x} fIoFlags=%#x\n", pSfFsi, pSfFsd, pvData, pcb, *pcb, fIoFlags));
1213
1214 /*
1215 * Validate and extract input.
1216 */
1217 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1218 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1219 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1220 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1221 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1222 Assert(pFolder->cOpenFiles > 0);
1223 RT_NOREF(pFolder);
1224
1225 uint64_t const offRead = pSfFsi->sfi_positionl;
1226 uint32_t const cbToRead = *pcb;
1227 uint32_t cbActual = cbToRead;
1228
1229 /*
1230 * We'll try embedded buffers for reads a smaller than ~2KB if we get
1231 * a heap block that's entirely within one page so the host can lock it
1232 * and avoid bouncing it off the heap on completion.
1233 */
1234 if (cbToRead <= _2K)
1235 {
1236 size_t cbReq = RT_UOFFSETOF(VBOXSFREADEMBEDDEDREQ, abData[0]) + cbToRead;
1237 VBOXSFREADEMBEDDEDREQ *pReq = (VBOXSFREADEMBEDDEDREQ *)VbglR0PhysHeapAlloc(cbReq);
1238 if ( pReq != NULL
1239 && ( PAGE_SIZE - (PAGE_OFFSET_MASK & (uintptr_t)pReq) >= cbReq
1240 || cbToRead == 0))
1241 {
1242 APIRET rc;
1243 int vrc = VbglR0SfHostReqReadEmbedded(pFolder->idHostRoot, pReq, pSfFsd->hHostFile, offRead, cbToRead);
1244 if (RT_SUCCESS(vrc))
1245 {
1246 cbActual = pReq->Parms.cb32Read.u.value32;
1247 if (cbActual > 0)
1248 {
1249 AssertStmt(cbActual <= cbToRead, cbActual = cbToRead);
1250 rc = KernCopyOut(pvData, &pReq->abData[0], cbActual);
1251 if (rc == NO_ERROR)
1252 {
1253 *pcb = vboxSfOs2ReadFinalize(pSfFsi, offRead, cbActual);
1254 LogFlow(("FS32_READ: returns; cbActual=%#x sfi_positionl=%RI64 [embedded]\n", cbActual, pSfFsi->sfi_positionl));
1255 }
1256 }
1257 else
1258 {
1259 LogFlow(("FS32_READ: returns; cbActual=0 (EOF); sfi_positionl=%RI64 [embedded]\n", pSfFsi->sfi_positionl));
1260 *pcb = 0;
1261 rc = NO_ERROR;
1262 }
1263 }
1264 else
1265 {
1266 Log(("FS32_READ: VbglR0SfHostReqReadEmbedded(off=%#RU64,cb=%#x) -> %Rrc [embedded]\n", offRead, cbToRead, vrc));
1267 rc = ERROR_BAD_NET_RESP;
1268 }
1269 VbglR0PhysHeapFree(pReq);
1270 return rc;
1271 }
1272 if (pReq)
1273 VbglR0PhysHeapFree(pReq);
1274 }
1275
1276 /*
1277 * Whatever we do now we're going to use a page list request structure.
1278 * So, we do one allocation large enough for both code paths below.
1279 */
1280 uint32_t cPages = ((cbToRead + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1;
1281 VBOXSFREADPGLSTREQ *pReq = (VBOXSFREADPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[cPages]));
1282 if (pReq)
1283 { /* likely */ }
1284 else
1285 {
1286 LogRel(("FS32_READ: Out of memory for page list request (%u pages)\n", cPages));
1287 return ERROR_NOT_ENOUGH_MEMORY;
1288 }
1289
1290 /*
1291 * If the request is less than 16KB or smaller, we try bounce it off the
1292 * physical heap (slab size is 64KB). For requests up to 64KB we try use
1293 * one of a handful of preallocated big buffers rather than the phys heap.
1294 */
1295 if (cbToRead <= _64K)
1296 {
1297 RTGCPHYS GCPhys;
1298 void *pvBuf = NULL;
1299 if (cbToRead <= _16K)
1300 {
1301 pvBuf = VbglR0PhysHeapAlloc(cbToRead);
1302 GCPhys = pvBuf ? VbglR0PhysHeapGetPhysAddr(pvBuf) : NIL_RTGCPHYS;
1303 }
1304 else
1305 pvBuf = vboxSfOs2AllocBigBuffer(&GCPhys);
1306 if (pvBuf)
1307 {
1308 APIRET rc;
1309 int vrc = VbglR0SfHostReqReadContig(pFolder->idHostRoot, pReq, pSfFsd->hHostFile, offRead, cbToRead, pvBuf, GCPhys);
1310 if (RT_SUCCESS(vrc))
1311 {
1312 cbActual = pReq->Parms.cb32Read.u.value32;
1313 if (cbActual > 0)
1314 {
1315 AssertStmt(cbActual <= cbToRead, cbActual = cbToRead);
1316 rc = KernCopyOut(pvData, pvBuf, cbActual);
1317 if (rc == NO_ERROR)
1318 {
1319 *pcb = vboxSfOs2ReadFinalize(pSfFsi, offRead, cbActual);
1320 LogFlow(("FS32_READ: returns; cbActual=%#x sfi_positionl=%RI64 [bounced]\n", cbActual, pSfFsi->sfi_positionl));
1321 }
1322 }
1323 else
1324 {
1325 LogFlow(("FS32_READ: returns; cbActual=0 (EOF) sfi_positionl=%RI64 [bounced]\n", pSfFsi->sfi_positionl));
1326 *pcb = 0;
1327 rc = NO_ERROR;
1328 }
1329 }
1330 else
1331 {
1332 Log(("FS32_READ: VbglR0SfHostReqReadEmbedded(off=%#RU64,cb=%#x) -> %Rrc [bounced]\n", offRead, cbToRead, vrc));
1333 rc = ERROR_BAD_NET_RESP;
1334 }
1335
1336 if (cbToRead <= _16K)
1337 VbglR0PhysHeapFree(pvBuf);
1338 else
1339 vboxSfOs2FreeBigBuffer(pvBuf);
1340 VbglR0PhysHeapFree(pReq);
1341 return rc;
1342 }
1343 }
1344
1345 /*
1346 * We couldn't use a bounce buffer for it, so lock the buffer pages.
1347 */
1348 KernVMLock_t Lock;
1349 ULONG cPagesRet;
1350 AssertCompile(sizeof(KernPageList_t) == sizeof(pReq->PgLst.aPages[0]));
1351 APIRET rc = KernVMLock(VMDHL_LONG | VMDHL_WRITE, (void *)pvData, cbToRead, &Lock,
1352 (KernPageList_t *)&pReq->PgLst.aPages[0], &cPagesRet);
1353 if (rc == NO_ERROR)
1354 {
1355 pReq->PgLst.offFirstPage = (uint16_t)(uintptr_t)pvData & (uint16_t)PAGE_OFFSET_MASK;
1356 cPages = (cbToRead + ((uint16_t)(uintptr_t)pvData & (uint16_t)PAGE_OFFSET_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
1357 vboxSfOs2ConvertPageList((KernPageList_t volatile *)&pReq->PgLst.aPages[0], &pReq->PgLst.aPages[0], cPagesRet, cPages);
1358
1359 int vrc = VbglR0SfHostReqReadPgLst(pFolder->idHostRoot, pReq, pSfFsd->hHostFile, offRead, cbToRead, cPages);
1360 if (RT_SUCCESS(vrc))
1361 {
1362 cbActual = pReq->Parms.cb32Read.u.value32;
1363 if (cbActual > 0)
1364 {
1365 AssertStmt(cbActual <= cbToRead, cbActual = cbToRead);
1366 *pcb = vboxSfOs2ReadFinalize(pSfFsi, offRead, cbActual);
1367 LogFlow(("FS32_READ: returns; cbActual=%#x sfi_positionl=%RI64 [locked]\n", cbActual, pSfFsi->sfi_positionl));
1368 }
1369 else
1370 {
1371 LogFlow(("FS32_READ: returns; cbActual=0 (EOF) sfi_positionl=%RI64 [locked]\n", pSfFsi->sfi_positionl));
1372 *pcb = 0;
1373 rc = NO_ERROR;
1374 }
1375 }
1376 else
1377 {
1378 Log(("FS32_READ: VbglR0SfHostReqReadEmbedded(off=%#RU64,cb=%#x) -> %Rrc [locked]\n", offRead, cbToRead, vrc));
1379 rc = ERROR_BAD_NET_RESP;
1380 }
1381
1382 KernVMUnlock(&Lock);
1383 }
1384 else
1385 Log(("FS32_READ: KernVMLock(,%p,%#x,) failed -> %u\n", pvData, cbToRead, rc));
1386 VbglR0PhysHeapFree(pReq);
1387 RT_NOREF_PV(fIoFlags);
1388 return rc;
1389}
1390
1391
1392/**
1393 * Helper for FS32_WRITE.
1394 */
1395DECLINLINE(uint32_t) vboxSfOs2WriteFinalize(PSFFSI pSfFsi, uint64_t offWrite, uint32_t cbActual)
1396{
1397 pSfFsi->sfi_positionl = offWrite + cbActual;
1398 if ((uint64_t)pSfFsi->sfi_sizel < offWrite + cbActual)
1399 pSfFsi->sfi_sizel = offWrite + cbActual;
1400 pSfFsi->sfi_tstamp |= ST_SWRITE | ST_PWRITE;
1401 return cbActual;
1402}
1403
1404
1405extern "C" APIRET APIENTRY
1406FS32_WRITE(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, void const *pvData, PULONG pcb, ULONG fIoFlags)
1407{
1408 /*
1409 * Validate and extract input.
1410 */
1411 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1412 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1413 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1414 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1415 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1416 Assert(pFolder->cOpenFiles > 0);
1417 RT_NOREF(pFolder);
1418
1419 uint64_t offWrite = pSfFsi->sfi_positionl;
1420 uint32_t cbToWrite = *pcb;
1421 uint32_t cbActual = cbToWrite;
1422
1423 /*
1424 * We'll try embedded buffers for writes a smaller than ~2KB if we get
1425 * a heap block that's entirely within one page so the host can lock it
1426 * and avoid bouncing it off the heap on completion.
1427 */
1428 if (cbToWrite <= _2K)
1429 {
1430 size_t cbReq = RT_UOFFSETOF(VBOXSFWRITEEMBEDDEDREQ, abData[0]) + cbToWrite;
1431 VBOXSFWRITEEMBEDDEDREQ *pReq = (VBOXSFWRITEEMBEDDEDREQ *)VbglR0PhysHeapAlloc(cbReq);
1432 if ( pReq != NULL
1433 && ( PAGE_SIZE - (PAGE_OFFSET_MASK & (uintptr_t)pReq) >= cbReq
1434 || cbToWrite == 0))
1435 {
1436 APIRET rc = KernCopyIn(&pReq->abData[0], pvData, cbToWrite);
1437 if (rc == NO_ERROR)
1438 {
1439 int vrc = VbglR0SfHostReqWriteEmbedded(pFolder->idHostRoot, pReq, pSfFsd->hHostFile, offWrite, cbToWrite);
1440 if (RT_SUCCESS(vrc))
1441 {
1442 cbActual = pReq->Parms.cb32Write.u.value32;
1443 AssertStmt(cbActual <= cbToWrite, cbActual = cbToWrite);
1444 *pcb = vboxSfOs2WriteFinalize(pSfFsi, offWrite, cbActual);
1445 LogFlow(("FS32_WRITE: returns; cbActual=%#x sfi_positionl=%RI64 [embedded]\n", cbActual, pSfFsi->sfi_positionl));
1446 }
1447 else
1448 {
1449 Log(("FS32_WRITE: VbglR0SfHostReqWriteEmbedded(off=%#RU64,cb=%#x) -> %Rrc [embedded]\n", offWrite, cbToWrite, vrc));
1450 rc = ERROR_BAD_NET_RESP;
1451 }
1452 }
1453 VbglR0PhysHeapFree(pReq);
1454 return rc;
1455 }
1456 if (pReq)
1457 VbglR0PhysHeapFree(pReq);
1458 }
1459
1460 /*
1461 * Whatever we do now we're going to use a page list request structure.
1462 * So, we do one allocation large enough for both code paths below.
1463 */
1464 uint32_t cPages = ((cbToWrite + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1;
1465 VBOXSFWRITEPGLSTREQ *pReq = (VBOXSFWRITEPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[cPages]));
1466 if (pReq)
1467 { /* likely */ }
1468 else
1469 {
1470 LogRel(("FS32_WRITE: Out of memory for page list request (%u pages)\n", cPages));
1471 return ERROR_NOT_ENOUGH_MEMORY;
1472 }
1473
1474 /*
1475 * If the request is less than 16KB or smaller, we try bounce it off the
1476 * physical heap (slab size is 64KB). For requests up to 64KB we try use
1477 * one of a handful of preallocated big buffers rather than the phys heap.
1478 */
1479 if (cbToWrite <= _64K)
1480 {
1481 RTGCPHYS GCPhys;
1482 void *pvBuf = NULL;
1483 if (cbToWrite <= _16K)
1484 {
1485 pvBuf = VbglR0PhysHeapAlloc(cbToWrite);
1486 GCPhys = pvBuf ? VbglR0PhysHeapGetPhysAddr(pvBuf) : NIL_RTGCPHYS;
1487 }
1488 else
1489 pvBuf = vboxSfOs2AllocBigBuffer(&GCPhys);
1490 if (pvBuf)
1491 {
1492 APIRET rc = KernCopyIn(pvBuf, pvData, cbToWrite);
1493 if (rc == NO_ERROR)
1494 {
1495 int vrc = VbglR0SfHostReqWriteContig(pFolder->idHostRoot, pReq, pSfFsd->hHostFile,
1496 offWrite, cbToWrite, pvBuf, GCPhys);
1497 if (RT_SUCCESS(vrc))
1498 {
1499 cbActual = pReq->Parms.cb32Write.u.value32;
1500 AssertStmt(cbActual <= cbToWrite, cbActual = cbToWrite);
1501 *pcb = vboxSfOs2WriteFinalize(pSfFsi, offWrite, cbActual);
1502 LogFlow(("FS32_WRITE: returns; cbActual=%#x sfi_positionl=%RI64 [bounced]\n", cbActual, pSfFsi->sfi_positionl));
1503 }
1504 else
1505 {
1506 Log(("FS32_WRITE: VbglR0SfHostReqWriteEmbedded(off=%#RU64,cb=%#x) -> %Rrc [bounced]\n", offWrite, cbToWrite, vrc));
1507 rc = ERROR_BAD_NET_RESP;
1508 }
1509 }
1510
1511 if (cbToWrite <= _16K)
1512 VbglR0PhysHeapFree(pvBuf);
1513 else
1514 vboxSfOs2FreeBigBuffer(pvBuf);
1515 VbglR0PhysHeapFree(pReq);
1516 return rc;
1517 }
1518 }
1519
1520 /*
1521 * We couldn't use a bounce buffer for it, so lock the buffer pages.
1522 */
1523 KernVMLock_t Lock;
1524 ULONG cPagesRet;
1525 AssertCompile(sizeof(KernPageList_t) == sizeof(pReq->PgLst.aPages[0]));
1526 APIRET rc = KernVMLock(VMDHL_LONG, (void *)pvData, cbToWrite, &Lock, (KernPageList_t *)&pReq->PgLst.aPages[0], &cPagesRet);
1527 if (rc == NO_ERROR)
1528 {
1529 pReq->PgLst.offFirstPage = (uint16_t)(uintptr_t)pvData & (uint16_t)PAGE_OFFSET_MASK;
1530 cPages = (cbToWrite + ((uint16_t)(uintptr_t)pvData & (uint16_t)PAGE_OFFSET_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
1531 vboxSfOs2ConvertPageList((KernPageList_t volatile *)&pReq->PgLst.aPages[0], &pReq->PgLst.aPages[0], cPagesRet, cPages);
1532
1533 int vrc = VbglR0SfHostReqWritePgLst(pFolder->idHostRoot, pReq, pSfFsd->hHostFile, offWrite, cbToWrite, cPages);
1534 if (RT_SUCCESS(vrc))
1535 {
1536 cbActual = pReq->Parms.cb32Write.u.value32;
1537 AssertStmt(cbActual <= cbToWrite, cbActual = cbToWrite);
1538 *pcb = vboxSfOs2WriteFinalize(pSfFsi, offWrite, cbActual);
1539 LogFlow(("FS32_WRITE: returns; cbActual=%#x sfi_positionl=%RI64 [locked]\n", cbActual, pSfFsi->sfi_positionl));
1540 }
1541 else
1542 {
1543 Log(("FS32_WRITE: VbglR0SfHostReqWriteEmbedded(off=%#RU64,cb=%#x) -> %Rrc [locked]\n", offWrite, cbToWrite, vrc));
1544 rc = ERROR_BAD_NET_RESP;
1545 }
1546
1547 KernVMUnlock(&Lock);
1548 }
1549 else
1550 Log(("FS32_WRITE: KernVMLock(,%p,%#x,) failed -> %u\n", pvData, cbToWrite, rc));
1551 VbglR0PhysHeapFree(pReq);
1552 RT_NOREF_PV(fIoFlags);
1553 return rc;
1554}
1555
1556
1557extern "C" APIRET APIENTRY
1558FS32_READFILEATCACHE(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, ULONG fIoFlags, LONGLONG off, ULONG pcb, KernCacheList_t **ppCacheList)
1559{
1560 /*
1561 * Validate input.
1562 */
1563 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1564 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1565 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1566 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1567 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1568 Assert(pFolder->cOpenFiles > 0);
1569 RT_NOREF(pFolder);
1570
1571 /* I think this is used for sendfile(). */
1572
1573 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(fIoFlags); NOREF(off); NOREF(pcb); NOREF(ppCacheList);
1574 return ERROR_NOT_SUPPORTED;
1575}
1576
1577
1578extern "C" APIRET APIENTRY
1579FS32_RETURNFILECACHE(KernCacheList_t *pCacheList)
1580{
1581 NOREF(pCacheList);
1582 return ERROR_NOT_SUPPORTED;
1583}
1584
1585
1586/* oddments */
1587
1588DECLASM(APIRET)
1589FS32_CANCELLOCKREQUESTL(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, struct filelockl *pLockRange)
1590{
1591 /*
1592 * Validate input.
1593 */
1594 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1595 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1596 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1597 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1598 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1599 Assert(pFolder->cOpenFiles > 0);
1600 RT_NOREF(pFolder);
1601
1602 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pLockRange);
1603 return ERROR_NOT_SUPPORTED;
1604}
1605
1606
1607DECLASM(APIRET)
1608FS32_CANCELLOCKREQUEST(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, struct filelock *pLockRange)
1609{
1610 /*
1611 * Validate input.
1612 */
1613 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1614 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1615 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1616 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1617 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1618 Assert(pFolder->cOpenFiles > 0);
1619 RT_NOREF(pFolder);
1620
1621 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pLockRange);
1622 return ERROR_NOT_SUPPORTED;
1623}
1624
1625
1626DECLASM(APIRET)
1627FS32_FILELOCKSL(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, struct filelockl *pUnLockRange,
1628 struct filelockl *pLockRange, ULONG cMsTimeout, ULONG fFlags)
1629{
1630 /*
1631 * Validate input.
1632 */
1633 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1634 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1635 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1636 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1637 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1638 Assert(pFolder->cOpenFiles > 0);
1639 RT_NOREF(pFolder);
1640
1641 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pUnLockRange); NOREF(pLockRange); NOREF(cMsTimeout); NOREF(fFlags);
1642 return ERROR_NOT_SUPPORTED;
1643}
1644
1645
1646DECLASM(APIRET)
1647FS32_FILELOCKS(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, struct filelock *pUnLockRange,
1648 struct filelock *pLockRange, ULONG cMsTimeout, ULONG fFlags)
1649{
1650 /*
1651 * Validate input.
1652 */
1653 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1654 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1655 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1656 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1657 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1658 Assert(pFolder->cOpenFiles > 0);
1659 RT_NOREF(pFolder);
1660
1661 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pUnLockRange); NOREF(pLockRange); NOREF(cMsTimeout); NOREF(fFlags);
1662 return ERROR_NOT_SUPPORTED;
1663}
1664
1665
1666DECLASM(APIRET)
1667FS32_IOCTL(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, USHORT uCategory, USHORT uFunction,
1668 PVOID pvParm, USHORT cbParm, PUSHORT pcbParmIO,
1669 PVOID pvData, USHORT cbData, PUSHORT pcbDataIO)
1670{
1671 /*
1672 * Validate input.
1673 */
1674 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1675 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1676 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1677 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1678 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1679 Assert(pFolder->cOpenFiles > 0);
1680 RT_NOREF(pFolder);
1681
1682 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(uCategory); NOREF(uFunction); NOREF(pvParm); NOREF(cbParm); NOREF(pcbParmIO);
1683 NOREF(pvData); NOREF(cbData); NOREF(pcbDataIO);
1684 return ERROR_NOT_SUPPORTED;
1685}
1686
1687
1688DECLASM(APIRET)
1689FS32_FILEIO(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, PBYTE pbCmdList, USHORT cbCmdList,
1690 PUSHORT poffError, USHORT fIoFlag)
1691{
1692 /*
1693 * Validate input.
1694 */
1695 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1696 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1697 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1698 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1699 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1700 Assert(pFolder->cOpenFiles > 0);
1701 RT_NOREF(pFolder);
1702
1703 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pbCmdList); NOREF(cbCmdList); NOREF(poffError); NOREF(fIoFlag);
1704 return ERROR_NOT_SUPPORTED;
1705}
1706
1707
1708DECLASM(APIRET)
1709FS32_NMPIPE(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, USHORT uOpType, union npoper *pOpRec,
1710 PBYTE pbData, PCSZ pszName)
1711{
1712 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(uOpType); NOREF(pOpRec); NOREF(pbData); NOREF(pszName);
1713 return ERROR_NOT_SUPPORTED;
1714}
1715
1716
1717DECLASM(APIRET)
1718FS32_OPENPAGEFILE(PULONG pfFlags, PULONG pcMaxReq, PCSZ pszName, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd,
1719 USHORT fOpenMode, USHORT fOpenFlags, USHORT fAttr, ULONG uReserved)
1720{
1721 NOREF(pfFlags); NOREF(pcMaxReq); NOREF(pszName); NOREF(pSfFsi); NOREF(pSfFsd); NOREF(fOpenMode); NOREF(fOpenFlags);
1722 NOREF(fAttr); NOREF(uReserved);
1723 return ERROR_NOT_SUPPORTED;
1724}
1725
1726
1727DECLASM(APIRET)
1728FS32_SETSWAP(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd)
1729{
1730 NOREF(pSfFsi); NOREF(pSfFsd);
1731 return ERROR_NOT_SUPPORTED;
1732}
1733
1734
1735DECLASM(APIRET)
1736FS32_ALLOCATEPAGESPACE(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, ULONG cb, USHORT cbWantContig)
1737{
1738 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(cb); NOREF(cbWantContig);
1739 return ERROR_NOT_SUPPORTED;
1740}
1741
1742
1743DECLASM(APIRET)
1744FS32_DOPAGEIO(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, struct PageCmdHeader *pList)
1745{
1746 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pList);
1747 return ERROR_NOT_SUPPORTED;
1748}
1749
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use