CVS: winex/dlls/ntdll nt.c,1.21,1.22

[email protected] 12 Sep 2007 12:48:36 -0000
Newsgroups gmane.comp.emulators.winex.cvs
Message-ID <[email protected]>
Subject: winex/dlls/ntdll nt.c,1.21,1.22Update of /var/lib/cvsd/cvsroot/winex/dlls/ntdll
In directory agravaine:/tmp/cvs-serv14452/dlls/ntdll

Modified Files:
	nt.c 
Log Message:
made NtQuerySystemInformation()'s behaviour closer to native
trac #1971

- changed the process information gathering so that it could be passed NULL for the destination buffer.  This would just calculate the [approximate] required size of the buffer.
- fixed up some of the function return values to match native.



Index: nt.c
===================================================================
RCS file: /var/lib/cvsd/cvsroot/winex/dlls/ntdll/nt.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- nt.c	12 Sep 2007 12:46:33 -0000	1.21
+++ nt.c	12 Sep 2007 12:48:34 -0000	1.22
@@ -766,6 +766,16 @@
 	return 0;
 }
 
+/******************************************************************************
+ *  NtCreateMailslotFile	[NTDLL.@]
+ *  ZwCreateMailslotFile	[NTDLL.@]
+ */
+NTSTATUS WINAPI NtCreateMailslotFile(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6,DWORD x7,DWORD x8)
+{
+	FIXME("(0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx),stub!\n",x1,x2,x3,x4,x5,x6,x7,x8);
+	return 0;
+}
+
 
 /******************************************************************************
  * Helper for NtQuerySystemInformation
@@ -792,117 +802,257 @@
 }
 
 
+
 /******************************************************************************
  * Helper for NtQuerySystemInformation
+ *
+ *  <hSnap> is the handle to an open process snapshot
+ *  <processID> is the ID of the parent process of the threads to be enumerated
+ *  <length> is the size of the buffer <pSTI> in bytes
+ *  <pSTI> is the buffer to start storing the thread information blocks at
  */
-static NTSTATUS SnapGetNextProcess (HANDLE hSnap, DWORD LenLeft,
-                                    PSYSTEM_PROCESS_INFORMATION pSPI)
+static NTSTATUS SnapWalkThreads(HANDLE hSnap, DWORD processID, DWORD length, SYSTEM_THREAD_INFORMATION *pSTI)
 {
-   NTSTATUS Ret;
-   CHAR ProcName[1024];
-   CHAR *pExeName;
-   DWORD Len, ExeLen;
-   STRING AnsiStr;
+    NTSTATUS    Ret = STATUS_SUCCESS;
+    DWORD       CurThread = 0;
 
-   SERVER_START_REQ (next_process)
-   {
-      req->handle = hSnap;
-      req->reset = FALSE;
-      wine_server_set_reply (req, ProcName, sizeof (ProcName));
-      if ((Ret = wine_server_call_err (req)) == STATUS_SUCCESS)
-      {
-         ProcName[wine_server_reply_size (reply)] = 0;
-         memset (pSPI, 0, sizeof (*pSPI));
-         pSPI->dwThreadCount = reply->threads;
-         pSPI->dwBasePriority = reply->priority;
-         pSPI->dwProcessID = (DWORD)reply->pid;
-         pSPI->dwParentProcessID = (DWORD)reply->ppid;
-      }
-   }
-   SERVER_END_REQ;
 
-   if (Ret != STATUS_SUCCESS)
-      return Ret;
+    while (Ret == STATUS_SUCCESS){
 
-   if ((pExeName = strrchr (ProcName, '\\')))
-      pExeName++;
-   else
-      pExeName = ProcName;
+        SERVER_START_REQ (next_thread){
+            req->handle = hSnap;
+            req->reset = (CurThread == 0);
+            Ret = wine_server_call_err (req);
 
-   ExeLen = (strlen (pExeName) + 1) * sizeof (WCHAR);
-   Len = sizeof (*pSPI) + ExeLen +
-      (pSPI->dwThreadCount * sizeof (SYSTEM_THREAD_INFORMATION));
 
-   if (LenLeft < Len)
-      return STATUS_INFO_LENGTH_MISMATCH;
+            if (Ret == STATUS_SUCCESS){
 
-   /* Place the exe name after the thread information array to match Windows */
-   pSPI->ProcessName.MaximumLength = ExeLen;
-   pSPI->ProcessName.Buffer = (LPWSTR)((CHAR *)pSPI + Len - ExeLen);
-   RtlInitAnsiString (&AnsiStr, pExeName);
-   if (RtlAnsiStringToUnicodeString (&pSPI->ProcessName, &AnsiStr, FALSE) != STATUS_SUCCESS)
-   {
-      ERR ("Failed to create Unicode string!\n");
-      return STATUS_INFO_LENGTH_MISMATCH;
-   }
+                /* only write the thread info if there is enough room in the buffer for another full block */
+                if (pSTI && length >= sizeof(*pSTI)){
 
-   pSPI->dwOffset = Len;
+                    /* not my thread => get next thread */
+                    if (reply->pid != processID)
+                        continue;
 
-   return Ret;
-}
+                    memset (pSTI, 0, sizeof(*pSTI));
+                    pSTI->dwOwningPID = (DWORD)reply->pid;
+                    pSTI->dwThreadID = (DWORD)reply->tid;
+                    pSTI->dwCurrentPriority = reply->base_pri + reply->delta_pri;
+                    pSTI->dwBasePriority = reply->base_pri;
+                    /* FIXME: several members of this struct are being left as 0 */
+
+                    /* add a bad food marker to the end of the thread info block (native does it; 
+                       perhaps for identification/sync/marking purposes?) */
+                    pSTI->dwUnknown = 0xbaadf00d;
+
+                    /* update the buffer size and move to the next thread info block */
+                    length -= sizeof(*pSTI);
+                    pSTI++;
+                }
+
+                CurThread++;
+            }
+        }
+        SERVER_END_REQ;
+    }
 
+    if (Ret == STATUS_NO_MORE_FILES)
+       Ret = STATUS_SUCCESS;
+
+    return Ret;
+}
 
 /******************************************************************************
  * Helper for NtQuerySystemInformation
  */
-static NTSTATUS SnapWalkThreads (HANDLE hSnap, PSYSTEM_PROCESS_INFORMATION pSPI)
+static NTSTATUS SnapGetNextProcess (HANDLE hSnap, DWORD LenLeft,
+                                    PSYSTEM_PROCESS_INFORMATION pSPI, ULONG *returnLength)
 {
-   NTSTATUS Ret = STATUS_SUCCESS;
-   DWORD CurThread = 0;
-   BOOL First = TRUE;
+    NTSTATUS    Ret;
+    CHAR        ProcName[1024];
+    CHAR *      pExeName;
+    DWORD       Len;
+    STRING      AnsiStr;
+    DWORD       threadCount;
+    DWORD       processID;
+    size_t      nameLen;
+    size_t      nameSize;
 
-   while (Ret == STATUS_SUCCESS)
-   {
-      SERVER_START_REQ (next_thread)
-      {
-         req->handle = hSnap;
-         req->reset = First;
-         Ret = wine_server_call_err (req);
-         First = FALSE;
-         if (Ret == STATUS_SUCCESS)
-         {
-            PSYSTEM_THREAD_INFORMATION pSTI = &pSPI->ti[CurThread];
 
-            if (reply->pid != pSPI->dwProcessID)
-               continue;
+    SERVER_START_REQ (next_process)
+    {
+        req->handle = hSnap;
+        req->reset = FALSE;
+        wine_server_set_reply (req, ProcName, sizeof (ProcName));
+        if ((Ret = wine_server_call_err (req)) == STATUS_SUCCESS)
+        {
+            ProcName[wine_server_reply_size (reply)] = 0;
 
-            memset (pSTI, 0, sizeof (pSPI->ti[0]));
-            pSTI->dwOwningPID = (DWORD)reply->pid;
-            pSTI->dwThreadID = (DWORD)reply->tid;
-            pSTI->dwCurrentPriority = reply->base_pri + reply->delta_pri;
-            pSTI->dwBasePriority = reply->base_pri;
+            /* save these since we can't necessarily access them from the <pSPI> block */
+            threadCount = reply->threads;
+            processID = (DWORD)reply->pid;
 
-            CurThread++;
-         }
-      }
-      SERVER_END_REQ;
-   }
+            if (pSPI && LenLeft >= sizeof(*pSPI)){
+                memset (pSPI, 0, sizeof (*pSPI));
+                pSPI->dwThreadCount = reply->threads;
+                pSPI->dwBasePriority = reply->priority;
+                pSPI->dwProcessID = (DWORD)reply->pid;
+                pSPI->dwParentProcessID = (DWORD)reply->ppid;
+            }
+        }
+    }
+    SERVER_END_REQ;
 
-   if (Ret == STATUS_NO_MORE_FILES)
-      Ret = STATUS_SUCCESS;
 
-   return Ret;
+    if (Ret != STATUS_SUCCESS){
+        if (returnLength)
+            *returnLength = 0;
+
+        return Ret;
+    }
+
+
+    if ((pExeName = strrchr(ProcName, '\\')))
+        pExeName++;
+
+    else
+        pExeName = ProcName;
+
+
+    nameLen = strlen(pExeName);
+    nameSize = ((((nameLen + 1) * sizeof(WCHAR)) + 7) & ~7);
+
+    /* the size of the string buffer is aligned to an 8-byte boundary in native */
+    Len = sizeof(*pSPI) + nameSize + (threadCount * sizeof (SYSTEM_THREAD_INFORMATION));
+
+
+    /* write the thread information blocks to the buffer as long as we can fit at least one */
+    if (pSPI && LenLeft > sizeof(*pSPI) + sizeof(SYSTEM_THREAD_INFORMATION)){
+
+        /* grab the thread info blocks */
+        Ret = SnapWalkThreads(  hSnap, 
+                                processID, 
+                                LenLeft >= sizeof(*pSPI) ? LenLeft - sizeof(*pSPI) : 0, 
+                                pSPI ? pSPI->ti : NULL);
+
+
+        /* write the process name at the end of the thread info blocks */
+        if (LenLeft >= Len){
+            NTSTATUS result;
+
+
+            /* the <Length> member of the process's name is the string length in bytes, not 
+                including the terminating null.  The <MaximumLength> member is the string's
+                size in bytes, including the terminating null, and aligned to an 8-byte
+                boundary. */
+            pSPI->ProcessName.MaximumLength = nameSize;
+            pSPI->ProcessName.Buffer = (LPWSTR)((CHAR *)pSPI + Len - nameSize);
+
+            RtlInitAnsiString (&AnsiStr, pExeName);
+            TRACE("pExeName = {'%s', length = %d, maxLength = %d}\n", AnsiStr.Buffer, AnsiStr.Length, AnsiStr.MaximumLength);
+
+
+            result = RtlAnsiStringToUnicodeString (&pSPI->ProcessName, &AnsiStr, FALSE);
+
+            /* couldn't convert the name string to unicode => clear out the name buffer
+                and set its length to 0.  This is not an error case */
+            if (result != STATUS_SUCCESS){
+                ERR("Failed to create Unicode string! {result = 0x%08lx}\n", result);
+
+                pSPI->ProcessName.Length = 0;
+                memset(pSPI->ProcessName.Buffer, 0, pSPI->ProcessName.MaximumLength);
+            }
+
+            TRACE("pSPI->ProcessName = {'%s', length = %d, maxLength = %d}, nameSize = %ld\n", debugstr_w(pSPI->ProcessName.Buffer), pSPI->ProcessName.Length, pSPI->ProcessName.MaximumLength, nameLen * sizeof(WCHAR));
+        }
+
+        pSPI->dwOffset = Len;
+    }
+
+
+    if (returnLength)
+        *returnLength = Len;
+
+    return STATUS_SUCCESS;
 }
 
 
-/******************************************************************************
- *  NtCreateMailslotFile	[NTDLL.@]
- *  ZwCreateMailslotFile	[NTDLL.@]
- */
-NTSTATUS WINAPI NtCreateMailslotFile(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6,DWORD x7,DWORD x8)
-{
-	FIXME("(0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx),stub!\n",x1,x2,x3,x4,x5,x6,x7,x8);
-	return 0;
+
+
+
+static NTSTATUS collectProcessInformation(void *buf, ULONG length, ULONG *resultLength){
+    ULONG                       resLength = 0;
+    ULONG                       processLength;
+    BOOL                        writeToBuffer = TRUE;
+    PSYSTEM_PROCESS_INFORMATION pSPI = (PSYSTEM_PROCESS_INFORMATION)buf;
+    PSYSTEM_PROCESS_INFORMATION pPrev;
+    HANDLE                      hSnap = INVALID_HANDLE_VALUE;
+
+
+    /* no buffer to write in and no return length to write in -> no point doing work => fail */
+    if (buf == NULL && (resultLength == NULL || length != 0)){
+        WARN("nothing to do! {buf = %p, resultLength = %p, length = %lu}\n", buf, resultLength, length);
+
+        return STATUS_ACCESS_VIOLATION;
+    }
+
+
+    /* no output buffer => turn off buffer writing immediately */
+    if (buf == NULL)
+        writeToBuffer = FALSE;
+
+
+    if (SnapCreate (&hSnap) != STATUS_SUCCESS){
+        ERR("snapshot failed!\n");
+
+        if (resultLength)
+            *resultLength = 0;
+
+        return STATUS_ACCESS_VIOLATION;
+    }
+
+
+    /* Iterate over processes */
+    pPrev = pSPI;
+    while (SnapGetNextProcess(hSnap, length - resLength, pSPI, &processLength) == STATUS_SUCCESS){
+
+        /* accumulate the size of this process's buffer.  This value includes space for the
+           main process info, all the thread info blocks, and the process's name */
+        resLength += processLength;
+
+
+        /* if we ran out of buffer space we can't trust the <pSPI->dwOffset> value.  Use the
+           value returned through <callLength> instead. */
+        if (resLength > length){            
+            if (pSPI)
+                pSPI->dwOffset = 0;
+
+            length = 0;
+            pSPI = NULL;
+            pPrev = NULL;
+        }
+
+        else{
+            pPrev = pSPI;
+            pSPI = (PSYSTEM_PROCESS_INFORMATION)((char *)pSPI + pSPI->dwOffset);
+        }
+    }
+
+    /* Clean up snapshot */
+    NtClose (hSnap);
+
+    if (pPrev)
+        pPrev->dwOffset = 0;
+
+    if (resultLength)
+        *resultLength = resLength;
+
+
+    /* the buffer wasn't sufficiently large to store the result => return size mismatch */
+    if (length < resLength)
+        return STATUS_INFO_LENGTH_MISMATCH;
+
+    return STATUS_SUCCESS;
 }
 
 
@@ -911,19 +1061,20 @@
  * ZwQuerySystemInformation [NTDLL.@]
  *
  * ARGUMENTS:
- *  SystemInformationClass	Index to a certain information structure
- *	SystemTimeAdjustmentInformation	SYSTEM_TIME_ADJUSTMENT
- *	SystemCacheInformation		SYSTEM_CACHE_INFORMATION
- *	SystemConfigurationInformation	CONFIGURATION_INFORMATION
- *	observed (class/len):
- *		0x0/0x2c
- *		0x12/0x18
- *		0x2/0x138
- *		0x8/0x600
- *              0x25/0xc
- *  SystemInformation	caller supplies storage for the information structure
- *  Length		size of the structure
- *  ResultLength	Data written
+ *  SystemInformationClass                  Index to a certain information structure    Size
+ *      SystemTimeAdjustmentInformation     SYSTEM_TIME_ADJUSTMENT                      0x0008
+ *      SystemCacheInformation              SYSTEM_CACHE_INFORMATION                    0x0018
+ *      SystemConfigurationInformation      CONFIGURATION_INFORMATION                   ?
+ *      SystemProcessInformation            SYSTEM_PROCESS_INFORMATION                  0x0160+
+ *      SystemRegistryQuotaInformation      SYSTEM_REGISTRY_QUOTA_INFORMATION           0x000c
+ *      SystemBasicInformation              SYSTEM_BASIC_INFORMATION                    0x002c
+ *      SystemPagefileInformation           ?                                           0x0018
+ *      SystemPerformanceInformation        SYSTEM_PERFORMANCE_INFORMATION              0x0138
+ *      SystemProcessorCounters             ?                                           0x0600
+ *  
+ *  SystemInformation   caller supplies storage for the information structure
+ *  Length              size of the structure
+ *  ResultLength        Data written
  */
 NTSTATUS WINAPI NtQuerySystemInformation(
     IN  SYSTEM_INFORMATION_CLASS    SystemInformationClass,
@@ -934,23 +1085,34 @@
     NTSTATUS result = STATUS_SUCCESS;
 
 
-    TRACE ("(0x%08x,%p,0x%08lx,%p)\n",
-           SystemInformationClass, SystemInformation,
-           Length, ResultLength);
+    FIXME("(0x%08x,%p,0x%08lx,%p), mostly-stub!\n",
+            SystemInformationClass, SystemInformation,
+            Length, ResultLength);
 
 
     /* native checks if the buffer length is 0 before checking if the buffer is NULL 
         (<ResultLength> is not modified in this case) => fail */
-    if (Length == 0)
-        return STATUS_INFO_LENGTH_MISMATCH;
+    if (Length == 0){
+       
+        /* NOTE: SystemProcessInformation handles this case differently - it returns the
+            required buffer size in ResultLength */
+        if (!(SystemInformationClass == SystemProcessInformation && ResultLength))
+            return STATUS_INFO_LENGTH_MISMATCH;
+    }
 
     /* native checks if this buffer is NULL on a case-by-case basis.  For now we'll just 
        do the same thing for all information classes */
     if (SystemInformation == NULL){
-        if (ResultLength)
-            *ResultLength = 0;
 
-        return STATUS_ACCESS_VIOLATION;
+        /* SystemProcessInformation handles this case differently - it calculates the required
+           buffer size and returns that in <ResultLength> */
+        if (!(Length == 0 && SystemInformationClass == SystemProcessInformation && ResultLength)){
+
+            if (ResultLength && SystemInformationClass != SystemProcessInformation)
+                *ResultLength = 0;
+
+            return STATUS_ACCESS_VIOLATION;
+        }
     }
 
 
@@ -979,12 +1141,12 @@
                     return STATUS_INFO_LENGTH_MISMATCH;
 
 
-                FIXME("(0x%08x,%p,0x%08lx,%p) faking max registry size of 32 MB\n",
+                FIXME("(0x%08x,%p,0x%08lx,%p) faking max registry size of 32 MB and used size of 2MB\n",
                       SystemInformationClass, SystemInformation, Length, ResultLength);
 
                 quota->RegistryQuotaAllowed =   0x02000000;
                 quota->RegistryQuotaUsed =      0x00200000;
-                quota->Reserved1 =              0x16800000;
+                quota->Reserved1 =              (VOID *)0x16800000;
 
                 if (ResultLength)
                     *ResultLength = sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION);
@@ -1002,48 +1164,12 @@
 
             break;
 
-        case SystemProcessInformation: {
-            PSYSTEM_PROCESS_INFORMATION pSPI =
-               (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
-            PSYSTEM_PROCESS_INFORMATION pPrev;
-            HANDLE hSnap = INVALID_HANDLE_VALUE;
-            ULONG InitialLen = Length;
-
-            /* FIXME - Check data alignment & return
-               STATUS_DATATYPE_MISALIGNMENT if necessary */
-
-            FIXME ("SystemProcessInformation class only partially implemented\n");
-
-            if ((result = SnapCreate (&hSnap)) != STATUS_SUCCESS)
-               break;
-
-            /* Iterate over processes */
-            pPrev = pSPI;
-            while ((result = SnapGetNextProcess (hSnap, Length,
-                                                 pSPI)) == STATUS_SUCCESS)
-            {
-               /* Iterate over all threads, and get info on those threads
-                  that are in the current process*/
-               if ((result = SnapWalkThreads (hSnap, pSPI)) != STATUS_SUCCESS)
-                  break;
-
-               pPrev = pSPI;
-               pSPI = (PSYSTEM_PROCESS_INFORMATION)((char *)pSPI + pSPI->dwOffset);
-               Length -= pPrev->dwOffset;
-            }
-
-            /* Clean up snapshot */
-            NtClose (hSnap);
-            pPrev->dwOffset = 0;
-
-            if (result == STATUS_NO_MORE_FILES)
-               result = STATUS_SUCCESS;
-
-            if ((result == STATUS_SUCCESS) && ResultLength)
-               *ResultLength = InitialLen - Length;
+        case SystemProcessInformation:
+            TRACE("(0x%08x, %p, 0x%08lx, %p) gathering information about all running processes\n",
+                    SystemInformationClass,SystemInformation,Length,ResultLength);
 
+            result = collectProcessInformation(SystemInformation, Length, ResultLength);
             break;
-        }
 
         default:
             FIXME("(0x%08x,%p,0x%08lx,%p) stub\n",