Added __PdxProcessDataToProcessParameters()
[reactos.git] / posix / lib / psxdll / misc / pdata.c
1 /* $Id: pdata.c,v 1.2 2002/03/11 20:45:07 hyperion Exp $
2 */
3 /*
4 * COPYRIGHT: See COPYING in the top level directory
5 * PROJECT: ReactOS POSIX+ Subsystem
6 * FILE: subsys/psx/lib/psxdll/misc/pdata.c
7 * PURPOSE: Process data management
8 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
9 * UPDATE HISTORY:
10 * 06/03/2002: Created
11 * 07/03/2002: Added __PdxUnserializeProcessData() (KJK::Hyperion
12 * <noog@libero.it>)
13 * 11/03/2002: Added __PdxProcessDataToProcessParameters()
14 * (KJK::Hyperion <noog@libero.it>)
15 */
16
17 #include <ddk/ntddk.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <psx/fdtable.h>
21 #include <psx/pdata.h>
22 #include <psx/stdlib.h>
23 #include <psx/debug.h>
24
25 NTSTATUS
26 STDCALL
27 __PdxProcessDataToProcessParameters
28 (
29 OUT PRTL_USER_PROCESS_PARAMETERS *ProcessParameters,
30 IN __PPDX_PDATA ProcessData,
31 IN PUNICODE_STRING ImageFile
32 )
33 {
34 UNICODE_STRING wstrEmpty = {0, 0, NULL};
35 UNICODE_STRING wstrCommandLine = {0, 0, NULL};
36 NTSTATUS nErrCode;
37 __fildes_t * fdDescriptor;
38 int i;
39
40 /* TODO: error checking */
41
42 /* build the command line string from argument count and argument vector */
43 if(ProcessData->ArgVect)
44 {
45 BOOL bQuoteArg;
46 BOOL bFirstArg;
47 ANSI_STRING strArgument;
48 PWCHAR pwcBufferTail;
49
50 for(i = 0; i < ProcessData->ArgCount; i ++)
51 {
52 RtlInitAnsiString(&strArgument, ProcessData->ArgVect[i]);
53
54 bFirstArg = (i == 0);
55 bQuoteArg = (strchr(strArgument.Buffer, ' ') != 0);
56
57 /* allocate buffer space for the argument, a blank space if the argument is
58 not the first, and two quotes if the argument contains a space */
59 /* TODO: check this operation for overflow */
60 wstrCommandLine.MaximumLength +=
61 (strArgument.Length + (bFirstArg ? 0 : 1) + (bQuoteArg ? 2 : 0)) *
62 sizeof(WCHAR);
63
64 if(bFirstArg)
65 {
66 wstrCommandLine.Buffer = __malloc(wstrCommandLine.MaximumLength);
67 }
68 else
69 {
70 wstrCommandLine.Buffer =
71 __realloc(wstrCommandLine.Buffer, wstrCommandLine.MaximumLength);
72 }
73
74 /* buffer tail */
75 pwcBufferTail =
76 (PWCHAR)((ULONG)wstrCommandLine.Buffer + wstrCommandLine.Length);
77
78 /* append the separator if the argument isn't the first */
79 if(!bFirstArg)
80 {
81 *pwcBufferTail = L' ';
82 pwcBufferTail ++;
83 }
84
85 /* append the opening quote if the argument contains spaces */
86 if(bQuoteArg)
87 {
88 *pwcBufferTail = L'"';
89 pwcBufferTail ++;
90 }
91
92 mbstowcs(pwcBufferTail, strArgument.Buffer, strArgument.Length);
93
94 /* append closing quote */
95 if(bQuoteArg)
96 {
97 pwcBufferTail = (PWCHAR)((ULONG)pwcBufferTail + strArgument.Length * sizeof(WCHAR));
98 *pwcBufferTail = L'"';
99 }
100
101 wstrCommandLine.Length = wstrCommandLine.MaximumLength;
102 }
103 }
104
105 #ifndef NDEBUG
106 wstrCommandLine.MaximumLength = wstrCommandLine.Length + sizeof(WCHAR);
107 wstrCommandLine.Buffer = __realloc(wstrCommandLine.Buffer, wstrCommandLine.MaximumLength);
108 wstrCommandLine.Buffer[wstrCommandLine.Length / sizeof(WCHAR)] = 0;
109
110 INFO("command line is \"%ls\"\n", wstrCommandLine.Buffer);
111 #endif
112
113 RtlCreateProcessParameters
114 (
115 ProcessParameters,
116 ImageFile,
117 &wstrEmpty,
118 &wstrEmpty,
119 &wstrCommandLine,
120 0,
121 &wstrEmpty,
122 &wstrEmpty,
123 &wstrEmpty,
124 &wstrEmpty
125 );
126
127 /* standard input handle */
128 fdDescriptor = __fdtable_entry_get(&ProcessData->FdTable, STDIN_FILENO);
129
130 if(fdDescriptor != NULL)
131 (*ProcessParameters)->InputHandle = fdDescriptor->FileHandle;
132
133 /* standard output handle */
134 fdDescriptor = __fdtable_entry_get(&ProcessData->FdTable, STDOUT_FILENO);
135
136 if(fdDescriptor != NULL)
137 (*ProcessParameters)->OutputHandle = fdDescriptor->FileHandle;
138
139 /* standard error handle */
140 fdDescriptor = __fdtable_entry_get(&ProcessData->FdTable, STDERR_FILENO);
141
142 if(fdDescriptor != NULL)
143 (*ProcessParameters)->ErrorHandle = fdDescriptor->FileHandle;
144
145 /* POSIX+ and NT environments are incompatible, we set the environment to
146 nothing */
147 (*ProcessParameters)->Environment = NULL;
148
149 (*ProcessParameters)->ConsoleHandle = (PVOID)-1;
150 (*ProcessParameters)->ConsoleFlags = 0;
151
152 return (STATUS_SUCCESS);
153 }
154
155 /* serialize a process data block in a contiguous, page-aligned block, suitable
156 for transfer across processes */
157 NTSTATUS
158 STDCALL
159 __PdxSerializeProcessData
160 (
161 IN __PPDX_PDATA ProcessData,
162 OUT __PPDX_SERIALIZED_PDATA *SerializedProcessData
163 )
164 {
165 __PPDX_SERIALIZED_PDATA pspdProcessData = 0;
166 NTSTATUS nErrCode;
167 PBYTE pBufferTail;
168 ULONG ulAllocSize = sizeof(__PDX_SERIALIZED_PDATA) - 1;
169 size_t *pnArgLengths;
170 size_t *pnEnvVarsLengths;
171 int nEnvVarsCount;
172 int i;
173
174 /* calculate buffer length */
175 /* FIXME please! this is the most inefficient way to do it */
176
177 /* argv */
178 INFO("serializing arguments\n");
179
180 if(ProcessData->ArgVect != 0)
181 {
182 pnArgLengths = __malloc(ProcessData->ArgCount * sizeof(size_t));
183
184 for(i = 0; i < ProcessData->ArgCount; i ++)
185 {
186 int nStrLen;
187
188 if(ProcessData->ArgVect[i] == 0)
189 {
190 INFO("argument %d is NULL\n", i);
191 pnArgLengths[i] = 0;
192 continue;
193 }
194
195 nStrLen = strlen(ProcessData->ArgVect[i]) + 1;
196 ulAllocSize += nStrLen;
197 pnArgLengths[i] = nStrLen;
198
199 INFO
200 (
201 "argument %d: \"%s\", length %d\n",
202 i,
203 ProcessData->ArgVect[i],
204 nStrLen
205 );
206 }
207
208 }
209 else
210 INFO("arguments vector is NULL\n");
211
212 /* environ */
213 pnEnvVarsLengths = NULL;
214 nEnvVarsCount = 0;
215
216 if(ProcessData->Environment == 0)
217 INFO("pointer to environ is NULL\n");
218 else if((ProcessData->Environment) == 0)
219 INFO("environ is NULL\n");
220 else
221 {
222 for(i = 0; *(ProcessData->Environment)[i] != 0; i++)
223 {
224 int nStrLen = strlen(*(ProcessData->Environment)[i]) + 1;
225 ulAllocSize += nStrLen;
226
227 nEnvVarsCount ++;
228 __realloc(pnEnvVarsLengths, nEnvVarsCount * sizeof(size_t));
229 pnEnvVarsLengths[i] = nStrLen;
230
231 INFO
232 (
233 "environment variable %d: \"%s\", length %d\n",
234 i,
235 *(ProcessData->Environment)[i],
236 nStrLen
237 );
238 }
239
240 INFO("(%d environment variables were found)\n", nEnvVarsCount);
241 }
242
243 /* current directory */
244 ulAllocSize += ProcessData->CurDir.Length;
245
246 INFO
247 (
248 "current directory: \"%.*ls\"\n",
249 ProcessData->CurDir.Length / sizeof(WCHAR),
250 ProcessData->CurDir.Buffer
251 );
252
253 /* root directory */
254 ulAllocSize += ProcessData->RootPath.Length;
255
256 INFO
257 (
258 "root directory: \"%.*ls\"\n",
259 ProcessData->RootPath.Length / sizeof(WCHAR),
260 ProcessData->RootPath.Buffer
261 );
262
263 /* file descriptors table */
264 ulAllocSize += sizeof(__fildes_t) * ProcessData->FdTable.AllocatedDescriptors;
265 INFO
266 (
267 "descriptors table contains %d allocated descriptors, combined length %d\n",
268 ProcessData->FdTable.AllocatedDescriptors,
269 sizeof(__fildes_t) * ProcessData->FdTable.AllocatedDescriptors
270 );
271
272 /* extra descriptors data */
273 for(i = 0; ProcessData->FdTable.AllocatedDescriptors; i ++)
274 if(ProcessData->FdTable.Descriptors[i].ExtraData != NULL)
275 {
276 ulAllocSize += ProcessData->FdTable.Descriptors[i].ExtraDataSize;
277
278 INFO
279 (
280 "descriptor %d has %d bytes of associated data\n",
281 i,
282 ProcessData->FdTable.Descriptors[i].ExtraDataSize
283 );
284
285 }
286
287 /* allocate return block */
288 INFO("about to allocate %d bytes\n", ulAllocSize);
289
290 nErrCode = NtAllocateVirtualMemory
291 (
292 NtCurrentProcess(),
293 (PVOID *)&pspdProcessData,
294 0,
295 &ulAllocSize,
296 MEM_COMMIT,
297 PAGE_READWRITE
298 );
299
300 /* failure */
301 if(!NT_SUCCESS(nErrCode))
302 {
303 ERR("NtAllocateVirtualMemory() failed with status 0x%08X\n", nErrCode);
304 __free(pnArgLengths);
305 __free(pnEnvVarsLengths);
306 *SerializedProcessData = 0;
307 return;
308 }
309
310 INFO("%d bytes actually allocated\n", ulAllocSize);
311 pspdProcessData->AllocSize = ulAllocSize;
312
313 /* copy data */
314 /* static data */
315 memcpy(&pspdProcessData->ProcessData, ProcessData, sizeof(__PDX_PDATA));
316
317 /* buffers */
318 pBufferTail = &pspdProcessData->Buffer[0];
319 INFO("buffer tail begins at 0x%08X\n", pBufferTail);
320
321 /* argv */
322 pspdProcessData->ProcessData.ArgVect = 0;
323
324 for(i = 0; i < ProcessData->ArgCount; i ++)
325 {
326 INFO
327 (
328 "copying %d bytes of argument %d (\"%s\") to 0x%08X\n",
329 pnArgLengths[i],
330 i,
331 ProcessData->ArgVect[i],
332 pBufferTail
333 );
334
335 strncpy(pBufferTail, ProcessData->ArgVect[i], pnArgLengths[i]);
336 pBufferTail += pnArgLengths[i];
337
338 INFO
339 (
340 "buffer tail increased by %d bytes, new tail at 0x%08X\n",
341 pnArgLengths[i],
342 pBufferTail
343 );
344
345 }
346
347 __free(pnArgLengths);
348
349 /* environ */
350 pspdProcessData->ProcessData.Environment = (char ***)nEnvVarsCount;
351
352 for(i = 0; i < nEnvVarsCount; i ++)
353 {
354 INFO
355 (
356 "copying %d bytes of environment variable %d (\"%s\") to 0x%08X\n",
357 pnEnvVarsLengths[i],
358 i,
359 ProcessData->Environment[i],
360 pBufferTail
361 );
362
363 strncpy(pBufferTail, *ProcessData->Environment[i], pnEnvVarsLengths[i]);
364 pBufferTail += pnEnvVarsLengths[i];
365
366 INFO
367 (
368 "buffer tail increased by %d bytes, new tail at 0x%08X\n",
369 pnEnvVarsLengths[i],
370 pBufferTail
371 );
372 }
373
374 __free(pnEnvVarsLengths);
375
376 /* current directory */
377 INFO
378 (
379 "copying %d bytes of current directory (\"%.*ls\") to 0x%08X\n",
380 ProcessData->CurDir.Length,
381 ProcessData->CurDir.Length / sizeof(WCHAR),
382 ProcessData->CurDir.Buffer,
383 pBufferTail
384 );
385
386 memcpy(pBufferTail, ProcessData->CurDir.Buffer, ProcessData->CurDir.Length);
387 pBufferTail += ProcessData->CurDir.Length;
388
389 INFO
390 (
391 "buffer tail increased by %d bytes, new tail at 0x%08X\n",
392 ProcessData->CurDir.Length,
393 pBufferTail
394 );
395
396 /* root directory */
397 INFO
398 (
399 "copying %d bytes of root directory (\"%.*ls\") to 0x%08X\n",
400 ProcessData->RootPath.Length,
401 ProcessData->RootPath.Length / sizeof(WCHAR),
402 ProcessData->RootPath.Buffer,
403 pBufferTail
404 );
405
406 memcpy
407 (
408 pBufferTail,
409 ProcessData->RootPath.Buffer,
410 ProcessData->RootPath.Length
411 );
412
413 pBufferTail += ProcessData->RootPath.Length;
414
415 INFO
416 (
417 "buffer tail increased by %d bytes, new tail at 0x%08X\n",
418 ProcessData->RootPath.Length,
419 pBufferTail
420 );
421
422 /* file descriptors table */
423 /* save the offset to the descriptors array */
424 pspdProcessData->ProcessData.FdTable.Descriptors =
425 (PVOID)((ULONG)pBufferTail - (ULONG)pspdProcessData);
426
427 INFO
428 (
429 "descriptors table contains %d allocated descriptors, combined length %d\n",
430 ProcessData->FdTable.AllocatedDescriptors,
431 sizeof(__fildes_t) * ProcessData->FdTable.AllocatedDescriptors
432 );
433
434 memcpy
435 (
436 pBufferTail,
437 ProcessData->FdTable.Descriptors,
438 sizeof(__fildes_t) * ProcessData->FdTable.AllocatedDescriptors
439 );
440
441 pBufferTail +=
442 sizeof(__fildes_t) * ProcessData->FdTable.AllocatedDescriptors;
443
444 INFO
445 (
446 "buffer tail increased by %d bytes, new tail at 0x%08X\n",
447 sizeof(__fildes_t) * ProcessData->FdTable.AllocatedDescriptors,
448 pBufferTail
449 );
450
451 /* extra descriptors data */
452 for(i = 0; ProcessData->FdTable.AllocatedDescriptors; i ++)
453 if(ProcessData->FdTable.Descriptors[i].ExtraData != 0)
454 {
455 INFO
456 (
457 "descriptor %d has %d bytes of associated data\n",
458 i,
459 ProcessData->FdTable.Descriptors[i].ExtraDataSize
460 );
461
462 memcpy
463 (
464 pBufferTail,
465 ProcessData->FdTable.Descriptors[i].ExtraData,
466 ProcessData->FdTable.Descriptors[i].ExtraDataSize
467 );
468
469 pBufferTail += ProcessData->FdTable.Descriptors[i].ExtraDataSize;
470
471 INFO
472 (
473 "buffer tail increased by %d bytes, new tail at 0x%08X\n",
474 ProcessData->FdTable.Descriptors[i].ExtraDataSize,
475 pBufferTail
476 );
477 }
478
479 /* success */
480 *SerializedProcessData = pspdProcessData;
481 }
482
483 /* unserialize a process data block. Dynamic data will be moved into the default
484 heap */
485 NTSTATUS
486 STDCALL
487 __PdxUnserializeProcessData
488 (
489 IN OUT __PPDX_SERIALIZED_PDATA *SerializedProcessData,
490 OUT __PPDX_PDATA *ProcessData OPTIONAL
491 )
492 {
493 int i;
494 int nEnvVarsCount;
495 __PPDX_PDATA ppdReturnBlock;
496 BOOLEAN bInPlace;
497 PBYTE pBufferTail;
498
499 /* no return buffer */
500 if(NULL == ProcessData)
501 {
502 /* perform an in-place conversion */
503 ppdReturnBlock = &((*SerializedProcessData)->ProcessData);
504 bInPlace = TRUE;
505 }
506 else
507 {
508 /* use the provided return buffer */
509 ppdReturnBlock = *ProcessData;
510 bInPlace = FALSE;
511 }
512
513 /* non in-place conversion: copy static data */
514 if(!bInPlace)
515 {
516 memcpy(ppdReturnBlock, *SerializedProcessData, sizeof(*ppdReturnBlock));
517 }
518
519 pBufferTail = &((*SerializedProcessData)->Buffer[0]);
520
521 /* allocate arguments array */
522 ppdReturnBlock->ArgVect = __malloc(ppdReturnBlock->ArgCount * sizeof(char *));
523
524 /* duplicate arguments */
525 for(i = 0; i < ppdReturnBlock->ArgCount; i ++)
526 {
527 int nStrLen = strlen(pBufferTail) + 1;
528 ppdReturnBlock->ArgVect[i] = __malloc(nStrLen);
529 strncpy(ppdReturnBlock->ArgVect[i], pBufferTail, nStrLen);
530 pBufferTail += nStrLen;
531 }
532
533 /* allocate environment array */
534 nEnvVarsCount = ppdReturnBlock->Environment;
535 ppdReturnBlock->Environment = __malloc(nEnvVarsCount * sizeof(char *));
536
537 /* duplicate environment */
538 for(i = 0; i < nEnvVarsCount; i ++)
539 {
540 int nStrLen = strlen(pBufferTail) + 1;
541 ppdReturnBlock->Environment[i] = __malloc(nStrLen);
542 strncpy(ppdReturnBlock->Environment[i], pBufferTail, nStrLen);
543 pBufferTail += nStrLen;
544 }
545
546 /* static buffer for path conversions */
547 ppdReturnBlock->NativePathBuffer.Buffer = __malloc(0xFFFF);
548 ppdReturnBlock->NativePathBuffer.Length = 0;
549 ppdReturnBlock->NativePathBuffer.MaximumLength = 0xFFFF;
550
551 /* current directory */
552 ppdReturnBlock->CurDir.Buffer = __malloc(ppdReturnBlock->CurDir.Length);
553 ppdReturnBlock->CurDir.MaximumLength = ppdReturnBlock->CurDir.Length;
554 memcpy(ppdReturnBlock->CurDir.Buffer, pBufferTail, ppdReturnBlock->CurDir.Length);
555 pBufferTail += ppdReturnBlock->CurDir.Length;
556
557 /* root directory */
558 ppdReturnBlock->RootPath.Buffer = __malloc(ppdReturnBlock->RootPath.Length);
559 ppdReturnBlock->RootPath.MaximumLength = ppdReturnBlock->RootPath.Length;
560 memcpy(ppdReturnBlock->RootPath.Buffer, pBufferTail, ppdReturnBlock->RootPath.Length);
561 pBufferTail += ppdReturnBlock->RootPath.Length;
562
563 /* file descriptors table */
564 ppdReturnBlock->FdTable.Descriptors = __malloc(ppdReturnBlock->FdTable.AllocatedDescriptors * sizeof(__fildes_t));
565 memcpy(ppdReturnBlock->FdTable.Descriptors, pBufferTail, ppdReturnBlock->FdTable.AllocatedDescriptors * sizeof(__fildes_t));
566 pBufferTail += ppdReturnBlock->FdTable.AllocatedDescriptors * sizeof(__fildes_t);
567
568 for(i = 0; i < ppdReturnBlock->FdTable.AllocatedDescriptors; i ++)
569 {
570 if(ppdReturnBlock->FdTable.Descriptors[i].ExtraData != 0)
571 {
572 ppdReturnBlock->FdTable.Descriptors[i].ExtraData = __malloc(ppdReturnBlock->FdTable.Descriptors[i].ExtraDataSize);
573 memcpy(ppdReturnBlock->FdTable.Descriptors[i].ExtraData, pBufferTail, ppdReturnBlock->FdTable.Descriptors[i].ExtraDataSize);
574 pBufferTail += ppdReturnBlock->FdTable.Descriptors[i].ExtraDataSize;
575 }
576 }
577 }
578
579 /* EOF */
580