#include <smbsrv/smb2_kproto.h>
#include <smbsrv/smb_fsops.h>
#include <smbsrv/ntifs.h>
static uint32_t smb2_setf_rename(smb_request_t *, smb_setinfo_t *);
static uint32_t smb2_setf_link(smb_request_t *, smb_setinfo_t *);
static uint32_t smb2_setf_seek(smb_request_t *, smb_setinfo_t *);
static uint32_t smb2_setf_full_ea(smb_request_t *, smb_setinfo_t *);
static uint32_t smb2_setf_mode(smb_request_t *, smb_setinfo_t *);
static uint32_t smb2_setf_pipe(smb_request_t *, smb_setinfo_t *);
static uint32_t smb2_setf_valid_len(smb_request_t *, smb_setinfo_t *);
static uint32_t smb2_setf_shortname(smb_request_t *, smb_setinfo_t *);
uint32_t
smb2_setinfo_file(smb_request_t *sr, smb_setinfo_t *si, int InfoClass)
{
smb_ofile_t *of = sr->fid_ofile;
uint32_t status;
si->si_node = of->f_node;
switch (of->f_ftype) {
case SMB_FTYPE_DISK:
case SMB_FTYPE_PRINTER:
break;
case SMB_FTYPE_BYTE_PIPE:
case SMB_FTYPE_MESG_PIPE:
if (InfoClass != FilePipeInformation)
return (NT_STATUS_INVALID_PARAMETER);
break;
default:
return (NT_STATUS_INTERNAL_ERROR);
break;
}
switch (InfoClass) {
case FileBasicInformation:
status = smb_set_basic_info(sr, si);
break;
case FileRenameInformation:
status = smb2_setf_rename(sr, si);
break;
case FileLinkInformation:
status = smb2_setf_link(sr, si);
break;
case FileDispositionInformation:
status = smb_set_disposition_info(sr, si);
break;
case FilePositionInformation:
status = smb2_setf_seek(sr, si);
break;
case FileFullEaInformation:
status = smb2_setf_full_ea(sr, si);
break;
case FileModeInformation:
status = smb2_setf_mode(sr, si);
break;
case FileAllocationInformation:
status = smb_set_alloc_info(sr, si);
break;
case FileEndOfFileInformation:
status = smb_set_eof_info(sr, si);
break;
case FilePipeInformation:
status = smb2_setf_pipe(sr, si);
break;
case FileValidDataLengthInformation:
status = smb2_setf_valid_len(sr, si);
break;
case FileShortNameInformation:
status = smb2_setf_shortname(sr, si);
break;
default:
status = NT_STATUS_INVALID_INFO_CLASS;
break;
}
return (status);
}
static uint32_t
smb2_setf_rename(smb_request_t *sr, smb_setinfo_t *si)
{
char *fname;
uint8_t flags;
uint64_t rootdir;
uint32_t namelen;
uint32_t status = 0;
int rc;
rc = smb_mbc_decodef(&si->si_data, "b7.ql",
&flags, &rootdir, &namelen);
if (rc == 0) {
rc = smb_mbc_decodef(&si->si_data, "%#U",
sr, namelen, &fname);
}
if (rc != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
if ((rootdir != 0) || (namelen == 0) || (namelen >= SMB_MAXPATHLEN)) {
return (NT_STATUS_INVALID_PARAMETER);
}
status = smb_setinfo_rename(sr, si->si_node, fname, flags);
return (status);
}
static uint32_t
smb2_setf_link(smb_request_t *sr, smb_setinfo_t *si)
{
char *fname;
uint8_t flags;
uint64_t rootdir;
uint32_t namelen;
uint32_t status = 0;
int rc;
rc = smb_mbc_decodef(&si->si_data, "b7.ql",
&flags, &rootdir, &namelen);
if (rc == 0) {
rc = smb_mbc_decodef(&si->si_data, "%#U",
sr, namelen, &fname);
}
if (rc != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
if ((rootdir != 0) || (namelen == 0) || (namelen >= SMB_MAXPATHLEN)) {
return (NT_STATUS_INVALID_PARAMETER);
}
status = smb_setinfo_link(sr, si->si_node, fname, flags);
return (status);
}
static uint32_t
smb2_setf_seek(smb_request_t *sr, smb_setinfo_t *si)
{
smb_ofile_t *of = sr->fid_ofile;
uint64_t newoff;
if (smb_mbc_decodef(&si->si_data, "q", &newoff) != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
ASSERT(of->f_magic == SMB_OFILE_MAGIC);
mutex_enter(&of->f_mutex);
of->f_seek_pos = newoff;
mutex_exit(&of->f_mutex);
return (0);
}
static uint32_t
smb2_setf_full_ea(smb_request_t *sr, smb_setinfo_t *si)
{
return (NT_STATUS_EAS_NOT_SUPPORTED);
}
static uint32_t
smb2_setf_mode(smb_request_t *sr, smb_setinfo_t *si)
{
_NOTE(ARGUNUSED(sr))
uint32_t Mode;
if (smb_mbc_decodef(&si->si_data, "l", &Mode) != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
#if 0
if (Mode & FILE_WRITE_THROUGH) {
}
#endif
return (NT_STATUS_SUCCESS);
}
static uint32_t
smb2_setf_pipe(smb_request_t *sr, smb_setinfo_t *si)
{
_NOTE(ARGUNUSED(si))
smb_ofile_t *of = sr->fid_ofile;
uint32_t ReadMode;
uint32_t CompletionMode;
uint32_t status;
if (smb_mbc_decodef(&si->si_data, "ll",
&ReadMode, &CompletionMode) != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
switch (of->f_ftype) {
case SMB_FTYPE_BYTE_PIPE:
case SMB_FTYPE_MESG_PIPE:
status = 0;
break;
case SMB_FTYPE_DISK:
case SMB_FTYPE_PRINTER:
default:
status = NT_STATUS_INVALID_PARAMETER;
}
return (status);
}
static uint32_t
smb2_setf_valid_len(smb_request_t *sr, smb_setinfo_t *si)
{
smb_ofile_t *of = sr->fid_ofile;
uint64_t eod;
int rc;
if (smb_mbc_decodef(&si->si_data, "q", &eod) != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
rc = smb_fsop_freesp(sr, of->f_cr, of, eod, 0);
if (rc != 0)
return (smb_errno2status(rc));
return (0);
}
static uint32_t
smb2_setf_shortname(smb_request_t *sr, smb_setinfo_t *si)
{
_NOTE(ARGUNUSED(si))
smb_ofile_t *of = sr->fid_ofile;
if (of->f_ftype != SMB_FTYPE_DISK)
return (NT_STATUS_INVALID_PARAMETER);
if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0)
return (NT_STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME);
return (NT_STATUS_ACCESS_DENIED);
}