#include <smbsrv/smb2_kproto.h>
#include <smbsrv/smb_fsops.h>
uint32_t
smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *si)
{
smb_attr_t *attr = &si->si_attr;
smb_node_t *node = si->si_node;
uint64_t crtime, atime, mtime, ctime;
uint32_t attributes;
int rc;
if (smb_mbc_decodef(&si->si_data, "qqqql",
&crtime, &atime, &mtime, &ctime, &attributes) != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
if (smb_node_is_dir(node)) {
if ((attributes & FILE_ATTRIBUTE_TEMPORARY) != 0)
return (NT_STATUS_INVALID_PARAMETER);
} else {
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
return (NT_STATUS_INVALID_PARAMETER);
}
bzero(attr, sizeof (*attr));
if (atime != 0) {
if ((int64_t)atime < -2)
return (NT_STATUS_INVALID_PARAMETER);
smb_time_nt_to_unix(atime, &attr->sa_vattr.va_atime);
attr->sa_mask |= SMB_AT_ATIME;
}
if (mtime != 0) {
if ((int64_t)mtime < -2)
return (NT_STATUS_INVALID_PARAMETER);
smb_time_nt_to_unix(mtime, &attr->sa_vattr.va_mtime);
attr->sa_mask |= SMB_AT_MTIME;
}
if (ctime != 0) {
if ((int64_t)ctime < -2)
return (NT_STATUS_INVALID_PARAMETER);
smb_time_nt_to_unix(ctime, &attr->sa_vattr.va_ctime);
attr->sa_mask |= SMB_AT_CTIME;
}
if (crtime != 0) {
if ((int64_t)crtime < -2)
return (NT_STATUS_INVALID_PARAMETER);
smb_time_nt_to_unix(crtime, &attr->sa_crtime);
attr->sa_mask |= SMB_AT_CRTIME;
}
if (attributes != 0) {
attr->sa_dosattr = attributes;
attr->sa_mask |= SMB_AT_DOSATTR;
}
rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
if (rc != 0)
return (smb_errno2status(rc));
return (0);
}
uint32_t
smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *si)
{
smb_attr_t *attr = &si->si_attr;
smb_node_t *node = si->si_node;
uint64_t eof;
uint32_t status;
int rc;
if (smb_mbc_decodef(&si->si_data, "q", &eof) != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
if (smb_node_is_dir(node))
return (NT_STATUS_INVALID_PARAMETER);
status = smb_oplock_break_SETINFO(node, sr->fid_ofile,
FileEndOfFileInformation);
if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
if (sr->session->dialect >= SMB_VERS_2_BASE)
(void) smb2sr_go_async(sr);
(void) smb_oplock_wait_break(sr, node, 0);
status = 0;
}
if (status != 0)
return (status);
bzero(attr, sizeof (*attr));
attr->sa_mask = SMB_AT_SIZE;
attr->sa_vattr.va_size = (u_offset_t)eof;
rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
if (rc != 0)
return (smb_errno2status(rc));
return (0);
}
uint32_t
smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *si)
{
smb_attr_t *attr = &si->si_attr;
smb_node_t *node = si->si_node;
uint64_t allocsz;
uint32_t status;
int rc;
if (smb_mbc_decodef(&si->si_data, "q", &allocsz) != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
if (smb_node_is_dir(node))
return (NT_STATUS_INVALID_PARAMETER);
status = smb_oplock_break_SETINFO(node, sr->fid_ofile,
FileAllocationInformation);
if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
if (sr->session->dialect >= SMB_VERS_2_BASE)
(void) smb2sr_go_async(sr);
(void) smb_oplock_wait_break(sr, node, 0);
status = 0;
}
if (status != 0)
return (status);
bzero(attr, sizeof (*attr));
attr->sa_mask = SMB_AT_ALLOCSZ;
attr->sa_allocsz = (u_offset_t)allocsz;
rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, attr);
if (rc != 0)
return (smb_errno2status(rc));
return (0);
}
uint32_t
smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *si)
{
smb_attr_t *attr = &si->si_attr;
smb_node_t *node = si->si_node;
smb_ofile_t *of = sr->fid_ofile;
uint8_t mark_delete;
uint32_t status;
uint32_t flags = 0;
if (smb_mbc_decodef(&si->si_data, "b", &mark_delete) != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
if ((of == NULL) || !(smb_ofile_granted_access(of) & DELETE))
return (NT_STATUS_ACCESS_DENIED);
if (mark_delete == 0) {
smb_node_reset_delete_on_close(node);
return (NT_STATUS_SUCCESS);
}
attr->sa_mask = SMB_AT_DOSATTR;
status = smb2_ofile_getattr(sr, of, attr);
if (status != 0)
return (status);
if ((attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0)
return (NT_STATUS_CANNOT_DELETE);
status = smb_oplock_break_SETINFO(node, of,
FileDispositionInformation);
if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
if (sr->session->dialect >= SMB_VERS_2_BASE)
(void) smb2sr_go_async(sr);
(void) smb_oplock_wait_break(sr, node, 0);
status = 0;
}
if (status != 0)
return (status);
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
return (smb_node_set_delete_on_close(node, of->f_cr, flags));
}