xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_qinfo_file.c (revision dd72704bd9e794056c558153663c739e2012d721)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
14  * Copyright 2022 RackTop Systems, Inc.
15  */
16 
17 /*
18  * Dispatch function for SMB2_QUERY_INFO
19  *
20  * [MS-FSCC 2.4] If a file system does not support ...
21  * an Information Classs, NT_STATUS_INVALID_PARAMETER...
22  */
23 
24 #include <smbsrv/smb2_kproto.h>
25 #include <smbsrv/smb_fsops.h>
26 #include <smbsrv/ntifs.h>
27 
28 static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *);
29 static uint32_t smb2_qif_basic(smb_request_t *, smb_queryinfo_t *);
30 static uint32_t smb2_qif_standard(smb_request_t *, smb_queryinfo_t *);
31 static uint32_t smb2_qif_internal(smb_request_t *, smb_queryinfo_t *);
32 static uint32_t smb2_qif_ea_size(smb_request_t *, smb_queryinfo_t *);
33 static uint32_t smb2_qif_access(smb_request_t *, smb_queryinfo_t *);
34 static uint32_t smb2_qif_name(smb_request_t *, smb_queryinfo_t *);
35 static uint32_t smb2_qif_normalized_name(smb_request_t *, smb_queryinfo_t *);
36 static uint32_t smb2_qif_position(smb_request_t *, smb_queryinfo_t *);
37 static uint32_t smb2_qif_full_ea(smb_request_t *, smb_queryinfo_t *);
38 static uint32_t smb2_qif_mode(smb_request_t *, smb_queryinfo_t *);
39 static uint32_t smb2_qif_alignment(smb_request_t *, smb_queryinfo_t *);
40 static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *);
41 static uint32_t smb2_qif_altname(smb_request_t *, smb_queryinfo_t *);
42 static uint32_t smb2_qif_stream(smb_request_t *, smb_queryinfo_t *);
43 static uint32_t smb2_qif_pipe(smb_request_t *, smb_queryinfo_t *);
44 static uint32_t smb2_qif_pipe_lcl(smb_request_t *, smb_queryinfo_t *);
45 static uint32_t smb2_qif_pipe_rem(smb_request_t *, smb_queryinfo_t *);
46 static uint32_t smb2_qif_compr(smb_request_t *, smb_queryinfo_t *);
47 static uint32_t smb2_qif_opens(smb_request_t *, smb_queryinfo_t *);
48 static uint32_t smb2_qif_tags(smb_request_t *, smb_queryinfo_t *);
49 static uint32_t smb2_qif_id_info(smb_request_t *, smb_queryinfo_t *);
50 
51 
52 uint32_t
53 smb2_qinfo_file(smb_request_t *sr, smb_queryinfo_t *qi)
54 {
55 	smb_ofile_t *of = sr->fid_ofile;
56 	uint_t mask = 0;
57 	boolean_t getstd = B_FALSE;
58 	boolean_t getname = B_FALSE;
59 	uint32_t status;
60 
61 	/*
62 	 * Which attributes do we need from the FS?
63 	 */
64 	switch (qi->qi_InfoClass) {
65 	case FileBasicInformation:
66 		mask = SMB_AT_BASIC;
67 		break;
68 	case FileStandardInformation:
69 		mask = SMB_AT_STANDARD;
70 		getstd = B_TRUE;
71 		break;
72 	case FileInternalInformation:
73 		mask = SMB_AT_NODEID;
74 		break;
75 	case FileAllInformation:
76 		mask = SMB_AT_ALL;
77 		getstd = B_TRUE;
78 		if (sr->session->dialect < SMB_VERS_3_11) {
79 			/* See smb2_qif_all() */
80 			getname = B_TRUE;
81 		}
82 		break;
83 
84 	case FileNameInformation:
85 	case FileNormalizedNameInformation:
86 		getname = B_TRUE;
87 		break;
88 
89 	case FileAlternateNameInformation:
90 		mask = SMB_AT_NODEID;
91 		getname = B_TRUE;
92 		break;
93 
94 	case FileStreamInformation:
95 		mask = SMB_AT_STANDARD;
96 		getstd = B_TRUE;
97 		break;
98 
99 	case FileCompressionInformation:
100 		mask = SMB_AT_SIZE | SMB_AT_ALLOCSZ;
101 		break;
102 
103 	case FileNetworkOpenInformation:
104 		mask = SMB_AT_BASIC | SMB_AT_STANDARD;
105 		break;
106 
107 	case FileIdInformation:
108 		mask = SMB_AT_NODEID;
109 		break;
110 
111 	default:
112 		break;
113 	}
114 
115 	qi->qi_attr.sa_mask = mask;
116 	qi->qi_node = of->f_node;
117 	if (mask & SMB_AT_ALL) {
118 		status = smb2_ofile_getattr(sr, of, &qi->qi_attr);
119 		if (status)
120 			return (status);
121 	}
122 	if (getstd) {
123 		status = smb2_ofile_getstd(of, qi);
124 		if (status)
125 			return (status);
126 	}
127 	if (getname) {
128 		status = smb2_ofile_getname(of, qi);
129 		if (status)
130 			return (status);
131 	}
132 
133 	switch (qi->qi_InfoClass) {
134 	case FileBasicInformation:
135 		status = smb2_qif_basic(sr, qi);
136 		break;
137 	case FileStandardInformation:
138 		status = smb2_qif_standard(sr, qi);
139 		break;
140 	case FileInternalInformation:
141 		status = smb2_qif_internal(sr, qi);
142 		break;
143 	case FileEaInformation:
144 		status = smb2_qif_ea_size(sr, qi);
145 		break;
146 	case FileAccessInformation:
147 		status = smb2_qif_access(sr, qi);
148 		break;
149 	case FileNameInformation:
150 		status = smb2_qif_name(sr, qi);
151 		break;
152 	case FileNormalizedNameInformation:
153 		status = smb2_qif_normalized_name(sr, qi);
154 		break;
155 	case FilePositionInformation:
156 		status = smb2_qif_position(sr, qi);
157 		break;
158 	case FileFullEaInformation:
159 		status = smb2_qif_full_ea(sr, qi);
160 		break;
161 	case FileModeInformation:
162 		status = smb2_qif_mode(sr, qi);
163 		break;
164 	case FileAlignmentInformation:
165 		status = smb2_qif_alignment(sr, qi);
166 		break;
167 	case FileAllInformation:
168 		status = smb2_qif_all(sr, qi);
169 		break;
170 	case FileAlternateNameInformation:
171 		status = smb2_qif_altname(sr, qi);
172 		break;
173 	case FileStreamInformation:
174 		status = smb2_qif_stream(sr, qi);
175 		break;
176 	case FilePipeInformation:
177 		status = smb2_qif_pipe(sr, qi);
178 		break;
179 	case FilePipeLocalInformation:
180 		status = smb2_qif_pipe_lcl(sr, qi);
181 		break;
182 	case FilePipeRemoteInformation:
183 		status = smb2_qif_pipe_rem(sr, qi);
184 		break;
185 	case FileCompressionInformation:
186 		status = smb2_qif_compr(sr, qi);
187 		break;
188 	case FileNetworkOpenInformation:
189 		status = smb2_qif_opens(sr, qi);
190 		break;
191 	case FileAttributeTagInformation:
192 		status = smb2_qif_tags(sr, qi);
193 		break;
194 	case FileIdInformation:
195 		status = smb2_qif_id_info(sr, qi);
196 		break;
197 	default:
198 		status = NT_STATUS_INVALID_INFO_CLASS;
199 		break;
200 	}
201 
202 	return (status);
203 }
204 
205 /*
206  * FileAllInformation
207  *
208  * This returns a concatenation of:
209  *	FileBasicInformation
210  *	FileStandardInformation
211  *	FileInternalInformation
212  *	FileEaInformation
213  *	FilePositionInformation
214  *	FileModeInformation
215  *	FileAlignmentInformation
216  *	FileNameInformation
217  *
218  * Note: FileNameInformation is all zero on Win2016 and later.
219  */
220 static uint32_t
221 smb2_qif_all(smb_request_t *sr, smb_queryinfo_t *qi)
222 {
223 	uint32_t status;
224 
225 	status = smb2_qif_basic(sr, qi);
226 	if (status)
227 		return (status);
228 	status = smb2_qif_standard(sr, qi);
229 	if (status)
230 		return (status);
231 	status = smb2_qif_internal(sr, qi);
232 	if (status)
233 		return (status);
234 	status = smb2_qif_ea_size(sr, qi);
235 	if (status)
236 		return (status);
237 	status = smb2_qif_position(sr, qi);
238 	if (status)
239 		return (status);
240 	status = smb2_qif_mode(sr, qi);
241 	if (status)
242 		return (status);
243 	status = smb2_qif_alignment(sr, qi);
244 	if (status)
245 		return (status);
246 
247 	/*
248 	 * MS-SMB2 3.3.5.20.1 says (in a windows behavior note) that
249 	 * 2012R2 and older fill in the FileNameInformation.
250 	 * We could let this depend on sr->sr_cfg->skc_version
251 	 * but doing it based on dialect is a lot easier and
252 	 * has nearly the same effect.
253 	 */
254 	if (sr->session->dialect < SMB_VERS_3_11) {
255 		/* Win2012r2 and earlier fill it in. (SMB 3.0) */
256 		status = smb2_qif_name(sr, qi);
257 	} else {
258 		/* Win2016 and later just put zeros (SMB 3.11) */
259 		int rc = smb_mbc_encodef(&sr->raw_data, "10.");
260 		status = (rc == 0) ? 0 : NT_STATUS_BUFFER_OVERFLOW;
261 	}
262 
263 	return (status);
264 }
265 
266 /*
267  * FileBasicInformation
268  * See also:
269  *	case SMB_QUERY_FILE_BASIC_INFO:
270  *	case SMB_FILE_BASIC_INFORMATION:
271  */
272 static uint32_t
273 smb2_qif_basic(smb_request_t *sr, smb_queryinfo_t *qi)
274 {
275 	smb_attr_t *sa = &qi->qi_attr;
276 	int rc;
277 
278 	ASSERT((sa->sa_mask & SMB_AT_BASIC) == SMB_AT_BASIC);
279 
280 	rc = smb_mbc_encodef(
281 	    &sr->raw_data, "TTTTll",
282 	    &sa->sa_crtime,		/* T */
283 	    &sa->sa_vattr.va_atime,	/* T */
284 	    &sa->sa_vattr.va_mtime,	/* T */
285 	    &sa->sa_vattr.va_ctime,	/* T */
286 	    sa->sa_dosattr,		/* l */
287 	    0); /* reserved */		/* l */
288 	if (rc != 0)
289 		return (NT_STATUS_BUFFER_OVERFLOW);
290 
291 	return (0);
292 }
293 
294 /*
295  * FileStandardInformation
296  * See also:
297  *	SMB_QUERY_FILE_STANDARD_INFO
298  *	SMB_FILE_STANDARD_INFORMATION
299  */
300 static uint32_t
301 smb2_qif_standard(smb_request_t *sr, smb_queryinfo_t *qi)
302 {
303 	smb_attr_t *sa = &qi->qi_attr;
304 	int rc;
305 
306 	ASSERT((sa->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD);
307 
308 	rc = smb_mbc_encodef(
309 	    &sr->raw_data, "qqlbbw",
310 	    sa->sa_allocsz,		/* q */
311 	    sa->sa_vattr.va_size,	/* q */
312 	    sa->sa_vattr.va_nlink,	/* l */
313 	    qi->qi_delete_on_close,	/* b */
314 	    qi->qi_isdir,		/* b */
315 	    0); /* reserved */		/* w */
316 	if (rc != 0)
317 		return (NT_STATUS_BUFFER_OVERFLOW);
318 
319 	return (0);
320 }
321 
322 /*
323  * FileInternalInformation
324  * See also:
325  *	SMB_FILE_INTERNAL_INFORMATION
326  */
327 static uint32_t
328 smb2_qif_internal(smb_request_t *sr, smb_queryinfo_t *qi)
329 {
330 	smb_attr_t *sa = &qi->qi_attr;
331 	u_longlong_t nodeid;
332 	int rc;
333 
334 	ASSERT((sa->sa_mask & SMB_AT_NODEID) == SMB_AT_NODEID);
335 	nodeid = sa->sa_vattr.va_nodeid;
336 
337 	if (smb2_aapl_use_file_ids == 0 &&
338 	    (sr->session->s_flags & SMB_SSN_AAPL_CCEXT) != 0)
339 		nodeid = 0;
340 
341 	rc = smb_mbc_encodef(
342 	    &sr->raw_data, "q",
343 	    nodeid);	/* q */
344 	if (rc != 0)
345 		return (NT_STATUS_BUFFER_OVERFLOW);
346 
347 	return (0);
348 }
349 
350 /*
351  * FileEaInformation
352  * See also:
353  *	SMB_QUERY_FILE_EA_INFO
354  *	SMB_FILE_EA_INFORMATION
355  */
356 static uint32_t
357 smb2_qif_ea_size(smb_request_t *sr, smb_queryinfo_t *qi)
358 {
359 	_NOTE(ARGUNUSED(qi))
360 	int rc;
361 
362 	rc = smb_mbc_encodef(
363 	    &sr->raw_data, "l", 0);
364 	if (rc != 0)
365 		return (NT_STATUS_BUFFER_OVERFLOW);
366 
367 	return (0);
368 }
369 
370 /*
371  * FileFullEaInformation
372  * We could put EAs in a named stream...
373  */
374 /* ARGSUSED */
375 static uint32_t
376 smb2_qif_full_ea(smb_request_t *sr, smb_queryinfo_t *qi)
377 {
378 	return (NT_STATUS_NO_EAS_ON_FILE);
379 }
380 
381 /*
382  * FileAccessInformation
383  */
384 static uint32_t
385 smb2_qif_access(smb_request_t *sr, smb_queryinfo_t *qi)
386 {
387 	_NOTE(ARGUNUSED(qi))
388 	smb_ofile_t *of = sr->fid_ofile;
389 	int rc;
390 
391 	rc = smb_mbc_encodef(
392 	    &sr->raw_data, "l",
393 	    of->f_granted_access);
394 	if (rc != 0)
395 		return (NT_STATUS_BUFFER_OVERFLOW);
396 
397 	return (0);
398 }
399 
400 /*
401  * FileNameInformation
402  * See also:
403  *	SMB_QUERY_FILE_NAME_INFO
404  *	SMB_FILE_NAME_INFORMATION
405  */
406 static uint32_t
407 smb2_qif_name(smb_request_t *sr, smb_queryinfo_t *qi)
408 {
409 	char *name;
410 	uint32_t nlen;
411 	int rc;
412 
413 	/* SMB2 leaves off the leading / */
414 	nlen = qi->qi_namelen;
415 	name = qi->qi_name;
416 	if (qi->qi_name[0] == '\\') {
417 		name++;
418 		nlen -= 2;
419 	}
420 
421 	rc = smb_mbc_encodef(
422 	    &sr->raw_data, "llU",
423 	    0, /* FileIndex	 (l) */
424 	    nlen,	/* l */
425 	    name);	/* U */
426 	if (rc != 0)
427 		return (NT_STATUS_BUFFER_OVERFLOW);
428 
429 	return (0);
430 }
431 
432 /*
433  * FileNormalizedNameInformation
434  */
435 static uint32_t
436 smb2_qif_normalized_name(smb_request_t *sr, smb_queryinfo_t *qi)
437 {
438 	char *name;
439 	uint32_t nlen;
440 	int rc;
441 
442 	/* SMB2 leaves off the leading / */
443 	nlen = qi->qi_namelen;
444 	name = qi->qi_name;
445 	if (qi->qi_name[0] == '\\') {
446 		name++;
447 		nlen -= 2;
448 	}
449 
450 	rc = smb_mbc_encodef(
451 	    &sr->raw_data, "lU",
452 	    nlen,	/* l */
453 	    name);	/* U */
454 	if (rc != 0)
455 		return (NT_STATUS_BUFFER_OVERFLOW);
456 
457 	return (0);
458 }
459 
460 /*
461  * FilePositionInformation
462  */
463 static uint32_t
464 smb2_qif_position(smb_request_t *sr, smb_queryinfo_t *qi)
465 {
466 	_NOTE(ARGUNUSED(qi))
467 	smb_ofile_t *of = sr->fid_ofile;
468 	uint64_t pos;
469 	int rc;
470 
471 	mutex_enter(&of->f_mutex);
472 	pos = of->f_seek_pos;
473 	mutex_exit(&of->f_mutex);
474 
475 	rc = smb_mbc_encodef(
476 	    &sr->raw_data, "q", pos);
477 	if (rc != 0)
478 		return (NT_STATUS_BUFFER_OVERFLOW);
479 
480 	return (0);
481 }
482 
483 /*
484  * FileModeInformation [MS-FSA 2.4.24]
485  */
486 static uint32_t
487 smb2_qif_mode(smb_request_t *sr, smb_queryinfo_t *qi)
488 {
489 	_NOTE(ARGUNUSED(qi))
490 	smb_ofile_t *of = sr->fid_ofile;
491 	uint32_t mode;
492 	int rc;
493 
494 	/*
495 	 * See MS-FSA description of Open.Mode
496 	 * For now, we have these in...
497 	 */
498 	mode = of->f_create_options &
499 	    (FILE_WRITE_THROUGH | FILE_SEQUENTIAL_ONLY |
500 	    FILE_NO_INTERMEDIATE_BUFFERING | FILE_DELETE_ON_CLOSE);
501 
502 	/*
503 	 * The ofile level DoC flag is currently in of->f_flags
504 	 * (SMB_OFLAGS_SET_DELETE_ON_CLOSE) though probably it
505 	 * should be in f_create_options (and perhaps rename
506 	 * that field to f_mode or something closer to the
507 	 * Open.Mode terminology used in MS-FSA).
508 	 */
509 	if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE)
510 		mode |= FILE_DELETE_ON_CLOSE;
511 
512 	rc = smb_mbc_encodef(
513 	    &sr->raw_data, "l", mode);
514 	if (rc != 0)
515 		return (NT_STATUS_BUFFER_OVERFLOW);
516 
517 	return (0);
518 }
519 
520 /*
521  * FileAlignmentInformation
522  */
523 static uint32_t
524 smb2_qif_alignment(smb_request_t *sr, smb_queryinfo_t *qi)
525 {
526 	_NOTE(ARGUNUSED(qi))
527 	int rc;
528 
529 	rc = smb_mbc_encodef(
530 	    &sr->raw_data, "l", 0);
531 	if (rc != 0)
532 		return (NT_STATUS_BUFFER_OVERFLOW);
533 
534 	return (0);
535 }
536 
537 /*
538  * FileAlternateNameInformation
539  * See also:
540  *	SMB_QUERY_FILE_ALT_NAME_INFO
541  *	SMB_FILE_ALT_NAME_INFORMATION
542  */
543 static uint32_t
544 smb2_qif_altname(smb_request_t *sr, smb_queryinfo_t *qi)
545 {
546 	smb_ofile_t *of = sr->fid_ofile;
547 	int rc;
548 
549 	ASSERT(qi->qi_namelen > 0);
550 	ASSERT(qi->qi_attr.sa_mask & SMB_AT_NODEID);
551 
552 	if (of->f_ftype != SMB_FTYPE_DISK)
553 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
554 	if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0)
555 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
556 
557 	/* fill in qi->qi_shortname */
558 	smb_query_shortname(of->f_node, qi);
559 
560 	rc = smb_mbc_encodef(
561 	    &sr->raw_data, "%lU", sr,
562 	    smb_wcequiv_strlen(qi->qi_shortname),
563 	    qi->qi_shortname);
564 	if (rc != 0)
565 		return (NT_STATUS_BUFFER_OVERFLOW);
566 
567 	return (0);
568 }
569 
570 /*
571  * FileStreamInformation
572  */
573 static uint32_t
574 smb2_qif_stream(smb_request_t *sr, smb_queryinfo_t *qi)
575 {
576 	smb_ofile_t *of = sr->fid_ofile;
577 	smb_attr_t *attr = &qi->qi_attr;
578 	uint32_t status;
579 
580 	ASSERT((attr->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD);
581 	if (of->f_ftype != SMB_FTYPE_DISK) {
582 		(void) smb_mbc_encodef(
583 		    &sr->raw_data, "l", 0);
584 		return (0);
585 	}
586 
587 	status = smb_query_stream_info(sr, &sr->raw_data, qi);
588 	return (status);
589 }
590 
591 /*
592  * FilePipeInformation
593  */
594 static uint32_t
595 smb2_qif_pipe(smb_request_t *sr, smb_queryinfo_t *qi)
596 {
597 	_NOTE(ARGUNUSED(qi))
598 	smb_ofile_t *of = sr->fid_ofile;
599 	uint32_t	pipe_mode;
600 	uint32_t	nonblock;
601 	int		rc;
602 
603 	switch (of->f_ftype) {
604 	case SMB_FTYPE_BYTE_PIPE:
605 		pipe_mode = 0;	/* FILE_PIPE_BYTE_STREAM_MODE */
606 		break;
607 	case SMB_FTYPE_MESG_PIPE:
608 		pipe_mode = 1;	/* FILE_PIPE_MESSAGE_MODE */
609 		break;
610 	case SMB_FTYPE_DISK:
611 	case SMB_FTYPE_PRINTER:
612 	default:
613 		return (NT_STATUS_INVALID_PARAMETER);
614 	}
615 	nonblock = 0;	/* XXX todo: Get this from the pipe handle. */
616 
617 	rc = smb_mbc_encodef(
618 	    &sr->raw_data, "ll",
619 	    pipe_mode, nonblock);
620 	if (rc != 0)
621 		return (NT_STATUS_BUFFER_OVERFLOW);
622 
623 	return (0);
624 }
625 
626 /*
627  * FilePipeLocalInformation
628  */
629 /* ARGSUSED */
630 static uint32_t
631 smb2_qif_pipe_lcl(smb_request_t *sr, smb_queryinfo_t *qi)
632 {
633 	return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */
634 }
635 
636 /*
637  * FilePipeRemoteInformation
638  */
639 /* ARGSUSED */
640 static uint32_t
641 smb2_qif_pipe_rem(smb_request_t *sr, smb_queryinfo_t *qi)
642 {
643 	return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */
644 }
645 
646 /*
647  * FileCompressionInformation
648  * XXX: For now, just say "not compressed".
649  */
650 static uint32_t
651 smb2_qif_compr(smb_request_t *sr, smb_queryinfo_t *qi)
652 {
653 	smb_attr_t *sa = &qi->qi_attr;
654 	uint16_t CompressionFormat = 0;	/* COMPRESSION_FORMAT_NONE */
655 	int rc;
656 
657 	ASSERT(sa->sa_mask & SMB_AT_SIZE);
658 
659 	rc = smb_mbc_encodef(
660 	    &sr->raw_data, "qw6.",
661 	    sa->sa_vattr.va_size,	/* q */
662 	    CompressionFormat);		/* w */
663 	if (rc != 0)
664 		return (NT_STATUS_BUFFER_OVERFLOW);
665 
666 	return (0);
667 }
668 
669 /*
670  * FileNetworkOpenInformation
671  */
672 static uint32_t
673 smb2_qif_opens(smb_request_t *sr, smb_queryinfo_t *qi)
674 {
675 	smb_attr_t *sa = &qi->qi_attr;
676 	int rc;
677 
678 	rc = smb_mbc_encodef(
679 	    &sr->raw_data, "TTTTqqll",
680 	    &sa->sa_crtime,		/* T */
681 	    &sa->sa_vattr.va_atime,	/* T */
682 	    &sa->sa_vattr.va_mtime,	/* T */
683 	    &sa->sa_vattr.va_ctime,	/* T */
684 	    sa->sa_allocsz,		/* q */
685 	    sa->sa_vattr.va_size,	/* q */
686 	    sa->sa_dosattr,		/* l */
687 	    0); /* reserved */		/* l */
688 	if (rc != 0)
689 		return (NT_STATUS_BUFFER_OVERFLOW);
690 
691 	return (0);
692 }
693 
694 /*
695  * FileAttributeTagInformation
696  *
697  * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
698  * second dword should be the reparse tag.  Otherwise
699  * the tag value should be set to zero.
700  * We don't support reparse points, so we set the tag
701  * to zero.
702  */
703 static uint32_t
704 smb2_qif_tags(smb_request_t *sr, smb_queryinfo_t *qi)
705 {
706 	_NOTE(ARGUNUSED(qi))
707 	int rc;
708 
709 	rc = smb_mbc_encodef(
710 	    &sr->raw_data, "ll", 0, 0);
711 	if (rc != 0)
712 		return (NT_STATUS_BUFFER_OVERFLOW);
713 
714 	return (0);
715 }
716 
717 /*
718  * FileIdInformation
719  *
720  * Returns a A FILE_ID_INFORMATION
721  *	VolumeSerialNumber (8 bytes)
722  *	FileId (16 bytes)
723  *
724  * Take the volume serial from the share root,
725  * and compose the FileId from the nodeid and fsid
726  * of the file (in case we crossed mounts)
727  */
728 static uint32_t
729 smb2_qif_id_info(smb_request_t *sr, smb_queryinfo_t *qi)
730 {
731 	smb_attr_t *sa = &qi->qi_attr;
732 	smb_ofile_t *of = sr->fid_ofile;
733 	smb_tree_t *tree = sr->tid_tree;
734 	vfs_t	*f_vfs;	// file
735 	vfs_t	*s_vfs;	// share
736 	uint64_t nodeid;
737 	int rc;
738 
739 	ASSERT((sa->sa_mask & SMB_AT_NODEID) != 0);
740 	if (of->f_ftype != SMB_FTYPE_DISK)
741 		return (NT_STATUS_INVALID_INFO_CLASS);
742 
743 	s_vfs = SMB_NODE_VFS(tree->t_snode);
744 	f_vfs = SMB_NODE_VFS(of->f_node);
745 	nodeid = (uint64_t)sa->sa_vattr.va_nodeid;
746 
747 	rc = smb_mbc_encodef(
748 	    &sr->raw_data, "llqll",
749 	    s_vfs->vfs_fsid.val[0],	/* l */
750 	    s_vfs->vfs_fsid.val[1],	/* l */
751 	    nodeid,			/* q */
752 	    f_vfs->vfs_fsid.val[0],	/* l */
753 	    f_vfs->vfs_fsid.val[1]);	/* l */
754 	if (rc != 0)
755 		return (NT_STATUS_INFO_LENGTH_MISMATCH);
756 
757 	return (0);
758 }
759