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

589 lines
18 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. DirCtrl.c
  5. Abstract:
  6. This module implements the File Directory Control routines for Rx called
  7. by the dispatch driver.
  8. Author:
  9. Joe Linn [Joe Linn] 4-oct-94
  10. Balan Sethu Raman [SethuR] 16-Oct-95 Hook in the notify change API routines
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. //
  16. // The local debug trace level
  17. //
  18. #define Dbg (DEBUG_TRACE_DIRCTRL)
  19. WCHAR Rx8QMdot3QM[12] = { DOS_QM, DOS_QM, DOS_QM, DOS_QM, DOS_QM, DOS_QM, DOS_QM, DOS_QM,
  20. L'.', DOS_QM, DOS_QM, DOS_QM};
  21. WCHAR RxStarForTemplate[] = L"*";
  22. //
  23. // Local procedure prototypes
  24. //
  25. NTSTATUS
  26. RxQueryDirectory (
  27. IN PRX_CONTEXT RxContext,
  28. IN PIRP Irp,
  29. IN PFCB Fcb,
  30. IN PFOBX Fobx
  31. );
  32. NTSTATUS
  33. RxNotifyChangeDirectory (
  34. IN PRX_CONTEXT RxContext,
  35. IN PIRP Irp,
  36. IN PFCB Fcb,
  37. IN PFOBX Fobx
  38. );
  39. NTSTATUS
  40. RxLowIoNotifyChangeDirectoryCompletion (
  41. IN PRX_CONTEXT RxContext
  42. );
  43. #ifdef ALLOC_PRAGMA
  44. #pragma alloc_text(PAGE, RxCommonDirectoryControl)
  45. #pragma alloc_text(PAGE, RxNotifyChangeDirectory)
  46. #pragma alloc_text(PAGE, RxQueryDirectory)
  47. #pragma alloc_text(PAGE, RxLowIoNotifyChangeDirectoryCompletion)
  48. #endif
  49. NTSTATUS
  50. RxCommonDirectoryControl (
  51. IN PRX_CONTEXT RxContext,
  52. IN PIRP Irp
  53. )
  54. /*++
  55. Routine Description:
  56. This is the common routine for doing directory control operations called
  57. by both the fsd and fsp threads
  58. Arguments:
  59. Irp - Supplies the Irp to process
  60. Return Value:
  61. NTSTATUS - The return status for the operation
  62. --*/
  63. {
  64. NTSTATUS Status;
  65. PFCB Fcb;
  66. PFOBX Fobx;
  67. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  68. PAGED_CODE();
  69. RxDecodeFileObject( IrpSp->FileObject, &Fcb, &Fobx );
  70. RxDbgTrace( +1, Dbg, ("RxCommonDirectoryControl IrpC/Fobx/Fcb = %08lx %08lx %08lx\n", RxContext, Fobx, Fcb) );
  71. RxDbgTrace( 0, Dbg, ("MinorFunction = %08lx\n", Irpsp->MinorFunction ) );
  72. RxLog(( "CommDirC %lx %lx %lx %ld\n", RxContext, Fobx, Fcb, IrpSp->MinorFunction) );
  73. RxWmiLog( LOG,
  74. RxCommonDirectoryControl,
  75. LOGPTR( RxContext )
  76. LOGPTR( Fobx )
  77. LOGPTR( Fcb )
  78. LOGUCHAR( IrpSp->MinorFunction ));
  79. //
  80. // We know this is a directory control so we'll case on the
  81. // minor function, and call a internal worker routine to complete
  82. // the irp.
  83. //
  84. switch (IrpSp->MinorFunction) {
  85. case IRP_MN_QUERY_DIRECTORY:
  86. Status = RxQueryDirectory( RxContext, Irp, Fcb, Fobx );
  87. break;
  88. case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
  89. Status = RxNotifyChangeDirectory( RxContext, Irp, Fcb, Fobx );
  90. if (Status == STATUS_PENDING) {
  91. RxDereferenceAndDeleteRxContext( RxContext );
  92. }
  93. break;
  94. default:
  95. RxDbgTrace( 0, Dbg, ("Invalid Directory Control Minor Function %08lx\n", IrpSp->MinorFunction ));
  96. Status = STATUS_INVALID_DEVICE_REQUEST;
  97. break;
  98. }
  99. RxDbgTrace(-1, Dbg, ("RxCommonDirectoryControl -> %08lx\n", Status));
  100. return Status;
  101. }
  102. //
  103. // Local Support Routine
  104. //
  105. NTSTATUS
  106. RxQueryDirectory (
  107. IN PRX_CONTEXT RxContext,
  108. IN PIRP Irp,
  109. IN PFCB Fcb,
  110. IN PFOBX Fobx
  111. )
  112. /*++
  113. Routine Description:
  114. This routine performs the query directory operation. It is responsible
  115. for either completing of enqueuing the input Irp.
  116. Arguments:
  117. Irp - Supplies the Irp to process
  118. Return Value:
  119. RXSTATUS - The return status for the operation
  120. --*/
  121. {
  122. NTSTATUS Status;
  123. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  124. TYPE_OF_OPEN TypeOfOpen = NodeType( Fcb );
  125. CLONG UserBufferLength;
  126. PUNICODE_STRING FileName;
  127. FILE_INFORMATION_CLASS FileInformationClass;
  128. BOOLEAN PostQuery = FALSE;
  129. PAGED_CODE();
  130. //
  131. // Display the input values.
  132. //
  133. RxDbgTrace( +1, Dbg, ("RxQueryDirectory...\n", 0) );
  134. RxDbgTrace( 0, Dbg, (" Wait = %08lx\n", FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT )) );
  135. RxDbgTrace( 0, Dbg, (" Irp = %08lx\n", Irp ));
  136. RxDbgTrace( 0, Dbg, (" ->UserBufLength = %08lx\n", IrpSp->Parameters.QueryDirectory.Length ));
  137. RxDbgTrace( 0, Dbg, (" ->FileName = %08lx\n", IrpSp->Parameters.QueryDirectory.FileName ));
  138. #if DBG
  139. if (IrpSp->Parameters.QueryDirectory.FileName) {
  140. RxDbgTrace( 0, Dbg, (" -> %wZ\n", IrpSp->Parameters.QueryDirectory.FileName ));
  141. }
  142. #endif
  143. RxDbgTrace( 0, Dbg, (" ->FileInformationClass = %08lx\n", IrpSp->Parameters.QueryDirectory.FileInformationClass ));
  144. RxDbgTrace( 0, Dbg, (" ->FileIndex = %08lx\n", IrpSp->Parameters.QueryDirectory.FileIndex ));
  145. RxDbgTrace( 0, Dbg, (" ->UserBuffer = %08lx\n", Irp->UserBuffer ));
  146. RxDbgTrace( 0, Dbg, (" ->RestartScan = %08lx\n", FlagOn( IrpSp->Flags, SL_RESTART_SCAN )));
  147. RxDbgTrace( 0, Dbg, (" ->ReturnSingleEntry = %08lx\n", FlagOn( IrpSp->Flags, SL_RETURN_SINGLE_ENTRY )));
  148. RxDbgTrace( 0, Dbg, (" ->IndexSpecified = %08lx\n", FlagOn( IrpSp->Flags, SL_INDEX_SPECIFIED )));
  149. RxLog(( "Qry %lx %d %ld %lx %d\n",
  150. RxContext, BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT), // 1,2
  151. IrpSp->Parameters.QueryDirectory.Length, IrpSp->Parameters.QueryDirectory.FileName, // 3,4
  152. IrpSp->Parameters.QueryDirectory.FileInformationClass // 5
  153. ));
  154. RxWmiLog( LOG,
  155. RxQueryDirectory_1,
  156. LOGPTR( RxContext )
  157. LOGULONG( RxContext->Flags )
  158. LOGULONG( IrpSp->Parameters.QueryDirectory.Length )
  159. LOGPTR( IrpSp->Parameters.QueryDirectory.FileName )
  160. LOGULONG( IrpSp->Parameters.QueryDirectory.FileInformationClass ));
  161. RxLog(( " alsoqry %d %lx %lx\n",
  162. IrpSp->Parameters.QueryDirectory.FileIndex,
  163. Irp->UserBuffer,
  164. IrpSp->Flags ));
  165. RxWmiLog( LOG,
  166. RxQueryDirectory_2,
  167. LOGULONG( IrpSp->Parameters.QueryDirectory.FileIndex )
  168. LOGPTR( Irp->UserBuffer )
  169. LOGUCHAR( IrpSp->Flags ));
  170. if (IrpSp->Parameters.QueryDirectory.FileName) {
  171. RxLog(( " QryName %wZ\n", ((PUNICODE_STRING)IrpSp->Parameters.QueryDirectory.FileName) ));
  172. RxWmiLog( LOG,
  173. RxQueryDirectory_3,
  174. LOGUSTR(*IrpSp->Parameters.QueryDirectory.FileName) );
  175. }
  176. //
  177. // If this is the initial query, then grab exclusive access in
  178. // order to update the search string in the Fobx. We may
  179. // discover that we are not the initial query once we grab the Fcb
  180. // and downgrade our status.
  181. //
  182. if (Fobx == NULL) {
  183. return STATUS_OBJECT_NAME_INVALID;
  184. }
  185. if (Fcb->NetRoot->Type != NET_ROOT_DISK) {
  186. return STATUS_INVALID_DEVICE_REQUEST;
  187. }
  188. //
  189. // Reference our input parameters to make things easier
  190. //
  191. UserBufferLength = IrpSp->Parameters.QueryDirectory.Length;
  192. FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
  193. FileName = IrpSp->Parameters.QueryDirectory.FileName;
  194. RxContext->QueryDirectory.FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;
  195. RxContext->QueryDirectory.RestartScan = BooleanFlagOn( IrpSp->Flags, SL_RESTART_SCAN );
  196. RxContext->QueryDirectory.ReturnSingleEntry = BooleanFlagOn( IrpSp->Flags, SL_RETURN_SINGLE_ENTRY );
  197. RxContext->QueryDirectory.IndexSpecified = BooleanFlagOn( IrpSp->Flags, SL_INDEX_SPECIFIED );
  198. RxContext->QueryDirectory.InitialQuery = (BOOLEAN)((Fobx->UnicodeQueryTemplate.Buffer == NULL) &&
  199. !FlagOn( Fobx->Flags, FOBX_FLAG_MATCH_ALL ));
  200. if (RxContext->QueryDirectory.IndexSpecified) {
  201. return STATUS_NOT_IMPLEMENTED;
  202. }
  203. if (RxContext->QueryDirectory.InitialQuery) {
  204. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  205. if (Status == STATUS_LOCK_NOT_GRANTED) {
  206. PostQuery = TRUE;
  207. } else if (Status != STATUS_SUCCESS) {
  208. RxDbgTrace( 0, Dbg, ("RxQueryDirectory -> Could not acquire Fcb(%lx) %lx\n", Fcb, Status) );
  209. return Status;
  210. } else if (Fobx->UnicodeQueryTemplate.Buffer != NULL) {
  211. RxContext->QueryDirectory.InitialQuery = FALSE;
  212. RxConvertToSharedFcb( RxContext, Fcb );
  213. }
  214. } else {
  215. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  216. if (Status == STATUS_LOCK_NOT_GRANTED) {
  217. PostQuery = TRUE;
  218. } else if (Status != STATUS_SUCCESS) {
  219. RxDbgTrace( 0, Dbg, ("RxQueryDirectory -> Could not acquire Fcb(%lx) %lx\n", Fcb, Status) );
  220. return Status;
  221. }
  222. }
  223. if (PostQuery) {
  224. RxDbgTrace( 0, Dbg, ("RxQueryDirectory -> Enqueue to Fsp\n", 0) );
  225. Status = RxFsdPostRequest( RxContext );
  226. RxDbgTrace( -1, Dbg, ("RxQueryDirectory -> %08lx\n", Status ));
  227. return Status;
  228. }
  229. if (FlagOn( Fcb->FcbState, FCB_STATE_ORPHANED )) {
  230. RxReleaseFcb( RxContext, Fcb );
  231. return STATUS_FILE_CLOSED;
  232. }
  233. try {
  234. Status = STATUS_SUCCESS;
  235. //
  236. // Determine where to start the scan. Highest priority is given
  237. // to the file index. Lower priority is the restart flag. If
  238. // neither of these is specified, then the existing value in the
  239. // Fobx is used.
  240. //
  241. if (!RxContext->QueryDirectory.IndexSpecified && RxContext->QueryDirectory.RestartScan) {
  242. RxContext->QueryDirectory.FileIndex = 0;
  243. }
  244. //
  245. // If this is the first try then allocate a buffer for the file
  246. // name.
  247. //
  248. if (RxContext->QueryDirectory.InitialQuery) {
  249. ASSERT( !FlagOn( Fobx->Flags, FOBX_FLAG_FREE_UNICODE ) );
  250. //
  251. // If either:
  252. //
  253. // - No name was specified
  254. // - An empty name was specified
  255. // - We received a '*'
  256. // - The user specified the DOS equivolent of ????????.???
  257. //
  258. // then match all names.
  259. //
  260. if ((FileName == NULL) ||
  261. (FileName->Length == 0) ||
  262. (FileName->Buffer == NULL) ||
  263. ((FileName->Length == sizeof( WCHAR )) &&
  264. (FileName->Buffer[0] == L'*')) ||
  265. ((FileName->Length == 12 * sizeof( WCHAR )) &&
  266. (RtlCompareMemory( FileName->Buffer,
  267. Rx8QMdot3QM,
  268. 12*sizeof(WCHAR) )) == 12 * sizeof(WCHAR))) {
  269. Fobx->ContainsWildCards = TRUE;
  270. Fobx->UnicodeQueryTemplate.Buffer = RxStarForTemplate;
  271. Fobx->UnicodeQueryTemplate.Length = sizeof(WCHAR);
  272. Fobx->UnicodeQueryTemplate.MaximumLength = sizeof(WCHAR);
  273. SetFlag( Fobx->Flags, FOBX_FLAG_MATCH_ALL );
  274. } else {
  275. PVOID TemplateBuffer;
  276. //
  277. // See if the name has wild cards & allocate template buffer
  278. //
  279. Fobx->ContainsWildCards = FsRtlDoesNameContainWildCards( FileName );
  280. TemplateBuffer = RxAllocatePoolWithTag( PagedPool, FileName->Length, RX_DIRCTL_POOLTAG );
  281. if (TemplateBuffer != NULL) {
  282. //
  283. // Validate that the length is in sizeof(WCHAR) increments
  284. //
  285. if(FlagOn( FileName->Length, 1 )) {
  286. Status = STATUS_INVALID_PARAMETER;
  287. } else {
  288. RxDbgTrace( 0, Dbg, ("RxQueryDirectory -> TplateBuffer = %08lx\n", TemplateBuffer) );
  289. Fobx->UnicodeQueryTemplate.Buffer = TemplateBuffer;
  290. Fobx->UnicodeQueryTemplate.Length = FileName->Length;
  291. Fobx->UnicodeQueryTemplate.MaximumLength = FileName->Length;
  292. RtlMoveMemory( Fobx->UnicodeQueryTemplate.Buffer,
  293. FileName->Buffer,FileName->Length );
  294. RxDbgTrace( 0, Dbg, ("RxQueryDirectory -> Template = %wZ\n", &Fobx->UnicodeQueryTemplate) );
  295. SetFlag( Fobx->Flags, FOBX_FLAG_FREE_UNICODE );
  296. }
  297. } else {
  298. Status = STATUS_INSUFFICIENT_RESOURCES;
  299. }
  300. }
  301. if (Status == STATUS_SUCCESS) {
  302. //
  303. // We convert to shared access before going to the net.
  304. //
  305. RxConvertToSharedFcb( RxContext, Fcb );
  306. }
  307. }
  308. if (Status == STATUS_SUCCESS) {
  309. RxLockUserBuffer( RxContext, Irp, IoModifyAccess, UserBufferLength );
  310. RxContext->Info.FileInformationClass = FileInformationClass;
  311. RxContext->Info.Buffer = RxMapUserBuffer( RxContext, Irp );
  312. RxContext->Info.LengthRemaining = UserBufferLength;
  313. if (RxContext->Info.Buffer != NULL) {
  314. //
  315. // minirdr updates the fileindex
  316. //
  317. MINIRDR_CALL( Status,
  318. RxContext,
  319. Fcb->MRxDispatch,
  320. MRxQueryDirectory,
  321. (RxContext) );
  322. if (RxContext->PostRequest) {
  323. RxDbgTrace( 0, Dbg, ("RxQueryDirectory -> Enqueue to Fsp from minirdr\n", 0) );
  324. Status = RxFsdPostRequest( RxContext );
  325. } else {
  326. Irp->IoStatus.Information = UserBufferLength - RxContext->Info.LengthRemaining;
  327. }
  328. } else {
  329. if (Irp->MdlAddress != NULL) {
  330. Status = STATUS_INSUFFICIENT_RESOURCES;
  331. } else {
  332. Status = STATUS_INVALID_PARAMETER;
  333. }
  334. }
  335. }
  336. } finally {
  337. DebugUnwind( RxQueryDirectory );
  338. RxReleaseFcb( RxContext, Fcb );
  339. RxDbgTrace(-1, Dbg, ("RxQueryDirectory -> %08lx\n", Status));
  340. }
  341. return Status;
  342. }
  343. NTSTATUS
  344. RxNotifyChangeDirectory (
  345. IN PRX_CONTEXT RxContext,
  346. IN PIRP Irp,
  347. IN PFCB Fcb,
  348. IN PFOBX Fobx
  349. )
  350. /*++
  351. Routine Description:
  352. This routine performs the notify change directory operation. It is
  353. responsible for either completing or enqueuing the operation.
  354. Arguments:
  355. RxContext - the RDBSS context for the operation
  356. Return Value:
  357. RXSTATUS - The return status for the operation
  358. --*/
  359. {
  360. NTSTATUS Status = STATUS_SUCCESS;
  361. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  362. ULONG CompletionFilter;
  363. BOOLEAN WatchTree;
  364. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  365. TYPE_OF_OPEN TypeOfOpen = NodeType( Fcb );
  366. PAGED_CODE();
  367. RxDbgTrace( +1, Dbg, ("RxNotifyChangeDirectory...\n", 0) );
  368. RxDbgTrace( 0, Dbg, (" Wait = %08lx\n", FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT)) );
  369. RxDbgTrace( 0, Dbg, (" Irp = %08lx\n", Irp) );
  370. RxDbgTrace( 0, Dbg, (" ->CompletionFilter = %08lx\n", IrpSp->Parameters.NotifyDirectory.CompletionFilter) );
  371. //
  372. // Always set the wait flag in the Irp context for the original request.
  373. //
  374. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
  375. RxInitializeLowIoContext( RxContext, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY, LowIoContext );
  376. //
  377. // Reference our input parameter to make things easier
  378. //
  379. CompletionFilter = IrpSp->Parameters.NotifyDirectory.CompletionFilter;
  380. WatchTree = BooleanFlagOn( IrpSp->Flags, SL_WATCH_TREE );
  381. try {
  382. RxLockUserBuffer( RxContext,
  383. Irp,
  384. IoWriteAccess,
  385. IrpSp->Parameters.NotifyDirectory.Length );
  386. LowIoContext->ParamsFor.NotifyChangeDirectory.WatchTree = WatchTree;
  387. LowIoContext->ParamsFor.NotifyChangeDirectory.CompletionFilter = CompletionFilter;
  388. LowIoContext->ParamsFor.NotifyChangeDirectory.NotificationBufferLength =
  389. IrpSp->Parameters.NotifyDirectory.Length;
  390. if (Irp->MdlAddress != NULL) {
  391. LowIoContext->ParamsFor.NotifyChangeDirectory.pNotificationBuffer =
  392. MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
  393. if (LowIoContext->ParamsFor.NotifyChangeDirectory.pNotificationBuffer == NULL) {
  394. Status = STATUS_INSUFFICIENT_RESOURCES;
  395. } else {
  396. Status = RxLowIoSubmit( RxContext,
  397. Irp,
  398. Fcb,
  399. RxLowIoNotifyChangeDirectoryCompletion );
  400. }
  401. } else {
  402. Status = STATUS_INVALID_PARAMETER;
  403. }
  404. } finally {
  405. DebugUnwind( RxNotifyChangeDirectory );
  406. RxDbgTrace(-1, Dbg, ("RxNotifyChangeDirectory -> %08lx\n", Status));
  407. }
  408. return Status;
  409. }
  410. NTSTATUS
  411. RxLowIoNotifyChangeDirectoryCompletion(
  412. IN PRX_CONTEXT RxContext
  413. )
  414. /*++
  415. Routine Description:
  416. This is the completion routine for NotifyChangeDirectory requests passed down
  417. to thr mini redirectors
  418. Arguments:
  419. RxContext -- the RDBSS context associated with the operation
  420. Return Value:
  421. RXSTATUS - The return status for the operation
  422. --*/
  423. {
  424. NTSTATUS Status;
  425. PIRP Irp = RxContext->CurrentIrp;
  426. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  427. PAGED_CODE();
  428. Status = RxContext->StoredStatus;
  429. RxDbgTrace(+1, Dbg, ("RxLowIoChangeNotifyDirectoryShellCompletion entry Status = %08lx\n", Status));
  430. Irp->IoStatus.Information = RxContext->InformationToReturn;
  431. Irp->IoStatus.Status = Status;
  432. RxDbgTrace(-1, Dbg, ("RxLowIoChangeNotifyDirectoryShellCompletion exit Status = %08lx\n", Status));
  433. return Status;
  434. }
  435.