Merge from amd64-branch:
[reactos.git] / reactos / dll / ntdll / ldr / utils.c
index a3a416b..9dcb999 100644 (file)
@@ -5,6 +5,7 @@
  * PURPOSE:         Process startup for PE executables
  * PROGRAMMERS:     Jean Michault
  *                  Rex Jolliff (rex@lvcablemodem.com)
+ *                  Michael Martin
  */
 
 /*
@@ -60,6 +61,7 @@ static NTSTATUS LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
                                OUT PVOID *BaseAddress OPTIONAL);
 static NTSTATUS LdrpAttachProcess(VOID);
 static VOID LdrpDetachProcess(BOOLEAN UnloadAll);
+static NTSTATUS LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Unload);
 
 NTSTATUS find_actctx_dll( LPCWSTR libname, WCHAR *fulldosname );
 NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module );
@@ -560,7 +562,7 @@ LdrAddModuleEntry(PVOID ImageBase,
   ASSERT(Module);
   memset(Module, 0, sizeof(LDR_DATA_TABLE_ENTRY));
   Module->DllBase = (PVOID)ImageBase;
-  Module->EntryPoint = (PVOID)(ULONG_PTR)NTHeaders->OptionalHeader.AddressOfEntryPoint;
+  Module->EntryPoint = (PVOID)NTHeaders->OptionalHeader.AddressOfEntryPoint;
   if (Module->EntryPoint != 0)
     Module->EntryPoint = (PVOID)((ULONG_PTR)Module->EntryPoint + (ULONG_PTR)Module->DllBase);
   Module->SizeOfImage = LdrpGetResidentSize(NTHeaders);
@@ -659,9 +661,12 @@ LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL,
                     IN BOOLEAN MapAsDataFile,
                     OUT PHANDLE SectionHandle)
 {
-  WCHAR                 SearchPathBuffer[MAX_PATH];
+  WCHAR                 *SearchPathBuffer = NULL;
+  WCHAR                 *ImagePathNameBufferPtr = NULL;
   WCHAR                 DosName[MAX_PATH];
   UNICODE_STRING        FullNtFileName;
+  UNICODE_STRING        PathEnvironmentVar_U;
+  UNICODE_STRING        PathName_U;
   OBJECT_ATTRIBUTES     FileObjectAttributes;
   HANDLE                FileHandle;
   char                  BlockBuffer [1024];
@@ -670,28 +675,84 @@ LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL,
   IO_STATUS_BLOCK       IoStatusBlock;
   NTSTATUS              Status;
   ULONG                 len;
+  ULONG                 ImagePathLen;
 
   DPRINT("LdrpMapDllImageFile() called\n");
 
   if (SearchPath == NULL)
     {
       /* get application running path */
+      ImagePathNameBufferPtr = NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer;
 
-      wcscpy (SearchPathBuffer, NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer);
+      /* Length of ImagePathName */
+      ImagePathLen = wcslen(ImagePathNameBufferPtr);
 
-      len = wcslen (SearchPathBuffer);
+      /* Subtract application name leaveing only the directory length */
+      while (ImagePathLen && ImagePathNameBufferPtr[ImagePathLen - 1] != L'\\')
+          ImagePathLen--;
 
-      while (len && SearchPathBuffer[len - 1] != L'\\')
-           len--;
+      /* Length of directory + semicolon */
+      len = ImagePathLen + 1;
 
-      if (len) SearchPathBuffer[len-1] = L'\0';
+      /* Length of SystemRoot + "//system32"  + semicolon*/
+      len += wcslen(SharedUserData->NtSystemRoot) + 10;
+      /* Length of SystemRoot + semicolon */
+      len += wcslen(SharedUserData->NtSystemRoot) + 1;
 
-      wcscat (SearchPathBuffer, L";");
+      RtlInitUnicodeString (&PathName_U, L"PATH");
+      PathEnvironmentVar_U.Length = 0;
+      PathEnvironmentVar_U.MaximumLength = 0;
+      PathEnvironmentVar_U.Buffer = NULL;
+
+      /* Get the path environment variable */
+      Status = RtlQueryEnvironmentVariable_U(NULL, &PathName_U, &PathEnvironmentVar_U);
+
+      /* Check that valid information was returned */
+      if ((Status == STATUS_BUFFER_TOO_SMALL) && (PathEnvironmentVar_U.Length > 0))
+        {
+          /* Allocate memory for the path env var */
+          PathEnvironmentVar_U.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, PathEnvironmentVar_U.Length + sizeof(WCHAR));
+          if (!PathEnvironmentVar_U.Buffer)
+            {
+              DPRINT1("Fatal! Out of Memory!!\n");
+              return STATUS_NO_MEMORY;
+            }
+          PathEnvironmentVar_U.MaximumLength = PathEnvironmentVar_U.Length + sizeof(WCHAR);
+
+          /* Retry */
+          Status = RtlQueryEnvironmentVariable_U(NULL, &PathName_U, &PathEnvironmentVar_U);
+
+          if (!NT_SUCCESS(Status))
+            {
+              DPRINT1("Unable to get path environment string!\n");
+              ASSERT(FALSE);
+            }
+          /* Length of path evn var + semicolon */
+          len += (PathEnvironmentVar_U.Length / sizeof(WCHAR)) + 1;
+        }
 
+      /* Allocate the size needed to hold all the above paths + period */
+      SearchPathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (len + 2) * sizeof(WCHAR));
+      if (!SearchPathBuffer)
+        {
+          DPRINT1("Fatal! Out of Memory!!\n");
+          return STATUS_NO_MEMORY;
+        }
+
+      wcsncpy(SearchPathBuffer, ImagePathNameBufferPtr, ImagePathLen);
+      wcscat (SearchPathBuffer, L";");
       wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
       wcscat (SearchPathBuffer, L"\\system32;");
       wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
-      wcscat (SearchPathBuffer, L";.");
+      wcscat (SearchPathBuffer, L";");
+
+      if (PathEnvironmentVar_U.Buffer)
+        {
+          wcscat (SearchPathBuffer, PathEnvironmentVar_U.Buffer);
+          wcscat (SearchPathBuffer, L";");
+          RtlFreeHeap(RtlGetProcessHeap(), 0, PathEnvironmentVar_U.Buffer);
+        }
+      wcscat (SearchPathBuffer, L".");
 
       SearchPath = SearchPathBuffer;
     }
@@ -708,7 +769,7 @@ LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL,
     if(Status == STATUS_SUCCESS)
         DPRINT("found %S for %S\n", DosName,DllName->Buffer);
     else
-    return STATUS_DLL_NOT_FOUND;
+        return STATUS_DLL_NOT_FOUND;
   }
 
   if (!RtlDosPathNameToNtPathName_U (DosName,
@@ -838,25 +899,32 @@ LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
 {
   NTSTATUS              Status;
   PLDR_DATA_TABLE_ENTRY Module;
-
+  ULONG_PTR cookie;
   PPEB Peb = NtCurrentPeb();
 
-  TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
+  TRACE_LDR("LdrLoadDll loading %wZ%S%S with flags %d\n",
             Name,
             SearchPath ? L" from " : L"",
-            SearchPath ? SearchPath : L"");
+            SearchPath ? SearchPath : L"",
+            LoadFlags ? *LoadFlags : 0);
 
   Status = LdrpLoadModule(SearchPath, LoadFlags ? *LoadFlags : 0, Name, &Module, BaseAddress);
 
   if (NT_SUCCESS(Status) &&
       (!LoadFlags || 0 == (*LoadFlags & LOAD_LIBRARY_AS_DATAFILE)))
     {
+      if (!create_module_activation_context( Module ))
+         {
+        RtlActivateActivationContext(0, Module->EntryPointActivationContext, &cookie);
+      }
+
       if (!(Module->Flags & LDRP_PROCESS_ATTACH_CALLED))
         {
           RtlEnterCriticalSection(Peb->LoaderLock);
           Status = LdrpAttachProcess();
           RtlLeaveCriticalSection(Peb->LoaderLock);
         }
+       if (Module->EntryPointActivationContext) RtlDeactivateActivationContext(0, cookie);
     }
 
  if ((!Module) && (NT_SUCCESS(Status)))
@@ -1142,8 +1210,8 @@ LdrGetExportByOrdinal (
                     ? RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
                     : NULL);
 
-        if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
-            ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
+        if (((ULONG)Function >= (ULONG)ExportDir) &&
+            ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
           {
              DPRINT("Forward: %s\n", (PCHAR)Function);
              Function = LdrFixupForward((PCHAR)Function);
@@ -1227,8 +1295,8 @@ LdrGetExportByName(PVOID BaseAddress,
           {
              Ordinal = ExOrdinals[Hint];
              Function = RVA(BaseAddress, ExFunctions[Ordinal]);
-             if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
-                 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
+             if (((ULONG)Function >= (ULONG)ExportDir) &&
+                 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
                {
                   DPRINT("Forward: %s\n", (PCHAR)Function);
                   Function = LdrFixupForward((PCHAR)Function);
@@ -1261,8 +1329,8 @@ LdrGetExportByName(PVOID BaseAddress,
           {
              Ordinal = ExOrdinals[mid];
              Function = RVA(BaseAddress, ExFunctions[Ordinal]);
-             if (((ULONG_PTR)Function >= (ULONG_PTR)ExportDir) &&
-                 ((ULONG_PTR)Function < (ULONG_PTR)ExportDir + (ULONG_PTR)ExportDirSize))
+             if (((ULONG)Function >= (ULONG)ExportDir) &&
+                 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
                {
                   DPRINT("Forward: %s\n", (PCHAR)Function);
                   Function = LdrFixupForward((PCHAR)Function);
@@ -1317,8 +1385,7 @@ LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders,
 {
   PIMAGE_DATA_DIRECTORY RelocationDDir;
   PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
-  ULONG Count, OldProtect, OldProtect2;
-  SIZE_T ProtectSize;
+  ULONG Count, ProtectSize, OldProtect, OldProtect2;
   PVOID Page, ProtectPage, ProtectPage2;
   PUSHORT TypeOffset;
   ULONG_PTR Delta;
@@ -1440,10 +1507,10 @@ LdrpGetOrLoadModule(PWCHAR SearchPath,
    if (Load && !NT_SUCCESS(Status))
      {
        Status = LdrpLoadModule(SearchPath,
-                                                          0,
+                               0,
                                &DllName,
                                Module,
-                                                          NULL);
+                               NULL);
        if (NT_SUCCESS(Status))
          {
            Status = LdrFindEntryForName (&DllName, Module, FALSE);
@@ -1506,7 +1573,7 @@ LdrpProcessImportDirectoryEntry(PLDR_DATA_TABLE_ENTRY Module,
    PVOID IATBase;
    ULONG OldProtect;
    ULONG Ordinal;
-   SIZE_T IATSize;
+   ULONG IATSize;
 
    if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
      {
@@ -1533,6 +1600,9 @@ LdrpProcessImportDirectoryEntry(PLDR_DATA_TABLE_ENTRY Module,
        IATSize++;
      }
 
+   /* No need to fixup anything if IAT is empty */
+   if (IATSize == 0) return STATUS_SUCCESS;
+
    /* Unprotect the region we are about to write into. */
    IATBase = (PVOID)ImportAddressList;
    IATSize *= sizeof(PVOID*);
@@ -1652,7 +1722,7 @@ LdrpAdjustImportDirectory(PLDR_DATA_TABLE_ENTRY Module,
    PVOID IATBase;
    ULONG OldProtect;
    ULONG Offset;
-   SIZE_T IATSize;
+   ULONG IATSize;
    PIMAGE_NT_HEADERS NTHeaders;
    PCHAR Name;
    ULONG Size;
@@ -1771,7 +1841,7 @@ LdrFixupImports(IN PWSTR SearchPath OPTIONAL,
    PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
    PIMAGE_TLS_DIRECTORY TlsDirectory;
    ULONG TlsSize = 0;
-   NTSTATUS Status;
+   NTSTATUS Status = STATUS_SUCCESS;
    PLDR_DATA_TABLE_ENTRY ImportedModule;
    PCHAR ImportedName;
    PWSTR ModulePath;
@@ -1978,7 +2048,7 @@ LdrFixupImports(IN PWSTR SearchPath OPTIONAL,
            if (!NT_SUCCESS(Status))
              {
                DPRINT1("failed to load %s\n", ImportedName);
-               return Status;
+               break;
              }
 Success:
            if (Module == ImportedModule)
@@ -1992,10 +2062,29 @@ Success:
            if (!NT_SUCCESS(Status))
              {
                DPRINT1("failed to import %s\n", ImportedName);
-               return Status;
+               break;
              }
            ImportModuleDirectoryCurrent++;
          }
+
+         if (!NT_SUCCESS(Status))
+           {
+            NTSTATUS errorStatus = Status;
+
+            while (ImportModuleDirectoryCurrent >= ImportModuleDirectory)
+              {
+                ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
+
+                Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
+                if (NT_SUCCESS(Status) && Module != ImportedModule)
+                  {
+                    Status = LdrpUnloadModule(ImportedModule, FALSE);
+                    if (!NT_SUCCESS(Status)) DPRINT1("unable to unload %s\n", ImportedName);
+                  }
+                ImportModuleDirectoryCurrent--;
+              }
+            return errorStatus;
+           }
      }
 
    if (TlsDirectory && TlsSize > 0)
@@ -2292,12 +2381,19 @@ LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
         if (!NT_SUCCESS(Status))
           {
             DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status);
+            NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
+            NtClose (SectionHandle);
+            RtlFreeUnicodeString (&FullDosName);
+            RtlFreeUnicodeString (&(*Module)->FullDllName);
+            RtlFreeUnicodeString (&(*Module)->BaseDllName);
+            RemoveEntryList (&(*Module)->InLoadOrderLinks);
+            RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
             return Status;
           }
 
         RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
         InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
-                       &(*Module)->InInitializationOrderLinks);
+                       &(*Module)->InInitializationOrderModuleList);
         RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
       }
     return STATUS_SUCCESS;
@@ -2312,7 +2408,7 @@ LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module,
    PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
    PCHAR ImportedName;
    PLDR_DATA_TABLE_ENTRY ImportedModule;
-   NTSTATUS Status;
+   NTSTATUS Status = 0;
    LONG LoadCount;
    ULONG Size;
 
@@ -2685,7 +2781,7 @@ LdrpDetachProcess(BOOLEAN UnloadAll)
    Entry = ModuleListHead->Blink;
    while (Entry != ModuleListHead)
      {
-       Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
+       Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
        if (((UnloadAll && Module->LoadCount == LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0) &&
            Module->Flags & LDRP_ENTRY_PROCESSED &&
            !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
@@ -2699,7 +2795,7 @@ LdrpDetachProcess(BOOLEAN UnloadAll)
              {
                TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
                          &Module->BaseDllName, Module->EntryPoint);
-               LdrpCallDllEntry(Module, DLL_PROCESS_DETACH, (PVOID)(INT_PTR)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
+               LdrpCallDllEntry(Module, DLL_PROCESS_DETACH, (PVOID)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
              }
            else
              {
@@ -2718,14 +2814,14 @@ LdrpDetachProcess(BOOLEAN UnloadAll)
        Entry = ModuleListHead->Blink;
        while (Entry != ModuleListHead)
          {
-           Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
+           Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
            Entry = Entry->Blink;
            if (Module->Flags & LDRP_UNLOAD_IN_PROGRESS &&
                ((UnloadAll && Module->LoadCount != LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0))
              {
                /* remove the module entry from the list */
                RemoveEntryList (&Module->InLoadOrderLinks);
-               RemoveEntryList (&Module->InInitializationOrderLinks);
+               RemoveEntryList (&Module->InInitializationOrderModuleList);
 
                NtUnmapViewOfSection (NtCurrentProcess (), Module->DllBase);
                NtClose (Module->SectionPointer);
@@ -2778,13 +2874,13 @@ LdrpAttachProcess(VOID)
    Entry = ModuleListHead->Flink;
    while (Entry != ModuleListHead)
      {
-       Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
+       Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
        if (!(Module->Flags & (LDRP_LOAD_IN_PROGRESS|LDRP_UNLOAD_IN_PROGRESS|LDRP_ENTRY_PROCESSED)))
          {
            Module->Flags |= LDRP_LOAD_IN_PROGRESS;
            TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
                      &Module->BaseDllName, Module->EntryPoint);
-           Result = LdrpCallDllEntry(Module, DLL_PROCESS_ATTACH, (PVOID)(INT_PTR)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
+           Result = LdrpCallDllEntry(Module, DLL_PROCESS_ATTACH, (PVOID)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
            if (!Result)
              {
                Status = STATUS_DLL_INIT_FAILED;
@@ -2853,7 +2949,7 @@ LdrpAttachThread (VOID)
 
       while (Entry != ModuleListHead)
         {
-          Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
+          Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
           if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
               !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
               !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
@@ -2897,7 +2993,7 @@ LdrShutdownThread (VOID)
    Entry = ModuleListHead->Blink;
    while (Entry != ModuleListHead)
      {
-       Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
+       Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
 
        if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
            !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
@@ -3404,12 +3500,6 @@ LdrProcessRelocationBlock(IN ULONG_PTR Address,
             LongPtr = (PULONG)((ULONG_PTR)Address + Offset);
             *LongPtr += Delta;
             break;
-#ifdef _WIN64
-          case IMAGE_REL_BASED_DIR64:
-            LongPtr = (PULONG)((ULONG_PTR)Address + Offset);
-            *LongPtr += Delta;
-            break;
-#endif
 
           case IMAGE_REL_BASED_HIGHADJ:
           case IMAGE_REL_BASED_MIPS_JMPADDR:
@@ -3445,7 +3535,7 @@ LdrLockLoaderLock(IN ULONG Flags,
         *Cookie = 0;
         CookieSet = TRUE;
         if (Disposition) *Disposition = 0;
-}
+    }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
         if (CookieSet)
@@ -3477,7 +3567,7 @@ LdrLockLoaderLock(IN ULONG Flags,
     }
 
     /* FIXME: Cookie is based on part of the thread id */
-    *Cookie = (ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread;
+    *Cookie = (ULONG)NtCurrentTeb()->RealClientId.UniqueThread;
     return Status;
 }
 
@@ -3489,7 +3579,7 @@ LdrUnlockLoaderLock(IN ULONG Flags,
     if (Flags != 0x01)
         return STATUS_INVALID_PARAMETER_1;
 
-    if (Cookie != (ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread)
+    if (Cookie != (ULONG)NtCurrentTeb()->RealClientId.UniqueThread)
         return STATUS_INVALID_PARAMETER_2;
 
     RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);