/*++ Copyright (c) 1989 Microsoft Corporation Module Name: openclos.c Abstract: This module implements the mini redirector call down routines pertaining to opening/ closing of file/directories. Author: Balan Sethu Raman [SethuR] 7-March-1995 Revision History: --*/ #include "precomp.h" #pragma hdrstop //// //// The Bug check file id for this module //// // //#define BugCheckFileId (RDBSS_BUG_CHECK_LOCAL_CREATE) // // The debug trace level // #define Dbg (DEBUG_TRACE_CREATE) #ifdef RX_PRIVATE_BUILD ULONG MRxProxyDbgPrintF = 1; //0; //1; #endif //ifdef RX_PRIVATE_BUILD #ifdef RX_PRIVATE_BUILD #undef IoGetTopLevelIrp #undef IoSetTopLevelIrp #endif //ifdef RX_PRIVATE_BUILD NTSTATUS MRxProxySyncIrpCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP CalldownIrp, IN PVOID Context ) /*++ Routine Description: This routine is called when the calldownirp is completed. Arguments: IN PDEVICE_OBJECT DeviceObject, IN PIRP CalldownIrp, IN PVOID Context Return Value: RXSTATUS - STATUS_MORE_PROCESSING_REQUIRED --*/ { PRX_CONTEXT RxContext = (PRX_CONTEXT)Context; PMRXPROXY_RX_CONTEXT pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext); if (CalldownIrp->PendingReturned){ //pMRxProxyContext->SyncCallDownIoStatus = CalldownIrp->IoStatus; RxSignalSynchronousWaiter(RxContext); } return(STATUS_MORE_PROCESSING_REQUIRED); } //not on the stack...just in case ULONG DummyReturnedLengthForXxxInfo; NTSTATUS MRxProxySyncXxxInformation( IN OUT PRX_CONTEXT RxContext, IN UCHAR MajorFunction, IN PFILE_OBJECT FileObject, IN ULONG InformationClass, IN ULONG Length, OUT PVOID Information, OUT PULONG ReturnedLength OPTIONAL ) /*++ Routine Description: This routine returns the requested information about a specified file or volume. The information returned is determined by the class that is specified, and it is placed into the caller's output buffer. Arguments: FsInformationClass - Specifies the type of information which should be returned about the file/volume. Length - Supplies the length of the buffer in bytes. FsInformation - Supplies a buffer to receive the requested information returned about the file. This buffer must not be pageable and must reside in system space. ReturnedLength - Supplies a variable that is to receive the length of the information written to the buffer. FileInformation - Boolean that indicates whether the information requested is for a file or a volume. Return Value: The status returned is the final completion status of the operation. --*/ { NTSTATUS Status; PIRP irp,TopIrp; PIO_STACK_LOCATION irpSp; PDEVICE_OBJECT DeviceObject; //ULONG SetFileInfoInfo; PAGED_CODE(); if (ReturnedLength==NULL) { ReturnedLength = &DummyReturnedLengthForXxxInfo; } ASSERT (FileObject); DeviceObject = IoGetRelatedDeviceObject( FileObject ); ASSERT (DeviceObject); // // 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) { return STATUS_INSUFFICIENT_RESOURCES; } irp->Tail.Overlay.OriginalFileObject = FileObject; irp->Tail.Overlay.Thread = PsGetCurrentThread(); irp->RequestorMode = KernelMode; // // 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 ); irpSp->MajorFunction = MajorFunction; irpSp->FileObject = FileObject; IoSetCompletionRoutine(irp, MRxProxySyncIrpCompletionRoutine, RxContext, TRUE,TRUE,TRUE); //call no matter what.... irp->AssociatedIrp.SystemBuffer = Information; // // Copy the caller's parameters to the service-specific portion of the // IRP. // IF_DEBUG { ASSERT( (irpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION) || (irpSp->MajorFunction == IRP_MJ_SET_INFORMATION) || (irpSp->MajorFunction == IRP_MJ_QUERY_VOLUME_INFORMATION) ); if (irpSp->MajorFunction == IRP_MJ_SET_INFORMATION) { //IF_LOUD_DOWNCALLS(MiniFileObject) { // SetFileInfoInfo = ((PFILE_END_OF_FILE_INFORMATION)Information)->EndOfFile.LowPart; //} } ASSERT(&irpSp->Parameters.QueryFile.Length == &irpSp->Parameters.SetFile.Length); ASSERT(&irpSp->Parameters.QueryFile.Length == &irpSp->Parameters.QueryVolume.Length); ASSERT(&irpSp->Parameters.QueryFile.FileInformationClass == &irpSp->Parameters.SetFile.FileInformationClass); ASSERT(&irpSp->Parameters.QueryFile.FileInformationClass == &irpSp->Parameters.QueryVolume.FsInformationClass); } irpSp->Parameters.QueryFile.Length = Length; irpSp->Parameters.QueryFile.FileInformationClass = InformationClass; // // Now simply invoke the driver at its dispatch entry with the IRP. // KeInitializeEvent( &RxContext->SyncEvent, NotificationEvent, FALSE ); //LoudCallsDbgPrint("Ready to", // MiniFileObject, // irpSp->MajorFunction, // irpSp->Parameters.QueryFile.FileInformationClass, // irpSp->Parameters.QueryFile.Length, // SetFileInfoInfo,0,0 // ); try { TopIrp = IoGetTopLevelIrp(); IoSetTopLevelIrp(NULL); //tell the underlying guy he's all clear Status = IoCallDriver(DeviceObject,irp); } finally { IoSetTopLevelIrp(TopIrp); //restore my context for unwind } //RxDbgTrace (0, Dbg, (" -->Status after iocalldriver %08lx(%08lx)\n",RxContext,Status)); if (Status == (STATUS_PENDING)) { RxWaitSync(RxContext); Status = irp->IoStatus.Status; } //LoudCallsDbgPrint("Back from", // MiniFileObject, // irpSp->MajorFunction, // irpSp->Parameters.QueryFile.FileInformationClass, // irpSp->Parameters.QueryFile.Length, // SetFileInfoInfo, // Status,irp->IoStatus.Information // ); if (Status==STATUS_SUCCESS) { *ReturnedLength = irp->IoStatus.Information; RxDbgTrace( 0, Dbg, ("MRxProxySyncXxxInformation(%x)Info<%x> %x bytes@%x returns %08lx/%08lx\n", RxContext,MajorFunction, Status,*ReturnedLength)); } IoFreeIrp(irp); return(Status); } NTSTATUS MRxProxyShouldTryToCollapseThisOpen ( IN PRX_CONTEXT RxContext ) /*++ Routine Description: This routine determines if the mini knows of a good reason not to try collapsing on this open. Presently, the only reason would be if this were a copychunk open. Arguments: RxContext - the RDBSS context Return Value: NTSTATUS - The return status for the operation SUCCESS --> okay to try collapse other (MORE_PROCESSING_REQUIRED) --> dont collapse --*/ { NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); return Status; } VOID MRxProxyMungeBufferingIfWriteOnlyHandles ( ULONG WriteOnlySrvOpenCount, PMRX_SRV_OPEN SrvOpen ) /*++ Routine Description: This routine modifies the buffering flags on a srvopen so that no cacheing will be allowed if there are any write-only handles to the file. CODE.IMPROVEMENT this should be inlined. Arguments: WriteOnlySrvOpenCount - the number of writeonly srvopens SrvOpen - the srvopen whose buffring flags are to be munged Return Value: RXSTATUS - The return status for the operation --*/ { BOOLEAN IsLoopBack = FALSE; PMRX_SRV_CALL pSrvCall; //PSMBCEDB_SERVER_ENTRY pServerEntry; pSrvCall = SrvOpen->pVNetRoot->pNetRoot->pSrvCall; #if 0 pServerEntry = SmbCeReferenceAssociatedServerEntry(pSrvCall); ASSERT(pServerEntry != NULL); IsLoopBack = pServerEntry->Server.IsLoopBack; SmbCeDereferenceServerEntry(pServerEntry); #endif if (!IsLoopBack && (WriteOnlySrvOpenCount==0)) { return; } SrvOpen->BufferingFlags &= ~( FCB_STATE_WRITECACHEING_ENABLED | FCB_STATE_FILESIZECACHEING_ENABLED | FCB_STATE_FILETIMECACHEING_ENABLED | FCB_STATE_LOCK_BUFFERING_ENABLED | FCB_STATE_READCACHEING_ENABLED | FCB_STATE_COLLAPSING_ENABLED ); } ULONG MRxProxyLoudStringTableSize = 0; UNICODE_STRING MRxProxyLoudStrings[50]; VOID MRxProxySetLoud( IN PBYTE Msg, IN PRX_CONTEXT RxContext, IN PUNICODE_STRING s ) { ULONG i; UNICODE_STRING temp; for (i=0;iBuffer) + s->Length - t->Length; temp.Length = t->Length; //DbgPrint("%s %lx Comparing %wZ with %wZ from %wZ\n",Msg,t->Length,&temp,t,s); if (RtlEqualUnicodeString(&temp,t,TRUE)) { DbgPrint("%s Found %wZ from %wZ\n",Msg,t,s); RxContext->LoudCompletionString = t; break; } } } VOID MRxProxyInitializeLoudStrings( void ) { RtlInitUnicodeString(&MRxProxyLoudStrings[0],L"xsync.exe"); //RtlInitUnicodeString(&MRxProxyLoudStrings[1],L"calc.exe"); //RtlInitUnicodeString(&MRxProxyLoudStrings[2],L"ecco.exe"); MRxProxyLoudStringTableSize = 1; } #define MustBeDirectory(co) ((co) & FILE_DIRECTORY_FILE) #define MustBeFile(co) ((co) & FILE_NON_DIRECTORY_FILE) // define structures for posting of open and close calls so that they end up in the // system process. typedef NTSTATUS (*PMRX_PROXY_POSTABLE_OPERATION) ( IN OUT PRX_CONTEXT RxContext ); #if 0 typedef struct _MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT_LOWER { PRX_CONTEXT RxContext; union { NTSTATUS PostReturnStatus; RX_WORK_QUEUE_ITEM WorkQueueItem; }; KEVENT PostEvent; } MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT_LOWER; typedef struct _MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT { union { MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT_LOWER; MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT_LOWER PostedOpContext; }; } MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT, *PMRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT;; typedef struct _MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT { MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT; } MRX_PROXY_POSTED_CREATE_CONTEXT, *PMRX_PROXY_POSTED_CREATE_CONTEXT; typedef struct _MRX_PROXY_POSTED_CLOSE_CONTEXT { MRX_PROXY_COMMON_POSTED_OPERATION_CONTEXT; } MRX_PROXY_POSTED_CLOSE_CONTEXT, *PMRX_PROXY_POSTED_CLOSE_CONTEXT; #endif NTSTATUS MRxProxyPostOperation ( IN OUT PRX_CONTEXT RxContext, IN OUT PVOID PostedOpContext, IN PMRX_PROXY_POSTABLE_OPERATION Operation ) { NTSTATUS Status,PostStatus; PMRXPROXY_RX_CONTEXT pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext); KeInitializeEvent( &RxContext->SyncEvent, NotificationEvent, FALSE ); pMRxProxyContext->PostedOpContext = PostedOpContext; IF_DEBUG { //fill the workqueue structure with deadbeef....all the better to diagnose //a failed post ULONG i; for (i=0;i+sizeof(ULONG)-1WorkQueueItem);i+=sizeof(ULONG)) { PBYTE BytePtr = ((PBYTE)&RxContext->WorkQueueItem)+i; PULONG UlongPtr = (PULONG)BytePtr; *UlongPtr = 0xdeadbeef; } } PostStatus = RxPostToWorkerThread( &MRxProxyDeviceObject->RxDeviceObject, DelayedWorkQueue, &RxContext->WorkQueueItem, Operation, RxContext); ASSERT(PostStatus == STATUS_SUCCESS); RxWaitSync(RxContext); Status = pMRxProxyContext->PostedOpStatus; return(Status); } NTSTATUS MRxProxyPostedCreate ( IN OUT PRX_CONTEXT RxContext ) /*++ Routine Description: This routine opens a file across the network Arguments: RxContext - the RDBSS context Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status; PMRXPROXY_RX_CONTEXT pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext); RxCaptureFcb; PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(capFcb); PMRX_SRV_OPEN SrvOpen = RxContext->Create.pSrvOpen; PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen); PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall; PMRX_NET_ROOT NetRoot = capFcb->pNetRoot; PUNICODE_STRING RemainingName = &(capFcb->AlreadyPrefixedName); PNT_CREATE_PARAMETERS CreateParameters = &RxContext->Create.NtCreateParameters; ULONG Disposition = CreateParameters->Disposition; ACCESS_MASK DesiredAccess = CreateParameters->DesiredAccess & 0x1FF; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; HANDLE handle; ULONG FilteredCreateOptions; PAGED_CODE(); RxDbgTrace(+1, Dbg, ("MRxProxyPostedCreate %08lx\n", RxContext )); ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN ); RxDbgTrace( 0, Dbg, (" Attempt to open %wZ\n", &(capFcb->AlreadyPrefixedName) )); MRxProxySetLoud("Create ",RxContext,&(capFcb->AlreadyPrefixedName)); #if 0 // we cannot have a file cached on a write only handle. so we have to behave a little // differently if this is a write-only open. remember this in the proxysrvopen if ( ((DesiredAccess & (FILE_EXECUTE | FILE_READ_DATA)) == 0) && ((DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0) ) { //SetFlag(proxySrvOpen->Flags,PROXY_SRVOPEN_FLAG_WRITE_ONLY_HANDLE); //SrvOpen->Flags |= SRVOPEN_FLAG_DONTUSE_WRITE_CACHEING; DesiredAccess |= FILE_READ_DATA; } #endif // we cannot have a file cached on a write only handle. so if write_data is // specified then so is read data if ( ((DesiredAccess & (FILE_EXECUTE | FILE_READ_DATA)) == 0) && ((DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0) ) { //SetFlag(proxySrvOpen->Flags,PROXY_SRVOPEN_FLAG_WRITE_ONLY_HANDLE); //SrvOpen->Flags |= SRVOPEN_FLAG_DONTUSE_WRITE_CACHEING; DesiredAccess |= FILE_READ_DATA; } if ( ( DesiredAccess &~ (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE) ) == 0 ){ SetFlag(SrvOpen->Flags,SRVOPEN_FLAG_NO_BUFFERING_STATE_CHANGE); } InitializeObjectAttributes( &ObjectAttributes, RemainingName, OBJ_CASE_INSENSITIVE, // !!! can we do this? probably need a flag BUGBUG 0, NULL // !!! Security BUGBUG ); FilteredCreateOptions = CreateParameters->CreateOptions; if (!MustBeDirectory(FilteredCreateOptions)) { FilteredCreateOptions &= ~(FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT); //always async } FilteredCreateOptions |= FILE_NO_INTERMEDIATE_BUFFERING; RxDbgTrace( 0, Dbg, (" ---->FilteredCreateOptions = %08lx\n", FilteredCreateOptions)); RxLog(("-->FilteredOptions/oc %lx %lx",FilteredCreateOptions,capFcb->OpenCount)); Status = IoCreateFile( &handle, DesiredAccess, &ObjectAttributes, &IoStatusBlock, &CreateParameters->AllocationSize, CreateParameters->FileAttributes, CreateParameters->ShareAccess, CreateParameters->Disposition, FilteredCreateOptions, RxContext->Create.EaBuffer, RxContext->Create.EaLength, CreateFileTypeNone, NULL, // extra parameters IO_NO_PARAMETER_CHECKING ); if (NT_SUCCESS(Status)) { Status = ObReferenceObjectByHandle( handle, 0L, NULL, KernelMode, (PVOID *) &proxySrvOpen->UnderlyingFileObject, NULL ); if (Status == STATUS_SUCCESS) { proxySrvOpen->UnderlyingHandle = handle; proxySrvOpen->UnderlyingDeviceObject = IoGetRelatedDeviceObject( proxySrvOpen->UnderlyingFileObject ); } else { ZwClose(handle); } } RxDbgTrace( 0, Dbg, ("Status of underlying open %08lx\n", Status )); RxLog(("--->UnderlyingOpen %lx",Status)); // DbgBreakPoint(); RxDbgTrace(-1, Dbg, ("MRxProxyPostedCreate %08lx exit with status=%08lx\n", RxContext, Status )); if (NT_SUCCESS(Status)) { RxContext->Create.ReturnedCreateInformation = IoStatusBlock.Information; } pMRxProxyContext->PostedOpStatus = Status; RxSignalSynchronousWaiter(RxContext); return(STATUS_SUCCESS); } NTSTATUS MRxProxyPostedCloseHandle ( IN OUT PRX_CONTEXT RxContext ) /*++ Routine Description: Arguments: RxContext - the RDBSS context Return Value: RXSTATUS - The return status for the operation --*/ { //NTSTATUS Status; PMRXPROXY_RX_CONTEXT pMRxProxyContext = MRxProxyGetMinirdrContext(RxContext); //RxCaptureFcb; //PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(capFcb); PMRX_SRV_OPEN SrvOpen = (PMRX_SRV_OPEN)(pMRxProxyContext->PostedOpContext); PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen); //HANDLE handle; PAGED_CODE(); RxDbgTrace(+1, Dbg, ("MRxProxyPostedCloseHandle %08lx %08lx\n", RxContext, SrvOpen )); ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN ); ZwClose(proxySrvOpen->UnderlyingHandle); RxDbgTrace(-1, Dbg, ("MRxProxyPostedCloseHandle %08lx exit\n", RxContext )); pMRxProxyContext->PostedOpStatus = STATUS_SUCCESS; RxSignalSynchronousWaiter(RxContext); return(STATUS_SUCCESS); } NTSTATUS MRxProxyCreate ( IN OUT PRX_CONTEXT RxContext ) /*++ Routine Description: This routine opens a file across the network Arguments: RxContext - the RDBSS context Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status; RxCaptureFcb; PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(capFcb); PMRX_SRV_OPEN SrvOpen = RxContext->Create.pSrvOpen; PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen); BOOLEAN MustRegainExclusiveResource = FALSE; PAGED_CODE(); RxDbgTrace(+1, Dbg, ("MRxProxyCreate %08lx\n", RxContext )); //do this BEFORE you drop the resource SetFlag(SrvOpen->Flags,SRVOPEN_FLAG_COLLAPSING_DISABLED); Status = MRxProxyPostOperation ( RxContext, NULL, MRxProxyPostedCreate ); //this Boolean should be passed...... if (MustRegainExclusiveResource) { //this is required if we do oplock breaks RxAcquireExclusiveFcb( RxContext, capFcb ); } if (NT_SUCCESS(Status)) { RX_FILE_TYPE StorageType; FILE_BASIC_INFORMATION BasicInformation; FILE_STANDARD_INFORMATION StandardInformation; NTSTATUS InfoStatus; FCB_INIT_PACKET InitPacket; ASSERT ( RxIsFcbAcquiredExclusive ( capFcb ) ); StorageType = RxInferFileType(RxContext); RxDbgTrace( 0, Dbg, ("Storagetype %08lx\n", StorageType )); // if we have never obtained the characteristics, we have to get them. if ((capFcb->OpenCount == 0) || !FlagOn(capFcb->FcbState,FCB_STATE_TIME_AND_SIZE_ALREADY_SET) ) { InfoStatus = MRxProxySyncXxxInformation( RxContext, //IN OUT PRX_CONTEXT RxContext, IRP_MJ_QUERY_INFORMATION, //IN UCHAR MajorFunction, proxySrvOpen->UnderlyingFileObject,//IN PFILE_OBJECT FileObject, FileBasicInformation, //IN ULONG InformationClass, sizeof(BasicInformation), //IN ULONG Length, &BasicInformation, //OUT PVOID Information, NULL); //OUT PULONG ReturnedLength OPTIONAL ASSERT (NT_SUCCESS(InfoStatus)); //BUGBUG what if not@! InfoStatus = MRxProxySyncXxxInformation( RxContext, //IN OUT PRX_CONTEXT RxContext, IRP_MJ_QUERY_INFORMATION, //IN UCHAR MajorFunction, proxySrvOpen->UnderlyingFileObject,//IN PFILE_OBJECT FileObject, FileStandardInformation, //IN ULONG InformationClass, sizeof(StandardInformation),//IN ULONG Length, &StandardInformation, //OUT PVOID Information, NULL); //OUT PULONG ReturnedLength OPTIONAL ASSERT (NT_SUCCESS(InfoStatus)); if (StorageType == 0) { StorageType = StandardInformation.Directory?(FileTypeDirectory) :(FileTypeFile); RxDbgTrace( 0, Dbg, ("ChangedStoragetype %08lx\n", StorageType )); } RxDbgTrace( 0, Dbg, ("FileSize %08lx\n", StandardInformation.EndOfFile.LowPart )); RxFinishFcbInitialization( capFcb, RDBSS_STORAGE_NTC(StorageType), RxFormInitPacket( InitPacket, //note no & &BasicInformation.FileAttributes, &StandardInformation.NumberOfLinks, &BasicInformation.CreationTime, &BasicInformation.LastAccessTime, &BasicInformation.LastWriteTime, &BasicInformation.ChangeTime, &StandardInformation.AllocationSize, &StandardInformation.EndOfFile, &StandardInformation.EndOfFile) ); //if (!MRxLocalNoOplocks) MRxLocalRequestOplock(SrvOpen,MRxOplockRequestType,MRxRequestLevelII); //RxDbgTrace( 0, Dbg, ("MRxLocalCreate oplockstate =%08lx\n", localSrvOpen->OplockState )); //SrvOpen->BufferingFlags = MRxLocalTranslateStateToBufferMode[localSrvOpen->OplockState]; SrvOpen->BufferingFlags |= FCB_STATE_COLLAPSING_ENABLED; //this can be turned off in the write path } } if (Status == STATUS_SUCCESS) { RxContext->pFobx = RxCreateNetFobx( RxContext, SrvOpen); if (!RxContext->pFobx) { NTSTATUS PostedCloseStatus; PostedCloseStatus = MRxProxyPostOperation( RxContext, ((PVOID)SrvOpen), MRxProxyPostedCloseHandle ); ObDereferenceObject(proxySrvOpen->UnderlyingFileObject); } } //note.........collapsing IS enabled on fcb but not on any srvopen........ SrvOpen->BufferingFlags |= (FCB_STATE_WRITECACHEING_ENABLED | FCB_STATE_FILESIZECACHEING_ENABLED | FCB_STATE_FILETIMECACHEING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED | FCB_STATE_LOCK_BUFFERING_ENABLED | FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHEING_ENABLED ); ASSERT(Status != (STATUS_PENDING)); ASSERT(RxIsFcbAcquiredExclusive( capFcb )); RxDbgTrace(-1, Dbg, ("MRxProxyCreate %08lx exit with status=%08lx\n", RxContext, Status )); return(Status); } NTSTATUS MRxProxyCollapseOpen( IN OUT PRX_CONTEXT RxContext ) /*++ Routine Description: This routine collapses a open locally Arguments: RxContext - the RDBSS context Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status; RxCaptureFcb; //RX_BLOCK_CONDITION FinalSrvOpenCondition; PMRX_SRV_OPEN SrvOpen = RxContext->Create.pSrvOpen; PMRX_SRV_CALL SrvCall = RxContext->Create.pSrvCall; PMRX_NET_ROOT NetRoot = capFcb->pNetRoot; ASSERT(FALSE); RxContext->pFobx = (PMRX_FOBX)RxCreateNetFobx( RxContext, SrvOpen); if (RxContext->pFobx != NULL) { ASSERT ( RxIsFcbAcquiredExclusive ( capFcb ) ); RxContext->pFobx->OffsetOfNextEaToReturn = 1; Status = STATUS_SUCCESS; } else { Status = (STATUS_INSUFFICIENT_RESOURCES); //DbgBreakPoint(); } return Status; } NTSTATUS MRxProxyComputeNewBufferingState( IN OUT PMRX_SRV_OPEN pMRxSrvOpen, IN PVOID pMRxContext, OUT PULONG pNewBufferingState) /*++ Routine Description: This routine maps the PROXY specific oplock levels into the appropriate RDBSS buffering state flags Arguments: pMRxSrvOpen - the MRX SRV_OPEN extension pMRxContext - the context passed to RDBSS at Oplock indication time pNewBufferingState - the place holder for the new buffering state Return Value: Notes: --*/ { //ULONG OplockLevel; ULONG NewBufferingState; PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(pMRxSrvOpen); PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(pMRxSrvOpen->pFcb); ASSERT(pNewBufferingState != NULL); #if 0 OplockLevel = (ULONG)pMRxContext; if (OplockLevel == PROXY_OPLOCK_LEVEL_II) { NewBufferingState = (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHEING_ENABLED); } else { NewBufferingState = 0; } #endif //0 NewBufferingState = 0; pMRxSrvOpen->BufferingFlags = NewBufferingState; MRxProxyMungeBufferingIfWriteOnlyHandles( proxyFcb->WriteOnlySrvOpenCount, pMRxSrvOpen); *pNewBufferingState = pMRxSrvOpen->BufferingFlags; return STATUS_SUCCESS; } //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- NTSTATUS MRxProxyZeroExtend( IN PRX_CONTEXT pRxContext) /*++ Routine Description: This routine extends the data stream of a file system object Arguments: pRxContext - the RDBSS context Return Value: RXSTATUS - The return status for the operation --*/ { return STATUS_NOT_IMPLEMENTED; } NTSTATUS MRxProxyTruncate( IN PRX_CONTEXT pRxContext) /*++ Routine Description: This routine truncates the contents of a file system object Arguments: pRxContext - the RDBSS context Return Value: RXSTATUS - The return status for the operation --*/ { ASSERT(!"Found a truncate"); return STATUS_NOT_IMPLEMENTED; } NTSTATUS MRxProxyCleanupFobx( IN PRX_CONTEXT RxContext) /*++ Routine Description: This routine cleansup a file system object...normally a noop. unless it's a pipe in which case we do the close at cleanup time and mark the file as being not open. Arguments: pRxContext - the RDBSS context Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status = STATUS_SUCCESS; RxCaptureFcb; RxCaptureFobx; PUNICODE_STRING RemainingName = &(capFcb->AlreadyPrefixedName); NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb); PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen; PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen); //PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(capFcb); //PMRX_PROXY_FOBX proxyFobx = MRxProxyGetFileObjectExtension(capFobx); PAGED_CODE(); ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN ); ASSERT ( NodeTypeIsFcb(capFcb) ); ASSERT (FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT)); ASSERT (proxySrvOpen->UnderlyingFileObject); //if (FlagOn(capFcb->FcbState,FCB_STATE_ORPHANED)) { // RxDbgTrace(-1, Dbg, ("File orphaned\n")); // return (STATUS_SUCCESS); //} // // if more fobxs are using this srvopen then just get out. // otherwise close the handle to trigger the underlying cleanup if (SrvOpen->UncleanFobxCount > 1) { return Status; } RxDbgTrace(+1, Dbg, ("MRxProxyCleanup %wZ\n", RemainingName )); RxLog(("ProxyCleanup %lx",SrvOpen)); //because we only have one handle onthe file....we do nothing for each //individual handle being closed. in this way we avoid doing paging ios! //we close the handle when the final close for the fcb comes down. RxDbgTrace(-1, Dbg, ("MRxProxyCleanup exit with status=%08lx\n", Status )); return(Status); } NTSTATUS MRxProxyForcedClose( IN PMRX_SRV_OPEN pSrvOpen) /*++ Routine Description: This routine closes a file system object Arguments: pSrvOpen - the instance to be closed Return Value: RXSTATUS - The return status for the operation Notes: --*/ { return STATUS_NOT_IMPLEMENTED; } //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //------------close close close close close close close -------------------------------- //------------close close close close close close close -------------------------------- //------------close close close close close close close -------------------------------- //------------close close close close close close close -------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- // // The local debug trace level // #undef Dbg #define Dbg (DEBUG_TRACE_CLOSE) NTSTATUS MRxProxyCloseSrvOpen( IN PRX_CONTEXT RxContext ) /*++ Routine Description: This routine closes a file across the network Arguments: RxContext - the RDBSS context Return Value: RXSTATUS - The return status for the operation --*/ { NTSTATUS Status = STATUS_SUCCESS; RxCaptureFcb; RxCaptureFobx; PUNICODE_STRING RemainingName = &(capFcb->AlreadyPrefixedName); NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb); PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen; PMRX_PROXY_SRV_OPEN proxySrvOpen = MRxProxyGetSrvOpenExtension(SrvOpen); //PMRX_PROXY_FCB proxyFcb = MRxProxyGetFcbExtension(capFcb); //PMRX_PROXY_FOBX proxyFobx = MRxProxyGetFileObjectExtension(capFobx); //IO_STATUS_BLOCK Iosb; //PMINIRDR_OPLOCK_COMPLETION_CONTEXT cc = localSrvOpen->Mocc; //KIRQL oldIrql; //BOOLEAN OplockBreakPending; PAGED_CODE(); ASSERT ( NodeTypeIsFcb(capFcb) ); ASSERT ( SrvOpen->OpenCount == 0 ); ASSERT (proxySrvOpen->UnderlyingFileObject); //if (capFcb->OpenCount > 0) { return STATUS_SUCCESS;} RxDbgTrace(+1, Dbg, ("MRxProxyClose %wZ\n", RemainingName )); RxLog(("ProxyClose fobx=%lx",capFobx)); //if (proxySrvOpen->DeferredOpenContext != NULL) { // RxFreePool(proxySrvOpen->DeferredOpenContext); //} //if ((FlagOn(capFcb->FcbState,FCB_STATE_ORPHANED))) { // RxDbgTrace(-1, Dbg, ("File orphan\n")); // return (STATUS_SUCCESS); //} ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN ); #if 0 IF WE REENABLE THIS, DONT USE IOSETINFO...USE MRxProxySyncXxxInformation INSTEAD // first we set the real filesize.....our pagingIos may have extended it // to a page boundary......... if ( NodeType(capFcb) == RDBSS_NTC_STORAGE_TYPE_FILE ) { FILE_END_OF_FILE_INFORMATION EndOfFileInformation; EndOfFileInformation.EndOfFile = capFcb->Header.FileSize; Status = IxxoSetInformation( proxySrvOpen->UnderlyingFileObject, //IN PFILE_OBJECT FileObject, FileEndOfFileInformation, //IN FILE_INFORMATION_CLASS FileInformationClass, sizeof(EndOfFileInformation), //IN ULONG Length, &EndOfFileInformation //IN PVOID FileInformation ); } //if bad status....keep going anyway........ #endif // next, we close our handle.......... Status = MRxProxyPostOperation( RxContext, ((PVOID)SrvOpen), MRxProxyPostedCloseHandle ); // then, we remove our reference.......... if (proxySrvOpen->UnderlyingFileObject) { RxDbgTrace( 0, Dbg, ("ProxyClose Attempt to close %wZ\n", &(capFcb->AlreadyPrefixedName) )); //if (cc) { // ASSERTMSG("Joejoe the right way to do this would be to CANCEL!!!!!!!!",FALSE); // //since this is a force closed, we get rid of a pending break // KeAcquireSpinLock( &MrxLocalOplockSpinLock, &oldIrql ); // OplockBreakPending = cc->OplockBreakPending; // if (!OplockBreakPending) { // cc->SrvOpen = NULL; // } // KeReleaseSpinLock( &MrxLocalOplockSpinLock, oldIrql ); // if (!OplockBreakPending) { // //gotta lose the spinlock befoer the call // RxDereferenceSrvOpen(SrvOpen); //elim ref! // } //} else { // ASSERT (localSrvOpen->OplockState == OplockStateNone); //} RxLog(("MRxProxyClose %lx %lx",capFcb,capFobx)); //DbgPrint("MRxProxyClose %lx %lx\n",capFcb,capFobx); ObDereferenceObject(proxySrvOpen->UnderlyingFileObject); proxySrvOpen->UnderlyingFileObject = NULL; } Status = STATUS_SUCCESS; RxDbgTrace(-1, Dbg, ("MRxProxyClose exit with status=%08lx\n", Status )); return(Status); }