Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4247 lines
141 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Create.c
  5. Abstract:
  6. This module implements the File Create routine for Rx called by the
  7. dispatch driver.
  8. The implementation of SL_OPEN_TARGET_DIRECTORY is a bit unusual...we don't
  9. actually do it unless the minirdr specifically requests it.
  10. Instead, we just get the fcb built and then return it. The nodetype is set so
  11. that no operations can be done except close/cleanup. In this way, we will not
  12. take an extra trip to the server or a trip to an incorrect server for rename
  13. operations. If SL_OPEN... can be used for something other than rename, a
  14. minirdr that uses this facility is toast.
  15. Author:
  16. Joe Linn [JoeLinn] 8-aug-94
  17. Revision History:
  18. Balan Sethu Raman [SethuR] 17-July-95
  19. --*/
  20. #include "precomp.h"
  21. #pragma hdrstop
  22. #include <ntddmup.h>
  23. #include <fsctlbuf.h>
  24. #include <dfsfsctl.h>
  25. #if 0 && defined(REMOTE_BOOT)
  26. BOOLEAN LogAllFiles = FALSE;
  27. BOOLEAN WatchAllFiles = FALSE;
  28. BOOLEAN FirstWatchOnly = FALSE;
  29. BOOLEAN IsFirstWatch = TRUE;
  30. #endif
  31. //
  32. // The debug trace level
  33. //
  34. #define Dbg (DEBUG_TRACE_CREATE)
  35. #ifdef LOG_SHARINGCHECKS
  36. #define RxLogForSharingCheck(x) RxLog(x)
  37. #else
  38. #define RxLogForSharingCheck(x)
  39. #endif
  40. #if DBG
  41. #define DEBUG_TAG(___xxx) ,(___xxx)
  42. #else
  43. #define DEBUG_TAG(_xxx)
  44. #endif
  45. LUID RxSecurityPrivilege = { SE_SECURITY_PRIVILEGE, 0 };
  46. #define StorageType(co) ((co) & FILE_STORAGE_TYPE_MASK)
  47. #define StorageFlag(co) ((co) & FILE_STORAGE_TYPE_SPECIFIED)
  48. #define IsStorageTypeSpecified(co) (StorageFlag(co) == FILE_STORAGE_TYPE_SPECIFIED)
  49. #define MustBeDirectory(co) ((co) & FILE_DIRECTORY_FILE)
  50. #define MustBeFile(co) ((co) & FILE_NON_DIRECTORY_FILE)
  51. //
  52. // Where 0 represents a SessionId, the following path formats are used:
  53. //
  54. // "\;m:0\Server\Share" for drive based connections
  55. //
  56. // "\;:0\Server\Share" for UNC based connections
  57. //
  58. // The SessionId is always 0 for NT 5, and a number representing a
  59. // unique session for Hydra.
  60. //
  61. #define DRIVE_BASED_PATH_IDENTIFIER (L';')
  62. //
  63. // The following is used to enable tracing when a specific file name is seen.
  64. // Tracing continues for a specified number of IRPs.
  65. // Usage:
  66. // Break in with debugger and set DbgTriggerNameStr to the ansi string for the
  67. // file name to trigger on (with trailing null).
  68. // Set DbgTriggerIrpCount to the number of IRPs to trace after the Create is
  69. // seen on the name string.
  70. // Set DbgTriggerState to zero and then continue.
  71. //
  72. #ifdef RDBSSTRACE
  73. UNICODE_STRING DbgTriggerUStr = {0,0,NULL};
  74. STRING DbgTriggerNameStr = {0,0,NULL};
  75. CHAR DbgTriggerName[120] = "\\;F:\\davidor4\\nb4\\clients\\client1\\~DMTMP\\WINWORD\\~WRD0003.tmp";
  76. #define DBG_TRIGGER_INIT 0
  77. #define DBG_TRIGGER_LOOKING 1
  78. #define DBG_TRIGGER_FOUND 2
  79. ULONG DbgTriggerState = DBG_TRIGGER_FOUND;
  80. ULONG DbgTriggerIrpCount = 130;
  81. ULONG RxGlobalTraceIrpCount = 0;
  82. #endif
  83. extern BOOLEAN DisableByteRangeLockingOnReadOnlyFiles;
  84. #define SPOOLER_PROCESS_NAME "spoolsv.exe"
  85. VOID
  86. RxSetFullNameInFcb (
  87. IN PRX_CONTEXT RxContext,
  88. IN PFCB Fcb,
  89. IN PUNICODE_STRING FinalName
  90. );
  91. VOID
  92. RxCopyCreateParameters (
  93. PRX_CONTEXT RxContext
  94. );
  95. VOID
  96. RxFreeCanonicalNameBuffer (
  97. IN OUT PRX_CONTEXT RxContext
  98. );
  99. NTSTATUS
  100. RxAllocateCanonicalNameBuffer (
  101. IN OUT PRX_CONTEXT RxContext,
  102. IN OUT PUNICODE_STRING CanonicalName,
  103. IN ULONG BufferSizeRequired);
  104. NTSTATUS
  105. RxFirstCanonicalize (
  106. IN OUT PRX_CONTEXT RxContext,
  107. IN PIRP Irp,
  108. IN PUNICODE_STRING FileName,
  109. IN OUT PUNICODE_STRING CanonicalName,
  110. OUT PNET_ROOT_TYPE NetRootType
  111. );
  112. NTSTATUS
  113. RxCanonicalizeFileNameByServerSpecs (
  114. IN OUT PRX_CONTEXT RxContext,
  115. IN OUT PUNICODE_STRING RemainingName
  116. );
  117. NTSTATUS
  118. RxCanonicalizeNameAndObtainNetRoot (
  119. IN OUT PRX_CONTEXT RxContext,
  120. IN PIRP Irp,
  121. IN PUNICODE_STRING FileName,
  122. OUT PUNICODE_STRING RemainingName
  123. );
  124. NTSTATUS
  125. RxFindOrCreateFcb (
  126. IN OUT PRX_CONTEXT RxContext,
  127. IN PIRP Irp,
  128. IN PUNICODE_STRING RemainingName,
  129. OUT PFCB *Fcb
  130. );
  131. VOID
  132. RxSetupNetFileObject (
  133. IN OUT PRX_CONTEXT RxContext,
  134. IN PIRP Irp,
  135. IN PFCB Fcb
  136. );
  137. NTSTATUS
  138. RxSearchForCollapsibleOpen (
  139. IN OUT PRX_CONTEXT RxContext,
  140. IN PFCB Fcb,
  141. IN ACCESS_MASK DesiredAccess,
  142. IN ULONG ShareAccess
  143. );
  144. NTSTATUS
  145. RxCollapseOrCreateSrvOpen (
  146. IN OUT PRX_CONTEXT RxContext,
  147. IN PIRP Irp,
  148. IN PFCB Fcb
  149. );
  150. NTSTATUS
  151. RxCreateFromNetRoot (
  152. IN OUT PRX_CONTEXT RxContext,
  153. IN PIRP Irp,
  154. IN PUNICODE_STRING RemainingName
  155. );
  156. NTSTATUS
  157. RxCreateTreeConnect (
  158. IN PRX_CONTEXT RxContext
  159. );
  160. UCHAR *
  161. PsGetProcessImageFileName(
  162. PEPROCESS Process
  163. );
  164. #ifdef ALLOC_PRAGMA
  165. #pragma alloc_text(PAGE, RxCommonCreate)
  166. #pragma alloc_text(PAGE, RxAllocateCanonicalNameBuffer)
  167. #pragma alloc_text(PAGE, RxFreeCanonicalNameBuffer)
  168. #pragma alloc_text(PAGE, RxFirstCanonicalize)
  169. #pragma alloc_text(PAGE, RxCanonicalizeFileNameByServerSpecs)
  170. #pragma alloc_text(PAGE, RxCanonicalizeNameAndObtainNetRoot)
  171. #pragma alloc_text(PAGE, RxFindOrCreateFcb)
  172. #pragma alloc_text(PAGE, RxSearchForCollapsibleOpen)
  173. #pragma alloc_text(PAGE, RxCollapseOrCreateSrvOpen)
  174. #pragma alloc_text(PAGE, RxSetupNetFileObject)
  175. #pragma alloc_text(PAGE, RxCreateFromNetRoot)
  176. #pragma alloc_text(PAGE, RxPrefixClaim)
  177. #pragma alloc_text(PAGE, RxCreateTreeConnect)
  178. #pragma alloc_text(PAGE, RxCheckShareAccessPerSrvOpens)
  179. #pragma alloc_text(PAGE, RxUpdateShareAccessPerSrvOpens)
  180. #pragma alloc_text(PAGE, RxRemoveShareAccessPerSrvOpens)
  181. #pragma alloc_text(PAGE, RxGetSessionId)
  182. #endif
  183. #if DBG
  184. #ifdef ALLOC_PRAGMA
  185. #pragma alloc_text(PAGE, RxDumpWantedAccess)
  186. #pragma alloc_text(PAGE, RxDumpCurrentAccess)
  187. #pragma alloc_text(PAGE, RxCheckShareAccess)
  188. #pragma alloc_text(PAGE, RxRemoveShareAccess)
  189. #pragma alloc_text(PAGE, RxSetShareAccess)
  190. #pragma alloc_text(PAGE, RxUpdateShareAccess)
  191. #endif
  192. #endif
  193. INLINE VOID
  194. RxCopyCreateParameters (
  195. IN PRX_CONTEXT RxContext
  196. )
  197. /*++
  198. Routine Description:
  199. This uses the RxContext as a base to reach out and get the values of the NT
  200. create parameters. The idea is to centralize this code.
  201. It also implements such as ideas as (a) it must be a directory if a backslash
  202. was stripped and (b) unbuffered is translated to write-through.
  203. Arguments:
  204. RxContext - the context instance
  205. Notes:
  206. --*/
  207. {
  208. PIRP Irp = RxContext->CurrentIrp;
  209. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  210. PFILE_OBJECT FileObject = IrpSp->FileObject;
  211. PNT_CREATE_PARAMETERS cp = &RxContext->Create.NtCreateParameters;
  212. RxDbgTrace(+1, Dbg, ("RxCopyCreateParameters\n"));
  213. cp->SecurityContext = IrpSp->Parameters.Create.SecurityContext;
  214. if ((cp->SecurityContext->AccessState != NULL) &&
  215. (cp->SecurityContext->AccessState->SecurityDescriptor != NULL)) {
  216. //
  217. // Note: Io subsystem captures and verifies security descriptor in irp
  218. //
  219. RxContext->Create.SdLength = RtlLengthSecurityDescriptor( cp->SecurityContext->AccessState->SecurityDescriptor );
  220. RxDbgTrace( 0, Dbg, ("->SecurityCtx/SdLength = %08lx %08lx\n",
  221. cp->SecurityContext,
  222. RxContext->Create.SdLength ));
  223. RxLog(( " SDss %lx %lx\n", cp->SecurityContext, RxContext->Create.SdLength ));
  224. RxWmiLog( LOG,
  225. RxCopyCreateParameters_1,
  226. LOGPTR( cp->SecurityContext )
  227. LOGULONG(RxContext->Create.SdLength ));
  228. }
  229. if (cp->SecurityContext->SecurityQos != NULL) {
  230. cp->ImpersonationLevel = cp->SecurityContext->SecurityQos->ImpersonationLevel;
  231. } else {
  232. cp->ImpersonationLevel = DEFAULT_IMPERSONATION_LEVEL;
  233. }
  234. cp->DesiredAccess = cp->SecurityContext->DesiredAccess;
  235. cp->AllocationSize = Irp->Overlay.AllocationSize;
  236. cp->FileAttributes = FlagOn( IrpSp->Parameters.Create.FileAttributes, FILE_ATTRIBUTE_VALID_FLAGS );
  237. cp->ShareAccess = FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_VALID_FLAGS );
  238. cp->Disposition = (((IrpSp->Parameters.Create.Options)) >> 24) & 0x000000ff;
  239. cp->CreateOptions = FlagOn( IrpSp->Parameters.Create.Options, FILE_VALID_OPTION_FLAGS );
  240. cp->DfsNameContext = FileObject->FsContext;
  241. cp->DfsContext = FileObject->FsContext2;
  242. ASSERT( (cp->DfsContext == NULL) ||
  243. (cp->DfsContext == UIntToPtr( DFS_OPEN_CONTEXT )) ||
  244. (cp->DfsContext == UIntToPtr( DFS_DOWNLEVEL_OPEN_CONTEXT )) ||
  245. (cp->DfsContext == UIntToPtr( DFS_CSCAGENT_NAME_CONTEXT )) ||
  246. (cp->DfsContext == UIntToPtr( DFS_USER_NAME_CONTEXT )) );
  247. ASSERT( (cp->DfsNameContext == NULL) ||
  248. (cp->DfsNameContext->NameContextType == DFS_OPEN_CONTEXT) ||
  249. (cp->DfsNameContext->NameContextType == DFS_DOWNLEVEL_OPEN_CONTEXT) ||
  250. (cp->DfsNameContext->NameContextType == DFS_CSCAGENT_NAME_CONTEXT) ||
  251. (cp->DfsNameContext->NameContextType == DFS_USER_NAME_CONTEXT) );
  252. FileObject->FsContext2 = NULL;
  253. FileObject->FsContext = NULL;
  254. //
  255. // The FsContext field was placed as the pFcb in the RX_CONTEXT. Clear it also
  256. //
  257. RxContext->pFcb = NULL;
  258. if (FlagOn( RxContext->Create.Flags,RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH )){
  259. SetFlag( cp->CreateOptions, FILE_DIRECTORY_FILE );
  260. }
  261. RxContext->Create.ReturnedCreateInformation = 0;
  262. RxContext->Create.EaLength = IrpSp->Parameters.Create.EaLength;
  263. if (RxContext->Create.EaLength) {
  264. RxContext->Create.EaBuffer = Irp->AssociatedIrp.SystemBuffer;
  265. RxDbgTrace( 0, Dbg, ("->System(Ea)Buffer/EALength = %08lx %08lx\n",
  266. Irp->AssociatedIrp.SystemBuffer,
  267. IrpSp->Parameters.Create.EaLength ));
  268. RxLog(( " EAs %lx %lx\n",
  269. Irp->AssociatedIrp.SystemBuffer,
  270. IrpSp->Parameters.Create.EaLength ));
  271. RxWmiLog( LOG,
  272. RxCopyCreateParameters_2,
  273. LOGPTR( Irp->AssociatedIrp.SystemBuffer )
  274. LOGULONG( IrpSp->Parameters.Create.EaLength ));
  275. } else {
  276. RxContext->Create.EaBuffer = NULL;
  277. }
  278. RxDbgTrace(-1, Dbg, ("RxCopyNtCreateParameters\n"));
  279. }
  280. VOID
  281. RxFreeCanonicalNameBuffer(
  282. IN OUT PRX_CONTEXT RxContext
  283. )
  284. /*++
  285. Routine Description:
  286. This routine is called to free the canonical name buffer and reset the state.
  287. COULD BE INLINED!
  288. Arguments:
  289. RxContext - the current workitem
  290. Return Value:
  291. none
  292. --*/
  293. {
  294. ASSERT( RxContext->Create.CanonicalNameBuffer == RxContext->AlsoCanonicalNameBuffer );
  295. if (RxContext->Create.CanonicalNameBuffer) {
  296. RxFreePool( RxContext->Create.CanonicalNameBuffer );
  297. RxContext->Create.CanonicalNameBuffer = NULL;
  298. RxContext->AlsoCanonicalNameBuffer = NULL;
  299. }
  300. ASSERT( RxContext->Create.CanonicalNameBuffer == NULL );
  301. }
  302. NTSTATUS
  303. RxAllocateCanonicalNameBuffer(
  304. IN OUT PRX_CONTEXT RxContext,
  305. IN OUT PUNICODE_STRING CanonicalName,
  306. IN ULONG BufferSizeRequired
  307. )
  308. /*++
  309. Routine Description:
  310. Allocate a new unicode string buffer in the CanonicalName and cache the buffer
  311. in the rxcontext
  312. Arguments:
  313. RxContext - the current workitem
  314. CanonicalName - the canonicalized name
  315. BufferSizeRequired - Size of the canonical name buffer
  316. Return Value:
  317. NTSTATUS - The Fsd status for the Operation.
  318. SUCCESS means that everything worked and processing should continue
  319. otherwise....failcomplete the operation.
  320. --*/
  321. {
  322. PAGED_CODE();
  323. ASSERT (RxContext->Create.CanonicalNameBuffer == NULL);
  324. CanonicalName->Buffer = (PWCHAR)RxAllocatePoolWithTag(
  325. PagedPool | POOL_COLD_ALLOCATION,
  326. BufferSizeRequired,
  327. RX_MISC_POOLTAG);
  328. if (CanonicalName->Buffer == NULL) {
  329. return STATUS_INSUFFICIENT_RESOURCES;
  330. }
  331. RxDbgTrace(0, Dbg, ("RxAllocateCanonicalNameBuffer allocated %08lx length %08lx\n",
  332. CanonicalName->Buffer,BufferSizeRequired));
  333. RxContext->Create.CanonicalNameBuffer = CanonicalName->Buffer;
  334. RxContext->AlsoCanonicalNameBuffer = CanonicalName->Buffer;
  335. CanonicalName->MaximumLength = (USHORT)BufferSizeRequired;
  336. CanonicalName->Length = 0;
  337. return STATUS_SUCCESS;
  338. }
  339. NTSTATUS
  340. RxFirstCanonicalize (
  341. IN OUT PRX_CONTEXT RxContext,
  342. IN PIRP Irp,
  343. IN PUNICODE_STRING FileName,
  344. IN OUT PUNICODE_STRING CanonicalName,
  345. OUT PNET_ROOT_TYPE NetRootType
  346. )
  347. /*++
  348. Routine Description:
  349. This routine is called to perform the first level of canonicalization on the
  350. name. Essentially, this amounts to copying the name and then upcasing the
  351. first or the first/second components. In addition for pipe/mailslot UNC names
  352. the appropriate mapping from pipe,mailslot to IPC$ is done by this routine.
  353. This routine also adds the appropriate prefix to distinguish deviceless
  354. connects(UNC names ).
  355. In addition to canonicalization this routine also deduces the NET_ROOT_TYPE by
  356. the information provided in the UNC name.
  357. Last, as a side effect of this call, the UNC_NAME flag of the RX_CONTEXT is
  358. set to record that this name came in as a UNC_NAME. This is finally stored in
  359. the FOBX and used in conjuring the original filename for QueryInfoFile/NameInfo.
  360. Arguments:
  361. RxContext - the current workitem
  362. FileName - the initial filename
  363. CanonicalName - the canonicalized name
  364. NetRootType - placeholder for the deduced net root type
  365. Return Value:
  366. NTSTATUS - The Fsd status for the Operation.
  367. SUCCESS means that everything worked and processing should continue
  368. otherwise....failcomplete the operation.
  369. --*/
  370. {
  371. NTSTATUS Status = STATUS_SUCCESS;
  372. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  373. ULONG CanonicalNameLength;
  374. BOOLEAN SynthesizeCanonicalName = FALSE;
  375. BOOLEAN UNCName = FALSE;
  376. BOOLEAN MungeNameForDevicelessTreeConnect = FALSE;
  377. NET_ROOT_TYPE DeducedNetRootType = NET_ROOT_WILD;
  378. UNICODE_STRING ServerName;
  379. UNICODE_STRING ShareName;
  380. UNICODE_STRING RemainingName;
  381. ULONG SessionId;
  382. WCHAR IdBuffer[16]; // From RtlIntegerToUnicodeString()
  383. UNICODE_STRING IdString;
  384. PAGED_CODE();
  385. RxDbgTrace(+1, Dbg, ("RxFirstCanonicalize entry, filename=%wZ\n",FileName));
  386. //
  387. // The FileName->Length cannot be less than two WCHARs.
  388. //
  389. if ( FileName->Length < (2 * sizeof(WCHAR)) ) {
  390. return STATUS_OBJECT_NAME_INVALID;
  391. }
  392. //
  393. // for core servers in particular, it's important to get the service string correct.......
  394. // so, if this is a devicefull netuse the we will get the netroottype by looking at the string
  395. //
  396. if ((FileName->Length > sizeof( L"\\;m:") ) &&
  397. (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) &&
  398. (FileName->Buffer[1] == DRIVE_BASED_PATH_IDENTIFIER)) {
  399. //
  400. // it looks like a deviceful netuse.....look for the "early colon"
  401. // The following test for the classification of net root types is predicated
  402. // upon the use of single drive letters for Disk files and multiple letters
  403. // for print shares. This will have to be reworked when the support for
  404. // extended drive letters is provided.
  405. //
  406. if (FileName->Buffer[3] == L':') {
  407. DeducedNetRootType = NET_ROOT_DISK;
  408. } else {
  409. DeducedNetRootType = NET_ROOT_PRINT;
  410. }
  411. CanonicalNameLength = FileName->Length;
  412. SynthesizeCanonicalName = FALSE;
  413. //
  414. // Parse all names of the form "\name" where name does not begin with a semicolon
  415. //
  416. } else if ((FileName->Length >= sizeof( WCHAR ) * 2) &&
  417. (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) &&
  418. (FileName->Buffer[1] != DRIVE_BASED_PATH_IDENTIFIER)) {
  419. PWCHAR Buffer;
  420. PWCHAR EndOfName;
  421. //
  422. // This is a UNC path name presented by the user.
  423. //
  424. RemainingName.Length = RemainingName.MaximumLength = FileName->Length - sizeof( WCHAR );
  425. RemainingName.Buffer = &FileName->Buffer[1];
  426. UNCName = TRUE;
  427. SetFlag( RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME );
  428. //
  429. // UNC tree connect path names have the following format:
  430. // "\;:0\Server\Share where 0 represents the SessionId of the session.
  431. //
  432. SessionId = RxGetSessionId( IrpSp );
  433. IdString.Length = 0;
  434. IdString.MaximumLength = sizeof( IdBuffer );
  435. IdString.Buffer = IdBuffer;
  436. //
  437. // NOTE: SessionId is a ulong which will always fit in IdString buffer so
  438. // we can skip checking the return code
  439. //
  440. Status = RtlIntegerToUnicodeString( SessionId, 10, &IdString );
  441. ASSERT( STATUS_SUCCESS == Status );
  442. //
  443. // scan until the second separator. This will give us the server name.
  444. //
  445. ServerName.Buffer = RemainingName.Buffer;
  446. EndOfName = (PWCHAR) Add2Ptr( RemainingName.Buffer, RemainingName.Length );
  447. Buffer = RemainingName.Buffer;
  448. while ((Buffer != EndOfName) && (*Buffer != OBJ_NAME_PATH_SEPARATOR)) {
  449. Buffer += 1;
  450. }
  451. ServerName.Length = (USHORT)((PCHAR)Buffer - (PCHAR)ServerName.Buffer);
  452. RemainingName.Length = (USHORT)((PCHAR)EndOfName - (PCHAR)Buffer);
  453. RemainingName.Buffer = Buffer;
  454. RxDbgTrace(0, Dbg, ("RxFirstCanonicalize entry, remainingname=%wZ\n",&RemainingName));
  455. //
  456. // Apply the transformation for mapping PIPE shares to IPC$ shares.
  457. // Note that this needs to be done only if the share name is specified.
  458. // since the mup always passes in the trailing slash account for it
  459. //
  460. if ((ServerName.Length > 0) && RemainingName.Length > sizeof( WCHAR )) {
  461. //
  462. // The second separator has been located. Compare to see if the name
  463. // maps needs to be munged from PIPE or MAILSLOT to IPC$. Note that the
  464. // leading / is accounted for as part of the compare
  465. //
  466. ShareName = RemainingName;
  467. //
  468. // Check to see if it is a named pipe connection \PIPE
  469. //
  470. if ((ShareName.Length == s_PipeShareName.Length) ||
  471. ((ShareName.Length > s_PipeShareName.Length) &&
  472. (ShareName.Buffer[s_PipeShareName.Length / sizeof( WCHAR )] == OBJ_NAME_PATH_SEPARATOR))) {
  473. ShareName.Length = s_PipeShareName.Length;
  474. SynthesizeCanonicalName = RtlEqualUnicodeString(
  475. &ShareName,
  476. &s_PipeShareName,
  477. TRUE ); // case insensitive
  478. }
  479. if (SynthesizeCanonicalName) {
  480. ShareName = s_IpcShareName;
  481. DeducedNetRootType = NET_ROOT_PIPE;
  482. RemainingName.Length -= s_PipeShareName.Length;
  483. RemainingName.Buffer = (PWCHAR) Add2Ptr( RemainingName.Buffer, s_PipeShareName.Length );
  484. } else {
  485. BOOLEAN FoundIPCdollar = FALSE;
  486. ShareName = RemainingName;
  487. //
  488. // Check for \IPC$ connection
  489. //
  490. if (ShareName.Length == s_IpcShareName.Length ||
  491. ShareName.Length > s_IpcShareName.Length &&
  492. ShareName.Buffer[s_IpcShareName.Length/2] == OBJ_NAME_PATH_SEPARATOR) {
  493. ShareName.Length = s_IpcShareName.Length;
  494. FoundIPCdollar = RtlEqualUnicodeString(
  495. &ShareName,
  496. &s_IpcShareName,
  497. TRUE); // Case insensitive
  498. }
  499. if (FoundIPCdollar) {
  500. DeducedNetRootType = NET_ROOT_PIPE;
  501. ASSERT( SynthesizeCanonicalName == FALSE );
  502. } else {
  503. ShareName = RemainingName;
  504. //
  505. // Check for \MAILSLOT
  506. //
  507. if ((ShareName.Length == s_MailSlotShareName.Length) ||
  508. ((ShareName.Length > s_MailSlotShareName.Length) &&
  509. (ShareName.Buffer[s_MailSlotShareName.Length/sizeof( WCHAR )] == OBJ_NAME_PATH_SEPARATOR))) {
  510. ShareName.Length = s_MailSlotShareName.Length;
  511. SynthesizeCanonicalName = RtlEqualUnicodeString(
  512. &ShareName,
  513. &s_MailSlotShareName,
  514. TRUE ); // Case insensitive
  515. }
  516. if (SynthesizeCanonicalName) {
  517. WCHAR LastCharacterInServerName;
  518. DeducedNetRootType = NET_ROOT_MAILSLOT;
  519. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT );
  520. //
  521. // It is a mailslot share. Check to see if further reduction to canonical
  522. // form is required.
  523. //
  524. LastCharacterInServerName = ServerName.Buffer[(ServerName.Length/sizeof(WCHAR)) - 1];
  525. if ((LastCharacterInServerName == L'*') &&
  526. (ServerName.Length == sizeof( WCHAR ))) {
  527. ServerName = s_PrimaryDomainName;
  528. RemainingName.Length -= ShareName.Length;
  529. RemainingName.Buffer = (PWCHAR)Add2Ptr( RemainingName.Buffer, ShareName.Length );
  530. } else {
  531. SynthesizeCanonicalName = FALSE;
  532. }
  533. }
  534. }
  535. }
  536. if (SynthesizeCanonicalName) {
  537. CanonicalNameLength = sizeof(WCHAR) + // obj name separator
  538. ServerName.Length +
  539. ShareName.Length +
  540. RemainingName.Length;
  541. if (FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT )) {
  542. CanonicalNameLength += s_MailSlotServerPrefix.Length;
  543. }
  544. } else {
  545. CanonicalNameLength = FileName->Length;
  546. }
  547. } else {
  548. Status = STATUS_OBJECT_NAME_INVALID;
  549. CanonicalNameLength = FileName->Length;
  550. SynthesizeCanonicalName = FALSE;
  551. }
  552. } else {
  553. CanonicalNameLength = FileName->Length;
  554. SynthesizeCanonicalName = FALSE;
  555. }
  556. *NetRootType = DeducedNetRootType;
  557. if (Status == STATUS_SUCCESS) {
  558. //
  559. // if this is a UNC name AND this is a tree connect then we have to munge
  560. // the name so as to avoid a conflict by adding '\;:'
  561. //
  562. if (UNCName && !SynthesizeCanonicalName) {
  563. MungeNameForDevicelessTreeConnect = TRUE;
  564. CanonicalNameLength += (3 * sizeof(WCHAR));
  565. // Hydra adds '\;:0' where 0 represents a SessionId
  566. CanonicalNameLength += IdString.Length;
  567. }
  568. if (!SynthesizeCanonicalName && !MungeNameForDevicelessTreeConnect) {
  569. if (FileName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR) {
  570. Status = STATUS_OBJECT_PATH_INVALID;
  571. }
  572. }
  573. //
  574. // Check for a maxed out name - strings only hold 64k due to Length being a ushort
  575. //
  576. if (CanonicalNameLength > MAXUSHORT) {
  577. Status = STATUS_OBJECT_NAME_INVALID;
  578. }
  579. if (Status == STATUS_SUCCESS) {
  580. Status = RxAllocateCanonicalNameBuffer(
  581. RxContext,
  582. CanonicalName,
  583. CanonicalNameLength );
  584. }
  585. if (Status == STATUS_SUCCESS) {
  586. if (!SynthesizeCanonicalName) {
  587. if (!MungeNameForDevicelessTreeConnect) {
  588. RtlCopyUnicodeString( CanonicalName, FileName );
  589. } else {
  590. CanonicalName->Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
  591. CanonicalName->Buffer[1] = DRIVE_BASED_PATH_IDENTIFIER;
  592. CanonicalName->Buffer[2] = L':';
  593. CanonicalName->Length = 3*sizeof(WCHAR);
  594. RtlAppendUnicodeStringToString( CanonicalName, &IdString );
  595. RtlAppendUnicodeStringToString( CanonicalName, FileName );
  596. }
  597. } else {
  598. PCHAR CanonicalNameBuffer = (PCHAR)CanonicalName->Buffer;
  599. //
  600. // The name has to be synthesized from the appropriate components.
  601. // Copy the initial prefix
  602. //
  603. ASSERT( CanonicalName->MaximumLength == CanonicalNameLength );
  604. CanonicalName->Length = (USHORT)CanonicalNameLength;
  605. CanonicalName->Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
  606. CanonicalNameBuffer += sizeof(WCHAR);
  607. if (MungeNameForDevicelessTreeConnect) {
  608. CanonicalName->Buffer[1] = DRIVE_BASED_PATH_IDENTIFIER;
  609. CanonicalName->Buffer[2] = L':';
  610. CanonicalName->Buffer[3] = OBJ_NAME_PATH_SEPARATOR;
  611. CanonicalNameBuffer += 3*sizeof(WCHAR);
  612. }
  613. if (RxContext->Flags & RX_CONTEXT_FLAG_CREATE_MAILSLOT) {
  614. RtlCopyMemory( CanonicalNameBuffer, s_MailSlotServerPrefix.Buffer, s_MailSlotServerPrefix.Length );
  615. CanonicalNameBuffer += s_MailSlotServerPrefix.Length;
  616. }
  617. //
  618. // Copy the server name
  619. //
  620. RtlCopyMemory( CanonicalNameBuffer, ServerName.Buffer, ServerName.Length );
  621. CanonicalNameBuffer += ServerName.Length;
  622. //
  623. // Copy the share name. Ensure that the share name includes the leading
  624. // OBJ_NAME_PATH_SEPARATOR - the share is one of \IPC$ \Mailslot etc.
  625. //
  626. ASSERT( ShareName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR );
  627. RtlCopyMemory( CanonicalNameBuffer, ShareName.Buffer, ShareName.Length );
  628. CanonicalNameBuffer += ShareName.Length;
  629. //
  630. // Copy the remaining name
  631. //
  632. RtlCopyMemory( CanonicalNameBuffer, RemainingName.Buffer, RemainingName.Length );
  633. #ifdef _WIN64
  634. //
  635. // (fcf) This should be addressed. I was finding that
  636. // CanonicalName->Length was ending up too large by 32 bytes
  637. // (16 chars).
  638. //
  639. // In the code above, CanonicalNameLength (and therefore
  640. // CanonicalName->Length) is padded with (16 * sizeof(WCHAR))
  641. // to accomodate a 16-character session ID... yet that
  642. // ID is not copied in some circumstances, such as this
  643. // code path where SynthesizeCanonicalName == TRUE.
  644. //
  645. // Someone more familiar with the code should figure out why
  646. // this isn't causing a problem on 32-bit builds and what
  647. // the correct fix is.
  648. //
  649. CanonicalName->Length =
  650. (USHORT)((CanonicalNameBuffer + RemainingName.Length) -
  651. (PCHAR)CanonicalName->Buffer);
  652. #endif
  653. RxDbgTrace(0,Dbg,("Final Munged Name .....%wZ\n", CanonicalName));
  654. }
  655. }
  656. }
  657. RxDbgTrace(-1, Dbg, ("RxFirstCanonicalize exit, status=%08lx\n",Status));
  658. return Status;
  659. }
  660. //#define RX2C_USE_ALTERNATES_FOR_DEBUG 1
  661. #ifndef RX2C_USE_ALTERNATES_FOR_DEBUG
  662. #define RX2C_IS_SEPARATOR(__c) ((__c==OBJ_NAME_PATH_SEPARATOR)||(__c==L':'))
  663. #define RX2C_IS_DOT(__c) ((__c==L'.'))
  664. #define RX2C_IS_COLON(__c) ((__c==L':'))
  665. #else
  666. #define RX2C_IS_SEPARATOR(__c) ((__c==OBJ_NAME_PATH_SEPARATOR)||(__c==L':')||(__c==L'!'))
  667. #define RX2C_IS_DOT(__c) ((__c==L'.')||(__c==L'q'))
  668. #define RX2C_IS_COLON(__c) ((__c==L':'))
  669. #endif
  670. NTSTATUS
  671. RxCanonicalizeFileNameByServerSpecs(
  672. IN OUT PRX_CONTEXT RxContext,
  673. IN OUT PUNICODE_STRING RemainingName
  674. )
  675. /*++
  676. Routine Description:
  677. This routine is called to canonicalize a filename according to the way that
  678. the server wants it.
  679. Arguments:
  680. RxContext - the current workitem
  681. RemainingName - the filename
  682. Return Value:
  683. NTSTATUS - The Fsd status for the Operation.
  684. MORE_PROCESSING_REQUIRED means that everything worked and processing
  685. should continue otherwise....failcomplete the operation.
  686. --*/
  687. {
  688. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  689. PWCHAR Buffer = RemainingName->Buffer;
  690. ULONG Length = RemainingName->Length / sizeof(WCHAR);
  691. ULONG i,o; // input and output pointers
  692. PAGED_CODE();
  693. if (Length==0) {
  694. return Status;
  695. }
  696. RxDbgTrace(+1, Dbg, ("RxCanonicalizeFileNameByServerSpecs Rname=%wZ\n", RemainingName));
  697. for (i=o=0;i<Length;) {
  698. ULONG firstchar,lastchar; // first and last char of the component
  699. //
  700. // find a component starting at i: [\][^\]* is the format
  701. //
  702. firstchar = i;
  703. for (lastchar=i+1;;lastchar++) {
  704. if ((lastchar>=Length) || RX2C_IS_SEPARATOR(Buffer[lastchar])) {
  705. lastchar--;
  706. break;
  707. }
  708. }
  709. IF_DEBUG {
  710. UNICODE_STRING Component;
  711. Component.Buffer = &Buffer[firstchar];
  712. Component.Length = (USHORT)(sizeof(WCHAR)*(lastchar-firstchar+1));
  713. RxDbgTraceLV(0, Dbg, 1001, ("RxCanonicalizeFileNameByServerSpecs component=%wZ\n", &Component));
  714. }
  715. //
  716. // firstchar..lastchar describe the component
  717. // according to darrylh, . and .. are illegal now
  718. // I believe that consecutive slashes are also illegal
  719. //
  720. switch (lastchar-firstchar) {
  721. case 0: // length 1
  722. //
  723. // the two bad cases are a backslash or a dot. if the backslash is at the end then that's okay
  724. //
  725. if ((RX2C_IS_SEPARATOR(Buffer[firstchar]) && (firstchar != Length-1)) ||
  726. RX2C_IS_DOT(Buffer[firstchar])) {
  727. if (lastchar != 0) {
  728. //
  729. // it is ok if two colons stick together, i.e. \\server\share\foo::stream
  730. //
  731. if ((lastchar < (Length - 1)) && !RX2C_IS_COLON( Buffer[lastchar + 1] )) {
  732. goto BADRETURN;
  733. }
  734. } else {
  735. //
  736. // it is fine if the colon follows the share, i.e. \\server\share\:stream
  737. //
  738. if (!RX2C_IS_COLON( Buffer[1] )) {
  739. goto BADRETURN;
  740. }
  741. }
  742. }
  743. break;
  744. case 1: // length 2
  745. //
  746. // bad cases: \. and ..
  747. //
  748. if (RX2C_IS_DOT(Buffer[firstchar+1]) &&
  749. (RX2C_IS_SEPARATOR(Buffer[firstchar]) || RX2C_IS_DOT(Buffer[firstchar]))) {
  750. goto BADRETURN;
  751. }
  752. break;
  753. case 2: //length 3
  754. if ( (RX2C_IS_SEPARATOR(Buffer[firstchar]) &&
  755. RX2C_IS_DOT(Buffer[firstchar+1]) &&
  756. RX2C_IS_DOT(Buffer[firstchar+2]))) {
  757. goto BADRETURN;
  758. }
  759. break;
  760. }
  761. //
  762. // DOWNLEVEL this is where you limit by component length. o will be the back ptr
  763. // but for no downlevel....do nothing.
  764. //
  765. i = lastchar + 1;
  766. }
  767. RxDbgTraceUnIndent(-1,Dbg);
  768. return Status;
  769. BADRETURN:
  770. RxDbgTrace(-1, Dbg, ("RxCanonicalizeFileNameByServerSpecs BADRETURN \n"));
  771. return STATUS_OBJECT_PATH_SYNTAX_BAD;
  772. }
  773. NTSTATUS
  774. RxCanonicalizeNameAndObtainNetRoot (
  775. IN OUT PRX_CONTEXT RxContext,
  776. IN PIRP Irp,
  777. IN PUNICODE_STRING FileName,
  778. OUT PUNICODE_STRING RemainingName
  779. )
  780. /*++
  781. Routine Description:
  782. This routine is called to find out the server or netroot associated with a
  783. name. In addition, the name is canonicalized according to what flags are set
  784. in the srvcall.
  785. Arguments:
  786. RxContext - the current workitem
  787. FileName - the initial filename
  788. CanonicalName - the canonicalized name. an initial string is passed in; if it
  789. is not big enough then a bigger one is allocated and freed
  790. when the rxcontx is freed.
  791. RemainingName - the name of the file after the netroot prefix is removed; it
  792. has been canonicalized. This points into the same buffer as
  793. canonical name.
  794. Return Value:
  795. NTSTATUS - The Fsd status for the Operation.
  796. SUCCESS means that everything worked and processing should continue
  797. otherwise....failcomplete the operation.
  798. --*/
  799. {
  800. NTSTATUS Status;
  801. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  802. PFILE_OBJECT FileObject = IrpSp->FileObject;
  803. UNICODE_STRING CanonicalName;
  804. PFILE_OBJECT RelatedFileObject = FileObject->RelatedFileObject;
  805. LOCK_HOLDING_STATE LockHoldingState = LHS_LockNotHeld;
  806. NET_ROOT_TYPE NetRootType = NET_ROOT_WILD;
  807. PAGED_CODE();
  808. RxDbgTrace(+1, Dbg, ("RxCanonicalizeName -> %08lx\n", 0));
  809. RemainingName->Buffer = NULL;
  810. RemainingName->Length = RemainingName->MaximumLength = 0;
  811. CanonicalName.Buffer = NULL;
  812. CanonicalName.Length = CanonicalName.MaximumLength = 0;
  813. if (!RelatedFileObject) {
  814. Status = RxFirstCanonicalize( RxContext,
  815. Irp,
  816. FileName,
  817. &CanonicalName,
  818. &NetRootType );
  819. if (Status != STATUS_SUCCESS) {
  820. RxDbgTraceUnIndent(-1,Dbg);
  821. return Status;
  822. }
  823. } else {
  824. PFCB RelatedFcb = (PFCB)(RelatedFileObject->FsContext);
  825. PFOBX RelatedFobx = (PFOBX)(RelatedFileObject->FsContext2);
  826. ULONG AllocationNeeded;
  827. PV_NET_ROOT RelatedVNetRoot;
  828. PUNICODE_STRING RelatedVNetRootName,RelatedFcbName;
  829. if ((RelatedFcb == NULL) || (RelatedFobx == NULL)) {
  830. RxDbgTraceUnIndent(-1,Dbg);
  831. return STATUS_INVALID_PARAMETER;
  832. }
  833. RelatedVNetRoot = RelatedFobx->SrvOpen->VNetRoot;
  834. if (!NodeTypeIsFcb( RelatedFcb ) ||
  835. (RelatedVNetRoot == NULL) ||
  836. (NodeType( RelatedVNetRoot ) != RDBSS_NTC_V_NETROOT)) {
  837. RxDbgTraceUnIndent(-1,Dbg);
  838. return STATUS_INVALID_PARAMETER;
  839. }
  840. RelatedVNetRootName = &RelatedVNetRoot->PrefixEntry.Prefix;
  841. RelatedFcbName = &RelatedFcb->FcbTableEntry.Path;
  842. //
  843. // relative open......
  844. // we have to ensure that we have a canonical name buffer that is
  845. // long enough so we add the name of the current file to the sum of
  846. // the vnetroot length of the relative file and the prefixname (not
  847. // the alreadyprefixedname) of the relative file. plus some slop for
  848. // chars. If this is greater than the maximum value for a USHORT we
  849. // reject the name as being invalid since we cannot represent it in
  850. // a UNICODE_STRING
  851. //
  852. AllocationNeeded = RelatedVNetRootName->Length + RelatedFcbName->Length + FileName->Length + 3 * sizeof(WCHAR);
  853. if (AllocationNeeded <= MAXUSHORT) {
  854. //
  855. // you may need some backslashs/colons in the middle
  856. //
  857. Status = RxAllocateCanonicalNameBuffer( RxContext,
  858. &CanonicalName,
  859. AllocationNeeded );
  860. } else {
  861. Status = STATUS_OBJECT_PATH_INVALID;
  862. }
  863. if (Status != STATUS_SUCCESS) {
  864. RxDbgTraceUnIndent(-1,Dbg);
  865. return Status;
  866. }
  867. RtlMoveMemory( CanonicalName.Buffer,
  868. RelatedVNetRootName->Buffer,
  869. RelatedVNetRootName->Length );
  870. RtlMoveMemory( Add2Ptr( CanonicalName.Buffer, RelatedVNetRootName->Length ),
  871. RelatedFcbName->Buffer,
  872. RelatedFcbName->Length );
  873. CanonicalName.Length = (USHORT)(RelatedVNetRootName->Length + RelatedFcbName->Length);
  874. RxDbgTrace(0,Dbg,("Name From Related Fileobj.....%wZ\n", &CanonicalName));
  875. if (FileName->Length != 0) {
  876. ULONG LastWCharIndex = (CanonicalName.Length / sizeof( WCHAR )) - 1;
  877. //
  878. // add on the rest...there are special cases here! with ':' for streams.........
  879. //
  880. if ((CanonicalName.Buffer[LastWCharIndex] != OBJ_NAME_PATH_SEPARATOR) &&
  881. (FileName->Buffer[0] != L':' ) ) {
  882. ASSERT(CanonicalName.Length < CanonicalName.MaximumLength);
  883. CanonicalName.Length += sizeof( WCHAR );
  884. CanonicalName.Buffer[LastWCharIndex+1] = OBJ_NAME_PATH_SEPARATOR;
  885. }
  886. ASSERT (CanonicalName.MaximumLength >= CanonicalName.Length + FileName->Length);
  887. RxDbgTrace(0,Dbg,("Name From Related Fileobj w/ trailer.....%wZ\n", &CanonicalName));
  888. RtlMoveMemory( Add2Ptr( CanonicalName.Buffer, CanonicalName.Length ), FileName->Buffer, FileName->Length);
  889. CanonicalName.Length += FileName->Length;
  890. }
  891. if (FlagOn( RelatedFobx->Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME )) {
  892. //
  893. // if the related guy was a UNC, we're a UNC
  894. //
  895. SetFlag( RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME );
  896. }
  897. RxDbgTrace(0,Dbg,("Final Name From Related Fileobj.....%wZ\n", &CanonicalName));
  898. }
  899. Status = RxFindOrConstructVirtualNetRoot( RxContext,
  900. Irp,
  901. &CanonicalName,
  902. NetRootType,
  903. RemainingName );
  904. if ((Status != STATUS_SUCCESS) &&
  905. (Status != STATUS_PENDING) &&
  906. (RxContext->Flags & RX_CONTEXT_FLAG_MAILSLOT_REPARSE)) {
  907. ASSERT(CanonicalName.Buffer == RxContext->Create.CanonicalNameBuffer);
  908. RxFreeCanonicalNameBuffer( RxContext );
  909. Status = RxFirstCanonicalize( RxContext,
  910. Irp,
  911. FileName,
  912. &CanonicalName,
  913. &NetRootType);
  914. if (Status == STATUS_SUCCESS) {
  915. Status = RxFindOrConstructVirtualNetRoot( RxContext,
  916. Irp,
  917. &CanonicalName,
  918. NetRootType,
  919. RemainingName );
  920. }
  921. }
  922. if (FsRtlDoesNameContainWildCards( RemainingName )) {
  923. Status = STATUS_OBJECT_NAME_INVALID;
  924. }
  925. if (Status == STATUS_SUCCESS) {
  926. RxDbgTrace( 0, Dbg, ("RxCanonicalizeName SrvCall-> %08lx\n", RxContext->Create.pSrvCall));
  927. RxDbgTrace( 0, Dbg, ("RxCanonicalizeName Root-> %08lx\n", RxContext->Create.pNetRoot));
  928. Status = RxCanonicalizeFileNameByServerSpecs(RxContext,RemainingName);
  929. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  930. RxDbgTrace(0, Dbg, ("RxCanonicalizeName Remaining -> %wZ\n", RemainingName));
  931. }
  932. }
  933. if((NT_SUCCESS( Status ) || (Status == STATUS_MORE_PROCESSING_REQUIRED)) &&
  934. (RxContext->Create.pNetRoot != NULL))
  935. {
  936. NTSTATUS PreparseStatus;
  937. //
  938. // Allow the Mini-RDR to do any extra "scanning" of the name
  939. //
  940. MINIRDR_CALL( PreparseStatus,
  941. RxContext,
  942. RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
  943. MRxPreparseName,
  944. (RxContext, &CanonicalName));
  945. }
  946. RxDbgTrace(-1, Dbg, ("RxCanonicalizeName Status -> %08lx\n", Status));
  947. return Status;
  948. }
  949. NTSTATUS
  950. RxFindOrCreateFcb (
  951. IN OUT PRX_CONTEXT RxContext,
  952. IN PIRP Irp,
  953. IN PUNICODE_STRING RemainingName,
  954. OUT PFCB *Fcb
  955. )
  956. /*++
  957. Routine Description:
  958. This routine is called to either find the Fcb associated with the
  959. name or to create it. If everything succeeds, it returns with a
  960. reference on the name and with the fcblock held exclusive.
  961. so, that's a total of two things for success:
  962. 1) fcb lock held exclusive
  963. 2) reference on the fcb ( be it through lookup or taking an additional
  964. reference on create)
  965. The current strategy is to not delete the Fcb if things don't work out and
  966. to let it be scavenged. this is a good strategy unless we are being bombarded
  967. with open requests that fail in which case we should change over to something
  968. different. for this reason, i record in the irp context if the fcb is built here.
  969. Arguments:
  970. RxContext - the current workitem
  971. RemainingName - the name of the file after the netroot prefix is removed; it has been
  972. canonicalized.
  973. Return Value:
  974. RXSTATUS - The Fsd status for the Irp
  975. Notes:
  976. On Exit -- the FCB resource would have been accquired exclusive if successful
  977. --*/
  978. {
  979. NTSTATUS Status = STATUS_SUCCESS;
  980. PV_NET_ROOT VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
  981. PNET_ROOT NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
  982. ULONG TableVersion;
  983. CLONG RemainingNameLength;
  984. BOOLEAN FcbTableLockAcquired;
  985. BOOLEAN FcbTableLockAcquiredExclusive = FALSE;
  986. PAGED_CODE();
  987. RxDbgTrace(+1, Dbg, ("RxFindOrCreateFcb -> %08lx\n", 0));
  988. ASSERT( NetRoot == (PNET_ROOT)VNetRoot->NetRoot );
  989. //
  990. // Acquire the NET_ROOT's FcbTable lock shared to beginwith. This will
  991. // ensure maximal concurrency and in those cases when the lookup fails
  992. // this will be converted to an exclusive lock before proceeding further.
  993. //
  994. RxAcquireFcbTableLockShared( &NetRoot->FcbTable, TRUE );
  995. FcbTableLockAcquired = TRUE;
  996. TableVersion = NetRoot->FcbTable.Version;
  997. RemainingNameLength = RemainingName->Length;
  998. *Fcb = RxFcbTableLookupFcb( &NetRoot->FcbTable, RemainingName );
  999. #if DBG
  1000. if (*Fcb) {
  1001. RxLoudFcbMsg("RxFindOrCreateFcb found: ",&((*Fcb)->FcbTableEntry.Path));
  1002. RxDbgTrace(0, Dbg, (" ----->Found Prefix Name=%wZ\n",
  1003. &(*Fcb)->FcbTableEntry.Path ));
  1004. } else {
  1005. RxDbgTrace(0, Dbg, ("Name not found - %wZ\n", RemainingName));
  1006. RxDbgTrace(0, Dbg, ("Fcb is NULL!!\n"));
  1007. RxLoudFcbMsg("RxFindOrCreateFcb fcbisnull found: ",RemainingName);
  1008. }
  1009. #endif
  1010. //
  1011. // If it has been marked for orphaning, lets do it!
  1012. //
  1013. if (*Fcb && (*Fcb)->fShouldBeOrphaned) {
  1014. //
  1015. // Release our reference from the first lookup
  1016. //
  1017. RxDereferenceNetFcb( *Fcb );
  1018. //
  1019. // Switch to an exclusive table lock so we know we're the only one referencing this FCB
  1020. //
  1021. RxReleaseFcbTableLock( &NetRoot->FcbTable );
  1022. FcbTableLockAcquired = FALSE;
  1023. RxAcquireFcbTableLockExclusive( &NetRoot->FcbTable, TRUE );
  1024. FcbTableLockAcquired = TRUE;
  1025. FcbTableLockAcquiredExclusive = TRUE;
  1026. //
  1027. // Make sure it is still in the table
  1028. //
  1029. *Fcb = RxFcbTableLookupFcb( &NetRoot->FcbTable, RemainingName );
  1030. if (*Fcb && (*Fcb)->fShouldBeOrphaned) {
  1031. RxOrphanThisFcb( *Fcb );
  1032. RxDereferenceNetFcb( *Fcb );
  1033. *Fcb = NULL;
  1034. }
  1035. }
  1036. if ((*Fcb == NULL) ||
  1037. ((*Fcb)->FcbTableEntry.Path.Length != RemainingNameLength)) {
  1038. //
  1039. // Convert the shared lock that is currently held to an exclusive lock.
  1040. // This will necessiate another lookup if the FCB table was updated during
  1041. // this interval
  1042. //
  1043. if (!FcbTableLockAcquiredExclusive) {
  1044. RxReleaseFcbTableLock( &NetRoot->FcbTable );
  1045. FcbTableLockAcquired = FALSE;
  1046. RxAcquireFcbTableLockExclusive( &NetRoot->FcbTable, TRUE );
  1047. FcbTableLockAcquired = TRUE;
  1048. }
  1049. if (TableVersion != NetRoot->FcbTable.Version) {
  1050. *Fcb = RxFcbTableLookupFcb( &NetRoot->FcbTable, RemainingName );
  1051. }
  1052. if ((*Fcb == NULL) ||
  1053. ((*Fcb)->FcbTableEntry.Path.Length != RemainingNameLength)) {
  1054. //
  1055. // we have to build it
  1056. //
  1057. try {
  1058. *Fcb = RxCreateNetFcb( RxContext, Irp, VNetRoot, RemainingName );
  1059. if (*Fcb == NULL) {
  1060. Status = STATUS_INSUFFICIENT_RESOURCES;
  1061. } else {
  1062. Status = RxAcquireExclusiveFcb( RxContext, *Fcb );
  1063. if (Status == STATUS_SUCCESS) {
  1064. RxContext->Create.FcbAcquired = TRUE;
  1065. } else {
  1066. RxContext->Create.FcbAcquired = FALSE;
  1067. }
  1068. }
  1069. } finally {
  1070. if (AbnormalTermination()) {
  1071. RxReleaseFcbTableLock( &NetRoot->FcbTable );
  1072. FcbTableLockAcquired = FALSE;
  1073. if (*Fcb) {
  1074. RxTransitionNetFcb( *Fcb, Condition_Bad );
  1075. ExAcquireResourceExclusiveLite( (*Fcb)->Header.Resource, TRUE );
  1076. if (!RxDereferenceAndFinalizeNetFcb( *Fcb, NULL, FALSE, FALSE )) {
  1077. ExReleaseResourceLite( (*Fcb)->Header.Resource );
  1078. }
  1079. }
  1080. }
  1081. }
  1082. }
  1083. }
  1084. if (FcbTableLockAcquired) {
  1085. RxReleaseFcbTableLock( &NetRoot->FcbTable );
  1086. }
  1087. if (Status == STATUS_SUCCESS) {
  1088. RxContext->pFcb = (PMRX_FCB)*Fcb;
  1089. RxLog(( "Found or created FCB %lx Condition %lx\n", *Fcb, (*Fcb)->Condition ));
  1090. RxWmiLog( LOG,
  1091. RxFindOrCreateFcb,
  1092. LOGPTR( *Fcb )
  1093. LOGULONG( (*Fcb)->Condition ) );
  1094. if (!RxContext->Create.FcbAcquired) {
  1095. //
  1096. // if the FCB was not newly built then ensure that it is in a stable
  1097. // condition before proceeding further. Note that since a reference
  1098. // to this FCB is held by this routine it cannot be finalized
  1099. // before the control can return to this routine.
  1100. //
  1101. RxWaitForStableNetFcb( *Fcb, RxContext );
  1102. Status = RxAcquireExclusiveFcb( RxContext, *Fcb );
  1103. if (Status == STATUS_SUCCESS) {
  1104. RxContext->Create.FcbAcquired = TRUE;
  1105. }
  1106. }
  1107. }
  1108. RxDbgTrace( -1, Dbg, ("RxFindOrCreateFcb Fcb=%08lx\n", *Fcb ));
  1109. if (*Fcb) {
  1110. RxDbgTrace( -1, Dbg, ("RxFindOrCreateFcb name=%wZ\n", &(*Fcb)->FcbTableEntry.Path) );
  1111. }
  1112. return Status;
  1113. }
  1114. NTSTATUS
  1115. RxSearchForCollapsibleOpen (
  1116. IN OUT PRX_CONTEXT RxContext,
  1117. IN PFCB Fcb,
  1118. IN ACCESS_MASK DesiredAccess,
  1119. IN ULONG ShareAccess
  1120. )
  1121. /*++
  1122. Routine Description:
  1123. This routine is called to seach the list of available srvopens on
  1124. the fcb to see if we can collapse onto an existing open.
  1125. If we search the whole list w/o finding a collapse, then we return
  1126. STATUS_NOT_FOUND.
  1127. Arguments:
  1128. RxContext - the current workitem
  1129. Return Value:
  1130. STATUS_SUCCESS -- a SRV_OPEN instance was found.
  1131. STATUS_MORE_PROCESSING_REQUIRED -- no SRV_OPEN instance was found.
  1132. STATUS_NOT_FOUND - collapsing is not allowed
  1133. --*/
  1134. {
  1135. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  1136. ULONG Disposition;
  1137. ULONG CurrentCreateOptions;
  1138. BOOLEAN AllowCollapse;
  1139. PNET_ROOT NetRoot = (PNET_ROOT)(RxContext->Create.pNetRoot);
  1140. PSRV_OPEN SrvOpen = NULL;
  1141. PAGED_CODE();
  1142. //
  1143. // Disallow collapsing for backup and delete on close opens.
  1144. //
  1145. if (FlagOn( RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT ) ||
  1146. FlagOn( RxContext->Create.NtCreateParameters.CreateOptions, FILE_DELETE_ON_CLOSE )) {
  1147. ClearFlag( Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED );
  1148. RxScavengeRelatedFobxs( Fcb );
  1149. RxPurgeFcbInSystemCache( Fcb,
  1150. NULL,
  1151. 0,
  1152. FALSE,
  1153. TRUE );
  1154. return STATUS_NOT_FOUND;
  1155. }
  1156. //
  1157. // if the create specifies a special create disposition then we don't
  1158. // collapse; as well, we give the minirdr the opportunity to defeat
  1159. // collapsing by a calldown
  1160. //
  1161. CurrentCreateOptions = RxContext->Create.NtCreateParameters.CreateOptions;
  1162. Disposition = RxContext->Create.NtCreateParameters.Disposition;
  1163. AllowCollapse = (Disposition == FILE_OPEN) || (Disposition == FILE_OPEN_IF);
  1164. if (AllowCollapse && (Fcb->MRxDispatch != NULL)) { // should be an ASSERT??
  1165. NTSTATUS CollapseStatus;
  1166. ASSERT( RxContext->pRelevantSrvOpen == NULL );
  1167. ASSERT( Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL );
  1168. CollapseStatus = Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen( RxContext );
  1169. AllowCollapse = (CollapseStatus == STATUS_SUCCESS);
  1170. }
  1171. if (!AllowCollapse) {
  1172. //
  1173. // it may be that there is an existing open that keeps this open from working....
  1174. // if so, prepurge
  1175. //
  1176. NTSTATUS SharingStatus;
  1177. SharingStatus = RxCheckShareAccessPerSrvOpens( Fcb,
  1178. DesiredAccess,
  1179. ShareAccess );
  1180. if (SharingStatus != STATUS_SUCCESS) {
  1181. ClearFlag( Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED );
  1182. RxScavengeRelatedFobxs( Fcb );
  1183. RxPurgeFcbInSystemCache( Fcb,
  1184. NULL,
  1185. 0,
  1186. FALSE,
  1187. TRUE );
  1188. }
  1189. return STATUS_NOT_FOUND;
  1190. }
  1191. if ((Fcb->NetRoot == (PNET_ROOT)RxContext->Create.pNetRoot) &&
  1192. (Fcb->NetRoot->Type == NET_ROOT_DISK)) {
  1193. BOOLEAN FobxsScavengingAttempted = FALSE;
  1194. BOOLEAN FcbPurgingAttempted = FALSE;
  1195. //
  1196. // Search the list of SRV_OPEN's to determine if this open request can be
  1197. // collapsed with an existing SRV_OPEN.
  1198. //
  1199. for (;;) {
  1200. PLIST_ENTRY SrvOpenListEntry;
  1201. SrvOpenListEntry = Fcb->SrvOpenList.Flink;
  1202. for (;;) {
  1203. if (SrvOpenListEntry == &Fcb->SrvOpenList) {
  1204. //
  1205. // If the end of the list of SRV_OPEN's has been reached then it
  1206. // is time to go to the server, i.e., create a new SRV_OPEN.
  1207. //
  1208. Status = STATUS_NOT_FOUND;
  1209. break;
  1210. }
  1211. SrvOpen = (PSRV_OPEN)CONTAINING_RECORD( SrvOpenListEntry, SRV_OPEN, SrvOpenQLinks );
  1212. if ((SrvOpen->VNetRoot == (PV_NET_ROOT)RxContext->Create.pVNetRoot) &&
  1213. (SrvOpen->DesiredAccess == DesiredAccess) &&
  1214. (SrvOpen->ShareAccess == ShareAccess) &&
  1215. !FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED ) &&
  1216. !FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_CLOSED ) &&
  1217. !FlagOn( SrvOpen->Flags,SRVOPEN_FLAG_FILE_RENAMED ) &&
  1218. !FlagOn( SrvOpen->Flags,SRVOPEN_FLAG_FILE_DELETED )) {
  1219. if ((FlagOn( SrvOpen->CreateOptions, FILE_OPEN_REPARSE_POINT )) !=
  1220. FlagOn( CurrentCreateOptions, FILE_OPEN_REPARSE_POINT )) {
  1221. FobxsScavengingAttempted = TRUE;
  1222. FcbPurgingAttempted = TRUE;
  1223. Status = STATUS_NOT_FOUND;
  1224. break;
  1225. }
  1226. //
  1227. // If a SRV_OPEN with identical DesiredAccess and ShareAccess
  1228. // has been found which has not been renamed/deleted then the
  1229. // new open request can be collapsed onto the existing open.
  1230. //
  1231. if (DisableByteRangeLockingOnReadOnlyFiles ||
  1232. !FlagOn( SrvOpen->Fcb->Attributes, FILE_ATTRIBUTE_READONLY )) {
  1233. Status = STATUS_SUCCESS;
  1234. break;
  1235. }
  1236. } else {
  1237. if (SrvOpen->VNetRoot != (PV_NET_ROOT)RxContext->Create.pVNetRoot) {
  1238. //
  1239. // the file is accessed by another user. It needs to be purged out
  1240. // if the current user is going to use it.
  1241. //
  1242. RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
  1243. //
  1244. // Don't collapse srvopens belonging to different vnetroots
  1245. //
  1246. SrvOpenListEntry = SrvOpenListEntry->Flink;
  1247. continue;
  1248. }
  1249. //
  1250. // If the existing SRV_OPEN does not match the access required by the
  1251. // new open request ensure that the new open request does not conflict
  1252. // with the existing SRV_OPEN's. If it does scavenging/purging needs
  1253. // to be attempted before forwarding the request to the server.
  1254. //
  1255. Status = RxCheckShareAccessPerSrvOpens( Fcb,
  1256. DesiredAccess,
  1257. ShareAccess );
  1258. if (Status != STATUS_SUCCESS) {
  1259. break;
  1260. }
  1261. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1262. }
  1263. SrvOpenListEntry = SrvOpenListEntry->Flink;
  1264. }
  1265. if (Status == STATUS_SUCCESS) {
  1266. //
  1267. // a collapsible open was found. return it.
  1268. //
  1269. RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
  1270. ASSERT( Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen != NULL );
  1271. if(Fcb->MRxDispatch->MRxShouldTryToCollapseThisOpen( RxContext ) == STATUS_SUCCESS) {
  1272. if (FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED )) {
  1273. RxLog(("****** Delayed Close worked reusing SrvOpen(%lx)\n", SrvOpen));
  1274. RxWmiLog(LOG,
  1275. RxSearchForCollapsibleOpen,
  1276. LOGPTR( SrvOpen ));
  1277. InterlockedDecrement( &NetRoot->SrvCall->NumberOfCloseDelayedFiles );
  1278. ClearFlag( SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED );
  1279. }
  1280. break;
  1281. } else {
  1282. Status = STATUS_NOT_FOUND;
  1283. }
  1284. }
  1285. if (!FobxsScavengingAttempted) {
  1286. //
  1287. // No SRV_OPEN instance onto which the new request can be collapsed was
  1288. // found. Attempt to scavenge any FOBX's, i.e., ensure that all the
  1289. // delayed close operations on the FOBX are done before checking again.
  1290. //
  1291. FobxsScavengingAttempted = TRUE;
  1292. ClearFlag( Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED );
  1293. RxScavengeRelatedFobxs( Fcb );
  1294. continue;
  1295. }
  1296. if (!FcbPurgingAttempted) {
  1297. //
  1298. // No SRV_OPEN instance was found. Ensure that the potential references
  1299. // held by the memory manager/cache manager can be purged before the
  1300. // open request to the server can be attempted.
  1301. //
  1302. RxPurgeFcbInSystemCache( Fcb,
  1303. NULL,
  1304. 0,
  1305. FALSE,
  1306. TRUE);
  1307. FcbPurgingAttempted = TRUE;
  1308. continue;
  1309. }
  1310. break;
  1311. }
  1312. } else {
  1313. Status = STATUS_NOT_FOUND;
  1314. }
  1315. if (Status == STATUS_SHARING_VIOLATION) {
  1316. //
  1317. // A local sharing violation was detected.
  1318. //
  1319. RxContext->Create.TryForScavengingOnSharingViolation = TRUE;
  1320. }
  1321. return Status;
  1322. }
  1323. NTSTATUS
  1324. RxCollapseOrCreateSrvOpen (
  1325. IN OUT PRX_CONTEXT RxContext,
  1326. IN PIRP Irp,
  1327. IN PFCB Fcb
  1328. )
  1329. /*++
  1330. Routine Description:
  1331. This routine is called to either find a SRV_OPEN instance that can be
  1332. collapsed onto or, failing that, to build a fresh one IN
  1333. TRANSITION. The fcblock will already be held exclusive and the
  1334. tablelock will be either exclusive or shared. If everything
  1335. succeeds, it returns with a reference on the srvopen and with the
  1336. fcblock still held excl BUT we always release the tablelock. IF
  1337. IT FAILS, THEN IT COMPLETES THE RXCONTEXT FROM HERE WHICH, IN
  1338. TURN, WILL RELEASE THE FCBLOCK.
  1339. The minirdr is consulted to determine if a collapse is possible so
  1340. there is no reason to call twice. If the minirdr determines to
  1341. collapse, then it will do so and passback a returnable status.
  1342. Thus, RxStatus(SUCCESS) is an terminating return from here. For this
  1343. reason, we return RxStatus(MORE_PROCESSING_REQUIRED) as the
  1344. nonterminating return and the minirdr routine uses the same.
  1345. RxContext->SrvOpen contains either the collapsed or built srvopen.
  1346. Arguments:
  1347. RxContext - the current workitem
  1348. Return Value:
  1349. RxStatus(MORE_PROCESSING_REQUIRED) - further processing of the newly
  1350. constructed SRV_OPEN instance is required.
  1351. RxStatus(SUCCESS) - the SRV_OPEN instance was found/constructed successfully
  1352. Notes:
  1353. On Entry -- the FCB resource must have been acquired exclusive
  1354. --*/
  1355. {
  1356. NTSTATUS Status = STATUS_NOT_FOUND;
  1357. PNET_ROOT NetRoot = (PNET_ROOT)(RxContext->Create.pNetRoot);
  1358. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1359. PFILE_OBJECT FileObject = IrpSp->FileObject;
  1360. ACCESS_MASK DesiredAccess = FlagOn( IrpSp->Parameters.Create.SecurityContext->DesiredAccess, FILE_ALL_ACCESS );
  1361. ULONG ShareAccess = FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_VALID_FLAGS );
  1362. RX_BLOCK_CONDITION FcbCondition;
  1363. ULONG CreateOptions;
  1364. BOOLEAN DeleteOnClose;
  1365. BOOLEAN NoIntermediateBuffering;
  1366. BOOLEAN PagingIoResourceTaken = FALSE;
  1367. ULONG Disposition = RxContext->Create.NtCreateParameters.Disposition;
  1368. PSRV_OPEN SrvOpen;
  1369. PAGED_CODE();
  1370. RxDbgTrace(+1, Dbg, ("RxCollapseOrCreateSrvOpen -> %08lx\n", 0));
  1371. CreateOptions = IrpSp->Parameters.Create.Options;
  1372. NoIntermediateBuffering = BooleanFlagOn( CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING );
  1373. DeleteOnClose = BooleanFlagOn( CreateOptions, FILE_DELETE_ON_CLOSE );
  1374. ASSERT( RxIsFcbAcquiredExclusive( Fcb ) );
  1375. //
  1376. // this ensures that the fcb will not be finalized while we are in the minirdr
  1377. //
  1378. Fcb->UncleanCount += 1;
  1379. //
  1380. // When we call RxSearchForCollapsibleOpen, it will (in addition to
  1381. // searching for a collapsing candidate) close down delayed closes
  1382. // that could end up giving us a sharing violation on this open.
  1383. // Because of this side effect, we shouldn't try to avoid making
  1384. // this call because of some obviously non-collapsible condition.
  1385. // RxSearchForCollapsibleOpen will take care of those conditions
  1386. // for us.
  1387. //
  1388. Status = RxSearchForCollapsibleOpen( RxContext,
  1389. Fcb,
  1390. DesiredAccess,
  1391. ShareAccess );
  1392. if (Status == STATUS_SUCCESS) {
  1393. RxContext->CurrentIrp->IoStatus.Information = FILE_OPENED;
  1394. }
  1395. if (Status == STATUS_NOT_FOUND) {
  1396. RxDbgTrace(0, Dbg, ("No collapsible srvopens found for %wZ\n", &Fcb->FcbTableEntry.Path));
  1397. try {
  1398. SrvOpen = RxCreateSrvOpen( (PV_NET_ROOT)RxContext->Create.pVNetRoot, Fcb );
  1399. if (SrvOpen != NULL) {
  1400. SrvOpen->DesiredAccess = DesiredAccess;
  1401. SrvOpen->ShareAccess = ShareAccess;
  1402. Status = STATUS_SUCCESS;
  1403. } else {
  1404. Status = STATUS_INSUFFICIENT_RESOURCES;
  1405. }
  1406. } except (CATCH_EXPECTED_EXCEPTIONS) {
  1407. //
  1408. // note: we do not give back the FCB!!!!
  1409. //
  1410. RxDbgTrace(-1, Dbg, ("RxCollapseOrCreateSrvOpen EXCEPTION %08lx\n", GetExceptionCode()));
  1411. return RxProcessException( RxContext, GetExceptionCode() );
  1412. } // try
  1413. RxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)SrvOpen;
  1414. if (Status == STATUS_SUCCESS) {
  1415. RxInitiateSrvOpenKeyAssociation( SrvOpen );
  1416. //
  1417. // calldown.....
  1418. //
  1419. #if DBG
  1420. RxContext->CurrentIrp->IoStatus.Information = 0xabcdef;
  1421. #endif
  1422. MINIRDR_CALL( Status,
  1423. RxContext,
  1424. Fcb->MRxDispatch,
  1425. MRxCreate,
  1426. (RxContext));
  1427. //
  1428. // help other minirdr writers find this bug, i.e. they should use the new way
  1429. //
  1430. ASSERT( RxContext->CurrentIrp->IoStatus.Information == 0xabcdef );
  1431. //
  1432. // if this is a successful overwrite, then truncate the file
  1433. //
  1434. if ((Disposition == FILE_OVERWRITE) || (Disposition == FILE_OVERWRITE_IF)) {
  1435. if (Status == STATUS_SUCCESS) {
  1436. RxAcquirePagingIoResource( RxContext, Fcb );
  1437. Fcb->Header.FileSize.QuadPart = 0;
  1438. Fcb->Header.AllocationSize.QuadPart = 0;
  1439. Fcb->Header.ValidDataLength.QuadPart = 0;
  1440. FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
  1441. CcSetFileSizes( FileObject,
  1442. (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
  1443. RxReleasePagingIoResource( RxContext, Fcb );
  1444. }
  1445. } else if (Status == STATUS_SUCCESS) {
  1446. FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
  1447. if(CcIsFileCached( FileObject )) {
  1448. //
  1449. // Since the file is cached, we need to update the sizes the cache manager
  1450. // has with the ones we just got back from the server. If the server is
  1451. // behaving properly, this will be a nop. But we have to protect ourselves
  1452. // from a bad server that returns updated file sizes that we do not know about.
  1453. //
  1454. RxAdjustAllocationSizeforCC( Fcb );
  1455. try {
  1456. CcSetFileSizes( FileObject,
  1457. (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
  1458. } except( EXCEPTION_EXECUTE_HANDLER ) {
  1459. //
  1460. // We took an exception setting the file sizes. This can happen
  1461. // if the cache manager was not able to allocate resources. We
  1462. // cannot restore the previous sizes, since we do not know what they
  1463. // were. The best we can do is purge the file from the cache.
  1464. //
  1465. RxPurgeFcbInSystemCache( Fcb,
  1466. NULL,
  1467. 0,
  1468. TRUE,
  1469. TRUE );
  1470. }
  1471. }
  1472. }
  1473. RxContext->CurrentIrp->IoStatus.Information = RxContext->Create.ReturnedCreateInformation;
  1474. SrvOpen->OpenStatus = Status;
  1475. RxTransitionSrvOpen( SrvOpen,
  1476. (Status==STATUS_SUCCESS) ? Condition_Good : Condition_Bad );
  1477. RxDumpCurrentAccess( "shareaccess status after calldown....","","ShrAccPostMini", &Fcb->ShareAccess );
  1478. RxDbgTrace( 0, Dbg, ("RxCollapseOrCreateSrvOpen Back from the minirdr, Status=%08lx\n", Status ));
  1479. ASSERT( RxIsFcbAcquiredExclusive ( Fcb ) );
  1480. RxCompleteSrvOpenKeyAssociation( SrvOpen );
  1481. if (Status != STATUS_SUCCESS) {
  1482. FcbCondition = Condition_Bad;
  1483. RxDereferenceSrvOpen( SrvOpen, LHS_ExclusiveLockHeld );
  1484. RxContext->pRelevantSrvOpen = NULL;
  1485. if (RxContext->pFobx != NULL) {
  1486. RxDereferenceNetFobx( RxContext->pFobx, LHS_ExclusiveLockHeld );
  1487. RxContext->pFobx = NULL;
  1488. }
  1489. } else {
  1490. if (DeleteOnClose) {
  1491. ClearFlag( Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED );
  1492. }
  1493. SrvOpen->CreateOptions = RxContext->Create.NtCreateParameters.CreateOptions;
  1494. FcbCondition = Condition_Good;
  1495. }
  1496. } else {
  1497. FcbCondition = Condition_Bad;
  1498. }
  1499. RxLog(("Transitioning FCB %lx Condition %lx\n", Fcb, FcbCondition ));
  1500. RxWmiLog(LOG,
  1501. RxCollapseOrCreateSrvOpen,
  1502. LOGPTR( Fcb )
  1503. LOGULONG( FcbCondition ));
  1504. RxTransitionNetFcb( Fcb, FcbCondition );
  1505. } else if (Status == STATUS_SUCCESS) {
  1506. BOOLEAN TransitionProcessingRequired = FALSE;
  1507. //
  1508. // An existing SRV_OPEN instance has been found. This instance can be in
  1509. // one of the following two states -- either it has already transitioned
  1510. // into a stable state or it is in the process of being constructed. In
  1511. // the later case this routine needs to wait for this transition to occur.
  1512. // Note that both the reference count and the OpenCount need to be
  1513. // incremented before releasing the resource. An incremented reference
  1514. // count by itself will not ensure that the Close request on a SRV_OPEN
  1515. // will be delayed till the threads waiting for the transitioning of the
  1516. // SRV_OPEN have had a chance to process it.
  1517. //
  1518. SrvOpen = (PSRV_OPEN)(RxContext->pRelevantSrvOpen);
  1519. if (!StableCondition( SrvOpen->Condition )) {
  1520. TransitionProcessingRequired = TRUE;
  1521. RxDbgTrace(0,Dbg,("waiting for stable srv open (%lx)\n",SrvOpen));
  1522. RxReferenceSrvOpen( SrvOpen );
  1523. SrvOpen->OpenCount += 1;
  1524. RxReleaseFcb( RxContext, Fcb );
  1525. RxContext->Create.FcbAcquired = FALSE;
  1526. RxWaitForStableSrvOpen( SrvOpen, RxContext);
  1527. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  1528. if (Status == STATUS_SUCCESS) {
  1529. RxContext->Create.FcbAcquired = TRUE;
  1530. }
  1531. }
  1532. if (SrvOpen->Condition == Condition_Good) {
  1533. MINIRDR_CALL( Status, RxContext, Fcb->MRxDispatch, MRxCollapseOpen, (RxContext) );
  1534. RxDbgTrace(0, Dbg, ("RxCollapseOrCreateSrvOpen Back from the minirdr, Status=%08lx\n", Status ));
  1535. ASSERT ( RxIsFcbAcquiredExclusive( Fcb ) );
  1536. } else {
  1537. Status = SrvOpen->OpenStatus;
  1538. }
  1539. if (TransitionProcessingRequired) {
  1540. SrvOpen->OpenCount -= 1;
  1541. RxDereferenceSrvOpen( SrvOpen, LHS_ExclusiveLockHeld );
  1542. }
  1543. }
  1544. Fcb->UncleanCount -= 1; // now that we're back from the minirdr
  1545. RxDbgTrace(-1, Dbg, ("RxCollapseOrCreateSrvOpen SrvOpen %08lx Status %08lx\n"
  1546. , RxContext->pRelevantSrvOpen, Status));
  1547. return Status;
  1548. }
  1549. VOID
  1550. RxSetupNetFileObject (
  1551. IN OUT PRX_CONTEXT RxContext,
  1552. IN PIRP Irp,
  1553. IN PFCB Fcb
  1554. )
  1555. /*++
  1556. Routine Description:
  1557. This routine is called to finish setting up the fileobject based on the
  1558. information in the Irpcontext.
  1559. Arguments:
  1560. RxContext - the current workitem
  1561. Irp - The create irp
  1562. Fcb - The fcb that has been found
  1563. Return Value:
  1564. none
  1565. --*/
  1566. {
  1567. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1568. PFILE_OBJECT FileObject = IrpSp->FileObject;
  1569. PAGED_CODE();
  1570. ASSERT( (RxContext->pFobx == NULL) || (NodeType( RxContext->pFobx ) == RDBSS_NTC_FOBX) );
  1571. if (Fcb != NULL) {
  1572. ASSERT( NodeTypeIsFcb( Fcb ) );
  1573. //
  1574. // If this is a temporary file, note it in the FcbState
  1575. //
  1576. if (FlagOn( Fcb->FcbState, FCB_STATE_TEMPORARY ) && (FileObject != NULL)) {
  1577. SetFlag( FileObject->Flags, FO_TEMPORARY_FILE );
  1578. }
  1579. }
  1580. //
  1581. // Now set the fscontext fields of the file object
  1582. //
  1583. if (FileObject != NULL) {
  1584. FileObject->FsContext = Fcb;
  1585. if (RxContext->pFobx != NULL) {
  1586. ULONG_PTR StackBottom,StackTop;
  1587. IoGetStackLimits( &StackTop, &StackBottom );
  1588. //
  1589. // Determine if the FileObject passed in is on the stack. If it is do
  1590. // not squirrel away the file object in the FOBX. Otherwise stash it
  1591. // away.
  1592. //
  1593. if (((ULONG_PTR)FileObject <= StackBottom) ||
  1594. ((ULONG_PTR)FileObject >= StackTop)) {
  1595. RxContext->pFobx->AssociatedFileObject = FileObject;
  1596. } else {
  1597. RxContext->pFobx->AssociatedFileObject = NULL;
  1598. }
  1599. if (RxContext->Create.NtCreateParameters.DfsContext == UIntToPtr(DFS_OPEN_CONTEXT)) {
  1600. SetFlag( RxContext->pFobx->Flags, FOBX_FLAG_DFS_OPEN );
  1601. RxDbgTrace( 0, Dbg, ("RxSetupNetFileObject %lx Dfs aware FOBX\n", RxContext->pFobx));
  1602. } else {
  1603. ClearFlag( RxContext->pFobx->Flags, FOBX_FLAG_DFS_OPEN );
  1604. RxDbgTrace( 0, Dbg, ("RxSetupNetFileObject %lx Dfs unaware FOBX\n", RxContext->pFobx));
  1605. }
  1606. }
  1607. FileObject->FsContext2 = RxContext->pFobx;
  1608. FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
  1609. //
  1610. // The create is being completed successfully. Turn off the remaining
  1611. // desired access flags in the IRP. This is required by Praerit/Robert
  1612. // to facilitate policy code.
  1613. //
  1614. if (IrpSp->Parameters.Create.SecurityContext != NULL) {
  1615. SetFlag( IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess,
  1616. IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess );
  1617. IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess = 0;
  1618. }
  1619. }
  1620. }
  1621. VOID
  1622. RxpPrepareCreateContextForReuse (
  1623. PRX_CONTEXT RxContext
  1624. )
  1625. /*++
  1626. Routine Description:
  1627. This routine prepares an instance of RX_CONTEXT for reuse. This centralizes all
  1628. the actions required to be undone, i.e., accquistion of resources etc.
  1629. Arguments:
  1630. RxContext - the current workitem
  1631. --*/
  1632. {
  1633. ASSERT( RxContext->MajorFunction == IRP_MJ_CREATE );
  1634. RxDbgTrace(0, Dbg, ("RxpPrepareCreateContextForReuse canonname %08lx\n",
  1635. RxContext->Create.CanonicalNameBuffer));
  1636. //
  1637. // the order is important here...release the fcb first
  1638. //
  1639. if (RxContext->Create.FcbAcquired) {
  1640. RxReleaseFcb( RxContext, RxContext->pFcb );
  1641. RxContext->Create.FcbAcquired = FALSE;
  1642. }
  1643. RxFreeCanonicalNameBuffer( RxContext );
  1644. if ((RxContext->Create.pVNetRoot != NULL) ||
  1645. (RxContext->Create.NetNamePrefixEntry != NULL)) {
  1646. PRX_PREFIX_TABLE RxNetNameTable = RxContext->RxDeviceObject->pRxNetNameTable;
  1647. RxAcquirePrefixTableLockShared( RxNetNameTable, TRUE );
  1648. //
  1649. // Dereference the data structures associated with the create operation
  1650. //
  1651. if (RxContext->Create.pVNetRoot != NULL) {
  1652. RxDereferenceVNetRoot( (PV_NET_ROOT)(RxContext->Create.pVNetRoot), LHS_SharedLockHeld );
  1653. RxContext->Create.pVNetRoot = NULL;
  1654. }
  1655. RxReleasePrefixTableLock( RxNetNameTable );
  1656. }
  1657. }
  1658. NTSTATUS
  1659. RxCreateFromNetRoot(
  1660. IN OUT PRX_CONTEXT RxContext,
  1661. IN PIRP Irp,
  1662. IN PUNICODE_STRING RemainingName
  1663. )
  1664. /*++
  1665. Routine Description:
  1666. This routine is called during from CommonCreate once a good netroot has
  1667. been established. This routine builds an Fcb, if necessary, and tries to
  1668. collapse the open onto an existing open if it can. If it cannot, then it
  1669. constructs an InTransition srv_open on this netroot and passes the open down
  1670. to the minirdr. By the time that we get here, there is a reference on the
  1671. netroot but we do not have the netname tablelock. When we complete the context,
  1672. this reference is removed.
  1673. Arguments:
  1674. RxContext - the current workitem
  1675. RemainingName - the name of the file after the netroot prefix is removed;
  1676. it has been canonicalized.
  1677. Return Value:
  1678. NTSTATUS - The Fsd status for the Irp
  1679. --*/
  1680. {
  1681. NTSTATUS Status;
  1682. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1683. PFILE_OBJECT FileObject = IrpSp->FileObject;
  1684. PV_NET_ROOT VNetRoot;
  1685. PNET_ROOT NetRoot;
  1686. PFCB Fcb;
  1687. PSRV_OPEN SrvOpen;
  1688. PFOBX Fobx;
  1689. ACCESS_MASK DesiredAccess;
  1690. ULONG ShareAccess;
  1691. BOOLEAN OpenTargetDirectory;
  1692. PNT_CREATE_PARAMETERS cp;
  1693. PAGED_CODE();
  1694. VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
  1695. NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
  1696. Fcb = NULL;
  1697. SrvOpen = NULL;
  1698. Fobx = NULL;
  1699. //
  1700. // Fix for bug 501657 (opening file with MAXIMUM_ALLOWED flag does not permit read/write
  1701. //
  1702. DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
  1703. if(FlagOn( DesiredAccess, MAXIMUM_ALLOWED )) {
  1704. DesiredAccess = FILE_ALL_ACCESS;
  1705. IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess = DesiredAccess;
  1706. } else {
  1707. DesiredAccess &= FILE_ALL_ACCESS;
  1708. }
  1709. ShareAccess = FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_VALID_FLAGS );
  1710. OpenTargetDirectory = BooleanFlagOn( IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY );
  1711. cp = &RxContext->Create.NtCreateParameters;
  1712. RxDbgTrace(+1, Dbg, ("RxCreateFromNetRoot Name=%wZ\n", RemainingName ));
  1713. //
  1714. // A Create request cannot succeed without a valid NET_ROOT instance.
  1715. //
  1716. if (RxContext->Create.pNetRoot == NULL){
  1717. RxDbgTrace(-1, Dbg, ("RxCreateFromNetRoot Couldn't create the FCB: No NetRoot!!\n"));
  1718. return STATUS_NO_SUCH_FILE;
  1719. }
  1720. //
  1721. // we cannot proceed unless this device owns the srvcall.
  1722. //
  1723. if (RxContext->RxDeviceObject != RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject){
  1724. RxDbgTrace(-1, Dbg, ("RxCreateFromNetRoot wrong DeviceObject!!!!!\n"));
  1725. return STATUS_BAD_NETWORK_PATH;
  1726. }
  1727. //
  1728. // The DFS driver builds up a logical name space from different physical
  1729. // volumes. In order to distinguish processing the DFS driver sets the
  1730. // FsContext2 field to DFS_OPEN_CONTEXT or DFS_DOWWNLEVEL_OPEN_CONTEXT. At
  1731. // this point in the control flow the V_NET_ROOT has been determined. This
  1732. // in turn determines the NET_ROOT and SRV_CALL instance and indirectly
  1733. // also determines the Server type. Uplevel opens can only be permitted to
  1734. // servers that are DFS aware.
  1735. //
  1736. if ((cp->DfsContext == UIntToPtr( DFS_OPEN_CONTEXT )) &&
  1737. !FlagOn( NetRoot->SrvCall->Flags, SRVCALL_FLAG_DFS_AWARE_SERVER )) {
  1738. return STATUS_DFS_UNAVAILABLE;
  1739. }
  1740. if ((cp->DfsContext == UIntToPtr( DFS_DOWNLEVEL_OPEN_CONTEXT )) &&
  1741. FlagOn( NetRoot->Flags, NETROOT_FLAG_DFS_AWARE_NETROOT )) {
  1742. return STATUS_OBJECT_TYPE_MISMATCH;
  1743. }
  1744. if (NetRoot->Type == NET_ROOT_PRINT) {
  1745. //
  1746. // allow share read and write to the printer server
  1747. //
  1748. ShareAccess = FILE_SHARE_VALID_FLAGS;
  1749. }
  1750. //
  1751. // if the create request is for opening the target directory for a rename
  1752. // a fake FCB needs to be created.
  1753. //
  1754. if (OpenTargetDirectory) {
  1755. if (FlagOn( cp->DesiredAccess, DELETE )) {
  1756. RxPurgeRelatedFobxs( VNetRoot->NetRoot,
  1757. RxContext,
  1758. ATTEMPT_FINALIZE_ON_PURGE,
  1759. NULL );
  1760. }
  1761. Fcb = RxCreateNetFcb( RxContext, Irp, VNetRoot, RemainingName );
  1762. if (Fcb != NULL) {
  1763. Fcb->Header.NodeTypeCode = (USHORT)RDBSS_NTC_OPENTARGETDIR_FCB;
  1764. RxContext->Create.FcbAcquired = FALSE;
  1765. //
  1766. // Normally the FileObjects reference the associated SRV_OPEN instance
  1767. // via the FileObjectExtension(FOBX). In this case there is no
  1768. // corresponding SRV_OPEN and a reference on the FCB is maintained.
  1769. //
  1770. RxContext->Create.NetNamePrefixEntry = NULL; // don't let it deref the netroot!!!!
  1771. FileObject->FsContext = Fcb;
  1772. if (RxContext->pFobx != NULL) {
  1773. if (FileObject->FsContext2 == UIntToPtr(DFS_OPEN_CONTEXT)) {
  1774. SetFlag( RxContext->pFobx->Flags, FOBX_FLAG_DFS_OPEN );
  1775. } else {
  1776. ClearFlag( RxContext->pFobx->Flags, FOBX_FLAG_DFS_OPEN );
  1777. }
  1778. }
  1779. FileObject->FsContext2 = NULL;
  1780. Fcb->UncleanCount += 1;
  1781. Fcb->OpenCount += 1;
  1782. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  1783. if (Status == STATUS_SUCCESS) {
  1784. RxReferenceNetFcb( Fcb );
  1785. RxReleaseFcb( RxContext, Fcb );
  1786. } else {
  1787. RxDbgTrace(-1, Dbg, ("RxCreateFromNetRoot -- Couldn't acquire FCB:(%lx) %lx!\n",Fcb,Status));
  1788. }
  1789. } else {
  1790. Status = STATUS_INSUFFICIENT_RESOURCES;
  1791. }
  1792. return Status;
  1793. }
  1794. Status = RxFindOrCreateFcb( RxContext, Irp, RemainingName, &Fcb );
  1795. ASSERT( (Fcb != NULL) || (Status != STATUS_SUCCESS) );
  1796. if ((Status != STATUS_SUCCESS) || (Fcb == NULL)) {
  1797. RxDbgTrace(-1, Dbg, ("RxCreateFromNetRoot Couldn't create the FCB%c\n", '!' ));
  1798. return Status;
  1799. }
  1800. //
  1801. // If the Create request is for a mailslot no further processing is required.
  1802. //
  1803. if (FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT )) {
  1804. Fcb->Header.NodeTypeCode = RDBSS_NTC_MAILSLOT;
  1805. RxTransitionNetFcb( Fcb, Condition_Good );
  1806. RxLog(("Transitioning FCB %lx Condition %lx\n",Fcb,Fcb->Condition));
  1807. RxWmiLog(LOG,
  1808. RxCollapseOrCreateSrvOpen,
  1809. LOGPTR(Fcb)
  1810. LOGULONG(Fcb->Condition));
  1811. Fcb->OpenCount += 1;
  1812. RxSetupNetFileObject( RxContext, Irp, Fcb );
  1813. return Status;
  1814. } else {
  1815. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1816. }
  1817. //
  1818. // This Create request is for a file/directory or pipe for which further
  1819. // processing is required. At this point the corresponding FCB resource
  1820. // has been accquired ( even for newly constructed FCB's). If this is not the
  1821. // first open then those requests that do not meet the necessary share access
  1822. // constraints can be rejected quickly. Note that this early check avoids
  1823. // a potential Network trip in some cases.
  1824. //
  1825. RxDumpCurrentAccess( "shareaccess status before anything....", "", "DumpAcc000", &Fcb->ShareAccess );
  1826. if (Fcb->OpenCount > 0) {
  1827. Status = RxCheckShareAccess( DesiredAccess,
  1828. ShareAccess,
  1829. FileObject,
  1830. &Fcb->ShareAccess,
  1831. FALSE,
  1832. "early check per useropens",
  1833. "EarlyPerUO" );
  1834. if (Status != STATUS_SUCCESS) {
  1835. RxDereferenceNetFcb( Fcb );
  1836. return Status;
  1837. }
  1838. }
  1839. if (FlagOn( cp->CreateOptions, FILE_DELETE_ON_CLOSE ) &&
  1840. (FlagOn( cp->DesiredAccess, ~DELETE ) == 0)) {
  1841. //
  1842. // if the file is opened for delete only, we push out possible delayed close on this file
  1843. // so that mini rdr has the opportunity to do the perfomance optimization, i.e. delete the
  1844. // file without even open it.
  1845. //
  1846. RxPurgeFcbInSystemCache( Fcb,
  1847. NULL,
  1848. 0,
  1849. TRUE,
  1850. FALSE );
  1851. RxScavengeRelatedFobxs( Fcb );
  1852. }
  1853. //
  1854. // A valid FCB which meets the Share access requirements of the create
  1855. // request is on hand. The associated SRV_OPEN should be either located
  1856. // amongst the existing SRV_OPEN's or a new SRV_OPEN instance needs to
  1857. // be constructed.
  1858. //
  1859. try {
  1860. ULONG CreateOptions;
  1861. BOOLEAN DeleteOnClose;
  1862. BOOLEAN NoIntermediateBuffering;
  1863. Status = RxCollapseOrCreateSrvOpen( RxContext, Irp, Fcb );
  1864. IF_DEBUG {
  1865. if (Status == STATUS_SUCCESS) {
  1866. RxDbgTrace(0, Dbg, ("RxCreateFromNetRoot Collapsed onto %08lx\n",
  1867. RxContext->pRelevantSrvOpen ));
  1868. } else {
  1869. RxDbgTrace(0, Dbg, ("RxCreateFromNetRoot Error in Srvopen Collapse %08lx\n", Status ));
  1870. }
  1871. }
  1872. if (Status != STATUS_SUCCESS) {
  1873. try_return( Status );
  1874. }
  1875. SrvOpen = (PSRV_OPEN)(RxContext->pRelevantSrvOpen);
  1876. Fobx = (PFOBX)(RxContext->pFobx);
  1877. CreateOptions = IrpSp->Parameters.Create.Options;
  1878. NoIntermediateBuffering = BooleanFlagOn( CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING );
  1879. DeleteOnClose = BooleanFlagOn( CreateOptions, FILE_DELETE_ON_CLOSE );
  1880. //
  1881. // If the FCB has multiple SRV_OPEN instances associated with it then it
  1882. // is possible for the Share access associated with the FCB has changed
  1883. // if the FCB resource was dropped by the mini redirector.
  1884. //
  1885. if (Fcb->OpenCount > 0) {
  1886. Status = RxCheckShareAccess( DesiredAccess,
  1887. ShareAccess,
  1888. FileObject,
  1889. &Fcb->ShareAccess,
  1890. FALSE,
  1891. "second check per useropens",
  1892. "2ndAccPerUO" );
  1893. if (Status != STATUS_SUCCESS) {
  1894. //
  1895. // When this Fobx goes away it will remove an open from the SrvOpen.
  1896. // Add a reference to the SrvOpen here to account for this. This
  1897. // will prevent the SrvOpen from getting closed prematurely.
  1898. //
  1899. SrvOpen->OpenCount += 1;
  1900. RxDereferenceNetFobx( RxContext->pFobx, LHS_LockNotHeld );
  1901. RxContext->pFobx = NULL;
  1902. try_return( Status );
  1903. }
  1904. } else {
  1905. if (RxContext->Create.pNetRoot->Type != NET_ROOT_PIPE) {
  1906. RxSetShareAccess( DesiredAccess,
  1907. ShareAccess,
  1908. FileObject,
  1909. &Fcb->ShareAccess,
  1910. "initial shareaccess setup",
  1911. "InitShrAcc" );
  1912. }
  1913. }
  1914. RxSetupNetFileObject( RxContext, Irp, Fcb );
  1915. RxDumpCurrentAccess( "shareaccess status after checkorset....",
  1916. "",
  1917. "CurrentAcc",
  1918. &Fcb->ShareAccess );
  1919. //
  1920. // At this point the necessary infrastructure to handle the create
  1921. // request successfully has been established. What remains to be done
  1922. // is the appropriate initialization of the FileObject( owned by IO
  1923. // subsystem), the FileObjectExtension(FOBX owned by RDBSS) and updating
  1924. // the fields associated with the SRV_OPEN and the FCB. This largely
  1925. // depends upon whether the FCB/SRV_OPEN was newly constructed or
  1926. // was collapsed.
  1927. //
  1928. // SRV_OPEN changes
  1929. // 1) For a newly constructed SRV_OPEN the buffering state needs to
  1930. // be updated
  1931. //
  1932. // FCB changes
  1933. // 1) for an existing FCB the SHARE ACCESS needs to be updated.
  1934. //
  1935. // In all the cases the corresponing OpenCounts and UncleanCounts needs
  1936. // to be updated.
  1937. //
  1938. if ((Fcb->OpenCount > 0) &&
  1939. (RxContext->Create.pNetRoot->Type != NET_ROOT_PIPE)) {
  1940. RxUpdateShareAccess( FileObject,
  1941. &Fcb->ShareAccess,
  1942. "update share access",
  1943. "UpdShrAcc" );
  1944. }
  1945. //
  1946. // incrementing the uncleancount must be done before RxChangeBufferingState
  1947. // because that routine will purge the cache otherwise if unclenacount==0
  1948. //
  1949. Fcb->UncleanCount += 1;
  1950. if (FlagOn( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING )) {
  1951. Fcb->UncachedUncleanCount += 1;
  1952. } else {
  1953. // maybe we should turn on the FO_CACHE_SUPPORTED flag
  1954. }
  1955. //
  1956. // For the first open, we want to initialize the Fcb buffering state flags
  1957. // to the default value
  1958. //
  1959. if ((SrvOpen->OpenCount == 0) &&
  1960. (Fcb->UncleanCount == 1) &&
  1961. (!FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE ))) {
  1962. RxChangeBufferingState( SrvOpen, NULL, FALSE );
  1963. }
  1964. //
  1965. // this might be from a previous usage.
  1966. //
  1967. ClearFlag( Fcb->FcbState, FCB_STATE_DELAY_CLOSE );
  1968. //
  1969. // Reference the Objects as needed
  1970. //
  1971. Fcb->OpenCount += 1;
  1972. SrvOpen->UncleanFobxCount += 1;
  1973. SrvOpen->OpenCount += 1;
  1974. SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
  1975. //
  1976. // For NoIntermediateBuffering opens, we need to disable caching on
  1977. // this FCB
  1978. //
  1979. if (NoIntermediateBuffering) {
  1980. SetFlag( SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_READ_CACHING );
  1981. SetFlag( SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING );
  1982. ClearFlag( Fcb->FcbState, FCB_STATE_READCACHING_ENABLED );
  1983. ClearFlag( Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED );
  1984. RxPurgeFcbInSystemCache( Fcb, NULL, 0, TRUE, TRUE );
  1985. }
  1986. RxUpdateShareAccessPerSrvOpens(SrvOpen);
  1987. //
  1988. // The file object extensions needs to be updated with configuration
  1989. // information for pipes and spool files. In addition the appropriate
  1990. // flags needs to be set based upon the parameters specfied in the
  1991. // request.
  1992. // For spool files the WriteSerializationQueue is the only field of
  1993. // interest.
  1994. //
  1995. //
  1996. // Mark the DeleteOnClose bit if the operation was successful.
  1997. //
  1998. if (DeleteOnClose) {
  1999. SetFlag( Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE );
  2000. }
  2001. if (Fobx != NULL) {
  2002. //
  2003. // fill in various type-specific fields of the fobx
  2004. //
  2005. switch (RxContext->Create.pNetRoot->Type) {
  2006. case NET_ROOT_PIPE:
  2007. SetFlag( FileObject->Flags, FO_NAMED_PIPE );
  2008. //
  2009. // lack of break intentional
  2010. //
  2011. case NET_ROOT_PRINT:
  2012. Fobx->PipeHandleInformation = &Fobx->Specific.NamedPipe.PipeHandleInformation;
  2013. Fobx->Specific.NamedPipe.CollectDataTime.QuadPart = 0;
  2014. Fobx->Specific.NamedPipe.CollectDataSize = RxContext->Create.pNetRoot->NamedPipeParameters.DataCollectionSize;
  2015. Fobx->Specific.NamedPipe.TypeOfPipe = RxContext->Create.PipeType;
  2016. Fobx->Specific.NamedPipe.ReadMode = RxContext->Create.PipeReadMode;
  2017. Fobx->Specific.NamedPipe.CompletionMode = RxContext->Create.PipeCompletionMode;
  2018. InitializeListHead( &Fobx->Specific.NamedPipe.ReadSerializationQueue );
  2019. InitializeListHead( &Fobx->Specific.NamedPipe.WriteSerializationQueue );
  2020. break;
  2021. default:
  2022. //
  2023. // check if we have post create handler installed on devfcb. The lwio driver
  2024. // opens the lanman driver and sets its mrxdispatch on the device fcb so that
  2025. // it gets informed of file creates on lwio capable servers.
  2026. //
  2027. if (RxDeviceFCB.MRxDispatch != NULL &&
  2028. NodeTypeIsFcb( Fcb ) &&
  2029. (NodeType( Fcb ) == RDBSS_NTC_STORAGE_TYPE_FILE) &&
  2030. FlagOn( Fcb->NetRoot->SrvCall->Flags, SRVCALL_FLAG_LWIO_AWARE_SERVER )) {
  2031. ExAcquireResourceSharedLite( &RxData.Resource, TRUE );
  2032. if (RxDeviceFCB.MRxDispatch != NULL &&
  2033. RxDeviceFCB.MRxDispatch->MRxCreate != NULL) {
  2034. RxDeviceFCB.MRxDispatch->MRxCreate( RxContext );
  2035. }
  2036. ExReleaseResourceLite( &RxData.Resource );
  2037. }
  2038. NOTHING;
  2039. }
  2040. }
  2041. try_exit: NOTHING;
  2042. } finally {
  2043. RxDbgTrace(0, Dbg, ("--->Fobx=%08lx, Ref=%08lx\n", Fobx, (Fobx)?Fobx->NodeReferenceCount:0 ));
  2044. RxDbgTrace(0, Dbg, ("--->SrvOpen=%08lx, Ref=%08lx\n", SrvOpen, (SrvOpen)?SrvOpen->NodeReferenceCount:0 ));
  2045. RxDbgTrace(0, Dbg, ("--->Fcb=%08lx, Ref=%08lx\n", Fcb, (Fcb)?Fcb->NodeReferenceCount:0 ));
  2046. //
  2047. // get rid of the reference on the fcb; we also finalize here if we can
  2048. //
  2049. if (Fcb->OpenCount == 0) {
  2050. //
  2051. // if we have the lock we can finalize.........
  2052. //
  2053. if (RxContext->Create.FcbAcquired) {
  2054. //
  2055. // try to finalize right now
  2056. //
  2057. RxContext->Create.FcbAcquired = !RxDereferenceAndFinalizeNetFcb( Fcb, RxContext, FALSE, FALSE);
  2058. //
  2059. // the tracker gets very unhappy if you don't do this!
  2060. //
  2061. if (!RxContext->Create.FcbAcquired) {
  2062. RxTrackerUpdateHistory( RxContext, NULL, 'rrCr', __LINE__, __FILE__, 0 );
  2063. }
  2064. }
  2065. } else {
  2066. //
  2067. // cant finalize now.....just remove our reference.......
  2068. //
  2069. RxDereferenceNetFcb( Fcb );
  2070. }
  2071. }
  2072. RxDbgTrace( -1, Dbg, ("Exiting RxCreateFromNetRoot status=%08lx\n", Status) );
  2073. return Status;
  2074. }
  2075. NTSTATUS
  2076. RxPrefixClaim (
  2077. IN PRX_CONTEXT RxContext
  2078. )
  2079. /*++
  2080. Routine Description:
  2081. This routine handles the call down from the MUP to claim a name. We pass the name down
  2082. to the routine for finding/creating connections.
  2083. Arguments:
  2084. IN PRX_CONTEXT RxContext - Describes the ioctl and Context
  2085. Return Value:
  2086. NTSTATUS
  2087. --*/
  2088. {
  2089. NTSTATUS Status = STATUS_SUCCESS;
  2090. PIRP Irp = RxContext->CurrentIrp;
  2091. PEPROCESS Process = IoGetRequestorProcess( Irp );
  2092. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2093. PQUERY_PATH_REQUEST QueryPathRequest;
  2094. PQUERY_PATH_RESPONSE QueryPathResponse;
  2095. UNICODE_STRING FilePathName;
  2096. UNICODE_STRING CanonicalName;
  2097. UNICODE_STRING RemainingName;
  2098. NET_ROOT_TYPE NetRootType = NET_ROOT_WILD;
  2099. PAGED_CODE();
  2100. RxDbgTrace(0, Dbg, ("RxPrefixClaim -> %08lx\n", 0));
  2101. if( !_stricmp( PsGetProcessImageFileName( Process ), SPOOLER_PROCESS_NAME ) )
  2102. {
  2103. ClearFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
  2104. }
  2105. //
  2106. // Initialize RemainingName.
  2107. //
  2108. RemainingName.Buffer = NULL;
  2109. RemainingName.Length = 0;
  2110. RemainingName.MaximumLength = 0;
  2111. //
  2112. // Only kernel mode callers allowed to use this path
  2113. //
  2114. if (Irp->RequestorMode == UserMode) {
  2115. Status = STATUS_INVALID_DEVICE_REQUEST;
  2116. return Status;
  2117. }
  2118. QueryPathResponse = Irp->UserBuffer;
  2119. if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
  2120. QueryPathRequest = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  2121. RxContext->MajorFunction = IRP_MJ_CREATE;
  2122. RxContext->PrefixClaim.SuppliedPathName.Buffer =
  2123. (PWCHAR)RxAllocatePoolWithTag( NonPagedPool,
  2124. QueryPathRequest->PathNameLength,
  2125. RX_MISC_POOLTAG);
  2126. if (RxContext->PrefixClaim.SuppliedPathName.Buffer == NULL) {
  2127. try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
  2128. }
  2129. RtlCopyMemory( RxContext->PrefixClaim.SuppliedPathName.Buffer,
  2130. QueryPathRequest->FilePathName,
  2131. QueryPathRequest->PathNameLength );
  2132. RxContext->PrefixClaim.SuppliedPathName.Length = (USHORT)QueryPathRequest->PathNameLength;
  2133. RxContext->PrefixClaim.SuppliedPathName.Length = (USHORT)QueryPathRequest->PathNameLength;
  2134. RtlZeroMemory( &RxContext->Create, sizeof( RxContext->Create ) );
  2135. RxContext->Create.ThisIsATreeConnectOpen = TRUE;
  2136. RxContext->Create.NtCreateParameters.SecurityContext = QueryPathRequest->SecurityContext;
  2137. } else {
  2138. ASSERT( RxContext->MajorFunction == IRP_MJ_CREATE );
  2139. ASSERT( RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL );
  2140. }
  2141. FilePathName = RxContext->PrefixClaim.SuppliedPathName;
  2142. RemainingName = FilePathName;
  2143. Status = RxFirstCanonicalize( RxContext, Irp, &FilePathName, &CanonicalName, &NetRootType );
  2144. if (Status == STATUS_SUCCESS) {
  2145. Status = RxFindOrConstructVirtualNetRoot( RxContext,
  2146. Irp,
  2147. &CanonicalName,
  2148. NetRootType,
  2149. &RemainingName );
  2150. }
  2151. try_exit:
  2152. if (Status != STATUS_PENDING) {
  2153. if (Status == STATUS_SUCCESS) {
  2154. QueryPathResponse->LengthAccepted = RxContext->PrefixClaim.SuppliedPathName.Length - RemainingName.Length;
  2155. }
  2156. if (RxContext->MajorFunction == IRP_MJ_CREATE) {
  2157. if (RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL) {
  2158. RxFreePool (RxContext->PrefixClaim.SuppliedPathName.Buffer );
  2159. }
  2160. RxpPrepareCreateContextForReuse( RxContext );
  2161. RxContext->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  2162. }
  2163. }
  2164. RxDbgTrace(0, Dbg, ("RxPrefixClaim -> Status %08lx\n", Status));
  2165. return Status;
  2166. }
  2167. NTSTATUS
  2168. RxCreateTreeConnect (
  2169. IN PRX_CONTEXT RxContext
  2170. )
  2171. /*++
  2172. Routine Description:
  2173. This is the routine for creating/opening a TC.
  2174. Arguments:
  2175. RxContext -
  2176. Return Value:
  2177. NTSTATUS - the return status for the operation
  2178. --*/
  2179. {
  2180. NTSTATUS Status;
  2181. PIRP Irp = RxContext->CurrentIrp;
  2182. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2183. PFILE_OBJECT FileObject = IrpSp->FileObject;
  2184. UNICODE_STRING CanonicalName, RemainingName;
  2185. PUNICODE_STRING OriginalName = &FileObject->FileName;
  2186. LOCK_HOLDING_STATE LockHoldingState = LHS_LockNotHeld;
  2187. NET_ROOT_TYPE NetRootType = NET_ROOT_WILD;
  2188. ULONG EaInformationLength;
  2189. PAGED_CODE();
  2190. RxDbgTrace(+1, Dbg, ("RxCreateTreeConnect entry\n"));
  2191. CanonicalName.Length = CanonicalName.MaximumLength = 0;
  2192. CanonicalName.Buffer = NULL;
  2193. Status = RxFirstCanonicalize( RxContext, Irp, OriginalName, &CanonicalName, &NetRootType );
  2194. if (Status != STATUS_SUCCESS) {
  2195. RxDbgTraceUnIndent( -1,Dbg );
  2196. return Status;
  2197. }
  2198. RxContext->Create.ThisIsATreeConnectOpen = TRUE;
  2199. RxContext->Create.TreeConnectOpenDeferred = FALSE;
  2200. RxContext->Create.TransportName.Length = 0;
  2201. RxContext->Create.TransportName.MaximumLength = 0;
  2202. RxContext->Create.TransportName.Buffer = NULL;
  2203. RxContext->Create.UserName.Length = 0;
  2204. RxContext->Create.UserName.MaximumLength = 0;
  2205. RxContext->Create.UserName.Buffer = NULL;
  2206. RxContext->Create.Password.Length = 0;
  2207. RxContext->Create.Password.MaximumLength = 0;
  2208. RxContext->Create.Password.Buffer = NULL;
  2209. RxContext->Create.UserDomainName.Length = 0;
  2210. RxContext->Create.UserDomainName.MaximumLength = 0;
  2211. RxContext->Create.UserDomainName.Buffer = NULL;
  2212. EaInformationLength = IrpSp->Parameters.Create.EaLength;
  2213. if (EaInformationLength > 0) {
  2214. BOOLEAN DeferredConnection = FALSE;
  2215. BOOLEAN CredentialsSupplied = FALSE;
  2216. PFILE_FULL_EA_INFORMATION EaEntry;
  2217. EaEntry = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  2218. ASSERT( EaEntry != NULL );
  2219. for(;;) {
  2220. PUNICODE_STRING TargetString;
  2221. //
  2222. // Note: iosubsystem verifies all EaNames are valid and null terminated
  2223. //
  2224. if (strcmp( EaEntry->EaName, EA_NAME_CONNECT ) == 0) {
  2225. DeferredConnection = TRUE;
  2226. } else if ((strcmp( EaEntry->EaName, EA_NAME_USERNAME ) == 0) ||
  2227. (strcmp( EaEntry->EaName, EA_NAME_PASSWORD ) == 0) ||
  2228. (strcmp( EaEntry->EaName, EA_NAME_DOMAIN ) == 0)) {
  2229. CredentialsSupplied = TRUE;
  2230. }
  2231. TargetString = NULL;
  2232. RxDbgTrace( 0, Dbg, ("RxCreateTreeConnect: Processing EA name %s\n", EaEntry->EaName) );
  2233. if (strcmp( EaEntry->EaName, EA_NAME_TRANSPORT ) == 0) {
  2234. TargetString = &RxContext->Create.TransportName;
  2235. } else if (strcmp( EaEntry->EaName, EA_NAME_USERNAME ) == 0) {
  2236. TargetString = &RxContext->Create.UserName;
  2237. } else if (strcmp( EaEntry->EaName, EA_NAME_PASSWORD ) == 0) {
  2238. TargetString = &RxContext->Create.Password;
  2239. } else if (strcmp( EaEntry->EaName, EA_NAME_DOMAIN ) == 0) {
  2240. TargetString = &RxContext->Create.UserDomainName;
  2241. } else {
  2242. RxDbgTrace( 0, Dbg, ("RxCreateTreeConnect: Invalid EA name/value %s\n", EaEntry->EaName) );
  2243. }
  2244. if (TargetString != NULL) {
  2245. TargetString->Length = EaEntry->EaValueLength;
  2246. TargetString->MaximumLength = EaEntry->EaValueLength;
  2247. TargetString->Buffer = (PWSTR)(EaEntry->EaName + EaEntry->EaNameLength + 1);
  2248. }
  2249. if (EaEntry->NextEntryOffset == 0) {
  2250. break;
  2251. } else {
  2252. EaEntry = (PFILE_FULL_EA_INFORMATION) Add2Ptr( EaEntry, EaEntry->NextEntryOffset );
  2253. }
  2254. }
  2255. if (!CredentialsSupplied && DeferredConnection) {
  2256. RxContext->Create.TreeConnectOpenDeferred = TRUE;
  2257. }
  2258. }
  2259. Status = RxFindOrConstructVirtualNetRoot( RxContext,
  2260. Irp,
  2261. &CanonicalName,
  2262. NetRootType,
  2263. &RemainingName );
  2264. if(Status == STATUS_NETWORK_CREDENTIAL_CONFLICT) {
  2265. //
  2266. // Scavenge the VNetRoots
  2267. //
  2268. RxScavengeVNetRoots( RxContext->RxDeviceObject );
  2269. Status = RxFindOrConstructVirtualNetRoot( RxContext,
  2270. Irp,
  2271. &CanonicalName,
  2272. NetRootType,
  2273. &RemainingName );
  2274. }
  2275. //
  2276. // We have to check whether the path is valid if it is provided.
  2277. //
  2278. if ((Status == STATUS_SUCCESS) && (RemainingName.Length > 0)) {
  2279. MINIRDR_CALL( Status,
  2280. RxContext,
  2281. RxContext->Create.pNetRoot->pSrvCall->RxDeviceObject->Dispatch,
  2282. MRxIsValidDirectory,
  2283. (RxContext,&RemainingName) );
  2284. }
  2285. if (Status == STATUS_SUCCESS) {
  2286. PV_NET_ROOT VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
  2287. RxReferenceVNetRoot(VNetRoot);
  2288. if (InterlockedCompareExchange( &VNetRoot->AdditionalReferenceForDeleteFsctlTaken, 1, 0) != 0) {
  2289. //
  2290. // The net use connections have a two phase delete protocol. An FSCTL to
  2291. // delete the connection is used followed by a close of the corresponding file
  2292. // object. The additional reference ensures that the finalization is delayed till
  2293. // the actual close of the corresponding file object.
  2294. //
  2295. RxDereferenceVNetRoot( VNetRoot, LHS_LockNotHeld );
  2296. }
  2297. FileObject->FsContext = &RxDeviceFCB;
  2298. FileObject->FsContext2 = RxContext->Create.pVNetRoot;
  2299. VNetRoot->IsExplicitConnection = TRUE;
  2300. RxContext->Create.pVNetRoot->NumberOfOpens += 1;
  2301. RxContext->Create.pVNetRoot = NULL;
  2302. RxContext->Create.pNetRoot = NULL;
  2303. RxContext->Create.pSrvCall = NULL;
  2304. }
  2305. RxDbgTrace(-1, Dbg, ("RxCreateTreeConnect exit, status=%08lx\n", Status));
  2306. return Status;
  2307. }
  2308. NTSTATUS
  2309. RxPrepareToReparseSymbolicLink(
  2310. IN PRX_CONTEXT RxContext,
  2311. IN BOOLEAN SymbolicLinkEmbeddedInOldPath,
  2312. IN PUNICODE_STRING NewPath,
  2313. IN BOOLEAN NewPathIsAbsolute,
  2314. OUT PBOOLEAN ReparseRequired
  2315. )
  2316. /*++
  2317. Routine Description:
  2318. This routine sets up the file object name to facilitate a reparse. This routine
  2319. is used by the mini redirectors to traverse symbolic links.
  2320. Arguments:
  2321. RxContext - the RDBSS context
  2322. SymbolicLinkEmbeddedInOldPath - if TRUE a symbolic link was encountered as part of the
  2323. traversal of the old path.
  2324. NewPath - the new path name to be traversed.
  2325. NewPathIsAbsolute - if FALSE, \Device\Mup should be prepended to NewPath. If TRUE,
  2326. NewPath is the full path to which to reparse. In this case, the buffer
  2327. containing NewPath is used directly, rather than allocating a new one.
  2328. ReparseRequired - set to TRUE if Reparse is required.
  2329. Return Value:
  2330. NTSTATUS - the return status for the operation
  2331. Notes:
  2332. The second parameter passed to this routine is a very important one. In order
  2333. to preserve the correct semantics it should be carefully used. As an example
  2334. consider the old path \A\B\C\D wherein C happens to be symbolic link. In such
  2335. cases the symbolic link is embedded in the path as opposed to the case when
  2336. D happens to be a symbolic link. In the former case the reparse constitutes
  2337. an intermediate step as opposed to the later case when it constitutes the
  2338. final step of the name resolution.
  2339. If DELETE access is specified the OPEN is denied for all in which the symbolic
  2340. link is not embedded. It is possible that if DELETE access were the only one
  2341. specified then the OPEN attempt must succeed without reparse. This will be
  2342. conformant with UNIX symbolic link semantics.
  2343. As part of this routine the RxContext is also tagged appropriately. This ensures
  2344. that the return value can be crosschecked with the invocation of this routine.
  2345. Once this routine is invoked the mini rdr has to return STATUS_REPARSE.
  2346. The value of *ReparseRequired assumes significance only if STATUS_SUCCESS is
  2347. returned from this routine. FALSE implies that no reparse attempt is required
  2348. and the symbolic link file itself should be manipulated as opposed to the
  2349. target of the link. TRUE implies that a reparse attempt was successfully setup.
  2350. In such cases it is imperative that the mini redirector return STATUS_REPARSE
  2351. for the associated MRxCreate call. The wrapper will initiate a check for this.
  2352. --*/
  2353. {
  2354. NTSTATUS Status = STATUS_SUCCESS;
  2355. PFILE_OBJECT FileObject = IoGetCurrentIrpStackLocation( RxContext->CurrentIrp )->FileObject;
  2356. *ReparseRequired = FALSE;
  2357. if (RxContext->MajorFunction == IRP_MJ_CREATE) {
  2358. ACCESS_MASK DesiredAccess = RxContext->Create.NtCreateParameters.DesiredAccess;
  2359. //
  2360. // Check the Create Parameters to determine the type of ACCESS specified.
  2361. // if only DELETE access was specified then no reparse is required and the
  2362. // operation is to be performed on the link itself.
  2363. //
  2364. if (!SymbolicLinkEmbeddedInOldPath) {
  2365. RxDbgTrace( 0, Dbg, ("Desired Access In Reparse %lx\n",DesiredAccess) );
  2366. if (FlagOn( DesiredAccess, DELETE )) {
  2367. *ReparseRequired = FALSE;
  2368. if (FlagOn( DesiredAccess, ~DELETE )) {
  2369. Status = STATUS_ACCESS_DENIED;
  2370. }
  2371. } else {
  2372. //
  2373. // If the appropriate flags were specified in the CREATE parameters then
  2374. // the reparse is to be suppressed since the intention is to open the link
  2375. // itself as opposed to the TARGET.
  2376. // TBD. -- The exact combination of flags will be determined for NT 5.0.
  2377. //
  2378. //
  2379. // If none of the above conditions were satisfied then the reparse is required
  2380. //
  2381. *ReparseRequired = TRUE;
  2382. }
  2383. } else {
  2384. *ReparseRequired = TRUE;
  2385. }
  2386. if (*ReparseRequired) {
  2387. PWSTR FileNameBuffer;
  2388. USHORT DeviceNameLength;
  2389. USHORT ReparsePathLength;
  2390. if (!NewPathIsAbsolute) {
  2391. DeviceNameLength = wcslen( DD_MUP_DEVICE_NAME ) * sizeof(WCHAR);
  2392. //
  2393. // On a reparse attempt the I/O subsystem will null out the related file
  2394. // object field.
  2395. //
  2396. ReparsePathLength = (DeviceNameLength + NewPath->Length);
  2397. FileNameBuffer = ExAllocatePoolWithTag( PagedPool | POOL_COLD_ALLOCATION,
  2398. ReparsePathLength,
  2399. RX_MISC_POOLTAG );
  2400. if (FileNameBuffer != NULL) {
  2401. //
  2402. // Copy the device name
  2403. //
  2404. RtlCopyMemory( FileNameBuffer, DD_MUP_DEVICE_NAME, DeviceNameLength );
  2405. //
  2406. // Copy the new name
  2407. //
  2408. RtlCopyMemory( Add2Ptr( FileNameBuffer, DeviceNameLength ), NewPath->Buffer, NewPath->Length );
  2409. } else {
  2410. Status = STATUS_INSUFFICIENT_RESOURCES;
  2411. }
  2412. } else {
  2413. FileNameBuffer = NewPath->Buffer;
  2414. ReparsePathLength = NewPath->Length;
  2415. }
  2416. //
  2417. // Free up the buffer associated with the old name.
  2418. //
  2419. ExFreePool( FileObject->FileName.Buffer );
  2420. //
  2421. // Set up the file object with the new name.
  2422. //
  2423. FileObject->FileName.Buffer = FileNameBuffer;
  2424. FileObject->FileName.Length = ReparsePathLength;
  2425. FileObject->FileName.MaximumLength = FileObject->FileName.Length;
  2426. //
  2427. // Mark the RxContext so that the return code can be verified. A mini
  2428. // redirector has to return STATUS_REPARSE is this routine was invoked
  2429. // as a response to MRxCreate. This will be enforced by marking the
  2430. // RxContext appropriately and comparing the returned status code against
  2431. // the expected value.
  2432. //
  2433. SetFlag( RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE );
  2434. }
  2435. } else {
  2436. Status = STATUS_INVALID_PARAMETER;
  2437. }
  2438. RxDbgTrace(0, Dbg, ("RxPrepareToReparseSymbolicLink : ReparseReqd: %lx, Status %lx\n",*ReparseRequired,Status));
  2439. return Status;
  2440. }
  2441. NTSTATUS
  2442. RxCommonCreate (
  2443. IN PRX_CONTEXT RxContext,
  2444. IN PIRP Irp
  2445. )
  2446. /*++
  2447. Routine Description:
  2448. This is the common routine for creating/opening a file called by
  2449. both the fsd and fsp threads.
  2450. Arguments:
  2451. Irp - Supplies the Irp to process
  2452. Return Value:
  2453. RXSTATUS - the return status for the operation
  2454. --*/
  2455. {
  2456. NTSTATUS Status;
  2457. ULONG Disposition;
  2458. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2459. PFILE_OBJECT FileObject = IrpSp->FileObject;
  2460. UNICODE_STRING RemainingName;
  2461. PAGED_CODE();
  2462. #if 0 && defined(REMOTE_BOOT)
  2463. {
  2464. PWCH buffer = ExAllocatePoolWithTag( NonPagedPool, FileObject->FileName.Length + 2,RX_MISC_POOLTAG );
  2465. BOOLEAN watchFile = FALSE;
  2466. BOOLEAN logFile = FALSE;
  2467. if ( buffer != NULL ) {
  2468. RtlCopyMemory( buffer, FileObject->FileName.Buffer, FileObject->FileName.Length );
  2469. buffer[FileObject->FileName.Length/sizeof(WCHAR)] = 0;
  2470. if (WatchAllFiles) watchFile = TRUE;
  2471. if (watchFile && (!FirstWatchOnly || IsFirstWatch) ) {
  2472. logFile = TRUE;
  2473. IsFirstWatch = FALSE;
  2474. }
  2475. if (LogAllFiles) logFile = TRUE;
  2476. if (logFile) {
  2477. DbgPrint( "RxCommonCreate: create IRP for %ws %x\n", buffer, FileObject );
  2478. }
  2479. ExFreePool(buffer);
  2480. }
  2481. }
  2482. #endif // defined(REMOTE_BOOT)
  2483. //
  2484. // check for the case of a device open; if so, handle and get out now
  2485. //
  2486. if ((FileObject->FileName.Length == 0) && (FileObject->RelatedFileObject == NULL)) {
  2487. //
  2488. // here we are just opening the device; set the FsContext&counts and get out
  2489. //
  2490. FileObject->FsContext = &RxDeviceFCB;
  2491. FileObject->FsContext2 = NULL;
  2492. RxDeviceFCB.OpenCount += 1;
  2493. RxDeviceFCB.UncleanCount += 1;
  2494. Irp->IoStatus.Information = FILE_OPENED;
  2495. RxDbgTrace( 0, Dbg, ("RxDeviceCreate, File = %08lx\n", FileObject) );
  2496. RxLog(( "DevOpen %lx %lx %lx", RxContext, FileObject, RxContext->RxDeviceObject ));
  2497. RxLog(( "DevOpen2 %wZ", &RxContext->RxDeviceObject->DeviceName));
  2498. RxWmiLog( LOG,
  2499. RxCommonCreate_1,
  2500. LOGPTR(RxContext)
  2501. LOGPTR(FileObject)
  2502. LOGPTR(RxContext->RxDeviceObject)
  2503. LOGUSTR(RxContext->RxDeviceObject->DeviceName) );
  2504. return STATUS_SUCCESS;
  2505. }
  2506. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_STRUCTURED_STORAGE ) == FILE_STRUCTURED_STORAGE) {
  2507. //
  2508. // Deprecated open type
  2509. //
  2510. return STATUS_INVALID_PARAMETER;
  2511. }
  2512. //
  2513. // Init the file name that will trigger the trace to start.
  2514. // To trigger on a different file edit DbgTriggerName with debugger (don't
  2515. // forget the null). Set DbgTriggerIrpCount to number of IRPs to trace and
  2516. // then set DbgTriggerState to 0.
  2517. //
  2518. RxDbgTraceDoit(
  2519. if (DbgTriggerState == DBG_TRIGGER_INIT) {
  2520. NTSTATUS Status;
  2521. DbgTriggerState = DBG_TRIGGER_LOOKING;
  2522. DbgTriggerNameStr.Length = (USHORT)strlen( DbgTriggerName );
  2523. DbgTriggerNameStr.MaximumLength = (USHORT)strlen( DbgTriggerName );
  2524. DbgTriggerNameStr.Buffer = &DbgTriggerName[0];
  2525. Status = RtlAnsiStringToUnicodeString( &DbgTriggerUStr, &DbgTriggerNameStr, TRUE );
  2526. if (STATUS_SUCCESS != Staus) {
  2527. DbgTriggerState == DBG_TRIGGER_INIT;
  2528. }
  2529. }
  2530. );
  2531. //
  2532. // If we find a match on the open file name the enable tracing for the
  2533. // next DbgTriggerIrpCount's worth of IRPs.
  2534. //
  2535. RxDbgTraceDoit(
  2536. if ((DbgTriggerState == DBG_TRIGGER_LOOKING) &&
  2537. RtlEqualUnicodeString( &DbgTriggerUStr, &FileObject->FileName, TRUE )) {
  2538. DbgTriggerState = DBG_TRIGGER_FOUND;
  2539. RxGlobalTraceIrpCount = DbgTriggerIrpCount;
  2540. RxGlobalTraceSuppress = FALSE;
  2541. }
  2542. );
  2543. RxDbgTrace( +1, Dbg, ("RxCommonCreate\n", 0 ));
  2544. RxDbgTrace( 0, Dbg, ("Irp = %08lx\n", IrpSp ));
  2545. RxDbgTrace( 0, Dbg, ("->IrpFlags = %08lx\n", IrpSp->Flags ));
  2546. RxDbgTrace( 0, Dbg, ("->FileObject(Related) = %08lx %08lx\n", // ok4->FileObj
  2547. FileObject,
  2548. FileObject->RelatedFileObject ));
  2549. RxDbgTrace( 0, Dbg, (" ->FileName = (%lx) %wZ\n",
  2550. FileObject->FileName.Length,
  2551. &FileObject->FileName ));
  2552. RxDbgTrace( 0, Dbg, ("->AllocationSize(Lo/Hi) = %08lx %08lx\n",
  2553. Irp->Overlay.AllocationSize.LowPart,
  2554. Irp->Overlay.AllocationSize.HighPart ));
  2555. RxDbgTrace( 0, Dbg, ("->DesiredAccess/Options = %08lx %08lx\n",
  2556. IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
  2557. IrpSp->Parameters.Create.Options ));
  2558. RxDbgTrace( 0, Dbg, ("->Attribs/ShrAccess/SPFlags= %04x %04lx %08lx\n",
  2559. IrpSp->Parameters.Create.FileAttributes,
  2560. IrpSp->Parameters.Create.ShareAccess,
  2561. IrpSp->Flags ));
  2562. RxLog(( "Open %lx %lx %lx %lx %lx %lx %lx\n",
  2563. RxContext,FileObject, //1,2
  2564. IrpSp->Parameters.Create.Options,
  2565. IrpSp->Flags,
  2566. IrpSp->Parameters.Create.FileAttributes,
  2567. IrpSp->Parameters.Create.ShareAccess,
  2568. IrpSp->Parameters.Create.SecurityContext->DesiredAccess ));
  2569. RxWmiLog( LOG,
  2570. RxCommonCreate_2,
  2571. LOGPTR(RxContext)
  2572. LOGPTR(FileObject)
  2573. LOGULONG(IrpSp->Parameters.Create.Options)
  2574. LOGUCHAR(IrpSp->Flags)
  2575. LOGXSHORT(IrpSp->Parameters.Create.FileAttributes)
  2576. LOGXSHORT(IrpSp->Parameters.Create.ShareAccess)
  2577. LOGULONG(IrpSp->Parameters.Create.SecurityContext->DesiredAccess));
  2578. RxLog(( " fn %wZ\n", &FileObject->FileName));
  2579. RxWmiLog( LOG,
  2580. RxCommonCreate_3,
  2581. LOGUSTR(FileObject->FileName));
  2582. if (FileObject->RelatedFileObject){
  2583. PFCB RelatedFcb = (PFCB)(FileObject->RelatedFileObject->FsContext);
  2584. RxDbgTrace( 0, Dbg, (" ->RelatedFileName = %wZ\n",
  2585. &(RelatedFcb->FcbTableEntry.Path) ));
  2586. RxLog(( " relat %lx %wZ\n",
  2587. FileObject->RelatedFileObject,
  2588. &(RelatedFcb->FcbTableEntry.Path) ));
  2589. RxWmiLog( LOG,
  2590. RxCommonCreate_4,
  2591. LOGPTR(FileObject->RelatedFileObject)
  2592. LOGUSTR(RelatedFcb->FcbTableEntry.Path));
  2593. }
  2594. if (FlagOn( IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY )) {
  2595. RxDbgTrace( 0, Dbg, (" ->OpenTargetDirectory\n"));
  2596. RxLog((" OpenTargetDir!\n"));
  2597. RxWmiLog(LOG,
  2598. RxCommonCreate_5,
  2599. LOGULONG(Status));
  2600. }
  2601. RxCopyCreateParameters( RxContext );
  2602. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION )) {
  2603. Status = RxCreateTreeConnect( RxContext );
  2604. } else {
  2605. //
  2606. //
  2607. //
  2608. // It's here because Mark says he can't avoid sending me double beginning
  2609. // backslashes in the Win32 layer.
  2610. //
  2611. if ((FileObject->FileName.Length > sizeof(WCHAR)) &&
  2612. (FileObject->FileName.Buffer[1] == L'\\') &&
  2613. (FileObject->FileName.Buffer[0] == L'\\')) {
  2614. FileObject->FileName.Length -= sizeof(WCHAR);
  2615. RtlMoveMemory( &FileObject->FileName.Buffer[0], &FileObject->FileName.Buffer[1], FileObject->FileName.Length );
  2616. //
  2617. // If there are still two beginning backslashes, the name is bogus.
  2618. //
  2619. if ((FileObject->FileName.Length > sizeof(WCHAR)) &&
  2620. (FileObject->FileName.Buffer[1] == L'\\') &&
  2621. (FileObject->FileName.Buffer[0] == L'\\')) {
  2622. RxDbgTrace(-1, Dbg, ("RxCommonCreate -> OBJECT_NAME_INVALID[slashes]\n)", 0));
  2623. return STATUS_OBJECT_NAME_INVALID;
  2624. }
  2625. }
  2626. do {
  2627. //
  2628. // If the file name has a trailing \, and the request is to
  2629. // operate on a file (not a directory), then the file name is
  2630. // invalid.
  2631. //
  2632. if ((FileObject->FileName.Length > 0) &&
  2633. (FileObject->FileName.Buffer[(FileObject->FileName.Length/sizeof(WCHAR))-1] == L'\\')) {
  2634. ULONG Options = IrpSp->Parameters.Create.Options;
  2635. if (MustBeFile( Options )) {
  2636. RxDbgTrace( -1, Dbg, ("RxCommonCreate -> OBJECT_NAME_INVALID[trailing+MBFile]\n)", 0));
  2637. Status = STATUS_OBJECT_NAME_INVALID;
  2638. return Status;
  2639. }
  2640. FileObject->FileName.Length -= sizeof(WCHAR);
  2641. SetFlag( RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH );
  2642. }
  2643. //
  2644. // If we have Write Through set in the FileObject, then set the FileObject
  2645. // flag as well, so that the fast write path call to FsRtlCopyWrite
  2646. // knows it is Write Through.
  2647. //
  2648. if (FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH )) {
  2649. SetFlag( FileObject->Flags, FO_WRITE_THROUGH );
  2650. }
  2651. //
  2652. // Convert the name to its canonical form, i.e. without . and .. and with the luid
  2653. // on the front as appropriate. try to avoid a pool operation by using an stack-based buffer
  2654. //
  2655. Status = RxCanonicalizeNameAndObtainNetRoot( RxContext,
  2656. Irp,
  2657. &FileObject->FileName,
  2658. &RemainingName );
  2659. if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
  2660. RxDbgTrace( 0, Dbg, ("RxCommonCreate -> Couldn't canonicalize %08lx\n", Status ));
  2661. } else {
  2662. RxDbgTrace( 0, Dbg, ("RxCommonCreate NetRootGoodWasGood status =%08lx\n", Status ));
  2663. Status = RxCreateFromNetRoot( RxContext, Irp, &RemainingName );
  2664. RxDbgTrace(0, Dbg, ("RxCommonCreate RxCreateFromNetRoot status =%08lx\n", Status));
  2665. switch (Status) {
  2666. case STATUS_SHARING_VIOLATION:
  2667. Disposition = RxContext->Create.NtCreateParameters.Disposition;
  2668. ASSERT( !FlagOn( RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE ));
  2669. if (Disposition != FILE_CREATE) {
  2670. if (RxContext->Create.TryForScavengingOnSharingViolation &&
  2671. !RxContext->Create.ScavengingAlreadyTried &&
  2672. RxContext->Create.pVNetRoot != NULL) {
  2673. PV_NET_ROOT VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
  2674. NT_CREATE_PARAMETERS NtCreateParameters = RxContext->Create.NtCreateParameters;
  2675. NTSTATUS PurgeStatus;
  2676. //
  2677. // Reference the VNetRoot instance. Reinitialize
  2678. // the context ( this will drop the FCB if it has
  2679. // been accquired. purge the FOBX's related to the
  2680. // NET_ROOT instance and resume the create
  2681. // operation if it was sucssesful
  2682. //
  2683. RxReferenceVNetRoot( VNetRoot );
  2684. //
  2685. // reinitialize the context
  2686. //
  2687. RxpPrepareCreateContextForReuse( RxContext );
  2688. RxReinitializeContext( RxContext );
  2689. //
  2690. // Reinitialize the Create parameters.
  2691. //
  2692. RxContext->Create.NtCreateParameters = NtCreateParameters;
  2693. RxCopyCreateParameters( RxContext );
  2694. PurgeStatus = RxPurgeRelatedFobxs( VNetRoot->NetRoot,
  2695. RxContext,
  2696. DONT_ATTEMPT_FINALIZE_ON_PURGE,
  2697. NULL );
  2698. //
  2699. // Map the SUCCESS code for continuation
  2700. //
  2701. Status = STATUS_MORE_PROCESSING_REQUIRED;
  2702. RxContext->Create.ScavengingAlreadyTried = TRUE;
  2703. //
  2704. // Ensure that any buffering state change pending
  2705. // requests have been processed. This will cover the
  2706. // cases when owing to processing delays the oplock
  2707. // response did not make it to the server and it
  2708. // returned SHARING_VIOLATION.
  2709. //
  2710. {
  2711. PSRV_CALL SrvCall = VNetRoot->NetRoot->SrvCall;
  2712. RxReferenceSrvCall( SrvCall );
  2713. RxpProcessChangeBufferingStateRequests( SrvCall,
  2714. FALSE ); // do not update handler state
  2715. }
  2716. //
  2717. // Drop the reference on the V_NET_ROOT instance
  2718. //
  2719. RxDereferenceVNetRoot( VNetRoot, LHS_LockNotHeld );
  2720. }
  2721. } else {
  2722. Status = STATUS_OBJECT_NAME_COLLISION;
  2723. }
  2724. break;
  2725. case STATUS_REPARSE:
  2726. //
  2727. // Ensure that the IRP is approrpiately marked for reparsing.
  2728. //
  2729. RxContext->CurrentIrp->IoStatus.Information = IO_REPARSE;
  2730. RxDbgTrace( 0, Dbg, ("RxCommonCreate(Reparse) IRP %lx New Name %wZ status =%08lx\n",
  2731. Irp,&FileObject->FileName, Status) );
  2732. break;
  2733. default:
  2734. ASSERT( !FlagOn( RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE ));
  2735. break;
  2736. }
  2737. }
  2738. } while (Status == STATUS_MORE_PROCESSING_REQUIRED);
  2739. }
  2740. if (Status == STATUS_RETRY) {
  2741. RxpPrepareCreateContextForReuse( RxContext );
  2742. }
  2743. ASSERT( Status != STATUS_PENDING );
  2744. RxDbgTraceUnIndent( -1, Dbg );
  2745. #if 0 && defined(REMOTE_BOOT)
  2746. if ( LogAllFiles ) {
  2747. DbgPrint( "RxCommonCreate: status %x creating %wZ %x %x\n", Status, &FileObject->FileName, FileObject, FileObject->FsContext );
  2748. }
  2749. #endif
  2750. return Status;
  2751. }
  2752. //
  2753. // these next routines are essentially just copies of the same routines from io\iosubs.c
  2754. // I cannot just use them directly because they make all sorts of assumptions about wanting to
  2755. // update the file object
  2756. //
  2757. #define RxSetAccessVariables(xxx) {\
  2758. ReadAccess = (BOOLEAN) ((DesiredAccess & (FILE_EXECUTE | FILE_READ_DATA)) != 0); \
  2759. WriteAccess = (BOOLEAN) ((DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0); \
  2760. DeleteAccess = (BOOLEAN) ((DesiredAccess & DELETE) != 0); \
  2761. }
  2762. #define RxSetShareVariables(xxx) {\
  2763. SharedRead = (BOOLEAN) ((DesiredShareAccess & FILE_SHARE_READ) != 0); \
  2764. SharedWrite = (BOOLEAN) ((DesiredShareAccess & FILE_SHARE_WRITE) != 0); \
  2765. SharedDelete = (BOOLEAN) ((DesiredShareAccess & FILE_SHARE_DELETE) != 0); \
  2766. }
  2767. #if DBG
  2768. VOID
  2769. RxDumpWantedAccess(
  2770. PSZ where1,
  2771. PSZ where2,
  2772. PSZ wherelogtag,
  2773. IN ACCESS_MASK DesiredAccess,
  2774. IN ULONG DesiredShareAccess
  2775. )
  2776. {
  2777. BOOLEAN ReadAccess,WriteAccess,DeleteAccess;
  2778. BOOLEAN SharedRead,SharedWrite,SharedDelete;
  2779. RxSetAccessVariables(SrvOpen);
  2780. RxSetShareVariables(SrvOpen);
  2781. PAGED_CODE();
  2782. //(VOID)(DbgPrint
  2783. RxDbgTrace(0, (DEBUG_TRACE_SHAREACCESS),
  2784. ("%s%s wanted = %s%s%s:%s%s%s\n", where1,where2,
  2785. ReadAccess?"R":"",
  2786. WriteAccess?"W":"",
  2787. DeleteAccess?"D":"",
  2788. SharedRead?"SR":"",
  2789. SharedWrite?"SW":"",
  2790. SharedDelete?"SD":""
  2791. ));
  2792. RxLogForSharingCheck(
  2793. ("%s%s wanted = %s%s%s:%s%s%s\n", wherelogtag, where2,
  2794. ReadAccess?"R":"",
  2795. WriteAccess?"W":"",
  2796. DeleteAccess?"D":"",
  2797. SharedRead?"SR":"",
  2798. SharedWrite?"SW":"",
  2799. SharedDelete?"SD":""
  2800. ));
  2801. }
  2802. VOID
  2803. RxDumpCurrentAccess (
  2804. PSZ where1,
  2805. PSZ where2,
  2806. PSZ wherelogtag,
  2807. PSHARE_ACCESS ShareAccess
  2808. )
  2809. {
  2810. PAGED_CODE();
  2811. // (VOID)(DbgPrint
  2812. RxDbgTrace(0, (DEBUG_TRACE_SHAREACCESS),
  2813. ("%s%s current = %d[%d][%d][%d]:[%d][%d][%d]\n", where1, where2,
  2814. ShareAccess->OpenCount,
  2815. ShareAccess->Readers,
  2816. ShareAccess->Writers,
  2817. ShareAccess->Deleters,
  2818. ShareAccess->SharedRead,
  2819. ShareAccess->SharedWrite,
  2820. ShareAccess->SharedDelete
  2821. ));
  2822. RxLogForSharingCheck(
  2823. ("%s%s current = %d[%d][%d][%d]:[%d][%d][%d]\n", wherelogtag, where2,
  2824. ShareAccess->OpenCount,
  2825. ShareAccess->Readers,
  2826. ShareAccess->Writers,
  2827. ShareAccess->Deleters,
  2828. ShareAccess->SharedRead,
  2829. ShareAccess->SharedWrite,
  2830. ShareAccess->SharedDelete
  2831. ));
  2832. }
  2833. NTSTATUS
  2834. RxCheckShareAccess (
  2835. IN ACCESS_MASK DesiredAccess,
  2836. IN ULONG DesiredShareAccess,
  2837. IN OUT PFILE_OBJECT FileObject,
  2838. IN OUT PSHARE_ACCESS ShareAccess,
  2839. IN BOOLEAN Update,
  2840. IN PSZ where,
  2841. IN PSZ wherelogtag
  2842. )
  2843. {
  2844. NTSTATUS Status;
  2845. PAGED_CODE();
  2846. RxDumpWantedAccess(where,"",wherelogtag,
  2847. DesiredAccess,DesiredShareAccess
  2848. );
  2849. RxDumpCurrentAccess(where,"",wherelogtag,ShareAccess);
  2850. Status = IoCheckShareAccess( DesiredAccess,
  2851. DesiredShareAccess,
  2852. FileObject,
  2853. ShareAccess,
  2854. Update);
  2855. return(Status);
  2856. }
  2857. VOID
  2858. RxRemoveShareAccess (
  2859. IN PFILE_OBJECT FileObject,
  2860. IN OUT PSHARE_ACCESS ShareAccess,
  2861. IN PSZ where,
  2862. IN PSZ wherelogtag
  2863. )
  2864. {
  2865. PAGED_CODE();
  2866. RxDumpCurrentAccess( where, "before", wherelogtag, ShareAccess );
  2867. IoRemoveShareAccess( FileObject, ShareAccess );
  2868. RxDumpCurrentAccess( where, "after", wherelogtag, ShareAccess );
  2869. }
  2870. VOID
  2871. RxSetShareAccess (
  2872. IN ACCESS_MASK DesiredAccess,
  2873. IN ULONG DesiredShareAccess,
  2874. IN OUT PFILE_OBJECT FileObject,
  2875. OUT PSHARE_ACCESS ShareAccess,
  2876. IN PSZ where,
  2877. IN PSZ wherelogtag
  2878. )
  2879. {
  2880. PAGED_CODE();
  2881. RxDumpCurrentAccess( where, "before", wherelogtag, ShareAccess );
  2882. IoSetShareAccess( DesiredAccess, DesiredShareAccess, FileObject, ShareAccess);
  2883. RxDumpCurrentAccess( where, "after",wherelogtag, ShareAccess);
  2884. }
  2885. VOID
  2886. RxUpdateShareAccess (
  2887. IN PFILE_OBJECT FileObject,
  2888. IN OUT PSHARE_ACCESS ShareAccess,
  2889. IN PSZ where,
  2890. IN PSZ wherelogtag
  2891. )
  2892. {
  2893. PAGED_CODE();
  2894. RxDumpCurrentAccess( where, "before", wherelogtag, ShareAccess);
  2895. IoUpdateShareAccess( FileObject, ShareAccess );
  2896. RxDumpCurrentAccess( where, "after", wherelogtag, ShareAccess );
  2897. }
  2898. #endif
  2899. NTSTATUS
  2900. RxCheckShareAccessPerSrvOpens (
  2901. IN PFCB Fcb,
  2902. IN ACCESS_MASK DesiredAccess,
  2903. IN ULONG DesiredShareAccess
  2904. )
  2905. /*++
  2906. Routine Description:
  2907. This routine is invoked to determine whether or not a new accessor to
  2908. a file actually has shared access to it. The check is made according
  2909. to:
  2910. 1) How the file is currently opened.
  2911. 2) What types of shared accesses are currently specified.
  2912. 3) The desired and shared accesses that the new open is requesting.
  2913. This check is made against the sharing state represented by the actual SrvOpens
  2914. on an Fcb so that we know whether we have to initiate close-behind.
  2915. Arguments:
  2916. DesiredAccess - Desired access of current open request.
  2917. DesiredShareAccess - Shared access requested by current open request.
  2918. Fcb - Pointer to the file object of the current open request.
  2919. Return Value:
  2920. The final status of the access check is the function value. If the
  2921. accessor has access to the file, STATUS_SUCCESS is returned. Otherwise,
  2922. STATUS_SHARING_VIOLATION is returned.
  2923. Note:
  2924. Note that the ShareAccess parameter must be locked against other accesses
  2925. from other threads while this routine is executing. Otherwise the counts
  2926. will be out-of-synch.
  2927. --*/
  2928. {
  2929. ULONG ocount;
  2930. PSHARE_ACCESS ShareAccess = &Fcb->ShareAccessPerSrvOpens;
  2931. BOOLEAN ReadAccess,WriteAccess,DeleteAccess;
  2932. BOOLEAN SharedRead,SharedWrite,SharedDelete;
  2933. PAGED_CODE();
  2934. //
  2935. // Set the access type in the file object for the current accessor.
  2936. // Note that reading and writing attributes are not included in the
  2937. // access check.
  2938. //
  2939. RxSetAccessVariables( SrvOpen );
  2940. //
  2941. // There is no more work to do unless the user specified one of the
  2942. // sharing modes above.
  2943. //
  2944. if (ReadAccess || WriteAccess || DeleteAccess) {
  2945. RxSetShareVariables( SrvOpen );
  2946. RxDumpWantedAccess("RxCheckShareAccessPerSrvOpens","","AccChkPerSO",
  2947. DesiredAccess,DesiredShareAccess
  2948. );
  2949. RxDumpCurrentAccess("RxCheckShareAccessPerSrvOpens","","AccChkPerSO",ShareAccess);
  2950. //
  2951. // Now check to see whether or not the desired accesses are compatible
  2952. // with the way that the file is currently open.
  2953. //
  2954. ocount = ShareAccess->OpenCount;
  2955. if ((ReadAccess && (ShareAccess->SharedRead < ocount)) ||
  2956. (WriteAccess && (ShareAccess->SharedWrite < ocount)) ||
  2957. (DeleteAccess && (ShareAccess->SharedDelete < ocount)) ||
  2958. ((ShareAccess->Readers != 0) && !SharedRead) ||
  2959. ((ShareAccess->Writers != 0) && !SharedWrite) ||
  2960. ((ShareAccess->Deleters != 0) && !SharedDelete)) {
  2961. //
  2962. // The check failed. Simply return to the caller indicating that the
  2963. // current open cannot access the file.
  2964. //
  2965. return STATUS_SHARING_VIOLATION;
  2966. }
  2967. }
  2968. return STATUS_SUCCESS;
  2969. }
  2970. VOID
  2971. RxUpdateShareAccessPerSrvOpens (
  2972. IN PSRV_OPEN SrvOpen
  2973. )
  2974. /*++
  2975. Routine Description:
  2976. This routine is invoked to update the access information about how the
  2977. file is currently opened by introducing the contribution of this srvopen. the wrapper
  2978. actually keeps up with two states: (a) the access state according to the files that the user
  2979. can see, and (b) the access state according to the srvopens on the file. this rouinte manipulates
  2980. the latter.
  2981. Arguments:
  2982. Return Value:
  2983. Note:
  2984. Note that the ShareAccess parameter must be locked against other accesses
  2985. from other threads while this routine is executing. Otherwise the counts
  2986. will be out-of-synch.
  2987. --*/
  2988. {
  2989. PSHARE_ACCESS ShareAccess = &SrvOpen->Fcb->ShareAccessPerSrvOpens;
  2990. BOOLEAN ReadAccess,WriteAccess,DeleteAccess;
  2991. BOOLEAN SharedRead,SharedWrite,SharedDelete;
  2992. ACCESS_MASK DesiredAccess = SrvOpen->DesiredAccess;
  2993. ULONG DesiredShareAccess = SrvOpen->ShareAccess;
  2994. PAGED_CODE();
  2995. if (!FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED )) {
  2996. //
  2997. // Set the access type in the file object for the current accessor.
  2998. // Note that reading and writing attributes are not included in the
  2999. // access check.
  3000. //
  3001. RxSetAccessVariables( SrvOpen );
  3002. //
  3003. // There is no more work to do unless the user specified one of the
  3004. // sharing modes above.
  3005. //
  3006. if (ReadAccess || WriteAccess || DeleteAccess) {
  3007. RxSetShareVariables( SrvOpen );
  3008. RxDumpWantedAccess( "RxUpdateShareAccessPerSrvOpens", "", "AccUpdPerSO", DesiredAccess, DesiredShareAccess );
  3009. RxDumpCurrentAccess( "RxUpdateShareAccessPerSrvOpens", "", "AccUpdPerSO", ShareAccess );
  3010. ShareAccess->OpenCount += 1;
  3011. ShareAccess->Readers += ReadAccess;
  3012. ShareAccess->Writers += WriteAccess;
  3013. ShareAccess->Deleters += DeleteAccess;
  3014. ShareAccess->SharedRead += SharedRead;
  3015. ShareAccess->SharedWrite += SharedWrite;
  3016. ShareAccess->SharedDelete += SharedDelete;
  3017. }
  3018. SetFlag( SrvOpen->Flags, SRVOPEN_FLAG_SHAREACCESS_UPDATED );
  3019. }
  3020. }
  3021. VOID
  3022. RxRemoveShareAccessPerSrvOpens (
  3023. IN OUT PSRV_OPEN SrvOpen
  3024. )
  3025. /*++
  3026. Routine Description:
  3027. This routine is invoked to remove the access and share access information
  3028. in a file system Share Access structure for a given open instance.
  3029. Arguments:
  3030. ShareAccess - Pointer to the share access structure that describes
  3031. how the file is currently being accessed.
  3032. Return Value:
  3033. None.
  3034. --*/
  3035. {
  3036. PSHARE_ACCESS ShareAccess = &SrvOpen->Fcb->ShareAccessPerSrvOpens;
  3037. BOOLEAN ReadAccess,WriteAccess,DeleteAccess;
  3038. BOOLEAN SharedRead,SharedWrite,SharedDelete;
  3039. ACCESS_MASK DesiredAccess = SrvOpen->DesiredAccess;
  3040. ULONG DesiredShareAccess = SrvOpen->ShareAccess;
  3041. PAGED_CODE();
  3042. //
  3043. // If this accessor wanted some type of access other than READ_ or
  3044. // WRITE_ATTRIBUTES, then account for the fact that he has closed the
  3045. // file. Otherwise, he hasn't been accounted for in the first place
  3046. // so don't do anything.
  3047. //
  3048. RxSetAccessVariables( SrvOpen );
  3049. if (ReadAccess || WriteAccess || DeleteAccess) {
  3050. RxSetShareVariables( SrvOpen );
  3051. RxDumpWantedAccess( "RxRemoveShareAccessPerSrvOpens", "", "AccRemPerSO", DesiredAccess, DesiredShareAccess );
  3052. RxDumpCurrentAccess( "RxRemoveShareAccessPerSrvOpens", "", "AccRemPerSO", ShareAccess);
  3053. //
  3054. // Decrement the number of opens in the Share Access structure.
  3055. //
  3056. ShareAccess->OpenCount -= 1;
  3057. ShareAccess->Readers -= ReadAccess;
  3058. ShareAccess->Writers -= WriteAccess;
  3059. ShareAccess->Deleters -= DeleteAccess;
  3060. ShareAccess->SharedRead -= SharedRead;
  3061. ShareAccess->SharedWrite -= SharedWrite;
  3062. ShareAccess->SharedDelete -= SharedDelete;
  3063. }
  3064. }
  3065. ULONG
  3066. RxGetSessionId (
  3067. IN PIO_STACK_LOCATION IrpSp
  3068. )
  3069. /*++
  3070. Routine Description:
  3071. This routine gets the effective SessionId to be used for this create.
  3072. Arguments:
  3073. SubjectSecurityContext - Supplies the information from IrpSp.
  3074. Return Value:
  3075. None
  3076. --*/
  3077. {
  3078. ULONG SessionId;
  3079. PQUERY_PATH_REQUEST QpReq;
  3080. PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  3081. NTSTATUS Status;
  3082. PAGED_CODE();
  3083. RxDbgTrace(+1, Dbg, ("RxGetSessionId ... \n", 0));
  3084. //
  3085. // If QUERY_PATH_REQUEST, must access from Type3InputBuffer
  3086. // BUGBUG: is this buffer safe to ref?
  3087. //
  3088. if ((IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) &&
  3089. (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)) {
  3090. QpReq = (PQUERY_PATH_REQUEST)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3091. SubjectSecurityContext = &QpReq->SecurityContext->AccessState->SubjectSecurityContext;
  3092. } else if((IrpSp->MajorFunction == IRP_MJ_CREATE) &&
  3093. (IrpSp->Parameters.Create.SecurityContext != NULL)) {
  3094. SubjectSecurityContext = &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext;
  3095. } else {
  3096. //
  3097. // Return 0 for cases we do not handle
  3098. //
  3099. return 0;
  3100. }
  3101. //
  3102. // Use SeQuerySubjetContextToken to get the proper token based on impersonation for use in
  3103. // querying - despite retval SeQuerySessionIdToken always returns success
  3104. //
  3105. Status = SeQuerySessionIdToken( SeQuerySubjectContextToken( SubjectSecurityContext ), &SessionId );
  3106. ASSERT( Status == STATUS_SUCCESS );
  3107. RxDbgTrace(-1, Dbg, (" ->SessionId = %08lx\n", SessionId));
  3108. return SessionId;
  3109. }
  3110. #if 0
  3111. VOID
  3112. RxUpcaseLeadingComponents(
  3113. IN OUT PUNICODE_STRING CanonicalName
  3114. )
  3115. /*++
  3116. Routine Description:
  3117. This routine is called to upcase the leading components of a name. Either 2 or 3 components are
  3118. upcased depending on the name (i.e. whether it's a UNC name or a vnetrootname). the operation is performed
  3119. in place!
  3120. Arguments:
  3121. RxContext - the current workitem
  3122. CanonicalName - the name being canonicalized
  3123. Return Value:
  3124. none
  3125. --*/
  3126. {
  3127. ULONG ComponentsToUpcase,wcLength,i;
  3128. UNICODE_STRING ShortenedCanonicalName;
  3129. PAGED_CODE();
  3130. ComponentsToUpcase = (*(CanonicalName->Buffer+1) == L';')?3:2;
  3131. wcLength = CanonicalName->Length/sizeof(WCHAR);
  3132. for (i=1;;i++) { //note: don't start at zero
  3133. if (i>=wcLength) break;
  3134. if (CanonicalName->Buffer[i]!=OBJ_NAME_PATH_SEPARATOR) continue;
  3135. ComponentsToUpcase--;
  3136. if (ComponentsToUpcase==0) break;
  3137. }
  3138. ShortenedCanonicalName.Buffer = CanonicalName->Buffer;
  3139. ShortenedCanonicalName.MaximumLength = CanonicalName->MaximumLength;
  3140. ShortenedCanonicalName.Length = (USHORT)(i*sizeof(WCHAR));
  3141. RtlUpcaseUnicodeString(&ShortenedCanonicalName,&ShortenedCanonicalName,FALSE); //don't allocate
  3142. RxDbgTrace(0, Dbg, ("RxUpcaseLeadingComponents -> %wZ\n", &ShortenedCanonicalName));
  3143. return;
  3144. }
  3145. #endif //if 0
  3146. #if 0
  3147. UNICODE_STRING InterestingNames[] = {
  3148. 32, 32, L"CreateParent.txt",
  3149. };
  3150. DWORD
  3151. IsInterestingFile(
  3152. PUNICODE_STRING pFileName
  3153. )
  3154. {
  3155. int i;
  3156. for (i=0; i< sizeof(InterestingNames)/sizeof(UNICODE_STRING); ++i)
  3157. {
  3158. if (pFileName->Length > InterestingNames[i].Length)
  3159. {
  3160. UNICODE_STRING uTemp;
  3161. uTemp.Length = uTemp.MaximumLength = InterestingNames[i].Length;
  3162. uTemp.Buffer = pFileName->Buffer + (pFileName->Length - InterestingNames[i].Length)/sizeof(WCHAR);
  3163. if(RtlCompareUnicodeString(&uTemp, &InterestingNames[i], TRUE)==0)
  3164. {
  3165. // DbgPrint("Interesting string %wZ \n", pFileName);
  3166. return i+1;
  3167. }
  3168. }
  3169. }
  3170. return 0;
  3171. }
  3172. #endif