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