From 9fd54b2838594badf3b7df11fca647594ce5bb0d Mon Sep 17 00:00:00 2001
From: Eric Pouech <pouech-eric@wanadoo.fr>
Date: Tue, 16 Sep 2003 01:07:21 +0000
Subject: [PATCH] - Implemented a few information classes in
 NtQuerySystemInformation. - Added handle information to (wineserver) process
 snapshot.

---
 dlls/ntdll/nt.c                | 219 +++++++++++++++++++++++++++++++--
 include/wine/server_protocol.h |   3 +-
 include/winternl.h             |  25 ++--
 server/handle.c                |   6 +
 server/handle.h                |   2 +
 server/process.c               |   1 +
 server/process.h               |   1 +
 server/protocol.def            |   1 +
 server/snapshot.c              |   1 +
 server/trace.c                 |   1 +
 10 files changed, 237 insertions(+), 23 deletions(-)

diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index c61ef4022eb..b1ef4af2a35 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -139,6 +139,7 @@ NTSTATUS WINAPI NtQueryInformationProcess(
 			ProcessInformation,ProcessInformationLength,
 			ReturnLength
 		);
+                ret = STATUS_NOT_IMPLEMENTED;
 		break;
 	}
 
@@ -316,7 +317,7 @@ NTSTATUS WINAPI NtQueryInformationToken(
     *retlen = len;
 
     if (tokeninfolength < len)
-        return STATUS_BUFFER_TOO_SMALL;
+        return STATUS_INFO_LENGTH_MISMATCH;
 
     switch (tokeninfoclass)
     {
@@ -542,28 +543,226 @@ NTSTATUS WINAPI NtQuerySystemInformation(
 	IN ULONG Length,
 	OUT PULONG ResultLength)
 {
-    switch(SystemInformationClass)
+    NTSTATUS    ret = STATUS_SUCCESS;
+    ULONG       len = 0;
+
+    TRACE("(0x%08x,%p,0x%08lx,%p)\n",
+          SystemInformationClass,SystemInformation,Length,ResultLength);
+
+    switch (SystemInformationClass)
     {
-    case 0x25:
+    case SystemBasicInformation:
+        {
+            SYSTEM_BASIC_INFORMATION* sbi = (SYSTEM_BASIC_INFORMATION*)SystemInformation;
+            if (Length >= sizeof(*sbi))
+            {
+                sbi->dwUnknown1 = 0;
+                sbi->uKeMaximumIncrement = 0;
+                sbi->uPageSize = 1024; /* FIXME */
+                sbi->uMmNumberOfPhysicalPages = 12345; /* FIXME */
+                sbi->uMmLowestPhysicalPage = 0; /* FIXME */
+                sbi->uMmHighestPhysicalPage = 12345; /* FIXME */
+                sbi->uAllocationGranularity = 65536; /* FIXME */
+                sbi->pLowestUserAddress = 0; /* FIXME */
+                sbi->pMmHighestUserAddress = (void*)~0; /* FIXME */
+                sbi->uKeActiveProcessors = 1; /* FIXME */
+                sbi->bKeNumberProcessors = 1; /* FIXME */
+                len = sizeof(*sbi);
+            }
+            else ret = STATUS_INFO_LENGTH_MISMATCH;
+        }
+        break;
+    case SystemPerformanceInformation:
+        {
+            SYSTEM_PERFORMANCE_INFORMATION* spi = (SYSTEM_PERFORMANCE_INFORMATION*)SystemInformation;
+            if (Length >= sizeof(*spi))
+            {
+                memset(spi, 0, sizeof(*spi)); /* FIXME */
+                len = sizeof(*spi);
+            }
+            else ret = STATUS_INFO_LENGTH_MISMATCH;
+        }
+        break;
+    case SystemTimeOfDayInformation:
+        {
+            SYSTEM_TIMEOFDAY_INFORMATION* sti = (SYSTEM_TIMEOFDAY_INFORMATION*)SystemInformation;
+            if (Length >= sizeof(*sti))
+            {
+                sti->liKeBootTime.QuadPart = 0; /* FIXME */
+                sti->liKeSystemTime.QuadPart = 0; /* FIXME */
+                sti->liExpTimeZoneBias.QuadPart  = 0; /* FIXME */
+                sti->uCurrentTimeZoneId = 0; /* FIXME */
+                sti->dwReserved = 0;
+                len = sizeof(*sti);
+            }
+            else ret = STATUS_INFO_LENGTH_MISMATCH;
+        }
+        break;
+    case SystemProcessInformation:
+        {
+            SYSTEM_PROCESS_INFORMATION* spi = (SYSTEM_PROCESS_INFORMATION*)SystemInformation;
+            SYSTEM_PROCESS_INFORMATION* last = NULL;
+            HANDLE hSnap = 0;
+            char procname[1024];
+            DWORD wlen;
+
+            SERVER_START_REQ( create_snapshot )
+            {
+                req->flags   = SNAP_PROCESS | SNAP_THREAD;
+                req->inherit = FALSE;
+                req->pid     = 0;
+                if (!(ret = wine_server_call( req ))) hSnap = reply->handle;
+            }
+            SERVER_END_REQ;
+            len = 0;
+            while (ret == STATUS_SUCCESS)
+            {
+                SERVER_START_REQ( next_process )
+                {
+                    req->handle = hSnap;
+                    req->reset = (len == 0);
+                    wine_server_set_reply( req, procname, sizeof(procname)-1 );
+                    if (!(ret = wine_server_call( req )))
+                    {
+                        procname[wine_server_reply_size(reply)] = 0;
+                        if (Length >= len + sizeof(*spi))
+                        {
+                            memset(spi, 0, sizeof(*spi));
+                            spi->dwOffset = sizeof(*spi);
+                            spi->dwThreadCount = reply->threads;
+                            memset(&spi->ftCreationTime, 0, sizeof(spi->ftCreationTime));
+                            /* spi->pszProcessName will be set later on */
+                            spi->dwBasePriority = reply->priority;
+                            spi->dwProcessID = (DWORD)reply->pid;
+                            spi->dwParentProcessID = (DWORD)reply->ppid;
+                            spi->dwHandleCount = reply->handles;
+                            spi->dwVirtualBytesPeak = 0; /* FIXME */
+                            spi->dwVirtualBytes = 0; /* FIXME */
+                            spi->dwPageFaults = 0; /* FIXME */
+                            spi->dwWorkingSetPeak = 0; /* FIXME */
+                            spi->dwWorkingSet = 0; /* FIXME */
+                            spi->dwUnknown5 = 0; /* FIXME */
+                            spi->dwPagedPool = 0; /* FIXME */
+                            spi->dwUnknown6 = 0; /* FIXME */
+                            spi->dwNonPagedPool = 0; /* FIXME */
+                            spi->dwPageFileBytesPeak = 0; /* FIXME */
+                            spi->dwPrivateBytes = 0; /* FIXME */
+                            spi->dwPageFileBytes = 0; /* FIXME */
+                            /* spi->ti will be set later on */
+                            len += sizeof(*spi) - sizeof(spi->ti);
+                        }
+                        else ret = STATUS_INFO_LENGTH_MISMATCH;
+                    }
+                }
+                SERVER_END_REQ;
+                if (ret != STATUS_SUCCESS)
+                {
+                    if (ret == STATUS_NO_MORE_FILES) ret = STATUS_SUCCESS;
+                    break;
+                }
+                RtlMultiByteToUnicodeN(NULL, 0, &wlen, procname, strlen(procname) + 1);
+                if (Length >= len + wlen + spi->dwThreadCount * sizeof(THREAD_INFO))
+                {
+                    int     i, j;
+
+                    /* set thread info */
+                    spi->dwOffset += spi->dwThreadCount * sizeof(THREAD_INFO);
+                    len += spi->dwThreadCount * sizeof(THREAD_INFO);
+                    i = j = 0;
+                    while (ret == STATUS_SUCCESS)
+                    {
+                        SERVER_START_REQ( next_thread )
+                        {
+                            req->handle = hSnap;
+                            req->reset = (j == 0);
+                            if (!(ret = wine_server_call( req )))
+                            {
+                                j++;
+                                if (reply->pid == spi->dwProcessID)
+                                {
+                                    /* ftKernelTime, ftUserTime, ftCreateTime;
+                                     * dwTickCount, dwStartAddress
+                                     */
+                                    spi->ti[i].dwOwningPID = reply->pid;
+                                    spi->ti[i].dwThreadID  = reply->tid;
+                                    spi->ti[i].dwCurrentPriority = reply->base_pri + reply->delta_pri;
+                                    spi->ti[i].dwBasePriority = reply->base_pri;
+                                    i++;
+                                }
+                            }
+                        }
+                        SERVER_END_REQ;
+                    }
+                    if (ret == STATUS_NO_MORE_FILES) ret = STATUS_SUCCESS;
+
+                    /* now append process name */
+                    spi->pszProcessName = (WCHAR*)((char*)spi + spi->dwOffset);
+                    RtlMultiByteToUnicodeN( spi->pszProcessName, wlen, NULL, procname, strlen(procname) + 1);
+                    len += wlen;
+                    spi->dwOffset += wlen;
+
+                    last = spi;
+                    spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + spi->dwOffset);
+                }
+                else ret = STATUS_INFO_LENGTH_MISMATCH;
+            }
+            if (ret == STATUS_SUCCESS && last) last->dwOffset = 0;
+            if (hSnap) NtClose(hSnap);
+        }
+        break;
+    case SystemProcessorPerformanceInformation:
+        {
+            SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*)SystemInformation;
+            if (Length >= sizeof(*sppi))
+            {
+                memset(sppi, 0, sizeof(*sppi)); /* FIXME */
+                len = sizeof(*sppi);
+            }
+            else ret = STATUS_INFO_LENGTH_MISMATCH;
+        }
+        break;
+
+    case SystemCacheInformation:
+        {
+            SYSTEM_CACHE_INFORMATION* sci = (SYSTEM_CACHE_INFORMATION*)SystemInformation;
+            if (Length >= sizeof(*sci))
+            {
+                memset(sci, 0, sizeof(*sci)); /* FIXME */
+                len = sizeof(*sci);
+            }
+            else ret = STATUS_INFO_LENGTH_MISMATCH;
+        }
+        break;
+    case SystemRegistryQuotaInformation:
 	/* Something to do with the size of the registry             *
 	 * Since we don't have a size limitation, fake it            *
 	 * This is almost certainly wrong.                           *
 	 * This sets each of the three words in the struct to 32 MB, *
 	 * which is enough to make the IE 5 installer happy.         */
-	FIXME("(0x%08x,%p,0x%08lx,%p) faking max registry size of 32 MB\n",
-	      SystemInformationClass,SystemInformation,Length,ResultLength);
-	*(DWORD *)SystemInformation = 0x2000000;
-	*(((DWORD *)SystemInformation)+1) = 0x200000;
-	*(((DWORD *)SystemInformation)+2) = 0x200000;
+        {
+            SYSTEM_REGISTRY_QUOTA_INFORMATION* srqi = (SYSTEM_REGISTRY_QUOTA_INFORMATION*)SystemInformation;
+            if (Length >= sizeof(*srqi))
+            {
+                FIXME("(0x%08x,%p,0x%08lx,%p) faking max registry size of 32 MB\n",
+                      SystemInformationClass,SystemInformation,Length,ResultLength);
+                srqi->RegistryQuotaAllowed = 0x2000000;
+                srqi->RegistryQuotaUsed = 0x200000;
+                srqi->Reserved1 = (void*)0x200000;
+                if (ResultLength) *ResultLength = sizeof(*srqi);
+            }
+            else ret = STATUS_INFO_LENGTH_MISMATCH;
+        }
 	break;
 
     default:
 	FIXME("(0x%08x,%p,0x%08lx,%p) stub\n",
 	      SystemInformationClass,SystemInformation,Length,ResultLength);
-	ZeroMemory (SystemInformation, Length);
+	memset(SystemInformation, 0, Length);
+        ret = STATUS_NOT_IMPLEMENTED;
     }
+    if (ResultLength) *ResultLength = len;
 
-    return STATUS_SUCCESS;
+    return ret;
 }
 
 
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index ac497012367..b3c0d72b3c1 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1592,6 +1592,7 @@ struct next_process_reply
     void*        module;
     int          threads;
     int          priority;
+    int          handles;
     /* VARARG(filename,string); */
 };
 
@@ -3664,6 +3665,6 @@ union generic_reply
     struct open_token_reply open_token_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 120
+#define SERVER_PROTOCOL_VERSION 121
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/winternl.h b/include/winternl.h
index 1ef12d87518..ecd0964c354 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -482,17 +482,18 @@ typedef struct _UNWIND_HISTORY_TABLE {
 /* This is used by NtQuerySystemInformation */
 /* FIXME: Isn't THREAD_INFO and THREADINFO the same structure? */
 typedef struct {
-    FILETIME ftCreationTime;
-    DWORD dwUnknown1;
-    DWORD dwStartAddress;
-    DWORD dwOwningPID;
-    DWORD dwThreadID;
-    DWORD dwCurrentPriority;
-    DWORD dwBasePriority;
-    DWORD dwContextSwitches;
-    DWORD dwThreadState;
-    DWORD dwWaitReason;
-    DWORD dwUnknown2[5];
+    FILETIME    ftKernelTime;
+    FILETIME    ftUserTime;
+    FILETIME    ftCreateTime;
+    DWORD       dwTickCount;
+    DWORD       dwStartAddress;
+    DWORD       dwOwningPID;
+    DWORD       dwThreadID;
+    DWORD       dwCurrentPriority;
+    DWORD       dwBasePriority;
+    DWORD       dwContextSwitches;
+    DWORD       dwThreadState;
+    DWORD       dwWaitReason;
 } THREADINFO, *PTHREADINFO;
 
 /* FIXME: Isn't THREAD_INFO and THREADINFO the same structure? */
@@ -771,7 +772,7 @@ typedef struct _SYSTEM_PERFORMANCE_INFORMATION {
 typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
 #ifdef __WINESRC__
     LARGE_INTEGER liIdleTime;
-    DWORD dwSpare[76];
+    DWORD dwSpare[10];
 #else
     LARGE_INTEGER IdleTime;
     LARGE_INTEGER KernelTime;
diff --git a/server/handle.c b/server/handle.c
index 7669688fdc2..ae68a7a4ef4 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -503,6 +503,12 @@ obj_handle_t open_object( const struct namespace *namespace, const WCHAR *name,
     return handle;
 }
 
+/* return the size of the handle table of a given process */
+unsigned int get_handle_table_count( struct process *process )
+{
+    return process->handles->count;
+}
+
 /* close a handle */
 DECL_HANDLER(close_handle)
 {
diff --git a/server/handle.h b/server/handle.h
index 212a0ae8a4e..91b7a2cbe5d 100644
--- a/server/handle.h
+++ b/server/handle.h
@@ -47,6 +47,8 @@ extern obj_handle_t open_object( const struct namespace *namespace, const WCHAR
 extern obj_handle_t find_inherited_handle( struct process *process, const struct object_ops *ops );
 extern struct handle_table *alloc_handle_table( struct process *process, int count );
 extern struct handle_table *copy_handle_table( struct process *process, struct process *parent );
+extern unsigned int get_handle_table_count( struct process *process);
+
 extern void close_global_handles(void);
 
 #endif  /* __WINE_SERVER_HANDLE_H */
diff --git a/server/process.c b/server/process.c
index 15ab052e936..055f1ef49d0 100644
--- a/server/process.c
+++ b/server/process.c
@@ -845,6 +845,7 @@ struct process_snapshot *process_snap( int *count )
         ptr->threads  = process->running_threads;
         ptr->count    = process->obj.refcount;
         ptr->priority = process->priority;
+        ptr->handles  = get_handle_table_count(process);
         grab_object( process );
         ptr++;
     }
diff --git a/server/process.h b/server/process.h
index 33ece35ccad..c5c481cd112 100644
--- a/server/process.h
+++ b/server/process.h
@@ -86,6 +86,7 @@ struct process_snapshot
     int             count;    /* process refcount */
     int             threads;  /* number of threads */
     int             priority; /* priority class */
+    int             handles;  /* number of handles */
 };
 
 struct module_snapshot
diff --git a/server/protocol.def b/server/protocol.def
index 6b510497f8c..3185cdec3f5 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1175,6 +1175,7 @@ enum char_info_mode
     void*        module;        /* main module */
     int          threads;       /* number of threads */
     int          priority;      /* process priority */
+    int          handles;       /* number of handles */
     VARARG(filename,string);    /* file name of main exe */
 @END
 
diff --git a/server/snapshot.c b/server/snapshot.c
index fda8355b77f..975728a8e31 100644
--- a/server/snapshot.c
+++ b/server/snapshot.c
@@ -128,6 +128,7 @@ static int snapshot_next_process( struct snapshot *snapshot, struct next_process
     reply->module   = 0;  /* FIXME */
     reply->threads  = ptr->threads;
     reply->priority = ptr->priority;
+    reply->handles  = ptr->handles;
     if (ptr->process->exe.filename)
     {
         size_t len = min( ptr->process->exe.namelen, get_reply_max_size() );
diff --git a/server/trace.c b/server/trace.c
index deba957e292..205307b1f2f 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1372,6 +1372,7 @@ static void dump_next_process_reply( const struct next_process_reply *req )
     fprintf( stderr, " module=%p,", req->module );
     fprintf( stderr, " threads=%d,", req->threads );
     fprintf( stderr, " priority=%d,", req->priority );
+    fprintf( stderr, " handles=%d,", req->handles );
     fprintf( stderr, " filename=" );
     dump_varargs_string( cur_size );
 }
-- 
GitLab