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.

1472 lines
39 KiB

  1. /*++
  2. Copyright (c) 1997, 1998 Microsoft Corporation
  3. Module Name:
  4. siinfo.c
  5. Abstract:
  6. Set/Query info 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. //
  15. // The parameters for a SipRenameOverCheck call.
  16. //
  17. //
  18. typedef struct _SIS_CHECK_OVERWRITE_REQUEST {
  19. //
  20. // The WORK_QUEUE_ITEM needed to get the request posted.
  21. //
  22. WORK_QUEUE_ITEM workItem[1];
  23. //
  24. // An event to set to signify completion
  25. //
  26. KEVENT event[1];
  27. //
  28. // The per link for the target file.
  29. //
  30. PSIS_PER_LINK perLink;
  31. //
  32. // The file ID for the target file.
  33. //
  34. PFILE_INTERNAL_INFORMATION internalInfo;
  35. //
  36. // The DeviceObject on which we were called.
  37. //
  38. PDEVICE_OBJECT DeviceObject;
  39. //
  40. // The thread that called SipPrepareCSRefcountChange
  41. //
  42. ERESOURCE_THREAD thread;
  43. } SIS_CHECK_OVERWRITE_REQUEST, *PSIS_CHECK_OVERWRITE_REQUEST;
  44. VOID
  45. SipRenameOverCheck(
  46. PVOID parameter)
  47. /*++
  48. Routine Description:
  49. Someone did a replace-if-exists NtSetInformationFile call, the target was
  50. a SIS link, and NTFS completed the request successfully. The caller posted
  51. to a worker thread to make the final determination if the file is really
  52. gone, and this function is the worker routine that makes that check.
  53. We open the target SIS file by ID, and if it's still there we check to see
  54. if it's still the same SIS file. If it is, we abort the refcount update,
  55. otherwise we complete it.
  56. Arguments:
  57. parameter - a PSIS_CHECK_OVERWRITE_REQUEST. See the structure definition for
  58. a description of the fields.
  59. Return Value:
  60. void
  61. --*/
  62. {
  63. PSIS_CHECK_OVERWRITE_REQUEST checkRequest = parameter;
  64. PDEVICE_OBJECT DeviceObject = checkRequest->DeviceObject;
  65. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  66. IO_STATUS_BLOCK Iosb[1];
  67. NTSTATUS status;
  68. OBJECT_ATTRIBUTES Obja[1];
  69. UNICODE_STRING fileIdString[1];
  70. HANDLE dstFileHandle = NULL;
  71. PFILE_OBJECT dstFileObject = NULL;
  72. BOOLEAN fileGone = FALSE;
  73. PSIS_PER_FILE_OBJECT perFO;
  74. PSIS_SCB scb;
  75. KIRQL OldIrql;
  76. fileIdString->Length = fileIdString->MaximumLength = sizeof(LARGE_INTEGER);
  77. fileIdString->Buffer = (PWCHAR)&checkRequest->internalInfo->IndexNumber;
  78. InitializeObjectAttributes(
  79. Obja,
  80. fileIdString,
  81. OBJ_CASE_INSENSITIVE,
  82. deviceExtension->GrovelerFileHandle,
  83. NULL);
  84. status = NtCreateFile(
  85. &dstFileHandle,
  86. 0,
  87. Obja,
  88. Iosb,
  89. NULL, // allocation size
  90. FILE_ATTRIBUTE_NORMAL,
  91. FILE_SHARE_READ |
  92. FILE_SHARE_WRITE |
  93. FILE_SHARE_DELETE,
  94. FILE_OPEN,
  95. FILE_NON_DIRECTORY_FILE,
  96. NULL, // EA buffer
  97. 0); // EA length
  98. if (!NT_SUCCESS(status)) {
  99. //
  100. // We couldn't open the file. open-by-id creates fail with invalid parameter
  101. // when there is no file with that id. If that's what happened, then the file's
  102. // gone and we can delete the backpointer. If it failed for some other reason,
  103. // then we'll err on the side of conservatism and leave it be.
  104. //
  105. SIS_MARK_POINT_ULONG(status);
  106. if ((STATUS_INVALID_PARAMETER == status) ||
  107. (STATUS_OBJECT_NAME_NOT_FOUND == status) ||
  108. (STATUS_OBJECT_PATH_NOT_FOUND == status)) {
  109. fileGone = TRUE;
  110. }
  111. goto done;
  112. }
  113. //
  114. // We opened a file with the right file ID. See if it's still a SIS file.
  115. //
  116. status = ObReferenceObjectByHandle(
  117. dstFileHandle,
  118. 0,
  119. *IoFileObjectType,
  120. KernelMode,
  121. &dstFileObject,
  122. NULL);
  123. if (!NT_SUCCESS(status)) {
  124. //
  125. // The file's there, but for some reason we can't access the file object.
  126. // Be conservative and assume that it's still the link.
  127. //
  128. SIS_MARK_POINT_ULONG(status);
  129. goto done;
  130. }
  131. if (!SipIsFileObjectSIS(dstFileObject, DeviceObject, FindActive, &perFO, &scb)) {
  132. //
  133. // The file exists, but it's not a SIS file.
  134. //
  135. SIS_MARK_POINT();
  136. fileGone = TRUE;
  137. goto done;
  138. }
  139. //
  140. // The file exists, and it's a SIS file. See if it's a reference to the same file,
  141. // or to a different one. We don't have to worry about it's being a new reference to the
  142. // same file, because we hold the refcount update resource for the common store file.
  143. //
  144. if (scb->PerLink != checkRequest->perLink) {
  145. SIS_MARK_POINT();
  146. fileGone = TRUE;
  147. } else {
  148. //
  149. // It's still there. Presumably someone renamed it before the rename that we're
  150. // tracking could blow it away.
  151. //
  152. }
  153. done:
  154. SIS_MARK_POINT_ULONG(checkRequest->perLink->CsFile);
  155. if (fileGone) {
  156. KeAcquireSpinLock(checkRequest->perLink->SpinLock, &OldIrql);
  157. checkRequest->perLink->Flags |= SIS_PER_LINK_FILE_DELETED;
  158. KeReleaseSpinLock(checkRequest->perLink->SpinLock, OldIrql);
  159. }
  160. SipCompleteCSRefcountChangeForThread(
  161. checkRequest->perLink,
  162. &checkRequest->perLink->Index,
  163. checkRequest->perLink->CsFile,
  164. fileGone,
  165. FALSE,
  166. checkRequest->thread);
  167. SipDereferencePerLink(checkRequest->perLink);
  168. if (NULL != dstFileObject) {
  169. ObDereferenceObject(dstFileObject);
  170. }
  171. if (NULL != dstFileHandle) {
  172. NtClose(dstFileHandle);
  173. }
  174. KeSetEvent(checkRequest->event, IO_NO_INCREMENT, FALSE);
  175. return;
  176. }
  177. NTSTATUS
  178. SiRenameOverCompletion(
  179. IN PDEVICE_OBJECT DeviceObject,
  180. IN PIRP Irp,
  181. IN PVOID context)
  182. /*++
  183. Routine Description:
  184. An IRP completion routine for a rename call with a SIS link as a target.
  185. This function just resynchronizes with the calling thread by clearing
  186. PendingReturned and setting an event.
  187. Arguments:
  188. DeviceObject - Pointer to this driver's device object.
  189. Irp - Pointer to the I/O Request Packet representing rename request.
  190. Return Value:
  191. STATUS_MORE_PROCESSING_REQUIRED
  192. --*/
  193. {
  194. PKEVENT event = (PKEVENT)context;
  195. UNREFERENCED_PARAMETER( DeviceObject );
  196. Irp->PendingReturned = FALSE;
  197. KeSetEvent(event, IO_NO_INCREMENT, FALSE);
  198. return STATUS_MORE_PROCESSING_REQUIRED;
  199. }
  200. NTSTATUS
  201. SipReplaceIfExistsRename(
  202. IN PDEVICE_OBJECT DeviceObject,
  203. IN PIRP Irp)
  204. /*++
  205. Routine Description:
  206. Someone did a replace-if-exists NtSetInformationFile call. We need to
  207. figure out if the target is a SIS link, and if so remove the backpointer
  208. for the file. This function does about half of the work, and then posts
  209. to a worker thread (SipRenameOverCheck) to do the final check to see if
  210. the SIS file was really overwritten.
  211. It is the responsibility of this function to complete the irp.
  212. Arguments:
  213. DeviceObject - Pointer to this driver's device object.
  214. Irp - Pointer to the I/O Request Packet representing rename request.
  215. Return Value:
  216. The status of the request
  217. --*/
  218. {
  219. HANDLE dstFileHandle = NULL;
  220. OBJECT_ATTRIBUTES Obja[1];
  221. PFILE_RENAME_INFORMATION renameInfo = Irp->AssociatedIrp.SystemBuffer;
  222. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  223. PIO_STACK_LOCATION nextIrpSp;
  224. UNICODE_STRING dstFileName[1];
  225. NTSTATUS status;
  226. IO_STATUS_BLOCK Iosb[1];
  227. PFILE_OBJECT dstFileObject = NULL;
  228. PSIS_PER_FILE_OBJECT perFO;
  229. PSIS_SCB scb;
  230. FILE_INTERNAL_INFORMATION internalInfo[1];
  231. PSIS_PER_LINK perLink;
  232. KEVENT event[1];
  233. SIS_CHECK_OVERWRITE_REQUEST checkRequest[1];
  234. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  235. ASSERT(IRP_MJ_SET_INFORMATION == irpSp->MajorFunction);
  236. ASSERT(renameInfo->ReplaceIfExists);
  237. //
  238. // The basic strategy here is similar to what we do in the overwrite/supersede open
  239. // case: we figure out if the file is a SIS file, and if so which one, let the
  240. // rename proceed and then see if the suspected target is gone. Like overwrite/supersede,
  241. // we're subject to a race in the case where someone renames a SIS link under the
  242. // destination after we do our local check. If that race goes the wrong way, we'll
  243. // lose the refcount decrement. This won't ever result in user data loss, but we
  244. // won't be able to reclaim the common store file until we do a volume check. C'est la vie.
  245. //
  246. //
  247. // The first step is to open the target file and see if it is a SIS link.
  248. //
  249. //
  250. // We have to be careful in dealing with the string lengths in the renameInfo buffer,
  251. // because they have not been checked anywhere.
  252. //
  253. if (renameInfo->FileNameLength + FIELD_OFFSET(FILE_RENAME_INFORMATION,FileName) >
  254. irpSp->Parameters.SetFile.Length) {
  255. //
  256. // It's bogus, just let NTFS deal with it.
  257. //
  258. SIS_MARK_POINT();
  259. goto PassThrough;
  260. }
  261. //
  262. // The length is OK, so build up an object attributes for this file.
  263. //
  264. dstFileName->Length = (USHORT)renameInfo->FileNameLength;
  265. dstFileName->MaximumLength = (USHORT)renameInfo->FileNameLength;
  266. dstFileName->Buffer = renameInfo->FileName;
  267. InitializeObjectAttributes(
  268. Obja,
  269. dstFileName,
  270. OBJ_CASE_INSENSITIVE,
  271. renameInfo->RootDirectory,
  272. NULL);
  273. //
  274. // Open the file. It's somewhat unusual to open a file with kernel privs in the
  275. // user context, but it's OK in this case for the following reasons:
  276. // 1) We're opening the file for no access, so the user can't do anything
  277. // aisde from close the handle.
  278. // 2) If the user does close the handle before we reference it, the worst
  279. // that happens is that we miss the loss of a SIS link, which could happen
  280. // via the rename race anyway.
  281. //
  282. status = ZwCreateFile(
  283. &dstFileHandle,
  284. 0, // desired access; avoid sharing violations
  285. Obja,
  286. Iosb,
  287. NULL, // allocation size
  288. FILE_ATTRIBUTE_NORMAL,
  289. FILE_SHARE_READ |
  290. FILE_SHARE_WRITE |
  291. FILE_SHARE_DELETE,
  292. FILE_OPEN,
  293. FILE_NON_DIRECTORY_FILE,
  294. NULL, // EA buffer
  295. 0); // EA length
  296. if (!NT_SUCCESS(status)) {
  297. //
  298. // For whatever reason, we couldn't open the file. It probably doesn't exist.
  299. // Just pass the request through.
  300. //
  301. SIS_MARK_POINT_ULONG(status);
  302. goto PassThrough;
  303. }
  304. status = ObReferenceObjectByHandle(
  305. dstFileHandle,
  306. 0,
  307. *IoFileObjectType,
  308. KernelMode,
  309. &dstFileObject,
  310. NULL); // handle info
  311. if (!NT_SUCCESS(status)) {
  312. SIS_MARK_POINT_ULONG(status);
  313. goto PassThrough;
  314. }
  315. //
  316. // See if this file is on the same device as we're being called on.
  317. //
  318. if (IoGetRelatedDeviceObject(dstFileObject) !=
  319. IoGetRelatedDeviceObject(irpSp->FileObject)) {
  320. //
  321. // They're not. This call will most likely fail in NTFS since cross-volume
  322. // renames aren't supported at the NT interface level. We'll just pass it
  323. // through.
  324. //
  325. SIS_MARK_POINT();
  326. goto PassThrough;
  327. }
  328. if (!SipCheckPhase2(deviceExtension)) {
  329. SIS_MARK_POINT();
  330. goto PassThrough;
  331. }
  332. if (!SipIsFileObjectSIS(dstFileObject, DeviceObject, FindActive, &perFO, &scb)) {
  333. //
  334. // It exists, but it's not a SIS file object. Pass through.
  335. //
  336. SIS_MARK_POINT();
  337. goto PassThrough;
  338. }
  339. perLink = scb->PerLink;
  340. //
  341. // This is a rename-over with a destination that's a SIS file object. Get the file
  342. // id of the destination file, prepare a refcount change, and close our handle to the
  343. // file.
  344. //
  345. status = SipQueryInformationFile(
  346. dstFileObject,
  347. DeviceObject,
  348. FileInternalInformation,
  349. sizeof(FILE_INTERNAL_INFORMATION),
  350. internalInfo,
  351. NULL); // returnedLength
  352. if (!NT_SUCCESS(status)) {
  353. SIS_MARK_POINT_ULONG(status);
  354. goto PassThrough;
  355. }
  356. status = SipPrepareCSRefcountChange(
  357. perLink->CsFile,
  358. &perLink->Index,
  359. &internalInfo->IndexNumber,
  360. SIS_REFCOUNT_UPDATE_LINK_DELETED); // rename-over destroys the destination file ID, so it's DELETED, not OVERWRITTEN
  361. if (!NT_SUCCESS(status)) {
  362. SIS_MARK_POINT_ULONG(status);
  363. goto PassThrough;
  364. }
  365. SipReferencePerLink(perLink);
  366. ObDereferenceObject(dstFileObject);
  367. ZwClose(dstFileHandle);
  368. dstFileObject = NULL;
  369. dstFileHandle = NULL;
  370. //
  371. // Now call NTFS and resynchronize with the irp when it completes.
  372. //
  373. KeInitializeEvent(event,NotificationEvent,FALSE);
  374. nextIrpSp = IoGetNextIrpStackLocation(Irp);
  375. RtlMoveMemory(nextIrpSp, irpSp, sizeof (IO_STACK_LOCATION));
  376. IoSetCompletionRoutine( Irp,
  377. SiRenameOverCompletion,
  378. event,
  379. TRUE,
  380. TRUE,
  381. TRUE);
  382. status = IoCallDriver(deviceExtension->AttachedToDeviceObject, Irp);
  383. if (STATUS_PENDING == status) {
  384. KeWaitForSingleObject(event, Executive, KernelMode, FALSE, NULL);
  385. }
  386. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  387. //
  388. // It failed, so the SIS link target wasn't destroyed.
  389. //
  390. SIS_MARK_POINT_ULONG(status);
  391. goto NoOverwrite;
  392. }
  393. //
  394. // The rename completed successfully. See if the destination file is still there.
  395. // Unfortunately, we have to post to do this, because we can't open the file by
  396. // name, lest someone rename it away from the rename-over that just completed (this
  397. // is a different race than the one that's left open, and would cause the backpointer
  398. // to go away when the file still exists, which is a much worse problem). In order
  399. // to open it by ID, we need a handle to a file on this volume, which we have in the
  400. // device extension, but it's in the system process context.
  401. //
  402. // We need to take an extra reference to the PerLink before handing off to the
  403. // worker thread. This is because we need to call SipHandoffBackpointerResource
  404. // after posting our work request, but in posting the work request we lose our
  405. // original reference to the per link, so there's no way to guarantee that the
  406. // csfile still exists after the post happens.
  407. //
  408. SipReferencePerLink(perLink);
  409. KeInitializeEvent(checkRequest->event, NotificationEvent, FALSE);
  410. checkRequest->perLink = perLink;
  411. checkRequest->internalInfo = internalInfo;
  412. checkRequest->DeviceObject = DeviceObject;
  413. checkRequest->thread = ExGetCurrentResourceThread();
  414. ExInitializeWorkItem(
  415. checkRequest->workItem,
  416. SipRenameOverCheck,
  417. checkRequest);
  418. ExQueueWorkItem(
  419. checkRequest->workItem,
  420. CriticalWorkQueue);
  421. //
  422. // The worker thread now will complete the refcount change, so we
  423. // need to say that we've handed off, and also drop the extra perLink
  424. // reference that we took.
  425. //
  426. SipHandoffBackpointerResource(perLink->CsFile);
  427. SipDereferencePerLink(perLink);
  428. KeWaitForSingleObject(checkRequest->event, Executive, KernelMode, FALSE, NULL);
  429. //
  430. // Now it's all done, just complete the irp.
  431. //
  432. status = Irp->IoStatus.Status;
  433. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  434. return status;
  435. PassThrough:
  436. //
  437. // Something went wrong (or this just isn't a SIS file or doesn't exist or whatever).
  438. // Clean up and pass the request down.
  439. //
  440. if (NULL != dstFileObject) {
  441. ObDereferenceObject(dstFileObject);
  442. }
  443. if (NULL != dstFileHandle) {
  444. ZwClose(dstFileHandle);
  445. }
  446. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  447. NoOverwrite:
  448. //
  449. // We got far enough to prepare the refcount change, but have decided that the
  450. // file wasn't overwritten. Get out. Note that we need to complete the irp
  451. // ourselves here, because we've already called into NTFS and stopped the
  452. // irp completion processing.
  453. //
  454. SipCompleteCSRefcountChange(
  455. perLink,
  456. &perLink->Index,
  457. perLink->CsFile,
  458. FALSE,
  459. FALSE);
  460. SipDereferencePerLink(perLink);
  461. status = Irp->IoStatus.Status;
  462. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  463. ASSERT(NULL == dstFileObject);
  464. ASSERT(NULL == dstFileHandle);
  465. return status;
  466. }
  467. NTSTATUS
  468. SiDeleteCompletion(
  469. IN PDEVICE_OBJECT DeviceObject,
  470. IN PIRP Irp,
  471. IN PVOID Context)
  472. {
  473. PSIS_PER_LINK perLink = (PSIS_PER_LINK)Context;
  474. KIRQL OldIrql;
  475. PFILE_DISPOSITION_INFORMATION disposition;
  476. UNREFERENCED_PARAMETER( DeviceObject );
  477. if (Irp->PendingReturned) {
  478. IoMarkIrpPending(Irp);
  479. }
  480. disposition = Irp->AssociatedIrp.SystemBuffer;
  481. ASSERT(NULL != disposition);
  482. // We just sent a delete setInformation call down to the link file. If it worked,
  483. // we need to decrement the reference count on the underlying CS file (the file, not
  484. // the SIS_CS_FILE object).
  485. SIS_MARK_POINT_ULONG(perLink);
  486. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  487. KeAcquireSpinLock(perLink->SpinLock, &OldIrql);
  488. if (disposition->DeleteFile) {
  489. perLink->Flags |= SIS_PER_LINK_DELETE_DISPOSITION_SET;
  490. } else {
  491. perLink->Flags &= ~SIS_PER_LINK_DELETE_DISPOSITION_SET;
  492. }
  493. KeReleaseSpinLock(perLink->SpinLock, OldIrql);
  494. }
  495. SipEndDeleteModificationOperation(perLink,disposition->DeleteFile);
  496. SIS_MARK_POINT_ULONG(perLink);
  497. return STATUS_SUCCESS;
  498. }
  499. NTSTATUS
  500. SiSetEofCompletion(
  501. IN PDEVICE_OBJECT DeviceObject,
  502. IN PIRP Irp,
  503. IN PVOID Context)
  504. /*++
  505. Routine Description:
  506. A SetFileInformation with class FileEndOfFileInformation has completed.
  507. We hold the scb for this file. Release it.
  508. Arguments:
  509. DeviceObject - Pointer to this driver's device object.
  510. Irp - Pointer to the I/O Request Packet representing the set EOF request.
  511. Context - Context parameter, a PSI_SET_EOF_COMPLETION_CONTEXT.
  512. Return Value:
  513. The function value for this routine is always success.
  514. --*/
  515. {
  516. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  517. PFILE_OBJECT fileObject;
  518. PSIS_SCB scb = (PSIS_SCB)Context;
  519. PFILE_END_OF_FILE_INFORMATION eofInfo;
  520. LONGLONG newLength;
  521. KIRQL OldIrql;
  522. UNREFERENCED_PARAMETER( DeviceObject );
  523. fileObject = irpSp->FileObject;
  524. eofInfo = Irp->AssociatedIrp.SystemBuffer;
  525. ASSERT(eofInfo);
  526. newLength = eofInfo->EndOfFile.QuadPart;
  527. SipAcquireScb(scb);
  528. //
  529. // If the set EOF succeeded, update our internal data structures to
  530. // record the new file length.
  531. //
  532. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  533. ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
  534. if (newLength != scb->SizeBackedByUnderlyingFile) {
  535. //
  536. // This call set the length to something other than the size of the
  537. // underlying file, which means that the file is now dirty. Indicate so.
  538. //
  539. PSIS_PER_LINK perLink = scb->PerLink;
  540. scb->Flags |= SIS_SCB_ANYTHING_IN_COPIED_FILE;
  541. KeAcquireSpinLock(perLink->SpinLock, &OldIrql);
  542. perLink->Flags |= SIS_PER_LINK_DIRTY;
  543. KeReleaseSpinLock(perLink->SpinLock, OldIrql);
  544. }
  545. if (newLength < scb->SizeBackedByUnderlyingFile) {
  546. //
  547. // This truncated the file.
  548. //
  549. SipTruncateScb(scb,newLength);
  550. }
  551. }
  552. SipReleaseScb(scb);
  553. //
  554. // Propogate the IRP pending flag.
  555. //
  556. if (Irp->PendingReturned) {
  557. IoMarkIrpPending( Irp );
  558. }
  559. return STATUS_SUCCESS;
  560. }
  561. NTSTATUS
  562. SiSetInfo(
  563. IN PDEVICE_OBJECT DeviceObject,
  564. IN PIRP Irp
  565. )
  566. /*++
  567. Routine Description:
  568. This is invoked on all NtSetInformationFile calls. We need to catch delete requests for files in
  569. the common store, which need to be turned into delete requests for the links (and also result in
  570. decrementing the ref count for the common store object, possibly deleting that as well.) All other
  571. set information calls are handled by the normal parts of the driver stack.
  572. Arguments:
  573. DeviceObject - Pointer to this driver's device object.
  574. Irp - Pointer to the I/O Request Packet representing the set file information request.
  575. Context - Context parameter for this driver, unused.
  576. Return Value:
  577. The function value for this routine is always success.
  578. --*/
  579. {
  580. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  581. PDEVICE_EXTENSION deviceExtension;
  582. PFILE_OBJECT fileObject = irpSp->FileObject;
  583. FILE_INFORMATION_CLASS FileInformationClass;
  584. NTSTATUS status;
  585. PSIS_SCB scb;
  586. PSIS_PER_FILE_OBJECT perFO;
  587. PIO_STACK_LOCATION nextIrpSp;
  588. SipHandleControlDeviceObject(DeviceObject, Irp);
  589. FileInformationClass = irpSp->Parameters.SetFile.FileInformationClass;
  590. if (FileRenameInformation == FileInformationClass) {
  591. //
  592. // We need to deal with the case where the target of a rename replace-if-exists
  593. // is a SIS link. So, regardless of what type of file the source is, if this
  594. // rename has replace-if-exists set, we have to deal with it.
  595. //
  596. PFILE_RENAME_INFORMATION fileRenameInfo = Irp->AssociatedIrp.SystemBuffer;
  597. if (fileRenameInfo->ReplaceIfExists) {
  598. //
  599. // This is a replace-if-exists rename request. Let our special code handle it.
  600. //
  601. return SipReplaceIfExistsRename(DeviceObject, Irp);
  602. }
  603. }
  604. if (!SipIsFileObjectSIS(fileObject,DeviceObject,FindActive,&perFO,&scb)) {
  605. // This isn't a SIS file, just pass the call through to NTFS
  606. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  607. }
  608. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  609. ASSERT(scb);
  610. SIS_MARK_POINT_ULONG(FileInformationClass);
  611. SIS_MARK_POINT_ULONG(scb);
  612. switch (FileInformationClass) {
  613. case FileLinkInformation: {
  614. //
  615. // Don't allow hard links to SIS files.
  616. //
  617. status = STATUS_OBJECT_TYPE_MISMATCH;
  618. SIS_MARK_POINT();
  619. Irp->IoStatus.Status = status;
  620. Irp->IoStatus.Information = 0;
  621. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  622. SIS_MARK_POINT();
  623. return status;
  624. }
  625. case FileDispositionInformation: {
  626. PFILE_DISPOSITION_INFORMATION disposition;
  627. PSIS_PER_LINK perLink;
  628. perLink = scb->PerLink;
  629. disposition = Irp->AssociatedIrp.SystemBuffer;
  630. SipBeginDeleteModificationOperation(perLink, disposition->DeleteFile);
  631. //
  632. // Send the delete irp down on the link/copied file.
  633. //
  634. nextIrpSp = IoGetNextIrpStackLocation( Irp );
  635. RtlMoveMemory(nextIrpSp, irpSp, sizeof (IO_STACK_LOCATION));
  636. IoSetCompletionRoutine( Irp,
  637. SiDeleteCompletion,
  638. perLink,
  639. TRUE,
  640. TRUE,
  641. TRUE);
  642. SIS_MARK_POINT_ULONG(scb);
  643. status = IoCallDriver(deviceExtension->AttachedToDeviceObject, Irp);
  644. return status;
  645. }
  646. case FilePositionInformation: {
  647. PFILE_POSITION_INFORMATION position = Irp->AssociatedIrp.SystemBuffer;
  648. //
  649. // Check if the file uses intermediate buffering. If it does
  650. // then the new position we're supplied must be aligned properly
  651. // for the device
  652. //
  653. if ((fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
  654. && position->CurrentByteOffset.LowPart % deviceExtension->FilesystemVolumeSectorSize) {
  655. status = STATUS_INVALID_PARAMETER;
  656. } else {
  657. //
  658. // Just set the offset, regardless of whether it's beyond EOF.
  659. //
  660. fileObject->CurrentByteOffset = position->CurrentByteOffset;
  661. status = STATUS_SUCCESS;
  662. }
  663. Irp->IoStatus.Status = status;
  664. Irp->IoStatus.Information = 0;
  665. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  666. SIS_MARK_POINT();
  667. return status;
  668. }
  669. case FileEndOfFileInformation: {
  670. PFILE_END_OF_FILE_INFORMATION endOfFile = Irp->AssociatedIrp.SystemBuffer;
  671. SIS_MARK_POINT_ULONG(endOfFile->EndOfFile.LowPart);
  672. #if DBG
  673. if (BJBDebug & 0x10000) {
  674. DbgPrint("SIS: SiSetInfo: set EOF information scb %p, AO %d, eof.lp 0x%x\n",
  675. scb,irpSp->Parameters.SetFile.AdvanceOnly,endOfFile->EndOfFile.LowPart);
  676. }
  677. #endif // DBG
  678. if (irpSp->Parameters.SetFile.AdvanceOnly) {
  679. //
  680. // This is the lazywriter advancing valid data length, so it's guaranteed
  681. // not to truncate the file, so we don't need to pay attention to it.
  682. // Just pass it down to NTFS unattended.
  683. //
  684. SIS_MARK_POINT_ULONG(scb);
  685. SipDirectPassThroughAndReturn(DeviceObject,Irp);
  686. }
  687. nextIrpSp = IoGetNextIrpStackLocation(Irp);
  688. RtlMoveMemory(nextIrpSp, irpSp, sizeof(IO_STACK_LOCATION));
  689. //
  690. // We've completed the copy on write. Pass the call down on the copied file object.
  691. // Hold the Scb while the call goes down, and release it in the completion routine.
  692. //
  693. IoSetCompletionRoutine(
  694. Irp,
  695. SiSetEofCompletion,
  696. scb,
  697. TRUE,
  698. TRUE,
  699. TRUE);
  700. return IoCallDriver(deviceExtension->AttachedToDeviceObject, Irp);
  701. }
  702. default: {
  703. // Just pass it down
  704. SIS_MARK_POINT();
  705. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  706. }
  707. }
  708. /*NOTREACHED*/
  709. ASSERT(FALSE && "NOTREACHED");
  710. SIS_MARK_POINT();
  711. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  712. }
  713. NTSTATUS
  714. SiQueryBasicInfoCompletion(
  715. IN PDEVICE_OBJECT DeviceObject,
  716. IN PIRP Irp,
  717. IN PVOID Context)
  718. /*++
  719. Routine Description:
  720. A QueryInformationFile with class FileBasicInformation has completed successfully
  721. for a non-FILE_OPEN_REPARSE_POINT file. Clear out the reparse and sparse flags.
  722. Arguments:
  723. DeviceObject - Pointer to this driver's device object.
  724. Irp - Pointer to the I/O Request Packet representing the query basic information
  725. request.
  726. Context - Context parameter, a PSIS_PER_FILE_OBJECT.
  727. Return Value:
  728. STATUS_SUCCESS.
  729. --*/
  730. {
  731. PFILE_BASIC_INFORMATION basicInfo = (PFILE_BASIC_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  732. UNREFERENCED_PARAMETER(Context);
  733. UNREFERENCED_PARAMETER(DeviceObject);
  734. ASSERT(NULL != basicInfo);
  735. SIS_MARK_POINT_ULONG(Irp);
  736. basicInfo->FileAttributes &= ~(FILE_ATTRIBUTE_SPARSE_FILE|FILE_ATTRIBUTE_REPARSE_POINT);
  737. //
  738. // If there are no remaining attributes set, explicitly set FILE_ATTRIBUTE_NORMAL.
  739. //
  740. if (0 == basicInfo->FileAttributes) {
  741. basicInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
  742. }
  743. return STATUS_SUCCESS;
  744. }
  745. NTSTATUS
  746. SiQueryAllInfoCompletion(
  747. IN PDEVICE_OBJECT DeviceObject,
  748. IN PIRP Irp,
  749. IN PVOID Context)
  750. /*++
  751. Routine Description:
  752. A QueryInformationFile with class FileAllInformation has completed successfully
  753. for a non-FILE_OPEN_REPARSE_POINT file. Clear out the reparse and sparse flags.
  754. Arguments:
  755. DeviceObject - Pointer to this driver's device object.
  756. Irp - Pointer to the I/O Request Packet representing the query all information
  757. request
  758. Context - Context parameter, a PSIS_PER_FILE_OBJECT.
  759. Return Value:
  760. STATUS_SUCCESS.
  761. --*/
  762. {
  763. PFILE_ALL_INFORMATION allInfo = (PFILE_ALL_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  764. UNREFERENCED_PARAMETER(Context);
  765. UNREFERENCED_PARAMETER(DeviceObject);
  766. ASSERT(NULL != allInfo);
  767. SIS_MARK_POINT_ULONG(Irp);
  768. allInfo->BasicInformation.FileAttributes &= ~(FILE_ATTRIBUTE_SPARSE_FILE|FILE_ATTRIBUTE_REPARSE_POINT);
  769. //
  770. // If there are no remaining attributes set, explicitly set FILE_ATTRIBUTE_NORMAL.
  771. //
  772. if (0 == allInfo->BasicInformation.FileAttributes) {
  773. allInfo->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_NORMAL;
  774. }
  775. return STATUS_SUCCESS;
  776. }
  777. NTSTATUS
  778. SiQueryNetworkOpenInfoCompletion(
  779. IN PDEVICE_OBJECT DeviceObject,
  780. IN PIRP Irp,
  781. IN PVOID Context)
  782. /*++
  783. Routine Description:
  784. A QueryInformationFile with class FileNetworkOpenInformation has completed successfully
  785. for a non-FILE_OPEN_REPARSE_POINT file. Clear out the reparse and sparse flags.
  786. Arguments:
  787. DeviceObject - Pointer to this driver's device object.
  788. Irp - Pointer to the I/O Request Packet representing the query network open information
  789. request
  790. Context - Context parameter, a PSIS_PER_FILE_OBJECT.
  791. Return Value:
  792. STATUS_SUCCESS.
  793. --*/
  794. {
  795. PFILE_NETWORK_OPEN_INFORMATION netOpenInfo = (PFILE_NETWORK_OPEN_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  796. UNREFERENCED_PARAMETER(Context);
  797. UNREFERENCED_PARAMETER(DeviceObject);
  798. ASSERT(NULL != netOpenInfo);
  799. SIS_MARK_POINT_ULONG(Irp);
  800. netOpenInfo->FileAttributes &= ~(FILE_ATTRIBUTE_SPARSE_FILE|FILE_ATTRIBUTE_REPARSE_POINT);
  801. //
  802. // If there are no remaining attributes set, explicitly set FILE_ATTRIBUTE_NORMAL.
  803. //
  804. if (0 == netOpenInfo->FileAttributes) {
  805. netOpenInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
  806. }
  807. return STATUS_SUCCESS;
  808. }
  809. NTSTATUS
  810. SiQueryAttributeTagInfoCompletion(
  811. IN PDEVICE_OBJECT DeviceObject,
  812. IN PIRP Irp,
  813. IN PVOID Context)
  814. /*++
  815. Routine Description:
  816. A QueryInformationFile with class FileAttributeTagInformation has completed successfully
  817. for a non-FILE_OPEN_REPARSE_POINT file. Clear out the reparse and sparse flags, and set
  818. the reparse tag as if it were not a reparse point.
  819. Arguments:
  820. DeviceObject - Pointer to this driver's device object.
  821. Irp - Pointer to the I/O Request Packet representing the query attribute tag request.
  822. Context - Context parameter, a PSIS_PER_FILE_OBJECT.
  823. Return Value:
  824. STATUS_SUCCESS.
  825. --*/
  826. {
  827. PFILE_ATTRIBUTE_TAG_INFORMATION attributeTagInfo = (PFILE_ATTRIBUTE_TAG_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  828. UNREFERENCED_PARAMETER(Context);
  829. UNREFERENCED_PARAMETER(DeviceObject);
  830. ASSERT(NULL != attributeTagInfo);
  831. SIS_MARK_POINT_ULONG(Irp);
  832. attributeTagInfo->FileAttributes &= ~(FILE_ATTRIBUTE_SPARSE_FILE|FILE_ATTRIBUTE_REPARSE_POINT);
  833. attributeTagInfo->ReparseTag = IO_REPARSE_TAG_RESERVED_ZERO;
  834. //
  835. // If there are no remaining attributes set, explicitly set FILE_ATTRIBUTE_NORMAL.
  836. //
  837. if (0 == attributeTagInfo->FileAttributes) {
  838. attributeTagInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
  839. }
  840. return STATUS_SUCCESS;
  841. }
  842. NTSTATUS
  843. SiQueryInfo(
  844. IN PDEVICE_OBJECT DeviceObject,
  845. IN PIRP Irp
  846. )
  847. /*++
  848. Routine Description:
  849. The top level entry point for a query information irp. We do special
  850. processing for a few of these, check to see if it's one and dispatch
  851. appropriately.
  852. Arguments:
  853. DeviceObject - Pointer to this driver's device object.
  854. Irp - Pointer to the I/O Request Packet representing the query request.
  855. Return Value:
  856. status of the request, typically returned from NTFS
  857. --*/
  858. {
  859. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  860. PIO_STACK_LOCATION nextIrpSp;
  861. PFILE_OBJECT fileObject = irpSp->FileObject;
  862. PSIS_PER_FILE_OBJECT perFO;
  863. PIO_COMPLETION_ROUTINE completionRoutine;
  864. KIRQL OldIrql;
  865. BOOLEAN openedAsReparsePoint;
  866. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  867. SipHandleControlDeviceObject(DeviceObject, Irp);
  868. if (!SipIsFileObjectSIS(fileObject,DeviceObject,FindActive,&perFO,NULL)) {
  869. // This isn't a SIS file, just pass the call through to NTFS
  870. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  871. }
  872. KeAcquireSpinLock(perFO->SpinLock, &OldIrql);
  873. openedAsReparsePoint = (perFO->Flags & SIS_PER_FO_OPEN_REPARSE) ? TRUE : FALSE;
  874. KeReleaseSpinLock(perFO->SpinLock, OldIrql);
  875. if (openedAsReparsePoint) {
  876. //
  877. // This was opened as a reparse point, so let the user see the real truth.
  878. //
  879. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  880. }
  881. SIS_MARK_POINT_ULONG(irpSp->Parameters.QueryFile.FileInformationClass);
  882. SIS_MARK_POINT_ULONG(perFO->fc->primaryScb);
  883. #if DBG
  884. if (BJBDebug & 0x10) {
  885. DbgPrint("SIS: SiQueryInfo: InformationClass %d\n",
  886. irpSp->Parameters.QueryFile.FileInformationClass);
  887. }
  888. #endif // DBG
  889. // Handle the request.
  890. //
  891. switch (irpSp->Parameters.QueryFile.FileInformationClass) {
  892. case FileDirectoryInformation: // 1 // diretory-only call, let NTFS reject it
  893. case FileFullDirectoryInformation: // 2 // diretory-only call, let NTFS reject it
  894. case FileBothDirectoryInformation: // 3 // diretory-only call, let NTFS reject it
  895. // 4 // FileBasicInfo handled separately
  896. case FileStandardInformation: // 5
  897. case FileInternalInformation: // 6
  898. case FileEaInformation: // 7
  899. case FileAccessInformation: // 8
  900. case FileNameInformation: // 9
  901. case FileRenameInformation: // 10 // rename isn't valid for query, but we'll let NTFS reject it
  902. case FileLinkInformation: // 11 // link isn't valid for query, but we'll let NTFS reject it
  903. case FileNamesInformation: // 12 // diretory-only call, let NTFS reject it
  904. case FileDispositionInformation: // 13
  905. case FilePositionInformation: // 14
  906. case FileFullEaInformation: // 15 // NTFS doesn't support this, but we'll let it reject it
  907. case FileModeInformation: // 16
  908. case FileAlignmentInformation: // 17
  909. // 18 // FileAllInformation handled separately
  910. case FileAllocationInformation: // 19
  911. case FileEndOfFileInformation: // 20
  912. case FileAlternateNameInformation: // 21
  913. case FileStreamInformation: // 22
  914. case FilePipeInformation: // 23 // NTFS doesn't support this, but we'll let it reject it
  915. case FilePipeLocalInformation: // 24 // NTFS doesn't support this, but we'll let it reject it
  916. case FilePipeRemoteInformation: // 25 // NTFS doesn't support this, but we'll let it reject it
  917. case FileMailslotQueryInformation: // 26 // NTFS doesn't support this, but we'll let it reject it
  918. case FileMailslotSetInformation: // 27 // NTFS doesn't support this, but we'll let it reject it
  919. case FileCompressionInformation: // 28
  920. case FileObjectIdInformation: // 29
  921. case FileCompletionInformation: // 30 // NTFS doesn't support this, but we'll let it reject it
  922. // 31 FileMoveCluserInformation - intentionally failed for SIS files (+ not supported by NTFS)
  923. case FileQuotaInformation: // 32 // diretory-only call, let NTFS reject it
  924. case FileReparsePointInformation: // 33 // diretory-only call, let NTFS reject it
  925. // 34 // FileNetworkOpenInformation handled separately
  926. // 35 // FileAttributeTagInformation handled separately
  927. case FileTrackingInformation: // 36 // NTFS doesn't support this, but we'll let it reject it
  928. //
  929. // Set the completion routine to NULL, which says that we never want to
  930. // catch completions on these calls.
  931. //
  932. completionRoutine = NULL;
  933. break;
  934. case FileBasicInformation: // 4
  935. completionRoutine = SiQueryBasicInfoCompletion;
  936. break;
  937. case FileAllInformation: // 18
  938. completionRoutine = SiQueryAllInfoCompletion;
  939. break;
  940. case FileNetworkOpenInformation: // 34
  941. completionRoutine = SiQueryNetworkOpenInfoCompletion;
  942. break;
  943. case FileAttributeTagInformation: // 35
  944. completionRoutine = SiQueryAttributeTagInfoCompletion;
  945. break;
  946. case FileMoveClusterInformation: // 31 // NTFS doesn't implement this, but it's too scary to pass through anyway
  947. //
  948. // Reject these calls, for now.
  949. //
  950. SIS_MARK_POINT_ULONG(perFO->fc->primaryScb);
  951. #if DBG
  952. DbgPrint("SIS: SiQueryInfo: aborting FileInformationClass %d\n",irpSp->Parameters.QueryFile.FileInformationClass);
  953. #endif // DBG
  954. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  955. Irp->IoStatus.Information = 0;
  956. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  957. return STATUS_INVALID_PARAMETER;
  958. default:
  959. //
  960. // It's an unknown or invalid information class. Assume that it's newly added and
  961. // benign, and pass it down to NTFS unmodified.
  962. //
  963. SIS_MARK_POINT_ULONG(perFO->fc->primaryScb);
  964. SIS_MARK_POINT_ULONG(irpSp->Parameters.QueryFile.FileInformationClass);
  965. completionRoutine = NULL;
  966. #if DBG
  967. DbgPrint("SIS: SiQueryInfo: passing though unknown FileInformationClass %d\n",irpSp->Parameters.QueryFile.FileInformationClass);
  968. #endif // DBG
  969. break;
  970. }
  971. if (NULL == completionRoutine) {
  972. //
  973. // This call doesn't require fixup on completion. Pass it through.
  974. //
  975. SipDirectPassThroughAndReturn(DeviceObject, Irp);
  976. } else {
  977. //
  978. // This call requires fixup on the way out. Only invoke the
  979. // completion routine on success; else, there's nothing to fix up.
  980. //
  981. nextIrpSp = IoGetNextIrpStackLocation( Irp );
  982. RtlMoveMemory(nextIrpSp, irpSp, sizeof (IO_STACK_LOCATION));
  983. IoSetCompletionRoutine(
  984. Irp,
  985. completionRoutine,
  986. perFO,
  987. TRUE,
  988. FALSE,
  989. FALSE);
  990. return IoCallDriver(deviceExtension->AttachedToDeviceObject, Irp);
  991. }
  992. }
  993. VOID
  994. SipTruncateScb(
  995. IN OUT PSIS_SCB scb,
  996. IN LONGLONG newLength)
  997. {
  998. LONGLONG newLengthInSectors;
  999. PDEVICE_EXTENSION deviceExtension;
  1000. deviceExtension = (PDEVICE_EXTENSION)scb->PerLink->CsFile->DeviceObject->DeviceExtension;
  1001. newLengthInSectors = (newLength + deviceExtension->FilesystemVolumeSectorSize - 1) /
  1002. deviceExtension->FilesystemVolumeSectorSize;
  1003. ASSERT(newLength < scb->SizeBackedByUnderlyingFile); // else this isn't a truncation
  1004. FsRtlTruncateLargeMcb(scb->Ranges,newLengthInSectors);
  1005. scb->SizeBackedByUnderlyingFile = newLength;
  1006. }
  1007. VOID
  1008. SipBeginDeleteModificationOperation(
  1009. IN OUT PSIS_PER_LINK perLink,
  1010. IN BOOLEAN delete)
  1011. /*++
  1012. Routine Description:
  1013. We are beginning a delete or undelete operation on the given
  1014. per-link. If there is the opposite kind of operation in
  1015. progress, wait for it to complete. Otherwise, indicate that
  1016. the new operation is in progress and continue.
  1017. Must be called at IRQL < DISPATCH_LEVEL.
  1018. Arguments:
  1019. perLink - the per link for the file on which we're doing the (un)delete.
  1020. delete - TRUE for delete, FALSE for undelete
  1021. Return Value:
  1022. void
  1023. --*/
  1024. {
  1025. KIRQL OldIrql;
  1026. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1027. KeAcquireSpinLock(perLink->SpinLock, &OldIrql);
  1028. while ((perLink->PendingDeleteCount > 0) &&
  1029. ((delete && (perLink->Flags & SIS_PER_LINK_UNDELETE_IN_PROGRESS)) ||
  1030. (((!delete) && !(perLink->Flags & SIS_PER_LINK_UNDELETE_IN_PROGRESS))))) {
  1031. //
  1032. // The wrong kind of operation is happening now, so we need to block.
  1033. //
  1034. if (!(perLink->Flags & SIS_PER_LINK_DELETE_WAITERS)) {
  1035. KeClearEvent(perLink->DeleteEvent);
  1036. perLink->Flags |= SIS_PER_LINK_DELETE_WAITERS;
  1037. }
  1038. KeReleaseSpinLock(perLink->SpinLock, OldIrql);
  1039. KeWaitForSingleObject(perLink->DeleteEvent, Executive, KernelMode, FALSE, NULL);
  1040. KeAcquireSpinLock(perLink->SpinLock, &OldIrql);
  1041. }
  1042. if (!delete) {
  1043. ASSERT((perLink->PendingDeleteCount == 0) || (perLink->Flags & SIS_PER_LINK_UNDELETE_IN_PROGRESS));
  1044. perLink->Flags |= SIS_PER_LINK_UNDELETE_IN_PROGRESS;
  1045. } else {
  1046. ASSERT(!(perLink->Flags & SIS_PER_LINK_UNDELETE_IN_PROGRESS));
  1047. }
  1048. perLink->PendingDeleteCount++;
  1049. KeReleaseSpinLock(perLink->SpinLock, OldIrql);
  1050. }
  1051. VOID
  1052. SipEndDeleteModificationOperation(
  1053. IN OUT PSIS_PER_LINK perLink,
  1054. IN BOOLEAN delete)
  1055. /*++
  1056. Routine Description:
  1057. We just finished a delete/undelete operation. Decrement our count and
  1058. if appropriate wake up any waiters.
  1059. Must be called with IRQL <= DISPATCH_LEVEL.
  1060. Arguments:
  1061. perLink - the per link for the file on which we're doing the (un)delete.
  1062. delete - TRUE for delete, FALSE for undelete
  1063. Return Value:
  1064. void
  1065. --*/
  1066. {
  1067. KIRQL OldIrql;
  1068. KeAcquireSpinLock(perLink->SpinLock, &OldIrql);
  1069. ASSERT(perLink->PendingDeleteCount > 0);
  1070. perLink->PendingDeleteCount--;
  1071. #if DBG
  1072. if (delete) {
  1073. ASSERT(!(perLink->Flags & SIS_PER_LINK_UNDELETE_IN_PROGRESS));
  1074. } else {
  1075. ASSERT(perLink->Flags & SIS_PER_LINK_UNDELETE_IN_PROGRESS);
  1076. }
  1077. #endif // DBG
  1078. if (0 == perLink->PendingDeleteCount) {
  1079. if (perLink->Flags & SIS_PER_LINK_DELETE_WAITERS) {
  1080. perLink->Flags &= ~SIS_PER_LINK_DELETE_WAITERS;
  1081. KeSetEvent(perLink->DeleteEvent, IO_NO_INCREMENT, FALSE);
  1082. }
  1083. if (!delete) {
  1084. perLink->Flags &= ~SIS_PER_LINK_UNDELETE_IN_PROGRESS;
  1085. }
  1086. }
  1087. KeReleaseSpinLock(perLink->SpinLock, OldIrql);
  1088. }