s4:selftest: explicitly set NSS/RESOLV_WAPPER_* in wait_for_start
[Samba.git] / source3 / libsmb / clilist.c
blob41f585120b92793b5f605ba76edfb78c764d6055
1 /*
2 Unix SMB/CIFS implementation.
3 client directory list routines
4 Copyright (C) Andrew Tridgell 1994-1998
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.
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.
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/>.
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"
27 /****************************************************************************
28 Calculate a safe next_entry_offset.
29 ****************************************************************************/
31 static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
33 size_t next_entry_offset = (size_t)IVAL(base,0);
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;
40 return next_entry_offset;
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 ****************************************************************************/
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)
62 int len;
63 size_t ret;
64 const char *base = p;
66 data_blob_free(p_last_name_raw);
68 if (p_resume_key) {
69 *p_resume_key = 0;
71 ZERO_STRUCTP(finfo);
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;
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);
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
104 if (p + len > pdata_end) {
105 return pdata_end - base;
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,
117 len+2,
118 STR_TERMINATE);
119 if (ret == (size_t)-1) {
120 return pdata_end - base;
122 p += ret;
123 return PTR_DIFF(p, base);
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;
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;
145 ret = clistr_pull_talloc(ctx,
146 base_ptr,
147 recv_flags2,
148 &finfo->name,
150 len,
151 STR_NOALIGN);
152 if (ret == (size_t)-1) {
153 return pdata_end - base;
155 p += ret;
156 return PTR_DIFF(p, base) + 1;
158 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
160 size_t namelen, slen;
162 if (pdata_end - base < 94) {
163 return pdata_end - base;
166 p += 4; /* next entry offset */
168 if (p_resume_key) {
169 *p_resume_key = IVAL(p,0);
171 p += 4; /* fileindex */
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;
194 p += 2;
195 ret = clistr_pull_talloc(ctx,
196 base_ptr,
197 recv_flags2,
198 &finfo->short_name,
200 slen,
201 STR_UNICODE);
202 if (ret == (size_t)-1) {
203 return pdata_end - base;
205 p += 24; /* short name? */
206 if (p + namelen < p || p + namelen > pdata_end) {
207 return pdata_end - base;
209 ret = clistr_pull_talloc(ctx,
210 base_ptr,
211 recv_flags2,
212 &finfo->name,
214 namelen,
216 if (ret == (size_t)-1) {
217 return pdata_end - base;
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. */
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);
230 return calc_next_entry_offset(base, pdata_end);
234 DEBUG(1,("Unknown long filename format %d\n",level));
235 return calc_next_entry_offset(base, pdata_end);
238 /****************************************************************************
239 Interpret a short filename structure.
240 The length of the structure is returned.
241 ****************************************************************************/
243 static bool interpret_short_filename(TALLOC_CTX *ctx,
244 struct cli_state *cli,
245 char *p,
246 struct file_info *finfo)
248 size_t ret;
249 ZERO_STRUCTP(finfo);
251 finfo->mode = CVAL(p,21);
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,
262 &finfo->name,
263 p+30,
265 STR_ASCII);
266 if (ret == (size_t)-1) {
267 return false;
270 if (finfo->name) {
271 finfo->short_name = talloc_strdup(ctx, finfo->name);
272 if (finfo->short_name == NULL) {
273 return false;
276 return true;
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;
292 static void cli_list_old_done(struct tevent_req *subreq);
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)
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;
306 req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
307 if (req == NULL) {
308 return NULL;
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);
318 usable_space = cli_state_available_size(cli, 100);
319 state->num_asked = usable_space / DIR_STRUCT_SIZE;
321 SSVAL(state->vwv + 0, 0, state->num_asked);
322 SSVAL(state->vwv + 1, 0, state->attribute);
324 bytes = talloc_array(state, uint8_t, 1);
325 if (tevent_req_nomem(bytes, req)) {
326 return tevent_req_post(req, ev);
328 bytes[0] = 4;
329 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), mask,
330 strlen(mask)+1, NULL);
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);
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);
342 tevent_req_set_callback(subreq, cli_list_old_done, req);
343 return req;
346 static void cli_list_old_done(struct tevent_req *subreq)
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;
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;
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;
381 received = SVAL(vwv + 0, 0);
384 if (received > 0) {
386 * I don't think this can wrap. received is
387 * initialized from a 16-bit value.
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;
396 dirlist_len = talloc_get_size(state->dirlist);
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;
404 state->dirlist = tmp;
405 memcpy(state->dirlist + dirlist_len, bytes + 3,
406 received * DIR_STRUCT_SIZE);
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;
417 state->done = true;
418 state->num_asked = 0;
419 cmd = SMBfclose;
421 TALLOC_FREE(subreq);
423 state->first = false;
425 SSVAL(state->vwv + 0, 0, state->num_asked);
426 SSVAL(state->vwv + 1, 0, state->attribute);
428 bytes = talloc_array(state, uint8_t, 1);
429 if (tevent_req_nomem(bytes, req)) {
430 return;
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;
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;
445 tevent_req_set_callback(subreq, cli_list_old_done, req);
448 static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
449 struct file_info **pfinfo)
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;
457 if (tevent_req_is_nterror(req, &status)) {
458 return status;
461 num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
463 finfo = talloc_array(mem_ctx, struct file_info, num_received);
464 if (finfo == NULL) {
465 return NT_STATUS_NO_MEMORY;
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;
477 *pfinfo = finfo;
478 return NT_STATUS_OK;
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)
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;
493 if (smbXcli_conn_has_async_calls(cli->conn)) {
495 * Can't use sync call while an async call is in flight
497 status = NT_STATUS_INVALID_PARAMETER;
498 goto fail;
500 ev = samba_tevent_context_init(frame);
501 if (ev == NULL) {
502 goto fail;
504 req = cli_list_old_send(frame, ev, cli, mask, attribute);
505 if (req == NULL) {
506 goto fail;
508 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
509 goto fail;
511 status = cli_list_old_recv(req, frame, &finfo);
512 if (!NT_STATUS_IS_OK(status)) {
513 goto fail;
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;
522 fail:
523 TALLOC_FREE(frame);
524 return status;
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;
534 int loop_count;
535 int total_received;
536 uint16_t max_matches;
537 bool first;
539 int ff_eos;
540 int ff_dir_handle;
542 uint16_t setup[1];
543 uint8_t *param;
545 struct file_info *finfo;
548 static void cli_list_trans_done(struct tevent_req *subreq);
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)
557 struct tevent_req *req, *subreq;
558 struct cli_list_trans_state *state;
559 size_t param_len;
560 uint16_t additional_flags2 = 0;
562 req = tevent_req_create(mem_ctx, &state,
563 struct cli_list_trans_state);
564 if (req == NULL) {
565 return NULL;
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);
573 state->attribute = attribute;
574 state->info_level = info_level;
575 state->loop_count = 0;
576 state->first = true;
578 state->max_matches = 1366; /* Match W2k */
580 SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
582 state->param = talloc_array(state, uint8_t, 12);
583 if (tevent_req_nomem(state->param, req)) {
584 return tevent_req_post(req, ev);
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);
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);
603 if (clistr_is_previous_version_path(state->mask, NULL, NULL, NULL)) {
604 additional_flags2 = FLAGS2_REPARSE_PATH;
607 param_len = talloc_get_size(state->param);
609 subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
610 SMBtrans2, NULL, -1, 0, 0,
611 state->setup, 1, 0,
612 state->param, param_len, 10,
613 NULL, 0, CLI_BUFFER_SIZE);
614 if (tevent_req_nomem(subreq, req)) {
615 return tevent_req_post(req, ev);
617 tevent_req_set_callback(subreq, cli_list_trans_done, req);
618 return req;
621 static void cli_list_trans_done(struct tevent_req *subreq)
623 struct tevent_req *req = tevent_req_callback_data(
624 subreq, struct tevent_req);
625 struct cli_list_trans_state *state = tevent_req_data(
626 req, struct cli_list_trans_state);
627 NTSTATUS status;
628 uint8_t *param;
629 uint32_t num_param;
630 uint8_t *data;
631 char *data_end;
632 uint32_t num_data;
633 uint32_t min_param;
634 struct file_info *tmp;
635 size_t old_num_finfo;
636 uint16_t recv_flags2;
637 int ff_searchcount;
638 bool ff_eos;
639 char *p, *p2;
640 uint32_t resume_key = 0;
641 int i;
642 DATA_BLOB last_name_raw;
643 struct file_info *finfo = NULL;
644 size_t param_len;
645 uint16_t additional_flags2 = 0;
647 min_param = (state->first ? 6 : 4);
649 status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
650 NULL, 0, NULL,
651 &param, min_param, &num_param,
652 &data, 0, &num_data);
653 TALLOC_FREE(subreq);
654 if (!NT_STATUS_IS_OK(status)) {
656 * TODO: retry, OS/2 nofiles
658 tevent_req_nterror(req, status);
659 return;
662 if (state->first) {
663 state->ff_dir_handle = SVAL(param, 0);
664 ff_searchcount = SVAL(param, 2);
665 ff_eos = SVAL(param, 4) != 0;
666 } else {
667 ff_searchcount = SVAL(param, 0);
668 ff_eos = SVAL(param, 2) != 0;
671 old_num_finfo = talloc_array_length(state->finfo);
673 tmp = talloc_realloc(state, state->finfo, struct file_info,
674 old_num_finfo + ff_searchcount);
675 if (tevent_req_nomem(tmp, req)) {
676 return;
678 state->finfo = tmp;
680 p2 = p = (char *)data;
681 data_end = (char *)data + num_data;
682 last_name_raw = data_blob_null;
684 for (i=0; i<ff_searchcount; i++) {
685 if (p2 >= data_end) {
686 ff_eos = true;
687 break;
689 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
690 && (i == ff_searchcount-1)) {
691 /* Last entry - fixup the last offset length. */
692 SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
695 data_blob_free(&last_name_raw);
697 finfo = &state->finfo[old_num_finfo + i];
699 p2 += interpret_long_filename(
700 state->finfo, /* Stick fname to the array as such */
701 state->cli, state->info_level,
702 (char *)data, recv_flags2, p2,
703 data_end, finfo, &resume_key, &last_name_raw);
705 if (finfo->name == NULL) {
706 DEBUG(1, ("cli_list: Error: unable to parse name from "
707 "info level %d\n", state->info_level));
708 ff_eos = true;
709 break;
711 if (!state->first && (state->mask[0] != '\0') &&
712 strcsequal(finfo->name, state->mask)) {
713 DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
714 "already been seen?\n", finfo->name));
715 ff_eos = true;
716 break;
720 if (ff_searchcount == 0) {
721 ff_eos = true;
724 TALLOC_FREE(param);
725 TALLOC_FREE(data);
728 * Shrink state->finfo to the real length we received
730 tmp = talloc_realloc(state, state->finfo, struct file_info,
731 old_num_finfo + i);
732 if (tevent_req_nomem(tmp, req)) {
733 return;
735 state->finfo = tmp;
737 state->first = false;
739 if (ff_eos) {
740 data_blob_free(&last_name_raw);
741 tevent_req_done(req);
742 return;
745 TALLOC_FREE(state->mask);
746 state->mask = talloc_strdup(state, finfo->name);
747 if (tevent_req_nomem(state->mask, req)) {
748 return;
751 SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
753 param = talloc_realloc(state, state->param, uint8_t, 12);
754 if (tevent_req_nomem(param, req)) {
755 return;
757 state->param = param;
759 SSVAL(param, 0, state->ff_dir_handle);
760 SSVAL(param, 2, state->max_matches); /* max count */
761 SSVAL(param, 4, state->info_level);
763 * For W2K servers serving out FAT filesystems we *must* set
764 * the resume key. If it's not FAT then it's returned as zero.
766 SIVAL(param, 6, resume_key); /* ff_resume_key */
768 * NB. *DON'T* use continue here. If you do it seems that W2K
769 * and bretheren can miss filenames. Use last filename
770 * continue instead. JRA
772 SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
773 |FLAG_TRANS2_FIND_CLOSE_IF_END
774 |(state->cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0)));
775 if (last_name_raw.length) {
776 state->param = trans2_bytes_push_bytes(state->param,
777 last_name_raw.data,
778 last_name_raw.length);
779 if (tevent_req_nomem(state->param, req)) {
780 return;
782 data_blob_free(&last_name_raw);
783 } else {
784 state->param = trans2_bytes_push_str(state->param,
785 smbXcli_conn_use_unicode(state->cli->conn),
786 state->mask,
787 strlen(state->mask)+1,
788 NULL);
789 if (tevent_req_nomem(state->param, req)) {
790 return;
793 param_len = talloc_get_size(state->param);
795 if (clistr_is_previous_version_path(state->mask, NULL, NULL, NULL)) {
796 additional_flags2 = FLAGS2_REPARSE_PATH;
799 subreq = cli_trans_send(state, state->ev, state->cli, additional_flags2,
800 SMBtrans2, NULL, -1, 0, 0,
801 state->setup, 1, 0,
802 state->param, param_len, 10,
803 NULL, 0, CLI_BUFFER_SIZE);
804 if (tevent_req_nomem(subreq, req)) {
805 return;
807 tevent_req_set_callback(subreq, cli_list_trans_done, req);
810 static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
811 TALLOC_CTX *mem_ctx,
812 struct file_info **finfo)
814 struct cli_list_trans_state *state = tevent_req_data(
815 req, struct cli_list_trans_state);
816 NTSTATUS status;
818 if (tevent_req_is_nterror(req, &status)) {
819 return status;
821 *finfo = talloc_move(mem_ctx, &state->finfo);
822 return NT_STATUS_OK;
825 NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
826 uint16_t attribute, int info_level,
827 NTSTATUS (*fn)(const char *mnt, struct file_info *finfo,
828 const char *mask, void *private_data),
829 void *private_data)
831 TALLOC_CTX *frame = talloc_stackframe();
832 struct tevent_context *ev;
833 struct tevent_req *req;
834 int i, num_finfo;
835 struct file_info *finfo = NULL;
836 NTSTATUS status = NT_STATUS_NO_MEMORY;
838 if (smbXcli_conn_has_async_calls(cli->conn)) {
840 * Can't use sync call while an async call is in flight
842 status = NT_STATUS_INVALID_PARAMETER;
843 goto fail;
845 ev = samba_tevent_context_init(frame);
846 if (ev == NULL) {
847 goto fail;
849 req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
850 if (req == NULL) {
851 goto fail;
853 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
854 goto fail;
856 status = cli_list_trans_recv(req, frame, &finfo);
857 if (!NT_STATUS_IS_OK(status)) {
858 goto fail;
860 num_finfo = talloc_array_length(finfo);
861 for (i=0; i<num_finfo; i++) {
862 status = fn(cli->dfs_mountpoint, &finfo[i], mask, private_data);
863 if (!NT_STATUS_IS_OK(status)) {
864 goto fail;
867 fail:
868 TALLOC_FREE(frame);
869 return status;
872 struct cli_list_state {
873 NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
874 struct file_info **finfo);
875 struct file_info *finfo;
878 static void cli_list_done(struct tevent_req *subreq);
880 struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
881 struct tevent_context *ev,
882 struct cli_state *cli,
883 const char *mask,
884 uint16_t attribute,
885 uint16_t info_level)
887 struct tevent_req *req, *subreq;
888 struct cli_list_state *state;
890 req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
891 if (req == NULL) {
892 return NULL;
895 if (smbXcli_conn_protocol(cli->conn) <= PROTOCOL_LANMAN1) {
896 subreq = cli_list_old_send(state, ev, cli, mask, attribute);
897 state->recv_fn = cli_list_old_recv;
898 } else {
899 subreq = cli_list_trans_send(state, ev, cli, mask, attribute,
900 info_level);
901 state->recv_fn = cli_list_trans_recv;
903 if (tevent_req_nomem(subreq, req)) {
904 return tevent_req_post(req, ev);
906 tevent_req_set_callback(subreq, cli_list_done, req);
907 return req;
910 static void cli_list_done(struct tevent_req *subreq)
912 struct tevent_req *req = tevent_req_callback_data(
913 subreq, struct tevent_req);
914 struct cli_list_state *state = tevent_req_data(
915 req, struct cli_list_state);
916 NTSTATUS status;
918 status = state->recv_fn(subreq, state, &state->finfo);
919 TALLOC_FREE(subreq);
920 if (!NT_STATUS_IS_OK(status)) {
921 tevent_req_nterror(req, status);
922 return;
924 tevent_req_done(req);
927 NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
928 struct file_info **finfo, size_t *num_finfo)
930 struct cli_list_state *state = tevent_req_data(
931 req, struct cli_list_state);
932 NTSTATUS status;
934 if (tevent_req_is_nterror(req, &status)) {
935 return status;
937 *num_finfo = talloc_array_length(state->finfo);
938 *finfo = talloc_move(mem_ctx, &state->finfo);
939 return NT_STATUS_OK;
942 NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16_t attribute,
943 NTSTATUS (*fn)(const char *, struct file_info *, const char *,
944 void *), void *state)
946 TALLOC_CTX *frame = NULL;
947 struct tevent_context *ev;
948 struct tevent_req *req;
949 NTSTATUS status = NT_STATUS_NO_MEMORY;
950 struct file_info *finfo;
951 size_t i, num_finfo;
952 uint16_t info_level;
954 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
955 return cli_smb2_list(cli, mask, attribute, fn, state);
958 frame = talloc_stackframe();
960 if (smbXcli_conn_has_async_calls(cli->conn)) {
962 * Can't use sync call while an async call is in flight
964 status = NT_STATUS_INVALID_PARAMETER;
965 goto fail;
967 ev = samba_tevent_context_init(frame);
968 if (ev == NULL) {
969 goto fail;
972 info_level = (smb1cli_conn_capabilities(cli->conn) & CAP_NT_SMBS)
973 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
975 req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
976 if (req == NULL) {
977 goto fail;
979 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
980 goto fail;
983 status = cli_list_recv(req, frame, &finfo, &num_finfo);
984 if (!NT_STATUS_IS_OK(status)) {
985 goto fail;
988 for (i=0; i<num_finfo; i++) {
989 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
990 if (!NT_STATUS_IS_OK(status)) {
991 goto fail;
994 fail:
995 TALLOC_FREE(frame);
996 return status;