xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_qinfo_file.c (revision 067afcb3a52b5ebe76a00b3f366353cad54c649e)
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  * XXX: These mode flags are supposed to be on the open handle,
486  * XXX: or I think so.  Not yet...  (just put zero for now)
487  */
488 static uint32_t
489 smb2_qif_mode(smb_request_t *sr, smb_queryinfo_t *qi)
490 {
491 	_NOTE(ARGUNUSED(qi))
492 	int rc;
493 
494 	rc = smb_mbc_encodef(
495 	    &sr->raw_data, "l", 0);
496 	if (rc != 0)
497 		return (NT_STATUS_BUFFER_OVERFLOW);
498 
499 	return (0);
500 }
501 
502 /*
503  * FileAlignmentInformation
504  */
505 static uint32_t
506 smb2_qif_alignment(smb_request_t *sr, smb_queryinfo_t *qi)
507 {
508 	_NOTE(ARGUNUSED(qi))
509 	int rc;
510 
511 	rc = smb_mbc_encodef(
512 	    &sr->raw_data, "l", 0);
513 	if (rc != 0)
514 		return (NT_STATUS_BUFFER_OVERFLOW);
515 
516 	return (0);
517 }
518 
519 /*
520  * FileAlternateNameInformation
521  * See also:
522  *	SMB_QUERY_FILE_ALT_NAME_INFO
523  *	SMB_FILE_ALT_NAME_INFORMATION
524  */
525 static uint32_t
526 smb2_qif_altname(smb_request_t *sr, smb_queryinfo_t *qi)
527 {
528 	smb_ofile_t *of = sr->fid_ofile;
529 	int rc;
530 
531 	ASSERT(qi->qi_namelen > 0);
532 	ASSERT(qi->qi_attr.sa_mask & SMB_AT_NODEID);
533 
534 	if (of->f_ftype != SMB_FTYPE_DISK)
535 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
536 	if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0)
537 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
538 
539 	/* fill in qi->qi_shortname */
540 	smb_query_shortname(of->f_node, qi);
541 
542 	rc = smb_mbc_encodef(
543 	    &sr->raw_data, "%lU", sr,
544 	    smb_wcequiv_strlen(qi->qi_shortname),
545 	    qi->qi_shortname);
546 	if (rc != 0)
547 		return (NT_STATUS_BUFFER_OVERFLOW);
548 
549 	return (0);
550 }
551 
552 /*
553  * FileStreamInformation
554  */
555 static uint32_t
556 smb2_qif_stream(smb_request_t *sr, smb_queryinfo_t *qi)
557 {
558 	smb_ofile_t *of = sr->fid_ofile;
559 	smb_attr_t *attr = &qi->qi_attr;
560 	uint32_t status;
561 
562 	ASSERT((attr->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD);
563 	if (of->f_ftype != SMB_FTYPE_DISK) {
564 		(void) smb_mbc_encodef(
565 		    &sr->raw_data, "l", 0);
566 		return (0);
567 	}
568 
569 	status = smb_query_stream_info(sr, &sr->raw_data, qi);
570 	return (status);
571 }
572 
573 /*
574  * FilePipeInformation
575  */
576 static uint32_t
577 smb2_qif_pipe(smb_request_t *sr, smb_queryinfo_t *qi)
578 {
579 	_NOTE(ARGUNUSED(qi))
580 	smb_ofile_t *of = sr->fid_ofile;
581 	uint32_t	pipe_mode;
582 	uint32_t	nonblock;
583 	int		rc;
584 
585 	switch (of->f_ftype) {
586 	case SMB_FTYPE_BYTE_PIPE:
587 		pipe_mode = 0;	/* FILE_PIPE_BYTE_STREAM_MODE */
588 		break;
589 	case SMB_FTYPE_MESG_PIPE:
590 		pipe_mode = 1;	/* FILE_PIPE_MESSAGE_MODE */
591 		break;
592 	case SMB_FTYPE_DISK:
593 	case SMB_FTYPE_PRINTER:
594 	default:
595 		return (NT_STATUS_INVALID_PARAMETER);
596 	}
597 	nonblock = 0;	/* XXX todo: Get this from the pipe handle. */
598 
599 	rc = smb_mbc_encodef(
600 	    &sr->raw_data, "ll",
601 	    pipe_mode, nonblock);
602 	if (rc != 0)
603 		return (NT_STATUS_BUFFER_OVERFLOW);
604 
605 	return (0);
606 }
607 
608 /*
609  * FilePipeLocalInformation
610  */
611 /* ARGSUSED */
612 static uint32_t
613 smb2_qif_pipe_lcl(smb_request_t *sr, smb_queryinfo_t *qi)
614 {
615 	return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */
616 }
617 
618 /*
619  * FilePipeRemoteInformation
620  */
621 /* ARGSUSED */
622 static uint32_t
623 smb2_qif_pipe_rem(smb_request_t *sr, smb_queryinfo_t *qi)
624 {
625 	return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */
626 }
627 
628 /*
629  * FileCompressionInformation
630  * XXX: For now, just say "not compressed".
631  */
632 static uint32_t
633 smb2_qif_compr(smb_request_t *sr, smb_queryinfo_t *qi)
634 {
635 	smb_attr_t *sa = &qi->qi_attr;
636 	uint16_t CompressionFormat = 0;	/* COMPRESSION_FORMAT_NONE */
637 	int rc;
638 
639 	ASSERT(sa->sa_mask & SMB_AT_SIZE);
640 
641 	rc = smb_mbc_encodef(
642 	    &sr->raw_data, "qw6.",
643 	    sa->sa_vattr.va_size,	/* q */
644 	    CompressionFormat);		/* w */
645 	if (rc != 0)
646 		return (NT_STATUS_BUFFER_OVERFLOW);
647 
648 	return (0);
649 }
650 
651 /*
652  * FileNetworkOpenInformation
653  */
654 static uint32_t
655 smb2_qif_opens(smb_request_t *sr, smb_queryinfo_t *qi)
656 {
657 	smb_attr_t *sa = &qi->qi_attr;
658 	int rc;
659 
660 	rc = smb_mbc_encodef(
661 	    &sr->raw_data, "TTTTqqll",
662 	    &sa->sa_crtime,		/* T */
663 	    &sa->sa_vattr.va_atime,	/* T */
664 	    &sa->sa_vattr.va_mtime,	/* T */
665 	    &sa->sa_vattr.va_ctime,	/* T */
666 	    sa->sa_allocsz,		/* q */
667 	    sa->sa_vattr.va_size,	/* q */
668 	    sa->sa_dosattr,		/* l */
669 	    0); /* reserved */		/* l */
670 	if (rc != 0)
671 		return (NT_STATUS_BUFFER_OVERFLOW);
672 
673 	return (0);
674 }
675 
676 /*
677  * FileAttributeTagInformation
678  *
679  * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
680  * second dword should be the reparse tag.  Otherwise
681  * the tag value should be set to zero.
682  * We don't support reparse points, so we set the tag
683  * to zero.
684  */
685 static uint32_t
686 smb2_qif_tags(smb_request_t *sr, smb_queryinfo_t *qi)
687 {
688 	_NOTE(ARGUNUSED(qi))
689 	int rc;
690 
691 	rc = smb_mbc_encodef(
692 	    &sr->raw_data, "ll", 0, 0);
693 	if (rc != 0)
694 		return (NT_STATUS_BUFFER_OVERFLOW);
695 
696 	return (0);
697 }
698 
699 /*
700  * FileIdInformation
701  *
702  * Returns a A FILE_ID_INFORMATION
703  *	VolumeSerialNumber (8 bytes)
704  *	FileId (16 bytes)
705  *
706  * Take the volume serial from the share root,
707  * and compose the FileId from the nodeid and fsid
708  * of the file (in case we crossed mounts)
709  */
710 static uint32_t
711 smb2_qif_id_info(smb_request_t *sr, smb_queryinfo_t *qi)
712 {
713 	smb_attr_t *sa = &qi->qi_attr;
714 	smb_ofile_t *of = sr->fid_ofile;
715 	smb_tree_t *tree = sr->tid_tree;
716 	vfs_t	*f_vfs;	// file
717 	vfs_t	*s_vfs;	// share
718 	uint64_t nodeid;
719 	int rc;
720 
721 	ASSERT((sa->sa_mask & SMB_AT_NODEID) != 0);
722 	if (of->f_ftype != SMB_FTYPE_DISK)
723 		return (NT_STATUS_INVALID_INFO_CLASS);
724 
725 	s_vfs = SMB_NODE_VFS(tree->t_snode);
726 	f_vfs = SMB_NODE_VFS(of->f_node);
727 	nodeid = (uint64_t)sa->sa_vattr.va_nodeid;
728 
729 	rc = smb_mbc_encodef(
730 	    &sr->raw_data, "llqll",
731 	    s_vfs->vfs_fsid.val[0],	/* l */
732 	    s_vfs->vfs_fsid.val[1],	/* l */
733 	    nodeid,			/* q */
734 	    f_vfs->vfs_fsid.val[0],	/* l */
735 	    f_vfs->vfs_fsid.val[1]);	/* l */
736 	if (rc != 0)
737 		return (NT_STATUS_INFO_LENGTH_MISMATCH);
738 
739 	return (0);
740 }
741