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