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/>.
21 #include "libsmb/libsmb.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.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
,
56 const char *pdata_end
,
57 struct file_info
*finfo
,
59 DATA_BLOB
*p_last_name_raw
)
65 data_blob_free(p_last_name_raw
);
73 case SMB_FIND_INFO_STANDARD
: /* OS/2 understands this */
74 /* these dates are converted to GMT by
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
->serverzone
));
81 finfo
->atime_ts
= convert_time_t_to_timespec(
82 make_unix_date2(p
+8, cli
->serverzone
));
83 finfo
->mtime_ts
= convert_time_t_to_timespec(
84 make_unix_date2(p
+12, cli
->serverzone
));
85 finfo
->size
= IVAL(p
,16);
86 finfo
->mode
= CVAL(p
,24);
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
109 ret
= clistr_pull_talloc(ctx
,
116 if (ret
== (size_t)-1) {
117 return pdata_end
- base
;
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
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
->serverzone
));
130 finfo
->atime_ts
= convert_time_t_to_timespec(
131 make_unix_date2(p
+8, cli
->serverzone
));
132 finfo
->mtime_ts
= convert_time_t_to_timespec(
133 make_unix_date2(p
+12, cli
->serverzone
));
134 finfo
->size
= IVAL(p
,16);
135 finfo
->mode
= CVAL(p
,24);
138 /* check for unisys! */
139 if (p
+ len
+ 1 > pdata_end
) {
140 return pdata_end
- base
;
142 ret
= clistr_pull_talloc(ctx
,
149 if (ret
== (size_t)-1) {
150 return pdata_end
- base
;
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 */
166 *p_resume_key
= IVAL(p
,0);
168 p
+= 4; /* fileindex */
170 /* Offset zero is "create time", not "change time". */
172 finfo
->atime_ts
= interpret_long_date(p
);
174 finfo
->mtime_ts
= interpret_long_date(p
);
176 finfo
->ctime_ts
= interpret_long_date(p
);
178 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(p
,0);
180 p
+= 8; /* alloc size */
181 finfo
->mode
= CVAL(p
,0);
185 p
+= 4; /* EA size */
188 /* Bad short name length. */
189 return pdata_end
- base
;
192 ret
= clistr_pull_talloc(ctx
,
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
,
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
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
,
243 struct file_info
*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
->serverzone
);
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
,
263 if (ret
== (size_t)-1) {
268 finfo
->short_name
= talloc_strdup(ctx
, finfo
->name
);
269 if (finfo
->short_name
== NULL
) {
276 struct cli_list_old_state
{
277 struct tevent_context
*ev
;
278 struct cli_state
*cli
;
283 uint8_t search_status
[23];
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
,
297 struct tevent_req
*req
, *subreq
;
298 struct cli_list_old_state
*state
;
300 static const uint16_t zero
= 0;
302 req
= tevent_req_create(mem_ctx
, &state
, struct cli_list_old_state
);
308 state
->attribute
= attribute
;
310 state
->mask
= talloc_strdup(state
, mask
);
311 if (tevent_req_nomem(state
->mask
, req
)) {
312 return tevent_req_post(req
, ev
);
314 state
->num_asked
= (cli
->max_xmit
- 100) / DIR_STRUCT_SIZE
;
316 SSVAL(state
->vwv
+ 0, 0, state
->num_asked
);
317 SSVAL(state
->vwv
+ 1, 0, state
->attribute
);
319 bytes
= talloc_array(state
, uint8_t, 1);
320 if (tevent_req_nomem(bytes
, req
)) {
321 return tevent_req_post(req
, ev
);
324 bytes
= smb_bytes_push_str(bytes
, cli_ucs2(cli
), mask
,
325 strlen(mask
)+1, NULL
);
327 bytes
= smb_bytes_push_bytes(bytes
, 5, (const uint8_t *)&zero
, 2);
328 if (tevent_req_nomem(bytes
, req
)) {
329 return tevent_req_post(req
, ev
);
332 subreq
= cli_smb_send(state
, state
->ev
, state
->cli
, SMBsearch
,
333 0, 2, state
->vwv
, talloc_get_size(bytes
), bytes
);
334 if (tevent_req_nomem(subreq
, req
)) {
335 return tevent_req_post(req
, ev
);
337 tevent_req_set_callback(subreq
, cli_list_old_done
, req
);
341 static void cli_list_old_done(struct tevent_req
*subreq
)
343 struct tevent_req
*req
= tevent_req_callback_data(
344 subreq
, struct tevent_req
);
345 struct cli_list_old_state
*state
= tevent_req_data(
346 req
, struct cli_list_old_state
);
357 status
= cli_smb_recv(subreq
, state
, NULL
, 0, &wct
, &vwv
, &num_bytes
,
359 if (!NT_STATUS_IS_OK(status
)
360 && !NT_STATUS_EQUAL(status
, NT_STATUS_DOS(ERRDOS
, ERRnofiles
))
361 && !NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
363 tevent_req_nterror(req
, status
);
366 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOS(ERRDOS
, ERRnofiles
))
367 || NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
373 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
376 received
= SVAL(vwv
+ 0, 0);
381 * I don't think this can wrap. received is
382 * initialized from a 16-bit value.
384 if (num_bytes
< (received
* DIR_STRUCT_SIZE
+ 3)) {
387 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
391 dirlist_len
= talloc_get_size(state
->dirlist
);
393 tmp
= talloc_realloc(
394 state
, state
->dirlist
, uint8_t,
395 dirlist_len
+ received
* DIR_STRUCT_SIZE
);
396 if (tevent_req_nomem(tmp
, req
)) {
399 state
->dirlist
= tmp
;
400 memcpy(state
->dirlist
+ dirlist_len
, bytes
+ 3,
401 received
* DIR_STRUCT_SIZE
);
403 SSVAL(state
->search_status
, 0, 21);
404 memcpy(state
->search_status
+ 2,
405 bytes
+ 3 + (received
-1)*DIR_STRUCT_SIZE
, 21);
408 if (state
->first
|| state
->done
) {
409 tevent_req_done(req
);
413 state
->num_asked
= 0;
418 state
->first
= false;
420 SSVAL(state
->vwv
+ 0, 0, state
->num_asked
);
421 SSVAL(state
->vwv
+ 1, 0, state
->attribute
);
423 bytes
= talloc_array(state
, uint8_t, 1);
424 if (tevent_req_nomem(bytes
, req
)) {
428 bytes
= smb_bytes_push_str(bytes
, cli_ucs2(state
->cli
), "",
430 bytes
= smb_bytes_push_bytes(bytes
, 5, state
->search_status
,
431 sizeof(state
->search_status
));
432 if (tevent_req_nomem(bytes
, req
)) {
435 subreq
= cli_smb_send(state
, state
->ev
, state
->cli
, cmd
, 0,
436 2, state
->vwv
, talloc_get_size(bytes
), bytes
);
437 if (tevent_req_nomem(subreq
, req
)) {
440 tevent_req_set_callback(subreq
, cli_list_old_done
, req
);
443 static NTSTATUS
cli_list_old_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
444 struct file_info
**pfinfo
)
446 struct cli_list_old_state
*state
= tevent_req_data(
447 req
, struct cli_list_old_state
);
449 size_t i
, num_received
;
450 struct file_info
*finfo
;
452 if (tevent_req_is_nterror(req
, &status
)) {
456 num_received
= talloc_array_length(state
->dirlist
) / DIR_STRUCT_SIZE
;
458 finfo
= talloc_array(mem_ctx
, struct file_info
, num_received
);
460 return NT_STATUS_NO_MEMORY
;
463 for (i
=0; i
<num_received
; i
++) {
464 if (!interpret_short_filename(
466 (char *)state
->dirlist
+ i
* DIR_STRUCT_SIZE
,
469 return NT_STATUS_NO_MEMORY
;
476 NTSTATUS
cli_list_old(struct cli_state
*cli
, const char *mask
,
478 NTSTATUS (*fn
)(const char *, struct file_info
*,
479 const char *, void *), void *state
)
481 TALLOC_CTX
*frame
= talloc_stackframe();
482 struct event_context
*ev
;
483 struct tevent_req
*req
;
484 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
485 struct file_info
*finfo
;
488 if (cli_has_async_calls(cli
)) {
490 * Can't use sync call while an async call is in flight
492 status
= NT_STATUS_INVALID_PARAMETER
;
495 ev
= event_context_init(frame
);
499 req
= cli_list_old_send(frame
, ev
, cli
, mask
, attribute
);
503 if (!tevent_req_poll(req
, ev
)) {
504 status
= map_nt_error_from_unix(errno
);
507 status
= cli_list_old_recv(req
, frame
, &finfo
);
508 if (!NT_STATUS_IS_OK(status
)) {
511 num_finfo
= talloc_array_length(finfo
);
512 for (i
=0; i
<num_finfo
; i
++) {
513 status
= fn(cli
->dfs_mountpoint
, &finfo
[i
], mask
, state
);
514 if (!NT_STATUS_IS_OK(status
)) {
523 struct cli_list_trans_state
{
524 struct tevent_context
*ev
;
525 struct cli_state
*cli
;
532 uint16_t max_matches
;
541 struct file_info
*finfo
;
544 static void cli_list_trans_done(struct tevent_req
*subreq
);
546 static struct tevent_req
*cli_list_trans_send(TALLOC_CTX
*mem_ctx
,
547 struct tevent_context
*ev
,
548 struct cli_state
*cli
,
553 struct tevent_req
*req
, *subreq
;
554 struct cli_list_trans_state
*state
;
557 req
= tevent_req_create(mem_ctx
, &state
,
558 struct cli_list_trans_state
);
564 state
->mask
= talloc_strdup(state
, mask
);
565 if (tevent_req_nomem(state
->mask
, req
)) {
566 return tevent_req_post(req
, ev
);
568 state
->attribute
= attribute
;
569 state
->info_level
= info_level
;
570 state
->loop_count
= 0;
573 state
->max_matches
= 1366; /* Match W2k */
575 SSVAL(&state
->setup
[0], 0, TRANSACT2_FINDFIRST
);
577 state
->param
= talloc_array(state
, uint8_t, 12);
578 if (tevent_req_nomem(state
->param
, req
)) {
579 return tevent_req_post(req
, ev
);
582 SSVAL(state
->param
, 0, state
->attribute
);
583 SSVAL(state
->param
, 2, state
->max_matches
);
584 SSVAL(state
->param
, 4,
585 FLAG_TRANS2_FIND_REQUIRE_RESUME
586 |FLAG_TRANS2_FIND_CLOSE_IF_END
);
587 SSVAL(state
->param
, 6, state
->info_level
);
588 SIVAL(state
->param
, 8, 0);
590 state
->param
= trans2_bytes_push_str(state
->param
, cli_ucs2(cli
),
591 state
->mask
, strlen(state
->mask
)+1,
593 if (tevent_req_nomem(state
->param
, req
)) {
594 return tevent_req_post(req
, ev
);
596 param_len
= talloc_get_size(state
->param
);
598 subreq
= cli_trans_send(state
, state
->ev
, state
->cli
,
599 SMBtrans2
, NULL
, -1, 0, 0,
601 state
->param
, param_len
, 10,
602 NULL
, 0, cli
->max_xmit
);
603 if (tevent_req_nomem(subreq
, req
)) {
604 return tevent_req_post(req
, ev
);
606 tevent_req_set_callback(subreq
, cli_list_trans_done
, req
);
610 static void cli_list_trans_done(struct tevent_req
*subreq
)
612 struct tevent_req
*req
= tevent_req_callback_data(
613 subreq
, struct tevent_req
);
614 struct cli_list_trans_state
*state
= tevent_req_data(
615 req
, struct cli_list_trans_state
);
623 struct file_info
*tmp
;
624 size_t old_num_finfo
;
625 uint16_t recv_flags2
;
629 uint32_t resume_key
= 0;
631 DATA_BLOB last_name_raw
;
632 struct file_info
*finfo
= NULL
;
635 min_param
= (state
->first
? 6 : 4);
637 status
= cli_trans_recv(subreq
, talloc_tos(), &recv_flags2
,
639 ¶m
, min_param
, &num_param
,
640 &data
, 0, &num_data
);
642 if (!NT_STATUS_IS_OK(status
)) {
644 * TODO: retry, OS/2 nofiles
646 tevent_req_nterror(req
, status
);
651 state
->ff_dir_handle
= SVAL(param
, 0);
652 ff_searchcount
= SVAL(param
, 2);
653 ff_eos
= SVAL(param
, 4) != 0;
655 ff_searchcount
= SVAL(param
, 0);
656 ff_eos
= SVAL(param
, 2) != 0;
659 old_num_finfo
= talloc_array_length(state
->finfo
);
661 tmp
= talloc_realloc(state
, state
->finfo
, struct file_info
,
662 old_num_finfo
+ ff_searchcount
);
663 if (tevent_req_nomem(tmp
, req
)) {
668 p2
= p
= (char *)data
;
669 data_end
= (char *)data
+ num_data
;
670 last_name_raw
= data_blob_null
;
672 for (i
=0; i
<ff_searchcount
; i
++) {
673 if (p2
>= data_end
) {
677 if ((state
->info_level
== SMB_FIND_FILE_BOTH_DIRECTORY_INFO
)
678 && (i
== ff_searchcount
-1)) {
679 /* Last entry - fixup the last offset length. */
680 SIVAL(p2
, 0, PTR_DIFF((data
+ num_data
), p2
));
683 data_blob_free(&last_name_raw
);
685 finfo
= &state
->finfo
[old_num_finfo
+ i
];
687 p2
+= interpret_long_filename(
688 state
->finfo
, /* Stick fname to the array as such */
689 state
->cli
, state
->info_level
,
690 (char *)data
, recv_flags2
, p2
,
691 data_end
, finfo
, &resume_key
, &last_name_raw
);
693 if (finfo
->name
== NULL
) {
694 DEBUG(1, ("cli_list: Error: unable to parse name from "
695 "info level %d\n", state
->info_level
));
699 if (!state
->first
&& (state
->mask
[0] != '\0') &&
700 strcsequal(finfo
->name
, state
->mask
)) {
701 DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
702 "already been seen?\n", finfo
->name
));
708 if (ff_searchcount
== 0) {
716 * Shrink state->finfo to the real length we received
718 tmp
= talloc_realloc(state
, state
->finfo
, struct file_info
,
720 if (tevent_req_nomem(tmp
, req
)) {
725 state
->first
= false;
728 data_blob_free(&last_name_raw
);
729 tevent_req_done(req
);
733 TALLOC_FREE(state
->mask
);
734 state
->mask
= talloc_strdup(state
, finfo
->name
);
735 if (tevent_req_nomem(state
->mask
, req
)) {
739 SSVAL(&state
->setup
[0], 0, TRANSACT2_FINDNEXT
);
741 param
= talloc_realloc(state
, state
->param
, uint8_t, 12);
742 if (tevent_req_nomem(param
, req
)) {
745 state
->param
= param
;
747 SSVAL(param
, 0, state
->ff_dir_handle
);
748 SSVAL(param
, 2, state
->max_matches
); /* max count */
749 SSVAL(param
, 4, state
->info_level
);
751 * For W2K servers serving out FAT filesystems we *must* set
752 * the resume key. If it's not FAT then it's returned as zero.
754 SIVAL(param
, 6, resume_key
); /* ff_resume_key */
756 * NB. *DON'T* use continue here. If you do it seems that W2K
757 * and bretheren can miss filenames. Use last filename
758 * continue instead. JRA
760 SSVAL(param
, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
761 |FLAG_TRANS2_FIND_CLOSE_IF_END
));
762 if (last_name_raw
.length
) {
763 state
->param
= trans2_bytes_push_bytes(state
->param
,
765 last_name_raw
.length
);
766 if (tevent_req_nomem(state
->param
, req
)) {
769 data_blob_free(&last_name_raw
);
771 state
->param
= trans2_bytes_push_str(state
->param
,
772 cli_ucs2(state
->cli
),
774 strlen(state
->mask
)+1,
776 if (tevent_req_nomem(state
->param
, req
)) {
780 param_len
= talloc_get_size(state
->param
);
782 subreq
= cli_trans_send(state
, state
->ev
, state
->cli
,
783 SMBtrans2
, NULL
, -1, 0, 0,
785 state
->param
, param_len
, 10,
786 NULL
, 0, state
->cli
->max_xmit
);
787 if (tevent_req_nomem(subreq
, req
)) {
790 tevent_req_set_callback(subreq
, cli_list_trans_done
, req
);
793 static NTSTATUS
cli_list_trans_recv(struct tevent_req
*req
,
795 struct file_info
**finfo
)
797 struct cli_list_trans_state
*state
= tevent_req_data(
798 req
, struct cli_list_trans_state
);
801 if (tevent_req_is_nterror(req
, &status
)) {
804 *finfo
= talloc_move(mem_ctx
, &state
->finfo
);
808 NTSTATUS
cli_list_trans(struct cli_state
*cli
, const char *mask
,
809 uint16_t attribute
, int info_level
,
810 NTSTATUS (*fn
)(const char *mnt
, struct file_info
*finfo
,
811 const char *mask
, void *private_data
),
814 TALLOC_CTX
*frame
= talloc_stackframe();
815 struct event_context
*ev
;
816 struct tevent_req
*req
;
818 struct file_info
*finfo
= NULL
;
819 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
821 if (cli_has_async_calls(cli
)) {
823 * Can't use sync call while an async call is in flight
825 status
= NT_STATUS_INVALID_PARAMETER
;
828 ev
= event_context_init(frame
);
832 req
= cli_list_trans_send(frame
, ev
, cli
, mask
, attribute
, info_level
);
836 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
839 status
= cli_list_trans_recv(req
, frame
, &finfo
);
840 if (!NT_STATUS_IS_OK(status
)) {
843 num_finfo
= talloc_array_length(finfo
);
844 for (i
=0; i
<num_finfo
; i
++) {
845 status
= fn(cli
->dfs_mountpoint
, &finfo
[i
], mask
, private_data
);
846 if (!NT_STATUS_IS_OK(status
)) {
855 struct cli_list_state
{
856 NTSTATUS (*recv_fn
)(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
857 struct file_info
**finfo
);
858 struct file_info
*finfo
;
861 static void cli_list_done(struct tevent_req
*subreq
);
863 struct tevent_req
*cli_list_send(TALLOC_CTX
*mem_ctx
,
864 struct tevent_context
*ev
,
865 struct cli_state
*cli
,
870 struct tevent_req
*req
, *subreq
;
871 struct cli_list_state
*state
;
873 req
= tevent_req_create(mem_ctx
, &state
, struct cli_list_state
);
878 if (cli_state_protocol(cli
) <= PROTOCOL_LANMAN1
) {
879 subreq
= cli_list_old_send(state
, ev
, cli
, mask
, attribute
);
880 state
->recv_fn
= cli_list_old_recv
;
882 subreq
= cli_list_trans_send(state
, ev
, cli
, mask
, attribute
,
884 state
->recv_fn
= cli_list_trans_recv
;
886 if (tevent_req_nomem(subreq
, req
)) {
887 return tevent_req_post(req
, ev
);
889 tevent_req_set_callback(subreq
, cli_list_done
, req
);
893 static void cli_list_done(struct tevent_req
*subreq
)
895 struct tevent_req
*req
= tevent_req_callback_data(
896 subreq
, struct tevent_req
);
897 struct cli_list_state
*state
= tevent_req_data(
898 req
, struct cli_list_state
);
901 status
= state
->recv_fn(subreq
, state
, &state
->finfo
);
903 if (!NT_STATUS_IS_OK(status
)) {
904 tevent_req_nterror(req
, status
);
907 tevent_req_done(req
);
910 NTSTATUS
cli_list_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
911 struct file_info
**finfo
, size_t *num_finfo
)
913 struct cli_list_state
*state
= tevent_req_data(
914 req
, struct cli_list_state
);
917 if (tevent_req_is_nterror(req
, &status
)) {
920 *num_finfo
= talloc_array_length(state
->finfo
);
921 *finfo
= talloc_move(mem_ctx
, &state
->finfo
);
925 NTSTATUS
cli_list(struct cli_state
*cli
, const char *mask
, uint16 attribute
,
926 NTSTATUS (*fn
)(const char *, struct file_info
*, const char *,
927 void *), void *state
)
929 TALLOC_CTX
*frame
= talloc_stackframe();
930 struct event_context
*ev
;
931 struct tevent_req
*req
;
932 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
933 struct file_info
*finfo
;
937 if (cli_has_async_calls(cli
)) {
939 * Can't use sync call while an async call is in flight
941 status
= NT_STATUS_INVALID_PARAMETER
;
944 ev
= event_context_init(frame
);
949 info_level
= (cli_state_capabilities(cli
) & CAP_NT_SMBS
)
950 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO
: SMB_FIND_INFO_STANDARD
;
952 req
= cli_list_send(frame
, ev
, cli
, mask
, attribute
, info_level
);
956 if (!tevent_req_poll(req
, ev
)) {
957 status
= map_nt_error_from_unix(errno
);
961 status
= cli_list_recv(req
, frame
, &finfo
, &num_finfo
);
962 if (!NT_STATUS_IS_OK(status
)) {
966 for (i
=0; i
<num_finfo
; i
++) {
967 status
= fn(cli
->dfs_mountpoint
, &finfo
[i
], mask
, state
);
968 if (!NT_STATUS_IS_OK(status
)) {