VirtualBox

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

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

winnt/vboxsf: Reworked the set-timestamp handling. Need testcase and some host service tinkering. Also optimized handle closing. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 77.1 KB
Line 
1/* $Id: info.cpp 78355 2019-04-30 03:48:46Z 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/err.h>
24
25
26/*********************************************************************************************************************************
27* Defined Constants And Macros *
28*********************************************************************************************************************************/
29/** Macro for copying a SHFLSTRING file name into a FILE_DIRECTORY_INFORMATION structure. */
30#define INIT_FILE_NAME(obj, str) \
31 do { \
32 ULONG cbLength = (str).u16Length; \
33 (obj)->FileNameLength = cbLength; \
34 RtlCopyMemory((obj)->FileName, &(str).String.ucs2[0], cbLength + 2); \
35 } while (0)
36
37
38NTSTATUS VBoxMRxQueryDirectory(IN OUT PRX_CONTEXT RxContext)
39{
40 NTSTATUS Status = STATUS_SUCCESS;
41
42 RxCaptureFobx;
43 RxCaptureFcb;
44
45 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
46 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
47
48 PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
49 PUNICODE_STRING Template = &capFobx->UnicodeQueryTemplate;
50 FILE_INFORMATION_CLASS FileInformationClass = RxContext->Info.FileInformationClass;
51 PCHAR pInfoBuffer = (PCHAR)RxContext->Info.Buffer;
52 LONG cbMaxSize = RxContext->Info.Length;
53 LONG *pLengthRemaining = (LONG *)&RxContext->Info.LengthRemaining;
54
55 LONG cbToCopy;
56 int vrc;
57 uint8_t *pHGCMBuffer;
58 uint32_t index, fSFFlags, cFiles, u32BufSize;
59 LONG cbHGCMBuffer;
60 PSHFLDIRINFO pDirEntry;
61
62 ULONG *pNextOffset = 0;
63 PSHFLSTRING ParsedPath = NULL;
64
65 Log(("VBOXSF: MrxQueryDirectory: FileInformationClass %d, pVBoxFobx %p, hFile %RX64, pInfoBuffer %p\n",
66 FileInformationClass, pVBoxFobx, pVBoxFobx->hFile, pInfoBuffer));
67
68 if (!pVBoxFobx)
69 {
70 Log(("VBOXSF: MrxQueryDirectory: pVBoxFobx is invalid!\n"));
71 return STATUS_INVALID_PARAMETER;
72 }
73
74 if (!DirectoryName)
75 return STATUS_INVALID_PARAMETER;
76
77 if (DirectoryName->Length == 0)
78 Log(("VBOXSF: MrxQueryDirectory: DirectoryName = \\ (null string)\n"));
79 else
80 Log(("VBOXSF: MrxQueryDirectory: DirectoryName = %.*ls\n",
81 DirectoryName->Length / sizeof(WCHAR), DirectoryName->Buffer));
82
83 if (!Template)
84 return STATUS_INVALID_PARAMETER;
85
86 if (Template->Length == 0)
87 Log(("VBOXSF: MrxQueryDirectory: Template = \\ (null string)\n"));
88 else
89 Log(("VBOXSF: MrxQueryDirectory: Template = %.*ls\n",
90 Template->Length / sizeof(WCHAR), Template->Buffer));
91
92 cbHGCMBuffer = RT_MAX(cbMaxSize, PAGE_SIZE);
93
94 Log(("VBOXSF: MrxQueryDirectory: Allocating cbHGCMBuffer = %d\n",
95 cbHGCMBuffer));
96
97 pHGCMBuffer = (uint8_t *)vbsfNtAllocNonPagedMem(cbHGCMBuffer);
98 if (!pHGCMBuffer)
99 {
100 AssertFailed();
101 return STATUS_INSUFFICIENT_RESOURCES;
102 }
103
104 /* Assume start from the beginning. */
105 index = 0;
106 if (RxContext->QueryDirectory.IndexSpecified == TRUE)
107 {
108 Log(("VBOXSF: MrxQueryDirectory: Index specified %d\n",
109 index));
110 index = RxContext->QueryDirectory.FileIndex;
111 }
112
113 fSFFlags = SHFL_LIST_NONE;
114 if (RxContext->QueryDirectory.ReturnSingleEntry == TRUE)
115 {
116 Log(("VBOXSF: MrxQueryDirectory: Query single entry\n"));
117 fSFFlags |= SHFL_LIST_RETURN_ONE;
118 }
119 if ( RxContext->QueryDirectory.RestartScan == TRUE
120 && RxContext->QueryDirectory.InitialQuery == FALSE)
121 {
122 Log(("VBOXSF: MrxQueryDirectory: Restart scan\n"));
123 fSFFlags |= SHFL_LIST_RESTART;
124 }
125
126 if (Template->Length)
127 {
128 ULONG ParsedPathSize, cch;
129
130 /* Calculate size required for parsed path: dir + \ + template + 0. */
131 ParsedPathSize = SHFLSTRING_HEADER_SIZE + Template->Length + sizeof(WCHAR);
132 if (DirectoryName->Length)
133 ParsedPathSize += DirectoryName->Length + sizeof(WCHAR);
134 Log(("VBOXSF: MrxQueryDirectory: ParsedPathSize = %d\n", ParsedPathSize));
135
136 ParsedPath = (PSHFLSTRING)vbsfNtAllocNonPagedMem(ParsedPathSize);
137 if (!ParsedPath)
138 {
139 Status = STATUS_INSUFFICIENT_RESOURCES;
140 goto end;
141 }
142
143 if (!ShflStringInitBuffer(ParsedPath, ParsedPathSize))
144 {
145 Status = STATUS_INSUFFICIENT_RESOURCES;
146 goto end;
147 }
148
149 cch = 0;
150 if (DirectoryName->Length)
151 {
152 /* Copy directory name into ParsedPath. */
153 RtlCopyMemory(ParsedPath->String.ucs2, DirectoryName->Buffer, DirectoryName->Length);
154 cch += DirectoryName->Length / sizeof(WCHAR);
155
156 /* Add terminating backslash. */
157 ParsedPath->String.ucs2[cch] = L'\\';
158 cch++;
159 }
160
161 RtlCopyMemory (&ParsedPath->String.ucs2[cch], Template->Buffer, Template->Length);
162 cch += Template->Length / sizeof(WCHAR);
163
164 /* Add terminating nul. */
165 ParsedPath->String.ucs2[cch] = 0;
166
167 /* cch is the number of chars without trailing nul. */
168 ParsedPath->u16Length = (uint16_t)(cch * sizeof(WCHAR));
169
170 AssertMsg(ParsedPath->u16Length + sizeof(WCHAR) == ParsedPath->u16Size,
171 ("u16Length %d, u16Size %d\n", ParsedPath->u16Length, ParsedPath->u16Size));
172
173 Log(("VBOXSF: MrxQueryDirectory: ParsedPath = %.*ls\n",
174 ParsedPath->u16Length / sizeof(WCHAR), ParsedPath->String.ucs2));
175 }
176
177 cFiles = 0;
178
179 /* VbglR0SfDirInfo requires a pointer to uint32_t. */
180 u32BufSize = cbHGCMBuffer;
181
182 Log(("VBOXSF: MrxQueryDirectory: CallDirInfo: File = 0x%08x, Flags = 0x%08x, Index = %d, u32BufSize = %d\n",
183 pVBoxFobx->hFile, fSFFlags, index, u32BufSize));
184 vrc = VbglR0SfDirInfo(&g_SfClient, &pNetRootExtension->map, pVBoxFobx->hFile,
185 ParsedPath, fSFFlags, index, &u32BufSize, (PSHFLDIRINFO)pHGCMBuffer, &cFiles);
186 Log(("VBOXSF: MrxQueryDirectory: u32BufSize after CallDirInfo = %d, rc = %Rrc\n",
187 u32BufSize, vrc));
188
189 switch (vrc)
190 {
191 case VINF_SUCCESS:
192 /* Nothing to do here. */
193 break;
194
195 case VERR_NO_TRANSLATION:
196 Log(("VBOXSF: MrxQueryDirectory: Host could not translate entry!\n"));
197 break;
198
199 case VERR_NO_MORE_FILES:
200 if (cFiles <= 0) /* VERR_NO_MORE_FILES appears at the first lookup when just returning the current dir ".".
201 * So we also have to check for the cFiles counter. */
202 {
203 /* Not an error, but we have to handle the return value. */
204 Log(("VBOXSF: MrxQueryDirectory: Host reported no more files!\n"));
205
206 if (RxContext->QueryDirectory.InitialQuery)
207 {
208 /* First call. MSDN on FindFirstFile: "If the function fails because no matching files
209 * can be found, the GetLastError function returns ERROR_FILE_NOT_FOUND."
210 * So map this rc to file not found.
211 */
212 Status = STATUS_NO_SUCH_FILE;
213 }
214 else
215 {
216 /* Search continued. */
217 Status = STATUS_NO_MORE_FILES;
218 }
219 }
220 break;
221
222 case VERR_FILE_NOT_FOUND:
223 Status = STATUS_NO_SUCH_FILE;
224 Log(("VBOXSF: MrxQueryDirectory: no such file!\n"));
225 break;
226
227 default:
228 Status = vbsfNtVBoxStatusToNt(vrc);
229 Log(("VBOXSF: MrxQueryDirectory: Error %Rrc from CallDirInfo (cFiles=%d)!\n",
230 vrc, cFiles));
231 break;
232 }
233
234 if (Status != STATUS_SUCCESS)
235 goto end;
236
237 /* Verify that the returned buffer length is not greater than the original one. */
238 if (u32BufSize > (uint32_t)cbHGCMBuffer)
239 {
240 Log(("VBOXSF: MrxQueryDirectory: returned buffer size (%u) is invalid!!!\n",
241 u32BufSize));
242 Status = STATUS_INVALID_NETWORK_RESPONSE;
243 goto end;
244 }
245
246 /* How many bytes remain in the buffer. */
247 cbHGCMBuffer = u32BufSize;
248
249 pDirEntry = (PSHFLDIRINFO)pHGCMBuffer;
250 Status = STATUS_SUCCESS;
251
252 Log(("VBOXSF: MrxQueryDirectory: cFiles=%d, Length=%d\n",
253 cFiles, cbHGCMBuffer));
254
255 while ((*pLengthRemaining) && (cFiles > 0) && (pDirEntry != NULL))
256 {
257 int cbEntry = RT_UOFFSETOF(SHFLDIRINFO, name.String) + pDirEntry->name.u16Size;
258
259 if (cbEntry > cbHGCMBuffer)
260 {
261 Log(("VBOXSF: MrxQueryDirectory: Entry size (%d) exceeds the buffer size (%d)!!!\n",
262 cbEntry, cbHGCMBuffer));
263 Status = STATUS_INVALID_NETWORK_RESPONSE;
264 goto end;
265 }
266
267 switch (FileInformationClass)
268 {
269 case FileDirectoryInformation:
270 {
271 PFILE_DIRECTORY_INFORMATION pInfo = (PFILE_DIRECTORY_INFORMATION)pInfoBuffer;
272 Log(("VBOXSF: MrxQueryDirectory: FileDirectoryInformation\n"));
273
274 cbToCopy = sizeof(FILE_DIRECTORY_INFORMATION);
275 /* Struct already contains one char for null terminator. */
276 cbToCopy += pDirEntry->name.u16Size;
277
278 if (*pLengthRemaining >= cbToCopy)
279 {
280 RtlZeroMemory(pInfo, cbToCopy);
281
282 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
283 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
284 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
285 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
286 pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
287 pInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
288 pInfo->FileIndex = index;
289 pInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
290
291 INIT_FILE_NAME(pInfo, pDirEntry->name);
292
293 /* Align to 8 byte boundary */
294 cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
295 pInfo->NextEntryOffset = cbToCopy;
296 pNextOffset = &pInfo->NextEntryOffset;
297 }
298 else
299 {
300 pInfo->NextEntryOffset = 0; /* last item */
301 Status = STATUS_BUFFER_OVERFLOW;
302 }
303 break;
304 }
305
306 case FileFullDirectoryInformation:
307 {
308 PFILE_FULL_DIR_INFORMATION pInfo = (PFILE_FULL_DIR_INFORMATION)pInfoBuffer;
309 Log(("VBOXSF: MrxQueryDirectory: FileFullDirectoryInformation\n"));
310
311 cbToCopy = sizeof(FILE_FULL_DIR_INFORMATION);
312 /* Struct already contains one char for null terminator. */
313 cbToCopy += pDirEntry->name.u16Size;
314
315 if (*pLengthRemaining >= cbToCopy)
316 {
317 RtlZeroMemory(pInfo, cbToCopy);
318
319 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
320 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
321 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
322 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
323 pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
324 pInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
325 pInfo->EaSize = 0;
326 pInfo->FileIndex = index;
327 pInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
328
329 INIT_FILE_NAME(pInfo, pDirEntry->name);
330
331 /* Align to 8 byte boundary */
332 cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
333 pInfo->NextEntryOffset = cbToCopy;
334 pNextOffset = &pInfo->NextEntryOffset;
335 }
336 else
337 {
338 pInfo->NextEntryOffset = 0; /* last item */
339 Status = STATUS_BUFFER_OVERFLOW;
340 }
341 break;
342 }
343
344 case FileBothDirectoryInformation:
345 {
346 PFILE_BOTH_DIR_INFORMATION pInfo = (PFILE_BOTH_DIR_INFORMATION)pInfoBuffer;
347 Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation\n"));
348
349 cbToCopy = sizeof(FILE_BOTH_DIR_INFORMATION);
350 /* struct already contains one char for null terminator */
351 cbToCopy += pDirEntry->name.u16Size;
352
353 if (*pLengthRemaining >= cbToCopy)
354 {
355 RtlZeroMemory(pInfo, cbToCopy);
356
357 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
358 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
359 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
360 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
361 pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
362 pInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
363 pInfo->EaSize = 0;
364 pInfo->ShortNameLength = 0; /** @todo ? */
365 pInfo->FileIndex = index;
366 pInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
367
368 INIT_FILE_NAME(pInfo, pDirEntry->name);
369
370 Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation cbAlloc = %x cbObject = %x\n",
371 pDirEntry->Info.cbAllocated, pDirEntry->Info.cbObject));
372 Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation cbToCopy = %d, name size=%d name len=%d\n",
373 cbToCopy, pDirEntry->name.u16Size, pDirEntry->name.u16Length));
374 Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation File name %.*ls (DirInfo)\n",
375 pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
376 Log(("VBOXSF: MrxQueryDirectory: FileBothDirectoryInformation File name %.*ls (DirEntry)\n",
377 pDirEntry->name.u16Size / sizeof(WCHAR), pDirEntry->name.String.ucs2));
378
379 /* Align to 8 byte boundary. */
380 cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
381 pInfo->NextEntryOffset = cbToCopy;
382 pNextOffset = &pInfo->NextEntryOffset;
383 }
384 else
385 {
386 pInfo->NextEntryOffset = 0; /* Last item. */
387 Status = STATUS_BUFFER_OVERFLOW;
388 }
389 break;
390 }
391
392 case FileIdBothDirectoryInformation:
393 {
394 PFILE_ID_BOTH_DIR_INFORMATION pInfo = (PFILE_ID_BOTH_DIR_INFORMATION)pInfoBuffer;
395 Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation\n"));
396
397 cbToCopy = sizeof(FILE_ID_BOTH_DIR_INFORMATION);
398 /* struct already contains one char for null terminator */
399 cbToCopy += pDirEntry->name.u16Size;
400
401 if (*pLengthRemaining >= cbToCopy)
402 {
403 RtlZeroMemory(pInfo, cbToCopy);
404
405 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.BirthTime); /* ridiculous name */
406 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.AccessTime);
407 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ModificationTime);
408 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pDirEntry->Info.ChangeTime);
409 pInfo->AllocationSize.QuadPart = pDirEntry->Info.cbAllocated;
410 pInfo->EndOfFile.QuadPart = pDirEntry->Info.cbObject;
411 pInfo->EaSize = 0;
412 pInfo->ShortNameLength = 0; /** @todo ? */
413 pInfo->EaSize = 0;
414 pInfo->FileId.QuadPart = 0;
415 pInfo->FileAttributes = VBoxToNTFileAttributes(pDirEntry->Info.Attr.fMode);
416
417 INIT_FILE_NAME(pInfo, pDirEntry->name);
418
419 Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation cbAlloc = 0x%RX64 cbObject = 0x%RX64\n",
420 pDirEntry->Info.cbAllocated, pDirEntry->Info.cbObject));
421 Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation cbToCopy = %d, name size=%d name len=%d\n",
422 cbToCopy, pDirEntry->name.u16Size, pDirEntry->name.u16Length));
423 Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation File name %.*ls (DirInfo)\n",
424 pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
425 Log(("VBOXSF: MrxQueryDirectory: FileIdBothDirectoryInformation File name %.*ls (DirEntry)\n",
426 pDirEntry->name.u16Size / sizeof(WCHAR), pDirEntry->name.String.ucs2));
427
428 /* Align to 8 byte boundary. */
429 cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
430 pInfo->NextEntryOffset = cbToCopy;
431 pNextOffset = &pInfo->NextEntryOffset;
432 }
433 else
434 {
435 pInfo->NextEntryOffset = 0; /* Last item. */
436 Status = STATUS_BUFFER_OVERFLOW;
437 }
438 break;
439 }
440
441 case FileNamesInformation:
442 {
443 PFILE_NAMES_INFORMATION pInfo = (PFILE_NAMES_INFORMATION)pInfoBuffer;
444 Log(("VBOXSF: MrxQueryDirectory: FileNamesInformation\n"));
445
446 cbToCopy = sizeof(FILE_NAMES_INFORMATION);
447 /* Struct already contains one char for null terminator. */
448 cbToCopy += pDirEntry->name.u16Size;
449
450 if (*pLengthRemaining >= cbToCopy)
451 {
452 RtlZeroMemory(pInfo, cbToCopy);
453
454 pInfo->FileIndex = index;
455
456 INIT_FILE_NAME(pInfo, pDirEntry->name);
457
458 Log(("VBOXSF: MrxQueryDirectory: FileNamesInformation: File name [%.*ls]\n",
459 pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
460
461 /* Align to 8 byte boundary. */
462 cbToCopy = RT_ALIGN(cbToCopy, sizeof(LONGLONG));
463 pInfo->NextEntryOffset = cbToCopy;
464 pNextOffset = &pInfo->NextEntryOffset;
465 }
466 else
467 {
468 pInfo->NextEntryOffset = 0; /* Last item. */
469 Status = STATUS_BUFFER_OVERFLOW;
470 }
471 break;
472 }
473
474 default:
475 Log(("VBOXSF: MrxQueryDirectory: Not supported FileInformationClass %d!\n",
476 FileInformationClass));
477 Status = STATUS_INVALID_PARAMETER;
478 goto end;
479 }
480
481 cbHGCMBuffer -= cbEntry;
482 pDirEntry = (PSHFLDIRINFO)((uintptr_t)pDirEntry + cbEntry);
483
484 Log(("VBOXSF: MrxQueryDirectory: %d bytes left in HGCM buffer\n",
485 cbHGCMBuffer));
486
487 if (*pLengthRemaining >= cbToCopy)
488 {
489 pInfoBuffer += cbToCopy;
490 *pLengthRemaining -= cbToCopy;
491 }
492 else
493 break;
494
495 if (RxContext->QueryDirectory.ReturnSingleEntry)
496 break;
497
498 /* More left? */
499 if (cbHGCMBuffer <= 0)
500 break;
501
502 index++; /* File Index. */
503
504 cFiles--;
505 }
506
507 if (pNextOffset)
508 *pNextOffset = 0; /* Last pInfo->NextEntryOffset should be set to zero! */
509
510end:
511 if (pHGCMBuffer)
512 vbsfNtFreeNonPagedMem(pHGCMBuffer);
513
514 if (ParsedPath)
515 vbsfNtFreeNonPagedMem(ParsedPath);
516
517 Log(("VBOXSF: MrxQueryDirectory: Returned 0x%08X\n",
518 Status));
519 return Status;
520}
521
522NTSTATUS VBoxMRxQueryVolumeInfo(IN OUT PRX_CONTEXT RxContext)
523{
524 NTSTATUS Status;
525
526 RxCaptureFcb;
527 RxCaptureFobx;
528
529 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
530 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
531
532 FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass;
533 PVOID pInfoBuffer = RxContext->Info.Buffer;
534 ULONG cbInfoBuffer = RxContext->Info.LengthRemaining;
535 ULONG cbToCopy = 0;
536 ULONG cbString = 0;
537
538 Log(("VBOXSF: MrxQueryVolumeInfo: pInfoBuffer = %p, cbInfoBuffer = %d\n",
539 RxContext->Info.Buffer, RxContext->Info.LengthRemaining));
540 Log(("VBOXSF: MrxQueryVolumeInfo: vboxFobx = %p, Handle = 0x%RX64\n",
541 pVBoxFobx, pVBoxFobx? pVBoxFobx->hFile: 0));
542
543 Status = STATUS_INVALID_PARAMETER;
544
545 switch (FsInformationClass)
546 {
547 case FileFsVolumeInformation:
548 {
549 PFILE_FS_VOLUME_INFORMATION pInfo = (PFILE_FS_VOLUME_INFORMATION)pInfoBuffer;
550
551 PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
552 PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
553
554 PWCHAR pRootName;
555 ULONG cbRootName;
556
557 PSHFLVOLINFO pShflVolInfo;
558 uint32_t cbHGCMBuffer;
559 uint8_t *pHGCMBuffer;
560 int vrc;
561
562 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsVolumeInformation\n"));
563
564 if (!pVBoxFobx)
565 {
566 Log(("VBOXSF: MrxQueryVolumeInfo: pVBoxFobx is NULL!\n"));
567 Status = STATUS_INVALID_PARAMETER;
568 break;
569 }
570
571 cbRootName = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
572 cbRootName -= sizeof(WCHAR); /* Remove the leading backslash. */
573 pRootName = pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR));
574 pRootName++; /* Remove the leading backslash. */
575
576 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsVolumeInformation: Root name = %.*ls, %d bytes\n",
577 cbRootName / sizeof(WCHAR), pRootName, cbRootName));
578
579 cbToCopy = FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel);
580
581 cbString = VBOX_VOLNAME_PREFIX_SIZE;
582 cbString += cbRootName;
583 cbString += sizeof(WCHAR);
584
585 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsVolumeInformation: cbToCopy %d, cbString %d\n",
586 cbToCopy, cbString));
587
588 if (cbInfoBuffer < cbToCopy)
589 {
590 Status = STATUS_BUFFER_TOO_SMALL;
591 break;
592 }
593
594 RtlZeroMemory(pInfo, cbToCopy);
595
596 /* Query serial number. */
597 cbHGCMBuffer = sizeof(SHFLVOLINFO);
598 pHGCMBuffer = (uint8_t *)vbsfNtAllocNonPagedMem(cbHGCMBuffer);
599 if (!pHGCMBuffer)
600 {
601 Status = STATUS_INSUFFICIENT_RESOURCES;
602 break;
603 }
604
605 vrc = VbglR0SfFsInfo(&g_SfClient, &pNetRootExtension->map, pVBoxFobx->hFile,
606 SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer);
607
608 if (vrc != VINF_SUCCESS)
609 {
610 Status = vbsfNtVBoxStatusToNt(vrc);
611 vbsfNtFreeNonPagedMem(pHGCMBuffer);
612 break;
613 }
614
615 pShflVolInfo = (PSHFLVOLINFO)pHGCMBuffer;
616 pInfo->VolumeSerialNumber = pShflVolInfo->ulSerial;
617 vbsfNtFreeNonPagedMem(pHGCMBuffer);
618
619 pInfo->VolumeCreationTime.QuadPart = 0;
620 pInfo->SupportsObjects = FALSE;
621
622 if (cbInfoBuffer >= cbToCopy + cbString)
623 {
624 RtlCopyMemory(&pInfo->VolumeLabel[0],
625 VBOX_VOLNAME_PREFIX,
626 VBOX_VOLNAME_PREFIX_SIZE);
627 RtlCopyMemory(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)],
628 pRootName,
629 cbRootName);
630 pInfo->VolumeLabel[cbString / sizeof(WCHAR) - 1] = 0;
631 }
632 else
633 {
634 cbString = cbInfoBuffer - cbToCopy;
635
636 RtlCopyMemory(&pInfo->VolumeLabel[0],
637 VBOX_VOLNAME_PREFIX,
638 RT_MIN(cbString, VBOX_VOLNAME_PREFIX_SIZE));
639 if (cbString > VBOX_VOLNAME_PREFIX_SIZE)
640 {
641 RtlCopyMemory(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)],
642 pRootName,
643 cbString - VBOX_VOLNAME_PREFIX_SIZE);
644 }
645 }
646
647 pInfo->VolumeLabelLength = cbString;
648
649 cbToCopy += cbString;
650
651 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsVolumeInformation: VolumeLabelLength %d\n",
652 pInfo->VolumeLabelLength));
653
654 Status = STATUS_SUCCESS;
655 break;
656 }
657
658 case FileFsLabelInformation:
659 {
660 PFILE_FS_LABEL_INFORMATION pInfo = (PFILE_FS_LABEL_INFORMATION)pInfoBuffer;
661
662 PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
663 PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall;
664
665 PWCHAR pRootName;
666 ULONG cbRootName;
667
668 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsLabelInformation\n"));
669
670 cbRootName = pNetRoot->pNetRootName->Length - pSrvCall->pSrvCallName->Length;
671 cbRootName -= sizeof(WCHAR); /* Remove the leading backslash. */
672 pRootName = pNetRoot->pNetRootName->Buffer + (pSrvCall->pSrvCallName->Length / sizeof(WCHAR));
673 pRootName++; /* Remove the leading backslash. */
674
675 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsLabelInformation: Root name = %.*ls, %d bytes\n",
676 cbRootName / sizeof(WCHAR), pRootName, cbRootName));
677
678 cbToCopy = FIELD_OFFSET(FILE_FS_LABEL_INFORMATION, VolumeLabel);
679
680 cbString = VBOX_VOLNAME_PREFIX_SIZE;
681 cbString += cbRootName;
682 cbString += sizeof(WCHAR);
683
684 if (cbInfoBuffer < cbToCopy)
685 {
686 Status = STATUS_BUFFER_TOO_SMALL;
687 break;
688 }
689
690 RtlZeroMemory(pInfo, cbToCopy);
691
692 if (cbInfoBuffer >= cbToCopy + cbString)
693 {
694 RtlCopyMemory(&pInfo->VolumeLabel[0],
695 VBOX_VOLNAME_PREFIX,
696 VBOX_VOLNAME_PREFIX_SIZE);
697 RtlCopyMemory(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)],
698 pRootName,
699 cbRootName);
700 pInfo->VolumeLabel[cbString / sizeof(WCHAR) - 1] = 0;
701 }
702 else
703 {
704 cbString = cbInfoBuffer - cbToCopy;
705
706 RtlCopyMemory(&pInfo->VolumeLabel[0],
707 VBOX_VOLNAME_PREFIX,
708 RT_MIN(cbString, VBOX_VOLNAME_PREFIX_SIZE));
709 if (cbString > VBOX_VOLNAME_PREFIX_SIZE)
710 {
711 RtlCopyMemory(&pInfo->VolumeLabel[VBOX_VOLNAME_PREFIX_SIZE / sizeof(WCHAR)],
712 pRootName,
713 cbString - VBOX_VOLNAME_PREFIX_SIZE);
714 }
715 }
716
717 pInfo->VolumeLabelLength = cbString;
718
719 cbToCopy += cbString;
720
721 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsLabelInformation: VolumeLabelLength %d\n",
722 pInfo->VolumeLabelLength));
723
724 Status = STATUS_SUCCESS;
725 break;
726 }
727
728 case FileFsFullSizeInformation:
729 case FileFsSizeInformation:
730 {
731 PFILE_FS_FULL_SIZE_INFORMATION pFullSizeInfo = (PFILE_FS_FULL_SIZE_INFORMATION)pInfoBuffer;
732 PFILE_FS_SIZE_INFORMATION pSizeInfo = (PFILE_FS_SIZE_INFORMATION)pInfoBuffer;
733
734 uint32_t cbHGCMBuffer;
735 uint8_t *pHGCMBuffer;
736 int vrc;
737 PSHFLVOLINFO pShflVolInfo;
738
739 LARGE_INTEGER TotalAllocationUnits;
740 LARGE_INTEGER AvailableAllocationUnits;
741 ULONG SectorsPerAllocationUnit;
742 ULONG BytesPerSector;
743
744 if (FsInformationClass == FileFsFullSizeInformation)
745 {
746 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsFullSizeInformation\n"));
747 cbToCopy = sizeof(FILE_FS_FULL_SIZE_INFORMATION);
748 }
749 else
750 {
751 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsSizeInformation\n"));
752 cbToCopy = sizeof(FILE_FS_SIZE_INFORMATION);
753 }
754
755 if (!pVBoxFobx)
756 {
757 Log(("VBOXSF: MrxQueryVolumeInfo: pVBoxFobx is NULL!\n"));
758 Status = STATUS_INVALID_PARAMETER;
759 break;
760 }
761
762 if (cbInfoBuffer < cbToCopy)
763 {
764 Status = STATUS_BUFFER_TOO_SMALL;
765 break;
766 }
767
768 RtlZeroMemory(pInfoBuffer, cbToCopy);
769
770 cbHGCMBuffer = sizeof(SHFLVOLINFO);
771 pHGCMBuffer = (uint8_t *)vbsfNtAllocNonPagedMem(cbHGCMBuffer);
772 if (!pHGCMBuffer)
773 {
774 Status = STATUS_INSUFFICIENT_RESOURCES;
775 break;
776 }
777
778 vrc = VbglR0SfFsInfo(&g_SfClient, &pNetRootExtension->map, pVBoxFobx->hFile,
779 SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer);
780
781 if (vrc != VINF_SUCCESS)
782 {
783 Status = vbsfNtVBoxStatusToNt(vrc);
784 vbsfNtFreeNonPagedMem(pHGCMBuffer);
785 break;
786 }
787
788 pShflVolInfo = (PSHFLVOLINFO)pHGCMBuffer;
789
790 TotalAllocationUnits.QuadPart = pShflVolInfo->ullTotalAllocationBytes / pShflVolInfo->ulBytesPerAllocationUnit;
791 AvailableAllocationUnits.QuadPart = pShflVolInfo->ullAvailableAllocationBytes / pShflVolInfo->ulBytesPerAllocationUnit;
792 SectorsPerAllocationUnit = pShflVolInfo->ulBytesPerAllocationUnit / pShflVolInfo->ulBytesPerSector;
793 BytesPerSector = pShflVolInfo->ulBytesPerSector;
794
795 Log(("VBOXSF: MrxQueryVolumeInfo: TotalAllocationUnits 0x%RX64\n", TotalAllocationUnits.QuadPart));
796 Log(("VBOXSF: MrxQueryVolumeInfo: AvailableAllocationUnits 0x%RX64\n", AvailableAllocationUnits.QuadPart));
797 Log(("VBOXSF: MrxQueryVolumeInfo: SectorsPerAllocationUnit 0x%X\n", SectorsPerAllocationUnit));
798 Log(("VBOXSF: MrxQueryVolumeInfo: BytesPerSector 0x%X\n", BytesPerSector));
799
800 if (FsInformationClass == FileFsFullSizeInformation)
801 {
802 pFullSizeInfo->TotalAllocationUnits = TotalAllocationUnits;
803 pFullSizeInfo->CallerAvailableAllocationUnits = AvailableAllocationUnits;
804 pFullSizeInfo->ActualAvailableAllocationUnits = AvailableAllocationUnits;
805 pFullSizeInfo->SectorsPerAllocationUnit = SectorsPerAllocationUnit;
806 pFullSizeInfo->BytesPerSector = BytesPerSector;
807 }
808 else
809 {
810 pSizeInfo->TotalAllocationUnits = TotalAllocationUnits;
811 pSizeInfo->AvailableAllocationUnits = AvailableAllocationUnits;
812 pSizeInfo->SectorsPerAllocationUnit = SectorsPerAllocationUnit;
813 pSizeInfo->BytesPerSector = BytesPerSector;
814 }
815
816 vbsfNtFreeNonPagedMem(pHGCMBuffer);
817
818 Status = STATUS_SUCCESS;
819 break;
820 }
821
822 case FileFsDeviceInformation:
823 {
824 PFILE_FS_DEVICE_INFORMATION pInfo = (PFILE_FS_DEVICE_INFORMATION)pInfoBuffer;
825 PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
826
827 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsDeviceInformation: Type = %d\n",
828 NetRoot->DeviceType));
829
830 cbToCopy = sizeof(FILE_FS_DEVICE_INFORMATION);
831
832 if (cbInfoBuffer < cbToCopy)
833 {
834 Status = STATUS_BUFFER_TOO_SMALL;
835 break;
836 }
837
838 pInfo->DeviceType = NetRoot->DeviceType;
839 pInfo->Characteristics = FILE_REMOTE_DEVICE;
840
841 Status = STATUS_SUCCESS;
842 break;
843 }
844
845 case FileFsAttributeInformation:
846 {
847 PFILE_FS_ATTRIBUTE_INFORMATION pInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)pInfoBuffer;
848
849 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsAttributeInformation\n"));
850
851 cbToCopy = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName);
852
853 cbString = sizeof(MRX_VBOX_FILESYS_NAME_U);
854
855 if (cbInfoBuffer < cbToCopy)
856 {
857 Status = STATUS_BUFFER_TOO_SMALL;
858 break;
859 }
860
861 pInfo->FileSystemAttributes = 0; /** @todo set unicode, case sensitive etc? */
862 pInfo->MaximumComponentNameLength = 255; /** @todo should query from the host */
863
864 if (cbInfoBuffer >= cbToCopy + cbString)
865 {
866 RtlCopyMemory(pInfo->FileSystemName,
867 MRX_VBOX_FILESYS_NAME_U,
868 sizeof(MRX_VBOX_FILESYS_NAME_U));
869 }
870 else
871 {
872 cbString = cbInfoBuffer - cbToCopy;
873
874 RtlCopyMemory(pInfo->FileSystemName,
875 MRX_VBOX_FILESYS_NAME_U,
876 RT_MIN(cbString, sizeof(MRX_VBOX_FILESYS_NAME_U)));
877 }
878
879 pInfo->FileSystemNameLength = cbString;
880
881 cbToCopy += cbString;
882
883 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsAttributeInformation: FileSystemNameLength %d\n",
884 pInfo->FileSystemNameLength));
885
886 Status = STATUS_SUCCESS;
887 break;
888 }
889
890 case FileFsControlInformation:
891 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsControlInformation: not supported\n"));
892 Status = STATUS_INVALID_PARAMETER;
893 break;
894
895 case FileFsObjectIdInformation:
896 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsObjectIdInformation: not supported\n"));
897 Status = STATUS_INVALID_PARAMETER;
898 break;
899
900 case FileFsMaximumInformation:
901 Log(("VBOXSF: MrxQueryVolumeInfo: FileFsMaximumInformation: not supported\n"));
902 Status = STATUS_INVALID_PARAMETER;
903 break;
904
905 default:
906 Log(("VBOXSF: MrxQueryVolumeInfo: Not supported FsInformationClass %d!\n",
907 FsInformationClass));
908 Status = STATUS_INVALID_PARAMETER;
909 break;
910 }
911
912 if (Status == STATUS_SUCCESS)
913 RxContext->Info.LengthRemaining = cbInfoBuffer - cbToCopy;
914 else if (Status == STATUS_BUFFER_TOO_SMALL)
915 {
916 Log(("VBOXSF: MrxQueryVolumeInfo: Insufficient buffer size %d, required %d\n",
917 cbInfoBuffer, cbToCopy));
918 RxContext->InformationToReturn = cbToCopy;
919 }
920
921 Log(("VBOXSF: MrxQueryVolumeInfo: cbToCopy = %d, LengthRemaining = %d, Status = 0x%08X\n",
922 cbToCopy, RxContext->Info.LengthRemaining, Status));
923
924 return Status;
925}
926
927/**
928 * Updates the object info to the VBox file object extension data.
929 *
930 * @param pVBoxFobx The VBox file object extension data.
931 * @param pObjInfo The fresh data from the host. Okay to modify.
932 * @param pVBoxFcbx The VBox FCB extension data.
933 * @param fTimestampsToCopyAnyway VBOX_FOBX_F_INFO_XXX mask of timestamps to
934 * copy regardless of their suppressed state.
935 * This is used by the info setter function to
936 * get current copies of newly modified and
937 * suppressed fields.
938 */
939static void vbsfNtCopyInfo(PMRX_VBOX_FOBX pVBoxFobx, PSHFLFSOBJINFO pObjInfo,
940 PVBSFNTFCBEXT pVBoxFcbx, uint8_t fTimestampsToCopyAnyway)
941{
942 /*
943 * Check if the size changed.
944 */
945 if (pObjInfo->cbObject != pVBoxFobx->Info.cbObject)
946 {
947 /** @todo Tell RDBSS about this? Seems we have to tell the cache manager
948 * ourselves, which sucks considering that RDBSS was supposed to
949 * shield us from crap like that (see the MS sales brochure). */
950 }
951
952 /*
953 * Check if the modified timestamp changed and try guess if it was the host.
954 */
955 /** @todo use modification timestamp to detect host changes? We do on linux. */
956
957 /*
958 * Copy the object info over. To simplify preserving the value of timestamps
959 * which implict updating is currently disabled, copy them over to the source
960 * structure before preforming the copy.
961 */
962 Assert((pVBoxFobx->fTimestampsSetByUser & ~pVBoxFobx->fTimestampsUpdatingSuppressed) == 0);
963 uint8_t fCopyTs = pVBoxFobx->fTimestampsUpdatingSuppressed & ~fTimestampsToCopyAnyway;
964 if (fCopyTs)
965 {
966 if ( (fCopyTs & VBOX_FOBX_F_INFO_LASTACCESS_TIME)
967 && pVBoxFcbx->pFobxLastAccessTime == pVBoxFobx)
968 pObjInfo->AccessTime = pVBoxFobx->Info.AccessTime;
969
970 if ( (fCopyTs & VBOX_FOBX_F_INFO_LASTWRITE_TIME)
971 && pVBoxFcbx->pFobxLastWriteTime == pVBoxFobx)
972 pObjInfo->ModificationTime = pVBoxFobx->Info.ModificationTime;
973
974 if ( (fCopyTs & VBOX_FOBX_F_INFO_CHANGE_TIME)
975 && pVBoxFcbx->pFobxChangeTime == pVBoxFobx)
976 pObjInfo->ChangeTime = pVBoxFobx->Info.ChangeTime;
977 }
978 pVBoxFobx->Info = *pObjInfo;
979
980 /*
981 * Try eliminate this one.
982 */
983 vbsfNtBasicInfoFromVBoxObjInfo(&pVBoxFobx->FileBasicInfo, pObjInfo);
984}
985
986
987/**
988 * Handle NtQueryInformationFile and similar requests.
989 *
990 * The RDBSS code has done various things before we get here wrt locking and
991 * request pre-processing.
992 */
993NTSTATUS VBoxMRxQueryFileInfo(IN PRX_CONTEXT RxContext)
994{
995 RxCaptureFcb;
996 RxCaptureFobx;
997 NTSTATUS Status = STATUS_SUCCESS;
998 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
999 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
1000 ULONG cbToCopy = 0;
1001
1002 Log(("VBOXSF: MrxQueryFileInfo: Buffer = %p, Length = %x (%d) bytes, FileInformationClass = %d\n",
1003 RxContext->Info.Buffer, RxContext->Info.Length, RxContext->Info.Length, RxContext->Info.FileInformationClass));
1004
1005 AssertReturn(pVBoxFobx, STATUS_INVALID_PARAMETER);
1006 AssertReturn(RxContext->Info.Buffer, STATUS_INVALID_PARAMETER);
1007
1008#define CHECK_SIZE_BREAK(a_RxContext, a_cbNeeded) \
1009 /* IO_STACK_LOCATION::Parameters::SetFile::Length is signed, the RxContext bugger is LONG. See end of function for why. */ \
1010 if ((ULONG)(a_RxContext)->Info.Length >= (a_cbNeeded)) \
1011 { /*likely */ } \
1012 else if (1) { Status = STATUS_BUFFER_TOO_SMALL; break; } else do { } while (0)
1013
1014 switch (RxContext->Info.FileInformationClass)
1015 {
1016 /*
1017 * Queries we can satisfy without calling the host:
1018 */
1019
1020 case FileNamesInformation:
1021 {
1022 PFILE_NAMES_INFORMATION pInfo = (PFILE_NAMES_INFORMATION)RxContext->Info.Buffer;
1023 PUNICODE_STRING FileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
1024 Log(("VBOXSF: MrxQueryFileInfo: FileNamesInformation\n"));
1025
1026 cbToCopy = RT_UOFFSETOF_DYN(FILE_NAMES_INFORMATION, FileName[FileName->Length / 2 + 1]);
1027 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1028
1029 pInfo->NextEntryOffset = 0;
1030 pInfo->FileIndex = 0;
1031 pInfo->FileNameLength = FileName->Length;
1032
1033 RtlCopyMemory(pInfo->FileName, FileName->Buffer, FileName->Length);
1034 pInfo->FileName[FileName->Length] = 0;
1035 break;
1036 }
1037
1038 case FileInternalInformation:
1039 {
1040 PFILE_INTERNAL_INFORMATION pInfo = (PFILE_INTERNAL_INFORMATION)RxContext->Info.Buffer;
1041 Log(("VBOXSF: MrxQueryFileInfo: FileInternalInformation\n"));
1042
1043 cbToCopy = sizeof(FILE_INTERNAL_INFORMATION);
1044 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1045
1046 /* A 8-byte file reference number for the file. */
1047 pInfo->IndexNumber.QuadPart = (ULONG_PTR)capFcb;
1048 break;
1049 }
1050
1051 case FileEaInformation:
1052 {
1053 PFILE_EA_INFORMATION pInfo = (PFILE_EA_INFORMATION)RxContext->Info.Buffer;
1054 Log(("VBOXSF: MrxQueryFileInfo: FileEaInformation\n"));
1055
1056 cbToCopy = sizeof(FILE_EA_INFORMATION);
1057 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1058
1059 pInfo->EaSize = 0;
1060 break;
1061 }
1062
1063 case FileStreamInformation:
1064 Log(("VBOXSF: MrxQueryFileInfo: FileStreamInformation: not supported\n"));
1065 Status = STATUS_INVALID_PARAMETER;
1066 break;
1067
1068 case FileAlternateNameInformation:
1069 Log(("VBOXSF: MrxQueryFileInfo: FileStreamInformation: not implemented\n"));
1070 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1071 break;
1072
1073 case FileNumaNodeInformation:
1074 Log(("VBOXSF: MrxQueryFileInfo: FileNumaNodeInformation: not supported\n"));
1075 Status = STATUS_NO_SUCH_DEVICE; /* what's returned on a samba share */
1076 break;
1077
1078 case FileStandardLinkInformation:
1079 Log(("VBOXSF: MrxQueryFileInfo: FileStandardLinkInformation: not supported\n"));
1080 Status = STATUS_NOT_SUPPORTED; /* what's returned on a samba share */
1081 break;
1082
1083 /*
1084 * Queries where we need info from the host.
1085 *
1086 * For directories we don't necessarily go to the host but use info from when we
1087 * opened the them, why we do this is a little unclear as all the clues that r9630
1088 * give is "fixes".
1089 *
1090 * Note! We verify the buffer size after talking to the host, assuming that there
1091 * won't be a problem and saving an extra switch statement. IIRC the
1092 * NtQueryInformationFile code verfies the sizes too.
1093 */
1094 /** @todo r=bird: install a hack so we get FileAllInformation directly up here
1095 * rather than 5 individual queries. We may end up going 3 times to
1096 * the host (depending on the TTL hack) to fetch the same info over
1097 * and over again. */
1098 case FileEndOfFileInformation:
1099 case FileAllocationInformation:
1100 case FileBasicInformation:
1101 case FileStandardInformation:
1102 case FileNetworkOpenInformation:
1103 case FileAttributeTagInformation:
1104 case FileCompressionInformation:
1105 {
1106 /* Query the information if necessary. */
1107 if ( !(pVBoxFobx->Info.Attr.fMode & RTFS_DOS_DIRECTORY) /** @todo figure out why we don't return up-to-date info for directories! */
1108 && ( !pVBoxFobx->nsUpToDate
1109 || pVBoxFobx->nsUpToDate - RTTimeSystemNanoTS() < RT_NS_100US /** @todo implement proper TTL */ ) )
1110 {
1111 PVBSFNTFCBEXT pVBoxFcbx = VBoxMRxGetFcbExtension(capFcb);
1112 AssertReturn(pVBoxFcbx, STATUS_INTERNAL_ERROR);
1113
1114 VBOXSFOBJINFOREQ *pReq = (VBOXSFOBJINFOREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
1115 AssertBreakStmt(pReq, Status = STATUS_NO_MEMORY);
1116
1117 int vrc = VbglR0SfHostReqQueryObjInfo(pNetRootExtension->map.root, pReq, pVBoxFobx->hFile);
1118 if (RT_SUCCESS(vrc))
1119 vbsfNtCopyInfo(pVBoxFobx, &pReq->ObjInfo, pVBoxFcbx, 0);
1120 else
1121 {
1122 Status = vbsfNtVBoxStatusToNt(vrc);
1123 VbglR0PhysHeapFree(pReq);
1124 break;
1125 }
1126 VbglR0PhysHeapFree(pReq);
1127 }
1128
1129 /* Copy it into the return buffer. */
1130 switch (RxContext->Info.FileInformationClass)
1131 {
1132 case FileBasicInformation:
1133 {
1134 PFILE_BASIC_INFORMATION pInfo = (PFILE_BASIC_INFORMATION)RxContext->Info.Buffer;
1135 Log(("VBOXSF: MrxQueryFileInfo: FileBasicInformation\n"));
1136
1137 cbToCopy = sizeof(FILE_BASIC_INFORMATION);
1138 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1139
1140 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.BirthTime);
1141 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.AccessTime);
1142 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.ModificationTime);
1143 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.ChangeTime);
1144 pInfo->FileAttributes = VBoxToNTFileAttributes(pVBoxFobx->Info.Attr.fMode);
1145 Log(("VBOXSF: MrxQueryFileInfo: FileBasicInformation: File attributes: 0x%x\n",
1146 pInfo->FileAttributes));
1147 break;
1148 }
1149
1150 case FileStandardInformation:
1151 {
1152 PFILE_STANDARD_INFORMATION pInfo = (PFILE_STANDARD_INFORMATION)RxContext->Info.Buffer;
1153 Log(("VBOXSF: MrxQueryFileInfo: FileStandardInformation\n"));
1154
1155 cbToCopy = sizeof(FILE_STANDARD_INFORMATION);
1156 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1157
1158 /* Note! We didn't used to set allocation size and end-of-file for directories.
1159 NTFS reports these, though, so why shouldn't we. */
1160 pInfo->AllocationSize.QuadPart = pVBoxFobx->Info.cbAllocated;
1161 pInfo->EndOfFile.QuadPart = pVBoxFobx->Info.cbObject;
1162 pInfo->NumberOfLinks = 1; /** @todo 0? */
1163 pInfo->DeletePending = FALSE;
1164 pInfo->Directory = pVBoxFobx->Info.Attr.fMode & RTFS_DOS_DIRECTORY ? TRUE : FALSE;
1165 break;
1166 }
1167
1168 case FileNetworkOpenInformation:
1169 {
1170 PFILE_NETWORK_OPEN_INFORMATION pInfo = (PFILE_NETWORK_OPEN_INFORMATION)RxContext->Info.Buffer;
1171 Log(("VBOXSF: MrxQueryFileInfo: FileNetworkOpenInformation\n"));
1172
1173 cbToCopy = sizeof(FILE_NETWORK_OPEN_INFORMATION);
1174 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1175
1176 pInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.BirthTime);
1177 pInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.AccessTime);
1178 pInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.ModificationTime);
1179 pInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pVBoxFobx->Info.ChangeTime);
1180 /* Note! We didn't used to set allocation size and end-of-file for directories.
1181 NTFS reports these, though, so why shouldn't we. */
1182 pInfo->AllocationSize.QuadPart = pVBoxFobx->Info.cbAllocated;
1183 pInfo->EndOfFile.QuadPart = pVBoxFobx->Info.cbObject;
1184 pInfo->FileAttributes = VBoxToNTFileAttributes(pVBoxFobx->Info.Attr.fMode);
1185 break;
1186 }
1187
1188 case FileEndOfFileInformation:
1189 {
1190 PFILE_END_OF_FILE_INFORMATION pInfo = (PFILE_END_OF_FILE_INFORMATION)RxContext->Info.Buffer;
1191 Log(("VBOXSF: MrxQueryFileInfo: FileEndOfFileInformation\n"));
1192
1193 cbToCopy = sizeof(FILE_END_OF_FILE_INFORMATION);
1194 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1195
1196 /* Note! We didn't used to set allocation size and end-of-file for directories.
1197 NTFS reports these, though, so why shouldn't we. */
1198 pInfo->EndOfFile.QuadPart = pVBoxFobx->Info.cbObject;
1199 break;
1200 }
1201
1202 case FileAllocationInformation:
1203 {
1204 PFILE_ALLOCATION_INFORMATION pInfo = (PFILE_ALLOCATION_INFORMATION)RxContext->Info.Buffer;
1205 Log(("VBOXSF: MrxQueryFileInfo: FileAllocationInformation\n"));
1206
1207 cbToCopy = sizeof(FILE_ALLOCATION_INFORMATION);
1208 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1209
1210 /* Note! We didn't used to set allocation size and end-of-file for directories.
1211 NTFS reports these, though, so why shouldn't we. */
1212 pInfo->AllocationSize.QuadPart = pVBoxFobx->Info.cbAllocated;
1213 break;
1214 }
1215
1216 case FileAttributeTagInformation:
1217 {
1218 PFILE_ATTRIBUTE_TAG_INFORMATION pInfo = (PFILE_ATTRIBUTE_TAG_INFORMATION)RxContext->Info.Buffer;
1219 Log(("VBOXSF: MrxQueryFileInfo: FileAttributeTagInformation\n"));
1220
1221 cbToCopy = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
1222 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1223
1224 pInfo->FileAttributes = VBoxToNTFileAttributes(pVBoxFobx->Info.Attr.fMode);
1225 pInfo->ReparseTag = 0;
1226 break;
1227 }
1228
1229 case FileCompressionInformation:
1230 {
1231 //PFILE_COMPRESSION_INFO pInfo = (PFILE_COMPRESSION_INFO)RxContext->Info.Buffer;
1232 struct MY_FILE_COMPRESSION_INFO
1233 {
1234 LARGE_INTEGER CompressedFileSize;
1235 WORD CompressionFormat;
1236 UCHAR CompressionUnitShift;
1237 UCHAR ChunkShift;
1238 UCHAR ClusterShift;
1239 UCHAR Reserved[3];
1240 } *pInfo = (struct MY_FILE_COMPRESSION_INFO *)RxContext->Info.Buffer;
1241 Log(("VBOXSF: MrxQueryFileInfo: FileCompressionInformation\n"));
1242
1243 cbToCopy = sizeof(*pInfo);
1244 CHECK_SIZE_BREAK(RxContext, cbToCopy);
1245
1246 pInfo->CompressedFileSize.QuadPart = pVBoxFobx->Info.cbObject;
1247 pInfo->CompressionFormat = 0;
1248 pInfo->CompressionUnitShift = 0;
1249 pInfo->ChunkShift = 0;
1250 pInfo->ClusterShift = 0;
1251 pInfo->Reserved[0] = 0;
1252 pInfo->Reserved[1] = 0;
1253 pInfo->Reserved[2] = 0;
1254 AssertCompile(sizeof(pInfo->Reserved) == 3);
1255 break;
1256 }
1257
1258 default:
1259 AssertLogRelMsgFailed(("FileInformationClass=%d\n",
1260 RxContext->Info.FileInformationClass));
1261 Status = STATUS_INTERNAL_ERROR;
1262 break;
1263 }
1264 break;
1265 }
1266
1267
1268/** @todo Implement:
1269 * FileHardLinkInformation: rcNt=0 (STATUS_SUCCESS) Ios.Status=0 (STATUS_SUCCESS) Ios.Information=0000000000000048
1270 * FileProcessIdsUsingFileInformation: rcNt=0 (STATUS_SUCCESS) Ios.Status=0 (STATUS_SUCCESS) Ios.Information=0000000000000010
1271 * FileNormalizedNameInformation: rcNt=0 (STATUS_SUCCESS) Ios.Status=0 (STATUS_SUCCESS) Ios.Information=00000000000000AA
1272 * FileNetworkPhysicalNameInformation: rcNt=0xc000000d (STATUS_INVALID_PARAMETER) Ios={not modified}
1273 * FileShortNameInformation?
1274 * FileNetworkPhysicalNameInformation
1275 */
1276
1277 /*
1278 * Unsupported ones (STATUS_INVALID_PARAMETER is correct here if you
1279 * go by what fat + ntfs return, however samba mounts generally returns
1280 * STATUS_INVALID_INFO_CLASS except for pipe info - see queryfileinfo-1).
1281 */
1282 default:
1283 Log(("VBOXSF: MrxQueryFileInfo: Not supported FileInformationClass: %d!\n",
1284 RxContext->Info.FileInformationClass));
1285 Status = STATUS_INVALID_PARAMETER;
1286 break;
1287
1288 }
1289#undef CHECK_SIZE_BREAK
1290
1291 /* Note! InformationToReturn doesn't seem to be used, instead Info.LengthRemaining should underflow
1292 so it can be used together with RxContext->CurrentIrpSp->Parameters.QueryFile.Length
1293 to calc the Ios.Information value. This explain the weird LONG type choice. */
1294 RxContext->InformationToReturn = cbToCopy;
1295 RxContext->Info.LengthRemaining -= cbToCopy;
1296 AssertStmt(RxContext->Info.LengthRemaining >= 0 || Status != STATUS_SUCCESS, Status = STATUS_BUFFER_TOO_SMALL);
1297
1298 Log(("VBOXSF: MrxQueryFileInfo: Returns %#x, Remaining length = %d, cbToCopy = %u (%#x)\n",
1299 Status, RxContext->Info.Length, cbToCopy));
1300 return Status;
1301}
1302
1303/**
1304 * Worker for vbsfNtSetBasicInfo.
1305 */
1306static NTSTATUS vbsfNtSetBasicInfo(PMRX_VBOX_FOBX pVBoxFobx, PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
1307 PVBSFNTFCBEXT pVBoxFcbx, PFILE_BASIC_INFORMATION pBasicInfo)
1308{
1309 Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: CreationTime %RX64\n", pBasicInfo->CreationTime.QuadPart));
1310 Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: LastAccessTime %RX64\n", pBasicInfo->LastAccessTime.QuadPart));
1311 Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: LastWriteTime %RX64\n", pBasicInfo->LastWriteTime.QuadPart));
1312 Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: ChangeTime %RX64\n", pBasicInfo->ChangeTime.QuadPart));
1313 Log(("VBOXSF: MRxSetFileInfo: FileBasicInformation: FileAttributes %RX32\n", pBasicInfo->FileAttributes));
1314 AssertReturn(pVBoxFobx, STATUS_INTERNAL_ERROR);
1315 AssertReturn(pVBoxFcbx, STATUS_INTERNAL_ERROR);
1316 AssertReturn(pNetRootExtension, STATUS_INTERNAL_ERROR);
1317
1318 /** @todo r=bird: The attempt at implementing the disable-timestamp-update
1319 * behaviour here needs a little adjusting. I'll get to that later.
1320 *
1321 * Reminders:
1322 *
1323 * X1. Drop VBOX_FOBX_F_INFO_CREATION_TIME.
1324 *
1325 * X2. Drop unused VBOX_FOBX_F_INFO_ATTRIBUTES.
1326 *
1327 * X3. Only act on VBOX_FOBX_F_INFO_CHANGE_TIME if modified attributes or grown
1328 * the file (?) so we don't cancel out updates by other parties (like the
1329 * host).
1330 *
1331 * X4. Only act on VBOX_FOBX_F_INFO_LASTWRITE_TIME if we've written to the
1332 * file.
1333 *
1334 * X5. Only act on VBOX_FOBX_F_INFO_LASTACCESS_TIME if we've read from the file
1335 * or done whatever else might modify the access time.
1336 *
1337 * 6. Don't bother calling the host if there are only zeros and -1 values.
1338 * => Not done / better use it to update FCB info?
1339 *
1340 * X7. Client application should probably be allowed to modify the timestamps
1341 * explicitly using this API after disabling updating, given the wording of
1342 * the footnote referenced above.
1343 * => Only verified via fastfat sample, need FsPerf test.
1344 *
1345 * 8. Extend the host interface to let the host handle this crap instead as it
1346 * can do a better job, like on windows it's done implicitly if we let -1
1347 * pass thru IPRT.
1348 * => We're actually better equipped to handle it than the host, given the
1349 * FCB/inode. New plan is to detect windows host and let it implement -1,
1350 * but use the old stuff as fallback for non-windows hosts.
1351 *
1352 * One worry here is that we hide timestamp updates made by the host or other
1353 * guest side processes. This could account for some of the issues we've been
1354 * having with the guest not noticing host side changes.
1355 */
1356
1357
1358 /*
1359 * The properties that need to be changed are set to something other
1360 * than zero and -1. (According to the fastfat sample code, -1 only
1361 * disable implicit timestamp updating, not explicit thru this code.)
1362 */
1363
1364 /*
1365 * In the host request, zero values are ignored.
1366 *
1367 * As for the NT request, the same is true but with a slight twist for the
1368 * timestamp fields. If a timestamp value is non-zero, the client disables
1369 * implicit updating of that timestamp via this handle when reading, writing
1370 * and * changing attributes. The special -1 value is used to just disable
1371 * implicit updating without modifying the timestamp. While the value is
1372 * allowed for the CreationTime field, it will be treated as zero.
1373 *
1374 * More clues to the NT behaviour can be found here:
1375 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/16023025-8a78-492f-8b96-c873b042ac50
1376 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d4bc551b-7aaf-4b4f-ba0e-3a75e7c528f0#Appendix_A_86
1377 *
1378 * P.S. One of the reasons behind suppressing of timestamp updating after setting
1379 * them is likely related to the need of opening objects to modify them. There are
1380 * no utimes() or chmod() function in NT, on the futimes() and fchmod() variants.
1381 */
1382 VBOXSFOBJINFOREQ *pReq = (VBOXSFOBJINFOREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
1383 if (pReq)
1384 RT_ZERO(pReq->ObjInfo);
1385 else
1386 return STATUS_INSUFFICIENT_RESOURCES;
1387 uint32_t fModified = 0;
1388 uint32_t fSuppressed = 0;
1389
1390 /** @todo FsPerf need to check what is supposed to happen if modified
1391 * against after -1 is specified. As state above, fastfat will not suppress
1392 * further setting of the timestamp like we used to do prior to revision
1393 * r130337 or thereabouts. */
1394
1395 if (pBasicInfo->CreationTime.QuadPart && pBasicInfo->CreationTime.QuadPart != -1)
1396 RTTimeSpecSetNtTime(&pReq->ObjInfo.BirthTime, pBasicInfo->CreationTime.QuadPart);
1397
1398 if (pBasicInfo->LastAccessTime.QuadPart)
1399 {
1400 if (pBasicInfo->LastAccessTime.QuadPart != -1)
1401 {
1402 RTTimeSpecSetNtTime(&pReq->ObjInfo.AccessTime, pBasicInfo->LastAccessTime.QuadPart);
1403 fModified |= VBOX_FOBX_F_INFO_LASTACCESS_TIME;
1404 }
1405 fSuppressed |= VBOX_FOBX_F_INFO_LASTACCESS_TIME;
1406 }
1407
1408 if (pBasicInfo->LastWriteTime.QuadPart)
1409 {
1410 if (pBasicInfo->LastWriteTime.QuadPart != -1)
1411 {
1412 RTTimeSpecSetNtTime(&pReq->ObjInfo.ModificationTime, pBasicInfo->LastWriteTime.QuadPart);
1413 fModified |= VBOX_FOBX_F_INFO_LASTWRITE_TIME;
1414 }
1415 fSuppressed |= VBOX_FOBX_F_INFO_LASTWRITE_TIME;
1416 }
1417
1418 if (pBasicInfo->ChangeTime.QuadPart)
1419 {
1420 if (pBasicInfo->ChangeTime.QuadPart != -1)
1421 {
1422 RTTimeSpecSetNtTime(&pReq->ObjInfo.ChangeTime, pBasicInfo->ChangeTime.QuadPart);
1423 fModified |= VBOX_FOBX_F_INFO_CHANGE_TIME;
1424 }
1425 fSuppressed |= VBOX_FOBX_F_INFO_CHANGE_TIME;
1426 }
1427
1428 if (pBasicInfo->FileAttributes)
1429 {
1430 pReq->ObjInfo.Attr.fMode = NTToVBoxFileAttributes(pBasicInfo->FileAttributes);
1431 Assert(pReq->ObjInfo.Attr.fMode != 0);
1432 }
1433
1434 /*
1435 * Call the host to do the actual updating.
1436 * Note! This may be a noop, but we want up-to-date info for any -1 timestamp.
1437 */
1438 int vrc = VbglR0SfHostReqSetObjInfo(pNetRootExtension->map.root, pReq, pVBoxFobx->hFile);
1439 NTSTATUS Status;
1440 if (RT_SUCCESS(vrc))
1441 {
1442 /*
1443 * Update our timestamp state tracking both in the file object and the file
1444 * control block extensions.
1445 */
1446 if (pBasicInfo->FileAttributes || fModified)
1447 {
1448 if ( pVBoxFcbx->pFobxChangeTime != pVBoxFobx
1449 && !(pVBoxFobx->fTimestampsUpdatingSuppressed & VBOX_FOBX_F_INFO_CHANGE_TIME))
1450 pVBoxFcbx->pFobxChangeTime = NULL;
1451 pVBoxFobx->fTimestampsImplicitlyUpdated |= VBOX_FOBX_F_INFO_CHANGE_TIME;
1452 }
1453 pVBoxFobx->fTimestampsImplicitlyUpdated &= ~fModified;
1454 pVBoxFobx->fTimestampsSetByUser |= fModified;
1455 pVBoxFobx->fTimestampsUpdatingSuppressed |= fSuppressed;
1456
1457 if (fSuppressed)
1458 {
1459 if (fSuppressed & VBOX_FOBX_F_INFO_LASTACCESS_TIME)
1460 pVBoxFcbx->pFobxLastAccessTime = pVBoxFobx;
1461 if (fSuppressed & VBOX_FOBX_F_INFO_LASTWRITE_TIME)
1462 pVBoxFcbx->pFobxLastWriteTime = pVBoxFobx;
1463 if (fSuppressed & VBOX_FOBX_F_INFO_CHANGE_TIME)
1464 pVBoxFcbx->pFobxChangeTime = pVBoxFobx;
1465 }
1466
1467 vbsfNtCopyInfo(pVBoxFobx, &pReq->ObjInfo, pVBoxFcbx, fSuppressed);
1468
1469 /*
1470 * Copy timestamps and attributes from the host into the return buffer to let
1471 * RDBSS update the FCB data when we return. Not sure if the FCB timestamps
1472 * are ever used for anything, but caller doesn't check for -1 so there will
1473 * be some funny/invalid timestamps in the FCB it ever does. (I seriously
1474 * doubt -1 is supposed to be there given that the FCB is shared and the -1
1475 * only applies to a given FILE_OBJECT/HANDLE.)
1476 */
1477 if (pBasicInfo->FileAttributes)
1478 pBasicInfo->FileAttributes = (pBasicInfo->FileAttributes & FILE_ATTRIBUTE_TEMPORARY)
1479 | VBoxToNTFileAttributes(pReq->ObjInfo.Attr.fMode);
1480 if (pBasicInfo->CreationTime.QuadPart)
1481 pBasicInfo->CreationTime.QuadPart = RTTimeSpecGetNtTime(&pReq->ObjInfo.BirthTime);
1482 if (pBasicInfo->LastAccessTime.QuadPart)
1483 pBasicInfo->LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&pReq->ObjInfo.AccessTime);
1484 if (pBasicInfo->LastWriteTime.QuadPart)
1485 pBasicInfo->LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&pReq->ObjInfo.ModificationTime);
1486 if (pBasicInfo->ChangeTime.QuadPart)
1487 pBasicInfo->ChangeTime.QuadPart = RTTimeSpecGetNtTime(&pReq->ObjInfo.ChangeTime);
1488
1489 Status = STATUS_SUCCESS;
1490 }
1491 else
1492 Status = vbsfNtVBoxStatusToNt(vrc);
1493
1494 VbglR0PhysHeapFree(pReq);
1495 return Status;
1496}
1497
1498/**
1499 * Worker for vbsfNtSetBasicInfo.
1500 */
1501static NTSTATUS vbsfNtSetEndOfFile(IN OUT struct _RX_CONTEXT * RxContext, IN uint64_t cbNewFileSize)
1502{
1503 NTSTATUS Status = STATUS_SUCCESS;
1504
1505 RxCaptureFcb;
1506 RxCaptureFobx;
1507
1508 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
1509 PVBSFNTFCBEXT pVBoxFcbx = VBoxMRxGetFcbExtension(capFcb);
1510 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
1511
1512 PSHFLFSOBJINFO pObjInfo;
1513 uint32_t cbBuffer;
1514 int vrc;
1515
1516 Log(("VBOXSF: vbsfNtSetEndOfFile: New size = %RX64\n",
1517 cbNewFileSize));
1518
1519 Assert(pVBoxFobx && pNetRootExtension);
1520
1521 cbBuffer = sizeof(SHFLFSOBJINFO);
1522 pObjInfo = (SHFLFSOBJINFO *)vbsfNtAllocNonPagedMem(cbBuffer);
1523 if (!pObjInfo)
1524 {
1525 AssertFailed();
1526 return STATUS_INSUFFICIENT_RESOURCES;
1527 }
1528
1529 RtlZeroMemory(pObjInfo, cbBuffer);
1530 pObjInfo->cbObject = cbNewFileSize;
1531
1532 vrc = VbglR0SfFsInfo(&g_SfClient, &pNetRootExtension->map, pVBoxFobx->hFile,
1533 SHFL_INFO_SET | SHFL_INFO_SIZE, &cbBuffer, (PSHFLDIRINFO)pObjInfo);
1534
1535 Log(("VBOXSF: vbsfNtSetEndOfFile: VbglR0SfFsInfo returned %Rrc\n", vrc));
1536
1537 Status = vbsfNtVBoxStatusToNt(vrc);
1538 if (Status == STATUS_SUCCESS)
1539 {
1540 pVBoxFobx->fTimestampsImplicitlyUpdated |= VBOX_FOBX_F_INFO_LASTWRITE_TIME;
1541 if (pVBoxFcbx->pFobxLastWriteTime != pVBoxFobx)
1542 pVBoxFcbx->pFobxLastWriteTime = NULL;
1543
1544 Log(("VBOXSF: vbsfNtSetEndOfFile: VbglR0SfFsInfo new allocation size = %RX64\n",
1545 pObjInfo->cbAllocated));
1546
1547 /** @todo update the file stats! */
1548 }
1549
1550 if (pObjInfo)
1551 vbsfNtFreeNonPagedMem(pObjInfo);
1552
1553 Log(("VBOXSF: vbsfNtSetEndOfFile: Returned 0x%08X\n", Status));
1554 return Status;
1555}
1556
1557/**
1558 * Worker for vbsfNtSetBasicInfo.
1559 */
1560static NTSTATUS vbsfNtRename(IN PRX_CONTEXT RxContext,
1561 IN FILE_INFORMATION_CLASS FileInformationClass,
1562 IN PVOID pBuffer,
1563 IN ULONG BufferLength)
1564{
1565 NTSTATUS Status = STATUS_SUCCESS;
1566
1567 RxCaptureFcb;
1568 RxCaptureFobx;
1569
1570 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
1571 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
1572 PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen;
1573
1574 PFILE_RENAME_INFORMATION RenameInformation = (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer;
1575 PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(pSrvOpen, capFcb);
1576
1577 int vrc;
1578 PSHFLSTRING SrcPath = 0, DestPath = 0;
1579 ULONG flags;
1580
1581 RT_NOREF(FileInformationClass, pBuffer, BufferLength);
1582
1583 Assert(FileInformationClass == FileRenameInformation);
1584
1585 Log(("VBOXSF: vbsfNtRename: FileName = %.*ls\n",
1586 RenameInformation->FileNameLength / sizeof(WCHAR), &RenameInformation->FileName[0]));
1587
1588 /* Must close the file before renaming it! */
1589 if (pVBoxFobx->hFile != SHFL_HANDLE_NIL)
1590 vbsfNtCloseFileHandle(pNetRootExtension, pVBoxFobx, VBoxMRxGetFcbExtension(capFcb));
1591
1592 /* Mark it as renamed, so we do nothing during close */
1593 SetFlag(pSrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED);
1594
1595 Log(("VBOXSF: vbsfNtRename: RenameInformation->FileNameLength = %d\n", RenameInformation->FileNameLength));
1596 Status = vbsfNtShflStringFromUnicodeAlloc(&DestPath, RenameInformation->FileName, (uint16_t)RenameInformation->FileNameLength);
1597 if (Status != STATUS_SUCCESS)
1598 return Status;
1599
1600 Log(("VBOXSF: vbsfNtRename: Destination path = %.*ls\n",
1601 DestPath->u16Length / sizeof(WCHAR), &DestPath->String.ucs2[0]));
1602
1603 Log(("VBOXSF: vbsfNtRename: RemainingName->Length = %d\n", RemainingName->Length));
1604 Status = vbsfNtShflStringFromUnicodeAlloc(&SrcPath, RemainingName->Buffer, RemainingName->Length);
1605 if (Status != STATUS_SUCCESS)
1606 {
1607 vbsfNtFreeNonPagedMem(DestPath);
1608 return Status;
1609 }
1610
1611 Log(("VBOXSF: vbsfNtRename: Source path = %.*ls\n",
1612 SrcPath->u16Length / sizeof(WCHAR), &SrcPath->String.ucs2[0]));
1613
1614 /* Call host. */
1615 flags = pVBoxFobx->Info.Attr.fMode & RTFS_DOS_DIRECTORY ? SHFL_RENAME_DIR : SHFL_RENAME_FILE;
1616 if (RenameInformation->ReplaceIfExists)
1617 flags |= SHFL_RENAME_REPLACE_IF_EXISTS;
1618
1619 Log(("VBOXSF: vbsfNtRename: Calling VbglR0SfRename\n"));
1620 vrc = VbglR0SfRename(&g_SfClient, &pNetRootExtension->map, SrcPath, DestPath, flags);
1621
1622 vbsfNtFreeNonPagedMem(SrcPath);
1623 vbsfNtFreeNonPagedMem(DestPath);
1624
1625 Status = vbsfNtVBoxStatusToNt(vrc);
1626 if (vrc != VINF_SUCCESS)
1627 Log(("VBOXSF: vbsfNtRename: VbglR0SfRename failed with %Rrc\n", vrc));
1628
1629 Log(("VBOXSF: vbsfNtRename: Returned 0x%08X\n", Status));
1630 return Status;
1631}
1632
1633
1634/**
1635 * Handle NtSetInformationFile and similar requests.
1636 *
1637 * The RDBSS code has done various things before we get here wrt locking and
1638 * request pre-processing. It will normally acquire an exclusive lock, but not
1639 * if this is related to a page file (FCB_STATE_PAGING_FILE set).
1640 */
1641NTSTATUS VBoxMRxSetFileInfo(IN PRX_CONTEXT RxContext)
1642{
1643 RxCaptureFcb;
1644 RxCaptureFobx;
1645 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
1646 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
1647 NTSTATUS Status = STATUS_SUCCESS;
1648
1649 Log(("VBOXSF: MrxSetFileInfo: Buffer = %p, Length = %#x (%d), FileInformationClass = %d\n",
1650 RxContext->Info.Buffer, RxContext->Info.Length, RxContext->Info.Length, RxContext->Info.FileInformationClass));
1651
1652 /*
1653 * The essence of the size validation table for NtSetInformationFile from w10 build 17763:
1654 * UCHAR IoCheckQuerySetFileInformation[77]:
1655 * db 28h ; 4 FileBasicInformation,
1656 * db 18h ; 10 FileRenameInformation,
1657 * db 18h ; 11 FileLinkInformation,
1658 * db 1 ; 13 FileDispositionInformation,
1659 * db 8 ; 14 FilePositionInformation,
1660 * db 4 ; 16 FileModeInformation,
1661 * db 8 ; 19 FileAllocationInformation,
1662 * db 8 ; 20 FileEndOfFileInformation,
1663 * db 8 ; 23 FilePipeInformation,
1664 * db 10h ; 25 FilePipeRemoteInformation,
1665 * db 8 ; 27 FileMailslotSetInformation,
1666 * db 48h ; 29 FileObjectIdInformation,
1667 * db 10h ; 30 FileCompletionInformation, - "reserved for system use"
1668 * db 18h ; 31 FileMoveClusterInformation, - "reserved for system use"
1669 * db 38h ; 32 FileQuotaInformation,
1670 * db 10h ; 36 FileTrackingInformation, - "reserved for system use"
1671 * db 8 ; 39 FileValidDataLengthInformation,
1672 * db 8 ; 40 FileShortNameInformation,
1673 * db 4 ; 41 FileIoCompletionNotificationInformation, - "reserved for system use"
1674 * db 10h ; 42 FileIoStatusBlockRangeInformation, - "reserved for system use"
1675 * db 4 ; 43 FileIoPriorityHintInformation,
1676 * db 14h ; 44 FileSfioReserveInformation, - "reserved for system use"
1677 * db 10h ; 61 FileReplaceCompletionInformation,
1678 * db 4 ; 64 FileDispositionInformationEx, - Adds posix semantics and stuff.
1679 * db 18h ; 65 FileRenameInformationEx, - Adds posix semantics and stuff.
1680 * db 8 ; 67 FileDesiredStorageClassInformation,
1681 * db 10h ; 69 FileMemoryPartitionInformation, - "reserved for system use", W10-1709
1682 * db 4 ; 71 FileCaseSensitiveInformation, - Per dir case sensitivity. (For linux?)
1683 * db 18h ; 72 FileLinkInformationEx, - Adds posix semantics and stuff.
1684 * db 4 ; 74 FileStorageReserveIdInformation,
1685 * db 4 ; 75 FileCaseSensitiveInformationForceAccessCheck, - for the i/o manager, w10-1809.
1686 */
1687 switch (RxContext->Info.FileInformationClass)
1688 {
1689 /*
1690 * This is used to modify timestamps and attributes.
1691 *
1692 * Upon successful return, RDBSS will ensure that FILE_ATTRIBUTE_DIRECTORY is set
1693 * according to the FCB object type (see RxFinishFcbInitialization in path.cpp),
1694 * and that the FILE_ATTRIBUTE_TEMPORARY attribute is reflected in FcbState
1695 * (FCB_STATE_TEMPORARY) and the file object flags (FO_TEMPORARY_FILE). It will
1696 * also copy each non-zero timestamp into the FCB and set the corresponding
1697 * FOBX_FLAG_USER_SET_xxxx flag in the FOBX.
1698 *
1699 * RDBSS behaviour is idential between 16299.0/w10 and 7600.16385.1/wnet.
1700 */
1701 case FileBasicInformation:
1702 {
1703 Assert(RxContext->Info.Length >= sizeof(FILE_BASIC_INFORMATION));
1704 Status = vbsfNtSetBasicInfo(pVBoxFobx, pNetRootExtension, VBoxMRxGetFcbExtension(capFcb),
1705 (PFILE_BASIC_INFORMATION)RxContext->Info.Buffer);
1706 break;
1707 }
1708
1709 /*
1710 * This is used to rename a file.
1711 */
1712 case FileRenameInformation:
1713 {
1714#ifdef LOG_ENABLED
1715 PFILE_RENAME_INFORMATION pInfo = (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer;
1716 Log(("VBOXSF: MrxSetFileInfo: FileRenameInformation: ReplaceIfExists = %d, RootDirectory = 0x%x = [%.*ls]\n",
1717 pInfo->ReplaceIfExists, pInfo->RootDirectory, pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
1718#endif
1719
1720 Status = vbsfNtRename(RxContext, FileRenameInformation, RxContext->Info.Buffer, RxContext->Info.Length);
1721 break;
1722 }
1723
1724 /*
1725 * This is presumably used for hardlinking purposes. We don't support that.
1726 */
1727 case FileLinkInformation:
1728 {
1729#ifdef LOG_ENABLED
1730 PFILE_LINK_INFORMATION pInfo = (PFILE_LINK_INFORMATION )RxContext->Info.Buffer;
1731 Log(("VBOXSF: MrxSetFileInfo: FileLinkInformation: ReplaceIfExists = %d, RootDirectory = 0x%x = [%.*ls]. Not implemented!\n",
1732 pInfo->ReplaceIfExists, pInfo->RootDirectory, pInfo->FileNameLength / sizeof(WCHAR), pInfo->FileName));
1733#endif
1734
1735 Status = STATUS_NOT_IMPLEMENTED;
1736 break;
1737 }
1738
1739 /*
1740 * This is used to delete file.
1741 */
1742 case FileDispositionInformation:
1743 {
1744 PFILE_DISPOSITION_INFORMATION pInfo = (PFILE_DISPOSITION_INFORMATION)RxContext->Info.Buffer;
1745 Log(("VBOXSF: MrxSetFileInfo: FileDispositionInformation: Delete = %d\n",
1746 pInfo->DeleteFile));
1747
1748 if (pInfo->DeleteFile && capFcb->OpenCount == 1)
1749 Status = vbsfNtRemove(RxContext);
1750 else
1751 Status = STATUS_SUCCESS;
1752 break;
1753 }
1754
1755 /*
1756 * The file position is handled by the RDBSS library (RxSetPositionInfo)
1757 * and we should never see this request.
1758 */
1759 case FilePositionInformation:
1760 AssertMsgFailed(("VBOXSF: MrxSetFileInfo: FilePositionInformation: CurrentByteOffset = 0x%RX64. Unsupported!\n",
1761 ((PFILE_POSITION_INFORMATION)RxContext->Info.Buffer)->CurrentByteOffset.QuadPart));
1762 Status = STATUS_INTERNAL_ERROR;
1763 break;
1764
1765 /*
1766 * Change the allocation size, leaving the EOF alone unless the file shrinks.
1767 *
1768 * There is no shared folder operation for this, so we only need to care
1769 * about adjusting EOF if the file shrinks.
1770 *
1771 * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d4bc551b-7aaf-4b4f-ba0e-3a75e7c528f0#Appendix_A_83
1772 */
1773 case FileAllocationInformation:
1774 {
1775 PFILE_ALLOCATION_INFORMATION pInfo = (PFILE_ALLOCATION_INFORMATION)RxContext->Info.Buffer;
1776 Log(("VBOXSF: MrxSetFileInfo: FileAllocationInformation: new AllocSize = 0x%RX64, FileSize = 0x%RX64\n",
1777 pInfo->AllocationSize.QuadPart, capFcb->Header.FileSize.QuadPart));
1778
1779 if (pInfo->AllocationSize.QuadPart >= capFcb->Header.FileSize.QuadPart)
1780 Status = STATUS_SUCCESS;
1781 else
1782 {
1783 /** @todo get up to date EOF from host? We may risk accidentally growing the
1784 * file here if the host (or someone else) truncated it. */
1785 Status = vbsfNtSetEndOfFile(RxContext, pInfo->AllocationSize.QuadPart);
1786 }
1787 break;
1788 }
1789
1790 /*
1791 * Prior to calling us, RxSetEndOfFileInfo will have updated the FCB fields space.FileSize,
1792 * Header.AllocationSize and (if old value was larger) Header.ValidDataLength. On success
1793 * it will inform the cache manager, while on failure the old values will be restored.
1794 *
1795 * Note! RxSetEndOfFileInfo assumes that the old Header.FileSize value is up to date and
1796 * will hide calls which does not change the size from us. This is of course not
1797 * the case for non-local file systems, as the server is the only which up-to-date
1798 * information. Don't see an easy way of working around it, so ignoring it for now.
1799 */
1800 case FileEndOfFileInformation:
1801 {
1802 PFILE_END_OF_FILE_INFORMATION pInfo = (PFILE_END_OF_FILE_INFORMATION)RxContext->Info.Buffer;
1803 Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation: new EndOfFile 0x%RX64, FileSize = 0x%RX64\n",
1804 pInfo->EndOfFile.QuadPart, capFcb->Header.FileSize.QuadPart));
1805
1806 Status = vbsfNtSetEndOfFile(RxContext, pInfo->EndOfFile.QuadPart);
1807
1808 Log(("VBOXSF: MrxSetFileInfo: FileEndOfFileInformation: Status 0x%08X\n",
1809 Status));
1810 break;
1811 }
1812
1813 /// @todo FileModeInformation ?
1814 /// @todo return access denied or something for FileValidDataLengthInformation?
1815
1816 default:
1817 Log(("VBOXSF: MrxSetFileInfo: Not supported FileInformationClass: %d!\n",
1818 RxContext->Info.FileInformationClass));
1819 Status = STATUS_INVALID_PARAMETER;
1820 break;
1821 }
1822
1823 Log(("VBOXSF: MrxSetFileInfo: Returned 0x%08X\n", Status));
1824 return Status;
1825}
1826
1827NTSTATUS VBoxMRxSetFileInfoAtCleanup(IN PRX_CONTEXT RxContext)
1828{
1829 RT_NOREF(RxContext);
1830 Log(("VBOXSF: MRxSetFileInfoAtCleanup\n"));
1831 return STATUS_SUCCESS;
1832}
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