|
|
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 <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 |
__out nt_statfs * statfs,
|
|
|
d8b407 |
__in uint32_t infolen,
|
|
|
dd89bb |
__out uintptr_t * buffer,
|
|
|
dd89bb |
__in uint32_t buffer_size,
|
|
|
dd89bb |
__in uint32_t flags)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
int32_t status;
|
|
|
dd89bb |
nt_iosb iosb;
|
|
|
dd89bb |
nt_unicode_string * sdev;
|
|
|
dd89bb |
wchar16_t * wch;
|
|
|
dd89bb |
wchar16_t * wch_mark;
|
|
|
7bb8ac |
wchar16_t * wch_cap;
|
|
|
dd89bb |
uint32_t offset;
|
|
|
030926 |
uint32_t hash;
|
|
|
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;
|
|
|
d8b407 |
uint32_t written;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* validation */
|
|
|
d8b407 |
if (infolen < sizeof(*statfs))
|
|
|
d8b407 |
return NT_STATUS_INFO_LENGTH_MISMATCH;
|
|
|
dd89bb |
|
|
|
d8b407 |
/* init */
|
|
|
d8b407 |
__ntapi->tt_aligned_block_memset(
|
|
|
d8b407 |
statfs,0,sizeof(*statfs));
|
|
|
dd89bb |
|
|
|
d8b407 |
statfs->hfile = hfile;
|
|
|
e47608 |
statfs->dev_name_maxlen = (uint16_t)infolen - sizeof(*statfs);
|
|
|
dd89bb |
|
|
|
85b392 |
/* sigh */
|
|
|
85b392 |
if (buffer_size >= 65536)
|
|
|
85b392 |
buffer_size = 65535;
|
|
|
85b392 |
|
|
|
dd89bb |
/* maximum component length, file system type */
|
|
|
3119b6 |
if ((status = __ntapi->zw_query_volume_information_file(
|
|
|
3119b6 |
hfile,
|
|
|
3119b6 |
&iosb,
|
|
|
3119b6 |
buffer,
|
|
|
3119b6 |
buffer_size,
|
|
|
3119b6 |
NT_FILE_FS_ATTRIBUTE_INFORMATION)))
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
fsai = (nt_fsai *)buffer;
|
|
|
3119b6 |
statfs->f_type = 0;
|
|
|
dd89bb |
statfs->f_namelen = fsai->maximum_component_name_length;
|
|
|
3119b6 |
|
|
|
dd89bb |
statfs->nt_fstype_hash = __ntapi->tt_buffer_crc32(
|
|
|
d8b407 |
0,&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 */
|
|
|
3e609e |
statfs->f_files = (uint64_t)(-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 */
|
|
|
3119b6 |
if ((status = __ntapi->zw_query_volume_information_file(
|
|
|
3119b6 |
hfile,
|
|
|
3119b6 |
&iosb,
|
|
|
3119b6 |
buffer,
|
|
|
3119b6 |
buffer_size,
|
|
|
3119b6 |
NT_FILE_FS_FULL_SIZE_INFORMATION)))
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
d8b407 |
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 |
/* system-unique device name */
|
|
|
3119b6 |
if ((status = __ntapi->zw_query_object(
|
|
|
3119b6 |
hfile,
|
|
|
3119b6 |
NT_OBJECT_NAME_INFORMATION,
|
|
|
3119b6 |
buffer,
|
|
|
3119b6 |
buffer_size,
|
|
|
d8b407 |
&written)))
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
sdev = (nt_unicode_string *)buffer;
|
|
|
3119b6 |
wch = sdev->buffer;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (sdev->strlen < __DEVICE_PATH_PREFIX_LEN)
|
|
|
d8b407 |
return NT_STATUS_NOT_SUPPORTED;
|
|
|
dd89bb |
|
|
|
3119b6 |
if ((wch[0] != '\\')
|
|
|
3119b6 |
|| (wch[1] != 'D')
|
|
|
3119b6 |
|| (wch[2] != 'e')
|
|
|
3119b6 |
|| (wch[3] != 'v')
|
|
|
3119b6 |
|| (wch[4] != 'i')
|
|
|
3119b6 |
|| (wch[5] != 'c')
|
|
|
3119b6 |
|| (wch[6] != 'e')
|
|
|
3119b6 |
|| (wch[7] != '\\'))
|
|
|
d8b407 |
return NT_STATUS_NOT_SUPPORTED;
|
|
|
dd89bb |
|
|
|
030926 |
if (sdev->strlen < __DEVICE_MUP_PREFIX_LEN)
|
|
|
fe73cf |
return NT_STATUS_INVALID_HANDLE;
|
|
|
fe73cf |
|
|
|
fe73cf |
if ((wch[8]=='M')
|
|
|
fe73cf |
&& (wch[9]=='u')
|
|
|
fe73cf |
&& (wch[10]=='p')
|
|
|
fe73cf |
&& (wch[11]=='\\')) {
|
|
|
d8b407 |
statfs->nt_drive_letter = 0;
|
|
|
d8b407 |
hash = __DEVICE_MUP_PREFIX_HASH;
|
|
|
d8b407 |
flags &= ~NT_STATFS_VOLUME_GUID;
|
|
|
fe73cf |
statfs->flags |= NT_STATFS_MUP_DEVICE;
|
|
|
030926 |
|
|
|
fd484f |
wch_mark = &wch[12];
|
|
|
d8b407 |
wch = wch_mark;
|
|
|
fd484f |
|
|
|
d8b407 |
for (; *wch!='\\'; )
|
|
|
d8b407 |
wch++;
|
|
|
fd484f |
wch++;
|
|
|
030926 |
} else {
|
|
|
030926 |
wch_mark = &wch[8];
|
|
|
fd484f |
wch = wch_mark;
|
|
|
fe73cf |
hash = __DEVICE_PATH_PREFIX_HASH;
|
|
|
030926 |
}
|
|
|
3119b6 |
|
|
|
7bb8ac |
wch_cap = sdev->buffer + (sdev->strlen / sizeof(wchar16_t));
|
|
|
7bb8ac |
|
|
|
7bb8ac |
for (; wch
|
|
|
fd484f |
wch++;
|
|
|
3119b6 |
|
|
|
1d3e99 |
statfs->obj_name_strlen = sdev->strlen;
|
|
|
1d3e99 |
statfs->obj_name_maxlen = statfs->dev_name_maxlen;
|
|
|
d8b407 |
statfs->dev_name_strlen = sizeof(uint16_t) * (uint16_t)(wch - sdev->buffer);
|
|
|
1d3e99 |
statfs->dev_name_hash = __ntapi->tt_buffer_crc32(
|
|
|
1d3e99 |
hash,wch_mark,
|
|
|
d8b407 |
sizeof(wchar16_t) * (wch - wch_mark));
|
|
|
dd89bb |
|
|
|
31ee70 |
/* device name */
|
|
|
31ee70 |
if (!(flags & NT_STATFS_DEV_NAME_COPY))
|
|
|
31ee70 |
(void)0;
|
|
|
31ee70 |
else if (statfs->dev_name_maxlen < sdev->strlen)
|
|
|
31ee70 |
return NT_STATUS_BUFFER_TOO_SMALL;
|
|
|
31ee70 |
else
|
|
|
31ee70 |
__ntapi->tt_memcpy_utf16(
|
|
|
31ee70 |
statfs->dev_name,
|
|
|
31ee70 |
sdev->buffer,
|
|
|
31ee70 |
sdev->strlen);
|
|
|
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 |
|
|
|
fe73cf |
/* f_flags, nt_attr */
|
|
|
dd89bb |
statfs->f_flags = 0;
|
|
|
dd89bb |
statfs->nt_attr = 0;
|
|
|
dd89bb |
statfs->nt_padding = 0;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (!(flags & NT_STATFS_VOLUME_GUID)) {
|
|
|
dd89bb |
statfs->nt_drive_letter = 0;
|
|
|
fe73cf |
pguid = (uint64_t *)&(statfs->nt_volume_guid);
|
|
|
fe73cf |
pguid[0] = 0;
|
|
|
fe73cf |
pguid[1] = 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 |
|
|
|
3119b6 |
if ((status = __ntapi->tt_get_dos_drive_mount_points(
|
|
|
fe73cf |
0,0,
|
|
|
3119b6 |
(nt_mount_dev_name *)wch,
|
|
|
3119b6 |
mnt_points_buffer,
|
|
|
3119b6 |
buffer_size - offset)))
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
3119b6 |
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(
|
|
|
fe73cf |
mnt_points,statfs);
|
|
|
dd89bb |
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
}
|