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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "libcli/raw/libcliraw.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_level info_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_level level
,
42 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_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_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, union smb_search_data
*file
)
78 struct search_private
*state
= (struct search_private
*) private;
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
->info_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_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_new(state
.mem_ctx
);
123 mask
= talloc_strdup(state
.mem_ctx
, Mask
);
125 if (level
== RAW_SEARCH_GENERIC
) {
126 if (tree
->session
->transport
->negotiate
.capabilities
& CAP_NT_SMBS
) {
127 level
= RAW_SEARCH_BOTH_DIRECTORY_INFO
;
129 level
= RAW_SEARCH_STANDARD
;
132 state
.info_level
= level
;
135 state
.ff_searchcount
= 0;
139 first_parms
.t2ffirst
.level
= state
.info_level
;
140 first_parms
.t2ffirst
.in
.max_count
= max_matches
;
141 first_parms
.t2ffirst
.in
.search_attrib
= attribute
;
142 first_parms
.t2ffirst
.in
.pattern
= mask
;
143 first_parms
.t2ffirst
.in
.flags
= FLAG_TRANS2_FIND_CLOSE_IF_END
;
144 first_parms
.t2ffirst
.in
.storage_type
= 0;
146 status
= smb_raw_search_first(tree
,
147 state
.mem_ctx
, &first_parms
,
148 (void*)&state
, smbcli_list_new_callback
);
149 if (!NT_STATUS_IS_OK(status
)) {
150 talloc_free(state
.mem_ctx
);
154 ff_dir_handle
= first_parms
.t2ffirst
.out
.handle
;
155 ff_searchcount
= first_parms
.t2ffirst
.out
.count
;
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
= state
.info_level
;
166 next_parms
.t2fnext
.in
.max_count
= max_matches
;
167 next_parms
.t2fnext
.in
.last_name
= state
.last_name
;
168 next_parms
.t2fnext
.in
.handle
= ff_dir_handle
;
169 next_parms
.t2fnext
.in
.resume_key
= 0;
170 next_parms
.t2fnext
.in
.flags
= FLAG_TRANS2_FIND_CLOSE_IF_END
;
172 status
= smb_raw_search_next(tree
,
176 smbcli_list_new_callback
);
178 if (!NT_STATUS_IS_OK(status
)) {
181 ff_searchcount
= next_parms
.t2fnext
.out
.count
;
182 ff_eos
= next_parms
.t2fnext
.out
.end_of_search
;
183 received
= next_parms
.t2fnext
.out
.count
;
184 if (received
<= 0) break;
188 num_received
+= received
;
191 for (i
=0;i
<state
.total_received
;i
++) {
192 fn(&state
.dirlist
[i
], Mask
, caller_state
);
195 talloc_free(state
.mem_ctx
);
197 return state
.total_received
;
200 /****************************************************************************
201 Interpret a short filename structure.
202 The length of the structure is returned.
203 ****************************************************************************/
204 static BOOL
interpret_short_filename(int level
,
205 union smb_search_data
*info
,
206 struct clilist_file_info
*finfo
)
208 struct clilist_file_info finfo2
;
210 if (!finfo
) finfo
= &finfo2
;
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 /* callback function used for smb_search */
222 static BOOL
smbcli_list_old_callback(void *private, union smb_search_data
*file
)
224 struct search_private
*state
= (struct search_private
*) private;
225 struct clilist_file_info
*tdl
;
227 /* add file info to the dirlist pool */
228 tdl
= talloc_realloc(state
,
230 struct clilist_file_info
,
231 state
->dirlist_len
+ 1);
236 state
->dirlist
= tdl
;
237 state
->dirlist_len
++;
239 interpret_short_filename(state
->info_level
, file
, &state
->dirlist
[state
->total_received
]);
241 state
->total_received
++;
242 state
->ff_searchcount
++;
243 state
->id
= file
->search
.id
; /* return resume info */
248 int smbcli_list_old(struct smbcli_tree
*tree
, const char *Mask
, uint16_t attribute
,
249 void (*fn
)(struct clilist_file_info
*, const char *, void *),
252 union smb_search_first first_parms
;
253 union smb_search_next next_parms
;
254 struct search_private state
; /* for callbacks */
255 const int num_asked
= 500;
258 int num_received
= 0;
262 /* initialize state for search */
263 state
.mem_ctx
= talloc_init("smbcli_list_old");
264 state
.dirlist_len
= 0;
265 state
.total_received
= 0;
267 state
.dirlist
= talloc_new(state
.mem_ctx
);
268 mask
= talloc_strdup(state
.mem_ctx
, Mask
);
271 state
.ff_searchcount
= 0;
275 first_parms
.search_first
.level
= RAW_SEARCH_SEARCH
;
276 first_parms
.search_first
.in
.max_count
= num_asked
;
277 first_parms
.search_first
.in
.search_attrib
= attribute
;
278 first_parms
.search_first
.in
.pattern
= mask
;
280 status
= smb_raw_search_first(tree
, state
.mem_ctx
,
283 smbcli_list_old_callback
);
285 if (!NT_STATUS_IS_OK(status
)) {
286 talloc_free(state
.mem_ctx
);
290 received
= first_parms
.search_first
.out
.count
;
291 if (received
<= 0) break;
296 next_parms
.search_next
.level
= RAW_SEARCH_SEARCH
;
297 next_parms
.search_next
.in
.max_count
= num_asked
;
298 next_parms
.search_next
.in
.search_attrib
= attribute
;
299 next_parms
.search_next
.in
.id
= state
.id
;
301 status
= smb_raw_search_next(tree
, state
.mem_ctx
,
304 smbcli_list_old_callback
);
306 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
309 if (!NT_STATUS_IS_OK(status
)) {
310 talloc_free(state
.mem_ctx
);
313 received
= next_parms
.search_next
.out
.count
;
314 if (received
<= 0) break;
317 num_received
+= received
;
320 for (i
=0;i
<state
.total_received
;i
++) {
321 fn(&state
.dirlist
[i
], Mask
, caller_state
);
324 talloc_free(state
.mem_ctx
);
326 return state
.total_received
;
329 /****************************************************************************
330 Do a directory listing, calling fn on each file found.
331 This auto-switches between old and new style.
332 ****************************************************************************/
334 int smbcli_list(struct smbcli_tree
*tree
, const char *Mask
,uint16_t attribute
,
335 void (*fn
)(struct clilist_file_info
*, const char *, void *), void *state
)
337 if (tree
->session
->transport
->negotiate
.protocol
<= PROTOCOL_LANMAN1
)
338 return smbcli_list_old(tree
, Mask
, attribute
, fn
, state
);
339 return smbcli_list_new(tree
, Mask
, attribute
, RAW_SEARCH_GENERIC
, fn
, state
);