VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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