r873: converted samba4 to use real 64 bit integers instead of
[jelmer/samba4-debian.git] / source / libcli / clilist.c
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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 struct search_private {
25         file_info *dirlist;
26         TALLOC_CTX *mem_ctx;
27         int dirlist_len;
28         int ff_searchcount;  /* total received in 1 server trip */
29         int total_received;  /* total received all together */
30         int info_level;
31         DATA_BLOB status;       /* used for old-style search */
32 };
33
34
35 /****************************************************************************
36  Interpret a long filename structure.
37 ****************************************************************************/
38 static BOOL interpret_long_filename(int level,
39                                     union smb_search_data *info,
40                                     file_info *finfo)
41 {
42         file_info finfo2;
43
44         if (!finfo) finfo = &finfo2;
45         ZERO_STRUCTP(finfo);
46         
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);
55         }
56         finfo->name = info->both_directory_info.name.s;
57         return True;
58 }
59
60 /* callback function used for trans2 search */
61 static BOOL cli_list_new_callback(void *private, union smb_search_data *file)
62 {
63         struct search_private *state = (struct search_private*) private;
64         file_info *tdl;
65  
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));
69
70         if (!tdl) {
71                 return False;
72         }
73         state->dirlist = tdl;
74         state->dirlist_len += sizeof(struct file_info);
75
76         interpret_long_filename(state->info_level, file, &state->dirlist[state->total_received]);
77
78         state->total_received++;
79         state->ff_searchcount++;
80         
81         return True;
82 }
83
84 int cli_list_new(struct cli_tree *tree, const char *Mask, uint16 attribute, 
85                  void (*fn)(file_info *, const char *, void *), 
86                  void *caller_state)
87 {
88         union smb_search_first first_parms;
89         union smb_search_next next_parms;
90         struct search_private state;  /* for callbacks */
91         int received = 0;
92         BOOL first = True;
93         int num_received = 0;
94         int max_matches = 512;
95         char *mask;
96         int ff_eos = 0, i, ff_searchcount;
97         int ff_dir_handle=0;
98         enum search_level level;
99
100         /* initialize state for search */
101         state.dirlist = NULL;
102         state.mem_ctx = talloc_init("cli_list_new");
103         state.dirlist_len = 0;
104         state.total_received = 0;
105         
106         mask = talloc_strdup(state.mem_ctx, Mask);
107
108         if (tree->session->transport->negotiate.capabilities & CAP_NT_SMBS) {
109                 level = RAW_SEARCH_BOTH_DIRECTORY_INFO;
110         } else {
111                 level = RAW_SEARCH_STANDARD;
112         }
113
114         while (1) {
115                 state.ff_searchcount = 0;
116                 if (first) {
117                         NTSTATUS status;
118
119                         first_parms.t2ffirst.level = level;
120                         first_parms.t2ffirst.in.max_count = max_matches;
121                         first_parms.t2ffirst.in.search_attrib = attribute;
122                         first_parms.t2ffirst.in.pattern = mask;
123                         first_parms.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
124                         first_parms.t2ffirst.in.storage_type = 0;
125                         
126                         status = smb_raw_search_first(tree, 
127                                                       state.mem_ctx, &first_parms,
128                                                       (void*)&state, cli_list_new_callback);
129                         if (!NT_STATUS_IS_OK(status)) {
130                                 talloc_destroy(state.mem_ctx);
131                                 return -1;
132                         }
133                 
134                         ff_dir_handle = first_parms.t2ffirst.out.handle;
135                         ff_searchcount = first_parms.t2ffirst.out.count;
136                         ff_eos = first_parms.t2ffirst.out.end_of_search;
137                         
138                         received = first_parms.t2ffirst.out.count;
139                         if (received <= 0) break;
140                         if (ff_eos) break;
141                         first = False;
142                 } else {
143                         NTSTATUS status;
144
145                         next_parms.t2fnext.level = level;
146                         next_parms.t2fnext.in.max_count = max_matches;
147                         next_parms.t2fnext.in.last_name = mask;
148                         next_parms.t2fnext.in.handle = ff_dir_handle;
149                         next_parms.t2fnext.in.resume_key = 0;
150                         next_parms.t2fnext.in.flags = FLAG_TRANS2_FIND_CONTINUE | FLAG_TRANS2_FIND_CLOSE_IF_END;
151                         
152                         status = smb_raw_search_next(tree, 
153                                                      state.mem_ctx,
154                                                      &next_parms,
155                                                      (void*)&state, 
156                                                      cli_list_new_callback);
157                         
158                         if (!NT_STATUS_IS_OK(status)) {
159                                 return -1;
160                         }
161                         ff_searchcount = next_parms.t2fnext.out.count;
162                         ff_eos = next_parms.t2fnext.out.end_of_search;
163                         received = next_parms.t2fnext.out.count;
164                         if (received <= 0) break;
165                         if (ff_eos) break;
166                 }
167                 
168                 num_received += received;
169         }
170
171         for (i=0;i<state.total_received;i++) {
172                 fn(&state.dirlist[i], Mask, caller_state);
173         }
174
175         talloc_destroy(state.mem_ctx);
176
177         return state.total_received;
178 }
179
180 /****************************************************************************
181  Interpret a short filename structure.
182  The length of the structure is returned.
183 ****************************************************************************/
184 static BOOL interpret_short_filename(int level,
185                                 union smb_search_data *info,
186                                 file_info *finfo)
187 {
188         file_info finfo2;
189
190         if (!finfo) finfo = &finfo2;
191         ZERO_STRUCTP(finfo);
192         
193         finfo->ctime = info->search.write_time;
194         finfo->atime = info->search.write_time;
195         finfo->mtime = info->search.write_time;
196         finfo->size = info->search.size;
197         finfo->mode = info->search.attrib;
198         finfo->name = info->search.name;
199         return True;
200 }
201
202 /* callback function used for smb_search */
203 static BOOL cli_list_old_callback(void *private, union smb_search_data *file)
204 {
205         struct search_private *state = (struct search_private*) private;
206         file_info *tdl;
207         
208         /* add file info to the dirlist pool */
209         tdl = talloc_realloc(state->mem_ctx, state->dirlist,
210                         state->dirlist_len + sizeof(struct file_info));
211
212         if (!tdl) {
213                 return False;
214         }
215         state->dirlist = tdl;
216         state->dirlist_len += sizeof(struct file_info);
217
218         interpret_short_filename(state->info_level, file, &state->dirlist[state->total_received]);
219
220         state->total_received++;
221         state->ff_searchcount++;
222         state->status = file->search.search_id; /* return resume info */
223         
224         return True;
225 }
226
227 int cli_list_old(struct cli_tree *tree, const char *Mask, uint16 attribute, 
228                  void (*fn)(file_info *, const char *, void *), 
229                  void *caller_state)
230 {
231         union smb_search_first first_parms;
232         union smb_search_next next_parms;
233         struct search_private state;  /* for callbacks */
234         const int num_asked = 500;
235         int received = 0;
236         BOOL first = True;
237         int num_received = 0;
238         char *mask;
239         int i;
240
241         /* initialize state for search */
242         state.dirlist = NULL;
243         state.mem_ctx = talloc_init("cli_list_old");
244         state.dirlist_len = 0;
245         state.total_received = 0;
246         
247         mask = talloc_strdup(state.mem_ctx, Mask);
248   
249         while (1) {
250                 state.ff_searchcount = 0;
251                 if (first) {
252                         NTSTATUS status;
253
254                         first_parms.search_first.level = RAW_SEARCH_SEARCH;
255                         first_parms.search_first.in.max_count = num_asked;
256                         first_parms.search_first.in.search_attrib = attribute;
257                         first_parms.search_first.in.pattern = mask;
258                         
259                         status = smb_raw_search_first(tree, state.mem_ctx, 
260                                                       &first_parms,
261                                                       (void*)&state, 
262                                                       cli_list_old_callback);
263
264                         if (!NT_STATUS_IS_OK(status)) {
265                                 talloc_destroy(state.mem_ctx);
266                                 return -1;
267                         }
268                 
269                         received = first_parms.search_first.out.count;
270                         if (received <= 0) break;
271                         first = False;
272                 } else {
273                         NTSTATUS status;
274
275                         next_parms.search_next.level = RAW_SEARCH_SEARCH;
276                         next_parms.search_next.in.max_count = num_asked;
277                         next_parms.search_next.in.search_attrib = attribute;
278                         next_parms.search_next.in.search_id = state.status;
279                         
280                         status = smb_raw_search_next(tree, state.mem_ctx,
281                                                      &next_parms,
282                                                      (void*)&state, 
283                                                      cli_list_old_callback);
284                         
285                         if (!NT_STATUS_IS_OK(status)) {
286                                 talloc_destroy(state.mem_ctx);
287                                 return -1;
288                         }
289                         received = next_parms.search_next.out.count;
290                         if (received <= 0) break;
291                 }
292                 
293                 num_received += received;
294         }
295
296         for (i=0;i<state.total_received;i++) {
297                 fn(&state.dirlist[i], Mask, caller_state);
298         }
299
300         talloc_destroy(state.mem_ctx);
301
302         return state.total_received;
303 }
304
305 /****************************************************************************
306  Do a directory listing, calling fn on each file found.
307  This auto-switches between old and new style.
308 ****************************************************************************/
309
310 int cli_list(struct cli_tree *tree, const char *Mask,uint16 attribute, 
311              void (*fn)(file_info *, const char *, void *), void *state)
312 {
313         if (tree->session->transport->negotiate.protocol <= PROTOCOL_LANMAN1)
314                 return cli_list_old(tree, Mask, attribute, fn, state);
315         return cli_list_new(tree, Mask, attribute, fn, state);
316 }