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