VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/SharedFolders/driver/info.cpp@ 78541

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

winnt/vboxsf: Final VBoxMRxQueryVolumeInfo cleanups. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 103.1 KB
Line 
1/* $Id: info.cpp 78541 2019-05-16 10:26:53Z vboxsync $ */
2/** @file
3 * VirtualBox Windows Guest Shared Folders FSD - Information Querying & Setting Routines.
4 */
5
6/*
7 * Copyright (C) 2012-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include "vbsf.h"
23#include <iprt/asm.h>
24#include <iprt/err.h>
25#include <iprt/mem.h>
26
27extern "C" NTSTATUS NTAPI RxSetEndOfFileInfo(PRX_CONTEXT, PIRP, PFCB, PFOBX);
28
29
30/*********************************************************************************************************************************
31* Defined Constants And Macros *
32*********************************************************************************************************************************/
33/** Macro for copying a SHFLSTRING file name into a FILE_DIRECTORY_INFORMATION structure. */
34#define INIT_FILE_NAME(obj, str) \
35 do { \
36 ULONG cbLength = (str).u16Length; \
37 (obj)->FileNameLength = cbLength; \
38 RtlCopyMemory((obj)->FileName, &(str).String.ucs2[0], cbLength + 2); \
39 } while (0)
40
41
42NTSTATUS VBoxMRxQueryDirectory(IN OUT PRX_CONTEXT RxContext)
43{
44 NTSTATUS Status = STATUS_SUCCESS;
45
46 RxCaptureFobx;
47 RxCaptureFcb;
48
49 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
50 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
51
52 PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
53 PUNICODE_STRING Template = &capFobx->UnicodeQueryTemplate;
54 FILE_INFORMATION_CLASS FileInformationClass = RxContext->Info.FileInformationClass;
55 PCHAR pInfoBuffer = (PCHAR)RxContext->Info.Buffer;
56 LONG cbMaxSize = RxContext->Info.Length;
57 LONG *pLengthRemaining = (LONG *)&RxContext->Info.LengthRemaining;
58
59 LONG cbToCopy;
60 int vrc;
61 uint8_t *pHGCMBuffer;
62 uint32_t index, fSFFlags, cFiles, u32BufSize;
63 LONG cbHGCMBuffer;
64 PSHFLDIRINFO pDirEntry;
65
66 ULONG *pNextOffset = 0;
67 PSHFLSTRING ParsedPath = NULL;
68
69 Log(("VBOXSF: MrxQueryDirectory: FileInformationClass %d, pVBoxFobx %p, hFile %RX64, pInfoBuffer %p\n",
70 FileInformationClass, pVBoxFobx, pVBoxFobx->hFile, pInfoBuffer));
71
72 if (!pVBoxFobx)
73 {
74 Log(("VBOXSF: MrxQueryDirectory: pVBoxFobx is invalid!\n"));
75 return STATUS_INVALID_PARAMETER;
76 }
77
78 if (!DirectoryName)
79 return STATUS_INVALID_PARAMETER;
80
81 if (DirectoryName->Length == 0)
82 Log(("VBOXSF: MrxQueryDirectory: DirectoryName = \\ (null string)\n"));
83 else
84 Log(("VBOXSF: MrxQueryDirectory: DirectoryName = %.*ls\n",
85 DirectoryName->Length / sizeof(WCHAR), DirectoryName->Buffer));
86
87 if (!Template)
88 return STATUS_INVALID_PARAMETER;
89
90 if (Template->Length == 0)
91 Log(("VBOXSF: MrxQueryDirectory: Template = \\ (null string)\n"));
92 else
93 Log(("VBOXSF: MrxQueryDirectory: Template = %.*ls\n",
94 Template->Length / sizeof(WCHAR), Template->Buffer));
95
96 cbHGCMBuffer = RT_MAX(cbMaxSize, PAGE_SIZE);
97
98 Log(("VBOXSF: MrxQueryDirectory: Allocating cbHGCMBuffer = %d\n",
99 cbHGCMBuffer));
100
101 pHGCMBuffer = (uint8_t *)vbsfNtAllocNonPagedMem(cbHGCMBuffer);
102 if (!pHGCMBuffer)
103 {
104 AssertFailed();
105 return STATUS_INSUFFICIENT_RESOURCES;
106 }
107
108 /* Assume start from the beginning. */
109 index = 0;
110 if (RxContext->QueryDirectory.IndexSpecified == TRUE)
111 {
112 Log(("VBOXSF: MrxQueryDirectory: Index specified %d\n",
113 index));
114 index = RxContext->QueryDirectory.FileIndex;
115 }
116
117 fSFFlags = SHFL_LIST_NONE;
118 if (RxContext->QueryDirectory.ReturnSingleEntry == TRUE)
119 {
120 Log(("VBOXSF: MrxQueryDirectory: Query single entry\n"));
121 fSFFlags |= SHFL_LIST_RETURN_ONE;
122 }
123 if ( RxContext->QueryDirectory.RestartScan == TRUE
124 && RxContext->QueryDirectory.InitialQuery == FALSE)
125 {
126 Log(("VBOXSF: MrxQueryDirectory: Restart scan\n"));
127 fSFFlags |= SHFL_LIST_RESTART;
128 }
129
130 if (Template->Length)
131 {
132 ULONG ParsedPathSize, cch;
133
134 /* Calculate size required for parsed path: dir + \ + template + 0. */
135 ParsedPathSize = SHFLSTRING_HEADER_SIZE + Template->Length + sizeof(WCHAR);
136 if (DirectoryName->Length)
137 ParsedPathSize += DirectoryName->Length + sizeof(WCHAR);
138 Log(("VBOXSF: MrxQueryDirectory: ParsedPathSize = %d\n", ParsedPathSize));
139
140 ParsedPath = (PSHFLSTRING)vbsfNtAllocNonPagedMem(ParsedPathSize);
141 if (!ParsedPath)
142 {
143 Status = STATUS_INSUFFICIENT_RESOURCES;
144 goto end;
145 }
146
147 if (!ShflStringInitBuffer(ParsedPath, ParsedPathSize))
148 {
149 Status = STATUS_INSUFFICIENT_RESOURCES;
150 goto end;
151 }
152
153 cch = 0;
154 if (DirectoryName->Length)
155 {
156 /* Copy directory name into ParsedPath. */
157 RtlCopyMemory(ParsedPath->String.ucs2, DirectoryName->Buffer, DirectoryName->Length);
158 cch += DirectoryName->Length / sizeof(WCHAR);
159
160 /* Add terminating backslash. */
161 ParsedPath->String.ucs2[cch] = L'\\';
162 cch++;
163 }
164
165 RtlCopyMemory (&ParsedPath->String.ucs2[cch], Template->Buffer, Template->Length);
166 cch += Template->Length / sizeof(WCHAR);
167
168 /* Add terminating nul. */
169 ParsedPath->String.ucs2[cch] = 0;
170
171 /* cch is the number of chars without trailing nul. */
172 ParsedPath->u16Length = (uint16_t)(cch * sizeof(WCHAR));
173
174 AssertMsg(ParsedPath->u16Length + sizeof(WCHAR) == ParsedPath->u16Size,
175 ("u16Length %d, u16Size %d\n", ParsedPath->u16Length, ParsedPath->u16Size));
176
177 Log(("VBOXSF: MrxQueryDirectory: ParsedPath = %.*ls\n",
178 ParsedPath->u16Length / sizeof(WCHAR), ParsedPath->String.ucs2));
179 }
180
181 cFiles = 0;
182
183 /* VbglR0SfDirInfo requires a pointer to uint32_t. */
184 u32BufSize = cbHGCMBuffer;
185
186 Log(("VBOXSF: MrxQueryDirectory: CallDirInfo: File = 0x%08x, Flags = 0x%08x, Index = %d, u32BufSize = %d\n",
187 pVBoxFobx->hFile, fSFFlags, index, u32BufSize));
188 vrc = VbglR0SfDirInfo(&g_SfClient, &pNetRootExtension->map, pVBoxFobx->hFile,
189 ParsedPath, fSFFlags, index, &u32BufSize, (PSHFLDIRINFO)pHGCMBuffer, &cFiles);
190 Log(("VBOXSF: MrxQueryDirectory: u32BufSize after CallDirInfo = %d, rc = %Rrc\n",
191 u32BufSize, vrc));
192
193 switch (vrc)
194 {
195 case VINF_SUCCESS:
196 /* Nothing to do here. */
197 break;
198
199 case VERR_NO_TRANSLATION:
200 Log(("VBOXSF: MrxQueryDirectory: Host could not translate entry!\n"));
201 break;
202
203 case VERR_NO_MORE_FILES:
204 if (cFiles <= 0) /* VERR_NO_MORE_FILES appears at the first lookup when just returning the current dir ".".
205 * So we also have to check for the cFiles counter. */
206 {
207 /* Not an error, but we have to handle the return value. */
208 Log(("VBOXSF: MrxQueryDirectory: Host reported no more files!\n"));
209
210 if (RxContext->QueryDirectory.InitialQuery)
211 {
212 /* First call. MSDN on FindFirstFile: "If the function fails because no matching files
213 * can be found, the GetLastError function returns ERROR_FILE_NOT_FOUND."
214 * So map this rc to file not found.
215 */
216 Status = STATUS_NO_SUCH_FILE;
217 }
218 else
219 {
220 /* Search continued. */
221 Status = STATUS_NO_MORE_FILES;
222 }
223 }
224 break;
225
226 case VERR_FILE_NOT_FOUND:
227 Status = STATUS_NO_SUCH_FILE;
228 Log(("VBOXSF: MrxQueryDirectory: no such file!\n"));
229 break;
230
231 default:
232 Status = vbsfNtVBoxStatusToNt(vrc);
233 Log(("VBOXSF: MrxQueryDirectory: Error %Rrc from CallDirInfo (cFiles=%d)!\n",
234 vrc, cFiles));
235 break;
236 }
237
238 if (Status != STATUS_SUCCESS)
239 goto end;
240
241 /* Verify that the returned buffer length is not greater than the original one. */
242 if (u32BufSize > (uint32_t)cbHGCMBuffer)
243 {
244 Log(("VBOXSF: MrxQueryDirectory: returned buffer size (%u) is invalid!!!\n",
245 u32BufSize));
246 Status = STATUS_INVALID_NETWORK_RESPONSE;
247 goto end;
248 }
249
250 /* How many bytes remain in the buffer. */
251 cbHGCMBuffer = u32BufSize;
252
253 pDirEntry = (PSHFLDIRINFO)pHGCMBuffer;
254 Status = STATUS_SUCCESS;
255
256 Log(("VBOXSF: MrxQueryDirectory: cFiles=%d, Length=%d\n",
257 cFiles, cbHGCMBuffer));
258
259 while ((*pLengthRemaining) && (cFiles > 0) && (pDirEntry != NULL))
260 {
261 int cbEntry = RT_UOFFSETOF(SHFLDIRINFO, name.String) + pDirEntry->name.u16Size;
262
263 if (cbEntry > cbHGCMBuffer)
264 {
265 Log(("VBOXSF: MrxQueryDirectory: Entry size (%d) exceeds the buffer size (%d)!!!\n",
266 cbEntry, cbHGCMBuffer));
267 Status = STATUS_INVALID_NETWORK_RESPONSE;
268 goto end;
269 }
270
271 switch (FileInformationClass)
272 {
273 case FileDirectoryInformation:
274 {
275 PFILE_DIRECTORY_INFORMATION pInfo = (PFILE_DIRECTORY_INFORMATION)pInfoBuffer;
276 Log(("VBOXSF: MrxQueryDirectory: FileDirectoryInformation\n"));
277
278 cbToCopy = sizeof(FILE_DIRECTORY_INFORMATION);
279 /* Struct already contains one char for null terminator. */
280 cbToCopy += pDirEntry->name.u16Size;
281
282 if (*pLengthRemaining >= cbToCopy)
283 {
284 RtlZeroMemory(pInfo, cbToCopy);
285
286 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
287 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
288 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
289 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
290 pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
291 pInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
292 pInfo->FileIndex = index;
293 pInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
294
295 INIT_FILE_NAME(pInfo, pDirEntry->name);
296
297 /* Align to 8 byte boundary */
298 cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
299 pInfo->NextEntryOffset = cbToCopy;
300 pNextOffset = &pInfo->NextEntryOffset;
301 }
302 else
303 {
304 pInfo->NextEntryOffset = 0; /* last item */
305 Status = STATUS_BUFFER_OVERFLOW;
306 }
307 break;
308 }
309
310 case FileFullDirectoryInformation:
311 {
312 PFILE_FULL_DIR_INFORMATION pInfo = (PFILE_FULL_DIR_INFORMATION)pInfoBuffer;
313 Log(("VBOXSF: MrxQueryDirectory: FileFullDirectoryInformation\n"));
314
315 cbToCopy = sizeof(FILE_FULL_DIR_INFORMATION);
316 /* Struct already contains one char for null terminator. */
317 cbToCopy += pDirEntry->name.u16Size;
318
319 if (*pLengthRemaining >= cbToCopy)
320 {
321 RtlZeroMemory(pInfo, cbToCopy);
322
323 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
324 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
325 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
326 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
327 pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
328 pInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
329 pInfo->EaSize = 0;
330 pInfo->FileIndex = index;
331 pInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
332
333 INIT_FILE_NAME(pInfo, pDirEntry->name);
334
335 /* Align to 8 byte boundary */
336 cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
337 pInfo->NextEntryOffset = cbToCopy;
338 pNextOffset = &pInfo->NextEntryOffset;
339 }
340 else
341 {
342 pInfo->NextEntryOffset = 0; /* last item */
343 Status = STATUS_BUFFER_OVERFLOW;
344 }
345 break;
346 }
347
348 case FileBothDirectoryInformation:
349 {
350 PFILE_BOTH_DIR_INFORMATION pInfo = (PFILE_BOTH_DIR_INFORMATION)pInfoBuffer;
351 Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation\n"));
352
353 cbToCopy = sizeof(FILE_BOTH_DIR_INFORMATION);
354 /* struct already contains one char for null terminator */
355 cbToCopy += pDirEntry->name.u16Size;
356
357 if (*pLengthRemaining >= cbToCopy)
358 {
359 RtlZeroMemory(pInfo, cbToCopy);
360
361 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
362 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
363 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
364 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
365 pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
366 pInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
367 pInfo->EaSize = 0;
368 pInfo->ShortNameLength = 0; /** @todo ? */
369 pInfo->FileIndex = index;
370 pInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
371
372 INIT_FILE_NAME(pInfo, pDirEntry->name);
373
374 Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation cbAlloc = %x cbObject = %x\n",
375 pDirEntry->Info.cbAllocated, pDirEntry->Info.cbObject));
376 Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation cbToCopy = %d, name size=%d name len=%d\n",
377 cbToCopy, pDirEntry->name.u16Size, pDirEntry->name.u16Length));
378 Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation File name %.*ls (DirInfo)\n",
379 pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
380 Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation File name %.*ls (DirEntry)\n",
381 pDirEntry->name.u16Size / sizeof(WCHAR), pDirEntry->name.String.ucs2));
382
383 /* Align to 8 byte boundary. */
384 cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
385 pInfo->NextEntryOffset = cbToCopy;
386 pNextOffset = &pInfo->NextEntryOffset;
387 }
388 else
389 {
390 pInfo->NextEntryOffset = 0; /* Last item. */
391 Status = STATUS_BUFFER_OVERFLOW;
392 }
393 break;
394 }
395
396 case FileIdBothDirectoryInformation:
397 {
398 PFILE_ID_BOTH_DIR_INFORMATION pInfo = (PFILE_ID_BOTH_DIR_INFORMATION)pInfoBuffer;
399 Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation\n"));
400
401 cbToCopy = sizeof(FILE_ID_BOTH_DIR_INFORMATION);
402 /* struct already contains one char for null terminator */
403 cbToCopy += pDirEntry->name.u16Size;
404
405 if (*pLengthRemaining >= cbToCopy)
406 {
407 RtlZeroMemory(pInfo, cbToCopy);
408
409 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
410 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
411 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
412 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
413 pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
414 pInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
415 pInfo->EaSize = 0;
416 pInfo->ShortNameLength = 0; /** @todo ? */
417 pInfo->EaSize = 0;
418 pInfo->FileId.QuadPart = 0;
419 pInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
420
421 INIT_FILE_NAME(pInfo, pDirEntry->name);
422
423 Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation cbAlloc = 0x%RX64 cbObject = 0x%RX64\n",
424 pDirEntry->Info.cbAllocated, pDirEntry->Info.cbObject));
425 Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation cbToCopy = %d, name size=%d name len=%d\n",
426 cbToCopy, pDirEntry->name.u16Size, pDirEntry->name.u16Length));
427 Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation File name %.*ls (DirInfo)\n",
428 pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
429 Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation File name %.*ls (DirEntry)\n",
430 pDirEntry->name.u16Size / sizeof(WCHAR), pDirEntry->name.String.ucs2));
431
432 /* Align to 8 byte boundary. */
433 cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
434 pInfo->NextEntryOffset = cbToCopy;
435 pNextOffset = &pInfo->NextEntryOffset;
436 }
437 else
438 {
439 pInfo->NextEntryOffset = 0; /* Last item. */
440 Status = STATUS_BUFFER_OVERFLOW;
441 }
442 break;
443 }
444
445 case FileNamesInformation:
446 {
447 PFILE_NAMES_INFORMATION pInfo = (PFILE_NAMES_INFORMATION)pInfoBuffer;
448 Log(("VBOXSF: MrxQueryDirectory: FileNamesInformation\n"));
449
450 cbToCopy = sizeof(FILE_NAMES_INFORMATION);
451 /* Struct already contains one char for null terminator. */
452 cbToCopy += pDirEntry->name.u16Size;
453
454 if (*pLengthRemaining >= cbToCopy)
455 {
456 RtlZeroMemory(pInfo, cbToCopy);
457
458 pInfo->FileIndex = index;
459
460 INIT_FILE_NAME(pInfo, pDirEntry->name);
461
462 Log(("VBOXSF: MrxQueryDirectory: FileNamesInformation: File name [%.*ls]\n",
463 pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
464
465 /* Align to 8 byte boundary. */
466 cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
467 pInfo->NextEntryOffset = cbToCopy;
468 pNextOffset = &pInfo->NextEntryOffset;
469 }
470 else
471 {
472 pInfo->NextEntryOffset = 0; /* Last item. */
473 Status = STATUS_BUFFER_OVERFLOW;
474 }
475 break;
476 }
477
478 default:
479 Log(("VBOXSF: MrxQueryDirectory: Not supported FileInformationClass %d!\n",
480 FileInformationClass));
481 Status = STATUS_INVALID_PARAMETER;
482 goto end;
483 }
484
485 cbHGCMBuffer -= cbEntry;
486 pDirEntry = (PSHFLDIRINFO)((uintptr_t)pDirEntry + cbEntry);
487
488 Log(("VBOXSF: MrxQueryDirectory: %d bytes left in HGCM buffer\n",
489 cbHGCMBuffer));
490
491 if (*pLengthRemaining >= cbToCopy)
492 {
493 pInfoBuffer += cbToCopy;
494 *pLengthRemaining -= cbToCopy;
495 }
496 else
497 break;
498
499 if (RxContext->QueryDirectory.ReturnSingleEntry)
500 break;
501
502 /* More left? */
503 if (cbHGCMBuffer <= 0)
504 break;
505
506 index++; /* File Index. */
507
508 cFiles--;
509 }
510
511 if (pNextOffset)
512 *pNextOffset = 0; /* Last pInfo->NextEntryOffset should be set to zero! */
513
514end:
515 if (pHGCMBuffer)
516 vbsfNtFreeNonPagedMem(pHGCMBuffer);
517
518 if (ParsedPath)
519 vbsfNtFreeNonPagedMem(ParsedPath);
520
521 Log(("VBOXSF: MrxQueryDirectory: Returned 0x%08X\n",
522 Status));
523 return Status;
524}
525
526
527/*********************************************************************************************************************************
528* NtQueryVolumeInformationFile *
529*********************************************************************************************************************************/
530
531/**
532 * Updates VBSFNTFCBEXT::VolInfo.
533 */
534static NTSTATUS vbsfNtUpdateFcbVolInfo(PVBSFNTFCBEXT pVBoxFcbX, PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
535 PMRX_VBOX_FOBX pVBoxFobx)
536{
537 NTSTATUS rcNt;
538 VBOXSFVOLINFOREQ *pReq = (VBOXSFVOLINFOREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
539 if (pReq)
540 {
541 int vrc = VbglR0SfHostReqQueryVolInfo(pNetRootExtension->map.root, pReq, pVBoxFobx->hFile);
542 if (RT_SUCCESS(vrc))
543 {
544 /* Make the units compatible with NT before assigning. */
545 if (pReq->VolInfo.ulBytesPerSector != 0)
546 {
547 if (pReq->VolInfo.ulBytesPerAllocationUnit > pReq->VolInfo.ulBytesPerSector)
548 {
549 uint32_t cSectorsPerUnit = pReq->VolInfo.ulBytesPerAllocationUnit / pReq->VolInfo.ulBytesPerSector;
550 pReq->VolInfo.ulBytesPerAllocationUnit = pReq->VolInfo.ulBytesPerSector * cSectorsPerUnit;
551 }
552 else if (pReq->VolInfo.ulBytesPerAllocationUnit < pReq->VolInfo.ulBytesPerSector)
553 pReq->VolInfo.ulBytesPerAllocationUnit = pReq->VolInfo.ulBytesPerSector;
554 }
555 else if (pReq->VolInfo.ulBytesPerAllocationUnit == 0)
556 pReq->VolInfo.ulBytesPerSector = pReq->VolInfo.ulBytesPerAllocationUnit = 512;
557 else
558 pReq->VolInfo.ulBytesPerSector = pReq->VolInfo.ulBytesPerAllocationUnit;
559
560 /* Copy the info assigning: */
561 ASMCompilerBarrier();
562 pVBoxFcbX->VolInfo.ullTotalAllocationBytes = pReq->VolInfo.ullTotalAllocationBytes;
563 pVBoxFcbX->VolInfo.ullAvailableAllocationBytes = pReq->VolInfo.ullAvailableAllocationBytes;
564 pVBoxFcbX->VolInfo.ulBytesPerAllocationUnit = pReq->VolInfo.ulBytesPerAllocationUnit;
565 pVBoxFcbX->VolInfo.ulBytesPerSector = pReq->VolInfo.ulBytesPerSector;
566 pVBoxFcbX->VolInfo.ulSerial = pReq->VolInfo.ulSerial;
567 pVBoxFcbX->VolInfo.fsProperties.cbMaxComponent = pReq->VolInfo.fsProperties.cbMaxComponent;
568 pVBoxFcbX->VolInfo.fsProperties.fRemote = pReq->VolInfo.fsProperties.fRemote;
569 pVBoxFcbX->VolInfo.fsProperties.fCaseSensitive = pReq->VolInfo.fsProperties.fCaseSensitive;
570 pVBoxFcbX->VolInfo.fsProperties.fReadOnly = pReq->VolInfo.fsProperties.fReadOnly;
571 /** @todo Use SHFL_FN_QUERY_MAP_INFO to get the correct read-only status of
572 * the share. */
573 pVBoxFcbX->VolInfo.fsProperties.fSupportsUnicode = pReq->VolInfo.fsProperties.fSupportsUnicode;
574 pVBoxFcbX->VolInfo.fsProperties.fCompressed = pReq->VolInfo.fsProperties.fCompressed;
575 pVBoxFcbX->VolInfo.fsProperties.fFileCompression = pReq->VolInfo.fsProperties.fFileCompression;
576 ASMWriteFence();
577 pVBoxFcbX->nsVolInfoUpToDate = RTTimeSystemNanoTS();
578 ASMWriteFence();
579
580 rcNt = STATUS_SUCCESS;
581 }
582 else
583 rcNt = vbsfNtVBoxStatusToNt(vrc);
584 VbglR0PhysHeapFree(pReq);
585 }
586 else
587 rcNt = STATUS_INSUFFICIENT_RESOURCES;
588 return rcNt;
589}
590
591/**
592 * Handles NtQueryVolumeInformationFile / FileFsVolumeInformation
593 */
594static NTSTATUS vbsfNtQueryFsVolumeInfo(IN OUT PRX_CONTEXT pRxContext,
595 PFILE_FS_VOLUME_INFORMATION pInfo,
596 ULONG cbInfo,
597 PMRX_NET_ROOT pNetRoot,
598 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
599 PMRX_VBOX_FOBX pVBoxFobx,
600 PVBSFNTFCBEXT pVBoxFcbX)
601{
602 /*
603 * NtQueryVolumeInformationFile should've checked the minimum buffer size
604 * but just in case.
605 */
606 AssertReturnStmt(cbInfo >= RT_UOFFSETOF(FILE_FS_VOLUME_INFORMATION, VolumeLabel),
607 pRxContext->InformationToReturn = RT_UOFFSETOF(FILE_FS_VOLUME_INFORMATION, VolumeLabel),
608 STATUS_BUFFER_TOO_SMALL);
609
610 /*
611 * Get up-to-date serial number.
612 *
613 * If we have a unixy host, we'll get additional unix attributes and the
614 * serial number is the same as INodeIdDevice.
615 *
616 * Note! Because it's possible that the host has mount points within the
617 * shared folder as well as symbolic links pointing out files or
618 * directories outside the tree, we cannot just cache the serial
619 * number in the net root extension data and skip querying it here.
620 *
621 * OTOH, only we don't report inode info from the host, so the only
622 * thing the serial number can be used for is to cache/whatever
623 * volume space information. So, we should probably provide a
624 * shortcut here via mount option, registry and guest properties.
625 */
626 /** @todo Make See OTOH above wrt. one serial per net root. */
627 uint64_t nsNow = RTTimeSystemNanoTS();
628 if ( pVBoxFobx->Info.Attr.enmAdditional == SHFLFSOBJATTRADD_UNIX
629 && pVBoxFobx->Info.Attr.u.Unix.INodeIdDevice != 0
630 && pVBoxFobx->nsUpToDate - nsNow < RT_NS_100US /** @todo implement proper TTL */)
631 pInfo->VolumeSerialNumber = pVBoxFobx->Info.Attr.u.Unix.INodeIdDevice;
632 else if (pVBoxFcbX->nsVolInfoUpToDate - nsNow < RT_NS_100MS /** @todo implement proper volume info TTL */ )
633 pInfo->VolumeSerialNumber = pVBoxFcbX->VolInfo.ulSerial;
634 else
635 {
636 /* Must fetch the info. */
637 NTSTATUS Status = vbsfNtUpdateFcbVolInfo(pVBoxFcbX, pNetRootExtension, pVBoxFobx);
638 if (NT_SUCCESS(Status))
639 pInfo->VolumeSerialNumber = pVBoxFcbX->VolInfo.ulSerial;
640 else
641 return Status;
642 }
643 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsVolumeInformation: VolumeSerialNumber=%#010RX32\n", pInfo->VolumeSerialNumber));
644
645 /*
646 * Fill in the static info.
647 */
648 pInfo->VolumeCreationTime.QuadPart = 0;
649 pInfo->SupportsObjects = FALSE;
650
651 /*
652 * The volume label.
653 *
654 * We may get queries with insufficient buffer space for the whole (or any)
655 * volume label. In those cases we're to return STATUS_BUFFER_OVERFLOW,
656 * return the returned number of bytes in Ios.Information and set the
657 * VolumeLabelLength to the actual length (rather than the returned). At
658 * least this is was FAT and NTFS does (however, it is not what the NulMrx
659 * sample from the 6.1.6001.18002 does).
660 *
661 * Note! VolumeLabelLength is a byte count.
662 * Note! NTFS does not include a terminator, so neither do we.
663 */
664 uint32_t const cbShareName = pNetRoot->pNetRootName->Length
665 - pNetRoot->pSrvCall->pSrvCallName->Length
666 - sizeof(WCHAR) /* Remove the leading backslash. */;
667 uint32_t const cbVolLabel = VBOX_VOLNAME_PREFIX_SIZE + cbShareName;
668 pInfo->VolumeLabelLength = cbVolLabel;
669
670 WCHAR const *pwcShareName = &pNetRoot->pNetRootName->Buffer[pNetRoot->pSrvCall->pSrvCallName->Length / sizeof(WCHAR) + 1];
671 uint32_t cbCopied = RT_UOFFSETOF(FILE_FS_VOLUME_INFORMATION, VolumeLabel);
672 NTSTATUS Status;
673 if (cbInfo >= cbCopied + cbVolLabel)
674 {
675 memcpy(pInfo->VolumeLabel, VBOX_VOLNAME_PREFIX, VBOX_VOLNAME_PREFIX_SIZE);
676 memcpy(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)], pwcShareName, cbShareName);
677 cbCopied += cbVolLabel;
678 Status = STATUS_SUCCESS;
679 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsVolumeInformation: full result (%#x)\n", cbCopied));
680 }
681 else
682 {
683 if (cbInfo > cbCopied)
684 {
685 uint32_t cbLeft = cbInfo - cbCopied;
686 memcpy(pInfo->VolumeLabel, VBOX_VOLNAME_PREFIX, RT_MIN(cbLeft, VBOX_VOLNAME_PREFIX_SIZE));
687 if (cbLeft > VBOX_VOLNAME_PREFIX_SIZE)
688 {
689 cbLeft -= VBOX_VOLNAME_PREFIX_SIZE;
690 memcpy(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)], pwcShareName, RT_MIN(cbLeft, cbShareName));
691 }
692 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsVolumeInformation: partial result (%#x, needed %#x)\n",
693 cbCopied, cbCopied + cbVolLabel));
694 cbCopied = cbInfo;
695 }
696 else
697 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsVolumeInformation: partial result no label (%#x, needed %#x)\n",
698 cbCopied, cbCopied + cbVolLabel));
699 Status = STATUS_BUFFER_OVERFLOW;
700 }
701
702 /*
703 * Update the return length in the context.
704 */
705 pRxContext->Info.LengthRemaining = cbInfo - cbCopied;
706 pRxContext->InformationToReturn = cbCopied;
707
708 return Status;
709}
710
711/**
712 * Handles NtQueryVolumeInformationFile / FileFsSizeInformation
713 *
714 * @note Almost identical to vbsfNtQueryFsFullSizeInfo.
715 */
716static NTSTATUS vbsfNtQueryFsSizeInfo(IN OUT PRX_CONTEXT pRxContext,
717 PFILE_FS_SIZE_INFORMATION pInfo,
718 ULONG cbInfo,
719 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
720 PMRX_VBOX_FOBX pVBoxFobx,
721 PVBSFNTFCBEXT pVBoxFcbX)
722{
723 /*
724 * NtQueryVolumeInformationFile should've checked the buffer size but just in case.
725 */
726 AssertReturnStmt(cbInfo >= sizeof(*pInfo), pRxContext->InformationToReturn = sizeof(*pInfo), STATUS_BUFFER_TOO_SMALL);
727
728 /*
729 * Get up-to-date information.
730 * For the time being we always re-query this information from the host.
731 */
732 /** @todo don't requery this if it happens with XXXX ns of a _different_ info
733 * request to the same handle. */
734 {
735 /* Must fetch the info. */
736 NTSTATUS Status = vbsfNtUpdateFcbVolInfo(pVBoxFcbX, pNetRootExtension, pVBoxFobx);
737 if (NT_SUCCESS(Status))
738 { /* likely */ }
739 else
740 return Status;
741 }
742
743 /* Make a copy of the info for paranoid reasons: */
744 SHFLVOLINFO VolInfoCopy;
745 memcpy(&VolInfoCopy, (void *)&pVBoxFcbX->VolInfo, sizeof(VolInfoCopy));
746 ASMCompilerBarrier();
747
748 /*
749 * Produce the requested data.
750 */
751 pInfo->BytesPerSector = RT_MIN(VolInfoCopy.ulBytesPerSector, 1);
752 pInfo->SectorsPerAllocationUnit = VolInfoCopy.ulBytesPerAllocationUnit / pInfo->BytesPerSector;
753 AssertReturn(pInfo->SectorsPerAllocationUnit > 0, STATUS_INTERNAL_ERROR);
754 pInfo->TotalAllocationUnits.QuadPart = pVBoxFcbX->VolInfo.ullTotalAllocationBytes
755 / VolInfoCopy.ulBytesPerAllocationUnit;
756 pInfo->AvailableAllocationUnits.QuadPart = pVBoxFcbX->VolInfo.ullAvailableAllocationBytes
757 / VolInfoCopy.ulBytesPerAllocationUnit;
758
759 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsSizeInformation: BytesPerSector = %#010RX32\n",
760 pInfo->BytesPerSector));
761 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsSizeInformation: SectorsPerAllocationUnit = %#010RX32\n",
762 pInfo->SectorsPerAllocationUnit));
763 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsSizeInformation: TotalAllocationUnits = %#018RX32\n",
764 pInfo->TotalAllocationUnits.QuadPart));
765 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsSizeInformation: AvailableAllocationUnits = %#018RX32\n",
766 pInfo->AvailableAllocationUnits.QuadPart));
767
768 /*
769 * Update the return length in the context.
770 */
771 pRxContext->Info.LengthRemaining = cbInfo - sizeof(*pInfo);
772 pRxContext->InformationToReturn = sizeof(*pInfo);
773 return STATUS_SUCCESS;
774}
775
776/**
777 * Handles NtQueryVolumeInformationFile / FileFsFullSizeInformation
778 *
779 * @note Almost identical to vbsfNtQueryFsSizeInfo.
780 */
781static NTSTATUS vbsfNtQueryFsFullSizeInfo(IN OUT PRX_CONTEXT pRxContext,
782 PFILE_FS_FULL_SIZE_INFORMATION pInfo,
783 ULONG cbInfo,
784 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
785 PMRX_VBOX_FOBX pVBoxFobx,
786 PVBSFNTFCBEXT pVBoxFcbX)
787{
788 /*
789 * NtQueryVolumeInformationFile should've checked the buffer size but just in case.
790 */
791 AssertReturnStmt(cbInfo >= sizeof(*pInfo), pRxContext->InformationToReturn = sizeof(*pInfo), STATUS_BUFFER_TOO_SMALL);
792
793 /*
794 * Get up-to-date information.
795 * For the time being we always re-query this information from the host.
796 */
797 /** @todo don't requery this if it happens with XXXX ns of a _different_ info
798 * request to the same handle. */
799 {
800 /* Must fetch the info. */
801 NTSTATUS Status = vbsfNtUpdateFcbVolInfo(pVBoxFcbX, pNetRootExtension, pVBoxFobx);
802 if (NT_SUCCESS(Status))
803 { /* likely */ }
804 else
805 return Status;
806 }
807
808 /* Make a copy of the info for paranoid reasons: */
809 SHFLVOLINFO VolInfoCopy;
810 memcpy(&VolInfoCopy, (void *)&pVBoxFcbX->VolInfo, sizeof(VolInfoCopy));
811 ASMCompilerBarrier();
812
813 /*
814 * Produce the requested data.
815 */
816 pInfo->BytesPerSector = RT_MIN(VolInfoCopy.ulBytesPerSector, 1);
817 pInfo->SectorsPerAllocationUnit = VolInfoCopy.ulBytesPerAllocationUnit / pInfo->BytesPerSector;
818 AssertReturn(pInfo->SectorsPerAllocationUnit > 0, STATUS_INTERNAL_ERROR);
819 pInfo->TotalAllocationUnits.QuadPart = pVBoxFcbX->VolInfo.ullTotalAllocationBytes
820 / VolInfoCopy.ulBytesPerAllocationUnit;
821 pInfo->ActualAvailableAllocationUnits.QuadPart = pVBoxFcbX->VolInfo.ullAvailableAllocationBytes
822 / VolInfoCopy.ulBytesPerAllocationUnit;
823 pInfo->CallerAvailableAllocationUnits.QuadPart = pInfo->ActualAvailableAllocationUnits.QuadPart;
824
825 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsFullSizeInformation: BytesPerSector = %#010RX32\n",
826 pInfo->BytesPerSector));
827 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsFullSizeInformation: SectorsPerAllocationUnit = %#010RX32\n",
828 pInfo->SectorsPerAllocationUnit));
829 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsFullSizeInformation: TotalAllocationUnits = %#018RX32\n",
830 pInfo->TotalAllocationUnits.QuadPart));
831 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsFullSizeInformation: ActualAvailableAllocationUnits = %#018RX32\n",
832 pInfo->ActualAvailableAllocationUnits.QuadPart));
833 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsFullSizeInformation: CallerAvailableAllocationUnits = %#018RX32\n",
834 pInfo->CallerAvailableAllocationUnits.QuadPart));
835
836 /*
837 * Update the return length in the context.
838 */
839 pRxContext->Info.LengthRemaining = cbInfo - sizeof(*pInfo);
840 pRxContext->InformationToReturn = sizeof(*pInfo);
841 return STATUS_SUCCESS;
842}
843
844/**
845 * Handles NtQueryVolumeInformationFile / FileFsDeviceInformation
846 */
847static NTSTATUS vbsfNtQueryFsDeviceInfo(IN OUT PRX_CONTEXT pRxContext,
848 PFILE_FS_DEVICE_INFORMATION pInfo,
849 ULONG cbInfo,
850 PMRX_NET_ROOT pNetRoot)
851{
852 /*
853 * NtQueryVolumeInformationFile should've checked the buffer size but just in case.
854 */
855 AssertReturnStmt(cbInfo >= sizeof(*pInfo), pRxContext->InformationToReturn = sizeof(*pInfo), STATUS_BUFFER_TOO_SMALL);
856
857 /*
858 * Produce the requested data.
859 */
860 pInfo->DeviceType = pNetRoot->DeviceType;
861 pInfo->Characteristics = FILE_REMOTE_DEVICE;
862
863 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsFullSizeInformation: DeviceType = %#x\n", pInfo->DeviceType));
864 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsFullSizeInformation: Characteristics = %#x (FILE_REMOTE_DEVICE)\n", FILE_REMOTE_DEVICE));
865
866 /*
867 * Update the return length in the context.
868 */
869 pRxContext->Info.LengthRemaining = cbInfo - sizeof(*pInfo);
870 pRxContext->InformationToReturn = sizeof(*pInfo);
871 return STATUS_SUCCESS;
872}
873
874/**
875 * Handles NtQueryVolumeInformationFile / FileFsDeviceInformation
876 */
877static NTSTATUS vbsfNtQueryFsAttributeInfo(IN OUT PRX_CONTEXT pRxContext,
878 PFILE_FS_ATTRIBUTE_INFORMATION pInfo,
879 ULONG cbInfo,
880 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
881 PMRX_VBOX_FOBX pVBoxFobx,
882 PVBSFNTFCBEXT pVBoxFcbX)
883{
884 static WCHAR const s_wszFsName[] = MRX_VBOX_FILESYS_NAME_U;
885 static ULONG const s_cbFsName = sizeof(s_wszFsName) - sizeof(s_wszFsName[0]);
886 ULONG const cbNeeded = RT_UOFFSETOF(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName) + s_cbFsName;
887
888 /*
889 * NtQueryVolumeInformationFile should've checked the buffer size but just in case.
890 */
891 AssertReturnStmt(cbInfo >= RT_UOFFSETOF(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName),
892 pRxContext->InformationToReturn = cbNeeded,
893 STATUS_BUFFER_TOO_SMALL);
894
895 /*
896 * Get up-to-date information about filename length and such.
897 */
898 if (pVBoxFcbX->nsVolInfoUpToDate - RTTimeSystemNanoTS() < RT_NS_100MS /** @todo implement proper volume info TTL */ )
899 {
900 /* Must fetch the info. */
901 NTSTATUS Status = vbsfNtUpdateFcbVolInfo(pVBoxFcbX, pNetRootExtension, pVBoxFobx);
902 if (NT_SUCCESS(Status))
903 { /* likely */ }
904 else
905 return Status;
906 }
907
908 /*
909 * Produce the requested data.
910 *
911 * Note! The MaximumComponentNameLength is documented (1) to be in bytes, but
912 * NTFS and FAT32 both return 255, indicating that it is really a UTF-16 char count.
913 *
914 * Note! Both NTFS and FAT32 seems to be setting Ios.Information and FileSystemNameLength
915 * the number of bytes returned in the STATUS_BUFFER_OVERFLOW case, making it
916 * impossible to guess the length from the returned data. RDR2 forwards information
917 * from the server, and samba returns a fixed FileSystemNameLength.
918 *
919 * (1) https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/ns-ntifs-_file_fs_attribute_information
920 */
921 pInfo->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES;
922 /** @todo Implement FILE_RETURNS_CLEANUP_RESULT_INFO. */
923 if (pVBoxFcbX->VolInfo.fsProperties.fSupportsUnicode)
924 pInfo->FileSystemAttributes |= FILE_UNICODE_ON_DISK;
925 if (pVBoxFcbX->VolInfo.fsProperties.fReadOnly)
926 pInfo->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
927 if (pVBoxFcbX->VolInfo.fsProperties.fFileCompression)
928 pInfo->FileSystemAttributes |= FILE_FILE_COMPRESSION;
929 else if (pVBoxFcbX->VolInfo.fsProperties.fCompressed)
930 pInfo->FileSystemAttributes |= FILE_VOLUME_IS_COMPRESSED;
931 pInfo->MaximumComponentNameLength = pVBoxFcbX->VolInfo.fsProperties.cbMaxComponent
932 ? pVBoxFcbX->VolInfo.fsProperties.cbMaxComponent : 255;
933 ULONG const cbStrCopied = RT_MIN(cbInfo - RT_UOFFSETOF(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName), s_cbFsName);
934 pInfo->FileSystemNameLength = s_cbFsName;
935 if (cbStrCopied > 0)
936 memcpy(pInfo->FileSystemName, MRX_VBOX_FILESYS_NAME_U, cbStrCopied);
937
938 /*
939 * Update the return length in the context.
940 */
941 pRxContext->Info.LengthRemaining = cbInfo - cbStrCopied - RT_UOFFSETOF(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName);
942 pRxContext->InformationToReturn = cbStrCopied + RT_UOFFSETOF(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName);
943 return cbInfo >= cbNeeded ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW;
944}
945
946/**
947 * Handles NtQueryVolumeInformationFile / FileFsSectorSizeInformation
948 */
949static NTSTATUS vbsfNtQueryFsSectorSizeInfo(IN OUT PRX_CONTEXT pRxContext,
950 PFILE_FS_SECTOR_SIZE_INFORMATION pInfo,
951 ULONG cbInfo,
952 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
953 PMRX_VBOX_FOBX pVBoxFobx,
954 PVBSFNTFCBEXT pVBoxFcbX)
955{
956 /*
957 * NtQueryVolumeInformationFile should've checked the buffer size but just in case.
958 */
959 AssertReturnStmt(cbInfo >= sizeof(*pInfo), pRxContext->InformationToReturn = sizeof(*pInfo), STATUS_BUFFER_TOO_SMALL);
960
961 /*
962 * Get up-to-date sector size info.
963 */
964 if (pVBoxFcbX->nsVolInfoUpToDate - RTTimeSystemNanoTS() < RT_NS_100MS /** @todo implement proper volume info TTL */ )
965 {
966 /* Must fetch the info. */
967 NTSTATUS Status = vbsfNtUpdateFcbVolInfo(pVBoxFcbX, pNetRootExtension, pVBoxFobx);
968 if (NT_SUCCESS(Status))
969 { /* likely */ }
970 else
971 return Status;
972 }
973
974 /*
975 * Produce the requested data (currently no way to query more than the
976 * basic sector size here, so just repeat it).
977 */
978 uint32_t const cbSector = pVBoxFcbX->VolInfo.ulBytesPerSector ? pVBoxFcbX->VolInfo.ulBytesPerSector : 512;
979 pInfo->LogicalBytesPerSector = cbSector;
980 pInfo->PhysicalBytesPerSectorForAtomicity = cbSector;
981 pInfo->PhysicalBytesPerSectorForPerformance = cbSector;
982 pInfo->FileSystemEffectivePhysicalBytesPerSectorForAtomicity = cbSector;
983 pInfo->Flags = 0;
984 pInfo->ByteOffsetForSectorAlignment = SSINFO_OFFSET_UNKNOWN;
985 pInfo->ByteOffsetForPartitionAlignment = SSINFO_OFFSET_UNKNOWN;
986
987 /*
988 * Update the return length in the context.
989 */
990 pRxContext->Info.LengthRemaining = cbInfo - sizeof(*pInfo);
991 pRxContext->InformationToReturn = sizeof(*pInfo);
992 return STATUS_SUCCESS;
993}
994
995
996/**
997 * Handles NtQueryVolumeInformationFile and similar.
998 *
999 * The RDBSS library does not do a whole lot for these queries. No FCB locking.
1000 * The IO_STATUS_BLOCK updating differs too, setting of Ios.Information is
1001 * limited to cbInitialBuf - RxContext->Info.LengthRemaining.
1002 */
1003NTSTATUS VBoxMRxQueryVolumeInfo(IN OUT PRX_CONTEXT RxContext)
1004{
1005#ifdef LOG_ENABLED
1006 static const char * const s_apszNames[] =
1007 {
1008 "FileFsInvalidZeroEntry", "FileFsVolumeInformation", "FileFsLabelInformation",
1009 "FileFsSizeInformation", "FileFsDeviceInformation", "FileFsAttributeInformation",
1010 "FileFsControlInformation", "FileFsFullSizeInformation", "FileFsObjectIdInformation",
1011 "FileFsDriverPathInformation", "FileFsVolumeFlagsInformation", "FileFsSectorSizeInformation",
1012 "FileFsDataCopyInformation", "FileFsMetadataSizeInformation", "FileFsFullSizeInformationEx",
1013 };
1014#endif
1015 RxCaptureFcb;
1016 RxCaptureFobx;
1017 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
1018 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
1019 NTSTATUS Status;
1020
1021 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: pInfoBuffer = %p, cbInfoBuffer = %d\n",
1022 RxContext->Info.Buffer, RxContext->Info.LengthRemaining));
1023 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: vboxFobx = %p, Handle = 0x%RX64\n",
1024 pVBoxFobx, pVBoxFobx ? pVBoxFobx->hFile : 0));
1025
1026 switch (RxContext->Info.FsInformationClass)
1027 {
1028 case FileFsVolumeInformation:
1029 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsVolumeInformation\n"));
1030 AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
1031 Status = vbsfNtQueryFsVolumeInfo(RxContext, (PFILE_FS_VOLUME_INFORMATION)RxContext->Info.Buffer,
1032 RxContext->Info.Length, capFcb->pNetRoot, pNetRootExtension, pVBoxFobx,
1033 VBoxMRxGetFcbExtension(capFcb));
1034 break;
1035
1036 case FileFsSizeInformation:
1037 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsSizeInformation\n"));
1038 AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
1039 Status = vbsfNtQueryFsSizeInfo(RxContext, (PFILE_FS_SIZE_INFORMATION)RxContext->Info.Buffer,
1040 RxContext->Info.Length, pNetRootExtension, pVBoxFobx,
1041 VBoxMRxGetFcbExtension(capFcb));
1042 break;
1043
1044 case FileFsFullSizeInformation:
1045 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsFullSizeInformation\n"));
1046 AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
1047 Status = vbsfNtQueryFsFullSizeInfo(RxContext, (PFILE_FS_FULL_SIZE_INFORMATION)RxContext->Info.Buffer,
1048 RxContext->Info.Length, pNetRootExtension, pVBoxFobx,
1049 VBoxMRxGetFcbExtension(capFcb));
1050 break;
1051
1052 case FileFsDeviceInformation:
1053 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsDeviceInformation\n"));
1054 AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
1055 Status = vbsfNtQueryFsDeviceInfo(RxContext, (PFILE_FS_DEVICE_INFORMATION)RxContext->Info.Buffer,
1056 RxContext->Info.Length, capFcb->pNetRoot);
1057 break;
1058
1059 case FileFsAttributeInformation:
1060 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsAttributeInformation\n"));
1061 AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
1062 Status = vbsfNtQueryFsAttributeInfo(RxContext, (PFILE_FS_ATTRIBUTE_INFORMATION)RxContext->Info.Buffer,
1063 RxContext->Info.Length, pNetRootExtension, pVBoxFobx,
1064 VBoxMRxGetFcbExtension(capFcb));
1065 break;
1066
1067 case FileFsSectorSizeInformation:
1068 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: FileFsSectorSizeInformation\n"));
1069 AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
1070 Status = vbsfNtQueryFsSectorSizeInfo(RxContext, (PFILE_FS_SECTOR_SIZE_INFORMATION)RxContext->Info.Buffer,
1071 RxContext->Info.Length, pNetRootExtension, pVBoxFobx,
1072 VBoxMRxGetFcbExtension(capFcb));
1073 break;
1074
1075 case FileFsLabelInformation:
1076 AssertFailed(/* Only for setting, not for querying. */);
1077 RT_FALL_THRU();
1078 default:
1079 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: Not supported FS_INFORMATION_CLASS value: %d (%s)!\n",
1080 RxContext->Info.FsInformationClass,
1081 (ULONG)RxContext->Info.FsInformationClass < RT_ELEMENTS(s_apszNames)
1082 ? s_apszNames[RxContext->Info.FsInformationClass] : "??"));
1083 Status = STATUS_INVALID_PARAMETER;
1084 RxContext->InformationToReturn = 0;
1085 break;
1086 }
1087
1088 /* Here is a weird issue I couldn't quite figure out. When working directories, I
1089 seem to get semi-random stuff back in the IO_STATUS_BLOCK when returning failures
1090 for unsupported classes. The difference between directories and files seemed to
1091 be the IRP_SYNCHRONOUS_API flag. Poking around a little bit more, the UserIosb
1092 seems to be a ring-0 stack address rather than the usermode one and
1093 IopSynchronousApiServiceTail being used for copying it back to user mode because
1094 the handle wasn't synchronous or something.
1095
1096 So, the following is kludge to make the IOS values 0,0 like FAT does it. The
1097 real fix for this escapes me, but this should do the trick for now... */
1098 PIRP pIrp = RxContext->CurrentIrp;
1099 if ( pIrp
1100 && (pIrp->Flags & IRP_SYNCHRONOUS_API)
1101 && RTR0MemKernelIsValidAddr(pIrp->UserIosb))
1102 {
1103 Log2(("VBOXSF: VBoxMRxQueryVolumeInfo: IRP_SYNCHRONOUS_API hack: Setting UserIosb (%p) values!\n", pIrp->UserIosb));
1104 __try
1105 {
1106 pIrp->UserIosb->Status = 0;
1107 pIrp->UserIosb->Information = RxContext->InformationToReturn;
1108 }
1109 __except(EXCEPTION_EXECUTE_HANDLER)
1110 {
1111#ifdef LOG_ENABLED
1112 NTSTATUS rcNt = GetExceptionCode();
1113 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: Oops %#x accessing %p\n", rcNt, pIrp->UserIosb));
1114#endif
1115 }
1116 }
1117 Log(("VBOXSF: VBoxMRxQueryVolumeInfo: Returned %#010x\n", Status));
1118 return Status;
1119}
1120
1121/**
1122 * Updates the FCBs copy of the file size.
1123 *
1124 * The RDBSS is using the file size from the FCB in a few places without giving
1125 * us the chance to make sure that the value is up to date and properly
1126 * reflecting the size of the actual file on the host. Thus this mess to try
1127 * keep the the size up to date where ever possible as well as some hacks to
1128 * bypass RDBSS' use of the FCB file size. (And no, we cannot just make the
1129 * FCB_STATE_FILESIZECACHEING_ENABLED flag isn't set, because it was never
1130 * implemented.)
1131 *
1132 * @param pFileObj The file object.
1133 * @param pFcb The FCB.
1134 * @param pVBoxFobX Out file object extension data.
1135 * @param cbFileNew The new file size.
1136 * @param cbFileOld The old file size from the FCB/RDBSS.
1137 * @param cbAllocated The allocated size for the file, -1 if not
1138 * available.
1139 *
1140 * @note Will acquire the paging I/O resource lock in exclusive mode. Caller
1141 * must not be holding it in shared mode.
1142 */
1143void vbsfNtUpdateFcbSize(PFILE_OBJECT pFileObj, PMRX_FCB pFcb, PMRX_VBOX_FOBX pVBoxFobX,
1144 LONGLONG cbFileNew, LONGLONG cbFileOld, LONGLONG cbAllocated)
1145{
1146 Assert(cbFileNew != cbFileOld);
1147 Assert(cbFileNew >= 0);
1148 Assert( !ExIsResourceAcquiredSharedLite(pFcb->Header.PagingIoResource)
1149 || ExIsResourceAcquiredExclusiveLite(pFcb->Header.PagingIoResource));
1150
1151 /*
1152 * Lock the paging I/O resources before trying to modify the header variables.
1153 *
1154 * Note! RxAcquirePagingIoResource and RxReleasePagingIoResource are unsafe
1155 * macros in need of {} wrappers when used with if statements.
1156 */
1157 NTSTATUS rcNtLock = RxAcquirePagingIoResource(NULL, pFcb);
1158
1159 LONGLONG cbFileOldRecheck;
1160 RxGetFileSizeWithLock((PFCB)pFcb, &cbFileOldRecheck);
1161 if (cbFileOldRecheck == cbFileOld)
1162 {
1163 LONGLONG cbFileNewCopy = cbFileNew;
1164 RxSetFileSizeWithLock((PFCB)pFcb, &cbFileNewCopy);
1165
1166 /* The valid data length is the same as the file size for us. */
1167 if (pFcb->Header.ValidDataLength.QuadPart != cbFileNew)
1168 pFcb->Header.ValidDataLength.QuadPart = cbFileNew;
1169
1170 /* The allocation size must be larger or equal to the file size says https://www.osronline.com/article.cfm%5Eid=167.htm . */
1171 if (cbAllocated >= cbFileNew)
1172 {
1173 if (pFcb->Header.AllocationSize.QuadPart != cbAllocated)
1174 pFcb->Header.AllocationSize.QuadPart = cbAllocated;
1175 }
1176 else if (pFcb->Header.AllocationSize.QuadPart < cbFileNew)
1177 pFcb->Header.AllocationSize.QuadPart = cbFileNew;
1178
1179 /* Update our copy. */
1180 pVBoxFobX->Info.cbObject = cbFileNew;
1181 if (cbAllocated >= 0)
1182 pVBoxFobX->Info.cbAllocated = cbAllocated;
1183
1184 /*
1185 * Tell the cache manager if we can.
1186 *
1187 * According to the MSDN documentation, we must update the cache manager when
1188 * the file size changes, allocation size increases, valid data length descreases,
1189 * and when a non-cached I/O operation increases the valid data length.
1190 */
1191 SECTION_OBJECT_POINTERS *pSectPtrs = pFileObj->SectionObjectPointer;
1192 if (pSectPtrs)
1193 {
1194 LARGE_INTEGER NewSize;
1195 NewSize.QuadPart = cbFileNew;
1196 if ( cbFileNew >= cbFileOld
1197 || MmCanFileBeTruncated(pSectPtrs, &NewSize)) /** @todo do we need to check this? */
1198 {
1199 CC_FILE_SIZES FileSizes;
1200 FileSizes.AllocationSize = pFcb->Header.AllocationSize;
1201 FileSizes.FileSize.QuadPart = cbFileNew;
1202 FileSizes.ValidDataLength.QuadPart = cbFileNew;
1203
1204 /* RDBSS leave the lock before calling CcSetFileSizes, so we do that too then.*/
1205 if (NT_SUCCESS(rcNtLock))
1206 {
1207 RxReleasePagingIoResource(NULL, pFcb);
1208 }
1209
1210 __try
1211 {
1212 CcSetFileSizes(pFileObj, &FileSizes);
1213 }
1214 __except(EXCEPTION_EXECUTE_HANDLER)
1215 {
1216#ifdef LOG_ENABLED
1217 NTSTATUS rcNt = GetExceptionCode();
1218 Log(("vbsfNtUpdateFcbSize: CcSetFileSizes -> %#x\n", rcNt));
1219#endif
1220 }
1221 return;
1222 }
1223 /** @todo should we flag this so we can try again later? */
1224 }
1225 }
1226 else
1227 Log(("vbsfNtUpdateFcbSize: Seems we raced someone updating the file size: old size = %#RX64, new size = %#RX64, current size = %#RX64\n",
1228 cbFileOld, cbFileNew, cbFileOldRecheck));
1229
1230 if (NT_SUCCESS(rcNtLock))
1231 {
1232 RxReleasePagingIoResource(NULL, pFcb);
1233 }
1234}
1235
1236
1237/**
1238 * Updates the object info to the VBox file object extension data.
1239 *
1240 * @param pVBoxFobX The VBox file object extension data.
1241 * @param pObjInfo The fresh data from the host. Okay to modify.
1242 * @param pVBoxFcbX The VBox FCB extension data.
1243 * @param fTimestampsToCopyAnyway VBOX_FOBX_F_INFO_XXX mask of timestamps to
1244 * copy regardless of their suppressed state.
1245 * This is used by the info setter function to
1246 * get current copies of newly modified and
1247 * suppressed fields.
1248 * @param pFileObj Pointer to the file object if we should
1249 * update the cache manager, otherwise NULL.
1250 * @param pFcb Pointer to the FCB if we should update its
1251 * copy of the file size, NULL if we should
1252 * leave it be. Must be NULL when pFileObj is.
1253 */
1254static void vbsfNtCopyInfo(PMRX_VBOX_FOBX pVBoxFobX, PSHFLFSOBJINFO pObjInfo, PVBSFNTFCBEXT pVBoxFcbX,
1255 uint8_t fTimestampsToCopyAnyway, PFILE_OBJECT pFileObj, PMRX_FCB pFcb)
1256{
1257 /*
1258 * Check if the size changed because RDBSS and the cache manager have
1259 * cached copies of the file and allocation sizes.
1260 */
1261 if (pFcb && pFileObj)
1262 {
1263 LONGLONG cbFileRdbss;
1264 RxGetFileSizeWithLock((PFCB)pFcb, &cbFileRdbss);
1265 if (pObjInfo->cbObject != cbFileRdbss)
1266 vbsfNtUpdateFcbSize(pFileObj, pFcb, pVBoxFobX, pObjInfo->cbObject, cbFileRdbss, pObjInfo->cbAllocated);
1267 }
1268
1269 /*
1270 * Check if the modified timestamp changed and try guess if it was the host.
1271 */
1272 /** @todo use modification timestamp to detect host changes? We do on linux. */
1273
1274 /*
1275 * Copy the object info over. To simplify preserving the value of timestamps
1276 * which implict updating is currently disabled, copy them over to the source
1277 * structure before preforming the copy.
1278 */
1279 Assert((pVBoxFobX->fTimestampsSetByUser & ~pVBoxFobX->fTimestampsUpdatingSuppressed) == 0);
1280 uint8_t fCopyTs = pVBoxFobX->fTimestampsUpdatingSuppressed & ~fTimestampsToCopyAnyway;
1281 if (fCopyTs)
1282 {
1283 if ( (fCopyTs & VBOX_FOBX_F_INFO_LASTACCESS_TIME)
1284 && pVBoxFcbX->pFobxLastAccessTime == pVBoxFobX)
1285 pObjInfo->AccessTime = pVBoxFobX->Info.AccessTime;
1286
1287 if ( (fCopyTs & VBOX_FOBX_F_INFO_LASTWRITE_TIME)
1288 && pVBoxFcbX->pFobxLastWriteTime == pVBoxFobX)
1289 pObjInfo->ModificationTime = pVBoxFobX->Info.ModificationTime;
1290
1291 if ( (fCopyTs & VBOX_FOBX_F_INFO_CHANGE_TIME)
1292 && pVBoxFcbX->pFobxChangeTime == pVBoxFobX)
1293 pObjInfo->ChangeTime = pVBoxFobX->Info.ChangeTime;
1294 }
1295 pVBoxFobX->Info = *pObjInfo;
1296}
1297
1298/**
1299 * Queries the current file stats from the host and updates the RDBSS' copy of
1300 * the file size if necessary.
1301 *
1302 * @returns IPRT status code
1303 * @param pNetRootX Our net root extension data.
1304 * @param pFileObj The file object.
1305 * @param pVBoxFobX Our file object extension data.
1306 * @param pFcb The FCB.
1307 * @param pVBoxFcbX Our FCB extension data.
1308 */
1309int vbsfNtQueryAndUpdateFcbSize(PMRX_VBOX_NETROOT_EXTENSION pNetRootX, PFILE_OBJECT pFileObj,
1310 PMRX_VBOX_FOBX pVBoxFobX, PMRX_FCB pFcb, PVBSFNTFCBEXT pVBoxFcbX)
1311{
1312 VBOXSFOBJINFOREQ *pReq = (VBOXSFOBJINFOREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
1313 AssertReturn(pReq, VERR_NO_MEMORY);
1314
1315 int vrc = VbglR0SfHostReqQueryObjInfo(pNetRootX->map.root, pReq, pVBoxFobX->hFile);
1316 if (RT_SUCCESS(vrc))
1317 vbsfNtCopyInfo(pVBoxFobX, &pReq->ObjInfo, pVBoxFcbX, 0, pFileObj, pFcb);
1318 else
1319 AssertMsgFailed(("vrc=%Rrc\n", vrc));
1320
1321 VbglR0PhysHeapFree(pReq);
1322 return vrc;
1323}
1324
1325/**
1326 * Handle NtQueryInformationFile and similar requests.
1327 *
1328 * The RDBSS code has done various things before we get here wrt locking and
1329 * request pre-processing. Unless this is a paging file (FCB_STATE_PAGING_FILE)
1330 * or FileNameInformation is being queried, the FCB is locked. For all except
1331 * for FileCompressionInformation, a shared FCB access (FCB.Header.Resource) is
1332 * acquired, where as for FileCompressionInformation it is taken exclusively.
1333 */
1334NTSTATUS VBoxMRxQueryFileInfo(IN PRX_CONTEXT RxContext)
1335{
1336 RxCaptureFcb;
1337 RxCaptureFobx;
1338 NTSTATUS Status = STATUS_SUCCESS;
1339 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
1340 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
1341 ULONG cbToCopy = 0;
1342
1343 Log(("VBOXSF: VBoxMRxQueryFileInfo: Buffer = %p, Length = %x (%d) bytes, FileInformationClass = %d\n",
1344 RxContext->Info.Buffer, RxContext->Info.Length, RxContext->Info.Length, RxContext->Info.FileInformationClass));
1345
1346 AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
1347 AssertReturn(RxContext->Info.Buffer, STATUS_INVALID_PARAMETER);
1348
1349#define CHECK_SIZE_BREAK(a_RxContext, a_cbNeeded) \
1350 /* IO_STACK_LOCATION::Parameters::SetFile::Length is signed, the RxContext bugger is LONG. See end of function for why. */ \
1351 if ((ULONG)(a_RxContext)->Info.Length >= (a_cbNeeded)) \
1352 { /*likely */ } \
1353 else if (1) { Status = STATUS_BUFFER_TOO_SMALL; break; } else do { } while (0)
1354
1355 switch (RxContext->Info.FileInformationClass)
1356 {
1357 /*
1358 * Queries we can satisfy without calling the host:
1359 */
1360
1361 case FileNamesInformation:
1362 {
1363 PFILE_NAMES_INFORMATION pInfo = (PFILE_NAMES_INFORMATION)RxContext->Info.Buffer;
1364 PUNICODE_STRING FileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
1365 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileNamesInformation\n"));
1366
1367 cbToCopy = RT_UOFFSETOF_DYN(FILE_NAMES_INFORMATION, FileName[FileName->Length / 2 + 1]);
1368 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1369
1370 pInfo->NextEntryOffset = 0;
1371 pInfo->FileIndex = 0;
1372 pInfo->FileNameLength = FileName->Length;
1373
1374 RtlCopyMemory(pInfo->FileName, FileName->Buffer, FileName->Length);
1375 pInfo->FileName[FileName->Length] = 0;
1376 break;
1377 }
1378
1379 case FileInternalInformation:
1380 {
1381 PFILE_INTERNAL_INFORMATION pInfo = (PFILE_INTERNAL_INFORMATION)RxContext->Info.Buffer;
1382 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileInternalInformation\n"));
1383
1384 cbToCopy = sizeof(FILE_INTERNAL_INFORMATION);
1385 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1386
1387 /* A 8-byte file reference number for the file. */
1388 pInfo->IndexNumber.QuadPart = (ULONG_PTR)capFcb;
1389 break;
1390 }
1391
1392 case FileEaInformation:
1393 {
1394 PFILE_EA_INFORMATION pInfo = (PFILE_EA_INFORMATION)RxContext->Info.Buffer;
1395 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileEaInformation\n"));
1396
1397 cbToCopy = sizeof(FILE_EA_INFORMATION);
1398 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1399
1400 pInfo->EaSize = 0;
1401 break;
1402 }
1403
1404 case FileStreamInformation:
1405 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileStreamInformation: not supported\n"));
1406 Status = STATUS_INVALID_PARAMETER;
1407 break;
1408
1409 case FileAlternateNameInformation:
1410 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileStreamInformation: not implemented\n"));
1411 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1412 break;
1413
1414 case FileNumaNodeInformation:
1415 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileNumaNodeInformation: not supported\n"));
1416 Status = STATUS_NO_SUCH_DEVICE; /* what's returned on a samba share */
1417 break;
1418
1419 case FileStandardLinkInformation:
1420 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileStandardLinkInformation: not supported\n"));
1421 Status = STATUS_NOT_SUPPORTED; /* what's returned on a samba share */
1422 break;
1423
1424 /*
1425 * Queries where we need info from the host.
1426 *
1427 * For directories we don't necessarily go to the host but use info from when we
1428 * opened the them, why we do this is a little unclear as all the clues that r9630
1429 * give is "fixes".
1430 *
1431 * Note! We verify the buffer size after talking to the host, assuming that there
1432 * won't be a problem and saving an extra switch statement. IIRC the
1433 * NtQueryInformationFile code verfies the sizes too.
1434 */
1435 /** @todo r=bird: install a hack so we get FileAllInformation directly up here
1436 * rather than 5 individual queries. We may end up going 3 times to
1437 * the host (depending on the TTL hack) to fetch the same info over
1438 * and over again. */
1439 case FileEndOfFileInformation:
1440 case FileAllocationInformation:
1441 case FileBasicInformation:
1442 case FileStandardInformation:
1443 case FileNetworkOpenInformation:
1444 case FileAttributeTagInformation:
1445 case FileCompressionInformation:
1446 {
1447 /* Query the information if necessary. */
1448 if ( !(pVBoxFobx->Info.Attr.fMode & RTFS_DOS_DIRECTORY) /** @todo figure out why we don't return up-to-date info for directories! */
1449 && ( !pVBoxFobx->nsUpToDate
1450 || pVBoxFobx->nsUpToDate - RTTimeSystemNanoTS() < RT_NS_100US /** @todo implement proper TTL */ ) )
1451 {
1452 PVBSFNTFCBEXT pVBoxFcbx = VBoxMRxGetFcbExtension(capFcb);
1453 AssertReturn(pVBoxFcbx, STATUS_INTERNAL_ERROR);
1454
1455 VBOXSFOBJINFOREQ *pReq = (VBOXSFOBJINFOREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
1456 AssertBreakStmt(pReq, Status = STATUS_NO_MEMORY);
1457
1458 int vrc = VbglR0SfHostReqQueryObjInfo(pNetRootExtension->map.root, pReq, pVBoxFobx->hFile);
1459 if (RT_SUCCESS(vrc))
1460 vbsfNtCopyInfo(pVBoxFobx, &pReq->ObjInfo, pVBoxFcbx, 0, /* ASSUMES that PageingIoResource is not */
1461 RxContext->pFobx->AssociatedFileObject, capFcb); /* held in shared mode here! */
1462 else
1463 {
1464 Status = vbsfNtVBoxStatusToNt(vrc);
1465 VbglR0PhysHeapFree(pReq);
1466 break;
1467 }
1468 VbglR0PhysHeapFree(pReq);
1469 }
1470
1471 /* Copy it into the return buffer. */
1472 switch (RxContext->Info.FileInformationClass)
1473 {
1474 case FileBasicInformation:
1475 {
1476 PFILE_BASIC_INFORMATION pInfo = (PFILE_BASIC_INFORMATION)RxContext->Info.Buffer;
1477 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileBasicInformation\n"));
1478
1479 cbToCopy = sizeof(FILE_BASIC_INFORMATION);
1480 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1481
1482 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.BirthTime);
1483 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.AccessTime);
1484 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.ModificationTime);
1485 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.ChangeTime);
1486 pInfo->FileAttributes = VBoxToNTFileAttributes(pVBoxFobx->Info.Attr.fMode);
1487 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileBasicInformation: File attributes: 0x%x\n",
1488 pInfo->FileAttributes));
1489 break;
1490 }
1491
1492 case FileStandardInformation:
1493 {
1494 PFILE_STANDARD_INFORMATION pInfo = (PFILE_STANDARD_INFORMATION)RxContext->Info.Buffer;
1495 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileStandardInformation\n"));
1496
1497 cbToCopy = sizeof(FILE_STANDARD_INFORMATION);
1498 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1499
1500 /* Note! We didn't used to set allocation size and end-of-file for directories.
1501 NTFS reports these, though, so why shouldn't we. */
1502 pInfo->AllocationSize.QuadPart = pVBoxFobx->Info.cbAllocated;
1503 pInfo->EndOfFile.QuadPart = pVBoxFobx->Info.cbObject;
1504 pInfo->NumberOfLinks = 1; /** @todo 0? */
1505 pInfo->DeletePending = FALSE;
1506 pInfo->Directory = pVBoxFobx->Info.Attr.fMode & RTFS_DOS_DIRECTORY ? TRUE : FALSE;
1507 break;
1508 }
1509
1510 case FileNetworkOpenInformation:
1511 {
1512 PFILE_NETWORK_OPEN_INFORMATION pInfo = (PFILE_NETWORK_OPEN_INFORMATION)RxContext->Info.Buffer;
1513 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileNetworkOpenInformation\n"));
1514
1515 cbToCopy = sizeof(FILE_NETWORK_OPEN_INFORMATION);
1516 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1517
1518 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.BirthTime);
1519 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.AccessTime);
1520 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.ModificationTime);
1521 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.ChangeTime);
1522 /* Note! We didn't used to set allocation size and end-of-file for directories.
1523 NTFS reports these, though, so why shouldn't we. */
1524 pInfo->AllocationSize.QuadPart = pVBoxFobx->Info.cbAllocated;
1525 pInfo->EndOfFile.QuadPart = pVBoxFobx->Info.cbObject;
1526 pInfo->FileAttributes = VBoxToNTFileAttributes(pVBoxFobx->Info.Attr.fMode);
1527 break;
1528 }
1529
1530 case FileEndOfFileInformation:
1531 {
1532 PFILE_END_OF_FILE_INFORMATION pInfo = (PFILE_END_OF_FILE_INFORMATION)RxContext->Info.Buffer;
1533 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileEndOfFileInformation\n"));
1534
1535 cbToCopy = sizeof(FILE_END_OF_FILE_INFORMATION);
1536 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1537
1538 /* Note! We didn't used to set allocation size and end-of-file for directories.
1539 NTFS reports these, though, so why shouldn't we. */
1540 pInfo->EndOfFile.QuadPart = pVBoxFobx->Info.cbObject;
1541 break;
1542 }
1543
1544 case FileAllocationInformation:
1545 {
1546 PFILE_ALLOCATION_INFORMATION pInfo = (PFILE_ALLOCATION_INFORMATION)RxContext->Info.Buffer;
1547 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileAllocationInformation\n"));
1548
1549 cbToCopy = sizeof(FILE_ALLOCATION_INFORMATION);
1550 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1551
1552 /* Note! We didn't used to set allocation size and end-of-file for directories.
1553 NTFS reports these, though, so why shouldn't we. */
1554 pInfo->AllocationSize.QuadPart = pVBoxFobx->Info.cbAllocated;
1555 break;
1556 }
1557
1558 case FileAttributeTagInformation:
1559 {
1560 PFILE_ATTRIBUTE_TAG_INFORMATION pInfo = (PFILE_ATTRIBUTE_TAG_INFORMATION)RxContext->Info.Buffer;
1561 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileAttributeTagInformation\n"));
1562
1563 cbToCopy = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
1564 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1565
1566 pInfo->FileAttributes = VBoxToNTFileAttributes(pVBoxFobx->Info.Attr.fMode);
1567 pInfo->ReparseTag = 0;
1568 break;
1569 }
1570
1571 case FileCompressionInformation:
1572 {
1573 //PFILE_COMPRESSION_INFO pInfo = (PFILE_COMPRESSION_INFO)RxContext->Info.Buffer;
1574 struct MY_FILE_COMPRESSION_INFO
1575 {
1576 LARGE_INTEGER CompressedFileSize;
1577 WORD CompressionFormat;
1578 UCHAR CompressionUnitShift;
1579 UCHAR ChunkShift;
1580 UCHAR ClusterShift;
1581 UCHAR Reserved[3];
1582 } *pInfo = (struct MY_FILE_COMPRESSION_INFO *)RxContext->Info.Buffer;
1583 Log(("VBOXSF: VBoxMRxQueryFileInfo: FileCompressionInformation\n"));
1584
1585 cbToCopy = sizeof(*pInfo);
1586 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1587
1588 pInfo->CompressedFileSize.QuadPart = pVBoxFobx->Info.cbObject;
1589 pInfo->CompressionFormat = 0;
1590 pInfo->CompressionUnitShift = 0;
1591 pInfo->ChunkShift = 0;
1592 pInfo->ClusterShift = 0;
1593 pInfo->Reserved[0] = 0;
1594 pInfo->Reserved[1] = 0;
1595 pInfo->Reserved[2] = 0;
1596 AssertCompile(sizeof(pInfo->Reserved) == 3);
1597 break;
1598 }
1599
1600 default:
1601 AssertLogRelMsgFailed(("FileInformationClass=%d\n",
1602 RxContext->Info.FileInformationClass));
1603 Status = STATUS_INTERNAL_ERROR;
1604 break;
1605 }
1606 break;
1607 }
1608
1609
1610/** @todo Implement:
1611 * FileHardLinkInformation: rcNt=0 (STATUS_SUCCESS) Ios.Status=0 (STATUS_SUCCESS) Ios.Information=0000000000000048
1612 * FileProcessIdsUsingFileInformation: rcNt=0 (STATUS_SUCCESS) Ios.Status=0 (STATUS_SUCCESS) Ios.Information=0000000000000010
1613 * FileNormalizedNameInformation: rcNt=0 (STATUS_SUCCESS) Ios.Status=0 (STATUS_SUCCESS) Ios.Information=00000000000000AA
1614 * => See during MoveFileEx call on W10.
1615 * FileNetworkPhysicalNameInformation: rcNt=0xc000000d (STATUS_INVALID_PARAMETER) Ios={not modified}
1616 * FileShortNameInformation?
1617 * FileNetworkPhysicalNameInformation
1618 */
1619
1620 /*
1621 * Unsupported ones (STATUS_INVALID_PARAMETER is correct here if you
1622 * go by what fat + ntfs return, however samba mounts generally returns
1623 * STATUS_INVALID_INFO_CLASS except for pipe info - see queryfileinfo-1).
1624 */
1625 default:
1626 Log(("VBOXSF: VBoxMRxQueryFileInfo: Not supported FileInformationClass: %d!\n",
1627 RxContext->Info.FileInformationClass));
1628 Status = STATUS_INVALID_PARAMETER;
1629 break;
1630
1631 }
1632#undef CHECK_SIZE_BREAK
1633
1634 /* Note! InformationToReturn doesn't seem to be used, instead Info.LengthRemaining should underflow
1635 so it can be used together with RxContext->CurrentIrpSp->Parameters.QueryFile.Length
1636 to calc the Ios.Information value. This explain the weird LONG type choice. */
1637 RxContext->InformationToReturn = cbToCopy;
1638 RxContext->Info.LengthRemaining -= cbToCopy;
1639 AssertStmt(RxContext->Info.LengthRemaining >= 0 || Status != STATUS_SUCCESS, Status = STATUS_BUFFER_TOO_SMALL);
1640
1641 Log(("VBOXSF: VBoxMRxQueryFileInfo: Returns %#x, Remaining length = %d, cbToCopy = %u (%#x)\n",
1642 Status, RxContext->Info.Length, cbToCopy));
1643 return Status;
1644}
1645
1646/**
1647 * Worker for VBoxMRxSetFileInfo.
1648 */
1649static NTSTATUS vbsfNtSetBasicInfo(PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension, PFILE_OBJECT pFileObj, PMRX_VBOX_FOBX pVBoxFobx,
1650 PMRX_FCB pFcb, PVBSFNTFCBEXT pVBoxFcbx, PFILE_BASIC_INFORMATION pBasicInfo)
1651{
1652 Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: CreationTime %RX64\n", pBasicInfo->CreationTime.QuadPart));
1653 Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: LastAccessTime %RX64\n", pBasicInfo->LastAccessTime.QuadPart));
1654 Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: LastWriteTime %RX64\n", pBasicInfo->LastWriteTime.QuadPart));
1655 Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: ChangeTime %RX64\n", pBasicInfo->ChangeTime.QuadPart));
1656 Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: FileAttributes %RX32\n", pBasicInfo->FileAttributes));
1657 AssertReturn(pVBoxFobx, STATUS_INTERNAL_ERROR);
1658 AssertReturn(pVBoxFcbx, STATUS_INTERNAL_ERROR);
1659 AssertReturn(pNetRootExtension, STATUS_INTERNAL_ERROR);
1660
1661 /** @todo r=bird: The attempt at implementing the disable-timestamp-update
1662 * behaviour here needs a little adjusting. I'll get to that later.
1663 *
1664 * Reminders:
1665 *
1666 * X1. Drop VBOX_FOBX_F_INFO_CREATION_TIME.
1667 *
1668 * X2. Drop unused VBOX_FOBX_F_INFO_ATTRIBUTES.
1669 *
1670 * X3. Only act on VBOX_FOBX_F_INFO_CHANGE_TIME if modified attributes or grown
1671 * the file (?) so we don't cancel out updates by other parties (like the
1672 * host).
1673 *
1674 * X4. Only act on VBOX_FOBX_F_INFO_LASTWRITE_TIME if we've written to the
1675 * file.
1676 *
1677 * X5. Only act on VBOX_FOBX_F_INFO_LASTACCESS_TIME if we've read from the file
1678 * or done whatever else might modify the access time.
1679 *
1680 * 6. Don't bother calling the host if there are only zeros and -1 values.
1681 * => Not done / better use it to update FCB info?
1682 *
1683 * X7. Client application should probably be allowed to modify the timestamps
1684 * explicitly using this API after disabling updating, given the wording of
1685 * the footnote referenced above.
1686 * => Only verified via fastfat sample, need FsPerf test.
1687 *
1688 * 8. Extend the host interface to let the host handle this crap instead as it
1689 * can do a better job, like on windows it's done implicitly if we let -1
1690 * pass thru IPRT.
1691 * => We're actually better equipped to handle it than the host, given the
1692 * FCB/inode. New plan is to detect windows host and let it implement -1,
1693 * but use the old stuff as fallback for non-windows hosts.
1694 *
1695 * One worry here is that we hide timestamp updates made by the host or other
1696 * guest side processes. This could account for some of the issues we've been
1697 * having with the guest not noticing host side changes.
1698 */
1699
1700
1701 /*
1702 * The properties that need to be changed are set to something other
1703 * than zero and -1. (According to the fastfat sample code, -1 only
1704 * disable implicit timestamp updating, not explicit thru this code.)
1705 */
1706
1707 /*
1708 * In the host request, zero values are ignored.
1709 *
1710 * As for the NT request, the same is true but with a slight twist for the
1711 * timestamp fields. If a timestamp value is non-zero, the client disables
1712 * implicit updating of that timestamp via this handle when reading, writing
1713 * and * changing attributes. The special -1 value is used to just disable
1714 * implicit updating without modifying the timestamp. While the value is
1715 * allowed for the CreationTime field, it will be treated as zero.
1716 *
1717 * More clues to the NT behaviour can be found here:
1718 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/16023025-8a78-492f-8b96-c873b042ac50
1719 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d4bc551b-7aaf-4b4f-ba0e-3a75e7c528f0#Appendix_A_86
1720 *
1721 * P.S. One of the reasons behind suppressing of timestamp updating after setting
1722 * them is likely related to the need of opening objects to modify them. There are
1723 * no utimes() or chmod() function in NT, on the futimes() and fchmod() variants.
1724 */
1725 VBOXSFOBJINFOREQ *pReq = (VBOXSFOBJINFOREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
1726 if (pReq)
1727 RT_ZERO(pReq->ObjInfo);
1728 else
1729 return STATUS_INSUFFICIENT_RESOURCES;
1730 uint32_t fModified = 0;
1731 uint32_t fSuppressed = 0;
1732
1733 /** @todo FsPerf need to check what is supposed to happen if modified
1734 * against after -1 is specified. As state above, fastfat will not suppress
1735 * further setting of the timestamp like we used to do prior to revision
1736 * r130337 or thereabouts. */
1737
1738 if (pBasicInfo->CreationTime.QuadPart && pBasicInfo->CreationTime.QuadPart != -1)
1739 RTTimeSpecSetNtTime(&pReq->ObjInfo.BirthTime, pBasicInfo->CreationTime.QuadPart);
1740
1741 if (pBasicInfo->LastAccessTime.QuadPart)
1742 {
1743 if (pBasicInfo->LastAccessTime.QuadPart != -1)
1744 {
1745 RTTimeSpecSetNtTime(&pReq->ObjInfo.AccessTime, pBasicInfo->LastAccessTime.QuadPart);
1746 fModified |= VBOX_FOBX_F_INFO_LASTACCESS_TIME;
1747 }
1748 fSuppressed |= VBOX_FOBX_F_INFO_LASTACCESS_TIME;
1749 }
1750
1751 if (pBasicInfo->LastWriteTime.QuadPart)
1752 {
1753 if (pBasicInfo->LastWriteTime.QuadPart != -1)
1754 {
1755 RTTimeSpecSetNtTime(&pReq->ObjInfo.ModificationTime, pBasicInfo->LastWriteTime.QuadPart);
1756 fModified |= VBOX_FOBX_F_INFO_LASTWRITE_TIME;
1757 }
1758 fSuppressed |= VBOX_FOBX_F_INFO_LASTWRITE_TIME;
1759 }
1760
1761 if (pBasicInfo->ChangeTime.QuadPart)
1762 {
1763 if (pBasicInfo->ChangeTime.QuadPart != -1)
1764 {
1765 RTTimeSpecSetNtTime(&pReq->ObjInfo.ChangeTime, pBasicInfo->ChangeTime.QuadPart);
1766 fModified |= VBOX_FOBX_F_INFO_CHANGE_TIME;
1767 }
1768 fSuppressed |= VBOX_FOBX_F_INFO_CHANGE_TIME;
1769 }
1770
1771 if (pBasicInfo->FileAttributes)
1772 {
1773 pReq->ObjInfo.Attr.fMode = NTToVBoxFileAttributes(pBasicInfo->FileAttributes);
1774 Assert(pReq->ObjInfo.Attr.fMode != 0);
1775 }
1776
1777 /*
1778 * Call the host to do the actual updating.
1779 * Note! This may be a noop, but we want up-to-date info for any -1 timestamp.
1780 */
1781 int vrc = VbglR0SfHostReqSetObjInfo(pNetRootExtension->map.root, pReq, pVBoxFobx->hFile);
1782 NTSTATUS Status;
1783 if (RT_SUCCESS(vrc))
1784 {
1785 /*
1786 * Update our timestamp state tracking both in the file object and the file
1787 * control block extensions.
1788 */
1789 if (pBasicInfo->FileAttributes || fModified)
1790 {
1791 if ( pVBoxFcbx->pFobxChangeTime != pVBoxFobx
1792 && !(pVBoxFobx->fTimestampsUpdatingSuppressed & VBOX_FOBX_F_INFO_CHANGE_TIME))
1793 pVBoxFcbx->pFobxChangeTime = NULL;
1794 pVBoxFobx->fTimestampsImplicitlyUpdated |= VBOX_FOBX_F_INFO_CHANGE_TIME;
1795 }
1796 pVBoxFobx->fTimestampsImplicitlyUpdated &= ~fModified;
1797 pVBoxFobx->fTimestampsSetByUser |= fModified;
1798 pVBoxFobx->fTimestampsUpdatingSuppressed |= fSuppressed;
1799
1800 if (fSuppressed)
1801 {
1802 if (fSuppressed & VBOX_FOBX_F_INFO_LASTACCESS_TIME)
1803 pVBoxFcbx->pFobxLastAccessTime = pVBoxFobx;
1804 if (fSuppressed & VBOX_FOBX_F_INFO_LASTWRITE_TIME)
1805 pVBoxFcbx->pFobxLastWriteTime = pVBoxFobx;
1806 if (fSuppressed & VBOX_FOBX_F_INFO_CHANGE_TIME)
1807 pVBoxFcbx->pFobxChangeTime = pVBoxFobx;
1808 }
1809
1810 vbsfNtCopyInfo(pVBoxFobx, &pReq->ObjInfo, pVBoxFcbx, fSuppressed, pFileObj, pFcb);
1811
1812 /*
1813 * Copy timestamps and attributes from the host into the return buffer to let
1814 * RDBSS update the FCB data when we return. Not sure if the FCB timestamps
1815 * are ever used for anything, but caller doesn't check for -1 so there will
1816 * be some funny/invalid timestamps in the FCB it ever does. (I seriously
1817 * doubt -1 is supposed to be there given that the FCB is shared and the -1
1818 * only applies to a given FILE_OBJECT/HANDLE.)
1819 */
1820 if (pBasicInfo->FileAttributes)
1821 pBasicInfo->FileAttributes = (pBasicInfo->FileAttributes & FILE_ATTRIBUTE_TEMPORARY)
1822 | VBoxToNTFileAttributes(pReq->ObjInfo.Attr.fMode);
1823 if (pBasicInfo->CreationTime.QuadPart)
1824 pBasicInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pReq->ObjInfo.BirthTime);
1825 if (pBasicInfo->LastAccessTime.QuadPart)
1826 pBasicInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pReq->ObjInfo.AccessTime);
1827 if (pBasicInfo->LastWriteTime.QuadPart)
1828 pBasicInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pReq->ObjInfo.ModificationTime);
1829 if (pBasicInfo->ChangeTime.QuadPart)
1830 pBasicInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pReq->ObjInfo.ChangeTime);
1831
1832 Status = STATUS_SUCCESS;
1833 }
1834 else
1835 Status = vbsfNtVBoxStatusToNt(vrc);
1836
1837 VbglR0PhysHeapFree(pReq);
1838 return Status;
1839}
1840
1841/**
1842 * Worker for VBoxMRxSetFileInfo.
1843 */
1844static NTSTATUS vbsfNtSetEndOfFile(IN OUT struct _RX_CONTEXT * RxContext, IN uint64_t cbNewFileSize)
1845{
1846 NTSTATUS Status = STATUS_SUCCESS;
1847
1848 RxCaptureFcb;
1849 RxCaptureFobx;
1850
1851 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
1852 PVBSFNTFCBEXT pVBoxFcbx = VBoxMRxGetFcbExtension(capFcb);
1853 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
1854
1855 PSHFLFSOBJINFO pObjInfo;
1856 uint32_t cbBuffer;
1857 int vrc;
1858
1859 Log(("VBOXSF: vbsfNtSetEndOfFile: New size = %RX64\n",
1860 cbNewFileSize));
1861
1862 Assert(pVBoxFobx && pNetRootExtension);
1863
1864 cbBuffer = sizeof(SHFLFSOBJINFO);
1865 pObjInfo = (SHFLFSOBJINFO *)vbsfNtAllocNonPagedMem(cbBuffer);
1866 if (!pObjInfo)
1867 {
1868 AssertFailed();
1869 return STATUS_INSUFFICIENT_RESOURCES;
1870 }
1871
1872 RtlZeroMemory(pObjInfo, cbBuffer);
1873 pObjInfo->cbObject = cbNewFileSize;
1874
1875 vrc = VbglR0SfFsInfo(&g_SfClient, &pNetRootExtension->map, pVBoxFobx->hFile,
1876 SHFL_INFO_SET | SHFL_INFO_SIZE, &cbBuffer, (PSHFLDIRINFO)pObjInfo);
1877
1878 Log(("VBOXSF: vbsfNtSetEndOfFile: VbglR0SfFsInfo returned %Rrc\n", vrc));
1879
1880 Status = vbsfNtVBoxStatusToNt(vrc);
1881 if (Status == STATUS_SUCCESS)
1882 {
1883 pVBoxFobx->fTimestampsImplicitlyUpdated |= VBOX_FOBX_F_INFO_LASTWRITE_TIME;
1884 if (pVBoxFcbx->pFobxLastWriteTime != pVBoxFobx)
1885 pVBoxFcbx->pFobxLastWriteTime = NULL;
1886
1887 Log(("VBOXSF: vbsfNtSetEndOfFile: VbglR0SfFsInfo new allocation size = %RX64\n",
1888 pObjInfo->cbAllocated));
1889
1890 /** @todo update the file stats! */
1891 }
1892
1893 if (pObjInfo)
1894 vbsfNtFreeNonPagedMem(pObjInfo);
1895
1896 Log(("VBOXSF: vbsfNtSetEndOfFile: Returned 0x%08X\n", Status));
1897 return Status;
1898}
1899
1900/**
1901 * Worker for VBoxMRxSetFileInfo handling FileRenameInformation.
1902 *
1903 * @note Renaming files from the guest is _very_ expensive:
1904 * - 52175 ns/call on the host
1905 * - 844237 ns/call from the guest
1906 *
1907 * The explanation for this is that RTPathRename translates to a
1908 * MoveFileEx call, which ends up doing a lot more than opening the
1909 * file and setting rename information on that handle (W10):
1910 * - Opens the file.
1911 * - Queries FileAllInformation.
1912 * - Tries to open the new filename (result: 0x00000000 but not
1913 * opened by our code - weird).
1914 * - Queries FileNormalizedNameInformation (result: 0xc000000d).
1915 * - Does IOCTL_REDIR_QUERY_PATH_EX on \vboxsvr\IPC$.
1916 * - Tries to open \vboxsvr\IPC$ (result: 0xc0000016)
1917 * - Opens the parent directory.
1918 * - Queries directory info with old name as filter.
1919 * - Closes parent directory handle.
1920 * - Finally does FileRenameInformation.
1921 * - Closes the handle to the renamed file.
1922 */
1923static NTSTATUS vbsfNtRename(IN PRX_CONTEXT RxContext,
1924 IN PFILE_RENAME_INFORMATION pRenameInfo,
1925 IN ULONG cbInfo)
1926{
1927 RxCaptureFcb;
1928 RxCaptureFobx;
1929 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
1930 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
1931 PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen;
1932
1933 /* Make sure we've got valid buffer and filename sizes: */
1934 AssertReturn(cbInfo >= RT_UOFFSETOF(FILE_RENAME_INFORMATION, FileName), STATUS_INFO_LENGTH_MISMATCH);
1935 size_t const cbFilename = pRenameInfo->FileNameLength;
1936 AssertReturn(cbFilename < _64K - 2, STATUS_INVALID_PARAMETER);
1937 AssertReturn(cbInfo - RT_UOFFSETOF(FILE_RENAME_INFORMATION, FileName) >= cbFilename, STATUS_INFO_LENGTH_MISMATCH);
1938
1939 Log(("VBOXSF: vbsfNtRename: FileNameLength = %#x (%d), FileName = %.*ls\n",
1940 cbFilename, cbFilename, cbFilename / sizeof(WCHAR), &pRenameInfo->FileName[0]));
1941
1942/** @todo Add new function that also closes the handle, like for remove, saving a host call. */
1943
1944 /* Must close the file before renaming it! */
1945 if (pVBoxFobx->hFile != SHFL_HANDLE_NIL)
1946 {
1947 Log(("VBOXSF: vbsfNtRename: Closing handle %#RX64...\n", pVBoxFobx->hFile));
1948 vbsfNtCloseFileHandle(pNetRootExtension, pVBoxFobx, VBoxMRxGetFcbExtension(capFcb));
1949 }
1950
1951 /* Mark it as renamed, so we do nothing during close. */
1952 /** @todo r=bird: Isn't this a bit premature? */
1953 SetFlag(pSrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED);
1954
1955 /*
1956 * Allocate a request embedding the destination string.
1957 */
1958 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
1959 size_t const cbReq = RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath.String) + cbFilename + sizeof(RTUTF16);
1960 VBOXSFRENAMEWITHSRCBUFREQ *pReq = (VBOXSFRENAMEWITHSRCBUFREQ *)VbglR0PhysHeapAlloc((uint32_t)cbReq);
1961 if (pReq)
1962 {
1963 /* The destination path string. */
1964 pReq->StrDstPath.u16Size = (uint16_t)(cbFilename + sizeof(RTUTF16));
1965 pReq->StrDstPath.u16Length = (uint16_t)cbFilename;
1966 memcpy(&pReq->StrDstPath.String, pRenameInfo->FileName, cbFilename);
1967 pReq->StrDstPath.String.utf16[cbFilename / sizeof(RTUTF16)] = '\0';
1968
1969 /* The source path string. */
1970 PUNICODE_STRING pNtSrcPath = GET_ALREADY_PREFIXED_NAME(pSrvOpen, capFcb);
1971 uint16_t const cbSrcPath = pNtSrcPath->Length;
1972 PSHFLSTRING pShflSrcPath = (PSHFLSTRING)VbglR0PhysHeapAlloc(SHFLSTRING_HEADER_SIZE + cbSrcPath + sizeof(RTUTF16));
1973 if (pShflSrcPath)
1974 {
1975 pShflSrcPath->u16Length = cbSrcPath;
1976 pShflSrcPath->u16Size = cbSrcPath + (uint16_t)sizeof(RTUTF16);
1977 memcpy(&pShflSrcPath->String, pNtSrcPath->Buffer, cbSrcPath);
1978 pShflSrcPath->String.utf16[cbSrcPath / sizeof(RTUTF16)] = '\0';
1979
1980 /*
1981 * Call the host.
1982 */
1983 uint32_t fRename = pVBoxFobx->Info.Attr.fMode & RTFS_DOS_DIRECTORY ? SHFL_RENAME_DIR : SHFL_RENAME_FILE;
1984 if (pRenameInfo->ReplaceIfExists)
1985 fRename |= SHFL_RENAME_REPLACE_IF_EXISTS;
1986 Log(("VBOXSF: vbsfNtRename: Calling VbglR0SfHostReqRenameWithSrcBuf fFlags=%#x SrcPath=%.*ls, DstPath=%.*ls\n",
1987 fRename, pShflSrcPath->u16Length / sizeof(RTUTF16), pShflSrcPath->String.utf16,
1988 pReq->StrDstPath.u16Size / sizeof(RTUTF16), pReq->StrDstPath.String.utf16));
1989 int vrc = VbglR0SfHostReqRenameWithSrcBuf(pNetRootExtension->map.root, pReq, pShflSrcPath, fRename);
1990 if (RT_SUCCESS(vrc))
1991 Status = STATUS_SUCCESS;
1992 else
1993 {
1994 Status = vbsfNtVBoxStatusToNt(vrc);
1995 Log(("VBOXSF: vbsfNtRename: VbglR0SfRename failed with %Rrc (Status=%#x)\n", vrc, Status));
1996 }
1997
1998 VbglR0PhysHeapFree(pShflSrcPath);
1999 }
2000 VbglR0PhysHeapFree(pReq);
2001 }
2002 Log(("VBOXSF: vbsfNtRename: Returned 0x%08X\n", Status));
2003 return Status;
2004}
2005
2006/**
2007 * Handle NtSetInformationFile and similar requests.
2008 *
2009 * The RDBSS code has done various things before we get here wrt locking and
2010 * request pre-processing. It will normally acquire an exclusive FCB lock, but
2011 * not if this is related to a page file (FCB_STATE_PAGING_FILE set).
2012 */
2013NTSTATUS VBoxMRxSetFileInfo(IN PRX_CONTEXT RxContext)
2014{
2015 RxCaptureFcb;
2016 RxCaptureFobx;
2017 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
2018 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
2019 NTSTATUS Status = STATUS_SUCCESS;
2020
2021 Log(("VBOXSF: MrxSetFileInfo: Buffer = %p, Length = %#x (%d), FileInformationClass = %d\n",
2022 RxContext->Info.Buffer, RxContext->Info.Length, RxContext->Info.Length, RxContext->Info.FileInformationClass));
2023
2024 /*
2025 * The essence of the size validation table for NtSetInformationFile from w10 build 17763:
2026 * UCHAR IoCheckQuerySetFileInformation[77]:
2027 * db 28h ; 4 FileBasicInformation, w7
2028 * db 18h ; 10 FileRenameInformation, w7
2029 * db 18h ; 11 FileLinkInformation, w7
2030 * db 1 ; 13 FileDispositionInformation, w7
2031 * db 8 ; 14 FilePositionInformation, w7
2032 * db 4 ; 16 FileModeInformation,
2033 * db 8 ; 19 FileAllocationInformation, w7
2034 * db 8 ; 20 FileEndOfFileInformation, w7
2035 * db 8 ; 23 FilePipeInformation, w7
2036 * db 10h ; 25 FilePipeRemoteInformation, w7
2037 * db 8 ; 27 FileMailslotSetInformation,
2038 * db 48h ; 29 FileObjectIdInformation,
2039 * db 10h ; 30 FileCompletionInformation, - "reserved for system use"
2040 * db 18h ; 31 FileMoveClusterInformation, w7 - "reserved for system use"
2041 * db 38h ; 32 FileQuotaInformation,
2042 * db 10h ; 36 FileTrackingInformation, - "reserved for system use"
2043 * db 8 ; 39 FileValidDataLengthInformation, w7
2044 * db 8 ; 40 FileShortNameInformation, w7
2045 * db 4 ; 41 FileIoCompletionNotificationInformation, - "reserved for system use"
2046 * db 10h ; 42 FileIoStatusBlockRangeInformation, - "reserved for system use"
2047 * db 4 ; 43 FileIoPriorityHintInformation,
2048 * db 14h ; 44 FileSfioReserveInformation, - "reserved for system use"
2049 * db 10h ; 61 FileReplaceCompletionInformation,
2050 * db 4 ; 64 FileDispositionInformationEx, - Adds posix semantics and stuff.
2051 * db 18h ; 65 FileRenameInformationEx, - Adds posix semantics and stuff.
2052 * db 8 ; 67 FileDesiredStorageClassInformation,
2053 * db 10h ; 69 FileMemoryPartitionInformation, - "reserved for system use", W10-1709
2054 * db 4 ; 71 FileCaseSensitiveInformation, - Per dir case sensitivity. (For linux?)
2055 * db 18h ; 72 FileLinkInformationEx, - Adds posix semantics and stuff.
2056 * db 4 ; 74 FileStorageReserveIdInformation,
2057 * db 4 ; 75 FileCaseSensitiveInformationForceAccessCheck, - for the i/o manager, w10-1809.
2058 *
2059 * Note! Using WDK 7600.16385.1/wnet, we're limited in what gets passed along, unknown
2060 * stuff will be rejected with STATUS_INVALID_PARAMETER and never get here. OTOH,
2061 * the 10.00.16299.0 WDK will forward anything it doesn't know from what I can tell.
2062 * Not sure exactly when this changed.
2063 */
2064 switch ((int)RxContext->Info.FileInformationClass)
2065 {
2066 /*
2067 * This is used to modify timestamps and attributes.
2068 *
2069 * Upon successful return, RDBSS will ensure that FILE_ATTRIBUTE_DIRECTORY is set
2070 * according to the FCB object type (see RxFinishFcbInitialization in path.cpp),
2071 * and that the FILE_ATTRIBUTE_TEMPORARY attribute is reflected in FcbState
2072 * (FCB_STATE_TEMPORARY) and the file object flags (FO_TEMPORARY_FILE). It will
2073 * also copy each non-zero timestamp into the FCB and set the corresponding
2074 * FOBX_FLAG_USER_SET_xxxx flag in the FOBX.
2075 *
2076 * RDBSS behaviour is idential between 16299.0/w10 and 7600.16385.1/wnet.
2077 */
2078 case FileBasicInformation:
2079 {
2080 Assert(RxContext->Info.Length >= sizeof(FILE_BASIC_INFORMATION));
2081 Status = vbsfNtSetBasicInfo(pNetRootExtension, RxContext->pFobx->AssociatedFileObject, pVBoxFobx, capFcb,
2082 VBoxMRxGetFcbExtension(capFcb), (PFILE_BASIC_INFORMATION)RxContext->Info.Buffer);
2083 break;
2084 }
2085
2086 /*
2087 * This is used to rename a file.
2088 */
2089 case FileRenameInformation:
2090 {
2091#ifdef LOG_ENABLED
2092 PFILE_RENAME_INFORMATION pInfo = (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer;
2093 Log(("VBOXSF: MrxSetFileInfo: FileRenameInformation: ReplaceIfExists = %d, RootDirectory = 0x%x = [%.*ls]\n",
2094 pInfo->ReplaceIfExists, pInfo->RootDirectory, pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
2095#endif
2096
2097 Status = vbsfNtRename(RxContext, (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer, RxContext->Info.Length);
2098 break;
2099 }
2100
2101 /*
2102 * This is presumably used for hardlinking purposes. We don't support that.
2103 */
2104 case FileLinkInformation:
2105 {
2106#ifdef LOG_ENABLED
2107 PFILE_LINK_INFORMATION pInfo = (PFILE_LINK_INFORMATION )RxContext->Info.Buffer;
2108 Log(("VBOXSF: MrxSetFileInfo: FileLinkInformation: ReplaceIfExists = %d, RootDirectory = 0x%x = [%.*ls]. Not implemented!\n",
2109 pInfo->ReplaceIfExists, pInfo->RootDirectory, pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
2110#endif
2111
2112 Status = STATUS_NOT_IMPLEMENTED;
2113 break;
2114 }
2115
2116 /*
2117 * This is used to delete file.
2118 */
2119 case FileDispositionInformation:
2120 {
2121 PFILE_DISPOSITION_INFORMATION pInfo = (PFILE_DISPOSITION_INFORMATION)RxContext->Info.Buffer;
2122 Log(("VBOXSF: MrxSetFileInfo: FileDispositionInformation: Delete = %d\n",
2123 pInfo->DeleteFile));
2124
2125 if (pInfo->DeleteFile && capFcb->OpenCount == 1)
2126 Status = vbsfNtRemove(RxContext);
2127 else
2128 Status = STATUS_SUCCESS;
2129 break;
2130 }
2131
2132 /*
2133 * The file position is handled by the RDBSS library (RxSetPositionInfo)
2134 * and we should never see this request.
2135 */
2136 case FilePositionInformation:
2137 AssertMsgFailed(("VBOXSF: MrxSetFileInfo: FilePositionInformation: CurrentByteOffset = 0x%RX64. Unsupported!\n",
2138 ((PFILE_POSITION_INFORMATION)RxContext->Info.Buffer)->CurrentByteOffset.QuadPart));
2139 Status = STATUS_INTERNAL_ERROR;
2140 break;
2141
2142 /*
2143 * Change the allocation size, leaving the EOF alone unless the file shrinks.
2144 *
2145 * There is no shared folder operation for this, so we only need to care
2146 * about adjusting EOF if the file shrinks.
2147 *
2148 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d4bc551b-7aaf-4b4f-ba0e-3a75e7c528f0#Appendix_A_83
2149 */
2150 case FileAllocationInformation:
2151 {
2152 PFILE_ALLOCATION_INFORMATION pInfo = (PFILE_ALLOCATION_INFORMATION)RxContext->Info.Buffer;
2153 Log(("VBOXSF: MrxSetFileInfo: FileAllocationInformation: new AllocSize = 0x%RX64, FileSize = 0x%RX64\n",
2154 pInfo->AllocationSize.QuadPart, capFcb->Header.FileSize.QuadPart));
2155
2156 if (pInfo->AllocationSize.QuadPart >= capFcb->Header.FileSize.QuadPart)
2157 Status = STATUS_SUCCESS;
2158 else
2159 {
2160 /** @todo get up to date EOF from host? We may risk accidentally growing the
2161 * file here if the host (or someone else) truncated it. */
2162 Status = vbsfNtSetEndOfFile(RxContext, pInfo->AllocationSize.QuadPart);
2163 }
2164 break;
2165 }
2166
2167 /*
2168 * Prior to calling us, RxSetEndOfFileInfo will have updated the FCB fields space.FileSize,
2169 * Header.AllocationSize and (if old value was larger) Header.ValidDataLength. On success
2170 * it will inform the cache manager, while on failure the old values will be restored.
2171 *
2172 * Note! RxSetEndOfFileInfo assumes that the old Header.FileSize value is up to date and
2173 * will hide calls which does not change the size from us. This is of course not
2174 * the case for non-local file systems, as the server is the only which up-to-date
2175 * information.
2176 *
2177 * We work around this either by modifying FCB.Header.FileSize slightly when it equals
2178 * the new size. This is either done below in the FileEndOfFileInformation + 4096 case,
2179 * or when using older WDK libs in VBoxHookMjSetInformation. The FCB is locked
2180 * exclusivly while we operate with the incorrect Header.FileSize value, which should
2181 * prevent anyone else from making use of it till it has been updated again.
2182 *
2183 */
2184 case FileEndOfFileInformation:
2185 {
2186 PFILE_END_OF_FILE_INFORMATION pInfo = (PFILE_END_OF_FILE_INFORMATION)RxContext->Info.Buffer;
2187 Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation: new EndOfFile 0x%RX64, FileSize = 0x%RX64\n",
2188 pInfo->EndOfFile.QuadPart, capFcb->Header.FileSize.QuadPart));
2189
2190 Status = vbsfNtSetEndOfFile(RxContext, pInfo->EndOfFile.QuadPart);
2191
2192 Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation: Status 0x%08X\n",
2193 Status));
2194 break;
2195 }
2196
2197#if 0 /* This only works for more recent versions of the RDBSS library, not for the one we're using (WDK 7600.16385.1). */
2198 /*
2199 * HACK ALERT! This is FileEndOfFileInformation after it passed thru
2200 * VBoxHookMjSetInformation so we can twiddle the cached file size in
2201 * the FCB to ensure the set EOF request always reaches the host.
2202 *
2203 * Note! We have to call thru RxSetEndOfFileInfo to benefit from its
2204 * update logic and avoid needing to replicate that code.
2205 */
2206 case FileEndOfFileInformation + 4096:
2207 {
2208 PFILE_END_OF_FILE_INFORMATION pInfo = (PFILE_END_OF_FILE_INFORMATION)RxContext->Info.Buffer;
2209 Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation+4096: new EndOfFile 0x%RX64, FileSize = 0x%RX64\n",
2210 pInfo->EndOfFile.QuadPart, capFcb->Header.FileSize.QuadPart));
2211
2212 /* Undo the change from VBoxHookMjSetInformation: */
2213 Assert(RxContext->CurrentIrpSp);
2214 RxContext->CurrentIrpSp->Parameters.SetFile.FileInformationClass = FileEndOfFileInformation;
2215 RxContext->Info.FileInformationClass = FileEndOfFileInformation;
2216
2217 /* Tweak the size if necessary and forward the call. */
2218 int64_t const cbOldSize = capFcb->Header.FileSize.QuadPart;
2219 if ( pInfo->EndOfFile.QuadPart != cbOldSize
2220 || !(capFcb->FcbState & FCB_STATE_PAGING_FILE))
2221 {
2222 Status = RxSetEndOfFileInfo(RxContext, RxContext->CurrentIrp, (PFCB)capFcb, (PFOBX)capFobx);
2223 Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation+4096: Status 0x%08X\n",
2224 Status));
2225 }
2226 else
2227 {
2228 int64_t const cbHackedSize = cbOldSize ? cbOldSize - 1 : 1;
2229 capFcb->Header.FileSize.QuadPart = cbHackedSize;
2230 Status = RxSetEndOfFileInfo(RxContext, RxContext->CurrentIrp, (PFCB)capFcb, (PFOBX)capFobx);
2231 if ( !NT_SUCCESS(Status)
2232 && capFcb->Header.FileSize.QuadPart == cbHackedSize)
2233 capFcb->Header.FileSize.QuadPart = cbOldSize;
2234 else
2235 Assert( capFcb->Header.FileSize.QuadPart != cbHackedSize
2236 || pVBoxFobx->Info.cbObject == cbHackedSize);
2237 Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation+4096: Status 0x%08X (tweaked)\n",
2238 Status));
2239 }
2240 break;
2241 }
2242#endif
2243
2244 /// @todo FileModeInformation ?
2245 /// @todo return access denied or something for FileValidDataLengthInformation?
2246
2247 default:
2248 Log(("VBOXSF: MrxSetFileInfo: Not supported FileInformationClass: %d!\n",
2249 RxContext->Info.FileInformationClass));
2250 Status = STATUS_INVALID_PARAMETER;
2251 break;
2252 }
2253
2254 Log(("VBOXSF: MrxSetFileInfo: Returned 0x%08X\n", Status));
2255 return Status;
2256}
2257
2258NTSTATUS VBoxMRxSetFileInfoAtCleanup(IN PRX_CONTEXT RxContext)
2259{
2260 RT_NOREF(RxContext);
2261 Log(("VBOXSF: MRxSetFileInfoAtCleanup\n"));
2262 return STATUS_SUCCESS;
2263}
2264
Note: See TracBrowser for help on using the repository browser.

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