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;
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_eos
= first_parms
.t2ffirst
.out
.end_of_search
;
159 received
= first_parms
.t2ffirst
.out
.count
;
160 if (received
<= 0) break;
166 next_parms
.t2fnext
.level
= RAW_SEARCH_TRANS2
;
167 next_parms
.t2fnext
.data_level
= state
.data_level
;
168 next_parms
.t2fnext
.in
.max_count
= max_matches
;
169 next_parms
.t2fnext
.in
.last_name
= state
.last_name
;
170 next_parms
.t2fnext
.in
.handle
= ff_dir_handle
;
171 next_parms
.t2fnext
.in
.resume_key
= 0;
172 next_parms
.t2fnext
.in
.flags
= FLAG_TRANS2_FIND_CLOSE_IF_END
;
174 status
= smb_raw_search_next(tree
,
178 smbcli_list_new_callback
);
180 if (!NT_STATUS_IS_OK(status
)) {
183 ff_eos
= next_parms
.t2fnext
.out
.end_of_search
;
184 received
= next_parms
.t2fnext
.out
.count
;
185 if (received
<= 0) break;
189 num_received
+= received
;
192 for (i
=0;i
<state
.total_received
;i
++) {
193 fn(&state
.dirlist
[i
], Mask
, caller_state
);
196 talloc_free(state
.mem_ctx
);
198 return state
.total_received
;
201 /****************************************************************************
202 Interpret a short filename structure.
203 The length of the structure is returned.
204 ****************************************************************************/
205 static bool interpret_short_filename(enum smb_search_data_level level
,
206 const union smb_search_data
*info
,
207 struct clilist_file_info
*finfo
)
209 struct clilist_file_info finfo2
;
211 if (!finfo
) finfo
= &finfo2
;
215 case RAW_SEARCH_DATA_SEARCH
:
216 finfo
->mtime
= info
->search
.write_time
;
217 finfo
->size
= info
->search
.size
;
218 finfo
->attrib
= info
->search
.attrib
;
219 finfo
->name
= info
->search
.name
;
220 finfo
->short_name
= info
->search
.name
;
224 DEBUG(0,("Unhandled level %d in interpret_short_filename\n", (int)level
));
231 /* callback function used for smb_search */
232 static bool smbcli_list_old_callback(void *private_data
, const union smb_search_data
*file
)
234 struct search_private
*state
= (struct search_private
*) private_data
;
235 struct clilist_file_info
*tdl
;
237 /* add file info to the dirlist pool */
238 tdl
= talloc_realloc(state
,
240 struct clilist_file_info
,
241 state
->dirlist_len
+ 1);
246 state
->dirlist
= tdl
;
247 state
->dirlist_len
++;
249 interpret_short_filename(state
->data_level
, file
, &state
->dirlist
[state
->total_received
]);
251 state
->total_received
++;
252 state
->ff_searchcount
++;
253 state
->id
= file
->search
.id
; /* return resume info */
258 int smbcli_list_old(struct smbcli_tree
*tree
, const char *Mask
, uint16_t attribute
,
259 void (*fn
)(struct clilist_file_info
*, const char *, void *),
262 union smb_search_first first_parms
;
263 union smb_search_next next_parms
;
264 struct search_private state
; /* for callbacks */
265 const int num_asked
= 500;
268 int num_received
= 0;
272 /* initialize state for search */
273 state
.mem_ctx
= talloc_init("smbcli_list_old");
274 state
.dirlist_len
= 0;
275 state
.total_received
= 0;
276 state
.data_level
= RAW_SEARCH_DATA_SEARCH
;
278 state
.dirlist
= talloc_array(state
.mem_ctx
, struct clilist_file_info
,
280 mask
= talloc_strdup(state
.mem_ctx
, Mask
);
283 state
.ff_searchcount
= 0;
287 first_parms
.search_first
.level
= RAW_SEARCH_SEARCH
;
288 first_parms
.search_first
.data_level
= RAW_SEARCH_DATA_SEARCH
;
289 first_parms
.search_first
.in
.max_count
= num_asked
;
290 first_parms
.search_first
.in
.search_attrib
= attribute
;
291 first_parms
.search_first
.in
.pattern
= mask
;
293 status
= smb_raw_search_first(tree
, state
.mem_ctx
,
296 smbcli_list_old_callback
);
298 if (!NT_STATUS_IS_OK(status
)) {
299 talloc_free(state
.mem_ctx
);
303 received
= first_parms
.search_first
.out
.count
;
304 if (received
<= 0) break;
309 next_parms
.search_next
.level
= RAW_SEARCH_SEARCH
;
310 next_parms
.search_next
.data_level
= RAW_SEARCH_DATA_SEARCH
;
311 next_parms
.search_next
.in
.max_count
= num_asked
;
312 next_parms
.search_next
.in
.search_attrib
= attribute
;
313 next_parms
.search_next
.in
.id
= state
.id
;
315 status
= smb_raw_search_next(tree
, state
.mem_ctx
,
318 smbcli_list_old_callback
);
320 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
323 if (!NT_STATUS_IS_OK(status
)) {
324 talloc_free(state
.mem_ctx
);
327 received
= next_parms
.search_next
.out
.count
;
328 if (received
<= 0) break;
331 num_received
+= received
;
334 for (i
=0;i
<state
.total_received
;i
++) {
335 fn(&state
.dirlist
[i
], Mask
, caller_state
);
338 talloc_free(state
.mem_ctx
);
340 return state
.total_received
;
343 /****************************************************************************
344 Do a directory listing, calling fn on each file found.
345 This auto-switches between old and new style.
346 ****************************************************************************/
348 int smbcli_list(struct smbcli_tree
*tree
, const char *Mask
,uint16_t attribute
,
349 void (*fn
)(struct clilist_file_info
*, const char *, void *), void *state
)
351 if (tree
->session
->transport
->negotiate
.protocol
<= PROTOCOL_LANMAN1
)
352 return smbcli_list_old(tree
, Mask
, attribute
, fn
, state
);
353 return smbcli_list_new(tree
, Mask
, attribute
, RAW_SEARCH_DATA_GENERIC
, fn
, state
);