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.

2002 lines
65 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. sifsctl.c
  5. Abstract:
  6. File system control routines for the single instance store
  7. Authors:
  8. Bill Bolosky, Summer, 1997
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "sip.h"
  14. #ifdef ALLOC_PRAGMA
  15. #endif // ALLOC_PRAGMA
  16. typedef struct _SIS_DISMOUNT_CONTEXT {
  17. WORK_QUEUE_ITEM workItem[1];
  18. PDEVICE_EXTENSION deviceExtension;
  19. } SIS_DISMOUNT_CONTEXT, *PSIS_DISMOUNT_CONTEXT;
  20. VOID
  21. SiDismountWork(
  22. IN PVOID parameter)
  23. {
  24. PSIS_DISMOUNT_CONTEXT dismountContext = parameter;
  25. #if DBG
  26. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_DISMOUNT_TRACE_LEVEL,
  27. "SIS: SiDismountWork\n");
  28. #endif // DBG
  29. //
  30. // We're in a system thread, so we don't need to diable APCs before taking the
  31. // GrovelerFileObjectResource.
  32. //
  33. ASSERT(PsIsSystemThread(PsGetCurrentThread()));
  34. ExAcquireResourceExclusiveLite(dismountContext->deviceExtension->GrovelerFileObjectResource, TRUE);
  35. if (NULL != dismountContext->deviceExtension->GrovelerFileHandle) {
  36. NtClose(dismountContext->deviceExtension->GrovelerFileHandle);
  37. dismountContext->deviceExtension->GrovelerFileHandle = NULL;
  38. #if DBG
  39. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_DISMOUNT_TRACE_LEVEL,
  40. "SIS: SiDismountWork closed GrovelerFile handle\n");
  41. #endif // DBG
  42. }
  43. if (NULL != dismountContext->deviceExtension->GrovelerFileObject) {
  44. ObDereferenceObject(dismountContext->deviceExtension->GrovelerFileObject);
  45. dismountContext->deviceExtension->GrovelerFileObject = NULL;
  46. #if DBG
  47. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_DISMOUNT_TRACE_LEVEL,
  48. "SIS: SiDismountWork closed GrovelerFile object\n");
  49. #endif // DBG
  50. }
  51. ExReleaseResourceLite(dismountContext->deviceExtension->GrovelerFileObjectResource);
  52. ExFreePool(dismountContext);
  53. }
  54. NTSTATUS
  55. SiDismountVolumeCompletion(
  56. IN PDEVICE_OBJECT DeviceObject,
  57. IN PIRP Irp,
  58. IN PVOID Context)
  59. {
  60. PDEVICE_EXTENSION deviceExtension = Context;
  61. PSIS_DISMOUNT_CONTEXT dismountContext;
  62. UNREFERENCED_PARAMETER( DeviceObject );
  63. UNREFERENCED_PARAMETER( Irp );
  64. ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
  65. ASSERT(STATUS_PENDING != Irp->IoStatus.Status);
  66. dismountContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(SIS_DISMOUNT_CONTEXT), ' siS');
  67. if (NULL != dismountContext) {
  68. SIS_MARK_POINT_ULONG(dismountContext);
  69. #if DBG
  70. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_DISMOUNT_TRACE_LEVEL,
  71. "SIS: SiDismountCompletion: queueing dismount work\n");
  72. #endif // DBG
  73. ExInitializeWorkItem(dismountContext->workItem, SiDismountWork, dismountContext);
  74. dismountContext->deviceExtension = deviceExtension;
  75. ExQueueWorkItem(dismountContext->workItem,CriticalWorkQueue);
  76. } else {
  77. //
  78. // Too bad, we'll just dribble it.
  79. //
  80. #if DBG
  81. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_ERROR_LEVEL,
  82. "SIS: SiDismountCompletion: Unable to allocate dismount context\n");
  83. #endif // DBG
  84. SIS_MARK_POINT();
  85. }
  86. return STATUS_SUCCESS;
  87. }
  88. NTSTATUS
  89. SipDismountVolume(
  90. IN PDEVICE_OBJECT DeviceObject,
  91. IN PIRP Irp)
  92. /*++
  93. Routine Description:
  94. Someone is trying a dismount volume request. We can't tell if it's valid, so
  95. trap the completion. If it completes successfully, then we need to clean up our
  96. state.
  97. Arguments:
  98. DeviceObject - Pointer to the device object for this driver.
  99. Irp - Pointer to the request packet representing the FSCTL_DISMOUNT_VOLUME
  100. Return Value:
  101. The function value is the status of the operation.
  102. --*/
  103. {
  104. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  105. PIO_STACK_LOCATION nextIrpSp = IoGetNextIrpStackLocation(Irp);
  106. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  107. #if DBG
  108. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_DISMOUNT_TRACE_LEVEL,
  109. "SIS: SipDismountVolume: called, DO 0x%x, Irp 0x%x\n",DeviceObject, Irp);
  110. #endif // DBG
  111. RtlMoveMemory(nextIrpSp,irpSp,sizeof(IO_STACK_LOCATION));
  112. IoSetCompletionRoutine(
  113. Irp,
  114. SiDismountVolumeCompletion,
  115. DeviceObject->DeviceExtension,
  116. TRUE, // invoke on success
  117. FALSE, // invoke on error
  118. FALSE); // invoke on cancel
  119. return IoCallDriver(deviceExtension->AttachedToDeviceObject, Irp);
  120. }
  121. NTSTATUS
  122. SiUserSetSISReparsePointCompletion(
  123. IN PDEVICE_OBJECT DeviceObject,
  124. IN PIRP Irp,
  125. IN PVOID Context)
  126. {
  127. PKEVENT event = (PKEVENT)Context;
  128. UNREFERENCED_PARAMETER( DeviceObject );
  129. Irp->PendingReturned = FALSE;
  130. KeSetEvent(event, IO_NO_INCREMENT, FALSE);
  131. return STATUS_MORE_PROCESSING_REQUIRED;
  132. }
  133. NTSTATUS
  134. SipUserSetSISReparsePoint(
  135. IN PDEVICE_OBJECT DeviceObject,
  136. IN PIRP Irp)
  137. {
  138. PREPARSE_DATA_BUFFER reparseBuffer = Irp->AssociatedIrp.SystemBuffer;
  139. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  140. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  141. PIO_STACK_LOCATION nextIrpSp;
  142. ULONG InputBufferLength = irpSp->Parameters.FileSystemControl.InputBufferLength;
  143. BOOLEAN validReparseData;
  144. CSID CSid;
  145. LINK_INDEX LinkIndex;
  146. LARGE_INTEGER CSFileNtfsId;
  147. LARGE_INTEGER LinkFileNtfsId;
  148. LONGLONG CSFileChecksum;
  149. PSIS_CS_FILE CSFile = NULL;
  150. NTSTATUS status;
  151. ULONG returnedLength;
  152. BOOLEAN prepared = FALSE;
  153. LINK_INDEX newLinkIndex;
  154. KEVENT event[1];
  155. PSIS_PER_LINK perLink = NULL;
  156. FILE_ALL_INFORMATION allInfo[1];
  157. BOOLEAN EligibleForPartialFinalCopy;
  158. KIRQL OldIrql;
  159. PSIS_PER_FILE_OBJECT perFO;
  160. PSIS_SCB scb;
  161. SIS_MARK_POINT();
  162. if (!SipCheckPhase2(deviceExtension)) {
  163. //
  164. // This isn't a SIS enabled volume, or something else bad happened. Just let it go.
  165. //
  166. SIS_MARK_POINT();
  167. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  168. }
  169. ASSERT(InputBufferLength >= SIS_REPARSE_DATA_SIZE); // must have been checked by caller
  170. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  171. //
  172. // This is a SIS reparse point. Figure out whether it's valid.
  173. //
  174. validReparseData = SipIndicesFromReparseBuffer(
  175. reparseBuffer,
  176. &CSid,
  177. &LinkIndex,
  178. &CSFileNtfsId,
  179. &LinkFileNtfsId,
  180. &CSFileChecksum,
  181. &EligibleForPartialFinalCopy,
  182. NULL);
  183. if (SipIsFileObjectSIS(irpSp->FileObject, DeviceObject, FindActive, &perFO, &scb)) {
  184. perLink = scb->PerLink;
  185. //
  186. // This is a SIS file object. If we're setting a reparse point where the CSid and
  187. // CSFile checksum are the same as the current file, assume that it's restore doing
  188. // the set, and just clear the dirty bit and leave the file be. If someone other
  189. // than restore does this, it's harmless to anyone but them.
  190. //
  191. if ((!validReparseData) || (!IsEqualGUID(&CSid, &perLink->CsFile->CSid)) || CSFileChecksum != perLink->CsFile->Checksum) {
  192. //
  193. // The user is trying to set to an invalid reparse point, a different file or
  194. // has a bogus checksum. This isn't implemented.
  195. //
  196. SIS_MARK_POINT_ULONG(scb);
  197. #if DBG
  198. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_ERROR_LEVEL,
  199. "SIS: SipUserSetSISReparsePoint: unimplemented set\n");
  200. #endif // DBG
  201. Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
  202. Irp->IoStatus.Information = 0;
  203. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  204. return STATUS_NOT_IMPLEMENTED;
  205. }
  206. KeAcquireSpinLock(perLink->SpinLock, &OldIrql);
  207. if ((perLink->Flags &
  208. ( SIS_PER_LINK_BACKPOINTER_GONE
  209. | SIS_PER_LINK_FINAL_COPY
  210. | SIS_PER_LINK_FINAL_COPY_DONE
  211. | SIS_PER_LINK_OVERWRITTEN
  212. | SIS_PER_LINK_FILE_DELETED
  213. | SIS_PER_LINK_DELETE_DISPOSITION_SET)) == 0) {
  214. SIS_MARK_POINT_ULONG(scb);
  215. Irp->IoStatus.Status = STATUS_SUCCESS;
  216. Irp->IoStatus.Information = 0;
  217. perLink->Flags &= ~SIS_PER_LINK_DIRTY;
  218. } else {
  219. SIS_MARK_POINT_ULONG(scb);
  220. #if DBG
  221. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_ERROR_LEVEL,
  222. "SIS: SipUserSetSISReparsePoint: trying to re-set reparse point on file in funny state\n");
  223. #endif // DBG
  224. Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
  225. Irp->IoStatus.Information = 0;
  226. }
  227. KeReleaseSpinLock(perLink->SpinLock, OldIrql);
  228. status = Irp->IoStatus.Status;
  229. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  230. return status;
  231. }
  232. if (!validReparseData) {
  233. //
  234. // It's not a valid reparse point, so we don't update our backpointers. Just let
  235. // it get set, and we'll delete it if anyone tries to open the resulting file.
  236. //
  237. SIS_MARK_POINT();
  238. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  239. }
  240. //
  241. // Rewrite reparse point in the buffer pointed to by the irp to have a new, unused link index
  242. // which prevents problems with files existing on disk with link indices > MaxIndex.
  243. //
  244. status = SipAllocateIndex(deviceExtension,&newLinkIndex);
  245. if (!NT_SUCCESS(status)) {
  246. SIS_MARK_POINT_ULONG(status);
  247. newLinkIndex.QuadPart = 0;
  248. newLinkIndex.Check = 0;
  249. }
  250. if (!SipIndicesIntoReparseBuffer(
  251. reparseBuffer,
  252. &CSid,
  253. &newLinkIndex,
  254. &CSFileNtfsId,
  255. &LinkFileNtfsId,
  256. &CSFileChecksum,
  257. EligibleForPartialFinalCopy)) {
  258. status = STATUS_DRIVER_INTERNAL_ERROR;
  259. SIS_MARK_POINT();
  260. goto Error;
  261. }
  262. //
  263. // Get the file information.
  264. //
  265. status = SipQueryInformationFile(
  266. irpSp->FileObject,
  267. DeviceObject,
  268. FileAllInformation,
  269. sizeof(FILE_ALL_INFORMATION),
  270. allInfo,
  271. &returnedLength);
  272. if ((STATUS_BUFFER_OVERFLOW == status) && (returnedLength == sizeof(FILE_ALL_INFORMATION))) {
  273. //
  274. // We expect to get a buffer overflow, because of the file name return. Treat this
  275. // like success.
  276. //
  277. SIS_MARK_POINT();
  278. status = STATUS_SUCCESS;
  279. }
  280. if (!NT_SUCCESS(status)) {
  281. SIS_MARK_POINT_ULONG(status);
  282. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  283. }
  284. //
  285. // If this is a sparse file and eliginle for partial final copy, then zero out any
  286. // trailing unallocated region.
  287. //
  288. if (EligibleForPartialFinalCopy && (allInfo->BasicInformation.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE)) {
  289. #define NUM_RANGES_PER_ITERATION 10
  290. FILE_ALLOCATED_RANGE_BUFFER inArb[1];
  291. FILE_ALLOCATED_RANGE_BUFFER outArb[NUM_RANGES_PER_ITERATION];
  292. FILE_ZERO_DATA_INFORMATION zeroData[1];
  293. unsigned allocatedRangesReturned;
  294. for (inArb->FileOffset.QuadPart = 0;
  295. inArb->FileOffset.QuadPart < allInfo->StandardInformation.EndOfFile.QuadPart;
  296. ) {
  297. //
  298. // Query the range.
  299. //
  300. inArb->Length.QuadPart = MAXLONGLONG;
  301. status = SipFsControlFile(
  302. irpSp->FileObject,
  303. DeviceObject,
  304. FSCTL_QUERY_ALLOCATED_RANGES,
  305. inArb,
  306. sizeof(FILE_ALLOCATED_RANGE_BUFFER),
  307. outArb,
  308. sizeof(FILE_ALLOCATED_RANGE_BUFFER) * NUM_RANGES_PER_ITERATION,
  309. &returnedLength);
  310. if (!NT_SUCCESS(status)) {
  311. //
  312. // Just skip this part.
  313. //
  314. SIS_MARK_POINT_ULONG(status);
  315. goto VDLExtended;
  316. }
  317. ASSERT(returnedLength % sizeof(FILE_ALLOCATED_RANGE_BUFFER) == 0);
  318. allocatedRangesReturned = returnedLength / sizeof(FILE_ALLOCATED_RANGE_BUFFER);
  319. if (allocatedRangesReturned < NUM_RANGES_PER_ITERATION) {
  320. if ((1 == allocatedRangesReturned) &&
  321. (0 == inArb->FileOffset.QuadPart) &&
  322. (0 == outArb[0].FileOffset.QuadPart) &&
  323. (allInfo->StandardInformation.EndOfFile.QuadPart <= outArb[0].Length.QuadPart) &&
  324. (deviceExtension->FilesystemBytesPerFileRecordSegment.QuadPart >= allInfo->StandardInformation.EndOfFile.QuadPart)) {
  325. //
  326. // This is a special case. This is a small file with a single allocated range extending from
  327. // the start of the file to the end. It's possibly a resident stream, so we FSCTL_SET_ZERO_DATA
  328. // won't necessarily make it go away. We just deal with this by make it not be eligible for partial
  329. // final copy.
  330. //
  331. EligibleForPartialFinalCopy = FALSE;
  332. } else if (allocatedRangesReturned > 0) {
  333. inArb->FileOffset.QuadPart =
  334. outArb[allocatedRangesReturned-1].FileOffset.QuadPart + outArb[allocatedRangesReturned-1].Length.QuadPart;
  335. }
  336. //
  337. // Zero out the remainder of the file, in order to extend ValidDataLength.
  338. //
  339. zeroData->FileOffset = inArb->FileOffset;
  340. zeroData->BeyondFinalZero.QuadPart = MAXLONGLONG;
  341. status = SipFsControlFile(
  342. irpSp->FileObject,
  343. DeviceObject,
  344. FSCTL_SET_ZERO_DATA,
  345. zeroData,
  346. sizeof(FILE_ZERO_DATA_INFORMATION),
  347. NULL, // output buffer
  348. 0, // o.b. length
  349. NULL); // returned length
  350. #if DBG
  351. if (!NT_SUCCESS(status)) {
  352. SIS_MARK_POINT_ULONG(status);
  353. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_ERROR_LEVEL,
  354. "SIS: SipUserSetSISReparsePoint: unable to zero data, 0x%x\n",status);
  355. }
  356. #endif // DBG
  357. goto VDLExtended;
  358. }
  359. ASSERT(allocatedRangesReturned == NUM_RANGES_PER_ITERATION);
  360. inArb->FileOffset.QuadPart =
  361. outArb[NUM_RANGES_PER_ITERATION-1].FileOffset.QuadPart + outArb[NUM_RANGES_PER_ITERATION-1].Length.QuadPart;
  362. }
  363. #undef NUM_RANGES_PER_ITERATION
  364. }
  365. VDLExtended:
  366. CSFile = SipLookupCSFile(
  367. &CSid,
  368. &CSFileNtfsId,
  369. DeviceObject);
  370. if (NULL == CSFile) {
  371. //
  372. // We couldn't allocate a CSFile, just fail the request.
  373. //
  374. SIS_MARK_POINT();
  375. status = STATUS_INSUFFICIENT_RESOURCES;
  376. goto Error;
  377. }
  378. //
  379. // Make sure the common store file is open.
  380. //
  381. status = SipAssureCSFileOpen(CSFile);
  382. if (!NT_SUCCESS(status)) {
  383. //
  384. // It wasn't there or we couldn't get to it for some reason, just let the set proceed.
  385. //
  386. SIS_MARK_POINT_ULONG(status);
  387. SipDereferenceCSFile(CSFile);
  388. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  389. }
  390. //
  391. // Check the checksum.
  392. //
  393. if (CSFile->Checksum != CSFileChecksum) {
  394. SIS_MARK_POINT();
  395. //
  396. // The checksum's bogus, so the reparse point isn't good for much. Let the set
  397. // proceed anyway. When the user tries to open this file, we'll delete the reparse
  398. // point.
  399. //
  400. SipDereferenceCSFile(CSFile);
  401. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  402. }
  403. //
  404. // Prepare for a refcount change, allocate the new link index,
  405. // and create a new perLink.
  406. //
  407. status = SipPrepareRefcountChangeAndAllocateNewPerLink(
  408. CSFile,
  409. &allInfo->InternalInformation.IndexNumber,
  410. DeviceObject,
  411. &newLinkIndex,
  412. &perLink,
  413. &prepared);
  414. if (!NT_SUCCESS(status)) {
  415. SIS_MARK_POINT_ULONG(status);
  416. goto Error;
  417. }
  418. //
  419. // Construct the new reparse point in the buffer pointed to by the irp.
  420. //
  421. if (!SipIndicesIntoReparseBuffer(
  422. reparseBuffer,
  423. &CSFile->CSid,
  424. &newLinkIndex,
  425. &CSFile->CSFileNtfsId,
  426. &allInfo->InternalInformation.IndexNumber,
  427. &CSFileChecksum,
  428. EligibleForPartialFinalCopy)) {
  429. status = STATUS_DRIVER_INTERNAL_ERROR;
  430. SIS_MARK_POINT();
  431. goto Error;
  432. }
  433. //
  434. // Set an event to synchronize completion.
  435. //
  436. KeInitializeEvent(event, NotificationEvent, FALSE);
  437. //
  438. // Set up the irp
  439. //
  440. nextIrpSp = IoGetNextIrpStackLocation(Irp);
  441. RtlCopyMemory(nextIrpSp, irpSp, sizeof(IO_STACK_LOCATION));
  442. IoSetCompletionRoutine(
  443. Irp,
  444. SiUserSetSISReparsePointCompletion,
  445. event,
  446. TRUE,
  447. TRUE,
  448. TRUE);
  449. IoCallDriver(deviceExtension->AttachedToDeviceObject, Irp);
  450. status = KeWaitForSingleObject(event, Executive, KernelMode, FALSE, NULL);
  451. ASSERT(STATUS_SUCCESS == status);
  452. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  453. SipCompleteCSRefcountChange(
  454. NULL,
  455. NULL,
  456. CSFile,
  457. FALSE,
  458. TRUE);
  459. } else {
  460. status = SipCompleteCSRefcountChange(
  461. perLink,
  462. &perLink->Index,
  463. CSFile,
  464. TRUE,
  465. TRUE);
  466. if (!NT_SUCCESS(status)) {
  467. //
  468. // We know we just messeded up, so just kick off the volume
  469. // check right away.
  470. //
  471. SIS_MARK_POINT_ULONG(status);
  472. SipCheckVolume(deviceExtension);
  473. }
  474. }
  475. SipDereferencePerLink(perLink);
  476. SipDereferenceCSFile(CSFile);
  477. #if DBG
  478. perLink = NULL;
  479. CSFile = NULL;
  480. #endif // DBG
  481. status = Irp->IoStatus.Status;
  482. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  483. return status;
  484. Error:
  485. Irp->IoStatus.Status = status;
  486. Irp->IoStatus.Information = 0;
  487. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  488. if (prepared) {
  489. ASSERT(NULL != CSFile);
  490. status = SipCompleteCSRefcountChange(
  491. NULL,
  492. NULL,
  493. CSFile,
  494. FALSE,
  495. TRUE);
  496. if (!NT_SUCCESS(status)) {
  497. SIS_MARK_POINT_ULONG(status);
  498. }
  499. }
  500. if (NULL != CSFile) {
  501. SipDereferenceCSFile(CSFile);
  502. #if DBG
  503. CSFile = NULL;
  504. #endif // DBG
  505. }
  506. if (NULL != perLink) {
  507. SipDereferencePerLink(perLink);
  508. #if DBG
  509. perLink = NULL;
  510. #endif // DBG
  511. }
  512. return status;
  513. }
  514. NTSTATUS
  515. SipQueryAllocatedRanges(
  516. IN PDEVICE_OBJECT DeviceObject,
  517. IN PIRP Irp)
  518. /*++
  519. Routine Description:
  520. This routine implements FSCTL_QUERY_ALLOCATED_RANGES for SIS links. SIS links
  521. that weren't opened FILE_OPEN_REPARSE_POINT look like they're completely allocated
  522. (ie., that they're all data and no holes). This function returns such.
  523. We complete the irp and return the appropriate status.
  524. This code is stolen from NTFS.
  525. Arguments:
  526. DeviceObject - Pointer to the device object for this driver.
  527. Irp - Pointer to the request packet representing the FSCTL_QUERY_ALLOCATED_RANGES.
  528. Return Value:
  529. The function value is the status of the operation.
  530. --*/
  531. {
  532. BOOLEAN validUserBuffer = TRUE;
  533. PFILE_ALLOCATED_RANGE_BUFFER OutputBuffer;
  534. LONGLONG Length, StartingOffset;
  535. NTSTATUS status;
  536. FILE_STANDARD_INFORMATION standardInformation[1];
  537. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  538. ULONG returnedLength;
  539. ULONG RemainingBytes;
  540. Irp->IoStatus.Information = 0;
  541. //
  542. // Query the file's standard information to get the length.
  543. //
  544. status = SipQueryInformationFile(
  545. IrpSp->FileObject,
  546. DeviceObject,
  547. FileStandardInformation,
  548. sizeof(FILE_STANDARD_INFORMATION),
  549. standardInformation,
  550. &returnedLength);
  551. if (!NT_SUCCESS(status)) {
  552. SIS_MARK_POINT_ULONG(status);
  553. goto done;
  554. }
  555. ASSERT(returnedLength == sizeof(FILE_STANDARD_INFORMATION));
  556. //
  557. // This is a METHOD_NEITHER buffer, so we have to be careful in touching it.
  558. // Code to check it out stolen from NTFS.
  559. //
  560. try {
  561. if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof(FILE_ALLOCATED_RANGE_BUFFER)) {
  562. status = STATUS_INVALID_PARAMETER;
  563. leave;
  564. }
  565. RemainingBytes = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  566. OutputBuffer = (PFILE_ALLOCATED_RANGE_BUFFER)SipMapUserBuffer(Irp);
  567. if (NULL == OutputBuffer) {
  568. //
  569. // We couldn't map the user buffer because of resource shortages.
  570. //
  571. SIS_MARK_POINT_ULONG(IrpSp->FileObject);
  572. status = STATUS_INSUFFICIENT_RESOURCES;
  573. goto done;
  574. }
  575. if (KernelMode != Irp->RequestorMode) {
  576. ProbeForRead( IrpSp->Parameters.FileSystemControl.Type3InputBuffer,
  577. IrpSp->Parameters.FileSystemControl.InputBufferLength,
  578. sizeof( ULONG ));
  579. ProbeForWrite( OutputBuffer, RemainingBytes, sizeof( ULONG ));
  580. } else if (!IsLongAligned( IrpSp->Parameters.FileSystemControl.Type3InputBuffer ) ||
  581. !IsLongAligned( OutputBuffer )) {
  582. validUserBuffer = FALSE;
  583. leave;
  584. }
  585. StartingOffset = ((PFILE_ALLOCATED_RANGE_BUFFER) IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->FileOffset.QuadPart;
  586. Length = ((PFILE_ALLOCATED_RANGE_BUFFER) IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->Length.QuadPart;
  587. //
  588. // Check that the input parameters are valid.
  589. //
  590. if ((Length < 0) ||
  591. (StartingOffset < 0) ||
  592. (Length > MAXLONGLONG - StartingOffset)) {
  593. status = STATUS_INVALID_PARAMETER;
  594. leave;
  595. }
  596. //
  597. // Check that the requested range is within file size
  598. // and has a non-zero length.
  599. //
  600. if (Length == 0) {
  601. SIS_MARK_POINT();
  602. leave;
  603. }
  604. if (StartingOffset >= standardInformation->EndOfFile.QuadPart) {
  605. SIS_MARK_POINT();
  606. leave;
  607. }
  608. if (standardInformation->EndOfFile.QuadPart - StartingOffset < Length) {
  609. Length = standardInformation->EndOfFile.QuadPart - StartingOffset;
  610. }
  611. //
  612. // Show that the entire requested range is allocated.
  613. //
  614. if (RemainingBytes < sizeof( FILE_ALLOCATED_RANGE_BUFFER )) {
  615. status = STATUS_BUFFER_TOO_SMALL;
  616. SIS_MARK_POINT();
  617. } else {
  618. OutputBuffer->FileOffset.QuadPart = StartingOffset;
  619. OutputBuffer->Length.QuadPart = Length;
  620. Irp->IoStatus.Information = sizeof( FILE_ALLOCATED_RANGE_BUFFER );
  621. status = STATUS_SUCCESS;
  622. }
  623. } except (EXCEPTION_EXECUTE_HANDLER) {
  624. validUserBuffer = FALSE;
  625. }
  626. if (!validUserBuffer) {
  627. status = STATUS_INVALID_USER_BUFFER;
  628. }
  629. done:
  630. Irp->IoStatus.Status = status;
  631. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  632. return status;
  633. }
  634. NTSTATUS
  635. SipMountCompletion (
  636. IN PDEVICE_OBJECT DeviceObject,
  637. IN PIRP Irp,
  638. IN PVOID Context
  639. )
  640. /*++
  641. Routine Description:
  642. This routine is invoked for the completion of a mount request. This
  643. simply re-syncs back to the dispatch routine so the operation can be
  644. completed.
  645. Arguments:
  646. DeviceObject - Pointer to this driver's device object that was attached to
  647. the file system device object
  648. Irp - Pointer to the IRP that was just completed.
  649. Context - Pointer to the device object allocated during the down path so
  650. we wouldn't have to deal with errors here.
  651. Return Value:
  652. The return value is always STATUS_SUCCESS.
  653. --*/
  654. {
  655. PKEVENT event = Context;
  656. UNREFERENCED_PARAMETER( DeviceObject );
  657. UNREFERENCED_PARAMETER( Irp );
  658. ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject ));
  659. //
  660. // If an event routine is defined, signal it
  661. //
  662. KeSetEvent(event, IO_NO_INCREMENT, FALSE);
  663. return STATUS_MORE_PROCESSING_REQUIRED;
  664. }
  665. NTSTATUS
  666. SipLoadFsCompletion (
  667. IN PDEVICE_OBJECT DeviceObject,
  668. IN PIRP Irp,
  669. IN PVOID Context
  670. )
  671. /*++
  672. Routine Description:
  673. This routine is invoked for the completion of a LoadFileSystem request.
  674. This simply re-syncs back to the dispatch routine so the operation can be
  675. completed.
  676. Arguments:
  677. DeviceObject - Pointer to this driver's device object.
  678. Irp - Pointer to the I/O Request Packet representing the file system
  679. driver load request.
  680. Context - Context parameter for this driver, unused.
  681. Return Value:
  682. The function value for this routine is always success.
  683. --*/
  684. {
  685. PKEVENT event = Context;
  686. UNREFERENCED_PARAMETER( DeviceObject );
  687. UNREFERENCED_PARAMETER( Irp );
  688. ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject ));
  689. //
  690. // If an event routine is defined, signal it
  691. //
  692. KeSetEvent(event, IO_NO_INCREMENT, FALSE);
  693. return STATUS_MORE_PROCESSING_REQUIRED;
  694. }
  695. NTSTATUS
  696. SiFsControl (
  697. IN PDEVICE_OBJECT DeviceObject,
  698. IN PIRP Irp
  699. )
  700. /*++
  701. Routine Description:
  702. This routine is invoked whenever an I/O Request Packet (IRP) w/a major
  703. function code of IRP_MJ_FILE_SYSTEM_CONTROL is encountered. For most
  704. IRPs of this type, the packet is simply passed through. However, for
  705. some requests, special processing is required.
  706. Arguments:
  707. DeviceObject - Pointer to the device object for this driver.
  708. Irp - Pointer to the request packet representing the I/O request.
  709. Return Value:
  710. The function value is the status of the operation.
  711. --*/
  712. {
  713. PDEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  714. PDEVICE_OBJECT newDeviceObject;
  715. PDEVICE_EXTENSION newDevExt;
  716. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  717. NTSTATUS status;
  718. PIO_STACK_LOCATION nextIrpSp;
  719. PSIS_PER_FILE_OBJECT perFO;
  720. PSIS_SCB scb;
  721. PVPB vpb;
  722. KEVENT waitEvent;
  723. #if DBG
  724. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_FSCONTROL_TRACE_LEVEL,
  725. "SIS: SiFsControl: fo %p, mf %x, code %x\n",
  726. irpSp->FileObject,
  727. irpSp->MinorFunction,
  728. irpSp->Parameters.FileSystemControl.FsControlCode );
  729. #endif
  730. //
  731. // The control device object can't be opened
  732. //
  733. ASSERT(!IS_MY_CONTROL_DEVICE_OBJECT( DeviceObject ));
  734. ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject ));
  735. //
  736. // Begin by determining the minor function code for this file system control
  737. // function.
  738. //
  739. if (irpSp->MinorFunction == IRP_MN_MOUNT_VOLUME) {
  740. SIS_MARK_POINT();
  741. //
  742. // This is a mount request. Create a device object that can be
  743. // attached to the file system's volume device object if this request
  744. // is successful. We allocate this memory now since we can not return
  745. // an error in the completion routine.
  746. //
  747. // Since the device object we are going to attach to has not yet been
  748. // created (it is created by the base file system) we are going to use
  749. // the type of the file system control device object. We are assuming
  750. // that the file system control device object will have the same type
  751. // as the volume device objects associated with it.
  752. //
  753. ASSERT(IS_DESIRED_DEVICE_TYPE(DeviceObject->DeviceType));
  754. status = IoCreateDevice(
  755. FsDriverObject,
  756. sizeof( DEVICE_EXTENSION ),
  757. (PUNICODE_STRING) NULL,
  758. DeviceObject->DeviceType,
  759. 0,
  760. FALSE,
  761. &newDeviceObject );
  762. if (NT_SUCCESS( status )) {
  763. //
  764. // We need to save the RealDevice object pointed to by the vpb
  765. // parameter because this vpb may be changed by the underlying
  766. // file system. Both FAT and CDFS may change the VPB address if
  767. // the volume being mounted is one they recognize from a previous
  768. // mount.
  769. //
  770. newDevExt = newDeviceObject->DeviceExtension;
  771. newDevExt->RealDeviceObject = irpSp->Parameters.MountVolume.Vpb->RealDevice;
  772. //
  773. // Get a new IRP stack location and set our mount completion
  774. // routine. Pass along the address of the device object we just
  775. // created as its context.
  776. //
  777. KeInitializeEvent( &waitEvent, SynchronizationEvent, FALSE );
  778. IoCopyCurrentIrpStackLocationToNext( Irp );
  779. IoSetCompletionRoutine(
  780. Irp,
  781. SipMountCompletion,
  782. &waitEvent,
  783. TRUE,
  784. TRUE,
  785. TRUE);
  786. //
  787. // Call the driver
  788. //
  789. status = IoCallDriver( devExt->AttachedToDeviceObject, Irp );
  790. //
  791. // Wait for the completion routine to be called
  792. //
  793. if (STATUS_PENDING == status) {
  794. NTSTATUS localStatus = KeWaitForSingleObject(&waitEvent, Executive, KernelMode, FALSE, NULL);
  795. ASSERT(localStatus == STATUS_SUCCESS);
  796. }
  797. //
  798. // Get the correct VPB from the real device object saved in our
  799. // device extension. We do this because the VPB in the IRP stack
  800. // may not be the correct VPB when we get here. The underlying
  801. // file system may change VPBs if it detects a volume it has
  802. // mounted previously.
  803. //
  804. vpb = newDevExt->RealDeviceObject->Vpb;
  805. //
  806. // If the operation succeeded and we are not alreayd attached,
  807. // attach to the device object.
  808. //
  809. if (NT_SUCCESS( Irp->IoStatus.Status )) {
  810. //
  811. // Acquire lock so we can atomically test if we area already attached
  812. // and if not, then attach. This prevents a double attach race
  813. // condition.
  814. //
  815. ExAcquireFastMutex( &SisDeviceAttachLock );
  816. //
  817. // The mount succeeded. If we are not already attached,
  818. // attach to the device object. Note: one reason we could
  819. // already be attached is if the underlying file system
  820. // revived a previous mount.
  821. //
  822. if (!SipAttachedToDevice( vpb->DeviceObject )) {
  823. //
  824. // Attach to the new mounted volume. Note that we must
  825. // go through the VPB to locate the file system volume
  826. // device object.
  827. // This routine will cleanup "newDeviceObject" if this
  828. // operation fails.
  829. //
  830. SipAttachToMountedDevice( vpb->DeviceObject,
  831. newDeviceObject,
  832. newDevExt->RealDeviceObject );
  833. } else {
  834. #if DBG
  835. SipCacheDeviceName( newDeviceObject );
  836. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_VOLNAME_TRACE_LEVEL,
  837. "SIS: Mount volume failure for \"%wZ\", already attached\n",
  838. &newDevExt->Name );
  839. #endif
  840. //
  841. // The mount request failed. Cleanup and delete the device
  842. // object we created.
  843. //
  844. SipCleanupDeviceExtension( newDeviceObject );
  845. IoDeleteDevice( newDeviceObject );
  846. }
  847. //
  848. // Release the lock
  849. //
  850. ExReleaseFastMutex( &SisDeviceAttachLock );
  851. } else {
  852. #if DBG
  853. //
  854. // Display what mount failed.
  855. //
  856. SipCacheDeviceName( newDeviceObject );
  857. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_VOLNAME_TRACE_LEVEL,
  858. "SIS: Mount volume failure for \"%wZ\", status=%08x\n",
  859. &newDevExt->Name,
  860. Irp->IoStatus.Status );
  861. #endif
  862. //
  863. // The mount request failed. Cleanup and delete the device
  864. // object we created.
  865. //
  866. SipCleanupDeviceExtension( newDeviceObject );
  867. IoDeleteDevice( newDeviceObject );
  868. }
  869. //
  870. // Continue processing the operation
  871. //
  872. status = Irp->IoStatus.Status;
  873. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  874. return status;
  875. } else {
  876. #if DBG
  877. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_ERROR_LEVEL,
  878. "SIS: Error creating volume device object, status=%08x\n",
  879. status );
  880. #endif
  881. //
  882. // Something went wrong so this volume cannot be filtered. Simply
  883. // allow the system to continue working normally, if possible.
  884. //
  885. IoSkipCurrentIrpStackLocation( Irp );
  886. }
  887. } else if (irpSp->MinorFunction == IRP_MN_LOAD_FILE_SYSTEM) {
  888. //
  889. // This is a "load file system" request being sent to a file system
  890. // recognizer device object.
  891. //
  892. #if DBG
  893. SipCacheDeviceName( DeviceObject );
  894. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_VOLNAME_TRACE_LEVEL,
  895. "SIS: Loading File System, Detaching from \"%wZ\"\n",
  896. &devExt->Name );
  897. #endif
  898. //
  899. // Set a completion routine so we can delete the device object when
  900. // the detach is complete.
  901. //
  902. KeInitializeEvent( &waitEvent, SynchronizationEvent, FALSE );
  903. IoCopyCurrentIrpStackLocationToNext( Irp );
  904. IoSetCompletionRoutine(
  905. Irp,
  906. SipLoadFsCompletion,
  907. &waitEvent,
  908. TRUE,
  909. TRUE,
  910. TRUE );
  911. //
  912. // Detach from the recognizer device.
  913. //
  914. IoDetachDevice( devExt->AttachedToDeviceObject );
  915. //
  916. // Call the driver
  917. //
  918. status = IoCallDriver( devExt->AttachedToDeviceObject, Irp );
  919. //
  920. // Wait for the completion routine to be called
  921. //
  922. if (STATUS_PENDING == status) {
  923. NTSTATUS localStatus = KeWaitForSingleObject(&waitEvent, Executive, KernelMode, FALSE, NULL);
  924. ASSERT(localStatus == STATUS_SUCCESS);
  925. }
  926. #if DBG
  927. //
  928. // Display the name if requested
  929. //
  930. SipCacheDeviceName( DeviceObject );
  931. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_VOLNAME_TRACE_LEVEL,
  932. "SIS: Detaching from recognizer \"%wZ\", status=%08x\n",
  933. &devExt->Name,
  934. Irp->IoStatus.Status );
  935. #endif
  936. //
  937. // Check status of the operation
  938. //
  939. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  940. //
  941. // The load was not successful. Simply reattach to the recognizer
  942. // driver in case it ever figures out how to get the driver loaded
  943. // on a subsequent call.
  944. //
  945. status = IoAttachDeviceToDeviceStackSafe( DeviceObject,
  946. devExt->AttachedToDeviceObject,
  947. &devExt->AttachedToDeviceObject );
  948. ASSERT(STATUS_SUCCESS == status);
  949. } else {
  950. //
  951. // The load was successful, delete the Device object attached to the
  952. // recognizer.
  953. //
  954. SipCleanupDeviceExtension( DeviceObject );
  955. IoDeleteDevice( DeviceObject );
  956. }
  957. //
  958. // Continue processing the operation
  959. //
  960. status = Irp->IoStatus.Status;
  961. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  962. return status;
  963. } else if (IRP_MN_USER_FS_REQUEST == irpSp->MinorFunction &&
  964. SipIsFileObjectSIS(irpSp->FileObject,DeviceObject,FindActive,&perFO,&scb)) {
  965. SIS_MARK_POINT_ULONG(scb);
  966. SIS_MARK_POINT_ULONG(irpSp->Parameters.FileSystemControl.FsControlCode);
  967. //
  968. // This is a big switch of all of the known fsctl calls. Most of these calls just get
  969. // passed through on the link file, but we explicity list them to indicate that we put
  970. // some thought into the particular call and determined that passing it through is
  971. // appropriate. In the checked build, we generate a DbgPrint for unknown fsctl calls,
  972. // then pass them through on the link file.
  973. //
  974. switch (irpSp->Parameters.FileSystemControl.FsControlCode) {
  975. //
  976. // Fsctl calls 0-5
  977. //
  978. // oplock calls all get passed through.
  979. //
  980. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  981. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  982. case FSCTL_REQUEST_BATCH_OPLOCK:
  983. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  984. case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
  985. case FSCTL_OPLOCK_BREAK_NOTIFY:
  986. goto PassThrough;
  987. //
  988. // Fsctl call 6
  989. //
  990. // Volume only - pass through and let NTFS fail.
  991. //
  992. case FSCTL_LOCK_VOLUME:
  993. goto PassThrough;
  994. //
  995. // Fsctl call 7
  996. //
  997. // Volume only - pass through and let NTFS fail.
  998. //
  999. case FSCTL_UNLOCK_VOLUME:
  1000. goto PassThrough;
  1001. //
  1002. // Fsctl call 8
  1003. //
  1004. // Volume only - pass through and let NTFS fail.
  1005. //
  1006. case FSCTL_DISMOUNT_VOLUME:
  1007. goto PassThrough;
  1008. //
  1009. // Fsctl call 9 is decommissioned.
  1010. //
  1011. //
  1012. // Fsctl call 10
  1013. //
  1014. // This call only looks at the volume on which the file is located, it doesn't
  1015. // depend on the particular file. Pass it through on the link file.
  1016. //
  1017. case FSCTL_IS_VOLUME_MOUNTED:
  1018. goto PassThrough;
  1019. //
  1020. // Fsctl call 11
  1021. //
  1022. // Ntfs doesn't even look at the parameters, it just succeeds the request.
  1023. //
  1024. case FSCTL_IS_PATHNAME_VALID:
  1025. goto PassThrough;
  1026. //
  1027. // Fsctl call 12
  1028. //
  1029. // Volume only - pass through and let NTFS fail.
  1030. //
  1031. case FSCTL_MARK_VOLUME_DIRTY:
  1032. goto PassThrough;
  1033. //
  1034. // Fsctl call 13 is decommissioned.
  1035. //
  1036. //
  1037. // Fsctl call 14
  1038. //
  1039. // This is valid only on paging files and only in kernel mode. Pass through and let NTFS
  1040. // fail or assert.
  1041. //
  1042. case FSCTL_QUERY_RETRIEVAL_POINTERS:
  1043. goto PassThrough;
  1044. //
  1045. // Fsctl calls 15 and 16
  1046. //
  1047. // The compression state of the link file is independent
  1048. // of the compression state of the CS file (which preferably
  1049. // is compressed). Pass through.
  1050. //
  1051. case FSCTL_GET_COMPRESSION:
  1052. case FSCTL_SET_COMPRESSION:
  1053. goto PassThrough;
  1054. //
  1055. // Fsctl calls 17 and 18 are decommissioned.
  1056. //
  1057. //
  1058. // Fsctl call 19
  1059. //
  1060. // This is disconcerting--ntfs treats system hives specially.
  1061. // Basically, it works hard to keep them consistent across crashes.
  1062. // It's not such a good idea to do this with a SIS file, since we're
  1063. // not going to be all that great with user data across a crash. However,
  1064. // given that we've gotten here, just go for it.
  1065. //
  1066. case FSCTL_MARK_AS_SYSTEM_HIVE:
  1067. ASSERT(!"SIS: SiFsControl: Someone called FSCTL_MARK_AS_SYSTEM_HIVE on a SIS file!\n");
  1068. goto PassThrough;
  1069. //
  1070. // Fsctl call 20
  1071. //
  1072. // oplock calls all get passed through.
  1073. //
  1074. case FSCTL_OPLOCK_BREAK_ACK_NO_2:
  1075. goto PassThrough;
  1076. //
  1077. // Fsctl call 21
  1078. //
  1079. // NTFS doesn't even mention this fsctl. We'll let it fail it.
  1080. //
  1081. case FSCTL_INVALIDATE_VOLUMES:
  1082. goto PassThrough;
  1083. //
  1084. // Fsctl call 22
  1085. //
  1086. // NTFS doesn't even mention this fsctl. We'll let it fail it.
  1087. //
  1088. case FSCTL_QUERY_FAT_BPB:
  1089. goto PassThrough;
  1090. //
  1091. // Fsctl call 23
  1092. //
  1093. // oplock calls all get passed through.
  1094. //
  1095. case FSCTL_REQUEST_FILTER_OPLOCK:
  1096. goto PassThrough;
  1097. //
  1098. // Fsctl call 24
  1099. //
  1100. // This call only looks at the volume on which the file is located, it doesn't
  1101. // depend on the particular file. Pass it through on the link file.
  1102. //
  1103. case FSCTL_FILESYSTEM_GET_STATISTICS:
  1104. goto PassThrough;
  1105. //
  1106. // Fsctl call 25
  1107. //
  1108. // This call only looks at the volume on which the file is located, it doesn't
  1109. // depend on the particular file. Pass it through on the link file.
  1110. //
  1111. case FSCTL_GET_NTFS_VOLUME_DATA:
  1112. goto PassThrough;
  1113. //
  1114. // Fsctl call 26
  1115. //
  1116. // Volume only - pass through and let NTFS fail.
  1117. //
  1118. case FSCTL_GET_NTFS_FILE_RECORD:
  1119. goto PassThrough;
  1120. //
  1121. // Fsctl call 27
  1122. //
  1123. // Volume only - pass through and let NTFS fail.
  1124. //
  1125. case FSCTL_GET_VOLUME_BITMAP:
  1126. goto PassThrough;
  1127. //
  1128. // Fsctl call 28
  1129. //
  1130. // This returns file cluster allocation information.
  1131. // If opened reparse, pass through. If not, then send to
  1132. // where the data is.
  1133. //
  1134. case FSCTL_GET_RETRIEVAL_POINTERS: {
  1135. BOOLEAN openedAsReparse;
  1136. KIRQL OldIrql;
  1137. BOOLEAN dirty;
  1138. KeAcquireSpinLock(perFO->SpinLock, &OldIrql);
  1139. openedAsReparse = (perFO->Flags & SIS_PER_FO_OPEN_REPARSE) ? TRUE : FALSE;
  1140. KeReleaseSpinLock(perFO->SpinLock, OldIrql);
  1141. if (openedAsReparse) {
  1142. //
  1143. // The user opened this file FILE_OPEN_REPARSE_POINT, so tell the truth
  1144. // about the link file.
  1145. //
  1146. goto PassThrough;
  1147. }
  1148. KeAcquireSpinLock(scb->PerLink->SpinLock, &OldIrql);
  1149. dirty = (scb->PerLink->Flags & SIS_PER_LINK_DIRTY) ? TRUE : FALSE;
  1150. KeReleaseSpinLock(scb->PerLink->SpinLock, OldIrql);
  1151. //
  1152. // Just because the per-link dirty bit isn't set doesn't mean that the
  1153. // file's totally clean. Check the scb bits.
  1154. //
  1155. if (!dirty) {
  1156. SipAcquireScb(scb);
  1157. if (scb->Flags & SIS_SCB_BACKING_FILE_OPENED_DIRTY) {
  1158. dirty = TRUE;
  1159. }
  1160. SipReleaseScb(scb);
  1161. }
  1162. if (dirty) {
  1163. //
  1164. // We should look at the ranges queried and split things up, much like we do with
  1165. // reads that span dirty/clean boundaries.
  1166. //
  1167. // NTRAID#65190-2000/03/10-nealch Handle FSCTL_GET_RETRIEVAL_POINTERS for "dirtied" sis files.
  1168. //
  1169. SIS_MARK_POINT_ULONG(scb);
  1170. #if DBG
  1171. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_ERROR_LEVEL,
  1172. "SIS: SiFsControl: FSCTL_GET_RETRIEVAL_POINTERS: called on dirty file, returning STATUS_NOT_IMPLEMENTED\n");
  1173. #endif // DBG
  1174. status = STATUS_NOT_IMPLEMENTED;
  1175. goto CompleteWithStatus;
  1176. }
  1177. //
  1178. // Just send this to the common store file.
  1179. //
  1180. goto SendToCSFile;
  1181. }
  1182. //
  1183. // Fsctl call 29
  1184. //
  1185. // This is called on a volume handle, but a file handle
  1186. // is passed in the input buffer. It moves a range of the
  1187. // file to a specified location on the volume. We just pass it through
  1188. // regardless; trying to move unallocated regions of a link file is
  1189. // meaningless, and trying to move allocated regions will do the
  1190. // right thing. To move the common store file, it can be called with
  1191. // a CS file handle.
  1192. //
  1193. case FSCTL_MOVE_FILE:
  1194. goto PassThrough;
  1195. //
  1196. // Fsctl call 30
  1197. //
  1198. // Volume only - pass through and let NTFS fail.
  1199. //
  1200. case FSCTL_IS_VOLUME_DIRTY:
  1201. goto PassThrough;
  1202. //
  1203. // Fsctl call 32
  1204. //
  1205. // Volume only - pass through and let NTFS fail.
  1206. //
  1207. case FSCTL_ALLOW_EXTENDED_DASD_IO:
  1208. goto PassThrough;
  1209. //
  1210. // Fsctl call 33 is decommissioned.
  1211. //
  1212. //
  1213. // Fsctl call 35
  1214. //
  1215. // Directory only - pass through and let NTFS fail.
  1216. //
  1217. case FSCTL_FIND_FILES_BY_SID:
  1218. goto PassThrough;
  1219. //
  1220. // Fsctl call 36 is decommissioned.
  1221. //
  1222. //
  1223. // Fsctl call 37 is decommissioned.
  1224. //
  1225. //
  1226. // Fsctls 38-40.
  1227. //
  1228. // Pass through. Object ID's are similar to file ID's, but are user assigned.
  1229. //
  1230. case FSCTL_SET_OBJECT_ID:
  1231. case FSCTL_GET_OBJECT_ID:
  1232. case FSCTL_DELETE_OBJECT_ID:
  1233. goto PassThrough;
  1234. //
  1235. // Fsctl call 41
  1236. //
  1237. // We can have only one reparse point on a file, and SIS is using it. We should
  1238. // probably COW this file, but for now just disallow this, except in the case
  1239. // where it's a SIS reparse point being set, in which case we forward the request to
  1240. // SipUserSetSISReparsePoint.
  1241. //
  1242. case FSCTL_SET_REPARSE_POINT: {
  1243. PREPARSE_DATA_BUFFER reparseBuffer = Irp->AssociatedIrp.SystemBuffer;
  1244. ULONG InputBufferLength = irpSp->Parameters.FileSystemControl.InputBufferLength;
  1245. if ((NULL == reparseBuffer) ||
  1246. (InputBufferLength < SIS_REPARSE_DATA_SIZE)) {
  1247. SIS_MARK_POINT_ULONG(InputBufferLength);
  1248. status = STATUS_INVALID_PARAMETER;
  1249. goto CompleteWithStatus;
  1250. }
  1251. if (IO_REPARSE_TAG_SIS != reparseBuffer->ReparseTag) {
  1252. status = STATUS_INVALID_PARAMETER;
  1253. goto CompleteWithStatus;
  1254. }
  1255. status = SipUserSetSISReparsePoint(DeviceObject, Irp);
  1256. SIS_MARK_POINT_ULONG(status);
  1257. return status;
  1258. }
  1259. //
  1260. // Fsctl call 42
  1261. //
  1262. // Just let the user read the SIS reparse point.
  1263. //
  1264. case FSCTL_GET_REPARSE_POINT:
  1265. goto PassThrough;
  1266. //
  1267. // Fsctl call 43
  1268. //
  1269. // Disallow deleting SIS reparse points directly.
  1270. //
  1271. case FSCTL_DELETE_REPARSE_POINT:
  1272. status = STATUS_ACCESS_DENIED;
  1273. goto CompleteWithStatus;
  1274. //
  1275. // Fsctl call 44
  1276. //
  1277. // Volume only - pass through and let NTFS fail.
  1278. //
  1279. case FSCTL_ENUM_USN_DATA:
  1280. goto PassThrough;
  1281. //
  1282. // Fsctl call 45
  1283. //
  1284. // Volume only - pass through and let NTFS fail.
  1285. //
  1286. case FSCTL_SECURITY_ID_CHECK:
  1287. goto PassThrough;
  1288. //
  1289. // Fsctl call 46
  1290. //
  1291. // Volume only - pass through and let NTFS fail.
  1292. //
  1293. case FSCTL_READ_USN_JOURNAL:
  1294. goto PassThrough;
  1295. //
  1296. // Fsctls 47 and 48
  1297. //
  1298. // Pass through. Object ID's are similar to file ID's, but are user assigned.
  1299. //
  1300. case FSCTL_SET_OBJECT_ID_EXTENDED:
  1301. case FSCTL_CREATE_OR_GET_OBJECT_ID:
  1302. goto PassThrough;
  1303. //
  1304. // Fsctl call 49
  1305. //
  1306. // SIS link files are already sparse.
  1307. //
  1308. case FSCTL_SET_SPARSE:
  1309. goto PassThrough;
  1310. //
  1311. // Fsctl call 50
  1312. //
  1313. // This is only partially implemented, for the case where the user opened the
  1314. // file FILE_OPEN_REPARSE_POINT.
  1315. //
  1316. case FSCTL_SET_ZERO_DATA: {
  1317. BOOLEAN openedAsReparse;
  1318. BOOLEAN openedDirty;
  1319. KIRQL OldIrql;
  1320. //
  1321. // Check to see if the file is opened FILE_OPEN_REPARSE_POINT, and fail the request if not.
  1322. //
  1323. KeAcquireSpinLock(perFO->SpinLock, &OldIrql);
  1324. openedAsReparse = (perFO->Flags & SIS_PER_FO_OPEN_REPARSE) ? TRUE : FALSE;
  1325. KeReleaseSpinLock(perFO->SpinLock, OldIrql);
  1326. if (!openedAsReparse) {
  1327. status = STATUS_NOT_IMPLEMENTED;
  1328. goto CompleteWithStatus;
  1329. }
  1330. //
  1331. // Verify that this file wasn't opened dirty.
  1332. //
  1333. SipAcquireScb(scb);
  1334. openedDirty = (scb->Flags & SIS_SCB_BACKING_FILE_OPENED_DIRTY) ? TRUE : FALSE;
  1335. SipReleaseScb(scb);
  1336. if (openedDirty) {
  1337. SIS_MARK_POINT();
  1338. #if DBG
  1339. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_ERROR_LEVEL,
  1340. "SIS: tried FSCTL_SET_ZERO_DATA on file that was opened dirty. Failing it.\n");
  1341. #endif // DBG
  1342. status = STATUS_NOT_IMPLEMENTED;
  1343. goto CompleteWithStatus;
  1344. }
  1345. goto PassThrough;
  1346. }
  1347. //
  1348. // Fsctl call 51
  1349. //
  1350. // Depends on whether the file is opened FILE_OPEN_REPARSE. Implemented in its own
  1351. // function.
  1352. //
  1353. case FSCTL_QUERY_ALLOCATED_RANGES: {
  1354. BOOLEAN openedAsReparse;
  1355. KIRQL OldIrql;
  1356. KeAcquireSpinLock(perFO->SpinLock, &OldIrql);
  1357. openedAsReparse = (perFO->Flags & SIS_PER_FO_OPEN_REPARSE) ? TRUE : FALSE;
  1358. KeReleaseSpinLock(perFO->SpinLock, OldIrql);
  1359. if (openedAsReparse) {
  1360. //
  1361. // This file was opened as a reparse point, so we just pass it
  1362. // through and let the real set of allocated ranges show through.
  1363. //
  1364. goto PassThrough;
  1365. } else {
  1366. //
  1367. // This was a normal open, so call our special routine that will
  1368. // show the file as a single, allocated chunk.
  1369. //
  1370. return SipQueryAllocatedRanges(DeviceObject,Irp);
  1371. }
  1372. }
  1373. //
  1374. // Fsctl call 52 obsolete
  1375. //
  1376. //
  1377. // Fsctl calls 53-56
  1378. //
  1379. // Encrypting a file results in the file being completely
  1380. // overwritten. SIS files, therefore, will simply COW back
  1381. // to normal if they're encrypted.
  1382. //
  1383. case FSCTL_SET_ENCRYPTION:
  1384. case FSCTL_ENCRYPTION_FSCTL_IO:
  1385. case FSCTL_WRITE_RAW_ENCRYPTED:
  1386. case FSCTL_READ_RAW_ENCRYPTED:
  1387. goto PassThrough;
  1388. //
  1389. // Fsctl call 57
  1390. //
  1391. // Volume only - pass through and let NTFS fail.
  1392. //
  1393. case FSCTL_CREATE_USN_JOURNAL:
  1394. goto PassThrough;
  1395. //
  1396. // Fsctl call 58
  1397. //
  1398. // Returns USN data for a file.
  1399. //
  1400. case FSCTL_READ_FILE_USN_DATA:
  1401. goto PassThrough;
  1402. //
  1403. // Fsctl call 59
  1404. //
  1405. // This call writes a USN record as if the file were closed, and posts
  1406. // any USN updates that were pending a close for this file. Pass it
  1407. // through on the link file.
  1408. //
  1409. case FSCTL_WRITE_USN_CLOSE_RECORD:
  1410. goto PassThrough;
  1411. //
  1412. // Fsctl call 60
  1413. //
  1414. // Volume only - pass through and let NTFS fail.
  1415. //
  1416. case FSCTL_EXTEND_VOLUME:
  1417. goto PassThrough;
  1418. //
  1419. // Fsctl call 61
  1420. //
  1421. // Volume only - pass through and let NTFS fail.
  1422. //
  1423. case FSCTL_QUERY_USN_JOURNAL:
  1424. goto PassThrough;
  1425. //
  1426. // Fsctl call 62
  1427. //
  1428. // Volume only - pass through and let NTFS fail.
  1429. //
  1430. case FSCTL_DELETE_USN_JOURNAL:
  1431. goto PassThrough;
  1432. //
  1433. // Fsctl call 63
  1434. //
  1435. // This sets some bits in the CCB related to USN processing
  1436. // for the file. These bits don't appear to be read by anything
  1437. // in ntfs.
  1438. //
  1439. case FSCTL_MARK_HANDLE:
  1440. goto PassThrough;
  1441. //
  1442. // Fsctl call 64
  1443. //
  1444. // Our very own copyfile request.
  1445. //
  1446. case FSCTL_SIS_COPYFILE:
  1447. return SipFsCopyFile(DeviceObject,Irp);
  1448. //
  1449. // Fsctl call 65
  1450. //
  1451. // The groveler fsctl. This is valid only on \SIS Common Store\GrovelerFile, which
  1452. // can never be a SIS link. Fail the request.
  1453. //
  1454. case FSCTL_SIS_LINK_FILES:
  1455. status = STATUS_ACCESS_DENIED;
  1456. goto CompleteWithStatus;
  1457. //
  1458. // Fsctl call 66
  1459. //
  1460. // Something related to HSM. Not sure what to do with this; just pass it through.
  1461. //
  1462. case FSCTL_HSM_MSG:
  1463. goto PassThrough;
  1464. //
  1465. // Handle everything else
  1466. //
  1467. default:
  1468. #if DBG
  1469. DbgPrintEx( DPFLTR_SIS_ID, DPFLTR_ERROR_LEVEL,
  1470. "SiFsControl with unknown code 0x%x\n",irpSp->Parameters.FileSystemControl.FsControlCode);
  1471. if (BJBDebug & 0x400) {
  1472. DbgBreakPoint();
  1473. }
  1474. #endif // DBG
  1475. goto PassThrough;
  1476. }
  1477. } else if (IRP_MN_USER_FS_REQUEST == irpSp->MinorFunction &&
  1478. FSCTL_SIS_COPYFILE == irpSp->Parameters.FileSystemControl.FsControlCode) {
  1479. return SipFsCopyFile(DeviceObject,Irp);
  1480. } else if (IRP_MN_USER_FS_REQUEST == irpSp->MinorFunction &&
  1481. FSCTL_SIS_LINK_FILES == irpSp->Parameters.FileSystemControl.FsControlCode) {
  1482. return SipLinkFiles(DeviceObject, Irp);
  1483. } else if (IRP_MN_USER_FS_REQUEST == irpSp->MinorFunction &&
  1484. FSCTL_DISMOUNT_VOLUME == irpSp->Parameters.FileSystemControl.FsControlCode) {
  1485. return SipDismountVolume(DeviceObject, Irp);
  1486. } else if (IRP_MN_USER_FS_REQUEST == irpSp->MinorFunction &&
  1487. FSCTL_SET_REPARSE_POINT == irpSp->Parameters.FileSystemControl.FsControlCode) {
  1488. PREPARSE_DATA_BUFFER reparseBuffer = Irp->AssociatedIrp.SystemBuffer;
  1489. ULONG InputBufferLength = irpSp->Parameters.FileSystemControl.InputBufferLength;
  1490. //
  1491. // Handle a user set of a SIS reparse point.
  1492. //
  1493. if ((NULL == reparseBuffer) ||
  1494. (InputBufferLength < SIS_REPARSE_DATA_SIZE) ||
  1495. (IO_REPARSE_TAG_SIS != reparseBuffer->ReparseTag)) {
  1496. //
  1497. // This isn't a valid SIS reparse point being set, just pass the call through.
  1498. //
  1499. goto PassThrough;
  1500. }
  1501. status = SipUserSetSISReparsePoint(DeviceObject, Irp);
  1502. return status;
  1503. } else {
  1504. //
  1505. // Simply pass this file system control request through, we don't need a callback
  1506. //
  1507. PassThrough:
  1508. IoSkipCurrentIrpStackLocation( Irp );
  1509. }
  1510. //
  1511. // Any special processing has been completed, so simply pass the request
  1512. // along to the next driver.
  1513. //
  1514. return IoCallDriver( devExt->AttachedToDeviceObject, Irp );
  1515. /////////////////////////////////////////////////////////////////////////////
  1516. // Handle status cases
  1517. /////////////////////////////////////////////////////////////////////////////
  1518. CompleteWithStatus:
  1519. SIS_MARK_POINT_ULONG(status);
  1520. Irp->IoStatus.Status = status;
  1521. Irp->IoStatus.Information = 0;
  1522. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1523. return status;
  1524. SendToCSFile:
  1525. IoCopyCurrentIrpStackLocationToNext( Irp );
  1526. nextIrpSp = IoGetNextIrpStackLocation(Irp);
  1527. nextIrpSp->FileObject = scb->PerLink->CsFile->UnderlyingFileObject;
  1528. IoSetCompletionRoutine(
  1529. Irp,
  1530. NULL,
  1531. NULL,
  1532. FALSE,
  1533. FALSE,
  1534. FALSE);
  1535. return IoCallDriver( devExt->AttachedToDeviceObject, Irp );
  1536. }