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/>.
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
,
52 const char *pdata_end
,
53 struct file_info
*finfo
,
55 DATA_BLOB
*p_last_name_raw
)
61 data_blob_free(p_last_name_raw
);
69 case SMB_FIND_INFO_STANDARD
: /* OS/2 understands this */
70 /* these dates are converted to GMT by
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);
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
105 ret
= clistr_pull_talloc(ctx
,
112 if (ret
== (size_t)-1) {
113 return pdata_end
- base
;
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
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);
134 /* check for unisys! */
135 if (p
+ len
+ 1 > pdata_end
) {
136 return pdata_end
- base
;
138 ret
= clistr_pull_talloc(ctx
,
145 if (ret
== (size_t)-1) {
146 return pdata_end
- base
;
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 */
162 *p_resume_key
= IVAL(p
,0);
164 p
+= 4; /* fileindex */
166 /* Offset zero is "create time", not "change time". */
168 finfo
->atime_ts
= interpret_long_date(p
);
170 finfo
->mtime_ts
= interpret_long_date(p
);
172 finfo
->ctime_ts
= interpret_long_date(p
);
174 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(p
,0);
176 p
+= 8; /* alloc size */
177 finfo
->mode
= CVAL(p
,0);
181 p
+= 4; /* EA size */
184 /* Bad short name length. */
185 return pdata_end
- base
;
189 /* stupid NT bugs. grr */
191 if (p
[1] == 0 && namelen
> 1) flags
|= STR_UNICODE
;
192 clistr_pull(base_ptr
, finfo
->short_name
, p
,
193 sizeof(finfo
->short_name
),
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
,
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
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
,
237 struct file_info
*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
,
252 SVAL(cli
->inbuf
, smb_flg2
),
257 if (ret
== (size_t)-1) {
262 strlcpy(finfo
->short_name
,
264 sizeof(finfo
->short_name
));
269 struct cli_list_old_state
{
270 struct tevent_context
*ev
;
271 struct cli_state
*cli
;
276 uint8_t search_status
[23];
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
,
290 struct tevent_req
*req
, *subreq
;
291 struct cli_list_old_state
*state
;
293 static const uint16_t zero
= 0;
295 req
= tevent_req_create(mem_ctx
, &state
, struct cli_list_old_state
);
301 state
->attribute
= attribute
;
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
);
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
);
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
);
350 status
= cli_smb_recv(subreq
, state
, NULL
, 0, &wct
, &vwv
, &num_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
)) {
356 tevent_req_nterror(req
, status
);
359 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOS(ERRDOS
, ERRnofiles
))
360 || NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
366 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
369 received
= SVAL(vwv
+ 0, 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)) {
380 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
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
)) {
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);
401 if (state
->first
|| state
->done
) {
402 tevent_req_done(req
);
406 state
->num_asked
= 0;
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
)) {
421 bytes
= smb_bytes_push_str(bytes
, cli_ucs2(state
->cli
), "",
423 bytes
= smb_bytes_push_bytes(bytes
, 5, state
->search_status
,
424 sizeof(state
->search_status
));
425 if (tevent_req_nomem(bytes
, req
)) {
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
)) {
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
);
442 size_t i
, num_received
;
443 struct file_info
*finfo
;
445 if (tevent_req_is_nterror(req
, &status
)) {
449 num_received
= talloc_array_length(state
->dirlist
) / DIR_STRUCT_SIZE
;
451 finfo
= TALLOC_ARRAY(mem_ctx
, struct file_info
, num_received
);
453 return NT_STATUS_NO_MEMORY
;
456 for (i
=0; i
<num_received
; i
++) {
457 if (!interpret_short_filename(
459 (char *)state
->dirlist
+ i
* DIR_STRUCT_SIZE
,
462 return NT_STATUS_NO_MEMORY
;
469 NTSTATUS
cli_list_old(struct cli_state
*cli
, const char *mask
,
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
;
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
;
488 ev
= event_context_init(frame
);
492 req
= cli_list_old_send(frame
, ev
, cli
, mask
, attribute
);
496 if (!tevent_req_poll(req
, ev
)) {
497 status
= map_nt_error_from_unix(errno
);
500 status
= cli_list_old_recv(req
, frame
, &finfo
);
501 if (!NT_STATUS_IS_OK(status
)) {
504 num_finfo
= talloc_array_length(finfo
);
505 for (i
=0; i
<num_finfo
; i
++) {
506 fn(cli
->dfs_mountpoint
, &finfo
[i
], mask
, state
);
510 if (!NT_STATUS_IS_OK(status
)) {
511 cli_set_error(cli
, status
);
516 struct cli_list_trans_state
{
517 struct tevent_context
*ev
;
518 struct cli_state
*cli
;
525 uint16_t max_matches
;
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
,
546 struct tevent_req
*req
, *subreq
;
547 struct cli_list_trans_state
*state
;
548 size_t nlen
, param_len
;
551 req
= tevent_req_create(mem_ctx
, &state
,
552 struct cli_list_trans_state
);
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;
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
,
588 param_len
= PTR_DIFF(p
, state
->param
);
590 subreq
= cli_trans_send(state
, state
->ev
, state
->cli
,
591 SMBtrans2
, NULL
, -1, 0, 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
);
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
);
615 struct file_info
*tmp
;
616 size_t old_num_finfo
;
617 uint16_t recv_flags2
;
621 uint32_t resume_key
= 0;
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
,
631 ¶m
, min_param
, &num_param
,
632 &data
, 0, &num_data
);
634 if (!NT_STATUS_IS_OK(status
)) {
636 * TODO: retry, OS/2 nofiles
638 tevent_req_nterror(req
, status
);
643 state
->ff_dir_handle
= SVAL(param
, 0);
644 ff_searchcount
= SVAL(param
, 2);
645 ff_eos
= SVAL(param
, 4) != 0;
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
)) {
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
) {
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
));
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
));
700 if (ff_searchcount
== 0) {
708 * Shrink state->finfo to the real length we received
710 tmp
= TALLOC_REALLOC_ARRAY(state
, state
->finfo
, struct file_info
,
712 if (tevent_req_nomem(tmp
, req
)) {
717 state
->first
= false;
720 data_blob_free(&last_name_raw
);
721 tevent_req_done(req
);
725 TALLOC_FREE(state
->mask
);
726 state
->mask
= talloc_strdup(state
, finfo
->name
);
727 if (tevent_req_nomem(state
->mask
, req
)) {
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
)) {
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
);
763 p
+= clistr_push(state
->cli
, p
, state
->mask
, nlen
,
767 param_len
= PTR_DIFF(p
, param
);
769 subreq
= cli_trans_send(state
, state
->ev
, state
->cli
,
770 SMBtrans2
, NULL
, -1, 0, 0,
772 state
->param
, param_len
, 10,
773 NULL
, 0, state
->cli
->max_xmit
);
774 if (tevent_req_nomem(subreq
, req
)) {
777 tevent_req_set_callback(subreq
, cli_list_trans_done
, req
);
780 static NTSTATUS
cli_list_trans_recv(struct tevent_req
*req
,
782 struct file_info
**finfo
)
784 struct cli_list_trans_state
*state
= tevent_req_data(
785 req
, struct cli_list_trans_state
);
788 if (tevent_req_is_nterror(req
, &status
)) {
791 *finfo
= talloc_move(mem_ctx
, &state
->finfo
);
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
),
801 TALLOC_CTX
*frame
= talloc_stackframe();
802 struct event_context
*ev
;
803 struct tevent_req
*req
;
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
;
815 ev
= event_context_init(frame
);
819 req
= cli_list_trans_send(frame
, ev
, cli
, mask
, attribute
, info_level
);
823 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
826 status
= cli_list_trans_recv(req
, frame
, &finfo
);
827 if (!NT_STATUS_IS_OK(status
)) {
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
);
836 if (!NT_STATUS_IS_OK(status
)) {
837 cli_set_error(cli
, 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
,
857 struct tevent_req
*req
, *subreq
;
858 struct cli_list_state
*state
;
860 req
= tevent_req_create(mem_ctx
, &state
, struct cli_list_state
);
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
;
869 subreq
= cli_list_trans_send(state
, ev
, cli
, mask
, attribute
,
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
);
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
);
888 status
= state
->recv_fn(subreq
, state
, &state
->finfo
);
890 if (!NT_STATUS_IS_OK(status
)) {
891 tevent_req_nterror(req
, status
);
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
);
904 if (tevent_req_is_nterror(req
, &status
)) {
907 *num_finfo
= talloc_array_length(state
->finfo
);
908 *finfo
= talloc_move(mem_ctx
, &state
->finfo
);
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
;
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
;
931 ev
= event_context_init(frame
);
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
);
943 if (!tevent_req_poll(req
, ev
)) {
944 status
= map_nt_error_from_unix(errno
);
948 status
= cli_list_recv(req
, frame
, &finfo
, &num_finfo
);
949 if (!NT_STATUS_IS_OK(status
)) {
953 for (i
=0; i
<num_finfo
; i
++) {
954 fn(cli
->dfs_mountpoint
, &finfo
[i
], mask
, state
);
958 if (!NT_STATUS_IS_OK(status
)) {
959 cli_set_error(cli
, status
);