Build error exception lost (without wafcache)
[Samba/ita.git] / source3 / libsmb / clilist.c
blobb580172317a0a82a0becacdd014cb52c9a897d40
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"
22 /****************************************************************************
23 Calculate a safe next_entry_offset.
24 ****************************************************************************/
26 static size_t calc_next_entry_offset(const char *base, const char *pdata_end)
28 size_t next_entry_offset = (size_t)IVAL(base,0);
30 if (next_entry_offset == 0 ||
31 base + next_entry_offset < base ||
32 base + next_entry_offset > pdata_end) {
33 next_entry_offset = pdata_end - base;
35 return next_entry_offset;
38 /****************************************************************************
39 Interpret a long filename structure - this is mostly guesses at the moment.
40 The length of the structure is returned
41 The structure of a long filename depends on the info level.
42 SMB_FIND_FILE_BOTH_DIRECTORY_INFO is used
43 by NT and SMB_FIND_EA_SIZE is used by OS/2
44 ****************************************************************************/
46 static size_t interpret_long_filename(TALLOC_CTX *ctx,
47 struct cli_state *cli,
48 int level,
49 const char *base_ptr,
50 uint16_t recv_flags2,
51 const char *p,
52 const char *pdata_end,
53 struct file_info *finfo,
54 uint32 *p_resume_key,
55 DATA_BLOB *p_last_name_raw)
57 int len;
58 size_t ret;
59 const char *base = p;
61 data_blob_free(p_last_name_raw);
63 if (p_resume_key) {
64 *p_resume_key = 0;
66 ZERO_STRUCTP(finfo);
68 switch (level) {
69 case SMB_FIND_INFO_STANDARD: /* OS/2 understands this */
70 /* these dates are converted to GMT by
71 make_unix_date */
72 if (pdata_end - base < 27) {
73 return pdata_end - base;
75 finfo->ctime_ts = convert_time_t_to_timespec(
76 make_unix_date2(p+4, cli->serverzone));
77 finfo->atime_ts = convert_time_t_to_timespec(
78 make_unix_date2(p+8, cli->serverzone));
79 finfo->mtime_ts = convert_time_t_to_timespec(
80 make_unix_date2(p+12, cli->serverzone));
81 finfo->size = IVAL(p,16);
82 finfo->mode = CVAL(p,24);
83 len = CVAL(p, 26);
84 p += 27;
85 p += align_string(base_ptr, p, 0);
87 /* We can safely use len here (which is required by OS/2)
88 * and the NAS-BASIC server instead of +2 or +1 as the
89 * STR_TERMINATE flag below is
90 * actually used as the length calculation.
91 * The len is merely an upper bound.
92 * Due to the explicit 2 byte null termination
93 * in cli_receive_trans/cli_receive_nt_trans
94 * we know this is safe. JRA + kukks
97 if (p + len > pdata_end) {
98 return pdata_end - base;
101 /* the len+2 below looks strange but it is
102 important to cope with the differences
103 between win2000 and win9x for this call
104 (tridge) */
105 ret = clistr_pull_talloc(ctx,
106 base_ptr,
107 recv_flags2,
108 &finfo->name,
110 len+2,
111 STR_TERMINATE);
112 if (ret == (size_t)-1) {
113 return pdata_end - base;
115 p += ret;
116 return PTR_DIFF(p, base);
118 case SMB_FIND_EA_SIZE: /* this is what OS/2 uses mostly */
119 /* these dates are converted to GMT by
120 make_unix_date */
121 if (pdata_end - base < 31) {
122 return pdata_end - base;
124 finfo->ctime_ts = convert_time_t_to_timespec(
125 make_unix_date2(p+4, cli->serverzone));
126 finfo->atime_ts = convert_time_t_to_timespec(
127 make_unix_date2(p+8, cli->serverzone));
128 finfo->mtime_ts = convert_time_t_to_timespec(
129 make_unix_date2(p+12, cli->serverzone));
130 finfo->size = IVAL(p,16);
131 finfo->mode = CVAL(p,24);
132 len = CVAL(p, 30);
133 p += 31;
134 /* check for unisys! */
135 if (p + len + 1 > pdata_end) {
136 return pdata_end - base;
138 ret = clistr_pull_talloc(ctx,
139 base_ptr,
140 recv_flags2,
141 &finfo->name,
143 len,
144 STR_NOALIGN);
145 if (ret == (size_t)-1) {
146 return pdata_end - base;
148 p += ret;
149 return PTR_DIFF(p, base) + 1;
151 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
153 size_t namelen, slen;
155 if (pdata_end - base < 94) {
156 return pdata_end - base;
159 p += 4; /* next entry offset */
161 if (p_resume_key) {
162 *p_resume_key = IVAL(p,0);
164 p += 4; /* fileindex */
166 /* Offset zero is "create time", not "change time". */
167 p += 8;
168 finfo->atime_ts = interpret_long_date(p);
169 p += 8;
170 finfo->mtime_ts = interpret_long_date(p);
171 p += 8;
172 finfo->ctime_ts = interpret_long_date(p);
173 p += 8;
174 finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
175 p += 8;
176 p += 8; /* alloc size */
177 finfo->mode = CVAL(p,0);
178 p += 4;
179 namelen = IVAL(p,0);
180 p += 4;
181 p += 4; /* EA size */
182 slen = SVAL(p, 0);
183 if (slen > 24) {
184 /* Bad short name length. */
185 return pdata_end - base;
187 p += 2;
189 /* stupid NT bugs. grr */
190 int flags = 0;
191 if (p[1] == 0 && namelen > 1) flags |= STR_UNICODE;
192 clistr_pull(base_ptr, finfo->short_name, p,
193 sizeof(finfo->short_name),
194 slen, flags);
196 p += 24; /* short name? */
197 if (p + namelen < p || p + namelen > pdata_end) {
198 return pdata_end - base;
200 ret = clistr_pull_talloc(ctx,
201 base_ptr,
202 recv_flags2,
203 &finfo->name,
205 namelen,
207 if (ret == (size_t)-1) {
208 return pdata_end - base;
211 /* To be robust in the face of unicode conversion failures
212 we need to copy the raw bytes of the last name seen here.
213 Namelen doesn't include the terminating unicode null, so
214 copy it here. */
216 if (p_last_name_raw) {
217 *p_last_name_raw = data_blob(NULL, namelen+2);
218 memcpy(p_last_name_raw->data, p, namelen);
219 SSVAL(p_last_name_raw->data, namelen, 0);
221 return calc_next_entry_offset(base, pdata_end);
225 DEBUG(1,("Unknown long filename format %d\n",level));
226 return calc_next_entry_offset(base, pdata_end);
229 /****************************************************************************
230 Interpret a short filename structure.
231 The length of the structure is returned.
232 ****************************************************************************/
234 static bool interpret_short_filename(TALLOC_CTX *ctx,
235 struct cli_state *cli,
236 char *p,
237 struct file_info *finfo)
239 size_t ret;
240 ZERO_STRUCTP(finfo);
242 finfo->mode = CVAL(p,21);
244 /* this date is converted to GMT by make_unix_date */
245 finfo->ctime_ts.tv_sec = make_unix_date(p+22, cli->serverzone);
246 finfo->ctime_ts.tv_nsec = 0;
247 finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
248 finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
249 finfo->size = IVAL(p,26);
250 ret = clistr_pull_talloc(ctx,
251 cli->inbuf,
252 SVAL(cli->inbuf, smb_flg2),
253 &finfo->name,
254 p+30,
256 STR_ASCII);
257 if (ret == (size_t)-1) {
258 return false;
261 if (finfo->name) {
262 strlcpy(finfo->short_name,
263 finfo->name,
264 sizeof(finfo->short_name));
266 return true;
269 struct cli_list_old_state {
270 struct tevent_context *ev;
271 struct cli_state *cli;
272 uint16_t vwv[2];
273 char *mask;
274 int num_asked;
275 uint16_t attribute;
276 uint8_t search_status[23];
277 bool first;
278 bool done;
279 uint8_t *dirlist;
282 static void cli_list_old_done(struct tevent_req *subreq);
284 static struct tevent_req *cli_list_old_send(TALLOC_CTX *mem_ctx,
285 struct tevent_context *ev,
286 struct cli_state *cli,
287 const char *mask,
288 uint16_t attribute)
290 struct tevent_req *req, *subreq;
291 struct cli_list_old_state *state;
292 uint8_t *bytes;
293 static const uint16_t zero = 0;
295 req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
296 if (req == NULL) {
297 return NULL;
299 state->ev = ev;
300 state->cli = cli;
301 state->attribute = attribute;
302 state->first = true;
303 state->mask = talloc_strdup(state, mask);
304 if (tevent_req_nomem(state->mask, req)) {
305 return tevent_req_post(req, ev);
307 state->num_asked = (cli->max_xmit - 100) / DIR_STRUCT_SIZE;
309 SSVAL(state->vwv + 0, 0, state->num_asked);
310 SSVAL(state->vwv + 1, 0, state->attribute);
312 bytes = talloc_array(state, uint8_t, 1);
313 if (tevent_req_nomem(bytes, req)) {
314 return tevent_req_post(req, ev);
316 bytes[0] = 4;
317 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), mask,
318 strlen(mask)+1, NULL);
320 bytes = smb_bytes_push_bytes(bytes, 5, (uint8_t *)&zero, 2);
321 if (tevent_req_nomem(bytes, req)) {
322 return tevent_req_post(req, ev);
325 subreq = cli_smb_send(state, state->ev, state->cli, SMBsearch,
326 0, 2, state->vwv, talloc_get_size(bytes), bytes);
327 if (tevent_req_nomem(subreq, req)) {
328 return tevent_req_post(req, ev);
330 tevent_req_set_callback(subreq, cli_list_old_done, req);
331 return req;
334 static void cli_list_old_done(struct tevent_req *subreq)
336 struct tevent_req *req = tevent_req_callback_data(
337 subreq, struct tevent_req);
338 struct cli_list_old_state *state = tevent_req_data(
339 req, struct cli_list_old_state);
340 NTSTATUS status;
341 uint8_t cmd;
342 uint8_t wct;
343 uint16_t *vwv;
344 uint32_t num_bytes;
345 uint8_t *bytes;
346 uint16_t received;
347 size_t dirlist_len;
348 uint8_t *tmp;
350 status = cli_smb_recv(subreq, state, NULL, 0, &wct, &vwv, &num_bytes,
351 &bytes);
352 if (!NT_STATUS_IS_OK(status)
353 && !NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
354 && !NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
355 TALLOC_FREE(subreq);
356 tevent_req_nterror(req, status);
357 return;
359 if (NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS, ERRnofiles))
360 || NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
361 received = 0;
362 } else {
363 if (wct < 1) {
364 TALLOC_FREE(subreq);
365 tevent_req_nterror(
366 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
367 return;
369 received = SVAL(vwv + 0, 0);
372 if (received > 0) {
374 * I don't think this can wrap. received is
375 * initialized from a 16-bit value.
377 if (num_bytes < (received * DIR_STRUCT_SIZE + 3)) {
378 TALLOC_FREE(subreq);
379 tevent_req_nterror(
380 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
381 return;
384 dirlist_len = talloc_get_size(state->dirlist);
386 tmp = TALLOC_REALLOC_ARRAY(
387 state, state->dirlist, uint8_t,
388 dirlist_len + received * DIR_STRUCT_SIZE);
389 if (tevent_req_nomem(tmp, req)) {
390 return;
392 state->dirlist = tmp;
393 memcpy(state->dirlist + dirlist_len, bytes + 3,
394 received * DIR_STRUCT_SIZE);
396 SSVAL(state->search_status, 0, 21);
397 memcpy(state->search_status + 2,
398 bytes + 3 + (received-1)*DIR_STRUCT_SIZE, 21);
399 cmd = SMBsearch;
400 } else {
401 if (state->first || state->done) {
402 tevent_req_done(req);
403 return;
405 state->done = true;
406 state->num_asked = 0;
407 cmd = SMBfclose;
409 TALLOC_FREE(subreq);
411 state->first = false;
413 SSVAL(state->vwv + 0, 0, state->num_asked);
414 SSVAL(state->vwv + 1, 0, state->attribute);
416 bytes = talloc_array(state, uint8_t, 1);
417 if (tevent_req_nomem(bytes, req)) {
418 return;
420 bytes[0] = 4;
421 bytes = smb_bytes_push_str(bytes, cli_ucs2(state->cli), "",
422 1, NULL);
423 bytes = smb_bytes_push_bytes(bytes, 5, state->search_status,
424 sizeof(state->search_status));
425 if (tevent_req_nomem(bytes, req)) {
426 return;
428 subreq = cli_smb_send(state, state->ev, state->cli, cmd, 0,
429 2, state->vwv, talloc_get_size(bytes), bytes);
430 if (tevent_req_nomem(subreq, req)) {
431 return;
433 tevent_req_set_callback(subreq, cli_list_old_done, req);
436 static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
437 struct file_info **pfinfo)
439 struct cli_list_old_state *state = tevent_req_data(
440 req, struct cli_list_old_state);
441 NTSTATUS status;
442 size_t i, num_received;
443 struct file_info *finfo;
445 if (tevent_req_is_nterror(req, &status)) {
446 return status;
449 num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
451 finfo = TALLOC_ARRAY(mem_ctx, struct file_info, num_received);
452 if (finfo == NULL) {
453 return NT_STATUS_NO_MEMORY;
456 for (i=0; i<num_received; i++) {
457 if (!interpret_short_filename(
458 finfo, state->cli,
459 (char *)state->dirlist + i * DIR_STRUCT_SIZE,
460 &finfo[i])) {
461 TALLOC_FREE(finfo);
462 return NT_STATUS_NO_MEMORY;
465 *pfinfo = finfo;
466 return NT_STATUS_OK;
469 NTSTATUS cli_list_old(struct cli_state *cli, const char *mask,
470 uint16 attribute,
471 void (*fn)(const char *, struct file_info *,
472 const char *, void *), void *state)
474 TALLOC_CTX *frame = talloc_stackframe();
475 struct event_context *ev;
476 struct tevent_req *req;
477 NTSTATUS status = NT_STATUS_NO_MEMORY;
478 struct file_info *finfo;
479 size_t i, num_finfo;
481 if (cli_has_async_calls(cli)) {
483 * Can't use sync call while an async call is in flight
485 status = NT_STATUS_INVALID_PARAMETER;
486 goto fail;
488 ev = event_context_init(frame);
489 if (ev == NULL) {
490 goto fail;
492 req = cli_list_old_send(frame, ev, cli, mask, attribute);
493 if (req == NULL) {
494 goto fail;
496 if (!tevent_req_poll(req, ev)) {
497 status = map_nt_error_from_unix(errno);
498 goto fail;
500 status = cli_list_old_recv(req, frame, &finfo);
501 if (!NT_STATUS_IS_OK(status)) {
502 goto fail;
504 num_finfo = talloc_array_length(finfo);
505 for (i=0; i<num_finfo; i++) {
506 fn(cli->dfs_mountpoint, &finfo[i], mask, state);
508 fail:
509 TALLOC_FREE(frame);
510 if (!NT_STATUS_IS_OK(status)) {
511 cli_set_error(cli, status);
513 return status;
516 struct cli_list_trans_state {
517 struct tevent_context *ev;
518 struct cli_state *cli;
519 char *mask;
520 uint16_t attribute;
521 uint16_t info_level;
523 int loop_count;
524 int total_received;
525 uint16_t max_matches;
526 bool first;
528 int ff_eos;
529 int ff_dir_handle;
531 uint16_t setup[1];
532 uint8_t *param;
534 struct file_info *finfo;
537 static void cli_list_trans_done(struct tevent_req *subreq);
539 static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
540 struct tevent_context *ev,
541 struct cli_state *cli,
542 const char *mask,
543 uint16_t attribute,
544 uint16_t info_level)
546 struct tevent_req *req, *subreq;
547 struct cli_list_trans_state *state;
548 size_t nlen, param_len;
549 char *p;
551 req = tevent_req_create(mem_ctx, &state,
552 struct cli_list_trans_state);
553 if (req == NULL) {
554 return NULL;
556 state->ev = ev;
557 state->cli = cli;
558 state->mask = talloc_strdup(state, mask);
559 if (tevent_req_nomem(state->mask, req)) {
560 return tevent_req_post(req, ev);
562 state->attribute = attribute;
563 state->info_level = info_level;
564 state->loop_count = 0;
565 state->first = true;
567 state->max_matches = 1366; /* Match W2k */
569 state->setup[0] = TRANSACT2_FINDFIRST;
571 nlen = 2*(strlen(mask)+1);
572 state->param = TALLOC_ARRAY(state, uint8_t, 12+nlen+2);
573 if (tevent_req_nomem(state->param, req)) {
574 return tevent_req_post(req, ev);
577 SSVAL(state->param, 0, state->attribute);
578 SSVAL(state->param, 2, state->max_matches);
579 SSVAL(state->param, 4,
580 FLAG_TRANS2_FIND_REQUIRE_RESUME
581 |FLAG_TRANS2_FIND_CLOSE_IF_END);
582 SSVAL(state->param, 6, state->info_level);
583 SIVAL(state->param, 8, 0);
585 p = ((char *)state->param)+12;
586 p += clistr_push(state->cli, p, state->mask, nlen,
587 STR_TERMINATE);
588 param_len = PTR_DIFF(p, state->param);
590 subreq = cli_trans_send(state, state->ev, state->cli,
591 SMBtrans2, NULL, -1, 0, 0,
592 state->setup, 1, 0,
593 state->param, param_len, 10,
594 NULL, 0, cli->max_xmit);
595 if (tevent_req_nomem(subreq, req)) {
596 return tevent_req_post(req, ev);
598 tevent_req_set_callback(subreq, cli_list_trans_done, req);
599 return req;
602 static void cli_list_trans_done(struct tevent_req *subreq)
604 struct tevent_req *req = tevent_req_callback_data(
605 subreq, struct tevent_req);
606 struct cli_list_trans_state *state = tevent_req_data(
607 req, struct cli_list_trans_state);
608 NTSTATUS status;
609 uint8_t *param;
610 uint32_t num_param;
611 uint8_t *data;
612 char *data_end;
613 uint32_t num_data;
614 uint32_t min_param;
615 struct file_info *tmp;
616 size_t old_num_finfo;
617 uint16_t recv_flags2;
618 int ff_searchcount;
619 bool ff_eos;
620 char *p, *p2;
621 uint32_t resume_key = 0;
622 int i;
623 DATA_BLOB last_name_raw;
624 struct file_info *finfo = NULL;
625 size_t nlen, param_len;
627 min_param = (state->first ? 6 : 4);
629 status = cli_trans_recv(subreq, talloc_tos(), &recv_flags2,
630 NULL, 0, NULL,
631 &param, min_param, &num_param,
632 &data, 0, &num_data);
633 TALLOC_FREE(subreq);
634 if (!NT_STATUS_IS_OK(status)) {
636 * TODO: retry, OS/2 nofiles
638 tevent_req_nterror(req, status);
639 return;
642 if (state->first) {
643 state->ff_dir_handle = SVAL(param, 0);
644 ff_searchcount = SVAL(param, 2);
645 ff_eos = SVAL(param, 4) != 0;
646 } else {
647 ff_searchcount = SVAL(param, 0);
648 ff_eos = SVAL(param, 2) != 0;
651 old_num_finfo = talloc_array_length(state->finfo);
653 tmp = TALLOC_REALLOC_ARRAY(state, state->finfo, struct file_info,
654 old_num_finfo + ff_searchcount);
655 if (tevent_req_nomem(tmp, req)) {
656 return;
658 state->finfo = tmp;
660 p2 = p = (char *)data;
661 data_end = (char *)data + num_data;
662 last_name_raw = data_blob_null;
664 for (i=0; i<ff_searchcount; i++) {
665 if (p2 >= data_end) {
666 ff_eos = true;
667 break;
669 if ((state->info_level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
670 && (i == ff_searchcount-1)) {
671 /* Last entry - fixup the last offset length. */
672 SIVAL(p2, 0, PTR_DIFF((data + num_data), p2));
675 data_blob_free(&last_name_raw);
677 finfo = &state->finfo[old_num_finfo + i];
679 p2 += interpret_long_filename(
680 state->finfo, /* Stick fname to the array as such */
681 state->cli, state->info_level,
682 (char *)data, recv_flags2, p2,
683 data_end, finfo, &resume_key, &last_name_raw);
685 if (finfo->name == NULL) {
686 DEBUG(1, ("cli_list: Error: unable to parse name from "
687 "info level %d\n", state->info_level));
688 ff_eos = true;
689 break;
691 if (!state->first && (state->mask[0] != '\0') &&
692 strcsequal(finfo->name, state->mask)) {
693 DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
694 "already been seen?\n", finfo->name));
695 ff_eos = true;
696 break;
700 if (ff_searchcount == 0) {
701 ff_eos = true;
704 TALLOC_FREE(param);
705 TALLOC_FREE(data);
708 * Shrink state->finfo to the real length we received
710 tmp = TALLOC_REALLOC_ARRAY(state, state->finfo, struct file_info,
711 old_num_finfo + i);
712 if (tevent_req_nomem(tmp, req)) {
713 return;
715 state->finfo = tmp;
717 state->first = false;
719 if (ff_eos) {
720 data_blob_free(&last_name_raw);
721 tevent_req_done(req);
722 return;
725 TALLOC_FREE(state->mask);
726 state->mask = talloc_strdup(state, finfo->name);
727 if (tevent_req_nomem(state->mask, req)) {
728 return;
731 state->setup[0] = TRANSACT2_FINDNEXT;
733 nlen = 2*(strlen(state->mask) + 1);
735 param = TALLOC_REALLOC_ARRAY(state, state->param, uint8_t,
736 12 + nlen + last_name_raw.length + 2);
737 if (tevent_req_nomem(param, req)) {
738 return;
740 state->param = param;
742 SSVAL(param, 0, state->ff_dir_handle);
743 SSVAL(param, 2, state->max_matches); /* max count */
744 SSVAL(param, 4, state->info_level);
746 * For W2K servers serving out FAT filesystems we *must* set
747 * the resume key. If it's not FAT then it's returned as zero.
749 SIVAL(param, 6, resume_key); /* ff_resume_key */
751 * NB. *DON'T* use continue here. If you do it seems that W2K
752 * and bretheren can miss filenames. Use last filename
753 * continue instead. JRA
755 SSVAL(param, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
756 |FLAG_TRANS2_FIND_CLOSE_IF_END));
757 p = ((char *)param)+12;
758 if (last_name_raw.length) {
759 memcpy(p, last_name_raw.data, last_name_raw.length);
760 p += last_name_raw.length;
761 data_blob_free(&last_name_raw);
762 } else {
763 p += clistr_push(state->cli, p, state->mask, nlen,
764 STR_TERMINATE);
767 param_len = PTR_DIFF(p, param);
769 subreq = cli_trans_send(state, state->ev, state->cli,
770 SMBtrans2, NULL, -1, 0, 0,
771 state->setup, 1, 0,
772 state->param, param_len, 10,
773 NULL, 0, state->cli->max_xmit);
774 if (tevent_req_nomem(subreq, req)) {
775 return;
777 tevent_req_set_callback(subreq, cli_list_trans_done, req);
780 static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
781 TALLOC_CTX *mem_ctx,
782 struct file_info **finfo)
784 struct cli_list_trans_state *state = tevent_req_data(
785 req, struct cli_list_trans_state);
786 NTSTATUS status;
788 if (tevent_req_is_nterror(req, &status)) {
789 return status;
791 *finfo = talloc_move(mem_ctx, &state->finfo);
792 return NT_STATUS_OK;
795 NTSTATUS cli_list_trans(struct cli_state *cli, const char *mask,
796 uint16_t attribute, int info_level,
797 void (*fn)(const char *mnt, struct file_info *finfo,
798 const char *mask, void *private_data),
799 void *private_data)
801 TALLOC_CTX *frame = talloc_stackframe();
802 struct event_context *ev;
803 struct tevent_req *req;
804 int i, num_finfo;
805 struct file_info *finfo = NULL;
806 NTSTATUS status = NT_STATUS_NO_MEMORY;
808 if (cli_has_async_calls(cli)) {
810 * Can't use sync call while an async call is in flight
812 status = NT_STATUS_INVALID_PARAMETER;
813 goto fail;
815 ev = event_context_init(frame);
816 if (ev == NULL) {
817 goto fail;
819 req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
820 if (req == NULL) {
821 goto fail;
823 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
824 goto fail;
826 status = cli_list_trans_recv(req, frame, &finfo);
827 if (!NT_STATUS_IS_OK(status)) {
828 goto fail;
830 num_finfo = talloc_array_length(finfo);
831 for (i=0; i<num_finfo; i++) {
832 fn(cli->dfs_mountpoint, &finfo[i], mask, private_data);
834 fail:
835 TALLOC_FREE(frame);
836 if (!NT_STATUS_IS_OK(status)) {
837 cli_set_error(cli, status);
839 return status;
842 struct cli_list_state {
843 NTSTATUS (*recv_fn)(struct tevent_req *req, TALLOC_CTX *mem_ctx,
844 struct file_info **finfo);
845 struct file_info *finfo;
848 static void cli_list_done(struct tevent_req *subreq);
850 struct tevent_req *cli_list_send(TALLOC_CTX *mem_ctx,
851 struct tevent_context *ev,
852 struct cli_state *cli,
853 const char *mask,
854 uint16_t attribute,
855 uint16_t info_level)
857 struct tevent_req *req, *subreq;
858 struct cli_list_state *state;
860 req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
861 if (req == NULL) {
862 return NULL;
865 if (cli->protocol <= PROTOCOL_LANMAN1) {
866 subreq = cli_list_old_send(state, ev, cli, mask, attribute);
867 state->recv_fn = cli_list_old_recv;
868 } else {
869 subreq = cli_list_trans_send(state, ev, cli, mask, attribute,
870 info_level);
871 state->recv_fn = cli_list_trans_recv;
873 if (tevent_req_nomem(subreq, req)) {
874 return tevent_req_post(req, ev);
876 tevent_req_set_callback(subreq, cli_list_done, req);
877 return req;
880 static void cli_list_done(struct tevent_req *subreq)
882 struct tevent_req *req = tevent_req_callback_data(
883 subreq, struct tevent_req);
884 struct cli_list_state *state = tevent_req_data(
885 req, struct cli_list_state);
886 NTSTATUS status;
888 status = state->recv_fn(subreq, state, &state->finfo);
889 TALLOC_FREE(subreq);
890 if (!NT_STATUS_IS_OK(status)) {
891 tevent_req_nterror(req, status);
892 return;
894 tevent_req_done(req);
897 NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
898 struct file_info **finfo, size_t *num_finfo)
900 struct cli_list_state *state = tevent_req_data(
901 req, struct cli_list_state);
902 NTSTATUS status;
904 if (tevent_req_is_nterror(req, &status)) {
905 return status;
907 *num_finfo = talloc_array_length(state->finfo);
908 *finfo = talloc_move(mem_ctx, &state->finfo);
909 return NT_STATUS_OK;
912 NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute,
913 void (*fn)(const char *, struct file_info *, const char *,
914 void *), void *state)
916 TALLOC_CTX *frame = talloc_stackframe();
917 struct event_context *ev;
918 struct tevent_req *req;
919 NTSTATUS status = NT_STATUS_NO_MEMORY;
920 struct file_info *finfo;
921 size_t i, num_finfo;
922 uint16_t info_level;
924 if (cli_has_async_calls(cli)) {
926 * Can't use sync call while an async call is in flight
928 status = NT_STATUS_INVALID_PARAMETER;
929 goto fail;
931 ev = event_context_init(frame);
932 if (ev == NULL) {
933 goto fail;
936 info_level = (cli->capabilities & CAP_NT_SMBS)
937 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
939 req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
940 if (req == NULL) {
941 goto fail;
943 if (!tevent_req_poll(req, ev)) {
944 status = map_nt_error_from_unix(errno);
945 goto fail;
948 status = cli_list_recv(req, frame, &finfo, &num_finfo);
949 if (!NT_STATUS_IS_OK(status)) {
950 goto fail;
953 for (i=0; i<num_finfo; i++) {
954 fn(cli->dfs_mountpoint, &finfo[i], mask, state);
956 fail:
957 TALLOC_FREE(frame);
958 if (!NT_STATUS_IS_OK(status)) {
959 cli_set_error(cli, status);
961 return status;