xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c (revision b23a7923c0fe493ed4beebaf775ad634ea217080)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  * This module provides functions for TRANS2_FIND_FIRST2 and
29  * TRANS2_FIND_NEXT2 requests. The requests allow the client to search
30  * for the file(s) which match the file specification.  The search is
31  * started with TRANS2_FIND_FIRST2 and can be continued if necessary with
32  * TRANS2_FIND_NEXT2. There are numerous levels of information which may be
33  * obtained for the returned files, the desired level is specified in the
34  * InformationLevel field of the requests.
35  *
36  *  InformationLevel Name              Value
37  *  =================================  ================
38  *
39  *  SMB_INFO_STANDARD                  1
40  *  SMB_INFO_QUERY_EA_SIZE             2
41  *  SMB_INFO_QUERY_EAS_FROM_LIST       3
42  *  SMB_FIND_FILE_DIRECTORY_INFO       0x101
43  *  SMB_FIND_FILE_FULL_DIRECTORY_INFO  0x102
44  *  SMB_FIND_FILE_NAMES_INFO           0x103
45  *  SMB_FIND_FILE_BOTH_DIRECTORY_INFO  0x104
46  *  SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO  0x105
47  *  SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO  0x106
48  *
49  * The following sections detail the data returned for each
50  * InformationLevel. The requested information is placed in the Data
51  * portion of the transaction response. Note: a client which does not
52  * support long names can only request SMB_INFO_STANDARD.
53  *
54  * A four-byte resume key precedes each data item (described below) if bit
55  * 2 in the Flags field is set, i.e. if the request indicates the server
56  * should return resume keys. Note: it is not always the case. If the
57  * data item already includes the resume key, the resume key should not be
58  * added again.
59  *
60  * 4.3.4.1   SMB_INFO_STANDARD
61  *
62  *  Response Field                    Description
63  *  ================================  ==================================
64  *
65  *  SMB_DATE CreationDate;            Date when file was created
66  *  SMB_TIME CreationTime;            Time when file was created
67  *  SMB_DATE LastAccessDate;          Date of last file access
68  *  SMB_TIME LastAccessTime;          Time of last file access
69  *  SMB_DATE LastWriteDate;           Date of last write to the file
70  *  SMB_TIME LastWriteTime;           Time of last write to the file
71  *  ULONG  DataSize;                  File Size
72  *  ULONG AllocationSize;             Size of filesystem allocation unit
73  *  USHORT Attributes;                File Attributes
74  *  UCHAR FileNameLength;             Length of filename in bytes
75  *  STRING FileName;                  Name of found file
76  *
77  * 4.3.4.2   SMB_INFO_QUERY_EA_SIZE
78  *
79  *  Response Field                     Description
80  *  =================================  ==================================
81  *
82  *   SMB_DATE CreationDate;            Date when file was created
83  *   SMB_TIME CreationTime;            Time when file was created
84  *   SMB_DATE LastAccessDate;          Date of last file access
85  *   SMB_TIME LastAccessTime;          Time of last file access
86  *   SMB_DATE LastWriteDate;           Date of last write to the file
87  *   SMB_TIME LastWriteTime;           Time of last write to the file
88  *   ULONG DataSize;                   File Size
89  *   ULONG AllocationSize;             Size of filesystem allocation unit
90  *   USHORT Attributes;                File Attributes
91  *   ULONG EaSize;                     Size of file's EA information
92  *   UCHAR FileNameLength;             Length of filename in bytes
93  *   STRING FileName;                  Name of found file
94  *
95  * 4.3.4.3   SMB_INFO_QUERY_EAS_FROM_LIST
96  *
97  * This request returns the same information as SMB_INFO_QUERY_EA_SIZE, but
98  * only for files which have an EA list which match the EA information in
99  * the Data part of the request.
100  *
101  * 4.3.4.4   SMB_FIND_FILE_DIRECTORY_INFO
102  *
103  *  Response Field                     Description
104  *  =================================  ==================================
105  *
106  *  ULONG NextEntryOffset;             Offset from this structure to
107  *					beginning of next one
108  *  ULONG FileIndex;
109  *  LARGE_INTEGER CreationTime;        file creation time
110  *  LARGE_INTEGER LastAccessTime;      last access time
111  *  LARGE_INTEGER LastWriteTime;       last write time
112  *  LARGE_INTEGER ChangeTime;          last attribute change time
113  *  LARGE_INTEGER EndOfFile;           file size
114  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
115  *  ULONG ExtFileAttributes;           Extended file attributes
116  *					(see section 3.11)
117  *  ULONG FileNameLength;              Length of filename in bytes
118  *  STRING FileName;                   Name of the file
119  *
120  * 4.3.4.5   SMB_FIND_FILE_FULL_DIRECTORY_INFO
121  *
122  *  Response Field                     Description
123  *  =================================  ==================================
124  *
125  *  ULONG NextEntryOffset;             Offset from this structure to
126  *					beginning of next one
127  *  ULONG FileIndex;
128  *  LARGE_INTEGER CreationTime;        file creation time
129  *  LARGE_INTEGER LastAccessTime;      last access time
130  *  LARGE_INTEGER LastWriteTime;       last write time
131  *  LARGE_INTEGER ChangeTime;          last attribute change time
132  *  LARGE_INTEGER EndOfFile;           file size
133  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
134  *  ULONG ExtFileAttributes;           Extended file attributes
135  *					(see section 3.11)
136  *  ULONG FileNameLength;              Length of filename in bytes
137  *  ULONG EaSize;                      Size of file's extended attributes
138  *  STRING FileName;                   Name of the file
139  *
140  *
141  *  SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO
142  *
143  *  This is the same as SMB_FIND_FILE_FULL_DIRECTORY_INFO but with
144  *  FileId inserted after EaSize. FileId is preceded by a 4 byte
145  *  alignment padding.
146  *
147  *  Response Field                     Description
148  *  =================================  ==================================
149  *  ...
150  *  ULONG EaSize;                      Size of file's extended attributes
151  *  UCHAR Reserved[4]
152  *  LARGE_INTEGER FileId               Internal file system unique id.
153  *  STRING FileName;                   Name of the file
154  *
155  * 4.3.4.6   SMB_FIND_FILE_BOTH_DIRECTORY_INFO
156  *
157  *  Response Field                     Description
158  *  =================================  ==================================
159  *
160  *  ULONG NextEntryOffset;             Offset from this structure to
161  *					beginning of next one
162  *  ULONG FileIndex;
163  *  LARGE_INTEGER CreationTime;        file creation time
164  *  LARGE_INTEGER LastAccessTime;      last access time
165  *  LARGE_INTEGER LastWriteTime;       last write time
166  *  LARGE_INTEGER ChangeTime;          last attribute change time
167  *  LARGE_INTEGER EndOfFile;           file size
168  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
169  *  ULONG ExtFileAttributes;           Extended file attributes
170  *					(see section 3.11)
171  *  ULONG FileNameLength;              Length of FileName in bytes
172  *  ULONG EaSize;                      Size of file's extended attributes
173  *  UCHAR ShortNameLength;             Length of file's short name in bytes
174  *  UCHAR Reserved
175  *  WCHAR ShortName[12];               File's 8.3 conformant name in Unicode
176  *  STRING FileName;                   Files full length name
177  *
178  *
179  *  SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO
180  *
181  *  This is the same as SMB_FIND_FILE_BOTH_DIRECTORY_INFO but with
182  *  FileId inserted after ShortName. FileId is preceded by a 2 byte
183  *  alignment pad.
184  *
185  *  Response Field                     Description
186  *  =================================  ==================================
187  *  ...
188  *  WCHAR ShortName[12];               File's 8.3 conformant name in Unicode
189  *  UCHAR Reserved[2]
190  *  LARGE_INTEGER FileId               Internal file system unique id.
191  *  STRING FileName;                   Files full length name
192  *
193  * 4.3.4.7   SMB_FIND_FILE_NAMES_INFO
194  *
195  *  Response Field                     Description
196  *  =================================  ==================================
197  *
198  *  ULONG NextEntryOffset;             Offset from this structure to
199  *                                     beginning of next one
200  *  ULONG FileIndex;
201  *  ULONG FileNameLength;              Length of FileName in bytes
202  *  STRING FileName;                   Files full length name
203  */
204 
205 #include <smbsrv/smb_kproto.h>
206 #include <smbsrv/msgbuf.h>
207 #include <smbsrv/smb_fsops.h>
208 
209 typedef struct smb_find_args {
210 	uint16_t fa_infolev;
211 	uint16_t fa_maxcount;
212 	uint16_t fa_fflag;
213 	uint32_t fa_maxdata;
214 } smb_find_args_t;
215 
216 static int smb_trans2_find_entries(smb_request_t *, smb_xa_t *,
217     smb_odir_t *, smb_find_args_t *, boolean_t *);
218 static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t);
219 static int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *,
220     smb_fileinfo_t *, smb_find_args_t *);
221 
222 /*
223  * Tunable parameter to limit the maximum
224  * number of entries to be returned.
225  */
226 uint16_t smb_trans2_find_max = 128;
227 
228 /*
229  * smb_com_trans2_find_first2
230  *
231  *  Client Request                Value
232  *  ============================  ==================================
233  *
234  *  UCHAR  WordCount              15
235  *  UCHAR  TotalDataCount         Total size of extended attribute list
236  *  UCHAR  SetupCount             1
237  *  UCHAR  Setup[0]               TRANS2_FIND_FIRST2
238  *
239  *  Parameter Block Encoding      Description
240  *  ============================  ==================================
241  *  USHORT SearchAttributes;
242  *  USHORT SearchCount;           Maximum number of entries to return
243  *  USHORT Flags;                 Additional information:
244  *                                Bit 0 - close search after this request
245  *                                Bit 1 - close search if end of search
246  *                                reached
247  *                                Bit 2 - return resume keys for each
248  *                                entry found
249  *                                Bit 3 - continue search from previous
250  *                                ending place
251  *                                Bit 4 - find with backup intent
252  *  USHORT InformationLevel;      See below
253  *  ULONG SearchStorageType;
254  *  STRING FileName;              Pattern for the search
255  *  UCHAR Data[ TotalDataCount ]  FEAList if InformationLevel is
256  *                                QUERY_EAS_FROM_LIST
257  *
258  *  Response Parameter Block      Description
259  *  ============================  ==================================
260  *
261  *  USHORT Sid;                   Search handle
262  *  USHORT SearchCount;           Number of entries returned
263  *  USHORT EndOfSearch;           Was last entry returned?
264  *  USHORT EaErrorOffset;         Offset into EA list if EA error
265  *  USHORT LastNameOffset;        Offset into data to file name of last
266  *                                entry, if server needs it to resume
267  *                                search; else 0
268  *  UCHAR Data[ TotalDataCount ]  Level dependent info about the matches
269  *                                found in the search
270  */
271 smb_sdrc_t
272 smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa)
273 {
274 	int		count;
275 	uint16_t	sattr, odid;
276 	smb_pathname_t	*pn;
277 	smb_odir_t	*od;
278 	smb_find_args_t	args;
279 	boolean_t	eos;
280 	uint32_t	odir_flags = 0;
281 
282 	bzero(&args, sizeof (smb_find_args_t));
283 
284 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
285 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
286 		    ERRDOS, ERROR_ACCESS_DENIED);
287 		return (SDRC_ERROR);
288 	}
289 
290 	pn = &sr->arg.dirop.fqi.fq_path;
291 
292 	if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr,
293 	    &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev,
294 	    &pn->pn_path) != 0) {
295 		return (SDRC_ERROR);
296 	}
297 
298 	smb_pathname_init(sr, pn, pn->pn_path);
299 	if (!smb_pathname_validate(sr, pn))
300 		return (-1);
301 
302 	if (smb_is_stream_name(pn->pn_path)) {
303 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
304 		    ERRDOS, ERROR_INVALID_NAME);
305 		return (SDRC_ERROR);
306 	}
307 
308 	if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) {
309 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
310 		odir_flags = SMB_ODIR_OPENF_BACKUP_INTENT;
311 	}
312 
313 	args.fa_maxdata =
314 	    smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
315 	if (args.fa_maxdata == 0)
316 		return (SDRC_ERROR);
317 
318 	odid = smb_odir_open(sr, pn->pn_path, sattr, odir_flags);
319 	if (odid == 0) {
320 		if (sr->smb_error.status == NT_STATUS_OBJECT_PATH_NOT_FOUND) {
321 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
322 			    ERRDOS, ERROR_FILE_NOT_FOUND);
323 		}
324 		return (SDRC_ERROR);
325 	}
326 
327 	od = smb_tree_lookup_odir(sr->tid_tree, odid);
328 	if (od == NULL)
329 		return (SDRC_ERROR);
330 	count = smb_trans2_find_entries(sr, xa, od, &args, &eos);
331 
332 	if (count == -1) {
333 		smb_odir_close(od);
334 		smb_odir_release(od);
335 		return (SDRC_ERROR);
336 	}
337 
338 	if (count == 0) {
339 		smb_odir_close(od);
340 		smb_odir_release(od);
341 		smbsr_errno(sr, ENOENT);
342 		return (SDRC_ERROR);
343 	}
344 
345 	if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
346 	    (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
347 		smb_odir_close(od);
348 	} /* else leave odir open for trans2_find_next2 */
349 
350 	smb_odir_release(od);
351 
352 	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww",
353 	    odid, count, (eos) ? 1 : 0, 0, 0);
354 
355 	return (SDRC_SUCCESS);
356 }
357 
358 /*
359  * smb_com_trans2_find_next2
360  *
361  *  Client Request                     Value
362  *  ================================== =================================
363  *
364  *  WordCount                          15
365  *  SetupCount                         1
366  *  Setup[0]                           TRANS2_FIND_NEXT2
367  *
368  *  Parameter Block Encoding           Description
369  *  ================================== =================================
370  *
371  *  USHORT Sid;                        Search handle
372  *  USHORT SearchCount;                Maximum number of entries to
373  *                                      return
374  *  USHORT InformationLevel;           Levels described in
375  *                                      TRANS2_FIND_FIRST2 request
376  *  ULONG ResumeKey;                   Value returned by previous find2
377  *                                      call
378  *  USHORT Flags;                      Additional information: bit set-
379  *                                      0 - close search after this
380  *                                      request
381  *                                      1 - close search if end of search
382  *                                      reached
383  *                                      2 - return resume keys for each
384  *                                      entry found
385  *                                      3 - resume/continue from previous
386  *                                      ending place
387  *                                      4 - find with backup intent
388  *  STRING FileName;                   Resume file name
389  *
390  * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2
391  * call.  If Bit3 of Flags is set, then FileName may be the NULL string,
392  * since the search is continued from the previous TRANS2_FIND request.
393  * Otherwise, FileName must not be more than 256 characters long.
394  *
395  *  Response Field                     Description
396  *  ================================== =================================
397  *
398  *  USHORT SearchCount;                Number of entries returned
399  *  USHORT EndOfSearch;                Was last entry returned?
400  *  USHORT EaErrorOffset;              Offset into EA list if EA error
401  *  USHORT LastNameOffset;             Offset into data to file name of
402  *                                      last entry, if server needs it to
403  *                                      resume search; else 0
404  *  UCHAR Data[TotalDataCount]         Level dependent info about the
405  *                                      matches found in the search
406  *
407  *
408  * The last parameter in the request is a filename, which is a
409  * null-terminated unicode string.
410  *
411  * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr,
412  *    &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname)
413  *
414  * The filename parameter is not currently decoded because we
415  * expect a 2-byte null but Mac OS 10 clients send a 1-byte null,
416  * which leads to a decode error.
417  * Thus, we do not support resume by filename.  We treat a request
418  * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST.
419  */
420 smb_sdrc_t
421 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa)
422 {
423 	int			count;
424 	uint16_t		odid;
425 	uint32_t		cookie;
426 	smb_odir_t		*od;
427 	smb_find_args_t		args;
428 	boolean_t		eos;
429 	smb_odir_resume_t	odir_resume;
430 
431 	bzero(&args, sizeof (smb_find_args_t));
432 
433 	if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlw", sr, &odid,
434 	    &args.fa_maxcount, &args.fa_infolev, &cookie, &args.fa_fflag)
435 	    != 0) {
436 		return (SDRC_ERROR);
437 	}
438 
439 	/* continuation by filename not supported */
440 	if ((args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) || (cookie == 0)) {
441 		odir_resume.or_type = SMB_ODIR_RESUME_IDX;
442 		odir_resume.or_idx = 0;
443 	} else {
444 		odir_resume.or_type = SMB_ODIR_RESUME_COOKIE;
445 		odir_resume.or_cookie = cookie;
446 	}
447 
448 	if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT)
449 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
450 
451 	args.fa_maxdata =
452 	    smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
453 	if (args.fa_maxdata == 0)
454 		return (SDRC_ERROR);
455 
456 	od = smb_tree_lookup_odir(sr->tid_tree, odid);
457 	if (od == NULL) {
458 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
459 		    ERRDOS, ERROR_INVALID_HANDLE);
460 		return (SDRC_ERROR);
461 	}
462 	smb_odir_resume_at(od, &odir_resume);
463 	count = smb_trans2_find_entries(sr, xa, od, &args, &eos);
464 
465 	if (count == -1) {
466 		smb_odir_close(od);
467 		smb_odir_release(od);
468 		return (SDRC_ERROR);
469 	}
470 
471 	if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
472 	    (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
473 		smb_odir_close(od);
474 	} /* else leave odir open for trans2_find_next2 */
475 
476 	smb_odir_release(od);
477 	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww",
478 	    count, (eos) ? 1 : 0, 0, 0);
479 
480 	return (SDRC_SUCCESS);
481 }
482 
483 
484 /*
485  * smb_trans2_find_entries
486  *
487  * Find and encode up to args->fa_maxcount directory entries.
488  * For compatibilty with Windows, if args->fa_maxcount is zero treat it as 1.
489  *
490  * Returns:
491  *   count - count of entries encoded
492  *           *eos = B_TRUE if no more directory entries
493  *      -1 - error
494  */
495 static int
496 smb_trans2_find_entries(smb_request_t *sr, smb_xa_t *xa, smb_odir_t *od,
497     smb_find_args_t *args, boolean_t *eos)
498 {
499 	int		rc;
500 	uint16_t	count, maxcount;
501 	uint32_t	cookie;
502 	smb_fileinfo_t	fileinfo;
503 
504 	if ((maxcount = args->fa_maxcount) == 0)
505 		maxcount = 1;
506 
507 	if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
508 		maxcount = smb_trans2_find_max;
509 
510 	count = 0;
511 	while (count < maxcount) {
512 		if (smb_odir_read_fileinfo(sr, od, &fileinfo, eos) != 0)
513 			return (-1);
514 		if (*eos == B_TRUE)
515 			break;
516 
517 		rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args);
518 		if (rc == -1)
519 			return (-1);
520 		if (rc == 1)
521 			break;
522 
523 		cookie = fileinfo.fi_cookie;
524 		++count;
525 	}
526 
527 	/* save the last cookie returned to client */
528 	if (count != 0)
529 		smb_odir_save_cookie(od, 0, cookie);
530 
531 	/*
532 	 * If all retrieved entries have been successfully encoded
533 	 * and eos has not already been detected, check if there are
534 	 * any more entries. eos will be set if there are no more.
535 	 */
536 	if ((rc == 0) && (!*eos))
537 		(void) smb_odir_read_fileinfo(sr, od, &fileinfo, eos);
538 
539 	return (count);
540 }
541 
542 /*
543  * smb_trans2_find_get_maxdata
544  *
545  * Calculate the minimum response space required for the specified
546  * information level.
547  *
548  * A non-zero return value provides the minimum space required.
549  * A return value of zero indicates an unknown information level.
550  */
551 static int
552 smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag)
553 {
554 	int maxdata;
555 
556 	maxdata = smb_ascii_or_unicode_null_len(sr);
557 
558 	switch (infolev) {
559 	case SMB_INFO_STANDARD :
560 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
561 			maxdata += sizeof (int32_t);
562 		maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1;
563 		break;
564 
565 	case SMB_INFO_QUERY_EA_SIZE:
566 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
567 			maxdata += sizeof (int32_t);
568 		maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1;
569 		break;
570 
571 	case SMB_FIND_FILE_DIRECTORY_INFO:
572 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4;
573 		break;
574 
575 	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
576 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4;
577 		break;
578 
579 	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
580 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 8;
581 		break;
582 
583 	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
584 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24;
585 		break;
586 
587 	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
588 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24
589 		    + 2 + 8;
590 		break;
591 
592 	case SMB_FIND_FILE_NAMES_INFO:
593 		maxdata += 4 + 4 + 4;
594 		break;
595 
596 	case SMB_MAC_FIND_BOTH_HFS_INFO:
597 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 +
598 		    4 + 32 + 4 + 1 + 1 + 24 + 4;
599 		break;
600 
601 	default:
602 		maxdata = 0;
603 		smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
604 		    ERRDOS, ERROR_INVALID_LEVEL);
605 	}
606 
607 	return (maxdata);
608 }
609 
610 /*
611  * smb_trans2_mbc_encode
612  *
613  * This function encodes the mbc for one directory entry.
614  *
615  * The function returns -1 when the max data requested by client
616  * is reached. If the entry is valid and successful encoded, 0
617  * will be returned; otherwise, 1 will be returned.
618  *
619  * We always null terminate the filename. The space for the null
620  * is included in the maxdata calculation and is therefore included
621  * in the next_entry_offset. namelen is the unterminated length of
622  * the filename. For levels except STANDARD and EA_SIZE, if the
623  * filename is ascii the name length returned to the client should
624  * include the null terminator. Otherwise the length returned to
625  * the client should not include the terminator.
626  *
627  * Returns: 0 - data successfully encoded
628  *          1 - client request's maxdata limit reached
629  *	   -1 - error
630  */
631 static int
632 smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
633     smb_fileinfo_t *fileinfo, smb_find_args_t *args)
634 {
635 	int		namelen, shortlen, buflen;
636 	uint32_t	next_entry_offset;
637 	uint32_t	dsize32, asize32;
638 	uint32_t	mb_flags = 0;
639 	char		buf83[26];
640 	char		*tmpbuf;
641 	smb_msgbuf_t	mb;
642 
643 	namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name);
644 	if (namelen == -1)
645 		return (-1);
646 
647 	next_entry_offset = args->fa_maxdata + namelen;
648 
649 	if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0)
650 		return (1);
651 
652 	/*
653 	 * If ascii the filename length returned to the client should
654 	 * include the null terminator for levels except STANDARD and
655 	 * EASIZE.
656 	 */
657 	if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
658 		if ((args->fa_infolev != SMB_INFO_STANDARD) &&
659 		    (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE))
660 			namelen += 1;
661 	}
662 
663 	mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0;
664 	dsize32 = (fileinfo->fi_size > UINT_MAX) ?
665 	    UINT_MAX : (uint32_t)fileinfo->fi_size;
666 	asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ?
667 	    UINT_MAX : (uint32_t)fileinfo->fi_alloc_size;
668 
669 	switch (args->fa_infolev) {
670 	case SMB_INFO_STANDARD:
671 		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
672 			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
673 			    fileinfo->fi_cookie);
674 
675 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr,
676 		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
677 		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
678 		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
679 		    dsize32,
680 		    asize32,
681 		    fileinfo->fi_dosattr,
682 		    namelen,
683 		    fileinfo->fi_name);
684 		break;
685 
686 	case SMB_INFO_QUERY_EA_SIZE:
687 		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
688 			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
689 			    fileinfo->fi_cookie);
690 
691 		/*
692 		 * Unicode filename should NOT be aligned. Encode ('u')
693 		 * into a temporary buffer, then encode buffer as a
694 		 * byte stream ('#c').
695 		 * Regardless of whether unicode or ascii, a single
696 		 * termination byte is used.
697 		 */
698 		buflen = namelen + sizeof (smb_wchar_t);
699 		tmpbuf = kmem_zalloc(buflen, KM_SLEEP);
700 		smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen, mb_flags);
701 		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_name) < 0) {
702 			smb_msgbuf_term(&mb);
703 			kmem_free(tmpbuf, buflen);
704 			return (-1);
705 		}
706 		tmpbuf[namelen] = '\0';
707 
708 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr,
709 		    smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
710 		    smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
711 		    smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
712 		    dsize32,
713 		    asize32,
714 		    fileinfo->fi_dosattr,
715 		    0L,		/* EA Size */
716 		    namelen,
717 		    namelen + 1,
718 		    tmpbuf);
719 
720 		smb_msgbuf_term(&mb);
721 		kmem_free(tmpbuf, buflen);
722 		break;
723 
724 	case SMB_FIND_FILE_DIRECTORY_INFO:
725 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqllu", sr,
726 		    next_entry_offset,
727 		    fileinfo->fi_cookie,
728 		    &fileinfo->fi_crtime,
729 		    &fileinfo->fi_atime,
730 		    &fileinfo->fi_mtime,
731 		    &fileinfo->fi_ctime,
732 		    fileinfo->fi_size,
733 		    fileinfo->fi_alloc_size,
734 		    fileinfo->fi_dosattr,
735 		    namelen,
736 		    fileinfo->fi_name);
737 		break;
738 
739 	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
740 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllu", sr,
741 		    next_entry_offset,
742 		    fileinfo->fi_cookie,
743 		    &fileinfo->fi_crtime,
744 		    &fileinfo->fi_atime,
745 		    &fileinfo->fi_mtime,
746 		    &fileinfo->fi_ctime,
747 		    fileinfo->fi_size,
748 		    fileinfo->fi_alloc_size,
749 		    fileinfo->fi_dosattr,
750 		    namelen,
751 		    0L,
752 		    fileinfo->fi_name);
753 		break;
754 
755 	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
756 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.qu", sr,
757 		    next_entry_offset,
758 		    fileinfo->fi_cookie,
759 		    &fileinfo->fi_crtime,
760 		    &fileinfo->fi_atime,
761 		    &fileinfo->fi_mtime,
762 		    &fileinfo->fi_ctime,
763 		    fileinfo->fi_size,
764 		    fileinfo->fi_alloc_size,
765 		    fileinfo->fi_dosattr,
766 		    namelen,
767 		    0L,
768 		    fileinfo->fi_nodeid,
769 		    fileinfo->fi_name);
770 		break;
771 
772 	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
773 		bzero(buf83, sizeof (buf83));
774 		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
775 		    mb_flags);
776 		if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) {
777 			smb_msgbuf_term(&mb);
778 			return (-1);
779 		}
780 		shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname);
781 
782 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24cu",
783 		    sr,
784 		    next_entry_offset,
785 		    fileinfo->fi_cookie,
786 		    &fileinfo->fi_crtime,
787 		    &fileinfo->fi_atime,
788 		    &fileinfo->fi_mtime,
789 		    &fileinfo->fi_ctime,
790 		    fileinfo->fi_size,
791 		    fileinfo->fi_alloc_size,
792 		    fileinfo->fi_dosattr,
793 		    namelen,
794 		    0L,
795 		    shortlen,
796 		    buf83,
797 		    fileinfo->fi_name);
798 
799 		smb_msgbuf_term(&mb);
800 		break;
801 
802 	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
803 		bzero(buf83, sizeof (buf83));
804 		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
805 		    mb_flags);
806 		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) {
807 			smb_msgbuf_term(&mb);
808 			return (-1);
809 		}
810 		shortlen = smb_ascii_or_unicode_strlen(sr,
811 		    fileinfo->fi_shortname);
812 
813 		(void) smb_mbc_encodef(&xa->rep_data_mb,
814 		    "%llTTTTqqlllb.24c2.qu",
815 		    sr,
816 		    next_entry_offset,
817 		    fileinfo->fi_cookie,
818 		    &fileinfo->fi_crtime,
819 		    &fileinfo->fi_atime,
820 		    &fileinfo->fi_mtime,
821 		    &fileinfo->fi_ctime,
822 		    fileinfo->fi_size,
823 		    fileinfo->fi_alloc_size,
824 		    fileinfo->fi_dosattr,
825 		    namelen,
826 		    0L,
827 		    shortlen,
828 		    buf83,
829 		    fileinfo->fi_nodeid,
830 		    fileinfo->fi_name);
831 
832 		smb_msgbuf_term(&mb);
833 		break;
834 
835 	case SMB_FIND_FILE_NAMES_INFO:
836 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr,
837 		    next_entry_offset,
838 		    fileinfo->fi_cookie,
839 		    namelen,
840 		    fileinfo->fi_name);
841 		break;
842 	}
843 
844 	return (0);
845 }
846 
847 /*
848  * Close a search started by a Trans2FindFirst2 request.
849  */
850 smb_sdrc_t
851 smb_pre_find_close2(smb_request_t *sr)
852 {
853 	DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr);
854 	return (SDRC_SUCCESS);
855 }
856 
857 void
858 smb_post_find_close2(smb_request_t *sr)
859 {
860 	DTRACE_SMB_1(op__FindClose2__done, smb_request_t *, sr);
861 }
862 
863 smb_sdrc_t
864 smb_com_find_close2(smb_request_t *sr)
865 {
866 	uint16_t	odid;
867 	smb_odir_t	*od;
868 
869 	if (smbsr_decode_vwv(sr, "w", &odid) != 0)
870 		return (SDRC_ERROR);
871 
872 	od = smb_tree_lookup_odir(sr->tid_tree, odid);
873 	if (od == NULL) {
874 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
875 		    ERRDOS, ERROR_INVALID_HANDLE);
876 		return (SDRC_ERROR);
877 	}
878 
879 	smb_odir_close(od);
880 	smb_odir_release(od);
881 
882 	if (smbsr_encode_empty_result(sr))
883 		return (SDRC_ERROR);
884 
885 	return (SDRC_SUCCESS);
886 }
887