s3: Remove chain_reply
[Samba/gebeck_regimport.git] / source3 / libsmb / clilist.c
blobce36a4b2e78a01f1858771f85502ca1512852871
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"
26 /****************************************************************************
27 Calculate a safe next_entry_offset.
28 ****************************************************************************/
30 static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
32 size_t next_entry_offset = (size_t)IVAL(base,0);
34 if (next_entry_offset == 0 ||
35 base + next_entry_offset < base ||
36 base + next_entry_offset > pdata_end) {
37 next_entry_offset = pdata_end - base;
39 return next_entry_offset;
42 /****************************************************************************
43 Interpret a long filename structure - this is mostly guesses at the moment.
44 The length of the structure is returned
45 The structure of a long filename depends on the info level.
46 SMB_FIND_FILE_BOTH_DIRECTORY_INFO is used
47 by NT and SMB_FIND_EA_SIZE is used by OS/2
48 ****************************************************************************/
50 static size_t interpret_long_filename(TALLOC_CTX *ctx,
51 struct cli_state *cli,
52 int level,
53 const char *base_ptr,
54 uint16_t recv_flags2,
55 const char *p,
56 const char *pdata_end,
57 struct file_info *finfo,
58 uint32 *p_resume_key,
59 DATA_BLOB *p_last_name_raw)
61 int len;
62 size_t ret;
63 const char *base = p;
65 data_blob_free(p_last_name_raw);
67 if (p_resume_key) {
68 *p_resume_key = 0;
70 ZERO_STRUCTP(finfo);
72 switch (level) {
73 case SMB_FIND_INFO_STANDARD: /* OS/2 understands this */
74 /* these dates are converted to GMT by
75 make_unix_date */
76 if (pdata_end - base < 27) {
77 return pdata_end - base;
79 finfo->ctime_ts = convert_time_t_to_timespec(
80 make_unix_date2(p+4, cli_state_server_time_zone(cli)));
81 finfo->atime_ts = convert_time_t_to_timespec(
82 make_unix_date2(p+8, cli_state_server_time_zone(cli)));
83 finfo->mtime_ts = convert_time_t_to_timespec(
84 make_unix_date2(p+12, cli_state_server_time_zone(cli)));
85 finfo->size = IVAL(p,16);
86 finfo->mode = CVAL(p,24);
87 len = CVAL(p, 26);
88 p += 27;
89 p += align_string(base_ptr, p, 0);
91 /* We can safely use len here (which is required by OS/2)
92 * and the NAS-BASIC server instead of +2 or +1 as the
93 * STR_TERMINATE flag below is
94 * actually used as the length calculation.
95 * The len is merely an upper bound.
96 * Due to the explicit 2 byte null termination
97 * in cli_receive_trans/cli_receive_nt_trans
98 * we know this is safe. JRA + kukks
101 if (p + len > pdata_end) {
102 return pdata_end - base;
105 /* the len+2 below looks strange but it is
106 important to cope with the differences
107 between win2000 and win9x for this call
108 (tridge) */
109 ret = clistr_pull_talloc(ctx,
110 base_ptr,
111 recv_flags2,
112 &finfo->name,
114 len+2,
115 STR_TERMINATE);
116 if (ret == (size_t)-1) {
117 return pdata_end - base;
119 p += ret;
120 return PTR_DIFF(p, base);
122 case SMB_FIND_EA_SIZE: /* this is what OS/2 uses mostly */
123 /* these dates are converted to GMT by
124 make_unix_date */
125 if (pdata_end - base < 31) {
126 return pdata_end - base;
128 finfo->ctime_ts = convert_time_t_to_timespec(
129 make_unix_date2(p+4, cli_state_server_time_zone(cli)));
130 finfo->atime_ts = convert_time_t_to_timespec(
131 make_unix_date2(p+8, cli_state_server_time_zone(cli)));
132 finfo->mtime_ts = convert_time_t_to_timespec(
133 make_unix_date2(p+12, cli_state_server_time_zone(cli)));
134 finfo->size = IVAL(p,16);
135 finfo->mode = CVAL(p,24);
136 len = CVAL(p, 30);
137 p += 31;
138 /* check for unisys! */
139 if (p + len + 1 > pdata_end) {
140 return pdata_end - base;
142 ret = clistr_pull_talloc(ctx,
143 base_ptr,
144 recv_flags2,
145 &finfo->name,
147 len,
148 STR_NOALIGN);
149 if (ret == (size_t)-1) {
150 return pdata_end - base;
152 p += ret;
153 return PTR_DIFF(p, base) + 1;
155 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
157 size_t namelen, slen;
159 if (pdata_end - base < 94) {
160 return pdata_end - base;
163 p += 4; /* next entry offset */
165 if (p_resume_key) {
166 *p_resume_key = IVAL(p,0);
168 p += 4; /* fileindex */
170 /* Offset zero is "create time", not "change time". */
171 p += 8;
172 finfo->atime_ts = interpret_long_date(p);
173 p += 8;
174 finfo->mtime_ts = interpret_long_date(p);
175 p += 8;
176 finfo->ctime_ts = interpret_long_date(p);
177 p += 8;
178 finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
179 p += 8;
180 p += 8; /* alloc size */
181 finfo->mode = CVAL(p,0);
182 p += 4;
183 namelen = IVAL(p,0);
184 p += 4;
185 p += 4; /* EA size */
186 slen = SVAL(p, 0);
187 if (slen > 24) {
188 /* Bad short name length. */
189 return pdata_end - base;
191 p += 2;
192 ret = clistr_pull_talloc(ctx,
193 base_ptr,
194 recv_flags2,
195 &finfo->short_name,
197 slen,
198 STR_UNICODE);
199 if (ret == (size_t)-1) {
200 return pdata_end - base;
202 p += 24; /* short name? */
203 if (p + namelen < p || p + namelen > pdata_end) {
204 return pdata_end - base;
206 ret = clistr_pull_talloc(ctx,
207 base_ptr,
208 recv_flags2,
209 &finfo->name,
211 namelen,
213 if (ret == (size_t)-1) {
214 return pdata_end - base;
217 /* To be robust in the face of unicode conversion failures
218 we need to copy the raw bytes of the last name seen here.
219 Namelen doesn't include the terminating unicode null, so
220 copy it here. */
222 if (p_last_name_raw) {
223 *p_last_name_raw = data_blob(NULL, namelen+2);
224 memcpy(p_last_name_raw->data, p, namelen);
225 SSVAL(p_last_name_raw->data, namelen, 0);
227 return calc_next_entry_offset(base, pdata_end);
231 DEBUG(1,("Unknown long filename format %d\n",level));
232 return calc_next_entry_offset(base, pdata_end);
235 /****************************************************************************
236 Interpret a short filename structure.
237 The length of the structure is returned.
238 ****************************************************************************/
240 static bool interpret_short_filename(TALLOC_CTX *ctx,
241 struct cli_state *cli,
242 char *p,
243 struct file_info *finfo)
245 size_t ret;
246 ZERO_STRUCTP(finfo);
248 finfo->mode = CVAL(p,21);
250 /* this date is converted to GMT by make_unix_date */
251 finfo->ctime_ts.tv_sec = make_unix_date(p+22, cli_state_server_time_zone(cli));
252 finfo->ctime_ts.tv_nsec = 0;
253 finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
254 finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
255 finfo->size = IVAL(p,26);
256 ret = clistr_pull_talloc(ctx,
257 NULL,
259 &finfo->name,
260 p+30,
262 STR_ASCII);
263 if (ret == (size_t)-1) {
264 return false;
267 if (finfo->name) {
268 finfo->short_name = talloc_strdup(ctx, finfo->name);
269 if (finfo->short_name == NULL) {
270 return false;
273 return true;
276 struct cli_list_old_state {
277 struct tevent_context *ev;
278 struct cli_state *cli;
279 uint16_t vwv[2];
280 char *mask;
281 int num_asked;
282 uint16_t attribute;
283 uint8_t search_status[23];
284 bool first;
285 bool done;
286 uint8_t *dirlist;
289 static void cli_list_old_done(struct tevent_req *subreq);
291 static struct tevent_req *cli_list_old_send(TALLOC_CTX *mem_ctx,
292 struct tevent_context *ev,
293 struct cli_state *cli,
294 const char *mask,
295 uint16_t attribute)
297 struct tevent_req *req, *subreq;
298 struct cli_list_old_state *state;
299 uint8_t *bytes;
300 static const uint16_t zero = 0;
301 uint32_t usable_space;
303 req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
304 if (req == NULL) {
305 return NULL;
307 state->ev = ev;
308 state->cli = cli;
309 state->attribute = attribute;
310 state->first = true;
311 state->mask = talloc_strdup(state, mask);
312 if (tevent_req_nomem(state->mask, req)) {
313 return tevent_req_post(req, ev);
315 usable_space = cli_state_available_size(cli, 100);
316 state->num_asked = usable_space / DIR_STRUCT_SIZE;
318 SSVAL(state->vwv + 0, 0, state->num_asked);
319 SSVAL(state->vwv + 1, 0, state->attribute);
321 bytes = talloc_array(state, uint8_t, 1);
322 if (tevent_req_nomem(bytes, req)) {
323 return tevent_req_post(req, ev);
325 bytes[0] = 4;
326 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), mask,
327 strlen(mask)+1, NULL);
329 bytes = smb_bytes_push_bytes(bytes, 5, (const uint8_t *)&zero, 2);
330 if (tevent_req_nomem(bytes, req)) {
331 return tevent_req_post(req, ev);
334 subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch,
335 0, 2, state->vwv, talloc_get_size(bytes), bytes);
336 if (tevent_req_nomem(subreq, req)) {
337 return tevent_req_post(req, ev);
339 tevent_req_set_callback(subreq, cli_list_old_done, req);
340 return req;
343 static void cli_list_old_done(struct tevent_req *subreq)
345 struct tevent_req *req = tevent_req_callback_data(
346 subreq, struct tevent_req);
347 struct cli_list_old_state *state = tevent_req_data(
348 req, struct cli_list_old_state);
349 NTSTATUS status;
350 uint8_t cmd;
351 uint8_t wct;
352 uint16_t *vwv;
353 uint32_t num_bytes;
354 uint8_t *bytes;
355 uint16_t received;
356 size_t dirlist_len;
357 uint8_t *tmp;
359 status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes,
360 &bytes);
361 if (!NT_STATUS_IS_OK(status)
362 && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
363 && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
364 TALLOC_FREE(subreq);
365 tevent_req_nterror(req, status);
366 return;
368 if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
369 || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
370 received = 0;
371 } else {
372 if (wct < 1) {
373 TALLOC_FREE(subreq);
374 tevent_req_nterror(
375 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
376 return;
378 received = SVAL(vwv + 0, 0);
381 if (received > 0) {
383 * I don't think this can wrap. received is
384 * initialized from a 16-bit value.
386 if (num_bytes < (received * DIR_STRUCT_SIZE + 3)) {
387 TALLOC_FREE(subreq);
388 tevent_req_nterror(
389 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
390 return;
393 dirlist_len = talloc_get_size(state->dirlist);
395 tmp = talloc_realloc(
396 state, state->dirlist, uint8_t,
397 dirlist_len + received * DIR_STRUCT_SIZE);
398 if (tevent_req_nomem(tmp, req)) {
399 return;
401 state->dirlist = tmp;
402 memcpy(state->dirlist + dirlist_len, bytes + 3,
403 received * DIR_STRUCT_SIZE);
405 SSVAL(state->search_status, 0, 21);
406 memcpy(state->search_status + 2,
407 bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21);
408 cmd = SMBsearch;
409 } else {
410 if (state->first || state->done) {
411 tevent_req_done(req);
412 return;
414 state->done = true;
415 state->num_asked = 0;
416 cmd = SMBfclose;
418 TALLOC_FREE(subreq);
420 state->first = false;
422 SSVAL(state->vwv + 0, 0, state->num_asked);
423 SSVAL(state->vwv + 1, 0, state->attribute);
425 bytes = talloc_array(state, uint8_t, 1);
426 if (tevent_req_nomem(bytes, req)) {
427 return;
429 bytes[0] = 4;
430 bytes = smb_bytes_push_str(bytes, cli_ucs2(state->cli), "",
431 1, NULL);
432 bytes = smb_bytes_push_bytes(bytes, 5, state->search_status,
433 sizeof(state->search_status));
434 if (tevent_req_nomem(bytes, req)) {
435 return;
437 subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0,
438 2, state->vwv, talloc_get_size(bytes), bytes);
439 if (tevent_req_nomem(subreq, req)) {
440 return;
442 tevent_req_set_callback(subreq, cli_list_old_done, req);
445 static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
446 struct file_info **pfinfo)
448 struct cli_list_old_state *state = tevent_req_data(
449 req, struct cli_list_old_state);
450 NTSTATUS status;
451 size_t i, num_received;
452 struct file_info *finfo;
454 if (tevent_req_is_nterror(req, &status)) {
455 return status;
458 num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
460 finfo = talloc_array(mem_ctx, struct file_info, num_received);
461 if (finfo == NULL) {
462 return NT_STATUS_NO_MEMORY;
465 for (i=0; i<num_received; i++) {
466 if (!interpret_short_filename(
467 finfo, state->cli,
468 (char *)state->dirlist + i * DIR_STRUCT_SIZE,
469 &finfo[i])) {
470 TALLOC_FREE(finfo);
471 return NT_STATUS_NO_MEMORY;
474 *pfinfo = finfo;
475 return NT_STATUS_OK;
478 NTSTATUS cli_list_old(struct cli_state *cli, const char *mask,
479 uint16 attribute,
480 NTSTATUS (*fn)(const char *, struct file_info *,
481 const char *, void *), void *state)
483 TALLOC_CTX *frame = talloc_stackframe();
484 struct event_context *ev;
485 struct tevent_req *req;
486 NTSTATUS status = NT_STATUS_NO_MEMORY;
487 struct file_info *finfo;
488 size_t i, num_finfo;
490 if (cli_has_async_calls(cli)) {
492 * Can't use sync call while an async call is in flight
494 status = NT_STATUS_INVALID_PARAMETER;
495 goto fail;
497 ev = event_context_init(frame);
498 if (ev == NULL) {
499 goto fail;
501 req = cli_list_old_send(frame, ev, cli, mask, attribute);
502 if (req == NULL) {
503 goto fail;
505 if (!tevent_req_poll(req, ev)) {
506 status = map_nt_error_from_unix(errno);
507 goto fail;
509 status = cli_list_old_recv(req, frame, &finfo);
510 if (!NT_STATUS_IS_OK(status)) {
511 goto fail;
513 num_finfo = talloc_array_length(finfo);
514 for (i=0; i<num_finfo; i++) {
515 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
516 if (!NT_STATUS_IS_OK(status)) {
517 goto fail;
520 fail:
521 TALLOC_FREE(frame);
522 return status;
525 struct cli_list_trans_state {
526 struct tevent_context *ev;
527 struct cli_state *cli;
528 char *mask;
529 uint16_t attribute;
530 uint16_t info_level;
532 int loop_count;
533 int total_received;
534 uint16_t max_matches;
535 bool first;
537 int ff_eos;
538 int ff_dir_handle;
540 uint16_t setup[1];
541 uint8_t *param;
543 struct file_info *finfo;
546 static void cli_list_trans_done(struct tevent_req *subreq);
548 static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
549 struct tevent_context *ev,
550 struct cli_state *cli,
551 const char *mask,
552 uint16_t attribute,
553 uint16_t info_level)
555 struct tevent_req *req, *subreq;
556 struct cli_list_trans_state *state;
557 size_t param_len;
559 req = tevent_req_create(mem_ctx, &state,
560 struct cli_list_trans_state);
561 if (req == NULL) {
562 return NULL;
564 state->ev = ev;
565 state->cli = cli;
566 state->mask = talloc_strdup(state, mask);
567 if (tevent_req_nomem(state->mask, req)) {
568 return tevent_req_post(req, ev);
570 state->attribute = attribute;
571 state->info_level = info_level;
572 state->loop_count = 0;
573 state->first = true;
575 state->max_matches = 1366; /* Match W2k */
577 SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
579 state->param = talloc_array(state, uint8_t, 12);
580 if (tevent_req_nomem(state->param, req)) {
581 return tevent_req_post(req, ev);
584 SSVAL(state->param, 0, state->attribute);
585 SSVAL(state->param, 2, state->max_matches);
586 SSVAL(state->param, 4,
587 FLAG_TRANS2_FIND_REQUIRE_RESUME
588 |FLAG_TRANS2_FIND_CLOSE_IF_END
589 |(cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0));
590 SSVAL(state->param, 6, state->info_level);
591 SIVAL(state->param, 8, 0);
593 state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli),
594 state->mask, strlen(state->mask)+1,
595 NULL);
596 if (tevent_req_nomem(state->param, req)) {
597 return tevent_req_post(req, ev);
599 param_len = talloc_get_size(state->param);
601 subreq = cli_trans_send(state, state->ev, state->cli,
602 SMBtrans2, NULL, -1, 0, 0,
603 state->setup, 1, 0,
604 state->param, param_len, 10,
605 NULL, 0, CLI_BUFFER_SIZE);
606 if (tevent_req_nomem(subreq, req)) {
607 return tevent_req_post(req, ev);
609 tevent_req_set_callback(subreq, cli_list_trans_done, req);
610 return req;
613 static void cli_list_trans_done(struct tevent_req *subreq)
615 struct tevent_req *req = tevent_req_callback_data(
616 subreq, struct tevent_req);
617 struct cli_list_trans_state *state = tevent_req_data(
618 req, struct cli_list_trans_state);
619 NTSTATUS status;
620 uint8_t *param;
621 uint32_t num_param;
622 uint8_t *data;
623 char *data_end;
624 uint32_t num_data;
625 uint32_t min_param;
626 struct file_info *tmp;
627 size_t old_num_finfo;
628 uint16_t recv_flags2;
629 int ff_searchcount;
630 bool ff_eos;
631 char *p, *p2;
632 uint32_t resume_key = 0;
633 int i;
634 DATA_BLOB last_name_raw;
635 struct file_info *finfo = NULL;
636 size_t param_len;
638 min_param = (state->first ? 6 : 4);
640 status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
641 NULL, 0, NULL,
642 &param, min_param, &num_param,
643 &data, 0, &num_data);
644 TALLOC_FREE(subreq);
645 if (!NT_STATUS_IS_OK(status)) {
647 * TODO: retry, OS/2 nofiles
649 tevent_req_nterror(req, status);
650 return;
653 if (state->first) {
654 state->ff_dir_handle = SVAL(param, 0);
655 ff_searchcount = SVAL(param, 2);
656 ff_eos = SVAL(param, 4) != 0;
657 } else {
658 ff_searchcount = SVAL(param, 0);
659 ff_eos = SVAL(param, 2) != 0;
662 old_num_finfo = talloc_array_length(state->finfo);
664 tmp = talloc_realloc(state, state->finfo, struct file_info,
665 old_num_finfo + ff_searchcount);
666 if (tevent_req_nomem(tmp, req)) {
667 return;
669 state->finfo = tmp;
671 p2 = p = (char *)data;
672 data_end = (char *)data + num_data;
673 last_name_raw = data_blob_null;
675 for (i=0; i<ff_searchcount; i++) {
676 if (p2 >= data_end) {
677 ff_eos = true;
678 break;
680 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
681 && (i == ff_searchcount-1)) {
682 /* Last entry - fixup the last offset length. */
683 SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
686 data_blob_free(&last_name_raw);
688 finfo = &state->finfo[old_num_finfo + i];
690 p2 += interpret_long_filename(
691 state->finfo, /* Stick fname to the array as such */
692 state->cli, state->info_level,
693 (char *)data, recv_flags2, p2,
694 data_end, finfo, &resume_key, &last_name_raw);
696 if (finfo->name == NULL) {
697 DEBUG(1, ("cli_list: Error: unable to parse name from "
698 "info level %d\n", state->info_level));
699 ff_eos = true;
700 break;
702 if (!state->first && (state->mask[0] != '\0') &&
703 strcsequal(finfo->name, state->mask)) {
704 DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
705 "already been seen?\n", finfo->name));
706 ff_eos = true;
707 break;
711 if (ff_searchcount == 0) {
712 ff_eos = true;
715 TALLOC_FREE(param);
716 TALLOC_FREE(data);
719 * Shrink state->finfo to the real length we received
721 tmp = talloc_realloc(state, state->finfo, struct file_info,
722 old_num_finfo + i);
723 if (tevent_req_nomem(tmp, req)) {
724 return;
726 state->finfo = tmp;
728 state->first = false;
730 if (ff_eos) {
731 data_blob_free(&last_name_raw);
732 tevent_req_done(req);
733 return;
736 TALLOC_FREE(state->mask);
737 state->mask = talloc_strdup(state, finfo->name);
738 if (tevent_req_nomem(state->mask, req)) {
739 return;
742 SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
744 param = talloc_realloc(state, state->param, uint8_t, 12);
745 if (tevent_req_nomem(param, req)) {
746 return;
748 state->param = param;
750 SSVAL(param, 0, state->ff_dir_handle);
751 SSVAL(param, 2, state->max_matches); /* max count */
752 SSVAL(param, 4, state->info_level);
754 * For W2K servers serving out FAT filesystems we *must* set
755 * the resume key. If it's not FAT then it's returned as zero.
757 SIVAL(param, 6, resume_key); /* ff_resume_key */
759 * NB. *DON'T* use continue here. If you do it seems that W2K
760 * and bretheren can miss filenames. Use last filename
761 * continue instead. JRA
763 SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
764 |FLAG_TRANS2_FIND_CLOSE_IF_END
765 |(state->cli->backup_intent ? FLAG_TRANS2_FIND_BACKUP_INTENT : 0)));
766 if (last_name_raw.length) {
767 state->param = trans2_bytes_push_bytes(state->param,
768 last_name_raw.data,
769 last_name_raw.length);
770 if (tevent_req_nomem(state->param, req)) {
771 return;
773 data_blob_free(&last_name_raw);
774 } else {
775 state->param = trans2_bytes_push_str(state->param,
776 cli_ucs2(state->cli),
777 state->mask,
778 strlen(state->mask)+1,
779 NULL);
780 if (tevent_req_nomem(state->param, req)) {
781 return;
784 param_len = talloc_get_size(state->param);
786 subreq = cli_trans_send(state, state->ev, state->cli,
787 SMBtrans2, NULL, -1, 0, 0,
788 state->setup, 1, 0,
789 state->param, param_len, 10,
790 NULL, 0, CLI_BUFFER_SIZE);
791 if (tevent_req_nomem(subreq, req)) {
792 return;
794 tevent_req_set_callback(subreq, cli_list_trans_done, req);
797 static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
798 TALLOC_CTX *mem_ctx,
799 struct file_info **finfo)
801 struct cli_list_trans_state *state = tevent_req_data(
802 req, struct cli_list_trans_state);
803 NTSTATUS status;
805 if (tevent_req_is_nterror(req, &status)) {
806 return status;
808 *finfo = talloc_move(mem_ctx, &state->finfo);
809 return NT_STATUS_OK;
812 NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
813 uint16_t attribute, int info_level,
814 NTSTATUS (*fn)(const char *mnt, struct file_info *finfo,
815 const char *mask, void *private_data),
816 void *private_data)
818 TALLOC_CTX *frame = talloc_stackframe();
819 struct event_context *ev;
820 struct tevent_req *req;
821 int i, num_finfo;
822 struct file_info *finfo = NULL;
823 NTSTATUS status = NT_STATUS_NO_MEMORY;
825 if (cli_has_async_calls(cli)) {
827 * Can't use sync call while an async call is in flight
829 status = NT_STATUS_INVALID_PARAMETER;
830 goto fail;
832 ev = event_context_init(frame);
833 if (ev == NULL) {
834 goto fail;
836 req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
837 if (req == NULL) {
838 goto fail;
840 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
841 goto fail;
843 status = cli_list_trans_recv(req, frame, &finfo);
844 if (!NT_STATUS_IS_OK(status)) {
845 goto fail;
847 num_finfo = talloc_array_length(finfo);
848 for (i=0; i<num_finfo; i++) {
849 status = fn(cli->dfs_mountpoint, &finfo[i], mask, private_data);
850 if (!NT_STATUS_IS_OK(status)) {
851 goto fail;
854 fail:
855 TALLOC_FREE(frame);
856 return status;
859 struct cli_list_state {
860 NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
861 struct file_info **finfo);
862 struct file_info *finfo;
865 static void cli_list_done(struct tevent_req *subreq);
867 struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
868 struct tevent_context *ev,
869 struct cli_state *cli,
870 const char *mask,
871 uint16_t attribute,
872 uint16_t info_level)
874 struct tevent_req *req, *subreq;
875 struct cli_list_state *state;
877 req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
878 if (req == NULL) {
879 return NULL;
882 if (cli_state_protocol(cli) <= PROTOCOL_LANMAN1) {
883 subreq = cli_list_old_send(state, ev, cli, mask, attribute);
884 state->recv_fn = cli_list_old_recv;
885 } else {
886 subreq = cli_list_trans_send(state, ev, cli, mask, attribute,
887 info_level);
888 state->recv_fn = cli_list_trans_recv;
890 if (tevent_req_nomem(subreq, req)) {
891 return tevent_req_post(req, ev);
893 tevent_req_set_callback(subreq, cli_list_done, req);
894 return req;
897 static void cli_list_done(struct tevent_req *subreq)
899 struct tevent_req *req = tevent_req_callback_data(
900 subreq, struct tevent_req);
901 struct cli_list_state *state = tevent_req_data(
902 req, struct cli_list_state);
903 NTSTATUS status;
905 status = state->recv_fn(subreq, state, &state->finfo);
906 TALLOC_FREE(subreq);
907 if (!NT_STATUS_IS_OK(status)) {
908 tevent_req_nterror(req, status);
909 return;
911 tevent_req_done(req);
914 NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
915 struct file_info **finfo, size_t *num_finfo)
917 struct cli_list_state *state = tevent_req_data(
918 req, struct cli_list_state);
919 NTSTATUS status;
921 if (tevent_req_is_nterror(req, &status)) {
922 return status;
924 *num_finfo = talloc_array_length(state->finfo);
925 *finfo = talloc_move(mem_ctx, &state->finfo);
926 return NT_STATUS_OK;
929 NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute,
930 NTSTATUS (*fn)(const char *, struct file_info *, const char *,
931 void *), void *state)
933 TALLOC_CTX *frame = talloc_stackframe();
934 struct event_context *ev;
935 struct tevent_req *req;
936 NTSTATUS status = NT_STATUS_NO_MEMORY;
937 struct file_info *finfo;
938 size_t i, num_finfo;
939 uint16_t info_level;
941 if (cli_has_async_calls(cli)) {
943 * Can't use sync call while an async call is in flight
945 status = NT_STATUS_INVALID_PARAMETER;
946 goto fail;
948 ev = event_context_init(frame);
949 if (ev == NULL) {
950 goto fail;
953 info_level = (cli_state_capabilities(cli) & CAP_NT_SMBS)
954 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
956 req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
957 if (req == NULL) {
958 goto fail;
960 if (!tevent_req_poll(req, ev)) {
961 status = map_nt_error_from_unix(errno);
962 goto fail;
965 status = cli_list_recv(req, frame, &finfo, &num_finfo);
966 if (!NT_STATUS_IS_OK(status)) {
967 goto fail;
970 for (i=0; i<num_finfo; i++) {
971 status = fn(cli->dfs_mountpoint, &finfo[i], mask, state);
972 if (!NT_STATUS_IS_OK(status)) {
973 goto fail;
976 fail:
977 TALLOC_FREE(frame);
978 return status;