From: Pierre Schweitzer Date: Wed, 5 Jul 2017 06:11:10 +0000 (+0000) Subject: [RXCE] X-Git-Tag: ReactOS-0.4.6~121 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=f93ac7e964ceaa61904c02d645078e55118e0796;hp=d135302c2f3a3ff86a64c6dd044c272f543557f7 [RXCE] - Implement RxFinalizeConnection(), RxOrphanSrvOpens() - Stub RxOrphanSrvOpensForThisFcb() [RDBSS] - Fix a bug in RxCommonDevFCBClose() where prefix table wasn't acquire exclusively; this was problematic due to potential prefix table removal on dereference - Stub RxCancelNotifyChangeDirectoryRequestsForVNetRoot() This commit basically allows you to delete a NFS share you would have made use of in ReactOS. Like net use z: \\share\path can be deleted through net use /delete z: Note that if you access the share using cmd tools (dir, copy, more, and so on), dismount will work. If you attempt to access with Explorer, then, handles will be kept open and dismount will fail. CORE-8204 CORE-11327 svn path=/trunk/; revision=75286 --- 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; }