Windows NT 4.0 source code leak
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.

1321 lines
33 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. create.c
  5. Abstract:
  6. This module implements the file create routine for the MUP.
  7. Author:
  8. Manny Weiser (mannyw) 16-Dec-1991
  9. Revision History:
  10. --*/
  11. #include "mup.h"
  12. #include "fsrtl.h"
  13. //
  14. // The debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_CREATE)
  17. //
  18. // Local functions
  19. //
  20. NTSTATUS
  21. CreateRedirectedFile(
  22. IN PIRP Irp,
  23. IN PFILE_OBJECT FileObject,
  24. IN PIO_SECURITY_CONTEXT Security
  25. );
  26. NTSTATUS
  27. QueryPathCompletionRoutine (
  28. IN PDEVICE_OBJECT DeviceObject,
  29. IN PIRP Irp,
  30. IN PVOID Context
  31. );
  32. NTSTATUS
  33. MupRerouteOpenToDfs (
  34. IN PFILE_OBJECT FileObject
  35. );
  36. NTSTATUS
  37. BroadcastOpen (
  38. IN PIRP Irp
  39. );
  40. IO_STATUS_BLOCK
  41. OpenMupFileSystem (
  42. IN PVCB Vcb,
  43. IN PFILE_OBJECT FileObject,
  44. IN ACCESS_MASK DesiredAccess,
  45. IN USHORT ShareAccess
  46. );
  47. #ifdef ALLOC_PRAGMA
  48. #pragma alloc_text( PAGE, BroadcastOpen )
  49. #pragma alloc_text( PAGE, CreateRedirectedFile )
  50. #pragma alloc_text( PAGE, MupCreate )
  51. #pragma alloc_text( PAGE, MupRerouteOpen )
  52. #pragma alloc_text( PAGE, MupRerouteOpenToDfs )
  53. #pragma alloc_text( PAGE, OpenMupFileSystem )
  54. #pragma alloc_text( PAGE, QueryPathCompletionRoutine )
  55. #endif
  56. NTSTATUS
  57. MupCreate (
  58. IN PMUP_DEVICE_OBJECT MupDeviceObject,
  59. IN PIRP Irp
  60. )
  61. /*++
  62. Routine Description:
  63. This routine implements the the Create IRP.
  64. Arguments:
  65. MupDeviceObject - Supplies the device object to use.
  66. Irp - Supplies the Irp being processed
  67. Return Value:
  68. NTSTATUS - The status for the IRP.
  69. --*/
  70. {
  71. NTSTATUS status;
  72. PIO_STACK_LOCATION irpSp;
  73. PFILE_OBJECT fileObject;
  74. PFILE_OBJECT relatedFileObject;
  75. STRING fileName;
  76. ACCESS_MASK desiredAccess;
  77. USHORT shareAccess;
  78. BOOLEAN caseInsensitive = TRUE; //**** Make all searches case insensitive
  79. PVCB vcb;
  80. PAGED_CODE();
  81. DebugTrace(+1, Dbg, "MupCreate\n", 0);
  82. //
  83. // Make local copies of our input parameters to make things easier.
  84. //
  85. irpSp = IoGetCurrentIrpStackLocation( Irp );
  86. fileObject = irpSp->FileObject;
  87. relatedFileObject = irpSp->FileObject->RelatedFileObject;
  88. fileName = *((PSTRING)(&irpSp->FileObject->FileName));
  89. desiredAccess = irpSp->Parameters.Create.SecurityContext->DesiredAccess;
  90. shareAccess = irpSp->Parameters.Create.ShareAccess;
  91. vcb = &MupDeviceObject->Vcb;
  92. DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG)Irp );
  93. DebugTrace( 0, Dbg, "FileObject = %08lx\n", (ULONG)fileObject );
  94. DebugTrace( 0, Dbg, "FileName = %Z\n", (ULONG)&fileName );
  95. FsRtlEnterFileSystem();
  96. try {
  97. //
  98. // Check to see if this is an open that came in via a Dfs device
  99. // object.
  100. //
  101. if (MupEnableDfs) {
  102. if ((MupDeviceObject->DeviceObject.DeviceType == FILE_DEVICE_DFS) ||
  103. (MupDeviceObject->DeviceObject.DeviceType ==
  104. FILE_DEVICE_DFS_FILE_SYSTEM)) {
  105. status = DfsFsdCreate( (PDEVICE_OBJECT) MupDeviceObject, Irp );
  106. try_return( NOTHING );
  107. }
  108. }
  109. //
  110. // Check if we are trying to open the mup file system
  111. //
  112. if ( fileName.Length == 0
  113. &&
  114. ( relatedFileObject == NULL ||
  115. BlockType(relatedFileObject->FsContext) == BlockTypeVcb ) ) {
  116. DebugTrace(0, Dbg, "Open MUP file system\n", 0);
  117. Irp->IoStatus = OpenMupFileSystem( &MupDeviceObject->Vcb,
  118. fileObject,
  119. desiredAccess,
  120. shareAccess );
  121. status = Irp->IoStatus.Status;
  122. MupCompleteRequest( Irp, status );
  123. try_return( NOTHING );
  124. }
  125. //
  126. // This is a UNC file open. Try to pass the request on.
  127. //
  128. status = CreateRedirectedFile(
  129. Irp,
  130. fileObject,
  131. irpSp->Parameters.Create.SecurityContext
  132. );
  133. if ( status == STATUS_REPARSE ) {
  134. Irp->IoStatus.Information = IO_REPARSE;
  135. } else if( status == STATUS_PENDING ) {
  136. IoMarkIrpPending( Irp );
  137. }
  138. try_exit: NOTHING;
  139. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  140. NOTHING;
  141. }
  142. FsRtlExitFileSystem();
  143. DebugTrace(-1, Dbg, "MupCreate -> %08lx\n", status);
  144. return status;
  145. }
  146. IO_STATUS_BLOCK
  147. OpenMupFileSystem (
  148. IN PVCB Vcb,
  149. IN PFILE_OBJECT FileObject,
  150. IN ACCESS_MASK DesiredAccess,
  151. IN USHORT ShareAccess
  152. )
  153. /*++
  154. Routine Description:
  155. This routine attempts to open the VCB.
  156. Arguments:
  157. Vcb - A pointer to the MUP volume control block.
  158. FileObject - A pointer to the IO system supplied file object for this
  159. Create IRP.
  160. DesiredAccess - The user specified desired access to the VCB.
  161. ShareAccess - The user specified share access to the VCB.
  162. Return Value:
  163. NTSTATUS - The status for the IRP.
  164. --*/
  165. {
  166. IO_STATUS_BLOCK iosb;
  167. PAGED_CODE();
  168. DebugTrace(+1, Dbg, "MupOpenMupFileSystem\n", 0 );
  169. ExAcquireResourceExclusive( &MupVcbLock, TRUE );
  170. try {
  171. //
  172. // Set the new share access
  173. //
  174. if (!NT_SUCCESS(iosb.Status = IoCheckShareAccess( DesiredAccess,
  175. ShareAccess,
  176. FileObject,
  177. &Vcb->ShareAccess,
  178. TRUE ))) {
  179. DebugTrace(0, Dbg, "bad share access\n", 0);
  180. try_return( NOTHING );
  181. }
  182. //
  183. // Supply the file object with a referenced pointer to the VCB.
  184. //
  185. MupReferenceBlock( Vcb );
  186. MupSetFileObject( FileObject, Vcb, NULL );
  187. //
  188. // Set the return status.
  189. //
  190. iosb.Status = STATUS_SUCCESS;
  191. iosb.Information = FILE_OPENED;
  192. try_exit: NOTHING;
  193. } finally {
  194. ExReleaseResource( &MupVcbLock );
  195. }
  196. //
  197. // Return to the caller.
  198. //
  199. DebugTrace(-1, Dbg, "MupOpenMupFileSystem -> Iosb.Status = %08lx\n", iosb.Status);
  200. return iosb;
  201. }
  202. NTSTATUS
  203. CreateRedirectedFile(
  204. IN PIRP Irp,
  205. IN PFILE_OBJECT FileObject,
  206. IN PIO_SECURITY_CONTEXT SecurityContext
  207. )
  208. /*++
  209. Routine Description:
  210. This routine attempts to reroute a file create request to a redirector.
  211. It attempts to find the correct redirector in 2 steps.
  212. (1) The routine checks a list of known prefixes. If the file object -
  213. file name prefix matches a known prefix, the request is forwarded to
  214. the redirector that "owns" the prefix.
  215. (2) The routine queries each redirector in turn, until one claims
  216. ownership of the file. The request is then rerouted to that redirector.
  217. If after these steps no owner is located, the MUP fails the request.
  218. Arguments:
  219. Irp - A pointer to the create IRP.
  220. FileObject - A pointer to the IO system supplied file object for this
  221. create request.
  222. SecurityContext - A pointer to the IO security context for this request.
  223. Return Value:
  224. NTSTATUS - The status for the IRP.
  225. --*/
  226. {
  227. NTSTATUS status;
  228. PUNICODE_PREFIX_TABLE_ENTRY entry;
  229. PKNOWN_PREFIX knownPrefix;
  230. PLIST_ENTRY listEntry;
  231. PUNC_PROVIDER provider;
  232. PWCH buffer;
  233. USHORT length;
  234. BOOLEAN ownLock;
  235. BOOLEAN providerReferenced = FALSE;
  236. PQUERY_PATH_REQUEST qpRequest;
  237. PMASTER_QUERY_PATH_CONTEXT masterContext = NULL;
  238. PQUERY_PATH_CONTEXT queryContext;
  239. PIRP irp;
  240. PIO_STACK_LOCATION irpSp;
  241. LARGE_INTEGER now;
  242. PAGED_CODE();
  243. DebugTrace(+1, Dbg, "CreateRedirectedFile\n", 0);
  244. //
  245. // Check to see if this file name begins with a known prefix.
  246. //
  247. ACQUIRE_LOCK( &MupPrefixTableLock );
  248. entry = RtlFindUnicodePrefix( &MupPrefixTable, &FileObject->FileName, TRUE );
  249. if ( entry != NULL ) {
  250. DebugTrace(0, Dbg, "Prefix %Z is known, rerouting...\n", (PSTRING)&FileObject->FileName);
  251. //
  252. // This is a known file, forward appropriately
  253. //
  254. knownPrefix = CONTAINING_RECORD( entry, KNOWN_PREFIX, TableEntry );
  255. KeQuerySystemTime( &now );
  256. if ( now.QuadPart < knownPrefix->LastUsedTime.QuadPart ) {
  257. //
  258. // The known prefix has not timed out yet, recalculate the
  259. // timeout time and reroute the open.
  260. //
  261. MupCalculateTimeout( &knownPrefix->LastUsedTime );
  262. RELEASE_LOCK( &MupPrefixTableLock );
  263. status = MupRerouteOpen( FileObject, knownPrefix->UncProvider );
  264. DebugTrace(-1, Dbg, "CreateRedirectedFile -> %8lx", status );
  265. MupCompleteRequest( Irp, status );
  266. return status;
  267. } else {
  268. DebugTrace(0, Dbg, "Prefix %Z has timed out\n", (PSTRING)&FileObject->FileName);
  269. //
  270. // The known prefix has timed out, dereference it so that
  271. // it will get removed from the table.
  272. //
  273. MupDereferenceKnownPrefix( knownPrefix );
  274. RELEASE_LOCK( &MupPrefixTableLock );
  275. }
  276. } else {
  277. RELEASE_LOCK( &MupPrefixTableLock );
  278. }
  279. //
  280. // Is this a client side mailslot file? It is if the file name
  281. // is of the form \\server\mailslot\Anything, and this is a create
  282. // operation.
  283. //
  284. irpSp = IoGetCurrentIrpStackLocation( Irp );
  285. buffer = (PWCH)FileObject->FileName.Buffer;
  286. length = FileObject->FileName.Length;
  287. if ( *buffer == L'\\' && irpSp->MajorFunction == IRP_MJ_CREATE ) {
  288. buffer++;
  289. while ( (length -= sizeof(WCHAR)) > 0 && *buffer++ != L'\\' );
  290. length -= sizeof(WCHAR);
  291. if ( length > 0 &&
  292. _wcsnicmp(
  293. buffer,
  294. L"Mailslot",
  295. MIN( length/sizeof(WCHAR), (sizeof( L"MAILSLOT" ) - sizeof(WCHAR)) / sizeof(WCHAR) ) ) == 0 ) {
  296. //
  297. // This is a mailslot file. Forward the create IRP to all
  298. // redirectors that support broadcast.
  299. //
  300. DebugTrace(0, Dbg, "Prefix %Z is a mailslot\n", (ULONG)&FileObject->FileName);
  301. status = BroadcastOpen( Irp );
  302. DebugTrace(-1, Dbg, "CreateRedirectedFile -> 0x%8lx\n", status );
  303. MupCompleteRequest( Irp, status );
  304. return status;
  305. }
  306. }
  307. //
  308. // Check to see if this is a Dfs name. If so, we'll handle it separately
  309. //
  310. if (MupEnableDfs &&
  311. (FileObject->FsContext2 != (PVOID) DFS_DOWNLEVEL_OPEN_CONTEXT)) {
  312. UNICODE_STRING pathName;
  313. status = DfsFsctrlIsThisADfsPath( &FileObject->FileName, &pathName );
  314. if (status == STATUS_SUCCESS) {
  315. DebugTrace(-1, Dbg, "Rerouting open of [%wZ] to Dfs\n", &FileObject->FileName);
  316. status = MupRerouteOpenToDfs(FileObject);
  317. MupCompleteRequest( Irp, status );
  318. return( status );
  319. }
  320. }
  321. try {
  322. //
  323. // Create an entry for this file.
  324. //
  325. knownPrefix = MupAllocatePrefixEntry( 0 );
  326. //
  327. // We don't know who owns this file, query the redirectors in sequence
  328. // until one works.
  329. //
  330. masterContext = MupAllocateMasterQueryContext();
  331. masterContext->OriginalIrp = Irp;
  332. masterContext->FileObject = FileObject;
  333. masterContext->Provider = NULL;
  334. masterContext->KnownPrefix = knownPrefix;
  335. masterContext->ErrorStatus = STATUS_BAD_NETWORK_PATH;
  336. MupAcquireGlobalLock();
  337. MupReferenceBlock( knownPrefix );
  338. MupReleaseGlobalLock();
  339. try {
  340. MupAcquireGlobalLock();
  341. ownLock = TRUE;
  342. listEntry = MupProviderList.Flink;
  343. while ( listEntry != &MupProviderList ) {
  344. provider = CONTAINING_RECORD(
  345. listEntry,
  346. UNC_PROVIDER,
  347. ListEntry
  348. );
  349. //
  350. // Reference the provider block so that it doesn't go away
  351. // while we are using it.
  352. //
  353. MupReferenceBlock( provider );
  354. providerReferenced = TRUE;
  355. MupReleaseGlobalLock();
  356. ownLock = FALSE;
  357. //
  358. // Allocate buffers for the io request.
  359. //
  360. qpRequest = ALLOCATE_PAGED_POOL(
  361. sizeof( QUERY_PATH_REQUEST ) +
  362. FileObject->FileName.Length,
  363. BlockTypeBuffer
  364. );
  365. queryContext = ALLOCATE_PAGED_POOL(
  366. sizeof( QUERY_PATH_CONTEXT ),
  367. BlockTypeQueryContext
  368. );
  369. queryContext->MasterContext = masterContext;
  370. queryContext->Buffer = qpRequest;
  371. //
  372. // Generate a query path request.
  373. //
  374. qpRequest->PathNameLength = FileObject->FileName.Length;
  375. qpRequest->SecurityContext = SecurityContext;
  376. RtlMoveMemory(
  377. qpRequest->FilePathName,
  378. FileObject->FileName.Buffer,
  379. FileObject->FileName.Length
  380. );
  381. //
  382. // Build the query path Io control IRP.
  383. //
  384. irp = MupBuildIoControlRequest(
  385. NULL,
  386. provider->FileObject,
  387. queryContext,
  388. IRP_MJ_DEVICE_CONTROL,
  389. IOCTL_REDIR_QUERY_PATH,
  390. qpRequest,
  391. sizeof( QUERY_PATH_REQUEST ) + FileObject->FileName.Length,
  392. qpRequest,
  393. sizeof( QUERY_PATH_RESPONSE ),
  394. QueryPathCompletionRoutine
  395. );
  396. if ( irp == NULL ) {
  397. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  398. }
  399. //
  400. // Set the RequestorMode to KernelMode, since all the
  401. // parameters to this Irp are in kernel space
  402. //
  403. irp->RequestorMode = KernelMode;
  404. //
  405. // Get a referenced pointer to the provider, the reference
  406. // is release when the IO completes.
  407. //
  408. queryContext->Provider = provider;
  409. MupAcquireGlobalLock();
  410. MupReferenceBlock( provider );
  411. MupReferenceBlock( masterContext );
  412. MupReleaseGlobalLock();
  413. //
  414. // Submit the request.
  415. //
  416. IoCallDriver( provider->DeviceObject, irp );
  417. //
  418. // Acquire the lock that protects the provider list, and get
  419. // a pointer to the next provider in the list.
  420. //
  421. MupAcquireGlobalLock();
  422. ownLock = TRUE;
  423. listEntry = listEntry->Flink;
  424. MupDereferenceUncProvider( provider );
  425. providerReferenced = FALSE;
  426. } // while
  427. } finally {
  428. //
  429. // Dereference the previous provider.
  430. //
  431. if ( providerReferenced ) {
  432. MupDereferenceUncProvider( provider );
  433. }
  434. if ( ownLock ) {
  435. MupReleaseGlobalLock();
  436. }
  437. }
  438. } finally {
  439. if (AbnormalTermination()) {
  440. status = STATUS_INSUFFICIENT_RESOURCES;
  441. MupCompleteRequest( Irp, status );
  442. } else {
  443. ASSERT( masterContext != NULL );
  444. //
  445. // Release our reference to the query context.
  446. //
  447. status = MupDereferenceMasterQueryContext( masterContext );
  448. }
  449. }
  450. DebugTrace(-1, Dbg, "CreateRedirectedFile -> 0x%8lx\n", status );
  451. return status;
  452. }
  453. NTSTATUS
  454. MupRerouteOpen (
  455. IN PFILE_OBJECT FileObject,
  456. IN PUNC_PROVIDER UncProvider
  457. )
  458. /*++
  459. Routine Description:
  460. This routine redirects an create IRP request to the specified redirector
  461. by changing the name of the file and returning STATUS_REPARSE to the
  462. IO system
  463. Arguments:
  464. FileObject - The file object to open
  465. UncProvider - The UNC provider that will process the create IRP.
  466. Return Value:
  467. NTSTATUS - The status of the operation
  468. --*/
  469. {
  470. PCHAR buffer;
  471. ULONG deviceNameLength;
  472. PAGED_CODE();
  473. //
  474. // Allocate storage for the new file name.
  475. //
  476. buffer = ExAllocatePoolWithTag(
  477. PagedPool,
  478. UncProvider->DeviceName.Length + FileObject->FileName.Length,
  479. ' puM'
  480. );
  481. if ( buffer == NULL) {
  482. return STATUS_INSUFFICIENT_RESOURCES;
  483. }
  484. //
  485. // Copy the device name to the string buffer.
  486. //
  487. RtlMoveMemory(
  488. buffer,
  489. UncProvider->DeviceName.Buffer,
  490. UncProvider->DeviceName.Length
  491. );
  492. deviceNameLength = UncProvider->DeviceName.Length;
  493. //
  494. // Append the file name
  495. //
  496. RtlMoveMemory(
  497. buffer + deviceNameLength,
  498. FileObject->FileName.Buffer,
  499. FileObject->FileName.Length
  500. );
  501. //
  502. // Free the old file name string buffer.
  503. //
  504. ExFreePool( FileObject->FileName.Buffer );
  505. FileObject->FileName.Buffer = (PWCHAR)buffer;
  506. FileObject->FileName.MaximumLength =
  507. FileObject->FileName.Length + (USHORT)deviceNameLength;
  508. FileObject->FileName.Length = FileObject->FileName.MaximumLength;
  509. //
  510. // Tell the file system to try again.
  511. //
  512. return STATUS_REPARSE;
  513. }
  514. NTSTATUS
  515. MupRerouteOpenToDfs (
  516. IN PFILE_OBJECT FileObject
  517. )
  518. /*++
  519. Routine Description:
  520. This routine redirects an create IRP request to the Dfs part of this
  521. driver by changing the name of the file and returning
  522. STATUS_REPARSE to the IO system
  523. Arguments:
  524. FileObject - The file object to open
  525. Return Value:
  526. NTSTATUS - The status of the operation
  527. --*/
  528. {
  529. PCHAR buffer;
  530. ULONG deviceNameLength;
  531. PAGED_CODE();
  532. //
  533. // Allocate storage for the new file name.
  534. //
  535. buffer = ExAllocatePoolWithTag(
  536. PagedPool,
  537. sizeof(DFS_DEVICE_ROOT) + FileObject->FileName.Length,
  538. ' puM'
  539. );
  540. if ( buffer == NULL) {
  541. return STATUS_INSUFFICIENT_RESOURCES;
  542. }
  543. //
  544. // Copy the device name to the string buffer.
  545. //
  546. RtlMoveMemory(
  547. buffer,
  548. DFS_DEVICE_ROOT,
  549. sizeof(DFS_DEVICE_ROOT)
  550. );
  551. deviceNameLength = sizeof(DFS_DEVICE_ROOT) - sizeof(UNICODE_NULL);
  552. //
  553. // Append the file name
  554. //
  555. RtlMoveMemory(
  556. buffer + deviceNameLength,
  557. FileObject->FileName.Buffer,
  558. FileObject->FileName.Length
  559. );
  560. //
  561. // Free the old file name string buffer.
  562. //
  563. ExFreePool( FileObject->FileName.Buffer );
  564. FileObject->FileName.Buffer = (PWCHAR)buffer;
  565. FileObject->FileName.MaximumLength =
  566. FileObject->FileName.Length + (USHORT)deviceNameLength;
  567. FileObject->FileName.Length = FileObject->FileName.MaximumLength;
  568. //
  569. // Tell the file system to try again.
  570. //
  571. return STATUS_REPARSE;
  572. }
  573. NTSTATUS
  574. BroadcastOpen (
  575. PIRP Irp
  576. )
  577. /*++
  578. Routine Description:
  579. Arguments:
  580. Return Value:
  581. NTSTATUS - The status for the IRP.
  582. --*/
  583. {
  584. NTSTATUS status;
  585. PFCB fcb;
  586. PIO_STACK_LOCATION irpSp;
  587. PFILE_OBJECT fileObject;
  588. BOOLEAN requestForwarded;
  589. PLIST_ENTRY listEntry;
  590. PUNC_PROVIDER uncProvider, previousUncProvider = NULL;
  591. OBJECT_ATTRIBUTES objectAttributes;
  592. IO_STATUS_BLOCK ioStatusBlock;
  593. PCCB ccb;
  594. OBJECT_HANDLE_INFORMATION handleInformation;
  595. HANDLE handle;
  596. BOOLEAN lockHeld = FALSE;
  597. BOOLEAN providerReferenced = FALSE;
  598. NTSTATUS statusToReturn = STATUS_NO_SUCH_FILE;
  599. ULONG priorityOfStatus = 0xFFFFFFFF;
  600. PAGED_CODE();
  601. DebugTrace(+1, Dbg, "BroadcastOpen\n", 0 );
  602. irpSp = IoGetCurrentIrpStackLocation( Irp );
  603. try {
  604. //
  605. // Create a FCB for this file.
  606. //
  607. fcb = MupCreateFcb( );
  608. //
  609. // Set the file object back pointers and our pointer to the
  610. // server file object.
  611. //
  612. fileObject = irpSp->FileObject;
  613. MupAcquireGlobalLock();
  614. lockHeld = TRUE;
  615. MupSetFileObject( fileObject,
  616. fcb,
  617. NULL );
  618. fcb->FileObject = fileObject;
  619. //
  620. // Loop through the list of UNC providers and try to create the
  621. // file on all file systems that support broadcast.
  622. //
  623. requestForwarded = FALSE;
  624. listEntry = MupProviderList.Flink;
  625. while ( listEntry != &MupProviderList ) {
  626. uncProvider = CONTAINING_RECORD( listEntry, UNC_PROVIDER, ListEntry );
  627. //
  628. // Reference the provider so that it won't go away
  629. //
  630. MupReferenceBlock( uncProvider );
  631. providerReferenced = TRUE;
  632. MupReleaseGlobalLock();
  633. lockHeld = FALSE;
  634. if ( uncProvider->MailslotsSupported ) {
  635. //
  636. // Build the rerouted file name, consisting of the file
  637. // named we received appended to the UNC provider device
  638. // name.
  639. //
  640. UNICODE_STRING fileName;
  641. fileName.MaximumLength = fileName.Length =
  642. uncProvider->DeviceName.Length + fileObject->FileName.Length;
  643. fileName.Buffer =
  644. ALLOCATE_PAGED_POOL(
  645. fileName.MaximumLength,
  646. BlockTypeBuffer
  647. );
  648. RtlMoveMemory(
  649. fileName.Buffer,
  650. uncProvider->DeviceName.Buffer,
  651. uncProvider->DeviceName.Length
  652. );
  653. RtlMoveMemory(
  654. (PCHAR)fileName.Buffer + uncProvider->DeviceName.Length,
  655. fileObject->FileName.Buffer,
  656. fileObject->FileName.Length
  657. );
  658. //
  659. // Attempt to open the file. Copy all of the information
  660. // from the create IRP we received, masking off additional
  661. // baggage that the IO system added along the way.
  662. //
  663. DebugTrace( 0, Dbg, "Attempt to open %Z\n", (ULONG)&fileName );
  664. InitializeObjectAttributes(
  665. &objectAttributes,
  666. &fileName,
  667. OBJ_CASE_INSENSITIVE, // !!! can we do this?
  668. 0,
  669. NULL // !!! Security
  670. );
  671. status = IoCreateFile(
  672. &handle,
  673. irpSp->Parameters.Create.SecurityContext->DesiredAccess & 0x1FF,
  674. &objectAttributes,
  675. &ioStatusBlock,
  676. NULL,
  677. irpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS,
  678. irpSp->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS,
  679. FILE_OPEN,
  680. irpSp->Parameters.Create.Options & FILE_VALID_SET_FLAGS,
  681. NULL, // Ea buffer
  682. 0, // Ea length
  683. CreateFileTypeNone,
  684. NULL, // parameters
  685. IO_NO_PARAMETER_CHECKING
  686. );
  687. FREE_POOL( fileName.Buffer );
  688. if ( NT_SUCCESS( status ) ) {
  689. status = ioStatusBlock.Status;
  690. }
  691. if ( NT_SUCCESS( status ) ) {
  692. DebugTrace( 0, Dbg, "Open attempt succeeded\n", 0 );
  693. ccb = MupCreateCcb( );
  694. status = ObReferenceObjectByHandle(
  695. handle,
  696. 0,
  697. NULL,
  698. KernelMode,
  699. (PVOID *)&ccb->FileObject,
  700. &handleInformation
  701. );
  702. ASSERT( NT_SUCCESS( status ) );
  703. ZwClose( handle );
  704. ccb->DeviceObject =
  705. IoGetRelatedDeviceObject( ccb->FileObject );
  706. ccb->Fcb = fcb;
  707. MupAcquireGlobalLock();
  708. lockHeld = TRUE;
  709. MupReferenceBlock( fcb );
  710. MupReleaseGlobalLock();
  711. lockHeld = FALSE;
  712. //
  713. // At least one provider will accept this mailslot
  714. // request.
  715. //
  716. requestForwarded = TRUE;
  717. //
  718. // Keep a list of CCBs. Since we just created the FCB
  719. // there is no need to use the lock to access the list.
  720. //
  721. InsertTailList( &fcb->CcbList, &ccb->ListEntry );
  722. } else { // NT_SUCCESS( status ), IoCreateFile
  723. DebugTrace( 0, Dbg, "Open attempt failed %8lx\n", status );
  724. //
  725. // Remember the status code if this is the highest
  726. // priority provider so far. This code is returned if
  727. // all providers fail the Create operation.
  728. //
  729. if ( uncProvider->Priority <= priorityOfStatus ) {
  730. priorityOfStatus = uncProvider->Priority;
  731. statusToReturn = status;
  732. }
  733. }
  734. } // uncProvider->MailslotsSupported
  735. MupAcquireGlobalLock();
  736. lockHeld = TRUE;
  737. listEntry = listEntry->Flink;
  738. //
  739. // It is now safe to dereference the previous provider.
  740. //
  741. MupDereferenceUncProvider( uncProvider );
  742. providerReferenced = FALSE;
  743. } // while
  744. MupReleaseGlobalLock();
  745. lockHeld = FALSE;
  746. //
  747. // And set our return status
  748. //
  749. if ( requestForwarded ) {
  750. status = STATUS_SUCCESS;
  751. } else {
  752. status = statusToReturn;
  753. }
  754. } finally {
  755. DebugTrace(-1, Dbg, "BroadcastOpen -> %08lx\n", status);
  756. if ( providerReferenced ) {
  757. MupDereferenceUncProvider( uncProvider );
  758. }
  759. if ( lockHeld ) {
  760. MupReleaseGlobalLock();
  761. }
  762. //
  763. // Now if we ever terminate the preceding try-statement with
  764. // a status that is not successful and the FCB pointer
  765. // is non-null then we need to deallocate the structure.
  766. //
  767. if (!NT_SUCCESS( status ) && fcb != NULL) {
  768. MupFreeFcb( fcb );
  769. }
  770. }
  771. return status;
  772. }
  773. NTSTATUS
  774. QueryPathCompletionRoutine (
  775. IN PDEVICE_OBJECT DeviceObject,
  776. IN PIRP Irp,
  777. IN PVOID Context
  778. )
  779. /*++
  780. Routine Description:
  781. This is the completion routine the querying a path. Cleanup our
  782. IRP and complete the original IRP if necessary.
  783. Arguments:
  784. DeviceObject - Pointer to target device object for the request.
  785. Irp - Pointer to I/O request packet
  786. Context - Caller-specified context parameter associated with IRP.
  787. This is actually a pointer to a Work Context block.
  788. Return Value:
  789. NTSTATUS - If STATUS_MORE_PROCESSING_REQUIRED is returned, I/O
  790. completion processing by IoCompleteRequest terminates its
  791. operation. Otherwise, IoCompleteRequest continues with I/O
  792. completion.
  793. --*/
  794. {
  795. PQUERY_PATH_RESPONSE qpResponse;
  796. PMASTER_QUERY_PATH_CONTEXT masterContext;
  797. PQUERY_PATH_CONTEXT queryPathContext;
  798. PCH buffer;
  799. PKNOWN_PREFIX knownPrefix;
  800. ULONG lengthAccepted;
  801. NTSTATUS status;
  802. DeviceObject; // prevent compiler warnings
  803. queryPathContext = Context;
  804. masterContext = queryPathContext->MasterContext;
  805. qpResponse = queryPathContext->Buffer;
  806. lengthAccepted = qpResponse->LengthAccepted;
  807. status = Irp->IoStatus.Status;
  808. //
  809. // Acquire the lock to protect access to the master context Provider
  810. // field.
  811. //
  812. ACQUIRE_LOCK( &masterContext->Lock );
  813. if ( NT_SUCCESS( status ) &&
  814. lengthAccepted != 0) {
  815. knownPrefix = masterContext->KnownPrefix;
  816. if ( masterContext->Provider != NULL ) {
  817. if ( queryPathContext->Provider->Priority < masterContext->Provider->Priority ) {
  818. //
  819. // A provider of higher priority (i.e. a lower priority code)
  820. // has claimed this prefix. Release the previous provider's
  821. // claim.
  822. //
  823. ACQUIRE_LOCK( &MupPrefixTableLock );
  824. if ( knownPrefix->InTable ) {
  825. RtlRemoveUnicodePrefix(
  826. &MupPrefixTable,
  827. &knownPrefix->TableEntry
  828. );
  829. knownPrefix->InTable = FALSE;
  830. }
  831. RELEASE_LOCK( &MupPrefixTableLock );
  832. FREE_POOL( knownPrefix->Prefix.Buffer );
  833. MupDereferenceUncProvider( knownPrefix->UncProvider );
  834. } else {
  835. //
  836. // The current provider keeps ownership of the prefix.
  837. //
  838. goto not_this_one;
  839. }
  840. }
  841. //
  842. // This provider get the prefix.
  843. //
  844. masterContext->Provider = queryPathContext->Provider;
  845. try {
  846. //
  847. // We have found a match. Attempt to remember it.
  848. //
  849. if (masterContext->FileObject->FsContext2 != (PVOID) DFS_DOWNLEVEL_OPEN_CONTEXT) {
  850. buffer = ALLOCATE_PAGED_POOL( lengthAccepted, BlockTypeBuffer );
  851. RtlMoveMemory(
  852. buffer,
  853. masterContext->FileObject->FileName.Buffer,
  854. lengthAccepted
  855. );
  856. //
  857. // Copy the reference provider pointer for the known prefix
  858. // block.
  859. //
  860. knownPrefix->UncProvider = masterContext->Provider;
  861. knownPrefix->Prefix.Buffer = (PWCH)buffer;
  862. knownPrefix->Prefix.Length = (USHORT)lengthAccepted;
  863. knownPrefix->Prefix.MaximumLength = (USHORT)lengthAccepted;
  864. knownPrefix->PrefixStringAllocated = TRUE;
  865. ACQUIRE_LOCK( &MupPrefixTableLock );
  866. RtlInsertUnicodePrefix(
  867. &MupPrefixTable,
  868. &knownPrefix->Prefix,
  869. &knownPrefix->TableEntry
  870. );
  871. knownPrefix->InTable = TRUE;
  872. RELEASE_LOCK( &MupPrefixTableLock );
  873. }
  874. } finally {
  875. if ( AbnormalTermination() ) {
  876. ACQUIRE_LOCK( &MupPrefixTableLock );
  877. MupDereferenceKnownPrefix( knownPrefix );
  878. RELEASE_LOCK( &MupPrefixTableLock );
  879. }
  880. RELEASE_LOCK( &masterContext->Lock );
  881. //
  882. // Free our buffers
  883. //
  884. FREE_POOL( qpResponse );
  885. FREE_POOL( queryPathContext );
  886. IoFreeIrp( Irp );
  887. }
  888. } else {
  889. //
  890. // If our error status is more significant than the error status
  891. // stored in the masterContext, then put ours there
  892. //
  893. ULONG newError, oldError;
  894. //
  895. // MupOrderedErrorList is a list of error codes ordered from least
  896. // important to most important. We're calling down to multiple
  897. // redirectors, but we can only return 1 error code on complete failure.
  898. //
  899. // To figure out which error to return, we look at the stored error and
  900. // the current error. We return the error having the highest index in
  901. // the MupOrderedErrorList
  902. //
  903. if( NT_SUCCESS( masterContext->ErrorStatus ) ) {
  904. masterContext->ErrorStatus = status;
  905. } else {
  906. for( oldError = 0; MupOrderedErrorList[ oldError ]; oldError++ )
  907. if( masterContext->ErrorStatus == MupOrderedErrorList[ oldError ] )
  908. break;
  909. for( newError = 0; newError < oldError; newError++ )
  910. if( status == MupOrderedErrorList[ newError ] )
  911. break;
  912. if( newError >= oldError ) {
  913. masterContext->ErrorStatus = status;
  914. }
  915. }
  916. not_this_one:
  917. MupDereferenceUncProvider( queryPathContext->Provider );
  918. //
  919. // Free our buffers
  920. //
  921. FREE_POOL( qpResponse );
  922. FREE_POOL( queryPathContext );
  923. IoFreeIrp( Irp );
  924. RELEASE_LOCK( &masterContext->Lock );
  925. }
  926. MupDereferenceMasterQueryContext( masterContext );
  927. //
  928. // Return more processing required to the IO system so that it
  929. // doesn't attempt further processing on the IRP we just freed.
  930. //
  931. return STATUS_MORE_PROCESSING_REQUIRED;
  932. }