2 Unix SMB/CIFS implementation.
3 client directory list routines
4 Copyright (C) Andrew Tridgell 1994-2003
5 Copyright (C) James Myers 2003 <myersjj@samba.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "libcli/libcli.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
26 struct search_private
{
27 struct clilist_file_info
*dirlist
;
30 int ff_searchcount
; /* total received in 1 server trip */
31 int total_received
; /* total received all together */
32 enum smb_search_data_level data_level
;
33 const char *last_name
; /* used to continue trans2 search */
34 struct smb_search_id id
; /* used for old-style search */
38 /****************************************************************************
39 Interpret a long filename structure.
40 ****************************************************************************/
41 static bool interpret_long_filename(enum smb_search_data_level level
,
42 const union smb_search_data
*info
,
43 struct clilist_file_info
*finfo
)
45 struct clilist_file_info finfo2
;
47 if (!finfo
) finfo
= &finfo2
;
51 case RAW_SEARCH_DATA_STANDARD
:
52 finfo
->size
= info
->standard
.size
;
53 finfo
->mtime
= info
->standard
.write_time
;
54 finfo
->attrib
= info
->standard
.attrib
;
55 finfo
->name
= info
->standard
.name
.s
;
56 finfo
->short_name
= info
->standard
.name
.s
;
59 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
60 finfo
->size
= info
->both_directory_info
.size
;
61 finfo
->mtime
= nt_time_to_unix(info
->both_directory_info
.write_time
);
62 finfo
->attrib
= info
->both_directory_info
.attrib
;
63 finfo
->short_name
= info
->both_directory_info
.short_name
.s
;
64 finfo
->name
= info
->both_directory_info
.name
.s
;
68 DEBUG(0,("Unhandled level %d in interpret_long_filename\n", (int)level
));
75 /* callback function used for trans2 search */
76 static bool smbcli_list_new_callback(void *private_data
, const union smb_search_data
*file
)
78 struct search_private
*state
= (struct search_private
*) private_data
;
79 struct clilist_file_info
*tdl
;
81 /* add file info to the dirlist pool */
82 tdl
= talloc_realloc(state
,
84 struct clilist_file_info
,
85 state
->dirlist_len
+ 1);
92 interpret_long_filename(state
->data_level
, file
, &state
->dirlist
[state
->total_received
]);
94 state
->last_name
= state
->dirlist
[state
->total_received
].name
;
95 state
->total_received
++;
96 state
->ff_searchcount
++;
101 int smbcli_list_new(struct smbcli_tree
*tree
, const char *Mask
, uint16_t attribute
,
102 enum smb_search_data_level level
,
103 void (*fn
)(struct clilist_file_info
*, const char *, void *),
106 union smb_search_first first_parms
;
107 union smb_search_next next_parms
;
108 struct search_private state
; /* for callbacks */
111 int num_received
= 0;
112 int max_matches
= 512;
114 int ff_eos
= 0, i
, ff_searchcount
;
117 /* initialize state for search */
118 state
.mem_ctx
= talloc_init("smbcli_list_new");
119 state
.dirlist_len
= 0;
120 state
.total_received
= 0;
122 state
.dirlist
= talloc_array(state
.mem_ctx
,
123 struct clilist_file_info
, 0);
124 mask
= talloc_strdup(state
.mem_ctx
, Mask
);
126 if (level
== RAW_SEARCH_DATA_GENERIC
) {
127 if (tree
->session
->transport
->negotiate
.capabilities
& CAP_NT_SMBS
) {
128 level
= RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
;
130 level
= RAW_SEARCH_DATA_STANDARD
;
133 state
.data_level
= level
;
136 state
.ff_searchcount
= 0;
140 first_parms
.t2ffirst
.level
= RAW_SEARCH_TRANS2
;
141 first_parms
.t2ffirst
.data_level
= state
.data_level
;
142 first_parms
.t2ffirst
.in
.max_count
= max_matches
;
143 first_parms
.t2ffirst
.in
.search_attrib
= attribute
;
144 first_parms
.t2ffirst
.in
.pattern
= mask
;
145 first_parms
.t2ffirst
.in
.flags
= FLAG_TRANS2_FIND_CLOSE_IF_END
;
146 first_parms
.t2ffirst
.in
.storage_type
= 0;
148 status
= smb_raw_search_first(tree
,
149 state
.mem_ctx
, &first_parms
,
150 (void*)&state
, smbcli_list_new_callback
);
151 if (!NT_STATUS_IS_OK(status
)) {
152 talloc_free(state
.mem_ctx
);
156 ff_dir_handle
= first_parms
.t2ffirst
.out
.handle
;
157 ff_searchcount
= first_parms
.t2ffirst
.out
.count
;
158 ff_eos
= first_parms
.t2ffirst
.out
.end_of_search
;
160 received
= first_parms
.t2ffirst
.out
.count
;
161 if (received
<= 0) break;
167 next_parms
.t2fnext
.level
= RAW_SEARCH_TRANS2
;
168 next_parms
.t2fnext
.data_level
= state
.data_level
;
169 next_parms
.t2fnext
.in
.max_count
= max_matches
;
170 next_parms
.t2fnext
.in
.last_name
= state
.last_name
;
171 next_parms
.t2fnext
.in
.handle
= ff_dir_handle
;
172 next_parms
.t2fnext
.in
.resume_key
= 0;
173 next_parms
.t2fnext
.in
.flags
= FLAG_TRANS2_FIND_CLOSE_IF_END
;
175 status
= smb_raw_search_next(tree
,
179 smbcli_list_new_callback
);
181 if (!NT_STATUS_IS_OK(status
)) {
184 ff_searchcount
= next_parms
.t2fnext
.out
.count
;
185 ff_eos
= next_parms
.t2fnext
.out
.end_of_search
;
186 received
= next_parms
.t2fnext
.out
.count
;
187 if (received
<= 0) break;
191 num_received
+= received
;
194 for (i
=0;i
<state
.total_received
;i
++) {
195 fn(&state
.dirlist
[i
], Mask
, caller_state
);
198 talloc_free(state
.mem_ctx
);
200 return state
.total_received
;
203 /****************************************************************************
204 Interpret a short filename structure.
205 The length of the structure is returned.
206 ****************************************************************************/
207 static bool interpret_short_filename(enum smb_search_data_level level
,
208 const union smb_search_data
*info
,
209 struct clilist_file_info
*finfo
)
211 struct clilist_file_info finfo2
;
213 if (!finfo
) finfo
= &finfo2
;
217 case RAW_SEARCH_DATA_SEARCH
:
218 finfo
->mtime
= info
->search
.write_time
;
219 finfo
->size
= info
->search
.size
;
220 finfo
->attrib
= info
->search
.attrib
;
221 finfo
->name
= info
->search
.name
;
222 finfo
->short_name
= info
->search
.name
;
226 DEBUG(0,("Unhandled level %d in interpret_short_filename\n", (int)level
));
233 /* callback function used for smb_search */
234 static bool smbcli_list_old_callback(void *private_data
, const union smb_search_data
*file
)
236 struct search_private
*state
= (struct search_private
*) private_data
;
237 struct clilist_file_info
*tdl
;
239 /* add file info to the dirlist pool */
240 tdl
= talloc_realloc(state
,
242 struct clilist_file_info
,
243 state
->dirlist_len
+ 1);
248 state
->dirlist
= tdl
;
249 state
->dirlist_len
++;
251 interpret_short_filename(state
->data_level
, file
, &state
->dirlist
[state
->total_received
]);
253 state
->total_received
++;
254 state
->ff_searchcount
++;
255 state
->id
= file
->search
.id
; /* return resume info */
260 int smbcli_list_old(struct smbcli_tree
*tree
, const char *Mask
, uint16_t attribute
,
261 void (*fn
)(struct clilist_file_info
*, const char *, void *),
264 union smb_search_first first_parms
;
265 union smb_search_next next_parms
;
266 struct search_private state
; /* for callbacks */
267 const int num_asked
= 500;
270 int num_received
= 0;
274 /* initialize state for search */
275 state
.mem_ctx
= talloc_init("smbcli_list_old");
276 state
.dirlist_len
= 0;
277 state
.total_received
= 0;
278 state
.data_level
= RAW_SEARCH_DATA_SEARCH
;
280 state
.dirlist
= talloc_array(state
.mem_ctx
, struct clilist_file_info
,
282 mask
= talloc_strdup(state
.mem_ctx
, Mask
);
285 state
.ff_searchcount
= 0;
289 first_parms
.search_first
.level
= RAW_SEARCH_SEARCH
;
290 first_parms
.search_first
.data_level
= RAW_SEARCH_DATA_SEARCH
;
291 first_parms
.search_first
.in
.max_count
= num_asked
;
292 first_parms
.search_first
.in
.search_attrib
= attribute
;
293 first_parms
.search_first
.in
.pattern
= mask
;
295 status
= smb_raw_search_first(tree
, state
.mem_ctx
,
298 smbcli_list_old_callback
);
300 if (!NT_STATUS_IS_OK(status
)) {
301 talloc_free(state
.mem_ctx
);
305 received
= first_parms
.search_first
.out
.count
;
306 if (received
<= 0) break;
311 next_parms
.search_next
.level
= RAW_SEARCH_SEARCH
;
312 next_parms
.search_next
.data_level
= RAW_SEARCH_DATA_SEARCH
;
313 next_parms
.search_next
.in
.max_count
= num_asked
;
314 next_parms
.search_next
.in
.search_attrib
= attribute
;
315 next_parms
.search_next
.in
.id
= state
.id
;
317 status
= smb_raw_search_next(tree
, state
.mem_ctx
,
320 smbcli_list_old_callback
);
322 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
325 if (!NT_STATUS_IS_OK(status
)) {
326 talloc_free(state
.mem_ctx
);
329 received
= next_parms
.search_next
.out
.count
;
330 if (received
<= 0) break;
333 num_received
+= received
;
336 for (i
=0;i
<state
.total_received
;i
++) {
337 fn(&state
.dirlist
[i
], Mask
, caller_state
);
340 talloc_free(state
.mem_ctx
);
342 return state
.total_received
;
345 /****************************************************************************
346 Do a directory listing, calling fn on each file found.
347 This auto-switches between old and new style.
348 ****************************************************************************/
350 int smbcli_list(struct smbcli_tree
*tree
, const char *Mask
,uint16_t attribute
,
351 void (*fn
)(struct clilist_file_info
*, const char *, void *), void *state
)
353 if (tree
->session
->transport
->negotiate
.protocol
<= PROTOCOL_LANMAN1
)
354 return smbcli_list_old(tree
, Mask
, attribute
, fn
, state
);
355 return smbcli_list_new(tree
, Mask
, attribute
, RAW_SEARCH_DATA_GENERIC
, fn
, state
);