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 struct search_private {
28 int ff_searchcount; /* total received in 1 server trip */
29 int total_received; /* total received all together */
31 DATA_BLOB status; /* used for old-style search */
35 /****************************************************************************
36 Interpret a long filename structure.
37 ****************************************************************************/
38 static BOOL interpret_long_filename(int level,
39 union smb_search_data *info,
44 if (!finfo) finfo = &finfo2;
47 finfo->size = info->both_directory_info.size;
48 finfo->ctime = nt_time_to_unix(info->both_directory_info.create_time);
49 finfo->atime = nt_time_to_unix(info->both_directory_info.access_time);
50 finfo->mtime = nt_time_to_unix(info->both_directory_info.write_time);
51 finfo->mode = info->both_directory_info.attrib; /* 32 bit->16 bit attrib */
52 if (info->both_directory_info.short_name.s) {
53 strncpy(finfo->short_name, info->both_directory_info.short_name.s,
54 sizeof(finfo->short_name)-1);
56 finfo->name = info->both_directory_info.name.s;
60 /* callback function used for trans2 search */
61 static BOOL cli_list_new_callback(void *private, union smb_search_data *file)
63 struct search_private *state = (struct search_private*) private;
66 /* add file info to the dirlist pool */
67 tdl = talloc_realloc(state->mem_ctx, state->dirlist,
68 state->dirlist_len + sizeof(struct file_info));
74 state->dirlist_len += sizeof(struct file_info);
76 interpret_long_filename(state->info_level, file, &state->dirlist[state->total_received]);
78 state->total_received++;
79 state->ff_searchcount++;
84 int cli_list_new(struct cli_tree *tree, const char *Mask, uint16_t attribute,
85 void (*fn)(file_info *, const char *, void *),
88 union smb_search_first first_parms;
89 union smb_search_next next_parms;
90 struct search_private state; /* for callbacks */
94 int max_matches = 512;
96 int ff_eos = 0, i, ff_searchcount;
98 enum search_level level;
100 /* initialize state for search */
101 state.dirlist = NULL;
102 state.mem_ctx = talloc_init("cli_list_new");
103 state.dirlist_len = 0;
104 state.total_received = 0;
106 mask = talloc_strdup(state.mem_ctx, Mask);
108 if (tree->session->transport->negotiate.capabilities & CAP_NT_SMBS) {
109 level = RAW_SEARCH_BOTH_DIRECTORY_INFO;
111 level = RAW_SEARCH_STANDARD;
115 state.ff_searchcount = 0;
119 first_parms.t2ffirst.level = level;
120 first_parms.t2ffirst.in.max_count = max_matches;
121 first_parms.t2ffirst.in.search_attrib = attribute;
122 first_parms.t2ffirst.in.pattern = mask;
123 first_parms.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
124 first_parms.t2ffirst.in.storage_type = 0;
126 status = smb_raw_search_first(tree,
127 state.mem_ctx, &first_parms,
128 (void*)&state, cli_list_new_callback);
129 if (!NT_STATUS_IS_OK(status)) {
130 talloc_destroy(state.mem_ctx);
134 ff_dir_handle = first_parms.t2ffirst.out.handle;
135 ff_searchcount = first_parms.t2ffirst.out.count;
136 ff_eos = first_parms.t2ffirst.out.end_of_search;
138 received = first_parms.t2ffirst.out.count;
139 if (received <= 0) break;
145 next_parms.t2fnext.level = level;
146 next_parms.t2fnext.in.max_count = max_matches;
147 next_parms.t2fnext.in.last_name = mask;
148 next_parms.t2fnext.in.handle = ff_dir_handle;
149 next_parms.t2fnext.in.resume_key = 0;
150 next_parms.t2fnext.in.flags = FLAG_TRANS2_FIND_CONTINUE | FLAG_TRANS2_FIND_CLOSE_IF_END;
152 status = smb_raw_search_next(tree,
156 cli_list_new_callback);
158 if (!NT_STATUS_IS_OK(status)) {
161 ff_searchcount = next_parms.t2fnext.out.count;
162 ff_eos = next_parms.t2fnext.out.end_of_search;
163 received = next_parms.t2fnext.out.count;
164 if (received <= 0) break;
168 num_received += received;
171 for (i=0;i<state.total_received;i++) {
172 fn(&state.dirlist[i], Mask, caller_state);
175 talloc_destroy(state.mem_ctx);
177 return state.total_received;
180 /****************************************************************************
181 Interpret a short filename structure.
182 The length of the structure is returned.
183 ****************************************************************************/
184 static BOOL interpret_short_filename(int level,
185 union smb_search_data *info,
190 if (!finfo) finfo = &finfo2;
193 finfo->ctime = info->search.write_time;
194 finfo->atime = info->search.write_time;
195 finfo->mtime = info->search.write_time;
196 finfo->size = info->search.size;
197 finfo->mode = info->search.attrib;
198 finfo->name = info->search.name;
202 /* callback function used for smb_search */
203 static BOOL cli_list_old_callback(void *private, union smb_search_data *file)
205 struct search_private *state = (struct search_private*) private;
208 /* add file info to the dirlist pool */
209 tdl = talloc_realloc(state->mem_ctx, state->dirlist,
210 state->dirlist_len + sizeof(struct file_info));
215 state->dirlist = tdl;
216 state->dirlist_len += sizeof(struct file_info);
218 interpret_short_filename(state->info_level, file, &state->dirlist[state->total_received]);
220 state->total_received++;
221 state->ff_searchcount++;
222 state->status = file->search.search_id; /* return resume info */
227 int cli_list_old(struct cli_tree *tree, const char *Mask, uint16_t attribute,
228 void (*fn)(file_info *, const char *, void *),
231 union smb_search_first first_parms;
232 union smb_search_next next_parms;
233 struct search_private state; /* for callbacks */
234 const int num_asked = 500;
237 int num_received = 0;
241 /* initialize state for search */
242 state.dirlist = NULL;
243 state.mem_ctx = talloc_init("cli_list_old");
244 state.dirlist_len = 0;
245 state.total_received = 0;
247 mask = talloc_strdup(state.mem_ctx, Mask);
250 state.ff_searchcount = 0;
254 first_parms.search_first.level = RAW_SEARCH_SEARCH;
255 first_parms.search_first.in.max_count = num_asked;
256 first_parms.search_first.in.search_attrib = attribute;
257 first_parms.search_first.in.pattern = mask;
259 status = smb_raw_search_first(tree, state.mem_ctx,
262 cli_list_old_callback);
264 if (!NT_STATUS_IS_OK(status)) {
265 talloc_destroy(state.mem_ctx);
269 received = first_parms.search_first.out.count;
270 if (received <= 0) break;
275 next_parms.search_next.level = RAW_SEARCH_SEARCH;
276 next_parms.search_next.in.max_count = num_asked;
277 next_parms.search_next.in.search_attrib = attribute;
278 next_parms.search_next.in.search_id = state.status;
280 status = smb_raw_search_next(tree, state.mem_ctx,
283 cli_list_old_callback);
285 if (!NT_STATUS_IS_OK(status)) {
286 talloc_destroy(state.mem_ctx);
289 received = next_parms.search_next.out.count;
290 if (received <= 0) break;
293 num_received += received;
296 for (i=0;i<state.total_received;i++) {
297 fn(&state.dirlist[i], Mask, caller_state);
300 talloc_destroy(state.mem_ctx);
302 return state.total_received;
305 /****************************************************************************
306 Do a directory listing, calling fn on each file found.
307 This auto-switches between old and new style.
308 ****************************************************************************/
310 int cli_list(struct cli_tree *tree, const char *Mask,uint16_t attribute,
311 void (*fn)(file_info *, const char *, void *), void *state)
313 if (tree->session->transport->negotiate.protocol <= PROTOCOL_LANMAN1)
314 return cli_list_old(tree, Mask, attribute, fn, state);
315 return cli_list_new(tree, Mask, attribute, fn, state);