#include <smbsrv/smb2_kproto.h>
#include <smbsrv/smb_fsops.h>
#include <smbsrv/ntifs.h>
uint32_t smb2_qfs_volume(smb_request_t *);
uint32_t smb2_qfs_size(smb_request_t *);
uint32_t smb2_qfs_device(smb_request_t *);
uint32_t smb2_qfs_attr(smb_request_t *);
uint32_t smb2_qfs_control(smb_request_t *);
uint32_t smb2_qfs_fullsize(smb_request_t *);
uint32_t smb2_qfs_obj_id(smb_request_t *);
uint32_t smb2_qfs_sectorsize(smb_request_t *);
uint32_t
smb2_qinfo_fs(smb_request_t *sr, smb_queryinfo_t *qi)
{
uint32_t status;
switch (qi->qi_InfoClass) {
case FileFsVolumeInformation:
status = smb2_qfs_volume(sr);
break;
case FileFsSizeInformation:
status = smb2_qfs_size(sr);
break;
case FileFsDeviceInformation:
status = smb2_qfs_device(sr);
break;
case FileFsAttributeInformation:
status = smb2_qfs_attr(sr);
break;
case FileFsControlInformation:
status = smb2_qfs_control(sr);
break;
case FileFsFullSizeInformation:
status = smb2_qfs_fullsize(sr);
break;
case FileFsObjectIdInformation:
status = smb2_qfs_obj_id(sr);
break;
case FileFsDriverPathInformation:
case FileFsVolumeFlagsInformation:
status = NT_STATUS_INVALID_INFO_CLASS;
break;
case FileFsSectorSizeInformation:
status = smb2_qfs_sectorsize(sr);
break;
default:
status = NT_STATUS_INVALID_INFO_CLASS;
#ifdef DEBUG
cmn_err(CE_NOTE, "unknown InfoClass 0x%x", qi->qi_InfoClass);
#endif
break;
}
return (status);
}
uint32_t
smb2_qfs_volume(smb_request_t *sr)
{
smb_tree_t *tree = sr->tid_tree;
smb_node_t *snode;
fsid_t fsid;
uint32_t LabelLength;
int rc;
if (!STYPE_ISDSK(tree->t_res_type))
return (NT_STATUS_INVALID_PARAMETER);
snode = tree->t_snode;
fsid = SMB_NODE_FSID(snode);
LabelLength = smb_wcequiv_strlen(tree->t_volume);
rc = smb_mbc_encodef(
&sr->raw_data, "Tllb.U",
&tree->t_create_time,
fsid.val[0],
LabelLength,
0,
tree->t_volume);
if (rc != 0)
return (NT_STATUS_BUFFER_OVERFLOW);
return (0);
}
uint32_t
smb2_qfs_size(smb_request_t *sr)
{
smb_fssize_t fssize;
smb_tree_t *tree = sr->tid_tree;
int rc;
if (!STYPE_ISDSK(tree->t_res_type))
return (NT_STATUS_INVALID_PARAMETER);
rc = smb_fssize(sr, &fssize);
if (rc)
return (smb_errno2status(rc));
rc = smb_mbc_encodef(
&sr->raw_data, "qqll",
fssize.fs_caller_units,
fssize.fs_caller_avail,
fssize.fs_sectors_per_unit,
fssize.fs_bytes_per_sector);
if (rc != 0)
return (NT_STATUS_BUFFER_OVERFLOW);
return (0);
}
uint32_t
smb2_qfs_fullsize(smb_request_t *sr)
{
smb_fssize_t fssize;
smb_tree_t *tree = sr->tid_tree;
int rc;
if (!STYPE_ISDSK(tree->t_res_type))
return (NT_STATUS_INVALID_PARAMETER);
rc = smb_fssize(sr, &fssize);
if (rc)
return (smb_errno2status(rc));
rc = smb_mbc_encodef(
&sr->raw_data, "qqqll",
fssize.fs_caller_units,
fssize.fs_caller_avail,
fssize.fs_volume_avail,
fssize.fs_sectors_per_unit,
fssize.fs_bytes_per_sector);
if (rc != 0)
return (NT_STATUS_BUFFER_OVERFLOW);
return (0);
}
uint32_t
smb2_qfs_device(smb_request_t *sr)
{
smb_tree_t *tree = sr->tid_tree;
uint32_t DeviceType;
uint32_t Characteristics;
int rc;
if (!STYPE_ISDSK(tree->t_res_type))
return (NT_STATUS_INVALID_PARAMETER);
DeviceType = FILE_DEVICE_DISK;
Characteristics = FILE_DEVICE_IS_MOUNTED;
rc = smb_mbc_encodef(
&sr->raw_data, "ll",
DeviceType,
Characteristics);
if (rc != 0)
return (NT_STATUS_BUFFER_OVERFLOW);
return (0);
}
uint32_t
smb2_qfs_attr(smb_request_t *sr)
{
smb_tree_t *tree = sr->tid_tree;
char *fsname;
uint32_t namelen;
uint32_t FsAttr;
int rc;
switch (tree->t_res_type & STYPE_MASK) {
case STYPE_IPC:
fsname = "PIPE";
break;
case STYPE_DISKTREE:
fsname = "NTFS";
break;
case STYPE_PRINTQ:
case STYPE_DEVICE:
default:
return (NT_STATUS_INVALID_PARAMETER);
}
namelen = smb_wcequiv_strlen(fsname);
FsAttr = FILE_CASE_PRESERVED_NAMES;
if (tree->t_flags & SMB_TREE_UNICODE_ON_DISK)
FsAttr |= FILE_UNICODE_ON_DISK;
if (tree->t_flags & SMB_TREE_SUPPORTS_ACLS)
FsAttr |= FILE_PERSISTENT_ACLS;
if ((tree->t_flags & SMB_TREE_CASEINSENSITIVE) == 0)
FsAttr |= FILE_CASE_SENSITIVE_SEARCH;
if (tree->t_flags & SMB_TREE_STREAMS)
FsAttr |= FILE_NAMED_STREAMS;
if (tree->t_flags & SMB_TREE_QUOTA)
FsAttr |= FILE_VOLUME_QUOTAS;
if (tree->t_flags & SMB_TREE_SPARSE)
FsAttr |= FILE_SUPPORTS_SPARSE_FILES;
rc = smb_mbc_encodef(
&sr->raw_data, "lllU",
FsAttr,
MAXNAMELEN-1,
namelen,
fsname);
if (rc != 0)
return (NT_STATUS_BUFFER_OVERFLOW);
return (0);
}
uint32_t
smb2_qfs_control(smb_request_t *sr)
{
smb_tree_t *tree = sr->tid_tree;
int rc;
if (!STYPE_ISDSK(tree->t_res_type))
return (NT_STATUS_INVALID_PARAMETER);
if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA)) {
return (NT_STATUS_VOLUME_NOT_UPGRADED);
}
rc = smb_mbc_encodef(
&sr->raw_data, "qqqqqll",
0,
0,
0,
SMB_QUOTA_UNLIMITED,
SMB_QUOTA_UNLIMITED,
FILE_VC_QUOTA_ENFORCE,
0);
if (rc != 0)
return (NT_STATUS_BUFFER_OVERFLOW);
return (0);
}
uint32_t
smb2_qfs_obj_id(smb_request_t *sr)
{
return (NT_STATUS_INVALID_PARAMETER);
}
#define SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001
#define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002
#define SSINFO_FLAGS_NO_SEEK_PENALTY 0x00000004
#define SSINFO_FLAGS_TRIM_ENABLED 0x00000008
#define SSINFO_OFFSET_UNKNOWN 0xffffffff
int smb2_max_logical_sector_size = 4096;
uint32_t
smb2_qfs_sectorsize(smb_request_t *sr)
{
smb_fssize_t fssize;
smb_tree_t *tree = sr->tid_tree;
uint32_t lbps, pbps;
uint32_t flags, unk;
int rc;
if (!STYPE_ISDSK(tree->t_res_type))
return (NT_STATUS_INVALID_PARAMETER);
rc = smb_fssize(sr, &fssize);
if (rc)
return (smb_errno2status(rc));
pbps = fssize.fs_bytes_per_sector;
lbps = fssize.fs_sectors_per_unit * pbps;
if (lbps > smb2_max_logical_sector_size)
lbps = smb2_max_logical_sector_size;
flags = SSINFO_FLAGS_ALIGNED_DEVICE |
SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE |
SSINFO_FLAGS_NO_SEEK_PENALTY;
unk = SSINFO_OFFSET_UNKNOWN;
rc = smb_mbc_encodef(
&sr->raw_data,
"lllllll",
lbps,
pbps,
lbps,
pbps,
flags,
unk, unk);
if (rc != 0)
return (NT_STATUS_BUFFER_OVERFLOW);
return (0);
}