|
|
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 <ntapi/ntapi.h>
|
|
|
dd89bb |
#include <ntapi/nt_fsctl.h>
|
|
|
dd89bb |
#include <ntapi/nt_mount.h>
|
|
|
dd89bb |
#include <ntapi/nt_statfs.h>
|
|
|
dd89bb |
#include "ntapi_impl.h"
|
|
|
dd89bb |
|
|
|
dd89bb |
int32_t __stdcall __ntapi_tt_statfs(
|
|
|
dd89bb |
__in void * hfile,
|
|
|
dd89bb |
__in void * hroot __optional,
|
|
|
dd89bb |
__in nt_unicode_string * path,
|
|
|
dd89bb |
__out nt_statfs * statfs,
|
|
|
dd89bb |
__out uintptr_t * buffer,
|
|
|
dd89bb |
__in uint32_t buffer_size,
|
|
|
dd89bb |
__in uint32_t flags)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
int32_t status;
|
|
|
dd89bb |
nt_oa oa;
|
|
|
dd89bb |
nt_iosb iosb;
|
|
|
dd89bb |
nt_unicode_string * sdev;
|
|
|
dd89bb |
uint32_t hash;
|
|
|
dd89bb |
wchar16_t * wch;
|
|
|
dd89bb |
wchar16_t * wch_mark;
|
|
|
dd89bb |
uint32_t offset;
|
|
|
dd89bb |
void * mnt_points_buffer;
|
|
|
dd89bb |
nt_mount_points * mnt_points;
|
|
|
dd89bb |
nt_fsai * fsai;
|
|
|
dd89bb |
nt_fsfsi * fsfsi;
|
|
|
dd89bb |
uint32_t * fsid;
|
|
|
dd89bb |
uint64_t * pguid;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* validation */
|
|
|
dd89bb |
if (!hfile && !path)
|
|
|
dd89bb |
return NT_STATUS_INVALID_HANDLE;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* hfile */
|
|
|
dd89bb |
if (!hfile) {
|
|
|
dd89bb |
/* oa */
|
|
|
dd89bb |
oa.len = sizeof(nt_oa);
|
|
|
dd89bb |
oa.root_dir = hroot;
|
|
|
dd89bb |
oa.obj_name = path;
|
|
|
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 |
&hfile,
|
|
|
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_SYNCHRONOUS_IO_ALERT);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status != NT_STATUS_SUCCESS)
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
statfs->flags_out = NT_STATFS_NEW_HANDLE;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
statfs->hfile = hfile;
|
|
|
dd89bb |
statfs->flags_in = flags;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* maximum component length, file system type */
|
|
|
dd89bb |
status = __ntapi->zw_query_volume_information_file(
|
|
|
dd89bb |
hfile,
|
|
|
dd89bb |
&iosb,
|
|
|
dd89bb |
buffer,
|
|
|
dd89bb |
buffer_size,
|
|
|
dd89bb |
NT_FILE_FS_ATTRIBUTE_INFORMATION);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status != NT_STATUS_SUCCESS)
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
fsai = (nt_fsai *)buffer;
|
|
|
dd89bb |
statfs->f_type = 0;
|
|
|
dd89bb |
statfs->f_namelen = fsai->maximum_component_name_length;
|
|
|
dd89bb |
statfs->nt_fstype_hash = __ntapi->tt_buffer_crc32(
|
|
|
dd89bb |
0,
|
|
|
dd89bb |
&fsai->file_system_name,
|
|
|
dd89bb |
fsai->file_system_name_length);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* max files per volume */
|
|
|
dd89bb |
switch (statfs->nt_fstype_hash) {
|
|
|
dd89bb |
case NT_FS_TYPE_HPFS_NAME_HASH:
|
|
|
dd89bb |
case NT_FS_TYPE_NTFS_NAME_HASH:
|
|
|
dd89bb |
case NT_FS_TYPE_SMB_NAME_HASH:
|
|
|
dd89bb |
case NT_FS_TYPE_UDF_NAME_HASH:
|
|
|
dd89bb |
statfs->f_files = 0xFFFFFFFF;
|
|
|
dd89bb |
break;
|
|
|
dd89bb |
|
|
|
dd89bb |
case NT_FS_TYPE_FAT16_NAME_HASH:
|
|
|
dd89bb |
statfs->f_files = 0x10000;
|
|
|
dd89bb |
break;
|
|
|
dd89bb |
|
|
|
dd89bb |
case NT_FS_TYPE_FAT32_NAME_HASH:
|
|
|
dd89bb |
statfs->f_files = 0x400000;
|
|
|
dd89bb |
break;
|
|
|
dd89bb |
|
|
|
dd89bb |
default:
|
|
|
dd89bb |
/* pretend there is no limitation */
|
|
|
dd89bb |
statfs->f_files = (-1);
|
|
|
dd89bb |
break;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* number of free file records on volume */
|
|
|
dd89bb |
/* (skip, yet indicate that the volume is not empty) */
|
|
|
dd89bb |
statfs->f_ffree = (size_t)statfs->f_files >> 4 << 3;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* file system size information */
|
|
|
dd89bb |
status = __ntapi->zw_query_volume_information_file(
|
|
|
dd89bb |
hfile,
|
|
|
dd89bb |
&iosb,
|
|
|
dd89bb |
buffer,
|
|
|
dd89bb |
buffer_size,
|
|
|
dd89bb |
NT_FILE_FS_FULL_SIZE_INFORMATION);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status != NT_STATUS_SUCCESS)
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
fsfsi = (nt_fsfsi *)buffer;
|
|
|
dd89bb |
statfs->f_blocks = fsfsi->total_allocation_units.quad;
|
|
|
dd89bb |
statfs->f_bfree = fsfsi->actual_available_allocation_units.quad;
|
|
|
dd89bb |
statfs->f_bavail = fsfsi->caller_available_allocation_units.quad;
|
|
|
dd89bb |
statfs->f_bsize = fsfsi->sectors_per_allocation_unit * fsfsi->bytes_per_sector;
|
|
|
dd89bb |
statfs->f_frsize = fsfsi->bytes_per_sector;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* TODO: consolidate with istat */
|
|
|
dd89bb |
/* system-unique device name */
|
|
|
dd89bb |
iosb.info = 0;
|
|
|
dd89bb |
status = __ntapi->zw_query_object(
|
|
|
dd89bb |
hfile,
|
|
|
dd89bb |
NT_OBJECT_NAME_INFORMATION,
|
|
|
dd89bb |
buffer,
|
|
|
dd89bb |
buffer_size,
|
|
|
dd89bb |
(uint32_t *)&iosb.info);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status != NT_STATUS_SUCCESS)
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
sdev = (nt_unicode_string *)buffer;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (sdev->strlen < __DEVICE_PATH_PREFIX_LEN)
|
|
|
dd89bb |
return NT_STATUS_INVALID_HANDLE;
|
|
|
dd89bb |
|
|
|
dd89bb |
hash = __ntapi->tt_buffer_crc32(
|
|
|
dd89bb |
0,
|
|
|
dd89bb |
sdev->buffer,
|
|
|
dd89bb |
__DEVICE_PATH_PREFIX_LEN);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (hash != __DEVICE_PATH_PREFIX_HASH)
|
|
|
dd89bb |
return NT_STATUS_INVALID_HANDLE;
|
|
|
dd89bb |
|
|
|
dd89bb |
wch_mark = sdev->buffer + __DEVICE_PATH_PREFIX_LEN/sizeof(wchar16_t);
|
|
|
dd89bb |
wch = wch_mark;
|
|
|
dd89bb |
while (*wch != '\\') wch++;
|
|
|
dd89bb |
statfs->dev_name_strlen = (uint16_t)((wch - sdev->buffer) * sizeof(uint16_t));
|
|
|
dd89bb |
statfs->record_name_strlen = sdev->strlen - statfs->dev_name_strlen;
|
|
|
dd89bb |
|
|
|
dd89bb |
statfs->dev_name_hash = __ntapi->tt_buffer_crc32(
|
|
|
dd89bb |
hash,wch_mark,
|
|
|
dd89bb |
sizeof(wchar16_t) * (wch - wch_mark));
|
|
|
dd89bb |
|
|
|
dd89bb |
/* copy device name (optional, no failure) */
|
|
|
dd89bb |
if (flags & NT_STATFS_DEV_NAME_COPY) {
|
|
|
dd89bb |
if (statfs->dev_name_maxlen < sdev->strlen)
|
|
|
dd89bb |
*statfs->dev_name = 0;
|
|
|
dd89bb |
else
|
|
|
dd89bb |
__ntapi->tt_memcpy_utf16(
|
|
|
dd89bb |
(wchar16_t *)statfs->dev_name,
|
|
|
dd89bb |
(wchar16_t *)sdev->buffer,
|
|
|
dd89bb |
sdev->strlen);
|
|
|
dd89bb |
} else
|
|
|
dd89bb |
*statfs->dev_name = 0;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* f_fsid: hash of the system-unique device name */
|
|
|
dd89bb |
/* (never use the volume serial number) */
|
|
|
dd89bb |
fsid = (uint32_t *)&(statfs->f_fsid);
|
|
|
dd89bb |
fsid[0] = statfs->dev_name_hash;
|
|
|
dd89bb |
fsid[1] = 0;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* f_flags, nt_attr, nt_control_flags (todo?) */
|
|
|
dd89bb |
statfs->f_flags = 0;
|
|
|
dd89bb |
statfs->nt_attr = 0;
|
|
|
dd89bb |
statfs->nt_control_flags = 0;
|
|
|
dd89bb |
statfs->nt_padding = 0;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (!(flags & NT_STATFS_VOLUME_GUID)) {
|
|
|
dd89bb |
statfs->nt_drive_letter = 0;
|
|
|
dd89bb |
pguid = (uint64_t *)&(statfs->nt_volume_guid);
|
|
|
dd89bb |
*pguid = 0; *(++pguid) = 0;
|
|
|
dd89bb |
return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* dos device letter and volume guid */
|
|
|
dd89bb |
wch = (wchar16_t *)sdev->buffer;
|
|
|
dd89bb |
mnt_points_buffer = (void *)((uintptr_t)wch + statfs->dev_name_strlen);
|
|
|
dd89bb |
|
|
|
dd89bb |
*(--wch) = statfs->dev_name_strlen;
|
|
|
dd89bb |
offset = sizeof(nt_unicode_string) + statfs->dev_name_strlen;
|
|
|
dd89bb |
|
|
|
dd89bb |
status = __ntapi->tt_get_dos_drive_mount_points(
|
|
|
dd89bb |
(void *)0,
|
|
|
dd89bb |
(wchar16_t *)0,
|
|
|
dd89bb |
(nt_mount_dev_name *)wch,
|
|
|
dd89bb |
mnt_points_buffer,
|
|
|
dd89bb |
buffer_size - offset);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status != NT_STATUS_SUCCESS)
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
offset = ((nt_mount_point_param *)mnt_points_buffer)->mount_points_offset;
|
|
|
dd89bb |
mnt_points = (nt_mount_points *)((uintptr_t)mnt_points_buffer + offset);
|
|
|
dd89bb |
|
|
|
dd89bb |
status = __ntapi->tt_dev_mount_points_to_statfs(
|
|
|
dd89bb |
mnt_points,
|
|
|
dd89bb |
statfs);
|
|
|
dd89bb |
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
}
|