Line data Source code
1 : /*
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>
6 :
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.
11 :
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.
16 :
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/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "libcli/libcli.h"
23 : #include "libcli/raw/libcliraw.h"
24 : #include "libcli/raw/raw_proto.h"
25 :
26 : struct search_private {
27 : struct clilist_file_info *dirlist;
28 : TALLOC_CTX *mem_ctx;
29 : int dirlist_len;
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 */
35 : };
36 :
37 :
38 : /****************************************************************************
39 : Interpret a long filename structure.
40 : ****************************************************************************/
41 11859 : static bool interpret_long_filename(enum smb_search_data_level level,
42 : const union smb_search_data *info,
43 : struct clilist_file_info *finfo)
44 : {
45 : struct clilist_file_info finfo2;
46 :
47 11859 : if (!finfo) finfo = &finfo2;
48 11859 : ZERO_STRUCTP(finfo);
49 :
50 11859 : switch (level) {
51 0 : case RAW_SEARCH_DATA_STANDARD:
52 0 : finfo->size = info->standard.size;
53 0 : finfo->mtime = info->standard.write_time;
54 0 : finfo->attrib = info->standard.attrib;
55 0 : finfo->name = info->standard.name.s;
56 0 : finfo->short_name = info->standard.name.s;
57 0 : break;
58 :
59 11859 : case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
60 11859 : finfo->size = info->both_directory_info.size;
61 11859 : finfo->mtime = nt_time_to_unix(info->both_directory_info.write_time);
62 11859 : finfo->attrib = info->both_directory_info.attrib;
63 11859 : finfo->short_name = info->both_directory_info.short_name.s;
64 11859 : finfo->name = info->both_directory_info.name.s;
65 11859 : break;
66 :
67 0 : default:
68 0 : DEBUG(0,("Unhandled level %d in interpret_long_filename\n", (int)level));
69 0 : return false;
70 : }
71 :
72 11859 : return true;
73 : }
74 :
75 : /* callback function used for trans2 search */
76 11859 : static bool smbcli_list_new_callback(void *private_data, const union smb_search_data *file)
77 : {
78 11859 : struct search_private *state = (struct search_private*) private_data;
79 : struct clilist_file_info *tdl;
80 :
81 : /* add file info to the dirlist pool */
82 11859 : tdl = talloc_realloc(state,
83 : state->dirlist,
84 : struct clilist_file_info,
85 : state->dirlist_len + 1);
86 11859 : if (!tdl) {
87 0 : return false;
88 : }
89 11859 : state->dirlist = tdl;
90 11859 : state->dirlist_len++;
91 :
92 11859 : interpret_long_filename(state->data_level, file, &state->dirlist[state->total_received]);
93 :
94 11859 : state->last_name = state->dirlist[state->total_received].name;
95 11859 : state->total_received++;
96 11859 : state->ff_searchcount++;
97 :
98 11859 : return true;
99 : }
100 :
101 2876 : 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 *),
104 : void *caller_state)
105 : {
106 : union smb_search_first first_parms;
107 : union smb_search_next next_parms;
108 : struct search_private state; /* for callbacks */
109 2876 : int received = 0;
110 2876 : bool first = true;
111 2876 : int max_matches = 512;
112 : char *mask;
113 2876 : int ff_eos = 0, i;
114 2876 : int ff_dir_handle=0;
115 :
116 : /* initialize state for search */
117 2876 : state.mem_ctx = talloc_init("smbcli_list_new");
118 2876 : state.dirlist_len = 0;
119 2876 : state.total_received = 0;
120 :
121 2876 : state.dirlist = talloc_array(state.mem_ctx,
122 : struct clilist_file_info, 0);
123 2876 : mask = talloc_strdup(state.mem_ctx, Mask);
124 :
125 2876 : if (level == RAW_SEARCH_DATA_GENERIC) {
126 2476 : if (tree->session->transport->negotiate.capabilities & CAP_NT_SMBS) {
127 2476 : level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
128 : } else {
129 0 : level = RAW_SEARCH_DATA_STANDARD;
130 : }
131 : }
132 2876 : state.data_level = level;
133 :
134 : while (1) {
135 2888 : state.ff_searchcount = 0;
136 2882 : if (first) {
137 : NTSTATUS status;
138 :
139 2876 : first_parms.t2ffirst.level = RAW_SEARCH_TRANS2;
140 2876 : first_parms.t2ffirst.data_level = state.data_level;
141 2876 : first_parms.t2ffirst.in.max_count = max_matches;
142 2876 : first_parms.t2ffirst.in.search_attrib = attribute;
143 2876 : first_parms.t2ffirst.in.pattern = mask;
144 2876 : first_parms.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
145 2876 : first_parms.t2ffirst.in.storage_type = 0;
146 :
147 2876 : status = smb_raw_search_first(tree,
148 : state.mem_ctx, &first_parms,
149 : (void*)&state, smbcli_list_new_callback);
150 2876 : if (!NT_STATUS_IS_OK(status)) {
151 265 : talloc_free(state.mem_ctx);
152 265 : return -1;
153 : }
154 :
155 2611 : ff_dir_handle = first_parms.t2ffirst.out.handle;
156 2611 : ff_eos = first_parms.t2ffirst.out.end_of_search;
157 :
158 2611 : received = first_parms.t2ffirst.out.count;
159 5216 : if (received <= 0) break;
160 2611 : if (ff_eos) break;
161 6 : first = false;
162 : } else {
163 : NTSTATUS status;
164 :
165 6 : next_parms.t2fnext.level = RAW_SEARCH_TRANS2;
166 6 : next_parms.t2fnext.data_level = state.data_level;
167 6 : next_parms.t2fnext.in.max_count = max_matches;
168 6 : next_parms.t2fnext.in.last_name = state.last_name;
169 6 : next_parms.t2fnext.in.handle = ff_dir_handle;
170 6 : next_parms.t2fnext.in.resume_key = 0;
171 6 : next_parms.t2fnext.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
172 :
173 6 : status = smb_raw_search_next(tree,
174 : state.mem_ctx,
175 : &next_parms,
176 : (void*)&state,
177 : smbcli_list_new_callback);
178 :
179 6 : if (!NT_STATUS_IS_OK(status)) {
180 0 : return -1;
181 : }
182 6 : ff_eos = next_parms.t2fnext.out.end_of_search;
183 6 : received = next_parms.t2fnext.out.count;
184 12 : if (received <= 0) break;
185 6 : if (ff_eos) break;
186 : }
187 : }
188 :
189 14470 : for (i=0;i<state.total_received;i++) {
190 11859 : fn(&state.dirlist[i], Mask, caller_state);
191 : }
192 :
193 2611 : talloc_free(state.mem_ctx);
194 :
195 2611 : return state.total_received;
196 : }
197 :
198 : /****************************************************************************
199 : Interpret a short filename structure.
200 : The length of the structure is returned.
201 : ****************************************************************************/
202 8008 : static bool interpret_short_filename(enum smb_search_data_level level,
203 : const union smb_search_data *info,
204 : struct clilist_file_info *finfo)
205 : {
206 : struct clilist_file_info finfo2;
207 :
208 8008 : if (!finfo) finfo = &finfo2;
209 8008 : ZERO_STRUCTP(finfo);
210 :
211 8008 : switch (level) {
212 8008 : case RAW_SEARCH_DATA_SEARCH:
213 8008 : finfo->mtime = info->search.write_time;
214 8008 : finfo->size = info->search.size;
215 8008 : finfo->attrib = info->search.attrib;
216 8008 : finfo->name = info->search.name;
217 8008 : finfo->short_name = info->search.name;
218 8008 : break;
219 :
220 0 : default:
221 0 : DEBUG(0,("Unhandled level %d in interpret_short_filename\n", (int)level));
222 0 : return false;
223 : }
224 :
225 8008 : return true;
226 : }
227 :
228 : /* callback function used for smb_search */
229 8008 : static bool smbcli_list_old_callback(void *private_data, const union smb_search_data *file)
230 : {
231 8008 : struct search_private *state = (struct search_private*) private_data;
232 : struct clilist_file_info *tdl;
233 :
234 : /* add file info to the dirlist pool */
235 8008 : tdl = talloc_realloc(state,
236 : state->dirlist,
237 : struct clilist_file_info,
238 : state->dirlist_len + 1);
239 :
240 8008 : if (!tdl) {
241 0 : return false;
242 : }
243 8008 : state->dirlist = tdl;
244 8008 : state->dirlist_len++;
245 :
246 8008 : interpret_short_filename(state->data_level, file, &state->dirlist[state->total_received]);
247 :
248 8008 : state->total_received++;
249 8008 : state->ff_searchcount++;
250 8008 : state->id = file->search.id; /* return resume info */
251 :
252 8008 : return true;
253 : }
254 :
255 6 : int smbcli_list_old(struct smbcli_tree *tree, const char *Mask, uint16_t attribute,
256 : void (*fn)(struct clilist_file_info *, const char *, void *),
257 : void *caller_state)
258 : {
259 : union smb_search_first first_parms;
260 : union smb_search_next next_parms;
261 : struct search_private state; /* for callbacks */
262 6 : const int num_asked = 500;
263 6 : int received = 0;
264 6 : bool first = true;
265 : char *mask;
266 : int i;
267 :
268 : /* initialize state for search */
269 6 : state.mem_ctx = talloc_init("smbcli_list_old");
270 6 : state.dirlist_len = 0;
271 6 : state.total_received = 0;
272 6 : state.data_level = RAW_SEARCH_DATA_SEARCH;
273 :
274 6 : state.dirlist = talloc_array(state.mem_ctx, struct clilist_file_info,
275 : 0);
276 6 : mask = talloc_strdup(state.mem_ctx, Mask);
277 :
278 : while (1) {
279 46 : state.ff_searchcount = 0;
280 26 : if (first) {
281 : NTSTATUS status;
282 :
283 6 : first_parms.search_first.level = RAW_SEARCH_SEARCH;
284 6 : first_parms.search_first.data_level = RAW_SEARCH_DATA_SEARCH;
285 6 : first_parms.search_first.in.max_count = num_asked;
286 6 : first_parms.search_first.in.search_attrib = attribute;
287 6 : first_parms.search_first.in.pattern = mask;
288 :
289 6 : status = smb_raw_search_first(tree, state.mem_ctx,
290 : &first_parms,
291 : (void*)&state,
292 : smbcli_list_old_callback);
293 :
294 6 : if (!NT_STATUS_IS_OK(status)) {
295 0 : talloc_free(state.mem_ctx);
296 0 : return -1;
297 : }
298 :
299 6 : received = first_parms.search_first.out.count;
300 6 : if (received <= 0) break;
301 6 : first = false;
302 : } else {
303 : NTSTATUS status;
304 :
305 20 : next_parms.search_next.level = RAW_SEARCH_SEARCH;
306 20 : next_parms.search_next.data_level = RAW_SEARCH_DATA_SEARCH;
307 20 : next_parms.search_next.in.max_count = num_asked;
308 20 : next_parms.search_next.in.search_attrib = attribute;
309 20 : next_parms.search_next.in.id = state.id;
310 :
311 20 : status = smb_raw_search_next(tree, state.mem_ctx,
312 : &next_parms,
313 : (void*)&state,
314 : smbcli_list_old_callback);
315 :
316 20 : if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
317 6 : break;
318 : }
319 20 : if (!NT_STATUS_IS_OK(status)) {
320 0 : talloc_free(state.mem_ctx);
321 0 : return -1;
322 : }
323 20 : received = next_parms.search_next.out.count;
324 20 : if (received <= 0) break;
325 : }
326 : }
327 :
328 8014 : for (i=0;i<state.total_received;i++) {
329 8008 : fn(&state.dirlist[i], Mask, caller_state);
330 : }
331 :
332 6 : talloc_free(state.mem_ctx);
333 :
334 6 : return state.total_received;
335 : }
336 :
337 : /****************************************************************************
338 : Do a directory listing, calling fn on each file found.
339 : This auto-switches between old and new style.
340 : ****************************************************************************/
341 :
342 2476 : 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)
344 : {
345 2476 : if (tree->session->transport->negotiate.protocol <= PROTOCOL_LANMAN1)
346 0 : return smbcli_list_old(tree, Mask, attribute, fn, state);
347 2476 : return smbcli_list_new(tree, Mask, attribute, RAW_SEARCH_DATA_GENERIC, fn, state);
348 : }
|