#include <sys/types.h>
#include <sys/cmn_err.h>
#include <sys/fcntl.h>
#include <sys/nbmlock.h>
#include <smbsrv/string.h>
#include <smbsrv/smb2_kproto.h>
#include <smbsrv/smb_fsops.h>
#include <smbsrv/smbinfo.h>
extern uint32_t smb_is_executable(char *);
static void smb_delete_new_object(smb_request_t *);
static int smb_set_open_attributes(smb_request_t *, smb_ofile_t *);
static uint32_t
smb_access_generic_to_file(uint32_t desired_access)
{
uint32_t access = 0;
if (desired_access & GENERIC_ALL)
return (FILE_ALL_ACCESS & ~SYNCHRONIZE);
if (desired_access & GENERIC_EXECUTE) {
desired_access &= ~GENERIC_EXECUTE;
access |= (STANDARD_RIGHTS_EXECUTE |
SYNCHRONIZE | FILE_EXECUTE);
}
if (desired_access & GENERIC_WRITE) {
desired_access &= ~GENERIC_WRITE;
access |= (FILE_GENERIC_WRITE & ~SYNCHRONIZE);
}
if (desired_access & GENERIC_READ) {
desired_access &= ~GENERIC_READ;
access |= FILE_GENERIC_READ;
}
return (access | desired_access);
}
uint32_t
smb_omode_to_amask(uint32_t desired_access)
{
switch (desired_access & SMB_DA_ACCESS_MASK) {
case SMB_DA_ACCESS_READ:
return (FILE_GENERIC_READ);
case SMB_DA_ACCESS_WRITE:
return (FILE_GENERIC_WRITE);
case SMB_DA_ACCESS_READ_WRITE:
return (FILE_GENERIC_READ | FILE_GENERIC_WRITE);
case SMB_DA_ACCESS_EXECUTE:
return (FILE_GENERIC_READ | FILE_GENERIC_EXECUTE);
default:
return (FILE_GENERIC_ALL);
}
}
uint32_t
smb_denymode_to_sharemode(uint32_t desired_access, char *fname)
{
switch (desired_access & SMB_DA_SHARE_MASK) {
case SMB_DA_SHARE_COMPATIBILITY:
if (smb_is_executable(fname))
return (FILE_SHARE_READ | FILE_SHARE_WRITE);
return (FILE_SHARE_ALL);
case SMB_DA_SHARE_EXCLUSIVE:
return (FILE_SHARE_NONE);
case SMB_DA_SHARE_DENY_WRITE:
return (FILE_SHARE_READ);
case SMB_DA_SHARE_DENY_READ:
return (FILE_SHARE_WRITE);
case SMB_DA_SHARE_DENY_NONE:
default:
return (FILE_SHARE_READ | FILE_SHARE_WRITE);
}
}
uint32_t
smb_ofun_to_crdisposition(uint16_t ofun)
{
static int ofun_cr_map[3][2] =
{
{ -1, FILE_CREATE },
{ FILE_OPEN, FILE_OPEN_IF },
{ FILE_OVERWRITE, FILE_OVERWRITE_IF }
};
int row = ofun & SMB_OFUN_OPEN_MASK;
int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4;
if (row == 3)
return (FILE_MAXIMUM_DISPOSITION + 1);
return (ofun_cr_map[row][col]);
}
uint32_t
smb_common_open(smb_request_t *sr)
{
smb_server_t *sv = sr->sr_server;
smb_tree_t *tree = sr->tid_tree;
smb_node_t *fnode = NULL;
smb_node_t *dnode = NULL;
smb_node_t *cur_node = NULL;
smb_node_t *tmp_node = NULL;
smb_arg_open_t *op = &sr->sr_open;
smb_pathname_t *pn = &op->fqi.fq_path;
smb_ofile_t *of = NULL;
smb_attr_t new_attr;
hrtime_t shrlock_t0;
int max_requested = 0;
uint32_t max_allowed;
uint32_t status = NT_STATUS_SUCCESS;
int is_dir;
int rc;
boolean_t is_stream = B_FALSE;
int lookup_flags = SMB_FOLLOW_LINKS;
uint32_t uniq_fid = 0;
uint16_t tree_fid = 0;
boolean_t created = B_FALSE;
boolean_t last_comp_found = B_FALSE;
boolean_t stream_found = B_FALSE;
boolean_t opening_incr = B_FALSE;
boolean_t dnode_held = B_FALSE;
boolean_t dnode_wlock = B_FALSE;
boolean_t fnode_held = B_FALSE;
boolean_t fnode_wlock = B_FALSE;
boolean_t fnode_shrlk = B_FALSE;
boolean_t did_open = B_FALSE;
boolean_t did_break_handle = B_FALSE;
boolean_t did_cleanup_orphans = B_FALSE;
char *sname = NULL;
mutex_enter(&sr->sr_mutex);
if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
mutex_exit(&sr->sr_mutex);
return (NT_STATUS_CANCELLED);
}
mutex_exit(&sr->sr_mutex);
is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0;
if (is_dir) {
if ((op->create_disposition != FILE_CREATE) &&
(op->create_disposition != FILE_OPEN_IF) &&
(op->create_disposition != FILE_OPEN)) {
return (NT_STATUS_INVALID_PARAMETER);
}
}
if (op->desired_access & MAXIMUM_ALLOWED) {
max_requested = 1;
op->desired_access &= ~MAXIMUM_ALLOWED;
}
op->desired_access = smb_access_generic_to_file(op->desired_access);
if (sr->session->s_cfg.skc_max_opens != 0 &&
sr->session->s_file_cnt >= sr->session->s_cfg.skc_max_opens) {
ASSERT(sr->uid_user);
cmn_err(CE_NOTE, "smbsrv[%s\\%s]: TOO_MANY_OPENED_FILES",
sr->uid_user->u_domain, sr->uid_user->u_name);
return (NT_STATUS_TOO_MANY_OPENED_FILES);
}
if (smb_idpool_alloc(&tree->t_fid_pool, &tree_fid))
return (NT_STATUS_TOO_MANY_OPENED_FILES);
sr->fid_ofile = NULL;
op->devstate = 0;
switch (sr->tid_tree->t_res_type & STYPE_MASK) {
case STYPE_DISKTREE:
case STYPE_PRINTQ:
break;
case STYPE_IPC:
op->desired_access = (READ_CONTROL | SYNCHRONIZE |
FILE_READ_DATA | FILE_READ_ATTRIBUTES |
FILE_WRITE_DATA | FILE_APPEND_DATA);
if ((rc = smb_threshold_enter(&sv->sv_opipe_ct)) != 0) {
status = RPC_NT_SERVER_TOO_BUSY;
goto errout;
}
op->create_options = 0;
of = smb_ofile_alloc(sr, op, NULL, SMB_FTYPE_MESG_PIPE,
tree_fid);
tree_fid = 0;
status = smb_opipe_open(sr, of);
smb_threshold_exit(&sv->sv_opipe_ct);
if (status != NT_STATUS_SUCCESS)
goto errout;
return (NT_STATUS_SUCCESS);
default:
status = NT_STATUS_BAD_DEVICE_TYPE;
goto errout;
}
smb_pathname_init(sr, pn, pn->pn_path);
if (!smb_pathname_validate(sr, pn)) {
status = sr->smb_error.status;
goto errout;
}
if (strlen(pn->pn_path) >= SMB_MAXPATHLEN) {
status = NT_STATUS_OBJECT_PATH_INVALID;
goto errout;
}
if (is_dir) {
if (!smb_validate_dirname(sr, pn)) {
status = sr->smb_error.status;
goto errout;
}
} else {
if (!smb_validate_object_name(sr, pn)) {
status = sr->smb_error.status;
goto errout;
}
}
cur_node = op->fqi.fq_dnode ?
op->fqi.fq_dnode : sr->tid_tree->t_snode;
rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
sr->tid_tree->t_snode, cur_node, &op->fqi.fq_dnode,
op->fqi.fq_last_comp);
if (rc != 0) {
status = smb_errno2status(rc);
goto errout;
}
dnode = op->fqi.fq_dnode;
dnode_held = B_TRUE;
smb_node_wrlock(dnode);
dnode_wlock = B_TRUE;
if ((op->desired_access & ~FILE_READ_ATTRIBUTES) == DELETE)
lookup_flags &= ~SMB_FOLLOW_LINKS;
rc = smb_fsop_lookup_file(sr, zone_kcred(), lookup_flags,
sr->tid_tree->t_snode, op->fqi.fq_dnode, op->fqi.fq_last_comp,
&sname, &op->fqi.fq_fnode);
if (rc == 0) {
last_comp_found = B_TRUE;
fnode = op->fqi.fq_fnode;
fnode_held = B_TRUE;
op->fqi.fq_fattr.sa_mask = SMB_AT_DOSATTR;
rc = smb_node_getattr(sr, op->fqi.fq_fnode, zone_kcred(),
NULL, &op->fqi.fq_fattr);
if (rc != 0) {
status = NT_STATUS_INTERNAL_ERROR;
goto errout;
}
} else if (rc == ENOENT) {
last_comp_found = B_FALSE;
op->fqi.fq_fnode = NULL;
rc = 0;
} else {
status = smb_errno2status(rc);
goto errout;
}
if (last_comp_found) {
fnode = op->fqi.fq_fnode;
dnode = op->fqi.fq_dnode;
if (!smb_node_is_file(fnode) &&
!smb_node_is_dir(fnode) &&
!smb_node_is_symlink(fnode)) {
status = NT_STATUS_ACCESS_DENIED;
goto errout;
}
if (smb_node_is_dir(fnode) && sname == NULL) {
if (op->create_options & FILE_NON_DIRECTORY_FILE) {
status = NT_STATUS_FILE_IS_A_DIRECTORY;
goto errout;
}
} else {
if ((op->create_options & FILE_DIRECTORY_FILE) ||
(op->nt_flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)) {
status = NT_STATUS_NOT_A_DIRECTORY;
goto errout;
}
}
if (sname != NULL) {
tmp_node = fnode;
rc = smb_fsop_lookup_stream(sr, zone_kcred(),
lookup_flags, sr->tid_tree->t_snode, fnode, sname,
&fnode);
} else {
rc = 0;
}
if (rc == 0) {
stream_found = B_TRUE;
smb_node_unlock(dnode);
dnode_wlock = B_FALSE;
if (tmp_node != NULL)
smb_node_release(tmp_node);
if (fnode->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
status = NT_STATUS_DELETE_PENDING;
goto errout;
}
if (op->create_disposition == FILE_CREATE) {
status = NT_STATUS_OBJECT_NAME_COLLISION;
goto errout;
}
if ((op->create_disposition == FILE_SUPERSEDE) ||
(op->create_disposition == FILE_OVERWRITE_IF) ||
(op->create_disposition == FILE_OVERWRITE)) {
if (sname == NULL) {
if (!smb_sattr_check(
op->fqi.fq_fattr.sa_dosattr,
op->dattr)) {
status =
NT_STATUS_ACCESS_DENIED;
goto errout;
}
op->desired_access |=
FILE_WRITE_ATTRIBUTES;
}
if (smb_node_is_dir(fnode)) {
status = NT_STATUS_ACCESS_DENIED;
goto errout;
}
}
if (op->create_disposition == FILE_SUPERSEDE)
op->desired_access |= DELETE;
if ((op->create_disposition == FILE_OVERWRITE_IF) ||
(op->create_disposition == FILE_OVERWRITE))
op->desired_access |= FILE_WRITE_DATA;
} else if (rc == ENOENT) {
if (op->create_disposition == FILE_OPEN ||
op->create_disposition == FILE_OVERWRITE) {
status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
goto errout;
}
op->desired_access |= FILE_WRITE_DATA;
} else {
status = smb_errno2status(rc);
fnode = tmp_node;
goto errout;
}
if (SMB_PATHFILE_IS_READONLY(sr, fnode) &&
!smb_node_is_dir(fnode)) {
if (op->desired_access &
(FILE_WRITE_DATA | FILE_APPEND_DATA)) {
status = NT_STATUS_ACCESS_DENIED;
goto errout;
}
if (op->create_options & FILE_DELETE_ON_CLOSE) {
status = NT_STATUS_CANNOT_DELETE;
goto errout;
}
}
if ((op->create_options & FILE_DELETE_ON_CLOSE) != 0 &&
(fnode->flags & NODE_FLAGS_VFSROOT) != 0) {
status = NT_STATUS_CANNOT_DELETE;
goto errout;
}
status = smb_fsop_access(sr, sr->user_cr, fnode,
op->desired_access);
if (status != NT_STATUS_SUCCESS)
goto errout;
if (max_requested) {
smb_fsop_eaccess(sr, sr->user_cr, fnode, &max_allowed);
op->desired_access |= max_allowed;
}
if ((op->desired_access &
(READ_CONTROL | FILE_READ_ATTRIBUTES)) == 0) {
op->fqi.fq_fattr.sa_mask = SMB_AT_DOSATTR | SMB_AT_UID;
rc = smb_node_getattr(sr, op->fqi.fq_fnode,
zone_kcred(), NULL, &op->fqi.fq_fattr);
if (rc == 0 && crgetuid(sr->user_cr) ==
op->fqi.fq_fattr.sa_vattr.va_uid) {
op->desired_access |=
(READ_CONTROL | FILE_READ_ATTRIBUTES);
}
}
if ((op->desired_access & FILE_DATA_ALL) != 0)
op->desired_access |= FILE_READ_ATTRIBUTES;
if (!stream_found) {
smb_node_t *tmp_node = fnode;
bzero(&new_attr, sizeof (new_attr));
new_attr.sa_vattr.va_type = VREG;
new_attr.sa_vattr.va_mode = S_IRUSR;
new_attr.sa_mask |= SMB_AT_TYPE | SMB_AT_MODE;
rc = smb_fsop_create_stream(sr, sr->user_cr, dnode,
fnode, sname, lookup_flags, &new_attr, &fnode);
smb_node_release(tmp_node);
if (rc != 0) {
status = smb_errno2status(rc);
fnode_held = B_FALSE;
goto errout;
}
op->action_taken = SMB_OACT_CREATED;
created = B_TRUE;
smb_node_unlock(dnode);
dnode_wlock = B_FALSE;
}
of = smb_ofile_alloc(sr, op, fnode, SMB_FTYPE_DISK,
tree_fid);
tree_fid = 0;
uniq_fid = of->f_uniqid;
smb_node_inc_opening_count(fnode);
opening_incr = B_TRUE;
if (!stream_found) {
smb_node_wrlock(fnode);
fnode_wlock = B_TRUE;
status = smb_fsop_shrlock(sr->user_cr, fnode, uniq_fid,
op->desired_access, op->share_access);
if (status != 0)
goto errout;
fnode_shrlk = B_TRUE;
smb_node_unlock(fnode);
fnode_wlock = B_FALSE;
goto stream_created;
}
status = smb_oplock_break_BATCH(fnode, of,
op->desired_access, op->create_disposition);
if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
if (sr->session->dialect >= SMB_VERS_2_BASE)
(void) smb2sr_go_async(sr);
status = smb_oplock_wait_break(sr, fnode, 0);
}
if (status != NT_STATUS_SUCCESS)
goto errout;
shrlock_t0 = gethrtime();
shrlock_again:
smb_node_wrlock(fnode);
fnode_wlock = B_TRUE;
status = smb_fsop_shrlock(sr->user_cr, fnode, uniq_fid,
op->desired_access, op->share_access);
smb_node_unlock(fnode);
fnode_wlock = B_FALSE;
if (status == NT_STATUS_SHARING_VIOLATION &&
did_break_handle == B_FALSE) {
did_break_handle = B_TRUE;
status = smb_oplock_break_HANDLE(fnode, of);
if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
if (sr->session->dialect >= SMB_VERS_2_BASE)
(void) smb2sr_go_async(sr);
status = smb_oplock_wait_break(sr, fnode, 0);
} else {
delay(MSEC_TO_TICK(10));
}
if (status != NT_STATUS_SUCCESS)
goto errout;
goto shrlock_again;
}
if (status == NT_STATUS_SHARING_VIOLATION &&
sr->session->dialect >= SMB_VERS_2_BASE &&
did_cleanup_orphans == B_FALSE) {
did_cleanup_orphans = B_TRUE;
smb2_dh_close_my_orphans(sr, of);
goto shrlock_again;
}
if (status == NT_STATUS_SHARING_VIOLATION &&
sr->session->dialect < SMB_VERS_2_BASE) {
hrtime_t t1 = shrlock_t0 + NANOSEC;
hrtime_t now = gethrtime();
if (now < t1) {
delay(NSEC_TO_TICK_ROUNDUP(t1 - now));
}
}
if (status != NT_STATUS_SUCCESS)
goto errout;
fnode_shrlk = B_TRUE;
status = smb_oplock_break_OPEN(fnode, of,
op->desired_access,
op->create_disposition);
if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
if (sr->session->dialect >= SMB_VERS_2_BASE)
(void) smb2sr_go_async(sr);
status = smb_oplock_wait_break(sr, fnode, 0);
}
if (status != NT_STATUS_SUCCESS)
goto errout;
if ((fnode->flags & NODE_FLAGS_DELETE_COMMITTED) != 0) {
DTRACE_PROBE1(node_deleted, smb_node_t *, fnode);
tree_fid = of->f_fid;
of->f_fid = 0;
smb_ofile_free(of);
of = NULL;
last_comp_found = B_FALSE;
fnode_shrlk = B_FALSE;
smb_fsop_unshrlock(sr->user_cr, fnode, uniq_fid);
opening_incr = B_FALSE;
smb_node_dec_opening_count(fnode);
fnode_held = B_FALSE;
smb_node_release(fnode);
dnode_wlock = B_TRUE;
smb_node_wrlock(dnode);
goto create;
}
switch (op->create_disposition) {
case FILE_SUPERSEDE:
case FILE_OVERWRITE_IF:
case FILE_OVERWRITE:
bzero(&new_attr, sizeof (new_attr));
if (sname == NULL) {
op->dattr |= FILE_ATTRIBUTE_ARCHIVE;
if (op->dattr & FILE_ATTRIBUTE_READONLY) {
op->dattr &= ~FILE_ATTRIBUTE_READONLY;
op->created_readonly = B_TRUE;
}
new_attr.sa_dosattr = op->dattr;
} else {
new_attr.sa_dosattr = FILE_ATTRIBUTE_ARCHIVE;
}
new_attr.sa_vattr.va_size = 0;
new_attr.sa_mask = SMB_AT_DOSATTR | SMB_AT_SIZE;
rc = smb_fsop_setattr(sr, sr->user_cr, fnode,
&new_attr);
if (rc != 0) {
status = smb_errno2status(rc);
goto errout;
}
if (SMB_IS_STREAM(fnode) == 0) {
status = smb_fsop_remove_streams(sr,
sr->user_cr, fnode);
if (status != 0)
goto errout;
}
op->action_taken = SMB_OACT_TRUNCATED;
break;
default:
op->dsize = 0L;
op->action_taken = SMB_OACT_OPENED;
break;
}
} else {
create:
dnode = op->fqi.fq_dnode;
if (is_dir == 0)
is_stream = smb_is_stream_name(pn->pn_path);
if ((op->create_disposition == FILE_OPEN) ||
(op->create_disposition == FILE_OVERWRITE)) {
status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
goto errout;
}
if (is_dir != 0 &&
(op->dattr & FILE_ATTRIBUTE_TEMPORARY) != 0) {
status = NT_STATUS_INVALID_PARAMETER;
goto errout;
}
if ((op->dattr & FILE_ATTRIBUTE_READONLY) != 0 &&
(op->create_options & FILE_DELETE_ON_CLOSE) != 0) {
status = NT_STATUS_CANNOT_DELETE;
goto errout;
}
if ((op->desired_access & ACCESS_SYSTEM_SECURITY) != 0 &&
!smb_user_has_security_priv(sr->uid_user, sr->user_cr)) {
status = NT_STATUS_ACCESS_DENIED;
goto errout;
}
if (pn->pn_fname && smb_is_invalid_filename(pn->pn_fname)) {
status = NT_STATUS_OBJECT_NAME_INVALID;
goto errout;
}
if (dnode->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
status = NT_STATUS_DELETE_PENDING;
goto errout;
}
bzero(&new_attr, sizeof (new_attr));
new_attr.sa_mask = SMB_AT_DOSATTR | SMB_AT_TYPE | SMB_AT_MODE;
if (op->dattr & FILE_ATTRIBUTE_READONLY) {
op->dattr &= ~FILE_ATTRIBUTE_READONLY;
op->created_readonly = B_TRUE;
}
if ((op->crtime.tv_sec != 0) &&
(op->crtime.tv_sec != UINT_MAX)) {
new_attr.sa_mask |= SMB_AT_CRTIME;
new_attr.sa_crtime = op->crtime;
}
if (is_dir == 0) {
op->dattr |= FILE_ATTRIBUTE_ARCHIVE;
new_attr.sa_dosattr = op->dattr;
new_attr.sa_vattr.va_type = VREG;
if (is_stream)
new_attr.sa_vattr.va_mode = S_IRUSR | S_IWUSR;
else
new_attr.sa_vattr.va_mode =
S_IRUSR | S_IRGRP | S_IROTH |
S_IWUSR | S_IWGRP | S_IWOTH;
if (sr->smb_com == SMB_COM_OPEN_ANDX) {
new_attr.sa_vattr.va_size = op->dsize;
new_attr.sa_mask |= SMB_AT_SIZE;
}
rc = smb_fsop_create(sr, sr->user_cr, dnode,
op->fqi.fq_last_comp, &new_attr, &op->fqi.fq_fnode);
} else {
op->dattr |= FILE_ATTRIBUTE_DIRECTORY;
new_attr.sa_dosattr = op->dattr;
new_attr.sa_vattr.va_type = VDIR;
new_attr.sa_vattr.va_mode = 0777;
rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
op->fqi.fq_last_comp, &new_attr, &op->fqi.fq_fnode);
}
if (rc != 0) {
status = smb_errno2status(rc);
goto errout;
}
smb_node_unlock(dnode);
dnode_wlock = B_FALSE;
created = B_TRUE;
op->action_taken = SMB_OACT_CREATED;
fnode = op->fqi.fq_fnode;
fnode_held = B_TRUE;
if (max_requested) {
smb_fsop_eaccess(sr, sr->user_cr, fnode, &max_allowed);
op->desired_access |= max_allowed;
}
op->desired_access |= (READ_CONTROL | FILE_READ_ATTRIBUTES);
of = smb_ofile_alloc(sr, op, fnode, SMB_FTYPE_DISK,
tree_fid);
tree_fid = 0;
uniq_fid = of->f_uniqid;
smb_node_inc_opening_count(fnode);
opening_incr = B_TRUE;
smb_node_wrlock(fnode);
fnode_wlock = B_TRUE;
status = smb_fsop_shrlock(sr->user_cr, fnode, uniq_fid,
op->desired_access, op->share_access);
if (status != 0)
goto errout;
fnode_shrlk = B_TRUE;
(void) smb_oplock_break_PARENT(dnode, of);
}
stream_created:
if (!smb_tree_is_connected(sr->tid_tree)) {
status = NT_STATUS_INVALID_PARAMETER;
goto errout;
}
if ((rc = smb_fsop_open(fnode, of->f_mode, of->f_cr)) != 0) {
status = smb_errno2status(rc);
goto errout;
}
smb_ofile_open(sr, op, of);
did_open = B_TRUE;
if ((rc = smb_set_open_attributes(sr, of)) != 0) {
status = smb_errno2status(rc);
goto errout;
}
op->fqi.fq_fattr.sa_mask = SMB_AT_ALL;
(void) smb_node_getattr(sr, fnode, zone_kcred(), of,
&op->fqi.fq_fattr);
if (sr->sr_cfg->skc_sync_enable ||
(op->create_options & FILE_WRITE_THROUGH))
fnode->flags |= NODE_FLAGS_WRITE_THROUGH;
op->fileid = op->fqi.fq_fattr.sa_vattr.va_nodeid;
op->dattr = op->fqi.fq_fattr.sa_dosattr;
op->ftype = SMB_FTYPE_DISK;
sr->smb_fid = of->f_fid;
sr->fid_ofile = of;
if (smb_node_is_file(fnode)) {
op->dsize = op->fqi.fq_fattr.sa_vattr.va_size;
} else {
op->dsize = 0;
}
if (sname != NULL)
kmem_free(sname, MAXNAMELEN);
if (fnode_wlock)
smb_node_unlock(fnode);
if (opening_incr)
smb_node_dec_opening_count(fnode);
if (fnode_held)
smb_node_release(fnode);
if (dnode_wlock)
smb_node_unlock(dnode);
if (dnode_held)
smb_node_release(dnode);
return (NT_STATUS_SUCCESS);
errout:
if (did_open) {
smb_ofile_close(of, 0);
} else if (of != NULL) {
smb_ofile_free(of);
}
if (fnode_shrlk)
smb_fsop_unshrlock(sr->user_cr, fnode, uniq_fid);
if (created) {
smb_delete_new_object(sr);
}
if (sname != NULL)
kmem_free(sname, MAXNAMELEN);
if (fnode_wlock)
smb_node_unlock(fnode);
if (opening_incr)
smb_node_dec_opening_count(fnode);
if (fnode_held)
smb_node_release(fnode);
if (dnode_wlock)
smb_node_unlock(dnode);
if (dnode_held)
smb_node_release(dnode);
if (tree_fid != 0)
smb_idpool_free(&tree->t_fid_pool, tree_fid);
return (status);
}
static int
smb_set_open_attributes(smb_request_t *sr, smb_ofile_t *of)
{
smb_attr_t attr;
smb_arg_open_t *op = &sr->sr_open;
smb_node_t *node = of->f_node;
int rc = 0;
bzero(&attr, sizeof (smb_attr_t));
if (op->created_readonly) {
attr.sa_dosattr = op->dattr | FILE_ATTRIBUTE_READONLY;
attr.sa_mask |= SMB_AT_DOSATTR;
}
if (op->dsize != 0) {
attr.sa_allocsz = op->dsize;
attr.sa_mask |= SMB_AT_ALLOCSZ;
}
if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX)) {
attr.sa_vattr.va_mtime = op->mtime;
attr.sa_mask |= SMB_AT_MTIME;
}
if (attr.sa_mask != 0)
rc = smb_node_setattr(sr, node, of->f_cr, of, &attr);
return (rc);
}
static void
smb_delete_new_object(smb_request_t *sr)
{
smb_arg_open_t *op = &sr->sr_open;
smb_fqi_t *fqi = &(op->fqi);
uint32_t flags = 0;
if (SMB_TREE_IS_CASEINSENSITIVE(sr))
flags |= SMB_IGNORE_CASE;
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
if (op->create_options & FILE_DIRECTORY_FILE)
(void) smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode,
fqi->fq_last_comp, flags);
else
(void) smb_fsop_remove(sr, sr->user_cr, fqi->fq_dnode,
fqi->fq_last_comp, flags);
}