xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c (revision dc20a3024900c47dd2ee44b9707e6df38f7d62a5)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22*dc20a302Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27da6c28aaSamw 
28da6c28aaSamw /*
29da6c28aaSamw  * This module provides functions for TRANS2_FIND_FIRST2 and
30da6c28aaSamw  * TRANS2_FIND_NEXT2 requests. The requests allow the client to search
31da6c28aaSamw  * for the file(s) which match the file specification.  The search is
32da6c28aaSamw  * started with TRANS2_FIND_FIRST2 and can be continued if necessary with
33da6c28aaSamw  * TRANS2_FIND_NEXT2. There are numerous levels of information which may be
34da6c28aaSamw  * obtained for the returned files, the desired level is specified in the
35da6c28aaSamw  * InformationLevel field of the requests.
36da6c28aaSamw  *
37da6c28aaSamw  *  InformationLevel Name              Value
38da6c28aaSamw  *  =================================  ================
39da6c28aaSamw  *
40da6c28aaSamw  *  SMB_INFO_STANDARD                  1
41da6c28aaSamw  *  SMB_INFO_QUERY_EA_SIZE             2
42da6c28aaSamw  *  SMB_INFO_QUERY_EAS_FROM_LIST       3
43da6c28aaSamw  *  SMB_FIND_FILE_DIRECTORY_INFO       0x101
44da6c28aaSamw  *  SMB_FIND_FILE_FULL_DIRECTORY_INFO  0x102
45da6c28aaSamw  *  SMB_FIND_FILE_NAMES_INFO           0x103
46da6c28aaSamw  *  SMB_FIND_FILE_BOTH_DIRECTORY_INFO  0x104
47da6c28aaSamw  *
48da6c28aaSamw  * The following sections detail the data returned for each
49da6c28aaSamw  * InformationLevel. The requested information is placed in the Data
50da6c28aaSamw  * portion of the transaction response. Note: a client which does not
51da6c28aaSamw  * support long names can only request SMB_INFO_STANDARD.
52da6c28aaSamw  *
53da6c28aaSamw  * A four-byte resume key precedes each data item (described below) if bit
54da6c28aaSamw  * 2 in the Flags field is set, i.e. if the request indicates the server
55da6c28aaSamw  * should return resume keys. Note: it is not always the case. If the
56da6c28aaSamw  * data item already includes the resume key, the resume key should not be
57da6c28aaSamw  * added again.
58da6c28aaSamw  *
59da6c28aaSamw  * 4.3.4.1   SMB_INFO_STANDARD
60da6c28aaSamw  *
61da6c28aaSamw  *  Response Field                    Description
62da6c28aaSamw  *  ================================  ==================================
63da6c28aaSamw  *
64da6c28aaSamw  *  SMB_DATE CreationDate;            Date when file was created
65da6c28aaSamw  *  SMB_TIME CreationTime;            Time when file was created
66da6c28aaSamw  *  SMB_DATE LastAccessDate;          Date of last file access
67da6c28aaSamw  *  SMB_TIME LastAccessTime;          Time of last file access
68da6c28aaSamw  *  SMB_DATE LastWriteDate;           Date of last write to the file
69da6c28aaSamw  *  SMB_TIME LastWriteTime;           Time of last write to the file
70da6c28aaSamw  *  ULONG  DataSize;                  File Size
71da6c28aaSamw  *  ULONG AllocationSize;             Size of filesystem allocation unit
72da6c28aaSamw  *  USHORT Attributes;                File Attributes
73da6c28aaSamw  *  UCHAR FileNameLength;             Length of filename in bytes
74da6c28aaSamw  *  STRING FileName;                  Name of found file
75da6c28aaSamw  *
76da6c28aaSamw  * 4.3.4.2   SMB_INFO_QUERY_EA_SIZE
77da6c28aaSamw  *
78da6c28aaSamw  *  Response Field                     Description
79da6c28aaSamw  *  =================================  ==================================
80da6c28aaSamw  *
81da6c28aaSamw  *   SMB_DATE CreationDate;            Date when file was created
82da6c28aaSamw  *   SMB_TIME CreationTime;            Time when file was created
83da6c28aaSamw  *   SMB_DATE LastAccessDate;          Date of last file access
84da6c28aaSamw  *   SMB_TIME LastAccessTime;          Time of last file access
85da6c28aaSamw  *   SMB_DATE LastWriteDate;           Date of last write to the file
86da6c28aaSamw  *   SMB_TIME LastWriteTime;           Time of last write to the file
87da6c28aaSamw  *   ULONG DataSize;                   File Size
88da6c28aaSamw  *   ULONG AllocationSize;             Size of filesystem allocation unit
89da6c28aaSamw  *   USHORT Attributes;                File Attributes
90da6c28aaSamw  *   ULONG EaSize;                     Size of file's EA information
91da6c28aaSamw  *   UCHAR FileNameLength;             Length of filename in bytes
92da6c28aaSamw  *   STRING FileName;                  Name of found file
93da6c28aaSamw  *
94da6c28aaSamw  * 4.3.4.3   SMB_INFO_QUERY_EAS_FROM_LIST
95da6c28aaSamw  *
96da6c28aaSamw  * This request returns the same information as SMB_INFO_QUERY_EA_SIZE, but
97da6c28aaSamw  * only for files which have an EA list which match the EA information in
98da6c28aaSamw  * the Data part of the request.
99da6c28aaSamw  *
100da6c28aaSamw  * 4.3.4.4   SMB_FIND_FILE_DIRECTORY_INFO
101da6c28aaSamw  *
102da6c28aaSamw  *  Response Field                     Description
103da6c28aaSamw  *  =================================  ==================================
104da6c28aaSamw  *
105da6c28aaSamw  *  ULONG NextEntryOffset;             Offset from this structure to
106da6c28aaSamw  *					beginning of next one
107da6c28aaSamw  *  ULONG FileIndex;
108da6c28aaSamw  *  LARGE_INTEGER CreationTime;        file creation time
109da6c28aaSamw  *  LARGE_INTEGER LastAccessTime;      last access time
110da6c28aaSamw  *  LARGE_INTEGER LastWriteTime;       last write time
111da6c28aaSamw  *  LARGE_INTEGER ChangeTime;          last attribute change time
112da6c28aaSamw  *  LARGE_INTEGER EndOfFile;           file size
113da6c28aaSamw  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
114da6c28aaSamw  *  ULONG ExtFileAttributes;           Extended file attributes
115da6c28aaSamw  *					(see section 3.11)
116da6c28aaSamw  *  ULONG FileNameLength;              Length of filename in bytes
117da6c28aaSamw  *  STRING FileName;                   Name of the file
118da6c28aaSamw  *
119da6c28aaSamw  * 4.3.4.5   SMB_FIND_FILE_FULL_DIRECTORY_INFO
120da6c28aaSamw  *
121da6c28aaSamw  *  Response Field                     Description
122da6c28aaSamw  *  =================================  ==================================
123da6c28aaSamw  *
124da6c28aaSamw  *  ULONG NextEntryOffset;             Offset from this structure to
125da6c28aaSamw  *					beginning of next one
126da6c28aaSamw  *  ULONG FileIndex;
127da6c28aaSamw  *  LARGE_INTEGER CreationTime;        file creation time
128da6c28aaSamw  *  LARGE_INTEGER LastAccessTime;      last access time
129da6c28aaSamw  *  LARGE_INTEGER LastWriteTime;       last write time
130da6c28aaSamw  *  LARGE_INTEGER ChangeTime;          last attribute change time
131da6c28aaSamw  *  LARGE_INTEGER EndOfFile;           file size
132da6c28aaSamw  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
133da6c28aaSamw  *  ULONG ExtFileAttributes;           Extended file attributes
134da6c28aaSamw  *					(see section 3.11)
135da6c28aaSamw  *  ULONG FileNameLength;              Length of filename in bytes
136da6c28aaSamw  *  ULONG EaSize;                      Size of file's extended attributes
137da6c28aaSamw  *  STRING FileName;                   Name of the file
138da6c28aaSamw  *
139da6c28aaSamw  * 4.3.4.6   SMB_FIND_FILE_BOTH_DIRECTORY_INFO
140da6c28aaSamw  *
141da6c28aaSamw  *  Response Field                     Description
142da6c28aaSamw  *  =================================  ==================================
143da6c28aaSamw  *
144da6c28aaSamw  *  ULONG NextEntryOffset;             Offset from this structure to
145da6c28aaSamw  *					beginning of next one
146da6c28aaSamw  *  ULONG FileIndex;
147da6c28aaSamw  *  LARGE_INTEGER CreationTime;        file creation time
148da6c28aaSamw  *  LARGE_INTEGER LastAccessTime;      last access time
149da6c28aaSamw  *  LARGE_INTEGER LastWriteTime;       last write time
150da6c28aaSamw  *  LARGE_INTEGER ChangeTime;          last attribute change time
151da6c28aaSamw  *  LARGE_INTEGER EndOfFile;           file size
152da6c28aaSamw  *  LARGE_INTEGER AllocationSize;      size of filesystem allocation information
153da6c28aaSamw  *  ULONG ExtFileAttributes;           Extended file attributes
154da6c28aaSamw  *					(see section 3.11)
155da6c28aaSamw  *  ULONG FileNameLength;              Length of FileName in bytes
156da6c28aaSamw  *  ULONG EaSize;                      Size of file's extended attributes
157da6c28aaSamw  *  UCHAR ShortNameLength;             Length of file's short name in bytes
158da6c28aaSamw  *  UCHAR Reserved
159da6c28aaSamw  *  WCHAR ShortName[12];               File's 8.3 conformant name in Unicode
160da6c28aaSamw  *  STRING FileName;                   Files full length name
161da6c28aaSamw  *
162da6c28aaSamw  * 4.3.4.7   SMB_FIND_FILE_NAMES_INFO
163da6c28aaSamw  *
164da6c28aaSamw  *  Response Field                     Description
165da6c28aaSamw  *  =================================  ==================================
166da6c28aaSamw  *
167da6c28aaSamw  *  ULONG NextEntryOffset;             Offset from this structure to
168da6c28aaSamw  *                                     beginning of next one
169da6c28aaSamw  *  ULONG FileIndex;
170da6c28aaSamw  *  ULONG FileNameLength;              Length of FileName in bytes
171da6c28aaSamw  *  STRING FileName;                   Files full length name
172da6c28aaSamw  */
173da6c28aaSamw 
174da6c28aaSamw #include <smbsrv/smb_incl.h>
175da6c28aaSamw #include <smbsrv/msgbuf.h>
176da6c28aaSamw #include <smbsrv/smbtrans.h>
177da6c28aaSamw #include <smbsrv/smb_fsops.h>
178da6c28aaSamw 
179*dc20a302Sas200622 static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t);
180da6c28aaSamw 
181*dc20a302Sas200622 int smb_trans2_find_get_dents(smb_request_t *, smb_xa_t *,
182*dc20a302Sas200622     uint16_t, uint16_t, int, smb_node_t *,
183*dc20a302Sas200622     uint16_t, uint16_t, int, char *, uint32_t *, int *, int *);
184da6c28aaSamw 
185da6c28aaSamw int smb_gather_dents_info(char *, ino_t, int, char *, uint32_t, int32_t *,
186*dc20a302Sas200622     smb_attr_t *, smb_node_t *, char *, char *);
187da6c28aaSamw 
188*dc20a302Sas200622 int smb_trans2_find_process_ients(smb_request_t *, smb_xa_t *,
189*dc20a302Sas200622     smb_dent_info_hdr_t *, uint16_t, uint16_t, int,
190*dc20a302Sas200622     smb_node_t *, int *, uint32_t *);
191da6c28aaSamw 
192*dc20a302Sas200622 int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *,
193*dc20a302Sas200622     smb_dent_info_t *, int, uint16_t, uint16_t,
194*dc20a302Sas200622     uint32_t, smb_node_t *, smb_node_t *);
195da6c28aaSamw 
196da6c28aaSamw /*
197*dc20a302Sas200622  * The UNIX characters below are considered illegal in Windows file names.
198*dc20a302Sas200622  * The following character conversions are used to support sites in which
199*dc20a302Sas200622  * Catia v4 is in use on UNIX and Catia v5 is in use on Windows.
200*dc20a302Sas200622  *
201*dc20a302Sas200622  * ---------------------------
202*dc20a302Sas200622  * Unix-char	| Windows-char
203*dc20a302Sas200622  * ---------------------------
204*dc20a302Sas200622  *   "		| (0x00a8) Diaeresis
205*dc20a302Sas200622  *   *		| (0x00a4) Currency Sign
206*dc20a302Sas200622  *   :		| (0x00f7) Division Sign
207*dc20a302Sas200622  *   <		| (0x00ab) Left-Pointing Double Angle Quotation Mark
208*dc20a302Sas200622  *   >		| (0x00bb) Right-Pointing Double Angle Quotation Mark
209*dc20a302Sas200622  *   ?		| (0x00bf) Inverted Question mark
210*dc20a302Sas200622  *   \		| (0x00ff) Latin Small Letter Y with Diaeresis
211*dc20a302Sas200622  *   |		| (0x00a6) Broken Bar
212da6c28aaSamw  */
213*dc20a302Sas200622 static int (*catia_callback)(uint8_t *, uint8_t *, int) = NULL;
214da6c28aaSamw void smb_register_catia_callback(
215*dc20a302Sas200622     int (*catia_v4tov5)(uint8_t *, uint8_t *, int));
216da6c28aaSamw void smb_unregister_catia_callback();
217da6c28aaSamw 
218da6c28aaSamw /*
219*dc20a302Sas200622  * Tunable parameter to limit the maximum
220*dc20a302Sas200622  * number of entries to be returned.
221da6c28aaSamw  */
222*dc20a302Sas200622 uint16_t smb_trans2_find_max = 128;
223da6c28aaSamw 
224da6c28aaSamw /*
225da6c28aaSamw  * smb_register_catia_callback
226da6c28aaSamw  *
227da6c28aaSamw  * This function will be invoked by the catia module to register its
228da6c28aaSamw  * function that translates filename in version 4 to a format that is
229da6c28aaSamw  * compatible to version 5.
230da6c28aaSamw  */
231da6c28aaSamw void
232da6c28aaSamw smb_register_catia_callback(
233*dc20a302Sas200622     int (*catia_v4tov5)(uint8_t *, uint8_t *, int))
234da6c28aaSamw {
235da6c28aaSamw 	catia_callback = catia_v4tov5;
236da6c28aaSamw }
237da6c28aaSamw 
238da6c28aaSamw /*
239da6c28aaSamw  * smb_unregister_catia_callback
240da6c28aaSamw  *
241da6c28aaSamw  * This function will unregister the catia callback prior to the catia
242da6c28aaSamw  * module gets unloaded.
243da6c28aaSamw  */
244da6c28aaSamw void
245da6c28aaSamw smb_unregister_catia_callback()
246da6c28aaSamw {
247da6c28aaSamw 	catia_callback = 0;
248da6c28aaSamw }
249da6c28aaSamw 
250da6c28aaSamw /*
251da6c28aaSamw  * smb_com_trans2_find_first2
252da6c28aaSamw  *
253da6c28aaSamw  *  Client Request                Value
254da6c28aaSamw  *  ============================  ==================================
255da6c28aaSamw  *
256da6c28aaSamw  *  UCHAR  WordCount              15
257da6c28aaSamw  *  UCHAR  TotalDataCount         Total size of extended attribute list
258da6c28aaSamw  *  UCHAR  SetupCount             1
259da6c28aaSamw  *  UCHAR  Setup[0]               TRANS2_FIND_FIRST2
260da6c28aaSamw  *
261da6c28aaSamw  *  Parameter Block Encoding      Description
262da6c28aaSamw  *  ============================  ==================================
263da6c28aaSamw  *  USHORT SearchAttributes;
264da6c28aaSamw  *  USHORT SearchCount;           Maximum number of entries to return
265da6c28aaSamw  *  USHORT Flags;                 Additional information:
266da6c28aaSamw  *                                Bit 0 - close search after this request
267da6c28aaSamw  *                                Bit 1 - close search if end of search
268da6c28aaSamw  *                                reached
269da6c28aaSamw  *                                Bit 2 - return resume keys for each
270da6c28aaSamw  *                                entry found
271da6c28aaSamw  *                                Bit 3 - continue search from previous
272da6c28aaSamw  *                                ending place
273da6c28aaSamw  *                                Bit 4 - find with backup intent
274da6c28aaSamw  *  USHORT InformationLevel;      See below
275da6c28aaSamw  *  ULONG SearchStorageType;
276da6c28aaSamw  *  STRING FileName;              Pattern for the search
277da6c28aaSamw  *  UCHAR Data[ TotalDataCount ]  FEAList if InformationLevel is
278da6c28aaSamw  *                                QUERY_EAS_FROM_LIST
279da6c28aaSamw  *
280da6c28aaSamw  *  Response Parameter Block      Description
281da6c28aaSamw  *  ============================  ==================================
282da6c28aaSamw  *
283da6c28aaSamw  *  USHORT Sid;                   Search handle
284da6c28aaSamw  *  USHORT SearchCount;           Number of entries returned
285da6c28aaSamw  *  USHORT EndOfSearch;           Was last entry returned?
286da6c28aaSamw  *  USHORT EaErrorOffset;         Offset into EA list if EA error
287da6c28aaSamw  *  USHORT LastNameOffset;        Offset into data to file name of last
288da6c28aaSamw  *                                entry, if server needs it to resume
289da6c28aaSamw  *                                search; else 0
290da6c28aaSamw  *  UCHAR Data[ TotalDataCount ]  Level dependent info about the matches
291da6c28aaSamw  *                                found in the search
292da6c28aaSamw  */
293da6c28aaSamw int
294*dc20a302Sas200622 smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa)
295da6c28aaSamw {
296da6c28aaSamw 	int		more = 0, rc;
297*dc20a302Sas200622 	uint16_t	sattr, fflag, infolev;
298*dc20a302Sas200622 	uint16_t	maxcount = 0;
299da6c28aaSamw 	int		maxdata;
300*dc20a302Sas200622 	int		count, wildcards;
301da6c28aaSamw 	uint32_t	cookie;
302da6c28aaSamw 	char		*path;
303*dc20a302Sas200622 	smb_node_t	*dir_snode;
304da6c28aaSamw 	char		*pattern;
305*dc20a302Sas200622 	uint16_t	sid;
306da6c28aaSamw 
307da6c28aaSamw 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
308*dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
309da6c28aaSamw 		    ERRDOS, ERROR_ACCESS_DENIED);
310da6c28aaSamw 		/* NOTREACHED */
311da6c28aaSamw 	}
312da6c28aaSamw 
313da6c28aaSamw 	if (smb_decode_mbc(&xa->req_param_mb, "%wwww4.u", sr,
314da6c28aaSamw 	    &sattr, &maxcount, &fflag, &infolev, &path) != 0) {
315da6c28aaSamw 		smbsr_decode_error(sr);
316da6c28aaSamw 		/* NOTREACHED */
317da6c28aaSamw 	}
318da6c28aaSamw 
319da6c28aaSamw 	maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag);
320da6c28aaSamw 	if (maxdata == 0) {
321*dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
322*dc20a302Sas200622 		    ERRDOS, ERROR_INVALID_LEVEL);
323da6c28aaSamw 		/* NOTREACHED */
324da6c28aaSamw 	}
325da6c28aaSamw 
326*dc20a302Sas200622 	/*
327*dc20a302Sas200622 	 * When maxcount is zero Windows behaves as if it was 1.
328*dc20a302Sas200622 	 */
329*dc20a302Sas200622 	if (maxcount == 0)
330*dc20a302Sas200622 		maxcount = 1;
331*dc20a302Sas200622 
332*dc20a302Sas200622 	if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
333*dc20a302Sas200622 		maxcount = smb_trans2_find_max;
334*dc20a302Sas200622 
335*dc20a302Sas200622 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
336da6c28aaSamw 		(void) smb_convert_unicode_wildcards(path);
337*dc20a302Sas200622 
338da6c28aaSamw 	(void) smb_rdir_open(sr, path, sattr);
339da6c28aaSamw 
340da6c28aaSamw 	/*
341da6c28aaSamw 	 * Get a copy of information
342da6c28aaSamw 	 */
343da6c28aaSamw 	dir_snode = sr->sid_odir->d_dir_snode;
344*dc20a302Sas200622 	pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP);
345da6c28aaSamw 	(void) strcpy(pattern, sr->sid_odir->d_pattern);
346*dc20a302Sas200622 
347da6c28aaSamw 	if (strcmp(pattern, "*.*") == 0)
348da6c28aaSamw 		(void) strncpy(pattern, "*", sizeof (pattern));
349*dc20a302Sas200622 
350da6c28aaSamw 	wildcards = sr->sid_odir->d_wildcards;
351da6c28aaSamw 	sattr = sr->sid_odir->d_sattr;
352da6c28aaSamw 	cookie = 0;
353da6c28aaSamw 
354da6c28aaSamw 	rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata,
355da6c28aaSamw 	    dir_snode, sattr, maxcount, wildcards,
356da6c28aaSamw 	    pattern, &cookie, &more, &count);
357da6c28aaSamw 
358da6c28aaSamw 	if (!count)
359da6c28aaSamw 		rc = ENOENT;
360da6c28aaSamw 
361da6c28aaSamw 	if (rc) {
362da6c28aaSamw 		smb_rdir_close(sr);
363da6c28aaSamw 		kmem_free(pattern, MAXNAMELEN);
364*dc20a302Sas200622 		smbsr_errno(sr, rc);
365da6c28aaSamw 		/* NOTREACHED */
366da6c28aaSamw 	}
367da6c28aaSamw 
368da6c28aaSamw 	/*
369*dc20a302Sas200622 	 * Save the sid here in case the search is closed below,
370*dc20a302Sas200622 	 * which will invalidate sr->smb_sid.  We return the
371*dc20a302Sas200622 	 * sid, even though the search has been closed, to be
372*dc20a302Sas200622 	 * compatible with Windows.
373da6c28aaSamw 	 */
374da6c28aaSamw 	sid = sr->smb_sid;
375da6c28aaSamw 
376da6c28aaSamw 	if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST ||
377*dc20a302Sas200622 	    (!more && fflag & SMB_FIND_CLOSE_AT_EOS)) {
378da6c28aaSamw 		smb_rdir_close(sr);
379*dc20a302Sas200622 	} else {
380da6c28aaSamw 		mutex_enter(&sr->sid_odir->d_mutex);
381da6c28aaSamw 		sr->sid_odir->d_cookie = cookie;
382da6c28aaSamw 		mutex_exit(&sr->sid_odir->d_mutex);
383da6c28aaSamw 	}
384da6c28aaSamw 
385da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_param_mb, "wwwww",
386da6c28aaSamw 	    sid, count, (more ? 0 : 1), 0, 0);
387da6c28aaSamw 
388da6c28aaSamw 	kmem_free(pattern, MAXNAMELEN);
389da6c28aaSamw 	return (SDRC_NORMAL_REPLY);
390da6c28aaSamw }
391da6c28aaSamw 
392da6c28aaSamw /*
393da6c28aaSamw  * smb_com_trans2_find_next2
394da6c28aaSamw  *
395da6c28aaSamw  *  Client Request                     Value
396da6c28aaSamw  *  ================================== =================================
397da6c28aaSamw  *
398da6c28aaSamw  *  WordCount                          15
399da6c28aaSamw  *  SetupCount                         1
400da6c28aaSamw  *  Setup[0]                           TRANS2_FIND_NEXT2
401da6c28aaSamw  *
402da6c28aaSamw  *  Parameter Block Encoding           Description
403da6c28aaSamw  *  ================================== =================================
404da6c28aaSamw  *
405da6c28aaSamw  *  USHORT Sid;                        Search handle
406da6c28aaSamw  *  USHORT SearchCount;                Maximum number of entries to
407da6c28aaSamw  *                                      return
408da6c28aaSamw  *  USHORT InformationLevel;           Levels described in
409da6c28aaSamw  *                                      TRANS2_FIND_FIRST2 request
410da6c28aaSamw  *  ULONG ResumeKey;                   Value returned by previous find2
411da6c28aaSamw  *                                      call
412da6c28aaSamw  *  USHORT Flags;                      Additional information: bit set-
413da6c28aaSamw  *                                      0 - close search after this
414da6c28aaSamw  *                                      request
415da6c28aaSamw  *                                      1 - close search if end of search
416da6c28aaSamw  *                                      reached
417da6c28aaSamw  *                                      2 - return resume keys for each
418da6c28aaSamw  *                                      entry found
419da6c28aaSamw  *                                      3 - resume/continue from previous
420da6c28aaSamw  *                                      ending place
421da6c28aaSamw  *                                      4 - find with backup intent
422da6c28aaSamw  *  STRING FileName;                   Resume file name
423da6c28aaSamw  *
424da6c28aaSamw  * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2
425da6c28aaSamw  * call.  If Bit3 of Flags is set, then FileName may be the NULL string,
426da6c28aaSamw  * since the search is continued from the previous TRANS2_FIND request.
427da6c28aaSamw  * Otherwise, FileName must not be more than 256 characters long.
428da6c28aaSamw  *
429da6c28aaSamw  *  Response Field                     Description
430da6c28aaSamw  *  ================================== =================================
431da6c28aaSamw  *
432da6c28aaSamw  *  USHORT SearchCount;                Number of entries returned
433da6c28aaSamw  *  USHORT EndOfSearch;                Was last entry returned?
434da6c28aaSamw  *  USHORT EaErrorOffset;              Offset into EA list if EA error
435da6c28aaSamw  *  USHORT LastNameOffset;             Offset into data to file name of
436da6c28aaSamw  *                                      last entry, if server needs it to
437da6c28aaSamw  *                                      resume search; else 0
438da6c28aaSamw  *  UCHAR Data[TotalDataCount]         Level dependent info about the
439da6c28aaSamw  *                                      matches found in the search
440da6c28aaSamw  */
441da6c28aaSamw int
442*dc20a302Sas200622 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa)
443da6c28aaSamw {
444*dc20a302Sas200622 	uint16_t fflag, infolev;
445da6c28aaSamw 	int	maxdata, count, wildcards, more = 0, rc;
446da6c28aaSamw 	uint32_t cookie;
447*dc20a302Sas200622 	uint16_t maxcount = 0;
448*dc20a302Sas200622 	smb_node_t *dir_snode;
449da6c28aaSamw 	char *pattern;
450*dc20a302Sas200622 	uint16_t sattr;
451da6c28aaSamw 
452da6c28aaSamw 	/*
453*dc20a302Sas200622 	 * The last parameter in the request is a path, which is a
454*dc20a302Sas200622 	 * null-terminated unicode string.
455da6c28aaSamw 	 *
456da6c28aaSamw 	 * smb_decode_mbc(&xa->req_param_mb, "%www lwu", sr,
457da6c28aaSamw 	 *    &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag, &path)
458da6c28aaSamw 	 *
459*dc20a302Sas200622 	 * We don't reference this parameter and it is not currently
460*dc20a302Sas200622 	 * decoded because we a expect 2-byte null but Mac OS 10
461*dc20a302Sas200622 	 * clients send a 1-byte null, which leads to a decode error.
462da6c28aaSamw 	 */
463da6c28aaSamw 	if (smb_decode_mbc(&xa->req_param_mb, "%www lw", sr,
464da6c28aaSamw 	    &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag) != 0) {
465da6c28aaSamw 		smbsr_decode_error(sr);
466da6c28aaSamw 		/* NOTREACHED */
467da6c28aaSamw 	}
468da6c28aaSamw 
469da6c28aaSamw 	sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid);
470da6c28aaSamw 	if (sr->sid_odir == NULL) {
471*dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
472da6c28aaSamw 		/* NOTREACHED */
473da6c28aaSamw 	}
474da6c28aaSamw 
475*dc20a302Sas200622 	maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag);
476da6c28aaSamw 	if (maxdata == 0) {
477da6c28aaSamw 		smb_rdir_close(sr);
478*dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
479*dc20a302Sas200622 		    ERRDOS, ERROR_INVALID_LEVEL);
480da6c28aaSamw 		/* NOTREACHED */
481da6c28aaSamw 	}
482da6c28aaSamw 
483da6c28aaSamw 	/*
484*dc20a302Sas200622 	 * When maxcount is zero Windows behaves as if it was 1.
485*dc20a302Sas200622 	 */
486*dc20a302Sas200622 	if (maxcount == 0)
487*dc20a302Sas200622 		maxcount = 1;
488*dc20a302Sas200622 
489*dc20a302Sas200622 	if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
490*dc20a302Sas200622 		maxcount = smb_trans2_find_max;
491*dc20a302Sas200622 
492*dc20a302Sas200622 	/*
493da6c28aaSamw 	 * Get a copy of information
494da6c28aaSamw 	 */
495da6c28aaSamw 	dir_snode = sr->sid_odir->d_dir_snode;
496*dc20a302Sas200622 	pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP);
497da6c28aaSamw 	(void) strcpy(pattern, sr->sid_odir->d_pattern);
498da6c28aaSamw 	wildcards = sr->sid_odir->d_wildcards;
499da6c28aaSamw 	sattr = sr->sid_odir->d_sattr;
500da6c28aaSamw 	if (fflag & SMB_FIND_CONTINUE_FROM_LAST) {
501da6c28aaSamw 		mutex_enter(&sr->sid_odir->d_mutex);
502da6c28aaSamw 		cookie = sr->sid_odir->d_cookie;
503da6c28aaSamw 		mutex_exit(&sr->sid_odir->d_mutex);
504da6c28aaSamw 	}
505da6c28aaSamw 
506da6c28aaSamw 	rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata,
507da6c28aaSamw 	    dir_snode, sattr, maxcount, wildcards, pattern, &cookie,
508da6c28aaSamw 	    &more, &count);
509da6c28aaSamw 
510da6c28aaSamw 	if (rc) {
511da6c28aaSamw 		smb_rdir_close(sr);
512da6c28aaSamw 		kmem_free(pattern, MAXNAMELEN);
513*dc20a302Sas200622 		smbsr_errno(sr, rc);
514da6c28aaSamw 		/* NOTREACHED */
515da6c28aaSamw 	}
516da6c28aaSamw 
517da6c28aaSamw 	if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST ||
518da6c28aaSamw 	    (!more && fflag & SMB_FIND_CLOSE_AT_EOS))
519da6c28aaSamw 		smb_rdir_close(sr);
520da6c28aaSamw 	else {
521da6c28aaSamw 		mutex_enter(&sr->sid_odir->d_mutex);
522da6c28aaSamw 		sr->sid_odir->d_cookie = cookie;
523da6c28aaSamw 		mutex_exit(&sr->sid_odir->d_mutex);
524da6c28aaSamw 	}
525da6c28aaSamw 
526da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
527da6c28aaSamw 	    count, (more ? 0 : 1), 0, 0);
528da6c28aaSamw 
529da6c28aaSamw 	kmem_free(pattern, MAXNAMELEN);
530da6c28aaSamw 	return (SDRC_NORMAL_REPLY);
531da6c28aaSamw }
532da6c28aaSamw 
533da6c28aaSamw /*
534da6c28aaSamw  * smb_trans2_find_get_maxdata
535da6c28aaSamw  *
536*dc20a302Sas200622  * Calculate the minimum response space required for the specified
537*dc20a302Sas200622  * information level.
538da6c28aaSamw  *
539*dc20a302Sas200622  * A non-zero return value provides the minimum space required.
540*dc20a302Sas200622  * A return value of zero indicates an unknown information level.
541da6c28aaSamw  */
542*dc20a302Sas200622 static int
543*dc20a302Sas200622 smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag)
544da6c28aaSamw {
545da6c28aaSamw 	int maxdata;
546da6c28aaSamw 
547da6c28aaSamw 	maxdata = smb_ascii_or_unicode_null_len(sr);
548da6c28aaSamw 
549da6c28aaSamw 	switch (infolev) {
550da6c28aaSamw 	case SMB_INFO_STANDARD :
551da6c28aaSamw 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
552da6c28aaSamw 			maxdata += sizeof (int32_t);
553da6c28aaSamw 		maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1;
554da6c28aaSamw 		break;
555da6c28aaSamw 
556da6c28aaSamw 	case SMB_INFO_QUERY_EA_SIZE:
557da6c28aaSamw 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
558da6c28aaSamw 			maxdata += sizeof (int32_t);
559da6c28aaSamw 		maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1;
560da6c28aaSamw 		break;
561da6c28aaSamw 
562da6c28aaSamw 	case SMB_FIND_FILE_DIRECTORY_INFO:
563da6c28aaSamw 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4;
564da6c28aaSamw 		break;
565da6c28aaSamw 
566da6c28aaSamw 	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
567da6c28aaSamw 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24;
568da6c28aaSamw 		break;
569da6c28aaSamw 
570da6c28aaSamw 	case SMB_FIND_FILE_NAMES_INFO:
571da6c28aaSamw 		maxdata += 4 + 4 + 4;
572da6c28aaSamw 		break;
573da6c28aaSamw 
574da6c28aaSamw 	case SMB_MAC_FIND_BOTH_HFS_INFO:
575da6c28aaSamw 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 +
576da6c28aaSamw 		    4 + 32 + 4 + 1 + 1 + 24 + 4;
577da6c28aaSamw 		break;
578da6c28aaSamw 
579da6c28aaSamw 	default:
580da6c28aaSamw 		maxdata = 0;
581da6c28aaSamw 	}
582da6c28aaSamw 
583da6c28aaSamw 	return (maxdata);
584da6c28aaSamw }
585da6c28aaSamw 
586da6c28aaSamw /*
587da6c28aaSamw  * smb_trans2_find_get_dents
588da6c28aaSamw  *
589da6c28aaSamw  * This function will get all the directory entry information and mbc
590da6c28aaSamw  * encode it in the xa. If there is an error, it will be returned;
591da6c28aaSamw  * otherwise, 0 is returned.
592da6c28aaSamw  *
593da6c28aaSamw  * The more field will be updated. If the value returned is one, it means
594da6c28aaSamw  * there are more entries; otherwise, the returned value will be zero. The
595da6c28aaSamw  * cookie will also be updated to indicate the next start point for the
596da6c28aaSamw  * search. The count value will also be updated to stores the total entries
597da6c28aaSamw  * encoded.
598da6c28aaSamw  */
599da6c28aaSamw int smb_trans2_find_get_dents(
600da6c28aaSamw     smb_request_t	*sr,
601da6c28aaSamw     smb_xa_t		*xa,
602*dc20a302Sas200622     uint16_t		fflag,
603*dc20a302Sas200622     uint16_t		infolev,
604da6c28aaSamw     int			maxdata,
605da6c28aaSamw     smb_node_t		*dir_snode,
606*dc20a302Sas200622     uint16_t		sattr,
607*dc20a302Sas200622     uint16_t		maxcount,
608da6c28aaSamw     int			wildcards,
609da6c28aaSamw     char		*pattern,
610da6c28aaSamw     uint32_t		*cookie,
611da6c28aaSamw     int			*more,
612da6c28aaSamw     int			*count)
613da6c28aaSamw {
614da6c28aaSamw 	smb_dent_info_hdr_t	*ihdr;
615da6c28aaSamw 	smb_dent_info_t		*ient;
616da6c28aaSamw 	int			dent_buf_size;
617da6c28aaSamw 	int			i;
618da6c28aaSamw 	int			total;
619da6c28aaSamw 	int			maxentries;
620da6c28aaSamw 	int			rc;
621da6c28aaSamw 
622da6c28aaSamw 	ihdr = kmem_zalloc(sizeof (smb_dent_info_hdr_t), KM_SLEEP);
623da6c28aaSamw 	*count = 0;
624da6c28aaSamw 
625da6c28aaSamw 	if (!wildcards)
626da6c28aaSamw 		maxentries = maxcount = 1;
627da6c28aaSamw 	else {
628da6c28aaSamw 		maxentries = (xa->rep_data_mb.max_bytes -
629da6c28aaSamw 		    xa->rep_data_mb.chain_offset) / maxdata;
630da6c28aaSamw 		if (maxcount > SMB_MAX_DENTS_IOVEC)
631da6c28aaSamw 			maxcount = SMB_MAX_DENTS_IOVEC;
632da6c28aaSamw 		if (maxentries > maxcount)
633da6c28aaSamw 			maxentries = maxcount;
634da6c28aaSamw 	}
635da6c28aaSamw 
636da6c28aaSamw 	/* Each entry will need to be aligned so add _POINTER_ALIGNMENT */
637da6c28aaSamw 	dent_buf_size =
638da6c28aaSamw 	    maxentries * (SMB_MAX_DENT_INFO_SIZE + _POINTER_ALIGNMENT);
639da6c28aaSamw 	ihdr->iov->iov_base = kmem_alloc(dent_buf_size, KM_SLEEP);
640da6c28aaSamw 
641da6c28aaSamw 	ihdr->sattr = sattr;
642da6c28aaSamw 	ihdr->pattern = pattern;
643da6c28aaSamw 	ihdr->sr = sr;
644da6c28aaSamw 
645da6c28aaSamw 	ihdr->uio.uio_iovcnt = maxcount;
646da6c28aaSamw 	ihdr->uio.uio_resid = dent_buf_size;
647da6c28aaSamw 	ihdr->uio.uio_iov = ihdr->iov;
64855bf511dSas200622 	ihdr->uio.uio_loffset = 0;
649da6c28aaSamw 
650da6c28aaSamw 	rc = smb_get_dents(sr, cookie, dir_snode, wildcards, ihdr, more);
651da6c28aaSamw 	if (rc != 0) {
652da6c28aaSamw 		goto out;
653da6c28aaSamw 	}
654da6c28aaSamw 
655da6c28aaSamw 	if (ihdr->iov->iov_len == 0)
656da6c28aaSamw 		*count = 0;
657da6c28aaSamw 	else
658da6c28aaSamw 		*count = smb_trans2_find_process_ients(sr, xa, ihdr, fflag,
659da6c28aaSamw 		    infolev, maxdata, dir_snode, more, cookie);
660da6c28aaSamw 	rc = 0;
661da6c28aaSamw 
662da6c28aaSamw out:
663da6c28aaSamw 
664da6c28aaSamw 	total = maxcount - ihdr->uio.uio_iovcnt;
665da6c28aaSamw 	ASSERT((total >= 0) && (total <= SMB_MAX_DENTS_IOVEC));
666da6c28aaSamw 	for (i = 0; i < total; i++) {
667da6c28aaSamw 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
668da6c28aaSamw 		ient = (smb_dent_info_t *)ihdr->iov[i].iov_base;
669da6c28aaSamw 		ASSERT(ient);
670da6c28aaSamw 		smb_node_release(ient->snode);
671da6c28aaSamw 	}
672da6c28aaSamw 
673da6c28aaSamw 	kmem_free(ihdr->iov->iov_base, dent_buf_size);
674da6c28aaSamw 	kmem_free(ihdr, sizeof (smb_dent_info_hdr_t));
675da6c28aaSamw 	return (0);
676da6c28aaSamw }
677da6c28aaSamw 
678da6c28aaSamw 
679da6c28aaSamw 
680da6c28aaSamw /*
681da6c28aaSamw  * smb_get_dents
682da6c28aaSamw  *
683da6c28aaSamw  * This function utilizes "smb_fsop_getdents()" to get dir entries.
684da6c28aaSamw  * The "smb_gather_dents_info()" is the call back function called
685da6c28aaSamw  * inside the file system. It is very important that the function
686da6c28aaSamw  * does not sleep or yield since it is processed inside a file
687da6c28aaSamw  * system transaction.
688da6c28aaSamw  *
689da6c28aaSamw  * The function returns 0 when successful and error code when failed.
690da6c28aaSamw  * If more is provided, the return value of 1 is returned indicating
691da6c28aaSamw  * more entries; otherwise, 0 is returned.
692da6c28aaSamw  */
693da6c28aaSamw int smb_get_dents(
694da6c28aaSamw     smb_request_t	*sr,
695da6c28aaSamw     uint32_t		*cookie,
696da6c28aaSamw     smb_node_t		*dir_snode,
697*dc20a302Sas200622     uint32_t		wildcards,
698da6c28aaSamw     smb_dent_info_hdr_t	*ihdr,
699da6c28aaSamw     int			*more)
700da6c28aaSamw {
701da6c28aaSamw 	int		rc;
702da6c28aaSamw 	char		*namebuf;
703da6c28aaSamw 	smb_node_t	*snode;
704da6c28aaSamw 	smb_attr_t	file_attr;
705da6c28aaSamw 	uint32_t	maxcnt = ihdr->uio.uio_iovcnt;
706da6c28aaSamw 	char		shortname[MANGLE_NAMELEN], name83[MANGLE_NAMELEN];
707da6c28aaSamw 	fsvol_attr_t	vol_attr;
708da6c28aaSamw 
709da6c28aaSamw 	namebuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
710da6c28aaSamw 	if (more)
711da6c28aaSamw 		*more = 0;
712da6c28aaSamw 
713da6c28aaSamw 	if ((rc = fsd_getattr(&sr->tid_tree->t_fsd, &vol_attr)) != 0) {
714da6c28aaSamw 		kmem_free(namebuf, MAXNAMELEN);
715da6c28aaSamw 		return (rc);
716da6c28aaSamw 	}
717da6c28aaSamw 
718da6c28aaSamw 	if (!wildcards) {
719da6c28aaSamw 		/* Already found entry? */
720da6c28aaSamw 		if (*cookie != 0)
721da6c28aaSamw 			return (0);
722da6c28aaSamw 		shortname[0] = '\0';
723da6c28aaSamw 
724da6c28aaSamw 		rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
725da6c28aaSamw 		    dir_snode, ihdr->pattern, &snode, &file_attr, shortname,
726da6c28aaSamw 		    name83);
727da6c28aaSamw 
728da6c28aaSamw 		if (rc) {
729da6c28aaSamw 			kmem_free(namebuf, MAXNAMELEN);
730da6c28aaSamw 			return (rc);
731da6c28aaSamw 		}
732da6c28aaSamw 
733da6c28aaSamw 		(void) strlcpy(namebuf, ihdr->pattern, MAXNAMELEN);
734da6c28aaSamw 
735da6c28aaSamw 		/*
736da6c28aaSamw 		 * It is not necessary to set the "force" flag (i.e. to
737da6c28aaSamw 		 * take into account mangling for case-insensitive collisions)
738da6c28aaSamw 		 */
739da6c28aaSamw 
740da6c28aaSamw 		if (shortname[0] == '\0')
741da6c28aaSamw 			(void) smb_mangle_name(snode->attr.sa_vattr.va_nodeid,
742da6c28aaSamw 			    namebuf, shortname, name83, 0);
743da6c28aaSamw 		(void) smb_gather_dents_info((char *)ihdr,
744da6c28aaSamw 		    snode->attr.sa_vattr.va_nodeid,
745da6c28aaSamw 		    strlen(namebuf), namebuf, -1, (int *)&maxcnt,
746da6c28aaSamw 		    &snode->attr, snode, shortname, name83);
747da6c28aaSamw 		kmem_free(namebuf, MAXNAMELEN);
748da6c28aaSamw 		return (0);
749da6c28aaSamw 	}
750da6c28aaSamw 
751da6c28aaSamw 	if ((rc = smb_fsop_getdents(sr, sr->user_cr, dir_snode, cookie,
752da6c28aaSamw 	    0, (int *)&maxcnt, (char *)ihdr, ihdr->pattern)) != 0) {
753da6c28aaSamw 		if (rc == ENOENT) {
754da6c28aaSamw 			kmem_free(namebuf, MAXNAMELEN);
755da6c28aaSamw 			return (0);
756da6c28aaSamw 		}
757da6c28aaSamw 		kmem_free(namebuf, MAXNAMELEN);
758da6c28aaSamw 		return (rc);
759da6c28aaSamw 	}
760da6c28aaSamw 
761da6c28aaSamw 	if (*cookie != 0x7FFFFFFF && more)
762da6c28aaSamw 		*more = 1;
763da6c28aaSamw 
764da6c28aaSamw 	kmem_free(namebuf, MAXNAMELEN);
765da6c28aaSamw 	return (0);
766da6c28aaSamw }
767da6c28aaSamw 
768da6c28aaSamw 
769da6c28aaSamw 
770da6c28aaSamw 
771da6c28aaSamw /*
772da6c28aaSamw  * smb_gather_dents_info
773da6c28aaSamw  *
774da6c28aaSamw  * The function will accept information of each directory entry and put
775da6c28aaSamw  * the needed information in the buffer. It is passed as the call back
776da6c28aaSamw  * function for smb_fsop_getdents() to gather trans2 find info.
777da6c28aaSamw  *
778da6c28aaSamw  * If the buffer space is not enough, -1 will be returned. Regardless
779da6c28aaSamw  * of valid entry or not, 0 will be returned; however, only valid entry
780da6c28aaSamw  * will be stored in the buffer.
781da6c28aaSamw  */
782da6c28aaSamw int /*ARGSUSED*/
783da6c28aaSamw smb_gather_dents_info(
784da6c28aaSamw     char	*args,
785da6c28aaSamw     ino_t	fileid,
786da6c28aaSamw     int		namelen,
787da6c28aaSamw     char	*name,
788da6c28aaSamw     uint32_t	cookie,
789da6c28aaSamw     int32_t	*countp,
790da6c28aaSamw     smb_attr_t	*attr,
791da6c28aaSamw     smb_node_t	*snode,
792da6c28aaSamw     char	*shortname,
793da6c28aaSamw     char	*name83)
794da6c28aaSamw {
795da6c28aaSamw 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
796da6c28aaSamw 	smb_dent_info_hdr_t	*ihdr = (smb_dent_info_hdr_t *)args;
797da6c28aaSamw 	smb_dent_info_t		*ient;
798*dc20a302Sas200622 	uint8_t			*v5_name = NULL;
799*dc20a302Sas200622 	uint8_t			*np = (uint8_t *)name;
800da6c28aaSamw 	int			reclen = sizeof (smb_dent_info_t) + namelen;
801da6c28aaSamw 
802da6c28aaSamw 	v5_name = kmem_alloc(MAXNAMELEN-1, KM_SLEEP);
803da6c28aaSamw 
804da6c28aaSamw 	if (!ihdr->uio.uio_iovcnt || ihdr->uio.uio_resid < reclen) {
805da6c28aaSamw 		kmem_free(v5_name, MAXNAMELEN-1);
806da6c28aaSamw 		smb_node_release(snode);
807da6c28aaSamw 		return (-1);
808da6c28aaSamw 	}
809da6c28aaSamw 
810da6c28aaSamw 	if (!smb_sattr_check(attr, name, ihdr->sattr)) {
811da6c28aaSamw 		kmem_free(v5_name, MAXNAMELEN-1);
812da6c28aaSamw 		smb_node_release(snode);
813da6c28aaSamw 		return (0);
814da6c28aaSamw 	}
815da6c28aaSamw 
816da6c28aaSamw 	if (catia_callback) {
817*dc20a302Sas200622 		catia_callback(v5_name, (uint8_t *)name,  MAXNAMELEN-1);
818da6c28aaSamw 		np = v5_name;
819da6c28aaSamw 		reclen = sizeof (smb_dent_info_t) + strlen((char *)v5_name);
820da6c28aaSamw 	}
821da6c28aaSamw 
822da6c28aaSamw 	ASSERT(snode);
823da6c28aaSamw 	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
824da6c28aaSamw 	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
825da6c28aaSamw 
826da6c28aaSamw 	/*
827da6c28aaSamw 	 * Each entry needs to be properly aligned or we may get an alignment
828da6c28aaSamw 	 * fault on sparc.
829da6c28aaSamw 	 */
83055bf511dSas200622 	ihdr->uio.uio_loffset = (offset_t)PTRALIGN(ihdr->uio.uio_loffset);
831da6c28aaSamw 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
83255bf511dSas200622 	ient = (smb_dent_info_t *)&ihdr->iov->iov_base[ihdr->uio.uio_loffset];
833da6c28aaSamw 
834da6c28aaSamw 	ient->cookie = cookie;
835da6c28aaSamw 	ient->attr = *attr;
836da6c28aaSamw 	ient->snode = snode;
837da6c28aaSamw 
838da6c28aaSamw 	(void) strcpy(ient->name, (char *)np);
839da6c28aaSamw 	(void) strcpy(ient->shortname, shortname);
840da6c28aaSamw 	(void) strcpy(ient->name83, name83);
841da6c28aaSamw 	ihdr->uio.uio_iov->iov_base = (char *)ient;
842da6c28aaSamw 	ihdr->uio.uio_iov->iov_len = reclen;
843da6c28aaSamw 
844da6c28aaSamw 	ihdr->uio.uio_iov++;
845da6c28aaSamw 	ihdr->uio.uio_iovcnt--;
846da6c28aaSamw 	ihdr->uio.uio_resid -= reclen;
84755bf511dSas200622 	ihdr->uio.uio_loffset += reclen;
848da6c28aaSamw 
849da6c28aaSamw 	kmem_free(v5_name, MAXNAMELEN-1);
850da6c28aaSamw 	return (0);
851da6c28aaSamw }
852da6c28aaSamw 
853da6c28aaSamw 
854da6c28aaSamw 
855da6c28aaSamw /*
856da6c28aaSamw  * smb_trans2_find_process_ients
857da6c28aaSamw  *
858da6c28aaSamw  * This function encodes the directory entry information store in
859da6c28aaSamw  * the iov structure of the ihdr structure.
860da6c28aaSamw  *
861da6c28aaSamw  * The total entries encoded will be returned. If the entries encoded
862da6c28aaSamw  * is less than the total entries in the iov, the more field will
863da6c28aaSamw  * be updated to 1. Also, the next cookie wil be updated as well.
864da6c28aaSamw  */
865da6c28aaSamw int
866da6c28aaSamw smb_trans2_find_process_ients(
867*dc20a302Sas200622     smb_request_t	*sr,
868*dc20a302Sas200622     smb_xa_t		*xa,
869da6c28aaSamw     smb_dent_info_hdr_t	*ihdr,
870*dc20a302Sas200622     uint16_t		fflag,
871*dc20a302Sas200622     uint16_t		infolev,
872da6c28aaSamw     int			maxdata,
873*dc20a302Sas200622     smb_node_t		*dir_snode,
874da6c28aaSamw     int			*more,
875da6c28aaSamw     uint32_t		*cookie)
876da6c28aaSamw {
877da6c28aaSamw 	int i, err = 0;
878da6c28aaSamw 	smb_dent_info_t *ient;
879da6c28aaSamw 	uint32_t mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
880da6c28aaSamw 	    ? SMB_MSGBUF_UNICODE : 0;
881da6c28aaSamw 
882da6c28aaSamw 	for (i = 0; i < SMB_MAX_DENTS_IOVEC; i++) {
883da6c28aaSamw 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
884da6c28aaSamw 		if ((ient = (smb_dent_info_t *)ihdr->iov[i].iov_base) == 0)
885da6c28aaSamw 			break;
886da6c28aaSamw 
887da6c28aaSamw 		/*
888*dc20a302Sas200622 		 * Observed differences between our response and Windows
889*dc20a302Sas200622 		 * response, which hasn't caused a problem yet!
890da6c28aaSamw 		 *
891*dc20a302Sas200622 		 * 1. The NextEntryOffset field for the last entry should
892*dc20a302Sas200622 		 * be 0.  This code always calculate the record length
893*dc20a302Sas200622 		 * and puts the result in the NextEntryOffset field.
894da6c28aaSamw 		 *
895*dc20a302Sas200622 		 * 2. The FileIndex field is always 0.  This code puts
896*dc20a302Sas200622 		 * the cookie in the FileIndex field.
897da6c28aaSamw 		 */
898da6c28aaSamw 		err = smb_trans2_find_mbc_encode(sr, xa, ient, maxdata, infolev,
899da6c28aaSamw 		    fflag, mb_flags, dir_snode, NULL);
900da6c28aaSamw 
901da6c28aaSamw 		if (err)
902da6c28aaSamw 			break;
903da6c28aaSamw 	}
904da6c28aaSamw 
905da6c28aaSamw 	/*
906*dc20a302Sas200622 	 * Not enough space to store all the entries returned,
907*dc20a302Sas200622 	 * which is indicated by setting more.
908da6c28aaSamw 	 */
909da6c28aaSamw 	if (more && err < 0) {
910da6c28aaSamw 		*more = 1;
911da6c28aaSamw 
912da6c28aaSamw 		/*
913da6c28aaSamw 		 * Assume the space will be at least enough for 1 entry.
914da6c28aaSamw 		 */
915da6c28aaSamw 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
916da6c28aaSamw 		ient = (smb_dent_info_t *)ihdr->iov[i-1].iov_base;
917da6c28aaSamw 		*cookie = ient->cookie;
918da6c28aaSamw 	}
919da6c28aaSamw 	return (i);
920da6c28aaSamw }
921da6c28aaSamw 
922da6c28aaSamw /*
923da6c28aaSamw  * smb_trans2_find_mbc_encode
924da6c28aaSamw  *
925da6c28aaSamw  * This function encodes the mbc for one directory entry.
926da6c28aaSamw  *
927da6c28aaSamw  * The function returns -1 when the max data requested by client
928da6c28aaSamw  * is reached. If the entry is valid and successful encoded, 0
929da6c28aaSamw  * will be returned; otherwise, 1 will be returned.
930da6c28aaSamw  */
931*dc20a302Sas200622 int /*ARGSUSED*/
932*dc20a302Sas200622 smb_trans2_find_mbc_encode(
933*dc20a302Sas200622     smb_request_t	*sr,
934*dc20a302Sas200622     smb_xa_t		*xa,
935da6c28aaSamw     smb_dent_info_t	*ient,
936da6c28aaSamw     int			maxdata,
937*dc20a302Sas200622     uint16_t		infolev,
938*dc20a302Sas200622     uint16_t		fflag,
939*dc20a302Sas200622     uint32_t		mb_flags,
940*dc20a302Sas200622     smb_node_t		*dir_snode,
941*dc20a302Sas200622     smb_node_t		*sd_snode)
942da6c28aaSamw {
943da6c28aaSamw 	int uni_namelen;
944*dc20a302Sas200622 	int shortlen;
945*dc20a302Sas200622 	uint32_t next_entry_offset;
946da6c28aaSamw 	char buf83[26];
947da6c28aaSamw 	smb_msgbuf_t mb;
948da6c28aaSamw 	uint32_t dattr = 0;
949da6c28aaSamw 	uint32_t size32 = 0;
950da6c28aaSamw 	uint64_t size64 = 0;
951*dc20a302Sas200622 	smb_node_t *lnk_snode;
952da6c28aaSamw 	smb_attr_t lnkattr;
953da6c28aaSamw 	int rc;
954da6c28aaSamw 
955da6c28aaSamw 	uni_namelen = smb_ascii_or_unicode_strlen(sr, ient->name);
956da6c28aaSamw 	if (uni_namelen == -1)
957da6c28aaSamw 		return (1);
958da6c28aaSamw 
959*dc20a302Sas200622 	next_entry_offset = maxdata + uni_namelen;
960*dc20a302Sas200622 
961da6c28aaSamw 	if (MBC_ROOM_FOR(&xa->rep_data_mb, (maxdata + uni_namelen)) == 0)
962da6c28aaSamw 		return (-1);
963da6c28aaSamw 
964da6c28aaSamw 	if (ient->attr.sa_vattr.va_type == VLNK) {
965da6c28aaSamw 		rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
966da6c28aaSamw 		    sr->tid_tree->t_snode, dir_snode, ient->name, &lnk_snode,
967da6c28aaSamw 		    &lnkattr, 0, 0);
968da6c28aaSamw 
969da6c28aaSamw 		/*
970da6c28aaSamw 		 * We normally want to resolve the object to which a symlink
971da6c28aaSamw 		 * refers so that CIFS clients can access sub-directories and
972da6c28aaSamw 		 * find the correct association for files. This causes a
973da6c28aaSamw 		 * problem, however, if a symlink in a sub-directory points
974da6c28aaSamw 		 * to a parent directory (some UNIX GUI's create a symlink in
975da6c28aaSamw 		 * $HOME/.desktop that points to the user's home directory).
976da6c28aaSamw 		 * Some Windows applications (i.e. virus scanning) loop/hang
977da6c28aaSamw 		 * trying to follow this recursive path and there is little
978da6c28aaSamw 		 * we can do because the path is constructed on the client.
979*dc20a302Sas200622 		 * skc_dirsymlink_enable allows an end-user to disable
980da6c28aaSamw 		 * symlinks to directories. Symlinks to other object types
981da6c28aaSamw 		 * should be unaffected.
982da6c28aaSamw 		 */
983da6c28aaSamw 		if (rc == 0) {
984da6c28aaSamw 			if (smb_info.si.skc_dirsymlink_enable ||
985da6c28aaSamw 			    (lnkattr.sa_vattr.va_type != VDIR)) {
986da6c28aaSamw 				smb_node_release(ient->snode);
987da6c28aaSamw 				ient->snode = lnk_snode;
988da6c28aaSamw 				ient->attr = lnkattr;
989da6c28aaSamw 			} else {
990da6c28aaSamw 				smb_node_release(lnk_snode);
991da6c28aaSamw 			}
992da6c28aaSamw 		}
993da6c28aaSamw 	}
994da6c28aaSamw 
995da6c28aaSamw 	if (infolev != SMB_FIND_FILE_NAMES_INFO) {
996da6c28aaSamw 		size64 = smb_node_get_size(ient->snode, &ient->attr);
997da6c28aaSamw 		size32 = (size64 > 0xFFFFFFFF) ? 0xFFFFFFFF : (uint32_t)size64;
998da6c28aaSamw 		dattr = smb_mode_to_dos_attributes(&ient->attr);
999da6c28aaSamw 	}
1000da6c28aaSamw 
1001da6c28aaSamw 	switch (infolev) {
1002da6c28aaSamw 	case SMB_INFO_STANDARD:
1003da6c28aaSamw 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
1004da6c28aaSamw 			(void) smb_encode_mbc(&xa->rep_data_mb, "l",
1005da6c28aaSamw 			    ient->cookie);
1006da6c28aaSamw 
1007da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_data_mb, "%yyyllwbu", sr,
1008da6c28aaSamw 		    ient->attr.sa_crtime.tv_sec ? ient->attr.sa_crtime.tv_sec :
1009da6c28aaSamw 		    ient->attr.sa_vattr.va_mtime.tv_sec,
1010da6c28aaSamw 		    ient->attr.sa_vattr.va_atime.tv_sec,
1011da6c28aaSamw 		    ient->attr.sa_vattr.va_mtime.tv_sec,
1012da6c28aaSamw 		    size32,
1013da6c28aaSamw 		    size32,
1014da6c28aaSamw 		    dattr,
1015da6c28aaSamw 		    uni_namelen,
1016da6c28aaSamw 		    ient->name);
1017da6c28aaSamw 		break;
1018da6c28aaSamw 
1019da6c28aaSamw 	case SMB_INFO_QUERY_EA_SIZE:
1020da6c28aaSamw 		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
1021*dc20a302Sas200622 			(void) smb_encode_mbc(&xa->rep_data_mb, "l",
1022*dc20a302Sas200622 			    ient->cookie);
1023da6c28aaSamw 
1024da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_data_mb, "%yyyllwlbu", sr,
1025da6c28aaSamw 		    ient->attr.sa_crtime.tv_sec ? ient->attr.sa_crtime.tv_sec :
1026da6c28aaSamw 		    ient->attr.sa_vattr.va_mtime.tv_sec,
1027da6c28aaSamw 		    ient->attr.sa_vattr.va_atime.tv_sec,
1028da6c28aaSamw 		    ient->attr.sa_vattr.va_mtime.tv_sec,
1029da6c28aaSamw 		    size32,
1030da6c28aaSamw 		    size32,
1031da6c28aaSamw 		    dattr,
1032da6c28aaSamw 		    0L,		/* EA Size */
1033da6c28aaSamw 		    uni_namelen,
1034da6c28aaSamw 		    ient->name);
1035da6c28aaSamw 		break;
1036da6c28aaSamw 
1037da6c28aaSamw 	case SMB_FIND_FILE_DIRECTORY_INFO:
1038da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_data_mb, "%llTTTTqqllu", sr,
1039*dc20a302Sas200622 		    next_entry_offset,
1040da6c28aaSamw 		    ient->cookie,
1041da6c28aaSamw 		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
1042da6c28aaSamw 		    &ient->attr.sa_vattr.va_mtime,
1043da6c28aaSamw 		    &ient->attr.sa_vattr.va_atime,
1044da6c28aaSamw 		    &ient->attr.sa_vattr.va_mtime,
1045da6c28aaSamw 		    &ient->attr.sa_vattr.va_ctime,
1046da6c28aaSamw 		    size64,
1047da6c28aaSamw 		    size64,
1048da6c28aaSamw 		    dattr,
1049da6c28aaSamw 		    uni_namelen,
1050da6c28aaSamw 		    ient->name);
1051da6c28aaSamw 		break;
1052da6c28aaSamw 
1053da6c28aaSamw 	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
1054da6c28aaSamw 		bzero(buf83, sizeof (buf83));
1055*dc20a302Sas200622 		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
1056da6c28aaSamw 		    mb_flags);
1057da6c28aaSamw 		if (smb_msgbuf_encode(&mb, "u", ient->shortname) < 0) {
1058da6c28aaSamw 			smb_msgbuf_term(&mb);
1059da6c28aaSamw 			return (-1);
1060da6c28aaSamw 		}
1061*dc20a302Sas200622 		shortlen = smb_ascii_or_unicode_strlen(sr, ient->shortname);
1062da6c28aaSamw 
1063*dc20a302Sas200622 		(void) smb_encode_mbc(&xa->rep_data_mb, "%llTTTTqqlllb.24cu",
1064*dc20a302Sas200622 		    sr,
1065*dc20a302Sas200622 		    next_entry_offset,
1066da6c28aaSamw 		    ient->cookie,
1067da6c28aaSamw 		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
1068da6c28aaSamw 		    &ient->attr.sa_vattr.va_mtime,
1069da6c28aaSamw 		    &ient->attr.sa_vattr.va_atime,
1070da6c28aaSamw 		    &ient->attr.sa_vattr.va_mtime,
1071da6c28aaSamw 		    &ient->attr.sa_vattr.va_ctime,
1072da6c28aaSamw 		    size64,
1073da6c28aaSamw 		    size64,
1074da6c28aaSamw 		    dattr,
1075da6c28aaSamw 		    uni_namelen,
1076da6c28aaSamw 		    0L,
1077*dc20a302Sas200622 		    shortlen,
1078da6c28aaSamw 		    buf83,
1079da6c28aaSamw 		    ient->name);
1080da6c28aaSamw 
1081da6c28aaSamw 		smb_msgbuf_term(&mb);
1082da6c28aaSamw 		break;
1083da6c28aaSamw 
1084da6c28aaSamw 	case SMB_FIND_FILE_NAMES_INFO:
1085da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_data_mb, "%lllu", sr,
1086*dc20a302Sas200622 		    next_entry_offset,
1087da6c28aaSamw 		    ient->cookie,
1088da6c28aaSamw 		    uni_namelen,
1089da6c28aaSamw 		    ient->name);
1090da6c28aaSamw 		break;
1091da6c28aaSamw 	}
1092da6c28aaSamw 
1093da6c28aaSamw 	return (0);
1094da6c28aaSamw }
1095da6c28aaSamw 
1096da6c28aaSamw /*
1097da6c28aaSamw  * Close a search started by a Trans2FindFirst2 request.
1098da6c28aaSamw  */
1099da6c28aaSamw int
1100*dc20a302Sas200622 smb_com_find_close2(smb_request_t *sr)
1101da6c28aaSamw {
1102da6c28aaSamw 	if (smbsr_decode_vwv(sr, "w", &sr->smb_sid) != 0) {
1103da6c28aaSamw 		smbsr_decode_error(sr);
1104da6c28aaSamw 		/* NOTREACHED */
1105da6c28aaSamw 	}
1106da6c28aaSamw 
1107da6c28aaSamw 	sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid);
1108da6c28aaSamw 	if (sr->sid_odir == NULL) {
1109*dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
1110da6c28aaSamw 		/* NOTREACHED */
1111da6c28aaSamw 	}
1112da6c28aaSamw 
1113da6c28aaSamw 	smb_rdir_close(sr);
1114da6c28aaSamw 	smbsr_encode_empty_result(sr);
1115da6c28aaSamw 	return (SDRC_NORMAL_REPLY);
1116da6c28aaSamw }
1117