FAST_IO_POSSIBLE Ext2IsFastIoPossible( IN PEXT2_FCB Fcb ) { FAST_IO_POSSIBLE IsPossible = FastIoIsNotPossible; if (!Fcb || !FsRtlOplockIsFastIoPossible(&Fcb->Oplock)) return IsPossible; IsPossible = FastIoIsQuestionable; if (!FsRtlAreThereCurrentFileLocks(&Fcb->FileLockAnchor)) { if (!IsFlagOn(Fcb->Vcb->Flags, VCB_READ_ONLY)) { IsPossible = FastIoIsPossible; } } return IsPossible; }
NTSTATUS VfatRead( PVFAT_IRP_CONTEXT IrpContext) { NTSTATUS Status; PVFATFCB Fcb; ULONG Length = 0; ULONG ReturnedLength = 0; PERESOURCE Resource = NULL; LARGE_INTEGER ByteOffset; PVOID Buffer; ULONG BytesPerSector; ASSERT(IrpContext); DPRINT("VfatRead(IrpContext %p)\n", IrpContext); ASSERT(IrpContext->DeviceObject); // This request is not allowed on the main device object if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) { DPRINT("VfatRead is called with the main device object.\n"); Status = STATUS_INVALID_DEVICE_REQUEST; goto ByeBye; } ASSERT(IrpContext->DeviceExt); ASSERT(IrpContext->FileObject); Fcb = IrpContext->FileObject->FsContext; ASSERT(Fcb); if (Fcb->Flags & FCB_IS_PAGE_FILE) { PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo; IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector; IoSkipCurrentIrpStackLocation(IrpContext->Irp); DPRINT("Read from page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart); Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp); VfatFreeIrpContext(IrpContext); return Status; } DPRINT("<%wZ>\n", &Fcb->PathNameU); ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset; Length = IrpContext->Stack->Parameters.Read.Length; BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector; /* fail if file is a directory and no paged read */ if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } DPRINT("'%wZ', Offset: %u, Length %u\n", &Fcb->PathNameU, ByteOffset.u.LowPart, Length); if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } if (ByteOffset.QuadPart >= Fcb->RFCB.FileSize.QuadPart) { IrpContext->Irp->IoStatus.Information = 0; Status = STATUS_END_OF_FILE; goto ByeBye; } if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME)) { if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0) { DPRINT("%u %u\n", ByteOffset.u.LowPart, Length); // non cached read must be sector aligned Status = STATUS_INVALID_PARAMETER; goto ByeBye; } } if (Length == 0) { IrpContext->Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; goto ByeBye; } if (Fcb->Flags & FCB_IS_VOLUME) { Resource = &IrpContext->DeviceExt->DirResource; } else if (IrpContext->Irp->Flags & IRP_PAGING_IO) { Resource = &Fcb->PagingIoResource; } else { Resource = &Fcb->MainResource; } if (!ExAcquireResourceSharedLite(Resource, IrpContext->Flags & IRPCONTEXT_CANWAIT ? TRUE : FALSE)) { Resource = NULL; Status = STATUS_PENDING; goto ByeBye; } if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && FsRtlAreThereCurrentFileLocks(&Fcb->FileLock)) { if (!FsRtlCheckLockForReadAccess(&Fcb->FileLock, IrpContext->Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; goto ByeBye; } } Buffer = VfatGetUserBuffer(IrpContext->Irp); if (!Buffer) { Status = STATUS_INVALID_USER_BUFFER; goto ByeBye; } if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) && !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME))) { // cached read Status = STATUS_SUCCESS; if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart) { Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart; Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS; } _SEH2_TRY { if (IrpContext->FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap(IrpContext->FileObject, (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), FALSE, &(VfatGlobalData->CacheMgrCallbacks), Fcb); } if (!CcCopyRead(IrpContext->FileObject, &ByteOffset, Length, (IrpContext->Flags & IRPCONTEXT_CANWAIT) != 0, Buffer, &IrpContext->Irp->IoStatus)) { ASSERT((IrpContext->Flags & IRPCONTEXT_CANWAIT) == 0); Status = STATUS_PENDING; goto ByeBye; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); goto ByeBye; } _SEH2_END; if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status)) { Status = IrpContext->Irp->IoStatus.Status; } }
NTSTATUS VfatWrite( PVFAT_IRP_CONTEXT IrpContext) { PVFATFCB Fcb; PERESOURCE Resource = NULL; LARGE_INTEGER ByteOffset; LARGE_INTEGER OldFileSize; NTSTATUS Status = STATUS_SUCCESS; ULONG Length = 0; PVOID Buffer; ULONG BytesPerSector; ASSERT(IrpContext); DPRINT("VfatWrite(IrpContext %p)\n", IrpContext); ASSERT(IrpContext->DeviceObject); // This request is not allowed on the main device object if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) { DPRINT("VfatWrite is called with the main device object.\n"); Status = STATUS_INVALID_DEVICE_REQUEST; goto ByeBye; } ASSERT(IrpContext->DeviceExt); ASSERT(IrpContext->FileObject); Fcb = IrpContext->FileObject->FsContext; ASSERT(Fcb); if (Fcb->Flags & FCB_IS_PAGE_FILE) { PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo; IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector; IoSkipCurrentIrpStackLocation(IrpContext->Irp); DPRINT("Write to page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart); Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp); VfatFreeIrpContext(IrpContext); return Status; } DPRINT("<%wZ>\n", &Fcb->PathNameU); /* fail if file is a directory and no paged read */ if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset; if (ByteOffset.u.LowPart == FILE_WRITE_TO_END_OF_FILE && ByteOffset.u.HighPart == -1) { ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart; } Length = IrpContext->Stack->Parameters.Write.Length; BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector; if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } if (Fcb->Flags & (FCB_IS_FAT | FCB_IS_VOLUME) || vfatDirEntryGetFirstCluster(IrpContext->DeviceExt, &Fcb->entry) == 1) { if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart) { // we can't extend the FAT, the volume or the root on FAT12/FAT16 Status = STATUS_END_OF_FILE; goto ByeBye; } } if (IrpContext->Irp->Flags & (IRP_PAGING_IO|IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME)) { if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0) { // non cached write must be sector aligned Status = STATUS_INVALID_PARAMETER; goto ByeBye; } } if (Length == 0) { /* FIXME: Update last write time */ IrpContext->Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; goto ByeBye; } if (IrpContext->Irp->Flags & IRP_PAGING_IO) { if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector)) { Length = ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart; } } if (Fcb->Flags & FCB_IS_VOLUME) { Resource = &IrpContext->DeviceExt->DirResource; } else if (IrpContext->Irp->Flags & IRP_PAGING_IO) { Resource = &Fcb->PagingIoResource; } else { Resource = &Fcb->MainResource; } if (Fcb->Flags & FCB_IS_PAGE_FILE) { if (!ExAcquireResourceSharedLite(Resource, (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) { Resource = NULL; Status = STATUS_PENDING; goto ByeBye; } } else { if (!ExAcquireResourceExclusiveLite(Resource, (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) { Resource = NULL; Status = STATUS_PENDING; goto ByeBye; } } if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && FsRtlAreThereCurrentFileLocks(&Fcb->FileLock)) { if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; goto ByeBye; } } if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME)) { if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart) { Status = STATUS_PENDING; goto ByeBye; } } OldFileSize = Fcb->RFCB.FileSize; Buffer = VfatGetUserBuffer(IrpContext->Irp); if (!Buffer) { Status = STATUS_INVALID_USER_BUFFER; goto ByeBye; } if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) && !(IrpContext->Irp->Flags & IRP_PAGING_IO) && ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart) { LARGE_INTEGER AllocationSize; AllocationSize.QuadPart = ByteOffset.u.LowPart + Length; Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb, IrpContext->DeviceExt, &AllocationSize); if (!NT_SUCCESS (Status)) { goto ByeBye; } } if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) && !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME))) { // cached write if (IrpContext->FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap(IrpContext->FileObject, (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), FALSE, &VfatGlobalData->CacheMgrCallbacks, Fcb); } if (ByteOffset.QuadPart > OldFileSize.QuadPart) { CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE); } if (CcCopyWrite(IrpContext->FileObject, &ByteOffset, Length, 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer)) { IrpContext->Irp->IoStatus.Information = Length; Status = STATUS_SUCCESS; } else { Status = STATUS_UNSUCCESSFUL; } } else { // non cached write if (ByteOffset.QuadPart > OldFileSize.QuadPart) { CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE); } Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { goto ByeBye; } Status = VfatWriteFileData(IrpContext, Length, ByteOffset); if (NT_SUCCESS(Status)) { IrpContext->Irp->IoStatus.Information = Length; } } if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && !(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME))) { if(!(*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)) { LARGE_INTEGER SystemTime; // set dates and times KeQuerySystemTime (&SystemTime); if (Fcb->Flags & FCB_IS_FATX_ENTRY) { FsdSystemTimeToDosDateTime(IrpContext->DeviceExt, &SystemTime, &Fcb->entry.FatX.UpdateDate, &Fcb->entry.FatX.UpdateTime); Fcb->entry.FatX.AccessDate = Fcb->entry.FatX.UpdateDate; Fcb->entry.FatX.AccessTime = Fcb->entry.FatX.UpdateTime; } else { FsdSystemTimeToDosDateTime(IrpContext->DeviceExt, &SystemTime, &Fcb->entry.Fat.UpdateDate, &Fcb->entry.Fat.UpdateTime); Fcb->entry.Fat.AccessDate = Fcb->entry.Fat.UpdateDate; } /* set date and times to dirty */ Fcb->Flags |= FCB_IS_DIRTY; } } ByeBye: if (Resource) { ExReleaseResourceLite(Resource); } if (Status == STATUS_PENDING) { Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { Status = VfatQueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); VfatFreeIrpContext(IrpContext); } } else { IrpContext->Irp->IoStatus.Status = Status; if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO && !(IrpContext->Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status)) { IrpContext->FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information; } IoCompleteRequest(IrpContext->Irp, (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT)); VfatFreeIrpContext(IrpContext); } DPRINT("%x\n", Status); return Status; }
BOOLEAN CdFastUnlockSingle ( 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 = FALSE; TYPE_OF_OPEN TypeOfOpen; PFCB Fcb; PAGED_CODE(); 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 = CdFastDecodeFileObject( FileObject, &Fcb ); if (TypeOfOpen != UserFileOpen) { IoStatus->Status = STATUS_INVALID_PARAMETER; return TRUE; } // // Only deal with 'good' Fcb's. // if (!CdVerifyFcbOperation( NULL, Fcb )) { return FALSE; } // // If there is no lock then return immediately. // if (Fcb->FileLock == NULL) { IoStatus->Status = STATUS_RANGE_NOT_LOCKED; return TRUE; } FsRtlEnterFileSystem(); try { // // We check whether we can proceed based on the state of the file oplocks. // if ((Fcb->Oplock != NULL) && !FsRtlOplockIsFastIoPossible( &Fcb->Oplock )) { try_return( NOTHING ); } // // If we don't have a file lock, then get one now. // if ((Fcb->FileLock == NULL) && !CdCreateFileLock( NULL, Fcb, FALSE )) { try_return( NOTHING ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request. The call will always succeed. // Results = TRUE; IoStatus->Status = FsRtlFastUnlockSingle( Fcb->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( Fcb->FileLock ) && (Fcb->IsFastIoPossible != FastIoIsPossible)) { CdLockFcb( IrpContext, Fcb ); Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb ); CdUnlockFcb( IrpContext, Fcb ); } try_exit: NOTHING; } finally { FsRtlExitFileSystem(); } return Results; }
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; }
NTSTATUS DokanOplockRequest(__in PIRP *pIrp) { NTSTATUS Status = STATUS_SUCCESS; ULONG FsControlCode; PDokanDCB Dcb; PDokanVCB Vcb; PDokanFCB Fcb = NULL; PDokanCCB Ccb; PFILE_OBJECT fileObject; PIRP Irp = *pIrp; ULONG OplockCount = 0; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); BOOLEAN AcquiredVcb = FALSE; #if (NTDDI_VERSION >= NTDDI_WIN7) PREQUEST_OPLOCK_INPUT_BUFFER InputBuffer = NULL; ULONG InputBufferLength; ULONG OutputBufferLength; #endif PAGED_CODE(); // // Save some references to make our life a little easier // FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; fileObject = IrpSp->FileObject; DokanPrintFileName(fileObject); Ccb = fileObject->FsContext2; if (Ccb == NULL || Ccb->Identifier.Type != CCB) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } Fcb = Ccb->Fcb; if (Fcb == NULL || Fcb->Identifier.Type != FCB) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } Vcb = Fcb->Vcb; if (Vcb == NULL || Vcb->Identifier.Type != VCB) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } Dcb = Vcb->Dcb; #if (NTDDI_VERSION >= NTDDI_WIN7) // // Get the input & output buffer lengths and pointers. // if (FsControlCode == FSCTL_REQUEST_OPLOCK) { InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; InputBuffer = (PREQUEST_OPLOCK_INPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer; OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; // // Check for a minimum length on the input and ouput buffers. // if ((InputBufferLength < sizeof(REQUEST_OPLOCK_INPUT_BUFFER)) || (OutputBufferLength < sizeof(REQUEST_OPLOCK_OUTPUT_BUFFER))) { DDbgPrint(" DokanOplockRequest STATUS_BUFFER_TOO_SMALL\n"); return STATUS_BUFFER_TOO_SMALL; } } // // If the oplock request is on a directory it must be for a Read or // Read-Handle // oplock only. // if ((DokanFCBFlagsIsSet(Fcb, DOKAN_FILE_DIRECTORY)) && ((FsControlCode != FSCTL_REQUEST_OPLOCK) || !FsRtlOplockIsSharedRequest(Irp))) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } #endif // // Use a try finally to free the Fcb/Vcb // try { // // We grab the Fcb exclusively for oplock requests, shared for oplock // break acknowledgement. // if ((FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_1) || (FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK) || (FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK) || (FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) #if (NTDDI_VERSION >= NTDDI_WIN7) || ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn(InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_REQUEST)) #endif ) { AcquiredVcb = ExAcquireResourceSharedLite(&(Fcb->Vcb->Resource), TRUE); #if (NTDDI_VERSION >= NTDDI_WIN7) if (!Dcb->FileLockInUserMode && FsRtlOplockIsSharedRequest(Irp)) { #else if (!Dcb->FileLockInUserMode && FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) { #endif // // Byte-range locks are only valid on files. // if (!DokanFCBFlagsIsSet(Fcb, DOKAN_FILE_DIRECTORY)) { // // Set OplockCount to nonzero if FsRtl denies access // based on current byte-range lock state. // #if (NTDDI_VERSION >= NTDDI_WIN8) OplockCount = (ULONG)!FsRtlCheckLockForOplockRequest( &Fcb->FileLock, &Fcb->AdvancedFCBHeader.AllocationSize); #elif (NTDDI_VERSION >= NTDDI_WIN7) OplockCount = (ULONG)FsRtlAreThereCurrentOrInProgressFileLocks(&Fcb->FileLock); #else OplockCount = (ULONG)FsRtlAreThereCurrentFileLocks(&Fcb->FileLock); #endif } } else { // Shouldn't be something like UncleanCount counter and not FileCount // here? OplockCount = 0;//Fcb->FileCount; } } else if ((FsControlCode == FSCTL_OPLOCK_BREAK_ACKNOWLEDGE) || (FsControlCode == FSCTL_OPBATCH_ACK_CLOSE_PENDING) || (FsControlCode == FSCTL_OPLOCK_BREAK_NOTIFY) || (FsControlCode == FSCTL_OPLOCK_BREAK_ACK_NO_2) #if (NTDDI_VERSION >= NTDDI_WIN7) || ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn(InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_ACK)) #endif ) { #if (NTDDI_VERSION >= NTDDI_WIN7) } else if (FsControlCode == FSCTL_REQUEST_OPLOCK) { // // The caller didn't provide either REQUEST_OPLOCK_INPUT_FLAG_REQUEST or // REQUEST_OPLOCK_INPUT_FLAG_ACK on the input buffer. // DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); Status = STATUS_INVALID_PARAMETER; __leave; } else { #else } else { #endif DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); Status = STATUS_INVALID_PARAMETER; __leave; } // // Fail batch, filter, and handle oplock requests if the file is marked // for delete. // if (((FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK) || (FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK) #if (NTDDI_VERSION >= NTDDI_WIN7) || ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn(InputBuffer->RequestedOplockLevel, OPLOCK_LEVEL_CACHE_HANDLE)) #endif ) && DokanFCBFlagsIsSet(Fcb, DOKAN_DELETE_ON_CLOSE)) { DDbgPrint(" DokanOplockRequest STATUS_DELETE_PENDING\n"); Status = STATUS_DELETE_PENDING; __leave; } // // Call the FsRtl routine to grant/acknowledge oplock. // Status = FsRtlOplockFsctrl(DokanGetFcbOplock(Fcb), Irp, OplockCount); // // Once we call FsRtlOplockFsctrl, we no longer own the IRP and we should // not complete it. // *pIrp = NULL; } finally {