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