s3: Do central cli_set_error
[amitay/samba.git] / source3 / libsmb / clilist.c
1 /*
2    Unix SMB/CIFS implementation.
3    client directory list routines
4    Copyright (C) Andrew Tridgell 1994-1998
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "libsmb/libsmb.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.h"
24 #include "trans2.h"
25
26 /****************************************************************************
27  Calculate a safe next_entry_offset.
28 ****************************************************************************/
29
30 static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
31 {
32         size_t next_entry_offset = (size_t)IVAL(base,0);
33
34         if (next_entry_offset == 0 ||
35                         base + next_entry_offset < base ||
36                         base + next_entry_offset > pdata_end) {
37                 next_entry_offset = pdata_end - base;
38         }
39         return next_entry_offset;
40 }
41
42 /****************************************************************************
43  Interpret a long filename structure - this is mostly guesses at the moment.
44  The length of the structure is returned
45  The structure of a long filename depends on the info level.
46  SMB_FIND_FILE_BOTH_DIRECTORY_INFO is used
47  by NT and SMB_FIND_EA_SIZE is used by OS/2
48 ****************************************************************************/
49
50 static size_t interpret_long_filename(TALLOC_CTX *ctx,
51                                         struct cli_state *cli,
52                                         int level,
53                                         const char *base_ptr,
54                                         uint16_t recv_flags2,
55                                         const char *p,
56                                         const char *pdata_end,
57                                         struct file_info *finfo,
58                                         uint32 *p_resume_key,
59                                         DATA_BLOB *p_last_name_raw)
60 {
61         int len;
62         size_t ret;
63         const char *base = p;
64
65         data_blob_free(p_last_name_raw);
66
67         if (p_resume_key) {
68                 *p_resume_key = 0;
69         }
70         ZERO_STRUCTP(finfo);
71
72         switch (level) {
73                 case SMB_FIND_INFO_STANDARD: /* OS/2 understands this */
74                         /* these dates are converted to GMT by
75                            make_unix_date */
76                         if (pdata_end - base < 27) {
77                                 return pdata_end - base;
78                         }
79                         finfo->ctime_ts = convert_time_t_to_timespec(
80                                 make_unix_date2(p+4, cli->serverzone));
81                         finfo->atime_ts = convert_time_t_to_timespec(
82                                 make_unix_date2(p+8, cli->serverzone));
83                         finfo->mtime_ts = convert_time_t_to_timespec(
84                                 make_unix_date2(p+12, cli->serverzone));
85                         finfo->size = IVAL(p,16);
86                         finfo->mode = CVAL(p,24);
87                         len = CVAL(p, 26);
88                         p += 27;
89                         p += align_string(base_ptr, p, 0);
90
91                         /* We can safely use len here (which is required by OS/2)
92                          * and the NAS-BASIC server instead of +2 or +1 as the
93                          * STR_TERMINATE flag below is
94                          * actually used as the length calculation.
95                          * The len is merely an upper bound.
96                          * Due to the explicit 2 byte null termination
97                          * in cli_receive_trans/cli_receive_nt_trans
98                          * we know this is safe. JRA + kukks
99                          */
100
101                         if (p + len > pdata_end) {
102                                 return pdata_end - base;
103                         }
104
105                         /* the len+2 below looks strange but it is
106                            important to cope with the differences
107                            between win2000 and win9x for this call
108                            (tridge) */
109                         ret = clistr_pull_talloc(ctx,
110                                                 base_ptr,
111                                                 recv_flags2,
112                                                 &finfo->name,
113                                                 p,
114                                                 len+2,
115                                                 STR_TERMINATE);
116                         if (ret == (size_t)-1) {
117                                 return pdata_end - base;
118                         }
119                         p += ret;
120                         return PTR_DIFF(p, base);
121
122                 case SMB_FIND_EA_SIZE: /* this is what OS/2 uses mostly */
123                         /* these dates are converted to GMT by
124                            make_unix_date */
125                         if (pdata_end - base < 31) {
126                                 return pdata_end - base;
127                         }
128                         finfo->ctime_ts = convert_time_t_to_timespec(
129                                 make_unix_date2(p+4, cli->serverzone));
130                         finfo->atime_ts = convert_time_t_to_timespec(
131                                 make_unix_date2(p+8, cli->serverzone));
132                         finfo->mtime_ts = convert_time_t_to_timespec(
133                                 make_unix_date2(p+12, cli->serverzone));
134                         finfo->size = IVAL(p,16);
135                         finfo->mode = CVAL(p,24);
136                         len = CVAL(p, 30);
137                         p += 31;
138                         /* check for unisys! */
139                         if (p + len + 1 > pdata_end) {
140                                 return pdata_end - base;
141                         }
142                         ret = clistr_pull_talloc(ctx,
143                                                 base_ptr,
144                                                 recv_flags2,
145                                                 &finfo->name,
146                                                 p,
147                                                 len,
148                                                 STR_NOALIGN);
149                         if (ret == (size_t)-1) {
150                                 return pdata_end - base;
151                         }
152                         p += ret;
153                         return PTR_DIFF(p, base) + 1;
154
155                 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
156                 {
157                         size_t namelen, slen;
158
159                         if (pdata_end - base < 94) {
160                                 return pdata_end - base;
161                         }
162
163                         p += 4; /* next entry offset */
164
165                         if (p_resume_key) {
166                                 *p_resume_key = IVAL(p,0);
167                         }
168                         p += 4; /* fileindex */
169
170                         /* Offset zero is "create time", not "change time". */
171                         p += 8;
172                         finfo->atime_ts = interpret_long_date(p);
173                         p += 8;
174                         finfo->mtime_ts = interpret_long_date(p);
175                         p += 8;
176                         finfo->ctime_ts = interpret_long_date(p);
177                         p += 8;
178                         finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
179                         p += 8;
180                         p += 8; /* alloc size */
181                         finfo->mode = CVAL(p,0);
182                         p += 4;
183                         namelen = IVAL(p,0);
184                         p += 4;
185                         p += 4; /* EA size */
186                         slen = SVAL(p, 0);
187                         if (slen > 24) {
188                                 /* Bad short name length. */
189                                 return pdata_end - base;
190                         }
191                         p += 2;
192                         {
193                                 /* stupid NT bugs. grr */
194                                 int flags = 0;
195                                 if (p[1] == 0 && namelen > 1) flags |= STR_UNICODE;
196                                 clistr_pull(base_ptr, finfo->short_name, p,
197                                             sizeof(finfo->short_name),
198                                             slen, flags);
199                         }
200                         p += 24; /* short name? */
201                         if (p + namelen < p || p + namelen > pdata_end) {
202                                 return pdata_end - base;
203                         }
204                         ret = clistr_pull_talloc(ctx,
205                                                 base_ptr,
206                                                 recv_flags2,
207                                                 &finfo->name,
208                                                 p,
209                                                 namelen,
210                                                 0);
211                         if (ret == (size_t)-1) {
212                                 return pdata_end - base;
213                         }
214
215                         /* To be robust in the face of unicode conversion failures
216                            we need to copy the raw bytes of the last name seen here.
217                            Namelen doesn't include the terminating unicode null, so
218                            copy it here. */
219
220                         if (p_last_name_raw) {
221                                 *p_last_name_raw = data_blob(NULL, namelen+2);
222                                 memcpy(p_last_name_raw->data, p, namelen);
223                                 SSVAL(p_last_name_raw->data, namelen, 0);
224                         }
225                         return calc_next_entry_offset(base, pdata_end);
226                 }
227         }
228
229         DEBUG(1,("Unknown long filename format %d\n",level));
230         return calc_next_entry_offset(base, pdata_end);
231 }
232
233 /****************************************************************************
234  Interpret a short filename structure.
235  The length of the structure is returned.
236 ****************************************************************************/
237
238 static bool interpret_short_filename(TALLOC_CTX *ctx,
239                                 struct cli_state *cli,
240                                 char *p,
241                                 struct file_info *finfo)
242 {
243         size_t ret;
244         ZERO_STRUCTP(finfo);
245
246         finfo->mode = CVAL(p,21);
247
248         /* this date is converted to GMT by make_unix_date */
249         finfo->ctime_ts.tv_sec = make_unix_date(p+22, cli->serverzone);
250         finfo->ctime_ts.tv_nsec = 0;
251         finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
252         finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
253         finfo->size = IVAL(p,26);
254         ret = clistr_pull_talloc(ctx,
255                         cli->inbuf,
256                         SVAL(cli->inbuf, smb_flg2),
257                         &finfo->name,
258                         p+30,
259                         12,
260                         STR_ASCII);
261         if (ret == (size_t)-1) {
262                 return false;
263         }
264
265         if (finfo->name) {
266                 strlcpy(finfo->short_name,
267                         finfo->name,
268                         sizeof(finfo->short_name));
269         }
270         return true;
271 }
272
273 struct cli_list_old_state {
274         struct tevent_context *ev;
275         struct cli_state *cli;
276         uint16_t vwv[2];
277         char *mask;
278         int num_asked;
279         uint16_t attribute;
280         uint8_t search_status[23];
281         bool first;
282         bool done;
283         uint8_t *dirlist;
284 };
285
286 static void cli_list_old_done(struct tevent_req *subreq);
287
288 static struct tevent_req *cli_list_old_send(TALLOC_CTX *mem_ctx,
289                                             struct tevent_context *ev,
290                                             struct cli_state *cli,
291                                             const char *mask,
292                                             uint16_t attribute)
293 {
294         struct tevent_req *req, *subreq;
295         struct cli_list_old_state *state;
296         uint8_t *bytes;
297         static const uint16_t zero = 0;
298
299         req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
300         if (req == NULL) {
301                 return NULL;
302         }
303         state->ev = ev;
304         state->cli = cli;
305         state->attribute = attribute;
306         state->first = true;
307         state->mask = talloc_strdup(state, mask);
308         if (tevent_req_nomem(state->mask, req)) {
309                 return tevent_req_post(req, ev);
310         }
311         state->num_asked = (cli->max_xmit - 100) / DIR_STRUCT_SIZE;
312
313         SSVAL(state->vwv + 0, 0, state->num_asked);
314         SSVAL(state->vwv + 1, 0, state->attribute);
315
316         bytes = talloc_array(state, uint8_t, 1);
317         if (tevent_req_nomem(bytes, req)) {
318                 return tevent_req_post(req, ev);
319         }
320         bytes[0] = 4;
321         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), mask,
322                                    strlen(mask)+1, NULL);
323
324         bytes = smb_bytes_push_bytes(bytes, 5, (const uint8_t *)&zero, 2);
325         if (tevent_req_nomem(bytes, req)) {
326                 return tevent_req_post(req, ev);
327         }
328
329         subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch,
330                               0, 2, state->vwv, talloc_get_size(bytes), bytes);
331         if (tevent_req_nomem(subreq, req)) {
332                 return tevent_req_post(req, ev);
333         }
334         tevent_req_set_callback(subreq, cli_list_old_done, req);
335         return req;
336 }
337
338 static void cli_list_old_done(struct tevent_req *subreq)
339 {
340         struct tevent_req *req = tevent_req_callback_data(
341                 subreq, struct tevent_req);
342         struct cli_list_old_state *state = tevent_req_data(
343                 req, struct cli_list_old_state);
344         NTSTATUS status;
345         uint8_t cmd;
346         uint8_t wct;
347         uint16_t *vwv;
348         uint32_t num_bytes;
349         uint8_t *bytes;
350         uint16_t received;
351         size_t dirlist_len;
352         uint8_t *tmp;
353
354         status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes,
355                               &bytes);
356         if (!NT_STATUS_IS_OK(status)
357             && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
358             && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
359                 TALLOC_FREE(subreq);
360                 tevent_req_nterror(req, status);
361                 return;
362         }
363         if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
364             || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
365                 received = 0;
366         } else {
367                 if (wct < 1) {
368                         TALLOC_FREE(subreq);
369                         tevent_req_nterror(
370                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
371                         return;
372                 }
373                 received = SVAL(vwv + 0, 0);
374         }
375
376         if (received > 0) {
377                 /*
378                  * I don't think this can wrap. received is
379                  * initialized from a 16-bit value.
380                  */
381                 if (num_bytes < (received * DIR_STRUCT_SIZE + 3)) {
382                         TALLOC_FREE(subreq);
383                         tevent_req_nterror(
384                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
385                         return;
386                 }
387
388                 dirlist_len = talloc_get_size(state->dirlist);
389
390                 tmp = TALLOC_REALLOC_ARRAY(
391                         state, state->dirlist, uint8_t,
392                         dirlist_len + received * DIR_STRUCT_SIZE);
393                 if (tevent_req_nomem(tmp, req)) {
394                         return;
395                 }
396                 state->dirlist = tmp;
397                 memcpy(state->dirlist + dirlist_len, bytes + 3,
398                        received * DIR_STRUCT_SIZE);
399
400                 SSVAL(state->search_status, 0, 21);
401                 memcpy(state->search_status + 2,
402                        bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21);
403                 cmd = SMBsearch;
404         } else {
405                 if (state->first || state->done) {
406                         tevent_req_done(req);
407                         return;
408                 }
409                 state->done = true;
410                 state->num_asked = 0;
411                 cmd = SMBfclose;
412         }
413         TALLOC_FREE(subreq);
414
415         state->first = false;
416
417         SSVAL(state->vwv + 0, 0, state->num_asked);
418         SSVAL(state->vwv + 1, 0, state->attribute);
419
420         bytes = talloc_array(state, uint8_t, 1);
421         if (tevent_req_nomem(bytes, req)) {
422                 return;
423         }
424         bytes[0] = 4;
425         bytes = smb_bytes_push_str(bytes, cli_ucs2(state->cli), "",
426                                    1, NULL);
427         bytes = smb_bytes_push_bytes(bytes, 5, state->search_status,
428                                      sizeof(state->search_status));
429         if (tevent_req_nomem(bytes, req)) {
430                 return;
431         }
432         subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0,
433                               2, state->vwv, talloc_get_size(bytes), bytes);
434         if (tevent_req_nomem(subreq, req)) {
435                 return;
436         }
437         tevent_req_set_callback(subreq, cli_list_old_done, req);
438 }
439
440 static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
441                                   struct file_info **pfinfo)
442 {
443         struct cli_list_old_state *state = tevent_req_data(
444                 req, struct cli_list_old_state);
445         NTSTATUS status;
446         size_t i, num_received;
447         struct file_info *finfo;
448
449         if (tevent_req_is_nterror(req, &status)) {
450                 return status;
451         }
452
453         num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
454
455         finfo = TALLOC_ARRAY(mem_ctx, struct file_info, num_received);
456         if (finfo == NULL) {
457                 return NT_STATUS_NO_MEMORY;
458         }
459
460         for (i=0; i<num_received; i++) {
461                 if (!interpret_short_filename(
462                             finfo, state->cli,
463                             (char *)state->dirlist + i * DIR_STRUCT_SIZE,
464                             &finfo[i])) {
465                         TALLOC_FREE(finfo);
466                         return NT_STATUS_NO_MEMORY;
467                 }
468         }
469         *pfinfo = finfo;
470         return NT_STATUS_OK;
471 }
472
473 NTSTATUS cli_list_old(struct cli_state *cli, const char *mask,
474                       uint16 attribute,
475                       NTSTATUS (*fn)(const char *, struct file_info *,
476                                  const char *, void *), void *state)
477 {
478         TALLOC_CTX *frame = talloc_stackframe();
479         struct event_context *ev;
480         struct tevent_req *req;
481         NTSTATUS status = NT_STATUS_NO_MEMORY;
482         struct file_info *finfo;
483         size_t i, num_finfo;
484
485         if (cli_has_async_calls(cli)) {
486                 /*
487                  * Can't use sync call while an async call is in flight
488                  */
489                 status = NT_STATUS_INVALID_PARAMETER;
490                 goto fail;
491         }
492         ev = event_context_init(frame);
493         if (ev == NULL) {
494                 goto fail;
495         }
496         req = cli_list_old_send(frame, ev, cli, mask, attribute);
497         if (req == NULL) {
498                 goto fail;
499         }
500         if (!tevent_req_poll(req, ev)) {
501                 status = map_nt_error_from_unix(errno);
502                 goto fail;
503         }
504         status = cli_list_old_recv(req, frame, &finfo);
505         if (!NT_STATUS_IS_OK(status)) {
506                 goto fail;
507         }
508         num_finfo = talloc_array_length(finfo);
509         for (i=0; i<num_finfo; i++) {
510                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
511                 if (!NT_STATUS_IS_OK(status)) {
512                         goto fail;
513                 }
514         }
515  fail:
516         TALLOC_FREE(frame);
517         return status;
518 }
519
520 struct cli_list_trans_state {
521         struct tevent_context *ev;
522         struct cli_state *cli;
523         char *mask;
524         uint16_t attribute;
525         uint16_t info_level;
526
527         int loop_count;
528         int total_received;
529         uint16_t max_matches;
530         bool first;
531
532         int ff_eos;
533         int ff_dir_handle;
534
535         uint16_t setup[1];
536         uint8_t *param;
537
538         struct file_info *finfo;
539 };
540
541 static void cli_list_trans_done(struct tevent_req *subreq);
542
543 static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
544                                               struct tevent_context *ev,
545                                               struct cli_state *cli,
546                                               const char *mask,
547                                               uint16_t attribute,
548                                               uint16_t info_level)
549 {
550         struct tevent_req *req, *subreq;
551         struct cli_list_trans_state *state;
552         size_t nlen, param_len;
553         char *p;
554
555         req = tevent_req_create(mem_ctx, &state,
556                                 struct cli_list_trans_state);
557         if (req == NULL) {
558                 return NULL;
559         }
560         state->ev = ev;
561         state->cli = cli;
562         state->mask = talloc_strdup(state, mask);
563         if (tevent_req_nomem(state->mask, req)) {
564                 return tevent_req_post(req, ev);
565         }
566         state->attribute = attribute;
567         state->info_level = info_level;
568         state->loop_count = 0;
569         state->first = true;
570
571         state->max_matches = 1366; /* Match W2k */
572
573         state->setup[0] = TRANSACT2_FINDFIRST;
574
575         nlen = 2*(strlen(mask)+1);
576         state->param = TALLOC_ARRAY(state, uint8_t, 12+nlen+2);
577         if (tevent_req_nomem(state->param, req)) {
578                 return tevent_req_post(req, ev);
579         }
580
581         SSVAL(state->param, 0, state->attribute);
582         SSVAL(state->param, 2, state->max_matches);
583         SSVAL(state->param, 4,
584               FLAG_TRANS2_FIND_REQUIRE_RESUME
585               |FLAG_TRANS2_FIND_CLOSE_IF_END);
586         SSVAL(state->param, 6, state->info_level);
587         SIVAL(state->param, 8, 0);
588
589         p = ((char *)state->param)+12;
590         p += clistr_push(state->cli, p, state->mask, nlen,
591                          STR_TERMINATE);
592         param_len = PTR_DIFF(p, state->param);
593
594         subreq = cli_trans_send(state, state->ev, state->cli,
595                                 SMBtrans2, NULL, -1, 0, 0,
596                                 state->setup, 1, 0,
597                                 state->param, param_len, 10,
598                                 NULL, 0, cli->max_xmit);
599         if (tevent_req_nomem(subreq, req)) {
600                 return tevent_req_post(req, ev);
601         }
602         tevent_req_set_callback(subreq, cli_list_trans_done, req);
603         return req;
604 }
605
606 static void cli_list_trans_done(struct tevent_req *subreq)
607 {
608         struct tevent_req *req = tevent_req_callback_data(
609                 subreq, struct tevent_req);
610         struct cli_list_trans_state *state = tevent_req_data(
611                 req, struct cli_list_trans_state);
612         NTSTATUS status;
613         uint8_t *param;
614         uint32_t num_param;
615         uint8_t *data;
616         char *data_end;
617         uint32_t num_data;
618         uint32_t min_param;
619         struct file_info *tmp;
620         size_t old_num_finfo;
621         uint16_t recv_flags2;
622         int ff_searchcount;
623         bool ff_eos;
624         char *p, *p2;
625         uint32_t resume_key = 0;
626         int i;
627         DATA_BLOB last_name_raw;
628         struct file_info *finfo = NULL;
629         size_t nlen, param_len;
630
631         min_param = (state->first ? 6 : 4);
632
633         status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
634                                 NULL, 0, NULL,
635                                 &param, min_param, &num_param,
636                                 &data, 0, &num_data);
637         TALLOC_FREE(subreq);
638         if (!NT_STATUS_IS_OK(status)) {
639                 /*
640                  * TODO: retry, OS/2 nofiles
641                  */
642                 tevent_req_nterror(req, status);
643                 return;
644         }
645
646         if (state->first) {
647                 state->ff_dir_handle = SVAL(param, 0);
648                 ff_searchcount = SVAL(param, 2);
649                 ff_eos = SVAL(param, 4) != 0;
650         } else {
651                 ff_searchcount = SVAL(param, 0);
652                 ff_eos = SVAL(param, 2) != 0;
653         }
654
655         old_num_finfo = talloc_array_length(state->finfo);
656
657         tmp = TALLOC_REALLOC_ARRAY(state, state->finfo, struct file_info,
658                                    old_num_finfo + ff_searchcount);
659         if (tevent_req_nomem(tmp, req)) {
660                 return;
661         }
662         state->finfo = tmp;
663
664         p2 = p = (char *)data;
665         data_end = (char *)data + num_data;
666         last_name_raw = data_blob_null;
667
668         for (i=0; i<ff_searchcount; i++) {
669                 if (p2 >= data_end) {
670                         ff_eos = true;
671                         break;
672                 }
673                 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
674                     && (i == ff_searchcount-1)) {
675                         /* Last entry - fixup the last offset length. */
676                         SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
677                 }
678
679                 data_blob_free(&last_name_raw);
680
681                 finfo = &state->finfo[old_num_finfo + i];
682
683                 p2 += interpret_long_filename(
684                         state->finfo, /* Stick fname to the array as such */
685                         state->cli, state->info_level,
686                         (char *)data, recv_flags2, p2,
687                         data_end, finfo, &resume_key, &last_name_raw);
688
689                 if (finfo->name == NULL) {
690                         DEBUG(1, ("cli_list: Error: unable to parse name from "
691                                   "info level %d\n", state->info_level));
692                         ff_eos = true;
693                         break;
694                 }
695                 if (!state->first && (state->mask[0] != '\0') &&
696                     strcsequal(finfo->name, state->mask)) {
697                         DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
698                                   "already been seen?\n", finfo->name));
699                         ff_eos = true;
700                         break;
701                 }
702         }
703
704         if (ff_searchcount == 0) {
705                 ff_eos = true;
706         }
707
708         TALLOC_FREE(param);
709         TALLOC_FREE(data);
710
711         /*
712          * Shrink state->finfo to the real length we received
713          */
714         tmp = TALLOC_REALLOC_ARRAY(state, state->finfo, struct file_info,
715                                    old_num_finfo + i);
716         if (tevent_req_nomem(tmp, req)) {
717                 return;
718         }
719         state->finfo = tmp;
720
721         state->first = false;
722
723         if (ff_eos) {
724                 data_blob_free(&last_name_raw);
725                 tevent_req_done(req);
726                 return;
727         }
728
729         TALLOC_FREE(state->mask);
730         state->mask = talloc_strdup(state, finfo->name);
731         if (tevent_req_nomem(state->mask, req)) {
732                 return;
733         }
734
735         state->setup[0] = TRANSACT2_FINDNEXT;
736
737         nlen = 2*(strlen(state->mask) + 1);
738
739         param = TALLOC_REALLOC_ARRAY(state, state->param, uint8_t,
740                                      12 + nlen + last_name_raw.length + 2);
741         if (tevent_req_nomem(param, req)) {
742                 return;
743         }
744         state->param = param;
745
746         SSVAL(param, 0, state->ff_dir_handle);
747         SSVAL(param, 2, state->max_matches); /* max count */
748         SSVAL(param, 4, state->info_level);
749         /*
750          * For W2K servers serving out FAT filesystems we *must* set
751          * the resume key. If it's not FAT then it's returned as zero.
752          */
753         SIVAL(param, 6, resume_key); /* ff_resume_key */
754         /*
755          * NB. *DON'T* use continue here. If you do it seems that W2K
756          * and bretheren can miss filenames. Use last filename
757          * continue instead. JRA
758          */
759         SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
760                           |FLAG_TRANS2_FIND_CLOSE_IF_END));
761         p = ((char *)param)+12;
762         if (last_name_raw.length) {
763                 memcpy(p, last_name_raw.data, last_name_raw.length);
764                 p += last_name_raw.length;
765                 data_blob_free(&last_name_raw);
766         } else {
767                 p += clistr_push(state->cli, p, state->mask, nlen,
768                                  STR_TERMINATE);
769         }
770
771         param_len = PTR_DIFF(p, param);
772
773         subreq = cli_trans_send(state, state->ev, state->cli,
774                                 SMBtrans2, NULL, -1, 0, 0,
775                                 state->setup, 1, 0,
776                                 state->param, param_len, 10,
777                                 NULL, 0, state->cli->max_xmit);
778         if (tevent_req_nomem(subreq, req)) {
779                 return;
780         }
781         tevent_req_set_callback(subreq, cli_list_trans_done, req);
782 }
783
784 static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
785                                     TALLOC_CTX *mem_ctx,
786                                     struct file_info **finfo)
787 {
788         struct cli_list_trans_state *state = tevent_req_data(
789                 req, struct cli_list_trans_state);
790         NTSTATUS status;
791
792         if (tevent_req_is_nterror(req, &status)) {
793                 return status;
794         }
795         *finfo = talloc_move(mem_ctx, &state->finfo);
796         return NT_STATUS_OK;
797 }
798
799 NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
800                         uint16_t attribute, int info_level,
801                         NTSTATUS (*fn)(const char *mnt, struct file_info *finfo,
802                                    const char *mask, void *private_data),
803                         void *private_data)
804 {
805         TALLOC_CTX *frame = talloc_stackframe();
806         struct event_context *ev;
807         struct tevent_req *req;
808         int i, num_finfo;
809         struct file_info *finfo = NULL;
810         NTSTATUS status = NT_STATUS_NO_MEMORY;
811
812         if (cli_has_async_calls(cli)) {
813                 /*
814                  * Can't use sync call while an async call is in flight
815                  */
816                 status = NT_STATUS_INVALID_PARAMETER;
817                 goto fail;
818         }
819         ev = event_context_init(frame);
820         if (ev == NULL) {
821                 goto fail;
822         }
823         req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
824         if (req == NULL) {
825                 goto fail;
826         }
827         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
828                 goto fail;
829         }
830         status = cli_list_trans_recv(req, frame, &finfo);
831         if (!NT_STATUS_IS_OK(status)) {
832                 goto fail;
833         }
834         num_finfo = talloc_array_length(finfo);
835         for (i=0; i<num_finfo; i++) {
836                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, private_data);
837                 if (!NT_STATUS_IS_OK(status)) {
838                         goto fail;
839                 }
840         }
841  fail:
842         TALLOC_FREE(frame);
843         return status;
844 }
845
846 struct cli_list_state {
847         NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
848                             struct file_info **finfo);
849         struct file_info *finfo;
850 };
851
852 static void cli_list_done(struct tevent_req *subreq);
853
854 struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
855                                  struct tevent_context *ev,
856                                  struct cli_state *cli,
857                                  const char *mask,
858                                  uint16_t attribute,
859                                  uint16_t info_level)
860 {
861         struct tevent_req *req, *subreq;
862         struct cli_list_state *state;
863
864         req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
865         if (req == NULL) {
866                 return NULL;
867         }
868
869         if (cli->protocol <= PROTOCOL_LANMAN1) {
870                 subreq = cli_list_old_send(state, ev, cli, mask, attribute);
871                 state->recv_fn = cli_list_old_recv;
872         } else {
873                 subreq = cli_list_trans_send(state, ev, cli, mask, attribute,
874                                              info_level);
875                 state->recv_fn = cli_list_trans_recv;
876         }
877         if (tevent_req_nomem(subreq, req)) {
878                 return tevent_req_post(req, ev);
879         }
880         tevent_req_set_callback(subreq, cli_list_done, req);
881         return req;
882 }
883
884 static void cli_list_done(struct tevent_req *subreq)
885 {
886         struct tevent_req *req = tevent_req_callback_data(
887                 subreq, struct tevent_req);
888         struct cli_list_state *state = tevent_req_data(
889                 req, struct cli_list_state);
890         NTSTATUS status;
891
892         status = state->recv_fn(subreq, state, &state->finfo);
893         TALLOC_FREE(subreq);
894         if (!NT_STATUS_IS_OK(status)) {
895                 tevent_req_nterror(req, status);
896                 return;
897         }
898         tevent_req_done(req);
899 }
900
901 NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
902                        struct file_info **finfo, size_t *num_finfo)
903 {
904         struct cli_list_state *state = tevent_req_data(
905                 req, struct cli_list_state);
906         NTSTATUS status;
907
908         if (tevent_req_is_nterror(req, &status)) {
909                 return status;
910         }
911         *num_finfo = talloc_array_length(state->finfo);
912         *finfo = talloc_move(mem_ctx, &state->finfo);
913         return NT_STATUS_OK;
914 }
915
916 NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute,
917                   NTSTATUS (*fn)(const char *, struct file_info *, const char *,
918                              void *), void *state)
919 {
920         TALLOC_CTX *frame = talloc_stackframe();
921         struct event_context *ev;
922         struct tevent_req *req;
923         NTSTATUS status = NT_STATUS_NO_MEMORY;
924         struct file_info *finfo;
925         size_t i, num_finfo;
926         uint16_t info_level;
927
928         if (cli_has_async_calls(cli)) {
929                 /*
930                  * Can't use sync call while an async call is in flight
931                  */
932                 status = NT_STATUS_INVALID_PARAMETER;
933                 goto fail;
934         }
935         ev = event_context_init(frame);
936         if (ev == NULL) {
937                 goto fail;
938         }
939
940         info_level = (cli->capabilities & CAP_NT_SMBS)
941                 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
942
943         req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
944         if (req == NULL) {
945                 goto fail;
946         }
947         if (!tevent_req_poll(req, ev)) {
948                 status = map_nt_error_from_unix(errno);
949                 goto fail;
950         }
951
952         status = cli_list_recv(req, frame, &finfo, &num_finfo);
953         if (!NT_STATUS_IS_OK(status)) {
954                 goto fail;
955         }
956
957         for (i=0; i<num_finfo; i++) {
958                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
959                 if (!NT_STATUS_IS_OK(status)) {
960                         goto fail;
961                 }
962         }
963  fail:
964         TALLOC_FREE(frame);
965         return status;
966 }