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.

992 lines
34 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. FsCtrl.c
  5. Abstract:
  6. This module implements the File System Control routines for Rdbss.
  7. Fsctls on the device fcb are handled in another module.
  8. Author:
  9. Joe Linn [JoeLinn] 7-mar-95
  10. Revision History:
  11. Balan Sethu Raman 18-May-95 -- Integrated with mini rdrs
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include <dfsfsctl.h>
  16. #include "fsctlbuf.h"
  17. // The local debug trace level
  18. #define Dbg (DEBUG_TRACE_FSCTRL)
  19. // Local procedure prototypes
  20. NTSTATUS
  21. RxUserFsCtrl ( RXCOMMON_SIGNATURE );
  22. NTSTATUS
  23. TranslateSisFsctlName (
  24. IN PWCHAR InputName,
  25. OUT PUNICODE_STRING RelativeName,
  26. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  27. IN PUNICODE_STRING NetRootName
  28. );
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text(PAGE, RxCommonFileSystemControl)
  31. #pragma alloc_text(PAGE, RxUserFsCtrl)
  32. #pragma alloc_text(PAGE, RxLowIoFsCtlShell)
  33. #pragma alloc_text(PAGE, RxLowIoFsCtlShellCompletion)
  34. #pragma alloc_text(PAGE, TranslateSisFsctlName)
  35. #endif
  36. NTSTATUS
  37. RxCommonFileSystemControl ( RXCOMMON_SIGNATURE )
  38. /*++
  39. Routine Description:
  40. This is the common routine for doing FileSystem control operations called
  41. by both the fsd and fsp threads. What happens is that we pick off fsctls that
  42. we know about and remote the rest....remoting means sending them thru the
  43. lowio stuff which may/will pick off a few more. the ones that we pick off here
  44. (and currently return STATUS_NOT_IMPLEMENTED) and the ones for being an oplock
  45. provider and for doing volume mounts....we don't even have volume fcbs
  46. yet since this is primarily a localFS concept.
  47. nevertheless, these are not passed thru to the mini.
  48. Arguments:
  49. Return Value:
  50. NTSTATUS - The return status for the operation
  51. --*/
  52. {
  53. RxCaptureRequestPacket;
  54. RxCaptureParamBlock;
  55. RxCaptureFcb;
  56. RxCaptureFobx;
  57. RxCaptureFileObject;
  58. NTSTATUS Status;
  59. NODE_TYPE_CODE TypeOfOpen;
  60. BOOLEAN TryLowIo = TRUE;
  61. ULONG FsControlCode = capPARAMS->Parameters.FileSystemControl.FsControlCode;
  62. PAGED_CODE();
  63. RxDbgTrace(+1, Dbg, ("RxCommonFileSystemControl %08lx\n", RxContext));
  64. RxDbgTrace( 0, Dbg, ("Irp = %08lx\n", capReqPacket));
  65. RxDbgTrace( 0, Dbg, ("MinorFunction = %08lx\n", capPARAMS->MinorFunction));
  66. RxDbgTrace( 0, Dbg, ("FsControlCode = %08lx\n", FsControlCode));
  67. RxLog(("FsCtl %x %x %x %x",RxContext,capReqPacket,capPARAMS->MinorFunction,FsControlCode));
  68. RxWmiLog(LOG,
  69. RxCommonFileSystemControl,
  70. LOGPTR(RxContext)
  71. LOGPTR(capReqPacket)
  72. LOGUCHAR(capPARAMS->MinorFunction)
  73. LOGULONG(FsControlCode));
  74. ASSERT(capPARAMS->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL);
  75. // Validate the buffers passed in for the FSCTL
  76. if ((capReqPacket->RequestorMode == UserMode) &&
  77. (!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_IN_FSP))) {
  78. try {
  79. switch (FsControlCode & 3) {
  80. case METHOD_NEITHER:
  81. {
  82. PVOID pInputBuffer,pOutputBuffer;
  83. ULONG InputBufferLength,OutputBufferLength;
  84. Status = STATUS_SUCCESS;
  85. pInputBuffer = METHODNEITHER_OriginalInputBuffer(capPARAMS);
  86. pOutputBuffer = METHODNEITHER_OriginalOutputBuffer(capReqPacket);
  87. InputBufferLength = capPARAMS->Parameters.FileSystemControl.InputBufferLength;
  88. OutputBufferLength = capPARAMS->Parameters.FileSystemControl.OutputBufferLength;
  89. if (pInputBuffer != NULL) {
  90. ProbeForRead(
  91. pInputBuffer,
  92. InputBufferLength,
  93. 1);
  94. ProbeForWrite(
  95. pInputBuffer,
  96. InputBufferLength,
  97. 1);
  98. } else if (InputBufferLength != 0) {
  99. Status = STATUS_INVALID_USER_BUFFER;
  100. }
  101. if (Status == STATUS_SUCCESS) {
  102. if (pOutputBuffer != NULL) {
  103. ProbeForRead(
  104. pOutputBuffer,
  105. OutputBufferLength,
  106. 1);
  107. ProbeForWrite(
  108. pOutputBuffer,
  109. OutputBufferLength,
  110. 1);
  111. } else if (OutputBufferLength != 0) {
  112. Status = STATUS_INVALID_USER_BUFFER;
  113. }
  114. }
  115. }
  116. break;
  117. case METHOD_BUFFERED:
  118. case METHOD_IN_DIRECT:
  119. case METHOD_OUT_DIRECT:
  120. {
  121. Status = STATUS_SUCCESS;
  122. }
  123. break;
  124. }
  125. } except( EXCEPTION_EXECUTE_HANDLER ) {
  126. Status = STATUS_INVALID_USER_BUFFER;
  127. }
  128. if (Status != STATUS_SUCCESS) {
  129. return Status;
  130. }
  131. }
  132. switch (capPARAMS->MinorFunction) {
  133. case IRP_MN_USER_FS_REQUEST:
  134. case IRP_MN_TRACK_LINK:
  135. {
  136. RxDbgTrace( 0, Dbg, ("FsControlCode = %08lx\n", FsControlCode));
  137. switch (FsControlCode) {
  138. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  139. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  140. case FSCTL_REQUEST_BATCH_OPLOCK:
  141. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  142. case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
  143. case FSCTL_OPLOCK_BREAK_NOTIFY:
  144. case FSCTL_OPLOCK_BREAK_ACK_NO_2:
  145. {
  146. // fsrtl oplock package is handled in common for all minirdrs
  147. //Status = RxOplockRequest( RXCOMMON_ARGUMENTS, &PostToFsp );
  148. Status = STATUS_NOT_IMPLEMENTED;
  149. TryLowIo = FALSE;
  150. }
  151. break;
  152. case FSCTL_LOCK_VOLUME:
  153. case FSCTL_UNLOCK_VOLUME:
  154. case FSCTL_DISMOUNT_VOLUME:
  155. case FSCTL_MARK_VOLUME_DIRTY:
  156. case FSCTL_IS_VOLUME_MOUNTED:
  157. {
  158. // Decode the file object, the only type of opens we accept are
  159. // user volume opens.
  160. TypeOfOpen = NodeType(capFcb);
  161. if (TypeOfOpen != RDBSS_NTC_VOLUME_FCB) {
  162. Status = STATUS_INVALID_PARAMETER;
  163. } else {
  164. Status = STATUS_NOT_IMPLEMENTED;
  165. }
  166. TryLowIo = FALSE;
  167. }
  168. break;
  169. case FSCTL_DFS_GET_REFERRALS:
  170. case FSCTL_DFS_REPORT_INCONSISTENCY:
  171. {
  172. if (!BooleanFlagOn(capFcb->pNetRoot->pSrvCall->Flags,SRVCALL_FLAG_DFS_AWARE_SERVER)) {
  173. TryLowIo = FALSE;
  174. Status = STATUS_DFS_UNAVAILABLE;
  175. }
  176. }
  177. break;
  178. case FSCTL_LMR_GET_LINK_TRACKING_INFORMATION:
  179. {
  180. // Validate the parameters and reject illformed requests
  181. ULONG OutputBufferLength;
  182. PLINK_TRACKING_INFORMATION pLinkTrackingInformation;
  183. OutputBufferLength = capPARAMS->Parameters.FileSystemControl.OutputBufferLength;
  184. pLinkTrackingInformation = capReqPacket->AssociatedIrp.SystemBuffer;
  185. TryLowIo = FALSE;
  186. if ((OutputBufferLength < sizeof(LINK_TRACKING_INFORMATION)) ||
  187. (pLinkTrackingInformation == NULL) ||
  188. (capFcb->pNetRoot->Type != NET_ROOT_DISK)) {
  189. Status = STATUS_INVALID_PARAMETER;
  190. } else {
  191. BYTE Buffer[
  192. sizeof(FILE_FS_OBJECTID_INFORMATION)];
  193. PFILE_FS_OBJECTID_INFORMATION pVolumeInformation;
  194. pVolumeInformation = (PFILE_FS_OBJECTID_INFORMATION)Buffer;
  195. RxContext->Info.FsInformationClass = FileFsObjectIdInformation;
  196. RxContext->Info.Buffer = pVolumeInformation;
  197. RxContext->Info.LengthRemaining = sizeof(Buffer);
  198. MINIRDR_CALL(
  199. Status,
  200. RxContext,
  201. capFcb->MRxDispatch,
  202. MRxQueryVolumeInfo,
  203. (RxContext));
  204. if ((Status == STATUS_SUCCESS) ||
  205. (Status == STATUS_BUFFER_OVERFLOW)) {
  206. // Copy the volume Id onto the net root.
  207. RtlCopyMemory(
  208. &capFcb->pNetRoot->DiskParameters.VolumeId,
  209. pVolumeInformation->ObjectId,
  210. sizeof(GUID));
  211. RtlCopyMemory(
  212. pLinkTrackingInformation->VolumeId,
  213. &capFcb->pNetRoot->DiskParameters.VolumeId,
  214. sizeof(GUID));
  215. if (FlagOn(capFcb->pNetRoot->Flags,NETROOT_FLAG_DFS_AWARE_NETROOT)) {
  216. pLinkTrackingInformation->Type = DfsLinkTrackingInformation;
  217. } else {
  218. pLinkTrackingInformation->Type = NtfsLinkTrackingInformation;
  219. }
  220. capReqPacket->IoStatus.Information = sizeof(LINK_TRACKING_INFORMATION);
  221. Status = STATUS_SUCCESS;
  222. }
  223. }
  224. capReqPacket->IoStatus.Status = Status;
  225. }
  226. break;
  227. case FSCTL_SET_ZERO_DATA:
  228. {
  229. PFILE_ZERO_DATA_INFORMATION ZeroRange;
  230. Status = STATUS_SUCCESS;
  231. // Verify if the request is well formed...
  232. // a. check if the input buffer length is OK
  233. if (capPARAMS->Parameters.FileSystemControl.InputBufferLength <
  234. sizeof( FILE_ZERO_DATA_INFORMATION )) {
  235. Status = STATUS_INVALID_PARAMETER;
  236. } else {
  237. //
  238. // b: ensure the ZeroRange request is properly formed.
  239. //
  240. ZeroRange = (PFILE_ZERO_DATA_INFORMATION)capReqPacket->AssociatedIrp.SystemBuffer;
  241. if ((ZeroRange->FileOffset.QuadPart < 0) ||
  242. (ZeroRange->BeyondFinalZero.QuadPart < 0) ||
  243. (ZeroRange->FileOffset.QuadPart > ZeroRange->BeyondFinalZero.QuadPart)) {
  244. Status = STATUS_INVALID_PARAMETER;
  245. }
  246. }
  247. if (Status == STATUS_SUCCESS) {
  248. // Before the request can be processed ensure that there
  249. // are no user mapped sections
  250. if (!MmCanFileBeTruncated(
  251. &capFcb->NonPaged->SectionObjectPointers,
  252. NULL)) {
  253. Status = STATUS_USER_MAPPED_FILE;
  254. }
  255. }
  256. TryLowIo = (Status == STATUS_SUCCESS);
  257. }
  258. break;
  259. case FSCTL_SET_COMPRESSION:
  260. case FSCTL_SET_SPARSE:
  261. {
  262. // Ensure that the close is not delayed is for these FCB's
  263. Status = RxAcquireExclusiveFcb( RxContext, capFcb );
  264. if ((Status == STATUS_LOCK_NOT_GRANTED) &&
  265. (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT))) {
  266. RxDbgTrace(0, Dbg, ("Cannot acquire Fcb\n", 0));
  267. RxContext->PostRequest = TRUE;
  268. }
  269. if (Status != STATUS_SUCCESS) {
  270. TryLowIo = FALSE;
  271. } else {
  272. ClearFlag(capFcb->FcbState,FCB_STATE_COLLAPSING_ENABLED);
  273. if (FsControlCode == FSCTL_SET_SPARSE) {
  274. if (NodeType(capFcb) == RDBSS_NTC_STORAGE_TYPE_FILE) {
  275. capFcb->Attributes |= FILE_ATTRIBUTE_SPARSE_FILE;
  276. capFobx->pSrvOpen->BufferingFlags = 0;
  277. RxChangeBufferingState(
  278. (PSRV_OPEN)capFobx->pSrvOpen,
  279. NULL,
  280. FALSE);
  281. } else {
  282. Status = STATUS_NOT_SUPPORTED;
  283. }
  284. }
  285. RxReleaseFcb(RxContext,capFcb);
  286. }
  287. }
  288. break;
  289. case FSCTL_SIS_COPYFILE:
  290. {
  291. //
  292. // This is the single-instance store copy FSCTL. The input
  293. // paths are fully qualified NT paths and must be made
  294. // relative to the share (which must be the same for both
  295. // names).
  296. //
  297. PSI_COPYFILE copyFile = capReqPacket->AssociatedIrp.SystemBuffer;
  298. ULONG bufferLength = capPARAMS->Parameters.FileSystemControl.InputBufferLength;
  299. PWCHAR source;
  300. PWCHAR dest;
  301. UNICODE_STRING sourceString;
  302. UNICODE_STRING destString;
  303. memset(&sourceString, 0, sizeof(sourceString));
  304. memset(&destString, 0, sizeof(destString));
  305. // Validate the buffer passed in
  306. if ((copyFile == NULL) ||
  307. (bufferLength < sizeof(SI_COPYFILE))) {
  308. Status = STATUS_INVALID_PARAMETER;
  309. TryLowIo = FALSE;
  310. break;
  311. }
  312. //
  313. // Get pointers to the two names.
  314. //
  315. source = copyFile->FileNameBuffer;
  316. dest = source + (copyFile->SourceFileNameLength / sizeof(WCHAR));
  317. //
  318. // Verify that the inputs are reasonable.
  319. //
  320. if ( (copyFile->SourceFileNameLength > bufferLength) ||
  321. (copyFile->DestinationFileNameLength > bufferLength) ||
  322. (copyFile->SourceFileNameLength < sizeof(WCHAR)) ||
  323. (copyFile->DestinationFileNameLength < sizeof(WCHAR)) ||
  324. ((FIELD_OFFSET(SI_COPYFILE,FileNameBuffer) +
  325. copyFile->SourceFileNameLength +
  326. copyFile->DestinationFileNameLength) > bufferLength) ||
  327. (*(source + (copyFile->SourceFileNameLength/sizeof(WCHAR)-1)) != 0) ||
  328. (*(dest + (copyFile->DestinationFileNameLength/sizeof(WCHAR)-1)) != 0) ) {
  329. Status = STATUS_INVALID_PARAMETER;
  330. TryLowIo = FALSE;
  331. break;
  332. }
  333. //
  334. // Perform symbolic link translation on the source and destination names,
  335. // and ensure that they translate to redirector names.
  336. //
  337. Status = TranslateSisFsctlName(
  338. source,
  339. &sourceString,
  340. capFcb->RxDeviceObject,
  341. &((PNET_ROOT)capFcb->pNetRoot)->PrefixEntry.Prefix );
  342. if ( !NT_SUCCESS(Status) ) {
  343. TryLowIo = FALSE;
  344. break;
  345. }
  346. Status = TranslateSisFsctlName(
  347. dest,
  348. &destString,
  349. capFcb->RxDeviceObject,
  350. &((PNET_ROOT)capFcb->pNetRoot)->PrefixEntry.Prefix );
  351. if ( !NT_SUCCESS(Status) ) {
  352. RtlFreeUnicodeString( &sourceString );
  353. TryLowIo = FALSE;
  354. break;
  355. }
  356. //
  357. // Convert the paths in the input buffer into share-relative
  358. // paths.
  359. //
  360. if ( (ULONG)(sourceString.MaximumLength + destString.MaximumLength) >
  361. (copyFile->SourceFileNameLength + copyFile->DestinationFileNameLength) ) {
  362. PSI_COPYFILE newCopyFile;
  363. ULONG length = FIELD_OFFSET(SI_COPYFILE,FileNameBuffer) +
  364. sourceString.MaximumLength + destString.MaximumLength;
  365. ASSERT( length > capPARAMS->Parameters.FileSystemControl.InputBufferLength );
  366. newCopyFile = RxAllocatePoolWithTag(
  367. NonPagedPool,
  368. length,
  369. RX_MISC_POOLTAG);
  370. if (newCopyFile == NULL) {
  371. Status = STATUS_INSUFFICIENT_RESOURCES;
  372. TryLowIo = FALSE;
  373. break;
  374. }
  375. newCopyFile->Flags = copyFile->Flags;
  376. ExFreePool( copyFile );
  377. copyFile = newCopyFile;
  378. capReqPacket->AssociatedIrp.SystemBuffer = copyFile;
  379. capPARAMS->Parameters.FileSystemControl.InputBufferLength = length;
  380. }
  381. copyFile->SourceFileNameLength = sourceString.MaximumLength;
  382. copyFile->DestinationFileNameLength = destString.MaximumLength;
  383. source = copyFile->FileNameBuffer;
  384. dest = source + (copyFile->SourceFileNameLength / sizeof(WCHAR));
  385. RtlCopyMemory( source, sourceString.Buffer, copyFile->SourceFileNameLength );
  386. RtlCopyMemory( dest, destString.Buffer, copyFile->DestinationFileNameLength );
  387. RtlFreeUnicodeString( &sourceString );
  388. RtlFreeUnicodeString( &destString );
  389. }
  390. break;
  391. default:
  392. break;
  393. }
  394. }
  395. break;
  396. default:
  397. break;
  398. }
  399. if (TryLowIo) {
  400. Status = RxLowIoFsCtlShell(RxContext);
  401. }
  402. if (RxContext->PostRequest) {
  403. Status = RxFsdPostRequest(RxContext);
  404. } else {
  405. if (Status == STATUS_PENDING) {
  406. RxDereferenceAndDeleteRxContext(RxContext);
  407. }
  408. }
  409. RxDbgTrace(-1, Dbg, ("RxCommonFileSystemControl -> %08lx\n", Status));
  410. return Status;
  411. }
  412. ULONG RxEnablePeekBackoff = 1;
  413. NTSTATUS
  414. RxLowIoFsCtlShell( RXCOMMON_SIGNATURE )
  415. /*++
  416. Routine Description:
  417. This is the common routine for implementing the user's requests made
  418. through NtFsControlFile.
  419. Arguments:
  420. Irp - Supplies the Irp being processed
  421. Return Value:
  422. NTSTATUS - The return status for the operation
  423. --*/
  424. {
  425. RxCaptureFcb;
  426. RxCaptureRequestPacket;
  427. RxCaptureParamBlock;
  428. RxCaptureFobx;
  429. RxCaptureFileObject;
  430. NTSTATUS Status = STATUS_SUCCESS;
  431. BOOLEAN PostToFsp = FALSE;
  432. NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
  433. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  434. ULONG FsControlCode = capPARAMS->Parameters.FileSystemControl.FsControlCode;
  435. BOOLEAN SubmitLowIoRequest = TRUE;
  436. PAGED_CODE();
  437. RxDbgTrace(+1, Dbg, ("RxLowIoFsCtlShell...\n", 0));
  438. RxDbgTrace( 0, Dbg, ("FsControlCode = %08lx\n", FsControlCode));
  439. RxInitializeLowIoContext(pLowIoContext,LOWIO_OP_FSCTL);
  440. switch (capPARAMS->MinorFunction) {
  441. case IRP_MN_USER_FS_REQUEST:
  442. {
  443. // The RDBSS filters out those FsCtls that can be handled without the intervention
  444. // of the mini rdr's. Currently all FsCtls are forwarded down to the mini rdr.
  445. switch (FsControlCode) {
  446. case FSCTL_PIPE_PEEK:
  447. {
  448. if ((capReqPacket->AssociatedIrp.SystemBuffer != NULL) &&
  449. (capPARAMS->Parameters.FileSystemControl.OutputBufferLength >=
  450. (ULONG)FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]))) {
  451. PFILE_PIPE_PEEK_BUFFER pPeekBuffer;
  452. pPeekBuffer = (PFILE_PIPE_PEEK_BUFFER)capReqPacket->AssociatedIrp.SystemBuffer;
  453. RtlZeroMemory(
  454. pPeekBuffer,
  455. capPARAMS->Parameters.FileSystemControl.OutputBufferLength);
  456. if (RxShouldRequestBeThrottled(&capFobx->Specific.NamedPipe.ThrottlingState) &&
  457. RxEnablePeekBackoff) {
  458. SubmitLowIoRequest = FALSE;
  459. RxDbgTrace(
  460. 0, (DEBUG_TRACE_ALWAYS),
  461. ("RxLowIoFsCtlShell: Throttling Peek Request\n"));
  462. capReqPacket->IoStatus.Information = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER,Data);
  463. pPeekBuffer->ReadDataAvailable = 0;
  464. pPeekBuffer->NamedPipeState = FILE_PIPE_CONNECTED_STATE;
  465. pPeekBuffer->NumberOfMessages = MAXULONG;
  466. pPeekBuffer->MessageLength = 0;
  467. RxContext->StoredStatus = STATUS_SUCCESS;
  468. Status = RxContext->StoredStatus;
  469. } else {
  470. RxDbgTrace(
  471. 0, (DEBUG_TRACE_ALWAYS),
  472. ("RxLowIoFsCtlShell: Throttling queries %ld\n",
  473. capFobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries));
  474. RxLog(
  475. ("ThrottlQs %lx %lx %lx %ld\n",
  476. RxContext,capFobx,&capFobx->Specific.NamedPipe.ThrottlingState,
  477. capFobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries));
  478. RxWmiLog(LOG,
  479. RxLowIoFsCtlShell,
  480. LOGPTR(RxContext)
  481. LOGPTR(capFobx)
  482. LOGULONG(capFobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries));
  483. }
  484. } else {
  485. RxContext->StoredStatus = STATUS_INVALID_PARAMETER;
  486. }
  487. }
  488. break;
  489. default:
  490. break;
  491. }
  492. }
  493. break;
  494. default:
  495. break;
  496. }
  497. if (SubmitLowIoRequest) {
  498. Status = RxLowIoSubmit(RxContext,RxLowIoFsCtlShellCompletion);
  499. }
  500. RxDbgTrace(-1, Dbg, ("RxLowIoFsCtlShell -> %08lx\n", Status ));
  501. return Status;
  502. }
  503. NTSTATUS
  504. RxLowIoFsCtlShellCompletion( RXCOMMON_SIGNATURE )
  505. /*++
  506. Routine Description:
  507. This is the completion routine for FSCTL requests passed down to the mini rdr
  508. Arguments:
  509. Irp - Supplies the Irp being processed
  510. Return Value:
  511. NTSTATUS - The return status for the operation
  512. --*/
  513. {
  514. RxCaptureRequestPacket;
  515. RxCaptureFcb;
  516. RxCaptureFobx;
  517. NTSTATUS Status;
  518. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  519. ULONG FsControlCode = pLowIoContext->ParamsFor.FsCtl.FsControlCode;
  520. PAGED_CODE();
  521. Status = RxContext->StoredStatus;
  522. RxDbgTrace(+1, Dbg, ("RxLowIoFsCtlShellCompletion entry Status = %08lx\n", Status));
  523. switch (FsControlCode) {
  524. case FSCTL_PIPE_PEEK:
  525. {
  526. if ((Status == STATUS_SUCCESS) ||
  527. (Status == STATUS_BUFFER_OVERFLOW)) {
  528. // In the case of Peek operations a throttle mechanism is in place to
  529. // prevent the network from being flodded with requests which return 0
  530. // bytes.
  531. PFILE_PIPE_PEEK_BUFFER pPeekBuffer;
  532. pPeekBuffer = (PFILE_PIPE_PEEK_BUFFER)pLowIoContext->ParamsFor.FsCtl.pOutputBuffer;
  533. if (pPeekBuffer->ReadDataAvailable == 0) {
  534. // The peek request returned zero bytes.
  535. RxDbgTrace(0, (DEBUG_TRACE_ALWAYS), ("RxLowIoFsCtlShellCompletion: Enabling Throttling for Peek Request\n"));
  536. RxInitiateOrContinueThrottling(&capFobx->Specific.NamedPipe.ThrottlingState);
  537. RxLog(("ThrottlYes %lx %lx %lx %ld\n",
  538. RxContext,capFobx,&capFobx->Specific.NamedPipe.ThrottlingState,
  539. capFobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries));
  540. RxWmiLog(LOG,
  541. RxLowIoFsCtlShellCompletion_1,
  542. LOGPTR(RxContext)
  543. LOGPTR(capFobx)
  544. LOGULONG(capFobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries));
  545. } else {
  546. RxDbgTrace(0, (DEBUG_TRACE_ALWAYS), ("RxLowIoFsCtlShellCompletion: Disabling Throttling for Peek Request\n"));
  547. RxTerminateThrottling(&capFobx->Specific.NamedPipe.ThrottlingState);
  548. RxLog(("ThrottlNo %lx %lx %lx %ld\n",
  549. RxContext,capFobx,&capFobx->Specific.NamedPipe.ThrottlingState,
  550. capFobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries));
  551. RxWmiLog(LOG,
  552. RxLowIoFsCtlShellCompletion_2,
  553. LOGPTR(RxContext)
  554. LOGPTR(capFobx)
  555. LOGULONG(capFobx->Specific.NamedPipe.ThrottlingState.NumberOfQueries));
  556. }
  557. capReqPacket->IoStatus.Information = RxContext->InformationToReturn;
  558. }
  559. }
  560. break;
  561. default:
  562. if ((Status == STATUS_BUFFER_OVERFLOW) ||
  563. (Status == STATUS_SUCCESS)) {
  564. capReqPacket->IoStatus.Information = RxContext->InformationToReturn;
  565. }
  566. break;
  567. }
  568. capReqPacket->IoStatus.Status = Status;
  569. RxDbgTrace(-1, Dbg, ("RxLowIoFsCtlShellCompletion exit Status = %08lx\n", Status));
  570. return Status;
  571. }
  572. NTSTATUS
  573. TranslateSisFsctlName(
  574. IN PWCHAR InputName,
  575. OUT PUNICODE_STRING RelativeName,
  576. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  577. IN PUNICODE_STRING NetRootName
  578. )
  579. /*++
  580. Routine Description:
  581. This routine converts a fully qualified name into a share-relative name.
  582. It is used to munge the input buffer of the SIS_COPYFILE FSCTL, which
  583. takes two fully qualified NT paths as inputs.
  584. The routine operates by translating the input path as necessary to get
  585. to an actual device name, verifying that the target device is the
  586. redirector, and verifying that the target server/share is the one on
  587. which the I/O was issued.
  588. Arguments:
  589. Return Value:
  590. --*/
  591. {
  592. NTSTATUS status;
  593. UNICODE_STRING currentString;
  594. UNICODE_STRING testString;
  595. PWCHAR p;
  596. PWCHAR q;
  597. HANDLE handle;
  598. OBJECT_ATTRIBUTES objectAttributes;
  599. PWCHAR translationBuffer = NULL;
  600. ULONG translationLength;
  601. ULONG remainingLength;
  602. ULONG resultLength;
  603. RtlInitUnicodeString( &currentString, InputName );
  604. p = currentString.Buffer;
  605. if (!p)
  606. {
  607. return STATUS_INVALID_PARAMETER;
  608. }
  609. if ( (*p == L'\\') && (*(p+1) == L'\\') ) {
  610. //
  611. // Special case for name that starts with \\ (i.e., a UNC name):
  612. // assume that the \\ would translate to the redirector's name and
  613. // skip the translation phase.
  614. //
  615. p++;
  616. } else {
  617. //
  618. // The outer loop is executed each time a translation occurs.
  619. //
  620. while ( TRUE ) {
  621. //
  622. // Walk through any directory objects at the beginning of the string.
  623. //
  624. if ( *p != L'\\' ) {
  625. status = STATUS_OBJECT_NAME_INVALID;
  626. goto error_exit;
  627. }
  628. p++;
  629. //
  630. // The inner loop is executed while walking the directory tree.
  631. //
  632. while ( TRUE ) {
  633. q = wcschr( p, L'\\' );
  634. if ( q == NULL ) {
  635. testString.Length = currentString.Length;
  636. } else {
  637. testString.Length = (USHORT)(q - currentString.Buffer) * sizeof(WCHAR);
  638. }
  639. testString.Buffer = currentString.Buffer;
  640. remainingLength = currentString.Length - testString.Length + sizeof(WCHAR);
  641. InitializeObjectAttributes(
  642. &objectAttributes,
  643. &testString,
  644. OBJ_CASE_INSENSITIVE,
  645. NULL,
  646. NULL
  647. );
  648. status = ZwOpenDirectoryObject( &handle, DIRECTORY_TRAVERSE, &objectAttributes );
  649. //
  650. // If we were unable to open the object as a directory, then break out
  651. // of the inner loop and try to open it as a symbolic link.
  652. //
  653. if ( !NT_SUCCESS(status) ) {
  654. if ( status != STATUS_OBJECT_TYPE_MISMATCH ) {
  655. goto error_exit;
  656. }
  657. break;
  658. }
  659. //
  660. // We opened the directory. Close it and try the next element of the path.
  661. //
  662. ZwClose( handle );
  663. if ( q == NULL ) {
  664. //
  665. // The last element of the name is an object directory. Clearly, this
  666. // is not a redirector path.
  667. //
  668. status = STATUS_OBJECT_TYPE_MISMATCH;
  669. goto error_exit;
  670. }
  671. p = q + 1;
  672. }
  673. //
  674. // Try to open the current name as a symbolic link.
  675. //
  676. status = ZwOpenSymbolicLinkObject( &handle, SYMBOLIC_LINK_QUERY, &objectAttributes );
  677. //
  678. // If we were unable to open the object as a symbolic link, then break out of
  679. // the outer loop and verify that this is a redirector name.
  680. //
  681. if ( !NT_SUCCESS(status) ) {
  682. if ( status != STATUS_OBJECT_TYPE_MISMATCH ) {
  683. goto error_exit;
  684. }
  685. break;
  686. }
  687. //
  688. // The object is a symbolic link. Translate it.
  689. //
  690. testString.MaximumLength = 0;
  691. status = ZwQuerySymbolicLinkObject( handle, &testString, &translationLength );
  692. if ( !NT_SUCCESS(status) && (status != STATUS_BUFFER_TOO_SMALL) ) {
  693. ZwClose( handle );
  694. goto error_exit;
  695. }
  696. resultLength = translationLength + remainingLength;
  697. p = RxAllocatePoolWithTag( PagedPool|POOL_COLD_ALLOCATION, resultLength, RX_MISC_POOLTAG );
  698. if ( p == NULL ) {
  699. status = STATUS_INSUFFICIENT_RESOURCES;
  700. ZwClose( handle );
  701. goto error_exit;
  702. }
  703. testString.MaximumLength = (USHORT)translationLength;
  704. testString.Buffer = p;
  705. status = ZwQuerySymbolicLinkObject( handle, &testString, NULL );
  706. ZwClose( handle );
  707. if ( !NT_SUCCESS(status) ) {
  708. RxFreePool( p );
  709. goto error_exit;
  710. }
  711. if ( testString.Length > translationLength ) {
  712. status = STATUS_OBJECT_NAME_INVALID;
  713. RxFreePool( p );
  714. goto error_exit;
  715. }
  716. RtlCopyMemory( (PCHAR)p + testString.Length, q, remainingLength );
  717. currentString.Buffer = p;
  718. currentString.Length = (USHORT)(resultLength - sizeof(WCHAR));
  719. currentString.MaximumLength = (USHORT)resultLength;
  720. if ( translationBuffer != NULL ) {
  721. RxFreePool( translationBuffer );
  722. }
  723. translationBuffer = p;
  724. }
  725. //
  726. // We have a result name. Verify that it is a redirector name.
  727. //
  728. if ( !RtlPrefixUnicodeString( &RxDeviceObject->DeviceName, &currentString, TRUE ) ) {
  729. status = STATUS_OBJECT_NAME_INVALID;
  730. goto error_exit;
  731. }
  732. //
  733. // Skip over the redirector device name.
  734. //
  735. p = currentString.Buffer + (RxDeviceObject->DeviceName.Length / sizeof(WCHAR));
  736. if ( *p != L'\\' ) {
  737. status = STATUS_OBJECT_NAME_INVALID;
  738. goto error_exit;
  739. }
  740. //
  741. // Skip over the drive letter, if present.
  742. //
  743. if ( *(p + 1) == L';' ) {
  744. p = wcschr( ++p, L'\\' );
  745. if ( p == NULL ) {
  746. status = STATUS_OBJECT_NAME_INVALID;
  747. goto error_exit;
  748. }
  749. }
  750. }
  751. //
  752. // Verify that the next part of the string is the correct net root name.
  753. //
  754. currentString.Length -= (USHORT)(p - currentString.Buffer) * sizeof(WCHAR);
  755. currentString.Buffer = p;
  756. if ( !RtlPrefixUnicodeString( NetRootName, &currentString, TRUE ) ) {
  757. status = STATUS_OBJECT_NAME_INVALID;
  758. goto error_exit;
  759. }
  760. p += NetRootName->Length / sizeof(WCHAR);
  761. if ( *p != L'\\' ) {
  762. status = STATUS_OBJECT_NAME_INVALID;
  763. goto error_exit;
  764. }
  765. p++;
  766. if ( *p == 0 ) {
  767. status = STATUS_OBJECT_NAME_INVALID;
  768. goto error_exit;
  769. }
  770. //
  771. // Copy the rest of the string after the redirector name to a new buffer.
  772. //
  773. RtlCreateUnicodeString( RelativeName, p );
  774. status = STATUS_SUCCESS;
  775. error_exit:
  776. if ( translationBuffer != NULL ) {
  777. RxFreePool( translationBuffer );
  778. }
  779. return status;
  780. }