|
|
dd89bb |
/********************************************************/
|
|
|
dd89bb |
/* ntapi: Native API core library */
|
|
|
dd89bb |
/* Copyright (C) 2013,2014,2015 Z. Gilboa */
|
|
|
dd89bb |
/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
|
|
|
dd89bb |
/********************************************************/
|
|
|
dd89bb |
|
|
|
dd89bb |
#include <psxtypes/psxtypes.h>
|
|
|
dd89bb |
#include <pemagine/pemagine.h>
|
|
|
dd89bb |
#include <ntapi/ntapi.h>
|
|
|
dd89bb |
#include "ntapi_impl.h"
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
/**
|
|
|
dd89bb |
* rules for parsing the process's command line arguments
|
|
|
dd89bb |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* delimiters:
|
|
|
dd89bb |
* -----------
|
|
|
dd89bb |
* + white space (ascii 0x20)
|
|
|
dd89bb |
* + horizontal tab (ascii 0x09)
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* quoted strings, and special characters
|
|
|
dd89bb |
* --------------------------------------
|
|
|
dd89bb |
* + delimiter characters within a quoted string ("string with white space",
|
|
|
dd89bb |
* or string" with white "space), stand for their literal respective
|
|
|
dd89bb |
* characters.
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* + a backslash followed by a double quote (\") stands for a literal
|
|
|
dd89bb |
* double quote.
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* + unless followed by a double quote, a backslash is just a (literal)
|
|
|
dd89bb |
* backslash.
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* + when followed by a double quotation mark, an even sequence of 2 or
|
|
|
dd89bb |
* more backslashes (2n) should be interpreted as a sequence of n literal
|
|
|
dd89bb |
* backslashes. The double quotation mark then designates the start
|
|
|
dd89bb |
* or end of a double quoted string.
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* + when followed by a double quotation mark, an odd sequence of 2 or
|
|
|
dd89bb |
* more backslashes (2n+1) should be interpreted as a sequence of n
|
|
|
dd89bb |
* literal backslashes, followed by a single literal double quote.
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* + if found within a double quoted string, a sequence of two double
|
|
|
dd89bb |
* quotation marks should be interpreted as a single literal double
|
|
|
dd89bb |
* quote.
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* + balanced nesting of syntactic double quotes is permitted.
|
|
|
dd89bb |
*
|
|
|
dd89bb |
**/
|
|
|
dd89bb |
|
|
|
dd89bb |
/* free-standing process runtime data */
|
|
|
dd89bb |
static nt_runtime_data __rtdata;
|
|
|
dd89bb |
|
|
|
dd89bb |
int32_t __stdcall __ntapi_tt_parse_cmd_line_args_utf16(
|
|
|
dd89bb |
__in wchar16_t * cmd_line,
|
|
|
dd89bb |
__out int * arg_count,
|
|
|
dd89bb |
__in wchar16_t * args_buffer,
|
|
|
dd89bb |
__in size_t args_buffer_len,
|
|
|
dd89bb |
__out size_t * args_bytes_written __optional,
|
|
|
dd89bb |
__in wchar16_t ** argv_buffer,
|
|
|
dd89bb |
__in size_t argv_buffer_len,
|
|
|
dd89bb |
__in uint32_t arg_flags)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
/**
|
|
|
dd89bb |
* parse the command line arguments pointed to by cmd_line,
|
|
|
dd89bb |
* copy the parsed arguments to args_buffer,
|
|
|
dd89bb |
* and return 0 upon success.
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* cmd_line must be a valid pointer to a command line string,
|
|
|
dd89bb |
* and args_buffer, argv_buffer, and arg_count should
|
|
|
dd89bb |
* all be aligned; furthermore, args_buffer_len and
|
|
|
dd89bb |
* and argv_buffer_len must be exact multiples of sizeof(size_t).
|
|
|
dd89bb |
*
|
|
|
dd89bb |
* In case of an error, report failure using the appropriate
|
|
|
dd89bb |
* native status code.
|
|
|
dd89bb |
**/
|
|
|
dd89bb |
|
|
|
dd89bb |
/**
|
|
|
dd89bb |
* UTF-16: no need to fully determine the code point of the
|
|
|
dd89bb |
* current character; all we need to do is validate the
|
|
|
dd89bb |
* character or surrogate pair, and set the value of
|
|
|
dd89bb |
* wch_next accordingly.
|
|
|
dd89bb |
**/
|
|
|
dd89bb |
|
|
|
dd89bb |
#define HORIZONTAL_TAB 0x09
|
|
|
dd89bb |
#define WHITE_SPACE 0x20
|
|
|
dd89bb |
#define DOUBLE_QUOTE 0x22
|
|
|
dd89bb |
#define SINGLE_QUOTE 0x27
|
|
|
dd89bb |
#define BACKSLASH 0x5C
|
|
|
dd89bb |
|
|
|
dd89bb |
#define IS_DELIMITER(x) ((x == HORIZONTAL_TAB) || (x == WHITE_SPACE))
|
|
|
dd89bb |
|
|
|
dd89bb |
#define TEST_ARGS_BUFFER(nbytes) \
|
|
|
dd89bb |
if ((uintptr_t)arg + nbytes \
|
|
|
dd89bb |
> (uintptr_t)args_buffer + args_buffer_len) { \
|
|
|
dd89bb |
return NT_STATUS_BUFFER_TOO_SMALL; \
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
#define ADD_N_BACKSLASHES \
|
|
|
dd89bb |
TEST_ARGS_BUFFER(backslash_count * sizeof(wchar16_t)); \
|
|
|
dd89bb |
for (islash = 0; \
|
|
|
dd89bb |
islash < backslash_count; \
|
|
|
dd89bb |
islash++) { \
|
|
|
dd89bb |
*arg = BACKSLASH; \
|
|
|
dd89bb |
arg++; \
|
|
|
dd89bb |
} \
|
|
|
dd89bb |
backslash_count = 0;
|
|
|
dd89bb |
|
|
|
dd89bb |
#define ADD_SINGLE_WCHAR16_t(x) \
|
|
|
dd89bb |
TEST_ARGS_BUFFER(sizeof(wchar16_t)); \
|
|
|
dd89bb |
*arg = x; \
|
|
|
dd89bb |
arg++;
|
|
|
dd89bb |
|
|
|
dd89bb |
wchar16_t * arg; /* null-terminated, copied to buffer */
|
|
|
dd89bb |
wchar16_t ** parg; /* next pointer in the argv array */
|
|
|
dd89bb |
wchar16_t * wch; /* character being processed */
|
|
|
dd89bb |
wchar16_t * wch_next;
|
|
|
dd89bb |
unsigned int backslash_count;
|
|
|
dd89bb |
unsigned int islash;
|
|
|
dd89bb |
unsigned char quoted_state;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* check parameters for validity and alignment */
|
|
|
dd89bb |
if ((!(uintptr_t)cmd_line) || (*cmd_line == 0))
|
|
|
dd89bb |
/* we require at least one argument */
|
|
|
dd89bb |
return NT_STATUS_INVALID_PARAMETER_1;
|
|
|
dd89bb |
|
|
|
dd89bb |
else if (__NT_IS_MISALIGNED_BUFFER(args_buffer))
|
|
|
dd89bb |
return NT_STATUS_INVALID_PARAMETER_2;
|
|
|
dd89bb |
|
|
|
dd89bb |
else if (__NT_IS_MISALIGNED_LENGTH(args_buffer_len))
|
|
|
dd89bb |
return NT_STATUS_INVALID_PARAMETER_3;
|
|
|
dd89bb |
|
|
|
dd89bb |
else if (__NT_IS_MISALIGNED_BUFFER(argv_buffer))
|
|
|
dd89bb |
return NT_STATUS_INVALID_PARAMETER_5;
|
|
|
dd89bb |
|
|
|
dd89bb |
else if (__NT_IS_MISALIGNED_LENGTH(argv_buffer_len))
|
|
|
dd89bb |
return NT_STATUS_INVALID_PARAMETER_6;
|
|
|
dd89bb |
|
|
|
dd89bb |
else if (__NT_IS_MISALIGNED_BUFFER(arg_count))
|
|
|
dd89bb |
return NT_STATUS_INVALID_PARAMETER_7;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* zero-out the aligned buffers */
|
|
|
dd89bb |
__ntapi->tt_aligned_block_memset(args_buffer,0,args_buffer_len);
|
|
|
dd89bb |
__ntapi->tt_aligned_block_memset(argv_buffer,0,argv_buffer_len);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* initialize */
|
|
|
dd89bb |
wch = cmd_line;
|
|
|
dd89bb |
arg = args_buffer;
|
|
|
dd89bb |
parg = argv_buffer;
|
|
|
dd89bb |
*parg = arg;
|
|
|
dd89bb |
*arg_count = 0;
|
|
|
dd89bb |
quoted_state = 0;
|
|
|
dd89bb |
backslash_count = 0;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* arg points to the first character of a command line argument */
|
|
|
dd89bb |
/* parg points to the next pointer in argv_buffer */
|
|
|
dd89bb |
while (*wch) {
|
|
|
dd89bb |
if (!(quoted_state) && (IS_DELIMITER(*wch))) {
|
|
|
dd89bb |
/* pending backslashes? */
|
|
|
dd89bb |
if (backslash_count)
|
|
|
dd89bb |
ADD_N_BACKSLASHES;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* reached a delimiter outside of a quoted string */
|
|
|
dd89bb |
/* argument: alignment and null-termination */
|
|
|
dd89bb |
arg = (wchar16_t *)((((uintptr_t)arg + sizeof(size_t))
|
|
|
dd89bb |
| (sizeof(size_t) - 1))
|
|
|
dd89bb |
^ (sizeof(size_t) - 1));
|
|
|
dd89bb |
|
|
|
dd89bb |
/* skip this and remaining delimiters */
|
|
|
dd89bb |
wch_next = wch + 1;
|
|
|
dd89bb |
while ((*wch_next) && (IS_DELIMITER(*wch_next)))
|
|
|
dd89bb |
wch_next++;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* keep going? */
|
|
|
dd89bb |
if (*wch_next == 0) {
|
|
|
dd89bb |
/* no more characters to process */
|
|
|
dd89bb |
/* nothing to do */
|
|
|
dd89bb |
} else if ((uintptr_t)parg >= \
|
|
|
dd89bb |
(uintptr_t)argv_buffer \
|
|
|
dd89bb |
+ argv_buffer_len) {
|
|
|
dd89bb |
/* argv_buffer is too small */
|
|
|
dd89bb |
return NT_STATUS_BUFFER_TOO_SMALL;
|
|
|
dd89bb |
} else if ((uintptr_t)arg >= \
|
|
|
dd89bb |
(uintptr_t)args_buffer \
|
|
|
dd89bb |
+ args_buffer_len) {
|
|
|
dd89bb |
/* args_buffer is too small */
|
|
|
dd89bb |
return NT_STATUS_BUFFER_TOO_SMALL;
|
|
|
dd89bb |
} else {
|
|
|
dd89bb |
/* advance parg, set last member */
|
|
|
dd89bb |
parg++;
|
|
|
dd89bb |
*parg = arg;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
} else {
|
|
|
dd89bb |
/* the current character is not a delimiter... */
|
|
|
dd89bb |
/* determine wch_next */
|
|
|
188aac |
if ((*wch < 0xD800) || (*wch >= 0xE000)) {
|
|
|
dd89bb |
/* in the BMP, single 16-bit representation */
|
|
|
dd89bb |
wch_next = wch + 1;
|
|
|
dd89bb |
} else if ((*wch >= 0xD800) && (*wch < 0xDC00)) {
|
|
|
dd89bb |
/* validate surrogate pair */
|
|
|
dd89bb |
wch_next = wch + 1;
|
|
|
dd89bb |
|
|
|
dd89bb |
if ((*wch_next >= 0xDC00) && (*wch_next < 0xE000))
|
|
|
dd89bb |
/* this is a valid surrogate pair */
|
|
|
dd89bb |
wch_next++;
|
|
|
dd89bb |
else
|
|
|
dd89bb |
return NT_STATUS_ILLEGAL_CHARACTER;
|
|
|
dd89bb |
} else
|
|
|
dd89bb |
return NT_STATUS_ILLEGAL_CHARACTER;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* we now know the position of this and the next character */
|
|
|
dd89bb |
/* continue with special cases */
|
|
|
dd89bb |
|
|
|
dd89bb |
if (quoted_state && (*wch == DOUBLE_QUOTE) \
|
|
|
dd89bb |
&& (*wch_next == DOUBLE_QUOTE)) {
|
|
|
dd89bb |
/**
|
|
|
dd89bb |
* two consecutive double quotation marks
|
|
|
dd89bb |
* within a quoted string:
|
|
|
dd89bb |
* add a single quotation mark to the argument
|
|
|
dd89bb |
**/
|
|
|
dd89bb |
ADD_SINGLE_WCHAR16_t(DOUBLE_QUOTE);
|
|
|
dd89bb |
wch_next++;
|
|
|
dd89bb |
} else if (((backslash_count % 2) == 0) \
|
|
|
dd89bb |
&& (*wch == BACKSLASH) \
|
|
|
dd89bb |
&& (*wch_next == DOUBLE_QUOTE)) {
|
|
|
dd89bb |
/* 2n+1 backslashes followed by a double quote */
|
|
|
dd89bb |
backslash_count /= 2;
|
|
|
dd89bb |
/* add n backslashes */
|
|
|
dd89bb |
ADD_N_BACKSLASHES;
|
|
|
dd89bb |
/* add a literal double quotation mark */
|
|
|
dd89bb |
ADD_SINGLE_WCHAR16_t(DOUBLE_QUOTE);
|
|
|
dd89bb |
/* get ready for next character */
|
|
|
dd89bb |
wch_next++;
|
|
|
dd89bb |
} else if (backslash_count && (*wch == DOUBLE_QUOTE)) {
|
|
|
dd89bb |
/* 2n backslashes followed by a double quote */
|
|
|
dd89bb |
backslash_count /= 2;
|
|
|
dd89bb |
/* add n backslashes */
|
|
|
dd89bb |
ADD_N_BACKSLASHES;
|
|
|
dd89bb |
/* turn quoted_state on/off */
|
|
|
dd89bb |
quoted_state = !quoted_state;
|
|
|
dd89bb |
} else if ((*wch == BACKSLASH) \
|
|
|
dd89bb |
&& (*wch_next == BACKSLASH)) {
|
|
|
dd89bb |
/* this is a sequence of two backslashes */
|
|
|
dd89bb |
backslash_count += 2;
|
|
|
dd89bb |
wch_next++;
|
|
|
dd89bb |
} else {
|
|
|
dd89bb |
/* copy pending backslashes as needed */
|
|
|
dd89bb |
if (backslash_count)
|
|
|
dd89bb |
ADD_N_BACKSLASHES;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (*wch == DOUBLE_QUOTE) {
|
|
|
dd89bb |
/* turn quoted_state on/off */
|
|
|
dd89bb |
quoted_state = !quoted_state;
|
|
|
dd89bb |
} else {
|
|
|
dd89bb |
/* copy either two or four bytes */
|
|
|
dd89bb |
ADD_SINGLE_WCHAR16_t(*wch);
|
|
|
dd89bb |
wch++;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* surrogate pair? */
|
|
|
dd89bb |
if (wch < wch_next) {
|
|
|
dd89bb |
ADD_SINGLE_WCHAR16_t(*wch);
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* proceed to the next character (or null termination) */
|
|
|
dd89bb |
wch = wch_next;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* pending backslashes? */
|
|
|
dd89bb |
if (backslash_count)
|
|
|
dd89bb |
ADD_N_BACKSLASHES;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* null termination */
|
|
|
dd89bb |
ADD_SINGLE_WCHAR16_t(0);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* how many arguments did you say? */
|
|
|
dd89bb |
*arg_count = (int)(((uintptr_t)parg - (uintptr_t)argv_buffer)
|
|
|
dd89bb |
/ sizeof(size_t) + 1);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* output bytes written */
|
|
|
dd89bb |
if (args_bytes_written)
|
|
|
dd89bb |
*args_bytes_written = (uintptr_t)arg - (uintptr_t)args_buffer;
|
|
|
dd89bb |
|
|
|
dd89bb |
return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
int32_t __stdcall __ntapi_tt_get_argv_envp_utf16(
|
|
|
dd89bb |
__out int * argc,
|
|
|
dd89bb |
__out wchar16_t *** wargv,
|
|
|
dd89bb |
__out wchar16_t *** wenvp,
|
|
|
dd89bb |
__in uint32_t flags,
|
|
|
dd89bb |
__in void * ext_params __optional,
|
|
|
dd89bb |
__out void * reserved __optional)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
nt_runtime_data * rtdata;
|
|
|
dd89bb |
nt_argv_envp_block_info main_params_internal;
|
|
|
dd89bb |
nt_argv_envp_block_info * main_params;
|
|
|
dd89bb |
nt_get_argv_envp_ext_params * __ext_params;
|
|
|
dd89bb |
ntapi_internals * __internals;
|
|
|
dd89bb |
|
|
|
dd89bb |
unsigned idx;
|
|
|
dd89bb |
int32_t status;
|
|
|
dd89bb |
uintptr_t addr;
|
|
|
dd89bb |
intptr_t offset;
|
|
|
dd89bb |
wchar16_t * wch_s;
|
|
|
dd89bb |
wchar16_t * wch_dst;
|
|
|
dd89bb |
wchar16_t ** wch_p;
|
|
|
dd89bb |
char ** ch_p;
|
|
|
dd89bb |
uintptr_t * psrc;
|
|
|
dd89bb |
uintptr_t * pdst;
|
|
|
dd89bb |
uintptr_t * paligned;
|
|
|
dd89bb |
wchar16_t * pboundary;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* init */
|
|
|
dd89bb |
__internals = __ntapi_internals();
|
|
|
dd89bb |
|
|
|
dd89bb |
/* use internal buffer? */
|
|
|
dd89bb |
if (flags & NT_GET_ARGV_ENVP_USE_CALLER_BUFFER) {
|
|
|
dd89bb |
__ext_params = (nt_get_argv_envp_ext_params *)ext_params;
|
|
|
dd89bb |
main_params = &(__ext_params->argv_envp_block_info);
|
|
|
dd89bb |
} else {
|
|
|
dd89bb |
/* pointers to internal/local structures */
|
|
|
dd89bb |
main_params = &main_params_internal;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* init */
|
|
|
dd89bb |
__ntapi->tt_aligned_block_memset(
|
|
|
dd89bb |
main_params,0,
|
|
|
dd89bb |
sizeof(*main_params));
|
|
|
dd89bb |
|
|
|
dd89bb |
/* use internal buffer */
|
|
|
dd89bb |
main_params->cmd_line = __ntapi_tt_get_cmd_line_utf16();
|
|
|
dd89bb |
main_params->wargv_buffer = __internals->ntapi_img_sec_bss->argv_envp_array;
|
|
|
dd89bb |
main_params->wargv_buffer_len = __NT_BSS_ARGV_BUFFER_SIZE;
|
|
|
dd89bb |
main_params->argv_envp_ptr_total = (int)(main_params->wargv_buffer_len
|
|
|
dd89bb |
/ sizeof(uintptr_t));
|
|
|
dd89bb |
main_params->wargs_buffer = (wchar16_t *)&(__internals->ntapi_img_sec_bss->args_envs_buffer);
|
|
|
dd89bb |
main_params->wargs_buffer_len = __NT_BSS_ARGS_BUFFER_SIZE;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* (__ntapi_parse_cmd_line_args_utf16 will zero-out both buffers) */
|
|
|
dd89bb |
status = __ntapi_tt_parse_cmd_line_args_utf16(
|
|
|
dd89bb |
main_params->cmd_line,
|
|
|
dd89bb |
&main_params->argc,
|
|
|
dd89bb |
main_params->wargs_buffer,
|
|
|
dd89bb |
main_params->wargs_buffer_len,
|
|
|
dd89bb |
&main_params->wargs_bytes_written,
|
|
|
dd89bb |
main_params->wargv_buffer,
|
|
|
dd89bb |
main_params->wargv_buffer_len,
|
|
|
dd89bb |
0);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status) return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* argv[] needs a terminating null pointer */
|
|
|
dd89bb |
if (main_params->argc == main_params->argv_envp_ptr_total)
|
|
|
dd89bb |
return NT_STATUS_BUFFER_TOO_SMALL;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* set idx to the envp[0] array index */
|
|
|
dd89bb |
idx = main_params->argc + 1;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* set wenvp[] to its starting address */
|
|
|
dd89bb |
main_params->wenvp_buffer = &main_params->wargv_buffer[idx];
|
|
|
dd89bb |
|
|
|
dd89bb |
/* update wargv_buffer_len and envp_buffer_len */
|
|
|
dd89bb |
main_params->wenvp_buffer_len = main_params->wargv_buffer_len
|
|
|
dd89bb |
- (idx * sizeof(uintptr_t));
|
|
|
dd89bb |
|
|
|
dd89bb |
main_params->wargv_buffer_len = idx * sizeof(uintptr_t);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* align wenvs at pointer-size boundary */
|
|
|
dd89bb |
main_params->wargs_bytes_written += sizeof(uintptr_t) - 1;
|
|
|
dd89bb |
main_params->wargs_bytes_written /= sizeof(uintptr_t);
|
|
|
dd89bb |
main_params->wargs_bytes_written *= sizeof(uintptr_t);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* book-keeping */
|
|
|
dd89bb |
main_params->wenvs_buffer = main_params->wargs_buffer
|
|
|
dd89bb |
+ main_params->wargs_bytes_written;
|
|
|
dd89bb |
|
|
|
dd89bb |
main_params->wenvs_buffer_len = main_params->wargs_buffer_len
|
|
|
dd89bb |
- main_params->wargs_bytes_written;
|
|
|
dd89bb |
|
|
|
dd89bb |
main_params->wargs_buffer_len = main_params->wargs_bytes_written;
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
/* peb environment block (read-only) */
|
|
|
dd89bb |
wch_s = __ntapi_tt_get_peb_env_block_utf16();
|
|
|
dd89bb |
|
|
|
dd89bb |
if ((!wch_s) || (!*wch_s))
|
|
|
dd89bb |
return NT_STATUS_DLL_INIT_FAILED;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* populate the envp[] array */
|
|
|
dd89bb |
while ((*wch_s) && (idx < main_params->argv_envp_ptr_total)) {
|
|
|
dd89bb |
main_params->envc++;
|
|
|
dd89bb |
wch_p = &(main_params->wargv_buffer[idx]);
|
|
|
dd89bb |
*wch_p = wch_s;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* skip the rest of the environment variable */
|
|
|
dd89bb |
while (*++wch_s);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* advance to the next variable (or final null termination) */
|
|
|
dd89bb |
wch_s++;
|
|
|
dd89bb |
idx++;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* envp[] needs a terminating null pointer */
|
|
|
dd89bb |
if ((*wch_s) && (idx = main_params->argv_envp_ptr_total))
|
|
|
dd89bb |
return NT_STATUS_BUFFER_TOO_SMALL;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* copy environment? */
|
|
|
dd89bb |
if (flags & NT_GET_ARGV_ENVP_COPY_ENVIRONMENT) {
|
|
|
dd89bb |
/* wch_s now points at the final null termination */
|
|
|
dd89bb |
main_params->wenvs_bytes_used =
|
|
|
dd89bb |
((uintptr_t)wch_s
|
|
|
dd89bb |
- (uintptr_t)(*main_params->wenvp_buffer));
|
|
|
dd89bb |
|
|
|
dd89bb |
/* do we have enough room? */
|
|
|
dd89bb |
if (main_params->wenvs_buffer_len < main_params->wenvs_bytes_used)
|
|
|
dd89bb |
return NT_STATUS_BUFFER_TOO_SMALL;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* upper boundary */
|
|
|
dd89bb |
pboundary = ++wch_s;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* you'd expect the peb environment block to be aligned,
|
|
|
dd89bb |
but one can never know... */
|
|
|
dd89bb |
wch_s = *main_params->wenvp_buffer;
|
|
|
dd89bb |
wch_dst = main_params->wenvs_buffer;
|
|
|
dd89bb |
|
|
|
dd89bb |
while ((uintptr_t)wch_s % sizeof(uintptr_t)) {
|
|
|
dd89bb |
*wch_dst = *wch_s;
|
|
|
dd89bb |
wch_s++;
|
|
|
dd89bb |
wch_dst++;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* copy the aligned portion of the environment block */
|
|
|
dd89bb |
addr = (uintptr_t)(pboundary);
|
|
|
dd89bb |
addr /= sizeof(uintptr_t);
|
|
|
dd89bb |
addr *= sizeof(uintptr_t);
|
|
|
dd89bb |
paligned = (uintptr_t *)addr;
|
|
|
dd89bb |
|
|
|
dd89bb |
psrc = (uintptr_t *)wch_s;
|
|
|
dd89bb |
pdst = (uintptr_t *)wch_dst;
|
|
|
dd89bb |
|
|
|
dd89bb |
while (psrc < paligned) {
|
|
|
dd89bb |
*pdst = *psrc;
|
|
|
dd89bb |
psrc++;
|
|
|
dd89bb |
pdst++;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* copy any remaining bytes */
|
|
|
dd89bb |
wch_s = (wchar16_t *)paligned;
|
|
|
dd89bb |
wch_dst = (wchar16_t *)pdst;
|
|
|
dd89bb |
|
|
|
dd89bb |
while (wch_s < pboundary) {
|
|
|
dd89bb |
*wch_dst = *wch_s;
|
|
|
dd89bb |
wch_s++;
|
|
|
dd89bb |
wch_dst++;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* finally, we update the envp[] pointers */
|
|
|
dd89bb |
offset = (intptr_t)main_params->wenvs_buffer
|
|
|
dd89bb |
- (intptr_t)*main_params->wenvp_buffer;
|
|
|
dd89bb |
|
|
|
dd89bb |
wch_p = main_params->wenvp_buffer;
|
|
|
dd89bb |
|
|
|
dd89bb |
while (*wch_p) {
|
|
|
dd89bb |
addr = ((uintptr_t)*wch_p) + offset;
|
|
|
dd89bb |
*wch_p = (wchar16_t *)addr;
|
|
|
dd89bb |
wch_p++;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* (command line arguments always get validated) */
|
|
|
dd89bb |
/* validate the environment block? */
|
|
|
dd89bb |
if (flags & NT_GET_ARGV_ENVP_VALIDATE_UTF16) {
|
|
|
dd89bb |
wch_p = main_params->wenvp_buffer;
|
|
|
dd89bb |
|
|
|
dd89bb |
while (*wch_p) {
|
|
|
dd89bb |
status = __ntapi->uc_validate_unicode_stream_utf16(
|
|
|
dd89bb |
*wch_p,
|
|
|
dd89bb |
0,0,0,0,0);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status != NT_STATUS_SUCCESS)
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
else
|
|
|
dd89bb |
wch_p++;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* once */
|
|
|
dd89bb |
if (!__internals->rtdata) {
|
|
|
dd89bb |
__ntapi->tt_get_runtime_data(
|
|
|
dd89bb |
&__internals->rtdata,
|
|
|
dd89bb |
main_params->wargv_buffer);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (!__internals->rtdata) {
|
|
|
dd89bb |
__internals->rtdata = &__rtdata;
|
|
|
dd89bb |
|
|
|
dd89bb |
if ((status =__ntapi->tt_init_runtime_data(&__rtdata)))
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
} else if ((status =__ntapi->tt_update_runtime_data(__internals->rtdata)))
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
rtdata = __internals->rtdata;
|
|
|
dd89bb |
|
|
|
dd89bb |
rtdata->peb_envc = main_params->envc;
|
|
|
dd89bb |
rtdata->peb_argc = main_params->argc;
|
|
|
dd89bb |
rtdata->peb_wargv = main_params->wargv_buffer;
|
|
|
dd89bb |
rtdata->peb_wenvp = main_params->wenvp_buffer;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* integral wargv, wenvp, argv, envp */
|
|
|
dd89bb |
if (rtdata->wargv) {
|
|
|
dd89bb |
rtdata->wargv += (uintptr_t)rtdata / sizeof(wchar16_t *);
|
|
|
dd89bb |
|
|
|
dd89bb |
for (wch_p=rtdata->wargv; *wch_p; wch_p++)
|
|
|
dd89bb |
*wch_p += (uintptr_t)rtdata / sizeof(wchar16_t);
|
|
|
dd89bb |
};
|
|
|
dd89bb |
|
|
|
dd89bb |
if (rtdata->wenvp) {
|
|
|
dd89bb |
rtdata->wenvp += (uintptr_t)rtdata / sizeof(wchar16_t *);
|
|
|
dd89bb |
|
|
|
dd89bb |
for (wch_p=rtdata->wenvp; *wch_p; wch_p++)
|
|
|
dd89bb |
*wch_p += (uintptr_t)rtdata / sizeof(wchar16_t);
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
if (rtdata->argv) {
|
|
|
dd89bb |
rtdata->argv += (uintptr_t)rtdata / sizeof(char *);
|
|
|
dd89bb |
|
|
|
dd89bb |
for (ch_p=rtdata->argv; *ch_p; ch_p++)
|
|
|
dd89bb |
*ch_p += (uintptr_t)rtdata;
|
|
|
dd89bb |
|
|
|
dd89bb |
rtdata->argc = (int32_t)(ch_p - rtdata->argv);
|
|
|
dd89bb |
};
|
|
|
dd89bb |
|
|
|
dd89bb |
if (rtdata->envp) {
|
|
|
dd89bb |
rtdata->envp += (uintptr_t)rtdata / sizeof(char *);
|
|
|
dd89bb |
|
|
|
dd89bb |
for (ch_p=rtdata->envp; *ch_p; ch_p++)
|
|
|
dd89bb |
*ch_p += (uintptr_t)rtdata;
|
|
|
dd89bb |
|
|
|
dd89bb |
rtdata->envc = (int32_t)(ch_p - rtdata->envp);
|
|
|
dd89bb |
};
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* we're good */
|
|
|
dd89bb |
*argc = main_params->argc;
|
|
|
dd89bb |
*wargv = main_params->wargv_buffer;
|
|
|
dd89bb |
*wenvp = main_params->wenvp_buffer;
|
|
|
dd89bb |
|
|
|
dd89bb |
return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
int32_t __stdcall __ntapi_tt_get_argv_envp_utf8(
|
|
|
dd89bb |
__out int * argc,
|
|
|
dd89bb |
__out char *** argv,
|
|
|
dd89bb |
__out char *** envp,
|
|
|
dd89bb |
__in uint32_t flags,
|
|
|
dd89bb |
__in void * ext_params __optional,
|
|
|
dd89bb |
__out void * reserved __optional)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
int32_t status;
|
|
|
dd89bb |
ntapi_internals * __internals;
|
|
|
dd89bb |
|
|
|
dd89bb |
wchar16_t ** wargv;
|
|
|
dd89bb |
wchar16_t ** wenvp;
|
|
|
dd89bb |
uint32_t pcount;
|
|
|
dd89bb |
|
|
|
dd89bb |
nt_get_argv_envp_ext_params __ext_params_internal;
|
|
|
dd89bb |
nt_get_argv_envp_ext_params * __ext_params;
|
|
|
dd89bb |
nt_argv_envp_block_info * main_params;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* use internal buffer? */
|
|
|
dd89bb |
if (flags & NT_GET_ARGV_ENVP_USE_CALLER_BUFFER) {
|
|
|
dd89bb |
__ext_params = (nt_get_argv_envp_ext_params *)ext_params;
|
|
|
dd89bb |
main_params = &__ext_params->argv_envp_block_info;
|
|
|
dd89bb |
} else {
|
|
|
dd89bb |
/* pointers to internal/local structures */
|
|
|
dd89bb |
__ext_params = &__ext_params_internal;
|
|
|
dd89bb |
main_params = &__ext_params->argv_envp_block_info;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* init */
|
|
|
dd89bb |
__ntapi->tt_aligned_block_memset(
|
|
|
dd89bb |
main_params,0,
|
|
|
dd89bb |
sizeof(*main_params));
|
|
|
dd89bb |
|
|
|
dd89bb |
__internals = __ntapi_internals();
|
|
|
dd89bb |
|
|
|
dd89bb |
/* use internal buffer */
|
|
|
dd89bb |
main_params->cmd_line = __ntapi_tt_get_cmd_line_utf16();
|
|
|
dd89bb |
main_params->wargv_buffer = __internals->ntapi_img_sec_bss->argv_envp_array;
|
|
|
dd89bb |
main_params->wargv_buffer_len = __NT_BSS_ARGV_BUFFER_SIZE;
|
|
|
dd89bb |
main_params->argv_envp_ptr_total = (int)(main_params->wargv_buffer_len
|
|
|
dd89bb |
/ sizeof(uintptr_t));
|
|
|
dd89bb |
main_params->wargs_buffer = (wchar16_t *)&(__internals->ntapi_img_sec_bss->args_envs_buffer);
|
|
|
dd89bb |
main_params->wargs_buffer_len = __NT_BSS_ARGS_BUFFER_SIZE;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* start with obtaining the utf-16 environment */
|
|
|
dd89bb |
status = __ntapi->tt_get_argv_envp_utf16(
|
|
|
dd89bb |
argc,
|
|
|
dd89bb |
&wargv,
|
|
|
dd89bb |
&wenvp,
|
|
|
dd89bb |
flags | NT_GET_ARGV_ENVP_USE_CALLER_BUFFER,
|
|
|
dd89bb |
__ext_params,
|
|
|
dd89bb |
reserved);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status) return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* enough pointers left? */
|
|
|
dd89bb |
pcount = main_params->argc + 1 + main_params->envc + 1;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (pcount > (main_params->argv_envp_ptr_total / 2))
|
|
|
dd89bb |
return NT_STATUS_BUFFER_TOO_SMALL;
|
|
|
dd89bb |
else if ((main_params->wenvs_buffer_len - main_params->wenvs_bytes_used)
|
|
|
dd89bb |
< sizeof(uintptr_t))
|
|
|
dd89bb |
return NT_STATUS_BUFFER_TOO_SMALL;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* first args byte should be aligned at pointer-size boundary */
|
|
|
dd89bb |
main_params->wenvs_bytes_used += sizeof(uintptr_t) - 1;
|
|
|
dd89bb |
main_params->wenvs_bytes_used /= sizeof(uintptr_t);
|
|
|
dd89bb |
main_params->wenvs_bytes_used *= sizeof(uintptr_t);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* book-keeping */
|
|
|
dd89bb |
/* block reminder: wargs -- wenvs -- args -- envs */
|
|
|
dd89bb |
main_params->argv = (char **)main_params->wenvp_buffer;
|
|
|
dd89bb |
main_params->argv += main_params->envc + 1;
|
|
|
dd89bb |
|
|
|
dd89bb |
main_params->args_buffer = (char *)main_params->wenvs_buffer;
|
|
|
dd89bb |
main_params->args_buffer += main_params->wenvs_bytes_used;
|
|
|
dd89bb |
|
|
|
dd89bb |
main_params->args_buffer_len = main_params->wenvs_buffer_len
|
|
|
dd89bb |
- main_params->wenvs_bytes_used;
|
|
|
dd89bb |
|
|
|
dd89bb |
main_params->wenvs_buffer_len = main_params->wenvs_bytes_used;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* create a utf-8 argv[] array */
|
|
|
dd89bb |
status = __ntapi_tt_array_convert_utf16_to_utf8(
|
|
|
dd89bb |
main_params->wargv_buffer,
|
|
|
dd89bb |
main_params->argv,
|
|
|
dd89bb |
0,
|
|
|
dd89bb |
main_params->args_buffer,
|
|
|
dd89bb |
main_params->args_buffer_len,
|
|
|
dd89bb |
&main_params->args_bytes_written);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status) return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* first envs byte should be aligned to pointer-size boundary */
|
|
|
dd89bb |
main_params->args_bytes_written += sizeof(uintptr_t) - 1;
|
|
|
dd89bb |
main_params->args_bytes_written /= sizeof(uintptr_t);
|
|
|
dd89bb |
main_params->args_bytes_written *= sizeof(uintptr_t);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* book-keeping */
|
|
|
dd89bb |
main_params->envp = main_params->argv + main_params->argc + 1;
|
|
|
dd89bb |
|
|
|
dd89bb |
main_params->envs_buffer = main_params->args_buffer
|
|
|
dd89bb |
+ main_params->args_bytes_written;
|
|
|
dd89bb |
|
|
|
dd89bb |
main_params->envs_buffer_len = main_params->args_buffer_len
|
|
|
dd89bb |
- main_params->args_bytes_written;
|
|
|
dd89bb |
|
|
|
dd89bb |
main_params->args_buffer_len = main_params->args_bytes_written;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* subsequent streams (if any) should be aligned to pointer-size boundary */
|
|
|
dd89bb |
main_params->envs_bytes_used += sizeof(uintptr_t) - 1;
|
|
|
dd89bb |
main_params->envs_bytes_used /= sizeof(uintptr_t);
|
|
|
dd89bb |
main_params->envs_bytes_used *= sizeof(uintptr_t);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* create a utf-8 envp[] array */
|
|
|
dd89bb |
status = __ntapi_tt_array_convert_utf16_to_utf8(
|
|
|
dd89bb |
main_params->wenvp_buffer,
|
|
|
dd89bb |
main_params->envp,
|
|
|
dd89bb |
0,
|
|
|
dd89bb |
main_params->envs_buffer,
|
|
|
dd89bb |
main_params->envs_buffer_len,
|
|
|
dd89bb |
&main_params->envs_bytes_used);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status) return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* we're good */
|
|
|
dd89bb |
*argc = main_params->argc;
|
|
|
dd89bb |
*argv = main_params->argv;
|
|
|
dd89bb |
*envp = main_params->envp;
|
|
|
dd89bb |
|
|
|
dd89bb |
return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
wchar16_t * __stdcall __ntapi_tt_get_cmd_line_utf16(void)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
nt_peb * peb;
|
|
|
dd89bb |
nt_unicode_string cmd_line;
|
|
|
dd89bb |
|
|
|
dd89bb |
peb = (nt_peb *)pe_get_peb_address();
|
|
|
dd89bb |
|
|
|
dd89bb |
if (peb) {
|
|
|
dd89bb |
cmd_line = peb->process_params->command_line;
|
|
|
dd89bb |
return cmd_line.buffer;
|
|
|
dd89bb |
} else
|
|
|
dd89bb |
return (wchar16_t *)0;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
wchar16_t * __stdcall __ntapi_tt_get_peb_env_block_utf16(void)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
nt_peb * peb;
|
|
|
dd89bb |
|
|
|
dd89bb |
peb = (nt_peb *)pe_get_peb_address();
|
|
|
dd89bb |
|
|
|
dd89bb |
if (peb)
|
|
|
dd89bb |
return peb->process_params->environment;
|
|
|
dd89bb |
else
|
|
|
dd89bb |
return (wchar16_t *)0;
|
|
|
dd89bb |
}
|