[RXCE]
authorPierre Schweitzer <pierre@reactos.org>
Wed, 5 Jul 2017 06:11:10 +0000 (06:11 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Wed, 5 Jul 2017 06:11:10 +0000 (06:11 +0000)
- 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

reactos/sdk/include/ddk/fcb.h
reactos/sdk/include/ddk/mrxfcb.h
reactos/sdk/include/ddk/rxcontx.h
reactos/sdk/include/ddk/rxprocs.h
reactos/sdk/lib/drivers/rdbsslib/rdbss.c
reactos/sdk/lib/drivers/rxce/rxce.c

index 352748f..2b53c19 100644 (file)
@@ -619,18 +619,18 @@ RxFinalizeNetFobx(
     _In_ BOOLEAN ForceFinalize);
 
 #ifdef __REACTOS__
     _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
 
 #define TRACKER_ACQUIRE_FCB 0x61616161
 #define TRACKER_RELEASE_FCB_NO_BUFF_PENDING 0x72727272
index e7244eb..9aadec3 100644 (file)
@@ -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_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;
 
 
 typedef UCHAR NET_ROOT_TYPE, *PNET_ROOT_TYPE;
 
index 82cb327..bb89028 100644 (file)
@@ -435,6 +435,11 @@ RxRemoveFirstContextFromSerializationQueue(
         ExReleaseFastMutex(Mutex);                          \
     }
 
         ExReleaseFastMutex(Mutex);                          \
     }
 
+NTSTATUS
+RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
+   PV_NET_ROOT VNetRoot,
+   BOOLEAN ForceFilesClosed);
+
 VOID
 RxCancelNotifyChangeDirectoryRequestsForFobx(
    PFOBX Fobx
 VOID
 RxCancelNotifyChangeDirectoryRequestsForFobx(
    PFOBX Fobx
index fd3a49a..68c5f1d 100644 (file)
@@ -693,6 +693,12 @@ VOID
 RxOrphanThisFcb(
     _In_ PFCB Fcb);
 
 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
 #define RxEqualConnectionId(C1, C2) RtlEqualMemory(C1, C2, sizeof(RX_CONNECTION_ID))
 
 NTSTATUS
index 348ae81..e1f30e6 100644 (file)
@@ -792,6 +792,15 @@ RxCancelNotifyChangeDirectoryRequestsForFobx(
     UNIMPLEMENTED;
 }
 
     UNIMPLEMENTED;
 }
 
+NTSTATUS
+RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
+   PV_NET_ROOT VNetRoot,
+   BOOLEAN ForceFilesClosed)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 VOID
 NTAPI
 RxCancelRoutine(
 VOID
 NTAPI
 RxCancelRoutine(
@@ -2066,7 +2075,7 @@ RxCommonDevFCBClose(
     /* Our FOBX if set, has to be a VNetRoot */
     if (NetRoot != NULL)
     {
     /* 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;
         if (NetRoot->NodeTypeCode == RDBSS_NTC_V_NETROOT)
         {
             --NetRoot->NumberOfOpens;
@@ -3786,17 +3795,6 @@ RxFastIoWrite(
     return FALSE;
 }
 
     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,
 NTSTATUS
 RxFindOrCreateFcb(
     PRX_CONTEXT RxContext,
index e10a14e..a19832a 100644 (file)
@@ -2435,6 +2435,182 @@ RxFcbTableRemoveFcb(
     return STATUS_SUCCESS;
 }
 
     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
  */
 /*
  * @implemented
  */
@@ -5433,6 +5609,67 @@ RxOrphanThisFcb(
 VOID
 RxOrphanSrvOpens(
     IN PV_NET_ROOT ThisVNetRoot)
 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;
 }
 {
     UNIMPLEMENTED;
 }