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 max_matches
= 512;
116 /* initialize state for search */
117 state
.mem_ctx
= talloc_init("smbcli_list_new");
118 state
.dirlist_len
= 0;
119 state
.total_received
= 0;
121 state
.dirlist
= talloc_array(state
.mem_ctx
,
122 struct clilist_file_info
, 0);
123 mask
= talloc_strdup(state
.mem_ctx
, Mask
);
125 if (level
== RAW_SEARCH_DATA_GENERIC
) {
126 if (tree
->session
->transport
->negotiate
.capabilities
& CAP_NT_SMBS
) {
127 level
= RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
;
129 level
= RAW_SEARCH_DATA_STANDARD
;
132 state
.data_level
= level
;
135 state
.ff_searchcount
= 0;
139 first_parms
.t2ffirst
.level
= RAW_SEARCH_TRANS2
;
140 first_parms
.t2ffirst
.data_level
= state
.data_level
;
141 first_parms
.t2ffirst
.in
.max_count
= max_matches
;
142 first_parms
.t2ffirst
.in
.search_attrib
= attribute
;
143 first_parms
.t2ffirst
.in
.pattern
= mask
;
144 first_parms
.t2ffirst
.in
.flags
= FLAG_TRANS2_FIND_CLOSE_IF_END
;
145 first_parms
.t2ffirst
.in
.storage_type
= 0;
147 status
= smb_raw_search_first(tree
,
148 state
.mem_ctx
, &first_parms
,
149 (void*)&state
, smbcli_list_new_callback
);
150 if (!NT_STATUS_IS_OK(status
)) {
151 talloc_free(state
.mem_ctx
);
155 ff_dir_handle
= first_parms
.t2ffirst
.out
.handle
;
156 ff_eos
= first_parms
.t2ffirst
.out
.end_of_search
;
158 received
= first_parms
.t2ffirst
.out
.count
;
159 if (received
<= 0) break;
165 next_parms
.t2fnext
.level
= RAW_SEARCH_TRANS2
;
166 next_parms
.t2fnext
.data_level
= state
.data_level
;
167 next_parms
.t2fnext
.in
.max_count
= max_matches
;
168 next_parms
.t2fnext
.in
.last_name
= state
.last_name
;
169 next_parms
.t2fnext
.in
.handle
= ff_dir_handle
;
170 next_parms
.t2fnext
.in
.resume_key
= 0;
171 next_parms
.t2fnext
.in
.flags
= FLAG_TRANS2_FIND_CLOSE_IF_END
;
173 status
= smb_raw_search_next(tree
,
177 smbcli_list_new_callback
);
179 if (!NT_STATUS_IS_OK(status
)) {
182 ff_eos
= next_parms
.t2fnext
.out
.end_of_search
;
183 received
= next_parms
.t2fnext
.out
.count
;
184 if (received
<= 0) break;
189 for (i
=0;i
<state
.total_received
;i
++) {
190 fn(&state
.dirlist
[i
], Mask
, caller_state
);
193 talloc_free(state
.mem_ctx
);
195 return state
.total_received
;
198 /****************************************************************************
199 Interpret a short filename structure.
200 The length of the structure is returned.
201 ****************************************************************************/
202 static bool interpret_short_filename(enum smb_search_data_level level
,
203 const union smb_search_data
*info
,
204 struct clilist_file_info
*finfo
)
206 struct clilist_file_info finfo2
;
208 if (!finfo
) finfo
= &finfo2
;
212 case RAW_SEARCH_DATA_SEARCH
:
213 finfo
->mtime
= info
->search
.write_time
;
214 finfo
->size
= info
->search
.size
;
215 finfo
->attrib
= info
->search
.attrib
;
216 finfo
->name
= info
->search
.name
;
217 finfo
->short_name
= info
->search
.name
;
221 DEBUG(0,("Unhandled level %d in interpret_short_filename\n", (int)level
));
228 /* callback function used for smb_search */
229 static bool smbcli_list_old_callback(void *private_data
, const union smb_search_data
*file
)
231 struct search_private
*state
= (struct search_private
*) private_data
;
232 struct clilist_file_info
*tdl
;
234 /* add file info to the dirlist pool */
235 tdl
= talloc_realloc(state
,
237 struct clilist_file_info
,
238 state
->dirlist_len
+ 1);
243 state
->dirlist
= tdl
;
244 state
->dirlist_len
++;
246 interpret_short_filename(state
->data_level
, file
, &state
->dirlist
[state
->total_received
]);
248 state
->total_received
++;
249 state
->ff_searchcount
++;
250 state
->id
= file
->search
.id
; /* return resume info */
255 int smbcli_list_old(struct smbcli_tree
*tree
, const char *Mask
, uint16_t attribute
,
256 void (*fn
)(struct clilist_file_info
*, const char *, void *),
259 union smb_search_first first_parms
;
260 union smb_search_next next_parms
;
261 struct search_private state
; /* for callbacks */
262 const int num_asked
= 500;
268 /* initialize state for search */
269 state
.mem_ctx
= talloc_init("smbcli_list_old");
270 state
.dirlist_len
= 0;
271 state
.total_received
= 0;
272 state
.data_level
= RAW_SEARCH_DATA_SEARCH
;
274 state
.dirlist
= talloc_array(state
.mem_ctx
, struct clilist_file_info
,
276 mask
= talloc_strdup(state
.mem_ctx
, Mask
);
279 state
.ff_searchcount
= 0;
283 first_parms
.search_first
.level
= RAW_SEARCH_SEARCH
;
284 first_parms
.search_first
.data_level
= RAW_SEARCH_DATA_SEARCH
;
285 first_parms
.search_first
.in
.max_count
= num_asked
;
286 first_parms
.search_first
.in
.search_attrib
= attribute
;
287 first_parms
.search_first
.in
.pattern
= mask
;
289 status
= smb_raw_search_first(tree
, state
.mem_ctx
,
292 smbcli_list_old_callback
);
294 if (!NT_STATUS_IS_OK(status
)) {
295 talloc_free(state
.mem_ctx
);
299 received
= first_parms
.search_first
.out
.count
;
300 if (received
<= 0) break;
305 next_parms
.search_next
.level
= RAW_SEARCH_SEARCH
;
306 next_parms
.search_next
.data_level
= RAW_SEARCH_DATA_SEARCH
;
307 next_parms
.search_next
.in
.max_count
= num_asked
;
308 next_parms
.search_next
.in
.search_attrib
= attribute
;
309 next_parms
.search_next
.in
.id
= state
.id
;
311 status
= smb_raw_search_next(tree
, state
.mem_ctx
,
314 smbcli_list_old_callback
);
316 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
319 if (!NT_STATUS_IS_OK(status
)) {
320 talloc_free(state
.mem_ctx
);
323 received
= next_parms
.search_next
.out
.count
;
324 if (received
<= 0) break;
328 for (i
=0;i
<state
.total_received
;i
++) {
329 fn(&state
.dirlist
[i
], Mask
, caller_state
);
332 talloc_free(state
.mem_ctx
);
334 return state
.total_received
;
337 /****************************************************************************
338 Do a directory listing, calling fn on each file found.
339 This auto-switches between old and new style.
340 ****************************************************************************/
342 int smbcli_list(struct smbcli_tree
*tree
, const char *Mask
,uint16_t attribute
,
343 void (*fn
)(struct clilist_file_info
*, const char *, void *), void *state
)
345 if (tree
->session
->transport
->negotiate
.protocol
<= PROTOCOL_LANMAN1
)
346 return smbcli_list_old(tree
, Mask
, attribute
, fn
, state
);
347 return smbcli_list_new(tree
, Mask
, attribute
, RAW_SEARCH_DATA_GENERIC
, fn
, state
);