VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/SharedFolders/driver/path.cpp@ 78543

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

winnt/vboxsf: Started on VBoxMRxCreate. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.5 KB
Line 
1/* $Id: path.cpp 78543 2019-05-16 11:35:40Z vboxsync $ */
2/** @file
3 * VirtualBox Windows Guest Shared Folders - Path related 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*********************************************************************************************************************************/
29static UNICODE_STRING g_UnicodeBackslash = { 2, 4, L"\\" };
30
31
32static NTSTATUS vbsfProcessCreate(PRX_CONTEXT RxContext,
33 PUNICODE_STRING RemainingName,
34 SHFLFSOBJINFO *pInfo,
35 PVOID EaBuffer,
36 ULONG EaLength,
37 ULONG *pulCreateAction,
38 SHFLHANDLE *pHandle)
39{
40 NTSTATUS Status = STATUS_SUCCESS;
41
42 RxCaptureFcb;
43
44 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
45
46 int vrc = VINF_SUCCESS;
47
48 /* Various boolean flags. */
49 struct
50 {
51 ULONG CreateDirectory :1;
52 ULONG OpenDirectory :1;
53 ULONG DirectoryFile :1;
54 ULONG NonDirectoryFile :1;
55 ULONG DeleteOnClose :1;
56 ULONG TemporaryFile :1;
57 ULONG SlashHack :1;
58 } bf;
59
60 ACCESS_MASK DesiredAccess;
61 ULONG Options;
62 UCHAR FileAttributes;
63 ULONG ShareAccess;
64 ULONG CreateDisposition;
65 SHFLCREATEPARMS *pCreateParms = NULL;
66
67 RT_NOREF(EaBuffer);
68
69 if (EaLength)
70 {
71 Log(("VBOXSF: vbsfProcessCreate: Unsupported: extended attributes!\n"));
72 Status = STATUS_NOT_SUPPORTED; /// @todo STATUS_EAS_NOT_SUPPORTED ?
73 goto failure;
74 }
75
76 if (BooleanFlagOn(capFcb->FcbState, FCB_STATE_PAGING_FILE))
77 {
78 Log(("VBOXSF: vbsfProcessCreate: Unsupported: paging file!\n"));
79 Status = STATUS_NOT_IMPLEMENTED;
80 goto failure;
81 }
82
83 Log(("VBOXSF: vbsfProcessCreate: FileAttributes = 0x%08x\n",
84 RxContext->Create.NtCreateParameters.FileAttributes));
85 Log(("VBOXSF: vbsfProcessCreate: CreateOptions = 0x%08x\n",
86 RxContext->Create.NtCreateParameters.CreateOptions));
87
88 RtlZeroMemory (&bf, sizeof (bf));
89
90 DesiredAccess = RxContext->Create.NtCreateParameters.DesiredAccess;
91 Options = RxContext->Create.NtCreateParameters.CreateOptions & FILE_VALID_OPTION_FLAGS;
92 FileAttributes = (UCHAR)(RxContext->Create.NtCreateParameters.FileAttributes & ~FILE_ATTRIBUTE_NORMAL);
93 ShareAccess = RxContext->Create.NtCreateParameters.ShareAccess;
94
95 /* We do not support opens by file ids. */
96 if (FlagOn(Options, FILE_OPEN_BY_FILE_ID))
97 {
98 Log(("VBOXSF: vbsfProcessCreate: Unsupported: file open by id!\n"));
99 Status = STATUS_NOT_IMPLEMENTED;
100 goto failure;
101 }
102
103 /* Mask out unsupported attribute bits. */
104 FileAttributes &= (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE);
105
106 bf.DirectoryFile = BooleanFlagOn(Options, FILE_DIRECTORY_FILE);
107 bf.NonDirectoryFile = BooleanFlagOn(Options, FILE_NON_DIRECTORY_FILE);
108 bf.DeleteOnClose = BooleanFlagOn(Options, FILE_DELETE_ON_CLOSE);
109 if (bf.DeleteOnClose)
110 Log(("VBOXSF: vbsfProcessCreate: Delete on close!\n"));
111
112 CreateDisposition = RxContext->Create.NtCreateParameters.Disposition;
113
114 bf.CreateDirectory = (bf.DirectoryFile && ((CreateDisposition == FILE_CREATE) || (CreateDisposition == FILE_OPEN_IF)));
115 bf.OpenDirectory = (bf.DirectoryFile && ((CreateDisposition == FILE_OPEN) || (CreateDisposition == FILE_OPEN_IF)));
116 bf.TemporaryFile = BooleanFlagOn(RxContext->Create.NtCreateParameters.FileAttributes, FILE_ATTRIBUTE_TEMPORARY);
117
118 if (FlagOn(capFcb->FcbState, FCB_STATE_TEMPORARY))
119 bf.TemporaryFile = TRUE;
120
121 bf.SlashHack = RxContext->CurrentIrpSp
122 && (RxContext->CurrentIrpSp->Parameters.Create.ShareAccess & VBOX_MJ_CREATE_SLASH_HACK);
123
124 Log(("VBOXSF: vbsfProcessCreate: bf.TemporaryFile %d, bf.CreateDirectory %d, bf.DirectoryFile = %d, bf.SlashHack = %d\n",
125 bf.TemporaryFile, bf.CreateDirectory, bf.DirectoryFile, bf.SlashHack));
126
127 /* Check consistency in specified flags. */
128 if (bf.TemporaryFile && bf.CreateDirectory) /* Directories with temporary flag set are not allowed! */
129 {
130 Log(("VBOXSF: vbsfProcessCreate: Not allowed: Temporary directories!\n"));
131 Status = STATUS_INVALID_PARAMETER;
132 goto failure;
133 }
134
135 if (bf.DirectoryFile && bf.NonDirectoryFile)
136 {
137 /** @todo r=bird: Check if FILE_DIRECTORY_FILE+FILE_NON_DIRECTORY_FILE really is illegal in all combinations... */
138 Log(("VBOXSF: vbsfProcessCreate: Unsupported combination: dir && !dir\n"));
139 Status = STATUS_INVALID_PARAMETER;
140 goto failure;
141 }
142
143 /* Initialize create parameters. */
144 pCreateParms = (SHFLCREATEPARMS *)vbsfNtAllocNonPagedMem(sizeof(SHFLCREATEPARMS));
145 if (!pCreateParms)
146 {
147 Status = STATUS_INSUFFICIENT_RESOURCES;
148 goto failure;
149 }
150
151 RtlZeroMemory(pCreateParms, sizeof (SHFLCREATEPARMS));
152
153 pCreateParms->Handle = SHFL_HANDLE_NIL;
154 pCreateParms->Result = SHFL_NO_RESULT;
155
156 if (bf.DirectoryFile)
157 {
158 if (CreateDisposition != FILE_CREATE && CreateDisposition != FILE_OPEN && CreateDisposition != FILE_OPEN_IF)
159 {
160 Log(("VBOXSF: vbsfProcessCreate: Invalid disposition 0x%08X for directory!\n",
161 CreateDisposition));
162 Status = STATUS_INVALID_PARAMETER;
163 goto failure;
164 }
165
166 pCreateParms->CreateFlags |= SHFL_CF_DIRECTORY;
167 }
168
169 Log(("VBOXSF: vbsfProcessCreate: CreateDisposition = 0x%08X\n",
170 CreateDisposition));
171
172 switch (CreateDisposition)
173 {
174 case FILE_SUPERSEDE:
175 pCreateParms->CreateFlags |= SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
176 Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n"));
177 break;
178
179 case FILE_OPEN:
180 pCreateParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW;
181 Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW\n"));
182 break;
183
184 case FILE_CREATE:
185 pCreateParms->CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
186 Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n"));
187 break;
188
189 case FILE_OPEN_IF:
190 pCreateParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
191 Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n"));
192 break;
193
194 case FILE_OVERWRITE:
195 pCreateParms->CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW;
196 Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_FAIL_IF_NEW\n"));
197 break;
198
199 case FILE_OVERWRITE_IF:
200 pCreateParms->CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW;
201 Log(("VBOXSF: vbsfProcessCreate: CreateFlags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS | SHFL_CF_ACT_CREATE_IF_NEW\n"));
202 break;
203
204 default:
205 Log(("VBOXSF: vbsfProcessCreate: Unexpected create disposition: 0x%08X\n",
206 CreateDisposition));
207 Status = STATUS_INVALID_PARAMETER;
208 goto failure;
209 }
210
211 Log(("VBOXSF: vbsfProcessCreate: DesiredAccess = 0x%08X\n",
212 DesiredAccess));
213 Log(("VBOXSF: vbsfProcessCreate: ShareAccess = 0x%08X\n",
214 ShareAccess));
215
216 if (DesiredAccess & FILE_READ_DATA)
217 {
218 Log(("VBOXSF: vbsfProcessCreate: FILE_READ_DATA\n"));
219 pCreateParms->CreateFlags |= SHFL_CF_ACCESS_READ;
220 }
221
222 if (DesiredAccess & FILE_WRITE_DATA)
223 {
224 Log(("VBOXSF: vbsfProcessCreate: FILE_WRITE_DATA\n"));
225 /* FILE_WRITE_DATA means write access regardless of FILE_APPEND_DATA bit.
226 */
227 pCreateParms->CreateFlags |= SHFL_CF_ACCESS_WRITE;
228 }
229 else if (DesiredAccess & FILE_APPEND_DATA)
230 {
231 Log(("VBOXSF: vbsfProcessCreate: FILE_APPEND_DATA\n"));
232 /* FILE_APPEND_DATA without FILE_WRITE_DATA means append only mode.
233 *
234 * Both write and append access flags are required for shared folders,
235 * as on Windows FILE_APPEND_DATA implies write access.
236 */
237 pCreateParms->CreateFlags |= SHFL_CF_ACCESS_WRITE | SHFL_CF_ACCESS_APPEND;
238 }
239
240 if (DesiredAccess & FILE_READ_ATTRIBUTES)
241 pCreateParms->CreateFlags |= SHFL_CF_ACCESS_ATTR_READ;
242 if (DesiredAccess & FILE_WRITE_ATTRIBUTES)
243 pCreateParms->CreateFlags |= SHFL_CF_ACCESS_ATTR_WRITE;
244
245 if (ShareAccess & (FILE_SHARE_READ | FILE_SHARE_WRITE))
246 pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYNONE;
247 else if (ShareAccess & FILE_SHARE_READ)
248 pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYWRITE;
249 else if (ShareAccess & FILE_SHARE_WRITE)
250 pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYREAD;
251 else pCreateParms->CreateFlags |= SHFL_CF_ACCESS_DENYALL;
252
253 /* Set initial allocation size. */
254 pCreateParms->Info.cbObject = RxContext->Create.NtCreateParameters.AllocationSize.QuadPart;
255
256 if (FileAttributes == 0)
257 FileAttributes = FILE_ATTRIBUTE_NORMAL;
258
259 pCreateParms->Info.Attr.fMode = NTToVBoxFileAttributes(FileAttributes);
260
261 {
262 PSHFLSTRING ParsedPath;
263 Log(("VBOXSF: vbsfProcessCreate: RemainingName->Length = %d\n", RemainingName->Length));
264
265
266 if (!bf.SlashHack)
267 {
268 Status = vbsfNtShflStringFromUnicodeAlloc(&ParsedPath, RemainingName->Buffer, RemainingName->Length);
269 if (Status != STATUS_SUCCESS)
270 goto failure;
271 }
272 else
273 {
274 /* Add back the slash we had to hide from RDBSS. */
275 Status = vbsfNtShflStringFromUnicodeAlloc(&ParsedPath, NULL, RemainingName->Length + sizeof(RTUTF16));
276 if (Status != STATUS_SUCCESS)
277 goto failure;
278 memcpy(ParsedPath->String.utf16, RemainingName->Buffer, RemainingName->Length);
279 ParsedPath->String.utf16[RemainingName->Length / sizeof(RTUTF16)] = '\\';
280 ParsedPath->String.utf16[RemainingName->Length / sizeof(RTUTF16) + 1] = '\0';
281 ParsedPath->u16Length = RemainingName->Length + sizeof(RTUTF16);
282 }
283
284 Log(("VBOXSF: ParsedPath: %.*ls\n",
285 ParsedPath->u16Length / sizeof(WCHAR), ParsedPath->String.ucs2));
286
287 /* Call host. */
288 Log(("VBOXSF: vbsfProcessCreate: VbglR0SfCreate called.\n"));
289 vrc = VbglR0SfCreate(&g_SfClient, &pNetRootExtension->map, ParsedPath, pCreateParms);
290
291 vbsfNtFreeNonPagedMem(ParsedPath);
292 }
293
294 Log(("VBOXSF: vbsfProcessCreate: VbglR0SfCreate returns vrc = %Rrc, Result = 0x%x\n",
295 vrc, pCreateParms->Result));
296
297 if (RT_FAILURE(vrc))
298 {
299 /* Map some VBoxRC to STATUS codes expected by the system. */
300 switch (vrc)
301 {
302 case VERR_ALREADY_EXISTS:
303 {
304 *pulCreateAction = FILE_EXISTS;
305 Status = STATUS_OBJECT_NAME_COLLISION;
306 goto failure;
307 }
308
309 /* On POSIX systems, the "mkdir" command returns VERR_FILE_NOT_FOUND when
310 doing a recursive directory create. Handle this case.
311
312 bird: We end up here on windows systems too if opening a dir that doesn't
313 exists. Thus, I've changed the SHFL_PATH_NOT_FOUND to SHFL_FILE_NOT_FOUND
314 so that FsPerf is happy. */
315 case VERR_FILE_NOT_FOUND: /** @todo r=bird: this is a host bug, isn't it? */
316 {
317 pCreateParms->Result = SHFL_FILE_NOT_FOUND;
318 break;
319 }
320
321 default:
322 {
323 *pulCreateAction = FILE_DOES_NOT_EXIST;
324 Status = vbsfNtVBoxStatusToNt(vrc);
325 goto failure;
326 }
327 }
328 }
329
330 /*
331 * The request succeeded. Analyze host response,
332 */
333 switch (pCreateParms->Result)
334 {
335 case SHFL_PATH_NOT_FOUND:
336 {
337 /* Path to the object does not exist. */
338 Log(("VBOXSF: vbsfProcessCreate: Path not found\n"));
339 *pulCreateAction = FILE_DOES_NOT_EXIST;
340 Status = STATUS_OBJECT_PATH_NOT_FOUND;
341 goto failure;
342 }
343
344 case SHFL_FILE_NOT_FOUND:
345 {
346 Log(("VBOXSF: vbsfProcessCreate: File not found\n"));
347 *pulCreateAction = FILE_DOES_NOT_EXIST;
348 if (pCreateParms->Handle == SHFL_HANDLE_NIL)
349 {
350 Status = STATUS_OBJECT_NAME_NOT_FOUND;
351 goto failure;
352 }
353
354 Log(("VBOXSF: vbsfProcessCreate: File not found but have a handle!\n"));
355 Status = STATUS_UNSUCCESSFUL;
356 goto failure;
357 }
358
359 case SHFL_FILE_EXISTS:
360 {
361 Log(("VBOXSF: vbsfProcessCreate: File exists, Handle = 0x%RX64\n",
362 pCreateParms->Handle));
363 if (pCreateParms->Handle == SHFL_HANDLE_NIL)
364 {
365 *pulCreateAction = FILE_EXISTS;
366 if (CreateDisposition == FILE_CREATE)
367 {
368 /* File was not opened because we requested a create. */
369 Status = STATUS_OBJECT_NAME_COLLISION;
370 goto failure;
371 }
372
373 /* Actually we should not go here, unless we have no rights to open the object. */
374 Log(("VBOXSF: vbsfProcessCreate: Existing file was not opened!\n"));
375 Status = STATUS_ACCESS_DENIED;
376 goto failure;
377 }
378
379 *pulCreateAction = FILE_OPENED;
380
381 /* Existing file was opened. Go check flags and create FCB. */
382 break;
383 }
384
385 case SHFL_FILE_CREATED:
386 {
387 /* A new file was created. */
388 Assert(pCreateParms->Handle != SHFL_HANDLE_NIL);
389
390 *pulCreateAction = FILE_CREATED;
391
392 /* Go check flags and create FCB. */
393 break;
394 }
395
396 case SHFL_FILE_REPLACED:
397 {
398 /* Existing file was replaced or overwriting. */
399 Assert(pCreateParms->Handle != SHFL_HANDLE_NIL);
400
401 if (CreateDisposition == FILE_SUPERSEDE)
402 *pulCreateAction = FILE_SUPERSEDED;
403 else
404 *pulCreateAction = FILE_OVERWRITTEN;
405 /* Go check flags and create FCB. */
406 break;
407 }
408
409 default:
410 {
411 Log(("VBOXSF: vbsfProcessCreate: Invalid CreateResult from host (0x%08X)\n",
412 pCreateParms->Result));
413 *pulCreateAction = FILE_DOES_NOT_EXIST;
414 Status = STATUS_OBJECT_PATH_NOT_FOUND;
415 goto failure;
416 }
417 }
418
419 /* Check flags. */
420 if (bf.NonDirectoryFile && FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY))
421 {
422 /* Caller wanted only a file, but the object is a directory. */
423 Log(("VBOXSF: vbsfProcessCreate: File is a directory!\n"));
424 Status = STATUS_FILE_IS_A_DIRECTORY;
425 goto failure;
426 }
427
428 if (bf.DirectoryFile && !FlagOn(pCreateParms->Info.Attr.fMode, RTFS_DOS_DIRECTORY))
429 {
430 /* Caller wanted only a directory, but the object is not a directory. */
431 Log(("VBOXSF: vbsfProcessCreate: File is not a directory!\n"));
432 Status = STATUS_NOT_A_DIRECTORY;
433 goto failure;
434 }
435
436 *pHandle = pCreateParms->Handle;
437 *pInfo = pCreateParms->Info;
438
439 vbsfNtFreeNonPagedMem(pCreateParms);
440
441 return Status;
442
443failure:
444
445 Log(("VBOXSF: vbsfProcessCreate: Returned with status = 0x%08X\n",
446 Status));
447
448 if (pCreateParms && pCreateParms->Handle != SHFL_HANDLE_NIL)
449 {
450 VbglR0SfClose(&g_SfClient, &pNetRootExtension->map, pCreateParms->Handle);
451 *pHandle = SHFL_HANDLE_NIL;
452 }
453
454 if (pCreateParms)
455 vbsfNtFreeNonPagedMem(pCreateParms);
456
457 return Status;
458}
459
460/**
461 * Create/open a file, directory, ++.
462 *
463 * The RDBSS library will do a table lookup on the path passed in by the user
464 * and therefore share FCBs for objects with the same path.
465 *
466 * The FCB needs to be locked exclusively upon successful return, however it
467 * seems like it's not always locked when we get here (only older RDBSS library
468 * versions?), so we have to check this before returning.
469 *
470 */
471NTSTATUS VBoxMRxCreate(IN OUT PRX_CONTEXT RxContext)
472{
473 RxCaptureFcb;
474 RxCaptureFobx;
475 PMRX_NET_ROOT pNetRoot = capFcb->pNetRoot;
476 PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
477 PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
478 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
479 ULONG CreateAction = FILE_CREATED;
480 SHFLHANDLE Handle = SHFL_HANDLE_NIL;
481 SHFLFSOBJINFO Info = {0};
482 NTSTATUS Status = STATUS_SUCCESS;
483 PMRX_VBOX_FOBX pVBoxFobx;
484
485 RT_NOREF(capFobx); /* RxCaptureFobx */
486
487 Log(("VBOXSF: MRxCreate: name ptr %p length=%d, SrvOpen->Flags 0x%08X\n",
488 RemainingName, RemainingName->Length, SrvOpen->Flags));
489
490 /* Disable FastIO. It causes a verifier bugcheck. */
491#ifdef SRVOPEN_FLAG_DONTUSE_READ_CACHING
492 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING | SRVOPEN_FLAG_DONTUSE_WRITE_CACHING);
493#else
494 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHEING | SRVOPEN_FLAG_DONTUSE_WRITE_CACHEING);
495#endif
496
497 if (RemainingName->Length)
498 Log(("VBOXSF: MRxCreate: Attempt to open %.*ls\n",
499 RemainingName->Length/sizeof(WCHAR), RemainingName->Buffer));
500 else if (FlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH))
501 {
502 Log(("VBOXSF: MRxCreate: Empty name -> Only backslash used\n"));
503 RemainingName = &g_UnicodeBackslash;
504 }
505
506 if ( pNetRoot->Type != NET_ROOT_WILD
507 && pNetRoot->Type != NET_ROOT_DISK)
508 {
509 Log(("VBOXSF: MRxCreate: netroot type %d not supported\n",
510 pNetRoot->Type));
511 return STATUS_NOT_IMPLEMENTED;
512 }
513
514 Status = vbsfProcessCreate(RxContext,
515 RemainingName,
516 &Info,
517 RxContext->Create.EaBuffer,
518 RxContext->Create.EaLength,
519 &CreateAction,
520 &Handle);
521
522 if (Status != STATUS_SUCCESS)
523 {
524 Log(("VBOXSF: MRxCreate: vbsfProcessCreate failed 0x%08X\n",
525 Status));
526 return Status;
527 }
528
529 Log(("VBOXSF: MRxCreate: EOF is 0x%RX64 AllocSize is 0x%RX64\n",
530 Info.cbObject, Info.cbAllocated));
531
532 RxContext->pFobx = RxCreateNetFobx(RxContext, SrvOpen);
533 if (!RxContext->pFobx)
534 {
535 Log(("VBOXSF: MRxCreate: RxCreateNetFobx failed\n"));
536 VbglR0SfHostReqCloseSimple(pNetRootExtension->map.root, Handle);
537 return STATUS_INSUFFICIENT_RESOURCES;
538 }
539 pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx);
540 Log(("VBOXSF: MRxCreate: VBoxFobx = %p\n",
541 pVBoxFobx));
542 AssertReturnStmt(pVBoxFobx, VbglR0SfHostReqCloseSimple(pNetRootExtension->map.root, Handle), STATUS_INTERNAL_ERROR);
543
544
545 Log(("VBOXSF: MRxCreate: CreateAction = 0x%08X\n",
546 CreateAction));
547
548 RxContext->Create.ReturnedCreateInformation = CreateAction;
549
550 /*
551 * Make sure we've got the FCB locked exclusivly before updating it and returning.
552 * (bird: not entirely sure if this is needed for the W10 RDBSS, but cannot hurt.)
553 */
554 if (!RxIsFcbAcquiredExclusive(capFcb))
555 RxAcquireExclusiveFcbResourceInMRx(capFcb);
556
557
558 /* Initialize the FCB if this is the first open.
559 Note! The RxFinishFcbInitialization call expects node types as the 2nd parameter, but is for
560 some reason given enum RX_FILE_TYPE as type. */
561 if (capFcb->OpenCount == 0)
562 {
563 FCB_INIT_PACKET InitPacket;
564 FILE_NETWORK_OPEN_INFORMATION Data;
565 ULONG NumberOfLinks = 0; /** @todo ?? */
566 Data.CreationTime.QuadPart = RTTimeSpecGetNtTime(&Info.BirthTime);
567 Data.LastAccessTime.QuadPart = RTTimeSpecGetNtTime(&Info.AccessTime);
568 Data.LastWriteTime.QuadPart = RTTimeSpecGetNtTime(&Info.ModificationTime);
569 Data.ChangeTime.QuadPart = RTTimeSpecGetNtTime(&Info.ChangeTime);
570 Data.AllocationSize.QuadPart = Info.cbAllocated; /** @todo test sparse files. CcSetFileSizes is documented to not want allocation size smaller than EOF offset. */
571 Data.EndOfFile.QuadPart = Info.cbObject;
572 Data.FileAttributes = VBoxToNTFileAttributes(Info.Attr.fMode);
573 RxFormInitPacket(InitPacket,
574 &Data.FileAttributes,
575 &NumberOfLinks,
576 &Data.CreationTime,
577 &Data.LastAccessTime,
578 &Data.LastWriteTime,
579 &Data.ChangeTime,
580 &Data.AllocationSize,
581 &Data.EndOfFile,
582 &Data.EndOfFile);
583 if (Info.Attr.fMode & RTFS_DOS_DIRECTORY)
584 RxFinishFcbInitialization(capFcb, (RX_FILE_TYPE)RDBSS_NTC_STORAGE_TYPE_DIRECTORY, &InitPacket);
585 else
586 RxFinishFcbInitialization(capFcb, (RX_FILE_TYPE)RDBSS_NTC_STORAGE_TYPE_FILE, &InitPacket);
587 }
588
589 SrvOpen->BufferingFlags = 0;
590
591 RxContext->pFobx->OffsetOfNextEaToReturn = 1;
592
593 pVBoxFobx->hFile = Handle;
594 pVBoxFobx->pSrvCall = RxContext->Create.pSrvCall;
595 pVBoxFobx->Info = Info;
596
597 /*
598 * See if the size has changed and update the FCB if it has.
599 */
600 if ( capFcb->OpenCount > 0
601 && capFcb->Header.FileSize.QuadPart != Info.cbObject)
602 {
603 PFILE_OBJECT pFileObj = RxContext->CurrentIrpSp->FileObject;
604 Assert(pFileObj);
605 if (pFileObj)
606 vbsfNtUpdateFcbSize(pFileObj, capFcb, pVBoxFobx, Info.cbObject, capFcb->Header.FileSize.QuadPart, Info.cbAllocated);
607 }
608
609 /*
610 * Do logging.
611 */
612 Log(("VBOXSF: MRxCreate: Info: BirthTime %RI64\n", RTTimeSpecGetNano(&pVBoxFobx->Info.BirthTime)));
613 Log(("VBOXSF: MRxCreate: Info: ChangeTime %RI64\n", RTTimeSpecGetNano(&pVBoxFobx->Info.ChangeTime)));
614 Log(("VBOXSF: MRxCreate: Info: ModificationTime %RI64\n", RTTimeSpecGetNano(&pVBoxFobx->Info.ModificationTime)));
615 Log(("VBOXSF: MRxCreate: Info: AccessTime %RI64\n", RTTimeSpecGetNano(&pVBoxFobx->Info.AccessTime)));
616 Log(("VBOXSF: MRxCreate: Info: fMode %#RX32\n", pVBoxFobx->Info.Attr.fMode));
617 if (!(Info.Attr.fMode & RTFS_DOS_DIRECTORY))
618 {
619 Log(("VBOXSF: MRxCreate: Info: cbObject %#RX64\n", pVBoxFobx->Info.cbObject));
620 Log(("VBOXSF: MRxCreate: Info: cbAllocated %#RX64\n", pVBoxFobx->Info.cbAllocated));
621 }
622
623 Log(("VBOXSF: MRxCreate: NetRoot is %p, Fcb is %p, SrvOpen is %p, Fobx is %p\n",
624 pNetRoot, capFcb, SrvOpen, RxContext->pFobx));
625 Log(("VBOXSF: MRxCreate: return 0x%08X\n",
626 Status));
627
628 return Status;
629}
630
631NTSTATUS VBoxMRxComputeNewBufferingState(IN OUT PMRX_SRV_OPEN pMRxSrvOpen, IN PVOID pMRxContext, OUT PULONG pNewBufferingState)
632{
633 RT_NOREF(pMRxSrvOpen, pMRxContext, pNewBufferingState);
634 Log(("VBOXSF: MRxComputeNewBufferingState\n"));
635 return STATUS_NOT_SUPPORTED;
636}
637
638NTSTATUS VBoxMRxDeallocateForFcb(IN OUT PMRX_FCB pFcb)
639{
640 RT_NOREF(pFcb);
641 Log(("VBOXSF: MRxDeallocateForFcb\n"));
642 return STATUS_SUCCESS;
643}
644
645NTSTATUS VBoxMRxDeallocateForFobx(IN OUT PMRX_FOBX pFobx)
646{
647 RT_NOREF(pFobx);
648 Log(("VBOXSF: MRxDeallocateForFobx\n"));
649 return STATUS_SUCCESS;
650}
651
652NTSTATUS VBoxMRxTruncate(IN PRX_CONTEXT RxContext)
653{
654 RT_NOREF(RxContext);
655 Log(("VBOXSF: MRxTruncate\n"));
656 return STATUS_NOT_IMPLEMENTED;
657}
658
659NTSTATUS VBoxMRxCleanupFobx(IN PRX_CONTEXT RxContext)
660{
661 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(RxContext->pFobx);
662
663 Log(("VBOXSF: MRxCleanupFobx: pVBoxFobx = %p, Handle = 0x%RX64\n", pVBoxFobx, pVBoxFobx? pVBoxFobx->hFile: 0));
664
665 if (!pVBoxFobx)
666 return STATUS_INVALID_PARAMETER;
667
668 return STATUS_SUCCESS;
669}
670
671NTSTATUS VBoxMRxForceClosed(IN PMRX_SRV_OPEN pSrvOpen)
672{
673 RT_NOREF(pSrvOpen);
674 Log(("VBOXSF: MRxForceClosed\n"));
675 return STATUS_NOT_IMPLEMENTED;
676}
677
678/**
679 * Ensures the FCBx doesn't have dangling pointers to @a pVBoxFobx.
680 *
681 * This isn't strictly speaking needed, as nobody currently dereference these
682 * pointers, however better keeping things neath and tidy.
683 */
684DECLINLINE(void) vbsfNtCleanupFcbxTimestampRefsOnClose(PMRX_VBOX_FOBX pVBoxFobx, PVBSFNTFCBEXT pVBoxFcbx)
685{
686 pVBoxFobx->fTimestampsSetByUser = 0;
687 pVBoxFobx->fTimestampsUpdatingSuppressed = 0;
688 pVBoxFobx->fTimestampsImplicitlyUpdated = 0;
689 if (pVBoxFcbx->pFobxLastAccessTime == pVBoxFobx)
690 pVBoxFcbx->pFobxLastAccessTime = NULL;
691 if (pVBoxFcbx->pFobxLastWriteTime == pVBoxFobx)
692 pVBoxFcbx->pFobxLastWriteTime = NULL;
693 if (pVBoxFcbx->pFobxChangeTime == pVBoxFobx)
694 pVBoxFcbx->pFobxChangeTime = NULL;
695}
696
697/**
698 * Closes an opened file handle of a MRX_VBOX_FOBX.
699 *
700 * Updates file attributes if necessary.
701 *
702 * Used by VBoxMRxCloseSrvOpen and vbsfNtRename.
703 */
704NTSTATUS vbsfNtCloseFileHandle(PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension,
705 PMRX_VBOX_FOBX pVBoxFobx,
706 PVBSFNTFCBEXT pVBoxFcbx)
707{
708 if (pVBoxFobx->hFile == SHFL_HANDLE_NIL)
709 {
710 Log(("VBOXSF: vbsfCloseFileHandle: SHFL_HANDLE_NIL\n"));
711 return STATUS_SUCCESS;
712 }
713
714 Log(("VBOXSF: vbsfCloseFileHandle: 0x%RX64, fTimestampsUpdatingSuppressed = %#x, fTimestampsImplicitlyUpdated = %#x\n",
715 pVBoxFobx->hFile, pVBoxFobx->fTimestampsUpdatingSuppressed, pVBoxFobx->fTimestampsImplicitlyUpdated));
716
717 /*
718 * We allocate a single request buffer for the timestamp updating and the closing
719 * to save time (at the risk of running out of heap, but whatever).
720 */
721 union MyCloseAndInfoReq
722 {
723 VBOXSFCLOSEREQ Close;
724 VBOXSFOBJINFOREQ Info;
725 } *pReq = (union MyCloseAndInfoReq *)VbglR0PhysHeapAlloc(sizeof(*pReq));
726 if (pReq)
727 RT_ZERO(*pReq);
728 else
729 return STATUS_INSUFF_SERVER_RESOURCES;
730
731 /*
732 * Restore timestamp that we may implicitly been updated via this handle
733 * after the user explicitly set them or turn off implict updating (the -1 value).
734 *
735 * Note! We ignore the status of this operation.
736 */
737 Assert(pVBoxFcbx);
738 uint8_t fUpdateTs = pVBoxFobx->fTimestampsUpdatingSuppressed & pVBoxFobx->fTimestampsImplicitlyUpdated;
739 if (fUpdateTs)
740 {
741 /** @todo skip this if the host is windows and fTimestampsUpdatingSuppressed == fTimestampsSetByUser */
742 /** @todo pass -1 timestamps thru so we can always skip this on windows hosts! */
743 if ( (fUpdateTs & VBOX_FOBX_F_INFO_LASTACCESS_TIME)
744 && pVBoxFcbx->pFobxLastAccessTime == pVBoxFobx)
745 pReq->Info.ObjInfo.AccessTime = pVBoxFobx->Info.AccessTime;
746 else
747 fUpdateTs &= ~VBOX_FOBX_F_INFO_LASTACCESS_TIME;
748
749 if ( (fUpdateTs & VBOX_FOBX_F_INFO_LASTWRITE_TIME)
750 && pVBoxFcbx->pFobxLastWriteTime == pVBoxFobx)
751 pReq->Info.ObjInfo.ModificationTime = pVBoxFobx->Info.ModificationTime;
752 else
753 fUpdateTs &= ~VBOX_FOBX_F_INFO_LASTWRITE_TIME;
754
755 if ( (fUpdateTs & VBOX_FOBX_F_INFO_CHANGE_TIME)
756 && pVBoxFcbx->pFobxChangeTime == pVBoxFobx)
757 pReq->Info.ObjInfo.ChangeTime = pVBoxFobx->Info.ChangeTime;
758 else
759 fUpdateTs &= ~VBOX_FOBX_F_INFO_CHANGE_TIME;
760 if (fUpdateTs)
761 {
762 Log(("VBOXSF: vbsfCloseFileHandle: Updating timestamp: %#x\n", fUpdateTs));
763 int vrc = VbglR0SfHostReqSetObjInfo(pNetRootExtension->map.root, &pReq->Info, pVBoxFobx->hFile);
764 if (RT_FAILURE(vrc))
765 Log(("VBOXSF: vbsfCloseFileHandle: VbglR0SfHostReqSetObjInfo failed for fUpdateTs=%#x: %Rrc\n", fUpdateTs, vrc));
766 RT_NOREF(vrc);
767 }
768 else
769 Log(("VBOXSF: vbsfCloseFileHandle: no timestamp needing updating\n"));
770 }
771
772 vbsfNtCleanupFcbxTimestampRefsOnClose(pVBoxFobx, pVBoxFcbx);
773
774 /*
775 * Now close the handle.
776 */
777 int vrc = VbglR0SfHostReqClose(pNetRootExtension->map.root, &pReq->Close, pVBoxFobx->hFile);
778
779 pVBoxFobx->hFile = SHFL_HANDLE_NIL;
780
781 VbglR0PhysHeapFree(pReq);
782
783 NTSTATUS const Status = RT_SUCCESS(vrc) ? STATUS_SUCCESS : vbsfNtVBoxStatusToNt(vrc);
784 Log(("VBOXSF: vbsfCloseFileHandle: Returned 0x%08X (vrc=%Rrc)\n", Status, vrc));
785 return Status;
786}
787
788/**
789 * @note We don't collapse opens, this is called whenever a handle is closed.
790 */
791NTSTATUS VBoxMRxCloseSrvOpen(IN PRX_CONTEXT RxContext)
792{
793 RxCaptureFcb;
794 RxCaptureFobx;
795
796 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
797 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
798 PMRX_SRV_OPEN pSrvOpen = capFobx->pSrvOpen;
799
800
801 Log(("VBOXSF: MRxCloseSrvOpen: capFcb = %p, capFobx = %p, pVBoxFobx = %p, pSrvOpen = %p\n",
802 capFcb, capFobx, pVBoxFobx, pSrvOpen));
803
804#ifdef LOG_ENABLED
805 PUNICODE_STRING pRemainingName = pSrvOpen->pAlreadyPrefixedName;
806 Log(("VBOXSF: MRxCloseSrvOpen: Remaining name = %.*ls, Len = %d\n",
807 pRemainingName->Length / sizeof(WCHAR), pRemainingName->Buffer, pRemainingName->Length));
808#endif
809
810 if (!pVBoxFobx)
811 return STATUS_INVALID_PARAMETER;
812
813 if (FlagOn(pSrvOpen->Flags, (SRVOPEN_FLAG_FILE_RENAMED | SRVOPEN_FLAG_FILE_DELETED)))
814 {
815 /* If we renamed or delete the file/dir, then it's already closed */
816 Assert(pVBoxFobx->hFile == SHFL_HANDLE_NIL);
817 Log(("VBOXSF: MRxCloseSrvOpen: File was renamed, handle 0x%RX64 ignore close.\n",
818 pVBoxFobx->hFile));
819 return STATUS_SUCCESS;
820 }
821
822 /*
823 * Remove file or directory if delete action is pending and the this is the last open handle.
824 */
825 NTSTATUS Status = STATUS_SUCCESS;
826 if (capFcb->FcbState & FCB_STATE_DELETE_ON_CLOSE)
827 {
828 Log(("VBOXSF: MRxCloseSrvOpen: Delete on close. Open count = %d\n",
829 capFcb->OpenCount));
830
831 if (capFcb->OpenCount == 0)
832 Status = vbsfNtRemove(RxContext);
833 }
834
835 /*
836 * Close file if we still have a handle to it.
837 */
838 if (pVBoxFobx->hFile != SHFL_HANDLE_NIL)
839 vbsfNtCloseFileHandle(pNetRootExtension, pVBoxFobx, VBoxMRxGetFcbExtension(capFcb));
840
841 return Status;
842}
843
844/**
845 * Worker for vbsfNtSetBasicInfo and VBoxMRxCloseSrvOpen.
846 *
847 * Only called by vbsfNtSetBasicInfo if there is exactly one open handle. And
848 * VBoxMRxCloseSrvOpen calls it when the last handle is being closed.
849 */
850NTSTATUS vbsfNtRemove(IN PRX_CONTEXT RxContext)
851{
852 RxCaptureFcb;
853 RxCaptureFobx;
854 PMRX_VBOX_NETROOT_EXTENSION pNetRootExtension = VBoxMRxGetNetRootExtension(capFcb->pNetRoot);
855 PMRX_VBOX_FOBX pVBoxFobx = VBoxMRxGetFileObjectExtension(capFobx);
856 PUNICODE_STRING pRemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
857 uint16_t const cwcRemainingName = pRemainingName->Length / sizeof(WCHAR);
858
859 Log(("VBOXSF: vbsfNtRemove: Delete %.*ls. open count = %d\n",
860 cwcRemainingName, pRemainingName->Buffer, capFcb->OpenCount));
861 Assert(RxIsFcbAcquiredExclusive(capFcb));
862
863 /*
864 * We've got function that does both deletion and handle closing starting with 6.0.8,
865 * this saves us a host call when just deleting the file/dir.
866 */
867 uint32_t const fRemove = pVBoxFobx->Info.Attr.fMode & RTFS_DOS_DIRECTORY ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE;
868 NTSTATUS Status;
869 int vrc;
870 if (g_uSfLastFunction >= SHFL_FN_CLOSE_AND_REMOVE)
871 {
872 size_t const cbReq = RT_UOFFSETOF(VBOXSFCLOSEANDREMOVEREQ, StrPath.String) + (cwcRemainingName + 1) * sizeof(RTUTF16);
873 VBOXSFCLOSEANDREMOVEREQ *pReq = (VBOXSFCLOSEANDREMOVEREQ *)VbglR0PhysHeapAlloc((uint32_t)cbReq);
874 if (pReq)
875 RT_ZERO(*pReq);
876 else
877 return STATUS_INSUFFICIENT_RESOURCES;
878
879 memcpy(&pReq->StrPath.String, pRemainingName->Buffer, cwcRemainingName * sizeof(RTUTF16));
880 pReq->StrPath.String.utf16[cwcRemainingName] = '\0';
881 pReq->StrPath.u16Length = cwcRemainingName * 2;
882 pReq->StrPath.u16Size = cwcRemainingName * 2 + (uint16_t)sizeof(RTUTF16);
883 vrc = VbglR0SfHostReqCloseAndRemove(pNetRootExtension->map.root, pReq, fRemove, pVBoxFobx->hFile);
884 pVBoxFobx->hFile = SHFL_HANDLE_NIL;
885
886 VbglR0PhysHeapFree(pReq);
887 }
888 else
889 {
890 /*
891 * We allocate a single request buffer for the closing and deletion to save time.
892 */
893 AssertCompile(sizeof(VBOXSFCLOSEREQ) <= sizeof(VBOXSFREMOVEREQ));
894 AssertReturn((cwcRemainingName + 1) * sizeof(RTUTF16) < _64K, STATUS_NAME_TOO_LONG);
895 size_t cbReq = RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath.String) + (cwcRemainingName + 1) * sizeof(RTUTF16);
896 union MyCloseAndRemoveReq
897 {
898 VBOXSFCLOSEREQ Close;
899 VBOXSFREMOVEREQ Remove;
900 } *pReq = (union MyCloseAndRemoveReq *)VbglR0PhysHeapAlloc((uint32_t)cbReq);
901 if (pReq)
902 RT_ZERO(*pReq);
903 else
904 return STATUS_INSUFFICIENT_RESOURCES;
905
906 /*
907 * Close file first if not already done. We dont use vbsfNtCloseFileHandle here
908 * as we got our own request buffer and have no need to update any file info.
909 */
910 if (pVBoxFobx->hFile != SHFL_HANDLE_NIL)
911 {
912 int vrcClose = VbglR0SfHostReqClose(pNetRootExtension->map.root, &pReq->Close, pVBoxFobx->hFile);
913 pVBoxFobx->hFile = SHFL_HANDLE_NIL;
914 if (RT_FAILURE(vrcClose))
915 Log(("VBOXSF: vbsfNtRemove: Closing the handle failed! vrcClose %Rrc, hFile %#RX64 (probably)\n",
916 vrcClose, pReq->Close.Parms.u64Handle.u.value64));
917 }
918
919 /*
920 * Try remove the file.
921 */
922 uint16_t const cwcToCopy = pRemainingName->Length / sizeof(WCHAR);
923 AssertMsgReturnStmt(cwcToCopy == cwcRemainingName,
924 ("%#x, was %#x; FCB exclusivity: %d\n", cwcToCopy, cwcRemainingName, RxIsFcbAcquiredExclusive(capFcb)),
925 VbglR0PhysHeapFree(pReq), STATUS_INTERNAL_ERROR);
926 memcpy(&pReq->Remove.StrPath.String, pRemainingName->Buffer, cwcToCopy * sizeof(RTUTF16));
927 pReq->Remove.StrPath.String.utf16[cwcToCopy] = '\0';
928 pReq->Remove.StrPath.u16Length = cwcToCopy * 2;
929 pReq->Remove.StrPath.u16Size = cwcToCopy * 2 + (uint16_t)sizeof(RTUTF16);
930 vrc = VbglR0SfHostReqRemove(pNetRootExtension->map.root, &pReq->Remove, fRemove);
931
932 VbglR0PhysHeapFree(pReq);
933 }
934
935 if (RT_SUCCESS(vrc))
936 {
937 SetFlag(capFobx->pSrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED);
938 vbsfNtCleanupFcbxTimestampRefsOnClose(pVBoxFobx, VBoxMRxGetFcbExtension(capFcb));
939 Status = STATUS_SUCCESS;
940 }
941 else
942 {
943 Log(("VBOXSF: vbsfNtRemove: VbglR0SfRemove failed with %Rrc\n", vrc));
944 Status = vbsfNtVBoxStatusToNt(vrc);
945 }
946
947 Log(("VBOXSF: vbsfNtRemove: Returned %#010X (%Rrc)\n", Status, vrc));
948 return Status;
949}
950
951NTSTATUS VBoxMRxShouldTryToCollapseThisOpen(IN PRX_CONTEXT RxContext)
952{
953 RT_NOREF(RxContext);
954 Log(("VBOXSF: MRxShouldTryToCollapseThisOpen\n"));
955 return STATUS_MORE_PROCESSING_REQUIRED;
956}
957
958NTSTATUS VBoxMRxCollapseOpen(IN OUT PRX_CONTEXT RxContext)
959{
960 RT_NOREF(RxContext);
961 Log(("VBOXSF: MRxCollapseOpen\n"));
962 return STATUS_MORE_PROCESSING_REQUIRED;
963}
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