Blame src/system/ntapi_tt_get_system_directory.c

dd89bb
/********************************************************/
dd89bb
/*  ntapi: Native API core library                      */
64e606
/*  Copyright (C) 2013--2021  SysDeer Technologies, LLC */
dd89bb
/*  Released under GPLv2 and GPLv3; see COPYING.NTAPI.  */
dd89bb
/********************************************************/
dd89bb
dd89bb
#include <psxtypes/psxtypes.h>
dd89bb
#include <pemagine/pemagine.h>
dd89bb
#include <ntapi/nt_sysinfo.h>
dd89bb
#include <ntapi/nt_memory.h>
dd89bb
#include <ntapi/ntapi.h>
dd89bb
#include <ntapi/nt_atomic.h>
dd89bb
#include "ntapi_impl.h"
dd89bb
dd89bb
int32_t __stdcall __ntapi_tt_get_system_directory_native_path(
dd89bb
	__out	nt_mem_sec_name *	buffer,
dd89bb
	__in	uint32_t		buffer_size,
dd89bb
	__in	wchar16_t *		base_name,
dd89bb
	__in	uint32_t		base_name_size,
dd89bb
	__out	nt_unicode_string *	nt_path		__optional)
dd89bb
{
dd89bb
	int32_t			status;
dd89bb
	wchar16_t *		wch_src;
dd89bb
	wchar16_t *		wch_dst;
dd89bb
	wchar16_t *		wch_cap;
dd89bb
	size_t			maxlen_saved;
dd89bb
	size_t			info_size;
dd89bb
dd89bb
	/* validation */
dd89bb
	if (!buffer || !buffer_size)
dd89bb
		return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
	else if (base_name && !base_name_size)
dd89bb
		return NT_STATUS_INVALID_PARAMETER_MIX;
dd89bb
dd89bb
	/* init buffer */
dd89bb
	buffer->section_name.strlen = 0;
dd89bb
	buffer->section_name.maxlen = (uint16_t)(buffer_size - sizeof(nt_unicode_string));
dd89bb
	buffer->section_name.buffer = buffer->section_name_buffer;
dd89bb
dd89bb
	maxlen_saved = buffer->section_name.maxlen;
dd89bb
	info_size    = 0;
dd89bb
dd89bb
	status = __ntapi->zw_query_virtual_memory(
dd89bb
		NT_CURRENT_PROCESS_HANDLE,
dd89bb
		pe_get_ntdll_module_handle(),
dd89bb
		NT_MEMORY_SECTION_NAME,
dd89bb
		buffer,
dd89bb
		buffer_size,
dd89bb
		&info_size);
dd89bb
dd89bb
	if (status != NT_STATUS_SUCCESS)
dd89bb
		return status;
dd89bb
dd89bb
	/* find directory portion */
dd89bb
	wch_dst = buffer->section_name.buffer + (buffer->section_name.strlen / sizeof(wchar16_t));
dd89bb
	wch_dst--;
dd89bb
dd89bb
	while ((*wch_dst != '\\') && (wch_dst > buffer->section_name.buffer))
dd89bb
		wch_dst--;
dd89bb
dd89bb
	if (wch_dst == buffer->section_name.buffer)
dd89bb
		return NT_STATUS_INTERNAL_ERROR;
dd89bb
dd89bb
	/* base_name */
dd89bb
	if (base_name) {
dd89bb
		wch_dst++;
dd89bb
		wch_src	= base_name;
dd89bb
		wch_cap = (wchar16_t *)((uintptr_t)wch_dst + base_name_size);
dd89bb
dd89bb
		if ((uintptr_t)wch_cap - (uintptr_t)(buffer->section_name.buffer) > maxlen_saved)
dd89bb
			return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
dd89bb
		while (wch_dst < wch_cap) {
dd89bb
			*wch_dst = *wch_src;
dd89bb
			wch_dst++;
dd89bb
			wch_src++;
dd89bb
		}
dd89bb
	}
dd89bb
dd89bb
	/* null termination */
dd89bb
	*wch_dst = 0;
dd89bb
dd89bb
	/* nt_path */
dd89bb
	if (nt_path)
dd89bb
		__ntapi->rtl_init_unicode_string(
dd89bb
			nt_path,
dd89bb
			buffer->section_name.buffer);
dd89bb
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall __ntapi_tt_get_system_directory_handle(
dd89bb
	__out	void **			hsysdir,
dd89bb
	__out	nt_mem_sec_name *	buffer		__optional,
dd89bb
	__in	uint32_t		buffer_size	__optional)
dd89bb
{
dd89bb
	int32_t			status;
dd89bb
	nt_oa			oa;
dd89bb
	nt_iosb			iosb;
dd89bb
	nt_unicode_string	path;
dd89bb
	char			_buffer[256];
dd89bb
dd89bb
	/* validation */
dd89bb
	if (!hsysdir)
dd89bb
		return NT_STATUS_INVALID_PARAMETER_1;
dd89bb
	else if (buffer_size && buffer_size < 0x20)
dd89bb
		return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
dd89bb
	/* buffer */
dd89bb
	if (!buffer) {
dd89bb
		buffer		= (nt_mem_sec_name *)_buffer;
dd89bb
		buffer_size	= sizeof(_buffer);
dd89bb
		__ntapi->tt_aligned_block_memset(buffer,0,sizeof(buffer));
dd89bb
	}
dd89bb
dd89bb
	/* sysdir path */
dd89bb
	status = __ntapi_tt_get_system_directory_native_path(
dd89bb
		buffer,
dd89bb
		buffer_size,
dd89bb
		(wchar16_t *)0,
dd89bb
		0,
dd89bb
		&path);
dd89bb
dd89bb
	if (status != NT_STATUS_SUCCESS)
dd89bb
		return status;
dd89bb
dd89bb
	/* oa */
dd89bb
	oa.len = sizeof(nt_oa);
dd89bb
	oa.root_dir = (void *)0;
dd89bb
	oa.obj_name = &pat;;
dd89bb
	oa.obj_attr = 0;
dd89bb
	oa.sec_desc = 0;
dd89bb
	oa.sec_qos = 0;
dd89bb
dd89bb
	/* open file/folder */
dd89bb
	status = __ntapi->zw_open_file(
dd89bb
		hsysdir,
dd89bb
		NT_SEC_SYNCHRONIZE | NT_FILE_READ_ATTRIBUTES | NT_FILE_READ_ACCESS,
dd89bb
		&oa,
dd89bb
		&iosb,
dd89bb
		NT_FILE_SHARE_READ | NT_FILE_SHARE_WRITE,
dd89bb
		NT_FILE_DIRECTORY_FILE | NT_FILE_SYNCHRONOUS_IO_ALERT);
dd89bb
dd89bb
	return status;
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall __ntapi_tt_get_system_directory_dos_path(
dd89bb
	__in	void *			hsysdir		__optional,
dd89bb
	__out	wchar16_t *		buffer,
dd89bb
	__in	uint32_t		buffer_size,
dd89bb
	__in	wchar16_t *		base_name,
dd89bb
	__in	uint32_t		base_name_size,
dd89bb
	__out	nt_unicode_string *	nt_path		__optional)
dd89bb
{
dd89bb
	int32_t			status;
dd89bb
	nt_statfs		statfs;
dd89bb
	wchar16_t *		wch;
dd89bb
	wchar16_t *		wch_src;
dd89bb
	wchar16_t *		wch_cap;
dd89bb
	nt_iosb			iosb;
dd89bb
	nt_fni *		fni;
dd89bb
	uint32_t		fni_length;
dd89bb
dd89bb
	/* validation */
dd89bb
	if (!buffer)
dd89bb
		return NT_STATUS_INVALID_PARAMETER_2;
dd89bb
dd89bb
	/* hsysdir */
dd89bb
	if (!hsysdir) {
dd89bb
		status = __ntapi_tt_get_system_directory_handle(
dd89bb
			&hsysdir,
dd89bb
			(nt_mem_sec_name *)buffer,
dd89bb
			buffer_size);
dd89bb
dd89bb
		if (status != NT_STATUS_SUCCESS)
dd89bb
			return status;
dd89bb
	}
dd89bb
dd89bb
	/* statfs */
dd89bb
	status = __ntapi->tt_statfs(
dd89bb
			hsysdir,
d8b407
			&statfs,sizeof(statfs),
d8b407
			(uintptr_t *)buffer,buffer_size,
dd89bb
			NT_STATFS_DOS_DRIVE_LETTER);
dd89bb
dd89bb
	if (status != NT_STATUS_SUCCESS)
dd89bb
		return status;
dd89bb
dd89bb
	/* dos path name (always shorter than the native path, so buffer_size must be ok) */
dd89bb
	wch = buffer;
dd89bb
	*wch = '\\'; wch++;
dd89bb
	*wch = '?';  wch++;
dd89bb
	*wch = '?';  wch++;
dd89bb
	*wch = '\\'; wch++;
dd89bb
	*wch = statfs.nt_drive_letter; wch++;
dd89bb
	*wch = ':';  wch++;
dd89bb
dd89bb
	/* alignment */
dd89bb
	fni  = (nt_fni *)((uintptr_t)buffer + 0x10);
dd89bb
dd89bb
	status = __ntapi->zw_query_information_file(
dd89bb
		hsysdir,
dd89bb
		&iosb,
dd89bb
		fni,
dd89bb
		buffer_size - 8 * sizeof(wchar16_t),
dd89bb
		NT_FILE_NAME_INFORMATION);
dd89bb
dd89bb
	if (status != NT_STATUS_SUCCESS)
dd89bb
		return status;
dd89bb
dd89bb
	/* fni->file_name_length: save */
dd89bb
	fni_length = fni->file_name_length;
dd89bb
dd89bb
	/* overwrite */
dd89bb
	wch_src  = fni->file_name;
dd89bb
	wch_cap  = (wchar16_t *)((uintptr_t)wch_src + fni_length);
dd89bb
dd89bb
	while (wch_src < wch_cap) {
dd89bb
		*wch = *wch_src;
dd89bb
		wch++;
dd89bb
		wch_src++;
dd89bb
	}
dd89bb
dd89bb
	/* ultimate path separator */
dd89bb
	*wch = '\\'; wch++;
dd89bb
dd89bb
	/* base_name */
dd89bb
	if (base_name) {
dd89bb
		wch_src	= base_name;
dd89bb
		wch_cap = (wchar16_t *)((uintptr_t)wch + base_name_size);
dd89bb
dd89bb
		if ((uintptr_t)wch_cap - (uintptr_t)buffer - sizeof(wchar16_t) > buffer_size)
dd89bb
			return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
dd89bb
		while (wch < wch_cap) {
dd89bb
			*wch = *wch_src;
dd89bb
			wch++;
dd89bb
			wch_src++;
dd89bb
		}
dd89bb
	}
dd89bb
dd89bb
	/* null termination */
dd89bb
	*wch = 0;
dd89bb
dd89bb
	/* nt_path */
dd89bb
	if (nt_path)
dd89bb
		__ntapi->rtl_init_unicode_string(
dd89bb
			nt_path,
dd89bb
			buffer);
dd89bb
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}