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 */
30 enum smb_search_level info_level;
31 const char *last_name; /* used to continue trans2 search */
32 DATA_BLOB status; /* used for old-style search */
36 /****************************************************************************
37 Interpret a long filename structure.
38 ****************************************************************************/
39 static BOOL interpret_long_filename(enum smb_search_level level,
40 union smb_search_data *info,
45 if (!finfo) finfo = &finfo2;
49 case RAW_SEARCH_STANDARD:
50 finfo->size = info->standard.size;
51 finfo->ctime = info->standard.create_time;
52 finfo->atime = info->standard.access_time;
53 finfo->mtime = info->standard.write_time;
54 finfo->mode = info->standard.attrib;
55 finfo->name = info->standard.name.s;
58 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
59 finfo->size = info->both_directory_info.size;
60 finfo->ctime = nt_time_to_unix(info->both_directory_info.create_time);
61 finfo->atime = nt_time_to_unix(info->both_directory_info.access_time);
62 finfo->mtime = nt_time_to_unix(info->both_directory_info.write_time);
63 finfo->mode = info->both_directory_info.attrib; /* 32 bit->16 bit attrib */
64 if (info->both_directory_info.short_name.s) {
65 strncpy(finfo->short_name, info->both_directory_info.short_name.s,
66 sizeof(finfo->short_name)-1);
68 finfo->name = info->both_directory_info.name.s;
72 DEBUG(0,("Unhandled level %d in interpret_long_filename\n", (int)level));
79 /* callback function used for trans2 search */
80 static BOOL smbcli_list_new_callback(void *private, union smb_search_data *file)
82 struct search_private *state = (struct search_private*) private;
85 /* add file info to the dirlist pool */
86 tdl = talloc_realloc(state->mem_ctx, state->dirlist,
87 state->dirlist_len + sizeof(struct file_info));
93 state->dirlist_len += sizeof(struct file_info);
95 interpret_long_filename(state->info_level, file, &state->dirlist[state->total_received]);
97 state->last_name = state->dirlist[state->total_received].name;
98 state->total_received++;
99 state->ff_searchcount++;
104 int smbcli_list_new(struct smbcli_tree *tree, const char *Mask, uint16_t attribute,
105 void (*fn)(file_info *, const char *, void *),
108 union smb_search_first first_parms;
109 union smb_search_next next_parms;
110 struct search_private state; /* for callbacks */
113 int num_received = 0;
114 int max_matches = 512;
116 int ff_eos = 0, i, ff_searchcount;
119 /* initialize state for search */
120 state.dirlist = NULL;
121 state.mem_ctx = talloc_init("smbcli_list_new");
122 state.dirlist_len = 0;
123 state.total_received = 0;
125 mask = talloc_strdup(state.mem_ctx, Mask);
127 if (tree->session->transport->negotiate.capabilities & CAP_NT_SMBS) {
128 state.info_level = RAW_SEARCH_BOTH_DIRECTORY_INFO;
130 state.info_level = RAW_SEARCH_STANDARD;
134 state.ff_searchcount = 0;
138 first_parms.t2ffirst.level = state.info_level;
139 first_parms.t2ffirst.in.max_count = max_matches;
140 first_parms.t2ffirst.in.search_attrib = attribute;
141 first_parms.t2ffirst.in.pattern = mask;
142 first_parms.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
143 first_parms.t2ffirst.in.storage_type = 0;
145 status = smb_raw_search_first(tree,
146 state.mem_ctx, &first_parms,
147 (void*)&state, smbcli_list_new_callback);
148 if (!NT_STATUS_IS_OK(status)) {
149 talloc_destroy(state.mem_ctx);
153 ff_dir_handle = first_parms.t2ffirst.out.handle;
154 ff_searchcount = first_parms.t2ffirst.out.count;
155 ff_eos = first_parms.t2ffirst.out.end_of_search;
157 received = first_parms.t2ffirst.out.count;
158 if (received <= 0) break;
164 next_parms.t2fnext.level = state.info_level;
165 next_parms.t2fnext.in.max_count = max_matches;
166 next_parms.t2fnext.in.last_name = state.last_name;
167 next_parms.t2fnext.in.handle = ff_dir_handle;
168 next_parms.t2fnext.in.resume_key = 0;
169 next_parms.t2fnext.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
171 status = smb_raw_search_next(tree,
175 smbcli_list_new_callback);
177 if (!NT_STATUS_IS_OK(status)) {
180 ff_searchcount = next_parms.t2fnext.out.count;
181 ff_eos = next_parms.t2fnext.out.end_of_search;
182 received = next_parms.t2fnext.out.count;
183 if (received <= 0) break;
187 num_received += received;
190 for (i=0;i<state.total_received;i++) {
191 fn(&state.dirlist[i], Mask, caller_state);
194 talloc_destroy(state.mem_ctx);
196 return state.total_received;
199 /****************************************************************************
200 Interpret a short filename structure.
201 The length of the structure is returned.
202 ****************************************************************************/
203 static BOOL interpret_short_filename(int level,
204 union smb_search_data *info,
209 if (!finfo) finfo = &finfo2;
212 finfo->ctime = info->search.write_time;
213 finfo->atime = info->search.write_time;
214 finfo->mtime = info->search.write_time;
215 finfo->size = info->search.size;
216 finfo->mode = info->search.attrib;
217 finfo->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;
227 /* add file info to the dirlist pool */
228 tdl = talloc_realloc(state->mem_ctx, state->dirlist,
229 state->dirlist_len + sizeof(struct file_info));
234 state->dirlist = tdl;
235 state->dirlist_len += sizeof(struct file_info);
237 interpret_short_filename(state->info_level, file, &state->dirlist[state->total_received]);
239 state->total_received++;
240 state->ff_searchcount++;
241 state->status = file->search.search_id; /* return resume info */
246 int smbcli_list_old(struct smbcli_tree *tree, const char *Mask, uint16_t attribute,
247 void (*fn)(file_info *, const char *, void *),
250 union smb_search_first first_parms;
251 union smb_search_next next_parms;
252 struct search_private state; /* for callbacks */
253 const int num_asked = 500;
256 int num_received = 0;
260 /* initialize state for search */
261 state.dirlist = NULL;
262 state.mem_ctx = talloc_init("smbcli_list_old");
263 state.dirlist_len = 0;
264 state.total_received = 0;
266 mask = talloc_strdup(state.mem_ctx, Mask);
269 state.ff_searchcount = 0;
273 first_parms.search_first.level = RAW_SEARCH_SEARCH;
274 first_parms.search_first.in.max_count = num_asked;
275 first_parms.search_first.in.search_attrib = attribute;
276 first_parms.search_first.in.pattern = mask;
278 status = smb_raw_search_first(tree, state.mem_ctx,
281 smbcli_list_old_callback);
283 if (!NT_STATUS_IS_OK(status)) {
284 talloc_destroy(state.mem_ctx);
288 received = first_parms.search_first.out.count;
289 if (received <= 0) break;
294 next_parms.search_next.level = RAW_SEARCH_SEARCH;
295 next_parms.search_next.in.max_count = num_asked;
296 next_parms.search_next.in.search_attrib = attribute;
297 next_parms.search_next.in.search_id = state.status;
299 status = smb_raw_search_next(tree, state.mem_ctx,
302 smbcli_list_old_callback);
304 if (!NT_STATUS_IS_OK(status)) {
305 talloc_destroy(state.mem_ctx);
308 received = next_parms.search_next.out.count;
309 if (received <= 0) break;
312 num_received += received;
315 for (i=0;i<state.total_received;i++) {
316 fn(&state.dirlist[i], Mask, caller_state);
319 talloc_destroy(state.mem_ctx);
321 return state.total_received;
324 /****************************************************************************
325 Do a directory listing, calling fn on each file found.
326 This auto-switches between old and new style.
327 ****************************************************************************/
329 int smbcli_list(struct smbcli_tree *tree, const char *Mask,uint16_t attribute,
330 void (*fn)(file_info *, const char *, void *), void *state)
332 if (tree->session->transport->negotiate.protocol <= PROTOCOL_LANMAN1)
333 return smbcli_list_old(tree, Mask, attribute, fn, state);
334 return smbcli_list_new(tree, Mask, attribute, fn, state);