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"
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
,
57 const char *pdata_end
,
58 struct file_info
*finfo
,
60 DATA_BLOB
*p_last_name_raw
)
66 data_blob_free(p_last_name_raw
);
74 case SMB_FIND_INFO_STANDARD
: /* OS/2 understands this */
75 /* these dates are converted to GMT by
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);
90 if (recv_flags2
& FLAGS2_UNICODE_STRINGS
) {
91 p
+= ucs2_align(base_ptr
, p
, STR_UNICODE
);
94 /* We can safely use len here (which is required by OS/2)
95 * and the NAS-BASIC server instead of +2 or +1 as the
96 * STR_TERMINATE flag below is
97 * actually used as the length calculation.
98 * The len is merely an upper bound.
99 * Due to the explicit 2 byte null termination
100 * in cli_receive_trans/cli_receive_nt_trans
101 * we know this is safe. JRA + kukks
104 if (p
+ len
> pdata_end
) {
105 return pdata_end
- base
;
108 /* the len+2 below looks strange but it is
109 important to cope with the differences
110 between win2000 and win9x for this call
112 ret
= clistr_pull_talloc(ctx
,
119 if (ret
== (size_t)-1) {
120 return pdata_end
- base
;
123 return PTR_DIFF(p
, base
);
125 case SMB_FIND_EA_SIZE
: /* this is what OS/2 uses mostly */
126 /* these dates are converted to GMT by
128 if (pdata_end
- base
< 31) {
129 return pdata_end
- base
;
131 finfo
->ctime_ts
= convert_time_t_to_timespec(
132 make_unix_date2(p
+4, smb1cli_conn_server_time_zone(cli
->conn
)));
133 finfo
->atime_ts
= convert_time_t_to_timespec(
134 make_unix_date2(p
+8, smb1cli_conn_server_time_zone(cli
->conn
)));
135 finfo
->mtime_ts
= convert_time_t_to_timespec(
136 make_unix_date2(p
+12, smb1cli_conn_server_time_zone(cli
->conn
)));
137 finfo
->size
= IVAL(p
,16);
138 finfo
->mode
= CVAL(p
,24);
141 /* check for unisys! */
142 if (p
+ len
+ 1 > pdata_end
) {
143 return pdata_end
- base
;
145 ret
= clistr_pull_talloc(ctx
,
152 if (ret
== (size_t)-1) {
153 return pdata_end
- base
;
156 return PTR_DIFF(p
, base
) + 1;
158 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO
: /* NT uses this, but also accepts 2 */
160 size_t namelen
, slen
;
162 if (pdata_end
- base
< 94) {
163 return pdata_end
- base
;
166 p
+= 4; /* next entry offset */
169 *p_resume_key
= IVAL(p
,0);
171 p
+= 4; /* fileindex */
173 /* Offset zero is "create time", not "change time". */
175 finfo
->atime_ts
= interpret_long_date(p
);
177 finfo
->mtime_ts
= interpret_long_date(p
);
179 finfo
->ctime_ts
= interpret_long_date(p
);
181 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(p
,0);
183 p
+= 8; /* alloc size */
184 finfo
->mode
= CVAL(p
,0);
188 p
+= 4; /* EA size */
191 /* Bad short name length. */
192 return pdata_end
- base
;
195 ret
= clistr_pull_talloc(ctx
,
202 if (ret
== (size_t)-1) {
203 return pdata_end
- base
;
205 p
+= 24; /* short name? */
206 if (p
+ namelen
< p
|| p
+ namelen
> pdata_end
) {
207 return pdata_end
- base
;
209 ret
= clistr_pull_talloc(ctx
,
216 if (ret
== (size_t)-1) {
217 return pdata_end
- base
;
220 /* To be robust in the face of unicode conversion failures
221 we need to copy the raw bytes of the last name seen here.
222 Namelen doesn't include the terminating unicode null, so
225 if (p_last_name_raw
) {
226 *p_last_name_raw
= data_blob(NULL
, namelen
+2);
227 memcpy(p_last_name_raw
->data
, p
, namelen
);
228 SSVAL(p_last_name_raw
->data
, namelen
, 0);
230 return calc_next_entry_offset(base
, pdata_end
);
234 DEBUG(1,("Unknown long filename format %d\n",level
));
235 return calc_next_entry_offset(base
, pdata_end
);
238 /****************************************************************************
239 Interpret a short filename structure.
240 The length of the structure is returned.
241 ****************************************************************************/
243 static bool interpret_short_filename(TALLOC_CTX
*ctx
,
244 struct cli_state
*cli
,
246 struct file_info
*finfo
)
251 finfo
->mode
= CVAL(p
,21);
253 /* this date is converted to GMT by make_unix_date */
254 finfo
->ctime_ts
.tv_sec
= make_unix_date(p
+22, smb1cli_conn_server_time_zone(cli
->conn
));
255 finfo
->ctime_ts
.tv_nsec
= 0;
256 finfo
->mtime_ts
.tv_sec
= finfo
->atime_ts
.tv_sec
= finfo
->ctime_ts
.tv_sec
;
257 finfo
->mtime_ts
.tv_nsec
= finfo
->atime_ts
.tv_nsec
= 0;
258 finfo
->size
= IVAL(p
,26);
259 ret
= clistr_pull_talloc(ctx
,
266 if (ret
== (size_t)-1) {
271 finfo
->short_name
= talloc_strdup(ctx
, finfo
->name
);
272 if (finfo
->short_name
== NULL
) {
279 struct cli_list_old_state
{
280 struct tevent_context
*ev
;
281 struct cli_state
*cli
;
286 uint8_t search_status
[23];
292 static void cli_list_old_done(struct tevent_req
*subreq
);
294 static struct tevent_req
*cli_list_old_send(TALLOC_CTX
*mem_ctx
,
295 struct tevent_context
*ev
,
296 struct cli_state
*cli
,
300 struct tevent_req
*req
, *subreq
;
301 struct cli_list_old_state
*state
;
303 static const uint16_t zero
= 0;
304 uint32_t usable_space
;
306 req
= tevent_req_create(mem_ctx
, &state
, struct cli_list_old_state
);
312 state
->attribute
= attribute
;
314 state
->mask
= talloc_strdup(state
, mask
);
315 if (tevent_req_nomem(state
->mask
, req
)) {
316 return tevent_req_post(req
, ev
);
318 usable_space
= cli_state_available_size(cli
, 100);
319 state
->num_asked
= usable_space
/ DIR_STRUCT_SIZE
;
321 SSVAL(state
->vwv
+ 0, 0, state
->num_asked
);
322 SSVAL(state
->vwv
+ 1, 0, state
->attribute
);
324 bytes
= talloc_array(state
, uint8_t, 1);
325 if (tevent_req_nomem(bytes
, req
)) {
326 return tevent_req_post(req
, ev
);
329 bytes
= smb_bytes_push_str(bytes
, smbXcli_conn_use_unicode(cli
->conn
), mask
,
330 strlen(mask
)+1, NULL
);
332 bytes
= smb_bytes_push_bytes(bytes
, 5, (const uint8_t *)&zero
, 2);
333 if (tevent_req_nomem(bytes
, req
)) {
334 return tevent_req_post(req
, ev
);
337 subreq
= cli_smb_send(state
, state
->ev
, state
->cli
, SMBsearch
,
338 0, 2, state
->vwv
, talloc_get_size(bytes
), bytes
);
339 if (tevent_req_nomem(subreq
, req
)) {
340 return tevent_req_post(req
, ev
);
342 tevent_req_set_callback(subreq
, cli_list_old_done
, req
);
346 static void cli_list_old_done(struct tevent_req
*subreq
)
348 struct tevent_req
*req
= tevent_req_callback_data(
349 subreq
, struct tevent_req
);
350 struct cli_list_old_state
*state
= tevent_req_data(
351 req
, struct cli_list_old_state
);
362 status
= cli_smb_recv(subreq
, state
, NULL
, 0, &wct
, &vwv
, &num_bytes
,
364 if (!NT_STATUS_IS_OK(status
)
365 && !NT_STATUS_EQUAL(status
, NT_STATUS_DOS(ERRDOS
, ERRnofiles
))
366 && !NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
368 tevent_req_nterror(req
, status
);
371 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOS(ERRDOS
, ERRnofiles
))
372 || NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
378 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
381 received
= SVAL(vwv
+ 0, 0);
386 * I don't think this can wrap. received is
387 * initialized from a 16-bit value.
389 if (num_bytes
< (received
* DIR_STRUCT_SIZE
+ 3)) {
392 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
396 dirlist_len
= talloc_get_size(state
->dirlist
);
398 tmp
= talloc_realloc(
399 state
, state
->dirlist
, uint8_t,
400 dirlist_len
+ received
* DIR_STRUCT_SIZE
);
401 if (tevent_req_nomem(tmp
, req
)) {
404 state
->dirlist
= tmp
;
405 memcpy(state
->dirlist
+ dirlist_len
, bytes
+ 3,
406 received
* DIR_STRUCT_SIZE
);
408 SSVAL(state
->search_status
, 0, 21);
409 memcpy(state
->search_status
+ 2,
410 bytes
+ 3 + (received
-1)*DIR_STRUCT_SIZE
, 21);
413 if (state
->first
|| state
->done
) {
414 tevent_req_done(req
);
418 state
->num_asked
= 0;
423 state
->first
= false;
425 SSVAL(state
->vwv
+ 0, 0, state
->num_asked
);
426 SSVAL(state
->vwv
+ 1, 0, state
->attribute
);
428 bytes
= talloc_array(state
, uint8_t, 1);
429 if (tevent_req_nomem(bytes
, req
)) {
433 bytes
= smb_bytes_push_str(bytes
, smbXcli_conn_use_unicode(state
->cli
->conn
), "",
435 bytes
= smb_bytes_push_bytes(bytes
, 5, state
->search_status
,
436 sizeof(state
->search_status
));
437 if (tevent_req_nomem(bytes
, req
)) {
440 subreq
= cli_smb_send(state
, state
->ev
, state
->cli
, cmd
, 0,
441 2, state
->vwv
, talloc_get_size(bytes
), bytes
);
442 if (tevent_req_nomem(subreq
, req
)) {
445 tevent_req_set_callback(subreq
, cli_list_old_done
, req
);
448 static NTSTATUS
cli_list_old_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
449 struct file_info
**pfinfo
)
451 struct cli_list_old_state
*state
= tevent_req_data(
452 req
, struct cli_list_old_state
);
454 size_t i
, num_received
;
455 struct file_info
*finfo
;
457 if (tevent_req_is_nterror(req
, &status
)) {
461 num_received
= talloc_array_length(state
->dirlist
) / DIR_STRUCT_SIZE
;
463 finfo
= talloc_array(mem_ctx
, struct file_info
, num_received
);
465 return NT_STATUS_NO_MEMORY
;
468 for (i
=0; i
<num_received
; i
++) {
469 if (!interpret_short_filename(
471 (char *)state
->dirlist
+ i
* DIR_STRUCT_SIZE
,
474 return NT_STATUS_NO_MEMORY
;
481 NTSTATUS
cli_list_old(struct cli_state
*cli
, const char *mask
,
483 NTSTATUS (*fn
)(const char *, struct file_info
*,
484 const char *, void *), void *state
)
486 TALLOC_CTX
*frame
= talloc_stackframe();
487 struct tevent_context
*ev
;
488 struct tevent_req
*req
;
489 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
490 struct file_info
*finfo
;
493 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
495 * Can't use sync call while an async call is in flight
497 status
= NT_STATUS_INVALID_PARAMETER
;
500 ev
= samba_tevent_context_init(frame
);
504 req
= cli_list_old_send(frame
, ev
, cli
, mask
, attribute
);
508 if (!tevent_req_poll(req
, ev
)) {
509 status
= map_nt_error_from_unix(errno
);
512 status
= cli_list_old_recv(req
, frame
, &finfo
);
513 if (!NT_STATUS_IS_OK(status
)) {
516 num_finfo
= talloc_array_length(finfo
);
517 for (i
=0; i
<num_finfo
; i
++) {
518 status
= fn(cli
->dfs_mountpoint
, &finfo
[i
], mask
, state
);
519 if (!NT_STATUS_IS_OK(status
)) {
528 struct cli_list_trans_state
{
529 struct tevent_context
*ev
;
530 struct cli_state
*cli
;
537 uint16_t max_matches
;
546 struct file_info
*finfo
;
549 static void cli_list_trans_done(struct tevent_req
*subreq
);
551 static struct tevent_req
*cli_list_trans_send(TALLOC_CTX
*mem_ctx
,
552 struct tevent_context
*ev
,
553 struct cli_state
*cli
,
558 struct tevent_req
*req
, *subreq
;
559 struct cli_list_trans_state
*state
;
562 req
= tevent_req_create(mem_ctx
, &state
,
563 struct cli_list_trans_state
);
569 state
->mask
= talloc_strdup(state
, mask
);
570 if (tevent_req_nomem(state
->mask
, req
)) {
571 return tevent_req_post(req
, ev
);
573 state
->attribute
= attribute
;
574 state
->info_level
= info_level
;
575 state
->loop_count
= 0;
578 state
->max_matches
= 1366; /* Match W2k */
580 SSVAL(&state
->setup
[0], 0, TRANSACT2_FINDFIRST
);
582 state
->param
= talloc_array(state
, uint8_t, 12);
583 if (tevent_req_nomem(state
->param
, req
)) {
584 return tevent_req_post(req
, ev
);
587 SSVAL(state
->param
, 0, state
->attribute
);
588 SSVAL(state
->param
, 2, state
->max_matches
);
589 SSVAL(state
->param
, 4,
590 FLAG_TRANS2_FIND_REQUIRE_RESUME
591 |FLAG_TRANS2_FIND_CLOSE_IF_END
592 |(cli
->backup_intent
? FLAG_TRANS2_FIND_BACKUP_INTENT
: 0));
593 SSVAL(state
->param
, 6, state
->info_level
);
594 SIVAL(state
->param
, 8, 0);
596 state
->param
= trans2_bytes_push_str(state
->param
, smbXcli_conn_use_unicode(cli
->conn
),
597 state
->mask
, strlen(state
->mask
)+1,
599 if (tevent_req_nomem(state
->param
, req
)) {
600 return tevent_req_post(req
, ev
);
602 param_len
= talloc_get_size(state
->param
);
604 subreq
= cli_trans_send(state
, state
->ev
, state
->cli
,
605 SMBtrans2
, NULL
, -1, 0, 0,
607 state
->param
, param_len
, 10,
608 NULL
, 0, CLI_BUFFER_SIZE
);
609 if (tevent_req_nomem(subreq
, req
)) {
610 return tevent_req_post(req
, ev
);
612 tevent_req_set_callback(subreq
, cli_list_trans_done
, req
);
616 static void cli_list_trans_done(struct tevent_req
*subreq
)
618 struct tevent_req
*req
= tevent_req_callback_data(
619 subreq
, struct tevent_req
);
620 struct cli_list_trans_state
*state
= tevent_req_data(
621 req
, struct cli_list_trans_state
);
629 struct file_info
*tmp
;
630 size_t old_num_finfo
;
631 uint16_t recv_flags2
;
635 uint32_t resume_key
= 0;
637 DATA_BLOB last_name_raw
;
638 struct file_info
*finfo
= NULL
;
641 min_param
= (state
->first
? 6 : 4);
643 status
= cli_trans_recv(subreq
, talloc_tos(), &recv_flags2
,
645 ¶m
, min_param
, &num_param
,
646 &data
, 0, &num_data
);
648 if (!NT_STATUS_IS_OK(status
)) {
650 * TODO: retry, OS/2 nofiles
652 tevent_req_nterror(req
, status
);
657 state
->ff_dir_handle
= SVAL(param
, 0);
658 ff_searchcount
= SVAL(param
, 2);
659 ff_eos
= SVAL(param
, 4) != 0;
661 ff_searchcount
= SVAL(param
, 0);
662 ff_eos
= SVAL(param
, 2) != 0;
665 old_num_finfo
= talloc_array_length(state
->finfo
);
667 tmp
= talloc_realloc(state
, state
->finfo
, struct file_info
,
668 old_num_finfo
+ ff_searchcount
);
669 if (tevent_req_nomem(tmp
, req
)) {
674 p2
= p
= (char *)data
;
675 data_end
= (char *)data
+ num_data
;
676 last_name_raw
= data_blob_null
;
678 for (i
=0; i
<ff_searchcount
; i
++) {
679 if (p2
>= data_end
) {
683 if ((state
->info_level
== SMB_FIND_FILE_BOTH_DIRECTORY_INFO
)
684 && (i
== ff_searchcount
-1)) {
685 /* Last entry - fixup the last offset length. */
686 SIVAL(p2
, 0, PTR_DIFF((data
+ num_data
), p2
));
689 data_blob_free(&last_name_raw
);
691 finfo
= &state
->finfo
[old_num_finfo
+ i
];
693 p2
+= interpret_long_filename(
694 state
->finfo
, /* Stick fname to the array as such */
695 state
->cli
, state
->info_level
,
696 (char *)data
, recv_flags2
, p2
,
697 data_end
, finfo
, &resume_key
, &last_name_raw
);
699 if (finfo
->name
== NULL
) {
700 DEBUG(1, ("cli_list: Error: unable to parse name from "
701 "info level %d\n", state
->info_level
));
705 if (!state
->first
&& (state
->mask
[0] != '\0') &&
706 strcsequal(finfo
->name
, state
->mask
)) {
707 DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "
708 "already been seen?\n", finfo
->name
));
714 if (ff_searchcount
== 0) {
722 * Shrink state->finfo to the real length we received
724 tmp
= talloc_realloc(state
, state
->finfo
, struct file_info
,
726 if (tevent_req_nomem(tmp
, req
)) {
731 state
->first
= false;
734 data_blob_free(&last_name_raw
);
735 tevent_req_done(req
);
739 TALLOC_FREE(state
->mask
);
740 state
->mask
= talloc_strdup(state
, finfo
->name
);
741 if (tevent_req_nomem(state
->mask
, req
)) {
745 SSVAL(&state
->setup
[0], 0, TRANSACT2_FINDNEXT
);
747 param
= talloc_realloc(state
, state
->param
, uint8_t, 12);
748 if (tevent_req_nomem(param
, req
)) {
751 state
->param
= param
;
753 SSVAL(param
, 0, state
->ff_dir_handle
);
754 SSVAL(param
, 2, state
->max_matches
); /* max count */
755 SSVAL(param
, 4, state
->info_level
);
757 * For W2K servers serving out FAT filesystems we *must* set
758 * the resume key. If it's not FAT then it's returned as zero.
760 SIVAL(param
, 6, resume_key
); /* ff_resume_key */
762 * NB. *DON'T* use continue here. If you do it seems that W2K
763 * and bretheren can miss filenames. Use last filename
764 * continue instead. JRA
766 SSVAL(param
, 10, (FLAG_TRANS2_FIND_REQUIRE_RESUME
767 |FLAG_TRANS2_FIND_CLOSE_IF_END
768 |(state
->cli
->backup_intent
? FLAG_TRANS2_FIND_BACKUP_INTENT
: 0)));
769 if (last_name_raw
.length
) {
770 state
->param
= trans2_bytes_push_bytes(state
->param
,
772 last_name_raw
.length
);
773 if (tevent_req_nomem(state
->param
, req
)) {
776 data_blob_free(&last_name_raw
);
778 state
->param
= trans2_bytes_push_str(state
->param
,
779 smbXcli_conn_use_unicode(state
->cli
->conn
),
781 strlen(state
->mask
)+1,
783 if (tevent_req_nomem(state
->param
, req
)) {
787 param_len
= talloc_get_size(state
->param
);
789 subreq
= cli_trans_send(state
, state
->ev
, state
->cli
,
790 SMBtrans2
, NULL
, -1, 0, 0,
792 state
->param
, param_len
, 10,
793 NULL
, 0, CLI_BUFFER_SIZE
);
794 if (tevent_req_nomem(subreq
, req
)) {
797 tevent_req_set_callback(subreq
, cli_list_trans_done
, req
);
800 static NTSTATUS
cli_list_trans_recv(struct tevent_req
*req
,
802 struct file_info
**finfo
)
804 struct cli_list_trans_state
*state
= tevent_req_data(
805 req
, struct cli_list_trans_state
);
808 if (tevent_req_is_nterror(req
, &status
)) {
811 *finfo
= talloc_move(mem_ctx
, &state
->finfo
);
815 NTSTATUS
cli_list_trans(struct cli_state
*cli
, const char *mask
,
816 uint16_t attribute
, int info_level
,
817 NTSTATUS (*fn
)(const char *mnt
, struct file_info
*finfo
,
818 const char *mask
, void *private_data
),
821 TALLOC_CTX
*frame
= talloc_stackframe();
822 struct tevent_context
*ev
;
823 struct tevent_req
*req
;
825 struct file_info
*finfo
= NULL
;
826 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
828 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
830 * Can't use sync call while an async call is in flight
832 status
= NT_STATUS_INVALID_PARAMETER
;
835 ev
= samba_tevent_context_init(frame
);
839 req
= cli_list_trans_send(frame
, ev
, cli
, mask
, attribute
, info_level
);
843 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
846 status
= cli_list_trans_recv(req
, frame
, &finfo
);
847 if (!NT_STATUS_IS_OK(status
)) {
850 num_finfo
= talloc_array_length(finfo
);
851 for (i
=0; i
<num_finfo
; i
++) {
852 status
= fn(cli
->dfs_mountpoint
, &finfo
[i
], mask
, private_data
);
853 if (!NT_STATUS_IS_OK(status
)) {
862 struct cli_list_state
{
863 NTSTATUS (*recv_fn
)(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
864 struct file_info
**finfo
);
865 struct file_info
*finfo
;
868 static void cli_list_done(struct tevent_req
*subreq
);
870 struct tevent_req
*cli_list_send(TALLOC_CTX
*mem_ctx
,
871 struct tevent_context
*ev
,
872 struct cli_state
*cli
,
877 struct tevent_req
*req
, *subreq
;
878 struct cli_list_state
*state
;
880 req
= tevent_req_create(mem_ctx
, &state
, struct cli_list_state
);
885 if (smbXcli_conn_protocol(cli
->conn
) <= PROTOCOL_LANMAN1
) {
886 subreq
= cli_list_old_send(state
, ev
, cli
, mask
, attribute
);
887 state
->recv_fn
= cli_list_old_recv
;
889 subreq
= cli_list_trans_send(state
, ev
, cli
, mask
, attribute
,
891 state
->recv_fn
= cli_list_trans_recv
;
893 if (tevent_req_nomem(subreq
, req
)) {
894 return tevent_req_post(req
, ev
);
896 tevent_req_set_callback(subreq
, cli_list_done
, req
);
900 static void cli_list_done(struct tevent_req
*subreq
)
902 struct tevent_req
*req
= tevent_req_callback_data(
903 subreq
, struct tevent_req
);
904 struct cli_list_state
*state
= tevent_req_data(
905 req
, struct cli_list_state
);
908 status
= state
->recv_fn(subreq
, state
, &state
->finfo
);
910 if (!NT_STATUS_IS_OK(status
)) {
911 tevent_req_nterror(req
, status
);
914 tevent_req_done(req
);
917 NTSTATUS
cli_list_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
918 struct file_info
**finfo
, size_t *num_finfo
)
920 struct cli_list_state
*state
= tevent_req_data(
921 req
, struct cli_list_state
);
924 if (tevent_req_is_nterror(req
, &status
)) {
927 *num_finfo
= talloc_array_length(state
->finfo
);
928 *finfo
= talloc_move(mem_ctx
, &state
->finfo
);
932 NTSTATUS
cli_list(struct cli_state
*cli
, const char *mask
, uint16 attribute
,
933 NTSTATUS (*fn
)(const char *, struct file_info
*, const char *,
934 void *), void *state
)
936 TALLOC_CTX
*frame
= NULL
;
937 struct tevent_context
*ev
;
938 struct tevent_req
*req
;
939 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
940 struct file_info
*finfo
;
944 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
945 return cli_smb2_list(cli
, mask
, fn
, state
);
948 frame
= talloc_stackframe();
950 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
952 * Can't use sync call while an async call is in flight
954 status
= NT_STATUS_INVALID_PARAMETER
;
957 ev
= samba_tevent_context_init(frame
);
962 info_level
= (smb1cli_conn_capabilities(cli
->conn
) & CAP_NT_SMBS
)
963 ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO
: SMB_FIND_INFO_STANDARD
;
965 req
= cli_list_send(frame
, ev
, cli
, mask
, attribute
, info_level
);
969 if (!tevent_req_poll(req
, ev
)) {
970 status
= map_nt_error_from_unix(errno
);
974 status
= cli_list_recv(req
, frame
, &finfo
, &num_finfo
);
975 if (!NT_STATUS_IS_OK(status
)) {
979 for (i
=0; i
<num_finfo
; i
++) {
980 status
= fn(cli
->dfs_mountpoint
, &finfo
[i
], mask
, state
);
981 if (!NT_STATUS_IS_OK(status
)) {