diff --git a/reactos/sdk/include/ddk/fcb.h b/reactos/sdk/include/ddk/fcb.h index 352748f558e..2b53c19438f 100644 --- a/reactos/sdk/include/ddk/fcb.h +++ b/reactos/sdk/include/ddk/fcb.h @@ -619,18 +619,18 @@ RxFinalizeNetFobx( _In_ BOOLEAN ForceFinalize); #ifdef __REACTOS__ -#define FILL_IN_FCB(Fcb, a, nl, ct, lat, lwt, lct, as, fs, vdl) \ - (Fcb)->Attributes = a; \ - (Fcb)->NumberOfLinks = nl; \ - (Fcb)->CreationTime.QuadPart = ct; \ - (Fcb)->LastAccessTime.QuadPart = lat; \ - (Fcb)->LastWriteTime.QuadPart = lwt; \ - (Fcb)->LastChangeTime.QuadPart = lct; \ - (Fcb)->ActualAllocationLength = as; \ - (Fcb)->Header.AllocationSize.QuadPart = as; \ - (Fcb)->Header.FileSize.QuadPart = fs; \ - (Fcb)->Header.ValidDataLength.QuadPart = vdl; \ - (Fcb)->FcbState |= FCB_STATE_TIME_AND_SIZE_ALREADY_SET +#define FILL_IN_FCB(Fcb, a, nl, ct, lat, lwt, lct, as, fs, vdl) \ + (Fcb)->Attributes = a; \ + (Fcb)->NumberOfLinks = nl; \ + (Fcb)->CreationTime.QuadPart = ct; \ + (Fcb)->LastAccessTime.QuadPart = lat; \ + (Fcb)->LastWriteTime.QuadPart = lwt; \ + (Fcb)->LastChangeTime.QuadPart = lct; \ + (Fcb)->ActualAllocationLength = as; \ + (Fcb)->Header.AllocationSize.QuadPart = as; \ + (Fcb)->Header.FileSize.QuadPart = fs; \ + (Fcb)->Header.ValidDataLength.QuadPart = vdl; \ + SetFlag((Fcb)->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET) #define TRACKER_ACQUIRE_FCB 0x61616161 #define TRACKER_RELEASE_FCB_NO_BUFF_PENDING 0x72727272 diff --git a/reactos/sdk/include/ddk/mrxfcb.h b/reactos/sdk/include/ddk/mrxfcb.h index e7244ebb4cd..9aadec36464 100644 --- a/reactos/sdk/include/ddk/mrxfcb.h +++ b/reactos/sdk/include/ddk/mrxfcb.h @@ -31,6 +31,7 @@ typedef struct _MRX_SRV_CALL_ #define NET_ROOT_PIPE ((UCHAR)1) #define NET_ROOT_PRINT ((UCHAR)3) #define NET_ROOT_WILD ((UCHAR)4) +#define NET_ROOT_MAILSLOT ((UCHAR)5) typedef UCHAR NET_ROOT_TYPE, *PNET_ROOT_TYPE; diff --git a/reactos/sdk/include/ddk/rxcontx.h b/reactos/sdk/include/ddk/rxcontx.h index 82cb3270aa6..bb8902810f5 100644 --- a/reactos/sdk/include/ddk/rxcontx.h +++ b/reactos/sdk/include/ddk/rxcontx.h @@ -435,6 +435,11 @@ RxRemoveFirstContextFromSerializationQueue( ExReleaseFastMutex(Mutex); \ } +NTSTATUS +RxCancelNotifyChangeDirectoryRequestsForVNetRoot( + PV_NET_ROOT VNetRoot, + BOOLEAN ForceFilesClosed); + VOID RxCancelNotifyChangeDirectoryRequestsForFobx( PFOBX Fobx diff --git a/reactos/sdk/include/ddk/rxprocs.h b/reactos/sdk/include/ddk/rxprocs.h index fd3a49a0401..68c5f1df774 100644 --- a/reactos/sdk/include/ddk/rxprocs.h +++ b/reactos/sdk/include/ddk/rxprocs.h @@ -693,6 +693,12 @@ VOID RxOrphanThisFcb( _In_ PFCB Fcb); +VOID +RxOrphanSrvOpensForThisFcb( + _In_ PFCB Fcb, + _In_ PV_NET_ROOT ThisVNetRoot, + _In_ BOOLEAN OrphanAll); + #define RxEqualConnectionId(C1, C2) RtlEqualMemory(C1, C2, sizeof(RX_CONNECTION_ID)) NTSTATUS diff --git a/reactos/sdk/lib/drivers/rdbsslib/rdbss.c b/reactos/sdk/lib/drivers/rdbsslib/rdbss.c index 348ae81a93f..e1f30e60381 100644 --- a/reactos/sdk/lib/drivers/rdbsslib/rdbss.c +++ b/reactos/sdk/lib/drivers/rdbsslib/rdbss.c @@ -792,6 +792,15 @@ RxCancelNotifyChangeDirectoryRequestsForFobx( UNIMPLEMENTED; } +NTSTATUS +RxCancelNotifyChangeDirectoryRequestsForVNetRoot( + PV_NET_ROOT VNetRoot, + BOOLEAN ForceFilesClosed) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + VOID NTAPI RxCancelRoutine( @@ -2066,7 +2075,7 @@ RxCommonDevFCBClose( /* Our FOBX if set, has to be a VNetRoot */ if (NetRoot != NULL) { - RxAcquirePrefixTableLockShared(Context->RxDeviceObject->pRxNetNameTable, TRUE); + RxAcquirePrefixTableLockExclusive(Context->RxDeviceObject->pRxNetNameTable, TRUE); if (NetRoot->NodeTypeCode == RDBSS_NTC_V_NETROOT) { --NetRoot->NumberOfOpens; @@ -3786,17 +3795,6 @@ RxFastIoWrite( return FALSE; } -NTSTATUS -NTAPI -RxFinalizeConnection( - IN OUT PNET_ROOT NetRoot, - IN OUT PV_NET_ROOT VNetRoot OPTIONAL, - IN LOGICAL ForceFilesClosed) -{ - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; -} - NTSTATUS RxFindOrCreateFcb( PRX_CONTEXT RxContext, diff --git a/reactos/sdk/lib/drivers/rxce/rxce.c b/reactos/sdk/lib/drivers/rxce/rxce.c index e10a14eb0b8..a19832a27e9 100644 --- a/reactos/sdk/lib/drivers/rxce/rxce.c +++ b/reactos/sdk/lib/drivers/rxce/rxce.c @@ -2435,6 +2435,182 @@ RxFcbTableRemoveFcb( return STATUS_SUCCESS; } +/* + * @implemented + */ +NTSTATUS +NTAPI +RxFinalizeConnection( + IN OUT PNET_ROOT NetRoot, + IN OUT PV_NET_ROOT VNetRoot OPTIONAL, + IN LOGICAL ForceFilesClosed) +{ + NTSTATUS Status; + PRX_PREFIX_TABLE PrefixTable; + ULONG UncleanAny, UncleanDir; + LONG FilesOpen, AdditionalRef; + BOOLEAN PrefixLocked, FcbTableLocked, ForceClose; + + PAGED_CODE(); + + ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT); + + /* Get a BOOLEAN out of LOGICAL + * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure + */ + ForceClose = (ForceFilesClosed == TRUE ? TRUE : FALSE); + + /* First, delete any notification change */ + Status = RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot, ForceClose); + /* If it failed, continue if forced */ + if (Status != STATUS_SUCCESS && !ForceFilesClosed) + { + return Status; + } + /* Reset status, in case notification deletion failed */ + Status = STATUS_SUCCESS; + + PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable; + + PrefixLocked = FALSE; + FcbTableLocked = FALSE; + FilesOpen = 0; + AdditionalRef = 0; + UncleanAny = 0; + UncleanDir = 0; + _SEH2_TRY + { + RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE); + PrefixLocked = TRUE; + + RxReferenceNetRoot(NetRoot); + + RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE); + FcbTableLocked = TRUE; + + /* If our V_NET_ROOT wasn't finalized yet, proceed! */ + if (!VNetRoot->ConnectionFinalizationDone) + { + USHORT Bucket; + PRX_FCB_TABLE FcbTable; + + DPRINT("Finalizing connection %p: %wZ\n", NetRoot, &NetRoot->PrefixEntry.Prefix); + + /* We'll browse all its associated FCB to check whether they're open/orphaned */ + FcbTable = &NetRoot->FcbTable; + for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket) + { + PLIST_ENTRY BucketList, Entry; + + BucketList = &FcbTable->HashBuckets[Bucket]; + Entry = BucketList->Flink; + while (Entry != BucketList) + { + PFCB Fcb; + + Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks); + Entry = Entry->Flink; + + /* FCB for this connection, go ahead */ + if (Fcb->VNetRoot == VNetRoot) + { + /* It's still open, and no force? Fail and keep track */ + if (Fcb->UncleanCount > 0 && !ForceClose) + { + Status = STATUS_CONNECTION_IN_USE; + if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY) + { + ++UncleanDir; + } + else + { + ++UncleanAny; + } + } + else + { + /* Else, force purge */ + ASSERT(NodeTypeIsFcb(Fcb)); + + Status = RxAcquireExclusiveFcb(NULL, Fcb); + ASSERT(Status == STATUS_SUCCESS); + + ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED); + + RxScavengeRelatedFobxs(Fcb); + RxPurgeFcb(Fcb); + + /* We don't need to release FCB lock, FCB finalize will take care of it */ + } + } + } + } + + /* No files left, our V_NET_ROOT is finalized */ + if (VNetRoot->NumberOfFobxs == 0) + { + VNetRoot->ConnectionFinalizationDone = TRUE; + } + } + + /* Keep Number of open files and track of the extra reference */ + FilesOpen = VNetRoot->NumberOfFobxs; + AdditionalRef = VNetRoot->AdditionalReferenceForDeleteFsctlTaken; + /* If force close, caller doesn't want to keep connection alive + * and wants it totally close, so drop the V_NET_ROOT too + */ + if (ForceClose) + { + RxFinalizeVNetRoot(VNetRoot, FALSE, TRUE); + } + } + _SEH2_FINALLY + { + /* Release what was acquired */ + if (FcbTableLocked) + { + RxReleaseFcbTableLock(&NetRoot->FcbTable); + } + + /* If close is forced, only fix status if there are open files */ + if (ForceClose) + { + if (Status != STATUS_SUCCESS && UncleanAny != 0) + { + Status = STATUS_FILES_OPEN; + } + } + /* Else, fix status and fail closing if there are open files */ + else + { + if ((Status != STATUS_SUCCESS && UncleanAny != 0) || FilesOpen > 0) + { + Status = STATUS_FILES_OPEN; + } + } + + DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny, UncleanDir, FilesOpen); + + /* If we're are asked to remove the extra ref, or if closing was a success, do it; + * only if it was still referenced! + */ + if ((ForceFilesClosed == 0xFF || Status == STATUS_SUCCESS) && AdditionalRef != 0) + { + VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0; + RxDereferenceVNetRoot(VNetRoot, LHS_ExclusiveLockHeld); + } + + if (PrefixLocked) + { + RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld); + RxReleasePrefixTableLock(PrefixTable); + } + } + _SEH2_END; + + return Status; +} + /* * @implemented */ @@ -5433,6 +5609,67 @@ RxOrphanThisFcb( VOID RxOrphanSrvOpens( IN PV_NET_ROOT ThisVNetRoot) +{ + PFCB Fcb; + USHORT Bucket; + PNET_ROOT NetRoot; + PRX_FCB_TABLE FcbTable; + PRX_PREFIX_TABLE PrefixTable; + + PAGED_CODE(); + + /* Mailslot won't have any SRV_OPEN (to orphan) */ + NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot; + if (NetRoot->Type == NET_ROOT_MAILSLOT) + { + return; + } + + PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable; + ASSERT(RxIsPrefixTableLockExclusive(PrefixTable)); + + FcbTable = &NetRoot->FcbTable; + RxAcquireFcbTableLockExclusive(FcbTable, TRUE); + + _SEH2_TRY + { + /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */ + for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket) + { + PLIST_ENTRY BucketList, Entry; + + BucketList = &FcbTable->HashBuckets[Bucket]; + Entry = BucketList->Flink; + while (Entry != BucketList) + { + Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks); + Entry = Entry->Flink; + + ASSERT(NodeTypeIsFcb(Fcb)); + RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE); + } + } + + /* Of course, don't forget about NULL-entry */ + if (FcbTable->TableEntryForNull != NULL) + { + Fcb = CONTAINING_RECORD(FcbTable->TableEntryForNull, FCB, FcbTableEntry.HashLinks); + ASSERT(NodeTypeIsFcb(Fcb)); + RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE); + } + } + _SEH2_FINALLY + { + RxReleaseFcbTableLock(FcbTable); + } + _SEH2_END; +} + +VOID +RxOrphanSrvOpensForThisFcb( + IN PFCB Fcb, + IN PV_NET_ROOT ThisVNetRoot, + IN BOOLEAN OrphanAll) { UNIMPLEMENTED; }