VirtualBox

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

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

winnt/vboxsf: Investigated all the file info queries after opening a file and used TTL on the stat info to try avoid those. The TTL code needed some fixing. bugref:9172

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