Convert all uint32/16/8 to _t in source3/libsmb.
[bbaumbach/samba-autobuild/.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 = SVAL(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,
338                               0, 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,
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(req, ev)) {
509                 status = map_nt_error_from_unix(errno);
510                 goto fail;
511         }
512         status = cli_list_old_recv(req, frame, &finfo);
513         if (!NT_STATUS_IS_OK(status)) {
514                 goto fail;
515         }
516         num_finfo = talloc_array_length(finfo);
517         for (i=0; i<num_finfo; i++) {
518                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
519                 if (!NT_STATUS_IS_OK(status)) {
520                         goto fail;
521                 }
522         }
523  fail:
524         TALLOC_FREE(frame);
525         return status;
526 }
527
528 struct cli_list_trans_state {
529         struct tevent_context *ev;
530         struct cli_state *cli;
531         char *mask;
532         uint16_t attribute;
533         uint16_t info_level;
534
535         int loop_count;
536         int total_received;
537         uint16_t max_matches;
538         bool first;
539
540         int ff_eos;
541         int ff_dir_handle;
542
543         uint16_t setup[1];
544         uint8_t *param;
545
546         struct file_info *finfo;
547 };
548
549 static void cli_list_trans_done(struct tevent_req *subreq);
550
551 static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
552                                               struct tevent_context *ev,
553                                               struct cli_state *cli,
554                                               const char *mask,
555                                               uint16_t attribute,
556                                               uint16_t info_level)
557 {
558         struct tevent_req *req, *subreq;
559         struct cli_list_trans_state *state;
560         size_t param_len;
561
562         req = tevent_req_create(mem_ctx, &state,
563                                 struct cli_list_trans_state);
564         if (req == NULL) {
565                 return NULL;
566         }
567         state->ev = ev;
568         state->cli = cli;
569         state->mask = talloc_strdup(state, mask);
570         if (tevent_req_nomem(state->mask, req)) {
571                 return tevent_req_post(req, ev);
572         }
573         state->attribute = attribute;
574         state->info_level = info_level;
575         state->loop_count = 0;
576         state->first = true;
577
578         state->max_matches = 1366; /* Match W2k */
579
580         SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
581
582         state->param = talloc_array(state, uint8_t, 12);
583         if (tevent_req_nomem(state->param, req)) {
584                 return tevent_req_post(req, ev);
585         }
586
587         SSVAL(state->param, 0, state->attribute);
588         SSVAL(state->param, 2, state->max_matches);
589         SSVAL(state->param, 4,
590               FLAG_TRANS2_FIND_REQUIRE_RESUME
591               |FLAG_TRANS2_FIND_CLOSE_IF_END
592               |(cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0));
593         SSVAL(state->param, 6, state->info_level);
594         SIVAL(state->param, 8, 0);
595
596         state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn),
597                                              state->mask, strlen(state->mask)+1,
598                                              NULL);
599         if (tevent_req_nomem(state->param, req)) {
600                 return tevent_req_post(req, ev);
601         }
602         param_len = talloc_get_size(state->param);
603
604         subreq = cli_trans_send(state, state->ev, state->cli,
605                                 SMBtrans2, NULL, -1, 0, 0,
606                                 state->setup, 1, 0,
607                                 state->param, param_len, 10,
608                                 NULL, 0, CLI_BUFFER_SIZE);
609         if (tevent_req_nomem(subreq, req)) {
610                 return tevent_req_post(req, ev);
611         }
612         tevent_req_set_callback(subreq, cli_list_trans_done, req);
613         return req;
614 }
615
616 static void cli_list_trans_done(struct tevent_req *subreq)
617 {
618         struct tevent_req *req = tevent_req_callback_data(
619                 subreq, struct tevent_req);
620         struct cli_list_trans_state *state = tevent_req_data(
621                 req, struct cli_list_trans_state);
622         NTSTATUS status;
623         uint8_t *param;
624         uint32_t num_param;
625         uint8_t *data;
626         char *data_end;
627         uint32_t num_data;
628         uint32_t min_param;
629         struct file_info *tmp;
630         size_t old_num_finfo;
631         uint16_t recv_flags2;
632         int ff_searchcount;
633         bool ff_eos;
634         char *p, *p2;
635         uint32_t resume_key = 0;
636         int i;
637         DATA_BLOB last_name_raw;
638         struct file_info *finfo = NULL;
639         size_t param_len;
640
641         min_param = (state->first ? 6 : 4);
642
643         status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
644                                 NULL, 0, NULL,
645                                 &param, min_param, &num_param,
646                                 &data, 0, &num_data);
647         TALLOC_FREE(subreq);
648         if (!NT_STATUS_IS_OK(status)) {
649                 /*
650                  * TODO: retry, OS/2 nofiles
651                  */
652                 tevent_req_nterror(req, status);
653                 return;
654         }
655
656         if (state->first) {
657                 state->ff_dir_handle = SVAL(param, 0);
658                 ff_searchcount = SVAL(param, 2);
659                 ff_eos = SVAL(param, 4) != 0;
660         } else {
661                 ff_searchcount = SVAL(param, 0);
662                 ff_eos = SVAL(param, 2) != 0;
663         }
664
665         old_num_finfo = talloc_array_length(state->finfo);
666
667         tmp = talloc_realloc(state, state->finfo, struct file_info,
668                                    old_num_finfo + ff_searchcount);
669         if (tevent_req_nomem(tmp, req)) {
670                 return;
671         }
672         state->finfo = tmp;
673
674         p2 = p = (char *)data;
675         data_end = (char *)data + num_data;
676         last_name_raw = data_blob_null;
677
678         for (i=0; i<ff_searchcount; i++) {
679                 if (p2 >= data_end) {
680                         ff_eos = true;
681                         break;
682                 }
683                 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
684                     && (i == ff_searchcount-1)) {
685                         /* Last entry - fixup the last offset length. */
686                         SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
687                 }
688
689                 data_blob_free(&last_name_raw);
690
691                 finfo = &state->finfo[old_num_finfo + i];
692
693                 p2 += interpret_long_filename(
694                         state->finfo, /* Stick fname to the array as such */
695                         state->cli, state->info_level,
696                         (char *)data, recv_flags2, p2,
697                         data_end, finfo, &resume_key, &last_name_raw);
698
699                 if (finfo->name == NULL) {
700                         DEBUG(1, ("cli_list: Error: unable to parse name from "
701                                   "info level %d\n", state->info_level));
702                         ff_eos = true;
703                         break;
704                 }
705                 if (!state->first && (state->mask[0] != '\0') &&
706                     strcsequal(finfo->name, state->mask)) {
707                         DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
708                                   "already been seen?\n", finfo->name));
709                         ff_eos = true;
710                         break;
711                 }
712         }
713
714         if (ff_searchcount == 0) {
715                 ff_eos = true;
716         }
717
718         TALLOC_FREE(param);
719         TALLOC_FREE(data);
720
721         /*
722          * Shrink state->finfo to the real length we received
723          */
724         tmp = talloc_realloc(state, state->finfo, struct file_info,
725                                    old_num_finfo + i);
726         if (tevent_req_nomem(tmp, req)) {
727                 return;
728         }
729         state->finfo = tmp;
730
731         state->first = false;
732
733         if (ff_eos) {
734                 data_blob_free(&last_name_raw);
735                 tevent_req_done(req);
736                 return;
737         }
738
739         TALLOC_FREE(state->mask);
740         state->mask = talloc_strdup(state, finfo->name);
741         if (tevent_req_nomem(state->mask, req)) {
742                 return;
743         }
744
745         SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
746
747         param = talloc_realloc(state, state->param, uint8_t, 12);
748         if (tevent_req_nomem(param, req)) {
749                 return;
750         }
751         state->param = param;
752
753         SSVAL(param, 0, state->ff_dir_handle);
754         SSVAL(param, 2, state->max_matches); /* max count */
755         SSVAL(param, 4, state->info_level);
756         /*
757          * For W2K servers serving out FAT filesystems we *must* set
758          * the resume key. If it's not FAT then it's returned as zero.
759          */
760         SIVAL(param, 6, resume_key); /* ff_resume_key */
761         /*
762          * NB. *DON'T* use continue here. If you do it seems that W2K
763          * and bretheren can miss filenames. Use last filename
764          * continue instead. JRA
765          */
766         SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
767                           |FLAG_TRANS2_FIND_CLOSE_IF_END
768                           |(state->cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0)));
769         if (last_name_raw.length) {
770                 state->param = trans2_bytes_push_bytes(state->param,
771                                                        last_name_raw.data,
772                                                        last_name_raw.length);
773                 if (tevent_req_nomem(state->param, req)) {
774                         return;
775                 }
776                 data_blob_free(&last_name_raw);
777         } else {
778                 state->param = trans2_bytes_push_str(state->param,
779                                                      smbXcli_conn_use_unicode(state->cli->conn),
780                                                      state->mask,
781                                                      strlen(state->mask)+1,
782                                                      NULL);
783                 if (tevent_req_nomem(state->param, req)) {
784                         return;
785                 }
786         }
787         param_len = talloc_get_size(state->param);
788
789         subreq = cli_trans_send(state, state->ev, state->cli,
790                                 SMBtrans2, NULL, -1, 0, 0,
791                                 state->setup, 1, 0,
792                                 state->param, param_len, 10,
793                                 NULL, 0, CLI_BUFFER_SIZE);
794         if (tevent_req_nomem(subreq, req)) {
795                 return;
796         }
797         tevent_req_set_callback(subreq, cli_list_trans_done, req);
798 }
799
800 static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
801                                     TALLOC_CTX *mem_ctx,
802                                     struct file_info **finfo)
803 {
804         struct cli_list_trans_state *state = tevent_req_data(
805                 req, struct cli_list_trans_state);
806         NTSTATUS status;
807
808         if (tevent_req_is_nterror(req, &status)) {
809                 return status;
810         }
811         *finfo = talloc_move(mem_ctx, &state->finfo);
812         return NT_STATUS_OK;
813 }
814
815 NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
816                         uint16_t attribute, int info_level,
817                         NTSTATUS (*fn)(const char *mnt, struct file_info *finfo,
818                                    const char *mask, void *private_data),
819                         void *private_data)
820 {
821         TALLOC_CTX *frame = talloc_stackframe();
822         struct tevent_context *ev;
823         struct tevent_req *req;
824         int i, num_finfo;
825         struct file_info *finfo = NULL;
826         NTSTATUS status = NT_STATUS_NO_MEMORY;
827
828         if (smbXcli_conn_has_async_calls(cli->conn)) {
829                 /*
830                  * Can't use sync call while an async call is in flight
831                  */
832                 status = NT_STATUS_INVALID_PARAMETER;
833                 goto fail;
834         }
835         ev = samba_tevent_context_init(frame);
836         if (ev == NULL) {
837                 goto fail;
838         }
839         req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
840         if (req == NULL) {
841                 goto fail;
842         }
843         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
844                 goto fail;
845         }
846         status = cli_list_trans_recv(req, frame, &finfo);
847         if (!NT_STATUS_IS_OK(status)) {
848                 goto fail;
849         }
850         num_finfo = talloc_array_length(finfo);
851         for (i=0; i<num_finfo; i++) {
852                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, private_data);
853                 if (!NT_STATUS_IS_OK(status)) {
854                         goto fail;
855                 }
856         }
857  fail:
858         TALLOC_FREE(frame);
859         return status;
860 }
861
862 struct cli_list_state {
863         NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
864                             struct file_info **finfo);
865         struct file_info *finfo;
866 };
867
868 static void cli_list_done(struct tevent_req *subreq);
869
870 struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
871                                  struct tevent_context *ev,
872                                  struct cli_state *cli,
873                                  const char *mask,
874                                  uint16_t attribute,
875                                  uint16_t info_level)
876 {
877         struct tevent_req *req, *subreq;
878         struct cli_list_state *state;
879
880         req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
881         if (req == NULL) {
882                 return NULL;
883         }
884
885         if (smbXcli_conn_protocol(cli->conn) <= PROTOCOL_LANMAN1) {
886                 subreq = cli_list_old_send(state, ev, cli, mask, attribute);
887                 state->recv_fn = cli_list_old_recv;
888         } else {
889                 subreq = cli_list_trans_send(state, ev, cli, mask, attribute,
890                                              info_level);
891                 state->recv_fn = cli_list_trans_recv;
892         }
893         if (tevent_req_nomem(subreq, req)) {
894                 return tevent_req_post(req, ev);
895         }
896         tevent_req_set_callback(subreq, cli_list_done, req);
897         return req;
898 }
899
900 static void cli_list_done(struct tevent_req *subreq)
901 {
902         struct tevent_req *req = tevent_req_callback_data(
903                 subreq, struct tevent_req);
904         struct cli_list_state *state = tevent_req_data(
905                 req, struct cli_list_state);
906         NTSTATUS status;
907
908         status = state->recv_fn(subreq, state, &state->finfo);
909         TALLOC_FREE(subreq);
910         if (!NT_STATUS_IS_OK(status)) {
911                 tevent_req_nterror(req, status);
912                 return;
913         }
914         tevent_req_done(req);
915 }
916
917 NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
918                        struct file_info **finfo, size_t *num_finfo)
919 {
920         struct cli_list_state *state = tevent_req_data(
921                 req, struct cli_list_state);
922         NTSTATUS status;
923
924         if (tevent_req_is_nterror(req, &status)) {
925                 return status;
926         }
927         *num_finfo = talloc_array_length(state->finfo);
928         *finfo = talloc_move(mem_ctx, &state->finfo);
929         return NT_STATUS_OK;
930 }
931
932 NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16_t attribute,
933                   NTSTATUS (*fn)(const char *, struct file_info *, const char *,
934                              void *), void *state)
935 {
936         TALLOC_CTX *frame = NULL;
937         struct tevent_context *ev;
938         struct tevent_req *req;
939         NTSTATUS status = NT_STATUS_NO_MEMORY;
940         struct file_info *finfo;
941         size_t i, num_finfo;
942         uint16_t info_level;
943
944         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
945                 return cli_smb2_list(cli, mask, attribute, fn, state);
946         }
947
948         frame = talloc_stackframe();
949
950         if (smbXcli_conn_has_async_calls(cli->conn)) {
951                 /*
952                  * Can't use sync call while an async call is in flight
953                  */
954                 status = NT_STATUS_INVALID_PARAMETER;
955                 goto fail;
956         }
957         ev = samba_tevent_context_init(frame);
958         if (ev == NULL) {
959                 goto fail;
960         }
961
962         info_level = (smb1cli_conn_capabilities(cli->conn) & CAP_NT_SMBS)
963                 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
964
965         req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
966         if (req == NULL) {
967                 goto fail;
968         }
969         if (!tevent_req_poll(req, ev)) {
970                 status = map_nt_error_from_unix(errno);
971                 goto fail;
972         }
973
974         status = cli_list_recv(req, frame, &finfo, &num_finfo);
975         if (!NT_STATUS_IS_OK(status)) {
976                 goto fail;
977         }
978
979         for (i=0; i<num_finfo; i++) {
980                 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
981                 if (!NT_STATUS_IS_OK(status)) {
982                         goto fail;
983                 }
984         }
985  fail:
986         TALLOC_FREE(frame);
987         return status;
988 }