Blame src/fs/ntapi_tt_mount.c

dd89bb
/********************************************************/
dd89bb
/*  ntapi: Native API core library                      */
4256e2
/*  Copyright (C) 2013--2016  Z. Gilboa                 */
dd89bb
/*  Released under GPLv2 and GPLv3; see COPYING.NTAPI.  */
dd89bb
/********************************************************/
dd89bb
dd89bb
#include <ntapi/nt_object.h>
dd89bb
#include <ntapi/nt_file.h>
dd89bb
#include <ntapi/nt_mount.h>
dd89bb
#include <ntapi/nt_atomic.h>
dd89bb
#include <ntapi/ntapi.h>
dd89bb
#include "ntapi_impl.h"
dd89bb
dd89bb
typedef enum __dos_drive_handle_type {
dd89bb
	__DOS_DRIVE_DEVICE_HANDLE,
dd89bb
	__DOS_DRIVE_ROOT_HANDLE
dd89bb
} _dos_drive_handle_type;
dd89bb
dd89bb
typedef struct __dos_name_buffer {
dd89bb
	wchar16_t	global_prefix[4];
dd89bb
	wchar16_t	dos_letter;
dd89bb
	wchar16_t	colon;
dd89bb
	wchar16_t	root;
dd89bb
	wchar16_t	null_termination;
dd89bb
} _dos_name_buffer;
dd89bb
dd89bb
dd89bb
static int32_t __stdcall __tt_connect_to_mount_point_manager(void)
dd89bb
{
dd89bb
	int32_t			status;
dd89bb
dd89bb
	void *			hdev;
dd89bb
	void *			hdev_prev;
dd89bb
	nt_oa			oa;
dd89bb
	nt_iosb			iosb;
dd89bb
	nt_unicode_string	dev_name;
dd89bb
	uint16_t		dev_name_buffer[] = {
dd89bb
				'\\','?','?','\\',
dd89bb
				'M','o','u','n','t',
dd89bb
				'P','o','i','n','t',
dd89bb
				'M','a','n','a','g','e','r',0};
dd89bb
dd89bb
	dev_name.strlen = sizeof(wchar16_t) * (4+5+5+7);
dd89bb
	dev_name.maxlen = 0;
dd89bb
	dev_name.buffer = dev_name_buffer;
dd89bb
dd89bb
	oa.len		= sizeof(nt_oa);
dd89bb
	oa.root_dir	= (void *)0;
dd89bb
	oa.obj_name	= &dev_name;
dd89bb
	oa.obj_attr	= NT_OBJ_CASE_INSENSITIVE;
dd89bb
	oa.sec_desc	= (nt_sd *)0;
dd89bb
	oa.sec_qos	= (nt_sqos *)0;
dd89bb
dd89bb
	status = __ntapi->zw_create_file(
dd89bb
		&hdev,
dd89bb
		NT_SEC_SYNCHRONIZE | NT_FILE_READ_ATTRIBUTES,
dd89bb
		&oa,
dd89bb
		&iosb,
dd89bb
		0,
dd89bb
		NT_FILE_ATTRIBUTE_NORMAL,
dd89bb
		NT_FILE_SHARE_READ | NT_FILE_SHARE_WRITE,
dd89bb
		NT_FILE_OPEN,
dd89bb
		NT_FILE_NON_DIRECTORY_FILE | NT_FILE_SYNCHRONOUS_IO_NONALERT,
dd89bb
		(void *)0,
dd89bb
		0);
dd89bb
dd89bb
	if (status != NT_STATUS_SUCCESS)
dd89bb
		return status;
dd89bb
dd89bb
	hdev_prev = (void *)at_locked_cas(
dd89bb
		(intptr_t *)&__ntapi_internals()->hdev_mount_point_mgr,
dd89bb
		0,(intptr_t)hdev);
dd89bb
dd89bb
	if (hdev_prev)
dd89bb
		__ntapi->zw_close(hdev);
dd89bb
dd89bb
	return status;
dd89bb
}
dd89bb
dd89bb
dd89bb
static int32_t __stdcall __tt_get_dos_drive_device_or_root_handle(
dd89bb
	__out	void **			hdrive,
dd89bb
	__in	wchar16_t *		drive_letter,
dd89bb
	__in	_dos_drive_handle_type	handle_type)
dd89bb
{
dd89bb
	#define		__common_mode	(NT_FILE_SYNCHRONOUS_IO_ALERT)
dd89bb
	#define		__common_access	(NT_SEC_SYNCHRONIZE \
dd89bb
					| NT_FILE_READ_ATTRIBUTES)
dd89bb
dd89bb
	int32_t			status;
dd89bb
dd89bb
	nt_oa			oa;
dd89bb
	nt_iosb			iosb;
dd89bb
	uint32_t		open_flags;
dd89bb
	uint32_t		access_flags;
dd89bb
	nt_unicode_string	dos_name;
dd89bb
	_dos_name_buffer	dos_name_buffer = {
dd89bb
					{'\\','?','?','\\'},
dd89bb
					'_',':',0,0};
dd89bb
dd89bb
	if (!hdrive || !drive_letter)
dd89bb
		return NT_STATUS_INVALID_PARAMETER;
dd89bb
dd89bb
	if ((*drive_letter>='A') && (*drive_letter<='Z'))
dd89bb
		dos_name_buffer.dos_letter = *drive_letter;
dd89bb
	else if ((*drive_letter>='a') && (*drive_letter<='z'))
dd89bb
		dos_name_buffer.dos_letter = *drive_letter + 'A' - 'a';
dd89bb
	else
dd89bb
		return NT_STATUS_INVALID_PARAMETER_2;
dd89bb
dd89bb
	dos_name.strlen = ((size_t)(&((_dos_name_buffer *)0)->root));
dd89bb
	dos_name.maxlen = 0;
dd89bb
	dos_name.buffer = &(dos_name_buffer.global_prefix[0]);
dd89bb
dd89bb
	switch (handle_type) {
dd89bb
		case __DOS_DRIVE_DEVICE_HANDLE:
dd89bb
			open_flags	= __common_mode;
dd89bb
			access_flags	= __common_access;
dd89bb
			break;
dd89bb
dd89bb
		case __DOS_DRIVE_ROOT_HANDLE:
dd89bb
			open_flags	= __common_mode   | NT_FILE_DIRECTORY_FILE;
dd89bb
			access_flags	= __common_access | NT_FILE_READ_ACCESS;
dd89bb
			dos_name_buffer.root = '\\';
dd89bb
			dos_name.strlen += sizeof(wchar16_t);
dd89bb
			break;
dd89bb
		default:
dd89bb
			open_flags	= 0;
dd89bb
			access_flags	= 0;
dd89bb
			break;
dd89bb
	}
dd89bb
dd89bb
	oa.len		= sizeof(nt_oa);
dd89bb
	oa.root_dir	= (void *)0;
dd89bb
	oa.obj_name	= &dos_name;
dd89bb
	oa.obj_attr	= NT_OBJ_INHERIT;
dd89bb
	oa.sec_desc	= (nt_sd *)0;
dd89bb
	oa.sec_qos	= (nt_sqos *)0;
dd89bb
dd89bb
	status = __ntapi->zw_open_file(
dd89bb
		hdrive,
dd89bb
		access_flags,
dd89bb
		&oa,
dd89bb
		&iosb,
dd89bb
		NT_FILE_SHARE_READ | NT_FILE_SHARE_WRITE,
dd89bb
		open_flags);
dd89bb
dd89bb
	return status;
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall	__ntapi_tt_get_dos_drive_device_handle(
dd89bb
	__out	void **			hdevice,
dd89bb
	__in	wchar16_t *		drive_letter)
dd89bb
{
dd89bb
	return __tt_get_dos_drive_device_or_root_handle(
dd89bb
		hdevice,
dd89bb
		drive_letter,
dd89bb
		__DOS_DRIVE_DEVICE_HANDLE);
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall	__ntapi_tt_get_dos_drive_root_handle(
dd89bb
	__out	void **			hroot,
dd89bb
	__in	wchar16_t *		drive_letter)
dd89bb
{
dd89bb
	return __tt_get_dos_drive_device_or_root_handle(
dd89bb
		hroot,
dd89bb
		drive_letter,
dd89bb
		__DOS_DRIVE_ROOT_HANDLE);
dd89bb
}
dd89bb
dd89bb
dd89bb
dd89bb
int32_t __stdcall	__ntapi_tt_get_dos_drive_device_name(
dd89bb
	__in	void *			hdevice		__optional,
dd89bb
	__in	wchar16_t *		drive_letter	__optional,
dd89bb
	__out	nt_mount_dev_name *	buffer,
dd89bb
	__in	uint32_t		buffer_size)
dd89bb
{
dd89bb
	int32_t			status;
dd89bb
	nt_iosb			iosb;
dd89bb
dd89bb
	if (!hdevice && (status = __tt_get_dos_drive_device_or_root_handle(
dd89bb
			&hdevice,
dd89bb
			drive_letter,
dd89bb
			__DOS_DRIVE_DEVICE_HANDLE)))
dd89bb
		return status;
dd89bb
dd89bb
	return __ntapi->zw_device_io_control_file(
dd89bb
		hdevice,
dd89bb
		(void *)0,
dd89bb
		(nt_io_apc_routine *)0,
dd89bb
		(void *)0,
dd89bb
		&iosb,
dd89bb
		NT_IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
dd89bb
		(void *)0,
dd89bb
		0,
dd89bb
		buffer,
dd89bb
		buffer_size);
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall	__ntapi_tt_get_dos_drive_mount_points(
dd89bb
	__in	void *			hdevice		__optional,
dd89bb
	__in	wchar16_t *		drive_letter	__optional,
dd89bb
	__in	nt_mount_dev_name *	dev_name	__optional,
dd89bb
	__out	void *			buffer,
dd89bb
	__in	uint32_t		buffer_size)
dd89bb
{
dd89bb
	int32_t			status;
dd89bb
	nt_iosb			iosb;
dd89bb
	wchar16_t		dev_name_buffer[64];
dd89bb
	nt_mount_point_param *	dev_mount_point;
dd89bb
	nt_mount_points *	dev_mount_points;
dd89bb
	uintptr_t		addr;
dd89bb
dd89bb
	if (!dev_name) {
dd89bb
		dev_name = (nt_mount_dev_name *)&dev_name_buffer;
dd89bb
		if ((status = __ntapi_tt_get_dos_drive_device_name(
dd89bb
				hdevice,
dd89bb
				drive_letter,
dd89bb
				dev_name,
dd89bb
				sizeof(dev_name_buffer))))
dd89bb
			return status;
dd89bb
	}
dd89bb
dd89bb
	if (buffer_size < sizeof(nt_mount_mgr_mount_point) \
dd89bb
				+ sizeof(nt_mount_dev_name) \
dd89bb
				+ sizeof(dev_name->name_length))
dd89bb
		return NT_STATUS_BUFFER_TOO_SMALL;
dd89bb
dd89bb
	dev_mount_point = (nt_mount_point_param *)buffer;
dd89bb
	dev_mount_point->symlink_name_offset = 0;
dd89bb
	dev_mount_point->symlink_name_length = 0;
dd89bb
	dev_mount_point->unique_id_offset    = 0;
dd89bb
	dev_mount_point->unique_id_length    = 0;
dd89bb
	dev_mount_point->device_name_offset  = ((size_t)(&((nt_mount_point_param *)0)->device_name));
dd89bb
	dev_mount_point->device_name_length  = dev_name->name_length;
dd89bb
	dev_mount_point->mount_points_offset = 0;
dd89bb
dd89bb
	__ntapi->tt_memcpy_utf16(
dd89bb
		dev_mount_point->device_name,
dd89bb
		dev_name->name,
dd89bb
		dev_name->name_length);
dd89bb
dd89bb
	addr = (uintptr_t)(dev_mount_point->device_name) + dev_name->name_length;
dd89bb
	addr += sizeof(uintptr_t) - 1;
dd89bb
	addr /= sizeof(uintptr_t);
dd89bb
	addr *= sizeof(uintptr_t);
dd89bb
	dev_mount_points = (nt_mount_points *)addr;
dd89bb
dd89bb
dd89bb
	if (!__ntapi_internals()->hdev_mount_point_mgr)
dd89bb
		status = __tt_connect_to_mount_point_manager();
dd89bb
dd89bb
	if (!__ntapi_internals()->hdev_mount_point_mgr)
dd89bb
		return status;
dd89bb
dd89bb
dd89bb
	status = __ntapi->zw_device_io_control_file(
dd89bb
		__ntapi_internals()->hdev_mount_point_mgr,
dd89bb
		(void *)0,
dd89bb
		(nt_io_apc_routine *)0,
dd89bb
		(void *)0,
dd89bb
		&iosb,
dd89bb
		NT_IOCTL_MOUNTMGR_QUERY_POINTS,
dd89bb
		dev_mount_point,
dd89bb
		(uint32_t)(uintptr_t)&(((nt_mount_point_param *)0)->device_name) + dev_name->name_length,
dd89bb
		dev_mount_points,
dd89bb
		(uint32_t)((uintptr_t)buffer + buffer_size - addr));
dd89bb
dd89bb
	dev_mount_point->mount_points_offset = (uint16_t)((uintptr_t)addr - (uintptr_t)buffer);
dd89bb
dd89bb
	return status;
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall	__ntapi_tt_dev_mount_points_to_statfs(
dd89bb
	__in		nt_mount_points *	mount_points,
dd89bb
	__in_out	nt_statfs *		statfs)
dd89bb
{
dd89bb
	int32_t				status;
dd89bb
	uint32_t			hash;
dd89bb
	uint32_t			i;
dd89bb
dd89bb
	nt_mount_mgr_mount_point *	mount_point;
dd89bb
	char *				symlink;
dd89bb
dd89bb
	mount_point = mount_points->mount_points;
dd89bb
	statfs->nt_drive_letter = 0;
dd89bb
dd89bb
dd89bb
	for (i = 0; i < mount_points->number; i++, mount_point++) {
dd89bb
		symlink = (char *)mount_points + mount_point->symlink_name_offset;
dd89bb
dd89bb
		/* both prefixes of interest happen to be of the same length */
dd89bb
		hash = __ntapi->tt_buffer_crc32(
dd89bb
			0, symlink, __DOS_DEVICES_PREFIX_LEN);
dd89bb
dd89bb
		if (hash == __DOS_DEVICES_PREFIX_HASH)
dd89bb
			statfs->nt_drive_letter = ((nt_dos_devices_name *)(symlink))->letter;
dd89bb
		else if (hash == __VOLUME_PATH_PREFIX_HASH) {
dd89bb
			status = __ntapi_tt_utf16_string_to_guid(
dd89bb
				(nt_guid_str_utf16 *)(symlink \
dd89bb
					+ __VOLUME_PATH_PREFIX_LEN \
dd89bb
					- sizeof(wchar16_t)),
dd89bb
				&statfs->nt_volume_guid);
dd89bb
dd89bb
			if (status != NT_STATUS_SUCCESS)
dd89bb
				return status;
dd89bb
		}
dd89bb
	}
dd89bb
dd89bb
	return 0;
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall	__ntapi_tt_get_dos_drive_letter_from_device(
dd89bb
	__in	void *			hdevice		__optional,
dd89bb
	__out	wchar16_t *		drive_letter,
dd89bb
	__in	nt_mount_dev_name *	dev_name	__optional,
dd89bb
	__out	void *			buffer,
dd89bb
	__in	uint32_t		buffer_size)
dd89bb
{
dd89bb
	int32_t			status;
dd89bb
	wchar16_t		dev_name_buffer[128];
dd89bb
	nt_statfs		statfs;
dd89bb
	uint32_t		offset;
dd89bb
	nt_mount_points *	mnt_points;
dd89bb
dd89bb
	if (!dev_name) {
dd89bb
		dev_name = (nt_mount_dev_name *)&dev_name_buffer;
dd89bb
		status = __ntapi_tt_get_dos_drive_device_name(
dd89bb
			hdevice,
dd89bb
			(wchar16_t *)0,
dd89bb
			dev_name,
dd89bb
			sizeof(dev_name_buffer));
dd89bb
dd89bb
		if (status != NT_STATUS_SUCCESS)
dd89bb
			return status;
dd89bb
	}
dd89bb
dd89bb
dd89bb
	offset = ((nt_mount_point_param *)buffer)->mount_points_offset;
dd89bb
	mnt_points = (nt_mount_points *)((uintptr_t)buffer + offset);
dd89bb
dd89bb
	status = __ntapi_tt_dev_mount_points_to_statfs(
dd89bb
		mnt_points,
dd89bb
		&statfs);
dd89bb
dd89bb
	if (status != NT_STATUS_SUCCESS)
dd89bb
		return status;
dd89bb
dd89bb
	*drive_letter = statfs.nt_drive_letter;
dd89bb
dd89bb
	return status;
dd89bb
}