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 39364 : 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 134 : struct clilist_file_info finfo2;
46 :
47 39364 : if (!finfo) finfo = &finfo2;
48 39364 : ZERO_STRUCTP(finfo);
49 :
50 39364 : 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 39364 : case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
60 39364 : finfo->size = info->both_directory_info.size;
61 39364 : finfo->mtime = nt_time_to_unix(info->both_directory_info.write_time);
62 39364 : finfo->attrib = info->both_directory_info.attrib;
63 39364 : finfo->short_name = info->both_directory_info.short_name.s;
64 39364 : finfo->name = info->both_directory_info.name.s;
65 39364 : 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 39230 : return true;
73 : }
74 :
75 : /* callback function used for trans2 search */
76 39364 : static bool smbcli_list_new_callback(void *private_data, const union smb_search_data *file)
77 : {
78 39364 : struct search_private *state = (struct search_private*) private_data;
79 134 : struct clilist_file_info *tdl;
80 :
81 : /* add file info to the dirlist pool */
82 39364 : tdl = talloc_realloc(state,
83 : state->dirlist,
84 : struct clilist_file_info,
85 : state->dirlist_len + 1);
86 39364 : if (!tdl) {
87 0 : return false;
88 : }
89 39364 : state->dirlist = tdl;
90 39364 : state->dirlist_len++;
91 :
92 39364 : interpret_long_filename(state->data_level, file, &state->dirlist[state->total_received]);
93 :
94 39364 : state->last_name = state->dirlist[state->total_received].name;
95 39364 : state->total_received++;
96 39364 : state->ff_searchcount++;
97 :
98 39364 : return true;
99 : }
100 :
101 8710 : 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 88 : union smb_search_first first_parms;
107 88 : union smb_search_next next_parms;
108 88 : struct search_private state; /* for callbacks */
109 8710 : int received = 0;
110 8710 : bool first = true;
111 8710 : int max_matches = 512;
112 88 : char *mask;
113 8710 : int ff_eos = 0, i;
114 8710 : int ff_dir_handle=0;
115 :
116 : /* initialize state for search */
117 8710 : state.mem_ctx = talloc_init("smbcli_list_new");
118 8710 : state.dirlist_len = 0;
119 8710 : state.total_received = 0;
120 :
121 8710 : state.dirlist = talloc_array(state.mem_ctx,
122 : struct clilist_file_info, 0);
123 8710 : mask = talloc_strdup(state.mem_ctx, Mask);
124 :
125 8710 : if (level == RAW_SEARCH_DATA_GENERIC) {
126 8310 : if (tree->session->transport->negotiate.capabilities & CAP_NT_SMBS) {
127 8222 : level = RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO;
128 : } else {
129 0 : level = RAW_SEARCH_DATA_STANDARD;
130 : }
131 : }
132 8710 : state.data_level = level;
133 :
134 88 : while (1) {
135 8736 : state.ff_searchcount = 0;
136 8736 : if (first) {
137 88 : NTSTATUS status;
138 :
139 8710 : first_parms.t2ffirst.level = RAW_SEARCH_TRANS2;
140 8710 : first_parms.t2ffirst.data_level = state.data_level;
141 8710 : first_parms.t2ffirst.in.max_count = max_matches;
142 8710 : first_parms.t2ffirst.in.search_attrib = attribute;
143 8710 : first_parms.t2ffirst.in.pattern = mask;
144 8710 : first_parms.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
145 8710 : first_parms.t2ffirst.in.storage_type = 0;
146 :
147 8710 : status = smb_raw_search_first(tree,
148 : state.mem_ctx, &first_parms,
149 : (void*)&state, smbcli_list_new_callback);
150 8710 : if (!NT_STATUS_IS_OK(status)) {
151 641 : talloc_free(state.mem_ctx);
152 641 : return -1;
153 : }
154 :
155 8069 : ff_dir_handle = first_parms.t2ffirst.out.handle;
156 8069 : ff_eos = first_parms.t2ffirst.out.end_of_search;
157 :
158 8069 : received = first_parms.t2ffirst.out.count;
159 16034 : if (received <= 0) break;
160 8069 : if (ff_eos) break;
161 26 : first = false;
162 : } else {
163 0 : NTSTATUS status;
164 :
165 26 : next_parms.t2fnext.level = RAW_SEARCH_TRANS2;
166 26 : next_parms.t2fnext.data_level = state.data_level;
167 26 : next_parms.t2fnext.in.max_count = max_matches;
168 26 : next_parms.t2fnext.in.last_name = state.last_name;
169 26 : next_parms.t2fnext.in.handle = ff_dir_handle;
170 26 : next_parms.t2fnext.in.resume_key = 0;
171 26 : next_parms.t2fnext.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
172 :
173 26 : status = smb_raw_search_next(tree,
174 : state.mem_ctx,
175 : &next_parms,
176 : (void*)&state,
177 : smbcli_list_new_callback);
178 :
179 26 : if (!NT_STATUS_IS_OK(status)) {
180 0 : return -1;
181 : }
182 26 : ff_eos = next_parms.t2fnext.out.end_of_search;
183 26 : received = next_parms.t2fnext.out.count;
184 52 : if (received <= 0) break;
185 26 : if (ff_eos) break;
186 : }
187 : }
188 :
189 47433 : for (i=0;i<state.total_received;i++) {
190 39364 : fn(&state.dirlist[i], Mask, caller_state);
191 : }
192 :
193 8069 : talloc_free(state.mem_ctx);
194 :
195 8069 : return state.total_received;
196 : }
197 :
198 : /****************************************************************************
199 : Interpret a short filename structure.
200 : The length of the structure is returned.
201 : ****************************************************************************/
202 24024 : 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 0 : struct clilist_file_info finfo2;
207 :
208 24024 : if (!finfo) finfo = &finfo2;
209 24024 : ZERO_STRUCTP(finfo);
210 :
211 24024 : switch (level) {
212 24024 : case RAW_SEARCH_DATA_SEARCH:
213 24024 : finfo->mtime = info->search.write_time;
214 24024 : finfo->size = info->search.size;
215 24024 : finfo->attrib = info->search.attrib;
216 24024 : finfo->name = info->search.name;
217 24024 : finfo->short_name = info->search.name;
218 24024 : 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 24024 : return true;
226 : }
227 :
228 : /* callback function used for smb_search */
229 24024 : static bool smbcli_list_old_callback(void *private_data, const union smb_search_data *file)
230 : {
231 24024 : struct search_private *state = (struct search_private*) private_data;
232 0 : struct clilist_file_info *tdl;
233 :
234 : /* add file info to the dirlist pool */
235 24024 : tdl = talloc_realloc(state,
236 : state->dirlist,
237 : struct clilist_file_info,
238 : state->dirlist_len + 1);
239 :
240 24024 : if (!tdl) {
241 0 : return false;
242 : }
243 24024 : state->dirlist = tdl;
244 24024 : state->dirlist_len++;
245 :
246 24024 : interpret_short_filename(state->data_level, file, &state->dirlist[state->total_received]);
247 :
248 24024 : state->total_received++;
249 24024 : state->ff_searchcount++;
250 24024 : state->id = file->search.id; /* return resume info */
251 :
252 24024 : return true;
253 : }
254 :
255 18 : 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 0 : union smb_search_first first_parms;
260 0 : union smb_search_next next_parms;
261 0 : struct search_private state; /* for callbacks */
262 18 : const int num_asked = 500;
263 18 : int received = 0;
264 18 : bool first = true;
265 0 : char *mask;
266 0 : int i;
267 :
268 : /* initialize state for search */
269 18 : state.mem_ctx = talloc_init("smbcli_list_old");
270 18 : state.dirlist_len = 0;
271 18 : state.total_received = 0;
272 18 : state.data_level = RAW_SEARCH_DATA_SEARCH;
273 :
274 18 : state.dirlist = talloc_array(state.mem_ctx, struct clilist_file_info,
275 : 0);
276 18 : mask = talloc_strdup(state.mem_ctx, Mask);
277 :
278 0 : while (1) {
279 78 : state.ff_searchcount = 0;
280 78 : if (first) {
281 0 : NTSTATUS status;
282 :
283 18 : first_parms.search_first.level = RAW_SEARCH_SEARCH;
284 18 : first_parms.search_first.data_level = RAW_SEARCH_DATA_SEARCH;
285 18 : first_parms.search_first.in.max_count = num_asked;
286 18 : first_parms.search_first.in.search_attrib = attribute;
287 18 : first_parms.search_first.in.pattern = mask;
288 :
289 18 : status = smb_raw_search_first(tree, state.mem_ctx,
290 : &first_parms,
291 : (void*)&state,
292 : smbcli_list_old_callback);
293 :
294 18 : if (!NT_STATUS_IS_OK(status)) {
295 0 : talloc_free(state.mem_ctx);
296 0 : return -1;
297 : }
298 :
299 18 : received = first_parms.search_first.out.count;
300 18 : if (received <= 0) break;
301 18 : first = false;
302 : } else {
303 0 : NTSTATUS status;
304 :
305 60 : next_parms.search_next.level = RAW_SEARCH_SEARCH;
306 60 : next_parms.search_next.data_level = RAW_SEARCH_DATA_SEARCH;
307 60 : next_parms.search_next.in.max_count = num_asked;
308 60 : next_parms.search_next.in.search_attrib = attribute;
309 60 : next_parms.search_next.in.id = state.id;
310 :
311 60 : status = smb_raw_search_next(tree, state.mem_ctx,
312 : &next_parms,
313 : (void*)&state,
314 : smbcli_list_old_callback);
315 :
316 60 : if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
317 0 : break;
318 : }
319 60 : if (!NT_STATUS_IS_OK(status)) {
320 0 : talloc_free(state.mem_ctx);
321 0 : return -1;
322 : }
323 60 : received = next_parms.search_next.out.count;
324 60 : if (received <= 0) break;
325 : }
326 : }
327 :
328 24042 : for (i=0;i<state.total_received;i++) {
329 24024 : fn(&state.dirlist[i], Mask, caller_state);
330 : }
331 :
332 18 : talloc_free(state.mem_ctx);
333 :
334 18 : 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 8310 : 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 8310 : if (tree->session->transport->negotiate.protocol <= PROTOCOL_LANMAN1)
346 0 : return smbcli_list_old(tree, Mask, attribute, fn, state);
347 8310 : return smbcli_list_new(tree, Mask, attribute, RAW_SEARCH_DATA_GENERIC, fn, state);
348 : }
|