VOID NpReleaseCcb ( IN PNONPAGED_CCB NonpagedCcb ) /*++ Routine Description: This routine releases access to the Ccb Arguments: Ccb - Supplies the Ccb being released Return Value: None. --*/ { PAGED_CODE(); DebugTrace(0, Dbg, "NpReleaseCcb, NonpagedCcb = %08lx\n", NonpagedCcb); ExReleaseResource( &(NonpagedCcb->Resource) ); ExReleaseResource( &(NpVcb->Resource) ); return; }
VOID NtfsReleaseScbFromLazyWrite ( IN PVOID OpaqueScb ) /*++ Routine Description: The address of this routine is specified when creating a CacheMap for a file. It is subsequently called by the Lazy Writer after its performing lazy writes to the file. Arguments: Scb - The Scb which was specified as a context parameter for this routine. Return Value: None --*/ { ULONG CompressedStream = (ULONG)OpaqueScb & 1; PSCB Scb = (PSCB)((ULONG)OpaqueScb & ~1); PFCB Fcb = Scb->Fcb; ASSERT_SCB(Scb); PAGED_CODE(); // // Clear the toplevel at this point, if we set it above. // if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) { IoSetTopLevelIrp( NULL ); } Scb->LazyWriteThread[CompressedStream] = NULL; if (NtfsSegmentNumber( &Fcb->FileReference ) <= MASTER_FILE_TABLE2_NUMBER) { NOTHING; } else if (Scb->Header.PagingIoResource != NULL) { ExReleaseResource( Scb->Header.PagingIoResource ); } else { ExReleaseResource( Scb->Header.Resource ); } return; }
static VOID NTAPI AcquireResourceThread( PVOID Context) { NTSTATUS Status = STATUS_SUCCESS; PTHREAD_DATA ThreadData = Context; BOOLEAN Ret; KeEnterCriticalRegion(); Ret = ThreadData->AcquireResource(ThreadData->Res, ThreadData->Wait); if (ThreadData->RetExpected) ok_bool_true(Ret, "AcquireResource returned"); else ok_bool_false(Ret, "AcquireResource returned"); ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent returned"); Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode, FALSE, NULL); ok_eq_hex(Status, STATUS_SUCCESS); if (Ret) ExReleaseResource(ThreadData->Res); KeLeaveCriticalRegion(); }
VOID NpReleaseVcb ( ) /*++ Routine Description: This routine releases access to the Vcb Arguments: Return Value: None. --*/ { PAGED_CODE(); DebugTrace(0, Dbg, "NpReleaseVcb\n", 0); ExReleaseResource( &(NpVcb->Resource) ); return; }
VOID FFSFloppyFlush( IN PVOID Parameter) { PFFS_FLPFLUSH_CONTEXT Context; PFILE_OBJECT FileObject; PFFS_FCB Fcb; PFFS_VCB Vcb; Context = (PFFS_FLPFLUSH_CONTEXT) Parameter; FileObject = Context->FileObject; Fcb = Context->Fcb; Vcb = Context->Vcb; FFSPrint((DBG_USER, "FFSFloppyFlushing ...\n")); IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); if (Vcb) { ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcFlushCache(&(Vcb->SectionObject), NULL, 0, NULL); } if (FileObject) { ASSERT(Fcb == (PFFS_FCB)FileObject->FsContext); ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResource(&Fcb->PagingIoResource); CcFlushCache(&(Fcb->SectionObject), NULL, 0, NULL); ObDereferenceObject(FileObject); } IoSetTopLevelIrp(NULL); ExFreePool(Parameter); }
VOID NtfsReleaseForCreateSection ( IN PFILE_OBJECT FileObject ) { PSCB Scb = (PSCB)FileObject->FsContext; PAGED_CODE(); if (Scb->Header.PagingIoResource != NULL) { ExReleaseResource( Scb->Header.PagingIoResource ); } }
NTSTATUS NtfsReleaseFileForCcFlush ( IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT DeviceObject ) { PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext; PAGED_CODE(); if (Header->PagingIoResource != NULL) { ExReleaseResource( Header->PagingIoResource ); } return STATUS_SUCCESS; UNREFERENCED_PARAMETER( DeviceObject ); }
VOID NtfsReleaseSharedResources ( IN PIRP_CONTEXT IrpContext ) /*++ Routine Description: The routine releases all of the resources acquired shared for transaction. The SharedScb structure is freed if necessary and the Irp Context field is cleared. Arguments: Return Value: None. --*/ { PAGED_CODE(); // // If only one then free the Scb main resource. // if (IrpContext->SharedScbSize == 1) { #ifdef _CAIRO_ if (SafeNodeType(IrpContext->SharedScb) == NTFS_NTC_QUOTA_CONTROL) { NtfsReleaseQuotaControl( IrpContext, (PQUOTA_CONTROL_BLOCK) IrpContext->SharedScb ); } else { ExReleaseResource( ((PSCB) IrpContext->SharedScb)->Header.Resource ); } #else ExReleaseResource( ((PSCB) IrpContext->SharedScb)->Header.Resource ); #endif // _CAIRO_ // // Otherwise traverse the array and look for Scb's to release. // } else { PSCB *NextScb; ULONG Count; NextScb = IrpContext->SharedScb; Count = IrpContext->SharedScbSize; do { if (*NextScb != NULL) { #ifdef _CAIRO_ if (SafeNodeType(*NextScb) == NTFS_NTC_QUOTA_CONTROL) { NtfsReleaseQuotaControl( IrpContext, (PQUOTA_CONTROL_BLOCK) *NextScb ); } else { ExReleaseResource( (*NextScb)->Header.Resource ); } #else ExReleaseResource( (*NextScb)->Header.Resource ); #endif // _CAIRO_ } Count -= 1; NextScb += 1; } while (Count != 0); NtfsFreePool( IrpContext->SharedScb ); } IrpContext->SharedScb = NULL; IrpContext->SharedScbSize = 0; }
VOID DfsDeleteDevices( PDFS_TIMER_CONTEXT DfsTimerContext) { PLIST_ENTRY plink; PDFS_VCB Vcb; PLOGICAL_ROOT_DEVICE_OBJECT DeletedObject; if (DfsData.DeletedVcbQueue.Flink != &DfsData.DeletedVcbQueue) { DfsDbgTrace(0, Dbg, "Examining Deleted Vcbs...\n", 0); ExAcquireResourceExclusive(&DfsData.Resource, TRUE); for (plink = DfsData.DeletedVcbQueue.Flink; plink != &DfsData.DeletedVcbQueue; NOTHING) { Vcb = CONTAINING_RECORD( plink, DFS_VCB, VcbLinks); plink = plink->Flink; DeletedObject = CONTAINING_RECORD( Vcb, LOGICAL_ROOT_DEVICE_OBJECT, Vcb); if (Vcb->OpenFileCount == 0 && Vcb->DirectAccessOpenCount == 0 && DeletedObject->DeviceObject.ReferenceCount == 0) { DfsDbgTrace(0, Dbg, "Deleting Vcb@%08lx\n", Vcb); if (Vcb->LogRootPrefix.Buffer != NULL) ExFreePool(Vcb->LogRootPrefix.Buffer); if (Vcb->LogicalRoot.Buffer != NULL) ExFreePool(Vcb->LogicalRoot.Buffer); RemoveEntryList(&Vcb->VcbLinks); ObDereferenceObject((PVOID) DeletedObject); IoDeleteDevice( &DeletedObject->DeviceObject ); } else { DfsDbgTrace(0, Dbg, "Not deleting Vcb@%08lx\n", Vcb); DfsDbgTrace(0, Dbg, "OpenFileCount = %d\n", Vcb->OpenFileCount); DfsDbgTrace(0, Dbg, "DirectAccessOpens = %d\n", Vcb->DirectAccessOpenCount); DfsDbgTrace(0, Dbg, "DeviceObject Reference count = %d\n", DeletedObject->DeviceObject.ReferenceCount); } } ExReleaseResource(&DfsData.Resource); } DfsTimerContext->InUse = FALSE; }
BOOLEAN UdfFastQueryNetworkInfo ( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This routine is for the fast query call for network file information. Arguments: FileObject - Supplies the file object used in this operation Wait - Indicates if we are allowed to wait for the information Buffer - Supplies the output buffer to receive the basic information IoStatus - Receives the final status of the operation Return Value: BOOLEAN - TRUE if the operation succeeded and FALSE if the caller needs to take the long route. --*/ { BOOLEAN Result = FALSE; TYPE_OF_OPEN TypeOfOpen; PFCB Fcb; PCCB Ccb; PAGED_CODE(); ASSERT_FILE_OBJECT( FileObject ); FsRtlEnterFileSystem(); // // Decode the file object to find the type of open and the data // structures. // TypeOfOpen = UdfDecodeFileObject( FileObject, &Fcb, &Ccb ); // // We only support this request on user file or directory objects. // if (TypeOfOpen != UserFileOpen && TypeOfOpen != UserDirectoryOpen) { FsRtlExitFileSystem(); return FALSE; } // // Acquire the file shared to access the Fcb. // if (!ExAcquireResourceShared( Fcb->Resource, Wait )) { FsRtlExitFileSystem(); return FALSE; } // // Use a try-finally to facilitate cleanup. // try { // // Only deal with 'good' Fcb's. // if (UdfVerifyFcbOperation( NULL, Fcb )) { // // Fill in the input buffer from the Fcb fields. // Buffer->CreationTime = Fcb->Timestamps.CreationTime; Buffer->LastWriteTime = Buffer->ChangeTime = Fcb->Timestamps.ModificationTime; Buffer->LastAccessTime = Fcb->Timestamps.AccessTime; Buffer->FileAttributes = Fcb->FileAttributes | UdfGetExtraFileAttributes( Ccb ); // // Check whether this is a directory. // if (FlagOn( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) { Buffer->AllocationSize.QuadPart = Buffer->EndOfFile.QuadPart = 0; } else { Buffer->AllocationSize.QuadPart = Fcb->AllocationSize.QuadPart; Buffer->EndOfFile.QuadPart = Fcb->FileSize.QuadPart; } // // Update the IoStatus block with the size of this data. // IoStatus->Status = STATUS_SUCCESS; IoStatus->Information = sizeof( FILE_NETWORK_OPEN_INFORMATION ); Result = TRUE; } } finally { ExReleaseResource( Fcb->Resource ); FsRtlExitFileSystem(); } return Result; }
NTSTATUS FFSWriteVolume( IN PFFS_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_VCB Vcb = NULL; PFFS_CCB Ccb = NULL; PFFS_FCBVCB FcbOrVcb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; ULONG Length; LARGE_INTEGER ByteOffset; BOOLEAN PagingIo; BOOLEAN Nocache; BOOLEAN SynchronousIo; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; BOOLEAN bDeferred = FALSE; PUCHAR Buffer = NULL; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); FileObject = IrpContext->FileObject; FcbOrVcb = (PFFS_FCBVCB)FileObject->FsContext; ASSERT(FcbOrVcb); if (!(FcbOrVcb->Identifier.Type == FFSVCB && (PVOID)FcbOrVcb == (PVOID)Vcb)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Ccb = (PFFS_CCB)FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Write.Length; ByteOffset = IoStackLocation->Parameters.Write.ByteOffset; PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE); Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE); SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE); FFSPrint((DBG_INFO, "FFSWriteVolume: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n", ByteOffset.QuadPart, Length, PagingIo, Nocache)); if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } // For the case of "Direct Access Storage Device", we // need flush/purge the cache if (Ccb != NULL) { ExAcquireResourceExclusive(&Vcb->MainResource, TRUE); MainResourceAcquired = TRUE; Status = FFSPurgeVolume(Vcb, TRUE); ExReleaseResource(&Vcb->MainResource); MainResourceAcquired = FALSE; if(!IsFlagOn(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO)) { if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart) { Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } } { FFS_BDL BlockArray; if ((ByteOffset.LowPart & (SECTOR_SIZE - 1)) || (Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; __leave; } Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { __leave; } BlockArray.Irp = NULL; BlockArray.Lba = ByteOffset.QuadPart;; BlockArray.Offset = 0; BlockArray.Length = Length; Status = FFSReadWriteBlocks(IrpContext, Vcb, &BlockArray, Length, 1, FALSE); Irp = IrpContext->Irp; __leave; } } if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) || Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; __leave; } if (ByteOffset.QuadPart >= Vcb->PartitionInformation.PartitionLength.QuadPart) { Irp->IoStatus.Information = 0; Status = STATUS_END_OF_FILE; __leave; } #if FALSE if (!Nocache) { BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); BOOLEAN bWait = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED); if (!CcCanIWrite( FileObject, Length, (bWait && bQueue), bAgain)) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)FFSDeferWrite, IrpContext, Irp, Length, bAgain); bDeferred = TRUE; FFSBreakPoint(); Status = STATUS_PENDING; __leave; } } #endif if (Nocache && !PagingIo && (Vcb->SectionObject.DataSectionObject != NULL)) { ExAcquireResourceExclusive(&Vcb->MainResource, TRUE); MainResourceAcquired = TRUE; ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcFlushCache(&(Vcb->SectionObject), &ByteOffset, Length, &(Irp->IoStatus)); if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; __leave; } ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcPurgeCacheSection(&(Vcb->SectionObject), (PLARGE_INTEGER)&(ByteOffset), Length, FALSE); ExReleaseResource(&Vcb->MainResource); MainResourceAcquired = FALSE; } if (!PagingIo) { if (!ExAcquireResourceExclusiveLite( &Vcb->MainResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } else { /* ULONG ResShCnt, ResExCnt; ResShCnt = ExIsResourceAcquiredSharedLite(&Vcb->PagingIoResource); ResExCnt = ExIsResourceAcquiredExclusiveLite(&Vcb->PagingIoResource); FFSPrint((DBG_USER, "PagingIoRes: %xh:%xh Synchronous=%xh\n", ResShCnt, ResExCnt, IrpContext->IsSynchronous)); */ if (Ccb) { if (!ExAcquireResourceSharedLite( &Vcb->PagingIoResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; } } if (!Nocache) { if ((ByteOffset.QuadPart + Length) > Vcb->PartitionInformation.PartitionLength.QuadPart ) { Length = (ULONG) ( Vcb->PartitionInformation.PartitionLength.QuadPart - ByteOffset.QuadPart); Length &= ~((ULONG)SECTOR_SIZE - 1); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcPrepareMdlWrite( Vcb->StreamObj, &ByteOffset, Length, &Irp->MdlAddress, &Irp->IoStatus); Status = Irp->IoStatus.Status; } else { Buffer = FFSGetUserBuffer(Irp); if (Buffer == NULL) { FFSBreakPoint(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (!CcCopyWrite(Vcb->StreamObj, (PLARGE_INTEGER)(&ByteOffset), Length, TRUE, Buffer)) { Status = STATUS_PENDING; __leave; } Status = Irp->IoStatus.Status; FFSAddMcbEntry(Vcb, ByteOffset.QuadPart, (LONGLONG)Length); } if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; } } else { PFFS_BDL ffs_bdl = NULL; ULONG Blocks = 0; LONGLONG DirtyStart; LONGLONG DirtyLba; LONGLONG DirtyLength; LONGLONG RemainLength; if ((ByteOffset.QuadPart + Length) > Vcb->PartitionInformation.PartitionLength.QuadPart) { Length = (ULONG)( Vcb->PartitionInformation.PartitionLength.QuadPart - ByteOffset.QuadPart); Length &= ~((ULONG)SECTOR_SIZE - 1); } Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { __leave; } ffs_bdl = ExAllocatePool(PagedPool, (Length / Vcb->BlockSize) * sizeof(FFS_BDL)); if (!ffs_bdl) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } DirtyLba = ByteOffset.QuadPart; RemainLength = (LONGLONG)Length; while (RemainLength > 0) { DirtyStart = DirtyLba; if (FFSLookupMcbEntry(Vcb, DirtyStart, &DirtyLba, &DirtyLength, (PLONGLONG)NULL, (PLONGLONG)NULL, (PULONG)NULL)) { if (DirtyLba == -1) { DirtyLba = DirtyStart + DirtyLength; RemainLength = ByteOffset.QuadPart + (LONGLONG)Length - DirtyLba; continue; } ffs_bdl[Blocks].Irp = NULL; ffs_bdl[Blocks].Lba = DirtyLba; ffs_bdl[Blocks].Offset = (ULONG)((LONGLONG)Length + DirtyStart - RemainLength - DirtyLba); if (DirtyLba + DirtyLength > DirtyStart + RemainLength) { ffs_bdl[Blocks].Length = (ULONG)(DirtyStart + RemainLength - DirtyLba); RemainLength = 0; } else { ffs_bdl[Blocks].Length = (ULONG)DirtyLength; RemainLength = (DirtyStart + RemainLength) - (DirtyLba + DirtyLength); } DirtyLba = DirtyStart + DirtyLength; Blocks++; } else { if (Blocks == 0) { if (ffs_bdl) ExFreePool(ffs_bdl); // // Lookup fails at the first time, ie. // no dirty blocks in the run // FFSBreakPoint(); if (RemainLength == (LONGLONG)Length) Status = STATUS_SUCCESS; else Status = STATUS_UNSUCCESSFUL; __leave; } else { break; } } } if (Blocks > 0) { Status = FFSReadWriteBlocks(IrpContext, Vcb, ffs_bdl, Length, Blocks, FALSE); Irp = IrpContext->Irp; if (NT_SUCCESS(Status)) { ULONG i; for (i = 0; i < Blocks; i++) { FFSRemoveMcbEntry(Vcb, ffs_bdl[i].Lba, ffs_bdl[i].Length); } } if (ffs_bdl) ExFreePool(ffs_bdl); if (!Irp) __leave; } else { if (ffs_bdl) ExFreePool(ffs_bdl); Irp->IoStatus.Information = Length; Status = STATUS_SUCCESS; __leave; } } } __finally { if (PagingIoResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->PagingIoResource, ExGetCurrentResourceThread()); } if (MainResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING) { if(!bDeferred) { Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { Status = FFSQueueRequest(IrpContext); } else { FFSCompleteIrpContext(IrpContext, Status); } } } else { if (NT_SUCCESS(Status)) { if (SynchronousIo && !PagingIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } if (!PagingIo) { SetFlag(FileObject->Flags, FO_FILE_MODIFIED); } } FFSCompleteIrpContext(IrpContext, Status); } } else { FFSFreeIrpContext(IrpContext); } } } return Status; }
BOOLEAN NtfsFastUnlockAllByKey ( IN PFILE_OBJECT FileObject, PVOID ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This is a call back routine for doing the fast unlock all by key call. Arguments: FileObject - Supplies the file object used in this operation ProcessId - Supplies the process ID used in this operation Key - Supplies the key used in this operation Status - Receives the Status if this operation is successful Return Value: BOOLEAN - TRUE if this operation completed and FALSE if caller needs to take the long route. --*/ { BOOLEAN Results; IRP_CONTEXT IrpContext; TYPE_OF_OPEN TypeOfOpen; PVCB Vcb; PFCB Fcb; PSCB Scb; PCCB Ccb; UNREFERENCED_PARAMETER( DeviceObject ); PAGED_CODE(); DebugTrace( +1, Dbg, ("NtfsFastUnlockAllByKey\n") ); IoStatus->Information = 0; // // Decode the type of file object we're being asked to process and // make sure that is is only a user file open. // TypeOfOpen = NtfsDecodeFileObject( &IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE ); if (TypeOfOpen != UserFileOpen) { IoStatus->Status = STATUS_INVALID_PARAMETER; IoStatus->Information = 0; DebugTrace( -1, Dbg, ("NtfsFastUnlockAllByKey -> TRUE (STATUS_INVALID_PARAMETER)\n") ); return TRUE; } // // Acquire exclusive access to the Fcb this operation can always wait // FsRtlEnterFileSystem(); if (Scb->ScbType.Data.FileLock == NULL) { (VOID) ExAcquireResourceExclusive( Fcb->Resource, TRUE ); } else { (VOID) ExAcquireResourceShared( Fcb->Resource, TRUE ); } try { // // We check whether we can proceed based on the state of the file oplocks. // if (!FsRtlOplockIsFastIoPossible( &Scb->ScbType.Data.Oplock )) { try_return( Results = FALSE ); } // // If we don't have a file lock, then get one now. // if (Scb->ScbType.Data.FileLock == NULL && !NtfsCreateFileLock( Scb, FALSE )) { try_return( Results = FALSE ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request. The call will always succeed. // Results = TRUE; IoStatus->Status = FsRtlFastUnlockAllByKey( Scb->ScbType.Data.FileLock, FileObject, ProcessId, Key, NULL ); // // Set the flag indicating if Fast I/O is possible // NtfsAcquireFsrtlHeader( Scb ); Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb ); NtfsReleaseFsrtlHeader( Scb ); try_exit: NOTHING; } finally { DebugUnwind( NtfsFastUnlockAllByKey ); // // Release the Fcb, and return to our caller // ExReleaseResource( Fcb->Resource ); FsRtlExitFileSystem(); DebugTrace( -1, Dbg, ("NtfsFastUnlockAllByKey -> %08lx\n", Results) ); } return Results; }
NTSTATUS NtAllocateUuids ( OUT PULARGE_INTEGER Time, OUT PULONG Range, OUT PULONG Sequence ) /*++ Routine Description: This function reserves a range of time for the caller(s) to use for handing out Uuids. As far a possible the same range of time and sequence number will never be given out. (It's possible to reboot 2^14-1 times and set the clock backwards and then call this allocator and get a duplicate. Since only the low 14bits of the sequence number are used in a real uuid.) Arguments: Time - Supplies the address of a variable that will receive the start time (SYSTEMTIME format) of the range of time reserved. Range - Supplies the address of a variable that will receive the number of ticks (100ns) reserved after the value in Time. The range reserved is *Time to (*Time + *Range - 1). Sequence - Supplies the address of a variable that will receive the time sequence number. This value is used with the associated range of time to prevent problems with clocks going backwards. Return Value: STATUS_SUCCESS is returned if the service is successfully executed. STATUS_RETRY is returned if we're unable to reserve a range of UUIDs. This may (?) occur if system clock hasn't advanced and the allocator is out of cached values. STATUS_ACCESS_VIOLATION is returned if the output parameter for the UUID cannot be written. STATUS_UNSUCCESSFUL is returned if some other service reports an error, most likly the registery. --*/ { KPROCESSOR_MODE PreviousMode; NTSTATUS Status; LARGE_INTEGER CurrentTime; LARGE_INTEGER AvailableTime; LARGE_INTEGER OutputTime; ULONG OutputRange; ULONG OutputSequence; PAGED_CODE(); // // Establish an exception handler and attempt to write the output // arguments. If the write attempt fails, then return // the exception code as the service status. Otherwise return success // as the service status. // try { // // Get previous processor mode and probe arguments if necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWrite((PVOID)Time, sizeof(LARGE_INTEGER), sizeof(ULONG)); ProbeForWrite((PVOID)Range, sizeof(ULONG), sizeof(ULONG)); ProbeForWrite((PVOID)Sequence, sizeof(ULONG), sizeof(ULONG)); } } except (ExSystemExceptionFilter()) { return GetExceptionCode(); } ExAcquireResourceExclusive(&ExpUuidLock, TRUE); // // Make sure we have a valid sequence number. If not, make one up. // if (ExpUuidSequenceNumberValid == FALSE) { Status = ExpUuidLoadSequenceNumber(&ExpUuidSequenceNumber); if (!NT_SUCCESS(Status)) { // Unable read the sequence number, this means we should make one up. LARGE_INTEGER PerfCounter; LARGE_INTEGER PerfFrequency; // This should only happen when NtAllocateUuids() is called // for the first time on a given machine. (machine, not boot) KdPrint(("Uuid: Generating first sequence number.\n")); PerfCounter = KeQueryPerformanceCounter(&PerfFrequency); ExpUuidSequenceNumber ^= (ULONG)&Status ^ PerfCounter.LowPart ^ PerfCounter.HighPart ^ (ULONG)Sequence; } else { // We increment the sequence number on every boot. ExpUuidSequenceNumber++; } ExpUuidSequenceNumberValid = TRUE; ExpUuidSequenceNumberNotSaved = TRUE; } // // Get the current time, usually we will have plenty of avaliable // to give the caller. But we may need to deal with time going // backwards and really fast machines. // KeQuerySystemTime(&CurrentTime); AvailableTime.QuadPart = CurrentTime.QuadPart - ExpUuidLastTimeAllocated.QuadPart; if (AvailableTime.QuadPart < 0) { // Time has been set time backwards. This means that we must make sure // that somebody increments the sequence number and saves the new // sequence number in the registry. ExpUuidSequenceNumberNotSaved = TRUE; ExpUuidSequenceNumber++; // The sequence number has been changed, so it's now okay to set time // backwards. Since time is going backwards anyway, it's okay to set // it back an extra millisecond or two. ExpUuidLastTimeAllocated.QuadPart = CurrentTime.QuadPart - 20000; AvailableTime.QuadPart = 20000; } if (AvailableTime.QuadPart == 0) { // System time hasn't moved. The caller should yield the CPU and retry. ExReleaseResource(&ExpUuidLock); return(STATUS_RETRY); } // // Common case, time has moved forward. // if (AvailableTime.QuadPart > 10*1000*1000) { // We never want to give out really old (> 1 second) Uuids. AvailableTime.QuadPart = 10*1000*1000; } if (AvailableTime.QuadPart > 10000) { // We've got over a millisecond to give out. We'll save some time for // another caller so that we can avoid returning STATUS_RETRY very offen. OutputRange = 10000; AvailableTime.QuadPart -= 10000; } else { // Not much time avaiable, give it all away. OutputRange = (ULONG)AvailableTime.QuadPart; AvailableTime.QuadPart = 0; } OutputTime.QuadPart = CurrentTime.QuadPart - (OutputRange + AvailableTime.QuadPart); ExpUuidLastTimeAllocated.QuadPart = OutputTime.QuadPart + OutputRange; // Last time allocated is just after the range we hand back to the caller // this may be almost a second behind the true system time. OutputSequence = ExpUuidSequenceNumber; ExReleaseResource(&ExpUuidLock); // Saving the sequence number will usually complete without any problems. // So we let any other threads go at this point. If the save fails, // we'll retry on some future call. if (ExpUuidSequenceNumberNotSaved == TRUE) { if (ExAcquireResourceExclusive(&ExpSequenceLock, FALSE) == TRUE) { if (ExpUuidSequenceNumberNotSaved == TRUE) { ExpUuidSequenceNumberNotSaved = FALSE; // Print this message just to make sure we aren't hitting the // registry too much under normal usage. KdPrint(("Uuid: Saving new sequence number.\n")); Status = ExpUuidSaveSequenceNumber(ExpUuidSequenceNumber); if (!NT_SUCCESS(Status)) { ExpUuidSequenceNumberNotSaved = TRUE; } } } ExReleaseResource(&ExpSequenceLock); } // // Attempt to store the result of this call into the output parameters. // This is done within an exception handler in case output parameters // are now invalid. // try { Time->QuadPart = OutputTime.QuadPart; *Range = OutputRange; *Sequence = OutputSequence; } except (ExSystemExceptionFilter()) { return GetExceptionCode(); } return(STATUS_SUCCESS); }
BOOLEAN NtfsAcquireExclusiveFcb ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PSCB Scb OPTIONAL, IN BOOLEAN NoDeleteCheck, IN BOOLEAN DontWait ) /*++ Routine Description: This routine acquires exclusive access to the Fcb. This routine will raise if it cannot acquire the resource and wait in the IrpContext is false. Arguments: Fcb - Supplies the Fcb to acquire Scb - This is the Scb for which we are acquiring the Fcb NoDeleteCheck - If TRUE, we don't do any check for deleted files but always acquire the Fcb. DontWait - If TRUE this overrides the wait value in the IrpContext. We won't wait for the resource and return whether the resource was acquired. Return Value: BOOLEAN - TRUE if acquired. FALSE otherwise. --*/ { NTSTATUS Status; BOOLEAN Wait; ASSERT_IRP_CONTEXT(IrpContext); ASSERT_FCB(Fcb); PAGED_CODE(); Status = STATUS_CANT_WAIT; if (DontWait || !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { Wait = FALSE; } else { Wait = TRUE; } if (ExAcquireResourceExclusive( Fcb->Resource, Wait )) { // // The link count should be non-zero or the file has been // deleted. We allow deleted files to be acquired for close and // also allow them to be acquired recursively in case we // acquire them a second time after marking them deleted (i.e. rename) // if (NoDeleteCheck || (IrpContext->MajorFunction == IRP_MJ_CLOSE) || (IrpContext->MajorFunction == IRP_MJ_CREATE) || (!FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED ) && (!ARGUMENT_PRESENT( Scb ) || !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )))) { // // Put Fcb in the exclusive Fcb list for this IrpContext, // excluding the bitmap for the volume, since we do not need // to modify its file record and do not want unnecessary // serialization/deadlock problems. // if ((Fcb->Vcb->BitmapScb == NULL) || (Fcb->Vcb->BitmapScb->Fcb != Fcb)) { // // We need to check if this Fcb is already in an // exclusive list. If it is then we want to attach // the current IrpContext to the IrpContext holding // this Fcb. // if (Fcb->ExclusiveFcbLinks.Flink == NULL) { ASSERT( Fcb->BaseExclusiveCount == 0 ); InsertTailList( &IrpContext->ExclusiveFcbList, &Fcb->ExclusiveFcbLinks ); } Fcb->BaseExclusiveCount += 1; } return TRUE; } // // We need to release the Fcb and remember the status code. // ExReleaseResource( Fcb->Resource ); Status = STATUS_FILE_DELETED; } else if (DontWait) { return FALSE; } NtfsRaiseStatus( IrpContext, Status, NULL, NULL ); }
VOID NtfsReleaseVcbCheckDelete ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN UCHAR MajorCode, IN PFILE_OBJECT FileObject OPTIONAL ) /*++ Routine Description: This routine will release the Vcb. We will also test here whether we should teardown the Vcb at this point. If this is the last open queued to a dismounted volume or the last close from a failed mount or the failed mount then we will want to test the Vcb for a teardown. Arguments: Vcb - Supplies the Vcb to acquire MajorCode - Indicates what type of operation we were called from. FileObject - Optionally supplies the file object whose VPB pointer we need to zero out Return Value: None. --*/ { ASSERT_IRP_CONTEXT(IrpContext); ASSERT_VCB(Vcb); if (FlagOn( Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT ) && (Vcb->CloseCount == 0)) { ULONG ReferenceCount; ULONG ResidualCount; KIRQL SavedIrql; BOOLEAN DeleteVcb = FALSE; ASSERT_EXCLUSIVE_RESOURCE( &Vcb->Resource ); // // The volume has gone through dismount. Now we need to decide if this // release of the Vcb is the last reference for this volume. If so we // can tear the volume down. // // We compare the reference count in the Vpb with the state of the volume // and the type of operation. We also need to check if there is a // referenced log file object. // IoAcquireVpbSpinLock( &SavedIrql ); ReferenceCount = Vcb->Vpb->ReferenceCount; IoReleaseVpbSpinLock( SavedIrql ); ResidualCount = 0; if (Vcb->LogFileObject != NULL) { ResidualCount = 1; } if (MajorCode == IRP_MJ_CREATE) { ResidualCount += 1; } // // If the residual count is the same as the count in the Vpb then we // can delete the Vpb. // if (ResidualCount == ReferenceCount) { SetFlag( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY ); ExReleaseResource( &Vcb->Resource ); // // Never delete the Vcb unless this is the last release of // this Vcb. // if (!ExIsResourceAcquiredExclusive( &Vcb->Resource ) && (ExIsResourceAcquiredShared( &Vcb->Resource ) == 0)) { if (ARGUMENT_PRESENT(FileObject)) { FileObject->Vpb = NULL; } // // If this is a create then the IO system will handle the // Vpb. // if (MajorCode == IRP_MJ_CREATE) { ClearFlag( Vcb->VcbState, VCB_STATE_TEMP_VPB ); } // // Use the global resource to synchronize the DeleteVcb process. // (VOID) ExAcquireResourceExclusive( &NtfsData.Resource, TRUE ); RemoveEntryList( &Vcb->VcbLinks ); ExReleaseResource( &NtfsData.Resource ); NtfsDeleteVcb( IrpContext, &Vcb ); } else { ClearFlag( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY ); } } else { ExReleaseResource( &Vcb->Resource ); } } else { ExReleaseResource( &Vcb->Resource ); } }
VOID NtfsReleaseAllFiles ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN BOOLEAN ReleasePagingIo ) /*++ Routine Description: This routine non-recursively requires all files on a volume. Arguments: Vcb - Supplies the volume ReleasePagingIo - Indicates whether we should release the paging io resources as well. Return Value: None --*/ { PFCB Fcb; PSCB *Scb; PVOID RestartKey; PAGED_CODE(); // // Loop to flush all of the prerestart streams, to do the loop // we cycle through the Fcb Table and for each fcb we acquire it. // RestartKey = NULL; while (TRUE) { NtfsAcquireFcbTable( IrpContext, Vcb ); Fcb = NtfsGetNextFcbTableEntry(Vcb, &RestartKey); NtfsReleaseFcbTable( IrpContext, Vcb ); if (Fcb == NULL) { break; } ASSERT_FCB( Fcb ); if (NtfsSegmentNumber( &Fcb->FileReference ) >= FIRST_USER_FILE_NUMBER) { // // Release the file. // if (ReleasePagingIo && (Fcb->PagingIoResource != NULL)) { ExReleaseResource( Fcb->PagingIoResource ); } NtfsReleaseFcb( IrpContext, Fcb ); } } // // Now release the Fcb's in the Vcb. // Scb = &Vcb->QuotaTableScb; while (TRUE) { if (*Scb != NULL) { if (ReleasePagingIo && ((*Scb)->Fcb->PagingIoResource != NULL)) { ExReleaseResource( (*Scb)->Fcb->PagingIoResource ); } NtfsReleaseFcb( IrpContext, (*Scb)->Fcb ); } if (Scb == &Vcb->MftScb) { break; } Scb -= 1; } NtfsReleaseVcb( IrpContext, Vcb ); return; }
VOID NtfsReleaseScbFromReadAhead ( IN PVOID OpaqueScb ) /*++ Routine Description: The address of this routine is specified when creating a CacheMap for a file. It is subsequently called by the Lazy Writer after its read ahead. Arguments: Scb - The Scb which was specified as a context parameter for this routine. Return Value: None --*/ { PREAD_AHEAD_THREAD ReadAheadThread; PVOID CurrentThread; KIRQL OldIrql; PSCB Scb = (PSCB)OpaqueScb; PFCB Fcb = Scb->Fcb; ASSERT_SCB(Scb); // // Free our read ahead entry. // KeAcquireSpinLock( &NtfsData.StrucSupSpinLock, &OldIrql ); CurrentThread = (PVOID)PsGetCurrentThread(); ReadAheadThread = (PREAD_AHEAD_THREAD)NtfsData.ReadAheadThreads.Flink; while ((ReadAheadThread != (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads) && (ReadAheadThread->Thread != CurrentThread)) { ReadAheadThread = (PREAD_AHEAD_THREAD)ReadAheadThread->Links.Flink; } ASSERT(ReadAheadThread != (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads); ReadAheadThread->Thread = NULL; // // Move him to the end of the list so all the allocated entries are at // the front, and we simplify our scans. // RemoveEntryList( &ReadAheadThread->Links ); InsertTailList( &NtfsData.ReadAheadThreads, &ReadAheadThread->Links ); KeReleaseSpinLock( &NtfsData.StrucSupSpinLock, OldIrql ); if (Scb->Header.PagingIoResource != NULL) { ExReleaseResource( Scb->Header.PagingIoResource ); } return; }
BOOLEAN NtfsAcquireScbForReadAhead ( IN PVOID OpaqueScb, IN BOOLEAN Wait ) /*++ Routine Description: The address of this routine is specified when creating a CacheMap for a file. It is subsequently called by the Lazy Writer prior to its performing read ahead to the file. Arguments: Scb - The Scb which was specified as a context parameter for this routine. Wait - TRUE if the caller is willing to block. Return Value: FALSE - if Wait was specified as FALSE and blocking would have been required. The Fcb is not acquired. TRUE - if the Scb has been acquired --*/ { PREAD_AHEAD_THREAD ReadAheadThread; PVOID CurrentThread; KIRQL OldIrql; PSCB Scb = (PSCB)OpaqueScb; PFCB Fcb = Scb->Fcb; BOOLEAN AcquiredFile = FALSE; ASSERT_SCB(Scb); // // Acquire the Scb only for those files that the read wil // acquire it for, i.e., not the first set of system files. // Otherwise we can deadlock, for example with someone needing // a new Mft record. // if ((Scb->Header.PagingIoResource == NULL) || ExAcquireResourceShared( Scb->Header.PagingIoResource, Wait )) { AcquiredFile = TRUE; // // Add our thread to the read ahead list. // KeAcquireSpinLock( &NtfsData.StrucSupSpinLock, &OldIrql ); CurrentThread = (PVOID)PsGetCurrentThread(); ReadAheadThread = (PREAD_AHEAD_THREAD)NtfsData.ReadAheadThreads.Flink; while ((ReadAheadThread != (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads) && (ReadAheadThread->Thread != NULL)) { // // We better not already see ourselves. // ASSERT( ReadAheadThread->Thread != CurrentThread ); ReadAheadThread = (PREAD_AHEAD_THREAD)ReadAheadThread->Links.Flink; } // // If we hit the end of the list, then allocate a new one. Note we // should have at most one entry per critical worker thread in the // system. // if (ReadAheadThread == (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads) { ReadAheadThread = ExAllocatePoolWithTag( NonPagedPool, sizeof(READ_AHEAD_THREAD), 'RftN' ); // // If we failed to allocate an entry, clean up and raise. // if (ReadAheadThread == NULL) { KeReleaseSpinLock( &NtfsData.StrucSupSpinLock, OldIrql ); if (NtfsSegmentNumber( &Fcb->FileReference ) > VOLUME_DASD_NUMBER) { if (Scb->Header.PagingIoResource != NULL) { ExReleaseResource( Scb->Header.PagingIoResource ); } } ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); } InsertTailList( &NtfsData.ReadAheadThreads, &ReadAheadThread->Links ); } ReadAheadThread->Thread = CurrentThread; KeReleaseSpinLock( &NtfsData.StrucSupSpinLock, OldIrql ); } return AcquiredFile; }
VOID BowserTrace( PCHAR FormatString, ... ) #define LAST_NAMED_ARGUMENT FormatString { CHAR OutputString[1024]; IO_STATUS_BLOCK IoStatus; BOOLEAN ProcessAttached = FALSE; va_list ParmPtr; // Pointer to stack parms. NTSTATUS Status; PAGED_CODE(); if (IoGetCurrentProcess() != BowserFspProcess) { KeAttachProcess(BowserFspProcess); ProcessAttached = TRUE; } if (BrowserTraceLogHandle == NULL) { if (!NT_SUCCESS(BowserOpenTraceLogFile(L"\\SystemRoot\\Bowser.Log"))) { BrowserTraceLogHandle = (HANDLE)0xffffffff; if (ProcessAttached) { KeDetachProcess(); } return; } } else if (BrowserTraceLogHandle == (HANDLE)0xffffffff) { if (ProcessAttached) { KeDetachProcess(); } return; } ExAcquireResourceExclusive(&BrowserTraceLock, TRUE); if (BrowserTraceLogHandle == NULL) { ExReleaseResource(&BrowserTraceLock); if (ProcessAttached) { KeDetachProcess(); } return; } try { LARGE_INTEGER EndOfFile; EndOfFile.HighPart = 0xffffffff; EndOfFile.LowPart = FILE_WRITE_TO_END_OF_FILE; if (LastCharacter == '\n') { LARGE_INTEGER SystemTime; TIME_FIELDS TimeFields; KeQuerySystemTime(&SystemTime); ExSystemTimeToLocalTime(&SystemTime, &SystemTime); RtlTimeToTimeFields(&SystemTime, &TimeFields); // // The last character written was a newline character. We should // timestamp this record in the file. // /**** sprintf(OutputString, "%2.2d/%2.2d/%4.4d %2.2d:%2.2d:%2.2d.%3.3d: ", TimeFields.Month, TimeFields.Day, TimeFields.Year, TimeFields.Hour, TimeFields.Minute, TimeFields.Second, TimeFields.Milliseconds); ****/ if (!NT_SUCCESS(Status = ZwWriteFile(BrowserTraceLogHandle, NULL, NULL, NULL, &IoStatus, OutputString, strlen(OutputString), &EndOfFile, NULL))) { KdPrint(("Error writing time to Browser log file: %lX\n", Status)); return; } if (!NT_SUCCESS(IoStatus.Status)) { KdPrint(("Error writing time to Browser log file: %lX\n", IoStatus.Status)); return; } if (IoStatus.Information != strlen(OutputString)) { KdPrint(("Error writing time to Browser log file: %lX\n", IoStatus.Status)); return; } } va_start(ParmPtr, LAST_NAMED_ARGUMENT); // // Format the parameters to the string. // vsprintf(OutputString, FormatString, ParmPtr); if (!NT_SUCCESS(Status = ZwWriteFile(BrowserTraceLogHandle, NULL, NULL, NULL, &IoStatus, OutputString, strlen(OutputString), &EndOfFile, NULL))) { KdPrint(("Error writing string to Browser log file: %ld\n", Status)); return; } if (!NT_SUCCESS(IoStatus.Status)) { KdPrint(("Error writing string to Browser log file: %lX\n", IoStatus.Status)); return; } if (IoStatus.Information != strlen(OutputString)) { KdPrint(("Error writing string to Browser log file: %ld\n", IoStatus.Status)); return; } // // Remember the last character output to the log. // LastCharacter = OutputString[strlen(OutputString)-1]; } finally { ExReleaseResource(&BrowserTraceLock); if (ProcessAttached) { KeDetachProcess(); } } }
VOID NtfsAcquireSharedFcb ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PSCB Scb OPTIONAL, IN BOOLEAN NoDeleteCheck ) /*++ Routine Description: This routine acquires shared access to the Fcb. This routine will raise if it cannot acquire the resource and wait in the IrpContext is false. Arguments: Fcb - Supplies the Fcb to acquire Scb - This is the Scb for which we are acquiring the Fcb NoDeleteCheck - If TRUE then acquire the file even if it has been deleted. Return Value: None. --*/ { NTSTATUS Status; ASSERT_IRP_CONTEXT(IrpContext); ASSERT_FCB(Fcb); Status = STATUS_CANT_WAIT; if (ExAcquireResourceShared( Fcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { // // The link count should be non-zero or the file has been // deleted. // if (NoDeleteCheck || (!FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED ) && (!ARGUMENT_PRESENT( Scb ) || !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )))) { // // It's possible that this is a recursive shared aquisition of an // Fcb we own exclusively at the top level. In that case we // need to bump the acquisition count. // if (Fcb->ExclusiveFcbLinks.Flink != NULL) { Fcb->BaseExclusiveCount += 1; } return; } // // We need to release the Fcb and remember the status code. // ExReleaseResource( Fcb->Resource ); Status = STATUS_FILE_DELETED; } NtfsRaiseStatus( IrpContext, Status, NULL, NULL ); }
NTSTATUS DfsCommonClose ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) { NTSTATUS Status; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); PFILE_OBJECT FileObject = IrpSp->FileObject; TYPE_OF_OPEN TypeOfOpen; PDFS_VCB Vcb; PDFS_FCB Fcb; BOOLEAN DontComplete = FALSE; BOOLEAN pktLocked; DfsDbgTrace(+1, Dbg, "DfsCommonClose: Entered\n", 0); DfsDbgTrace( 0, Dbg, "Irp = %08lx\n", Irp); DfsDbgTrace( 0, Dbg, "->FileObject = %08lx\n", FileObject); // // This action is a noop for unopened file objects. Nothing needs // to be done for FS device opens, either. // TypeOfOpen = DfsDecodeFileObject( FileObject, &Vcb, &Fcb); if (TypeOfOpen == UnopenedFileObject || TypeOfOpen == FilesystemDeviceOpen ) { DfsDbgTrace(-1, Dbg, "DfsCommonClose: Filesystem file object\n", 0); DfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); return STATUS_SUCCESS; } try { // // Case on the type of open that we are trying to close. // switch (TypeOfOpen) { case LogicalRootDeviceOpen: DfsDbgTrace(0, Dbg, "DfsCommonClose: Close LogicalRootDevice\n", 0); ExInterlockedDecrementLong(&Vcb->DirectAccessOpenCount, &DfsData.DfsLock); ExInterlockedDecrementLong(&Vcb->OpenFileCount, &DfsData.DfsLock); if (Vcb->VcbState & VCB_STATE_FLAG_LOCKED) { ASSERT (Vcb->FileObjectWithVcbLocked == FileObject); Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED; Vcb->FileObjectWithVcbLocked = NULL; } try_return( Status = STATUS_SUCCESS ); case RedirectedFileOpen: DfsDbgTrace(0, Dbg, "DfsCommonClose: File -> %wZ\n", &Fcb->FullFileName); // // Decrement the OpenFileCount for the Vcb through which this // file was opened. // ExInterlockedDecrementLong(&Vcb->OpenFileCount, &DfsData.DfsLock); // // Decrement the RefCount on the DFS_MACHINE_ENTRY through which // this file was opened // PktAcquireExclusive( TRUE, &pktLocked ); ExAcquireResourceExclusive( &DfsData.Resource, TRUE ); DfsDecrementMachEntryCount(Fcb->DfsMachineEntry, TRUE); ExReleaseResource( &DfsData.Resource ); PktRelease(); // // Close the redirected file by simply passing through // to the redirected device. We detach the DFS_FCB from the // file object before the close so it cannot be looked // up in some other thread. // DfsDetachFcb( FileObject, Fcb); Status = DfsFilePassThrough(Fcb, Irp); DontComplete = TRUE; DfsDeleteFcb( IrpContext, Fcb ); break; default: BugCheck("Dfs close, unexpected open type"); } Status = STATUS_SUCCESS; try_exit: NOTHING; } finally { // // If this is a normal termination, then complete the request. // Even if we're not to complete the IRP, we still need to // delete the IRP_CONTEXT. // if (!AbnormalTermination()) { if (DontComplete) { DfsCompleteRequest( IrpContext, NULL, 0 ); } else { DfsCompleteRequest( IrpContext, Irp, Status ); } } DfsDbgTrace(-1, Dbg, "DfsCommonClose: Exit -> %08lx\n", Status); } return Status; }
NTSTATUS FFSv1WriteInode( IN PFFS_IRP_CONTEXT IrpContext, IN PFFS_VCB Vcb, IN PFFSv1_INODE dinode1, IN ULONGLONG offset, IN PVOID Buffer, IN ULONG size, IN BOOLEAN bWriteToDisk, OUT PULONG dwRet) { PFFS_BDL ffs_bdl = NULL; ULONG blocks, i; NTSTATUS Status = STATUS_UNSUCCESSFUL; ULONG Totalblocks; LONGLONG AllocSize; if (dwRet) { *dwRet = 0; } Totalblocks = (dinode1->di_blocks); AllocSize = ((LONGLONG)(FFSDataBlocks(Vcb, Totalblocks)) << BLOCK_BITS); if ((LONGLONG)offset >= AllocSize) { FFSPrint((DBG_ERROR, "FFSv1WriteInode: beyond the file range.\n")); return STATUS_SUCCESS; } if ((LONGLONG)offset + size > AllocSize) { size = (ULONG)(AllocSize - offset); } blocks = FFSv1BuildBDL(IrpContext, Vcb, dinode1, offset, size, &ffs_bdl); if (blocks <= 0) { return STATUS_SUCCESS; } #if DBG { ULONG dwTotal = 0; FFSPrint((DBG_INFO, "FFSv1WriteInode: BDLCount = %xh Size=%xh Off=%xh\n", blocks, size, offset)); for(i = 0; i < blocks; i++) { FFSPrint((DBG_INFO, "FFSv1WriteInode: Lba=%I64xh Len=%xh Off=%xh\n", ffs_bdl[i].Lba, ffs_bdl[i].Length, ffs_bdl[i].Offset)); dwTotal += ffs_bdl[i].Length; } if (dwTotal != size) { FFSBreakPoint(); } FFSPrint((DBG_INFO, "FFSv1WriteInode: Total = %xh (WriteToDisk=%x)\n", dwTotal, bWriteToDisk)); } #endif if (bWriteToDisk) { #if 0 for(i = 0; i < blocks; i++) { { CcFlushCache(&(Vcb->SectionObject), (PLARGE_INTEGER)&(ffs_bdl[i].Lba), ffs_bdl[i].Length, NULL); if (Vcb->SectionObject.DataSectionObject != NULL) { ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcPurgeCacheSection(&(Vcb->SectionObject), (PLARGE_INTEGER)&(ffs_bdl[i].Lba), ffs_bdl[i].Length, FALSE); } } } #endif // assume offset is aligned. Status = FFSReadWriteBlocks(IrpContext, Vcb, ffs_bdl, size, blocks, FALSE); } else { for(i = 0; i < blocks; i++) { if(!FFSSaveBuffer(IrpContext, Vcb, ffs_bdl[i].Lba, ffs_bdl[i].Length, (PVOID)((PUCHAR)Buffer + ffs_bdl[i].Offset))) goto errorout; } if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { FFSPrint((DBG_USER, "FFSv1WriteInode is starting FlushingDpc...\n")); FFSStartFloppyFlushDpc(Vcb, NULL, NULL); } Status = STATUS_SUCCESS; } errorout: if (ffs_bdl) ExFreePool(ffs_bdl); if (NT_SUCCESS(Status)) { if (dwRet) *dwRet = size; } return Status; }
BOOLEAN NtfsFastUnlockSingle ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This is a call back routine for doing the fast unlock single call. Arguments: FileObject - Supplies the file object used in this operation FileOffset - Supplies the file offset used in this operation Length - Supplies the length used in this operation ProcessId - Supplies the process ID used in this operation Key - Supplies the key used in this operation Status - Receives the Status if this operation is successful Return Value: BOOLEAN - TRUE if this operation completed and FALSE if caller needs to take the long route. --*/ { BOOLEAN Results; PFCB Fcb; PSCB Scb; BOOLEAN ResourceAcquired = FALSE; UNREFERENCED_PARAMETER( DeviceObject ); PAGED_CODE(); DebugTrace( +1, Dbg, ("NtfsFastUnlockSingle\n") ); IoStatus->Information = 0; // // Decode the type of file object we're being asked to process and // make sure that is is only a user file open. // if ((Scb = NtfsFastDecodeUserFileOpen( FileObject )) == NULL) { IoStatus->Status = STATUS_INVALID_PARAMETER; DebugTrace( -1, Dbg, ("NtfsFastUnlockSingle -> TRUE (STATUS_INVALID_PARAMETER)\n") ); return TRUE; } Fcb = Scb->Fcb; // // Acquire exclusive access to the Fcb this operation can always wait // FsRtlEnterFileSystem(); if (Scb->ScbType.Data.FileLock == NULL) { (VOID) ExAcquireResourceExclusive( Fcb->Resource, TRUE ); ResourceAcquired = TRUE; } else { //(VOID) ExAcquireResourceShared( Fcb->Resource, TRUE ); } try { // // We check whether we can proceed based on the state of the file oplocks. // if ((Scb->ScbType.Data.Oplock != NULL) && !FsRtlOplockIsFastIoPossible( &Scb->ScbType.Data.Oplock )) { try_return( Results = FALSE ); } // // If we don't have a file lock, then get one now. // if (Scb->ScbType.Data.FileLock == NULL && !NtfsCreateFileLock( Scb, FALSE )) { try_return( Results = FALSE ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request. The call will always succeed. // Results = TRUE; IoStatus->Status = FsRtlFastUnlockSingle( Scb->ScbType.Data.FileLock, FileObject, FileOffset, Length, ProcessId, Key, NULL, FALSE ); // // Set the flag indicating if Fast I/O is possible. We are // only concerned if there are no longer any filelocks on this // file. // if (!FsRtlAreThereCurrentFileLocks( Scb->ScbType.Data.FileLock ) && (Scb->Header.IsFastIoPossible != FastIoIsPossible)) { NtfsAcquireFsrtlHeader( Scb ); Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb ); NtfsReleaseFsrtlHeader( Scb ); } try_exit: NOTHING; } finally { DebugUnwind( NtfsFastUnlockSingle ); // // Release the Fcb, and return to our caller // if (ResourceAcquired) { ExReleaseResource( Fcb->Resource ); } FsRtlExitFileSystem(); DebugTrace( -1, Dbg, ("NtfsFastUnlockSingle -> %08lx\n", Results) ); } return Results; }
BOOLEAN NtfsAcquireScbForLazyWrite ( IN PVOID OpaqueScb, IN BOOLEAN Wait ) /*++ Routine Description: The address of this routine is specified when creating a CacheMap for a file. It is subsequently called by the Lazy Writer prior to its performing lazy writes to the file. This callback is necessary to avoid deadlocks with the Lazy Writer. (Note that normal writes acquire the Fcb, and then call the Cache Manager, who must acquire some of his internal structures. If the Lazy Writer could not call this routine first, and were to issue a write after locking Caching data structures, then a deadlock could occur.) Arguments: OpaqueScb - The Scb which was specified as a context parameter for this routine. Wait - TRUE if the caller is willing to block. Return Value: FALSE - if Wait was specified as FALSE and blocking would have been required. The Fcb is not acquired. TRUE - if the Scb has been acquired --*/ { BOOLEAN AcquiredFile = TRUE; ULONG CompressedStream = (ULONG)OpaqueScb & 1; PSCB Scb = (PSCB)((ULONG)OpaqueScb & ~1); PFCB Fcb = Scb->Fcb; ASSERT_SCB(Scb); PAGED_CODE(); // // Acquire the Scb only for those files that the write will // acquire it for, i.e., not the first set of system files. // Otherwise we can deadlock, for example with someone needing // a new Mft record. // if (NtfsSegmentNumber( &Fcb->FileReference ) <= MASTER_FILE_TABLE2_NUMBER) { // // We need to synchronize the lazy writer with the clean volume // checkpoint. We do this by acquiring and immediately releasing this // Scb. This is to prevent the lazy writer from flushing the log file // when the space may be at a premium. // if (ExAcquireResourceShared( Scb->Header.Resource, Wait )) { ExReleaseResource( Scb->Header.Resource ); AcquiredFile = TRUE; } // // Now acquire either the main or paging io resource depending on the // state of the file. // } else if (Scb->Header.PagingIoResource != NULL) { AcquiredFile = ExAcquireResourceShared( Scb->Header.PagingIoResource, Wait ); } else { AcquiredFile = ExAcquireResourceShared( Scb->Header.Resource, Wait ); } if (AcquiredFile) { // // We assume the Lazy Writer only acquires this Scb once. When he // has acquired it, then he has eliminated anyone who would extend // valid data, since they must take out the resource exclusive. // Therefore, it should be guaranteed that this flag is currently // clear (the ASSERT), and then we will set this flag, to insure // that the Lazy Writer will never try to advance Valid Data, and // also not deadlock by trying to get the Fcb exclusive. // ASSERT( Scb->LazyWriteThread[CompressedStream] == NULL ); Scb->LazyWriteThread[CompressedStream] = PsGetCurrentThread(); // // Make Cc top level, so that we will not post or retry on errors. // (If it is not NULL, it must be one of our internal calls to this // routine, such as from Restart or Hot Fix.) // if (IoGetTopLevelIrp() == NULL) { IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); } } return AcquiredFile; }
BOOLEAN PiInitPhase1( VOID ) /*++ Routine Description: This function performs Phase 1 initializaion of the Plug and Play Manager component of the NT system. It performs the following tasks: (1) performs initialization of value entries under all subkeys of HKLM\System\Enum (e.g., resetting 'FoundAtEnum' to FALSE). (2) initializes bus enumerator structures for all built-in bus extenders provided by the HAL. (3) builds up a list of all installed bus extenders. Arguments: None. Return Value: TRUE - Initialization succeeded. FALSE - Initialization failed. --*/ { #if _PNP_POWER_ NTSTATUS Status; #endif PiScratchBuffer = ExAllocatePool(PagedPool, PNP_LARGE_SCRATCH_BUFFER_SIZE); if(!PiScratchBuffer) { return FALSE; } // // Since we'll be writing to PnP device sections in the registry, acquire // the PnP device registry resource for exclusive access. We'll also be // initializing the bus enumerator list, so we need exclusive access to // the PnP bus enumerator list as well. // KeEnterCriticalRegion(); #if _PNP_POWER_ ExAcquireResourceExclusive(&PpBusResource, TRUE); #endif // _PNP_POWER_ ExAcquireResourceExclusive(&PpRegistryDeviceResource, TRUE); // // Initialize all 'FoundAtEnum' value entries in the HKLM\System\Enum tree // to FALSE. // PiInitializeSystemEnum(); #if _PNP_POWER_ // // Initialize our bus enumerator list with all bus instances under the control // of the HAL's built-in bus extenders. // Status = PiRegisterBuiltInBuses(); if(!NT_SUCCESS(Status)) { #if DBG DbgPrint("PiInitPhase1: Couldn't register built-in buses\n"); #endif return FALSE; } // // Enumerate all services in the registry, building up a list of all // installed bus extenders. // Status = IopApplyFunctionToSubKeys(NULL, &CmRegistryMachineSystemCurrentControlSetServices, KEY_READ, TRUE, PiAddPlugPlayBusEnumeratorToList, NULL ); if(!NT_SUCCESS(Status)) { #if DBG DbgPrint("PiInitPhase1: Couldn't build bus enumerator list\n"); #endif return FALSE; } #endif // _PNP_POWER_ ExReleaseResource(&PpRegistryDeviceResource); #if _PNP_POWER_ ExReleaseResource(&PpBusResource); #endif // _PNP_POWER_ KeLeaveCriticalRegion(); ExFreePool(PiScratchBuffer); return TRUE; }
NTSTATUS NtSystemDebugControl ( IN SYSDBG_COMMAND Command, IN PVOID InputBuffer, IN ULONG InputBufferLength, OUT PVOID OutputBuffer, IN ULONG OutputBufferLength, OUT PULONG ReturnLength OPTIONAL ) /*++ Routine Description: This function controls the system debugger. Arguments: Command - The command to be executed. One of the following: SysDbgQueryTraceInformation SysDbgSetTracepoint SysDbgSetSpecialCall SysDbgClearSpecialCalls SysDbgQuerySpecialCalls InputBuffer - A pointer to a buffer describing the input data for the request, if any. The structure of this buffer varies depending upon Command. InputBufferLength - The length in bytes of InputBuffer. OutputBuffer - A pointer to a buffer that is to receive the output data for the request, if any. The structure of this buffer varies depending upon Command. OutputBufferLength - The length in bytes of OutputBuffer. ReturnLength - A optional pointer to a ULONG that is to receive the output data length for the request. Return Value: Returns one of the following status codes: STATUS_SUCCESS - normal, successful completion. STATUS_INVALID_INFO_CLASS - The Command parameter did not specify a valid value. STATUS_INFO_LENGTH_MISMATCH - The value of the Length field in the Parameters buffer was not correct. STATUS_ACCESS_VIOLATION - Either the Parameters buffer pointer or a pointer within the Parameters buffer specified an invalid address. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist for this request to complete. --*/ { NTSTATUS status = STATUS_SUCCESS; BOOLEAN releaseModuleResoure = FALSE; ULONG length = 0; KPROCESSOR_MODE PreviousMode; PreviousMode = KeGetPreviousMode(); if (!SeSinglePrivilegeCheck( SeDebugPrivilege, PreviousMode)) { return STATUS_ACCESS_DENIED; } // // Operate within a try block in order to catch errors. // try { // // Probe input and output buffers, if previous mode is not // kernel. // if ( PreviousMode != KernelMode ) { if ( InputBufferLength != 0 ) { ProbeForRead( InputBuffer, InputBufferLength, sizeof(ULONG) ); } if ( OutputBufferLength != 0 ) { ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(ULONG) ); } if ( ARGUMENT_PRESENT(ReturnLength) ) { ProbeForWriteUlong( ReturnLength ); } } // // Switch on the command code. // switch ( Command ) { #ifdef _X86_ case SysDbgQueryTraceInformation: status = KdGetTraceInformation( OutputBuffer, OutputBufferLength, &length ); break; case SysDbgSetTracepoint: if ( InputBufferLength != sizeof(DBGKD_MANIPULATE_STATE64) ) { return STATUS_INFO_LENGTH_MISMATCH; } KdSetInternalBreakpoint( InputBuffer ); break; case SysDbgSetSpecialCall: if ( InputBufferLength != sizeof(PVOID) ) { return STATUS_INFO_LENGTH_MISMATCH; } KdSetSpecialCall( InputBuffer, NULL ); break; case SysDbgClearSpecialCalls: KdClearSpecialCalls( ); break; case SysDbgQuerySpecialCalls: status = KdQuerySpecialCalls( OutputBuffer, OutputBufferLength, &length ); break; #endif case SysDbgBreakPoint: if (KdDebuggerEnabled) { DbgBreakPointWithStatus(DBG_STATUS_DEBUG_CONTROL); } else { status = STATUS_UNSUCCESSFUL; } break; default: // // Invalid Command. // status = STATUS_INVALID_INFO_CLASS; } if ( ARGUMENT_PRESENT(ReturnLength) ) { *ReturnLength = length; } } except ( EXCEPTION_EXECUTE_HANDLER ) { if ( releaseModuleResoure ) { ExReleaseResource( &PsLoadedModuleResource ); KeLeaveCriticalRegion(); } status = GetExceptionCode(); } return status; } // NtSystemDebugControl
NTSTATUS IopSetDeviceSecurityDescriptors( IN PDEVICE_OBJECT DeviceObject, IN PSECURITY_INFORMATION SecurityInformation, IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN POOL_TYPE PoolType, IN PGENERIC_MAPPING GenericMapping, IN BOOLEAN DoAttachedDevices ) /*++ Routine Description: Call this routine to set device security descriptor Arguments: DeviceObject - pointer to base device object (first one to set) SecurityInformation )_ passed directly from IopGetSetSecurityObject SecurityDescriptor ) PoolType ) GenericMapping ) DoAttachedDevices - if true, iterate the AttachedDevice list ReturnValue: success, or error from first failure --*/ { PDEVICE_OBJECT NewDeviceObject = NULL; PSECURITY_DESCRIPTOR OldSecurityDescriptor; KIRQL irql; NTSTATUS status; NTSTATUS firsterr = STATUS_SUCCESS; BOOLEAN first = TRUE; ASSERT(DeviceObject); IopAcquireEnumerationLock(NULL); // ensure we have acquired P&P locks // // pre-reference this object to match the dereference later // ObReferenceObject( DeviceObject ); do { KeEnterCriticalRegion(); ExAcquireResourceExclusive( &IopSecurityResource, TRUE ); OldSecurityDescriptor = DeviceObject->SecurityDescriptor; if (OldSecurityDescriptor || first) { // // always call this on the first object, only do it for others that have a security descriptor // status = SeSetSecurityDescriptorInfo( NULL, SecurityInformation, SecurityDescriptor, &DeviceObject->SecurityDescriptor, PoolType, GenericMapping ); if (NT_SUCCESS(firsterr)) { firsterr = status; } if (NT_SUCCESS( status )) { ASSERT(OldSecurityDescriptor); ExFreePool( OldSecurityDescriptor ); } first = FALSE; } ExReleaseResource( &IopSecurityResource ); KeLeaveCriticalRegion(); // // get next device on attachment chain // ExAcquireSpinLock(&IopDatabaseLock,&irql); NewDeviceObject = DeviceObject->AttachedDevice; if ( NewDeviceObject != NULL ) { ObReferenceObject( NewDeviceObject ); } else { DoAttachedDevices = FALSE; } ExReleaseSpinLock(&IopDatabaseLock,irql); ObDereferenceObject( DeviceObject ); DeviceObject = NewDeviceObject; } while(DoAttachedDevices); IopReleaseEnumerationLock(NULL); return firsterr; // of the PDO / single object }
NTSTATUS NtfsAcquireFileForModWrite ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER EndingOffset, OUT PERESOURCE *ResourceToRelease, IN PDEVICE_OBJECT DeviceObject ) { BOOLEAN AcquiredFile; PSCB Scb = (PSCB) (FileObject->FsContext); PFCB Fcb = Scb->Fcb; ASSERT_SCB(Scb); UNREFERENCED_PARAMETER( DeviceObject ); PAGED_CODE(); // // Acquire the Scb only for those files that the write will // acquire it for, i.e., not the first set of system files. // Otherwise we can deadlock, for example with someone needing // a new Mft record. // if (NtfsSegmentNumber( &Fcb->FileReference ) <= MASTER_FILE_TABLE2_NUMBER) { // // We need to synchronize the lazy writer with the clean volume // checkpoint. We do this by acquiring and immediately releasing this // Scb. This is to prevent the lazy writer from flushing the log file // when the space may be at a premium. // if (AcquiredFile = ExAcquireResourceShared( Scb->Header.Resource, FALSE )) { ExReleaseResource( Scb->Header.Resource ); } *ResourceToRelease = NULL; // // Now acquire either the main or paging io resource depending on the // state of the file. // } else { // // Figure out which resource to acquire. // if (Scb->Header.PagingIoResource != NULL) { *ResourceToRelease = Scb->Header.PagingIoResource; } else { *ResourceToRelease = Scb->Header.Resource; } // // Try to acquire the resource with Wait FALSE // AcquiredFile = ExAcquireResourceShared( *ResourceToRelease, FALSE ); // // If we got the resource, check if he is possibly trying to extend // ValidDataLength. If so that will cause us to go into useless mode // possibly doing actual I/O writing zeros out to the file past actual // valid data in the cache. This is so inefficient that it is better // to tell MM not to do this write. // if (AcquiredFile) { if (Scb->CompressionUnit != 0) { ExAcquireFastMutex( Scb->Header.FastMutex ); if ((EndingOffset->QuadPart > Scb->ValidDataToDisk) && (EndingOffset->QuadPart < (Scb->Header.FileSize.QuadPart + PAGE_SIZE - 1)) && !FlagOn(Scb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE)) { ExReleaseResource(*ResourceToRelease); AcquiredFile = FALSE; *ResourceToRelease = NULL; } ExReleaseFastMutex( Scb->Header.FastMutex ); } } else { *ResourceToRelease = NULL; } } return (AcquiredFile ? STATUS_SUCCESS : STATUS_CANT_WAIT); }
NTSTATUS FFSWriteFile( IN PFFS_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_VCB Vcb = NULL; PFFS_FCB Fcb = NULL; PFFS_CCB Ccb = NULL; PFILE_OBJECT FileObject = NULL; PFILE_OBJECT CacheObject; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; ULONG Length; ULONG ReturnedLength = 0; LARGE_INTEGER ByteOffset; BOOLEAN PagingIo; BOOLEAN Nocache; BOOLEAN SynchronousIo; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; BOOLEAN bNeedExtending = FALSE; BOOLEAN bAppendFile = FALSE; BOOLEAN bDeferred = FALSE; PUCHAR Buffer = NULL; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); FileObject = IrpContext->FileObject; Fcb = (PFFS_FCB)FileObject->FsContext; ASSERT(Fcb); ASSERT((Fcb->Identifier.Type == FFSFCB) && (Fcb->Identifier.Size == sizeof(FFS_FCB))); Ccb = (PFFS_CCB)FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Write.Length; ByteOffset = IoStackLocation->Parameters.Write.ByteOffset; PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE); Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE); SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE); FFSPrint((DBG_INFO, "FFSWriteFile: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n", ByteOffset.QuadPart, Length, PagingIo, Nocache)); /* if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED)) { Status = STATUS_FILE_DELETED; __leave; } if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { Status = STATUS_DELETE_PENDING; __leave; } */ if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) || Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; __leave; } #if FALSE if (!Nocache) { BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); BOOLEAN bWait = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED); if (!CcCanIWrite( FileObject, Length, (bWait && bQueue), bAgain)) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)FFSDeferWrite, IrpContext, Irp, Length, bAgain); bDeferred = TRUE; FFSBreakPoint(); Status = STATUS_PENDING; __leave; } } #endif if (IsEndOfFile(ByteOffset)) { bAppendFile = TRUE; ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart; } if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY) && !PagingIo) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } // // Do flushing for such cases // if (Nocache && !PagingIo && (Fcb->SectionObject.DataSectionObject != NULL)) { ExAcquireResourceExclusive(&Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)); MainResourceAcquired = TRUE; ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResource(&Fcb->PagingIoResource); CcFlushCache(&(Fcb->SectionObject), &ByteOffset, Length, &(Irp->IoStatus)); ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED); if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; __leave; } ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResource(&Fcb->PagingIoResource); CcPurgeCacheSection(&(Fcb->SectionObject), (PLARGE_INTEGER)&(ByteOffset), Length, FALSE); ExReleaseResource(&Fcb->MainResource); MainResourceAcquired = FALSE; } if (!PagingIo) { if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } else { /* ULONG ResShCnt, ResExCnt; ResShCnt = ExIsResourceAcquiredSharedLite(&Fcb->PagingIoResource); ResExCnt = ExIsResourceAcquiredExclusiveLite(&Fcb->PagingIoResource); FFSPrint((DBG_USER, "FFSWriteFile: Inode=%xh %S PagingIo: %xh:%xh Synchronous=%xh\n", Fcb->FFSMcb->Inode, Fcb->FFSMcb->ShortName.Buffer, ResShCnt, ResExCnt, IrpContext->IsSynchronous)); */ if (!ExAcquireResourceSharedLite( &Fcb->PagingIoResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; } if (!PagingIo) { if (!FsRtlCheckLockForWriteAccess( &Fcb->FileLockAnchor, Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; __leave; } } if (Nocache) { if ((ByteOffset.QuadPart + Length) > Fcb->Header.AllocationSize.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) { Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; __leave; } else { if (Length > (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart)) { Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart); } } } } if (!Nocache) { if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) { __leave; } if (FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( FileObject, (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize), FALSE, &FFSGlobal->CacheManagerCallbacks, Fcb); CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY); CcSetFileSizes( FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } CacheObject = FileObject; // // Need extending the size of inode ? // if ((bAppendFile) || ((ULONG)(ByteOffset.QuadPart + Length) > (ULONG)(Fcb->Header.FileSize.QuadPart))) { LARGE_INTEGER ExtendSize; LARGE_INTEGER FileSize; bNeedExtending = TRUE; FileSize = Fcb->Header.FileSize; ExtendSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length); if (ExtendSize.QuadPart > Fcb->Header.AllocationSize.QuadPart) { if (!FFSExpandFile(IrpContext, Vcb, Fcb, &ExtendSize)) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } } { Fcb->Header.FileSize.QuadPart = ExtendSize.QuadPart; Fcb->dinode1->di_size = (ULONG)ExtendSize.QuadPart; } if (FileObject->PrivateCacheMap) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); if (ByteOffset.QuadPart > FileSize.QuadPart) { FFSZeroHoles(IrpContext, Vcb, FileObject, FileSize.QuadPart, ByteOffset.QuadPart - FileSize.QuadPart); } if (Fcb->Header.AllocationSize.QuadPart > ExtendSize.QuadPart) { FFSZeroHoles(IrpContext, Vcb, FileObject, ExtendSize.QuadPart, Fcb->Header.AllocationSize.QuadPart - ExtendSize.QuadPart); } } if (FFSv1SaveInode(IrpContext, Vcb, Fcb->FFSMcb->Inode, Fcb->dinode1)) { Status = STATUS_SUCCESS; } FFSNotifyReportChange( IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcPrepareMdlWrite( CacheObject, (&ByteOffset), Length, &Irp->MdlAddress, &Irp->IoStatus); Status = Irp->IoStatus.Status; } else { Buffer = FFSGetUserBuffer(Irp); if (Buffer == NULL) { FFSBreakPoint(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (!CcCopyWrite( CacheObject, (PLARGE_INTEGER)&ByteOffset, Length, IrpContext->IsSynchronous, Buffer)) { Status = STATUS_PENDING; __leave; } Status = Irp->IoStatus.Status; } if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { FFSPrint((DBG_USER, "FFSWriteFile is starting FlushingDpc...\n")); FFSStartFloppyFlushDpc(Vcb, Fcb, FileObject); } } } else { ReturnedLength = Length; Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { __leave; } Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = Length; Status = FFSv1WriteInode( IrpContext, Vcb, Fcb->dinode1, (ULONGLONG)(ByteOffset.QuadPart), NULL, Length, TRUE, &ReturnedLength); Irp = IrpContext->Irp; } } __finally { if (PagingIoResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->PagingIoResource, ExGetCurrentResourceThread()); } if (MainResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING) { if (!bDeferred) { Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { Status = FFSQueueRequest(IrpContext); } else { FFSCompleteIrpContext(IrpContext, Status); } } } else { if (NT_SUCCESS(Status)) { if (SynchronousIo && !PagingIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } if (!PagingIo) { SetFlag(FileObject->Flags, FO_FILE_MODIFIED); SetFlag(Fcb->Flags, FCB_FILE_MODIFIED); } } FFSCompleteIrpContext(IrpContext, Status); } } else { FFSFreeIrpContext(IrpContext); } } } return Status; }
NTSTATUS IopGetSetSecurityObject( IN PVOID Object, IN SECURITY_OPERATION_CODE OperationCode, IN PSECURITY_INFORMATION SecurityInformation, IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, IN OUT PULONG CapturedLength, IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor, IN POOL_TYPE PoolType, IN PGENERIC_MAPPING GenericMapping ) /*++ Routine Description: This routine is invoked to either query or set the security descriptor for a file, directory, volume, or device. It implements these functions by either performing an in-line check if the file is a device or a volume, or an I/O Request Packet (IRP) is generated and given to the driver to perform the operation. Arguments: Object - Pointer to the file or device object representing the open object. SecurityInformation - Information about what is being done to or obtained from the object's security descriptor. SecurityDescriptor - Supplies the base security descriptor and returns the final security descriptor. Note that if this buffer is coming from user space, it has already been probed by the object manager to length "CapturedLength", otherwise it points to kernel space and should not be probed. It must, however, be referenced in a try clause. CapturedLength - For a query operation this specifies the size, in bytes, of the output security descriptor buffer and on return contains the number of bytes needed to store the complete security descriptor. If the length needed is greater than the length supplied the operation will fail. This parameter is ignored for the set and delete operations. It is expected to point into system space, ie, it need not be probed and it will not change. ObjectsSecurityDescriptor - Supplies and returns the object's security descriptor. PoolType - Specifies from which type of pool memory is to be allocated. GenericMapping - Supplies the generic mapping for the object type. Return Value: The final status of the operation is returned as the function value. --*/ { NTSTATUS status; PFILE_OBJECT fileObject; PDEVICE_OBJECT deviceObject; PDEVICE_OBJECT devicePDO = NULL; BOOLEAN synchronousIo; UNREFERENCED_PARAMETER( ObjectsSecurityDescriptor ); UNREFERENCED_PARAMETER( PoolType ); PAGED_CODE(); // // Begin by determining whether the security operation is to be performed // in this routine or by the driver. This is based upon whether the // object represents a device object, or it represents a file object // to a device, or a file on the device. If the open is a direct device // open then use the device object. // if (((PDEVICE_OBJECT) (Object))->Type == IO_TYPE_DEVICE) { deviceObject = (PDEVICE_OBJECT) Object; fileObject = (PFILE_OBJECT) NULL; } else { fileObject = (PFILE_OBJECT) Object; if (fileObject->Flags & FO_DIRECT_DEVICE_OPEN) { deviceObject = IoGetAttachedDevice( fileObject->DeviceObject ); } else { deviceObject = fileObject->DeviceObject; } } if (!fileObject || (!fileObject->FileName.Length && !fileObject->RelatedFileObject) || (fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) { // // This security operation is for the device itself, either through // a file object, or directly to the device object. For the latter // case, assignment operations are also possible. Also note that // this may be a stream file object, which do not have security. // The security for a stream file is actually represented by the // security descriptor on the file itself, or the volume, or the // device. // if (OperationCode == AssignSecurityDescriptor) { // // Simply assign the security descriptor to the device object, // if this is a device object. // if (fileObject == NULL || !(fileObject->Flags & FO_STREAM_FILE)) { KeEnterCriticalRegion(); ExAcquireResourceExclusive( &IopSecurityResource, TRUE ); deviceObject->SecurityDescriptor = SecurityDescriptor; ExReleaseResource( &IopSecurityResource ); KeLeaveCriticalRegion(); } status = STATUS_SUCCESS; } else if (OperationCode == SetSecurityDescriptor) { // // This is a set operation. The SecurityInformation parameter // determines what part of the SecurityDescriptor is going to // be applied to the ObjectsSecurityDescriptor. // // // if this deviceObject is attached to a PDO then we want // to modify the security on the PDO and apply it up the // device chain // if (fileObject == NULL || !(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) { // // see if there is a PDO for this object, and obtain it // devicePDO = IopGetDevicePDO(deviceObject); } else { devicePDO = NULL; } if (devicePDO) { // // set PDO and all attached device objects // status = IopSetDeviceSecurityDescriptors(devicePDO,SecurityInformation,SecurityDescriptor,PoolType,GenericMapping,TRUE); ObDereferenceObject( devicePDO ); } else { // // set this device object only // status = IopSetDeviceSecurityDescriptors(deviceObject,SecurityInformation,SecurityDescriptor,PoolType,GenericMapping,FALSE); } } else if (OperationCode == QuerySecurityDescriptor) { // // This is a get operation. The SecurityInformation parameter // determines what part of the SecurityDescriptor is going to // be returned from the ObjectsSecurityDescriptor. // KeEnterCriticalRegion(); ExAcquireResourceShared( &IopSecurityResource, TRUE ); status = SeQuerySecurityDescriptorInfo( SecurityInformation, SecurityDescriptor, CapturedLength, &deviceObject->SecurityDescriptor ); ExReleaseResource( &IopSecurityResource ); KeLeaveCriticalRegion(); } else { // // This is a delete operation. Simply indicate that everything // worked just fine. // status = STATUS_SUCCESS; } } else if (OperationCode == DeleteSecurityDescriptor) { // // This is a delete operation for the security descriptor on a file // object. This function will be performed by the file system once // the FCB itself is deleted. Simply indicate that the operation // was successful. // status = STATUS_SUCCESS; } else { PIRP irp; IO_STATUS_BLOCK localIoStatus; KEVENT event; PIO_STACK_LOCATION irpSp; KPROCESSOR_MODE requestorMode; // // This file object does not refer to the device itself. Rather, it // refers to either a file or a directory on the device. This means // that the request must be passed to the file system for processing. // Note that the only requests that are passed through in this manner // are SET or QUERY security operations. DELETE operations have // already been taken care of above since the file system which just // drop the storage on the floor when it really needs to, and ASSIGN // operations are irrelevant to file systems since they never // generate one because they never assign the security descriptor // to the object in the first place, they just assign it to the FCB. // requestorMode = KeGetPreviousMode(); // // Begin by referencing the object by pointer. Note that the object // handle has already been checked for the appropriate access by the // object system caller. This reference must be performed because // standard I/O completion will dereference the object. // ObReferenceObject( fileObject ); // // Make a special check here to determine whether this is a synchronous // I/O operation. If it is, then wait here until the file is owned by // the current thread. If this is not a (serialized) synchronous I/O // operation, then initialize the local event. // if (fileObject->Flags & FO_SYNCHRONOUS_IO) { BOOLEAN interrupted; if (!IopAcquireFastLock( fileObject )) { status = IopAcquireFileObjectLock( fileObject, requestorMode, (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), &interrupted ); if (interrupted) { ObDereferenceObject( fileObject ); return status; } } synchronousIo = TRUE; } else { KeInitializeEvent( &event, SynchronizationEvent, FALSE ); synchronousIo = FALSE; } // // Set the file object to the Not-Signaled state. // KeClearEvent( &fileObject->Event ); // // Get the address of the target device object. // deviceObject = IoGetRelatedDeviceObject( fileObject ); // // Allocate and initialize the I/O Request Packet (IRP) for this // operation. The allocation is performed with an exception handler // in case the caller does not have enough quota to allocate the packet. irp = IoAllocateIrp( deviceObject->StackSize, TRUE ); if (!irp) { // // An IRP could not be allocated. Cleanup and return an // appropriate error status code. // IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL ); return STATUS_INSUFFICIENT_RESOURCES; } irp->Tail.Overlay.OriginalFileObject = fileObject; irp->Tail.Overlay.Thread = PsGetCurrentThread(); irp->RequestorMode = requestorMode; // // Fill in the service independent parameters in the IRP. // if (fileObject->Flags & FO_SYNCHRONOUS_IO) { irp->UserEvent = (PKEVENT) NULL; } else { irp->UserEvent = &event; irp->Flags = IRP_SYNCHRONOUS_API; } irp->UserIosb = &localIoStatus; irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL; // // Get a pointer to the stack location for the first driver. This will // be used to pass the original function codes and parameters. // irpSp = IoGetNextIrpStackLocation( irp ); // // Now determine whether this is a set or a query operation. // if (OperationCode == QuerySecurityDescriptor) { // // This is a query operation. Fill in the appropriate fields in // the stack location for the packet, as well as the fixed part // of the packet. Note that each of these parameters has been // captured as well, so there is no need to perform any probing. // The only exception is the UserBuffer memory may change, but // that is the file system's responsibility to check. Note that // it has already been probed, so the pointer is at least not // in an address space that the caller should not be accessing // because of mode. // irpSp->MajorFunction = IRP_MJ_QUERY_SECURITY; irpSp->Parameters.QuerySecurity.SecurityInformation = *SecurityInformation; irpSp->Parameters.QuerySecurity.Length = *CapturedLength; irp->UserBuffer = SecurityDescriptor; } else { // // This is a set operation. Fill in the appropriate fields in // the stack location for the packet. Note that access to the // SecurityInformation parameter is safe, as the parameter was // captured by the caller. Likewise, the SecurityDescriptor // refers to a captured copy of the descriptor. // irpSp->MajorFunction = IRP_MJ_SET_SECURITY; irpSp->Parameters.SetSecurity.SecurityInformation = *SecurityInformation; irpSp->Parameters.SetSecurity.SecurityDescriptor = SecurityDescriptor; } irpSp->FileObject = fileObject; // // Insert the packet at the head of the IRP list for the thread. // IopQueueThreadIrp( irp ); // // Update the operation count statistic for the current process for // operations other than read and write. // IopUpdateOtherOperationCount(); // // Everything has been properly set up, so simply invoke the driver. // status = IoCallDriver( deviceObject, irp ); // // If this operation was a synchronous I/O operation, check the return // status to determine whether or not to wait on the file object. If // the file object is to be waited on, wait for the operation to be // completed and obtain the final status from the file object itself. // if (synchronousIo) { if (status == STATUS_PENDING) { (VOID) KeWaitForSingleObject( &fileObject->Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER) NULL ); status = fileObject->FinalStatus; } IopReleaseFileObjectLock( fileObject ); } else { // // This is a normal synchronous I/O operation, as opposed to a // serialized synchronous I/O operation. For this case, wait // for the local event and return the final status information // back to the caller. // if (status == STATUS_PENDING) { (VOID) KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, (PLARGE_INTEGER) NULL ); status = localIoStatus.Status; } } // // If this operation was just attempted on a file system or a device // driver of some kind that does not implement security, then return // a normal null security descriptor. // if (status == STATUS_INVALID_DEVICE_REQUEST) { // // The file system does not implement a security policy. Determine // what type of operation this was and implement the correct // semantics for the file system. // if (OperationCode == QuerySecurityDescriptor) { // // The operation is a query. If the caller's buffer is too // small, then indicate that this is the case and let him know // what size buffer is required. Otherwise, attempt to return // a null security descriptor. // try { status = SeAssignWorldSecurityDescriptor( SecurityDescriptor, CapturedLength, SecurityInformation ); } except( EXCEPTION_EXECUTE_HANDLER ) { // // An exception was incurred while attempting to // access the caller's buffer. Clean everything // up and return an appropriate status code. // status = GetExceptionCode(); } } else { // // This was an operation other than a query. Simply indicate // that the operation was successful. // status = STATUS_SUCCESS; } } else if (OperationCode == QuerySecurityDescriptor) {