VirtualBox

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

最後變更 在這個檔案從79112是 79112,由 vboxsync 提交於 5 年 前

os2/VBoxSF: More EA fun, now for CMD.EXE opening files for copying. Ignore empty EAOPs and non-creation/replace opens.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 65.9 KB
 
1/** $Id: VBoxSFFile.cpp 79112 2019-06-13 03:33:29Z 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 <[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/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 RT_FALL_THRU();
312 case SHFL_FILE_CREATED:
313 case SHFL_FILE_REPLACED:
314 if ( pReq->CreateParms.Info.cbObject < _2G
315 || (fOpenMode & OPEN_FLAGS_LARGEFILE))
316 {
317 pSfFsd->u32Magic = VBOXSFSYFI_MAGIC;
318 pSfFsd->pSelf = pSfFsd;
319 pSfFsd->hHostFile = pReq->CreateParms.Handle;
320 pSfFsd->pFolder = pFolder;
321
322 uint32_t cOpenFiles = ASMAtomicIncU32(&pFolder->cOpenFiles);
323 Assert(cOpenFiles < _32K);
324 pFolder = NULL; /* Reference now taken by pSfFsd->pFolder. */
325
326 pSfFsi->sfi_sizel = pReq->CreateParms.Info.cbObject;
327 pSfFsi->sfi_type = STYPE_FILE;
328 pSfFsi->sfi_DOSattr = (uint8_t)((pReq->CreateParms.Info.Attr.fMode & RTFS_DOS_MASK_OS2) >> RTFS_DOS_SHIFT);
329 int16_t cMinLocalTimeDelta = vboxSfOs2GetLocalTimeDelta();
330 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_cdate, &pSfFsi->sfi_ctime, pReq->CreateParms.Info.BirthTime, cMinLocalTimeDelta);
331 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_adate, &pSfFsi->sfi_atime, pReq->CreateParms.Info.AccessTime, cMinLocalTimeDelta);
332 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_mdate, &pSfFsi->sfi_mtime, pReq->CreateParms.Info.ModificationTime, cMinLocalTimeDelta);
333 if (pReq->CreateParms.Result == SHFL_FILE_CREATED)
334 pSfFsi->sfi_tstamp |= ST_PCREAT | ST_SCREAT | ST_PWRITE | ST_SWRITE | ST_PREAD | ST_SREAD;
335
336 *puAction = pReq->CreateParms.Result == SHFL_FILE_CREATED ? FILE_CREATED
337 : pReq->CreateParms.Result == SHFL_FILE_EXISTS ? FILE_EXISTED
338 : FILE_TRUNCATED;
339
340 Log(("FS32_OPENCREATE: hHandle=%#RX64 for '%s'\n", pSfFsd->hHostFile, pszName));
341 rc = NO_ERROR;
342 }
343 else
344 {
345 LogRel(("FS32_OPENCREATE: cbObject=%#RX64 no OPEN_FLAGS_LARGEFILE (%s)\n", pReq->CreateParms.Info.cbObject, pszName));
346 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
347 VbglR0SfHostReqClose(pFolder->idHostRoot, (VBOXSFCLOSEREQ *)pReq, pReq->CreateParms.Handle);
348 rc = ERROR_ACCESS_DENIED;
349 }
350 break;
351
352 case SHFL_PATH_NOT_FOUND:
353 rc = ERROR_PATH_NOT_FOUND;
354 break;
355
356 default:
357 case SHFL_FILE_NOT_FOUND:
358 rc = ERROR_OPEN_FAILED;
359 break;
360 }
361 }
362 else if (vrc == VERR_ALREADY_EXISTS)
363 rc = ERROR_ACCESS_DENIED;
364 else if (vrc == VERR_FILE_NOT_FOUND)
365 rc = ERROR_OPEN_FAILED;
366 else
367 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_PATH_NOT_FOUND);
368 VbglR0PhysHeapFree(pReq);
369 vboxSfOs2ReleaseFolder(pFolder);
370 LogFlow(("FS32_OPENCREATE: returns %u\n", rc));
371 return rc;
372}
373
374
375DECLASM(APIRET)
376FS32_CLOSE(ULONG uType, ULONG fIoFlags, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd)
377{
378 LogFlow(("FS32_CLOSE: uType=%#x fIoFlags=%#x pSfFsi=%p pSfFsd=%p:{%#x, %#llx}\n",
379 uType, fIoFlags, pSfFsi, pSfFsd, pSfFsd->u32Magic, pSfFsd->hHostFile));
380
381 /*
382 * Validate input.
383 */
384 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
385 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
386 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
387 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
388 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
389 Assert(pFolder->cOpenFiles > 0);
390
391 /*
392 * We only care for when the system is done truly with the file
393 * and we can close it.
394 */
395 if (uType != FS_CL_FORSYS)
396 return NO_ERROR;
397
398 /** @todo flush file if fIoFlags says so? */
399 RT_NOREF(fIoFlags);
400
401 int vrc = VbglR0SfHostReqCloseSimple(pFolder->idHostRoot, pSfFsd->hHostFile);
402 AssertRC(vrc);
403
404 pSfFsd->hHostFile = SHFL_HANDLE_NIL;
405 pSfFsd->pSelf = NULL;
406 pSfFsd->u32Magic = ~VBOXSFSYFI_MAGIC;
407 pSfFsd->pFolder = NULL;
408
409 ASMAtomicDecU32(&pFolder->cOpenFiles);
410 vboxSfOs2ReleaseFolder(pFolder);
411
412 RT_NOREF(pSfFsi);
413 LogFlow(("FS32_CLOSE: returns NO_ERROR\n"));
414 return NO_ERROR;
415}
416
417
418DECLASM(APIRET)
419FS32_COMMIT(ULONG uType, ULONG fIoFlags, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd)
420{
421 LogFlow(("FS32_COMMIT: uType=%#x fIoFlags=%#x pSfFsi=%p pSfFsd=%p:{%#x}\n", uType, fIoFlags, pSfFsi, pSfFsd, pSfFsd->u32Magic));
422
423 /*
424 * Validate input.
425 */
426 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
427 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
428 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
429 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
430 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
431 Assert(pFolder->cOpenFiles > 0);
432 RT_NOREF(pFolder);
433
434 /*
435 * We only need to flush writable files.
436 */
437 if ( (pSfFsi->sfi_mode & SFMODE_OPEN_ACCESS) == SFMODE_OPEN_WRITEONLY
438 || (pSfFsi->sfi_mode & SFMODE_OPEN_ACCESS) == SFMODE_OPEN_READWRITE)
439 {
440 int vrc = VbglR0SfHostReqFlushSimple(pFolder->idHostRoot, pSfFsd->hHostFile);
441 if (RT_FAILURE(vrc))
442 {
443 LogRel(("FS32_COMMIT: VbglR0SfHostReqFlushSimple failed: %Rrc\n", vrc));
444 return ERROR_FLUSHBUF_FAILED;
445 }
446 }
447
448 NOREF(uType); NOREF(fIoFlags); NOREF(pSfFsi);
449 LogFlow(("FS32_COMMIT: returns NO_ERROR\n"));
450 return NO_ERROR;
451}
452
453
454extern "C" APIRET APIENTRY
455FS32_CHGFILEPTRL(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, LONGLONG off, ULONG uMethod, ULONG fIoFlags)
456{
457 LogFlow(("FS32_CHGFILEPTRL: pSfFsi=%p pSfFsd=%p off=%RI64 (%#RX64) uMethod=%u fIoFlags=%#x\n",
458 pSfFsi, pSfFsd, off, off, uMethod, fIoFlags));
459
460 /*
461 * Validate input.
462 */
463 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
464 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
465 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
466 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
467 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
468 Assert(pFolder->cOpenFiles > 0);
469
470 /*
471 * Calc absolute offset.
472 */
473 int64_t offNew;
474 switch (uMethod)
475 {
476 case CFP_RELBEGIN:
477 if (off >= 0)
478 {
479 offNew = off;
480 break;
481 }
482 Log(("FS32_CHGFILEPTRL: Negative seek (BEGIN): %RI64\n", off));
483 return ERROR_NEGATIVE_SEEK;
484
485 case CFP_RELCUR:
486 offNew = pSfFsi->sfi_positionl + off;
487 if (offNew >= 0)
488 break;
489 Log(("FS32_CHGFILEPTRL: Negative seek (RELCUR): %RU64 + %RI64\n", pSfFsi->sfi_positionl, off));
490 return ERROR_NEGATIVE_SEEK;
491
492 case CFP_RELEND:
493 {
494 /* Have to consult the host to get the current file size. */
495 VBOXSFOBJINFOREQ *pReq = (VBOXSFOBJINFOREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
496 if (pReq)
497 RT_ZERO(*pReq);
498 else
499 return ERROR_NOT_ENOUGH_MEMORY;
500
501 int vrc = VbglR0SfHostReqQueryObjInfo(pFolder->idHostRoot, pReq, pSfFsd->hHostFile);
502 if (RT_SUCCESS(vrc))
503 {
504 if (pSfFsi->sfi_mode & SFMODE_LARGE_FILE)
505 pSfFsi->sfi_sizel = pReq->ObjInfo.cbObject;
506 else
507 pSfFsi->sfi_sizel = RT_MIN(pReq->ObjInfo.cbObject, _2G - 1);
508 }
509 else
510 LogRel(("FS32_CHGFILEPTRL/CFP_RELEND: VbglR0SfFsInfo failed: %Rrc\n", vrc));
511
512 VbglR0PhysHeapFree(pReq);
513
514 offNew = pSfFsi->sfi_sizel + off;
515 if (offNew >= 0)
516 break;
517 Log(("FS32_CHGFILEPTRL: Negative seek (CFP_RELEND): %RI64 + %RI64\n", pSfFsi->sfi_sizel, off));
518 return ERROR_NEGATIVE_SEEK;
519 }
520
521
522 default:
523 LogRel(("FS32_CHGFILEPTRL: Unknown seek method: %#x\n", uMethod));
524 return ERROR_INVALID_FUNCTION;
525 }
526
527 /*
528 * Commit the seek.
529 */
530 pSfFsi->sfi_positionl = offNew;
531 LogFlow(("FS32_CHGFILEPTRL: returns; sfi_positionl=%RI64\n", offNew));
532 RT_NOREF_PV(fIoFlags);
533 return NO_ERROR;
534}
535
536
537/** Forwards the call to FS32_CHGFILEPTRL. */
538DECLASM(APIRET)
539FS32_CHGFILEPTR(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, LONG off, ULONG uMethod, ULONG fIoFlags)
540{
541 return FS32_CHGFILEPTRL(pSfFsi, pSfFsd, off, uMethod, fIoFlags);
542}
543
544
545/**
546 * Worker for FS32_PATHINFO that handles file stat setting.
547 *
548 * @returns OS/2 status code
549 * @param pFolder The folder.
550 * @param pSfFsi The file system independent file structure. We'll
551 * update the timestamps and size here.
552 * @param pSfFsd Out file data.
553 * @param uLevel The information level.
554 * @param pbData The stat data to set.
555 * @param cbData The uLevel specific input size.
556 */
557static APIRET
558vboxSfOs2SetFileInfo(PVBOXSFFOLDER pFolder, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, ULONG uLevel, PBYTE pbData, ULONG cbData)
559{
560 APIRET rc;
561
562 /*
563 * Data buffer both for caching user data and for issuing the
564 * change request to the host.
565 */
566 struct SetFileInfoBuf
567 {
568 union
569 {
570 FILESTATUS Lvl1;
571 FILESTATUS3L Lvl1L;
572 };
573 SHFLFSOBJINFO ObjInfo;
574 } *pBuf = (struct SetFileInfoBuf *)VbglR0PhysHeapAlloc(sizeof(*pBuf));
575 if (pBuf)
576 {
577 /* Copy in the data. */
578 rc = KernCopyIn(&pBuf->Lvl1, pbData, cbData);
579 if (rc == NO_ERROR)
580 {
581 /*
582 * Join paths with FS32_PATHINFO and FS32_FILEATTRIBUTE.
583 */
584 rc = vboxSfOs2SetInfoCommonWorker(pFolder, pSfFsd->hHostFile,
585 uLevel == FI_LVL_STANDARD ? pBuf->Lvl1.attrFile : pBuf->Lvl1L.attrFile,
586 &pBuf->Lvl1, &pBuf->ObjInfo, RT_UOFFSETOF(struct SetFileInfoBuf, ObjInfo));
587 if (rc == NO_ERROR)
588 {
589 /*
590 * Update the timestamps in the independent file data with what
591 * the host returned:
592 */
593 pSfFsi->sfi_tstamp |= ST_PCREAT | ST_PWRITE | ST_PREAD;
594 pSfFsi->sfi_tstamp &= ~(ST_SCREAT | ST_SWRITE| ST_SREAD);
595 uint16_t cDelta = vboxSfOs2GetLocalTimeDelta();
596 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_cdate, &pSfFsi->sfi_ctime, pBuf->ObjInfo.BirthTime, cDelta);
597 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_adate, &pSfFsi->sfi_atime, pBuf->ObjInfo.AccessTime, cDelta);
598 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_mdate, &pSfFsi->sfi_mtime, pBuf->ObjInfo.ModificationTime, cDelta);
599
600 /* And the size field as we're at it: */
601 pSfFsi->sfi_sizel = pBuf->ObjInfo.cbObject;
602 }
603 else
604 rc = ERROR_INVALID_PARAMETER;
605 }
606
607 VbglR0PhysHeapFree(pBuf);
608 }
609 else
610 rc = ERROR_NOT_ENOUGH_MEMORY;
611 return rc;
612}
613
614
615#if 0
616
617DECLVBGL(int) VbglR0SfFastPhysFsInfo(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile,
618 uint32_t flags, uint32_t *pcbBuffer, PSHFLDIRINFO pBuffer)
619{
620 struct FsInfoReq
621 {
622 VBGLIOCIDCHGCMFASTCALL Hdr;
623 VMMDevHGCMCall Call;
624 VBoxSFParmInformation Parms;
625 HGCMPageListInfo PgLst;
626 RTGCPHYS64 PageTwo;
627 } *pReq;
628 AssertCompileMemberOffset(struct FsInfoReq, Call, 52);
629 AssertCompileMemberOffset(struct FsInfoReq, Parms, 0x60);
630
631 pReq = (struct FsInfoReq *)VbglR0PhysHeapAlloc(sizeof(*pReq));
632 if (!pReq)
633 return VERR_NO_MEMORY;
634
635 VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, pClient->idClient,
636 SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, sizeof(*pReq));
637#if 0
638 VBGLREQHDR_INIT_EX(&pReq->Hdr.Hdr, sizeof(*pReq), sizeof(*pReq));
639 pReq->Hdr.GCPhysReq = VbglR0PhysHeapGetPhysAddr(pReq) + sizeof(pReq->Hdr);
640 pReq->Hdr.fInterruptible = false;
641
642 pReq->Call.header.header.size = sizeof(*pReq) - sizeof(pReq->Hdr);
643 pReq->Call.header.header.version = VBGLREQHDR_VERSION;
644 pReq->Call.header.header.requestType= VMMDevReq_HGCMCall32;
645 pReq->Call.header.header.rc = VERR_INTERNAL_ERROR;
646 pReq->Call.header.header.reserved1 = 0;
647 pReq->Call.header.header.fRequestor = VMMDEV_REQUESTOR_KERNEL | VMMDEV_REQUESTOR_USR_DRV_OTHER
648 | VMMDEV_REQUESTOR_CON_DONT_KNOW | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN;
649 pReq->Call.header.fu32Flags = 0;
650 pReq->Call.header.result = VERR_INTERNAL_ERROR;
651 pReq->Call.u32ClientID = pClient->idClient;
652 pReq->Call.u32Function = SHFL_FN_INFORMATION;
653 pReq->Call.cParms = SHFL_CPARMS_INFORMATION;
654#endif
655 uint32_t const cbBuffer = *pcbBuffer;
656 pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit;
657 pReq->Parms.id32Root.u.value32 = pMap->root;
658 pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit;
659 pReq->Parms.u64Handle.u.value64 = hFile;
660 pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit;
661 pReq->Parms.f32Flags.u.value32 = flags;
662 pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit;
663 pReq->Parms.cb32.u.value32 = cbBuffer;
664 pReq->Parms.pInfo.type = VMMDevHGCMParmType_PageList;
665 pReq->Parms.pInfo.u.PageList.size = cbBuffer;
666 pReq->Parms.pInfo.u.PageList.offset = RT_UOFFSETOF(struct FsInfoReq, PgLst) - RT_UOFFSETOF(struct FsInfoReq, Call);
667
668 Assert(cbBuffer < _1K);
669 pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
670 pReq->PgLst.cPages = cbBuffer <= (PAGE_SIZE - ((uintptr_t)pBuffer & PAGE_OFFSET_MASK)) ? 1 : 2;
671 pReq->PgLst.offFirstPage = (uint16_t)((uintptr_t)pBuffer & PAGE_OFFSET_MASK);
672 pReq->PgLst.aPages[0] = VbglR0PhysHeapGetPhysAddr(pBuffer) & ~(RTGCPHYS64)PAGE_OFFSET_MASK;
673 if (pReq->PgLst.cPages == 1)
674 pReq->PageTwo = NIL_RTGCPHYS64;
675 else
676 pReq->PageTwo = pReq->PgLst.aPages[0] + PAGE_SIZE;
677
678 int rc = VbglR0HGCMFastCall(pClient->handle, &pReq->Hdr, sizeof(*pReq));
679 if (RT_SUCCESS(rc))
680 {
681 rc = pReq->Call.header.result;
682 *pcbBuffer = pReq->Parms.cb32.u.value32;
683 }
684 VbglR0PhysHeapFree(pReq);
685 return rc;
686}
687
688
689DECLVBGL(int) VbglR0SfPhysFsInfo(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile,
690 uint32_t flags, uint32_t *pcbBuffer, PSHFLDIRINFO pBuffer)
691{
692 uint32_t const cbBuffer = *pcbBuffer;
693
694 struct
695 {
696 VBoxSFInformation Core;
697 HGCMPageListInfo PgLst;
698 RTGCPHYS64 PageTwo;
699 } Req;
700
701 VBGL_HGCM_HDR_INIT_EX(&Req.Core.callInfo, pClient->idClient, SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, sizeof(Req));
702 Req.Core.callInfo.fInterruptible = false;
703
704 Req.Core.root.type = VMMDevHGCMParmType_32bit;
705 Req.Core.root.u.value32 = pMap->root;
706
707 Req.Core.handle.type = VMMDevHGCMParmType_64bit;
708 Req.Core.handle.u.value64 = hFile;
709 Req.Core.flags.type = VMMDevHGCMParmType_32bit;
710 Req.Core.flags.u.value32 = flags;
711 Req.Core.cb.type = VMMDevHGCMParmType_32bit;
712 Req.Core.cb.u.value32 = cbBuffer;
713 Req.Core.info.type = VMMDevHGCMParmType_PageList;
714 Req.Core.info.u.PageList.size = cbBuffer;
715 Req.Core.info.u.PageList.offset = sizeof(Req.Core);
716
717 Assert(cbBuffer < _1K);
718 Req.PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
719 Req.PgLst.cPages = cbBuffer <= (PAGE_SIZE - ((uintptr_t)pBuffer & PAGE_OFFSET_MASK)) ? 1 : 2;
720 Req.PgLst.offFirstPage = (uint16_t)((uintptr_t)pBuffer & PAGE_OFFSET_MASK);
721 Req.PgLst.aPages[0] = VbglR0PhysHeapGetPhysAddr(pBuffer) & ~(RTGCPHYS64)PAGE_OFFSET_MASK;
722 if (Req.PgLst.cPages == 1)
723 Req.PageTwo = NIL_RTGCPHYS64;
724 else
725 Req.PageTwo = Req.PgLst.aPages[0] + PAGE_SIZE;
726
727 int rc = VbglR0HGCMCallRaw(pClient->handle, &Req.Core.callInfo, sizeof(Req));
728 //Log(("VBOXSF: VbglR0SfFsInfo: VbglR0HGCMCall rc = %#x, result = %#x\n", rc, data.callInfo.Hdr.rc));
729 if (RT_SUCCESS(rc))
730 {
731 rc = Req.Core.callInfo.Hdr.rc;
732 *pcbBuffer = Req.Core.cb.u.value32;
733 }
734 return rc;
735}
736
737#endif
738
739
740/**
741 * Worker for FS32_PATHINFO that handles file stat queries.
742 *
743 * @returns OS/2 status code
744 * @param pFolder The folder.
745 * @param pSfFsi The file system independent file structure. We'll
746 * update the timestamps and size here.
747 * @param pSfFsd Out file data.
748 * @param uLevel The information level.
749 * @param pbData Where to return the data (user address).
750 * @param cbData The amount of data to produce.
751 */
752static APIRET
753vboxSfOs2QueryFileInfo(PVBOXSFFOLDER pFolder, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, ULONG uLevel, PBYTE pbData, ULONG cbData)
754{
755 /*
756 * Performance notes (@bugref{9172}):
757 *
758 * This function was used for some performance hacking in an attempt at
759 * squeezing more performance out of the HGCM and shared folders code.
760 *
761 * 0. Skip calling the host and returning zeros:
762 * 906 ns / 3653 ticks
763 *
764 * This is comparable to JFS (859 ns) and HPFS (1107 ns) and give an
765 * idea what we're up against compared to a "local" file system.
766 *
767 * Host build of r126639 with strict VBoxGuest.sys and VBoxSF.ifs
768 * circa r126775, just for establishing some actual base line for (2, 3, +):
769 * (a) 39095 ns / 156757 ticks - VbglR0SfFsInfo.
770 * (b) 35074 ns / 140880 ticks - VbglR0SfPhysFsInfo.
771 *
772 * 1. Having shortcircuted the host side processing by faking a success when
773 * VMMDevHGCM.cpp is about to do pThis->pHGCMDrv->pfnCall, then measuring
774 * various guest side changes in the request and request submission path:
775 *
776 * - Saved by page lists vs virtul address for buffers:
777 * 4095 ns / 16253 ticks / %35.
778 *
779 * Suspect this is due to expensive memory locking on the guest side and
780 * the host doing extra virtual address conversion.
781 *
782 * - Saved by no repackaging the HGCM requests:
783 * 450 ns / 1941 ticks / 5.8%.
784 *
785 * - Embedding the SHFLFSOBJINFO into the buffer may save a little as well:
786 * 286 ns / 1086 ticks / 3.9%.
787 *
788 * Raw data:
789 * 11843 ns / 47469 ticks - VbglR0SfFsInfo.
790 * 7748 ns / 31216 ticks - VbglR0SfPhysFsInfo.
791 * 7298 ns / 29275 ticks - VbglR0SfFastPhysFsInfo.
792 * 7012 ns / 28189 ticks - Embedded buffer.
793 *
794 * 2. Interrupt acknowledgement in VBoxGuest goes to ring-3, which is wasteful.
795 * Played around with handling VMMDevReq_AcknowledgeEvents requests in
796 * ring-0, but since it just returns a 32-bit mask of pending events it was
797 * more natural to implement it as a 32-bit IN operation.
798 *
799 * Saves 4217 ns / 17048 ticks / 13%.
800 *
801 * Raw data:
802 * 32027 ns / 128506 ticks - ring-3 VMMDevReq_AcknowledgeEvents.
803 * 27810 ns / 111458 ticks - fast ring-0 ACK.
804 *
805 * 3. Use single release & auto resetting event semaphore in HGCMThread.
806 *
807 * Saves 922 ns / 3406 ticks / 3.4%.
808 *
809 * Raw data:
810 * 27472 ns / 110237 ticks - RTSEMEVENTMULTI
811 * 26550 ns / 106831 ticks - RTSEMEVENT
812 *
813 * Gain since 0a: 12545 ns / 49926 ticks / 32%
814 * Gain since 0b: 8524 ns / 34049 ticks / 24%
815 *
816 * 4. Try handle VINF_EM_HALT from HMR0 in ring-0, avoiding 4 context switches
817 * and a EM reschduling.
818 *
819 * Saves 1216 ns / 4734 ticks / 4.8%.
820 *
821 * Raw data:
822 * 25595 ns / 102768 ticks - no ring-0 HLT.
823 * 24379 ns / 98034 ticks - ring-0 HLT (42 spins)
824 *
825 * Gain since 0a: 14716 ns / 58723 ticks / 38%
826 * Gain since 0b: 10695 ns / 42846 ticks / 30%
827 *
828 */
829#if 0
830 APIRET rc;
831 PSHFLFSOBJINFO pObjInfo = (PSHFLFSOBJINFO)VbglR0PhysHeapAlloc(sizeof(*pObjInfo));
832 if (pObjInfo)
833 {
834 RT_ZERO(*pObjInfo);
835 uint32_t cbObjInfo = sizeof(*pObjInfo);
836
837 int vrc = VbglR0SfFsInfo(&g_SfClient, &pFolder->hHostFolder, pSfFsd->hHostFile,
838 SHFL_INFO_FILE | SHFL_INFO_GET, &cbObjInfo, (PSHFLDIRINFO)pObjInfo);
839 if (RT_SUCCESS(vrc))
840 {
841 rc = vboxSfOs2FileStatusFromObjInfo(pbData, cbData, uLevel, pObjInfo);
842 if (rc == NO_ERROR)
843 {
844 /* Update the timestamps in the independent file data: */
845 int16_t cMinLocalTimeDelta = vboxSfOs2GetLocalTimeDelta();
846 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_cdate, &pSfFsi->sfi_ctime, pObjInfo->BirthTime, cMinLocalTimeDelta);
847 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_adate, &pSfFsi->sfi_atime, pObjInfo->AccessTime, cMinLocalTimeDelta);
848 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_mdate, &pSfFsi->sfi_mtime, pObjInfo->ModificationTime, cMinLocalTimeDelta);
849
850 /* And the size field as we're at it: */
851 pSfFsi->sfi_sizel = pObjInfo->cbObject;
852 }
853 }
854 else
855 {
856 Log(("vboxSfOs2QueryFileInfo: VbglR0SfFsInfo failed: %Rrc\n", vrc));
857 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_GEN_FAILURE);
858 }
859 VbglR0PhysHeapFree(pObjInfo);
860 }
861 else
862 rc = ERROR_NOT_ENOUGH_MEMORY;
863#elif 0
864 APIRET rc;
865 struct MyEmbReq
866 {
867 VBGLIOCIDCHGCMFASTCALL Hdr;
868 VMMDevHGCMCall Call;
869 VBoxSFParmInformation Parms;
870 SHFLFSOBJINFO ObjInfo;
871 } *pReq = (struct MyEmbReq *)VbglR0PhysHeapAlloc(sizeof(*pReq));
872 if (pReq)
873 {
874 RT_ZERO(pReq->ObjInfo);
875
876 VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
877 SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, sizeof(*pReq));
878 pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit;
879 pReq->Parms.id32Root.u.value32 = pFolder->idHostRoot;
880 pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit;
881 pReq->Parms.u64Handle.u.value64 = pSfFsd->hHostFile;
882 pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit;
883 pReq->Parms.f32Flags.u.value32 = SHFL_INFO_FILE | SHFL_INFO_GET;
884 pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit;
885 pReq->Parms.cb32.u.value32 = sizeof(pReq->ObjInfo);
886 pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded;
887 pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->ObjInfo);
888 pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(struct MyEmbReq, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL);
889 pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
890
891 int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
892 if (RT_SUCCESS(vrc))
893 vrc = pReq->Call.header.result;
894 if (RT_SUCCESS(vrc))
895 {
896 rc = vboxSfOs2FileStatusFromObjInfo(pbData, cbData, uLevel, &pReq->ObjInfo);
897 if (rc == NO_ERROR)
898 {
899 /* Update the timestamps in the independent file data: */
900 int16_t cMinLocalTimeDelta = vboxSfOs2GetLocalTimeDelta();
901 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_cdate, &pSfFsi->sfi_ctime, pReq->ObjInfo.BirthTime, cMinLocalTimeDelta);
902 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_adate, &pSfFsi->sfi_atime, pReq->ObjInfo.AccessTime, cMinLocalTimeDelta);
903 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_mdate, &pSfFsi->sfi_mtime, pReq->ObjInfo.ModificationTime, cMinLocalTimeDelta);
904
905 /* And the size field as we're at it: */
906 pSfFsi->sfi_sizel = pReq->ObjInfo.cbObject;
907 }
908 }
909 else
910 {
911 Log(("vboxSfOs2QueryFileInfo: VbglR0SfFsInfo failed: %Rrc\n", vrc));
912 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_GEN_FAILURE);
913 }
914
915 VbglR0PhysHeapFree(pReq);
916 }
917 else
918 rc = ERROR_NOT_ENOUGH_MEMORY;
919#else /* clean version of the above. */
920 APIRET rc;
921 VBOXSFOBJINFOREQ *pReq = (VBOXSFOBJINFOREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
922 if (pReq)
923 {
924 int vrc = VbglR0SfHostReqQueryObjInfo(pFolder->idHostRoot, pReq, pSfFsd->hHostFile);
925 if (RT_SUCCESS(vrc))
926 {
927 rc = vboxSfOs2FileStatusFromObjInfo(pbData, cbData, uLevel, &pReq->ObjInfo);
928 if (rc == NO_ERROR)
929 {
930 /* Update the timestamps in the independent file data: */
931 int16_t cMinLocalTimeDelta = vboxSfOs2GetLocalTimeDelta();
932 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_cdate, &pSfFsi->sfi_ctime, pReq->ObjInfo.BirthTime, cMinLocalTimeDelta);
933 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_adate, &pSfFsi->sfi_atime, pReq->ObjInfo.AccessTime, cMinLocalTimeDelta);
934 vboxSfOs2DateTimeFromTimeSpec(&pSfFsi->sfi_mdate, &pSfFsi->sfi_mtime, pReq->ObjInfo.ModificationTime, cMinLocalTimeDelta);
935
936 /* And the size field as we're at it: */
937 pSfFsi->sfi_sizel = pReq->ObjInfo.cbObject;
938 }
939 }
940 else
941 {
942 Log(("vboxSfOs2QueryFileInfo: VbglR0SfHostReqQueryObjInfo failed: %Rrc\n", vrc));
943 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_GEN_FAILURE);
944 }
945
946 VbglR0PhysHeapFree(pReq);
947 }
948 else
949 rc = ERROR_NOT_ENOUGH_MEMORY;
950#endif
951 return rc;
952}
953
954
955DECLASM(APIRET)
956FS32_FILEINFO(ULONG fFlags, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, ULONG uLevel,
957 PBYTE pbData, ULONG cbData, ULONG fIoFlags)
958{
959 LogFlow(("FS32_FILEINFO: fFlags=%#x pSfFsi=%p pSfFsd=%p uLevel=%p pbData=%p cbData=%#x fIoFlags=%#x\n",
960 fFlags, pSfFsi, pSfFsd, uLevel, pbData, cbData, fIoFlags));
961
962 /*
963 * Validate input.
964 */
965 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
966 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
967 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
968 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
969 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
970 Assert(pFolder->cOpenFiles > 0);
971
972 /*
973 * Check the level.
974 * Note! See notes in FS32_PATHINFO.
975 */
976 ULONG cbMinData;
977 switch (uLevel)
978 {
979 case FI_LVL_STANDARD:
980 cbMinData = sizeof(FILESTATUS);
981 AssertCompileSize(FILESTATUS, 0x16);
982 break;
983 case FI_LVL_STANDARD_64:
984 cbMinData = sizeof(FILESTATUS3L);
985 AssertCompileSize(FILESTATUS3L, 0x20); /* cbFile and cbFileAlloc are misaligned. */
986 break;
987 case FI_LVL_STANDARD_EASIZE:
988 cbMinData = sizeof(FILESTATUS2);
989 AssertCompileSize(FILESTATUS2, 0x1a);
990 break;
991 case FI_LVL_STANDARD_EASIZE_64:
992 cbMinData = sizeof(FILESTATUS4L);
993 AssertCompileSize(FILESTATUS4L, 0x24); /* cbFile and cbFileAlloc are misaligned. */
994 break;
995 case FI_LVL_EAS_FROM_LIST:
996 case FI_LVL_EAS_FULL:
997 case FI_LVL_EAS_FULL_5:
998 case FI_LVL_EAS_FULL_8:
999 cbMinData = sizeof(EAOP);
1000 break;
1001 default:
1002 LogRel(("FS32_PATHINFO: Unsupported info level %u!\n", uLevel));
1003 return ERROR_INVALID_LEVEL;
1004 }
1005 if (cbData < cbMinData || pbData == NULL)
1006 {
1007 Log(("FS32_FILEINFO: ERROR_BUFFER_OVERFLOW (cbMinData=%#x, cbData=%#x)\n", cbMinData, cbData));
1008 return ERROR_BUFFER_OVERFLOW;
1009 }
1010
1011 /*
1012 * Query information.
1013 */
1014 APIRET rc;
1015 if (fFlags == FI_RETRIEVE)
1016 {
1017 switch (uLevel)
1018 {
1019 case FI_LVL_STANDARD:
1020 case FI_LVL_STANDARD_EASIZE:
1021 case FI_LVL_STANDARD_64:
1022 case FI_LVL_STANDARD_EASIZE_64:
1023 rc = vboxSfOs2QueryFileInfo(pFolder, pSfFsi, pSfFsd, uLevel, pbData, cbMinData);
1024 break;
1025
1026 /*
1027 * We don't do EAs and we "just" need to return no-EAs.
1028 * However, that's not as easy as you might think.
1029 */
1030 case FI_LVL_EAS_FROM_LIST:
1031 case FI_LVL_EAS_FULL:
1032 case FI_LVL_EAS_FULL_5:
1033 case FI_LVL_EAS_FULL_8:
1034 rc = vboxSfOs2MakeEmptyEaList((PEAOP)pbData, uLevel);
1035 break;
1036
1037 default:
1038 AssertFailed();
1039 rc = ERROR_GEN_FAILURE;
1040 break;
1041 }
1042 }
1043 /*
1044 * Update information.
1045 */
1046 else if (fFlags == FI_SET)
1047 {
1048 switch (uLevel)
1049 {
1050 case FI_LVL_STANDARD:
1051 case FI_LVL_STANDARD_64:
1052 rc = vboxSfOs2SetFileInfo(pFolder, pSfFsi, pSfFsd, uLevel, pbData, cbMinData);
1053 break;
1054
1055 case FI_LVL_STANDARD_EASIZE:
1056 rc = ERROR_EAS_NOT_SUPPORTED;
1057 break;
1058
1059 case FI_LVL_STANDARD_EASIZE_64:
1060 case FI_LVL_EAS_FROM_LIST:
1061 case FI_LVL_EAS_FULL:
1062 case FI_LVL_EAS_FULL_5:
1063 case FI_LVL_EAS_FULL_8:
1064 rc = ERROR_INVALID_LEVEL;
1065 break;
1066
1067 default:
1068 AssertFailed();
1069 rc = ERROR_GEN_FAILURE;
1070 break;
1071 }
1072 }
1073 else
1074 {
1075 LogRel(("FS32_FILEINFO: Unknown flags value: %#x\n", fFlags));
1076 rc = ERROR_INVALID_PARAMETER;
1077 }
1078 RT_NOREF_PV(fIoFlags);
1079 return rc;
1080}
1081
1082
1083DECLASM(APIRET)
1084FS32_NEWSIZEL(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, LONGLONG cbFile, ULONG fIoFlags)
1085{
1086 LogFlow(("FS32_NEWSIZEL: pSfFsi=%p pSfFsd=%p cbFile=%RI64 (%#RX64) fIoFlags=%#x\n", pSfFsi, pSfFsd, cbFile, cbFile, fIoFlags));
1087
1088 /*
1089 * Validate input.
1090 */
1091 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1092 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1093 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1094 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1095 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1096 Assert(pFolder->cOpenFiles > 0);
1097 if (cbFile < 0)
1098 {
1099 LogRel(("FS32_NEWSIZEL: Negative size: %RI64\n", cbFile));
1100 return ERROR_INVALID_PARAMETER;
1101 }
1102
1103 /*
1104 * This should only be possible on a file that is writable.
1105 */
1106 APIRET rc;
1107 if ( (pSfFsi->sfi_mode & SFMODE_OPEN_ACCESS) == SFMODE_OPEN_WRITEONLY
1108 || (pSfFsi->sfi_mode & SFMODE_OPEN_ACCESS) == SFMODE_OPEN_READWRITE)
1109 {
1110 /*
1111 * Call the host.
1112 */
1113 int vrc = VbglR0SfHostReqSetFileSizeSimple(pFolder->idHostRoot, pSfFsd->hHostFile, cbFile);
1114 if (RT_SUCCESS(vrc))
1115 {
1116 pSfFsi->sfi_sizel = cbFile;
1117 rc = NO_ERROR;
1118 }
1119 else
1120 {
1121 LogRel(("FS32_NEWSIZEL: VbglR0SfFsInfo failed: %Rrc\n", vrc));
1122 rc = vboxSfOs2ConvertStatusToOs2(vrc, ERROR_GEN_FAILURE);
1123 }
1124 }
1125 else
1126 rc = ERROR_ACCESS_DENIED;
1127
1128 RT_NOREF(fIoFlags);
1129 LogFlow(("FS32_NEWSIZEL: returns %u\n", rc));
1130 return rc;
1131}
1132
1133
1134/**
1135 * Convert KernVMLock page list to HGCM page list.
1136 *
1137 * The trouble is that it combine pages.
1138 */
1139static void vboxSfOs2ConvertPageList(KernPageList_t volatile *paSrc, RTGCPHYS64 volatile *paDst, ULONG cSrc, uint32_t cDst)
1140{
1141 LogFlow(("vboxSfOs2ConvertPageList: %d vs %d\n", cSrc, cDst));
1142
1143 /* If the list have identical length, the job is easy. */
1144 if (cSrc == cDst)
1145 for (uint32_t i = 0; i < cSrc; i++)
1146 paDst[i] &= ~(uint32_t)PAGE_OFFSET_MASK;
1147 else
1148 {
1149 Assert(cSrc <= cDst);
1150 Assert(cSrc > 0);
1151
1152 /*
1153 * We have fewer source entries than destiation pages, so something needs
1154 * expanding. The fact that the first and last pages might be partial ones
1155 * makes this more interesting. We have to do it backwards, of course.
1156 */
1157
1158 /* Deal with the partial page stuff first. */
1159 paSrc[0].Size += paSrc[0].Addr & PAGE_OFFSET_MASK;
1160 paSrc[0].Addr &= ~(ULONG)PAGE_OFFSET_MASK;
1161 paSrc[cSrc - 1].Size = RT_ALIGN_32(paSrc[cSrc - 1].Size, PAGE_SIZE);
1162
1163 /* The go do work on the conversion. */
1164 uint32_t iDst = cDst;
1165 uint32_t iSrc = cSrc;
1166 while (iSrc-- > 0)
1167 {
1168 ULONG cbSrc = paSrc[iSrc].Size;
1169 ULONG uAddrSrc = paSrc[iSrc].Addr + cbSrc;
1170 Assert(!(cbSrc & PAGE_OFFSET_MASK));
1171 Assert(!(uAddrSrc & PAGE_OFFSET_MASK));
1172 while (cbSrc > 0)
1173 {
1174 uAddrSrc -= PAGE_SIZE;
1175 Assert(iDst > 0);
1176 paDst[--iDst] = uAddrSrc;
1177 cbSrc -= PAGE_SIZE;
1178 }
1179 }
1180 Assert(iDst == 0);
1181 }
1182}
1183
1184
1185/**
1186 * Helper for FS32_READ.
1187 *
1188 * @note Must not called if reading beyond the end of the file, as we would give
1189 * sfi_sizel an incorrect value then.
1190 */
1191DECLINLINE(uint32_t) vboxSfOs2ReadFinalize(PSFFSI pSfFsi, uint64_t offRead, uint32_t cbActual)
1192{
1193 pSfFsi->sfi_positionl = offRead + cbActual;
1194 if ((uint64_t)pSfFsi->sfi_sizel < offRead + cbActual)
1195 pSfFsi->sfi_sizel = offRead + cbActual;
1196 pSfFsi->sfi_tstamp |= ST_SREAD | ST_PREAD;
1197 return cbActual;
1198}
1199
1200
1201extern "C" APIRET APIENTRY
1202FS32_READ(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, PVOID pvData, PULONG pcb, ULONG fIoFlags)
1203{
1204 LogFlow(("FS32_READ: pSfFsi=%p pSfFsd=%p pvData=%p pcb=%p:{%#x} fIoFlags=%#x\n", pSfFsi, pSfFsd, pvData, pcb, *pcb, fIoFlags));
1205
1206 /*
1207 * Validate and extract input.
1208 */
1209 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1210 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1211 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1212 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1213 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1214 Assert(pFolder->cOpenFiles > 0);
1215 RT_NOREF(pFolder);
1216
1217 uint64_t const offRead = pSfFsi->sfi_positionl;
1218 uint32_t const cbToRead = *pcb;
1219 uint32_t cbActual = cbToRead;
1220
1221 /*
1222 * We'll try embedded buffers for reads a smaller than ~2KB if we get
1223 * a heap block that's entirely within one page so the host can lock it
1224 * and avoid bouncing it off the heap on completion.
1225 */
1226 if (cbToRead <= _2K)
1227 {
1228 size_t cbReq = RT_UOFFSETOF(VBOXSFREADEMBEDDEDREQ, abData[0]) + cbToRead;
1229 VBOXSFREADEMBEDDEDREQ *pReq = (VBOXSFREADEMBEDDEDREQ *)VbglR0PhysHeapAlloc(cbReq);
1230 if ( pReq != NULL
1231 && ( PAGE_SIZE - (PAGE_OFFSET_MASK & (uintptr_t)pReq) >= cbReq
1232 || cbToRead == 0))
1233 {
1234 APIRET rc;
1235 int vrc = VbglR0SfHostReqReadEmbedded(pFolder->idHostRoot, pReq, pSfFsd->hHostFile, offRead, cbToRead);
1236 if (RT_SUCCESS(vrc))
1237 {
1238 cbActual = pReq->Parms.cb32Read.u.value32;
1239 if (cbActual > 0)
1240 {
1241 AssertStmt(cbActual <= cbToRead, cbActual = cbToRead);
1242 rc = KernCopyOut(pvData, &pReq->abData[0], cbActual);
1243 if (rc == NO_ERROR)
1244 {
1245 *pcb = vboxSfOs2ReadFinalize(pSfFsi, offRead, cbActual);
1246 LogFlow(("FS32_READ: returns; cbActual=%#x sfi_positionl=%RI64 [embedded]\n", cbActual, pSfFsi->sfi_positionl));
1247 }
1248 }
1249 else
1250 {
1251 LogFlow(("FS32_READ: returns; cbActual=0 (EOF); sfi_positionl=%RI64 [embedded]\n", pSfFsi->sfi_positionl));
1252 *pcb = 0;
1253 rc = NO_ERROR;
1254 }
1255 }
1256 else
1257 {
1258 Log(("FS32_READ: VbglR0SfHostReqReadEmbedded(off=%#RU64,cb=%#x) -> %Rrc [embedded]\n", offRead, cbToRead, vrc));
1259 rc = ERROR_BAD_NET_RESP;
1260 }
1261 VbglR0PhysHeapFree(pReq);
1262 return rc;
1263 }
1264 if (pReq)
1265 VbglR0PhysHeapFree(pReq);
1266 }
1267
1268 /*
1269 * Whatever we do now we're going to use a page list request structure.
1270 * So, we do one allocation large enough for both code paths below.
1271 */
1272 uint32_t cPages = ((cbToRead + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1;
1273 VBOXSFREADPGLSTREQ *pReq = (VBOXSFREADPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[cPages]));
1274 if (pReq)
1275 { /* likely */ }
1276 else
1277 {
1278 LogRel(("FS32_READ: Out of memory for page list request (%u pages)\n", cPages));
1279 return ERROR_NOT_ENOUGH_MEMORY;
1280 }
1281
1282 /*
1283 * If the request is less than 16KB or smaller, we try bounce it off the
1284 * physical heap (slab size is 64KB). For requests up to 64KB we try use
1285 * one of a handful of preallocated big buffers rather than the phys heap.
1286 */
1287 if (cbToRead <= _64K)
1288 {
1289 RTGCPHYS GCPhys;
1290 void *pvBuf = NULL;
1291 if (cbToRead <= _16K)
1292 {
1293 pvBuf = VbglR0PhysHeapAlloc(cbToRead);
1294 GCPhys = pvBuf ? VbglR0PhysHeapGetPhysAddr(pvBuf) : NIL_RTGCPHYS;
1295 }
1296 else
1297 pvBuf = vboxSfOs2AllocBigBuffer(&GCPhys);
1298 if (pvBuf)
1299 {
1300 APIRET rc;
1301 int vrc = VbglR0SfHostReqReadContig(pFolder->idHostRoot, pReq, pSfFsd->hHostFile, offRead, cbToRead, pvBuf, GCPhys);
1302 if (RT_SUCCESS(vrc))
1303 {
1304 cbActual = pReq->Parms.cb32Read.u.value32;
1305 if (cbActual > 0)
1306 {
1307 AssertStmt(cbActual <= cbToRead, cbActual = cbToRead);
1308 rc = KernCopyOut(pvData, pvBuf, cbActual);
1309 if (rc == NO_ERROR)
1310 {
1311 *pcb = vboxSfOs2ReadFinalize(pSfFsi, offRead, cbActual);
1312 LogFlow(("FS32_READ: returns; cbActual=%#x sfi_positionl=%RI64 [bounced]\n", cbActual, pSfFsi->sfi_positionl));
1313 }
1314 }
1315 else
1316 {
1317 LogFlow(("FS32_READ: returns; cbActual=0 (EOF) sfi_positionl=%RI64 [bounced]\n", pSfFsi->sfi_positionl));
1318 *pcb = 0;
1319 rc = NO_ERROR;
1320 }
1321 }
1322 else
1323 {
1324 Log(("FS32_READ: VbglR0SfHostReqReadEmbedded(off=%#RU64,cb=%#x) -> %Rrc [bounced]\n", offRead, cbToRead, vrc));
1325 rc = ERROR_BAD_NET_RESP;
1326 }
1327
1328 if (cbToRead <= _16K)
1329 VbglR0PhysHeapFree(pvBuf);
1330 else
1331 vboxSfOs2FreeBigBuffer(pvBuf);
1332 VbglR0PhysHeapFree(pReq);
1333 return rc;
1334 }
1335 }
1336
1337 /*
1338 * We couldn't use a bounce buffer for it, so lock the buffer pages.
1339 */
1340 KernVMLock_t Lock;
1341 ULONG cPagesRet;
1342 AssertCompile(sizeof(KernPageList_t) == sizeof(pReq->PgLst.aPages[0]));
1343 APIRET rc = KernVMLock(VMDHL_LONG | VMDHL_WRITE, (void *)pvData, cbToRead, &Lock,
1344 (KernPageList_t *)&pReq->PgLst.aPages[0], &cPagesRet);
1345 if (rc == NO_ERROR)
1346 {
1347 pReq->PgLst.offFirstPage = (uint16_t)(uintptr_t)pvData & (uint16_t)PAGE_OFFSET_MASK;
1348 cPages = (cbToRead + ((uint16_t)(uintptr_t)pvData & (uint16_t)PAGE_OFFSET_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
1349 vboxSfOs2ConvertPageList((KernPageList_t volatile *)&pReq->PgLst.aPages[0], &pReq->PgLst.aPages[0], cPagesRet, cPages);
1350
1351 int vrc = VbglR0SfHostReqReadPgLst(pFolder->idHostRoot, pReq, pSfFsd->hHostFile, offRead, cbToRead, cPages);
1352 if (RT_SUCCESS(vrc))
1353 {
1354 cbActual = pReq->Parms.cb32Read.u.value32;
1355 if (cbActual > 0)
1356 {
1357 AssertStmt(cbActual <= cbToRead, cbActual = cbToRead);
1358 *pcb = vboxSfOs2ReadFinalize(pSfFsi, offRead, cbActual);
1359 LogFlow(("FS32_READ: returns; cbActual=%#x sfi_positionl=%RI64 [locked]\n", cbActual, pSfFsi->sfi_positionl));
1360 }
1361 else
1362 {
1363 LogFlow(("FS32_READ: returns; cbActual=0 (EOF) sfi_positionl=%RI64 [locked]\n", pSfFsi->sfi_positionl));
1364 *pcb = 0;
1365 rc = NO_ERROR;
1366 }
1367 }
1368 else
1369 {
1370 Log(("FS32_READ: VbglR0SfHostReqReadEmbedded(off=%#RU64,cb=%#x) -> %Rrc [locked]\n", offRead, cbToRead, vrc));
1371 rc = ERROR_BAD_NET_RESP;
1372 }
1373
1374 KernVMUnlock(&Lock);
1375 }
1376 else
1377 Log(("FS32_READ: KernVMLock(,%p,%#x,) failed -> %u\n", pvData, cbToRead, rc));
1378 VbglR0PhysHeapFree(pReq);
1379 RT_NOREF_PV(fIoFlags);
1380 return rc;
1381}
1382
1383
1384/**
1385 * Helper for FS32_WRITE.
1386 */
1387DECLINLINE(uint32_t) vboxSfOs2WriteFinalize(PSFFSI pSfFsi, uint64_t offWrite, uint32_t cbActual)
1388{
1389 pSfFsi->sfi_positionl = offWrite + cbActual;
1390 if ((uint64_t)pSfFsi->sfi_sizel < offWrite + cbActual)
1391 pSfFsi->sfi_sizel = offWrite + cbActual;
1392 pSfFsi->sfi_tstamp |= ST_SWRITE | ST_PWRITE;
1393 return cbActual;
1394}
1395
1396
1397extern "C" APIRET APIENTRY
1398FS32_WRITE(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, void const *pvData, PULONG pcb, ULONG fIoFlags)
1399{
1400 /*
1401 * Validate and extract input.
1402 */
1403 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1404 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1405 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1406 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1407 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1408 Assert(pFolder->cOpenFiles > 0);
1409 RT_NOREF(pFolder);
1410
1411 uint64_t offWrite = pSfFsi->sfi_positionl;
1412 uint32_t cbToWrite = *pcb;
1413 uint32_t cbActual = cbToWrite;
1414
1415 /*
1416 * We'll try embedded buffers for writes a smaller than ~2KB if we get
1417 * a heap block that's entirely within one page so the host can lock it
1418 * and avoid bouncing it off the heap on completion.
1419 */
1420 if (cbToWrite <= _2K)
1421 {
1422 size_t cbReq = RT_UOFFSETOF(VBOXSFWRITEEMBEDDEDREQ, abData[0]) + cbToWrite;
1423 VBOXSFWRITEEMBEDDEDREQ *pReq = (VBOXSFWRITEEMBEDDEDREQ *)VbglR0PhysHeapAlloc(cbReq);
1424 if ( pReq != NULL
1425 && ( PAGE_SIZE - (PAGE_OFFSET_MASK & (uintptr_t)pReq) >= cbReq
1426 || cbToWrite == 0))
1427 {
1428 APIRET rc = KernCopyIn(&pReq->abData[0], pvData, cbToWrite);
1429 if (rc == NO_ERROR)
1430 {
1431 int vrc = VbglR0SfHostReqWriteEmbedded(pFolder->idHostRoot, pReq, pSfFsd->hHostFile, offWrite, cbToWrite);
1432 if (RT_SUCCESS(vrc))
1433 {
1434 cbActual = pReq->Parms.cb32Write.u.value32;
1435 AssertStmt(cbActual <= cbToWrite, cbActual = cbToWrite);
1436 *pcb = vboxSfOs2WriteFinalize(pSfFsi, offWrite, cbActual);
1437 LogFlow(("FS32_WRITE: returns; cbActual=%#x sfi_positionl=%RI64 [embedded]\n", cbActual, pSfFsi->sfi_positionl));
1438 }
1439 else
1440 {
1441 Log(("FS32_WRITE: VbglR0SfHostReqWriteEmbedded(off=%#RU64,cb=%#x) -> %Rrc [embedded]\n", offWrite, cbToWrite, vrc));
1442 rc = ERROR_BAD_NET_RESP;
1443 }
1444 }
1445 VbglR0PhysHeapFree(pReq);
1446 return rc;
1447 }
1448 if (pReq)
1449 VbglR0PhysHeapFree(pReq);
1450 }
1451
1452 /*
1453 * Whatever we do now we're going to use a page list request structure.
1454 * So, we do one allocation large enough for both code paths below.
1455 */
1456 uint32_t cPages = ((cbToWrite + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1;
1457 VBOXSFWRITEPGLSTREQ *pReq = (VBOXSFWRITEPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[cPages]));
1458 if (pReq)
1459 { /* likely */ }
1460 else
1461 {
1462 LogRel(("FS32_WRITE: Out of memory for page list request (%u pages)\n", cPages));
1463 return ERROR_NOT_ENOUGH_MEMORY;
1464 }
1465
1466 /*
1467 * If the request is less than 16KB or smaller, we try bounce it off the
1468 * physical heap (slab size is 64KB). For requests up to 64KB we try use
1469 * one of a handful of preallocated big buffers rather than the phys heap.
1470 */
1471 if (cbToWrite <= _64K)
1472 {
1473 RTGCPHYS GCPhys;
1474 void *pvBuf = NULL;
1475 if (cbToWrite <= _16K)
1476 {
1477 pvBuf = VbglR0PhysHeapAlloc(cbToWrite);
1478 GCPhys = pvBuf ? VbglR0PhysHeapGetPhysAddr(pvBuf) : NIL_RTGCPHYS;
1479 }
1480 else
1481 pvBuf = vboxSfOs2AllocBigBuffer(&GCPhys);
1482 if (pvBuf)
1483 {
1484 APIRET rc = KernCopyIn(pvBuf, pvData, cbToWrite);
1485 if (rc == NO_ERROR)
1486 {
1487 int vrc = VbglR0SfHostReqWriteContig(pFolder->idHostRoot, pReq, pSfFsd->hHostFile,
1488 offWrite, cbToWrite, pvBuf, GCPhys);
1489 if (RT_SUCCESS(vrc))
1490 {
1491 cbActual = pReq->Parms.cb32Write.u.value32;
1492 AssertStmt(cbActual <= cbToWrite, cbActual = cbToWrite);
1493 *pcb = vboxSfOs2WriteFinalize(pSfFsi, offWrite, cbActual);
1494 LogFlow(("FS32_WRITE: returns; cbActual=%#x sfi_positionl=%RI64 [bounced]\n", cbActual, pSfFsi->sfi_positionl));
1495 }
1496 else
1497 {
1498 Log(("FS32_WRITE: VbglR0SfHostReqWriteEmbedded(off=%#RU64,cb=%#x) -> %Rrc [bounced]\n", offWrite, cbToWrite, vrc));
1499 rc = ERROR_BAD_NET_RESP;
1500 }
1501 }
1502
1503 if (cbToWrite <= _16K)
1504 VbglR0PhysHeapFree(pvBuf);
1505 else
1506 vboxSfOs2FreeBigBuffer(pvBuf);
1507 VbglR0PhysHeapFree(pReq);
1508 return rc;
1509 }
1510 }
1511
1512 /*
1513 * We couldn't use a bounce buffer for it, so lock the buffer pages.
1514 */
1515 KernVMLock_t Lock;
1516 ULONG cPagesRet;
1517 AssertCompile(sizeof(KernPageList_t) == sizeof(pReq->PgLst.aPages[0]));
1518 APIRET rc = KernVMLock(VMDHL_LONG, (void *)pvData, cbToWrite, &Lock, (KernPageList_t *)&pReq->PgLst.aPages[0], &cPagesRet);
1519 if (rc == NO_ERROR)
1520 {
1521 pReq->PgLst.offFirstPage = (uint16_t)(uintptr_t)pvData & (uint16_t)PAGE_OFFSET_MASK;
1522 cPages = (cbToWrite + ((uint16_t)(uintptr_t)pvData & (uint16_t)PAGE_OFFSET_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT;
1523 vboxSfOs2ConvertPageList((KernPageList_t volatile *)&pReq->PgLst.aPages[0], &pReq->PgLst.aPages[0], cPagesRet, cPages);
1524
1525 int vrc = VbglR0SfHostReqWritePgLst(pFolder->idHostRoot, pReq, pSfFsd->hHostFile, offWrite, cbToWrite, cPages);
1526 if (RT_SUCCESS(vrc))
1527 {
1528 cbActual = pReq->Parms.cb32Write.u.value32;
1529 AssertStmt(cbActual <= cbToWrite, cbActual = cbToWrite);
1530 *pcb = vboxSfOs2WriteFinalize(pSfFsi, offWrite, cbActual);
1531 LogFlow(("FS32_WRITE: returns; cbActual=%#x sfi_positionl=%RI64 [locked]\n", cbActual, pSfFsi->sfi_positionl));
1532 }
1533 else
1534 {
1535 Log(("FS32_WRITE: VbglR0SfHostReqWriteEmbedded(off=%#RU64,cb=%#x) -> %Rrc [locked]\n", offWrite, cbToWrite, vrc));
1536 rc = ERROR_BAD_NET_RESP;
1537 }
1538
1539 KernVMUnlock(&Lock);
1540 }
1541 else
1542 Log(("FS32_WRITE: KernVMLock(,%p,%#x,) failed -> %u\n", pvData, cbToWrite, rc));
1543 VbglR0PhysHeapFree(pReq);
1544 RT_NOREF_PV(fIoFlags);
1545 return rc;
1546}
1547
1548
1549extern "C" APIRET APIENTRY
1550FS32_READFILEATCACHE(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, ULONG fIoFlags, LONGLONG off, ULONG pcb, KernCacheList_t **ppCacheList)
1551{
1552 /*
1553 * Validate input.
1554 */
1555 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1556 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1557 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1558 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1559 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1560 Assert(pFolder->cOpenFiles > 0);
1561 RT_NOREF(pFolder);
1562
1563 /* I think this is used for sendfile(). */
1564
1565 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(fIoFlags); NOREF(off); NOREF(pcb); NOREF(ppCacheList);
1566 return ERROR_NOT_SUPPORTED;
1567}
1568
1569
1570extern "C" APIRET APIENTRY
1571FS32_RETURNFILECACHE(KernCacheList_t *pCacheList)
1572{
1573 NOREF(pCacheList);
1574 return ERROR_NOT_SUPPORTED;
1575}
1576
1577
1578/* oddments */
1579
1580DECLASM(APIRET)
1581FS32_CANCELLOCKREQUESTL(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, struct filelockl *pLockRange)
1582{
1583 /*
1584 * Validate input.
1585 */
1586 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1587 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1588 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1589 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1590 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1591 Assert(pFolder->cOpenFiles > 0);
1592 RT_NOREF(pFolder);
1593
1594 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pLockRange);
1595 return ERROR_NOT_SUPPORTED;
1596}
1597
1598
1599DECLASM(APIRET)
1600FS32_CANCELLOCKREQUEST(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, struct filelock *pLockRange)
1601{
1602 /*
1603 * Validate input.
1604 */
1605 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1606 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1607 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1608 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1609 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1610 Assert(pFolder->cOpenFiles > 0);
1611 RT_NOREF(pFolder);
1612
1613 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pLockRange);
1614 return ERROR_NOT_SUPPORTED;
1615}
1616
1617
1618DECLASM(APIRET)
1619FS32_FILELOCKSL(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, struct filelockl *pUnLockRange,
1620 struct filelockl *pLockRange, ULONG cMsTimeout, ULONG fFlags)
1621{
1622 /*
1623 * Validate input.
1624 */
1625 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1626 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1627 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1628 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1629 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1630 Assert(pFolder->cOpenFiles > 0);
1631 RT_NOREF(pFolder);
1632
1633 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pUnLockRange); NOREF(pLockRange); NOREF(cMsTimeout); NOREF(fFlags);
1634 return ERROR_NOT_SUPPORTED;
1635}
1636
1637
1638DECLASM(APIRET)
1639FS32_FILELOCKS(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, struct filelock *pUnLockRange,
1640 struct filelock *pLockRange, ULONG cMsTimeout, ULONG fFlags)
1641{
1642 /*
1643 * Validate input.
1644 */
1645 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1646 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1647 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1648 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1649 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1650 Assert(pFolder->cOpenFiles > 0);
1651 RT_NOREF(pFolder);
1652
1653 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pUnLockRange); NOREF(pLockRange); NOREF(cMsTimeout); NOREF(fFlags);
1654 return ERROR_NOT_SUPPORTED;
1655}
1656
1657
1658DECLASM(APIRET)
1659FS32_IOCTL(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, USHORT uCategory, USHORT uFunction,
1660 PVOID pvParm, USHORT cbParm, PUSHORT pcbParmIO,
1661 PVOID pvData, USHORT cbData, PUSHORT pcbDataIO)
1662{
1663 /*
1664 * Validate input.
1665 */
1666 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1667 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1668 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1669 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1670 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1671 Assert(pFolder->cOpenFiles > 0);
1672 RT_NOREF(pFolder);
1673
1674 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(uCategory); NOREF(uFunction); NOREF(pvParm); NOREF(cbParm); NOREF(pcbParmIO);
1675 NOREF(pvData); NOREF(cbData); NOREF(pcbDataIO);
1676 return ERROR_NOT_SUPPORTED;
1677}
1678
1679
1680DECLASM(APIRET)
1681FS32_FILEIO(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, PBYTE pbCmdList, USHORT cbCmdList,
1682 PUSHORT poffError, USHORT fIoFlag)
1683{
1684 /*
1685 * Validate input.
1686 */
1687 AssertReturn(pSfFsd->u32Magic == VBOXSFSYFI_MAGIC, ERROR_SYS_INTERNAL);
1688 AssertReturn(pSfFsd->pSelf == pSfFsd, ERROR_SYS_INTERNAL);
1689 PVBOXSFFOLDER pFolder = pSfFsd->pFolder;
1690 AssertReturn(pFolder != NULL, ERROR_SYS_INTERNAL);
1691 Assert(pFolder->u32Magic == VBOXSFFOLDER_MAGIC);
1692 Assert(pFolder->cOpenFiles > 0);
1693 RT_NOREF(pFolder);
1694
1695 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pbCmdList); NOREF(cbCmdList); NOREF(poffError); NOREF(fIoFlag);
1696 return ERROR_NOT_SUPPORTED;
1697}
1698
1699
1700DECLASM(APIRET)
1701FS32_NMPIPE(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, USHORT uOpType, union npoper *pOpRec,
1702 PBYTE pbData, PCSZ pszName)
1703{
1704 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(uOpType); NOREF(pOpRec); NOREF(pbData); NOREF(pszName);
1705 return ERROR_NOT_SUPPORTED;
1706}
1707
1708
1709DECLASM(APIRET)
1710FS32_OPENPAGEFILE(PULONG pfFlags, PULONG pcMaxReq, PCSZ pszName, PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd,
1711 USHORT fOpenMode, USHORT fOpenFlags, USHORT fAttr, ULONG uReserved)
1712{
1713 NOREF(pfFlags); NOREF(pcMaxReq); NOREF(pszName); NOREF(pSfFsi); NOREF(pSfFsd); NOREF(fOpenMode); NOREF(fOpenFlags);
1714 NOREF(fAttr); NOREF(uReserved);
1715 return ERROR_NOT_SUPPORTED;
1716}
1717
1718
1719DECLASM(APIRET)
1720FS32_SETSWAP(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd)
1721{
1722 NOREF(pSfFsi); NOREF(pSfFsd);
1723 return ERROR_NOT_SUPPORTED;
1724}
1725
1726
1727DECLASM(APIRET)
1728FS32_ALLOCATEPAGESPACE(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, ULONG cb, USHORT cbWantContig)
1729{
1730 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(cb); NOREF(cbWantContig);
1731 return ERROR_NOT_SUPPORTED;
1732}
1733
1734
1735DECLASM(APIRET)
1736FS32_DOPAGEIO(PSFFSI pSfFsi, PVBOXSFSYFI pSfFsd, struct PageCmdHeader *pList)
1737{
1738 NOREF(pSfFsi); NOREF(pSfFsd); NOREF(pList);
1739 return ERROR_NOT_SUPPORTED;
1740}
1741
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette