lib/param: Add .flags to max/min protocol to match s3
[Samba/gebeck_regimport.git] / source3 / libsmb / clilist.c
blob6185c5a99739c842ff4174f0118db0bc42bcd8f7
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 *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 p += align_string(base_ptr, p, 0);
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
102 if (p + len > pdata_end) {
103 return pdata_end - base;
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,
115 len+2,
116 STR_TERMINATE);
117 if (ret == (size_t)-1) {
118 return pdata_end - base;
120 p += ret;
121 return PTR_DIFF(p, base);
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;
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;
143 ret = clistr_pull_talloc(ctx,
144 base_ptr,
145 recv_flags2,
146 &finfo->name,
148 len,
149 STR_NOALIGN);
150 if (ret == (size_t)-1) {
151 return pdata_end - base;
153 p += ret;
154 return PTR_DIFF(p, base) + 1;
156 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: /* NT uses this, but also accepts 2 */
158 size_t namelen, slen;
160 if (pdata_end - base < 94) {
161 return pdata_end - base;
164 p += 4; /* next entry offset */
166 if (p_resume_key) {
167 *p_resume_key = IVAL(p,0);
169 p += 4; /* fileindex */
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;
192 p += 2;
193 ret = clistr_pull_talloc(ctx,
194 base_ptr,
195 recv_flags2,
196 &finfo->short_name,
198 slen,
199 STR_UNICODE);
200 if (ret == (size_t)-1) {
201 return pdata_end - base;
203 p += 24; /* short name? */
204 if (p + namelen < p || p + namelen > pdata_end) {
205 return pdata_end - base;
207 ret = clistr_pull_talloc(ctx,
208 base_ptr,
209 recv_flags2,
210 &finfo->name,
212 namelen,
214 if (ret == (size_t)-1) {
215 return pdata_end - base;
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. */
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);
228 return calc_next_entry_offset(base, pdata_end);
232 DEBUG(1,("Unknown long filename format %d\n",level));
233 return calc_next_entry_offset(base, pdata_end);
236 /****************************************************************************
237 Interpret a short filename structure.
238 The length of the structure is returned.
239 ****************************************************************************/
241 static bool interpret_short_filename(TALLOC_CTX *ctx,
242 struct cli_state *cli,
243 char *p,
244 struct file_info *finfo)
246 size_t ret;
247 ZERO_STRUCTP(finfo);
249 finfo->mode = CVAL(p,21);
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,
260 &finfo->name,
261 p+30,
263 STR_ASCII);
264 if (ret == (size_t)-1) {
265 return false;
268 if (finfo->name) {
269 finfo->short_name = talloc_strdup(ctx, finfo->name);
270 if (finfo->short_name == NULL) {
271 return false;
274 return true;
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;
290 static void cli_list_old_done(struct tevent_req *subreq);
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)
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;
304 req = tevent_req_create(mem_ctx, &state, struct cli_list_old_state);
305 if (req == NULL) {
306 return NULL;
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);
316 usable_space = cli_state_available_size(cli, 100);
317 state->num_asked = usable_space / DIR_STRUCT_SIZE;
319 SSVAL(state->vwv + 0, 0, state->num_asked);
320 SSVAL(state->vwv + 1, 0, state->attribute);
322 bytes = talloc_array(state, uint8_t, 1);
323 if (tevent_req_nomem(bytes, req)) {
324 return tevent_req_post(req, ev);
326 bytes[0] = 4;
327 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), mask,
328 strlen(mask)+1, NULL);
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);
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);
340 tevent_req_set_callback(subreq, cli_list_old_done, req);
341 return req;
344 static void cli_list_old_done(struct tevent_req *subreq)
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;
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;
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;
379 received = SVAL(vwv + 0, 0);
382 if (received > 0) {
384 * I don't think this can wrap. received is
385 * initialized from a 16-bit value.
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;
394 dirlist_len = talloc_get_size(state->dirlist);
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;
402 state->dirlist = tmp;
403 memcpy(state->dirlist + dirlist_len, bytes + 3,
404 received * DIR_STRUCT_SIZE);
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;
415 state->done = true;
416 state->num_asked = 0;
417 cmd = SMBfclose;
419 TALLOC_FREE(subreq);
421 state->first = false;
423 SSVAL(state->vwv + 0, 0, state->num_asked);
424 SSVAL(state->vwv + 1, 0, state->attribute);
426 bytes = talloc_array(state, uint8_t, 1);
427 if (tevent_req_nomem(bytes, req)) {
428 return;
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;
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;
443 tevent_req_set_callback(subreq, cli_list_old_done, req);
446 static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
447 struct file_info **pfinfo)
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;
455 if (tevent_req_is_nterror(req, &status)) {
456 return status;
459 num_received = talloc_array_length(state->dirlist) / DIR_STRUCT_SIZE;
461 finfo = talloc_array(mem_ctx, struct file_info, num_received);
462 if (finfo == NULL) {
463 return NT_STATUS_NO_MEMORY;
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;
475 *pfinfo = finfo;
476 return NT_STATUS_OK;
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)
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;
491 if (smbXcli_conn_has_async_calls(cli->conn)) {
493 * Can't use sync call while an async call is in flight
495 status = NT_STATUS_INVALID_PARAMETER;
496 goto fail;
498 ev = event_context_init(frame);
499 if (ev == NULL) {
500 goto fail;
502 req = cli_list_old_send(frame, ev, cli, mask, attribute);
503 if (req == NULL) {
504 goto fail;
506 if (!tevent_req_poll(req, ev)) {
507 status = map_nt_error_from_unix(errno);
508 goto fail;
510 status = cli_list_old_recv(req, frame, &finfo);
511 if (!NT_STATUS_IS_OK(status)) {
512 goto fail;
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;
521 fail:
522 TALLOC_FREE(frame);
523 return status;
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;
533 int loop_count;
534 int total_received;
535 uint16_t max_matches;
536 bool first;
538 int ff_eos;
539 int ff_dir_handle;
541 uint16_t setup[1];
542 uint8_t *param;
544 struct file_info *finfo;
547 static void cli_list_trans_done(struct tevent_req *subreq);
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)
556 struct tevent_req *req, *subreq;
557 struct cli_list_trans_state *state;
558 size_t param_len;
560 req = tevent_req_create(mem_ctx, &state,
561 struct cli_list_trans_state);
562 if (req == NULL) {
563 return NULL;
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);
571 state->attribute = attribute;
572 state->info_level = info_level;
573 state->loop_count = 0;
574 state->first = true;
576 state->max_matches = 1366; /* Match W2k */
578 SSVAL(&state->setup[0], 0, TRANSACT2_FINDFIRST);
580 state->param = talloc_array(state, uint8_t, 12);
581 if (tevent_req_nomem(state->param, req)) {
582 return tevent_req_post(req, ev);
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);
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);
600 param_len = talloc_get_size(state->param);
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);
610 tevent_req_set_callback(subreq, cli_list_trans_done, req);
611 return req;
614 static void cli_list_trans_done(struct tevent_req *subreq)
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;
639 min_param = (state->first ? 6 : 4);
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)) {
648 * TODO: retry, OS/2 nofiles
650 tevent_req_nterror(req, status);
651 return;
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;
663 old_num_finfo = talloc_array_length(state->finfo);
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;
670 state->finfo = tmp;
672 p2 = p = (char *)data;
673 data_end = (char *)data + num_data;
674 last_name_raw = data_blob_null;
676 for (i=0; i<ff_searchcount; i++) {
677 if (p2 >= data_end) {
678 ff_eos = true;
679 break;
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));
687 data_blob_free(&last_name_raw);
689 finfo = &state->finfo[old_num_finfo + i];
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);
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;
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;
712 if (ff_searchcount == 0) {
713 ff_eos = true;
716 TALLOC_FREE(param);
717 TALLOC_FREE(data);
720 * Shrink state->finfo to the real length we received
722 tmp = talloc_realloc(state, state->finfo, struct file_info,
723 old_num_finfo + i);
724 if (tevent_req_nomem(tmp, req)) {
725 return;
727 state->finfo = tmp;
729 state->first = false;
731 if (ff_eos) {
732 data_blob_free(&last_name_raw);
733 tevent_req_done(req);
734 return;
737 TALLOC_FREE(state->mask);
738 state->mask = talloc_strdup(state, finfo->name);
739 if (tevent_req_nomem(state->mask, req)) {
740 return;
743 SSVAL(&state->setup[0], 0, TRANSACT2_FINDNEXT);
745 param = talloc_realloc(state, state->param, uint8_t, 12);
746 if (tevent_req_nomem(param, req)) {
747 return;
749 state->param = param;
751 SSVAL(param, 0, state->ff_dir_handle);
752 SSVAL(param, 2, state->max_matches); /* max count */
753 SSVAL(param, 4, state->info_level);
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.
758 SIVAL(param, 6, resume_key); /* ff_resume_key */
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
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;
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;
785 param_len = talloc_get_size(state->param);
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;
795 tevent_req_set_callback(subreq, cli_list_trans_done, req);
798 static NTSTATUS cli_list_trans_recv(struct tevent_req *req,
799 TALLOC_CTX *mem_ctx,
800 struct file_info **finfo)
802 struct cli_list_trans_state *state = tevent_req_data(
803 req, struct cli_list_trans_state);
804 NTSTATUS status;
806 if (tevent_req_is_nterror(req, &status)) {
807 return status;
809 *finfo = talloc_move(mem_ctx, &state->finfo);
810 return NT_STATUS_OK;
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)
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;
826 if (smbXcli_conn_has_async_calls(cli->conn)) {
828 * Can't use sync call while an async call is in flight
830 status = NT_STATUS_INVALID_PARAMETER;
831 goto fail;
833 ev = event_context_init(frame);
834 if (ev == NULL) {
835 goto fail;
837 req = cli_list_trans_send(frame, ev, cli, mask, attribute, info_level);
838 if (req == NULL) {
839 goto fail;
841 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
842 goto fail;
844 status = cli_list_trans_recv(req, frame, &finfo);
845 if (!NT_STATUS_IS_OK(status)) {
846 goto fail;
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;
855 fail:
856 TALLOC_FREE(frame);
857 return status;
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;
866 static void cli_list_done(struct tevent_req *subreq);
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)
875 struct tevent_req *req, *subreq;
876 struct cli_list_state *state;
878 req = tevent_req_create(mem_ctx, &state, struct cli_list_state);
879 if (req == NULL) {
880 return NULL;
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;
891 if (tevent_req_nomem(subreq, req)) {
892 return tevent_req_post(req, ev);
894 tevent_req_set_callback(subreq, cli_list_done, req);
895 return req;
898 static void cli_list_done(struct tevent_req *subreq)
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;
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;
912 tevent_req_done(req);
915 NTSTATUS cli_list_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
916 struct file_info **finfo, size_t *num_finfo)
918 struct cli_list_state *state = tevent_req_data(
919 req, struct cli_list_state);
920 NTSTATUS status;
922 if (tevent_req_is_nterror(req, &status)) {
923 return status;
925 *num_finfo = talloc_array_length(state->finfo);
926 *finfo = talloc_move(mem_ctx, &state->finfo);
927 return NT_STATUS_OK;
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)
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;
942 if (smbXcli_conn_has_async_calls(cli->conn)) {
944 * Can't use sync call while an async call is in flight
946 status = NT_STATUS_INVALID_PARAMETER;
947 goto fail;
949 ev = event_context_init(frame);
950 if (ev == NULL) {
951 goto fail;
954 info_level = (smb1cli_conn_capabilities(cli->conn) & CAP_NT_SMBS)
955 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD;
957 req = cli_list_send(frame, ev, cli, mask, attribute, info_level);
958 if (req == NULL) {
959 goto fail;
961 if (!tevent_req_poll(req, ev)) {
962 status = map_nt_error_from_unix(errno);
963 goto fail;
966 status = cli_list_recv(req, frame, &finfo, &num_finfo);
967 if (!NT_STATUS_IS_OK(status)) {
968 goto fail;
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;
977 fail:
978 TALLOC_FREE(frame);
979 return status;