1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22cb174861Sjoyce mcintosh  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23adee6784SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
24da6c28aaSamw  */
25da6c28aaSamw 
26bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
27adee6784SGordon Ross #include <smb/winioctl.h>
28da6c28aaSamw 
29e3f2c991SKeyur Desai 
30e3f2c991SKeyur Desai static uint32_t smb_nt_trans_ioctl_noop(smb_request_t *, smb_xa_t *);
31fd9ee8b5Sjoyce mcintosh static uint32_t smb_nt_trans_ioctl_invalid_parm(smb_request_t *, smb_xa_t *);
32fd9ee8b5Sjoyce mcintosh static uint32_t smb_nt_trans_ioctl_set_sparse(smb_request_t *, smb_xa_t *);
33fd9ee8b5Sjoyce mcintosh static uint32_t smb_nt_trans_ioctl_query_alloc_ranges(smb_request_t *,
3489dc44ceSjose borrego     smb_xa_t *);
35fd9ee8b5Sjoyce mcintosh static uint32_t smb_nt_trans_ioctl_set_zero_data(smb_request_t *, smb_xa_t *);
36a90cf9f2SGordon Ross static uint32_t smb_nt_trans_ioctl_enum_snaps(smb_request_t *, smb_xa_t *);
37da6c28aaSamw 
38da6c28aaSamw /*
39e3f2c991SKeyur Desai  * This table defines the list of FSCTL values for which we'll
40e3f2c991SKeyur Desai  * call a funtion to perform specific processing.
41da6c28aaSamw  */
428622ec45SGordon Ross static const struct {
43da6c28aaSamw 	uint32_t fcode;
4489dc44ceSjose borrego 	uint32_t (*ioctl_func)(smb_request_t *sr, smb_xa_t *xa);
45da6c28aaSamw } ioctl_ret_tbl[] = {
46e3f2c991SKeyur Desai 	{ FSCTL_GET_OBJECT_ID, smb_nt_trans_ioctl_invalid_parm },
47fd9ee8b5Sjoyce mcintosh 	{ FSCTL_QUERY_ALLOCATED_RANGES, smb_nt_trans_ioctl_query_alloc_ranges },
48fd9ee8b5Sjoyce mcintosh 	{ FSCTL_SET_ZERO_DATA, smb_nt_trans_ioctl_set_zero_data },
49a90cf9f2SGordon Ross 	{ FSCTL_SRV_ENUMERATE_SNAPSHOTS, smb_nt_trans_ioctl_enum_snaps },
50fd9ee8b5Sjoyce mcintosh 	{ FSCTL_SET_SPARSE, smb_nt_trans_ioctl_set_sparse },
519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	{ FSCTL_FIND_FILES_BY_SID, smb_nt_trans_ioctl_noop }
52da6c28aaSamw };
53da6c28aaSamw 
54da6c28aaSamw /*
55da6c28aaSamw  * smb_nt_transact_ioctl
56da6c28aaSamw  *
57da6c28aaSamw  * This command allows device and file system control functions to be
58e3f2c991SKeyur Desai  * transferred transparently from client to server.
59da6c28aaSamw  *
60da6c28aaSamw  * Setup Words Encoding        Description
61da6c28aaSamw  * =========================== =========================================
62da6c28aaSamw  * ULONG FunctionCode;         NT device or file system control code
63da6c28aaSamw  * USHORT Fid;                 Handle for io or fs control. Unless BIT0
64da6c28aaSamw  *                             of ISFLAGS is set.
65da6c28aaSamw  * BOOLEAN IsFsctl;            Indicates whether the command is a device
66da6c28aaSamw  *                             control (FALSE) or a file system control
67da6c28aaSamw  *                             (TRUE).
68da6c28aaSamw  * UCHAR   IsFlags;            BIT0 - command is to be applied to share
69da6c28aaSamw  *                             root handle. Share must be a DFS share.
70da6c28aaSamw  *
71da6c28aaSamw  * Data Block Encoding         Description
72da6c28aaSamw  * =========================== =========================================
73da6c28aaSamw  * Data[ TotalDataCount ]      Passed to the Fsctl or Ioctl
74da6c28aaSamw  *
75da6c28aaSamw  * Server Response             Description
76da6c28aaSamw  * =========================== ==================================
77da6c28aaSamw  * SetupCount                  1
78da6c28aaSamw  * Setup[0]                    Length of information returned by
79da6c28aaSamw  *                             io or fs control.
80da6c28aaSamw  * DataCount                   Length of information returned by
81da6c28aaSamw  *                             io or fs control.
82da6c28aaSamw  * Data[ DataCount ]           The results of the io or fs control.
83da6c28aaSamw  */
847b59d02dSjb smb_sdrc_t
smb_nt_transact_ioctl(smb_request_t * sr,smb_xa_t * xa)8589dc44ceSjose borrego smb_nt_transact_ioctl(smb_request_t *sr, smb_xa_t *xa)
86da6c28aaSamw {
87e3f2c991SKeyur Desai 	uint32_t status = NT_STATUS_NOT_SUPPORTED;
88da6c28aaSamw 	uint32_t fcode;
89da6c28aaSamw 	unsigned char is_fsctl;
90da6c28aaSamw 	unsigned char is_flags;
91da6c28aaSamw 	int i;
92da6c28aaSamw 
933db3f65cSamw 	if (smb_mbc_decodef(&xa->req_setup_mb, "lwbb",
94fd9ee8b5Sjoyce mcintosh 	    &fcode, &sr->smb_fid, &is_fsctl, &is_flags) != 0) {
95dc20a302Sas 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
96faa1795aSjb 		return (SDRC_ERROR);
97da6c28aaSamw 	}
98da6c28aaSamw 
99e3f2c991SKeyur Desai 	/*
100e3f2c991SKeyur Desai 	 * Invoke handler if specified, otherwise the default
101e3f2c991SKeyur Desai 	 * behavior is to return NT_STATUS_NOT_SUPPORTED
102e3f2c991SKeyur Desai 	 */
1037b59d02dSjb 	for (i = 0; i < sizeof (ioctl_ret_tbl) / sizeof (ioctl_ret_tbl[0]);
104da6c28aaSamw 	    i++) {
105da6c28aaSamw 		if (ioctl_ret_tbl[i].fcode == fcode) {
10689dc44ceSjose borrego 			status = ioctl_ret_tbl[i].ioctl_func(sr, xa);
107da6c28aaSamw 			break;
108da6c28aaSamw 		}
109da6c28aaSamw 	}
110da6c28aaSamw 
1117b59d02dSjb 	if (status != NT_STATUS_SUCCESS) {
112dc20a302Sas 		smbsr_error(sr, status, 0, 0);
113faa1795aSjb 		return (SDRC_ERROR);
1147b59d02dSjb 	}
115da6c28aaSamw 
1163db3f65cSamw 	(void) smb_mbc_encodef(&xa->rep_param_mb, "l", 0);
117faa1795aSjb 	return (SDRC_SUCCESS);
118da6c28aaSamw }
11989dc44ceSjose borrego 
120e3f2c991SKeyur Desai /* ARGSUSED */
121e3f2c991SKeyur Desai static uint32_t
smb_nt_trans_ioctl_noop(smb_request_t * sr,smb_xa_t * xa)122e3f2c991SKeyur Desai smb_nt_trans_ioctl_noop(smb_request_t *sr, smb_xa_t *xa)
123e3f2c991SKeyur Desai {
124e3f2c991SKeyur Desai 	return (NT_STATUS_SUCCESS);
125e3f2c991SKeyur Desai }
126e3f2c991SKeyur Desai 
12789dc44ceSjose borrego /* ARGSUSED */
12889dc44ceSjose borrego static uint32_t
smb_nt_trans_ioctl_invalid_parm(smb_request_t * sr,smb_xa_t * xa)12989dc44ceSjose borrego smb_nt_trans_ioctl_invalid_parm(smb_request_t *sr, smb_xa_t *xa)
13089dc44ceSjose borrego {
13189dc44ceSjose borrego 	return (NT_STATUS_INVALID_PARAMETER);
13289dc44ceSjose borrego }
133fd9ee8b5Sjoyce mcintosh 
134fd9ee8b5Sjoyce mcintosh /*
135fd9ee8b5Sjoyce mcintosh  * smb_nt_trans_ioctl_set_sparse
136fd9ee8b5Sjoyce mcintosh  *
137fd9ee8b5Sjoyce mcintosh  * There may, or may not be a data block in this request.
138fd9ee8b5Sjoyce mcintosh  * If there IS a data block, the first byte is a boolean
139fd9ee8b5Sjoyce mcintosh  * specifying whether to set (non zero) or clear (zero)
140fd9ee8b5Sjoyce mcintosh  * the sparse attribute of the file.
141fd9ee8b5Sjoyce mcintosh  * If there is no data block, this indicates a request to
142fd9ee8b5Sjoyce mcintosh  * set the sparse attribute.
143fd9ee8b5Sjoyce mcintosh  */
144fd9ee8b5Sjoyce mcintosh static uint32_t
smb_nt_trans_ioctl_set_sparse(smb_request_t * sr,smb_xa_t * xa)145fd9ee8b5Sjoyce mcintosh smb_nt_trans_ioctl_set_sparse(smb_request_t *sr, smb_xa_t *xa)
146fd9ee8b5Sjoyce mcintosh {
147fd9ee8b5Sjoyce mcintosh 	int		rc = 0;
148fd9ee8b5Sjoyce mcintosh 	uint8_t		set = 1;
1495fd03bc0SGordon Ross 	smb_ofile_t	*of;
150fd9ee8b5Sjoyce mcintosh 	smb_attr_t	attr;
151fd9ee8b5Sjoyce mcintosh 
152fd9ee8b5Sjoyce mcintosh 	if (SMB_TREE_IS_READONLY(sr))
153fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_ACCESS_DENIED);
154fd9ee8b5Sjoyce mcintosh 
155fd9ee8b5Sjoyce mcintosh 	if (STYPE_ISIPC(sr->tid_tree->t_res_type))
156fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_PARAMETER);
157fd9ee8b5Sjoyce mcintosh 
158fd9ee8b5Sjoyce mcintosh 	smbsr_lookup_file(sr);
159fd9ee8b5Sjoyce mcintosh 	if (sr->fid_ofile == NULL)
160fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_HANDLE);
161fd9ee8b5Sjoyce mcintosh 
162fd9ee8b5Sjoyce mcintosh 	if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
163fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
164fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_PARAMETER);
165fd9ee8b5Sjoyce mcintosh 	}
166fd9ee8b5Sjoyce mcintosh 
1675fd03bc0SGordon Ross 	of = sr->fid_ofile;
1685fd03bc0SGordon Ross 	if (smb_node_is_dir(of->f_node)) {
169fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
170fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_PARAMETER);
171fd9ee8b5Sjoyce mcintosh 	}
172fd9ee8b5Sjoyce mcintosh 
173fd9ee8b5Sjoyce mcintosh 	if (smbsr_decode_data_avail(sr)) {
174fd9ee8b5Sjoyce mcintosh 		if (smb_mbc_decodef(&xa->req_data_mb, "b", &set) != 0) {
175fd9ee8b5Sjoyce mcintosh 			smbsr_release_file(sr);
176fd9ee8b5Sjoyce mcintosh 			return (sr->smb_error.status);
177fd9ee8b5Sjoyce mcintosh 		}
178fd9ee8b5Sjoyce mcintosh 	}
179fd9ee8b5Sjoyce mcintosh 
1805fd03bc0SGordon Ross 	/*
1815fd03bc0SGordon Ross 	 * Using kcred because we just want the DOS attrs
1825fd03bc0SGordon Ross 	 * and don't want access errors for this.
1835fd03bc0SGordon Ross 	 */
184fd9ee8b5Sjoyce mcintosh 	bzero(&attr, sizeof (smb_attr_t));
185fd9ee8b5Sjoyce mcintosh 	attr.sa_mask = SMB_AT_DOSATTR;
1868622ec45SGordon Ross 	rc = smb_node_getattr(sr, of->f_node, zone_kcred(), of, &attr);
1875fd03bc0SGordon Ross 	if (rc != 0) {
188fd9ee8b5Sjoyce mcintosh 		smbsr_errno(sr, rc);
189fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
190fd9ee8b5Sjoyce mcintosh 		return (sr->smb_error.status);
191fd9ee8b5Sjoyce mcintosh 	}
192fd9ee8b5Sjoyce mcintosh 
193fd9ee8b5Sjoyce mcintosh 	attr.sa_mask = 0;
194fd9ee8b5Sjoyce mcintosh 	if ((set == 0) &&
195fd9ee8b5Sjoyce mcintosh 	    (attr.sa_dosattr & FILE_ATTRIBUTE_SPARSE_FILE)) {
196fd9ee8b5Sjoyce mcintosh 		attr.sa_dosattr &= ~FILE_ATTRIBUTE_SPARSE_FILE;
197fd9ee8b5Sjoyce mcintosh 		attr.sa_mask = SMB_AT_DOSATTR;
198fd9ee8b5Sjoyce mcintosh 	} else if ((set != 0) &&
199fd9ee8b5Sjoyce mcintosh 	    !(attr.sa_dosattr & FILE_ATTRIBUTE_SPARSE_FILE)) {
200fd9ee8b5Sjoyce mcintosh 		attr.sa_dosattr |= FILE_ATTRIBUTE_SPARSE_FILE;
201fd9ee8b5Sjoyce mcintosh 		attr.sa_mask = SMB_AT_DOSATTR;
202fd9ee8b5Sjoyce mcintosh 	}
203fd9ee8b5Sjoyce mcintosh 
204fd9ee8b5Sjoyce mcintosh 	if (attr.sa_mask != 0) {
2055fd03bc0SGordon Ross 		rc = smb_node_setattr(sr, of->f_node, of->f_cr, of, &attr);
206fd9ee8b5Sjoyce mcintosh 		if (rc != 0) {
207fd9ee8b5Sjoyce mcintosh 			smbsr_errno(sr, rc);
208fd9ee8b5Sjoyce mcintosh 			smbsr_release_file(sr);
209fd9ee8b5Sjoyce mcintosh 			return (sr->smb_error.status);
210fd9ee8b5Sjoyce mcintosh 		}
211fd9ee8b5Sjoyce mcintosh 	}
212fd9ee8b5Sjoyce mcintosh 
213fd9ee8b5Sjoyce mcintosh 	smbsr_release_file(sr);
214fd9ee8b5Sjoyce mcintosh 	return (NT_STATUS_SUCCESS);
215fd9ee8b5Sjoyce mcintosh }
216fd9ee8b5Sjoyce mcintosh 
217fd9ee8b5Sjoyce mcintosh /*
218fd9ee8b5Sjoyce mcintosh  * smb_nt_trans_ioctl_set_zero_data
219fd9ee8b5Sjoyce mcintosh  *
220fd9ee8b5Sjoyce mcintosh  * Check that the request is valid on the specified file.
221*94047d49SGordon Ross  * The implementation is a noop. XXX - bug!
222*94047d49SGordon Ross  * XXX: We have this in the fsclt module now.  Call that.
223*94047d49SGordon Ross  *
224*94047d49SGordon Ross  * Note: When support is added for FSCTL_SET_ZERO_DATA, it must
225*94047d49SGordon Ross  * break any oplocks on the file to none:
226*94047d49SGordon Ross  *	(void) smb_oplock_break_WRITE(node, ofile);
227fd9ee8b5Sjoyce mcintosh  */
228fd9ee8b5Sjoyce mcintosh /* ARGSUSED */
229fd9ee8b5Sjoyce mcintosh static uint32_t
smb_nt_trans_ioctl_set_zero_data(smb_request_t * sr,smb_xa_t * xa)230fd9ee8b5Sjoyce mcintosh smb_nt_trans_ioctl_set_zero_data(smb_request_t *sr, smb_xa_t *xa)
231fd9ee8b5Sjoyce mcintosh {
232fd9ee8b5Sjoyce mcintosh 	smb_node_t *node;
233fd9ee8b5Sjoyce mcintosh 
234fd9ee8b5Sjoyce mcintosh 	if (SMB_TREE_IS_READONLY(sr))
235fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_ACCESS_DENIED);
236fd9ee8b5Sjoyce mcintosh 
237fd9ee8b5Sjoyce mcintosh 	if (STYPE_ISIPC(sr->tid_tree->t_res_type))
238fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_PARAMETER);
239fd9ee8b5Sjoyce mcintosh 
240fd9ee8b5Sjoyce mcintosh 	smbsr_lookup_file(sr);
241fd9ee8b5Sjoyce mcintosh 	if (sr->fid_ofile == NULL)
242fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_HANDLE);
243fd9ee8b5Sjoyce mcintosh 
244fd9ee8b5Sjoyce mcintosh 	if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
245fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
246fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_PARAMETER);
247fd9ee8b5Sjoyce mcintosh 	}
248fd9ee8b5Sjoyce mcintosh 
249fd9ee8b5Sjoyce mcintosh 	node = sr->fid_ofile->f_node;
250fd9ee8b5Sjoyce mcintosh 	if (smb_node_is_dir(node)) {
251fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
252fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_PARAMETER);
253fd9ee8b5Sjoyce mcintosh 	}
254fd9ee8b5Sjoyce mcintosh 
255fd9ee8b5Sjoyce mcintosh 	smbsr_release_file(sr);
256fd9ee8b5Sjoyce mcintosh 	return (NT_STATUS_SUCCESS);
257fd9ee8b5Sjoyce mcintosh }
258fd9ee8b5Sjoyce mcintosh 
259fd9ee8b5Sjoyce mcintosh /*
260fd9ee8b5Sjoyce mcintosh  * smb_nt_trans_ioctl_query_alloc_ranges
261fd9ee8b5Sjoyce mcintosh  *
262fd9ee8b5Sjoyce mcintosh  * Responds with either:
263fd9ee8b5Sjoyce mcintosh  * - no data if the file is zero size
264fd9ee8b5Sjoyce mcintosh  * - a single range containing the starting point and length requested
265fd9ee8b5Sjoyce mcintosh  */
266fd9ee8b5Sjoyce mcintosh static uint32_t
smb_nt_trans_ioctl_query_alloc_ranges(smb_request_t * sr,smb_xa_t * xa)267fd9ee8b5Sjoyce mcintosh smb_nt_trans_ioctl_query_alloc_ranges(smb_request_t *sr, smb_xa_t *xa)
268fd9ee8b5Sjoyce mcintosh {
269fd9ee8b5Sjoyce mcintosh 	int		rc;
270fd9ee8b5Sjoyce mcintosh 	uint64_t	offset, len;
2715fd03bc0SGordon Ross 	smb_ofile_t	*of;
272fd9ee8b5Sjoyce mcintosh 	smb_attr_t	attr;
273fd9ee8b5Sjoyce mcintosh 
274fd9ee8b5Sjoyce mcintosh 	if (STYPE_ISIPC(sr->tid_tree->t_res_type))
275fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_PARAMETER);
276fd9ee8b5Sjoyce mcintosh 
277fd9ee8b5Sjoyce mcintosh 	smbsr_lookup_file(sr);
278fd9ee8b5Sjoyce mcintosh 	if (sr->fid_ofile == NULL)
279fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_HANDLE);
280fd9ee8b5Sjoyce mcintosh 
281fd9ee8b5Sjoyce mcintosh 	if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
282fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
283fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_PARAMETER);
284fd9ee8b5Sjoyce mcintosh 	}
285fd9ee8b5Sjoyce mcintosh 
2865fd03bc0SGordon Ross 	of = sr->fid_ofile;
2875fd03bc0SGordon Ross 	if (smb_node_is_dir(of->f_node)) {
288fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
289fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_INVALID_PARAMETER);
290fd9ee8b5Sjoyce mcintosh 	}
291fd9ee8b5Sjoyce mcintosh 
292fd9ee8b5Sjoyce mcintosh 	/* If zero size file don't return any data */
293fd9ee8b5Sjoyce mcintosh 	bzero(&attr, sizeof (smb_attr_t));
294fd9ee8b5Sjoyce mcintosh 	attr.sa_mask = SMB_AT_SIZE;
2955fd03bc0SGordon Ross 	rc = smb_node_getattr(sr, of->f_node, of->f_cr, of, &attr);
2965fd03bc0SGordon Ross 	if (rc != 0) {
297fd9ee8b5Sjoyce mcintosh 		smbsr_errno(sr, rc);
298fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
299fd9ee8b5Sjoyce mcintosh 		return (sr->smb_error.status);
300fd9ee8b5Sjoyce mcintosh 	}
301fd9ee8b5Sjoyce mcintosh 
302fd9ee8b5Sjoyce mcintosh 	if (attr.sa_vattr.va_size == 0) {
303fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
304fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_SUCCESS);
305fd9ee8b5Sjoyce mcintosh 	}
306fd9ee8b5Sjoyce mcintosh 
307fd9ee8b5Sjoyce mcintosh 	if (smb_mbc_decodef(&xa->req_data_mb, "qq", &offset, &len) != 0) {
308fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
309fd9ee8b5Sjoyce mcintosh 		return (sr->smb_error.status);
310fd9ee8b5Sjoyce mcintosh 	}
311fd9ee8b5Sjoyce mcintosh 
312fd9ee8b5Sjoyce mcintosh 	/*
313fd9ee8b5Sjoyce mcintosh 	 * Return a single range regardless of whether the file
314fd9ee8b5Sjoyce mcintosh 	 * is sparse or not.
315fd9ee8b5Sjoyce mcintosh 	 */
316fd9ee8b5Sjoyce mcintosh 	if (MBC_ROOM_FOR(&xa->rep_data_mb, 16) == 0) {
317fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
318fd9ee8b5Sjoyce mcintosh 		return (NT_STATUS_BUFFER_TOO_SMALL);
319fd9ee8b5Sjoyce mcintosh 	}
320fd9ee8b5Sjoyce mcintosh 
321fd9ee8b5Sjoyce mcintosh 	if (smb_mbc_encodef(&xa->rep_data_mb, "qq", offset, len) != 0) {
322fd9ee8b5Sjoyce mcintosh 		smbsr_release_file(sr);
323fd9ee8b5Sjoyce mcintosh 		return (sr->smb_error.status);
324fd9ee8b5Sjoyce mcintosh 	}
325fd9ee8b5Sjoyce mcintosh 
326fd9ee8b5Sjoyce mcintosh 	smbsr_release_file(sr);
327fd9ee8b5Sjoyce mcintosh 	return (NT_STATUS_SUCCESS);
328fd9ee8b5Sjoyce mcintosh }
329a90cf9f2SGordon Ross 
330a90cf9f2SGordon Ross static uint32_t
smb_nt_trans_ioctl_enum_snaps(smb_request_t * sr,smb_xa_t * xa)331a90cf9f2SGordon Ross smb_nt_trans_ioctl_enum_snaps(smb_request_t *sr, smb_xa_t *xa)
332a90cf9f2SGordon Ross {
333a90cf9f2SGordon Ross 	smb_fsctl_t fsctl;
334a90cf9f2SGordon Ross 	uint32_t status;
335a90cf9f2SGordon Ross 
336a90cf9f2SGordon Ross 	if (STYPE_ISIPC(sr->tid_tree->t_res_type))
337a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
338a90cf9f2SGordon Ross 
339a90cf9f2SGordon Ross 	smbsr_lookup_file(sr);
340a90cf9f2SGordon Ross 	if (sr->fid_ofile == NULL)
341a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_HANDLE);
342a90cf9f2SGordon Ross 
343a90cf9f2SGordon Ross 	if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
344a90cf9f2SGordon Ross 		smbsr_release_file(sr);
345a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
346a90cf9f2SGordon Ross 	}
347a90cf9f2SGordon Ross 
348a90cf9f2SGordon Ross 	fsctl.CtlCode = FSCTL_SRV_ENUMERATE_SNAPSHOTS;
349a90cf9f2SGordon Ross 	fsctl.InputCount = xa->smb_tpscnt;
350a90cf9f2SGordon Ross 	fsctl.OutputCount = 0;
351a90cf9f2SGordon Ross 	fsctl.MaxOutputResp = xa->smb_mdrcnt;
352a90cf9f2SGordon Ross 	fsctl.in_mbc = &xa->req_param_mb;
353a90cf9f2SGordon Ross 	fsctl.out_mbc = &xa->rep_data_mb;
354a90cf9f2SGordon Ross 
355a90cf9f2SGordon Ross 	status = smb_vss_enum_snapshots(sr, &fsctl);
356a90cf9f2SGordon Ross 
357a90cf9f2SGordon Ross 	smbsr_release_file(sr);
358a90cf9f2SGordon Ross 	return (status);
359a90cf9f2SGordon Ross }
360