summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/fs')
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_open.c24
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_create.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_delete.c17
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_directory.c191
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dispatch.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_find.c6
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fsops.c60
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mangle_name.c5
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c52
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_node.c253
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c30
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_odir.c31
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_ofile.c14
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_open_andx.c9
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c79
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c891
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_information.c145
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_information2.c127
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_rename.c193
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c683
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_information.c172
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_information2.c130
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_find.c12
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c636
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c663
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c160
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c386
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c180
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree.c8
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_util.c63
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_vops.c13
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_write_raw.c19
34 files changed, 2255 insertions, 3009 deletions
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
index 8525dcb4b7..74049d0c60 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
@@ -441,14 +441,11 @@ smb_open_subr(smb_request_t *sr)
if (rc == 0) {
last_comp_found = B_TRUE;
- (void) strcpy(op->fqi.fq_od_name,
- op->fqi.fq_fnode->od_name);
rc = smb_node_getattr(sr, op->fqi.fq_fnode,
&op->fqi.fq_fattr);
if (rc != 0) {
smb_node_release(op->fqi.fq_fnode);
smb_node_release(op->fqi.fq_dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
ERRDOS, ERROR_INTERNAL_ERROR);
return (sr->smb_error.status);
@@ -459,7 +456,6 @@ smb_open_subr(smb_request_t *sr)
rc = 0;
} else {
smb_node_release(op->fqi.fq_dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_errno(sr, rc);
return (sr->smb_error.status);
}
@@ -481,7 +477,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_release(op->fqi.fq_fnode);
smb_node_release(op->fqi.fq_dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
ERRnoaccess);
return (NT_STATUS_ACCESS_DENIED);
@@ -501,7 +496,6 @@ smb_open_subr(smb_request_t *sr)
if (op->create_options & FILE_NON_DIRECTORY_FILE) {
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY,
ERRDOS, ERROR_ACCESS_DENIED);
return (NT_STATUS_FILE_IS_A_DIRECTORY);
@@ -511,7 +505,6 @@ smb_open_subr(smb_request_t *sr)
(op->nt_flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)) {
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
ERRDOS, ERROR_DIRECTORY);
return (NT_STATUS_NOT_A_DIRECTORY);
@@ -525,7 +518,6 @@ smb_open_subr(smb_request_t *sr)
if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_DELETE_PENDING,
ERRDOS, ERROR_ACCESS_DENIED);
return (NT_STATUS_DELETE_PENDING);
@@ -537,7 +529,6 @@ smb_open_subr(smb_request_t *sr)
if (op->create_disposition == FILE_CREATE) {
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
ERRDOS, ERROR_FILE_EXISTS);
return (NT_STATUS_OBJECT_NAME_COLLISION);
@@ -557,7 +548,6 @@ smb_open_subr(smb_request_t *sr)
FILE_APPEND_DATA)) {
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
ERRDOS, ERRnoaccess);
return (NT_STATUS_ACCESS_DENIED);
@@ -582,7 +572,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
ERRDOS, ERRnoaccess);
return (NT_STATUS_ACCESS_DENIED);
@@ -596,7 +585,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
return (status);
}
@@ -609,7 +597,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
if (status == NT_STATUS_PRIVILEGE_NOT_HELD) {
smbsr_error(sr, status,
@@ -631,7 +618,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
ERRDOS, ERROR_ACCESS_DENIED);
return (NT_STATUS_ACCESS_DENIED);
@@ -654,7 +640,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_errno(sr, rc);
return (sr->smb_error.status);
}
@@ -671,7 +656,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
return (sr->smb_error.status);
}
}
@@ -696,7 +680,6 @@ smb_open_subr(smb_request_t *sr)
if ((op->create_disposition == FILE_OPEN) ||
(op->create_disposition == FILE_OVERWRITE)) {
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
ERRDOS, ERROR_FILE_NOT_FOUND);
return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
@@ -705,7 +688,6 @@ smb_open_subr(smb_request_t *sr)
if ((is_dir == 0) && (!is_stream) &&
smb_is_invalid_filename(op->fqi.fq_last_comp)) {
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
ERRDOS, ERROR_INVALID_NAME);
return (NT_STATUS_OBJECT_NAME_INVALID);
@@ -752,7 +734,6 @@ smb_open_subr(smb_request_t *sr)
if (rc != 0) {
smb_node_unlock(dnode);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_errno(sr, rc);
return (sr->smb_error.status);
}
@@ -769,7 +750,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_release(node);
smb_node_unlock(dnode);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
return (status);
}
} else {
@@ -785,7 +765,6 @@ smb_open_subr(smb_request_t *sr)
if (rc != 0) {
smb_node_unlock(dnode);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_errno(sr, rc);
return (sr->smb_error.status);
}
@@ -796,7 +775,6 @@ smb_open_subr(smb_request_t *sr)
created = B_TRUE;
op->action_taken = SMB_OACT_CREATED;
- node->flags |= NODE_FLAGS_CREATED;
}
if (max_requested) {
@@ -857,7 +835,6 @@ smb_open_subr(smb_request_t *sr)
if (created)
smb_node_unlock(dnode);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
return (status);
}
@@ -896,7 +873,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
return (NT_STATUS_SUCCESS);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_create.c b/usr/src/uts/common/fs/smbsrv/smb_create.c
index fe01c89490..ddc8408248 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_create.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_create.c
@@ -185,7 +185,7 @@ smb_common_create(smb_request_t *sr)
uint32_t status;
if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX))
- op->mtime.tv_sec = smb_local2gmt(sr, op->mtime.tv_sec);
+ op->mtime.tv_sec = smb_time_local_to_gmt(sr, op->mtime.tv_sec);
op->mtime.tv_nsec = 0;
op->dsize = 0;
op->omode = SMB_DA_ACCESS_READ_WRITE | SMB_DA_SHARE_COMPATIBILITY;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete.c b/usr/src/uts/common/fs/smbsrv/smb_delete.c
index c486ae9f30..7c1481bfae 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c
@@ -31,7 +31,7 @@
static int smb_delete_check_path(smb_request_t *, boolean_t *);
static int smb_delete_single_file(smb_request_t *, smb_error_t *);
static int smb_delete_multiple_files(smb_request_t *, smb_error_t *);
-static int smb_delete_find_fname(smb_request_t *, smb_odir_t *);
+static int smb_delete_find_fname(smb_request_t *, smb_odir_t *, char *, int);
static int smb_delete_check_dosattr(smb_request_t *, smb_error_t *);
static int smb_delete_remove_file(smb_request_t *, smb_error_t *);
@@ -276,6 +276,7 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
smb_fqi_t *fqi;
uint16_t odid;
smb_odir_t *od;
+ char namebuf[MAXNAMELEN];
fqi = &sr->arg.dirop.fqi;
@@ -292,13 +293,13 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
return (-1);
for (;;) {
- rc = smb_delete_find_fname(sr, od);
+ rc = smb_delete_find_fname(sr, od, namebuf, MAXNAMELEN);
if (rc != 0)
break;
rc = smb_fsop_lookup_name(sr, sr->user_cr, 0,
sr->tid_tree->t_snode, fqi->fq_dnode,
- fqi->fq_od_name, &fqi->fq_fnode);
+ namebuf, &fqi->fq_fnode);
if (rc != 0)
break;
@@ -351,8 +352,8 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
/*
* smb_delete_find_fname
*
- * Find next filename that matches search pattern (fqi->fq_last_comp)
- * and save it in fqi->fq_od_name.
+ * Find next filename that matches search pattern and return it
+ * in namebuf.
*
* Case insensitivity note:
* If the tree is case insensitive and there's a case conflict
@@ -365,7 +366,7 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
* errno
*/
static int
-smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od)
+smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od, char *namebuf, int len)
{
int rc;
smb_odirent_t *odirent;
@@ -373,9 +374,7 @@ smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od)
char *name;
char shortname[SMB_SHORTNAMELEN];
char name83[SMB_SHORTNAMELEN];
- smb_fqi_t *fqi;
- fqi = &sr->arg.dirop.fqi;
odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
rc = smb_odir_read(sr, od, odirent, &eos);
@@ -397,7 +396,7 @@ smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od)
} else {
name = odirent->od_name;
}
- (void) strlcpy(fqi->fq_od_name, name, sizeof (fqi->fq_od_name));
+ (void) strlcpy(namebuf, name, len);
kmem_free(odirent, sizeof (smb_odirent_t));
return (0);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_directory.c b/usr/src/uts/common/fs/smbsrv/smb_directory.c
index c59d8cce2e..60d95d0198 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_directory.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_directory.c
@@ -91,9 +91,9 @@ smb_sdrc_t
smb_com_create_directory(smb_request_t *sr)
{
smb_dirpath_t *spp;
- smb_attr_t *attr;
DWORD status;
int rc = 0;
+ char *path = sr->arg.dirop.fqi.fq_path.pn_path;
if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
@@ -101,13 +101,13 @@ smb_com_create_directory(smb_request_t *sr)
return (SDRC_ERROR);
}
- if (!smb_dirpath_isvalid(sr->arg.dirop.fqi.fq_path.pn_path)) {
+ if (!smb_dirpath_isvalid(path)) {
smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
ERRDOS, ERROR_BAD_PATHNAME);
return (SDRC_ERROR);
}
- status = smb_validate_dirname(sr->arg.dirop.fqi.fq_path.pn_path);
+ status = smb_validate_dirname(path);
if (status != 0) {
smbsr_error(sr, status, ERRDOS, ERROR_INVALID_NAME);
return (SDRC_ERROR);
@@ -126,20 +126,17 @@ smb_com_create_directory(smb_request_t *sr)
case 0:
break;
case EEXIST:
- attr = &sr->arg.dirop.fqi.fq_fattr;
-
- if (attr->sa_vattr.va_type != VDIR) {
- smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
- ERRDOS, ERROR_PATH_NOT_FOUND);
- return (SDRC_ERROR);
- }
break;
case ENOENT:
smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
ERRDOS, ERROR_FILE_NOT_FOUND);
return (SDRC_ERROR);
case ENOTDIR:
- smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
+ /*
+ * Spec says status should be OBJECT_PATH_INVALID
+ * but testing shows OBJECT_PATH_NOT_FOUND
+ */
+ smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND,
ERRDOS, ERROR_PATH_NOT_FOUND);
return (SDRC_ERROR);
default:
@@ -149,7 +146,11 @@ smb_com_create_directory(smb_request_t *sr)
}
if (rc != 0) {
- smbsr_errno(sr, rc);
+ if (rc == EEXIST)
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
+ ERRDOS, ERROR_FILE_EXISTS);
+ else
+ smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
@@ -195,25 +196,36 @@ smb_common_create_directory(smb_request_t *sr)
{
int rc;
smb_attr_t new_attr;
- smb_node_t *dnode;
- smb_node_t *node;
+ smb_fqi_t *fqi;
+ smb_node_t *tnode;
- sr->arg.dirop.fqi.fq_sattr = 0;
+ fqi = &sr->arg.dirop.fqi;
+ tnode = sr->tid_tree->t_snode;
- rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_NOT_EXIST);
- if (rc)
+ rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
+ tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
+ if (rc != 0)
return (rc);
- /*
- * Because of FQM_PATH_MUST_NOT_EXIST and the successful return
- * value, only fqi.fq_dnode has a valid parameter (fqi.fq_fnode
- * is NULL).
- */
- dnode = sr->arg.dirop.fqi.fq_dnode;
+ /* lookup node - to ensure that it does NOT exist */
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
+ if (rc == 0) {
+ smb_node_release(fqi->fq_dnode);
+ smb_node_release(fqi->fq_fnode);
+ return (EEXIST);
+ }
+ if (rc != ENOENT) {
+ smb_node_release(fqi->fq_dnode);
+ return (rc);
+ }
- rc = smb_fsop_access(sr, sr->user_cr, dnode, FILE_ADD_SUBDIRECTORY);
- if (rc != NT_STATUS_SUCCESS)
+ rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_dnode,
+ FILE_ADD_SUBDIRECTORY);
+ if (rc != NT_STATUS_SUCCESS) {
+ smb_node_release(fqi->fq_dnode);
return (EACCES);
+ }
/*
* Explicitly set sa_dosattr, otherwise the file system may
@@ -226,28 +238,17 @@ smb_common_create_directory(smb_request_t *sr)
new_attr.sa_vattr.va_mode = 0777;
new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE | SMB_AT_DOSATTR;
- if ((rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
- sr->arg.dirop.fqi.fq_last_comp, &new_attr,
- &sr->arg.dirop.fqi.fq_fnode)) != 0) {
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
- return (rc);
- }
-
- node = sr->arg.dirop.fqi.fq_fnode;
- rc = smb_node_getattr(sr, node, &sr->arg.dirop.fqi.fq_fattr);
+ rc = smb_fsop_mkdir(sr, sr->user_cr, fqi->fq_dnode, fqi->fq_last_comp,
+ &new_attr, &fqi->fq_fnode);
if (rc != 0) {
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ smb_node_release(fqi->fq_dnode);
return (rc);
}
- node->flags |= NODE_FLAGS_CREATED;
sr->arg.open.create_options = FILE_DIRECTORY_FILE;
- smb_node_release(node);
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ smb_node_release(fqi->fq_dnode);
+ smb_node_release(fqi->fq_fnode);
return (0);
}
@@ -364,10 +365,10 @@ smb_post_delete_directory(smb_request_t *sr)
smb_sdrc_t
smb_com_delete_directory(smb_request_t *sr)
{
- smb_node_t *dnode;
- smb_attr_t *attr;
int rc;
uint32_t flags = 0;
+ smb_fqi_t *fqi;
+ smb_node_t *tnode;
if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
@@ -375,50 +376,64 @@ smb_com_delete_directory(smb_request_t *sr)
return (SDRC_ERROR);
}
- sr->arg.dirop.fqi.fq_sattr = 0;
+ fqi = &sr->arg.dirop.fqi;
+ tnode = sr->tid_tree->t_snode;
- rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
- if (rc) {
+ rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
+ tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (SDRC_ERROR);
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
+ if (rc != 0) {
if (rc == ENOENT)
smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
ERRDOS, ERROR_FILE_NOT_FOUND);
else
smbsr_errno(sr, rc);
+ smb_node_release(fqi->fq_dnode);
return (SDRC_ERROR);
}
- attr = &sr->arg.dirop.fqi.fq_fattr;
- if (attr->sa_vattr.va_type != VDIR) {
+ rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ smb_node_release(fqi->fq_dnode);
+ smb_node_release(fqi->fq_fnode);
+ return (SDRC_ERROR);
+ }
+
+ if (fqi->fq_fattr.sa_vattr.va_type != VDIR) {
smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
ERRDOS, ERROR_PATH_NOT_FOUND);
+ smb_node_release(fqi->fq_dnode);
+ smb_node_release(fqi->fq_fnode);
return (SDRC_ERROR);
}
- dnode = sr->arg.dirop.fqi.fq_fnode;
- rc = smb_fsop_access(sr, sr->user_cr, dnode, DELETE);
-
- if ((rc != NT_STATUS_SUCCESS) ||
- attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) {
- smb_node_release(dnode);
- smb_node_release(sr->arg.dirop.fqi.fq_dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ if ((fqi->fq_fattr.sa_dosattr & FILE_ATTRIBUTE_READONLY) ||
+ (smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, DELETE)
+ != NT_STATUS_SUCCESS)) {
smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
ERRDOS, ERROR_ACCESS_DENIED);
+ smb_node_release(fqi->fq_dnode);
+ smb_node_release(fqi->fq_fnode);
return (SDRC_ERROR);
}
- smb_node_release(dnode);
-
- dnode = sr->arg.dirop.fqi.fq_dnode;
-
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
- rc = smb_fsop_rmdir(sr, sr->user_cr, dnode,
- sr->arg.dirop.fqi.fq_od_name, flags);
+ rc = smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode,
+ fqi->fq_fnode->od_name, flags);
+
+ smb_node_release(fqi->fq_fnode);
+ smb_node_release(fqi->fq_dnode);
+
if (rc != 0) {
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
if (rc == EEXIST)
smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY,
ERRDOS, ERROR_DIR_NOT_EMPTY);
@@ -427,9 +442,6 @@ smb_com_delete_directory(smb_request_t *sr)
return (SDRC_ERROR);
}
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
-
rc = smbsr_encode_empty_result(sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
@@ -483,8 +495,10 @@ smb_post_check_directory(smb_request_t *sr)
smb_sdrc_t
smb_com_check_directory(smb_request_t *sr)
{
- smb_node_t *dnode;
int rc;
+ smb_fqi_t *fqi;
+ smb_node_t *tnode;
+ char *path;
if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
@@ -492,21 +506,33 @@ smb_com_check_directory(smb_request_t *sr)
return (SDRC_ERROR);
}
- if (sr->arg.dirop.fqi.fq_path.pn_path[0] == '\0') {
+ fqi = &sr->arg.dirop.fqi;
+ path = fqi->fq_path.pn_path;
+
+ if (path[0] == '\0') {
rc = smbsr_encode_empty_result(sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
- if (!smb_dirpath_isvalid(sr->arg.dirop.fqi.fq_path.pn_path)) {
+ if (!smb_dirpath_isvalid(path)) {
smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
ERRDOS, ERROR_PATH_NOT_FOUND);
return (SDRC_ERROR);
}
- sr->arg.dirop.fqi.fq_sattr = 0;
+ tnode = sr->tid_tree->t_snode;
- rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
- if (rc) {
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
+ &fqi->fq_dnode, fqi->fq_last_comp);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (SDRC_ERROR);
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
+ smb_node_release(fqi->fq_dnode);
+ if (rc != 0) {
if (rc == ENOENT)
smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
ERRDOS, ERROR_PATH_NOT_FOUND);
@@ -515,22 +541,23 @@ smb_com_check_directory(smb_request_t *sr)
return (SDRC_ERROR);
}
- smb_node_release(sr->arg.dirop.fqi.fq_dnode);
-
- dnode = sr->arg.dirop.fqi.fq_fnode;
+ rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ smb_node_release(fqi->fq_fnode);
+ return (SDRC_ERROR);
+ }
- if (sr->arg.dirop.fqi.fq_fattr.sa_vattr.va_type != VDIR) {
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ if (fqi->fq_fattr.sa_vattr.va_type != VDIR) {
smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
ERRDOS, ERROR_PATH_NOT_FOUND);
+ smb_node_release(fqi->fq_fnode);
return (SDRC_ERROR);
}
- rc = smb_fsop_access(sr, sr->user_cr, dnode, FILE_TRAVERSE);
+ rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, FILE_TRAVERSE);
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ smb_node_release(fqi->fq_fnode);
if (rc != 0) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
index d4e7747c83..75b42e37bb 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
@@ -1158,7 +1158,7 @@ smbsr_lookup_xa(smb_request_t *sr)
}
void
-smbsr_disconnect_file(smb_request_t *sr)
+smbsr_release_file(smb_request_t *sr)
{
smb_ofile_t *of = sr->fid_ofile;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_find.c b/usr/src/uts/common/fs/smbsrv/smb_find.c
index 99ec45c8e4..ec55d1e6ba 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_find.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_find.c
@@ -340,7 +340,7 @@ smb_com_search(smb_request_t *sr)
fileinfo.fi_name83, fileinfo.fi_name83+9,
index, odid, client_key,
fileinfo.fi_dosattr & 0xff,
- smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec),
(int32_t)fileinfo.fi_size,
name);
@@ -476,7 +476,7 @@ smb_com_find(smb_request_t *sr)
fileinfo.fi_name83, fileinfo.fi_name83+9,
index, odid, client_key,
fileinfo.fi_dosattr & 0xff,
- smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec),
(int32_t)fileinfo.fi_size,
name);
@@ -654,7 +654,7 @@ smb_com_find_unique(struct smb_request *sr)
fileinfo.fi_name83, fileinfo.fi_name83+9,
index, odid, client_key,
fileinfo.fi_dosattr & 0xff,
- smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec),
(int32_t)fileinfo.fi_size,
name);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsops.c b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
index 358fc93c3a..c427df5632 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
@@ -340,6 +340,8 @@ smb_fsop_create(smb_request_t *sr, cred_t *cr, smb_node_t *dnode,
flags = SMB_IGNORE_CASE;
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
if (smb_is_stream_name(name)) {
fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
@@ -358,7 +360,8 @@ smb_fsop_create(smb_request_t *sr, cred_t *cr, smb_node_t *dnode,
if (smb_maybe_mangled_name(name)) {
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
+ rc = smb_unmangle_name(dnode, name, longname,
+ MAXNAMELEN, flags);
kmem_free(longname, MAXNAMELEN);
if (rc == 0)
@@ -575,10 +578,13 @@ smb_fsop_mkdir(
return (EROFS);
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
if (smb_maybe_mangled_name(name)) {
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
+ rc = smb_unmangle_name(dnode, name, longname,
+ MAXNAMELEN, flags);
kmem_free(longname, MAXNAMELEN);
/*
@@ -733,8 +739,11 @@ smb_fsop_remove(
}
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
+
rc = smb_unmangle_name(dnode, name,
- longname, MAXNAMELEN);
+ longname, MAXNAMELEN, flags);
if (rc == 0) {
/*
@@ -866,7 +875,11 @@ smb_fsop_rmdir(
return (rc);
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
+
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
+ rc = smb_unmangle_name(dnode, name, longname,
+ MAXNAMELEN, flags);
if (rc == 0) {
/*
@@ -989,10 +1002,13 @@ smb_fsop_link(smb_request_t *sr, cred_t *cr, smb_node_t *to_dnode,
flags = SMB_IGNORE_CASE;
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
if (smb_maybe_mangled_name(to_name)) {
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- rc = smb_unmangle_name(to_dnode, to_name, longname, MAXNAMELEN);
+ rc = smb_unmangle_name(to_dnode, to_name,
+ longname, MAXNAMELEN, flags);
kmem_free(longname, MAXNAMELEN);
if (rc == 0)
@@ -1116,7 +1132,8 @@ smb_fsop_rename(
* Please document any direct call to explain the reason
* for avoiding this wrapper.
*
- * It is assumed that a reference exists on snode coming into this routine.
+ * It is assumed that a reference exists on snode coming into
+ * this function.
* A null smb_request might be passed to this function.
*/
int
@@ -1149,6 +1166,11 @@ smb_fsop_setattr(
ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0)
return (EACCES);
+ /*
+ * The file system cannot detect pending READDONLY
+ * (i.e. if the file has been opened readonly but
+ * not yet closed) so we need to test READONLY here.
+ */
if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) {
if (sr->fid_ofile) {
if (SMB_OFILE_IS_READONLY(sr->fid_ofile))
@@ -1159,14 +1181,29 @@ smb_fsop_setattr(
}
}
- /* sr could be NULL in some cases */
+ /*
+ * SMB checks access on open and retains an access granted
+ * mask for use while the file is open. ACL changes should
+ * not affect access to an open file.
+ *
+ * If the setattr is being performed on an ofile:
+ * - Check the ofile's access granted mask to see if the
+ * setattr is permitted.
+ * UID, GID - require WRITE_OWNER
+ * SIZE, ALLOCSZ - require FILE_WRITE_DATA
+ * all other attributes require FILE_WRITE_ATTRIBUTES
+ *
+ * - If the file system does access checking, set the
+ * ATTR_NOACLCHECK flag to ensure that the file system
+ * does not check permissions on subsequent calls.
+ */
if (sr && sr->fid_ofile) {
sa_mask = set_attr->sa_mask;
access = 0;
- if (sa_mask & SMB_AT_SIZE) {
+ if (sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ)) {
access |= FILE_WRITE_DATA;
- sa_mask &= ~SMB_AT_SIZE;
+ sa_mask &= ~(SMB_AT_SIZE | SMB_AT_ALLOCSZ);
}
if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) {
@@ -1645,6 +1682,8 @@ smb_fsop_lookup(
flags |= SMB_IGNORE_CASE;
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
@@ -1658,7 +1697,8 @@ smb_fsop_lookup(
}
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
+ rc = smb_unmangle_name(dnode, name, longname,
+ MAXNAMELEN, flags);
if (rc != 0) {
kmem_free(od_name, MAXNAMELEN);
kmem_free(longname, MAXNAMELEN);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
index e8b17c6d96..2d73bb38ac 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
@@ -664,7 +664,8 @@ int smb_mangle_name(
*/
#define SMB_UNMANGLE_BUFSIZE (4 * 1024)
int
-smb_unmangle_name(smb_node_t *dnode, char *name, char *namebuf, int buflen)
+smb_unmangle_name(smb_node_t *dnode, char *name, char *namebuf,
+ int buflen, uint32_t flags)
{
int err, eof, bufsize, reclen;
uint64_t offset;
@@ -700,7 +701,7 @@ smb_unmangle_name(smb_node_t *dnode, char *name, char *namebuf, int buflen)
offset = 0;
while ((err = smb_vop_readdir(vp, offset, buf, &bufsize,
- &eof, kcred)) == 0) {
+ &eof, flags, kcred)) == 0) {
if (bufsize == 0) {
err = ENOENT;
break;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
index 7e0ee57629..3eb054e383 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
@@ -29,6 +29,9 @@
#include <smbsrv/smb_incl.h>
+#include <sys/sunddi.h>
+
+
#define MALLOC_QUANTUM 80
#define DECODE_NO_ERROR 0
@@ -36,6 +39,7 @@
#define DECODE_ALLOCATION_ERROR 2
#define DECODE_CONVERSION_ERROR 3
+static int mbc_marshal_cstou8(char *, char *, size_t, char *, size_t);
static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
@@ -323,7 +327,7 @@ unicode_translation:
if (mbc_marshal_get_short(mbc,
(uint16_t *)&d) != 0)
return (-1);
- *lvalp++ = smb_dos_to_ux_time(d, t);
+ *lvalp++ = smb_time_dos_to_unix(d, t);
}
break;
@@ -338,7 +342,7 @@ unicode_translation:
if (mbc_marshal_get_short(mbc,
(uint16_t *)&t) != 0)
return (-1);
- *lvalp++ = smb_dos_to_ux_time(d, t);
+ *lvalp++ = smb_time_dos_to_unix(d, t);
}
break;
@@ -554,7 +558,7 @@ smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
case 'T':
tvp = va_arg(ap, timestruc_t *);
- nt_time = unix_to_nt_time(tvp);
+ nt_time = smb_time_unix_to_nt(tvp);
if (mbc_marshal_put_long_long(mbc, nt_time) != 0)
return (DECODE_NO_MORE_DATA);
break;
@@ -653,7 +657,7 @@ ascii_conversion: cvalp = va_arg(ap, uint8_t *);
uint16_t d, t;
lval = va_arg(ap, uint32_t);
- (void) smb_ux_to_dos_time(lval,
+ smb_time_unix_to_dos(lval,
(short *)&d, (short *)&t);
if (mbc_marshal_put_short(mbc, t) != 0)
return (DECODE_NO_MORE_DATA);
@@ -667,7 +671,7 @@ ascii_conversion: cvalp = va_arg(ap, uint8_t *);
uint16_t d, t;
lval = va_arg(ap, uint32_t);
- (void) smb_ux_to_dos_time(lval,
+ smb_time_unix_to_dos(lval,
(short *)&d, (short *)&t);
if (mbc_marshal_put_short(mbc, d) != 0)
return (DECODE_NO_MORE_DATA);
@@ -1218,10 +1222,8 @@ mbc_marshal_get_ascii_string(
{
char *rcvbuf;
char *ch;
- mts_wchar_t *wtmpbuf;
int max;
int length = 0;
- uint_t cpid = oem_get_smb_cpid();
max = MALLOC_QUANTUM;
rcvbuf = smbsr_malloc(ml, max);
@@ -1254,15 +1256,9 @@ multibyte_encode:
* UTF-8 encode the string for internal system use.
*/
length = strlen(rcvbuf) + 1;
- wtmpbuf = smbsr_malloc(ml, length*sizeof (mts_wchar_t));
*ascii = smbsr_malloc(ml, length * MTS_MB_CHAR_MAX);
-
- if (oemstounicodes(wtmpbuf, rcvbuf, length, cpid) > 0)
- (void) mts_wcstombs((char *)*ascii, wtmpbuf,
- length * MTS_MB_CHAR_MAX);
- else
- (void) mts_stombs((char *)*ascii, rcvbuf, length * 2);
- return (0);
+ return (mbc_marshal_cstou8("CP850", (char *)*ascii,
+ (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length));
}
static int
@@ -1403,3 +1399,29 @@ mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
mbc->chain_offset += skip;
return (0);
}
+
+/*
+ * Converts oem string to UTF-8 string with an output string of max
+ * maxconv bytes. The string may be truncated or not null-terminated if
+ * there is not enough room.
+ *
+ * returns -1, cnt (partial conversion) or 0 (success)
+ */
+
+static int
+mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv,
+ char *inbuf, size_t srcbytes)
+{
+ kiconv_t t2u;
+ size_t inlen = srcbytes;
+ size_t outlen = maxconv;
+ int err = 0;
+ size_t rc;
+
+ if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1)
+ return (-1);
+
+ rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err);
+ (void) kiconv_close(t2u);
+ return ((int)rc);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_node.c b/usr/src/uts/common/fs/smbsrv/smb_node.c
index 3b0da29344..4df9749094 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_node.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_node.c
@@ -145,16 +145,28 @@ static void smb_node_free(smb_node_t *);
static int smb_node_constructor(void *, void *, int);
static void smb_node_destructor(void *, void *);
static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
-static void smb_node_init_cached_timestamps(smb_node_t *);
+
+static void smb_node_init_cached_data(smb_node_t *);
+static void smb_node_clear_cached_data(smb_node_t *);
+
+static void smb_node_init_cached_timestamps(smb_node_t *, smb_attr_t *);
static void smb_node_clear_cached_timestamps(smb_node_t *);
static void smb_node_get_cached_timestamps(smb_node_t *, smb_attr_t *);
static void smb_node_set_cached_timestamps(smb_node_t *, smb_attr_t *);
+static void smb_node_init_cached_allocsz(smb_node_t *, smb_attr_t *);
+static void smb_node_clear_cached_allocsz(smb_node_t *);
+static void smb_node_get_cached_allocsz(smb_node_t *, smb_attr_t *);
+static void smb_node_set_cached_allocsz(smb_node_t *, smb_attr_t *);
+
#define VALIDATE_DIR_NODE(_dir_, _node_) \
ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
ASSERT((_dir_)->n_dnode != (_node_));
+/* round sz to DEV_BSIZE block */
+#define SMB_ALLOCSZ(sz) (((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1))
+
static kmem_cache_t *smb_node_cache = NULL;
static boolean_t smb_node_initialized = B_FALSE;
static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1];
@@ -898,7 +910,7 @@ smb_node_inc_open_ofiles(smb_node_t *node)
node->n_open_count++;
mutex_exit(&node->n_mutex);
- smb_node_init_cached_timestamps(node);
+ smb_node_init_cached_data(node);
}
/*
@@ -913,7 +925,7 @@ smb_node_dec_open_ofiles(smb_node_t *node)
node->n_open_count--;
mutex_exit(&node->n_mutex);
- smb_node_clear_cached_timestamps(node);
+ smb_node_clear_cached_data(node);
}
uint32_t
@@ -1135,6 +1147,7 @@ smb_node_file_is_readonly(smb_node_t *node)
* The ofile may be NULL, for example when a client request
* specifies the file by pathname.
*
+ * Timestamps
* When attributes are set on an ofile, any pending timestamps
* from a write request on the ofile are implicitly set to "now".
* For compatibility with windows the following timestamps are
@@ -1142,13 +1155,21 @@ smb_node_file_is_readonly(smb_node_t *node)
* - if any attribute is being explicitly set, set ctime to now
* - if file size is being explicitly set, set atime & ctime to now
*
- * Any attribute that is being explicitly set, or has previously
+ * Any timestamp that is being explicitly set, or has previously
* been explicitly set on the ofile, is excluded from implicit
* (now) setting.
*
* Updates the node's cached timestamp values.
* Updates the ofile's explicit times flag.
*
+ * File allocation size
+ * When the file allocation size is set it is first rounded up
+ * to block size. If the file size is smaller than the allocation
+ * size the file is truncated by setting the filesize to allocsz.
+ * If there are open ofiles, the allocsz is cached on the node.
+ *
+ * Updates the node's cached allocsz value.
+ *
* Returns: errno
*/
int
@@ -1156,56 +1177,77 @@ smb_node_setattr(smb_request_t *sr, smb_node_t *node,
cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
{
int rc;
- uint32_t what;
- uint32_t now_times = 0;
+ uint32_t pending_times = 0;
+ uint32_t explicit_times = 0;
timestruc_t now;
+ smb_attr_t tmp_attr;
ASSERT(attr);
SMB_NODE_VALID(node);
- what = attr->sa_mask;
+ /* set attributes specified in attr */
+ if (attr->sa_mask != 0) {
+ /* if allocation size is < file size, truncate the file */
+ if (attr->sa_mask & SMB_AT_ALLOCSZ) {
+ attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz);
- /* determine which timestamps to implicitly set to "now" */
- if (what)
- now_times |= SMB_AT_CTIME;
- if (what & SMB_AT_SIZE)
- now_times |= (SMB_AT_MTIME | SMB_AT_CTIME);
- if (of) {
- if (smb_ofile_write_time_pending(of))
- now_times |=
- (SMB_AT_MTIME | SMB_AT_CTIME | SMB_AT_ATIME);
- now_times &= ~(smb_ofile_explicit_times(of));
- }
- now_times &= ~what;
+ bzero(&tmp_attr, sizeof (smb_attr_t));
+ tmp_attr.sa_mask = SMB_AT_SIZE;
+ (void) smb_fsop_getattr(NULL, kcred, node, &tmp_attr);
- if (now_times) {
- gethrestime(&now);
-
- if (now_times & SMB_AT_ATIME) {
- attr->sa_vattr.va_atime = now;
- attr->sa_mask |= SMB_AT_ATIME;
- }
- if (now_times & SMB_AT_MTIME) {
- attr->sa_vattr.va_mtime = now;
- attr->sa_mask |= SMB_AT_MTIME;
+ if (tmp_attr.sa_vattr.va_size > attr->sa_allocsz) {
+ attr->sa_vattr.va_size = attr->sa_allocsz;
+ attr->sa_mask |= SMB_AT_SIZE;
+ }
}
- if (now_times & SMB_AT_CTIME) {
- attr->sa_vattr.va_ctime = now;
- attr->sa_mask |= SMB_AT_CTIME;
+
+ rc = smb_fsop_setattr(sr, cr, node, attr);
+ if (rc != 0)
+ return (rc);
+
+ smb_node_set_cached_allocsz(node, attr);
+ smb_node_set_cached_timestamps(node, attr);
+ if (of) {
+ smb_ofile_set_explicit_times(of,
+ (attr->sa_mask & SMB_AT_TIMES));
}
}
- if (attr->sa_mask == 0)
- return (0);
+ /*
+ * Determine which timestamps to implicitly set to "now".
+ * Don't overwrite timestamps already explicitly set.
+ */
+ bzero(&tmp_attr, sizeof (smb_attr_t));
+ gethrestime(&now);
+ tmp_attr.sa_vattr.va_atime = now;
+ tmp_attr.sa_vattr.va_mtime = now;
+ tmp_attr.sa_vattr.va_ctime = now;
- rc = smb_fsop_setattr(sr, cr, node, attr);
- if (rc != 0)
- return (rc);
+ /* pending write timestamps */
+ if (of) {
+ if (smb_ofile_write_time_pending(of)) {
+ pending_times |=
+ (SMB_AT_MTIME | SMB_AT_CTIME | SMB_AT_ATIME);
+ }
+ explicit_times |= (smb_ofile_explicit_times(of));
+ }
+ explicit_times |= (attr->sa_mask & SMB_AT_TIMES);
+ pending_times &= ~explicit_times;
- smb_node_set_cached_timestamps(node, attr);
+ if (pending_times) {
+ tmp_attr.sa_mask = pending_times;
+ (void) smb_fsop_setattr(NULL, kcred, node, &tmp_attr);
+ }
- if (of)
- smb_ofile_set_explicit_times(of, (what & SMB_AT_TIMES));
+ /* additional timestamps to update in cache */
+ if (attr->sa_mask)
+ tmp_attr.sa_mask |= SMB_AT_CTIME;
+ if (attr->sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ))
+ tmp_attr.sa_mask |= SMB_AT_MTIME;
+ tmp_attr.sa_mask &= ~explicit_times;
+
+ if (tmp_attr.sa_mask)
+ smb_node_set_cached_timestamps(node, &tmp_attr);
return (0);
}
@@ -1238,21 +1280,136 @@ smb_node_getattr(smb_request_t *sr, smb_node_t *node, smb_attr_t *attr)
mutex_enter(&node->n_mutex);
- if (node->vp->v_type == VDIR)
+ if (node->vp->v_type == VDIR) {
attr->sa_vattr.va_size = 0;
+ attr->sa_allocsz = 0;
+ }
if (node->readonly_creator)
attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
if (attr->sa_dosattr == 0)
attr->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
+
mutex_exit(&node->n_mutex);
+ smb_node_get_cached_allocsz(node, attr);
smb_node_get_cached_timestamps(node, attr);
+
return (0);
}
/*
+ * smb_node_init_cached_data
+ */
+static void
+smb_node_init_cached_data(smb_node_t *node)
+{
+ smb_attr_t attr;
+
+ bzero(&attr, sizeof (smb_attr_t));
+ attr.sa_mask = SMB_AT_ALL;
+ (void) smb_fsop_getattr(NULL, kcred, node, &attr);
+
+ smb_node_init_cached_allocsz(node, &attr);
+ smb_node_init_cached_timestamps(node, &attr);
+}
+
+/*
+ * smb_node_clear_cached_data
+ */
+static void
+smb_node_clear_cached_data(smb_node_t *node)
+{
+ smb_node_clear_cached_allocsz(node);
+ smb_node_clear_cached_timestamps(node);
+}
+
+/*
+ * File allocation size (allocsz) caching
+ *
+ * When there are open ofiles on the node, the file allocsz is cached.
+ * The cached value (n_allocsz) is initialized when the first ofile is
+ * opened and cleared when the last is closed. Allocsz calculated from
+ * the filesize (rounded up to block size).
+ * When the allocation size is queried, if the cached allocsz is less
+ * than the filesize, it is recalculated from the filesize.
+ */
+
+/*
+ * smb_node_init_cached_allocsz
+ *
+ * If there are open ofiles, cache the allocsz in the node.
+ * Calculate the allocsz from the filesizes.
+ * block size).
+ */
+static void
+smb_node_init_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
+{
+ mutex_enter(&node->n_mutex);
+ if (node->n_open_count == 1)
+ node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
+ mutex_exit(&node->n_mutex);
+}
+
+/*
+ * smb_node_clear_cached_allocsz
+ */
+static void
+smb_node_clear_cached_allocsz(smb_node_t *node)
+{
+ mutex_enter(&node->n_mutex);
+ if (node->n_open_count == 0)
+ node->n_allocsz = 0;
+ mutex_exit(&node->n_mutex);
+}
+
+/*
+ * smb_node_get_cached_allocsz
+ *
+ * If there is no cached allocsz (no open files), calculate
+ * allocsz from the filesize.
+ * If the allocsz is cached but is smaller than the filesize
+ * recalculate the cached allocsz from the filesize.
+ *
+ * Return allocs in attr->sa_allocsz.
+ */
+static void
+smb_node_get_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
+{
+ if (node->vp->v_type == VDIR)
+ return;
+
+ mutex_enter(&node->n_mutex);
+ if (node->n_open_count == 0) {
+ attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
+ } else {
+ if (node->n_allocsz < attr->sa_vattr.va_size)
+ node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
+ attr->sa_allocsz = node->n_allocsz;
+ }
+ mutex_exit(&node->n_mutex);
+}
+
+/*
+ * smb_node_set_cached_allocsz
+ *
+ * attr->sa_allocsz has already been rounded to block size by
+ * the caller.
+ */
+static void
+smb_node_set_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
+{
+ mutex_enter(&node->n_mutex);
+ if (attr->sa_mask & SMB_AT_ALLOCSZ) {
+ if (node->n_open_count > 0)
+ node->n_allocsz = attr->sa_allocsz;
+ }
+ mutex_exit(&node->n_mutex);
+}
+
+
+/*
* Timestamp caching
*
* Solaris file systems handle timestamps different from NTFS. For
@@ -1282,10 +1439,9 @@ smb_node_getattr(smb_request_t *sr, smb_node_t *node, smb_attr_t *attr)
* file system values.
*/
static void
-smb_node_init_cached_timestamps(smb_node_t *node)
+smb_node_init_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
{
smb_node_t *unode;
- smb_attr_t attr;
if ((unode = SMB_IS_STREAM(node)) != NULL)
node = unode;
@@ -1293,13 +1449,10 @@ smb_node_init_cached_timestamps(smb_node_t *node)
mutex_enter(&node->n_mutex);
++(node->n_timestamps.t_open_ofiles);
if (node->n_timestamps.t_open_ofiles == 1) {
- bzero(&attr, sizeof (smb_attr_t));
- attr.sa_mask = SMB_AT_TIMES;
- (void) smb_fsop_getattr(NULL, kcred, node, &attr);
- node->n_timestamps.t_mtime = attr.sa_vattr.va_mtime;
- node->n_timestamps.t_atime = attr.sa_vattr.va_atime;
- node->n_timestamps.t_ctime = attr.sa_vattr.va_ctime;
- node->n_timestamps.t_crtime = attr.sa_crtime;
+ node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime;
+ node->n_timestamps.t_atime = attr->sa_vattr.va_atime;
+ node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime;
+ node->n_timestamps.t_crtime = attr->sa_crtime;
node->n_timestamps.t_cached = B_TRUE;
}
mutex_exit(&node->n_mutex);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
index 36300171cf..aa12b2c96b 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
@@ -269,7 +269,7 @@ smb_com_nt_create_andx(struct smb_request *sr)
}
op->fqi.fq_dnode = sr->fid_ofile->f_node;
- smbsr_disconnect_file(sr);
+ smbsr_release_file(sr);
}
if (smb_common_open(sr) != NT_STATUS_SUCCESS)
@@ -315,7 +315,7 @@ smb_com_nt_create_andx(struct smb_request *sr)
&attr.sa_vattr.va_mtime,
&attr.sa_vattr.va_ctime,
op->dattr & FILE_ATTRIBUTE_MASK,
- attr.sa_vattr.va_size,
+ attr.sa_allocsz,
attr.sa_vattr.va_size,
op->ftype,
op->devstate,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
index f0791b5573..80f2319a96 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
@@ -185,7 +185,7 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
}
op->fqi.fq_dnode = sr->fid_ofile->f_node;
- smbsr_disconnect_file(sr);
+ smbsr_release_file(sr);
}
status = smb_common_open(sr);
@@ -231,7 +231,7 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
&attr.sa_vattr.va_mtime,
&attr.sa_vattr.va_ctime,
op->dattr & FILE_ATTRIBUTE_MASK,
- attr.sa_vattr.va_size,
+ attr.sa_allocsz,
attr.sa_vattr.va_size,
op->ftype,
op->devstate,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
index 68f86a155c..d1290e5889 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
@@ -27,29 +27,30 @@
#include <smbsrv/winioctl.h>
#include <smbsrv/ntstatus.h>
+
+static uint32_t smb_nt_trans_ioctl_noop(smb_request_t *, smb_xa_t *);
static uint32_t smb_nt_trans_ioctl_invalid_parm(smb_request_t *,
smb_xa_t *);
/*
- * This table defines the list of IOCTL/FSCTL values for which we'll
- * call a funtion to return a specific processing.
+ * This table defines the list of FSCTL values for which we'll
+ * call a funtion to perform specific processing.
*/
static struct {
uint32_t fcode;
uint32_t (*ioctl_func)(smb_request_t *sr, smb_xa_t *xa);
} ioctl_ret_tbl[] = {
- { FSCTL_GET_OBJECT_ID, smb_nt_trans_ioctl_invalid_parm },
- { FSCTL_QUERY_ALLOCATED_RANGES, smb_nt_trans_ioctl_invalid_parm },
- { FSCTL_SRV_ENUMERATE_SNAPSHOTS, smb_vss_ioctl_enumerate_snaps }
+ { FSCTL_GET_OBJECT_ID, smb_nt_trans_ioctl_invalid_parm },
+ { FSCTL_QUERY_ALLOCATED_RANGES, smb_nt_trans_ioctl_invalid_parm },
+ { FSCTL_SRV_ENUMERATE_SNAPSHOTS, smb_vss_ioctl_enumerate_snaps },
+ { FSCTL_SET_SPARSE, smb_nt_trans_ioctl_noop }
};
/*
* smb_nt_transact_ioctl
*
* This command allows device and file system control functions to be
- * transferred transparently from client to server. This is currently
- * a stub to work out whether or not we need to return an NT status
- * code.
+ * transferred transparently from client to server.
*
* Setup Words Encoding Description
* =========================== =========================================
@@ -78,7 +79,7 @@ static struct {
smb_sdrc_t
smb_nt_transact_ioctl(smb_request_t *sr, smb_xa_t *xa)
{
- uint32_t status = NT_STATUS_SUCCESS;
+ uint32_t status = NT_STATUS_NOT_SUPPORTED;
uint32_t fcode;
unsigned short fid;
unsigned char is_fsctl;
@@ -91,6 +92,10 @@ smb_nt_transact_ioctl(smb_request_t *sr, smb_xa_t *xa)
return (SDRC_ERROR);
}
+ /*
+ * Invoke handler if specified, otherwise the default
+ * behavior is to return NT_STATUS_NOT_SUPPORTED
+ */
for (i = 0; i < sizeof (ioctl_ret_tbl) / sizeof (ioctl_ret_tbl[0]);
i++) {
if (ioctl_ret_tbl[i].fcode == fcode) {
@@ -110,6 +115,13 @@ smb_nt_transact_ioctl(smb_request_t *sr, smb_xa_t *xa)
/* ARGSUSED */
static uint32_t
+smb_nt_trans_ioctl_noop(smb_request_t *sr, smb_xa_t *xa)
+{
+ return (NT_STATUS_SUCCESS);
+}
+
+/* ARGSUSED */
+static uint32_t
smb_nt_trans_ioctl_invalid_parm(smb_request_t *sr, smb_xa_t *xa)
{
return (NT_STATUS_INVALID_PARAMETER);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_odir.c b/usr/src/uts/common/fs/smbsrv/smb_odir.c
index 61e92b3366..c953aa05a5 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_odir.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c
@@ -246,6 +246,7 @@
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_share.h>
#include <sys/extdirent.h>
/* static functions */
@@ -659,9 +660,8 @@ smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od,
{
int rc;
smb_odirent_t *odirent;
- vnode_t *vp;
+ smb_node_t *fnode;
smb_attr_t attr;
- int tmpflg;
ASSERT(sr);
ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
@@ -702,15 +702,11 @@ smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od,
continue;
}
- /*
- * since we only care about the size attributes we don't need
- * to pass the vp of the unnamed stream file to smb_vop_getattr
- */
- rc = smb_vop_lookup(od->d_dnode->vp, odirent->od_name, &vp,
- NULL, 0, &tmpflg, od->d_tree->t_snode->vp, od->d_cred);
+ rc = smb_fsop_lookup(sr, od->d_cred, 0, od->d_tree->t_snode,
+ od->d_dnode, odirent->od_name, &fnode);
if (rc == 0) {
- rc = smb_vop_getattr(vp, NULL, &attr, 0, od->d_cred);
- VN_RELE(vp);
+ rc = smb_node_getattr(sr, fnode, &attr);
+ smb_node_release(fnode);
}
if (rc == 0) {
@@ -718,8 +714,7 @@ smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od,
odirent->od_name + SMB_STREAM_PREFIX_LEN,
sizeof (sinfo->si_name));
sinfo->si_size = attr.sa_vattr.va_size;
- sinfo->si_alloc_size =
- attr.sa_vattr.va_nblocks * DEV_BSIZE;
+ sinfo->si_alloc_size = attr.sa_allocsz;
break;
}
}
@@ -872,6 +867,8 @@ smb_odir_create(smb_request_t *sr, smb_node_t *dnode,
od->d_flags |= SMB_ODIR_FLAG_IGNORE_CASE;
if (SMB_TREE_SUPPORTS_CATIA(sr))
od->d_flags |= SMB_ODIR_FLAG_CATIA;
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ od->d_flags |= SMB_ODIR_FLAG_ABE;
od->d_eof = B_FALSE;
smb_llist_enter(&tree->t_odir_list, RW_WRITER);
@@ -939,6 +936,7 @@ smb_odir_next_odirent(smb_odir_t *od, smb_odirent_t *odirent)
dirent64_t *dp;
edirent_t *edp;
char *np;
+ uint32_t abe_flag = 0;
ASSERT(MUTEX_HELD(&od->d_mutex));
@@ -965,8 +963,11 @@ smb_odir_next_odirent(smb_odir_t *od, smb_odirent_t *odirent)
od->d_bufsize = sizeof (od->d_buf);
+ if (od->d_flags & SMB_ODIR_FLAG_ABE)
+ abe_flag = SMB_ABE;
+
rc = smb_vop_readdir(od->d_dnode->vp, od->d_offset,
- od->d_buf, &od->d_bufsize, &eof, od->d_cred);
+ od->d_buf, &od->d_bufsize, &eof, abe_flag, od->d_cred);
if ((rc == 0) && (od->d_bufsize == 0))
rc = ENOENT;
@@ -1109,7 +1110,7 @@ smb_odir_single_fileinfo(smb_request_t *sr, smb_odir_t *od,
fileinfo->fi_dosattr = attr.sa_dosattr;
fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid;
fileinfo->fi_size = attr.sa_vattr.va_size;
- fileinfo->fi_alloc_size = attr.sa_vattr.va_nblocks * DEV_BSIZE;
+ fileinfo->fi_alloc_size = attr.sa_allocsz;
fileinfo->fi_atime = attr.sa_vattr.va_atime;
fileinfo->fi_mtime = attr.sa_vattr.va_mtime;
fileinfo->fi_ctime = attr.sa_vattr.va_ctime;
@@ -1200,7 +1201,7 @@ smb_odir_wildcard_fileinfo(smb_request_t *sr, smb_odir_t *od,
fileinfo->fi_dosattr = attr.sa_dosattr;
fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid;
fileinfo->fi_size = attr.sa_vattr.va_size;
- fileinfo->fi_alloc_size = attr.sa_vattr.va_nblocks * DEV_BSIZE;
+ fileinfo->fi_alloc_size = attr.sa_allocsz;
fileinfo->fi_atime = attr.sa_vattr.va_atime;
fileinfo->fi_mtime = attr.sa_vattr.va_mtime;
fileinfo->fi_ctime = attr.sa_vattr.va_ctime;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
index 56eb9b8c8d..8d7ec2f06d 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
@@ -764,6 +764,11 @@ smb_ofile_set_write_time_pending(smb_ofile_t *of)
mutex_exit(&of->f_mutex);
}
+/*
+ * smb_ofile_write_time_pending
+ *
+ * Get and reset the write times pending flag.
+ */
boolean_t
smb_ofile_write_time_pending(smb_ofile_t *of)
{
@@ -771,8 +776,10 @@ smb_ofile_write_time_pending(smb_ofile_t *of)
SMB_OFILE_VALID(of);
mutex_enter(&of->f_mutex);
- if (of->f_flags & SMB_OFLAGS_TIMESTAMPS_PENDING)
+ if (of->f_flags & SMB_OFLAGS_TIMESTAMPS_PENDING) {
rc = B_TRUE;
+ of->f_flags &= ~SMB_OFLAGS_TIMESTAMPS_PENDING;
+ }
mutex_exit(&of->f_mutex);
return (rc);
@@ -782,16 +789,13 @@ smb_ofile_write_time_pending(smb_ofile_t *of)
* smb_ofile_set_explicit_time_flag
*
* Note the timestamps specified in "what", as having been
- * explicity set for the ofile. Also clear the flag for pending
- * timestamps as the pending timestamps will have been applied
- * by the explicit set.
+ * explicity set for the ofile.
*/
void
smb_ofile_set_explicit_times(smb_ofile_t *of, uint32_t what)
{
SMB_OFILE_VALID(of);
mutex_enter(&of->f_mutex);
- of->f_flags &= ~SMB_OFLAGS_TIMESTAMPS_PENDING;
of->f_explicit_times |= (what & SMB_AT_TIMES);
mutex_exit(&of->f_mutex);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
index e0730d580f..f701f35c7b 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
@@ -290,7 +290,7 @@ smb_com_open(smb_request_t *sr)
7,
sr->smb_fid,
file_attr,
- smb_gmt2local(sr, attr.sa_vattr.va_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec),
(uint32_t)op->dsize,
op->omode,
(uint16_t)0); /* bcc */
@@ -331,7 +331,8 @@ smb_pre_open_andx(smb_request_t *sr)
op->op_oplock_level = SMB_OPLOCK_NONE;
if ((creation_time != 0) && (creation_time != UINT_MAX))
- op->crtime.tv_sec = smb_local2gmt(sr, creation_time);
+ op->crtime.tv_sec =
+ smb_time_local_to_gmt(sr, creation_time);
op->crtime.tv_nsec = 0;
op->create_disposition = smb_ofun_to_crdisposition(op->ofun);
@@ -399,7 +400,7 @@ smb_com_open_andx(smb_request_t *sr)
sr->andx_com, VAR_BCC,
sr->smb_fid,
file_attr,
- smb_gmt2local(sr, attr.sa_vattr.va_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec),
(uint32_t)op->dsize,
op->omode, op->ftype,
op->devstate,
@@ -442,7 +443,7 @@ smb_com_trans2_open2(smb_request_t *sr, smb_xa_t *xa)
return (SDRC_ERROR);
if ((creation_time != 0) && (creation_time != UINT_MAX))
- op->crtime.tv_sec = smb_local2gmt(sr, creation_time);
+ op->crtime.tv_sec = smb_time_local_to_gmt(sr, creation_time);
op->crtime.tv_nsec = 0;
op->dattr = file_attr;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
index e585d4cf3c..cfc1956044 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
@@ -60,79 +60,6 @@ smb_is_executable(char *path)
}
/*
- * smbd_fs_query
- *
- * Upon success, the caller will need to call smb_node_release() on
- * fqi.fq_fnode (if it isn't already set to NULL by this routine) and
- * and fqi.fq_dnode. These pointers will not be used after the caller
- * is done with them and should be released immediately. (The position
- * of smb_fqi in a union in the smb_request structure makes it difficult
- * to free these pointers at smb_request deallocation time.)
- *
- * If smbd_fs_query() returns error, no smb_nodes will need to be released
- * by callers as a result of references taken in this routine, and
- * fqi.fq_fnode and fqi.fq_dnode will be set to NULL.
- */
-
-int
-smbd_fs_query(smb_request_t *sr, smb_fqi_t *fqi, int fqm)
-{
- int rc;
-
- rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
- sr->tid_tree->t_snode, sr->tid_tree->t_snode, &fqi->fq_dnode,
- fqi->fq_last_comp);
-
- if (rc)
- return (rc);
-
- rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
- sr->tid_tree->t_snode, fqi->fq_dnode, fqi->fq_last_comp,
- &fqi->fq_fnode);
-
- if (rc == 0) {
- (void) strcpy(fqi->fq_od_name, fqi->fq_fnode->od_name);
-
- /*
- * fqi->fq_fattr MUST be set even if returning EEXIST, as it
- * is used by some callers to determine how to handle EEXIST
- */
- rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr);
- if (rc != 0) {
- smb_node_release(fqi->fq_dnode);
- smb_node_release(fqi->fq_fnode);
- SMB_NULL_FQI_NODES(*fqi);
- return (rc);
- }
-
- if (fqm == FQM_PATH_MUST_NOT_EXIST) {
- smb_node_release(fqi->fq_dnode);
- smb_node_release(fqi->fq_fnode);
- SMB_NULL_FQI_NODES(*fqi);
- return (EEXIST);
- }
-
- return (0);
- }
-
- if (fqm == FQM_PATH_MUST_EXIST) {
- smb_node_release(fqi->fq_dnode);
- SMB_NULL_FQI_NODES(*fqi);
- return (rc);
- }
-
- if (rc == ENOENT) {
- fqi->fq_fnode = NULL;
- return (0);
- }
-
- smb_node_release(fqi->fq_dnode);
- SMB_NULL_FQI_NODES(*fqi);
-
- return (rc);
-}
-
-/*
* smb_pathname_reduce
*
* smb_pathname_reduce() takes a path and returns the smb_node for the
@@ -398,6 +325,7 @@ smb_pathname(smb_request_t *sr, char *path, int flags,
int err = 0;
int nlink = 0;
int local_flags;
+ uint32_t abe_flag = 0;
char namebuf[MAXNAMELEN];
if (path == NULL)
@@ -419,6 +347,9 @@ smb_pathname(smb_request_t *sr, char *path, int flags,
return (err);
}
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ abe_flag = SMB_ABE;
+
(void) pn_alloc(&pn);
(void) pn_alloc(&rpn);
@@ -458,7 +389,7 @@ smb_pathname(smb_request_t *sr, char *path, int flags,
break;
if ((err = smb_unmangle_name(dnode, component,
- real_name, MAXNAMELEN)) != 0)
+ real_name, MAXNAMELEN, abe_flag)) != 0)
break;
if ((namep = smb_pathname_catia_v5tov4(sr, real_name,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c b/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c
new file mode 100644
index 0000000000..377baec57e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c
@@ -0,0 +1,891 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+/*
+ * Trans2 Query File/Path Information Levels:
+ *
+ * SMB_INFO_STANDARD
+ * SMB_INFO_QUERY_EA_SIZE
+ * SMB_INFO_QUERY_EAS_FROM_LIST
+ * SMB_INFO_QUERY_ALL_EAS - not valid for pipes
+ * SMB_INFO_IS_NAME_VALID - only valid when query is by path
+ *
+ * SMB_QUERY_FILE_BASIC_INFO
+ * SMB_QUERY_FILE_STANDARD_INFO
+ * SMB_QUERY_FILE_EA_INFO
+ * SMB_QUERY_FILE_NAME_INFO
+ * SMB_QUERY_FILE_ALL_INFO
+ * SMB_QUERY_FILE_ALT_NAME_INFO - not valid for pipes
+ * SMB_QUERY_FILE_STREAM_INFO - not valid for pipes
+ * SMB_QUERY_FILE_COMPRESSION_INFO - not valid for pipes
+ *
+ * Supported Passthrough levels:
+ * SMB_FILE_BASIC_INFORMATION
+ * SMB_FILE_STANDARD_INFORMATION
+ * SMB_FILE_INTERNAL_INFORMATION
+ * SMB_FILE_EA_INFORMATION
+ * SMB_FILE_ACCESS_INFORMATION - not yet supported quen query by path
+ * SMB_FILE_NAME_INFORMATION
+ * SMB_FILE_ALL_INFORMATION
+ * SMB_FILE_ALT_NAME_INFORMATION - not valid for pipes
+ * SMB_FILE_STREAM_INFORMATION - not valid for pipes
+ * SMB_FILE_COMPRESSION_INFORMATION - not valid for pipes
+ * SMB_FILE_ATTR_TAG_INFORMATION - not valid for pipes
+ *
+ * Internal levels representing non trans2 requests
+ * SMB_QUERY_INFORMATION
+ * SMB_QUERY_INFORMATION2
+ */
+
+typedef struct smb_queryinfo {
+ smb_node_t *qi_node; /* NULL for pipes */
+ smb_attr_t qi_attr;
+ boolean_t qi_delete_on_close;
+ uint32_t qi_namelen;
+ char qi_name83[SMB_SHORTNAMELEN];
+ char qi_shortname[SMB_SHORTNAMELEN];
+ char qi_name[MAXPATHLEN];
+} smb_queryinfo_t;
+#define qi_mtime qi_attr.sa_vattr.va_mtime
+#define qi_ctime qi_attr.sa_vattr.va_ctime
+#define qi_atime qi_attr.sa_vattr.va_atime
+#define qi_crtime qi_attr.sa_crtime
+
+static int smb_query_by_fid(smb_request_t *, smb_xa_t *, uint16_t);
+static int smb_query_by_path(smb_request_t *, smb_xa_t *,
+ uint16_t, char *);
+
+static int smb_query_fileinfo(smb_request_t *, smb_node_t *,
+ uint16_t, smb_queryinfo_t *);
+static int smb_query_pipeinfo(smb_request_t *, smb_opipe_t *,
+ uint16_t, smb_queryinfo_t *);
+static boolean_t smb_query_pipe_valid_infolev(smb_request_t *, uint16_t);
+
+static int smb_query_encode_response(smb_request_t *, smb_xa_t *,
+ uint16_t, smb_queryinfo_t *);
+static void smb_encode_stream_info(smb_request_t *, smb_xa_t *,
+ smb_queryinfo_t *);
+static int smb_all_info_filename(smb_tree_t *, smb_node_t *, char *, size_t);
+uint32_t smb_pad_align(uint32_t offset, uint32_t align);
+
+
+/*
+ * smb_com_trans2_query_file_information
+ */
+smb_sdrc_t
+smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t infolev;
+
+ if (smb_mbc_decodef(&xa->req_param_mb, "ww",
+ &sr->smb_fid, &infolev) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_query_by_fid(sr, xa, infolev) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_trans2_query_path_information
+ */
+smb_sdrc_t
+smb_com_trans2_query_path_information(smb_request_t *sr, smb_xa_t *xa)
+{
+ uint16_t infolev;
+ char *path;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
+ ERRDOS, ERROR_INVALID_FUNCTION);
+ return (SDRC_ERROR);
+ }
+
+ if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u",
+ sr, &infolev, &path) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_query_by_path(sr, xa, infolev, path) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_query_information (aka getattr)
+ */
+smb_sdrc_t
+smb_pre_query_information(smb_request_t *sr)
+{
+ int rc;
+ smb_fqi_t *fqi = &sr->arg.dirop.fqi;
+
+ rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
+
+ DTRACE_SMB_2(op__QueryInformation__start, smb_request_t *, sr,
+ smb_fqi_t *, fqi);
+
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+}
+
+void
+smb_post_query_information(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__QueryInformation__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_query_information(smb_request_t *sr)
+{
+ char *path = sr->arg.dirop.fqi.fq_path.pn_path;
+ uint16_t infolev = SMB_QUERY_INFORMATION;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
+ }
+
+ if (smb_query_by_path(sr, NULL, infolev, path) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_query_information2 (aka getattre)
+ */
+smb_sdrc_t
+smb_pre_query_information2(smb_request_t *sr)
+{
+ int rc;
+ rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
+
+ DTRACE_SMB_1(op__QueryInformation2__start, smb_request_t *, sr);
+
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+}
+
+void
+smb_post_query_information2(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__QueryInformation2__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_query_information2(smb_request_t *sr)
+{
+ uint16_t infolev = SMB_QUERY_INFORMATION2;
+
+ if (smb_query_by_fid(sr, NULL, infolev) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_query_by_fid
+ *
+ * Common code for querying file information by open file (or pipe) id.
+ * Use the id to identify the node / pipe object and request the
+ * smb_queryinfo_t data for that object.
+ */
+static int
+smb_query_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
+{
+ int rc;
+ smb_queryinfo_t *qinfo;
+ smb_node_t *node;
+ smb_opipe_t *opipe;
+
+ smbsr_lookup_file(sr);
+
+ if (sr->fid_ofile == NULL) {
+ smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
+ return (-1);
+ }
+
+ if (infolev == SMB_INFO_IS_NAME_VALID) {
+ smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
+ smbsr_release_file(sr);
+ return (-1);
+ }
+
+ if ((sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE) &&
+ (!smb_query_pipe_valid_infolev(sr, infolev))) {
+ smbsr_release_file(sr);
+ return (-1);
+ }
+
+ qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP);
+
+ switch (sr->fid_ofile->f_ftype) {
+ case SMB_FTYPE_DISK:
+ node = sr->fid_ofile->f_node;
+ rc = smb_query_fileinfo(sr, node, infolev, qinfo);
+ break;
+ case SMB_FTYPE_MESG_PIPE:
+ opipe = sr->fid_ofile->f_pipe;
+ rc = smb_query_pipeinfo(sr, opipe, infolev, qinfo);
+ break;
+ default:
+ smbsr_error(sr, 0, ERRDOS, ERRbadfile);
+ rc = -1;
+ break;
+ }
+
+ if (rc == 0)
+ rc = smb_query_encode_response(sr, xa, infolev, qinfo);
+
+ kmem_free(qinfo, sizeof (smb_queryinfo_t));
+ smbsr_release_file(sr);
+ return (rc);
+}
+
+/*
+ * smb_query_by_path
+ *
+ * Common code for querying file information by file name.
+ * Use the file name to identify the node object and request the
+ * smb_queryinfo_t data for that node.
+ *
+ * Querying attributes on a named pipe by name is an error and
+ * is handled in the calling functions so that they can return
+ * the appropriate error status code (which differs by caller).
+ */
+static int
+smb_query_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev, char *path)
+{
+ smb_queryinfo_t *qinfo;
+ smb_node_t *node, *dnode;
+ int rc;
+ int len;
+
+ /* VALID, but not yet supported */
+ if (infolev == SMB_FILE_ACCESS_INFORMATION) {
+ smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
+ return (-1);
+ }
+
+ /*
+ * Some MS clients pass NULL file names. NT interprets this as "\".
+ * Otherwise, if path is not "\\", remove the terminating slash.
+ */
+ if ((len = strlen(path)) == 0)
+ path = "\\";
+ else {
+ if ((len > 1) && (path[len - 1] == '\\')) {
+ path[len - 1] = 0;
+ }
+ }
+
+ qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP);
+
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, sr->tid_tree->t_snode,
+ sr->tid_tree->t_snode, &dnode, qinfo->qi_name);
+ if (rc == 0) {
+ rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dnode, qinfo->qi_name, &node);
+ smb_node_release(dnode);
+ }
+
+ if (rc != 0) {
+ if (rc == ENOENT)
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERROR_FILE_NOT_FOUND);
+ else
+ smbsr_errno(sr, rc);
+
+ kmem_free(qinfo, sizeof (smb_queryinfo_t));
+ return (-1);
+ }
+
+ rc = smb_query_fileinfo(sr, node, infolev, qinfo);
+ if (rc != 0) {
+ kmem_free(qinfo, sizeof (smb_queryinfo_t));
+ smb_node_release(node);
+ return (rc);
+ }
+
+ /* If delete_on_close - NT_STATUS_DELETE_PENDING */
+ if (qinfo->qi_delete_on_close) {
+ smbsr_error(sr, NT_STATUS_DELETE_PENDING,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ kmem_free(qinfo, sizeof (smb_queryinfo_t));
+ smb_node_release(node);
+ return (-1);
+ }
+
+ rc = smb_query_encode_response(sr, xa, infolev, qinfo);
+ kmem_free(qinfo, sizeof (smb_queryinfo_t));
+ smb_node_release(node);
+ return (rc);
+}
+
+/*
+ * smb_size32
+ * Some responses only support 32 bit file sizes. If the file size
+ * exceeds UINT_MAX (32 bit) we return UINT_MAX in the response.
+ */
+static uint32_t
+smb_size32(u_offset_t size)
+{
+ return ((size > UINT_MAX) ? UINT_MAX : (uint32_t)size);
+}
+
+/*
+ * smb_query_encode_response
+ *
+ * Encode the data from smb_queryinfo_t into client response
+ */
+int
+smb_query_encode_response(smb_request_t *sr, smb_xa_t *xa,
+ uint16_t infolev, smb_queryinfo_t *qinfo)
+{
+ uint16_t dattr;
+ u_offset_t datasz, allocsz;
+
+ dattr = qinfo->qi_attr.sa_dosattr & FILE_ATTRIBUTE_MASK;
+ datasz = qinfo->qi_attr.sa_vattr.va_size;
+ allocsz = qinfo->qi_attr.sa_allocsz;
+
+ switch (infolev) {
+ case SMB_QUERY_INFORMATION:
+ (void) smbsr_encode_result(sr, 10, 0, "bwll10.w",
+ 10,
+ dattr,
+ smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
+ smb_size32(datasz),
+ 0);
+ break;
+
+ case SMB_QUERY_INFORMATION2:
+ (void) smbsr_encode_result(sr, 11, 0, "byyyllww",
+ 11,
+ smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
+ smb_size32(datasz), smb_size32(allocsz), dattr, 0);
+ break;
+
+ case SMB_FILE_ACCESS_INFORMATION:
+ ASSERT(sr->fid_ofile);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
+ sr->fid_ofile->f_granted_access);
+ break;
+
+ case SMB_INFO_STANDARD:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95) ?
+ "YYYllw" : "yyyllw"),
+ smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
+ smb_size32(datasz), smb_size32(allocsz), dattr);
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95) ?
+ "YYYllwl" : "yyyllwl"),
+ smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
+ smb_size32(datasz), smb_size32(allocsz), dattr, 0);
+ break;
+
+ case SMB_INFO_QUERY_ALL_EAS:
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_INFO_IS_NAME_VALID:
+ break;
+
+ case SMB_QUERY_FILE_BASIC_INFO:
+ case SMB_FILE_BASIC_INFORMATION:
+ /*
+ * NT includes 6 bytes (spec says 4) at the end of this
+ * response, which are required by NetBench 5.01.
+ */
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.",
+ &qinfo->qi_crtime,
+ &qinfo->qi_atime,
+ &qinfo->qi_mtime,
+ &qinfo->qi_ctime,
+ dattr);
+ break;
+
+ case SMB_QUERY_FILE_STANDARD_INFO:
+ case SMB_FILE_STANDARD_INFORMATION:
+ /* 2-byte pad at end */
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
+ (uint64_t)allocsz,
+ (uint64_t)datasz,
+ qinfo->qi_attr.sa_vattr.va_nlink,
+ qinfo->qi_delete_on_close,
+ (qinfo->qi_attr.sa_vattr.va_type == VDIR));
+ break;
+
+ case SMB_QUERY_FILE_EA_INFO:
+ case SMB_FILE_EA_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_QUERY_FILE_NAME_INFO:
+ case SMB_FILE_NAME_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
+ qinfo->qi_namelen, qinfo->qi_name);
+ break;
+
+ case SMB_QUERY_FILE_ALL_INFO:
+ case SMB_FILE_ALL_INFORMATION:
+ /*
+ * There is a 6-byte pad between Attributes and AllocationSize,
+ * and a 2-byte pad after the Directory field.
+ */
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
+ &qinfo->qi_crtime,
+ &qinfo->qi_atime,
+ &qinfo->qi_mtime,
+ &qinfo->qi_ctime,
+ dattr,
+ (uint64_t)allocsz,
+ (uint64_t)datasz,
+ qinfo->qi_attr.sa_vattr.va_nlink,
+ qinfo->qi_delete_on_close,
+ (qinfo->qi_attr.sa_vattr.va_type == VDIR),
+ 0);
+
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu",
+ sr, qinfo->qi_namelen, qinfo->qi_name);
+ break;
+
+ case SMB_QUERY_FILE_ALT_NAME_INFO:
+ case SMB_FILE_ALT_NAME_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
+ mts_wcequiv_strlen(qinfo->qi_shortname),
+ qinfo->qi_shortname);
+ break;
+
+ case SMB_QUERY_FILE_STREAM_INFO:
+ case SMB_FILE_STREAM_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ smb_encode_stream_info(sr, xa, qinfo);
+ break;
+
+ case SMB_QUERY_FILE_COMPRESSION_INFO:
+ case SMB_FILE_COMPRESSION_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.",
+ datasz, 0, 0, 0, 0);
+ break;
+
+ case SMB_FILE_INTERNAL_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "q",
+ qinfo->qi_attr.sa_vattr.va_nodeid);
+ break;
+
+ case SMB_FILE_ATTR_TAG_INFORMATION:
+ /*
+ * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
+ * second dword should be the reparse tag. Otherwise
+ * the tag value should be set to zero.
+ * We don't support reparse points, so we set the tag
+ * to zero.
+ */
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
+ (uint32_t)dattr, 0);
+ break;
+
+ default:
+ smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_encode_stream_info
+ *
+ * This function encodes the streams information.
+ * The following rules about how have been derived from observed NT
+ * behaviour.
+ *
+ * If the target is a file:
+ * 1. If there are no named streams, the response should still contain
+ * an entry for the unnamed stream.
+ * 2. If there are named streams, the response should contain an entry
+ * for the unnamed stream followed by the entries for the named
+ * streams.
+ *
+ * If the target is a directory:
+ * 1. If there are no streams, the response is complete. Directories
+ * do not report the unnamed stream.
+ * 2. If there are streams, the response should contain entries for
+ * those streams but there should not be an entry for the unnamed
+ * stream.
+ *
+ * Note that the stream name lengths exclude the null terminator but
+ * the field lengths (i.e. next offset calculations) need to include
+ * the null terminator and be padded to a multiple of 8 bytes. The
+ * last entry does not seem to need any padding.
+ *
+ * If an error is encountered when trying to read the stream entries
+ * (smb_odir_read_streaminfo) it is treated as if there are no [more]
+ * entries. The entries that have been read so far are returned and
+ * no error is reported.
+ *
+ * Offset calculation:
+ * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
+ */
+static void
+smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa, smb_queryinfo_t *qinfo)
+{
+ char *stream_name;
+ uint32_t next_offset;
+ uint32_t stream_nlen;
+ uint32_t pad;
+ u_offset_t datasz, allocsz;
+ boolean_t is_dir;
+ smb_streaminfo_t *sinfo, *sinfo_next;
+ int rc = 0;
+ boolean_t done = B_FALSE;
+ boolean_t eos = B_FALSE;
+ uint16_t odid;
+ smb_odir_t *od = NULL;
+
+ smb_node_t *fnode = qinfo->qi_node;
+ smb_attr_t *attr = &qinfo->qi_attr;
+
+ ASSERT(fnode);
+ if (SMB_IS_STREAM(fnode)) {
+ fnode = fnode->n_unode;
+ ASSERT(fnode);
+ }
+ ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
+ sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
+ is_dir = (attr->sa_vattr.va_type == VDIR);
+ datasz = attr->sa_vattr.va_size;
+ allocsz = attr->sa_allocsz;
+
+ odid = smb_odir_openat(sr, fnode);
+ if (odid != 0)
+ od = smb_tree_lookup_odir(sr->tid_tree, odid);
+ if (od != NULL)
+ rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos);
+
+ if ((od == NULL) || (rc != 0) || (eos))
+ done = B_TRUE;
+
+ /* If not a directory, encode an entry for the unnamed stream. */
+ if (!is_dir) {
+ stream_name = "::$DATA";
+ stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
+
+ if (done)
+ next_offset = 0;
+ else
+ next_offset = 24 + stream_nlen +
+ smb_ascii_or_unicode_null_len(sr);
+
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr,
+ next_offset, stream_nlen, datasz, allocsz, stream_name);
+ }
+
+ /*
+ * Since last packet does not have a pad we need to check
+ * for the next stream before we encode the current one
+ */
+ while (!done) {
+ stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name);
+ sinfo_next->si_name[0] = 0;
+
+ rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos);
+ if ((rc != 0) || (eos)) {
+ done = B_TRUE;
+ next_offset = 0;
+ pad = 0;
+ } else {
+ next_offset = 24 + stream_nlen +
+ smb_ascii_or_unicode_null_len(sr);
+ pad = smb_pad_align(next_offset, 8);
+ next_offset += pad;
+ }
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.",
+ sr, next_offset, stream_nlen,
+ sinfo->si_size, sinfo->si_alloc_size,
+ sinfo->si_name, pad);
+
+ (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t));
+ }
+
+ kmem_free(sinfo, sizeof (smb_streaminfo_t));
+ kmem_free(sinfo_next, sizeof (smb_streaminfo_t));
+ if (od) {
+ smb_odir_close(od);
+ smb_odir_release(od);
+ }
+}
+
+/*
+ * smb_pad_align
+ *
+ * Returns the number of bytes required to pad an offset to the
+ * specified alignment.
+ */
+uint32_t
+smb_pad_align(uint32_t offset, uint32_t align)
+{
+ uint32_t pad = offset % align;
+
+ if (pad != 0)
+ pad = align - pad;
+
+ return (pad);
+}
+
+/*
+ * smb_all_info_filename
+ *
+ * This format of filename is only used by the ALL_INFO levels.
+ *
+ * Determine the absolute pathname of 'node' within the share.
+ * For example if the node represents file "test1.txt" in directory
+ * "dir1" on share "share1", the path would be: \share1\dir1\test1.txt
+ *
+ * If node represents a named stream, construct the pathname for the
+ * associated unnamed stream then append the stream name.
+ */
+static int
+smb_all_info_filename(smb_tree_t *tree, smb_node_t *node,
+ char *buf, size_t buflen)
+{
+ char *sharename = tree->t_sharename;
+ int rc;
+ size_t len;
+ vnode_t *vp;
+
+ len = snprintf(buf, buflen, "\\%s", sharename);
+ if (len == (buflen - 1))
+ return (ENAMETOOLONG);
+
+ buf += len;
+ buflen -= len;
+
+ if (SMB_IS_STREAM(node))
+ vp = node->n_unode->vp;
+ else
+ vp = node->vp;
+
+ rc = vnodetopath(tree->t_snode->vp, vp, buf, buflen, kcred);
+ if (rc == 0) {
+ (void) strsubst(buf, '/', '\\');
+
+ if (SMB_IS_STREAM(node))
+ (void) strlcat(buf, node->od_name, buflen);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_query_fileinfo
+ *
+ * Populate smb_queryinfo_t structure for SMB_FTYPE_DISK
+ * (This should become an smb_ofile / smb_node function.)
+ */
+int
+smb_query_fileinfo(smb_request_t *sr, smb_node_t *node, uint16_t infolev,
+ smb_queryinfo_t *qinfo)
+{
+ char *namep = node->od_name;
+ int rc;
+
+ (void) bzero(qinfo, sizeof (smb_queryinfo_t));
+
+ if (smb_node_getattr(sr, node, &qinfo->qi_attr) != 0) {
+ smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+ ERRDOS, ERROR_INTERNAL_ERROR);
+ return (-1);
+ }
+
+ qinfo->qi_node = node;
+ qinfo->qi_delete_on_close =
+ (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
+
+ /*
+ * The number of links reported should be the number of
+ * non-deleted links. Thus if delete_on_close is set,
+ * decrement the link count.
+ */
+ if (qinfo->qi_delete_on_close &&
+ qinfo->qi_attr.sa_vattr.va_nlink > 0) {
+ --(qinfo->qi_attr.sa_vattr.va_nlink);
+ }
+
+ /* populate name, namelen and shortname */
+
+ /* ALL_INFO levels are a special case for name field */
+ if ((infolev == SMB_QUERY_FILE_ALL_INFO) ||
+ (infolev == SMB_FILE_ALL_INFORMATION)) {
+ rc = smb_all_info_filename(sr->tid_tree, node,
+ qinfo->qi_name, MAXPATHLEN);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+ qinfo->qi_namelen =
+ smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
+ return (0);
+ }
+
+ /*
+ * It looks like NT doesn't know what to do with the name "."
+ * so we convert it to "\\" to indicate the root directory.
+ * If the leading \ is missing, add it.
+ */
+ if (strcmp(namep, ".") == 0)
+ (void) strlcpy(qinfo->qi_name, "\\", MAXNAMELEN);
+ else if (*namep != '\\')
+ (void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep);
+ else
+ (void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN);
+
+ qinfo->qi_namelen = smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
+
+ /*
+ * For some reason NT will not show the security tab in the root
+ * directory of a mapped drive unless the filename length is
+ * greater than one. So we hack the length here to persuade NT
+ * to show the tab. It should be safe because of the null
+ * terminator character.
+ */
+ if (qinfo->qi_namelen == 1)
+ qinfo->qi_namelen = 2;
+
+ /*
+ * If the shortname is generated by smb_mangle_name()
+ * it will be returned as the alternative name.
+ * Otherwise, convert the original name to upper-case
+ * and return it as the alternative name.
+ */
+ (void) smb_mangle_name(qinfo->qi_attr.sa_vattr.va_nodeid,
+ namep, qinfo->qi_shortname, qinfo->qi_name83, 0);
+ if (*qinfo->qi_shortname == 0) {
+ (void) strlcpy(qinfo->qi_shortname, namep, SMB_SHORTNAMELEN);
+ (void) utf8_strupr(qinfo->qi_shortname);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_query_pipeinfo
+ *
+ * Populate smb_queryinfo_t structure for SMB_FTYPE_MESG_PIPE
+ * (This should become an smb_opipe function.)
+ */
+static int
+smb_query_pipeinfo(smb_request_t *sr, smb_opipe_t *opipe, uint16_t infolev,
+ smb_queryinfo_t *qinfo)
+{
+ char *namep = opipe->p_name;
+
+ (void) bzero(qinfo, sizeof (smb_queryinfo_t));
+ qinfo->qi_node = NULL;
+ qinfo->qi_attr.sa_vattr.va_nlink = 1;
+ qinfo->qi_delete_on_close = 1;
+
+ if ((infolev == SMB_INFO_STANDARD) ||
+ (infolev == SMB_INFO_QUERY_EA_SIZE) ||
+ (infolev == SMB_QUERY_INFORMATION2)) {
+ qinfo->qi_attr.sa_dosattr = 0;
+ } else {
+ qinfo->qi_attr.sa_dosattr = FILE_ATTRIBUTE_NORMAL;
+ }
+
+ /* If the leading \ is missing from the pipe name, add it. */
+ if (*namep != '\\')
+ (void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep);
+ else
+ (void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN);
+
+ qinfo->qi_namelen=
+ smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
+
+ return (0);
+}
+
+/*
+ * smb_query_pipe_valid_infolev
+ *
+ * If the infolev is not valid for a message pipe, the error
+ * information is set in sr and B_FALSE is returned.
+ * Otherwise, returns B_TRUE.
+ */
+static boolean_t
+smb_query_pipe_valid_infolev(smb_request_t *sr, uint16_t infolev)
+{
+ switch (infolev) {
+ case SMB_INFO_QUERY_ALL_EAS:
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (B_FALSE);
+
+ case SMB_QUERY_FILE_ALT_NAME_INFO:
+ case SMB_FILE_ALT_NAME_INFORMATION:
+ case SMB_QUERY_FILE_STREAM_INFO:
+ case SMB_FILE_STREAM_INFORMATION:
+ case SMB_QUERY_FILE_COMPRESSION_INFO:
+ case SMB_FILE_COMPRESSION_INFORMATION:
+ case SMB_FILE_ATTR_TAG_INFORMATION:
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information.c b/usr/src/uts/common/fs/smbsrv/smb_query_information.c
deleted file mode 100644
index 8718361d06..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * SMB: query_information
- *
- * This request is sent to obtain information about a file.
- *
- * Client Request Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 0
- * USHORT ByteCount; Count of data bytes; min = 2
- * UCHAR BufferFormat; 0x04
- * STRING FileName[]; File name
- *
- * FileName is the fully qualified name of the file relative to the Tid in
- * the header.
- *
- * Server Response Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 10
- * USHORT FileAttributes;
- * UTIME LastWriteTime; Time of last write
- * ULONG FileSize; File size
- * USHORT Reserved [5]; Reserved - client should ignore
- * USHORT ByteCount; Count of data bytes = 0
- *
- * FileAttributes are as described in the "Attributes Encoding" section of
- * this document.
- *
- * Note that FileSize is limited to 32 bits, this request is inappropriate
- * for files whose size is too large.
- *
- * NOTES:
- * Some clients send a NULL file name. Right now we return ERRbadfile
- * until we find out what a MS client would send...
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-smb_sdrc_t
-smb_pre_query_information(smb_request_t *sr)
-{
- smb_fqi_t *fqi = &sr->arg.dirop.fqi;
- int rc;
-
- rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
- if (rc == 0) {
- if (strlen(fqi->fq_path.pn_path) == 0)
- fqi->fq_path.pn_path = "\\";
- }
-
- DTRACE_SMB_2(op__QueryInformation__start, smb_request_t *, sr,
- smb_fqi_t *, fqi);
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
-
-void
-smb_post_query_information(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__QueryInformation__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_query_information(smb_request_t *sr)
-{
- char *path = sr->arg.dirop.fqi.fq_path.pn_path;
- char *name = sr->arg.dirop.fqi.fq_last_comp;
- int rc;
- uint16_t dattr;
- uint32_t write_time;
- u_offset_t datasz;
- smb_node_t *dir_node;
- smb_node_t *node;
- smb_attr_t attr;
- timestruc_t *mtime;
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
- ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
- sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
- != 0) {
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- if ((rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
- sr->tid_tree->t_snode, dir_node, name, &node)) != 0) {
- smb_node_release(dir_node);
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- smb_node_release(dir_node);
- rc = smb_node_getattr(sr, node, &attr);
- smb_node_release(node);
-
- if (rc != 0) {
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- dattr = attr.sa_dosattr & FILE_ATTRIBUTE_MASK;
- mtime = &attr.sa_vattr.va_mtime;
- write_time = smb_gmt2local(sr, mtime->tv_sec);
- datasz = attr.sa_vattr.va_size;
- if (datasz > UINT_MAX)
- datasz = UINT_MAX;
-
- rc = smbsr_encode_result(sr, 10, 0, "bwll10.w",
- 10, dattr, write_time, (uint32_t)datasz, 0);
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c
deleted file mode 100644
index 0c03e480fc..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * SMB: query_information2
- *
- * This SMB is gets information about the file represented by Fid.
- *
- * Client Request Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 2
- * USHORT Fid; File handle
- * USHORT ByteCount; Count of data bytes = 0
- *
- * Server Response Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 11
- * SMB_DATE CreationDate;
- * SMB_TIME CreationTime;
- * SMB_DATE LastAccessDate;
- * SMB_TIME LastAccessTime;
- * SMB_DATE LastWriteDate;
- * SMB_TIME LastWriteTime;
- * ULONG FileDataSize; File end of data
- * ULONG FileAllocationSize; File allocation size
- * USHORT FileAttributes;
- * USHORT ByteCount; Count of data bytes; min = 0
- *
- * The file being interrogated is specified by Fid, which must possess at
- * least read permission.
- *
- * FileAttributes are described in the "File Attribute Encoding" section
- * elsewhere in this document.
- */
-
-#include <smbsrv/smb_incl.h>
-
-smb_sdrc_t
-smb_pre_query_information2(smb_request_t *sr)
-{
- int rc;
-
- rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
-
- DTRACE_SMB_1(op__QueryInformation2__start, smb_request_t *, sr);
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
-
-void
-smb_post_query_information2(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__QueryInformation2__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_query_information2(smb_request_t *sr)
-{
- smb_node_t *node;
- smb_attr_t attr;
- u_offset_t size64;
- uint32_t datasz, allocsz;
- int rc;
-
- smbsr_lookup_file(sr);
- if (sr->fid_ofile == NULL) {
- smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
- return (SDRC_ERROR);
- }
-
- if (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) {
- rc = smbsr_encode_result(sr, 11, 0, "blllllww",
- 11, 0, 0, 0, 0, 0, 0, 0);
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
- }
-
- node = sr->fid_ofile->f_node;
- if (smb_node_getattr(sr, node, &attr) != 0) {
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- size64 = attr.sa_vattr.va_size;
- datasz = (size64 > UINT_MAX) ? UINT_MAX : (uint32_t)size64;
-
- size64 = attr.sa_vattr.va_nblocks * DEV_BSIZE;
- allocsz = (size64 > UINT_MAX) ? UINT_MAX : (uint32_t)size64;
-
- rc = smbsr_encode_result(sr, 11, 0, "byyyllww",
- 11, /* wct */
- smb_gmt2local(sr, attr.sa_crtime.tv_sec),
- /* LastAccessTime */
- smb_gmt2local(sr, attr.sa_vattr.va_atime.tv_sec),
- /* LastWriteTime */
- smb_gmt2local(sr, attr.sa_vattr.va_mtime.tv_sec),
- datasz,
- allocsz,
- attr.sa_dosattr & FILE_ATTRIBUTE_MASK,
- 0); /* bcc */
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_rename.c b/usr/src/uts/common/fs/smbsrv/smb_rename.c
index 18365da04e..6da6809374 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_rename.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c
@@ -130,19 +130,36 @@ smb_com_rename(smb_request_t *sr)
static int
smb_do_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
{
- smb_node_t *src_node;
+ smb_node_t *src_node, *tnode;
char *dstname;
DWORD status;
int rc;
int count;
+ char *path;
- if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0)
+ tnode = sr->tid_tree->t_snode;
+
+ /* Lookup the source node. It MUST exist. */
+ path = src_fqi->fq_path.pn_path;
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
+ &src_fqi->fq_dnode, src_fqi->fq_last_comp);
+ if (rc != 0)
return (rc);
- src_node = src_fqi->fq_fnode;
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode,
+ src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
+ if (rc != 0) {
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
- if ((rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr)) != 0)
- goto rename_cleanup_nodes;
+ src_node = src_fqi->fq_fnode;
+ rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr);
+ if (rc != 0) {
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
/*
* Break the oplock before access checks. If a client
@@ -167,88 +184,100 @@ smb_do_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
if (status == NT_STATUS_SHARING_VIOLATION) {
smb_node_end_crit(src_node);
- rc = EPIPE; /* = ERRbadshare */
- goto rename_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (EPIPE); /* = ERRbadshare */
}
status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE);
if (status != NT_STATUS_SUCCESS) {
smb_node_end_crit(src_node);
- rc = EACCES;
- goto rename_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (EACCES);
+ }
+
+ /* Lookup destination node. */
+ path = dst_fqi->fq_path.pn_path;
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
+ &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
+ if (rc != 0) {
+ smb_node_end_crit(src_node);
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode,
+ dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode);
+ if ((rc != 0) && (rc != ENOENT)) {
+ smb_node_end_crit(src_node);
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ smb_node_release(dst_fqi->fq_dnode);
+ return (rc);
}
if (utf8_strcasecmp(src_fqi->fq_path.pn_path,
dst_fqi->fq_path.pn_path) == 0) {
- if ((rc = smbd_fs_query(sr, dst_fqi, 0)) != 0) {
- smb_node_end_crit(src_node);
- goto rename_cleanup_nodes;
- }
- /*
- * Because the fqm parameter to smbd_fs_query() was 0,
- * dst_fqi->fq_fnode may be NULL.
- */
if (dst_fqi->fq_fnode)
smb_node_release(dst_fqi->fq_fnode);
- rc = strcmp(src_fqi->fq_od_name, dst_fqi->fq_last_comp);
+ rc = strcmp(src_fqi->fq_fnode->od_name, dst_fqi->fq_last_comp);
if (rc == 0) {
smb_node_end_crit(src_node);
- goto rename_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ smb_node_release(dst_fqi->fq_dnode);
+ return (0);
}
rc = smb_fsop_rename(sr, sr->user_cr,
- src_fqi->fq_dnode, src_fqi->fq_od_name,
+ src_fqi->fq_dnode, src_fqi->fq_fnode->od_name,
dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
smb_node_end_crit(src_node);
if (rc == 0)
smb_node_notify_change(dst_fqi->fq_dnode);
- goto rename_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ smb_node_release(dst_fqi->fq_dnode);
+ return (rc);
}
- rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST);
- if (rc != 0) {
+ /* dst node must not exist */
+ if (dst_fqi->fq_fnode) {
smb_node_end_crit(src_node);
- goto rename_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ smb_node_release(dst_fqi->fq_fnode);
+ smb_node_release(dst_fqi->fq_dnode);
+ return (EEXIST);
}
/*
- * On success of FQM_PATH_MUST_NOT_EXIST only dst_fqi->fq_dnode
- * is valid (dst_fqi->fq_fnode is NULL).
- */
-
- /*
* If the source name is mangled but the source and destination
* on-disk names are identical, we'll use the on-disk name.
*/
if ((smb_maybe_mangled_name(src_fqi->fq_last_comp)) &&
(strcmp(src_fqi->fq_last_comp, dst_fqi->fq_last_comp) == 0)) {
- dstname = src_fqi->fq_od_name;
+ dstname = src_fqi->fq_fnode->od_name;
} else {
dstname = dst_fqi->fq_last_comp;
}
rc = smb_fsop_rename(sr, sr->user_cr,
- src_fqi->fq_dnode, src_fqi->fq_od_name,
+ src_fqi->fq_dnode, src_fqi->fq_fnode->od_name,
dst_fqi->fq_dnode, dstname);
smb_node_end_crit(src_node);
-
if (rc == 0)
smb_node_notify_change(dst_fqi->fq_dnode);
-
-rename_cleanup_nodes:
- smb_node_release(src_node);
+ smb_node_release(src_fqi->fq_fnode);
smb_node_release(src_fqi->fq_dnode);
-
- if (dst_fqi->fq_dnode)
- smb_node_release(dst_fqi->fq_dnode);
-
- SMB_NULL_FQI_NODES(*src_fqi);
- SMB_NULL_FQI_NODES(*dst_fqi);
+ smb_node_release(dst_fqi->fq_dnode);
return (rc);
}
@@ -377,18 +406,35 @@ smb_com_nt_rename(smb_request_t *sr)
static int
smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
{
- smb_node_t *src_fnode;
+ smb_node_t *src_fnode, *tnode;
DWORD status;
int rc;
int count;
+ char *path;
- if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0)
+ tnode = sr->tid_tree->t_snode;
+
+ /* Lookup the source node. It MUST exist. */
+ path = src_fqi->fq_path.pn_path;
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
+ &src_fqi->fq_dnode, src_fqi->fq_last_comp);
+ if (rc != 0)
return (rc);
- src_fnode = src_fqi->fq_fnode;
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode,
+ src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
+ if (rc != 0) {
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
- if ((rc = smb_rename_check_attr(sr, src_fnode, src_fqi->fq_sattr)) != 0)
- goto link_cleanup_nodes;
+ src_fnode = src_fqi->fq_fnode;
+ rc = smb_rename_check_attr(sr, src_fnode, src_fqi->fq_sattr);
+ if (rc != 0) {
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
/*
* Break the oplock before access checks. If a client
@@ -412,52 +458,61 @@ smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
if (status == NT_STATUS_SHARING_VIOLATION) {
smb_node_end_crit(src_fnode);
- rc = EPIPE; /* = ERRbadshare */
- goto link_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (EPIPE); /* = ERRbadshare */
}
status = smb_range_check(sr, src_fnode, 0, UINT64_MAX, B_TRUE);
-
if (status != NT_STATUS_SUCCESS) {
smb_node_end_crit(src_fnode);
- rc = EACCES;
- goto link_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (EACCES);
}
if (utf8_strcasecmp(src_fqi->fq_path.pn_path,
dst_fqi->fq_path.pn_path) == 0) {
smb_node_end_crit(src_fnode);
- rc = 0;
- goto link_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (0);
}
- rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST);
+ /* Lookup the destination node. It MUST NOT exist. */
+ path = dst_fqi->fq_path.pn_path;
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
+ &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
if (rc != 0) {
smb_node_end_crit(src_fnode);
- goto link_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode,
+ dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode);
+ if (rc == 0) {
+ smb_node_release(dst_fqi->fq_fnode);
+ rc = EEXIST;
+ }
+ if (rc != ENOENT) {
+ smb_node_end_crit(src_fnode);
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ smb_node_release(dst_fqi->fq_dnode);
+ return (rc);
}
- /*
- * On success of FQM_PATH_MUST_NOT_EXIST only dst_fqi->fq_dnode
- * is valid (dst_fqi->fq_fnode is NULL).
- */
rc = smb_fsop_link(sr, sr->user_cr, dst_fqi->fq_dnode, src_fnode,
dst_fqi->fq_last_comp);
smb_node_end_crit(src_fnode);
-
if (rc == 0)
smb_node_notify_change(dst_fqi->fq_dnode);
-
-link_cleanup_nodes:
- smb_node_release(src_fnode);
+ smb_node_release(src_fqi->fq_fnode);
smb_node_release(src_fqi->fq_dnode);
-
- if (dst_fqi->fq_dnode)
- smb_node_release(dst_fqi->fq_dnode);
-
- SMB_NULL_FQI_NODES(*src_fqi);
- SMB_NULL_FQI_NODES(*dst_fqi);
+ smb_node_release(dst_fqi->fq_dnode);
return (rc);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c b/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c
new file mode 100644
index 0000000000..2f9111516d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c
@@ -0,0 +1,683 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Trans2 Set File/Path Information Levels:
+ *
+ * SMB_INFO_STANDARD
+ * SMB_INFO_SET_EAS
+ * SMB_SET_FILE_BASIC_INFO
+ * SMB_SET_FILE_DISPOSITION_INFO
+ * SMB_SET_FILE_END_OF_FILE_INFO
+ * SMB_SET_FILE_ALLOCATION_INFO
+ *
+ * Supported Passthrough levels:
+ * SMB_FILE_BASIC_INFORMATION
+ * SMB_FILE_DISPOSITION_INFORMATION
+ * SMB_FILE_END_OF_FILE_INFORMATION
+ * SMB_FILE_ALLOCATION_INFORMATION
+ *
+ * Internal levels representing non trans2 requests
+ * SMB_SET_INFORMATION
+ * SMB_SET_INFORMATION2
+ */
+
+/*
+ * Setting timestamps:
+ * The behaviour when the time field is set to -1 is not documented
+ * but is generally treated like 0, meaning that that server file
+ * system assigned value need not be changed.
+ *
+ * Setting attributes - FILE_ATTRIBUTE_NORMAL:
+ * SMB_SET_INFORMATION -
+ * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
+ * do NOT change the file's attributes.
+ * SMB_SET_BASIC_INFO -
+ * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
+ * clear (0) the file's attributes.
+ * - if the specified attributes are 0 do NOT change the file's
+ * attributes.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+typedef struct smb_setinfo {
+ uint16_t si_infolev;
+ smb_xa_t *si_xa;
+ smb_node_t *si_node;
+} smb_setinfo_t;
+
+/*
+ * These functions all return 0 (success) or -1 (error).
+ * They set error details in the sr when appropriate.
+ */
+static int smb_set_by_fid(smb_request_t *, smb_xa_t *, uint16_t);
+static int smb_set_by_path(smb_request_t *, smb_xa_t *, uint16_t, char *);
+static int smb_set_fileinfo(smb_request_t *, smb_setinfo_t *);
+static int smb_set_information(smb_request_t *, smb_setinfo_t *);
+static int smb_set_information2(smb_request_t *, smb_setinfo_t *);
+static int smb_set_standard_info(smb_request_t *, smb_setinfo_t *);
+static int smb_set_basic_info(smb_request_t *, smb_setinfo_t *);
+static int smb_set_disposition_info(smb_request_t *, smb_setinfo_t *);
+static int smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *);
+static int smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *);
+
+/*
+ * smb_com_trans2_set_file_information
+ */
+smb_sdrc_t
+smb_com_trans2_set_file_information(smb_request_t *sr, smb_xa_t *xa)
+{
+ uint16_t infolev;
+
+ if (smb_mbc_decodef(&xa->req_param_mb, "ww",
+ &sr->smb_fid, &infolev) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_set_by_fid(sr, xa, infolev) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_trans2_set_path_information
+ */
+smb_sdrc_t
+smb_com_trans2_set_path_information(smb_request_t *sr, smb_xa_t *xa)
+{
+ uint16_t infolev;
+ char *path;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
+ ERRDOS, ERROR_INVALID_FUNCTION);
+ return (SDRC_ERROR);
+ }
+
+ if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u",
+ sr, &infolev, &path) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_set_by_path(sr, xa, infolev, path) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_set_information (aka setattr)
+ */
+smb_sdrc_t
+smb_pre_set_information(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__SetInformation__start, smb_request_t *, sr);
+ return (SDRC_SUCCESS);
+}
+
+void
+smb_post_set_information(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__SetInformation__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_set_information(smb_request_t *sr)
+{
+ uint16_t infolev = SMB_SET_INFORMATION;
+ char *path;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &path) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_set_by_path(sr, NULL, infolev, path) != 0)
+ return (SDRC_ERROR);
+
+ if (smbsr_encode_empty_result(sr) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_set_information2 (aka setattre)
+ */
+smb_sdrc_t
+smb_pre_set_information2(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__SetInformation2__start, smb_request_t *, sr);
+ return (SDRC_SUCCESS);
+}
+
+void
+smb_post_set_information2(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__SetInformation2__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_set_information2(smb_request_t *sr)
+{
+ uint16_t infolev = SMB_SET_INFORMATION2;
+
+ if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_set_by_fid(sr, NULL, infolev) != 0)
+ return (SDRC_ERROR);
+
+ if (smbsr_encode_empty_result(sr) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_set_by_fid
+ *
+ * Common code for setting file information by open file id.
+ * Use the id to identify the node object and invoke smb_set_fileinfo
+ * for that node.
+ *
+ * Setting attributes on a named pipe by id is handled by simply
+ * returning success.
+ */
+static int
+smb_set_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
+{
+ int rc;
+ smb_setinfo_t sinfo;
+
+ if (SMB_TREE_IS_READONLY(sr)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (-1);
+ }
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type))
+ return (0);
+
+ smbsr_lookup_file(sr);
+ if (sr->fid_ofile == NULL) {
+ smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
+ return (-1);
+ }
+
+ if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
+ smbsr_release_file(sr);
+ return (0);
+ }
+
+ sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
+ sinfo.si_xa = xa;
+ sinfo.si_infolev = infolev;
+ sinfo.si_node = sr->fid_ofile->f_node;
+ rc = smb_set_fileinfo(sr, &sinfo);
+
+ smbsr_release_file(sr);
+ return (rc);
+}
+
+/*
+ * smb_set_by_path
+ *
+ * Common code for setting file information by file name.
+ * Use the file name to identify the node object and invoke
+ * smb_set_fileinfo for that node.
+ *
+ * Setting attributes on a named pipe by name is an error and
+ * is handled in the calling functions so that they can return
+ * the appropriate error status code (which differs by caller).
+ */
+static int
+smb_set_by_path(smb_request_t *sr, smb_xa_t *xa,
+ uint16_t infolev, char *path)
+{
+ int rc;
+ smb_setinfo_t sinfo;
+ smb_node_t *node, *dnode;
+ char *name;
+
+ if (SMB_TREE_IS_READONLY(sr)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (-1);
+ }
+
+ name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ rc = smb_pathname_reduce(sr, sr->user_cr, path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, name);
+ if (rc == 0) {
+ rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dnode, name, &node);
+ smb_node_release(dnode);
+ }
+ kmem_free(name, MAXNAMELEN);
+
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ /* Break any conflicting oplock for subsequent attribute setting */
+ if (smb_oplock_conflict(node, sr->session, NULL)) {
+ (void) smb_oplock_break(node, sr->session, B_FALSE);
+ }
+
+ sinfo.si_xa = xa;
+ sinfo.si_infolev = infolev;
+ sinfo.si_node = node;
+ rc = smb_set_fileinfo(sr, &sinfo);
+
+ smb_node_release(node);
+ return (rc);
+}
+
+/*
+ * smb_set_fileinfo
+ */
+static int
+smb_set_fileinfo(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ switch (sinfo->si_infolev) {
+ case SMB_SET_INFORMATION:
+ return (smb_set_information(sr, sinfo));
+
+ case SMB_SET_INFORMATION2:
+ return (smb_set_information2(sr, sinfo));
+
+ case SMB_INFO_STANDARD:
+ return (smb_set_standard_info(sr, sinfo));
+
+ case SMB_INFO_SET_EAS:
+ /* EAs not supported */
+ return (0);
+
+ case SMB_SET_FILE_BASIC_INFO:
+ case SMB_FILE_BASIC_INFORMATION:
+ return (smb_set_basic_info(sr, sinfo));
+
+ case SMB_SET_FILE_DISPOSITION_INFO:
+ case SMB_FILE_DISPOSITION_INFORMATION:
+ return (smb_set_disposition_info(sr, sinfo));
+
+ case SMB_SET_FILE_END_OF_FILE_INFO:
+ case SMB_FILE_END_OF_FILE_INFORMATION:
+ return (smb_set_eof_info(sr, sinfo));
+
+ case SMB_SET_FILE_ALLOCATION_INFO:
+ case SMB_FILE_ALLOCATION_INFORMATION:
+ return (smb_set_alloc_info(sr, sinfo));
+
+ default:
+ break;
+ }
+
+ smbsr_error(sr, NT_STATUS_INVALID_INFO_CLASS,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (-1);
+}
+
+/*
+ * smb_set_information
+ *
+ * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
+ * target is not a directory.
+ *
+ * For compatibility with Windows Servers, if the specified
+ * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change
+ * the file's attributes.
+ */
+static int
+smb_set_information(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ int rc;
+ uint16_t attributes;
+ smb_node_t *node = sinfo->si_node;
+ smb_attr_t attr;
+ uint32_t mtime;
+
+ if (smbsr_decode_vwv(sr, "wl10.", &attributes, &mtime) != 0)
+ return (-1);
+
+ if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ (!smb_node_is_dir(node))) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (-1);
+ }
+
+ bzero(&attr, sizeof (smb_attr_t));
+ if (attributes != FILE_ATTRIBUTE_NORMAL) {
+ attr.sa_dosattr = attributes;
+ attr.sa_mask |= SMB_AT_DOSATTR;
+ }
+
+ if (mtime != 0 && mtime != UINT_MAX) {
+ attr.sa_vattr.va_mtime.tv_sec =
+ smb_time_local_to_gmt(sr, mtime);
+ attr.sa_mask |= SMB_AT_MTIME;
+ }
+
+ rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_information2
+ */
+static int
+smb_set_information2(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ int rc;
+ uint32_t crtime, atime, mtime;
+ smb_attr_t attr;
+
+ if (smbsr_decode_vwv(sr, "yyy", &crtime, &atime, &mtime) != 0)
+ return (-1);
+
+ bzero(&attr, sizeof (smb_attr_t));
+ if (mtime != 0 && mtime != UINT_MAX) {
+ attr.sa_vattr.va_mtime.tv_sec =
+ smb_time_local_to_gmt(sr, mtime);
+ attr.sa_mask |= SMB_AT_MTIME;
+ }
+
+ if (crtime != 0 && crtime != UINT_MAX) {
+ attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
+ attr.sa_mask |= SMB_AT_CRTIME;
+ }
+
+ if (atime != 0 && atime != UINT_MAX) {
+ attr.sa_vattr.va_atime.tv_sec =
+ smb_time_local_to_gmt(sr, atime);
+ attr.sa_mask |= SMB_AT_ATIME;
+ }
+
+ rc = smb_node_setattr(sr, sinfo->si_node, sr->user_cr,
+ sr->fid_ofile, &attr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_standard_info
+ *
+ * Sets standard file/path information.
+ */
+static int
+smb_set_standard_info(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ smb_attr_t attr;
+ uint32_t crtime, atime, mtime;
+ smb_node_t *node = sinfo->si_node;
+ int rc;
+
+ if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "yyy",
+ &crtime, &atime, &mtime) != 0) {
+ return (-1);
+ }
+
+ bzero(&attr, sizeof (smb_attr_t));
+ if (mtime != 0 && mtime != (uint32_t)-1) {
+ attr.sa_vattr.va_mtime.tv_sec =
+ smb_time_local_to_gmt(sr, mtime);
+ attr.sa_mask |= SMB_AT_MTIME;
+ }
+
+ if (crtime != 0 && crtime != (uint32_t)-1) {
+ attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
+ attr.sa_mask |= SMB_AT_CRTIME;
+ }
+
+ if (atime != 0 && atime != (uint32_t)-1) {
+ attr.sa_vattr.va_atime.tv_sec =
+ smb_time_local_to_gmt(sr, atime);
+ attr.sa_mask |= SMB_AT_ATIME;
+ }
+
+ rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_basic_info
+ *
+ * Sets basic file/path information.
+ *
+ * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
+ * target is not a directory.
+ *
+ * For compatibility with windows servers:
+ * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
+ * clear (0) the file's attributes.
+ * - if the specified attributes are 0 do NOT change the file's attributes.
+ */
+static int
+smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ int rc;
+ uint64_t crtime, atime, mtime, ctime;
+ uint16_t attributes;
+ smb_attr_t attr;
+ smb_node_t *node = sinfo->si_node;
+
+ if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "qqqqw",
+ &crtime, &atime, &mtime, &ctime, &attributes) != 0) {
+ return (-1);
+ }
+
+ if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ (!smb_node_is_dir(node))) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (-1);
+ }
+
+ bzero(&attr, sizeof (smb_attr_t));
+ if (ctime != 0 && ctime != (uint64_t)-1) {
+ smb_time_nt_to_unix(ctime, &attr.sa_vattr.va_ctime);
+ attr.sa_mask |= SMB_AT_CTIME;
+ }
+
+ if (crtime != 0 && crtime != (uint64_t)-1) {
+ smb_time_nt_to_unix(crtime, &attr.sa_crtime);
+ attr.sa_mask |= SMB_AT_CRTIME;
+ }
+
+ if (mtime != 0 && mtime != (uint64_t)-1) {
+ smb_time_nt_to_unix(mtime, &attr.sa_vattr.va_mtime);
+ attr.sa_mask |= SMB_AT_MTIME;
+ }
+
+ if (atime != 0 && atime != (uint64_t)-1) {
+ smb_time_nt_to_unix(atime, &attr.sa_vattr.va_atime);
+ attr.sa_mask |= SMB_AT_ATIME;
+ }
+
+ 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) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_eof_info
+ */
+static int
+smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ int rc;
+ smb_attr_t attr;
+ uint64_t eof;
+ smb_node_t *node = sinfo->si_node;
+
+ if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &eof) != 0)
+ return (-1);
+
+ if (smb_node_is_dir(node)) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (-1);
+ }
+
+ bzero(&attr, sizeof (smb_attr_t));
+ 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) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_alloc_info
+ */
+static int
+smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ int rc;
+ smb_attr_t attr;
+ uint64_t allocsz;
+ smb_node_t *node = sinfo->si_node;
+
+ if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &allocsz) != 0)
+ return (-1);
+
+ if (smb_node_is_dir(node)) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (-1);
+ }
+
+ bzero(&attr, sizeof (smb_attr_t));
+ 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) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_disposition_info
+ *
+ * Set/Clear DELETE_ON_CLOSE flag for an open file.
+ * File should have been opened with DELETE access otherwise
+ * the operation is not permitted.
+ *
+ * NOTE: The node should be marked delete-on-close upon the receipt
+ * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
+ * It is different than both SmbNtCreateAndX and SmbNtTransact, which
+ * set delete-on-close on the ofile and defer setting the flag on the
+ * node until the file is closed.
+ *
+ * Observation of Windows 2000 indicates the following:
+ *
+ * 1) If a file is not opened with delete-on-close create options and
+ * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
+ * using that open file handle, any subsequent open requests will fail
+ * with DELETE_PENDING.
+ *
+ * 2) If a file is opened with delete-on-close create options and the
+ * client attempts to unset delete-on-close via Trans2SetFileInfo
+ * (SetDispositionInfo) prior to the file close, any subsequent open
+ * requests will still fail with DELETE_PENDING after the file is closed.
+ *
+ * 3) If a file is opened with delete-on-close create options and that
+ * file handle (not the last open handle and the only file handle
+ * with delete-on-close set) is closed. Any subsequent open requests
+ * will fail with DELETE_PENDING. Unsetting delete-on-close via
+ * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
+ * node delete-on-close flag, which will result in the file not being
+ * removed even after the last file handle is closed.
+ */
+static int
+smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ unsigned char mark_delete;
+ uint32_t flags = 0;
+
+ if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "b", &mark_delete) != 0)
+ return (-1);
+
+ if ((sr->fid_ofile == NULL) ||
+ !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (-1);
+ }
+
+ if (mark_delete) {
+ if (SMB_TREE_SUPPORTS_CATIA(sr))
+ flags |= SMB_CATIA;
+
+ if (smb_node_set_delete_on_close(sinfo->si_node,
+ sr->user_cr, flags)) {
+ smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (-1);
+ }
+ } else {
+ smb_node_reset_delete_on_close(sinfo->si_node);
+ }
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information.c b/usr/src/uts/common/fs/smbsrv/smb_set_information.c
deleted file mode 100644
index e4073921b2..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_set_information.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * SMB: set_information
- *
- * This message is sent to change the information about a file.
- *
- * Client Request Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 8
- * USHORT FileAttributes; Attributes of the file
- * UTIME LastWriteTime; Time of last write
- * USHORT Reserved [5]; Reserved (must be 0)
- * USHORT ByteCount; Count of data bytes; min = 2
- * UCHAR BufferFormat; 0x04
- * STRING FileName[]; File name
- *
- * FileName is the fully qualified name of the file relative to the Tid.
- *
- * Support of all parameters is optional. A server which does not
- * implement one of the parameters will ignore that field. If the
- * LastWriteTime field contain zero then the file's time is not changed.
- *
- * Server Response Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 0
- * USHORT ByteCount; Count of data bytes = 0
- *
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-smb_sdrc_t
-smb_pre_set_information(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__SetInformation__start, smb_request_t *, sr);
- return (SDRC_SUCCESS);
-}
-
-void
-smb_post_set_information(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__SetInformation__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_set_information(smb_request_t *sr)
-{
- int rc;
- unsigned short dattr;
- char *path;
- smb_node_t *dir_node;
- smb_node_t *node;
- smb_attr_t attr;
- char *name;
- uint32_t last_wtime;
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- (void) smbsr_encode_empty_result(sr);
- return (SDRC_SUCCESS);
- }
-
- name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- if (smbsr_decode_vwv(sr, "wl10.", &dattr, &last_wtime) != 0) {
- kmem_free(name, MAXNAMELEN);
- return (SDRC_ERROR);
- }
-
- if (smbsr_decode_data(sr, "%S", sr, &path) != 0) {
- kmem_free(name, MAXNAMELEN);
- return (SDRC_ERROR);
- }
-
- rc = smb_pathname_reduce(sr, sr->user_cr, path,
- sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name);
- if (rc != 0) {
- kmem_free(name, MAXNAMELEN);
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
- sr->tid_tree->t_snode, dir_node, name, &node);
- if (rc != 0) {
- smb_node_release(dir_node);
- kmem_free(name, MAXNAMELEN);
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- smb_node_release(dir_node);
-
- /*
- * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
- * target is not a directory.
- */
- if ((dattr & FILE_ATTRIBUTE_DIRECTORY) &&
- (!smb_node_is_dir(node))) {
- smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
- ERRDOS, ERROR_INVALID_PARAMETER);
- return (SDRC_ERROR);
- }
-
- if (smb_oplock_conflict(node, sr->session, NULL)) {
- /*
- * for the benefit of attribute setting later on
- */
- (void) smb_oplock_break(node, sr->session, B_FALSE);
- }
-
- bzero(&attr, sizeof (smb_attr_t));
-
- /*
- * For compatibility with Windows Servers, if the specified
- * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change
- * the file's attributes.
- * Note - this is different from TRANS2_SET_PATH/FILE_INFORMATION
- */
- if (dattr != FILE_ATTRIBUTE_NORMAL) {
- attr.sa_dosattr = dattr;
- attr.sa_mask |= SMB_AT_DOSATTR;
- }
-
- /*
- * The behaviour when the time field is set to -1
- * is not documented but is generally treated like 0,
- * meaning that that server file system assigned value
- * need not be changed.
- */
- if (last_wtime != 0 && last_wtime != 0xFFFFFFFF) {
- attr.sa_vattr.va_mtime.tv_sec = smb_local2gmt(sr, last_wtime);
- attr.sa_mask |= SMB_AT_MTIME;
- }
-
- rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr);
- smb_node_release(node);
- kmem_free(name, MAXNAMELEN);
-
- if (rc) {
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- rc = smbsr_encode_empty_result(sr);
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c b/usr/src/uts/common/fs/smbsrv/smb_set_information2.c
deleted file mode 100644
index c3a5257598..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * SMB: set_information2
- *
- * Client Request Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 7
- * USHORT Fid; File handle
- * SMB_DATE CreationDate;
- * SMB_TIME CreationTime;
- * SMB_DATE LastAccessDate;
- * SMB_TIME LastAccessTime;
- * SMB_DATE LastWriteDate;
- * SMB_TIME LastWriteTime;
- * USHORT ByteCount; Count of data bytes = 0
- *
- * SMB_COM_SET_INFORMATION2 sets information about the file represented by
- * Fid. The target file is updated from the values specified. A date or
- * time value or zero indicates to leave that specific date and time
- * unchanged.
- *
- * Server Response Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 0
- * USHORT ByteCount; Count of data bytes = 0
- *
- * Fid must be open with (at least) write permission.
- */
-
-#include <smbsrv/smb_incl.h>
-
-smb_sdrc_t
-smb_pre_set_information2(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__SetInformation2__start, smb_request_t *, sr);
- return (SDRC_SUCCESS);
-}
-
-void
-smb_post_set_information2(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__SetInformation2__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_set_information2(smb_request_t *sr)
-{
- uint32_t creation, last_access, last_write; /* times */
- smb_attr_t attr;
- smb_node_t *node;
- int rc;
-
- rc = smbsr_decode_vwv(sr, "wyyy", &sr->smb_fid,
- &creation, &last_access, &last_write);
- if (rc != 0)
- return (SDRC_ERROR);
-
- smbsr_lookup_file(sr);
- if (sr->fid_ofile == NULL) {
- smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
- return (SDRC_ERROR);
- }
-
- sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
-
- node = sr->fid_ofile->f_node;
-
- if (node == 0 || sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) {
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
- return (SDRC_ERROR);
- }
-
- bzero(&attr, sizeof (smb_attr_t));
-
- /*
- * The behaviour when the time field is set to -1
- * is not documented but is generally treated like 0,
- * meaning that that server file system assigned value
- * need not be changed.
- */
- if (last_write != 0 && last_write != UINT_MAX) {
- attr.sa_vattr.va_mtime.tv_sec = smb_local2gmt(sr, last_write);
- attr.sa_mask |= SMB_AT_MTIME;
- }
-
- if (creation != 0 && creation != UINT_MAX) {
- attr.sa_crtime.tv_sec = smb_local2gmt(sr, creation);
- attr.sa_mask |= SMB_AT_CRTIME;
- }
-
- if (last_access != 0 && last_access != UINT_MAX) {
- attr.sa_vattr.va_atime.tv_sec = smb_local2gmt(sr, last_access);
- attr.sa_mask |= SMB_AT_ATIME;
- }
-
- rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
- if (rc) {
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- rc = smbsr_encode_empty_result(sr);
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
index d2b618fd5c..f3aef8da99 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
@@ -664,9 +664,9 @@ smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
fileinfo->fi_cookie);
(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr,
- smb_gmt2local(sr, fileinfo->fi_crtime.tv_sec),
- smb_gmt2local(sr, fileinfo->fi_atime.tv_sec),
- smb_gmt2local(sr, fileinfo->fi_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
dsize32,
asize32,
fileinfo->fi_dosattr,
@@ -697,9 +697,9 @@ smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
tmpbuf[namelen] = '\0';
(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr,
- smb_gmt2local(sr, fileinfo->fi_crtime.tv_sec),
- smb_gmt2local(sr, fileinfo->fi_atime.tv_sec),
- smb_gmt2local(sr, fileinfo->fi_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
dsize32,
asize32,
fileinfo->fi_dosattr,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
deleted file mode 100644
index 1141fb6d12..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
+++ /dev/null
@@ -1,636 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * SMB: trans2_query_file_information
- *
- * This request is used to get information about a specific file or
- * subdirectory given a handle to it.
- *
- * Client Request Value
- * ========================== ==========================================
- *
- * WordCount 15
- * MaxSetupCount 0
- * SetupCount 1
- * Setup[0] TRANS2_QUERY_FILE_INFORMATION
- *
- * Parameter Block Encoding Description
- * ========================== ==========================================
- *
- * USHORT Fid; Handle of file for request
- * USHORT InformationLevel; Level of information requested
- *
- * The available information levels, as well as the format of the response
- * are identical to TRANS2_QUERY_PATH_INFORMATION.
- */
-
-#include <smbsrv/smb_vops.h>
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-uint32_t smb_pad_align(uint32_t offset, uint32_t align);
-void smb_encode_smb_datetimes(smb_request_t *, smb_xa_t *, smb_attr_t *);
-void smb_encode_nt_times(smb_request_t *, smb_xa_t *, smb_attr_t *);
-extern int smb_query_all_info_filename(smb_tree_t *, smb_node_t *,
- char *, size_t);
-
-
-/*
- * smb_com_trans2_query_file_information
- *
- * Observation of Windows 2000 indicates the following:
- *
- * 1) If a file is opened with delete-on-close create options, the
- * delete-on-close status returned by the Trans2QueryFileInfo will not
- * be set. The delete-on-close status will only be set when the above
- * file handle is closed.
- *
- * 2) If a file is not opened with delete-on-close create options but the
- * delete-on-close is set via Trans2SetFileInfo/DispositionInfo, the
- * delete-on-close status returned by Trans2QueryFileInfo will be set
- * immediately.
- */
-smb_sdrc_t
-smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
-{
- static smb_attr_t pipe_attr;
- smb_attr_t file_attr;
- unsigned short infolev, dattr = 0;
- u_offset_t datasz = 0, allocsz = 0;
- smb_attr_t *ap = NULL;
- char *namep = NULL;
- char *filename = NULL;
- int filename_len = 0;
- smb_node_t *node = NULL; /* only set for SMB_FTYPE_DISK files */
- smb_node_t *dnode = NULL;
- unsigned char delete_on_close = 0;
- unsigned char is_dir = 0;
- char *filebuf = NULL;
- char short_name[SMB_SHORTNAMELEN];
- char name83[SMB_SHORTNAMELEN];
- int rc;
-
- if (smb_mbc_decodef(&xa->req_param_mb, "ww", &sr->smb_fid,
- &infolev) != 0) {
- return (SDRC_ERROR);
- }
-
- smbsr_lookup_file(sr);
- if (sr->fid_ofile == NULL) {
- smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
- return (SDRC_ERROR);
- }
-
- switch (sr->fid_ofile->f_ftype) {
- case SMB_FTYPE_DISK:
- {
- /* The node is only valid for SMB_FTYPE_DISK files. */
- node = sr->fid_ofile->f_node;
-
- /*
- * For some reason NT will not show the security tab in the root
- * directory of a mapped drive unless the filename length is
- * greater than one.
- * This may be a NT vs Windows9x UNICODE check.
- * So we hack the length here to persuade NT to show the tab. It
- * should be safe because of the null terminator character.
- */
- /* be careful here we need od_name now rather than node_name */
- /* do we want to use node_name in the case of softlinks ?? */
- namep = node->od_name;
- filename = namep;
- filename_len = smb_ascii_or_unicode_strlen(sr, filename);
- if (strcmp(namep, ".") == 0 && filename_len == 1)
- filename_len = 2;
-
- ap = &file_attr;
- if (smb_node_getattr(sr, node, ap) != 0) {
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- dattr = ap->sa_dosattr;
-
- if (smb_node_is_dir(node)) {
- is_dir = 1;
- datasz = allocsz = 0;
- } else {
- is_dir = 0;
- datasz = ap->sa_vattr.va_size;
- allocsz = ap->sa_vattr.va_nblocks * DEV_BSIZE;
- }
-
- dnode = node->n_dnode;
- delete_on_close =
- (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
-
- /*
- * The number of links reported should be the number of
- * non-deleted links. Thus if delete_on_close is set,
- * decrement the link count.
- */
- if (delete_on_close && ap->sa_vattr.va_nlink > 0)
- --(ap->sa_vattr.va_nlink);
-
- }
- break;
-
- case SMB_FTYPE_MESG_PIPE:
- {
- /* The pipe is only valid for SMB_FTYPE_MESG_PIPE files */
- namep = sr->fid_ofile->f_pipe->p_name;
- filename = namep;
- filename_len = smb_ascii_or_unicode_strlen(sr, filename);
-
- ap = &pipe_attr;
- ap->sa_vattr.va_nlink = 1;
- dattr = FILE_ATTRIBUTE_NORMAL;
- datasz = allocsz = 0;
-
- delete_on_close = 1;
- is_dir = 0;
-
- /* some levels are not valid for pipes */
- switch (infolev) {
- case SMB_QUERY_FILE_ALT_NAME_INFO:
- case SMB_FILE_ALT_NAME_INFORMATION:
- case SMB_QUERY_FILE_STREAM_INFO:
- case SMB_FILE_STREAM_INFORMATION:
- case SMB_QUERY_FILE_COMPRESSION_INFO:
- case SMB_FILE_COMPRESSION_INFORMATION:
- case SMB_FILE_ATTR_TAG_INFORMATION:
- smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
- ERRDOS, ERROR_INVALID_PARAMETER);
- return (SDRC_ERROR);
- case SMB_INFO_QUERY_ALL_EAS:
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
- }
- break;
- default:
- smbsr_error(sr, 0, ERRDOS, ERRbadfile);
- return (SDRC_ERROR);
- }
-
- filebuf = kmem_alloc(MAXPATHLEN+1, KM_SLEEP);
-
- switch (infolev) {
- case SMB_FILE_ACCESS_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
- sr->fid_ofile->f_granted_access);
- break;
-
- case SMB_INFO_STANDARD:
- if (datasz > UINT_MAX)
- datasz = UINT_MAX;
- if (allocsz > UINT_MAX)
- allocsz = UINT_MAX;
-
- /* unlike other levels attributes should be 0 here for pipes */
- if (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)
- dattr = 0;
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_smb_datetimes(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "llw",
- (uint32_t)datasz, (uint32_t)allocsz, dattr);
- break;
-
- case SMB_INFO_QUERY_EA_SIZE:
- if (datasz > UINT_MAX)
- datasz = UINT_MAX;
- if (allocsz > UINT_MAX)
- allocsz = UINT_MAX;
-
- /* unlike other levels attributes should be 0 here for pipes */
- if (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)
- dattr = 0;
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_smb_datetimes(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "llwl",
- (uint32_t)datasz, (uint32_t)allocsz, dattr, 0);
- break;
-
- case SMB_INFO_QUERY_ALL_EAS:
- case SMB_INFO_QUERY_EAS_FROM_LIST:
- case SMB_FILE_EA_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
- break;
-
- case SMB_INFO_IS_NAME_VALID:
- break;
-
- case SMB_QUERY_FILE_BASIC_INFO:
- case SMB_FILE_BASIC_INFORMATION:
- /*
- * NT includes 6 undocumented bytes at the end of this
- * response, which are required by NetBench 5.01.
- * Similar change in smb_trans2_query_path_information.c.
- */
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_nt_times(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.", dattr);
- break;
-
- case SMB_QUERY_FILE_STANDARD_INFO:
- case SMB_FILE_STANDARD_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- /*
- * Add 2 bytes to pad data to long. It is
- * necessary because Win2k expects the padded bytes.
- */
- (void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
- (uint64_t)allocsz,
- (uint64_t)datasz,
- ap->sa_vattr.va_nlink,
- delete_on_close,
- is_dir);
- break;
-
- case SMB_QUERY_FILE_EA_INFO:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
- break;
-
- case SMB_QUERY_FILE_NAME_INFO:
- case SMB_FILE_NAME_INFORMATION:
- /*
- * It looks like NT doesn't know what to do with the name "."
- * so we convert it to "\\" to indicate the root directory.
- *
- * If the leading \ is missing, add it.
- */
- if (strcmp(namep, ".") == 0) {
- filename = "\\";
- filename_len = 2;
- } else if (*namep != '\\') {
- filename = filebuf;
- (void) snprintf(filename, MAXNAMELEN + 1, "\\%s",
- namep);
- filename_len =
- smb_ascii_or_unicode_strlen(sr, filename);
- } else {
- filename = namep;
- filename_len =
- smb_ascii_or_unicode_strlen(sr, filename);
- }
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
- filename_len, filename);
- break;
-
- case SMB_QUERY_FILE_ALL_INFO:
- case SMB_FILE_ALL_INFORMATION:
- if (sr->fid_ofile->f_ftype == SMB_FTYPE_DISK) {
- rc = smb_query_all_info_filename(sr->tid_tree, node,
- filebuf, MAXPATHLEN);
- if (rc != 0) {
- smbsr_errno(sr, rc);
- kmem_free(filebuf, MAXPATHLEN+1);
- return (SDRC_ERROR);
- }
- filename = filebuf;
- } else {
- /* If the leading \ is missing, add it. */
- if (*namep != '\\') {
- (void) snprintf(filebuf, MAXNAMELEN,
- "\\%s", namep);
- filename = filebuf;
- }
- }
- filename_len = smb_ascii_or_unicode_strlen(sr, filename);
-
- /*
- * There is a 6-byte pad between Attributes and AllocationSize,
- * and a 2-byte pad after the Directory field.
- */
- if (node) {
- rc = smb_query_all_info_filename(sr->tid_tree, node,
- filebuf, MAXPATHLEN);
- if (rc != 0) {
- smbsr_errno(sr, rc);
- kmem_free(filebuf, MAXPATHLEN+1);
- return (SDRC_ERROR);
- }
- filename = filebuf;
- filename_len = smb_ascii_or_unicode_strlen(sr,
- filename);
- }
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_nt_times(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.qqlbb2.l",
- dattr,
- (uint64_t)allocsz,
- (uint64_t)datasz,
- ap->sa_vattr.va_nlink,
- delete_on_close,
- is_dir,
- 0);
-
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu",
- sr, filename_len, filename);
- break;
-
- case SMB_QUERY_FILE_ALT_NAME_INFO:
- case SMB_FILE_ALT_NAME_INFORMATION:
- /*
- * If the shortname is generated by smb_mangle_name()
- * it will be returned as the alternative name.
- * Otherwise, convert the original name to upper-case
- * and return it as the alternative name.
- */
- (void) smb_mangle_name(ap->sa_vattr.va_nodeid,
- filename, short_name, name83, 0);
- if (*short_name == 0) {
- (void) strlcpy(short_name, filename, SMB_SHORTNAMELEN);
- (void) utf8_strupr(short_name);
- }
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
- mts_wcequiv_strlen(short_name), short_name);
- break;
-
- case SMB_QUERY_FILE_STREAM_INFO:
- case SMB_FILE_STREAM_INFORMATION:
- {
- struct smb_node *node = sr->fid_ofile->f_node;
- if (dnode == NULL) {
- kmem_free(filebuf, MAXPATHLEN+1);
- smbsr_error(sr, 0, ERRDOS, ERRbadfile);
- return (SDRC_ERROR);
- }
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- if (SMB_IS_STREAM(node)) {
- ASSERT(node->n_unode);
- ASSERT(node->n_unode->n_magic == SMB_NODE_MAGIC);
- ASSERT(node->n_unode->n_state !=
- SMB_NODE_STATE_DESTROYING);
-
- (void) smb_encode_stream_info(sr, xa,
- node->n_unode, ap);
- } else {
- (void) smb_encode_stream_info(sr, xa, node, ap);
- }
- break;
- }
- case SMB_QUERY_FILE_COMPRESSION_INFO:
- case SMB_FILE_COMPRESSION_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.",
- datasz, 0, 0, 0, 0);
- break;
-
- case SMB_FILE_INTERNAL_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "q",
- ap->sa_vattr.va_nodeid);
- break;
-
- case SMB_FILE_ATTR_TAG_INFORMATION:
- /*
- * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
- * second dword should be the reparse tag. Otherwise
- * the tag value should be set to zero.
- * We don't support reparse points, so we set the tag
- * to zero.
- */
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
- (uint32_t)dattr, 0);
- break;
-
- default:
- kmem_free(filebuf, MAXPATHLEN+1);
- smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
- return (SDRC_ERROR);
- }
-
- kmem_free(filebuf, MAXPATHLEN+1);
- return (SDRC_SUCCESS);
-}
-
-/*
- * smb_encode_stream_info
- *
- * This function encodes the streams information for both T2QueryFileInfo
- * and T2QueryPathInfo. The rules about how to do this are not documented.
- * They have been derived using observed NT behaviour and the IR's listed
- * below.
- *
- * IR101680: ArcServe2000 problem. ArcServe doesn't like the null-
- * stream data on directories that don't have any associated streams.
- *
- * IR103484 and KB article Q234765: Citrix problem. If there are no
- * streams, only return the unnamed stream data if the target is a
- * file. The Citrix Metaframe cdm.sys driver crashes the Windows server,
- * on which it's running, if it receives the unexpected stream data
- * for a directory.
- *
- * If there are streams, on files or directories, we need to return
- * them to support Mac/DAVE clients. Mac clients make this request
- * to see if there is a comment stream. If we don't provide the
- * information, the client won't try to access the comment stream.
- *
- * If the target is a file:
- * 1. If there are no named streams, the response should still contain
- * an entry for the unnamed stream.
- * 2. If there are named streams, the response should contain an entry
- * for the unnamed stream followed by the entries for the named
- * streams.
- *
- * If the target is a directory:
- * 1. If there are no streams, the response is complete. Directories
- * do not report the unnamed stream.
- * 2. If there are streams, the response should contain entries for
- * those streams but there should not be an entry for the unnamed
- * stream.
- *
- * Note that the stream name lengths exclude the null terminator but
- * the field lengths (i.e. next offset calculations) need to include
- * the null terminator and be padded to a multiple of 8 bytes. The
- * last entry does not seem to need any padding.
- *
- * If an error is encountered when trying to read the directory
- * entries (smb_fsop_stream_readdir) it is treated as if there are
- * no [more] directory entries. The entries that have been read so
- * far are returned and no error is reported.
- *
- * Offset calculation:
- * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
- */
-void
-smb_encode_stream_info(
- struct smb_request *sr,
- struct smb_xa *xa,
- struct smb_node *fnode,
- smb_attr_t *attr)
-{
- char *stream_name;
- uint32_t next_offset;
- uint32_t stream_nlen;
- uint32_t pad;
- u_offset_t datasz, allocsz;
- boolean_t is_dir;
- smb_streaminfo_t *sinfo, *sinfo_next;
- int rc = 0;
- boolean_t done = B_FALSE;
- boolean_t eos = B_FALSE;
- uint16_t odid;
- smb_odir_t *od = NULL;
-
- sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
- sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
- is_dir = (attr->sa_vattr.va_type == VDIR);
- datasz = attr->sa_vattr.va_size;
- allocsz = attr->sa_vattr.va_nblocks * DEV_BSIZE;
-
- odid = smb_odir_openat(sr, fnode);
- if (odid != 0)
- od = smb_tree_lookup_odir(sr->tid_tree, odid);
- if (od != NULL)
- rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos);
-
- if ((od == NULL) || (rc != 0) || (eos))
- done = B_TRUE;
-
- /*
- * If not a directory, encode an entry for the unnamed stream.
- */
- if (!is_dir) {
- stream_name = "::$DATA";
- stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
-
- if (done)
- next_offset = 0;
- else
- next_offset = 24 + stream_nlen +
- smb_ascii_or_unicode_null_len(sr);
-
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr,
- next_offset, stream_nlen, datasz, allocsz, stream_name);
- }
-
- /*
- * Since last packet does not have a pad we need to check
- * for the next stream before we encode the current one
- */
- while (!done) {
- stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name);
- sinfo_next->si_name[0] = 0;
-
- rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos);
- if ((rc != 0) || (eos)) {
- done = B_TRUE;
- next_offset = 0;
- pad = 0;
- } else {
- next_offset = 24 + stream_nlen +
- smb_ascii_or_unicode_null_len(sr);
- pad = smb_pad_align(next_offset, 8);
- next_offset += pad;
- }
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.",
- sr, next_offset, stream_nlen,
- sinfo->si_size, sinfo->si_alloc_size,
- sinfo->si_name, pad);
-
- (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t));
- }
-
- kmem_free(sinfo, sizeof (smb_streaminfo_t));
- kmem_free(sinfo_next, sizeof (smb_streaminfo_t));
- if (od) {
- smb_odir_close(od);
- smb_odir_release(od);
- }
-}
-
-/*
- * smb_pad_align
- *
- * Returns the number of bytes required to get pad an offset to the
- * specified alignment.
- */
-uint32_t
-smb_pad_align(uint32_t offset, uint32_t align)
-{
- uint32_t pad = offset % align;
-
- if (pad != 0)
- pad = align - pad;
-
- return (pad);
-}
-
-/*
- * smb_encode_smb_datetimes
- *
- * Encode timestamps in the SMB_DATE / SMB_TIME format.
- */
-void
-smb_encode_smb_datetimes(smb_request_t *sr, smb_xa_t *xa, smb_attr_t *attr)
-{
- if ((sr->fid_ofile) &&
- (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)) {
- (void) smb_mbc_encodef(&xa->rep_data_mb, "lll", 0, 0, 0);
- return;
- }
-
- (void) smb_mbc_encodef(&xa->rep_data_mb,
- ((sr->session->native_os == NATIVE_OS_WIN95) ? "YYY" : "yyy"),
- smb_gmt2local(sr, attr->sa_crtime.tv_sec),
- smb_gmt2local(sr, attr->sa_vattr.va_atime.tv_sec),
- smb_gmt2local(sr, attr->sa_vattr.va_mtime.tv_sec));
-}
-
-/*
- * smb_encode_nt_times
- *
- * Encode timestamps in LARGE INTEGER format NT Times.
- */
-void
-smb_encode_nt_times(smb_request_t *sr, smb_xa_t *xa, smb_attr_t *attr)
-{
- if ((sr->fid_ofile) &&
- (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)) {
- (void) smb_mbc_encodef(&xa->rep_data_mb, "qqqq", 0, 0, 0, 0);
- return;
- }
-
- (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTT",
- &attr->sa_crtime,
- &attr->sa_vattr.va_atime,
- &attr->sa_vattr.va_mtime,
- &attr->sa_vattr.va_ctime);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
deleted file mode 100644
index 078fd4e4af..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-
-/*
- * SMB: trans2_query_path_information
- *
- * This request is used to get information about a specific file or
- * subdirectory.
- *
- * Client Request Value
- * ========================== =========================================
- *
- * WordCount 15
- * MaxSetupCount 0
- * SetupCount 1
- * Setup[0] TRANS2_QUERY_PATH_INFORMATION
- *
- * Parameter Block Encoding Description
- * ========================== =========================================
- *
- * USHORT InformationLevel; Level of information requested
- * ULONG Reserved; Must be zero
- * STRING FileName; File or directory name
- *
- * The following InformationLevels may be requested:
- *
- * Information Level Value
- *
- * ================================ =====
- *
- * SMB_INFO_STANDARD 1
- * SMB_INFO_QUERY_EA_SIZE 2
- * SMB_INFO_QUERY_EAS_FROM_LIST 3
- * SMB_INFO_QUERY_ALL_EAS 4
- * SMB_INFO_IS_NAME_VALID 6
- * SMB_QUERY_FILE_BASIC_INFO 0x101
- * SMB_QUERY_FILE_STANDARD_INFO 0x102
- * SMB_QUERY_FILE_EA_INFO 0x103
- * SMB_QUERY_FILE_NAME_INFO 0x104
- * SMB_QUERY_FILE_ALL_INFO 0x107
- * SMB_QUERY_FILE_ALT_NAME_INFO 0x108
- * SMB_QUERY_FILE_STREAM_INFO 0x109
- * SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
- * SMB_FILE_INTERNAL_INFORMATION 1006
- *
- * The requested information is placed in the Data portion of the
- * transaction response. For the information levels greater than 0x100,
- * the transaction response has 1 parameter word which should be ignored by
- * the client.
- *
- * The following sections describe the InformationLevel dependent encoding
- * of the data part of the transaction response.
- *
- * 4.2.14.1 SMB_INFO_STANDARD & SMB_INFO_QUERY_EA_SIZE
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * SMB_DATE CreationDate; Date when file was created
- * SMB_TIME CreationTime; Time when file was created
- * SMB_DATE LastAccessDate; Date of last file access
- * SMB_TIME LastAccessTime; Time of last file access
- * SMB_DATE LastWriteDate; Date of last write to the file
- * SMB_TIME LastWriteTime; Time of last write to the file
- * ULONG DataSize; File Size
- * ULONG AllocationSize; Size of filesystem allocation unit
- * USHORT Attributes; File Attributes
- * ULONG EaSize; Size of file's EA information
- * (SMB_INFO_QUERY_EA_SIZE)
- *
- * 4.2.14.2 SMB_INFO_QUERY_EAS_FROM_LIST & SMB_INFO_QUERY_ALL_EAS
- *
- * Response Field Value
- * ==================== ===============================================
- *
- * MaxDataCount Length of EAlist found (minimum value is 4)
- *
- * Parameter Block Description
- * Encoding ===============================================
- * ====================
- *
- * USHORT EaErrorOffset Offset into EAList of EA error
- *
- * Data Block Encoding Description
- * ==================== ===============================================
- *
- * ULONG ListLength; Length of the remaining data
- * UCHAR EaList[] The extended attributes list
- *
- * 4.2.14.3 SMB_INFO_IS_NAME_VALID
- *
- * This requests checks to see if the name of the file contained in the
- * request's Data field has a valid path syntax. No parameters or data are
- * returned on this information request. An error is returned if the syntax
- * of the name is incorrect. Success indicates the server accepts the path
- * syntax, but it does not ensure the file or directory actually exists.
- *
- * 4.2.14.4 SMB_QUERY_FILE_BASIC_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * LARGE_INTEGER CreationTime; Time when file was created
- * LARGE_INTEGER LastAccessTime; Time of last file access
- * LARGE_INTEGER LastWriteTime; Time of last write to the file
- * LARGE_INTEGER ChangeTime Time when file was last changed
- * USHORT Attributes; File Attributes
- *
- * 4.2.14.5 SMB_QUERY_FILE_STANDARD_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * LARGE_INTEGER AllocationSize Allocated size of the file in number
- * of bytes
- * LARGE_INTEGER EndofFile; Offset to the first free byte in the
- * file
- * ULONG NumberOfLinks Number of hard links to the file
- * BOOLEAN DeletePending Indicates whether the file is marked
- * for deletion
- * BOOLEAN Directory Indicates whether the file is a
- * directory
- *
- * 4.2.14.6 SMB_QUERY_FILE_EA_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * ULONG EASize Size of the file's extended
- * attributes in number of bytes
- *
- * 4.2.14.7 SMB_QUERY_FILE_NAME_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * ULONG FileNameLength Length of the file name in number of
- * bytes
- * STRING FileName Name of the file
- *
- * 4.2.14.8 SMB_QUERY_FILE_ALL_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * LARGE_INTEGER CreationTime; Time when file was created
- * LARGE_INTEGER LastAccessTime; Time of last file access
- * LARGE_INTEGER LastWriteTime; Time of last write to the file
- * LARGE_INTEGER ChangeTime Time when file was last changed
- * USHORT Attributes; File Attributes
- * LARGE_INTEGER AllocationSize Allocated size of the file in number
- * of bytes
- * LARGE_INTEGER EndofFile; Offset to the first free byte in the
- * file
- * ULONG NumberOfLinks Number of hard links to the file
- * BOOLEAN DeletePending Indicates whether the file is marked
- * for deletion
- * BOOLEAN Directory Indicates whether the file is a
- * directory
- * LARGE_INTEGER Index Number A file system unique identifier
- * ULONG EASize Size of the file's extended
- * attributes in number of bytes
- * ULONG AccessFlags Access that a caller has to the
- * file; Possible values and meanings
- * are specified below
- * LARGE_INTEGER Index Number A file system unique identifier
- * LARGE_INTEGER CurrentByteOffset Current byte offset within the file
- * ULONG Mode Current Open mode of the file handle
- * to the file; possible values and
- * meanings are detailed below
- * ULONG AlignmentRequirement Buffer Alignment required by device;
- * possible values detailed below
- * ULONG FileNameLength Length of the file name in number of
- * bytes
- * STRING FileName Name of the file
- *
- * The AccessFlags specifies the access permissions a caller has to the
- * file and can have any suitable combination of the following values:
- *
- * Value Meaning
- *
- * ILE_READ_DATA 0x00000001 Data can be read from the file
- * ILE_WRITE_DATA 0x00000002 Data can be written to the file
- * ILE_APPEND_DATA 0x00000004 Data can be appended to the file
- * ILE_READ_EA 0x00000008 Extended attributes associated
- * with the file can be read
- * ILE_WRITE_EA 0x00000010 Extended attributes associated
- * with the file can be written
- * ILE_EXECUTE 0x00000020 Data can be read into memory from
- * the file using system paging I/O
- * ILE_READ_ATTRIBUTES 0x00000080 Attributes associated with the
- * file can be read
- * ILE_WRITE_ATTRIBUTES 0x00000100 Attributes associated with the
- * file can be written
- * ELETE 0x00010000 The file can be deleted
- * EAD_CONTROL 0x00020000 The access control list and
- * ownership associated with the
- * file can be read
- * RITE_DAC 0x00040000 The access control list and
- * ownership associated with the
- * file can be written.
- * RITE_OWNER 0x00080000 Ownership information associated
- * with the file can be written
- * YNCHRONIZE 0x00100000 The file handle can waited on to
- * synchronize with the completion
- * of an input/output request
- *
- * The Mode field specifies the mode in which the file is currently opened.
- * The possible values may be a suitable and logical combination of the
- * following:
- *
- * Value Meaning
- *
- * FILE_WRITE_THROUGH 0x00000002 File is opened in mode
- * where data is written to
- * file before the driver
- * completes a write request
- * FILE_SEQUENTIAL_ONLY 0x00000004 All access to the file is
- * sequential
- * FILE_SYNCHRONOUS_IO_ALERT 0x00000010 All operations on the
- * file are performed
- * synchronously
- * FILE_SYNCHRONOUS_IO_NONALER 0x00000020 All operations on the
- * T file are to be performed
- * synchronously. Waits in
- * the system to synchronize
- * I/O queuing and
- * completion are not
- * subject to alerts.
- *
- * The AlignmentRequirement field specifies buffer alignment required by
- * the device and can have any one of the following values:
- *
- * Value Meaning
- *
- * FILE_BYTE_ALIGNMENT 0x00000000 The buffer needs to be aligned
- * on a byte boundary
- * FILE_WORD_ALIGNMENT 0x00000001 The buffer needs to be aligned
- * on a word boundary
- * FILE_LONG_ALIGNMENT 0x00000003 The buffer needs to be aligned
- * on a 4 byte boundary
- * FILE_QUAD_ALIGNMENT 0x00000007 The buffer needs to be aligned
- * on an 8 byte boundary
- * FILE_OCTA_ALIGNMENT 0x0000000f The buffer needs to be aligned
- * on a 16 byte boundary
- * FILE_32_BYTE_ALIGNMENT 0x0000001f The buffer needs to be aligned
- * on a 32 byte boundary
- * FILE_64_BYTE_ALIGNMENT 0x0000003f The buffer needs to be aligned
- * on a 64 byte boundary
- * FILE_128_BYTE_ALIGNMENT 0x0000007f The buffer needs to be aligned
- * on a 128 byte boundary
- * FILE_256_BYTE_ALIGNMENT 0x000000ff The buffer needs to be aligned
- * on a 256 byte boundary
- * FILE_512_BYTE_ALIGNMENT 0x000001ff The buffer needs to be aligned
- * on a 512 byte boundary
- *
- * 4.2.14.9 SMB_QUERY_FILE_ALT_NAME_INFO
- *
- * Data Block Encoding Description
- * ===================== =================================
- * ULONG FileNameLength Length of the file name in number of bytes
- * STRING FileName Name of the file
- *
- * 4.2.14.10 SMB_QUERY_FILE_STREAM_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- * ULONG NextEntryOffset Offset to the next entry (in bytes)
- * ULONG StreamNameLength Length of the stream name in # of bytes
- * LARGE_INTEGER StreamSize Size of the stream in number of bytes
- * LARGE_INTEGER AllocationSize Allocated size of stream in bytes
- * STRING FileName Name of the stream
- *
- * 4.2.14.11 SMB_QUERY_FILE_COMPRESSION_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- * LARGE_INTEGER Size of the compressed file in
- * CompressedFileSize number of bytes
- * USHORT CompressionFormat compression algorithm used
- * UCHAR CompressionUnitShift Size of the stream in number of bytes
- * UCHAR ChunkShift Allocated size of the stream in # of bytes
- * UCHAR ClusterShift Allocated size of the stream in # of bytes
- * UCHAR Reserved[3] Name of the stream
- *
- * typedef struct {
- * LARGE_INTEGER CompressedFileSize;
- * USHORT CompressionFormat;
- * UCHAR CompressionUnitShift;
- * UCHAR ChunkShift;
- * UCHAR ClusterShift;
- * UCHAR Reserved[3];
- * } FILE_COMPRESSION_INFORMATION;
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/msgbuf.h>
-#include <smbsrv/smb_vops.h>
-#include <smbsrv/smb_fsops.h>
-
-int smb_query_all_info_filename(smb_tree_t *, smb_node_t *, char *, size_t);
-extern void smb_encode_smb_datetimes(smb_request_t *, smb_xa_t *, smb_attr_t *);
-extern void smb_encode_nt_times(smb_request_t *, smb_xa_t *, smb_attr_t *);
-
-/*
- * Function: int smb_com_trans2_query_path_information(struct smb_request *)
- */
-smb_sdrc_t
-smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
-{
- char *path, *alt_nm_ptr;
- int rc;
- u_offset_t datasz, allocsz;
- unsigned short infolev, dattr;
- smb_attr_t *ap, ret_attr;
- struct smb_node *dir_node;
- struct smb_node *node;
- char *name, *namep;
- char short_name[SMB_SHORTNAMELEN];
- char name83[SMB_SHORTNAMELEN];
- unsigned char is_dir;
- unsigned char delete_on_close;
- int len;
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, ERRDOS,
- ERROR_INVALID_FUNCTION);
- return (SDRC_ERROR);
- }
-
-
- if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u", sr,
- &infolev, &path) != 0) {
- return (SDRC_ERROR);
- }
-
- /*
- * Some MS clients pass NULL file names
- * NT interprets this as "\"
- */
- if ((len = strlen(path)) == 0)
- path = "\\";
- else {
- if ((len > 1) && (path[len - 1] == '\\')) {
- /*
- * Remove the terminating slash to prevent
- * sending back '.' instead of path name.
- */
- path[len - 1] = 0;
- }
- }
-
- ap = &ret_attr;
- name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
-
- if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
- sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
- != 0) {
- kmem_free(name, MAXPATHLEN);
- if (rc == ENOENT)
- smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
- ERRDOS, ERROR_FILE_NOT_FOUND);
- else
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- if ((rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
- sr->tid_tree->t_snode, dir_node, name, &node)) != 0) {
- smb_node_release(dir_node);
- kmem_free(name, MAXPATHLEN);
-
- if (rc == ENOENT)
- smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
- ERRDOS, ERROR_FILE_NOT_FOUND);
- else
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- smb_node_release(dir_node);
-
- if (smb_node_getattr(sr, node, ap) != 0) {
- smb_node_release(node);
- kmem_free(name, MAXPATHLEN);
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- (void) strcpy(name, node->od_name);
- namep = node->od_name;
- dattr = ap->sa_dosattr;
-
- if (smb_node_is_dir(node)) {
- is_dir = 1;
- /* Win2K and NT reply with the size of directory file */
- datasz = allocsz = 0;
- } else {
- is_dir = 0;
- datasz = ap->sa_vattr.va_size;
- allocsz = ap->sa_vattr.va_nblocks * DEV_BSIZE;
- }
-
- delete_on_close =
- (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
-
- /*
- * The number of links reported should be the number of
- * non-deleted links. Thus if delete_on_close is set,
- * decrement the link count.
- */
- if (delete_on_close && ap->sa_vattr.va_nlink > 0)
- --(ap->sa_vattr.va_nlink);
-
-
-
- switch (infolev) {
- case SMB_INFO_STANDARD:
- if (datasz > UINT_MAX)
- datasz = UINT_MAX;
- if (allocsz > UINT_MAX)
- allocsz = UINT_MAX;
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_smb_datetimes(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "llw",
- (uint32_t)datasz, (uint32_t)allocsz, dattr);
- break;
-
- case SMB_INFO_QUERY_EA_SIZE:
- if (datasz > UINT_MAX)
- datasz = UINT_MAX;
- if (allocsz > UINT_MAX)
- allocsz = UINT_MAX;
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_smb_datetimes(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "llwl",
- (uint32_t)datasz, (uint32_t)allocsz, dattr, 0);
- break;
-
- case SMB_INFO_QUERY_EAS_FROM_LIST:
- case SMB_INFO_QUERY_ALL_EAS:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
- break;
-
- case SMB_INFO_IS_NAME_VALID:
- break;
-
- case SMB_QUERY_FILE_BASIC_INFO:
- case SMB_FILE_BASIC_INFORMATION:
- /*
- * NT includes 6 undocumented bytes at the end of this
- * response, which are required by NetBench 5.01.
- * Similar change in smb_trans2_query_file_information.c.
- */
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_nt_times(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.", dattr);
- break;
-
- case SMB_QUERY_FILE_STANDARD_INFO:
- case SMB_FILE_STANDARD_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- /*
- * Add 2 bytes to pad data to long. It is
- * necessary because Win2k expects the padded bytes.
- */
- (void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
- (uint64_t)allocsz,
- (uint64_t)datasz,
- ap->sa_vattr.va_nlink,
- delete_on_close,
- (char)(ap->sa_vattr.va_type == VDIR));
- break;
-
- case SMB_QUERY_FILE_EA_INFO:
- case SMB_FILE_EA_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
- break;
-
- case SMB_QUERY_FILE_NAME_INFO:
- case SMB_FILE_NAME_INFORMATION:
- /* If the leading \ is missing, add it. */
- if (*namep != '\\') {
- (void) snprintf(name, MAXNAMELEN, "\\%s", namep);
- namep = name;
- }
- len = smb_ascii_or_unicode_strlen(sr, namep);
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr, len, namep);
- break;
-
- case SMB_QUERY_FILE_ALL_INFO:
- case SMB_FILE_ALL_INFORMATION:
- rc = smb_query_all_info_filename(sr->tid_tree, node,
- name, MAXPATHLEN);
- if (rc != 0) {
- smbsr_errno(sr, rc);
- smb_node_release(node);
- kmem_free(name, MAXPATHLEN);
- return (SDRC_ERROR);
- }
-
- /*
- * There is a 6-byte pad between Attributes and AllocationSize,
- * and a 2-byte pad after the Directory field.
- */
- rc = smb_query_all_info_filename(sr->tid_tree, node,
- name, MAXPATHLEN);
- if (rc != 0) {
- smbsr_errno(sr, rc);
- smb_node_release(node);
- kmem_free(name, MAXPATHLEN);
- return (SDRC_ERROR);
- }
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_nt_times(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.qqlbb2.l",
- dattr,
- (uint64_t)allocsz,
- (uint64_t)datasz,
- ap->sa_vattr.va_nlink,
- 0,
- is_dir,
- 0);
-
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
- smb_ascii_or_unicode_strlen(sr, name), name);
- break;
-
- case SMB_QUERY_FILE_ALT_NAME_INFO:
- case SMB_FILE_ALT_NAME_INFORMATION:
- /*
- * If the shortname is generated by smb_mangle_name()
- * it will be returned as the alternative name.
- * Otherwise, convert the original name to upper-case
- * and return it as the alternative name.
- */
- (void) smb_mangle_name(ap->sa_vattr.va_nodeid,
- name, short_name, name83, 0);
- alt_nm_ptr = ((*short_name == 0) ?
- utf8_strupr(name) : short_name);
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
- mts_wcequiv_strlen(alt_nm_ptr), alt_nm_ptr);
- break;
-
- case SMB_QUERY_FILE_STREAM_INFO:
- case SMB_FILE_STREAM_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_stream_info(sr, xa, node, ap);
- break;
-
- case SMB_QUERY_FILE_COMPRESSION_INFO:
- case SMB_FILE_COMPRESSION_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb,
- "qwbbb3.", datasz, 0, 0, 0, 0);
- break;
-
- case SMB_FILE_INTERNAL_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "q",
- ap->sa_vattr.va_nodeid);
- break;
-
- case SMB_FILE_ATTR_TAG_INFORMATION:
- /*
- * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
- * second dword should be the reparse tag. Otherwise
- * the tag value should be set to zero.
- * We don't support reparse points, so we set the tag
- * to zero.
- */
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
- (uint32_t)dattr, 0);
- break;
-
- default:
- smb_node_release(node);
- kmem_free(name, MAXPATHLEN);
- smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
- return (SDRC_ERROR);
- }
-
- smb_node_release(node);
- kmem_free(name, MAXPATHLEN);
- return (SDRC_SUCCESS);
-}
-
-
-/*
- * smb_query_all_info_filename
- *
- * This format of filename is only used by the ALL_INFO level.
- *
- * Determine the absolute pathname of 'node' within the share.
- * For example if the node represents file "test1.txt" in directory
- * "dir1" on share "share1", the path would be: \share1\dir1\test1.txt
- *
- * If node represents a named stream, construct the pathname for the
- * associated unnamed stream then append the stream name.
- */
-int
-smb_query_all_info_filename(smb_tree_t *tree, smb_node_t *node,
- char *buf, size_t buflen)
-{
- char *sharename = tree->t_sharename;
- int rc;
- size_t len;
- vnode_t *vp;
-
- len = snprintf(buf, buflen, "\\%s", sharename);
- if (len == (buflen - 1))
- return (ENAMETOOLONG);
-
- buf += len;
- buflen -= len;
-
- if (SMB_IS_STREAM(node))
- vp = node->n_unode->vp;
- else
- vp = node->vp;
-
- rc = vnodetopath(tree->t_snode->vp, vp, buf, buflen, kcred);
- if (rc == 0) {
- (void) strsubst(buf, '/', '\\');
-
- if (SMB_IS_STREAM(node))
- (void) strlcat(buf, node->od_name, buflen);
- }
-
- return (rc);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
deleted file mode 100644
index c57c58d8aa..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * SMB: trans2_set_file_information
- *
- * This request is used to set information about a specific file or
- * subdirectory given a handle to the file or subdirectory.
- *
- * Client Request Value
- * ========================== ==========================================
- *
- * WordCount 15
- * MaxSetupCount 0
- * SetupCount 1
- * Setup[0] TRANS2_SET_FILE_INFORMATION
- *
- * Parameter Block Encoding Description
- * ========================== ==========================================
- *
- * USHORT Fid; Handle of file for request
- * USHORT InformationLevel; Level of information requested
- * USHORT Reserved; Ignored by the server
- *
- * The following InformationLevels may be set:
- *
- * Information Level Value
- * ================================ =====
- *
- * SMB_INFO_STANDARD 1
- * SMB_INFO_QUERY_EA_SIZE 2
- * SMB_SET_FILE_BASIC_INFO 0x101
- * SMB_SET_FILE_DISPOSITION_INFO 0x102
- * SMB_SET_FILE_ALLOCATION_INFO 0x103
- * SMB_SET_FILE_END_OF_FILE_INFO 0x104
- *
- * The two levels below 0x101 are as described in the
- * NT_SET_PATH_INFORMATION transaction. The requested information is
- * placed in the Data portion of the transaction response. For the
- * information levels greater than 0x100, the transaction response has 1
- * parameter word which should be ignored by the client.
- *
- * 4.2.17.1 SMB_FILE_DISPOSITION_INFO
- *
- * Response Field Value
- * ==================== ===============================================
- *
- * BOOLEAN A boolean which is TRUE if the file is marked
- * FileIsDeleted for deletion
- *
- * 4.2.17.2 SMB_FILE_ALLOCATION_INFO
- *
- * Response Field Value
- * ==================== ===============================================
- *
- * LARGE_INTEGER File Allocation size in number of bytes
- *
- * 4.2.17.3 SMB_FILE_END_OF_FILE_INFO
- *
- * Response Field Value
- * ==================== ===============================================
- *
- * LARGE_INTEGER The total number of bytes that need to be
- * traversed from the beginning of the file in
- * order to locate the end of the file
- *
- * Undocumented things:
- * Poorly documented information levels. Information must be infered
- * from other commands.
- *
- * NULL Attributes means don't set them. NT sets the high bit to
- * set attributes to 0.
- */
-
-#include <smbsrv/smb_incl.h>
-
-/*
- * smb_com_trans2_set_file_information
- */
-smb_sdrc_t
-smb_com_trans2_set_file_information(struct smb_request *sr, struct smb_xa *xa)
-{
- smb_trans2_setinfo_t *info;
- smb_error_t smberr;
- uint32_t status;
- int rc;
-
- info = kmem_zalloc(sizeof (smb_trans2_setinfo_t), KM_SLEEP);
- info->ts_xa = xa;
-
- rc = smb_mbc_decodef(&xa->req_param_mb, "ww", &sr->smb_fid,
- &info->level);
- if (rc != 0) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- return (SDRC_ERROR);
- }
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type) ||
- SMB_TREE_IS_READONLY(sr)) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- smbsr_lookup_file(sr);
- if (sr->fid_ofile == NULL) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
- return (SDRC_ERROR);
- }
-
- sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
-
- info->node = sr->fid_ofile->f_node;
-
- if (info->node == 0 ||
- !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
- cmn_err(CE_NOTE, "SmbT2SetFileInfo: access denied");
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- status = smb_trans2_set_information(sr, info, &smberr);
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
-
- if (status == NT_STATUS_DATA_ERROR)
- return (SDRC_ERROR);
-
- if (status != NT_STATUS_SUCCESS) {
- smbsr_error(sr, smberr.status, smberr.errcls, smberr.errcode);
- return (SDRC_ERROR);
- }
-
- return (SDRC_SUCCESS);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c
deleted file mode 100644
index 8c8efeb7a0..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * This file contains the common code used by
- * Trans2SetFileInfo and Trans2SetPathInfo SMBs.
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-static uint32_t smb_set_standard_info(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-static uint32_t smb_set_basic_info(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-static uint32_t smb_set_disposition_info(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-static uint32_t smb_set_alloc_info(smb_request_t *sr,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-/*LINTED E_STATIC_UNUSED*/
-static uint32_t smb_set_mac_info(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-/*LINTED E_STATIC_UNUSED*/
-static uint32_t smb_set_mac_addappl(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-/*LINTED E_STATIC_UNUSED*/
-static uint32_t smb_set_mac_rmvappl(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-/*LINTED E_STATIC_UNUSED*/
-static uint32_t smb_set_mac_addicon(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-static unsigned short smb_info_passthru(unsigned short infolevel);
-
-/*
- * smb_trans2_set_information
- *
- * This is a common function called by both Trans2SetFileInfo
- * and Trans2SetPathInfo.
- */
-uint32_t
-smb_trans2_set_information(smb_request_t *sr, smb_trans2_setinfo_t *info,
- smb_error_t *smberr)
-{
- info->level = smb_info_passthru(info->level);
-
- switch (info->level) {
- case SMB_INFO_STANDARD:
- return (smb_set_standard_info(sr, info, smberr));
-
- case SMB_INFO_SET_EAS:
- /* EAs not supported */
- return (NT_STATUS_SUCCESS);
-
- case SMB_SET_FILE_BASIC_INFO:
- return (smb_set_basic_info(sr, info, smberr));
-
- case SMB_SET_FILE_DISPOSITION_INFO:
- return (smb_set_disposition_info(sr, info, smberr));
-
- case SMB_SET_FILE_END_OF_FILE_INFO:
- case SMB_SET_FILE_ALLOCATION_INFO:
- return (smb_set_alloc_info(sr, info, smberr));
-
- default:
- break;
- }
-
- smberr->status = NT_STATUS_INVALID_INFO_CLASS;
- smberr->errcls = ERRDOS;
- smberr->errcode = ERROR_INVALID_PARAMETER;
- return (NT_STATUS_UNSUCCESSFUL);
-}
-
-/*
- * smb_info_passthru
- *
- * SMB_INFO_PASSTHROUGH
- * If the server supports information level request passing through,
- * the client may add the information level with SMB_INFO_PASSTHROUGH
- * and submit the file information in NT data format instead of SMB
- * data format. Please refer to MSDN for related NT file information
- * data structure.
- *
- * SMB_INFO_PASSTHROUGH (1000) is defined in win32/cifs.h and the file
- * information class values are defined in win32/ntifs.h. we have
- * observed:
- * 0x3EC = SMB_INFO_PASSTHROUGH + FileBasicInformation (4)
- * 0x3F5 = SMB_INFO_PASSTHROUGH + FileDispositionInformation (13)
- * 0x3FC = SMB_INFO_PASSTHROUGH + FileEndOfFileInformation (20)
- *
- * Based on network traces between two Win2K systems:
- * FileBasicInformation <=> SMB_SET_FILE_BASIC_INFO
- * FileDispositionInformation <=> SMB_SET_FILE_DISPOSITION_INFO
- * FileEndOfFileInformation <=> SMB_SET_FILE_END_OF_FILE_INFO
- */
-static unsigned short
-smb_info_passthru(unsigned short infolevel)
-{
- if (infolevel <= SMB_INFO_PASSTHROUGH)
- return (infolevel);
-
- infolevel -= SMB_INFO_PASSTHROUGH;
-
- switch (infolevel) {
- case FileBasicInformation:
- return (SMB_SET_FILE_BASIC_INFO);
-
- case FileDispositionInformation:
- return (SMB_SET_FILE_DISPOSITION_INFO);
-
- case FileEndOfFileInformation:
- return (SMB_SET_FILE_END_OF_FILE_INFO);
-
- case FileAllocationInformation:
- return (SMB_SET_FILE_ALLOCATION_INFO);
- }
-
- return (infolevel);
-}
-
-/*
- * smb_set_standard_info
- *
- * Sets standard file/path information.
- */
-static uint32_t
-smb_set_standard_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
- smb_error_t *smberr)
-{
- smb_attr_t attr;
- uint32_t Creation, LastAccess, LastWrite; /* times */
- uint32_t status = NT_STATUS_SUCCESS;
- smb_node_t *node = info->node;
- int rc;
-
- if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "yyy",
- &Creation, /* CreationDate/Time */
- &LastAccess, /* LastAccessDate/Time */
- &LastWrite) != 0) { /* LastWriteDate/Time */
- return (NT_STATUS_DATA_ERROR);
- }
-
- bzero(&attr, sizeof (smb_attr_t));
-
- /*
- * The behaviour when the time field is set to -1
- * is not documented but is generally treated like 0,
- * meaning that that server file system assigned value
- * need not be changed.
- */
- if (LastWrite != 0 && LastWrite != (uint32_t)-1) {
- attr.sa_vattr.va_mtime.tv_sec = smb_local2gmt(sr, LastWrite);
- attr.sa_mask |= SMB_AT_MTIME;
- }
-
- if (Creation != 0 && Creation != (uint32_t)-1) {
- attr.sa_crtime.tv_sec = smb_local2gmt(sr, Creation);
- attr.sa_mask |= SMB_AT_CRTIME;
- }
-
- if (LastAccess != 0 && LastAccess != (uint32_t)-1) {
- attr.sa_vattr.va_atime.tv_sec = smb_local2gmt(sr, LastAccess);
- attr.sa_mask |= SMB_AT_ATIME;
- }
-
- rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
- if (rc) {
- smbsr_map_errno(rc, smberr);
- status = NT_STATUS_UNSUCCESSFUL;
- }
-
- return (status);
-}
-
-/*
- * smb_set_basic_info
- *
- * Sets basic file/path information.
- */
-static uint32_t
-smb_set_basic_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
- smb_error_t *smberr)
-{
- smb_attr_t attr;
- uint64_t NT_Creation, NT_LastAccess, NT_LastWrite, NT_Change;
- unsigned short Attributes;
- smb_node_t *node = info->node;
- uint32_t status = NT_STATUS_SUCCESS;
- int rc;
-
- if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "qqqqw",
- &NT_Creation, /* CreationDate/Time */
- &NT_LastAccess, /* LastAccessDate/Time */
- &NT_LastWrite, /* LastWriteDate/Time */
- &NT_Change, /* LastWriteDate/Time */
- &Attributes) != 0) { /* File Attributes */
- return (NT_STATUS_DATA_ERROR);
- }
-
- bzero(&attr, sizeof (smb_attr_t));
-
- /*
- * The behaviour when the time field is set to -1
- * is not documented but is generally treated like 0,
- * meaning that that server file system assigned value
- * need not be changed.
- */
- if (NT_Change != 0 && NT_Change != (uint64_t)-1) {
- (void) nt_to_unix_time(NT_Change, &attr.sa_vattr.va_ctime);
- attr.sa_mask |= SMB_AT_CTIME;
- }
-
- if (NT_Creation != 0 && NT_Creation != (uint64_t)-1) {
- (void) nt_to_unix_time(NT_Creation, &attr.sa_crtime);
- attr.sa_mask |= SMB_AT_CRTIME;
- }
-
- if (NT_LastWrite != 0 && NT_LastWrite != (uint64_t)-1) {
- (void) nt_to_unix_time(NT_LastWrite, &attr.sa_vattr.va_mtime);
- attr.sa_mask |= SMB_AT_MTIME;
- }
-
- if (NT_LastAccess != 0 && NT_LastAccess != (uint64_t)-1) {
- (void) nt_to_unix_time(NT_LastAccess, &attr.sa_vattr.va_atime);
- attr.sa_mask |= SMB_AT_ATIME;
- }
-
- /*
- * If Attributes are 0 this means that the file's attributes
- * should be left unchanged. If the client wanted to 0 (clear)
- * all of the attributes Attributes would be FILE_ATTRIBUTE_NORMAL.
- * Note - this is different from SMBsetatr (SMBSetInformation).
- *
- * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
- * target is not a directory.
- */
- if (Attributes != 0) {
- if ((Attributes & FILE_ATTRIBUTE_DIRECTORY) &&
- (!smb_node_is_dir(node))) {
- smberr->status = NT_STATUS_INVALID_PARAMETER;
- smberr->errcls = ERRDOS;
- smberr->errcode = ERROR_INVALID_PARAMETER;
- return (NT_STATUS_UNSUCCESSFUL);
- }
-
- 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) {
- smbsr_map_errno(rc, smberr);
- status = NT_STATUS_UNSUCCESSFUL;
- }
-
- return (status);
-}
-
-
-/*
- * smb_set_alloc_info
- *
- * Sets file allocation/end_of_file info
- */
-static uint32_t
-smb_set_alloc_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
- smb_error_t *smberr)
-{
- smb_attr_t attr;
- uint64_t DataSize;
- uint32_t status = NT_STATUS_SUCCESS;
- smb_node_t *node = info->node;
- int rc;
-
- if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "q", &DataSize) != 0)
- return (NT_STATUS_DATA_ERROR);
-
- bzero(&attr, sizeof (smb_attr_t));
- attr.sa_mask = SMB_AT_SIZE;
- attr.sa_vattr.va_size = (u_offset_t)DataSize;
- rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
- if (rc) {
- smbsr_map_errno(rc, smberr);
- status = NT_STATUS_UNSUCCESSFUL;
- }
-
- return (status);
-}
-
-/*
- * smb_set_disposition_info
- *
- * Set/Clear DELETE_ON_CLOSE flag for an open file.
- * File should have been opened with DELETE access otherwise
- * the operation is not permitted.
- *
- * NOTE: The node should be marked delete-on-close upon the receipt
- * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
- * It is different than both SmbNtCreateAndX and SmbNtTransact, which
- * set delete-on-close on the ofile and defer setting the flag on the
- * node until the file is closed.
- *
- * Observation of Windows 2000 indicates the following:
- *
- * 1) If a file is not opened with delete-on-close create options and
- * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
- * using that open file handle, any subsequent open requests will fail
- * with DELETE_PENDING.
- *
- * 2) If a file is opened with delete-on-close create options and the
- * client attempts to unset delete-on-close via Trans2SetFileInfo
- * (SetDispositionInfo) prior to the file close, any subsequent open
- * requests will still fail with DELETE_PENDING after the file is closed.
- *
- * 3) If a file is opened with delete-on-close create options and that
- * file handle (not the last open handle and the only file handle
- * with delete-on-close set) is closed. Any subsequent open requests
- * will fail with DELETE_PENDING. Unsetting delete-on-close via
- * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
- * node delete-on-close flag, which will result in the file not being
- * removed even after the last file handle is closed.
- */
-static uint32_t
-smb_set_disposition_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
- smb_error_t *smberr)
-{
- unsigned char mark_delete;
- uint32_t flags = 0;
-
- if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "b", &mark_delete) != 0)
- return (NT_STATUS_DATA_ERROR);
-
- if ((sr->fid_ofile == NULL) ||
- !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) {
- smberr->status = NT_STATUS_ACCESS_DENIED;
- smberr->errcls = ERRDOS;
- smberr->errcode = ERROR_ACCESS_DENIED;
- return (NT_STATUS_UNSUCCESSFUL);
- }
-
- if (mark_delete) {
- if (SMB_TREE_SUPPORTS_CATIA(sr))
- flags |= SMB_CATIA;
-
- if (smb_node_set_delete_on_close(info->node,
- sr->user_cr, flags)) {
- smberr->status = NT_STATUS_CANNOT_DELETE;
- smberr->errcls = ERRDOS;
- smberr->errcode = ERROR_ACCESS_DENIED;
- return (NT_STATUS_UNSUCCESSFUL);
- }
- } else {
- smb_node_reset_delete_on_close(info->node);
- }
- return (NT_STATUS_SUCCESS);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c
deleted file mode 100644
index 204018072d..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-/*
- * SMB: trans2_set_path_information
- *
- * This request is used to set information about a specific file or
- * subdirectory.
- *
- * Client Request Value
- * ========================== =========================================
- *
- * WordCount 15
- * MaxSetupCount 0
- * SetupCount 1
- * Setup[0] TRANS2_SET_PATH_INFORMATION
- *
- * Parameter Block Encoding Description
- * ========================== =========================================
- *
- * USHORT InformationLevel; Level of information to set
- * ULONG Reserved; Must be zero
- * STRING FileName; File or directory name
- *
- * The following InformationLevels may be set:
- *
- * Information Level Value
- * ========================== =========================================
- *
- * SMB_INFO_STANDARD 1
- * SMB_INFO_QUERY_EA_SIZE 2
- * SMB_INFO_QUERY_ALL_EAS 4
- *
- * The response formats are:
- *
- * 4.2.16.1 SMB_INFO_STANDARD & SMB_INFO_QUERY_EA_SIZE
- *
- * Parameter Block Encoding Description
- * ================================== =================================
- *
- * USHORT Reserved 0
- *
- * Data Block Encoding Description
- * ================================== =================================
- *
- * SMB_DATE CreationDate; Date when file was created
- * SMB_TIME CreationTime; Time when file was created
- * SMB_DATE LastAccessDate; Date of last file access
- * SMB_TIME LastAccessTime; Time of last file access
- * SMB_DATE LastWriteDate; Date of last write to the file
- * SMB_TIME LastWriteTime; Time of last write to the file
- * ULONG DataSize; File Size
- * ULONG AllocationSize; Size of filesystem allocation
- * unit
- * USHORT Attributes; File Attributes
- * ULONG EaSize; Size of file's EA information
- * (SMB_INFO_QUERY_EA_SIZE)
- *
- * 4.2.16.2 SMB_INFO_QUERY_ALL_EAS
- *
- * Response Field Value
- * ==================== ===============================================
- *
- * MaxDataCount Length of FEAlist found (minimum value is 4)
- *
- * Parameter Block Description
- * Encoding ===============================================
- * ====================
- *
- * USHORT EaErrorOffset Offset into EAList of EA error
- *
- * Data Block Encoding Description
- * ==================== ===============================================
- *
- * ULONG ListLength; Length of the remaining data
- * UCHAR EaList[] The extended attributes list
- *
- * Undocumented things:
- * Poorly documented information levels. Information must be infered
- * from other commands.
- *
- * NULL Attributes means don't set them. NT sets the high bit to
- * set attributes to 0.
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-smb_sdrc_t
-smb_com_trans2_set_path_information(struct smb_request *sr, struct smb_xa *xa)
-{
- smb_trans2_setinfo_t *info;
- struct smb_node *dir_node;
- struct smb_node *ret_snode;
- smb_error_t smberr;
- uint32_t status;
- int rc = 0;
-
- info = kmem_zalloc(sizeof (smb_trans2_setinfo_t), KM_SLEEP);
- info->ts_xa = xa;
-
- if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u", sr, &info->level,
- &info->path) != 0) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- return (SDRC_ERROR);
- }
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type) ||
- SMB_TREE_IS_READONLY(sr)) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- rc = smb_pathname_reduce(sr, sr->user_cr, info->path,
- sr->tid_tree->t_snode, sr->tid_tree->t_snode,
- &dir_node, info->name);
-
- if (rc != 0) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
- sr->tid_tree->t_snode, dir_node, info->name, &ret_snode);
-
- smb_node_release(dir_node);
-
- if (rc != 0) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- if (smb_oplock_conflict(ret_snode, sr->session, NULL)) {
- /*
- * for the benefit of attribute setting later on
- */
- (void) smb_oplock_break(ret_snode, sr->session, B_FALSE);
- }
-
- info->node = ret_snode;
- status = smb_trans2_set_information(sr, info, &smberr);
- info->node = NULL;
- smb_node_release(ret_snode);
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
-
- if (status == NT_STATUS_DATA_ERROR)
- return (SDRC_ERROR);
-
- if (status != NT_STATUS_SUCCESS) {
- smbsr_error(sr, smberr.status, smberr.errcls, smberr.errcode);
- return (SDRC_ERROR);
- }
-
- return (SDRC_SUCCESS);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c
index 66c3095851..ebe14f4cae 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c
@@ -581,6 +581,11 @@ smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
break;
}
+ /* ABE support */
+ if (si->shr_flags & SMB_SHRF_ABE)
+ sr->arg.tcon.optional_support |=
+ SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
+
access = si->shr_access_value & SMB_SHRF_ACC_ALL;
if (access == SMB_SHRF_ACC_RO) {
@@ -1022,6 +1027,9 @@ smb_tree_get_flags(const smb_share_t *si, vfs_t *vfsp, smb_tree_t *tree)
if (si->shr_flags & SMB_SHRF_CATIA)
flags |= SMB_TREE_CATIA;
+ if (si->shr_flags & SMB_SHRF_ABE)
+ flags |= SMB_TREE_ABE;
+
if (vfsp->vfs_flag & VFS_RDONLY)
flags |= SMB_TREE_READONLY;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_util.c b/usr/src/uts/common/fs/smbsrv/smb_util.c
index dab839fbf9..870c68ae51 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_util.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_util.c
@@ -1613,32 +1613,64 @@ smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
}
uint64_t
-unix_to_nt_time(timestruc_t *unix_time)
+smb_time_unix_to_nt(timestruc_t *unix_time)
{
uint64_t nt_time;
+ if ((unix_time->tv_sec == 0) && (unix_time->tv_nsec == 0))
+ return (0);
+
nt_time = unix_time->tv_sec;
nt_time *= 10000000; /* seconds to 100ns */
nt_time += unix_time->tv_nsec / 100;
return (nt_time + NT_TIME_BIAS);
}
-uint32_t
-nt_to_unix_time(uint64_t nt_time, timestruc_t *unix_time)
+void
+smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time)
{
uint32_t seconds;
+ ASSERT(unix_time);
+
+ if ((nt_time == 0) || (nt_time == -1)) {
+ unix_time->tv_sec = 0;
+ unix_time->tv_nsec = 0;
+ return;
+ }
+
nt_time -= NT_TIME_BIAS;
seconds = nt_time / 10000000;
- if (unix_time) {
- unix_time->tv_sec = seconds;
- unix_time->tv_nsec = (nt_time % 10000000) * 100;
- }
- return (seconds);
+ unix_time->tv_sec = seconds;
+ unix_time->tv_nsec = (nt_time % 10000000) * 100;
+}
+
+/*
+ * smb_time_gmt_to_local, smb_time_local_to_gmt
+ *
+ * Apply the gmt offset to convert between local time and gmt
+ */
+int32_t
+smb_time_gmt_to_local(smb_request_t *sr, int32_t gmt)
+{
+ if ((gmt == 0) || (gmt == -1))
+ return (0);
+
+ return (gmt - sr->sr_gmtoff);
}
+int32_t
+smb_time_local_to_gmt(smb_request_t *sr, int32_t local)
+{
+ if ((local == 0) || (local == -1))
+ return (0);
+
+ return (local + sr->sr_gmtoff);
+}
+
+
/*
- * smb_dos_to_ux_time
+ * smb_time_dos_to_unix
*
* Convert SMB_DATE & SMB_TIME values to a unix timestamp.
*
@@ -1650,7 +1682,7 @@ nt_to_unix_time(uint64_t nt_time, timestruc_t *unix_time)
* so that the caller can identify and handle this special case.
*/
int32_t
-smb_dos_to_ux_time(int16_t date, int16_t time)
+smb_time_dos_to_unix(int16_t date, int16_t time)
{
struct tm atm;
@@ -1669,13 +1701,19 @@ smb_dos_to_ux_time(int16_t date, int16_t time)
return (smb_timegm(&atm));
}
-int32_t
-smb_ux_to_dos_time(int32_t ux_time, int16_t *date_p, int16_t *time_p)
+void
+smb_time_unix_to_dos(int32_t ux_time, int16_t *date_p, int16_t *time_p)
{
struct tm atm;
int i;
time_t tmp_time;
+ if (ux_time == 0) {
+ *date_p = 0;
+ *time_p = 0;
+ return;
+ }
+
tmp_time = (time_t)ux_time;
(void) smb_gmtime_r(&tmp_time, &atm);
@@ -1699,7 +1737,6 @@ smb_ux_to_dos_time(int32_t ux_time, int16_t *date_p, int16_t *time_p)
*time_p = (short)i;
}
- return (ux_time);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_vops.c b/usr/src/uts/common/fs/smbsrv/smb_vops.c
index 9cda0fe7cf..386e02af4b 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_vops.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_vops.c
@@ -890,13 +890,15 @@ smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr)
* If the file system supports extended directory entries (has features
* VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be
* filled with edirent_t structures, instead of dirent64_t structures.
+ * If the file system supports access based enumeration (abe), set
+ * V_RDDIR_ACCFILTER to filter directory entries based on user cred.
*/
int
smb_vop_readdir(vnode_t *vp, uint32_t offset,
- void *buf, int *count, int *eof, cred_t *cr)
+ void *buf, int *count, int *eof, uint32_t rddir_flag, cred_t *cr)
{
int error = 0;
- int rdirent_flags = 0;
+ int flags = 0;
int rdirent_size;
struct uio auio;
struct iovec aiov;
@@ -905,7 +907,7 @@ smb_vop_readdir(vnode_t *vp, uint32_t offset,
return (ENOTDIR);
if (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) {
- rdirent_flags = V_RDDIR_ENTFLAGS;
+ flags |= V_RDDIR_ENTFLAGS;
rdirent_size = sizeof (edirent_t);
} else {
rdirent_size = sizeof (dirent64_t);
@@ -914,6 +916,9 @@ smb_vop_readdir(vnode_t *vp, uint32_t offset,
if (*count < rdirent_size)
return (EINVAL);
+ if (rddir_flag & SMB_ABE)
+ flags |= V_RDDIR_ACCFILTER;
+
aiov.iov_base = buf;
aiov.iov_len = *count;
auio.uio_iov = &aiov;
@@ -924,7 +929,7 @@ smb_vop_readdir(vnode_t *vp, uint32_t offset,
auio.uio_fmode = 0;
(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
- error = VOP_READDIR(vp, &auio, cr, eof, &smb_ct, rdirent_flags);
+ error = VOP_READDIR(vp, &auio, cr, eof, &smb_ct, flags);
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
if (error == 0)
diff --git a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
index 1872c9ef46..a1d7948412 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
@@ -349,11 +349,10 @@ smb_com_write_raw(struct smb_request *sr)
/*
* smb_write_raw_helper will call smb_opipe_write or
- * smb_fsop_write as appropriate, handle the NODE_FLAGS_SET_SIZE
- * flag (if set) and update the other f_node fields. It's possible
- * that data_length may be 0 for this transfer but we still want
- * process it since it will update the file state (seek position,
- * file size (possibly), etc).
+ * smb_fsop_write as appropriate, and update the other f_node fields.
+ * It's possible that data_length may be 0 for this transfer but
+ * we still want to process it since it will update the file state
+ * (seek position, file size (possibly), etc).
*/
rc = smb_write_raw_helper(sr, &uio, stability, &off, &lcount);
@@ -475,11 +474,11 @@ notify_write_raw_complete:
/*
* smb_write_raw_helper
*
- * This function will call smb_opipe_write or smb_fsop_write as appropriate,
- * handle the NODE_FLAGS_SET_SIZE flag (if set) and update the other f_node
- * fields. It's possible that data_length may be 0 for this transfer but
- * we still want process it since it will update the file state (seek
- * position, file size (possibly), etc).
+ * This function will call smb_opipe_write or smb_fsop_write
+ * as appropriate, and update the other f_node fields.
+ * It's possible that data_length may be 0 for this transfer but
+ * we still want process it since it will update the file state
+ * (seek position, file size (possibly), etc).
*
* Returns 0 for success, non-zero for failure
*/