Source code of Windows XP (NT5)
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.

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