don't dereference the port in NtSetInformationFile with information class FileCompletionInformation. The Also make setting the completion port thread-safe. This might fix bug 816
Modified: trunk/reactos/ntoskrnl/io/file.c

Modified: trunk/reactos/ntoskrnl/io/file.c
--- trunk/reactos/ntoskrnl/io/file.c	2005-09-28 15:40:52 UTC (rev 18136)
+++ trunk/reactos/ntoskrnl/io/file.c	2005-09-28 17:15:57 UTC (rev 18137)
@@ -3059,34 +3059,57 @@
         PVOID Queue;
         PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
         PIO_COMPLETION_CONTEXT Context;
-
-        if (Length < sizeof(FILE_COMPLETION_INFORMATION))
+        
+        if (FileObject->Flags & FO_SYNCHRONOUS_IO || FileObject->CompletionContext != NULL)
         {
-            Status = STATUS_INFO_LENGTH_MISMATCH;
+            Status = STATUS_INVALID_PARAMETER;
         }
         else
         {
-            /* Reference the Port */
-            Status = ObReferenceObjectByHandle(CompletionInfo->Port,
-                                               IO_COMPLETION_MODIFY_STATE,
-                                               IoCompletionType,
-                                               PreviousMode,
-                                               (PVOID*)&Queue,
-                                               NULL);
-            if (NT_SUCCESS(Status))
+            if (Length < sizeof(FILE_COMPLETION_INFORMATION))
             {
-                /* Allocate the Context */
-                Context = ExAllocatePoolWithTag(PagedPool,
-                                                sizeof(IO_COMPLETION_CONTEXT),
-                                                TAG('I', 'o', 'C', 'p'));
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+            }
+            else
+            {
+                /* Reference the Port */
+                Status = ObReferenceObjectByHandle(CompletionInfo->Port, /* FIXME - protect with SEH! */
+                                                   IO_COMPLETION_MODIFY_STATE,
+                                                   IoCompletionType,
+                                                   PreviousMode,
+                                                   (PVOID*)&Queue,
+                                                   NULL);
+                if (NT_SUCCESS(Status))
+                {
+                    /* Allocate the Context */
+                    Context = ExAllocatePoolWithTag(PagedPool,
+                                                    sizeof(IO_COMPLETION_CONTEXT),
+                                                    TAG('I', 'o', 'C', 'p'));
 
-                /* Set the Data */
-                Context->Key = CompletionInfo->Key;
-                Context->Port = Queue;
-                FileObject->CompletionContext = Context;
-
-                /* Dereference the Port now */
-                ObDereferenceObject(Queue);
+                    if (Context != NULL)
+                    {
+                        /* Set the Data */
+                        Context->Key = CompletionInfo->Key; /* FIXME - protect with SEH! */
+                        Context->Port = Queue;
+                        
+                        if (InterlockedCompareExchangePointer(&FileObject->CompletionContext,
+                                                              Context,
+                                                              NULL) != NULL)
+                        {
+                            /* someone else set the completion port in the
+                               meanwhile, fail */
+                            ExFreePool(Context);
+                            ObDereferenceObject(Queue);
+                            Status = STATUS_INVALID_PARAMETER;
+                        }
+                    }
+                    else
+                    {
+                        /* Dereference the Port now */
+                        ObDereferenceObject(Queue);
+                        Status = STATUS_INSUFFICIENT_RESOURCES;
+                    }
+                }
             }
         }