[RXCE]
[reactos.git] / reactos / sdk / lib / drivers / rxce / rxce.c
index 2685567..a19832a 100644 (file)
@@ -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
  */
@@ -2899,13 +3075,13 @@ RxFinalizeSrvOpen(
     {
         PLIST_ENTRY ListEntry;
 
-        for (ListEntry = ThisSrvOpen->FobxList.Flink;
-             ListEntry != &ThisSrvOpen->FobxList;
-             ListEntry = ListEntry->Flink)
+        ListEntry = ThisSrvOpen->FobxList.Flink;
+        while (ListEntry != &ThisSrvOpen->FobxList)
         {
             PFOBX Fobx;
 
             Fobx = CONTAINING_RECORD(ListEntry, FOBX, FobxQLinks);
+            ListEntry = ListEntry->Flink;
             RxFinalizeNetFobx(Fobx, TRUE, ForceFinalize);
         }
     }
@@ -3662,14 +3838,14 @@ RxFinishFcbInitialization(
     IN RX_FILE_TYPE FileType,
     IN PFCB_INIT_PACKET InitPacket OPTIONAL)
 {
-    NODE_TYPE_CODE OldType;
+    RX_FILE_TYPE OldType;
 
     PAGED_CODE();
 
     DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
 
-    OldType = Fcb->Header.NodeTypeCode;
-    Fcb->Header.NodeTypeCode = FileType;
+    OldType = NodeType(Fcb);
+    NodeType(Fcb) = FileType;
     /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
     if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET) && FileType == RDBSS_NTC_MAILSLOT)
     {
@@ -3688,19 +3864,23 @@ RxFinishFcbInitialization(
     if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
         FileType != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
     {
-        /* If our FCB newly points to a file, initiliaz everything related */
-        if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE &&
-            OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
+        /* If our FCB newly points to a file, initiliaze everything related */
+        if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE)
+            
         {
-            RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
-            FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, &RxLockOperationCompletion,
-                                    &RxUnlockOperation);
+            if (OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
+            {
+                RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
+                FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, RxLockOperationCompletion,
+                                        RxUnlockOperation);
 
-            ((PFCB)Fcb)->BufferedLocks.List = NULL;
-            ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
+                ((PFCB)Fcb)->BufferedLocks.List = NULL;
+                ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
 
-            Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
+                Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
+            }
         }
+        /* If not a file, validate type */
         else
         {
             ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
@@ -4561,8 +4741,7 @@ RxInitializeRxTimer(
 {
     PAGED_CODE();
 
-    RxTimerInterval.HighPart = -1;
-    RxTimerInterval.LowPart = -550000;
+    RxTimerInterval.QuadPart = -550000;
     KeInitializeSpinLock(&RxTimerLock);
     InitializeListHead(&RxTimerQueueHead);
     InitializeListHead(&RxRecurrentWorkItemsList);
@@ -5430,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;
 }
@@ -6205,15 +6445,17 @@ VOID
 RxProcessChangeBufferingStateRequestsForSrvOpen(
     PSRV_OPEN SrvOpen)
 {
-    LONG NumberOfBufferingChangeRequests, OldBufferingToken;
+    LONG NumberOfBufferingChangeRequests, LockedOldBufferingToken, OldBufferingToken;
 
     /* Get the current number of change requests */
     NumberOfBufferingChangeRequests = ((PSRV_CALL)SrvOpen->pVNetRoot->pNetRoot->pSrvCall)->BufferingManager.CumulativeNumberOfBufferingChangeRequests;
     /* Get our old token */
-    OldBufferingToken = InterlockedCompareExchange(&SrvOpen->BufferingToken,
-                                                   NumberOfBufferingChangeRequests, NumberOfBufferingChangeRequests);
-    /* Do we have stuff to process? */
-    if (OldBufferingToken != SrvOpen->BufferingToken)
+    OldBufferingToken = SrvOpen->BufferingToken;
+    LockedOldBufferingToken = InterlockedCompareExchange(&SrvOpen->BufferingToken,
+                                                         NumberOfBufferingChangeRequests,
+                                                         NumberOfBufferingChangeRequests);
+    /* If buffering state changed in between, process changes */
+    if (OldBufferingToken != LockedOldBufferingToken)
     {
         PFCB Fcb;
         NTSTATUS Status;