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.

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