From dd89bb8ad4fe184a34b5dbdda237e640fc82121b Mon Sep 17 00:00:00 2001 From: midipix Date: Mon, 27 Jul 2015 04:01:18 -0400 Subject: entered advanced internal development stage. --- src/fs/ntapi_tt_get_file_handle_type.c | 83 ++++++ src/fs/ntapi_tt_istat.c | 155 ++++++++++ src/fs/ntapi_tt_mount.c | 358 +++++++++++++++++++++++ src/fs/ntapi_tt_open_logical_parent_directory.c | 21 ++ src/fs/ntapi_tt_open_physical_parent_directory.c | 69 +++++ src/fs/ntapi_tt_stat.c | 129 ++++++++ src/fs/ntapi_tt_statfs.c | 225 ++++++++++++++ 7 files changed, 1040 insertions(+) create mode 100644 src/fs/ntapi_tt_get_file_handle_type.c create mode 100644 src/fs/ntapi_tt_istat.c create mode 100644 src/fs/ntapi_tt_mount.c create mode 100644 src/fs/ntapi_tt_open_logical_parent_directory.c create mode 100644 src/fs/ntapi_tt_open_physical_parent_directory.c create mode 100644 src/fs/ntapi_tt_stat.c create mode 100644 src/fs/ntapi_tt_statfs.c (limited to 'src/fs') diff --git a/src/fs/ntapi_tt_get_file_handle_type.c b/src/fs/ntapi_tt_get_file_handle_type.c new file mode 100644 index 0000000..e1175a5 --- /dev/null +++ b/src/fs/ntapi_tt_get_file_handle_type.c @@ -0,0 +1,83 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include +#include +#include "ntapi_impl.h" + +typedef int __stdcall winapi_get_console_mode(void * handle, uint32_t * mode); + +int32_t __stdcall __ntapi_tt_get_file_handle_type( + __in void * handle, + __out int32_t * type) +{ + int32_t status; + uint32_t info; + nt_iosb iosb; + nt_fsssi fsssi; + nt_file_directory_information fdi; + nt_file_pipe_information fpi; + nt_object_basic_information obi; + + void * hkernel32; + char str_get_con_mode[32] = "GetConsoleMode"; + winapi_get_console_mode * pfn_get_con_mode; + + /* validation */ + if (!handle) return NT_STATUS_INVALID_HANDLE; + + /* file-system directory? */ + if (!(status = __ntapi->zw_query_information_file( + handle, + &iosb,&fdi,sizeof(fdi), + NT_FILE_DIRECTORY_INFORMATION))) { + *type = NT_FILE_TYPE_DIRECTORY; + return 0; + } + + /* file-system file? */ + if (!(status = __ntapi->zw_query_volume_information_file( + handle, + &iosb,&fsssi,sizeof(fsssi), + NT_FILE_FS_SECTOR_SIZE_INFORMATION))) { + *type = NT_FILE_TYPE_FILE; + return 0; + } + + /* pipe? */ + if (!(status = __ntapi->zw_query_information_file( + handle, + &iosb,&fpi,sizeof(fpi), + NT_FILE_PIPE_INFORMATION))) { + *type = NT_FILE_TYPE_PIPE; + return 0; + } + + + /* csrss? */ + if (!(hkernel32 = pe_get_kernel32_module_handle())) + return NT_STATUS_DLL_INIT_FAILED; + else if (!(pfn_get_con_mode = (winapi_get_console_mode *)pe_get_procedure_address( + hkernel32,str_get_con_mode))) + return NT_STATUS_DLL_INIT_FAILED; + + + /* (console functions return non-zero on success) */ + if ((pfn_get_con_mode(handle,&info))) { + *type = NT_FILE_TYPE_CSRSS; + return 0; + } + + /* invalid handle? */ + if ((status = __ntapi->zw_query_object( + handle,NT_OBJECT_BASIC_INFORMATION, + &obi,sizeof(obi),&info))) + return status; + + /* unknown object */ + *type = NT_FILE_TYPE_UNKNOWN; + return NT_STATUS_SUCCESS; +} diff --git a/src/fs/ntapi_tt_istat.c b/src/fs/ntapi_tt_istat.c new file mode 100644 index 0000000..bd2029d --- /dev/null +++ b/src/fs/ntapi_tt_istat.c @@ -0,0 +1,155 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include +#include +#include +#include +#include +#include "ntapi_impl.h" + +int32_t __stdcall __ntapi_tt_istat( + __in void * hfile, + __in void * hroot __optional, + __in nt_unicode_string * path, + __out nt_istat * istat, + __out uintptr_t * buffer, + __in uint32_t buffer_size, + __in uint32_t open_options, + __in uint32_t flags) +{ + int32_t status; + + nt_oa oa; + nt_iosb iosb; + nt_unicode_string * sdev; + uint32_t hash; + wchar16_t * wch; + wchar16_t * wch_mark; + + /* validaton */ + if (!hfile && !path) + return NT_STATUS_INVALID_HANDLE; + + /* hfile */ + if (!hfile) { + /* oa */ + oa.len = sizeof(nt_oa); + oa.root_dir = hroot; + oa.obj_name = path; + oa.obj_attr = 0; + oa.sec_desc = 0; + oa.sec_qos = 0; + + /* open file/folder */ + status = __ntapi->zw_open_file( + &hfile, + NT_SEC_SYNCHRONIZE | NT_FILE_READ_ATTRIBUTES | NT_FILE_READ_ACCESS, + &oa, + &iosb, + NT_FILE_SHARE_READ | NT_FILE_SHARE_WRITE, + open_options | NT_FILE_SYNCHRONOUS_IO_ALERT); + + if (status != NT_STATUS_SUCCESS) + return status; + + istat->flags_out = NT_STAT_NEW_HANDLE; + } + + istat->hfile = hfile; + istat->flags_in = flags; + + /* file index number */ + status = __ntapi->zw_query_information_file( + hfile, + &iosb, + &istat->fii, + sizeof(istat->fii), + NT_FILE_INTERNAL_INFORMATION); + + if (status != NT_STATUS_SUCCESS) + return status; + + /* attributes & reparse tag information */ + status = __ntapi->zw_query_information_file( + hfile, + &iosb, + &istat->ftagi, + sizeof(istat->ftagi), + NT_FILE_ATTRIBUTE_TAG_INFORMATION); + + if (status != NT_STATUS_SUCCESS) + return status; + + /* TODO: consolidate with statfs */ + /* system-unique device name */ + iosb.info = 0; + status = __ntapi->zw_query_object( + hfile, + NT_OBJECT_NAME_INFORMATION, + buffer, + buffer_size, + (uint32_t *)&iosb.info); + + if (status != NT_STATUS_SUCCESS) + return status; + + sdev = (nt_unicode_string *)buffer; + + if (sdev->strlen < __DEVICE_PATH_PREFIX_LEN) + return NT_STATUS_INVALID_HANDLE; + + hash = __ntapi->tt_buffer_crc32( + 0, + sdev->buffer, + __DEVICE_PATH_PREFIX_LEN); + + if (hash != __DEVICE_PATH_PREFIX_HASH) + return NT_STATUS_INVALID_HANDLE; + + wch_mark = sdev->buffer + __DEVICE_PATH_PREFIX_LEN/sizeof(wchar16_t); + wch = wch_mark; + while (*wch != '\\') wch++; + istat->dev_name_strlen = (uint16_t)((wch - sdev->buffer) * sizeof(uint16_t)); + + istat->dev_name_hash = __ntapi->tt_buffer_crc32( + hash, + wch_mark, + (uintptr_t)wch - (uintptr_t)wch_mark); + + return status; +} + + +int32_t __stdcall __ntapi_tt_validate_fs_handle( + __in void * hfile, + __in uint32_t dev_name_hash, + __in nt_fii fii, + __out uintptr_t * buffer, + __in uint32_t buffer_size) +{ + int32_t status; + nt_istat istat; + + status = __ntapi->tt_istat( + hfile, + (void *)0, + (nt_unicode_string *)0, + &istat, + buffer, + buffer_size, + 0, + NT_ISTAT_DEFAULT); + + if (status) return status; + + if (istat.fii.index_number.quad != fii.index_number.quad) + return NT_STATUS_CONTEXT_MISMATCH; + else if (istat.dev_name_hash != dev_name_hash) + return NT_STATUS_CONTEXT_MISMATCH; + + return NT_STATUS_SUCCESS; +} diff --git a/src/fs/ntapi_tt_mount.c b/src/fs/ntapi_tt_mount.c new file mode 100644 index 0000000..1718750 --- /dev/null +++ b/src/fs/ntapi_tt_mount.c @@ -0,0 +1,358 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include +#include +#include +#include +#include +#include "ntapi_impl.h" + +typedef enum __dos_drive_handle_type { + __DOS_DRIVE_DEVICE_HANDLE, + __DOS_DRIVE_ROOT_HANDLE +} _dos_drive_handle_type; + +typedef struct __dos_name_buffer { + wchar16_t global_prefix[4]; + wchar16_t dos_letter; + wchar16_t colon; + wchar16_t root; + wchar16_t null_termination; +} _dos_name_buffer; + + +static int32_t __stdcall __tt_connect_to_mount_point_manager(void) +{ + int32_t status; + + void * hdev; + void * hdev_prev; + nt_oa oa; + nt_iosb iosb; + nt_unicode_string dev_name; + uint16_t dev_name_buffer[] = { + '\\','?','?','\\', + 'M','o','u','n','t', + 'P','o','i','n','t', + 'M','a','n','a','g','e','r',0}; + + dev_name.strlen = sizeof(wchar16_t) * (4+5+5+7); + dev_name.maxlen = 0; + dev_name.buffer = dev_name_buffer; + + oa.len = sizeof(nt_oa); + oa.root_dir = (void *)0; + oa.obj_name = &dev_name; + oa.obj_attr = NT_OBJ_CASE_INSENSITIVE; + oa.sec_desc = (nt_sd *)0; + oa.sec_qos = (nt_sqos *)0; + + status = __ntapi->zw_create_file( + &hdev, + NT_SEC_SYNCHRONIZE | NT_FILE_READ_ATTRIBUTES, + &oa, + &iosb, + 0, + NT_FILE_ATTRIBUTE_NORMAL, + NT_FILE_SHARE_READ | NT_FILE_SHARE_WRITE, + NT_FILE_OPEN, + NT_FILE_NON_DIRECTORY_FILE | NT_FILE_SYNCHRONOUS_IO_NONALERT, + (void *)0, + 0); + + if (status != NT_STATUS_SUCCESS) + return status; + + hdev_prev = (void *)at_locked_cas( + (intptr_t *)&__ntapi_internals()->hdev_mount_point_mgr, + 0,(intptr_t)hdev); + + if (hdev_prev) + __ntapi->zw_close(hdev); + + return status; +} + + +static int32_t __stdcall __tt_get_dos_drive_device_or_root_handle( + __out void ** hdrive, + __in wchar16_t * drive_letter, + __in _dos_drive_handle_type handle_type) +{ + #define __common_mode (NT_FILE_SYNCHRONOUS_IO_ALERT) + #define __common_access (NT_SEC_SYNCHRONIZE \ + | NT_FILE_READ_ATTRIBUTES) + + int32_t status; + + nt_oa oa; + nt_iosb iosb; + uint32_t open_flags; + uint32_t access_flags; + nt_unicode_string dos_name; + _dos_name_buffer dos_name_buffer = { + {'\\','?','?','\\'}, + '_',':',0,0}; + + if (!hdrive || !drive_letter) + return NT_STATUS_INVALID_PARAMETER; + + if ((*drive_letter>='A') && (*drive_letter<='Z')) + dos_name_buffer.dos_letter = *drive_letter; + else if ((*drive_letter>='a') && (*drive_letter<='z')) + dos_name_buffer.dos_letter = *drive_letter + 'A' - 'a'; + else + return NT_STATUS_INVALID_PARAMETER_2; + + dos_name.strlen = ((size_t)(&((_dos_name_buffer *)0)->root)); + dos_name.maxlen = 0; + dos_name.buffer = &(dos_name_buffer.global_prefix[0]); + + switch (handle_type) { + case __DOS_DRIVE_DEVICE_HANDLE: + open_flags = __common_mode; + access_flags = __common_access; + break; + + case __DOS_DRIVE_ROOT_HANDLE: + open_flags = __common_mode | NT_FILE_DIRECTORY_FILE; + access_flags = __common_access | NT_FILE_READ_ACCESS; + dos_name_buffer.root = '\\'; + dos_name.strlen += sizeof(wchar16_t); + break; + default: + open_flags = 0; + access_flags = 0; + break; + } + + oa.len = sizeof(nt_oa); + oa.root_dir = (void *)0; + oa.obj_name = &dos_name; + oa.obj_attr = NT_OBJ_INHERIT; + oa.sec_desc = (nt_sd *)0; + oa.sec_qos = (nt_sqos *)0; + + status = __ntapi->zw_open_file( + hdrive, + access_flags, + &oa, + &iosb, + NT_FILE_SHARE_READ | NT_FILE_SHARE_WRITE, + open_flags); + + return status; +} + + +int32_t __stdcall __ntapi_tt_get_dos_drive_device_handle( + __out void ** hdevice, + __in wchar16_t * drive_letter) +{ + return __tt_get_dos_drive_device_or_root_handle( + hdevice, + drive_letter, + __DOS_DRIVE_DEVICE_HANDLE); +} + + +int32_t __stdcall __ntapi_tt_get_dos_drive_root_handle( + __out void ** hroot, + __in wchar16_t * drive_letter) +{ + return __tt_get_dos_drive_device_or_root_handle( + hroot, + drive_letter, + __DOS_DRIVE_ROOT_HANDLE); +} + + + +int32_t __stdcall __ntapi_tt_get_dos_drive_device_name( + __in void * hdevice __optional, + __in wchar16_t * drive_letter __optional, + __out nt_mount_dev_name * buffer, + __in uint32_t buffer_size) +{ + int32_t status; + nt_iosb iosb; + + if (!hdevice && (status = __tt_get_dos_drive_device_or_root_handle( + &hdevice, + drive_letter, + __DOS_DRIVE_DEVICE_HANDLE))) + return status; + + return __ntapi->zw_device_io_control_file( + hdevice, + (void *)0, + (nt_io_apc_routine *)0, + (void *)0, + &iosb, + NT_IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, + (void *)0, + 0, + buffer, + buffer_size); +} + + +int32_t __stdcall __ntapi_tt_get_dos_drive_mount_points( + __in void * hdevice __optional, + __in wchar16_t * drive_letter __optional, + __in nt_mount_dev_name * dev_name __optional, + __out void * buffer, + __in uint32_t buffer_size) +{ + int32_t status; + nt_iosb iosb; + wchar16_t dev_name_buffer[64]; + nt_mount_point_param * dev_mount_point; + nt_mount_points * dev_mount_points; + uintptr_t addr; + + if (!dev_name) { + dev_name = (nt_mount_dev_name *)&dev_name_buffer; + if ((status = __ntapi_tt_get_dos_drive_device_name( + hdevice, + drive_letter, + dev_name, + sizeof(dev_name_buffer)))) + return status; + } + + if (buffer_size < sizeof(nt_mount_mgr_mount_point) \ + + sizeof(nt_mount_dev_name) \ + + sizeof(dev_name->name_length)) + return NT_STATUS_BUFFER_TOO_SMALL; + + dev_mount_point = (nt_mount_point_param *)buffer; + dev_mount_point->symlink_name_offset = 0; + dev_mount_point->symlink_name_length = 0; + dev_mount_point->unique_id_offset = 0; + dev_mount_point->unique_id_length = 0; + dev_mount_point->device_name_offset = ((size_t)(&((nt_mount_point_param *)0)->device_name)); + dev_mount_point->device_name_length = dev_name->name_length; + dev_mount_point->mount_points_offset = 0; + + __ntapi->tt_memcpy_utf16( + dev_mount_point->device_name, + dev_name->name, + dev_name->name_length); + + addr = (uintptr_t)(dev_mount_point->device_name) + dev_name->name_length; + addr += sizeof(uintptr_t) - 1; + addr /= sizeof(uintptr_t); + addr *= sizeof(uintptr_t); + dev_mount_points = (nt_mount_points *)addr; + + + if (!__ntapi_internals()->hdev_mount_point_mgr) + status = __tt_connect_to_mount_point_manager(); + + if (!__ntapi_internals()->hdev_mount_point_mgr) + return status; + + + status = __ntapi->zw_device_io_control_file( + __ntapi_internals()->hdev_mount_point_mgr, + (void *)0, + (nt_io_apc_routine *)0, + (void *)0, + &iosb, + NT_IOCTL_MOUNTMGR_QUERY_POINTS, + dev_mount_point, + (uint32_t)(uintptr_t)&(((nt_mount_point_param *)0)->device_name) + dev_name->name_length, + dev_mount_points, + (uint32_t)((uintptr_t)buffer + buffer_size - addr)); + + dev_mount_point->mount_points_offset = (uint16_t)((uintptr_t)addr - (uintptr_t)buffer); + + return status; +} + + +int32_t __stdcall __ntapi_tt_dev_mount_points_to_statfs( + __in nt_mount_points * mount_points, + __in_out nt_statfs * statfs) +{ + int32_t status; + uint32_t hash; + uint32_t i; + + nt_mount_mgr_mount_point * mount_point; + char * symlink; + + mount_point = mount_points->mount_points; + statfs->nt_drive_letter = 0; + + + for (i = 0; i < mount_points->number; i++, mount_point++) { + symlink = (char *)mount_points + mount_point->symlink_name_offset; + + /* both prefixes of interest happen to be of the same length */ + hash = __ntapi->tt_buffer_crc32( + 0, symlink, __DOS_DEVICES_PREFIX_LEN); + + if (hash == __DOS_DEVICES_PREFIX_HASH) + statfs->nt_drive_letter = ((nt_dos_devices_name *)(symlink))->letter; + else if (hash == __VOLUME_PATH_PREFIX_HASH) { + status = __ntapi_tt_utf16_string_to_guid( + (nt_guid_str_utf16 *)(symlink \ + + __VOLUME_PATH_PREFIX_LEN \ + - sizeof(wchar16_t)), + &statfs->nt_volume_guid); + + if (status != NT_STATUS_SUCCESS) + return status; + } + } + + return 0; +} + + +int32_t __stdcall __ntapi_tt_get_dos_drive_letter_from_device( + __in void * hdevice __optional, + __out wchar16_t * drive_letter, + __in nt_mount_dev_name * dev_name __optional, + __out void * buffer, + __in uint32_t buffer_size) +{ + int32_t status; + wchar16_t dev_name_buffer[128]; + nt_statfs statfs; + uint32_t offset; + nt_mount_points * mnt_points; + + if (!dev_name) { + dev_name = (nt_mount_dev_name *)&dev_name_buffer; + status = __ntapi_tt_get_dos_drive_device_name( + hdevice, + (wchar16_t *)0, + dev_name, + sizeof(dev_name_buffer)); + + if (status != NT_STATUS_SUCCESS) + return status; + } + + + offset = ((nt_mount_point_param *)buffer)->mount_points_offset; + mnt_points = (nt_mount_points *)((uintptr_t)buffer + offset); + + status = __ntapi_tt_dev_mount_points_to_statfs( + mnt_points, + &statfs); + + if (status != NT_STATUS_SUCCESS) + return status; + + *drive_letter = statfs.nt_drive_letter; + + return status; +} diff --git a/src/fs/ntapi_tt_open_logical_parent_directory.c b/src/fs/ntapi_tt_open_logical_parent_directory.c new file mode 100644 index 0000000..c20d05b --- /dev/null +++ b/src/fs/ntapi_tt_open_logical_parent_directory.c @@ -0,0 +1,21 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include +#include +#include "ntapi_impl.h" + +int32_t __stdcall __ntapi_tt_open_logical_parent_directory( + __out void ** hparent, + __in void * hdir, + __out uintptr_t * buffer, + __in uint32_t buffer_size, + __in uint32_t desired_access, + __in uint32_t open_options, + __out int32_t * type) +{ + return NT_STATUS_MORE_PROCESSING_REQUIRED; +} diff --git a/src/fs/ntapi_tt_open_physical_parent_directory.c b/src/fs/ntapi_tt_open_physical_parent_directory.c new file mode 100644 index 0000000..68d282b --- /dev/null +++ b/src/fs/ntapi_tt_open_physical_parent_directory.c @@ -0,0 +1,69 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include +#include +#include "ntapi_impl.h" + +int32_t __stdcall __ntapi_tt_open_physical_parent_directory( + __out void ** hparent, + __in void * hdir, + __out uintptr_t * buffer, + __in uint32_t buffer_size, + __in uint32_t desired_access, + __in uint32_t open_options, + __out int32_t * type) +{ + int32_t status; + nt_oa oa; + nt_iosb iosb; + wchar16_t * wch; + nt_unicode_string * path; + uint32_t len; + + path = (nt_unicode_string *)buffer; + + if ((status = __ntapi->zw_query_object( + hdir, + NT_OBJECT_NAME_INFORMATION, + path, + buffer_size, + &len))) + return status; + else if (len == sizeof(nt_unicode_string)) + return NT_STATUS_BAD_FILE_TYPE; + + wch = path->buffer + (path->strlen / sizeof(uint16_t)); + while ((--wch >= path->buffer) && (*wch != '\\')); + + if (wch == path->buffer ) + return NT_STATUS_MORE_PROCESSING_REQUIRED; + + path->strlen = sizeof(uint16_t) * (uint16_t)(wch-path->buffer); + path->maxlen = 0; + + /* oa */ + oa.len = sizeof(nt_oa); + oa.root_dir = 0; + oa.obj_name = path; + oa.obj_attr = 0; + oa.sec_desc = 0; + oa.sec_qos = 0; + + /* default access */ + desired_access = desired_access + ? desired_access + : NT_SEC_SYNCHRONIZE | NT_FILE_READ_ATTRIBUTES | NT_FILE_READ_ACCESS; + + /* open parent directory */ + return __ntapi->zw_open_file( + hparent, + desired_access, + &oa, + &iosb, + NT_FILE_SHARE_READ | NT_FILE_SHARE_WRITE, + open_options | NT_FILE_DIRECTORY_FILE); +} diff --git a/src/fs/ntapi_tt_stat.c b/src/fs/ntapi_tt_stat.c new file mode 100644 index 0000000..51cc55a --- /dev/null +++ b/src/fs/ntapi_tt_stat.c @@ -0,0 +1,129 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include +#include +#include +#include +#include +#include "ntapi_impl.h" + +int32_t __stdcall __ntapi_tt_stat( + __in void * hfile, + __in void * hroot __optional, + __in nt_unicode_string * path, + __out nt_stat * stat, + __out uintptr_t * buffer, + __in uint32_t buffer_size, + __in uint32_t open_options, + __in uint32_t flags) +{ + int32_t status; + nt_oa oa; + nt_iosb iosb; + nt_unicode_string * sdev; + nt_fai * fai; + + /* validation */ + if (!hfile && !path) + return NT_STATUS_INVALID_HANDLE; + + /* hfile */ + if (!hfile) { + /* oa */ + oa.len = sizeof(nt_oa); + oa.root_dir = hroot; + oa.obj_name = path; + oa.obj_attr = 0; + oa.sec_desc = 0; + oa.sec_qos = 0; + + /* open file/folder */ + status = __ntapi->zw_open_file( + &hfile, + NT_SEC_SYNCHRONIZE | NT_FILE_READ_ATTRIBUTES | NT_FILE_READ_ACCESS, + &oa, + &iosb, + NT_FILE_SHARE_READ | NT_FILE_SHARE_WRITE, + open_options | NT_FILE_SYNCHRONOUS_IO_ALERT); + + if (status != NT_STATUS_SUCCESS) + return status; + + stat->flags_out = NT_STAT_NEW_HANDLE; + } + + stat->hfile = hfile; + stat->flags_in = flags; + + /* system-unique device name */ + status = __ntapi->zw_query_information_file( + hfile, + &iosb, + buffer, + buffer_size, + NT_FILE_ALL_INFORMATION); + + if (status != NT_STATUS_SUCCESS) + return status; + + /* copy file info minus name */ + fai = (nt_fai *)buffer; + __ntapi->tt_aligned_block_memcpy( + (uintptr_t *)stat, + (uintptr_t *)fai, + ((size_t)(&((nt_fai *)0)->name_info))); + + /* record the file name length, but do not hash */ + stat->file_name_length = fai->name_info.file_name_length; + stat->file_name_hash = 0; + + + /* file system size information */ + status = __ntapi->zw_query_volume_information_file( + hfile, + &iosb, + &(stat->fssi), + sizeof(stat->fssi), + NT_FILE_FS_SIZE_INFORMATION); + + if (status != NT_STATUS_SUCCESS) + return status; + + /* system-unique device name (simpler than statfs) */ + iosb.info = 0; + status = __ntapi->zw_query_object( + hfile, + NT_OBJECT_NAME_INFORMATION, + buffer, + buffer_size, + (uint32_t *)&iosb.info); + + if (status != NT_STATUS_SUCCESS) + return status; + + sdev = (nt_unicode_string *)buffer; + stat->dev_name_strlen = sdev->strlen - (uint16_t)stat->file_name_length; + + stat->dev_name_hash = __ntapi->tt_buffer_crc32( + 0, + sdev->buffer, + stat->dev_name_strlen); + + if (flags & NT_STAT_DEV_NAME_COPY) { + if (stat->dev_name_maxlen < sdev->strlen) + /* does not justify failure */ + *stat->dev_name = 0; + else + __ntapi->tt_memcpy_utf16( + (wchar16_t *)stat->dev_name, + (wchar16_t *)sdev->buffer, + stat->dev_name_strlen); + } else + *stat->dev_name = 0; + + return status; +} diff --git a/src/fs/ntapi_tt_statfs.c b/src/fs/ntapi_tt_statfs.c new file mode 100644 index 0000000..114cc8e --- /dev/null +++ b/src/fs/ntapi_tt_statfs.c @@ -0,0 +1,225 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include +#include +#include +#include +#include "ntapi_impl.h" + +int32_t __stdcall __ntapi_tt_statfs( + __in void * hfile, + __in void * hroot __optional, + __in nt_unicode_string * path, + __out nt_statfs * statfs, + __out uintptr_t * buffer, + __in uint32_t buffer_size, + __in uint32_t flags) +{ + int32_t status; + nt_oa oa; + nt_iosb iosb; + nt_unicode_string * sdev; + uint32_t hash; + wchar16_t * wch; + wchar16_t * wch_mark; + uint32_t offset; + void * mnt_points_buffer; + nt_mount_points * mnt_points; + nt_fsai * fsai; + nt_fsfsi * fsfsi; + uint32_t * fsid; + uint64_t * pguid; + + /* validation */ + if (!hfile && !path) + return NT_STATUS_INVALID_HANDLE; + + /* hfile */ + if (!hfile) { + /* oa */ + oa.len = sizeof(nt_oa); + oa.root_dir = hroot; + oa.obj_name = path; + oa.obj_attr = 0; + oa.sec_desc = 0; + oa.sec_qos = 0; + + /* open file/folder */ + status = __ntapi->zw_open_file( + &hfile, + NT_SEC_SYNCHRONIZE | NT_FILE_READ_ATTRIBUTES | NT_FILE_READ_ACCESS, + &oa, + &iosb, + NT_FILE_SHARE_READ | NT_FILE_SHARE_WRITE, + NT_FILE_SYNCHRONOUS_IO_ALERT); + + if (status != NT_STATUS_SUCCESS) + return status; + + statfs->flags_out = NT_STATFS_NEW_HANDLE; + } + + statfs->hfile = hfile; + statfs->flags_in = flags; + + /* maximum component length, file system type */ + status = __ntapi->zw_query_volume_information_file( + hfile, + &iosb, + buffer, + buffer_size, + NT_FILE_FS_ATTRIBUTE_INFORMATION); + + if (status != NT_STATUS_SUCCESS) + return status; + + fsai = (nt_fsai *)buffer; + statfs->f_type = 0; + statfs->f_namelen = fsai->maximum_component_name_length; + statfs->nt_fstype_hash = __ntapi->tt_buffer_crc32( + 0, + &fsai->file_system_name, + fsai->file_system_name_length); + + /* max files per volume */ + switch (statfs->nt_fstype_hash) { + case NT_FS_TYPE_HPFS_NAME_HASH: + case NT_FS_TYPE_NTFS_NAME_HASH: + case NT_FS_TYPE_SMB_NAME_HASH: + case NT_FS_TYPE_UDF_NAME_HASH: + statfs->f_files = 0xFFFFFFFF; + break; + + case NT_FS_TYPE_FAT16_NAME_HASH: + statfs->f_files = 0x10000; + break; + + case NT_FS_TYPE_FAT32_NAME_HASH: + statfs->f_files = 0x400000; + break; + + default: + /* pretend there is no limitation */ + statfs->f_files = (-1); + break; + } + + /* number of free file records on volume */ + /* (skip, yet indicate that the volume is not empty) */ + statfs->f_ffree = (size_t)statfs->f_files >> 4 << 3; + + /* file system size information */ + status = __ntapi->zw_query_volume_information_file( + hfile, + &iosb, + buffer, + buffer_size, + NT_FILE_FS_FULL_SIZE_INFORMATION); + + if (status != NT_STATUS_SUCCESS) + return status; + + fsfsi = (nt_fsfsi *)buffer; + statfs->f_blocks = fsfsi->total_allocation_units.quad; + statfs->f_bfree = fsfsi->actual_available_allocation_units.quad; + statfs->f_bavail = fsfsi->caller_available_allocation_units.quad; + statfs->f_bsize = fsfsi->sectors_per_allocation_unit * fsfsi->bytes_per_sector; + statfs->f_frsize = fsfsi->bytes_per_sector; + + /* TODO: consolidate with istat */ + /* system-unique device name */ + iosb.info = 0; + status = __ntapi->zw_query_object( + hfile, + NT_OBJECT_NAME_INFORMATION, + buffer, + buffer_size, + (uint32_t *)&iosb.info); + + if (status != NT_STATUS_SUCCESS) + return status; + + sdev = (nt_unicode_string *)buffer; + + if (sdev->strlen < __DEVICE_PATH_PREFIX_LEN) + return NT_STATUS_INVALID_HANDLE; + + hash = __ntapi->tt_buffer_crc32( + 0, + sdev->buffer, + __DEVICE_PATH_PREFIX_LEN); + + if (hash != __DEVICE_PATH_PREFIX_HASH) + return NT_STATUS_INVALID_HANDLE; + + wch_mark = sdev->buffer + __DEVICE_PATH_PREFIX_LEN/sizeof(wchar16_t); + wch = wch_mark; + while (*wch != '\\') wch++; + statfs->dev_name_strlen = (uint16_t)((wch - sdev->buffer) * sizeof(uint16_t)); + statfs->record_name_strlen = sdev->strlen - statfs->dev_name_strlen; + + statfs->dev_name_hash = __ntapi->tt_buffer_crc32( + hash,wch_mark, + sizeof(wchar16_t) * (wch - wch_mark)); + + /* copy device name (optional, no failure) */ + if (flags & NT_STATFS_DEV_NAME_COPY) { + if (statfs->dev_name_maxlen < sdev->strlen) + *statfs->dev_name = 0; + else + __ntapi->tt_memcpy_utf16( + (wchar16_t *)statfs->dev_name, + (wchar16_t *)sdev->buffer, + sdev->strlen); + } else + *statfs->dev_name = 0; + + /* f_fsid: hash of the system-unique device name */ + /* (never use the volume serial number) */ + fsid = (uint32_t *)&(statfs->f_fsid); + fsid[0] = statfs->dev_name_hash; + fsid[1] = 0; + + /* f_flags, nt_attr, nt_control_flags (todo?) */ + statfs->f_flags = 0; + statfs->nt_attr = 0; + statfs->nt_control_flags = 0; + statfs->nt_padding = 0; + + if (!(flags & NT_STATFS_VOLUME_GUID)) { + statfs->nt_drive_letter = 0; + pguid = (uint64_t *)&(statfs->nt_volume_guid); + *pguid = 0; *(++pguid) = 0; + return NT_STATUS_SUCCESS; + } + + /* dos device letter and volume guid */ + wch = (wchar16_t *)sdev->buffer; + mnt_points_buffer = (void *)((uintptr_t)wch + statfs->dev_name_strlen); + + *(--wch) = statfs->dev_name_strlen; + offset = sizeof(nt_unicode_string) + statfs->dev_name_strlen; + + status = __ntapi->tt_get_dos_drive_mount_points( + (void *)0, + (wchar16_t *)0, + (nt_mount_dev_name *)wch, + mnt_points_buffer, + buffer_size - offset); + + if (status != NT_STATUS_SUCCESS) + return status; + + offset = ((nt_mount_point_param *)mnt_points_buffer)->mount_points_offset; + mnt_points = (nt_mount_points *)((uintptr_t)mnt_points_buffer + offset); + + status = __ntapi->tt_dev_mount_points_to_statfs( + mnt_points, + statfs); + + return status; +} -- cgit v1.2.3