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_state *cli, const char *Mask, uint16 attribute,
85 void (*fn)(file_info *, const char *, void *), void *caller_state)
87 union smb_search_first first_parms;
88 union smb_search_next next_parms;
89 struct search_private state; /* for callbacks */
93 int max_matches = 512;
95 int ff_eos = 0, i, ff_searchcount;
99 /* initialize state for search */
100 state.dirlist = NULL;
101 state.mem_ctx = talloc_init("cli_list_new");
102 state.dirlist_len = 0;
103 state.total_received = 0;
105 mask = talloc_strdup(state.mem_ctx, Mask);
107 if (cli->transport->negotiate.capabilities & CAP_NT_SMBS) {
108 level = RAW_SEARCH_BOTH_DIRECTORY_INFO;
110 level = RAW_SEARCH_STANDARD;
114 state.ff_searchcount = 0;
118 first_parms.t2ffirst.level = level;
119 first_parms.t2ffirst.in.max_count = max_matches;
120 first_parms.t2ffirst.in.search_attrib = attribute;
121 first_parms.t2ffirst.in.pattern = mask;
122 first_parms.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
123 first_parms.t2ffirst.in.storage_type = 0;
125 status = smb_raw_search_first(cli->tree,
126 state.mem_ctx, &first_parms,
127 (void*)&state, cli_list_new_callback);
128 if (!NT_STATUS_IS_OK(status)) {
129 talloc_destroy(state.mem_ctx);
133 ff_dir_handle = first_parms.t2ffirst.out.handle;
134 ff_searchcount = first_parms.t2ffirst.out.count;
135 ff_eos = first_parms.t2ffirst.out.end_of_search;
137 received = first_parms.t2ffirst.out.count;
138 if (received <= 0) break;
144 next_parms.t2fnext.level = level;
145 next_parms.t2fnext.in.max_count = max_matches;
146 next_parms.t2fnext.in.last_name = mask;
147 next_parms.t2fnext.in.handle = ff_dir_handle;
148 next_parms.t2fnext.in.resume_key = 0;
149 next_parms.t2fnext.in.flags = FLAG_TRANS2_FIND_CONTINUE | FLAG_TRANS2_FIND_CLOSE_IF_END;
151 status = smb_raw_search_next(cli->tree,
155 cli_list_new_callback);
157 if (!NT_STATUS_IS_OK(status)) {
160 ff_searchcount = next_parms.t2fnext.out.count;
161 ff_eos = next_parms.t2fnext.out.end_of_search;
162 received = next_parms.t2fnext.out.count;
163 if (received <= 0) break;
167 num_received += received;
170 for (i=0;i<state.total_received;i++) {
171 fn(&state.dirlist[i], Mask, caller_state);
174 talloc_destroy(state.mem_ctx);
176 return state.total_received;
179 /****************************************************************************
180 Interpret a short filename structure.
181 The length of the structure is returned.
182 ****************************************************************************/
183 static BOOL interpret_short_filename(int level,
184 union smb_search_data *info,
189 if (!finfo) finfo = &finfo2;
192 finfo->ctime = info->search.write_time;
193 finfo->atime = info->search.write_time;
194 finfo->mtime = info->search.write_time;
195 finfo->size = info->search.size;
196 finfo->mode = info->search.attrib;
197 finfo->name = info->search.name;
201 /* callback function used for smb_search */
202 static BOOL cli_list_old_callback(void *private, union smb_search_data *file)
204 struct search_private *state = (struct search_private*) private;
207 /* add file info to the dirlist pool */
208 tdl = talloc_realloc(state->mem_ctx, state->dirlist,
209 state->dirlist_len + sizeof(struct file_info));
214 state->dirlist = tdl;
215 state->dirlist_len += sizeof(struct file_info);
217 interpret_short_filename(state->info_level, file, &state->dirlist[state->total_received]);
219 state->total_received++;
220 state->ff_searchcount++;
221 state->status = file->search.search_id; /* return resume info */
226 int cli_list_old(struct cli_state *cli, const char *Mask, uint16 attribute,
227 void (*fn)(file_info *, const char *, void *), void *caller_state)
229 union smb_search_first first_parms;
230 union smb_search_next next_parms;
231 struct search_private state; /* for callbacks */
232 const int num_asked = 500;
235 int num_received = 0;
239 /* initialize state for search */
240 state.dirlist = NULL;
241 state.mem_ctx = talloc_init("cli_list_old");
242 state.dirlist_len = 0;
243 state.total_received = 0;
245 mask = talloc_strdup(state.mem_ctx, Mask);
248 state.ff_searchcount = 0;
252 first_parms.search_first.level = RAW_SEARCH_SEARCH;
253 first_parms.search_first.in.max_count = num_asked;
254 first_parms.search_first.in.search_attrib = attribute;
255 first_parms.search_first.in.pattern = mask;
257 status = smb_raw_search_first(cli->tree, state.mem_ctx,
260 cli_list_old_callback);
261 if (!NT_STATUS_IS_OK(status)) {
262 talloc_destroy(state.mem_ctx);
266 received = first_parms.search_first.out.count;
267 if (received <= 0) break;
272 next_parms.search_next.level = RAW_SEARCH_SEARCH;
273 next_parms.search_next.in.max_count = num_asked;
274 next_parms.search_next.in.search_attrib = attribute;
275 next_parms.search_next.in.search_id = state.status;
277 status = smb_raw_search_next(cli->tree, state.mem_ctx,
280 cli_list_old_callback);
282 if (!NT_STATUS_IS_OK(status)) {
283 talloc_destroy(state.mem_ctx);
286 received = next_parms.search_next.out.count;
287 if (received <= 0) break;
290 num_received += received;
293 for (i=0;i<state.total_received;i++) {
294 fn(&state.dirlist[i], Mask, caller_state);
297 talloc_destroy(state.mem_ctx);
299 return state.total_received;
302 /****************************************************************************
303 Do a directory listing, calling fn on each file found.
304 This auto-switches between old and new style.
305 ****************************************************************************/
307 int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
308 void (*fn)(file_info *, const char *, void *), void *state)
310 if (cli->transport->negotiate.protocol <= PROTOCOL_LANMAN1)
311 return cli_list_old(cli, Mask, attribute, fn, state);
312 return cli_list_new(cli, Mask, attribute, fn, state);