xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c (revision 6e375c8351497b82ffa4f33cbf61d712999b4605)
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 2008 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_incl.h>
206 #include <smbsrv/msgbuf.h>
207 #include <smbsrv/smbtrans.h>
208 #include <smbsrv/smb_fsops.h>
209 
210 static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t);
211 
212 int smb_trans2_find_get_dents(smb_request_t *, smb_xa_t *,
213     uint16_t, uint16_t, int, smb_node_t *,
214     uint16_t, uint16_t, int, char *, uint32_t *, int *, int *);
215 
216 int smb_gather_dents_info(char *, ino_t, int, char *, uint32_t, int32_t *,
217     smb_attr_t *, smb_node_t *, char *, char *);
218 
219 int smb_trans2_find_process_ients(smb_request_t *, smb_xa_t *,
220     smb_dent_info_hdr_t *, uint16_t, uint16_t, int,
221     smb_node_t *, int *, uint32_t *);
222 
223 int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *,
224     smb_dent_info_t *, int, uint16_t, uint16_t,
225     uint32_t, smb_node_t *, smb_node_t *);
226 
227 /*
228  * The UNIX characters below are considered illegal in Windows file names.
229  * The following character conversions are used to support sites in which
230  * Catia v4 is in use on UNIX and Catia v5 is in use on Windows.
231  *
232  * ---------------------------
233  * Unix-char	| Windows-char
234  * ---------------------------
235  *   "		| (0x00a8) Diaeresis
236  *   *		| (0x00a4) Currency Sign
237  *   :		| (0x00f7) Division Sign
238  *   <		| (0x00ab) Left-Pointing Double Angle Quotation Mark
239  *   >		| (0x00bb) Right-Pointing Double Angle Quotation Mark
240  *   ?		| (0x00bf) Inverted Question mark
241  *   \		| (0x00ff) Latin Small Letter Y with Diaeresis
242  *   |		| (0x00a6) Broken Bar
243  */
244 static int (*catia_callback)(uint8_t *, uint8_t *, int) = NULL;
245 void smb_register_catia_callback(
246     int (*catia_v4tov5)(uint8_t *, uint8_t *, int));
247 void smb_unregister_catia_callback();
248 
249 /*
250  * Tunable parameter to limit the maximum
251  * number of entries to be returned.
252  */
253 uint16_t smb_trans2_find_max = 128;
254 
255 /*
256  * smb_register_catia_callback
257  *
258  * This function will be invoked by the catia module to register its
259  * function that translates filename in version 4 to a format that is
260  * compatible to version 5.
261  */
262 void
263 smb_register_catia_callback(
264     int (*catia_v4tov5)(uint8_t *, uint8_t *, int))
265 {
266 	catia_callback = catia_v4tov5;
267 }
268 
269 /*
270  * smb_unregister_catia_callback
271  *
272  * This function will unregister the catia callback prior to the catia
273  * module gets unloaded.
274  */
275 void
276 smb_unregister_catia_callback()
277 {
278 	catia_callback = 0;
279 }
280 
281 /*
282  * smb_com_trans2_find_first2
283  *
284  *  Client Request                Value
285  *  ============================  ==================================
286  *
287  *  UCHAR  WordCount              15
288  *  UCHAR  TotalDataCount         Total size of extended attribute list
289  *  UCHAR  SetupCount             1
290  *  UCHAR  Setup[0]               TRANS2_FIND_FIRST2
291  *
292  *  Parameter Block Encoding      Description
293  *  ============================  ==================================
294  *  USHORT SearchAttributes;
295  *  USHORT SearchCount;           Maximum number of entries to return
296  *  USHORT Flags;                 Additional information:
297  *                                Bit 0 - close search after this request
298  *                                Bit 1 - close search if end of search
299  *                                reached
300  *                                Bit 2 - return resume keys for each
301  *                                entry found
302  *                                Bit 3 - continue search from previous
303  *                                ending place
304  *                                Bit 4 - find with backup intent
305  *  USHORT InformationLevel;      See below
306  *  ULONG SearchStorageType;
307  *  STRING FileName;              Pattern for the search
308  *  UCHAR Data[ TotalDataCount ]  FEAList if InformationLevel is
309  *                                QUERY_EAS_FROM_LIST
310  *
311  *  Response Parameter Block      Description
312  *  ============================  ==================================
313  *
314  *  USHORT Sid;                   Search handle
315  *  USHORT SearchCount;           Number of entries returned
316  *  USHORT EndOfSearch;           Was last entry returned?
317  *  USHORT EaErrorOffset;         Offset into EA list if EA error
318  *  USHORT LastNameOffset;        Offset into data to file name of last
319  *                                entry, if server needs it to resume
320  *                                search; else 0
321  *  UCHAR Data[ TotalDataCount ]  Level dependent info about the matches
322  *                                found in the search
323  */
324 smb_sdrc_t
325 smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa)
326 {
327 	int		more = 0, rc;
328 	uint16_t	sattr, fflag, infolev;
329 	uint16_t	maxcount = 0;
330 	int		maxdata;
331 	int		count, wildcards;
332 	uint32_t	cookie;
333 	char		*path;
334 	smb_node_t	*dir_snode;
335 	char		*pattern;
336 	uint16_t	sid;
337 
338 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
339 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
340 		    ERRDOS, ERROR_ACCESS_DENIED);
341 		return (SDRC_ERROR);
342 	}
343 
344 	if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr,
345 	    &sattr, &maxcount, &fflag, &infolev, &path) != 0) {
346 		return (SDRC_ERROR);
347 	}
348 
349 	/*
350 	 * stream files not allowed
351 	 */
352 	if (smb_is_stream_name(path)) {
353 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
354 		    ERRDOS, ERROR_INVALID_NAME);
355 		return (SDRC_ERROR);
356 	}
357 
358 	if (fflag & SMB_FIND_WITH_BACKUP_INTENT)
359 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
360 
361 	maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag);
362 	if (maxdata == 0) {
363 		smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
364 		    ERRDOS, ERROR_INVALID_LEVEL);
365 		return (SDRC_ERROR);
366 	}
367 
368 	/*
369 	 * When maxcount is zero Windows behaves as if it was 1.
370 	 */
371 	if (maxcount == 0)
372 		maxcount = 1;
373 
374 	if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
375 		maxcount = smb_trans2_find_max;
376 
377 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
378 		(void) smb_convert_unicode_wildcards(path);
379 
380 	if (smb_rdir_open(sr, path, sattr) != 0)
381 		return (SDRC_ERROR);
382 
383 	/*
384 	 * Get a copy of information
385 	 */
386 	dir_snode = sr->sid_odir->d_dir_snode;
387 	pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP);
388 	(void) strcpy(pattern, sr->sid_odir->d_pattern);
389 
390 	if (strcmp(pattern, "*.*") == 0)
391 		(void) strncpy(pattern, "*", sizeof (pattern));
392 
393 	wildcards = sr->sid_odir->d_wildcards;
394 	sattr = sr->sid_odir->d_sattr;
395 	cookie = 0;
396 
397 	rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata,
398 	    dir_snode, sattr, maxcount, wildcards,
399 	    pattern, &cookie, &more, &count);
400 
401 	if (!count)
402 		rc = ENOENT;
403 
404 	if (rc) {
405 		smb_rdir_close(sr);
406 		kmem_free(pattern, MAXNAMELEN);
407 		smbsr_errno(sr, rc);
408 		return (SDRC_ERROR);
409 	}
410 
411 	/*
412 	 * Save the sid here in case the search is closed below,
413 	 * which will invalidate sr->smb_sid.  We return the
414 	 * sid, even though the search has been closed, to be
415 	 * compatible with Windows.
416 	 */
417 	sid = sr->smb_sid;
418 
419 	if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST ||
420 	    (!more && fflag & SMB_FIND_CLOSE_AT_EOS)) {
421 		smb_rdir_close(sr);
422 	} else {
423 		mutex_enter(&sr->sid_odir->d_mutex);
424 		sr->sid_odir->d_cookie = cookie;
425 		mutex_exit(&sr->sid_odir->d_mutex);
426 	}
427 
428 	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww",
429 	    sid, count, (more ? 0 : 1), 0, 0);
430 
431 	kmem_free(pattern, MAXNAMELEN);
432 	return (SDRC_SUCCESS);
433 }
434 
435 /*
436  * smb_com_trans2_find_next2
437  *
438  *  Client Request                     Value
439  *  ================================== =================================
440  *
441  *  WordCount                          15
442  *  SetupCount                         1
443  *  Setup[0]                           TRANS2_FIND_NEXT2
444  *
445  *  Parameter Block Encoding           Description
446  *  ================================== =================================
447  *
448  *  USHORT Sid;                        Search handle
449  *  USHORT SearchCount;                Maximum number of entries to
450  *                                      return
451  *  USHORT InformationLevel;           Levels described in
452  *                                      TRANS2_FIND_FIRST2 request
453  *  ULONG ResumeKey;                   Value returned by previous find2
454  *                                      call
455  *  USHORT Flags;                      Additional information: bit set-
456  *                                      0 - close search after this
457  *                                      request
458  *                                      1 - close search if end of search
459  *                                      reached
460  *                                      2 - return resume keys for each
461  *                                      entry found
462  *                                      3 - resume/continue from previous
463  *                                      ending place
464  *                                      4 - find with backup intent
465  *  STRING FileName;                   Resume file name
466  *
467  * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2
468  * call.  If Bit3 of Flags is set, then FileName may be the NULL string,
469  * since the search is continued from the previous TRANS2_FIND request.
470  * Otherwise, FileName must not be more than 256 characters long.
471  *
472  *  Response Field                     Description
473  *  ================================== =================================
474  *
475  *  USHORT SearchCount;                Number of entries returned
476  *  USHORT EndOfSearch;                Was last entry returned?
477  *  USHORT EaErrorOffset;              Offset into EA list if EA error
478  *  USHORT LastNameOffset;             Offset into data to file name of
479  *                                      last entry, if server needs it to
480  *                                      resume search; else 0
481  *  UCHAR Data[TotalDataCount]         Level dependent info about the
482  *                                      matches found in the search
483  *
484  *
485  * The last parameter in the request is a filename, which is a
486  * null-terminated unicode string.
487  *
488  * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr,
489  *    &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag, &fname)
490  *
491  * The filename parameter is not currently decoded because we a
492  * expect 2-byte null but Mac OS 10 clients send a 1-byte null,
493  * which leads to a decode error.
494  * Thus, we do not support resume by filename.  We treat a request
495  * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST.
496  */
497 smb_sdrc_t
498 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa)
499 {
500 	uint16_t fflag, infolev;
501 	int	maxdata, count, wildcards, more = 0, rc;
502 	uint32_t cookie;
503 	uint16_t maxcount = 0;
504 	smb_node_t *dir_snode;
505 	char *pattern;
506 	uint16_t sattr;
507 
508 	if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlw", sr,
509 	    &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag) != 0) {
510 		return (SDRC_ERROR);
511 	}
512 
513 	/* continuation by filename not supported */
514 	if (cookie == 0)
515 		fflag |= SMB_FIND_CONTINUE_FROM_LAST;
516 
517 	if (fflag & SMB_FIND_WITH_BACKUP_INTENT)
518 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
519 
520 	sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid);
521 	if (sr->sid_odir == NULL) {
522 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
523 		return (SDRC_ERROR);
524 	}
525 
526 	maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag);
527 	if (maxdata == 0) {
528 		smb_rdir_close(sr);
529 		smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
530 		    ERRDOS, ERROR_INVALID_LEVEL);
531 		return (SDRC_ERROR);
532 	}
533 
534 	/*
535 	 * When maxcount is zero Windows behaves as if it was 1.
536 	 */
537 	if (maxcount == 0)
538 		maxcount = 1;
539 
540 	if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
541 		maxcount = smb_trans2_find_max;
542 
543 	/*
544 	 * Get a copy of information
545 	 */
546 	dir_snode = sr->sid_odir->d_dir_snode;
547 	pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP);
548 	(void) strcpy(pattern, sr->sid_odir->d_pattern);
549 	wildcards = sr->sid_odir->d_wildcards;
550 	sattr = sr->sid_odir->d_sattr;
551 	if (fflag & SMB_FIND_CONTINUE_FROM_LAST) {
552 		mutex_enter(&sr->sid_odir->d_mutex);
553 		cookie = sr->sid_odir->d_cookie;
554 		mutex_exit(&sr->sid_odir->d_mutex);
555 	}
556 
557 	rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata,
558 	    dir_snode, sattr, maxcount, wildcards, pattern, &cookie,
559 	    &more, &count);
560 
561 	if (rc) {
562 		smb_rdir_close(sr);
563 		kmem_free(pattern, MAXNAMELEN);
564 		smbsr_errno(sr, rc);
565 		return (SDRC_ERROR);
566 	}
567 
568 	if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST ||
569 	    (!more && fflag & SMB_FIND_CLOSE_AT_EOS))
570 		smb_rdir_close(sr);
571 	else {
572 		mutex_enter(&sr->sid_odir->d_mutex);
573 		sr->sid_odir->d_cookie = cookie;
574 		mutex_exit(&sr->sid_odir->d_mutex);
575 	}
576 
577 	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww",
578 	    count, (more ? 0 : 1), 0, 0);
579 
580 	kmem_free(pattern, MAXNAMELEN);
581 	return (SDRC_SUCCESS);
582 }
583 
584 /*
585  * smb_trans2_find_get_maxdata
586  *
587  * Calculate the minimum response space required for the specified
588  * information level.
589  *
590  * A non-zero return value provides the minimum space required.
591  * A return value of zero indicates an unknown information level.
592  */
593 static int
594 smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag)
595 {
596 	int maxdata;
597 
598 	maxdata = smb_ascii_or_unicode_null_len(sr);
599 
600 	switch (infolev) {
601 	case SMB_INFO_STANDARD :
602 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
603 			maxdata += sizeof (int32_t);
604 		maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1;
605 		break;
606 
607 	case SMB_INFO_QUERY_EA_SIZE:
608 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
609 			maxdata += sizeof (int32_t);
610 		maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1;
611 		break;
612 
613 	case SMB_FIND_FILE_DIRECTORY_INFO:
614 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4;
615 		break;
616 
617 	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
618 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4;
619 		break;
620 
621 	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
622 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 8;
623 		break;
624 
625 	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
626 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24;
627 		break;
628 
629 	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
630 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24
631 		    + 2 + 8;
632 		break;
633 
634 	case SMB_FIND_FILE_NAMES_INFO:
635 		maxdata += 4 + 4 + 4;
636 		break;
637 
638 	case SMB_MAC_FIND_BOTH_HFS_INFO:
639 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 +
640 		    4 + 32 + 4 + 1 + 1 + 24 + 4;
641 		break;
642 
643 	default:
644 		maxdata = 0;
645 	}
646 
647 	return (maxdata);
648 }
649 
650 /*
651  * smb_trans2_find_get_dents
652  *
653  * This function will get all the directory entry information and mbc
654  * encode it in the xa. If there is an error, it will be returned;
655  * otherwise, 0 is returned.
656  *
657  * The more field will be updated. If the value returned is one, it means
658  * there are more entries; otherwise, the returned value will be zero. The
659  * cookie will also be updated to indicate the next start point for the
660  * search. The count value will also be updated to stores the total entries
661  * encoded.
662  */
663 int smb_trans2_find_get_dents(
664     smb_request_t	*sr,
665     smb_xa_t		*xa,
666     uint16_t		fflag,
667     uint16_t		infolev,
668     int			maxdata,
669     smb_node_t		*dir_snode,
670     uint16_t		sattr,
671     uint16_t		maxcount,
672     int			wildcards,
673     char		*pattern,
674     uint32_t		*cookie,
675     int			*more,
676     int			*count)
677 {
678 	smb_dent_info_hdr_t	*ihdr;
679 	smb_dent_info_t		*ient;
680 	int			dent_buf_size;
681 	int			i;
682 	int			total;
683 	int			maxentries;
684 	int			rc;
685 
686 	ihdr = kmem_zalloc(sizeof (smb_dent_info_hdr_t), KM_SLEEP);
687 	*count = 0;
688 
689 	if (!wildcards)
690 		maxentries = maxcount = 1;
691 	else {
692 		maxentries = (xa->rep_data_mb.max_bytes -
693 		    xa->rep_data_mb.chain_offset) / maxdata;
694 		if (maxcount > SMB_MAX_DENTS_IOVEC)
695 			maxcount = SMB_MAX_DENTS_IOVEC;
696 		if (maxentries > maxcount)
697 			maxentries = maxcount;
698 	}
699 
700 	/* Each entry will need to be aligned so add _POINTER_ALIGNMENT */
701 	dent_buf_size =
702 	    maxentries * (SMB_MAX_DENT_INFO_SIZE + _POINTER_ALIGNMENT);
703 	ihdr->iov->iov_base = kmem_alloc(dent_buf_size, KM_SLEEP);
704 
705 	ihdr->sattr = sattr;
706 	ihdr->pattern = pattern;
707 	ihdr->sr = sr;
708 
709 	ihdr->uio.uio_iovcnt = maxcount;
710 	ihdr->uio.uio_resid = dent_buf_size;
711 	ihdr->uio.uio_iov = ihdr->iov;
712 	ihdr->uio.uio_loffset = 0;
713 
714 	rc = smb_get_dents(sr, cookie, dir_snode, wildcards, ihdr, more);
715 	if (rc != 0) {
716 		goto out;
717 	}
718 
719 	if (ihdr->iov->iov_len == 0)
720 		*count = 0;
721 	else
722 		*count = smb_trans2_find_process_ients(sr, xa, ihdr, fflag,
723 		    infolev, maxdata, dir_snode, more, cookie);
724 	rc = 0;
725 
726 out:
727 
728 	total = maxcount - ihdr->uio.uio_iovcnt;
729 	ASSERT((total >= 0) && (total <= SMB_MAX_DENTS_IOVEC));
730 	for (i = 0; i < total; i++) {
731 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
732 		ient = (smb_dent_info_t *)ihdr->iov[i].iov_base;
733 		ASSERT(ient);
734 		smb_node_release(ient->snode);
735 	}
736 
737 	kmem_free(ihdr->iov->iov_base, dent_buf_size);
738 	kmem_free(ihdr, sizeof (smb_dent_info_hdr_t));
739 	return (0);
740 }
741 
742 
743 /*
744  * smb_get_dents
745  *
746  * This function utilizes "smb_fsop_getdents()" to get dir entries.
747  * The "smb_gather_dents_info()" is the call back function called
748  * inside the file system. It is very important that the function
749  * does not sleep or yield since it is processed inside a file
750  * system transaction.
751  *
752  * The function returns 0 when successful and error code when failed.
753  * If more is provided, the return value of 1 is returned indicating
754  * more entries; otherwise, 0 is returned.
755  */
756 int smb_get_dents(
757     smb_request_t	*sr,
758     uint32_t		*cookie,
759     smb_node_t		*dir_snode,
760     uint32_t		wildcards,
761     smb_dent_info_hdr_t	*ihdr,
762     int			*more)
763 {
764 	int		rc;
765 	char		*namebuf;
766 	smb_node_t	*snode;
767 	smb_attr_t	file_attr;
768 	uint32_t	maxcnt = ihdr->uio.uio_iovcnt;
769 	char		shortname[SMB_SHORTNAMELEN], name83[SMB_SHORTNAMELEN];
770 
771 	namebuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
772 	if (more)
773 		*more = 0;
774 
775 	if (!wildcards) {
776 		/* Already found entry? */
777 		if (*cookie != 0)
778 			return (0);
779 		shortname[0] = '\0';
780 
781 		rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
782 		    dir_snode, ihdr->pattern, &snode, &file_attr, shortname,
783 		    name83);
784 
785 		if (rc) {
786 			kmem_free(namebuf, MAXNAMELEN);
787 			return (rc);
788 		}
789 
790 		(void) strlcpy(namebuf, snode->od_name, MAXNAMELEN);
791 
792 		/*
793 		 * It is not necessary to set the "force" flag (i.e. to
794 		 * take into account mangling for case-insensitive collisions)
795 		 */
796 
797 		if (shortname[0] == '\0')
798 			(void) smb_mangle_name(snode->attr.sa_vattr.va_nodeid,
799 			    namebuf, shortname, name83, 0);
800 		(void) smb_gather_dents_info((char *)ihdr,
801 		    snode->attr.sa_vattr.va_nodeid,
802 		    strlen(namebuf), namebuf, -1, (int *)&maxcnt,
803 		    &snode->attr, snode, shortname, name83);
804 		kmem_free(namebuf, MAXNAMELEN);
805 		return (0);
806 	}
807 
808 	if ((rc = smb_fsop_getdents(sr, sr->user_cr, dir_snode, cookie,
809 	    0, (int *)&maxcnt, (char *)ihdr, ihdr->pattern)) != 0) {
810 		if (rc == ENOENT) {
811 			kmem_free(namebuf, MAXNAMELEN);
812 			return (0);
813 		}
814 		kmem_free(namebuf, MAXNAMELEN);
815 		return (rc);
816 	}
817 
818 	if (*cookie != 0x7FFFFFFF && more)
819 		*more = 1;
820 
821 	kmem_free(namebuf, MAXNAMELEN);
822 	return (0);
823 }
824 
825 
826 /*
827  * smb_gather_dents_info
828  *
829  * The function will accept information of each directory entry and put
830  * the needed information in the buffer. It is passed as the call back
831  * function for smb_fsop_getdents() to gather trans2 find info.
832  *
833  * Only valid entry will be stored in the buffer.
834  *
835  * Returns: -1 - error, buffer too small
836  *           n - number of valid entries (0 or 1)
837  */
838 int /*ARGSUSED*/
839 smb_gather_dents_info(
840     char	*args,
841 	ino_t	fileid,
842     int		namelen,
843     char	*name,
844     uint32_t	cookie,
845     int32_t	*countp,
846     smb_attr_t	*attr,
847     smb_node_t	*snode,
848     char	*shortname,
849     char	*name83)
850 {
851 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
852 	smb_dent_info_hdr_t	*ihdr = (smb_dent_info_hdr_t *)args;
853 	smb_dent_info_t		*ient;
854 	uint8_t			*v5_name = NULL;
855 	uint8_t			*np = (uint8_t *)name;
856 	int			reclen = sizeof (smb_dent_info_t) + namelen;
857 
858 	v5_name = kmem_alloc(MAXNAMELEN-1, KM_SLEEP);
859 
860 	if (!ihdr->uio.uio_iovcnt || ihdr->uio.uio_resid < reclen) {
861 		kmem_free(v5_name, MAXNAMELEN-1);
862 		smb_node_release(snode);
863 		return (-1);
864 	}
865 
866 	if (!smb_sattr_check(attr, name, ihdr->sattr)) {
867 		kmem_free(v5_name, MAXNAMELEN-1);
868 		smb_node_release(snode);
869 		return (0);
870 	}
871 
872 	if (catia_callback) {
873 		catia_callback(v5_name, (uint8_t *)name,  MAXNAMELEN-1);
874 		np = v5_name;
875 		reclen = sizeof (smb_dent_info_t) + strlen((char *)v5_name);
876 	}
877 
878 	ASSERT(snode);
879 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
880 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
881 
882 	/*
883 	 * Each entry needs to be properly aligned or we may get an alignment
884 	 * fault on sparc.
885 	 */
886 	ihdr->uio.uio_loffset = (offset_t)PTRALIGN(ihdr->uio.uio_loffset);
887 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
888 	ient = (smb_dent_info_t *)&ihdr->iov->iov_base[ihdr->uio.uio_loffset];
889 
890 	ient->cookie = cookie;
891 	ient->attr = *attr;
892 	ient->snode = snode;
893 
894 	(void) strcpy(ient->name, (char *)np);
895 	(void) strcpy(ient->shortname, shortname);
896 	(void) strcpy(ient->name83, name83);
897 	ihdr->uio.uio_iov->iov_base = (char *)ient;
898 	ihdr->uio.uio_iov->iov_len = reclen;
899 
900 	ihdr->uio.uio_iov++;
901 	ihdr->uio.uio_iovcnt--;
902 	ihdr->uio.uio_resid -= reclen;
903 	ihdr->uio.uio_loffset += reclen;
904 
905 	kmem_free(v5_name, MAXNAMELEN-1);
906 	return (1);
907 }
908 
909 
910 
911 /*
912  * smb_trans2_find_process_ients
913  *
914  * This function encodes the directory entry information store in
915  * the iov structure of the ihdr structure.
916  *
917  * The total entries encoded will be returned. If the entries encoded
918  * is less than the total entries in the iov, the more field will
919  * be updated to 1. Also, the next cookie wil be updated as well.
920  */
921 int
922 smb_trans2_find_process_ients(
923     smb_request_t	*sr,
924     smb_xa_t		*xa,
925     smb_dent_info_hdr_t	*ihdr,
926     uint16_t		fflag,
927     uint16_t		infolev,
928     int			maxdata,
929     smb_node_t		*dir_snode,
930     int			*more,
931     uint32_t		*cookie)
932 {
933 	int i, err = 0;
934 	smb_dent_info_t *ient;
935 	uint32_t mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
936 	    ? SMB_MSGBUF_UNICODE : 0;
937 
938 	for (i = 0; i < SMB_MAX_DENTS_IOVEC; i++) {
939 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
940 		if ((ient = (smb_dent_info_t *)ihdr->iov[i].iov_base) == 0)
941 			break;
942 
943 		/*
944 		 * Observed differences between our response and Windows
945 		 * response, which hasn't caused a problem yet!
946 		 *
947 		 * 1. The NextEntryOffset field for the last entry should
948 		 * be 0.  This code always calculate the record length
949 		 * and puts the result in the NextEntryOffset field.
950 		 *
951 		 * 2. The FileIndex field is always 0.  This code puts
952 		 * the cookie in the FileIndex field.
953 		 */
954 		err = smb_trans2_find_mbc_encode(sr, xa, ient, maxdata, infolev,
955 		    fflag, mb_flags, dir_snode, NULL);
956 
957 		if (err)
958 			break;
959 	}
960 
961 	/*
962 	 * Not enough space to store all the entries returned,
963 	 * which is indicated by setting more.
964 	 */
965 	if (more && err < 0) {
966 		*more = 1;
967 
968 		/*
969 		 * Assume the space will be at least enough for 1 entry.
970 		 */
971 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
972 		ient = (smb_dent_info_t *)ihdr->iov[i-1].iov_base;
973 		*cookie = ient->cookie;
974 	}
975 	return (i);
976 }
977 
978 /*
979  * smb_trans2_find_mbc_encode
980  *
981  * This function encodes the mbc for one directory entry.
982  *
983  * The function returns -1 when the max data requested by client
984  * is reached. If the entry is valid and successful encoded, 0
985  * will be returned; otherwise, 1 will be returned.
986  *
987  * We always null terminate the filename. The space for the null
988  * is included in the maxdata calculation and is therefore included
989  * in the next_entry_offset. namelen is the unterminated length of
990  * the filename. For levels except STANDARD and EA_SIZE, if the
991  * filename is ascii the name length returned to the client should
992  * include the null terminator. Otherwise the length returned to
993  * the client should not include the terminator.
994  */
995 int /*ARGSUSED*/
996 smb_trans2_find_mbc_encode(
997     smb_request_t	*sr,
998     smb_xa_t		*xa,
999     smb_dent_info_t	*ient,
1000     int			maxdata,
1001     uint16_t		infolev,
1002     uint16_t		fflag,
1003     uint32_t		mb_flags,
1004     smb_node_t		*dir_snode,
1005     smb_node_t		*sd_snode)
1006 {
1007 	int namelen, shortlen, buflen;
1008 	uint32_t next_entry_offset;
1009 	char buf83[26];
1010 	char *tmpbuf;
1011 	smb_msgbuf_t mb;
1012 	uint32_t dattr = 0;
1013 	uint32_t dsize32 = 0;
1014 	uint32_t asize32 = 0;
1015 	u_offset_t datasz = 0;
1016 	u_offset_t allocsz = 0;
1017 	smb_node_t *lnk_snode;
1018 	smb_attr_t lnkattr;
1019 	int rc;
1020 
1021 	namelen = smb_ascii_or_unicode_strlen(sr, ient->name);
1022 	if (namelen == -1)
1023 		return (1);
1024 
1025 	next_entry_offset = maxdata + namelen;
1026 
1027 	if (MBC_ROOM_FOR(&xa->rep_data_mb, (maxdata + namelen)) == 0)
1028 		return (-1);
1029 
1030 	/*
1031 	 * If ascii the filename length returned to the client should
1032 	 * include the null terminator for levels except STANDARD and
1033 	 * EASIZE.
1034 	 */
1035 	if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
1036 		if ((infolev != SMB_INFO_STANDARD) &&
1037 		    (infolev != SMB_INFO_QUERY_EA_SIZE))
1038 			namelen += 1;
1039 	}
1040 
1041 	if (ient->attr.sa_vattr.va_type == VLNK) {
1042 		rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
1043 		    sr->tid_tree->t_snode, dir_snode, ient->name, &lnk_snode,
1044 		    &lnkattr, 0, 0);
1045 
1046 		/*
1047 		 * We normally want to resolve the object to which a symlink
1048 		 * refers so that CIFS clients can access sub-directories and
1049 		 * find the correct association for files. This causes a
1050 		 * problem, however, if a symlink in a sub-directory points
1051 		 * to a parent directory (some UNIX GUI's create a symlink in
1052 		 * $HOME/.desktop that points to the user's home directory).
1053 		 * Some Windows applications (i.e. virus scanning) loop/hang
1054 		 * trying to follow this recursive path and there is little
1055 		 * we can do because the path is constructed on the client.
1056 		 * skc_dirsymlink_enable allows an end-user to disable
1057 		 * symlinks to directories. Symlinks to other object types
1058 		 * should be unaffected.
1059 		 */
1060 		if (rc == 0) {
1061 			if (smb_dirsymlink_enable ||
1062 			    (lnkattr.sa_vattr.va_type != VDIR)) {
1063 				smb_node_release(ient->snode);
1064 				ient->snode = lnk_snode;
1065 				ient->attr = lnkattr;
1066 			} else {
1067 				smb_node_release(lnk_snode);
1068 			}
1069 		}
1070 	}
1071 
1072 	if (infolev != SMB_FIND_FILE_NAMES_INFO) {
1073 		/* data size */
1074 		datasz = smb_node_get_size(ient->snode, &ient->attr);
1075 		dsize32 = (datasz > UINT_MAX) ? UINT_MAX : (uint32_t)datasz;
1076 
1077 		/* allocation size */
1078 		allocsz = ient->attr.sa_vattr.va_nblocks * DEV_BSIZE;
1079 		asize32 = (allocsz > UINT_MAX) ? UINT_MAX : (uint32_t)allocsz;
1080 
1081 		dattr = smb_node_get_dosattr(ient->snode);
1082 	}
1083 
1084 	switch (infolev) {
1085 	case SMB_INFO_STANDARD:
1086 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
1087 			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
1088 			    ient->cookie);
1089 
1090 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr,
1091 		    ient->attr.sa_crtime.tv_sec ?
1092 		    smb_gmt2local(sr, ient->attr.sa_crtime.tv_sec) :
1093 		    smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec),
1094 		    smb_gmt2local(sr, ient->attr.sa_vattr.va_atime.tv_sec),
1095 		    smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec),
1096 		    dsize32,
1097 		    asize32,
1098 		    dattr,
1099 		    namelen,
1100 		    ient->name);
1101 		break;
1102 
1103 	case SMB_INFO_QUERY_EA_SIZE:
1104 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
1105 			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
1106 			    ient->cookie);
1107 
1108 		/*
1109 		 * Unicode filename should NOT be aligned. Encode ('u')
1110 		 * into a temporary buffer, then encode buffer as a
1111 		 * byte stream ('#c').
1112 		 * Regardless of whether unicode or ascii, a single
1113 		 * termination byte is used.
1114 		 */
1115 		buflen = namelen + sizeof (mts_wchar_t);
1116 		tmpbuf = kmem_zalloc(buflen, KM_SLEEP);
1117 		smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen, mb_flags);
1118 		if (smb_msgbuf_encode(&mb, "u", ient->name) < 0) {
1119 			smb_msgbuf_term(&mb);
1120 			kmem_free(tmpbuf, buflen);
1121 			return (-1);
1122 		}
1123 		tmpbuf[namelen] = '\0';
1124 
1125 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr,
1126 		    ient->attr.sa_crtime.tv_sec ?
1127 		    smb_gmt2local(sr, ient->attr.sa_crtime.tv_sec) :
1128 		    smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec),
1129 		    smb_gmt2local(sr, ient->attr.sa_vattr.va_atime.tv_sec),
1130 		    smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec),
1131 		    dsize32,
1132 		    asize32,
1133 		    dattr,
1134 		    0L,		/* EA Size */
1135 		    namelen,
1136 		    namelen + 1,
1137 		    tmpbuf);
1138 
1139 		smb_msgbuf_term(&mb);
1140 		kmem_free(tmpbuf, buflen);
1141 		break;
1142 
1143 	case SMB_FIND_FILE_DIRECTORY_INFO:
1144 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqllu", sr,
1145 		    next_entry_offset,
1146 		    ient->cookie,
1147 		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
1148 		    &ient->attr.sa_vattr.va_mtime,
1149 		    &ient->attr.sa_vattr.va_atime,
1150 		    &ient->attr.sa_vattr.va_mtime,
1151 		    &ient->attr.sa_vattr.va_ctime,
1152 		    (uint64_t)datasz,
1153 		    (uint64_t)allocsz,
1154 		    dattr,
1155 		    namelen,
1156 		    ient->name);
1157 		break;
1158 
1159 	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
1160 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllu", sr,
1161 		    next_entry_offset,
1162 		    ient->cookie,
1163 		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
1164 		    &ient->attr.sa_vattr.va_mtime,
1165 		    &ient->attr.sa_vattr.va_atime,
1166 		    &ient->attr.sa_vattr.va_mtime,
1167 		    &ient->attr.sa_vattr.va_ctime,
1168 		    (uint64_t)datasz,
1169 		    (uint64_t)allocsz,
1170 		    dattr,
1171 		    namelen,
1172 		    0L,
1173 		    ient->name);
1174 		break;
1175 
1176 	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
1177 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.qu", sr,
1178 		    next_entry_offset,
1179 		    ient->cookie,
1180 		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
1181 		    &ient->attr.sa_vattr.va_mtime,
1182 		    &ient->attr.sa_vattr.va_atime,
1183 		    &ient->attr.sa_vattr.va_mtime,
1184 		    &ient->attr.sa_vattr.va_ctime,
1185 		    (uint64_t)datasz,
1186 		    (uint64_t)allocsz,
1187 		    dattr,
1188 		    namelen,
1189 		    0L,
1190 		    ient->attr.sa_vattr.va_nodeid,
1191 		    ient->name);
1192 		break;
1193 
1194 	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
1195 		bzero(buf83, sizeof (buf83));
1196 		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
1197 		    mb_flags);
1198 		if (smb_msgbuf_encode(&mb, "U", ient->shortname) < 0) {
1199 			smb_msgbuf_term(&mb);
1200 			return (-1);
1201 		}
1202 		shortlen = mts_wcequiv_strlen(ient->shortname);
1203 
1204 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24cu",
1205 		    sr,
1206 		    next_entry_offset,
1207 		    ient->cookie,
1208 		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
1209 		    &ient->attr.sa_vattr.va_mtime,
1210 		    &ient->attr.sa_vattr.va_atime,
1211 		    &ient->attr.sa_vattr.va_mtime,
1212 		    &ient->attr.sa_vattr.va_ctime,
1213 		    (uint64_t)datasz,
1214 		    (uint64_t)allocsz,
1215 		    dattr,
1216 		    namelen,
1217 		    0L,
1218 		    shortlen,
1219 		    buf83,
1220 		    ient->name);
1221 
1222 		smb_msgbuf_term(&mb);
1223 		break;
1224 
1225 	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
1226 		bzero(buf83, sizeof (buf83));
1227 		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
1228 		    mb_flags);
1229 		if (smb_msgbuf_encode(&mb, "u", ient->shortname) < 0) {
1230 			smb_msgbuf_term(&mb);
1231 			return (-1);
1232 		}
1233 		shortlen = smb_ascii_or_unicode_strlen(sr, ient->shortname);
1234 
1235 		(void) smb_mbc_encodef(&xa->rep_data_mb,
1236 		    "%llTTTTqqlllb.24c2.qu",
1237 		    sr,
1238 		    next_entry_offset,
1239 		    ient->cookie,
1240 		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
1241 		    &ient->attr.sa_vattr.va_mtime,
1242 		    &ient->attr.sa_vattr.va_atime,
1243 		    &ient->attr.sa_vattr.va_mtime,
1244 		    &ient->attr.sa_vattr.va_ctime,
1245 		    (uint64_t)datasz,
1246 		    (uint64_t)allocsz,
1247 		    dattr,
1248 		    namelen,
1249 		    0L,
1250 		    shortlen,
1251 		    buf83,
1252 		    ient->attr.sa_vattr.va_nodeid,
1253 		    ient->name);
1254 
1255 		smb_msgbuf_term(&mb);
1256 		break;
1257 
1258 	case SMB_FIND_FILE_NAMES_INFO:
1259 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr,
1260 		    next_entry_offset,
1261 		    ient->cookie,
1262 		    namelen,
1263 		    ient->name);
1264 		break;
1265 	}
1266 
1267 	return (0);
1268 }
1269 
1270 /*
1271  * Close a search started by a Trans2FindFirst2 request.
1272  */
1273 smb_sdrc_t
1274 smb_pre_find_close2(smb_request_t *sr)
1275 {
1276 	int rc;
1277 
1278 	rc = smbsr_decode_vwv(sr, "w", &sr->smb_sid);
1279 
1280 	DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr);
1281 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1282 }
1283 
1284 void
1285 smb_post_find_close2(smb_request_t *sr)
1286 {
1287 	DTRACE_SMB_1(op__FindClose2__done, smb_request_t *, sr);
1288 }
1289 
1290 smb_sdrc_t
1291 smb_com_find_close2(smb_request_t *sr)
1292 {
1293 	sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid);
1294 	if (sr->sid_odir == NULL) {
1295 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
1296 		return (SDRC_ERROR);
1297 	}
1298 
1299 	smb_rdir_close(sr);
1300 
1301 	if (smbsr_encode_empty_result(sr))
1302 		return (SDRC_ERROR);
1303 
1304 	return (SDRC_SUCCESS);
1305 }
1306