- Major formatting cleanup and optimizations to NtQueryInformationProcess so that...
[reactos.git] / reactos / ntoskrnl / ps / query.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/query.c
5 * PURPOSE: Process Manager: Thread/Process Query/Set Information
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller (w3seek@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* Include Information Class Tables */
17 #include "internal/ps_i.h"
18
19 /* PRIVATE FUNCTIONS *********************************************************/
20
21 /* FIXME:
22 * This entire API is messed up because:
23 * 1) Directly pokes SECTION_OBJECT/FILE_OBJECT without special reffing.
24 * 2) Ignores SeAuditProcessImageFileName stuff added in XP (and ROS).
25 * 3) Doesn't use ObQueryNameString.
26 */
27 NTSTATUS
28 NTAPI
29 PspGetImagePath(IN PEPROCESS Process,
30 OUT PUNICODE_STRING DstPath,
31 IN ULONG ProcessInformationLength)
32 {
33 NTSTATUS Status;
34 ULONG ImagePathLen = 0;
35 PROS_SECTION_OBJECT Section;
36 PWSTR SrcBuffer = NULL, DstBuffer = (PWSTR)(DstPath + 1);
37
38 Section = (PROS_SECTION_OBJECT)Process->SectionObject;
39 if ((Section)&& (Section->FileObject))
40 {
41 /* FIXME - check for SEC_IMAGE and/or SEC_FILE instead
42 of relying on FileObject being != NULL? */
43 SrcBuffer = Section->FileObject->FileName.Buffer;
44 if (SrcBuffer) ImagePathLen = Section->FileObject->FileName.Length;
45 }
46
47 if (ProcessInformationLength < (sizeof(UNICODE_STRING) +
48 ImagePathLen +
49 sizeof(WCHAR)))
50 {
51 return STATUS_INFO_LENGTH_MISMATCH;
52 }
53
54 Status = STATUS_SUCCESS;
55 _SEH_TRY
56 {
57 /* copy the string manually, don't use RtlCopyUnicodeString with DstPath! */
58 DstPath->Length = ImagePathLen;
59 DstPath->MaximumLength = ImagePathLen + sizeof(WCHAR);
60 DstPath->Buffer = DstBuffer;
61 if (ImagePathLen) RtlCopyMemory(DstBuffer, SrcBuffer, ImagePathLen);
62 DstBuffer[ImagePathLen / sizeof(WCHAR)] = L'\0';
63 }
64 _SEH_HANDLE
65 {
66 Status = _SEH_GetExceptionCode();
67 }
68 _SEH_END;
69
70 /* Return status */
71 return Status;
72 }
73
74 /* PUBLIC FUNCTIONS **********************************************************/
75
76 /*
77 * @implemented
78 */
79 NTSTATUS
80 NTAPI
81 NtQueryInformationProcess(IN HANDLE ProcessHandle,
82 IN PROCESSINFOCLASS ProcessInformationClass,
83 OUT PVOID ProcessInformation,
84 IN ULONG ProcessInformationLength,
85 OUT PULONG ReturnLength OPTIONAL)
86 {
87 PEPROCESS Process;
88 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
89 NTSTATUS Status = STATUS_SUCCESS;
90 ULONG Length = 0;
91 PPROCESS_BASIC_INFORMATION ProcessBasicInfo =
92 (PPROCESS_BASIC_INFORMATION)ProcessInformation;
93 PKERNEL_USER_TIMES ProcessTime = (PKERNEL_USER_TIMES)ProcessInformation;
94 ULONG HandleCount;
95 PPROCESS_SESSION_INFORMATION SessionInfo =
96 (PPROCESS_SESSION_INFORMATION)ProcessInformation;
97 PVM_COUNTERS VmCounters = (PVM_COUNTERS)ProcessInformation;
98 PROCESS_DEVICEMAP_INFORMATION DeviceMap;
99 ULONG Cookie;
100 PAGED_CODE();
101
102 /* Check validity of Information Class */
103 Status = DefaultQueryInfoBufferCheck(ProcessInformationClass,
104 PsProcessInfoClass,
105 RTL_NUMBER_OF(PsProcessInfoClass),
106 ProcessInformation,
107 ProcessInformationLength,
108 ReturnLength,
109 PreviousMode);
110 if (!NT_SUCCESS(Status)) return Status;
111
112 /* Check if this isn't the cookie class */
113 if(ProcessInformationClass != ProcessCookie)
114 {
115 /* Reference the process */
116 Status = ObReferenceObjectByHandle(ProcessHandle,
117 PROCESS_QUERY_INFORMATION,
118 PsProcessType,
119 PreviousMode,
120 (PVOID*)&Process,
121 NULL);
122 if (!NT_SUCCESS(Status)) return Status;
123 }
124 else if(ProcessHandle != NtCurrentProcess())
125 {
126 /*
127 * Retreiving the process cookie is only allowed for the calling process
128 * itself! XP only allowes NtCurrentProcess() as process handles even if
129 * a real handle actually represents the current process.
130 */
131 return STATUS_INVALID_PARAMETER;
132 }
133
134 /* Check the information class */
135 switch (ProcessInformationClass)
136 {
137 /* Basic process information */
138 case ProcessBasicInformation:
139
140 /* Protect writes with SEH */
141 _SEH_TRY
142 {
143 /* Write all the information from the EPROCESS/KPROCESS */
144 ProcessBasicInfo->ExitStatus = Process->ExitStatus;
145 ProcessBasicInfo->PebBaseAddress = Process->Peb;
146 ProcessBasicInfo->AffinityMask = Process->Pcb.Affinity;
147 ProcessBasicInfo->UniqueProcessId = (ULONG)Process->
148 UniqueProcessId;
149 ProcessBasicInfo->InheritedFromUniqueProcessId =
150 (ULONG)Process->InheritedFromUniqueProcessId;
151 ProcessBasicInfo->BasePriority = Process->Pcb.BasePriority;
152
153 /* Set return length */
154 Length = sizeof(PROCESS_BASIC_INFORMATION);
155 }
156 _SEH_HANDLE
157 {
158 /* Get exception code */
159 Status = _SEH_GetExceptionCode();
160 }
161 _SEH_END;
162 break;
163
164 /* Quote limits and I/O Counters: not implemented */
165 case ProcessQuotaLimits:
166 case ProcessIoCounters:
167 Status = STATUS_NOT_IMPLEMENTED;
168 break;
169
170 /* Timing */
171 case ProcessTimes:
172
173 /* Protect writes with SEH */
174 _SEH_TRY
175 {
176 /* Copy time information from EPROCESS/KPROCESS */
177 ProcessTime->CreateTime = Process->CreateTime;
178 ProcessTime->UserTime.QuadPart = Process->Pcb.UserTime *
179 100000LL;
180 ProcessTime->KernelTime.QuadPart = Process->Pcb.KernelTime *
181 100000LL;
182 ProcessTime->ExitTime = Process->ExitTime;
183
184 /* Set the return length */
185 Length = sizeof(KERNEL_USER_TIMES);
186 }
187 _SEH_HANDLE
188 {
189 /* Get exception code */
190 Status = _SEH_GetExceptionCode();
191 }
192 _SEH_END;
193 break;
194
195 /* Process Debug Port */
196 case ProcessDebugPort:
197
198 /* Protect write with SEH */
199 _SEH_TRY
200 {
201 /* Return whether or not we have a debug port */
202 *(PHANDLE)ProcessInformation = (Process->DebugPort ?
203 (HANDLE)-1 : NULL);
204
205 /* Set the return length*/
206 Length = sizeof(HANDLE);
207 }
208 _SEH_HANDLE
209 {
210 /* Get exception code */
211 Status = _SEH_GetExceptionCode();
212 }
213 _SEH_END;
214 break;
215
216 /* LDT, WS and VDM Information: not implemented */
217 case ProcessLdtInformation:
218 case ProcessWorkingSetWatch:
219 case ProcessWx86Information:
220 Status = STATUS_NOT_IMPLEMENTED;
221 break;
222
223 case ProcessHandleCount:
224
225 /* Count the number of handles this process has */
226 HandleCount = ObpGetHandleCountByHandleTable(Process->ObjectTable);
227
228 /* Protect write in SEH */
229 _SEH_TRY
230 {
231 /* Return the count of handles */
232 *(PULONG)ProcessInformation = HandleCount;
233
234 /* Set the return length*/
235 Length = sizeof(ULONG);
236 }
237 _SEH_HANDLE
238 {
239 /* Get the exception code */
240 Status = _SEH_GetExceptionCode();
241 }
242 _SEH_END;
243 break;
244
245 /* Session ID for the process */
246 case ProcessSessionInformation:
247
248 /* Enter SEH for write safety */
249 _SEH_TRY
250 {
251 /* Write back the Session ID */
252 SessionInfo->SessionId = Process->Session;
253
254 /* Set the return length */
255 Length = sizeof(PROCESS_SESSION_INFORMATION);
256 }
257 _SEH_HANDLE
258 {
259 /* Get the exception code */
260 Status = _SEH_GetExceptionCode();
261 }
262 _SEH_END;
263 break;
264
265 /* WOW64: Not implemented */
266 case ProcessWow64Information:
267 Status = STATUS_NOT_IMPLEMENTED;
268 break;
269
270 /* Virtual Memory Statistics */
271 case ProcessVmCounters:
272
273 /* Enter SEH for write safety */
274 _SEH_TRY
275 {
276 /* Return data from EPROCESS */
277 VmCounters->PeakVirtualSize = Process->PeakVirtualSize;
278 VmCounters->VirtualSize = Process->VirtualSize;
279 VmCounters->PageFaultCount = Process->Vm.PageFaultCount;
280 VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
281 VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize;
282 VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
283 VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[0];
284 VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
285 VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
286 VmCounters->PagefileUsage = Process->QuotaUsage[2];
287 VmCounters->PeakPagefileUsage = Process->QuotaPeak[2];
288
289 /* Set the return length */
290 *ReturnLength = sizeof(VM_COUNTERS);
291 }
292 _SEH_HANDLE
293 {
294 /* Get the exception code */
295 Status = _SEH_GetExceptionCode();
296 }
297 _SEH_END;
298 break;
299
300 /* Hard Error Processing Mode */
301 case ProcessDefaultHardErrorMode:
302
303 /* Enter SEH for writing back data */
304 _SEH_TRY
305 {
306 /* Write the current processing mode */
307 *(PULONG)ProcessInformation = Process->
308 DefaultHardErrorProcessing;
309
310 /* Set the return length */
311 Length = sizeof(ULONG);
312 }
313 _SEH_HANDLE
314 {
315 /* Get the exception code */
316 Status = _SEH_GetExceptionCode();
317 }
318 _SEH_END;
319 break;
320
321 /* Priority Boosting status */
322 case ProcessPriorityBoost:
323
324 /* Enter SEH for writing back data */
325 _SEH_TRY
326 {
327 /* Return boost status */
328 *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ?
329 FALSE : TRUE;
330
331 /* Set the return length */
332 Length = sizeof(ULONG);
333 }
334 _SEH_HANDLE
335 {
336 /* Get the exception code */
337 Status = _SEH_GetExceptionCode();
338 }
339 _SEH_END;
340 break;
341
342 /* DOS Device Map */
343 case ProcessDeviceMap:
344
345 /* Query the device map information */
346 ObQueryDeviceMapInformation(Process, &DeviceMap);
347
348 /* Enter SEH for writing back data */
349 _SEH_TRY
350 {
351 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
352
353 /* Set the return length */
354 Length = sizeof(PROCESS_DEVICEMAP_INFORMATION);
355 }
356 _SEH_HANDLE
357 {
358 /* Get the exception code */
359 Status = _SEH_GetExceptionCode();
360 }
361 _SEH_END;
362 break;
363
364 /* Priority class */
365 case ProcessPriorityClass:
366
367 /* Enter SEH for writing back data */
368 _SEH_TRY
369 {
370 /* Return current priority class */
371 *(PUSHORT)ProcessInformation = Process->PriorityClass;
372
373 /* Set the return length */
374 Length = sizeof(USHORT);
375 }
376 _SEH_HANDLE
377 {
378 /* Get the exception code */
379 Status = _SEH_GetExceptionCode();
380 }
381 _SEH_END;
382 break;
383
384 case ProcessImageFileName:
385
386 /* Get the image path */
387 Status = PspGetImagePath(Process,
388 (PUNICODE_STRING)ProcessInformation,
389 ProcessInformationLength);
390 break;
391
392 /* Per-process security cookie */
393 case ProcessCookie:
394
395 /* Get the current process and cookie */
396 Process = PsGetCurrentProcess();
397 Cookie = Process->Cookie;
398 if(!Cookie)
399 {
400 LARGE_INTEGER SystemTime;
401 ULONG NewCookie;
402 PKPRCB Prcb;
403
404 /* Generate a new cookie */
405 KeQuerySystemTime(&SystemTime);
406 Prcb = KeGetCurrentPrcb();
407 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
408 SystemTime.u.LowPart ^ SystemTime.u.HighPart;
409
410 /* Set the new cookie or return the current one */
411 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
412 NewCookie,
413 Cookie);
414 if(!Cookie) Cookie = NewCookie;
415
416 /* Set return length */
417 Length = sizeof(ULONG);
418 }
419
420 /* Enter SEH to protect write */
421 _SEH_TRY
422 {
423 /* Write back the cookie */
424 *(PULONG)ProcessInformation = Cookie;
425 }
426 _SEH_HANDLE
427 {
428 /* Get the exception code */
429 Status = _SEH_GetExceptionCode();
430 }
431 _SEH_END;
432 break;
433
434 /* Not yet implemented, or unknown */
435 case ProcessBasePriority:
436 case ProcessRaisePriority:
437 case ProcessExceptionPort:
438 case ProcessAccessToken:
439 case ProcessLdtSize:
440 case ProcessIoPortHandlers:
441 case ProcessUserModeIOPL:
442 case ProcessEnableAlignmentFaultFixup:
443 case ProcessAffinityMask:
444 case ProcessForegroundInformation:
445 default:
446 Status = STATUS_INVALID_INFO_CLASS;
447 }
448
449 /* Protect write with SEH */
450 _SEH_TRY
451 {
452 /* Check if caller wanted return length */
453 if (ReturnLength) *ReturnLength = Length;
454 }
455 _SEH_HANDLE
456 {
457 /* Get exception code */
458 Status = _SEH_GetExceptionCode();
459 }
460 _SEH_END;
461
462 /* If we referenced the process, dereference it */
463 if(ProcessInformationClass != ProcessCookie) ObDereferenceObject(Process);
464 return Status;
465 }
466
467 /*
468 * @unimplemented
469 */
470 NTSTATUS
471 NTAPI
472 NtSetInformationProcess(IN HANDLE ProcessHandle,
473 IN PROCESSINFOCLASS ProcessInformationClass,
474 IN PVOID ProcessInformation,
475 IN ULONG ProcessInformationLength)
476 {
477 PEPROCESS Process;
478 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
479 ACCESS_MASK Access;
480 NTSTATUS Status = STATUS_SUCCESS;
481 PAGED_CODE();
482
483 /* Verify Information Class validity */
484 Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
485 PsProcessInfoClass,
486 RTL_NUMBER_OF(PsProcessInfoClass),
487 ProcessInformation,
488 ProcessInformationLength,
489 PreviousMode);
490 if(!NT_SUCCESS(Status))
491 {
492 DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status);
493 return Status;
494 }
495
496 switch(ProcessInformationClass)
497 {
498 case ProcessSessionInformation:
499 Access = PROCESS_SET_INFORMATION | PROCESS_SET_SESSIONID;
500 break;
501 case ProcessExceptionPort:
502 Access = PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME;
503 break;
504
505 default:
506 Access = PROCESS_SET_INFORMATION;
507 break;
508 }
509
510 Status = ObReferenceObjectByHandle(ProcessHandle,
511 Access,
512 PsProcessType,
513 PreviousMode,
514 (PVOID*)&Process,
515 NULL);
516 if (!NT_SUCCESS(Status)) return(Status);
517
518 switch (ProcessInformationClass)
519 {
520 case ProcessQuotaLimits:
521 case ProcessBasePriority:
522 case ProcessRaisePriority:
523 Status = STATUS_NOT_IMPLEMENTED;
524 break;
525
526 case ProcessExceptionPort:
527 {
528 HANDLE PortHandle = NULL;
529
530 /* make a safe copy of the buffer on the stack */
531 _SEH_TRY
532 {
533 PortHandle = *(PHANDLE)ProcessInformation;
534 Status = STATUS_SUCCESS;
535 }
536 _SEH_HANDLE
537 {
538 Status = _SEH_GetExceptionCode();
539 }
540 _SEH_END;
541
542 if(NT_SUCCESS(Status))
543 {
544 PEPORT ExceptionPort;
545
546 /* in case we had success reading from the buffer, verify the provided
547 * LPC port handle
548 */
549 Status = ObReferenceObjectByHandle(PortHandle,
550 0,
551 LpcPortObjectType,
552 PreviousMode,
553 (PVOID)&ExceptionPort,
554 NULL);
555 if(NT_SUCCESS(Status))
556 {
557 /* lock the process to be thread-safe! */
558
559 Status = PsLockProcess(Process, FALSE);
560 if(NT_SUCCESS(Status))
561 {
562 /*
563 * according to "NT Native API" documentation, setting the exception
564 * port is only permitted once!
565 */
566 if(Process->ExceptionPort == NULL)
567 {
568 /* keep the reference to the handle! */
569 Process->ExceptionPort = ExceptionPort;
570 Status = STATUS_SUCCESS;
571 }
572 else
573 {
574 ObDereferenceObject(ExceptionPort);
575 Status = STATUS_PORT_ALREADY_SET;
576 }
577 PsUnlockProcess(Process);
578 }
579 else
580 {
581 ObDereferenceObject(ExceptionPort);
582 }
583 }
584 }
585 break;
586 }
587
588 case ProcessAccessToken:
589 {
590 HANDLE TokenHandle = NULL;
591
592 /* make a safe copy of the buffer on the stack */
593 _SEH_TRY
594 {
595 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->Token;
596 Status = STATUS_SUCCESS;
597 }
598 _SEH_HANDLE
599 {
600 Status = _SEH_GetExceptionCode();
601 }
602 _SEH_END;
603
604 if(NT_SUCCESS(Status))
605 {
606 /* in case we had success reading from the buffer, perform the actual task */
607 Status = PspAssignPrimaryToken(Process, TokenHandle);
608 }
609 break;
610 }
611
612 case ProcessDefaultHardErrorMode:
613 {
614 _SEH_TRY
615 {
616 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
617 *(PLONG)ProcessInformation);
618 Status = STATUS_SUCCESS;
619 }
620 _SEH_HANDLE
621 {
622 Status = _SEH_GetExceptionCode();
623 }
624 _SEH_END;
625 break;
626 }
627
628 case ProcessSessionInformation:
629 {
630 PROCESS_SESSION_INFORMATION SessionInfo;
631 Status = STATUS_SUCCESS;
632
633 RtlZeroMemory(&SessionInfo, sizeof(SessionInfo));
634
635 _SEH_TRY
636 {
637 /* copy the structure to the stack */
638 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
639 }
640 _SEH_HANDLE
641 {
642 Status = _SEH_GetExceptionCode();
643 }
644 _SEH_END;
645
646 if(NT_SUCCESS(Status))
647 {
648 /* we successfully copied the structure to the stack, continue processing */
649
650 /*
651 * setting the session id requires the SeTcbPrivilege!
652 */
653 if(!SeSinglePrivilegeCheck(SeTcbPrivilege,
654 PreviousMode))
655 {
656 DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n");
657 /* can't set the session id, bail! */
658 Status = STATUS_PRIVILEGE_NOT_HELD;
659 break;
660 }
661
662 /* FIXME - update the session id for the process token */
663
664 Status = PsLockProcess(Process, FALSE);
665 if(NT_SUCCESS(Status))
666 {
667 Process->Session = SessionInfo.SessionId;
668
669 /* Update the session id in the PEB structure */
670 if(Process->Peb != NULL)
671 {
672 /* we need to attach to the process to make sure we're in the right
673 context to access the PEB structure */
674 KeAttachProcess(&Process->Pcb);
675
676 _SEH_TRY
677 {
678 /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
679
680 Status = STATUS_SUCCESS;
681 }
682 _SEH_HANDLE
683 {
684 Status = _SEH_GetExceptionCode();
685 }
686 _SEH_END;
687
688 KeDetachProcess();
689 }
690
691 PsUnlockProcess(Process);
692 }
693 }
694 break;
695 }
696
697 case ProcessPriorityClass:
698 {
699 PROCESS_PRIORITY_CLASS ppc;
700
701 _SEH_TRY
702 {
703 ppc = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
704 }
705 _SEH_HANDLE
706 {
707 Status = _SEH_GetExceptionCode();
708 }
709 _SEH_END;
710
711 if(NT_SUCCESS(Status))
712 {
713 }
714
715 break;
716 }
717
718 case ProcessLdtInformation:
719 case ProcessLdtSize:
720 case ProcessIoPortHandlers:
721 case ProcessWorkingSetWatch:
722 case ProcessUserModeIOPL:
723 case ProcessEnableAlignmentFaultFixup:
724 case ProcessAffinityMask:
725 Status = STATUS_NOT_IMPLEMENTED;
726 break;
727
728 case ProcessBasicInformation:
729 case ProcessIoCounters:
730 case ProcessTimes:
731 case ProcessPooledUsageAndLimits:
732 case ProcessWx86Information:
733 case ProcessHandleCount:
734 case ProcessWow64Information:
735 case ProcessDebugPort:
736 default:
737 Status = STATUS_INVALID_INFO_CLASS;
738 }
739 ObDereferenceObject(Process);
740 return(Status);
741 }
742
743 /*
744 * @unimplemented
745 */
746 NTSTATUS
747 NTAPI
748 NtSetInformationThread(IN HANDLE ThreadHandle,
749 IN THREADINFOCLASS ThreadInformationClass,
750 IN PVOID ThreadInformation,
751 IN ULONG ThreadInformationLength)
752 {
753 PETHREAD Thread;
754 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
755 NTSTATUS Status = STATUS_SUCCESS;
756 PAGED_CODE();
757
758 DPRINT1("%s called for: %d\n", __FUNCTION__, ThreadInformationClass);
759 /* FIXME: This is REALLY wrong. Some types don't need THREAD_SET_INFORMATION */
760 /* FIXME: We should also check for certain things before doing the reference */
761 Status = ObReferenceObjectByHandle(ThreadHandle,
762 THREAD_SET_INFORMATION,
763 PsThreadType,
764 PreviousMode,
765 (PVOID*)&Thread,
766 NULL);
767 if (NT_SUCCESS(Status))
768 {
769 #if 0
770 switch (ThreadInformationClass)
771 {
772 case ThreadPriority:
773
774 if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY)
775 {
776 Status = STATUS_INVALID_PARAMETER;
777 break;
778 }
779 KeSetPriorityThread(&Thread->Tcb, u.Priority);
780 break;
781
782 case ThreadBasePriority:
783 KeSetBasePriorityThread (&Thread->Tcb, u.Increment);
784 break;
785
786 case ThreadAffinityMask:
787
788 /* Check if this is valid */
789 DPRINT1("%lx, %lx\n", Thread->ThreadsProcess->Pcb.Affinity, u.Affinity);
790 if ((Thread->ThreadsProcess->Pcb.Affinity & u.Affinity) !=
791 u.Affinity)
792 {
793 DPRINT1("Wrong affinity given\n");
794 Status = STATUS_INVALID_PARAMETER;
795 }
796 else
797 {
798 Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity);
799 }
800 break;
801
802 case ThreadImpersonationToken:
803 Status = PsAssignImpersonationToken (Thread, u.Handle);
804 break;
805
806 case ThreadQuerySetWin32StartAddress:
807 Thread->Win32StartAddress = u.Address;
808 break;
809
810 default:
811 /* Shoult never occure if the data table is correct */
812 KEBUGCHECK(0);
813 }
814 #endif
815 ObDereferenceObject (Thread);
816 }
817
818 return Status;
819 }
820
821 /*
822 * @implemented
823 */
824 NTSTATUS
825 NTAPI
826 NtQueryInformationThread(IN HANDLE ThreadHandle,
827 IN THREADINFOCLASS ThreadInformationClass,
828 OUT PVOID ThreadInformation,
829 IN ULONG ThreadInformationLength,
830 OUT PULONG ReturnLength OPTIONAL)
831 {
832 PETHREAD Thread;
833 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
834 NTSTATUS Status = STATUS_SUCCESS;
835 PAGED_CODE();
836
837 DPRINT1("%s called for: %d\n", __FUNCTION__, ThreadInformationClass);
838 Status = ObReferenceObjectByHandle(ThreadHandle,
839 THREAD_QUERY_INFORMATION,
840 PsThreadType,
841 PreviousMode,
842 (PVOID*)&Thread,
843 NULL);
844 if (!NT_SUCCESS(Status)) return Status;
845
846 #if 0
847 switch (ThreadInformationClass)
848 {
849 case ThreadBasicInformation:
850 /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
851 * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
852 * 0. So do the conversion here:
853 * -Gunnar */
854 u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus;
855 u.TBI.TebBaseAddress = (PVOID)Thread->Tcb.Teb;
856 u.TBI.ClientId = Thread->Cid;
857 u.TBI.AffinityMask = Thread->Tcb.Affinity;
858 u.TBI.Priority = Thread->Tcb.Priority;
859 u.TBI.BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
860 break;
861
862 case ThreadTimes:
863 u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
864 u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
865 u.TTI.CreateTime = Thread->CreateTime;
866 /*This works*/
867 u.TTI.ExitTime = Thread->ExitTime;
868 break;
869
870 case ThreadQuerySetWin32StartAddress:
871 u.Address = Thread->Win32StartAddress;
872 break;
873
874 case ThreadPerformanceCount:
875 /* Nebbett says this class is always zero */
876 u.Count.QuadPart = 0;
877 break;
878
879 case ThreadAmILastThread:
880 if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
881 &Thread->ThreadsProcess->ThreadListHead)
882 {
883 u.Last = TRUE;
884 }
885 else
886 {
887 u.Last = FALSE;
888 }
889 break;
890
891 case ThreadIsIoPending:
892 {
893 KIRQL OldIrql;
894
895 /* Raise the IRQL to protect the IRP list */
896 KeRaiseIrql(APC_LEVEL, &OldIrql);
897 u.IsIoPending = !IsListEmpty(&Thread->IrpList);
898 KeLowerIrql(OldIrql);
899 break;
900 }
901
902 default:
903 /* Shoult never occure if the data table is correct */
904 KEBUGCHECK(0);
905 }
906 #endif
907 ObDereferenceObject(Thread);
908 return(Status);
909 }
910 /* EOF */