VOID NpAcquireExclusiveCcb ( IN PNONPAGED_CCB NonpagedCcb ) /*++ Routine Description: This routine acquires exclusive access to the Ccb by first getting shared access to the Fcb. Arguments: NonpagedCcb - Supplies the Ccb to acquire Return Value: None. --*/ { PAGED_CODE(); DebugTrace(+1, Dbg, "NpAcquireExclusiveCcb, NonpagedCcb = %08lx\n", NonpagedCcb); (VOID)ExAcquireResourceShared( &(NpVcb->Resource), TRUE ); (VOID)ExAcquireResourceExclusive( &(NonpagedCcb->Resource), TRUE ); DebugTrace(-1, Dbg, "NpAcquireExclusiveCcb -> (VOID)\n", 0); return; }
VOID NpAcquireExclusiveVcb ( ) /*++ Routine Description: This routine acquires exclusive access to the Vcb Arguments: Return Value: None. --*/ { PAGED_CODE(); DebugTrace(+1, Dbg, "NpAcquireExclusiveVcb\n", 0); ExAcquireResourceExclusive( &(NpVcb->Resource), TRUE ); DebugTrace(-1, Dbg, "NpAcquireExclusiveVcb -> (VOID)\n", 0); return; }
VOID NtfsAcquireExclusiveGlobal ( IN PIRP_CONTEXT IrpContext ) /*++ Routine Description: This routine acquires exclusive access to the global resource. This routine will raise if it cannot acquire the resource and wait in the IrpContext is false. Arguments: Return Value: None. --*/ { ASSERT_IRP_CONTEXT(IrpContext); PAGED_CODE(); if (!ExAcquireResourceExclusive( &NtfsData.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL ); } return; }
BOOLEAN NtfsAcquireVolumeForClose ( IN PVOID OpaqueVcb, 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 closes to the file. This callback is necessary to avoid deadlocks with the Lazy Writer. (Note that normal closes acquire the Vcb, 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: Vcb - The Vcb which was specified as a close 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 Vcb has been acquired --*/ { PVCB Vcb = (PVCB)OpaqueVcb; ASSERT_VCB(Vcb); PAGED_CODE(); // // Do the code of acquire exclusive Vcb but without the IrpContext // if (ExAcquireResourceExclusive( &Vcb->Resource, Wait )) { return TRUE; } return FALSE; }
BOOLEAN NtfsAcquireExclusiveVcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN BOOLEAN RaiseOnCantWait ) /*++ Routine Description: This routine acquires exclusive access to the Vcb. This routine will raise if it cannot acquire the resource and wait in the IrpContext is false. Arguments: Vcb - Supplies the Vcb to acquire RaiseOnCantWait - Indicates if we should raise on an acquisition error or simply return a BOOLEAN indicating that we couldn't get the resource. Return Value: BOOLEAN - Indicates if we were able to acquire the resource. This is really only meaningful if the RaiseOnCantWait value is FALSE. --*/ { ASSERT_IRP_CONTEXT(IrpContext); ASSERT_VCB(Vcb); PAGED_CODE(); if (ExAcquireResourceExclusive( &Vcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { return TRUE; } if (RaiseOnCantWait) { NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL ); } return FALSE; }
VOID NtfsAcquireForCreateSection ( IN PFILE_OBJECT FileObject ) { PSCB Scb = (PSCB)FileObject->FsContext; PAGED_CODE(); if (Scb->Header.PagingIoResource != NULL) { ExAcquireResourceExclusive( Scb->Header.PagingIoResource, TRUE ); } }
FINISHED FatAcquireExclusiveVcb ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ) /*++ Routine Description: This routine acquires exclusive access to the Vcb. After we acquire the resource check to see if this operation is legal. If it isn't (ie. we get an exception), release the resource. Arguments: Vcb - Supplies the Vcb to acquire Return Value: FINISHED - TRUE if we have the resource and FALSE if we needed to block for the resource but Wait is FALSE. --*/ { if (ExAcquireResourceExclusive( &Vcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { try { FatVerifyOperationIsLegal( IrpContext ); } finally { if ( AbnormalTermination() ) { FatReleaseVcb( IrpContext, Vcb ); } } return TRUE; } else { return FALSE;
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; }
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 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; }
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) {
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 }
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 ); }
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); }
//+---------------------------------------------------------------------- // // Function: DfsAgePktEntries, public // // Synopsis: This function gets called in the FSP to step through the PKT // entries and delete those entries which are old. // // Arguments: [TimerContext] -- This context block contains a busy flag // and a count of the number of ticks that // have elapsed. // // Returns: Nothing. // // Notes: In case the PKT cannot be acquired exclusive, the // routine just returns without doing anything. We // will have missed an aging interval, but aging is // a non-critical activity. // // History: 04/23/93 SudK Created. // //----------------------------------------------------------------------- VOID DfsAgePktEntries(PDFS_TIMER_CONTEXT DfsTimerContext) { PDFS_PKT pkt = _GetPkt(); PDFS_PKT_ENTRY entry, nextEntry; PLIST_ENTRY link; PDFS_CREDENTIALS creds; BOOLEAN pktLocked = FALSE; DfsDbgTrace(+1, Dbg, "DfsAgePktEntries called\n", 0); // // First we need to acquire a lock on the PKT and step through the PKT // // // If we can't get to the resource then let us return right away. // This is really not that critical. We can always try again. // PktAcquireExclusive(FALSE, &pktLocked); if (pktLocked == FALSE) { DfsTimerContext->TickCount = 0; DfsTimerContext->InUse = FALSE; DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit (no scan)\n", 0); return; } if (ExAcquireResourceExclusive(&DfsData.Resource, FALSE) == FALSE) { PktRelease(); DfsTimerContext->TickCount = 0; DfsTimerContext->InUse = FALSE; DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit (no scan 2)\n", 0); return; } entry = PktFirstEntry(pkt); while (entry != NULL) { DfsDbgTrace(0, Dbg, "DfsAgePktEntries: Scanning %wZ\n", &entry->Id.Prefix); // // We may lose this entry due to deletion. Let us get the Next // entry before we go into the next stage. // nextEntry = PktNextEntry(pkt, entry); // // For each entry if it is not permanent and its expire time is // less than DFS_MAX_TICKS then we can delete it else we just // update its expire time and go on to the next entry. // if ( !(entry->Type & PKT_ENTRY_TYPE_PERMANENT) && (entry->UseCount == 0) && IsListEmpty(&entry->ChildList)) { if (entry->ExpireTime < DfsTimerContext->TickCount) { DfsDbgTrace(0, Dbg, "DfsAgePktEntries: Deleted: %wZ\n", &entry->Id.Prefix); PktEntryDestroy(entry, pkt, (BOOLEAN) TRUE); } else { entry->ExpireTime -= DfsTimerContext->TickCount; } } entry = nextEntry; } // // Check the deleted credentials queue... // for (link = DfsData.DeletedCredentials.Flink; link != &DfsData.DeletedCredentials; NOTHING) { creds = CONTAINING_RECORD(link, DFS_CREDENTIALS, Link); link = link->Flink; if (creds->RefCount == 0) { RemoveEntryList( &creds->Link ); ExFreePool( creds ); } } ExReleaseResource( &DfsData.Resource ); PktRelease(); // // Finally we need to reset the count so that the Timer Routine can // work fine. We also release the context block by resetting the InUse // boolean. This will make sure that the next count towards the PKT // aging will start again. // DfsTimerContext->TickCount = 0; DfsTimerContext->InUse = FALSE; DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit\n", 0); }
VOID NtfsAcquireAllFiles ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN BOOLEAN Exclusive, IN BOOLEAN AcquirePagingIo ) /*++ Routine Description: This routine non-recursively requires all files on a volume. Arguments: Vcb - Supplies the volume Exclusive - Indicates if we should be acquiring all the files exclusively. If FALSE then we acquire all the files shared except for files with streams which could be part of transactions. AcquirePagingIo - Indicates if we need to acquire the paging io resource exclusively. Only needed if a future call will flush the volume (i.e. shutdown) Return Value: None --*/ { PFCB Fcb; PSCB *Scb; PSCB NextScb; PVOID RestartKey; PAGED_CODE(); SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE ); RestartKey = NULL; while (TRUE) { NtfsAcquireFcbTable( IrpContext, Vcb ); Fcb = NtfsGetNextFcbTableEntry(Vcb, &RestartKey); NtfsReleaseFcbTable( IrpContext, Vcb ); if (Fcb == NULL) { break; } ASSERT_FCB( Fcb ); // // We can skip over the Fcb's for any of the Scb's in the Vcb. // We delay acquiring those to avoid deadlocks. // if (NtfsSegmentNumber( &Fcb->FileReference ) >= FIRST_USER_FILE_NUMBER) { // // If there is a paging Io resource then acquire this if required. // if (AcquirePagingIo && (Fcb->PagingIoResource != NULL)) { ExAcquireResourceExclusive( Fcb->PagingIoResource, TRUE ); } // // Acquire this Fcb whether or not the underlying file has been deleted. // if (Exclusive || IsDirectory( &Fcb->Info )) { NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, TRUE, FALSE ); } else { // // Assume that we only need this file shared. We will then // look for Lsn related streams. // NtfsAcquireSharedFcb( IrpContext, Fcb, NULL, TRUE ); // // Walk through all of the Scb's for the file and look for // an Lsn protected stream. // NtfsLockFcb( IrpContext, Fcb ); NextScb = NULL; while (NextScb = NtfsGetNextChildScb( Fcb, NextScb )) { if (!(NextScb->AttributeTypeCode == $DATA || NextScb->AttributeTypeCode == $EA)) { break; } } NtfsUnlockFcb( IrpContext, Fcb ); // // If we found a protected Scb then release and reacquire the Fcb // exclusively. // if (NextScb != NULL) { NtfsReleaseFcb( IrpContext, Fcb ); NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, TRUE, FALSE ); } } } } // // Now acquire the Fcb's in the Vcb. // Scb = &Vcb->QuotaTableScb; while (TRUE) { if ((*Scb != NULL) && (*Scb != Vcb->BitmapScb)) { if (AcquirePagingIo && ((*Scb)->Fcb->PagingIoResource != NULL)) { ExAcquireResourceExclusive( (*Scb)->Fcb->PagingIoResource, TRUE ); } NtfsAcquireExclusiveFcb( IrpContext, (*Scb)->Fcb, NULL, TRUE, FALSE ); } if (Scb == &Vcb->MftScb) { break; } Scb -= 1; } // // Treat the bitmap as an end resource and acquire it last. // if (Vcb->BitmapScb != NULL) { if (AcquirePagingIo && (Vcb->BitmapScb->Fcb->PagingIoResource != NULL)) { ExAcquireResourceExclusive( Vcb->BitmapScb->Fcb->PagingIoResource, TRUE ); } NtfsAcquireExclusiveFcb( IrpContext, Vcb->BitmapScb->Fcb, NULL, TRUE, FALSE ); } return; }
VOID NtfsAcquireSharedScbForTransaction ( IN PIRP_CONTEXT IrpContext, IN PSCB Scb ) /*++ Routine Description: This routine is called to acquire an Scb shared in order to perform updates to the an Scb stream. This is used if the transaction writes to a range of the stream without changing the size or position of the data. The caller must already provide synchronization to the data itself. There is no corresponding Scb release. It will be released when the transaction commits. We will acquire the Scb exclusive if it is not yet in the open attribute table. Arguments: Scb - Scb to acquire Return Value: None. --*/ { PSCB *Position; PSCB *ScbArray; ULONG Count; PAGED_CODE(); // // Make sure we have a free spot in the Scb array in the IrpContext. // if (IrpContext->SharedScb == NULL) { Position = (PSCB *) &IrpContext->SharedScb; IrpContext->SharedScbSize = 1; // // Too bad the first one is not available. If the current size is one then allocate a // new block and copy the existing value to it. // } else if (IrpContext->SharedScbSize == 1) { ScbArray = NtfsAllocatePool( PagedPool, sizeof( PSCB ) * 4 ); RtlZeroMemory( ScbArray, sizeof( PSCB ) * 4 ); *ScbArray = IrpContext->SharedScb; IrpContext->SharedScb = ScbArray; IrpContext->SharedScbSize = 4; Position = ScbArray + 1; // // Otherwise look through the existing array and look for a free spot. Allocate a larger // array if we need to grow it. // } else { Position = IrpContext->SharedScb; Count = IrpContext->SharedScbSize; do { if (*Position == NULL) { break; } Count -= 1; Position += 1; } while (Count != 0); // // If we didn't find one then allocate a new structure. // if (Count == 0) { ScbArray = NtfsAllocatePool( PagedPool, sizeof( PSCB ) * IrpContext->SharedScbSize * 2 ); RtlZeroMemory( ScbArray, sizeof( PSCB ) * IrpContext->SharedScbSize * 2 ); RtlCopyMemory( ScbArray, IrpContext->SharedScb, sizeof( PSCB ) * IrpContext->SharedScbSize ); NtfsFreePool( IrpContext->SharedScb ); IrpContext->SharedScb = ScbArray; Position = ScbArray + IrpContext->SharedScbSize; IrpContext->SharedScbSize *= 2; } } ExAcquireResourceShared( Scb->Header.Resource, TRUE ); if (Scb->NonpagedScb->OpenAttributeTableIndex == 0) { ExReleaseResource( Scb->Header.Resource ); ExAcquireResourceExclusive( Scb->Header.Resource, TRUE ); } *Position = Scb; return; }
NTSTATUS FatCommonRead ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common read routine for NtReadFile, called from both the Fsd, or from the Fsp if a request could not be completed without blocking in the Fsd. This routine has no code where it determines whether it is running in the Fsd or Fsp. Instead, its actions are conditionalized by the Wait input parameter, which determines whether it is allowed to block or not. If a blocking condition is encountered with Wait == FALSE, however, the request is posted to the Fsp, who always calls with WAIT == TRUE. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { PVCB Vcb; PFCB FcbOrDcb; PCCB Ccb; VBO StartingVbo; ULONG ByteCount; ULONG RequestedByteCount; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfRead; BOOLEAN PostIrp = FALSE; BOOLEAN OplockPostIrp = FALSE; BOOLEAN FcbOrDcbAcquired = FALSE; BOOLEAN Wait; BOOLEAN PagingIo; BOOLEAN NonCachedIo; BOOLEAN SynchronousIo; NTSTATUS Status; FAT_IO_CONTEXT StackFatIoContext; // // A system buffer is only used if we have to access the // buffer directly from the Fsp to clear a portion or to // do a synchronous I/O, or a cached transfer. It is // possible that our caller may have already mapped a // system buffer, in which case we must remember this so // we do not unmap it on the way out. // PVOID SystemBuffer = NULL; LARGE_INTEGER StartingByte; // // Get current Irp stack location. // IrpSp = IoGetCurrentIrpStackLocation( Irp ); FileObject = IrpSp->FileObject; // // Initialize the appropriate local variables. // Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); NonCachedIo = BooleanFlagOn(Irp->Flags,IRP_NOCACHE); SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); DebugTrace(+1, Dbg, "CommonRead\n", 0); DebugTrace( 0, Dbg, " Irp = %8lx\n", Irp); DebugTrace( 0, Dbg, " ->ByteCount = %8lx\n", IrpSp->Parameters.Read.Length); DebugTrace( 0, Dbg, " ->ByteOffset.LowPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.LowPart); DebugTrace( 0, Dbg, " ->ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.HighPart); // // Extract starting Vbo and offset. // StartingByte = IrpSp->Parameters.Read.ByteOffset; StartingVbo = StartingByte.LowPart; ByteCount = IrpSp->Parameters.Read.Length; RequestedByteCount = ByteCount; // // Check for a null request, and return immediately // if (ByteCount == 0) { Irp->IoStatus.Information = 0; FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); return STATUS_SUCCESS; } // // Check for a non-zero high part offset // if ( StartingByte.HighPart != 0 ) { Irp->IoStatus.Information = 0; FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE ); return STATUS_END_OF_FILE; } // // Extract the nature of the read from the file object, and case on it // TypeOfRead = FatDecodeFileObject(FileObject, &Vcb, &FcbOrDcb, &Ccb); // // Collect interesting statistics. The FLAG_USER_IO bit will indicate // what type of io we're doing in the FatNonCachedIo function. // if (PagingIo) { CollectReadStats(Vcb, TypeOfRead, ByteCount); if (TypeOfRead == UserFileOpen) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO); } else { ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO); } } // // If there is a previous STACK FatIoContext pointer, NULL it. // if ((IrpContext->FatIoContext != NULL) && FlagOn(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT)) { IrpContext->FatIoContext = NULL; } // // Allocate if necessary and initialize a FAT_IO_CONTEXT block for // all non cached Io, except Cvf file Io. For synchronous Io // we use stack storage, otherwise we allocate pool. // if (NonCachedIo && !(FcbOrDcb && FlagOn(FcbOrDcb->FcbState, FCB_STATE_COMPRESSED_VOLUME_FILE))) { if (IrpContext->FatIoContext == NULL) { if (!Wait) { IrpContext->FatIoContext = FsRtlAllocatePool( NonPagedPool, sizeof(FAT_IO_CONTEXT) ); } else { IrpContext->FatIoContext = &StackFatIoContext; SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT ); } } RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) ); if (Wait) { KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent, NotificationEvent, FALSE ); } else { IrpContext->FatIoContext->Wait.Async.ResourceThreadId = ExGetCurrentResourceThread(); IrpContext->FatIoContext->Wait.Async.RequestedByteCount = ByteCount; IrpContext->FatIoContext->Wait.Async.FileObject = FileObject; } } // // These two cases correspond to either a general opened volume, ie. // open ("a:"), or a read of the volume file (boot sector + fat(s)) // if ((TypeOfRead == VirtualVolumeFile) || (TypeOfRead == UserVolumeOpen)) { DebugTrace(0, Dbg, "Type of read is User Volume or virtual volume file\n", 0); if (TypeOfRead == UserVolumeOpen) { // // Verify that the volume for this handle is still valid // FatQuickVerifyVcb( IrpContext, Vcb ); if (!FlagOn( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE )) { (VOID)ExAcquireResourceExclusive( &Vcb->Resource, TRUE ); try { // // If the volume isn't locked, flush it. // if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) { FatFlushVolume( IrpContext, Vcb ); } } finally { ExReleaseResource( &Vcb->Resource ); } SetFlag( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE ); }
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; }
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 ); } }
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; }
BOOLEAN NtfsAcquireFcbWithPaging ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN BOOLEAN DontWait ) /*++ Routine Description: This routine is used in the create path only. It acquires the Fcb and also the paging IO resource if it exists but only if the create operation was doing a supersede/overwrite operation. This routine will raise if it cannot acquire the resource and wait in the IrpContext is false. Arguments: Fcb - Supplies the Fcb to acquire 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. --*/ { BOOLEAN Status = FALSE; BOOLEAN Wait = FALSE; BOOLEAN PagingIoAcquired = FALSE; ASSERT_IRP_CONTEXT(IrpContext); ASSERT_FCB(Fcb); PAGED_CODE(); // // Sanity check that this is create. The supersede flag is only // set in the create path and only tested here. // ASSERT( IrpContext->MajorFunction == IRP_MJ_CREATE ); if (!DontWait && FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { Wait = TRUE; } // // Free any exclusive paging I/O resource, we currently have, which // must presumably be from a directory with a paging I/O resource. // // We defer releasing the paging io resource when we have logged // changes against a stream. The only transaction that should be // underway at this point is the create file case where we allocated // a file record. In this case it is OK to release the paging io // resource for the parent. // if (IrpContext->FcbWithPagingExclusive != NULL) { // ASSERT(IrpContext->TransactionId == 0); NtfsReleasePagingIo( IrpContext, IrpContext->FcbWithPagingExclusive ); } // // Loop until we get it right - worst case is twice through loop. // while (TRUE) { // // Acquire Paging I/O first. Testing for the PagingIoResource // is not really safe without holding the main resource, so we // correct for that below. // if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ) && (Fcb->PagingIoResource != NULL)) { if (!ExAcquireResourceExclusive( Fcb->PagingIoResource, Wait )) { break; } IrpContext->FcbWithPagingExclusive = Fcb; PagingIoAcquired = TRUE; } // // Let's acquire this Fcb exclusively. // if (!NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, TRUE, DontWait )) { if (PagingIoAcquired) { ASSERT(IrpContext->TransactionId == 0); NtfsReleasePagingIo( IrpContext, Fcb ); } break; } // // If we now do not see a paging I/O resource we are golden, // othewise we can absolutely release and acquire the resources // safely in the right order, since a resource in the Fcb is // not going to go away. // if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ) || PagingIoAcquired || (Fcb->PagingIoResource == NULL)) { Status = TRUE; break; } NtfsReleaseFcb( IrpContext, Fcb ); } return Status; }
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 AfdBind ( IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp ) /*++ Routine Description: Handles the IOCTL_AFD_BIND IOCTL. Arguments: Irp - Pointer to I/O request packet. IrpSp - pointer to the IO stack location to use for this request. Return Value: NTSTATUS -- Indicates whether the request was successfully queued. --*/ { NTSTATUS status; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iosb; PTRANSPORT_ADDRESS transportAddress; PTRANSPORT_ADDRESS requestedAddress; ULONG requestedAddressLength; PAFD_ENDPOINT endpoint; PFILE_FULL_EA_INFORMATION ea; ULONG eaBufferLength; PAGED_CODE( ); // // Set up local pointers. // requestedAddress = Irp->AssociatedIrp.SystemBuffer; requestedAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; endpoint = IrpSp->FileObject->FsContext; ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) ); // // Bomb off if this is a helper endpoint. // if ( endpoint->Type == AfdBlockTypeHelper ) { return STATUS_INVALID_PARAMETER; } // // If the client wants a unique address, make sure that there are no // other sockets with this address. ExAcquireResourceExclusive( AfdResource, TRUE ); if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0 ) { PLIST_ENTRY listEntry; // // Walk the global list of endpoints, // and compare this address againat the address on each endpoint. // for ( listEntry = AfdEndpointListHead.Flink; listEntry != &AfdEndpointListHead; listEntry = listEntry->Flink ) { PAFD_ENDPOINT compareEndpoint; compareEndpoint = CONTAINING_RECORD( listEntry, AFD_ENDPOINT, GlobalEndpointListEntry ); ASSERT( IS_AFD_ENDPOINT_TYPE( compareEndpoint ) ); // // Check whether the endpoint has a local address, whether // the endpoint has been disconnected, and whether the // endpoint is in the process of closing. If any of these // is true, don't compare addresses with this endpoint. // if ( compareEndpoint->LocalAddress != NULL && ( (compareEndpoint->DisconnectMode & (AFD_PARTIAL_DISCONNECT_SEND | AFD_ABORTIVE_DISCONNECT) ) == 0 ) && (compareEndpoint->State != AfdEndpointStateClosing) ) { // // Compare the bits in the endpoint's address and the // address we're attempting to bind to. Note that we // also compare the transport device names on the // endpoints, as it is legal to bind to the same address // on different transports (e.g. bind to same port in // TCP and UDP). We can just compare the transport // device name pointers because unique names are stored // globally. // if ( compareEndpoint->LocalAddressLength == IrpSp->Parameters.DeviceIoControl.InputBufferLength && AfdAreTransportAddressesEqual( compareEndpoint->LocalAddress, compareEndpoint->LocalAddressLength, requestedAddress, requestedAddressLength, FALSE ) && endpoint->TransportInfo == compareEndpoint->TransportInfo ) { // // The addresses are equal. Fail the request. // ExReleaseResource( AfdResource ); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SHARING_VIOLATION; return STATUS_SHARING_VIOLATION; } } } } // // Store the address to which the endpoint is bound. // endpoint->LocalAddress = AFD_ALLOCATE_POOL( NonPagedPool, requestedAddressLength, AFD_LOCAL_ADDRESS_POOL_TAG ); if ( endpoint->LocalAddress == NULL ) { ExReleaseResource( AfdResource ); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES; } endpoint->LocalAddressLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; RtlMoveMemory( endpoint->LocalAddress, requestedAddress, endpoint->LocalAddressLength ); ExReleaseResource( AfdResource ); // // Allocate memory to hold the EA buffer we'll use to specify the // transport address to NtCreateFile. // eaBufferLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 + TDI_TRANSPORT_ADDRESS_LENGTH + 1 + IrpSp->Parameters.DeviceIoControl.InputBufferLength; #if DBG ea = AFD_ALLOCATE_POOL( NonPagedPool, eaBufferLength, AFD_EA_POOL_TAG ); #else ea = AFD_ALLOCATE_POOL( PagedPool, eaBufferLength, AFD_EA_POOL_TAG ); #endif if ( ea == NULL ) { return STATUS_INSUFFICIENT_RESOURCES; } // // Initialize the EA. // ea->NextEntryOffset = 0; ea->Flags = 0; ea->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH; ea->EaValueLength = (USHORT)IrpSp->Parameters.DeviceIoControl.InputBufferLength; RtlMoveMemory( ea->EaName, TdiTransportAddress, ea->EaNameLength + 1 ); transportAddress = (PTRANSPORT_ADDRESS)(&ea->EaName[ea->EaNameLength + 1]); RtlMoveMemory( transportAddress, requestedAddress, ea->EaValueLength ); // // Prepare for opening the address object. // InitializeObjectAttributes( &objectAttributes, &endpoint->TransportInfo->TransportDeviceName, OBJ_CASE_INSENSITIVE, // attributes NULL, NULL ); // // Perform the actual open of the address object. // KeAttachProcess( AfdSystemProcess ); status = ZwCreateFile( &endpoint->AddressHandle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &objectAttributes, &iosb, // returned status information. 0, // block size (unused). 0, // file attributes. FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_CREATE, // create disposition. 0, // create options. ea, eaBufferLength ); AFD_FREE_POOL( ea, AFD_EA_POOL_TAG ); if ( !NT_SUCCESS(status) ) { // // We store the local address in a local before freeing it to // avoid a timing window. // PVOID localAddress = endpoint->LocalAddress; endpoint->LocalAddress = NULL; endpoint->LocalAddressLength = 0; AFD_FREE_POOL( localAddress, AFD_LOCAL_ADDRESS_POOL_TAG ); KeDetachProcess( ); return status; } AfdRecordAddrOpened(); // // Get a pointer to the file object of the address. // status = ObReferenceObjectByHandle( endpoint->AddressHandle, 0L, // DesiredAccess NULL, KernelMode, (PVOID *)&endpoint->AddressFileObject, NULL ); ASSERT( NT_SUCCESS(status) ); AfdRecordAddrRef(); IF_DEBUG(BIND) { KdPrint(( "AfdBind: address file object for endpoint %lx at %lx\n", endpoint, endpoint->AddressFileObject )); } // // Remember the device object to which we need to give requests for // this address object. We can't just use the // fileObject->DeviceObject pointer because there may be a device // attached to the transport protocol. // endpoint->AddressDeviceObject = IoGetRelatedDeviceObject( endpoint->AddressFileObject ); // // Determine whether the TDI provider supports data bufferring. // If the provider doesn't, then we have to do it. // if ( (endpoint->TransportInfo->ProviderInfo.ServiceFlags & TDI_SERVICE_INTERNAL_BUFFERING) != 0 ) { endpoint->TdiBufferring = TRUE; } else { endpoint->TdiBufferring = FALSE; } // // Determine whether the TDI provider is message or stream oriented. // if ( (endpoint->TransportInfo->ProviderInfo.ServiceFlags & TDI_SERVICE_MESSAGE_MODE) != 0 ) { endpoint->TdiMessageMode = TRUE; } else { endpoint->TdiMessageMode = FALSE; } // // Remember that the endpoint has been bound to a transport address. // endpoint->State = AfdEndpointStateBound; // // Set up indication handlers on the address object. Only set up // appropriate event handlers--don't set unnecessary event handlers. // status = AfdSetEventHandler( endpoint->AddressFileObject, TDI_EVENT_ERROR, AfdErrorEventHandler, endpoint ); #if DBG if ( !NT_SUCCESS(status) ) { DbgPrint( "AFD: Setting TDI_EVENT_ERROR failed: %lx\n", status ); } #endif if ( IS_DGRAM_ENDPOINT(endpoint) ) { endpoint->EventsActive = AFD_POLL_SEND; IF_DEBUG(EVENT_SELECT) { KdPrint(( "AfdBind: Endp %08lX, Active %08lX\n", endpoint, endpoint->EventsActive )); } status = AfdSetEventHandler( endpoint->AddressFileObject, TDI_EVENT_RECEIVE_DATAGRAM, AfdReceiveDatagramEventHandler, endpoint ); #if DBG if ( !NT_SUCCESS(status) ) { DbgPrint( "AFD: Setting TDI_EVENT_RECEIVE_DATAGRAM failed: %lx\n", status ); } #endif } else {