Section and general memory manager enhancements including COW
[reactos.git] / reactos / lib / kernel32 / process / create.c
1 /* $Id: create.c,v 1.35 2001/02/10 22:51:08 dwelch Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/proc/proc.c
6 * PURPOSE: Process functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <windows.h>
16 #include <kernel32/proc.h>
17 #include <kernel32/thread.h>
18 #include <wchar.h>
19 #include <string.h>
20 #include <napi/i386/segment.h>
21 #include <ntdll/ldr.h>
22 #include <napi/teb.h>
23 #include <ntdll/base.h>
24 #include <ntdll/rtl.h>
25 #include <csrss/csrss.h>
26 #include <ntdll/csr.h>
27
28 #define NDEBUG
29 #include <kernel32/kernel32.h>
30 #include <kernel32/error.h>
31
32 /* FUNCTIONS ****************************************************************/
33
34 WINBOOL
35 STDCALL
36 CreateProcessA (
37 LPCSTR lpApplicationName,
38 LPSTR lpCommandLine,
39 LPSECURITY_ATTRIBUTES lpProcessAttributes,
40 LPSECURITY_ATTRIBUTES lpThreadAttributes,
41 WINBOOL bInheritHandles,
42 DWORD dwCreationFlags,
43 LPVOID lpEnvironment,
44 LPCSTR lpCurrentDirectory,
45 LPSTARTUPINFOA lpStartupInfo,
46 LPPROCESS_INFORMATION lpProcessInformation
47 )
48 /*
49 * FUNCTION: The CreateProcess function creates a new process and its
50 * primary thread. The new process executes the specified executable file
51 * ARGUMENTS:
52 *
53 * lpApplicationName = Pointer to name of executable module
54 * lpCommandLine = Pointer to command line string
55 * lpProcessAttributes = Process security attributes
56 * lpThreadAttributes = Thread security attributes
57 * bInheritHandles = Handle inheritance flag
58 * dwCreationFlags = Creation flags
59 * lpEnvironment = Pointer to new environment block
60 * lpCurrentDirectory = Pointer to current directory name
61 * lpStartupInfo = Pointer to startup info
62 * lpProcessInformation = Pointer to process information
63 */
64 {
65 UNICODE_STRING ApplicationNameU;
66 UNICODE_STRING CurrentDirectoryU;
67 UNICODE_STRING CommandLineU;
68 ANSI_STRING ApplicationName;
69 ANSI_STRING CurrentDirectory;
70 ANSI_STRING CommandLine;
71 WINBOOL Result;
72
73 DPRINT("CreateProcessA\n");
74
75 RtlInitAnsiString (&CommandLine,
76 lpCommandLine);
77 RtlInitAnsiString (&ApplicationName,
78 (LPSTR)lpApplicationName);
79 RtlInitAnsiString (&CurrentDirectory,
80 (LPSTR)lpCurrentDirectory);
81
82 /* convert ansi (or oem) strings to unicode */
83 if (bIsFileApiAnsi)
84 {
85 RtlAnsiStringToUnicodeString (&CommandLineU,
86 &CommandLine,
87 TRUE);
88 RtlAnsiStringToUnicodeString (&ApplicationNameU,
89 &ApplicationName,
90 TRUE);
91 RtlAnsiStringToUnicodeString (&CurrentDirectoryU,
92 &CurrentDirectory,
93 TRUE);
94 }
95 else
96 {
97 RtlOemStringToUnicodeString (&CommandLineU,
98 &CommandLine,
99 TRUE);
100 RtlOemStringToUnicodeString (&ApplicationNameU,
101 &ApplicationName,
102 TRUE);
103 RtlOemStringToUnicodeString (&CurrentDirectoryU,
104 &CurrentDirectory,
105 TRUE);
106 }
107
108 Result = CreateProcessW (ApplicationNameU.Buffer,
109 CommandLineU.Buffer,
110 lpProcessAttributes,
111 lpThreadAttributes,
112 bInheritHandles,
113 dwCreationFlags,
114 lpEnvironment,
115 (lpCurrentDirectory == NULL) ? NULL : CurrentDirectoryU.Buffer,
116 (LPSTARTUPINFOW)lpStartupInfo,
117 lpProcessInformation);
118
119 RtlFreeUnicodeString (&ApplicationNameU);
120 RtlFreeUnicodeString (&CommandLineU);
121 RtlFreeUnicodeString (&CurrentDirectoryU);
122
123 return Result;
124 }
125
126
127 HANDLE STDCALL KlCreateFirstThread(HANDLE ProcessHandle,
128 LPSECURITY_ATTRIBUTES lpThreadAttributes,
129 DWORD dwStackSize,
130 LPTHREAD_START_ROUTINE lpStartAddress,
131 DWORD dwCreationFlags,
132 LPDWORD lpThreadId)
133 {
134 NTSTATUS Status;
135 HANDLE ThreadHandle;
136 OBJECT_ATTRIBUTES ObjectAttributes;
137 CLIENT_ID ClientId;
138 CONTEXT ThreadContext;
139 INITIAL_TEB InitialTeb;
140 BOOLEAN CreateSuspended = FALSE;
141 PVOID BaseAddress;
142
143 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
144 ObjectAttributes.RootDirectory = NULL;
145 ObjectAttributes.ObjectName = NULL;
146 ObjectAttributes.Attributes = 0;
147 if (lpThreadAttributes != NULL)
148 {
149 if (lpThreadAttributes->bInheritHandle)
150 ObjectAttributes.Attributes = OBJ_INHERIT;
151 ObjectAttributes.SecurityDescriptor =
152 lpThreadAttributes->lpSecurityDescriptor;
153 }
154 ObjectAttributes.SecurityQualityOfService = NULL;
155
156 if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
157 CreateSuspended = TRUE;
158 else
159 CreateSuspended = FALSE;
160
161 /* Allocate thread stack */
162 BaseAddress = NULL;
163 Status = NtAllocateVirtualMemory(ProcessHandle,
164 &BaseAddress,
165 0,
166 (PULONG)&dwStackSize,
167 MEM_COMMIT,
168 PAGE_READWRITE);
169 if (!NT_SUCCESS(Status))
170 {
171 return(NULL);
172 }
173
174 memset(&ThreadContext,0,sizeof(CONTEXT));
175 ThreadContext.Eip = (ULONG)lpStartAddress;
176 ThreadContext.SegGs = USER_DS;
177 ThreadContext.SegFs = USER_DS;
178 ThreadContext.SegEs = USER_DS;
179 ThreadContext.SegDs = USER_DS;
180 ThreadContext.SegCs = USER_CS;
181 ThreadContext.SegSs = USER_DS;
182 ThreadContext.Esp = (ULONG)(BaseAddress + dwStackSize - 20);
183 ThreadContext.EFlags = (1<<1) + (1<<9);
184
185 DPRINT("ThreadContext.Eip %x\n",ThreadContext.Eip);
186
187 Status = NtCreateThread(&ThreadHandle,
188 THREAD_ALL_ACCESS,
189 &ObjectAttributes,
190 ProcessHandle,
191 &ClientId,
192 &ThreadContext,
193 &InitialTeb,
194 CreateSuspended);
195 if (lpThreadId != NULL)
196 {
197 memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
198 }
199
200 return(ThreadHandle);
201 }
202
203 HANDLE KlMapFile(LPCWSTR lpApplicationName,
204 LPCWSTR lpCommandLine)
205 {
206 HANDLE hFile;
207 IO_STATUS_BLOCK IoStatusBlock;
208 UNICODE_STRING ApplicationNameString;
209 OBJECT_ATTRIBUTES ObjectAttributes;
210 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
211 NTSTATUS Status;
212 HANDLE hSection;
213
214 hFile = NULL;
215
216 /*
217 * Find the application name
218 */
219
220 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName,
221 &ApplicationNameString,
222 NULL,
223 NULL))
224 return NULL;
225
226 DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer);
227
228 InitializeObjectAttributes(&ObjectAttributes,
229 &ApplicationNameString,
230 OBJ_CASE_INSENSITIVE,
231 NULL,
232 SecurityDescriptor);
233
234 /*
235 * Try to open the executable
236 */
237
238 Status = NtOpenFile(&hFile,
239 SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
240 &ObjectAttributes,
241 &IoStatusBlock,
242 FILE_SHARE_DELETE|FILE_SHARE_READ,
243 FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
244
245 RtlFreeUnicodeString (&ApplicationNameString);
246
247 if (!NT_SUCCESS(Status))
248 {
249 DPRINT("Failed to open file\n");
250 SetLastErrorByStatus (Status);
251 return(NULL);
252 }
253
254 Status = NtCreateSection(&hSection,
255 SECTION_ALL_ACCESS,
256 NULL,
257 NULL,
258 PAGE_EXECUTE,
259 SEC_IMAGE,
260 hFile);
261 NtClose(hFile);
262
263 if (!NT_SUCCESS(Status))
264 {
265 DPRINT("Failed to create section\n");
266 SetLastErrorByStatus (Status);
267 return(NULL);
268 }
269
270 return(hSection);
271 }
272
273 static NTSTATUS KlInitPeb (HANDLE ProcessHandle,
274 PRTL_USER_PROCESS_PARAMETERS Ppb)
275 {
276 NTSTATUS Status;
277 PVOID PpbBase;
278 ULONG PpbSize;
279 ULONG BytesWritten;
280 ULONG Offset;
281 PVOID ParentEnv = NULL;
282 PVOID EnvPtr = NULL;
283 ULONG EnvSize = 0;
284
285 /* create the Environment */
286 if (Ppb->Environment != NULL)
287 ParentEnv = Ppb->Environment;
288 else if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
289 ParentEnv = NtCurrentPeb()->ProcessParameters->Environment;
290
291 if (ParentEnv != NULL)
292 {
293 MEMORY_BASIC_INFORMATION MemInfo;
294
295 Status = NtQueryVirtualMemory (NtCurrentProcess (),
296 ParentEnv,
297 MemoryBasicInformation,
298 &MemInfo,
299 sizeof(MEMORY_BASIC_INFORMATION),
300 NULL);
301 if (!NT_SUCCESS(Status))
302 {
303 return Status;
304 }
305 EnvSize = MemInfo.RegionSize;
306 }
307 DPRINT("EnvironmentSize %ld\n", EnvSize);
308
309 /* allocate and initialize new environment block */
310 if (EnvSize != 0)
311 {
312 Status = NtAllocateVirtualMemory(ProcessHandle,
313 &EnvPtr,
314 0,
315 &EnvSize,
316 MEM_COMMIT,
317 PAGE_READWRITE);
318 if (!NT_SUCCESS(Status))
319 {
320 return(Status);
321 }
322
323 NtWriteVirtualMemory(ProcessHandle,
324 EnvPtr,
325 ParentEnv,
326 EnvSize,
327 &BytesWritten);
328 }
329
330 /* create the PPB */
331 PpbBase = (PVOID)PEB_STARTUPINFO;
332 PpbSize = Ppb->MaximumLength;
333 Status = NtAllocateVirtualMemory(ProcessHandle,
334 &PpbBase,
335 0,
336 &PpbSize,
337 MEM_COMMIT,
338 PAGE_READWRITE);
339 if (!NT_SUCCESS(Status))
340 {
341 return(Status);
342 }
343
344 DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
345 NtWriteVirtualMemory(ProcessHandle,
346 PpbBase,
347 Ppb,
348 Ppb->MaximumLength,
349 &BytesWritten);
350
351 /* write pointer to environment */
352 Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
353 NtWriteVirtualMemory(ProcessHandle,
354 (PVOID)(PpbBase + Offset),
355 &EnvPtr,
356 sizeof(EnvPtr),
357 &BytesWritten);
358
359 /* write pointer to process parameter block */
360 Offset = FIELD_OFFSET(PEB, ProcessParameters);
361 NtWriteVirtualMemory(ProcessHandle,
362 (PVOID)(PEB_BASE + Offset),
363 &PpbBase,
364 sizeof(PpbBase),
365 &BytesWritten);
366
367 return(STATUS_SUCCESS);
368 }
369
370
371 WINBOOL STDCALL CreateProcessW(LPCWSTR lpApplicationName,
372 LPWSTR lpCommandLine,
373 LPSECURITY_ATTRIBUTES lpProcessAttributes,
374 LPSECURITY_ATTRIBUTES lpThreadAttributes,
375 WINBOOL bInheritHandles,
376 DWORD dwCreationFlags,
377 LPVOID lpEnvironment,
378 LPCWSTR lpCurrentDirectory,
379 LPSTARTUPINFOW lpStartupInfo,
380 LPPROCESS_INFORMATION lpProcessInformation)
381 {
382 HANDLE hSection, hProcess, hThread;
383 NTSTATUS Status;
384 LPTHREAD_START_ROUTINE lpStartAddress = NULL;
385 WCHAR TempCommandLine[256];
386 WCHAR ImagePathName[256];
387 UNICODE_STRING ImagePathName_U;
388 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
389 ULONG retlen;
390 PRTL_USER_PROCESS_PARAMETERS Ppb;
391 UNICODE_STRING CommandLine_U;
392 CSRSS_API_REQUEST CsrRequest;
393 CSRSS_API_REPLY CsrReply;
394 CHAR ImageFileName[8];
395 PWCHAR s;
396 PWCHAR e;
397 ULONG i;
398 ANSI_STRING ProcedureName;
399 UNICODE_STRING CurrentDirectoryW;
400
401 DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n",
402 lpApplicationName,lpCommandLine);
403
404 /*
405 * Store the image file name for the process
406 */
407 s = wcsrchr(lpApplicationName, '\\');
408 if (s == NULL)
409 {
410 s = (PWCHAR)lpApplicationName;
411 }
412 else
413 {
414 s++;
415 }
416 e = wcschr(s, '.');
417 if (e != NULL)
418 {
419 *e = 0;
420 }
421 for (i = 0; i < 8; i++)
422 {
423 ImageFileName[i] = (CHAR)(s[i]);
424 }
425 if (e != NULL)
426 {
427 *e = '.';
428 }
429
430 /*
431 * Process the application name and command line
432 */
433
434 RtlGetFullPathName_U ((LPWSTR)lpApplicationName,
435 256 * sizeof(WCHAR),
436 TempCommandLine,
437 NULL);
438 wcscpy(ImagePathName, TempCommandLine);
439 RtlInitUnicodeString(&ImagePathName_U, ImagePathName);
440
441 if (lpCommandLine != NULL)
442 {
443 wcscat(TempCommandLine, L" ");
444 wcscat(TempCommandLine, lpCommandLine);
445 }
446
447 /* Initialize the current directory string */
448 RtlInitUnicodeString(&CurrentDirectoryW,
449 lpCurrentDirectory);
450
451 /*
452 * Create the PPB
453 */
454
455 RtlInitUnicodeString(&CommandLine_U, TempCommandLine);
456
457 DPRINT("CommandLine_U %S\n", CommandLine_U.Buffer);
458
459 RtlCreateProcessParameters(&Ppb,
460 &ImagePathName_U,
461 NULL,
462 (lpCurrentDirectory == NULL) ? NULL : &CurrentDirectoryW,
463 &CommandLine_U,
464 lpEnvironment,
465 NULL,
466 NULL,
467 NULL,
468 NULL);
469
470 /*
471 * Create a section for the executable
472 */
473
474 hSection = KlMapFile (lpApplicationName, lpCommandLine);
475 if (hSection == NULL)
476 {
477 RtlDestroyProcessParameters (Ppb);
478 return FALSE;
479 }
480
481 /*
482 * Create a new process
483 */
484 Status = NtCreateProcess(&hProcess,
485 PROCESS_ALL_ACCESS,
486 NULL,
487 NtCurrentProcess(),
488 bInheritHandles,
489 hSection,
490 NULL,
491 NULL);
492
493 /*
494 * Get some information about the process
495 */
496 ZwQueryInformationProcess(hProcess,
497 ProcessBasicInformation,
498 &ProcessBasicInfo,
499 sizeof(ProcessBasicInfo),
500 &retlen);
501 DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
502 ProcessBasicInfo.UniqueProcessId);
503 lpProcessInformation->dwProcessId = ProcessBasicInfo.UniqueProcessId;
504
505 /*
506 * Tell the csrss server we are creating a new process
507 */
508 CsrRequest.Type = CSRSS_CREATE_PROCESS;
509 CsrRequest.Data.CreateProcessRequest.NewProcessId =
510 ProcessBasicInfo.UniqueProcessId;
511 CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
512 Status = CsrClientCallServer(&CsrRequest,
513 &CsrReply,
514 sizeof(CSRSS_API_REQUEST),
515 sizeof(CSRSS_API_REPLY));
516 if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
517 {
518 DbgPrint("Failed to tell csrss about new process. Expect trouble.\n");
519 }
520
521 /*
522 * Create Process Environment Block
523 */
524 DPRINT("Creating peb\n");
525
526 Ppb->InputHandle = CsrReply.Data.CreateProcessReply.InputHandle;
527 Ppb->OutputHandle = CsrReply.Data.CreateProcessReply.OutputHandle;;
528 Ppb->ErrorHandle = Ppb->OutputHandle;
529 KlInitPeb(hProcess, Ppb);
530
531 RtlDestroyProcessParameters (Ppb);
532
533 Status = NtSetInformationProcess(hProcess,
534 ProcessImageFileName,
535 ImageFileName,
536 8);
537 /*
538 * Retrieve the start address
539 */
540 DPRINT("Retrieving entry point address\n");
541 RtlInitAnsiString (&ProcedureName, "LdrInitializeThunk");
542 Status = LdrGetProcedureAddress ((PVOID)NTDLL_BASE,
543 &ProcedureName,
544 0,
545 (PVOID*)&lpStartAddress);
546 if (!NT_SUCCESS(Status))
547 {
548 DbgPrint ("LdrGetProcedureAddress failed (Status %x)\n", Status);
549 return (Status);
550 }
551 DPRINT("lpStartAddress 0x%08lx\n", (ULONG)lpStartAddress);
552
553 /*
554 * Create the thread for the kernel
555 */
556 DPRINT("Creating thread for process\n");
557 hThread = KlCreateFirstThread(hProcess,
558 lpThreadAttributes,
559 // Headers.OptionalHeader.SizeOfStackReserve,
560 0x200000,
561 lpStartAddress,
562 dwCreationFlags,
563 &lpProcessInformation->dwThreadId);
564
565 if (hThread == NULL)
566 {
567 return FALSE;
568 }
569
570 lpProcessInformation->hProcess = hProcess;
571 lpProcessInformation->hThread = hThread;
572
573 return TRUE;
574 }
575
576 /* EOF */