2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Jeremy Allison 2001-2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/filesys.h"
23 #include "libsmb/libsmb.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "async_smb.h"
26 #include "libsmb/clirap.h"
29 #include "libcli/security/security.h"
30 #include "../libcli/smb/smbXcli_base.h"
31 #include "libcli/smb/reparse.h"
33 struct cli_setpathinfo_state
{
38 static void cli_setpathinfo_done(struct tevent_req
*subreq
);
40 struct tevent_req
*cli_setpathinfo_send(TALLOC_CTX
*mem_ctx
,
41 struct tevent_context
*ev
,
42 struct cli_state
*cli
,
48 struct tevent_req
*req
, *subreq
;
49 struct cli_setpathinfo_state
*state
;
50 uint16_t additional_flags2
= 0;
53 req
= tevent_req_create(mem_ctx
, &state
,
54 struct cli_setpathinfo_state
);
59 /* Setup setup word. */
60 SSVAL(&state
->setup
, 0, TRANSACT2_SETPATHINFO
);
62 /* Setup param array. */
63 state
->param
= talloc_zero_array(state
, uint8_t, 6);
64 if (tevent_req_nomem(state
->param
, req
)) {
65 return tevent_req_post(req
, ev
);
67 SSVAL(state
->param
, 0, level
);
70 path_cp
= smb1_dfs_share_path(state
, cli
, path
);
71 if (tevent_req_nomem(path_cp
, req
)) {
72 return tevent_req_post(req
, ev
);
74 state
->param
= trans2_bytes_push_str(state
->param
,
75 smbXcli_conn_use_unicode(cli
->conn
),
79 if (tevent_req_nomem(state
->param
, req
)) {
80 return tevent_req_post(req
, ev
);
83 if (clistr_is_previous_version_path(path
) &&
84 !INFO_LEVEL_IS_UNIX(level
)) {
85 additional_flags2
= FLAGS2_REPARSE_PATH
;
88 subreq
= cli_trans_send(
92 additional_flags2
, /* additional_flags2 */
94 NULL
, /* pipe name. */
98 &state
->setup
, /* setup. */
99 1, /* num setup uint16_t words. */
100 0, /* max returned setup. */
101 state
->param
, /* param. */
102 talloc_get_size(state
->param
), /* num param. */
103 2, /* max returned param. */
105 data_len
, /* num data. */
106 0); /* max returned data. */
108 if (tevent_req_nomem(subreq
, req
)) {
109 return tevent_req_post(req
, ev
);
111 tevent_req_set_callback(subreq
, cli_setpathinfo_done
, req
);
115 static void cli_setpathinfo_done(struct tevent_req
*subreq
)
117 NTSTATUS status
= cli_trans_recv(subreq
, NULL
, NULL
, NULL
, 0, NULL
,
118 NULL
, 0, NULL
, NULL
, 0, NULL
);
119 tevent_req_simple_finish_ntstatus(subreq
, status
);
122 NTSTATUS
cli_setpathinfo_recv(struct tevent_req
*req
)
124 return tevent_req_simple_recv_ntstatus(req
);
127 NTSTATUS
cli_setpathinfo(struct cli_state
*cli
,
133 TALLOC_CTX
*frame
= talloc_stackframe();
134 struct tevent_context
*ev
;
135 struct tevent_req
*req
;
136 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
138 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
140 * Can't use sync call while an async call is in flight
142 status
= NT_STATUS_INVALID_PARAMETER
;
145 ev
= samba_tevent_context_init(frame
);
149 req
= cli_setpathinfo_send(ev
, ev
, cli
, level
, path
, data
, data_len
);
153 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
156 status
= cli_setpathinfo_recv(req
);
162 struct cli_setfileinfo_state
{
167 static void cli_setfileinfo_done(struct tevent_req
*subreq
);
169 struct tevent_req
*cli_setfileinfo_send(
171 struct tevent_context
*ev
,
172 struct cli_state
*cli
,
178 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
179 struct cli_setfileinfo_state
*state
= NULL
;
181 req
= tevent_req_create(mem_ctx
, &state
, struct cli_setfileinfo_state
);
185 PUSH_LE_U16(&state
->setup
, 0, TRANSACT2_SETFILEINFO
);
187 PUSH_LE_U16(state
->param
, 0, fnum
);
188 PUSH_LE_U16(state
->param
, 2, level
);
190 subreq
= cli_trans_send(state
, /* mem ctx. */
192 cli
, /* cli_state. */
193 0, /* additional_flags2 */
194 SMBtrans2
, /* cmd. */
195 NULL
, /* pipe name. */
199 &state
->setup
, /* setup. */
200 1, /* num setup uint16_t words. */
201 0, /* max returned setup. */
202 state
->param
, /* param. */
204 2, /* max returned param. */
206 data_len
, /* num data. */
207 0); /* max returned data. */
209 if (tevent_req_nomem(subreq
, req
)) {
210 return tevent_req_post(req
, ev
);
212 tevent_req_set_callback(subreq
, cli_setfileinfo_done
, req
);
216 static void cli_setfileinfo_done(struct tevent_req
*subreq
)
218 NTSTATUS status
= cli_trans_recv(
221 NULL
, /* recv_flags2 */
224 NULL
, /* num_setup */
227 NULL
, /* num_param */
230 NULL
); /* num_data */
231 tevent_req_simple_finish_ntstatus(subreq
, status
);
234 NTSTATUS
cli_setfileinfo_recv(struct tevent_req
*req
)
236 return tevent_req_simple_recv_ntstatus(req
);
239 /****************************************************************************
240 Hard/Symlink a file (UNIX extensions).
241 Creates new name (sym)linked to link_target.
242 ****************************************************************************/
244 struct cli_posix_link_internal_state
{
248 static void cli_posix_link_internal_done(struct tevent_req
*subreq
);
250 static struct tevent_req
*cli_posix_link_internal_send(TALLOC_CTX
*mem_ctx
,
251 struct tevent_context
*ev
,
252 struct cli_state
*cli
,
254 const char *link_target
,
257 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
258 struct cli_posix_link_internal_state
*state
= NULL
;
260 req
= tevent_req_create(mem_ctx
, &state
,
261 struct cli_posix_link_internal_state
);
266 /* Setup data array. */
267 state
->data
= talloc_array(state
, uint8_t, 0);
268 if (tevent_req_nomem(state
->data
, req
)) {
269 return tevent_req_post(req
, ev
);
271 state
->data
= trans2_bytes_push_str(
272 state
->data
, smbXcli_conn_use_unicode(cli
->conn
),
273 link_target
, strlen(link_target
)+1, NULL
);
275 subreq
= cli_setpathinfo_send(
276 state
, ev
, cli
, level
, newname
,
277 state
->data
, talloc_get_size(state
->data
));
278 if (tevent_req_nomem(subreq
, req
)) {
279 return tevent_req_post(req
, ev
);
281 tevent_req_set_callback(subreq
, cli_posix_link_internal_done
, req
);
285 static void cli_posix_link_internal_done(struct tevent_req
*subreq
)
287 NTSTATUS status
= cli_setpathinfo_recv(subreq
);
288 tevent_req_simple_finish_ntstatus(subreq
, status
);
291 static NTSTATUS
cli_posix_link_internal_recv(struct tevent_req
*req
)
293 return tevent_req_simple_recv_ntstatus(req
);
296 /****************************************************************************
297 Symlink a file (UNIX extensions).
298 ****************************************************************************/
300 struct cli_posix_symlink_state
{
304 static void cli_posix_symlink_done(struct tevent_req
*subreq
);
306 struct tevent_req
*cli_posix_symlink_send(TALLOC_CTX
*mem_ctx
,
307 struct tevent_context
*ev
,
308 struct cli_state
*cli
,
309 const char *link_target
,
312 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
313 struct cli_posix_symlink_state
*state
= NULL
;
315 req
= tevent_req_create(
316 mem_ctx
, &state
, struct cli_posix_symlink_state
);
321 subreq
= cli_posix_link_internal_send(
322 mem_ctx
, ev
, cli
, SMB_SET_FILE_UNIX_LINK
, link_target
, newname
);
323 if (tevent_req_nomem(subreq
, req
)) {
324 return tevent_req_post(req
, ev
);
326 tevent_req_set_callback(subreq
, cli_posix_symlink_done
, req
);
330 static void cli_posix_symlink_done(struct tevent_req
*subreq
)
332 NTSTATUS status
= cli_posix_link_internal_recv(subreq
);
333 tevent_req_simple_finish_ntstatus(subreq
, status
);
336 NTSTATUS
cli_posix_symlink_recv(struct tevent_req
*req
)
338 return tevent_req_simple_recv_ntstatus(req
);
341 NTSTATUS
cli_posix_symlink(struct cli_state
*cli
,
342 const char *link_target
,
345 TALLOC_CTX
*frame
= talloc_stackframe();
346 struct tevent_context
*ev
= NULL
;
347 struct tevent_req
*req
= NULL
;
348 NTSTATUS status
= NT_STATUS_OK
;
350 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
352 * Can't use sync call while an async call is in flight
354 status
= NT_STATUS_INVALID_PARAMETER
;
358 ev
= samba_tevent_context_init(frame
);
360 status
= NT_STATUS_NO_MEMORY
;
364 req
= cli_posix_symlink_send(frame
,
370 status
= NT_STATUS_NO_MEMORY
;
374 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
378 status
= cli_posix_symlink_recv(req
);
385 /****************************************************************************
386 Read a POSIX symlink.
387 ****************************************************************************/
389 struct cli_posix_readlink_state
{
390 struct cli_state
*cli
;
394 static void cli_posix_readlink_done(struct tevent_req
*subreq
);
396 struct tevent_req
*cli_posix_readlink_send(TALLOC_CTX
*mem_ctx
,
397 struct tevent_context
*ev
,
398 struct cli_state
*cli
,
401 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
402 struct cli_posix_readlink_state
*state
= NULL
;
404 req
= tevent_req_create(
405 mem_ctx
, &state
, struct cli_posix_readlink_state
);
411 subreq
= cli_qpathinfo_send(
416 SMB_QUERY_FILE_UNIX_LINK
,
419 if (tevent_req_nomem(subreq
, req
)) {
420 return tevent_req_post(req
, ev
);
422 tevent_req_set_callback(subreq
, cli_posix_readlink_done
, req
);
426 static void cli_posix_readlink_done(struct tevent_req
*subreq
)
428 struct tevent_req
*req
= tevent_req_callback_data(
429 subreq
, struct tevent_req
);
430 struct cli_posix_readlink_state
*state
= tevent_req_data(
431 req
, struct cli_posix_readlink_state
);
433 uint8_t *data
= NULL
;
434 uint32_t num_data
= 0;
436 size_t converted_size
;
439 status
= cli_qpathinfo_recv(subreq
, state
, &data
, &num_data
);
441 if (tevent_req_nterror(req
, status
)) {
445 * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
447 if (data
== NULL
|| data
[num_data
-1] != '\0') {
448 tevent_req_nterror(req
, NT_STATUS_DATA_ERROR
);
452 charset
= smbXcli_conn_use_unicode(state
->cli
->conn
) ?
455 /* The returned data is a pushed string, not raw data. */
456 ok
= convert_string_talloc(
468 tevent_req_done(req
);
471 NTSTATUS
cli_posix_readlink_recv(
472 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, char **target
)
474 struct cli_posix_readlink_state
*state
= tevent_req_data(
475 req
, struct cli_posix_readlink_state
);
478 if (tevent_req_is_nterror(req
, &status
)) {
481 *target
= talloc_move(mem_ctx
, &state
->converted
);
482 tevent_req_received(req
);
486 /****************************************************************************
487 Hard link a file (UNIX extensions).
488 ****************************************************************************/
490 struct cli_posix_hardlink_state
{
494 static void cli_posix_hardlink_done(struct tevent_req
*subreq
);
496 struct tevent_req
*cli_posix_hardlink_send(TALLOC_CTX
*mem_ctx
,
497 struct tevent_context
*ev
,
498 struct cli_state
*cli
,
502 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
503 struct cli_posix_hardlink_state
*state
= NULL
;
505 req
= tevent_req_create(
506 mem_ctx
, &state
, struct cli_posix_hardlink_state
);
511 subreq
= cli_posix_link_internal_send(
512 state
, ev
, cli
, SMB_SET_FILE_UNIX_HLINK
, oldname
, newname
);
513 if (tevent_req_nomem(subreq
, req
)) {
514 return tevent_req_post(req
, ev
);
516 tevent_req_set_callback(subreq
, cli_posix_hardlink_done
, req
);
520 static void cli_posix_hardlink_done(struct tevent_req
*subreq
)
522 NTSTATUS status
= cli_posix_link_internal_recv(subreq
);
523 tevent_req_simple_finish_ntstatus(subreq
, status
);
526 NTSTATUS
cli_posix_hardlink_recv(struct tevent_req
*req
)
528 return tevent_req_simple_recv_ntstatus(req
);
531 NTSTATUS
cli_posix_hardlink(struct cli_state
*cli
,
535 TALLOC_CTX
*frame
= talloc_stackframe();
536 struct tevent_context
*ev
= NULL
;
537 struct tevent_req
*req
= NULL
;
538 NTSTATUS status
= NT_STATUS_OK
;
540 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
542 * Can't use sync call while an async call is in flight
544 status
= NT_STATUS_INVALID_PARAMETER
;
548 ev
= samba_tevent_context_init(frame
);
550 status
= NT_STATUS_NO_MEMORY
;
554 req
= cli_posix_hardlink_send(frame
,
560 status
= NT_STATUS_NO_MEMORY
;
564 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
568 status
= cli_posix_hardlink_recv(req
);
575 /****************************************************************************
576 Do a POSIX getacl - pathname based ACL get (UNIX extensions).
577 ****************************************************************************/
579 struct getacl_state
{
584 static void cli_posix_getacl_done(struct tevent_req
*subreq
);
586 struct tevent_req
*cli_posix_getacl_send(TALLOC_CTX
*mem_ctx
,
587 struct tevent_context
*ev
,
588 struct cli_state
*cli
,
591 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
592 struct getacl_state
*state
= NULL
;
594 req
= tevent_req_create(mem_ctx
, &state
, struct getacl_state
);
598 subreq
= cli_qpathinfo_send(state
, ev
, cli
, fname
, SMB_QUERY_POSIX_ACL
,
600 if (tevent_req_nomem(subreq
, req
)) {
601 return tevent_req_post(req
, ev
);
603 tevent_req_set_callback(subreq
, cli_posix_getacl_done
, req
);
607 static void cli_posix_getacl_done(struct tevent_req
*subreq
)
609 struct tevent_req
*req
= tevent_req_callback_data(
610 subreq
, struct tevent_req
);
611 struct getacl_state
*state
= tevent_req_data(
612 req
, struct getacl_state
);
615 status
= cli_qpathinfo_recv(subreq
, state
, &state
->data
,
618 if (tevent_req_nterror(req
, status
)) {
621 tevent_req_done(req
);
624 NTSTATUS
cli_posix_getacl_recv(struct tevent_req
*req
,
629 struct getacl_state
*state
= tevent_req_data(req
, struct getacl_state
);
632 if (tevent_req_is_nterror(req
, &status
)) {
635 *prb_size
= (size_t)state
->num_data
;
636 *retbuf
= (char *)talloc_move(mem_ctx
, &state
->data
);
640 NTSTATUS
cli_posix_getacl(struct cli_state
*cli
,
646 TALLOC_CTX
*frame
= talloc_stackframe();
647 struct tevent_context
*ev
= NULL
;
648 struct tevent_req
*req
= NULL
;
649 NTSTATUS status
= NT_STATUS_OK
;
651 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
653 * Can't use sync call while an async call is in flight
655 status
= NT_STATUS_INVALID_PARAMETER
;
659 ev
= samba_tevent_context_init(frame
);
661 status
= NT_STATUS_NO_MEMORY
;
665 req
= cli_posix_getacl_send(frame
,
670 status
= NT_STATUS_NO_MEMORY
;
674 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
678 status
= cli_posix_getacl_recv(req
, mem_ctx
, prb_size
, retbuf
);
685 /****************************************************************************
686 Do a POSIX setacl - pathname based ACL set (UNIX extensions).
687 ****************************************************************************/
689 struct setacl_state
{
693 static void cli_posix_setacl_done(struct tevent_req
*subreq
);
695 struct tevent_req
*cli_posix_setacl_send(TALLOC_CTX
*mem_ctx
,
696 struct tevent_context
*ev
,
697 struct cli_state
*cli
,
702 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
703 struct setacl_state
*state
= NULL
;
705 req
= tevent_req_create(mem_ctx
, &state
, struct setacl_state
);
709 state
->data
= talloc_memdup(state
, data
, num_data
);
710 if (tevent_req_nomem(state
->data
, req
)) {
711 return tevent_req_post(req
, ev
);
714 subreq
= cli_setpathinfo_send(state
,
721 if (tevent_req_nomem(subreq
, req
)) {
722 return tevent_req_post(req
, ev
);
724 tevent_req_set_callback(subreq
, cli_posix_setacl_done
, req
);
728 static void cli_posix_setacl_done(struct tevent_req
*subreq
)
730 NTSTATUS status
= cli_setpathinfo_recv(subreq
);
731 tevent_req_simple_finish_ntstatus(subreq
, status
);
734 NTSTATUS
cli_posix_setacl_recv(struct tevent_req
*req
)
736 return tevent_req_simple_recv_ntstatus(req
);
739 NTSTATUS
cli_posix_setacl(struct cli_state
*cli
,
744 TALLOC_CTX
*frame
= talloc_stackframe();
745 struct tevent_context
*ev
= NULL
;
746 struct tevent_req
*req
= NULL
;
747 NTSTATUS status
= NT_STATUS_OK
;
749 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
751 * Can't use sync call while an async call is in flight
753 status
= NT_STATUS_INVALID_PARAMETER
;
757 ev
= samba_tevent_context_init(frame
);
759 status
= NT_STATUS_NO_MEMORY
;
763 req
= cli_posix_setacl_send(frame
,
770 status
= NT_STATUS_NO_MEMORY
;
774 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
778 status
= cli_posix_setacl_recv(req
);
785 /****************************************************************************
786 Stat a file (UNIX extensions).
787 ****************************************************************************/
789 struct cli_posix_stat_state
{
793 static void cli_posix_stat_done(struct tevent_req
*subreq
);
795 struct tevent_req
*cli_posix_stat_send(TALLOC_CTX
*mem_ctx
,
796 struct tevent_context
*ev
,
797 struct cli_state
*cli
,
800 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
801 struct stat_state
*state
= NULL
;
803 req
= tevent_req_create(mem_ctx
, &state
, struct cli_posix_stat_state
);
808 subreq
= cli_qpathinfo_send(state
, ev
, cli
, fname
,
809 SMB_QUERY_FILE_UNIX_BASIC
, 100, 100);
810 if (tevent_req_nomem(subreq
, req
)) {
811 return tevent_req_post(req
, ev
);
813 tevent_req_set_callback(subreq
, cli_posix_stat_done
, req
);
817 static void cli_posix_stat_done(struct tevent_req
*subreq
)
819 struct tevent_req
*req
= tevent_req_callback_data(
820 subreq
, struct tevent_req
);
821 struct cli_posix_stat_state
*state
= tevent_req_data(
822 req
, struct cli_posix_stat_state
);
823 SMB_STRUCT_STAT
*sbuf
= &state
->sbuf
;
825 uint32_t num_data
= 0;
828 status
= cli_qpathinfo_recv(subreq
, state
, &data
, &num_data
);
830 if (tevent_req_nterror(req
, status
)) {
834 if (num_data
!= 100) {
836 * Paranoia, cli_qpathinfo should have guaranteed
837 * this, but you never know...
839 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
843 /* total size, in bytes */
844 sbuf
->st_ex_size
= BVAL(data
, 0);
846 /* number of blocks allocated */
847 sbuf
->st_ex_blocks
= BVAL(data
,8);
848 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
849 sbuf
->st_ex_blocks
/= STAT_ST_BLOCKSIZE
;
851 /* assume 512 byte blocks */
852 sbuf
->st_ex_blocks
/= 512;
854 /* time of last change */
855 sbuf
->st_ex_ctime
= interpret_long_date(BVAL(data
, 16));
857 /* time of last access */
858 sbuf
->st_ex_atime
= interpret_long_date(BVAL(data
, 24));
860 /* time of last modification */
861 sbuf
->st_ex_mtime
= interpret_long_date(BVAL(data
, 32));
863 sbuf
->st_ex_uid
= (uid_t
) IVAL(data
, 40); /* user ID of owner */
864 sbuf
->st_ex_gid
= (gid_t
) IVAL(data
, 48); /* group ID of owner */
865 sbuf
->st_ex_mode
= wire_filetype_to_unix(IVAL(data
, 56));
867 #if defined(HAVE_MAKEDEV)
869 uint32_t dev_major
= IVAL(data
,60);
870 uint32_t dev_minor
= IVAL(data
,68);
871 sbuf
->st_ex_rdev
= makedev(dev_major
, dev_minor
);
875 sbuf
->st_ex_ino
= (SMB_INO_T
)BVAL(data
, 76);
878 sbuf
->st_ex_mode
|= wire_perms_to_unix(IVAL(data
, 84));
880 /* number of hard links */
881 sbuf
->st_ex_nlink
= BIG_UINT(data
, 92);
883 tevent_req_done(req
);
886 NTSTATUS
cli_posix_stat_recv(struct tevent_req
*req
, struct stat_ex
*sbuf
)
888 struct cli_posix_stat_state
*state
= tevent_req_data(
889 req
, struct cli_posix_stat_state
);
892 if (tevent_req_is_nterror(req
, &status
)) {
899 NTSTATUS
cli_posix_stat(struct cli_state
*cli
,
901 struct stat_ex
*sbuf
)
903 TALLOC_CTX
*frame
= talloc_stackframe();
904 struct tevent_context
*ev
= NULL
;
905 struct tevent_req
*req
= NULL
;
906 NTSTATUS status
= NT_STATUS_OK
;
908 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
910 * Can't use sync call while an async call is in flight
912 status
= NT_STATUS_INVALID_PARAMETER
;
916 ev
= samba_tevent_context_init(frame
);
918 status
= NT_STATUS_NO_MEMORY
;
922 req
= cli_posix_stat_send(frame
, ev
, cli
, fname
);
924 status
= NT_STATUS_NO_MEMORY
;
928 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
932 status
= cli_posix_stat_recv(req
, sbuf
);
939 /****************************************************************************
940 Chmod or chown a file internal (UNIX extensions).
941 ****************************************************************************/
943 struct cli_posix_chown_chmod_internal_state
{
947 static void cli_posix_chown_chmod_internal_done(struct tevent_req
*subreq
);
949 static struct tevent_req
*cli_posix_chown_chmod_internal_send(TALLOC_CTX
*mem_ctx
,
950 struct tevent_context
*ev
,
951 struct cli_state
*cli
,
957 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
958 struct cli_posix_chown_chmod_internal_state
*state
= NULL
;
960 req
= tevent_req_create(mem_ctx
, &state
,
961 struct cli_posix_chown_chmod_internal_state
);
966 memset(state
->data
, 0xff, 40); /* Set all sizes/times to no change. */
967 SIVAL(state
->data
,40,uid
);
968 SIVAL(state
->data
,48,gid
);
969 SIVAL(state
->data
,84,mode
);
971 subreq
= cli_setpathinfo_send(state
, ev
, cli
, SMB_SET_FILE_UNIX_BASIC
,
972 fname
, state
->data
, sizeof(state
->data
));
973 if (tevent_req_nomem(subreq
, req
)) {
974 return tevent_req_post(req
, ev
);
976 tevent_req_set_callback(subreq
, cli_posix_chown_chmod_internal_done
,
981 static void cli_posix_chown_chmod_internal_done(struct tevent_req
*subreq
)
983 NTSTATUS status
= cli_setpathinfo_recv(subreq
);
984 tevent_req_simple_finish_ntstatus(subreq
, status
);
987 static NTSTATUS
cli_posix_chown_chmod_internal_recv(struct tevent_req
*req
)
989 return tevent_req_simple_recv_ntstatus(req
);
992 struct cli_fchmod_state
{
993 uint8_t data
[100]; /* smb1 posix extensions */
996 static void cli_fchmod_done1(struct tevent_req
*subreq
);
997 static void cli_fchmod_done2(struct tevent_req
*subreq
);
999 struct tevent_req
*cli_fchmod_send(TALLOC_CTX
*mem_ctx
,
1000 struct tevent_context
*ev
,
1001 struct cli_state
*cli
,
1005 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1006 struct cli_fchmod_state
*state
= NULL
;
1007 const enum protocol_types proto
= smbXcli_conn_protocol(cli
->conn
);
1009 req
= tevent_req_create(mem_ctx
, &state
, struct cli_fchmod_state
);
1014 if ((proto
< PROTOCOL_SMB2_02
) && SERVER_HAS_UNIX_CIFS(cli
)) {
1017 40); /* Set all sizes/times to no change. */
1018 PUSH_LE_U32(state
->data
, 40, SMB_UID_NO_CHANGE
);
1019 PUSH_LE_U32(state
->data
, 48, SMB_GID_NO_CHANGE
);
1020 PUSH_LE_U32(state
->data
, 84, mode
);
1022 subreq
= cli_setfileinfo_send(state
,
1026 SMB_SET_FILE_UNIX_BASIC
,
1028 sizeof(state
->data
));
1029 if (tevent_req_nomem(subreq
, req
)) {
1030 return tevent_req_post(req
, ev
);
1032 tevent_req_set_callback(subreq
, cli_fchmod_done1
, req
);
1036 if ((proto
>= PROTOCOL_SMB3_11
) && cli_smb2_fnum_is_posix(cli
, fnum
)) {
1037 struct security_ace ace
= {
1038 .type
= SEC_ACE_TYPE_ACCESS_ALLOWED
,
1039 .trustee
= global_sid_Unix_NFS_Mode
,
1041 struct security_acl acl
= {
1042 .revision
= SECURITY_ACL_REVISION_NT4
,
1046 struct security_descriptor
*sd
= NULL
;
1048 sid_append_rid(&ace
.trustee
, mode
);
1050 sd
= make_sec_desc(state
,
1051 SECURITY_DESCRIPTOR_REVISION_1
,
1052 SEC_DESC_SELF_RELATIVE
|
1053 SEC_DESC_DACL_PRESENT
,
1059 if (tevent_req_nomem(sd
, req
)) {
1060 return tevent_req_post(req
, ev
);
1063 subreq
= cli_set_security_descriptor_send(
1064 state
, ev
, cli
, fnum
, SECINFO_DACL
, sd
);
1065 if (tevent_req_nomem(subreq
, req
)) {
1066 return tevent_req_post(req
, ev
);
1068 tevent_req_set_callback(subreq
, cli_fchmod_done2
, req
);
1072 tevent_req_nterror(req
, NT_STATUS_INVALID_LEVEL
);
1073 return tevent_req_post(req
, ev
);
1076 static void cli_fchmod_done1(struct tevent_req
*subreq
)
1078 NTSTATUS status
= cli_setfileinfo_recv(subreq
);
1079 tevent_req_simple_finish_ntstatus(subreq
, status
);
1082 static void cli_fchmod_done2(struct tevent_req
*subreq
)
1084 NTSTATUS status
= cli_set_security_descriptor_recv(subreq
);
1085 tevent_req_simple_finish_ntstatus(subreq
, status
);
1088 NTSTATUS
cli_fchmod_recv(struct tevent_req
*req
)
1090 return tevent_req_simple_recv_ntstatus(req
);
1093 struct cli_chmod_state
{
1094 struct tevent_context
*ev
;
1095 struct cli_state
*cli
;
1100 NTSTATUS fchmod_status
;
1102 uint8_t data
[100]; /* smb1 posix extensions */
1105 static void cli_chmod_opened(struct tevent_req
*subreq
);
1106 static void cli_chmod_done(struct tevent_req
*subreq
);
1107 static void cli_chmod_closed(struct tevent_req
*subreq
);
1109 struct tevent_req
*cli_chmod_send(TALLOC_CTX
*mem_ctx
,
1110 struct tevent_context
*ev
,
1111 struct cli_state
*cli
,
1115 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1116 struct cli_chmod_state
*state
= NULL
;
1118 req
= tevent_req_create(mem_ctx
, &state
, struct cli_chmod_state
);
1126 subreq
= cli_ntcreate_send(
1127 state
, /* mem_ctx */
1131 0, /* create_flags */
1132 SEC_STD_WRITE_DAC
, /* desired_access */
1133 0, /* file_attributes */
1134 FILE_SHARE_READ
| FILE_SHARE_WRITE
, /* share_access */
1135 FILE_OPEN
, /* create_disposition */
1136 0x0, /* create_options */
1137 SMB2_IMPERSONATION_IMPERSONATION
, /* impersonation_level */
1138 0x0); /* SecurityFlags */
1139 if (tevent_req_nomem(subreq
, req
)) {
1140 return tevent_req_post(req
, ev
);
1142 tevent_req_set_callback(subreq
, cli_chmod_opened
, req
);
1146 static void cli_chmod_opened(struct tevent_req
*subreq
)
1148 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1150 struct cli_chmod_state
*state
= tevent_req_data(
1151 req
, struct cli_chmod_state
);
1154 status
= cli_ntcreate_recv(subreq
, &state
->fnum
, NULL
);
1155 TALLOC_FREE(subreq
);
1156 if (tevent_req_nterror(req
, status
)) {
1160 subreq
= cli_fchmod_send(
1161 state
, state
->ev
, state
->cli
, state
->fnum
, state
->mode
);
1162 if (tevent_req_nomem(subreq
, req
)) {
1165 tevent_req_set_callback(subreq
, cli_chmod_done
, req
);
1168 static void cli_chmod_done(struct tevent_req
*subreq
)
1170 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1172 struct cli_chmod_state
*state
= tevent_req_data(
1173 req
, struct cli_chmod_state
);
1175 state
->fchmod_status
= cli_fchmod_recv(subreq
);
1176 TALLOC_FREE(subreq
);
1178 subreq
= cli_close_send(state
, state
->ev
, state
->cli
, state
->fnum
, 0);
1179 if (tevent_req_nomem(subreq
, req
)) {
1182 tevent_req_set_callback(subreq
, cli_chmod_closed
, req
);
1185 static void cli_chmod_closed(struct tevent_req
*subreq
)
1187 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1191 status
= cli_close_recv(subreq
);
1192 TALLOC_FREE(subreq
);
1193 if (tevent_req_nterror(req
, status
)) {
1196 tevent_req_done(req
);
1199 NTSTATUS
cli_chmod_recv(struct tevent_req
*req
)
1201 struct cli_chmod_state
*state
= tevent_req_data(
1202 req
, struct cli_chmod_state
);
1205 if (tevent_req_is_nterror(req
, &status
)) {
1206 tevent_req_received(req
);
1209 tevent_req_received(req
);
1210 return state
->fchmod_status
;
1213 NTSTATUS
cli_chmod(struct cli_state
*cli
, const char *fname
, mode_t mode
)
1215 TALLOC_CTX
*frame
= talloc_stackframe();
1216 struct tevent_context
*ev
= NULL
;
1217 struct tevent_req
*req
= NULL
;
1218 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1220 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1222 * Can't use sync call while an async call is in flight
1224 status
= NT_STATUS_INVALID_PARAMETER
;
1227 ev
= samba_tevent_context_init(frame
);
1231 req
= cli_chmod_send(frame
, ev
, cli
, fname
, mode
);
1235 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1238 status
= cli_chmod_recv(req
);
1244 /****************************************************************************
1245 chown a file (UNIX extensions).
1246 ****************************************************************************/
1248 struct cli_posix_chown_state
{
1252 static void cli_posix_chown_done(struct tevent_req
*subreq
);
1254 struct tevent_req
*cli_posix_chown_send(TALLOC_CTX
*mem_ctx
,
1255 struct tevent_context
*ev
,
1256 struct cli_state
*cli
,
1261 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1262 struct cli_posix_chown_state
*state
= NULL
;
1264 req
= tevent_req_create(
1265 mem_ctx
, &state
, struct cli_posix_chown_state
);
1270 subreq
= cli_posix_chown_chmod_internal_send(
1278 if (tevent_req_nomem(subreq
, req
)) {
1279 return tevent_req_post(req
, ev
);
1281 tevent_req_set_callback(subreq
, cli_posix_chown_done
, req
);
1285 static void cli_posix_chown_done(struct tevent_req
*subreq
)
1287 NTSTATUS status
= cli_posix_chown_chmod_internal_recv(subreq
);
1288 tevent_req_simple_finish_ntstatus(subreq
, status
);
1291 NTSTATUS
cli_posix_chown_recv(struct tevent_req
*req
)
1293 return tevent_req_simple_recv_ntstatus(req
);
1296 NTSTATUS
cli_posix_chown(struct cli_state
*cli
,
1301 TALLOC_CTX
*frame
= talloc_stackframe();
1302 struct tevent_context
*ev
= NULL
;
1303 struct tevent_req
*req
= NULL
;
1304 NTSTATUS status
= NT_STATUS_OK
;
1306 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1308 * Can't use sync call while an async call is in flight
1310 status
= NT_STATUS_INVALID_PARAMETER
;
1314 ev
= samba_tevent_context_init(frame
);
1316 status
= NT_STATUS_NO_MEMORY
;
1320 req
= cli_posix_chown_send(frame
,
1327 status
= NT_STATUS_NO_MEMORY
;
1331 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1335 status
= cli_posix_chown_recv(req
);
1342 struct cli_smb1_posix_mknod_state
{
1346 static void cli_smb1_posix_mknod_done(struct tevent_req
*subreq
);
1348 static struct tevent_req
*cli_smb1_posix_mknod_send(
1349 TALLOC_CTX
*mem_ctx
,
1350 struct tevent_context
*ev
,
1351 struct cli_state
*cli
,
1356 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1357 struct cli_smb1_posix_mknod_state
*state
= NULL
;
1358 mode_t type
= mode
& S_IFMT
;
1359 uint32_t smb_unix_type
= 0xFFFFFFFF;
1361 req
= tevent_req_create(
1362 mem_ctx
, &state
, struct cli_smb1_posix_mknod_state
);
1367 * Set all sizes/times/ids to no change.
1369 memset(state
->data
, 0xff, 56);
1373 smb_unix_type
= UNIX_TYPE_FILE
;
1376 smb_unix_type
= UNIX_TYPE_DIR
;
1379 smb_unix_type
= UNIX_TYPE_SYMLINK
;
1382 smb_unix_type
= UNIX_TYPE_CHARDEV
;
1385 smb_unix_type
= UNIX_TYPE_BLKDEV
;
1388 smb_unix_type
= UNIX_TYPE_FIFO
;
1391 smb_unix_type
= UNIX_TYPE_SOCKET
;
1394 PUSH_LE_U32(state
->data
, 56, smb_unix_type
);
1396 if ((type
== S_IFCHR
) || (type
== S_IFBLK
)) {
1397 PUSH_LE_U64(state
->data
, 60, unix_dev_major(dev
));
1398 PUSH_LE_U64(state
->data
, 68, unix_dev_minor(dev
));
1401 PUSH_LE_U32(state
->data
, 84, unix_perms_to_wire(mode
));
1403 subreq
= cli_setpathinfo_send(
1407 SMB_SET_FILE_UNIX_BASIC
,
1410 sizeof(state
->data
));
1411 if (tevent_req_nomem(subreq
, req
)) {
1412 return tevent_req_post(req
, ev
);
1414 tevent_req_set_callback(subreq
, cli_smb1_posix_mknod_done
, req
);
1418 static void cli_smb1_posix_mknod_done(struct tevent_req
*subreq
)
1420 NTSTATUS status
= cli_setpathinfo_recv(subreq
);
1421 tevent_req_simple_finish_ntstatus(subreq
, status
);
1424 static NTSTATUS
cli_smb1_posix_mknod_recv(struct tevent_req
*req
)
1426 return tevent_req_simple_recv_ntstatus(req
);
1429 struct cli_mknod_state
{
1433 static void cli_mknod_done1(struct tevent_req
*subreq
);
1434 static void cli_mknod_reparse_done(struct tevent_req
*subreq
);
1436 struct tevent_req
*cli_mknod_send(
1437 TALLOC_CTX
*mem_ctx
,
1438 struct tevent_context
*ev
,
1439 struct cli_state
*cli
,
1444 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1445 struct cli_mknod_state
*state
= NULL
;
1446 struct reparse_data_buffer reparse_buf
= {
1447 .tag
= IO_REPARSE_TAG_NFS
,
1449 struct nfs_reparse_data_buffer
*nfs
= &reparse_buf
.parsed
.nfs
;
1452 req
= tevent_req_create(mem_ctx
, &state
, struct cli_mknod_state
);
1457 if (cli
->requested_posix_capabilities
!= 0) {
1458 subreq
= cli_smb1_posix_mknod_send(
1459 state
, ev
, cli
, fname
, mode
, dev
);
1460 if (tevent_req_nomem(subreq
, req
)) {
1461 return tevent_req_post(req
, ev
);
1463 tevent_req_set_callback(subreq
, cli_mknod_done1
, req
);
1468 * Ignored for all but BLK and CHR
1470 nfs
->data
.dev
.major
= major(dev
);
1471 nfs
->data
.dev
.minor
= minor(dev
);
1473 switch (mode
& S_IFMT
) {
1475 nfs
->type
= NFS_SPECFILE_FIFO
;
1478 nfs
->type
= NFS_SPECFILE_SOCK
;
1481 nfs
->type
= NFS_SPECFILE_CHR
;
1484 nfs
->type
= NFS_SPECFILE_BLK
;
1488 buflen
= reparse_data_buffer_marshall(&reparse_buf
,
1490 sizeof(state
->buf
));
1491 if ((buflen
== -1) || (buflen
> sizeof(state
->buf
))) {
1492 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
1493 return tevent_req_post(req
, ev
);
1496 subreq
= cli_create_reparse_point_send(state
,
1504 if (tevent_req_nomem(subreq
, req
)) {
1505 return tevent_req_post(req
, ev
);
1507 tevent_req_set_callback(subreq
, cli_mknod_reparse_done
, req
);
1511 static void cli_mknod_done1(struct tevent_req
*subreq
)
1513 NTSTATUS status
= cli_smb1_posix_mknod_recv(subreq
);
1514 tevent_req_simple_finish_ntstatus(subreq
, status
);
1517 static void cli_mknod_reparse_done(struct tevent_req
*subreq
)
1519 NTSTATUS status
= cli_create_reparse_point_recv(subreq
);
1520 tevent_req_simple_finish_ntstatus(subreq
, status
);
1523 NTSTATUS
cli_mknod_recv(struct tevent_req
*req
)
1525 return tevent_req_simple_recv_ntstatus(req
);
1529 cli_mknod(struct cli_state
*cli
, const char *fname
, mode_t mode
, dev_t dev
)
1531 TALLOC_CTX
*frame
= talloc_stackframe();
1532 struct tevent_context
*ev
;
1533 struct tevent_req
*req
;
1534 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1536 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1538 * Can't use sync call while an async call is in flight
1540 status
= NT_STATUS_INVALID_PARAMETER
;
1543 ev
= samba_tevent_context_init(frame
);
1547 req
= cli_mknod_send(ev
, ev
, cli
, fname
, mode
, dev
);
1551 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1554 status
= cli_mknod_recv(req
);
1560 /****************************************************************************
1562 ****************************************************************************/
1564 struct cli_smb1_rename_state
{
1568 static void cli_smb1_rename_done(struct tevent_req
*subreq
);
1570 static struct tevent_req
*cli_smb1_rename_send(TALLOC_CTX
*mem_ctx
,
1571 struct tevent_context
*ev
,
1572 struct cli_state
*cli
,
1573 const char *fname_src
,
1574 const char *fname_dst
,
1578 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1579 struct cli_smb1_rename_state
*state
= NULL
;
1580 smb_ucs2_t
*converted_str
= NULL
;
1581 size_t converted_size_bytes
= 0;
1583 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb1_rename_state
);
1589 * Strip a MSDFS path from fname_dst if we were given one.
1591 status
= cli_dfs_target_check(state
,
1595 if (!NT_STATUS_IS_OK(status
)) {
1599 if (!push_ucs2_talloc(talloc_tos(), &converted_str
, fname_dst
,
1600 &converted_size_bytes
)) {
1601 status
= NT_STATUS_INVALID_PARAMETER
;
1605 /* W2K8 insists the dest name is not null
1606 terminated. Remove the last 2 zero bytes
1607 and reduce the name length. */
1609 if (converted_size_bytes
< 2) {
1610 status
= NT_STATUS_INVALID_PARAMETER
;
1613 converted_size_bytes
-= 2;
1616 talloc_zero_array(state
, uint8_t, 12 + converted_size_bytes
);
1617 if (state
->data
== NULL
) {
1618 status
= NT_STATUS_NO_MEMORY
;
1623 SCVAL(state
->data
, 0, 1);
1626 SIVAL(state
->data
, 8, converted_size_bytes
);
1627 memcpy(state
->data
+ 12, converted_str
, converted_size_bytes
);
1629 TALLOC_FREE(converted_str
);
1631 subreq
= cli_setpathinfo_send(
1632 state
, ev
, cli
, SMB_FILE_RENAME_INFORMATION
, fname_src
, state
->data
,
1633 talloc_get_size(state
->data
));
1634 if (tevent_req_nomem(subreq
, req
)) {
1635 status
= NT_STATUS_NO_MEMORY
;
1638 tevent_req_set_callback(subreq
, cli_smb1_rename_done
, req
);
1642 TALLOC_FREE(converted_str
);
1643 tevent_req_nterror(req
, status
);
1644 return tevent_req_post(req
, ev
);
1647 static void cli_smb1_rename_done(struct tevent_req
*subreq
)
1649 NTSTATUS status
= cli_setpathinfo_recv(subreq
);
1650 tevent_req_simple_finish_ntstatus(subreq
, status
);
1653 static NTSTATUS
cli_smb1_rename_recv(struct tevent_req
*req
)
1655 return tevent_req_simple_recv_ntstatus(req
);
1658 static void cli_cifs_rename_done(struct tevent_req
*subreq
);
1660 struct cli_cifs_rename_state
{
1664 static struct tevent_req
*cli_cifs_rename_send(TALLOC_CTX
*mem_ctx
,
1665 struct tevent_context
*ev
,
1666 struct cli_state
*cli
,
1667 const char *fname_src
,
1668 const char *fname_dst
,
1671 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1672 struct cli_cifs_rename_state
*state
= NULL
;
1673 uint8_t additional_flags
= 0;
1674 uint16_t additional_flags2
= 0;
1675 uint8_t *bytes
= NULL
;
1676 char *fname_src_cp
= NULL
;
1677 char *fname_dst_cp
= NULL
;
1679 req
= tevent_req_create(mem_ctx
, &state
, struct cli_cifs_rename_state
);
1686 * CIFS doesn't support replace
1688 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1689 return tevent_req_post(req
, ev
);
1692 SSVAL(state
->vwv
+0, 0, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_DIRECTORY
);
1694 bytes
= talloc_array(state
, uint8_t, 1);
1695 if (tevent_req_nomem(bytes
, req
)) {
1696 return tevent_req_post(req
, ev
);
1700 * SMBmv on a DFS share uses DFS names for src and dst.
1701 * See smbtorture3: SMB1-DFS-PATHS: test_smb1_mv().
1704 fname_src_cp
= smb1_dfs_share_path(state
, cli
, fname_src
);
1705 if (tevent_req_nomem(fname_src_cp
, req
)) {
1706 return tevent_req_post(req
, ev
);
1709 bytes
= smb_bytes_push_str(bytes
,
1710 smbXcli_conn_use_unicode(cli
->conn
),
1712 strlen(fname_src_cp
)+1,
1714 if (tevent_req_nomem(bytes
, req
)) {
1715 return tevent_req_post(req
, ev
);
1718 if (clistr_is_previous_version_path(fname_src
)) {
1719 additional_flags2
= FLAGS2_REPARSE_PATH
;
1722 bytes
= talloc_realloc(state
, bytes
, uint8_t,
1723 talloc_get_size(bytes
)+1);
1724 if (tevent_req_nomem(bytes
, req
)) {
1725 return tevent_req_post(req
, ev
);
1729 * SMBmv on a DFS share uses DFS names for src and dst.
1730 * See smbtorture3: SMB1-DFS-PATHS: test_smb1_mv().
1733 fname_dst_cp
= smb1_dfs_share_path(state
, cli
, fname_dst
);
1734 if (tevent_req_nomem(fname_dst_cp
, req
)) {
1735 return tevent_req_post(req
, ev
);
1737 bytes
[talloc_get_size(bytes
)-1] = 4;
1738 bytes
= smb_bytes_push_str(bytes
,
1739 smbXcli_conn_use_unicode(cli
->conn
),
1741 strlen(fname_dst_cp
)+1,
1743 if (tevent_req_nomem(bytes
, req
)) {
1744 return tevent_req_post(req
, ev
);
1747 subreq
= cli_smb_send(state
, ev
, cli
, SMBmv
, additional_flags
,
1749 1, state
->vwv
, talloc_get_size(bytes
), bytes
);
1750 if (tevent_req_nomem(subreq
, req
)) {
1751 return tevent_req_post(req
, ev
);
1753 tevent_req_set_callback(subreq
, cli_cifs_rename_done
, req
);
1757 static void cli_cifs_rename_done(struct tevent_req
*subreq
)
1759 NTSTATUS status
= cli_smb_recv(
1760 subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
1761 tevent_req_simple_finish_ntstatus(subreq
, status
);
1764 static NTSTATUS
cli_cifs_rename_recv(struct tevent_req
*req
)
1766 return tevent_req_simple_recv_ntstatus(req
);
1769 struct cli_rename_state
{
1773 static void cli_rename_done1(struct tevent_req
*subreq
);
1774 static void cli_rename_done_cifs(struct tevent_req
*subreq
);
1775 static void cli_rename_done2(struct tevent_req
*subreq
);
1777 struct tevent_req
*cli_rename_send(TALLOC_CTX
*mem_ctx
,
1778 struct tevent_context
*ev
,
1779 struct cli_state
*cli
,
1780 const char *fname_src
,
1781 const char *fname_dst
,
1784 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1785 struct cli_rename_state
*state
= NULL
;
1787 req
= tevent_req_create(mem_ctx
, &state
, struct cli_rename_state
);
1792 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
1793 subreq
= cli_smb2_rename_send(
1794 state
, ev
, cli
, fname_src
, fname_dst
, replace
);
1795 if (tevent_req_nomem(subreq
, req
)) {
1796 return tevent_req_post(req
, ev
);
1798 tevent_req_set_callback(subreq
, cli_rename_done2
, req
);
1802 if (replace
&& smbXcli_conn_support_passthrough(cli
->conn
)) {
1803 subreq
= cli_smb1_rename_send(
1804 state
, ev
, cli
, fname_src
, fname_dst
, replace
);
1805 if (tevent_req_nomem(subreq
, req
)) {
1806 return tevent_req_post(req
, ev
);
1808 tevent_req_set_callback(subreq
, cli_rename_done1
, req
);
1812 subreq
= cli_cifs_rename_send(
1813 state
, ev
, cli
, fname_src
,fname_dst
, replace
);
1814 if (tevent_req_nomem(subreq
, req
)) {
1815 return tevent_req_post(req
, ev
);
1817 tevent_req_set_callback(subreq
, cli_rename_done_cifs
, req
);
1821 static void cli_rename_done1(struct tevent_req
*subreq
)
1823 NTSTATUS status
= cli_smb1_rename_recv(subreq
);
1824 tevent_req_simple_finish_ntstatus(subreq
, status
);
1827 static void cli_rename_done_cifs(struct tevent_req
*subreq
)
1829 NTSTATUS status
= cli_cifs_rename_recv(subreq
);
1830 tevent_req_simple_finish_ntstatus(subreq
, status
);
1833 static void cli_rename_done2(struct tevent_req
*subreq
)
1835 NTSTATUS status
= cli_smb2_rename_recv(subreq
);
1836 tevent_req_simple_finish_ntstatus(subreq
, status
);
1839 NTSTATUS
cli_rename_recv(struct tevent_req
*req
)
1841 return tevent_req_simple_recv_ntstatus(req
);
1844 NTSTATUS
cli_rename(struct cli_state
*cli
,
1845 const char *fname_src
,
1846 const char *fname_dst
,
1849 TALLOC_CTX
*frame
= NULL
;
1850 struct tevent_context
*ev
;
1851 struct tevent_req
*req
;
1852 NTSTATUS status
= NT_STATUS_OK
;
1854 frame
= talloc_stackframe();
1856 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1858 * Can't use sync call while an async call is in flight
1860 status
= NT_STATUS_INVALID_PARAMETER
;
1864 ev
= samba_tevent_context_init(frame
);
1866 status
= NT_STATUS_NO_MEMORY
;
1870 req
= cli_rename_send(frame
, ev
, cli
, fname_src
, fname_dst
, replace
);
1872 status
= NT_STATUS_NO_MEMORY
;
1876 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1880 status
= cli_rename_recv(req
);
1886 /****************************************************************************
1888 ****************************************************************************/
1890 static void cli_ntrename_internal_done(struct tevent_req
*subreq
);
1892 struct cli_ntrename_internal_state
{
1896 static struct tevent_req
*cli_ntrename_internal_send(TALLOC_CTX
*mem_ctx
,
1897 struct tevent_context
*ev
,
1898 struct cli_state
*cli
,
1899 const char *fname_src
,
1900 const char *fname_dst
,
1901 uint16_t rename_flag
)
1903 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
1904 struct cli_ntrename_internal_state
*state
= NULL
;
1905 uint8_t additional_flags
= 0;
1906 uint16_t additional_flags2
= 0;
1907 uint8_t *bytes
= NULL
;
1908 char *fname_src_cp
= NULL
;
1909 char *fname_dst_cp
= NULL
;
1911 req
= tevent_req_create(mem_ctx
, &state
,
1912 struct cli_ntrename_internal_state
);
1917 SSVAL(state
->vwv
+0, 0 ,FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_DIRECTORY
);
1918 SSVAL(state
->vwv
+1, 0, rename_flag
);
1920 bytes
= talloc_array(state
, uint8_t, 1);
1921 if (tevent_req_nomem(bytes
, req
)) {
1922 return tevent_req_post(req
, ev
);
1925 * SMBntrename on a DFS share uses DFS names for src and dst.
1926 * See smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_rename().
1928 fname_src_cp
= smb1_dfs_share_path(state
, cli
, fname_src
);
1929 if (tevent_req_nomem(fname_src_cp
, req
)) {
1930 return tevent_req_post(req
, ev
);
1933 bytes
= smb_bytes_push_str(bytes
,
1934 smbXcli_conn_use_unicode(cli
->conn
),
1936 strlen(fname_src_cp
)+1,
1938 if (tevent_req_nomem(bytes
, req
)) {
1939 return tevent_req_post(req
, ev
);
1942 if (clistr_is_previous_version_path(fname_src
)) {
1943 additional_flags2
= FLAGS2_REPARSE_PATH
;
1946 bytes
= talloc_realloc(state
, bytes
, uint8_t,
1947 talloc_get_size(bytes
)+1);
1948 if (tevent_req_nomem(bytes
, req
)) {
1949 return tevent_req_post(req
, ev
);
1953 * SMBntrename on a DFS share uses DFS names for src and dst.
1954 * See smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_rename().
1955 * and smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_hardlink()
1957 fname_dst_cp
= smb1_dfs_share_path(state
, cli
, fname_dst
);
1958 if (tevent_req_nomem(fname_dst_cp
, req
)) {
1959 return tevent_req_post(req
, ev
);
1961 bytes
[talloc_get_size(bytes
)-1] = 4;
1962 bytes
= smb_bytes_push_str(bytes
,
1963 smbXcli_conn_use_unicode(cli
->conn
),
1965 strlen(fname_dst_cp
)+1,
1967 if (tevent_req_nomem(bytes
, req
)) {
1968 return tevent_req_post(req
, ev
);
1971 subreq
= cli_smb_send(state
, ev
, cli
, SMBntrename
, additional_flags
,
1973 4, state
->vwv
, talloc_get_size(bytes
), bytes
);
1974 if (tevent_req_nomem(subreq
, req
)) {
1975 return tevent_req_post(req
, ev
);
1977 tevent_req_set_callback(subreq
, cli_ntrename_internal_done
, req
);
1981 static void cli_ntrename_internal_done(struct tevent_req
*subreq
)
1983 NTSTATUS status
= cli_smb_recv(
1984 subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
1985 tevent_req_simple_finish_ntstatus(subreq
, status
);
1988 static NTSTATUS
cli_ntrename_internal_recv(struct tevent_req
*req
)
1990 return tevent_req_simple_recv_ntstatus(req
);
1993 struct tevent_req
*cli_ntrename_send(TALLOC_CTX
*mem_ctx
,
1994 struct tevent_context
*ev
,
1995 struct cli_state
*cli
,
1996 const char *fname_src
,
1997 const char *fname_dst
)
1999 return cli_ntrename_internal_send(mem_ctx
,
2004 RENAME_FLAG_RENAME
);
2007 NTSTATUS
cli_ntrename_recv(struct tevent_req
*req
)
2009 return cli_ntrename_internal_recv(req
);
2012 NTSTATUS
cli_ntrename(struct cli_state
*cli
, const char *fname_src
, const char *fname_dst
)
2014 TALLOC_CTX
*frame
= talloc_stackframe();
2015 struct tevent_context
*ev
;
2016 struct tevent_req
*req
;
2017 NTSTATUS status
= NT_STATUS_OK
;
2019 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2021 * Can't use sync call while an async call is in flight
2023 status
= NT_STATUS_INVALID_PARAMETER
;
2027 ev
= samba_tevent_context_init(frame
);
2029 status
= NT_STATUS_NO_MEMORY
;
2033 req
= cli_ntrename_send(frame
, ev
, cli
, fname_src
, fname_dst
);
2035 status
= NT_STATUS_NO_MEMORY
;
2039 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2043 status
= cli_ntrename_recv(req
);
2050 /****************************************************************************
2052 ****************************************************************************/
2054 static struct tevent_req
*cli_nt_hardlink_send(TALLOC_CTX
*mem_ctx
,
2055 struct tevent_context
*ev
,
2056 struct cli_state
*cli
,
2057 const char *fname_src
,
2058 const char *fname_dst
)
2060 return cli_ntrename_internal_send(mem_ctx
,
2065 RENAME_FLAG_HARD_LINK
);
2068 static NTSTATUS
cli_nt_hardlink_recv(struct tevent_req
*req
)
2070 return cli_ntrename_internal_recv(req
);
2073 struct cli_smb2_hardlink_state
{
2074 struct tevent_context
*ev
;
2075 struct cli_state
*cli
;
2077 const char *fname_dst
;
2082 static void cli_smb2_hardlink_opened(struct tevent_req
*subreq
);
2083 static void cli_smb2_hardlink_info_set(struct tevent_req
*subreq
);
2084 static void cli_smb2_hardlink_closed(struct tevent_req
*subreq
);
2086 static struct tevent_req
*cli_smb2_hardlink_send(
2087 TALLOC_CTX
*mem_ctx
,
2088 struct tevent_context
*ev
,
2089 struct cli_state
*cli
,
2090 const char *fname_src
,
2091 const char *fname_dst
,
2093 struct smb2_create_blobs
*in_cblobs
)
2095 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2096 struct cli_smb2_hardlink_state
*state
= NULL
;
2099 req
= tevent_req_create(
2100 mem_ctx
, &state
, struct cli_smb2_hardlink_state
);
2106 * Strip a MSDFS path from fname_dst if we were given one.
2108 status
= cli_dfs_target_check(state
,
2112 if (tevent_req_nterror(req
, status
)) {
2113 return tevent_req_post(req
, ev
);
2118 state
->fname_dst
= fname_dst
;
2119 state
->overwrite
= overwrite
;
2121 subreq
= cli_smb2_create_fnum_send(
2126 (struct cli_smb2_create_flags
){0},
2127 SMB2_IMPERSONATION_IMPERSONATION
,
2128 FILE_WRITE_ATTRIBUTES
,
2129 0, /* file attributes */
2132 FILE_SHARE_DELETE
, /* share_access */
2133 FILE_OPEN
, /* create_disposition */
2134 FILE_NON_DIRECTORY_FILE
, /* no hardlinks on directories */
2136 if (tevent_req_nomem(subreq
, req
)) {
2137 return tevent_req_post(req
, ev
);
2139 tevent_req_set_callback(subreq
, cli_smb2_hardlink_opened
, req
);
2143 static void cli_smb2_hardlink_opened(struct tevent_req
*subreq
)
2145 struct tevent_req
*req
= tevent_req_callback_data(
2146 subreq
, struct tevent_req
);
2147 struct cli_smb2_hardlink_state
*state
= tevent_req_data(
2148 req
, struct cli_smb2_hardlink_state
);
2150 smb_ucs2_t
*ucs2_dst
;
2155 status
= cli_smb2_create_fnum_recv(
2156 subreq
, &state
->fnum_src
, NULL
, NULL
, NULL
, NULL
);
2157 TALLOC_FREE(subreq
);
2158 if (tevent_req_nterror(req
, status
)) {
2162 ok
= push_ucs2_talloc(state
, &ucs2_dst
, state
->fname_dst
, &ucs2_len
);
2163 if (!ok
|| (ucs2_len
< 2)) {
2164 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
2167 /* Don't 0-terminate the name */
2170 inbuf
= data_blob_talloc_zero(state
, ucs2_len
+ 20);
2171 if (tevent_req_nomem(inbuf
.data
, req
)) {
2175 if (state
->overwrite
) {
2176 SCVAL(inbuf
.data
, 0, 1);
2178 SIVAL(inbuf
.data
, 16, ucs2_len
);
2179 memcpy(inbuf
.data
+ 20, ucs2_dst
, ucs2_len
);
2180 TALLOC_FREE(ucs2_dst
);
2182 subreq
= cli_smb2_set_info_fnum_send(
2187 SMB2_0_INFO_FILE
, /* in_info_type */
2188 FSCC_FILE_LINK_INFORMATION
, /* in_file_info_class */
2190 0); /* in_additional_info */
2191 if (tevent_req_nomem(subreq
, req
)) {
2194 tevent_req_set_callback(subreq
, cli_smb2_hardlink_info_set
, req
);
2197 static void cli_smb2_hardlink_info_set(struct tevent_req
*subreq
)
2199 struct tevent_req
*req
= tevent_req_callback_data(
2200 subreq
, struct tevent_req
);
2201 struct cli_smb2_hardlink_state
*state
= tevent_req_data(
2202 req
, struct cli_smb2_hardlink_state
);
2204 state
->status
= cli_smb2_set_info_fnum_recv(subreq
);
2205 TALLOC_FREE(subreq
);
2207 /* ignore error here, we need to close the file */
2209 subreq
= cli_smb2_close_fnum_send(state
,
2214 if (tevent_req_nomem(subreq
, req
)) {
2217 tevent_req_set_callback(subreq
, cli_smb2_hardlink_closed
, req
);
2220 static void cli_smb2_hardlink_closed(struct tevent_req
*subreq
)
2222 NTSTATUS status
= cli_smb2_close_fnum_recv(subreq
);
2223 tevent_req_simple_finish_ntstatus(subreq
, status
);
2226 static NTSTATUS
cli_smb2_hardlink_recv(struct tevent_req
*req
)
2228 struct cli_smb2_hardlink_state
*state
= tevent_req_data(
2229 req
, struct cli_smb2_hardlink_state
);
2232 if (tevent_req_is_nterror(req
, &status
)) {
2235 return state
->status
;
2238 struct cli_hardlink_state
{
2242 static void cli_hardlink_done(struct tevent_req
*subreq
);
2243 static void cli_hardlink_done2(struct tevent_req
*subreq
);
2245 struct tevent_req
*cli_hardlink_send(
2246 TALLOC_CTX
*mem_ctx
,
2247 struct tevent_context
*ev
,
2248 struct cli_state
*cli
,
2249 const char *fname_src
,
2250 const char *fname_dst
)
2252 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2253 struct cli_hardlink_state
*state
;
2255 req
= tevent_req_create(mem_ctx
, &state
, struct cli_hardlink_state
);
2260 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
2261 subreq
= cli_smb2_hardlink_send(
2262 state
, ev
, cli
, fname_src
, fname_dst
, false, NULL
);
2263 if (tevent_req_nomem(subreq
, req
)) {
2264 return tevent_req_post(req
, ev
);
2266 tevent_req_set_callback(subreq
, cli_hardlink_done2
, req
);
2270 subreq
= cli_nt_hardlink_send(state
, ev
, cli
, fname_src
, fname_dst
);
2271 if (tevent_req_nomem(subreq
, req
)) {
2272 return tevent_req_post(req
, ev
);
2274 tevent_req_set_callback(subreq
, cli_hardlink_done
, req
);
2278 static void cli_hardlink_done(struct tevent_req
*subreq
)
2280 NTSTATUS status
= cli_nt_hardlink_recv(subreq
);
2281 tevent_req_simple_finish_ntstatus(subreq
, status
);
2284 static void cli_hardlink_done2(struct tevent_req
*subreq
)
2286 NTSTATUS status
= cli_smb2_hardlink_recv(subreq
);
2287 tevent_req_simple_finish_ntstatus(subreq
, status
);
2290 NTSTATUS
cli_hardlink_recv(struct tevent_req
*req
)
2292 return tevent_req_simple_recv_ntstatus(req
);
2295 NTSTATUS
cli_hardlink(
2296 struct cli_state
*cli
, const char *fname_src
, const char *fname_dst
)
2298 TALLOC_CTX
*frame
= talloc_stackframe();
2299 struct tevent_context
*ev
= NULL
;
2300 struct tevent_req
*req
= NULL
;
2301 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2303 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2304 status
= NT_STATUS_INVALID_PARAMETER
;
2307 ev
= samba_tevent_context_init(frame
);
2311 req
= cli_hardlink_send(frame
, ev
, cli
, fname_src
, fname_dst
);
2315 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2318 status
= cli_hardlink_recv(req
);
2324 /****************************************************************************
2326 ****************************************************************************/
2328 static void cli_unlink_done(struct tevent_req
*subreq
);
2329 static void cli_unlink_done2(struct tevent_req
*subreq
);
2331 struct cli_unlink_state
{
2335 struct tevent_req
*cli_unlink_send(TALLOC_CTX
*mem_ctx
,
2336 struct tevent_context
*ev
,
2337 struct cli_state
*cli
,
2339 uint32_t mayhave_attrs
)
2341 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2342 struct cli_unlink_state
*state
= NULL
;
2343 uint8_t additional_flags
= 0;
2344 uint16_t additional_flags2
= 0;
2345 uint8_t *bytes
= NULL
;
2346 char *fname_cp
= NULL
;
2348 req
= tevent_req_create(mem_ctx
, &state
, struct cli_unlink_state
);
2353 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
2354 subreq
= cli_smb2_unlink_send(state
, ev
, cli
, fname
, NULL
);
2355 if (tevent_req_nomem(subreq
, req
)) {
2356 return tevent_req_post(req
, ev
);
2358 tevent_req_set_callback(subreq
, cli_unlink_done2
, req
);
2362 if (mayhave_attrs
& 0xFFFF0000) {
2364 * Don't allow attributes greater than
2365 * 16-bits for a 16-bit protocol value.
2367 if (tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
)) {
2368 return tevent_req_post(req
, ev
);
2372 SSVAL(state
->vwv
+0, 0, mayhave_attrs
);
2374 bytes
= talloc_array(state
, uint8_t, 1);
2375 if (tevent_req_nomem(bytes
, req
)) {
2376 return tevent_req_post(req
, ev
);
2379 * SMBunlink on a DFS share must use DFS names.
2381 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
2382 if (tevent_req_nomem(fname_cp
, req
)) {
2383 return tevent_req_post(req
, ev
);
2386 bytes
= smb_bytes_push_str(bytes
,
2387 smbXcli_conn_use_unicode(cli
->conn
),
2392 if (tevent_req_nomem(bytes
, req
)) {
2393 return tevent_req_post(req
, ev
);
2396 if (clistr_is_previous_version_path(fname
)) {
2397 additional_flags2
= FLAGS2_REPARSE_PATH
;
2400 subreq
= cli_smb_send(state
, ev
, cli
, SMBunlink
, additional_flags
,
2402 1, state
->vwv
, talloc_get_size(bytes
), bytes
);
2403 if (tevent_req_nomem(subreq
, req
)) {
2404 return tevent_req_post(req
, ev
);
2406 tevent_req_set_callback(subreq
, cli_unlink_done
, req
);
2410 static void cli_unlink_done(struct tevent_req
*subreq
)
2412 NTSTATUS status
= cli_smb_recv(
2413 subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
2414 tevent_req_simple_finish_ntstatus(subreq
, status
);
2417 static void cli_unlink_done2(struct tevent_req
*subreq
)
2419 NTSTATUS status
= cli_smb2_unlink_recv(subreq
);
2420 tevent_req_simple_finish_ntstatus(subreq
, status
);
2423 NTSTATUS
cli_unlink_recv(struct tevent_req
*req
)
2425 return tevent_req_simple_recv_ntstatus(req
);
2428 NTSTATUS
cli_unlink(struct cli_state
*cli
, const char *fname
, uint32_t mayhave_attrs
)
2430 TALLOC_CTX
*frame
= NULL
;
2431 struct tevent_context
*ev
;
2432 struct tevent_req
*req
;
2433 NTSTATUS status
= NT_STATUS_OK
;
2435 frame
= talloc_stackframe();
2437 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2439 * Can't use sync call while an async call is in flight
2441 status
= NT_STATUS_INVALID_PARAMETER
;
2445 ev
= samba_tevent_context_init(frame
);
2447 status
= NT_STATUS_NO_MEMORY
;
2451 req
= cli_unlink_send(frame
, ev
, cli
, fname
, mayhave_attrs
);
2453 status
= NT_STATUS_NO_MEMORY
;
2457 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2461 status
= cli_unlink_recv(req
);
2467 /****************************************************************************
2469 ****************************************************************************/
2471 static void cli_mkdir_done(struct tevent_req
*subreq
);
2472 static void cli_mkdir_done2(struct tevent_req
*subreq
);
2474 struct cli_mkdir_state
{
2478 struct tevent_req
*cli_mkdir_send(TALLOC_CTX
*mem_ctx
,
2479 struct tevent_context
*ev
,
2480 struct cli_state
*cli
,
2483 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2484 struct cli_mkdir_state
*state
= NULL
;
2485 uint8_t additional_flags
= 0;
2486 uint16_t additional_flags2
= 0;
2487 uint8_t *bytes
= NULL
;
2488 char *dname_cp
= NULL
;
2490 req
= tevent_req_create(mem_ctx
, &state
, struct cli_mkdir_state
);
2495 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
2496 subreq
= cli_smb2_mkdir_send(state
, ev
, cli
, dname
);
2497 if (tevent_req_nomem(subreq
, req
)) {
2498 return tevent_req_post(req
, ev
);
2500 tevent_req_set_callback(subreq
, cli_mkdir_done2
, req
);
2504 bytes
= talloc_array(state
, uint8_t, 1);
2505 if (tevent_req_nomem(bytes
, req
)) {
2506 return tevent_req_post(req
, ev
);
2509 * SMBmkdir on a DFS share must use DFS names.
2511 dname_cp
= smb1_dfs_share_path(state
, cli
, dname
);
2512 if (tevent_req_nomem(dname_cp
, req
)) {
2513 return tevent_req_post(req
, ev
);
2516 bytes
= smb_bytes_push_str(bytes
,
2517 smbXcli_conn_use_unicode(cli
->conn
),
2522 if (tevent_req_nomem(bytes
, req
)) {
2523 return tevent_req_post(req
, ev
);
2526 if (clistr_is_previous_version_path(dname
)) {
2527 additional_flags2
= FLAGS2_REPARSE_PATH
;
2530 subreq
= cli_smb_send(state
, ev
, cli
, SMBmkdir
, additional_flags
,
2532 0, NULL
, talloc_get_size(bytes
), bytes
);
2533 if (tevent_req_nomem(subreq
, req
)) {
2534 return tevent_req_post(req
, ev
);
2536 tevent_req_set_callback(subreq
, cli_mkdir_done
, req
);
2540 static void cli_mkdir_done(struct tevent_req
*subreq
)
2542 struct tevent_req
*req
= tevent_req_callback_data(
2543 subreq
, struct tevent_req
);
2546 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
2547 TALLOC_FREE(subreq
);
2548 if (tevent_req_nterror(req
, status
)) {
2551 tevent_req_done(req
);
2554 static void cli_mkdir_done2(struct tevent_req
*subreq
)
2556 NTSTATUS status
= cli_smb2_mkdir_recv(subreq
);
2557 tevent_req_simple_finish_ntstatus(subreq
, status
);
2560 NTSTATUS
cli_mkdir_recv(struct tevent_req
*req
)
2562 return tevent_req_simple_recv_ntstatus(req
);
2565 NTSTATUS
cli_mkdir(struct cli_state
*cli
, const char *dname
)
2567 TALLOC_CTX
*frame
= NULL
;
2568 struct tevent_context
*ev
;
2569 struct tevent_req
*req
;
2570 NTSTATUS status
= NT_STATUS_OK
;
2572 frame
= talloc_stackframe();
2574 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2576 * Can't use sync call while an async call is in flight
2578 status
= NT_STATUS_INVALID_PARAMETER
;
2582 ev
= samba_tevent_context_init(frame
);
2584 status
= NT_STATUS_NO_MEMORY
;
2588 req
= cli_mkdir_send(frame
, ev
, cli
, dname
);
2590 status
= NT_STATUS_NO_MEMORY
;
2594 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2598 status
= cli_mkdir_recv(req
);
2604 /****************************************************************************
2606 ****************************************************************************/
2608 static void cli_rmdir_done(struct tevent_req
*subreq
);
2609 static void cli_rmdir_done2(struct tevent_req
*subreq
);
2611 struct cli_rmdir_state
{
2615 struct tevent_req
*cli_rmdir_send(TALLOC_CTX
*mem_ctx
,
2616 struct tevent_context
*ev
,
2617 struct cli_state
*cli
,
2620 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2621 struct cli_rmdir_state
*state
= NULL
;
2622 uint8_t additional_flags
= 0;
2623 uint16_t additional_flags2
= 0;
2624 uint8_t *bytes
= NULL
;
2625 char *dname_cp
= NULL
;
2627 req
= tevent_req_create(mem_ctx
, &state
, struct cli_rmdir_state
);
2632 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
2633 subreq
= cli_smb2_rmdir_send(state
, ev
, cli
, dname
, NULL
);
2634 if (tevent_req_nomem(subreq
, req
)) {
2635 return tevent_req_post(req
, ev
);
2637 tevent_req_set_callback(subreq
, cli_rmdir_done2
, req
);
2641 bytes
= talloc_array(state
, uint8_t, 1);
2642 if (tevent_req_nomem(bytes
, req
)) {
2643 return tevent_req_post(req
, ev
);
2646 * SMBrmdir on a DFS share must use DFS names.
2648 dname_cp
= smb1_dfs_share_path(state
, cli
, dname
);
2649 if (tevent_req_nomem(dname_cp
, req
)) {
2650 return tevent_req_post(req
, ev
);
2653 bytes
= smb_bytes_push_str(bytes
,
2654 smbXcli_conn_use_unicode(cli
->conn
),
2659 if (tevent_req_nomem(bytes
, req
)) {
2660 return tevent_req_post(req
, ev
);
2663 if (clistr_is_previous_version_path(dname
)) {
2664 additional_flags2
= FLAGS2_REPARSE_PATH
;
2667 subreq
= cli_smb_send(state
, ev
, cli
, SMBrmdir
, additional_flags
,
2669 0, NULL
, talloc_get_size(bytes
), bytes
);
2670 if (tevent_req_nomem(subreq
, req
)) {
2671 return tevent_req_post(req
, ev
);
2673 tevent_req_set_callback(subreq
, cli_rmdir_done
, req
);
2677 static void cli_rmdir_done(struct tevent_req
*subreq
)
2679 NTSTATUS status
= cli_smb_recv(
2680 subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
2681 tevent_req_simple_finish_ntstatus(subreq
, status
);
2684 static void cli_rmdir_done2(struct tevent_req
*subreq
)
2686 NTSTATUS status
= cli_smb2_rmdir_recv(subreq
);
2687 tevent_req_simple_finish_ntstatus(subreq
, status
);
2690 NTSTATUS
cli_rmdir_recv(struct tevent_req
*req
)
2692 return tevent_req_simple_recv_ntstatus(req
);
2695 NTSTATUS
cli_rmdir(struct cli_state
*cli
, const char *dname
)
2697 TALLOC_CTX
*frame
= NULL
;
2698 struct tevent_context
*ev
;
2699 struct tevent_req
*req
;
2700 NTSTATUS status
= NT_STATUS_OK
;
2702 frame
= talloc_stackframe();
2704 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2706 * Can't use sync call while an async call is in flight
2708 status
= NT_STATUS_INVALID_PARAMETER
;
2712 ev
= samba_tevent_context_init(frame
);
2714 status
= NT_STATUS_NO_MEMORY
;
2718 req
= cli_rmdir_send(frame
, ev
, cli
, dname
);
2720 status
= NT_STATUS_NO_MEMORY
;
2724 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2728 status
= cli_rmdir_recv(req
);
2734 /****************************************************************************
2735 Set or clear the delete on close flag.
2736 ****************************************************************************/
2742 static void cli_nt_delete_on_close_smb1_done(struct tevent_req
*subreq
);
2743 static void cli_nt_delete_on_close_smb2_done(struct tevent_req
*subreq
);
2745 struct tevent_req
*cli_nt_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
2746 struct tevent_context
*ev
,
2747 struct cli_state
*cli
,
2751 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2752 struct doc_state
*state
= NULL
;
2754 req
= tevent_req_create(mem_ctx
, &state
, struct doc_state
);
2759 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
2760 subreq
= cli_smb2_delete_on_close_send(state
, ev
, cli
,
2762 if (tevent_req_nomem(subreq
, req
)) {
2763 return tevent_req_post(req
, ev
);
2765 tevent_req_set_callback(subreq
,
2766 cli_nt_delete_on_close_smb2_done
,
2771 /* Setup data array. */
2772 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
2774 subreq
= cli_setfileinfo_send(
2779 SMB_SET_FILE_DISPOSITION_INFO
,
2781 sizeof(state
->data
));
2783 if (tevent_req_nomem(subreq
, req
)) {
2784 return tevent_req_post(req
, ev
);
2786 tevent_req_set_callback(subreq
,
2787 cli_nt_delete_on_close_smb1_done
,
2792 static void cli_nt_delete_on_close_smb1_done(struct tevent_req
*subreq
)
2794 NTSTATUS status
= cli_setfileinfo_recv(subreq
);
2795 tevent_req_simple_finish_ntstatus(subreq
, status
);
2798 static void cli_nt_delete_on_close_smb2_done(struct tevent_req
*subreq
)
2800 NTSTATUS status
= cli_smb2_delete_on_close_recv(subreq
);
2801 tevent_req_simple_finish_ntstatus(subreq
, status
);
2804 NTSTATUS
cli_nt_delete_on_close_recv(struct tevent_req
*req
)
2806 return tevent_req_simple_recv_ntstatus(req
);
2809 NTSTATUS
cli_nt_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
2811 TALLOC_CTX
*frame
= talloc_stackframe();
2812 struct tevent_context
*ev
= NULL
;
2813 struct tevent_req
*req
= NULL
;
2814 NTSTATUS status
= NT_STATUS_OK
;
2816 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2818 * Can't use sync call while an async call is in flight
2820 status
= NT_STATUS_INVALID_PARAMETER
;
2824 ev
= samba_tevent_context_init(frame
);
2826 status
= NT_STATUS_NO_MEMORY
;
2830 req
= cli_nt_delete_on_close_send(frame
,
2836 status
= NT_STATUS_NO_MEMORY
;
2840 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2844 status
= cli_nt_delete_on_close_recv(req
);
2851 struct cli_ntcreate1_state
{
2854 struct smb_create_returns cr
;
2855 struct tevent_req
*subreq
;
2858 static void cli_ntcreate1_done(struct tevent_req
*subreq
);
2859 static bool cli_ntcreate1_cancel(struct tevent_req
*req
);
2861 static struct tevent_req
*cli_ntcreate1_send(TALLOC_CTX
*mem_ctx
,
2862 struct tevent_context
*ev
,
2863 struct cli_state
*cli
,
2865 uint32_t CreatFlags
,
2866 uint32_t DesiredAccess
,
2867 uint32_t FileAttributes
,
2868 uint32_t ShareAccess
,
2869 uint32_t CreateDisposition
,
2870 uint32_t CreateOptions
,
2871 uint32_t ImpersonationLevel
,
2872 uint8_t SecurityFlags
)
2874 struct tevent_req
*req
, *subreq
;
2875 struct cli_ntcreate1_state
*state
;
2878 size_t converted_len
;
2879 uint16_t additional_flags2
= 0;
2880 char *fname_cp
= NULL
;
2882 req
= tevent_req_create(mem_ctx
, &state
, struct cli_ntcreate1_state
);
2889 SCVAL(vwv
+0, 0, 0xFF);
2894 if (cli
->use_oplocks
) {
2895 CreatFlags
|= (REQUEST_OPLOCK
|REQUEST_BATCH_OPLOCK
);
2897 SIVAL(vwv
+3, 1, CreatFlags
);
2898 SIVAL(vwv
+5, 1, 0x0); /* RootDirectoryFid */
2899 SIVAL(vwv
+7, 1, DesiredAccess
);
2900 SIVAL(vwv
+9, 1, 0x0); /* AllocationSize */
2901 SIVAL(vwv
+11, 1, 0x0); /* AllocationSize */
2902 SIVAL(vwv
+13, 1, FileAttributes
);
2903 SIVAL(vwv
+15, 1, ShareAccess
);
2904 SIVAL(vwv
+17, 1, CreateDisposition
);
2905 SIVAL(vwv
+19, 1, CreateOptions
|
2906 (cli
->backup_intent
? FILE_OPEN_FOR_BACKUP_INTENT
: 0));
2907 SIVAL(vwv
+21, 1, ImpersonationLevel
);
2908 SCVAL(vwv
+23, 1, SecurityFlags
);
2910 bytes
= talloc_array(state
, uint8_t, 0);
2911 if (tevent_req_nomem(bytes
, req
)) {
2912 return tevent_req_post(req
, ev
);
2915 * SMBntcreateX on a DFS share must use DFS names.
2917 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
2918 if (tevent_req_nomem(fname_cp
, req
)) {
2919 return tevent_req_post(req
, ev
);
2921 bytes
= smb_bytes_push_str(bytes
,
2922 smbXcli_conn_use_unicode(cli
->conn
),
2926 if (tevent_req_nomem(bytes
, req
)) {
2927 return tevent_req_post(req
, ev
);
2930 if (clistr_is_previous_version_path(fname
)) {
2931 additional_flags2
= FLAGS2_REPARSE_PATH
;
2934 /* sigh. this copes with broken netapp filer behaviour */
2935 bytes
= smb_bytes_push_str(bytes
, smbXcli_conn_use_unicode(cli
->conn
), "", 1, NULL
);
2937 if (tevent_req_nomem(bytes
, req
)) {
2938 return tevent_req_post(req
, ev
);
2941 SSVAL(vwv
+2, 1, converted_len
);
2943 subreq
= cli_smb_send(state
, ev
, cli
, SMBntcreateX
, 0,
2944 additional_flags2
, 24, vwv
,
2945 talloc_get_size(bytes
), bytes
);
2946 if (tevent_req_nomem(subreq
, req
)) {
2947 return tevent_req_post(req
, ev
);
2949 tevent_req_set_callback(subreq
, cli_ntcreate1_done
, req
);
2951 state
->subreq
= subreq
;
2952 tevent_req_set_cancel_fn(req
, cli_ntcreate1_cancel
);
2957 static void cli_ntcreate1_done(struct tevent_req
*subreq
)
2959 struct tevent_req
*req
= tevent_req_callback_data(
2960 subreq
, struct tevent_req
);
2961 struct cli_ntcreate1_state
*state
= tevent_req_data(
2962 req
, struct cli_ntcreate1_state
);
2969 status
= cli_smb_recv(subreq
, state
, NULL
, 34, &wct
, &vwv
,
2970 &num_bytes
, &bytes
);
2971 TALLOC_FREE(subreq
);
2972 if (tevent_req_nterror(req
, status
)) {
2975 state
->cr
.oplock_level
= CVAL(vwv
+2, 0);
2976 state
->fnum
= SVAL(vwv
+2, 1);
2977 state
->cr
.create_action
= IVAL(vwv
+3, 1);
2978 state
->cr
.creation_time
= BVAL(vwv
+5, 1);
2979 state
->cr
.last_access_time
= BVAL(vwv
+9, 1);
2980 state
->cr
.last_write_time
= BVAL(vwv
+13, 1);
2981 state
->cr
.change_time
= BVAL(vwv
+17, 1);
2982 state
->cr
.file_attributes
= IVAL(vwv
+21, 1);
2983 state
->cr
.allocation_size
= BVAL(vwv
+23, 1);
2984 state
->cr
.end_of_file
= BVAL(vwv
+27, 1);
2986 tevent_req_done(req
);
2989 static bool cli_ntcreate1_cancel(struct tevent_req
*req
)
2991 struct cli_ntcreate1_state
*state
= tevent_req_data(
2992 req
, struct cli_ntcreate1_state
);
2993 return tevent_req_cancel(state
->subreq
);
2996 static NTSTATUS
cli_ntcreate1_recv(struct tevent_req
*req
,
2998 struct smb_create_returns
*cr
)
3000 struct cli_ntcreate1_state
*state
= tevent_req_data(
3001 req
, struct cli_ntcreate1_state
);
3004 if (tevent_req_is_nterror(req
, &status
)) {
3007 *pfnum
= state
->fnum
;
3011 return NT_STATUS_OK
;
3014 struct cli_ntcreate_state
{
3015 struct smb_create_returns cr
;
3017 struct tevent_req
*subreq
;
3020 static void cli_ntcreate_done_nt1(struct tevent_req
*subreq
);
3021 static void cli_ntcreate_done_smb2(struct tevent_req
*subreq
);
3022 static bool cli_ntcreate_cancel(struct tevent_req
*req
);
3024 struct tevent_req
*cli_ntcreate_send(TALLOC_CTX
*mem_ctx
,
3025 struct tevent_context
*ev
,
3026 struct cli_state
*cli
,
3028 uint32_t create_flags
,
3029 uint32_t desired_access
,
3030 uint32_t file_attributes
,
3031 uint32_t share_access
,
3032 uint32_t create_disposition
,
3033 uint32_t create_options
,
3034 uint32_t impersonation_level
,
3035 uint8_t security_flags
)
3037 struct tevent_req
*req
, *subreq
;
3038 struct cli_ntcreate_state
*state
;
3040 req
= tevent_req_create(mem_ctx
, &state
, struct cli_ntcreate_state
);
3045 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
3046 struct cli_smb2_create_flags cflags
= {0};
3048 if (cli
->use_oplocks
) {
3049 create_flags
|= REQUEST_OPLOCK
|REQUEST_BATCH_OPLOCK
;
3052 cflags
= (struct cli_smb2_create_flags
) {
3053 .batch_oplock
= (create_flags
& REQUEST_BATCH_OPLOCK
),
3054 .exclusive_oplock
= (create_flags
& REQUEST_OPLOCK
),
3057 subreq
= cli_smb2_create_fnum_send(
3063 impersonation_level
,
3070 if (tevent_req_nomem(subreq
, req
)) {
3071 return tevent_req_post(req
, ev
);
3073 tevent_req_set_callback(subreq
, cli_ntcreate_done_smb2
, req
);
3075 subreq
= cli_ntcreate1_send(
3076 state
, ev
, cli
, fname
, create_flags
, desired_access
,
3077 file_attributes
, share_access
, create_disposition
,
3078 create_options
, impersonation_level
, security_flags
);
3079 if (tevent_req_nomem(subreq
, req
)) {
3080 return tevent_req_post(req
, ev
);
3082 tevent_req_set_callback(subreq
, cli_ntcreate_done_nt1
, req
);
3085 state
->subreq
= subreq
;
3086 tevent_req_set_cancel_fn(req
, cli_ntcreate_cancel
);
3091 static void cli_ntcreate_done_nt1(struct tevent_req
*subreq
)
3093 struct tevent_req
*req
= tevent_req_callback_data(
3094 subreq
, struct tevent_req
);
3095 struct cli_ntcreate_state
*state
= tevent_req_data(
3096 req
, struct cli_ntcreate_state
);
3099 status
= cli_ntcreate1_recv(subreq
, &state
->fnum
, &state
->cr
);
3100 TALLOC_FREE(subreq
);
3101 if (tevent_req_nterror(req
, status
)) {
3104 tevent_req_done(req
);
3107 static void cli_ntcreate_done_smb2(struct tevent_req
*subreq
)
3109 struct tevent_req
*req
= tevent_req_callback_data(
3110 subreq
, struct tevent_req
);
3111 struct cli_ntcreate_state
*state
= tevent_req_data(
3112 req
, struct cli_ntcreate_state
);
3115 status
= cli_smb2_create_fnum_recv(
3122 TALLOC_FREE(subreq
);
3123 if (tevent_req_nterror(req
, status
)) {
3126 tevent_req_done(req
);
3129 static bool cli_ntcreate_cancel(struct tevent_req
*req
)
3131 struct cli_ntcreate_state
*state
= tevent_req_data(
3132 req
, struct cli_ntcreate_state
);
3133 return tevent_req_cancel(state
->subreq
);
3136 NTSTATUS
cli_ntcreate_recv(struct tevent_req
*req
, uint16_t *fnum
,
3137 struct smb_create_returns
*cr
)
3139 struct cli_ntcreate_state
*state
= tevent_req_data(
3140 req
, struct cli_ntcreate_state
);
3143 if (tevent_req_is_nterror(req
, &status
)) {
3147 *fnum
= state
->fnum
;
3152 return NT_STATUS_OK
;
3155 NTSTATUS
cli_ntcreate(struct cli_state
*cli
,
3157 uint32_t CreatFlags
,
3158 uint32_t DesiredAccess
,
3159 uint32_t FileAttributes
,
3160 uint32_t ShareAccess
,
3161 uint32_t CreateDisposition
,
3162 uint32_t CreateOptions
,
3163 uint8_t SecurityFlags
,
3165 struct smb_create_returns
*cr
)
3167 TALLOC_CTX
*frame
= talloc_stackframe();
3168 struct tevent_context
*ev
;
3169 struct tevent_req
*req
;
3170 uint32_t ImpersonationLevel
= SMB2_IMPERSONATION_IMPERSONATION
;
3171 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3173 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3175 * Can't use sync call while an async call is in flight
3177 status
= NT_STATUS_INVALID_PARAMETER
;
3181 ev
= samba_tevent_context_init(frame
);
3186 req
= cli_ntcreate_send(frame
, ev
, cli
, fname
, CreatFlags
,
3187 DesiredAccess
, FileAttributes
, ShareAccess
,
3188 CreateDisposition
, CreateOptions
,
3189 ImpersonationLevel
, SecurityFlags
);
3194 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3198 status
= cli_ntcreate_recv(req
, pfid
, cr
);
3204 struct cli_nttrans_create_state
{
3206 struct smb_create_returns cr
;
3209 static void cli_nttrans_create_done(struct tevent_req
*subreq
);
3211 struct tevent_req
*cli_nttrans_create_send(TALLOC_CTX
*mem_ctx
,
3212 struct tevent_context
*ev
,
3213 struct cli_state
*cli
,
3215 uint32_t CreatFlags
,
3216 uint32_t DesiredAccess
,
3217 uint32_t FileAttributes
,
3218 uint32_t ShareAccess
,
3219 uint32_t CreateDisposition
,
3220 uint32_t CreateOptions
,
3221 uint8_t SecurityFlags
,
3222 struct security_descriptor
*secdesc
,
3223 struct ea_struct
*eas
,
3226 struct tevent_req
*req
, *subreq
;
3227 struct cli_nttrans_create_state
*state
;
3229 uint8_t *secdesc_buf
;
3232 size_t converted_len
;
3233 uint16_t additional_flags2
= 0;
3234 char *fname_cp
= NULL
;
3236 req
= tevent_req_create(mem_ctx
,
3237 &state
, struct cli_nttrans_create_state
);
3242 if (secdesc
!= NULL
) {
3243 status
= marshall_sec_desc(talloc_tos(), secdesc
,
3244 &secdesc_buf
, &secdesc_len
);
3245 if (tevent_req_nterror(req
, status
)) {
3246 DEBUG(10, ("marshall_sec_desc failed: %s\n",
3247 nt_errstr(status
)));
3248 return tevent_req_post(req
, ev
);
3259 tevent_req_nterror(req
, NT_STATUS_NOT_IMPLEMENTED
);
3260 return tevent_req_post(req
, ev
);
3263 param
= talloc_array(state
, uint8_t, 53);
3264 if (tevent_req_nomem(param
, req
)) {
3265 return tevent_req_post(req
, ev
);
3269 * SMBntcreateX on a DFS share must use DFS names.
3271 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
3272 if (tevent_req_nomem(fname_cp
, req
)) {
3273 return tevent_req_post(req
, ev
);
3275 param
= trans2_bytes_push_str(param
,
3276 smbXcli_conn_use_unicode(cli
->conn
),
3280 if (tevent_req_nomem(param
, req
)) {
3281 return tevent_req_post(req
, ev
);
3284 if (clistr_is_previous_version_path(fname
)) {
3285 additional_flags2
= FLAGS2_REPARSE_PATH
;
3288 SIVAL(param
, 0, CreatFlags
);
3289 SIVAL(param
, 4, 0x0); /* RootDirectoryFid */
3290 SIVAL(param
, 8, DesiredAccess
);
3291 SIVAL(param
, 12, 0x0); /* AllocationSize */
3292 SIVAL(param
, 16, 0x0); /* AllocationSize */
3293 SIVAL(param
, 20, FileAttributes
);
3294 SIVAL(param
, 24, ShareAccess
);
3295 SIVAL(param
, 28, CreateDisposition
);
3296 SIVAL(param
, 32, CreateOptions
|
3297 (cli
->backup_intent
? FILE_OPEN_FOR_BACKUP_INTENT
: 0));
3298 SIVAL(param
, 36, secdesc_len
);
3299 SIVAL(param
, 40, 0); /* EA length*/
3300 SIVAL(param
, 44, converted_len
);
3301 SIVAL(param
, 48, 0x02); /* ImpersonationLevel */
3302 SCVAL(param
, 52, SecurityFlags
);
3304 subreq
= cli_trans_send(state
, ev
, cli
,
3305 additional_flags2
, /* additional_flags2 */
3307 NULL
, -1, /* name, fid */
3308 NT_TRANSACT_CREATE
, 0,
3309 NULL
, 0, 0, /* setup */
3310 param
, talloc_get_size(param
), 128, /* param */
3311 secdesc_buf
, secdesc_len
, 0); /* data */
3312 if (tevent_req_nomem(subreq
, req
)) {
3313 return tevent_req_post(req
, ev
);
3315 tevent_req_set_callback(subreq
, cli_nttrans_create_done
, req
);
3319 static void cli_nttrans_create_done(struct tevent_req
*subreq
)
3321 struct tevent_req
*req
= tevent_req_callback_data(
3322 subreq
, struct tevent_req
);
3323 struct cli_nttrans_create_state
*state
= tevent_req_data(
3324 req
, struct cli_nttrans_create_state
);
3329 status
= cli_trans_recv(subreq
, talloc_tos(), NULL
,
3330 NULL
, 0, NULL
, /* rsetup */
3331 ¶m
, 69, &num_param
,
3333 if (tevent_req_nterror(req
, status
)) {
3336 state
->cr
.oplock_level
= CVAL(param
, 0);
3337 state
->fnum
= SVAL(param
, 2);
3338 state
->cr
.create_action
= IVAL(param
, 4);
3339 state
->cr
.creation_time
= BVAL(param
, 12);
3340 state
->cr
.last_access_time
= BVAL(param
, 20);
3341 state
->cr
.last_write_time
= BVAL(param
, 28);
3342 state
->cr
.change_time
= BVAL(param
, 36);
3343 state
->cr
.file_attributes
= IVAL(param
, 44);
3344 state
->cr
.allocation_size
= BVAL(param
, 48);
3345 state
->cr
.end_of_file
= BVAL(param
, 56);
3348 tevent_req_done(req
);
3351 NTSTATUS
cli_nttrans_create_recv(struct tevent_req
*req
,
3353 struct smb_create_returns
*cr
)
3355 struct cli_nttrans_create_state
*state
= tevent_req_data(
3356 req
, struct cli_nttrans_create_state
);
3359 if (tevent_req_is_nterror(req
, &status
)) {
3362 *fnum
= state
->fnum
;
3366 return NT_STATUS_OK
;
3369 NTSTATUS
cli_nttrans_create(struct cli_state
*cli
,
3371 uint32_t CreatFlags
,
3372 uint32_t DesiredAccess
,
3373 uint32_t FileAttributes
,
3374 uint32_t ShareAccess
,
3375 uint32_t CreateDisposition
,
3376 uint32_t CreateOptions
,
3377 uint8_t SecurityFlags
,
3378 struct security_descriptor
*secdesc
,
3379 struct ea_struct
*eas
,
3382 struct smb_create_returns
*cr
)
3384 TALLOC_CTX
*frame
= talloc_stackframe();
3385 struct tevent_context
*ev
;
3386 struct tevent_req
*req
;
3387 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3389 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3391 * Can't use sync call while an async call is in flight
3393 status
= NT_STATUS_INVALID_PARAMETER
;
3396 ev
= samba_tevent_context_init(frame
);
3400 req
= cli_nttrans_create_send(frame
, ev
, cli
, fname
, CreatFlags
,
3401 DesiredAccess
, FileAttributes
,
3402 ShareAccess
, CreateDisposition
,
3403 CreateOptions
, SecurityFlags
,
3404 secdesc
, eas
, num_eas
);
3408 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3411 status
= cli_nttrans_create_recv(req
, pfid
, cr
);
3417 /****************************************************************************
3419 WARNING: if you open with O_WRONLY then getattrE won't work!
3420 ****************************************************************************/
3422 struct cli_openx_state
{
3429 static void cli_openx_done(struct tevent_req
*subreq
);
3431 struct tevent_req
*cli_openx_create(TALLOC_CTX
*mem_ctx
,
3432 struct tevent_context
*ev
,
3433 struct cli_state
*cli
, const char *fname
,
3434 int flags
, int share_mode
,
3435 struct tevent_req
**psmbreq
)
3437 struct tevent_req
*req
, *subreq
;
3438 struct cli_openx_state
*state
;
3440 unsigned accessmode
;
3441 uint8_t additional_flags
;
3442 uint16_t additional_flags2
= 0;
3444 char *fname_cp
= NULL
;
3446 req
= tevent_req_create(mem_ctx
, &state
, struct cli_openx_state
);
3452 if (flags
& O_CREAT
) {
3455 if (!(flags
& O_EXCL
)) {
3456 if (flags
& O_TRUNC
)
3462 accessmode
= (share_mode
<<4);
3464 if ((flags
& O_ACCMODE
) == O_RDWR
) {
3466 } else if ((flags
& O_ACCMODE
) == O_WRONLY
) {
3471 if ((flags
& O_SYNC
) == O_SYNC
) {
3472 accessmode
|= (1<<14);
3476 if (share_mode
== DENY_FCB
) {
3480 SCVAL(state
->vwv
+ 0, 0, 0xFF);
3481 SCVAL(state
->vwv
+ 0, 1, 0);
3482 SSVAL(state
->vwv
+ 1, 0, 0);
3483 SSVAL(state
->vwv
+ 2, 0, 0); /* no additional info */
3484 SSVAL(state
->vwv
+ 3, 0, accessmode
);
3485 SSVAL(state
->vwv
+ 4, 0, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
);
3486 SSVAL(state
->vwv
+ 5, 0, 0);
3487 SIVAL(state
->vwv
+ 6, 0, 0);
3488 SSVAL(state
->vwv
+ 8, 0, openfn
);
3489 SIVAL(state
->vwv
+ 9, 0, 0);
3490 SIVAL(state
->vwv
+ 11, 0, 0);
3491 SIVAL(state
->vwv
+ 13, 0, 0);
3493 additional_flags
= 0;
3495 if (cli
->use_oplocks
) {
3496 /* if using oplocks then ask for a batch oplock via
3497 core and extended methods */
3499 FLAG_REQUEST_OPLOCK
|FLAG_REQUEST_BATCH_OPLOCK
;
3500 SSVAL(state
->vwv
+2, 0, SVAL(state
->vwv
+2, 0) | 6);
3503 bytes
= talloc_array(state
, uint8_t, 0);
3504 if (tevent_req_nomem(bytes
, req
)) {
3505 return tevent_req_post(req
, ev
);
3508 * SMBopenX on a DFS share must use DFS names.
3510 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
3511 if (tevent_req_nomem(fname_cp
, req
)) {
3512 return tevent_req_post(req
, ev
);
3514 bytes
= smb_bytes_push_str(bytes
,
3515 smbXcli_conn_use_unicode(cli
->conn
),
3520 if (tevent_req_nomem(bytes
, req
)) {
3521 return tevent_req_post(req
, ev
);
3524 if (clistr_is_previous_version_path(fname
)) {
3525 additional_flags2
= FLAGS2_REPARSE_PATH
;
3528 state
->bytes
.iov_base
= (void *)bytes
;
3529 state
->bytes
.iov_len
= talloc_get_size(bytes
);
3531 subreq
= cli_smb_req_create(state
, ev
, cli
, SMBopenX
, additional_flags
,
3532 additional_flags2
, 15, state
->vwv
, 1, &state
->bytes
);
3533 if (subreq
== NULL
) {
3537 tevent_req_set_callback(subreq
, cli_openx_done
, req
);
3542 struct tevent_req
*cli_openx_send(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
3543 struct cli_state
*cli
, const char *fname
,
3544 int flags
, int share_mode
)
3546 struct tevent_req
*req
, *subreq
;
3549 req
= cli_openx_create(mem_ctx
, ev
, cli
, fname
, flags
, share_mode
,
3555 status
= smb1cli_req_chain_submit(&subreq
, 1);
3556 if (tevent_req_nterror(req
, status
)) {
3557 return tevent_req_post(req
, ev
);
3562 static void cli_openx_done(struct tevent_req
*subreq
)
3564 struct tevent_req
*req
= tevent_req_callback_data(
3565 subreq
, struct tevent_req
);
3566 struct cli_openx_state
*state
= tevent_req_data(
3567 req
, struct cli_openx_state
);
3572 status
= cli_smb_recv(subreq
, state
, NULL
, 3, &wct
, &vwv
, NULL
,
3574 TALLOC_FREE(subreq
);
3575 if (tevent_req_nterror(req
, status
)) {
3578 state
->fnum
= SVAL(vwv
+2, 0);
3579 tevent_req_done(req
);
3582 NTSTATUS
cli_openx_recv(struct tevent_req
*req
, uint16_t *pfnum
)
3584 struct cli_openx_state
*state
= tevent_req_data(
3585 req
, struct cli_openx_state
);
3588 if (tevent_req_is_nterror(req
, &status
)) {
3591 *pfnum
= state
->fnum
;
3592 return NT_STATUS_OK
;
3595 NTSTATUS
cli_openx(struct cli_state
*cli
, const char *fname
, int flags
,
3596 int share_mode
, uint16_t *pfnum
)
3598 TALLOC_CTX
*frame
= talloc_stackframe();
3599 struct tevent_context
*ev
;
3600 struct tevent_req
*req
;
3601 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3603 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3605 * Can't use sync call while an async call is in flight
3607 status
= NT_STATUS_INVALID_PARAMETER
;
3611 ev
= samba_tevent_context_init(frame
);
3616 req
= cli_openx_send(frame
, ev
, cli
, fname
, flags
, share_mode
);
3621 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3625 status
= cli_openx_recv(req
, pfnum
);
3630 /****************************************************************************
3631 Synchronous wrapper function that does an NtCreateX open by preference
3632 and falls back to openX if this fails.
3633 ****************************************************************************/
3635 NTSTATUS
cli_open(struct cli_state
*cli
, const char *fname
, int flags
,
3636 int share_mode_in
, uint16_t *pfnum
)
3639 unsigned int openfn
= 0;
3640 unsigned int dos_deny
= 0;
3641 uint32_t access_mask
, share_mode
, create_disposition
, create_options
;
3642 struct smb_create_returns cr
= {0};
3644 /* Do the initial mapping into OpenX parameters. */
3645 if (flags
& O_CREAT
) {
3648 if (!(flags
& O_EXCL
)) {
3649 if (flags
& O_TRUNC
)
3655 dos_deny
= (share_mode_in
<<4);
3657 if ((flags
& O_ACCMODE
) == O_RDWR
) {
3659 } else if ((flags
& O_ACCMODE
) == O_WRONLY
) {
3664 if (flags
& O_SYNC
) {
3665 dos_deny
|= (1<<14);
3669 if (share_mode_in
== DENY_FCB
) {
3673 if (!map_open_params_to_ntcreate(fname
, dos_deny
,
3674 openfn
, &access_mask
,
3675 &share_mode
, &create_disposition
,
3676 &create_options
, NULL
)) {
3680 status
= cli_ntcreate(cli
,
3692 /* Try and cope will all variants of "we don't do this call"
3693 and fall back to openX. */
3695 if (NT_STATUS_EQUAL(status
,NT_STATUS_NOT_IMPLEMENTED
) ||
3696 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_INFO_CLASS
) ||
3697 NT_STATUS_EQUAL(status
,NT_STATUS_PROCEDURE_NOT_FOUND
) ||
3698 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_LEVEL
) ||
3699 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_PARAMETER
) ||
3700 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_DEVICE_REQUEST
) ||
3701 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_DEVICE_STATE
) ||
3702 NT_STATUS_EQUAL(status
,NT_STATUS_CTL_FILE_NOT_SUPPORTED
) ||
3703 NT_STATUS_EQUAL(status
,NT_STATUS_UNSUCCESSFUL
)) {
3707 if (NT_STATUS_IS_OK(status
) &&
3708 (create_options
& FILE_NON_DIRECTORY_FILE
) &&
3709 (cr
.file_attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3712 * Some (broken) servers return a valid handle
3713 * for directories even if FILE_NON_DIRECTORY_FILE
3714 * is set. Just close the handle and set the
3715 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
3717 status
= cli_close(cli
, *pfnum
);
3718 if (!NT_STATUS_IS_OK(status
)) {
3721 status
= NT_STATUS_FILE_IS_A_DIRECTORY
;
3728 return cli_openx(cli
, fname
, flags
, share_mode_in
, pfnum
);
3731 /****************************************************************************
3733 ****************************************************************************/
3735 struct cli_smb1_close_state
{
3739 static void cli_smb1_close_done(struct tevent_req
*subreq
);
3741 struct tevent_req
*cli_smb1_close_create(TALLOC_CTX
*mem_ctx
,
3742 struct tevent_context
*ev
,
3743 struct cli_state
*cli
,
3745 struct tevent_req
**psubreq
)
3747 struct tevent_req
*req
, *subreq
;
3748 struct cli_smb1_close_state
*state
;
3750 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb1_close_state
);
3755 SSVAL(state
->vwv
+0, 0, fnum
);
3756 SIVALS(state
->vwv
+1, 0, -1);
3758 subreq
= cli_smb_req_create(state
, ev
, cli
, SMBclose
, 0, 0,
3759 3, state
->vwv
, 0, NULL
);
3760 if (subreq
== NULL
) {
3764 tevent_req_set_callback(subreq
, cli_smb1_close_done
, req
);
3769 static void cli_smb1_close_done(struct tevent_req
*subreq
)
3771 struct tevent_req
*req
= tevent_req_callback_data(
3772 subreq
, struct tevent_req
);
3775 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
3776 TALLOC_FREE(subreq
);
3777 if (tevent_req_nterror(req
, status
)) {
3780 tevent_req_done(req
);
3783 struct cli_close_state
{
3787 static void cli_close_done(struct tevent_req
*subreq
);
3789 struct tevent_req
*cli_close_send(TALLOC_CTX
*mem_ctx
,
3790 struct tevent_context
*ev
,
3791 struct cli_state
*cli
,
3795 struct tevent_req
*req
, *subreq
;
3796 struct cli_close_state
*state
;
3799 req
= tevent_req_create(mem_ctx
, &state
, struct cli_close_state
);
3804 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
3805 subreq
= cli_smb2_close_fnum_send(state
, ev
, cli
, fnum
, flags
);
3806 if (tevent_req_nomem(subreq
, req
)) {
3807 return tevent_req_post(req
, ev
);
3810 struct tevent_req
*ch_req
= NULL
;
3811 subreq
= cli_smb1_close_create(state
, ev
, cli
, fnum
, &ch_req
);
3812 if (tevent_req_nomem(subreq
, req
)) {
3813 return tevent_req_post(req
, ev
);
3815 status
= smb1cli_req_chain_submit(&ch_req
, 1);
3816 if (tevent_req_nterror(req
, status
)) {
3817 return tevent_req_post(req
, ev
);
3821 tevent_req_set_callback(subreq
, cli_close_done
, req
);
3825 static void cli_close_done(struct tevent_req
*subreq
)
3827 struct tevent_req
*req
= tevent_req_callback_data(
3828 subreq
, struct tevent_req
);
3829 NTSTATUS status
= NT_STATUS_OK
;
3830 bool err
= tevent_req_is_nterror(subreq
, &status
);
3832 TALLOC_FREE(subreq
);
3834 tevent_req_nterror(req
, status
);
3837 tevent_req_done(req
);
3840 NTSTATUS
cli_close_recv(struct tevent_req
*req
)
3842 return tevent_req_simple_recv_ntstatus(req
);
3845 NTSTATUS
cli_close(struct cli_state
*cli
, uint16_t fnum
)
3847 TALLOC_CTX
*frame
= NULL
;
3848 struct tevent_context
*ev
;
3849 struct tevent_req
*req
;
3850 NTSTATUS status
= NT_STATUS_OK
;
3852 frame
= talloc_stackframe();
3854 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3856 * Can't use sync call while an async call is in flight
3858 status
= NT_STATUS_INVALID_PARAMETER
;
3862 ev
= samba_tevent_context_init(frame
);
3864 status
= NT_STATUS_NO_MEMORY
;
3868 req
= cli_close_send(frame
, ev
, cli
, fnum
, 0);
3870 status
= NT_STATUS_NO_MEMORY
;
3874 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3878 status
= cli_close_recv(req
);
3884 /****************************************************************************
3885 Truncate a file to a specified size
3886 ****************************************************************************/
3888 struct ftrunc_state
{
3892 static void cli_ftruncate_done(struct tevent_req
*subreq
)
3894 NTSTATUS status
= cli_setfileinfo_recv(subreq
);
3895 tevent_req_simple_finish_ntstatus(subreq
, status
);
3898 struct tevent_req
*cli_ftruncate_send(TALLOC_CTX
*mem_ctx
,
3899 struct tevent_context
*ev
,
3900 struct cli_state
*cli
,
3904 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3905 struct ftrunc_state
*state
= NULL
;
3907 req
= tevent_req_create(mem_ctx
, &state
, struct ftrunc_state
);
3912 /* Setup data array. */
3913 SBVAL(state
->data
, 0, size
);
3915 subreq
= cli_setfileinfo_send(
3920 SMB_SET_FILE_END_OF_FILE_INFO
,
3922 sizeof(state
->data
));
3924 if (tevent_req_nomem(subreq
, req
)) {
3925 return tevent_req_post(req
, ev
);
3927 tevent_req_set_callback(subreq
, cli_ftruncate_done
, req
);
3931 NTSTATUS
cli_ftruncate_recv(struct tevent_req
*req
)
3933 return tevent_req_simple_recv_ntstatus(req
);
3936 NTSTATUS
cli_ftruncate(struct cli_state
*cli
, uint16_t fnum
, uint64_t size
)
3938 TALLOC_CTX
*frame
= NULL
;
3939 struct tevent_context
*ev
= NULL
;
3940 struct tevent_req
*req
= NULL
;
3941 NTSTATUS status
= NT_STATUS_OK
;
3943 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
3944 return cli_smb2_ftruncate(cli
, fnum
, size
);
3947 frame
= talloc_stackframe();
3949 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3951 * Can't use sync call while an async call is in flight
3953 status
= NT_STATUS_INVALID_PARAMETER
;
3957 ev
= samba_tevent_context_init(frame
);
3959 status
= NT_STATUS_NO_MEMORY
;
3963 req
= cli_ftruncate_send(frame
,
3969 status
= NT_STATUS_NO_MEMORY
;
3973 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3977 status
= cli_ftruncate_recv(req
);
3984 static uint8_t *cli_lockingx_put_locks(
3988 const struct smb1_lock_element
*locks
)
3992 for (i
=0; i
<num_locks
; i
++) {
3993 const struct smb1_lock_element
*e
= &locks
[i
];
3995 SSVAL(buf
, 0, e
->pid
);
3997 SOFF_T_R(buf
, 4, e
->offset
);
3998 SOFF_T_R(buf
, 12, e
->length
);
4001 SSVAL(buf
, 0, e
->pid
);
4002 SIVAL(buf
, 2, e
->offset
);
4003 SIVAL(buf
, 6, e
->length
);
4010 struct cli_lockingx_state
{
4013 struct tevent_req
*subreq
;
4016 static void cli_lockingx_done(struct tevent_req
*subreq
);
4017 static bool cli_lockingx_cancel(struct tevent_req
*req
);
4019 struct tevent_req
*cli_lockingx_create(
4020 TALLOC_CTX
*mem_ctx
,
4021 struct tevent_context
*ev
,
4022 struct cli_state
*cli
,
4025 uint8_t newoplocklevel
,
4027 uint16_t num_unlocks
,
4028 const struct smb1_lock_element
*unlocks
,
4030 const struct smb1_lock_element
*locks
,
4031 struct tevent_req
**psmbreq
)
4033 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4034 struct cli_lockingx_state
*state
= NULL
;
4037 const bool large
= (typeoflock
& LOCKING_ANDX_LARGE_FILES
);
4038 const size_t element_len
= large
? 20 : 10;
4040 /* uint16->size_t, no overflow */
4041 const size_t num_elements
= (size_t)num_locks
+ (size_t)num_unlocks
;
4043 /* at most 20*2*65535 = 2621400, no overflow */
4044 const size_t num_bytes
= num_elements
* element_len
;
4046 req
= tevent_req_create(mem_ctx
, &state
, struct cli_lockingx_state
);
4052 SCVAL(vwv
+ 0, 0, 0xFF);
4053 SCVAL(vwv
+ 0, 1, 0);
4054 SSVAL(vwv
+ 1, 0, 0);
4055 SSVAL(vwv
+ 2, 0, fnum
);
4056 SCVAL(vwv
+ 3, 0, typeoflock
);
4057 SCVAL(vwv
+ 3, 1, newoplocklevel
);
4058 SIVALS(vwv
+ 4, 0, timeout
);
4059 SSVAL(vwv
+ 6, 0, num_unlocks
);
4060 SSVAL(vwv
+ 7, 0, num_locks
);
4062 state
->bytes
.iov_len
= num_bytes
;
4063 state
->bytes
.iov_base
= talloc_array(state
, uint8_t, num_bytes
);
4064 if (tevent_req_nomem(state
->bytes
.iov_base
, req
)) {
4065 return tevent_req_post(req
, ev
);
4068 p
= cli_lockingx_put_locks(
4069 state
->bytes
.iov_base
, large
, num_unlocks
, unlocks
);
4070 cli_lockingx_put_locks(p
, large
, num_locks
, locks
);
4072 subreq
= cli_smb_req_create(
4073 state
, ev
, cli
, SMBlockingX
, 0, 0, 8, vwv
, 1, &state
->bytes
);
4074 if (tevent_req_nomem(subreq
, req
)) {
4075 return tevent_req_post(req
, ev
);
4077 tevent_req_set_callback(subreq
, cli_lockingx_done
, req
);
4082 struct tevent_req
*cli_lockingx_send(
4083 TALLOC_CTX
*mem_ctx
,
4084 struct tevent_context
*ev
,
4085 struct cli_state
*cli
,
4088 uint8_t newoplocklevel
,
4090 uint16_t num_unlocks
,
4091 const struct smb1_lock_element
*unlocks
,
4093 const struct smb1_lock_element
*locks
)
4095 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4096 struct cli_lockingx_state
*state
= NULL
;
4099 req
= cli_lockingx_create(
4115 state
= tevent_req_data(req
, struct cli_lockingx_state
);
4116 state
->subreq
= subreq
;
4118 status
= smb1cli_req_chain_submit(&subreq
, 1);
4119 if (tevent_req_nterror(req
, status
)) {
4120 return tevent_req_post(req
, ev
);
4122 tevent_req_set_cancel_fn(req
, cli_lockingx_cancel
);
4126 static void cli_lockingx_done(struct tevent_req
*subreq
)
4128 NTSTATUS status
= cli_smb_recv(
4129 subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
4130 tevent_req_simple_finish_ntstatus(subreq
, status
);
4133 static bool cli_lockingx_cancel(struct tevent_req
*req
)
4135 struct cli_lockingx_state
*state
= tevent_req_data(
4136 req
, struct cli_lockingx_state
);
4137 if (state
->subreq
== NULL
) {
4140 return tevent_req_cancel(state
->subreq
);
4143 NTSTATUS
cli_lockingx_recv(struct tevent_req
*req
)
4145 return tevent_req_simple_recv_ntstatus(req
);
4148 NTSTATUS
cli_lockingx(
4149 struct cli_state
*cli
,
4152 uint8_t newoplocklevel
,
4154 uint16_t num_unlocks
,
4155 const struct smb1_lock_element
*unlocks
,
4157 const struct smb1_lock_element
*locks
)
4159 TALLOC_CTX
*frame
= talloc_stackframe();
4160 struct tevent_context
*ev
= NULL
;
4161 struct tevent_req
*req
= NULL
;
4162 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4163 unsigned int set_timeout
= 0;
4164 unsigned int saved_timeout
= 0;
4166 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4167 return NT_STATUS_INVALID_PARAMETER
;
4169 ev
= samba_tevent_context_init(frame
);
4175 if (timeout
== -1) {
4176 set_timeout
= 0x7FFFFFFF;
4178 set_timeout
= timeout
+ 2*1000;
4180 saved_timeout
= cli_set_timeout(cli
, set_timeout
);
4183 req
= cli_lockingx_send(
4198 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4201 status
= cli_lockingx_recv(req
);
4203 if (saved_timeout
!= 0) {
4204 cli_set_timeout(cli
, saved_timeout
);
4211 /****************************************************************************
4212 send a lock with a specified locktype
4213 this is used for testing LOCKING_ANDX_CANCEL_LOCK
4214 ****************************************************************************/
4216 NTSTATUS
cli_locktype(struct cli_state
*cli
, uint16_t fnum
,
4217 uint32_t offset
, uint32_t len
,
4218 int timeout
, unsigned char locktype
)
4220 struct smb1_lock_element lck
= {
4221 .pid
= cli_getpid(cli
),
4227 status
= cli_lockingx(
4230 locktype
, /* typeoflock */
4231 0, /* newoplocklevel */
4232 timeout
, /* timeout */
4233 0, /* num_unlocks */
4240 /****************************************************************************
4242 note that timeout is in units of 2 milliseconds
4243 ****************************************************************************/
4245 NTSTATUS
cli_lock32(struct cli_state
*cli
, uint16_t fnum
,
4246 uint32_t offset
, uint32_t len
, int timeout
,
4247 enum brl_type lock_type
)
4251 status
= cli_locktype(cli
, fnum
, offset
, len
, timeout
,
4252 (lock_type
== READ_LOCK
? 1 : 0));
4256 /****************************************************************************
4258 ****************************************************************************/
4260 struct cli_unlock_state
{
4261 struct smb1_lock_element lck
;
4264 static void cli_unlock_done(struct tevent_req
*subreq
);
4266 struct tevent_req
*cli_unlock_send(TALLOC_CTX
*mem_ctx
,
4267 struct tevent_context
*ev
,
4268 struct cli_state
*cli
,
4274 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4275 struct cli_unlock_state
*state
= NULL
;
4277 req
= tevent_req_create(mem_ctx
, &state
, struct cli_unlock_state
);
4281 state
->lck
= (struct smb1_lock_element
) {
4282 .pid
= cli_getpid(cli
),
4287 subreq
= cli_lockingx_send(
4288 state
, /* mem_ctx */
4289 ev
, /* tevent_context */
4293 0, /* newoplocklevel */
4295 1, /* num_unlocks */
4296 &state
->lck
, /* unlocks */
4299 if (tevent_req_nomem(subreq
, req
)) {
4300 return tevent_req_post(req
, ev
);
4302 tevent_req_set_callback(subreq
, cli_unlock_done
, req
);
4306 static void cli_unlock_done(struct tevent_req
*subreq
)
4308 NTSTATUS status
= cli_lockingx_recv(subreq
);
4309 tevent_req_simple_finish_ntstatus(subreq
, status
);
4312 NTSTATUS
cli_unlock_recv(struct tevent_req
*req
)
4314 return tevent_req_simple_recv_ntstatus(req
);
4317 NTSTATUS
cli_unlock(struct cli_state
*cli
,
4322 TALLOC_CTX
*frame
= talloc_stackframe();
4323 struct tevent_context
*ev
;
4324 struct tevent_req
*req
;
4325 NTSTATUS status
= NT_STATUS_OK
;
4327 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4329 * Can't use sync call while an async call is in flight
4331 status
= NT_STATUS_INVALID_PARAMETER
;
4335 ev
= samba_tevent_context_init(frame
);
4337 status
= NT_STATUS_NO_MEMORY
;
4341 req
= cli_unlock_send(frame
, ev
, cli
,
4344 status
= NT_STATUS_NO_MEMORY
;
4348 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4352 status
= cli_unlock_recv(req
);
4359 /****************************************************************************
4360 Get/unlock a POSIX lock on a file - internal function.
4361 ****************************************************************************/
4363 struct posix_lock_state
{
4366 uint8_t data
[POSIX_LOCK_DATA_SIZE
];
4369 static void cli_posix_unlock_internal_done(struct tevent_req
*subreq
)
4371 NTSTATUS status
= cli_trans_recv(subreq
, NULL
, NULL
, NULL
, 0, NULL
,
4372 NULL
, 0, NULL
, NULL
, 0, NULL
);
4373 tevent_req_simple_finish_ntstatus(subreq
, status
);
4376 static struct tevent_req
*cli_posix_lock_internal_send(TALLOC_CTX
*mem_ctx
,
4377 struct tevent_context
*ev
,
4378 struct cli_state
*cli
,
4383 enum brl_type lock_type
)
4385 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4386 struct posix_lock_state
*state
= NULL
;
4388 req
= tevent_req_create(mem_ctx
, &state
, struct posix_lock_state
);
4393 /* Setup setup word. */
4394 SSVAL(&state
->setup
, 0, TRANSACT2_SETFILEINFO
);
4396 /* Setup param array. */
4397 SSVAL(&state
->param
, 0, fnum
);
4398 SSVAL(&state
->param
, 2, SMB_SET_POSIX_LOCK
);
4400 /* Setup data array. */
4401 switch (lock_type
) {
4403 SSVAL(&state
->data
, POSIX_LOCK_TYPE_OFFSET
,
4404 POSIX_LOCK_TYPE_READ
);
4407 SSVAL(&state
->data
, POSIX_LOCK_TYPE_OFFSET
,
4408 POSIX_LOCK_TYPE_WRITE
);
4411 SSVAL(&state
->data
, POSIX_LOCK_TYPE_OFFSET
,
4412 POSIX_LOCK_TYPE_UNLOCK
);
4419 SSVAL(&state
->data
, POSIX_LOCK_FLAGS_OFFSET
,
4420 POSIX_LOCK_FLAG_WAIT
);
4422 SSVAL(state
->data
, POSIX_LOCK_FLAGS_OFFSET
,
4423 POSIX_LOCK_FLAG_NOWAIT
);
4426 SIVAL(&state
->data
, POSIX_LOCK_PID_OFFSET
, cli_getpid(cli
));
4427 SOFF_T(&state
->data
, POSIX_LOCK_START_OFFSET
, offset
);
4428 SOFF_T(&state
->data
, POSIX_LOCK_LEN_OFFSET
, len
);
4430 subreq
= cli_trans_send(state
, /* mem ctx. */
4431 ev
, /* event ctx. */
4432 cli
, /* cli_state. */
4433 0, /* additional_flags2 */
4434 SMBtrans2
, /* cmd. */
4435 NULL
, /* pipe name. */
4439 &state
->setup
, /* setup. */
4440 1, /* num setup uint16_t words. */
4441 0, /* max returned setup. */
4442 state
->param
, /* param. */
4444 2, /* max returned param. */
4445 state
->data
, /* data. */
4446 POSIX_LOCK_DATA_SIZE
, /* num data. */
4447 0); /* max returned data. */
4449 if (tevent_req_nomem(subreq
, req
)) {
4450 return tevent_req_post(req
, ev
);
4452 tevent_req_set_callback(subreq
, cli_posix_unlock_internal_done
, req
);
4456 /****************************************************************************
4458 ****************************************************************************/
4460 struct tevent_req
*cli_posix_lock_send(TALLOC_CTX
*mem_ctx
,
4461 struct tevent_context
*ev
,
4462 struct cli_state
*cli
,
4467 enum brl_type lock_type
)
4469 return cli_posix_lock_internal_send(mem_ctx
, ev
, cli
, fnum
, offset
, len
,
4470 wait_lock
, lock_type
);
4473 NTSTATUS
cli_posix_lock_recv(struct tevent_req
*req
)
4475 return tevent_req_simple_recv_ntstatus(req
);
4478 NTSTATUS
cli_posix_lock(struct cli_state
*cli
, uint16_t fnum
,
4479 uint64_t offset
, uint64_t len
,
4480 bool wait_lock
, enum brl_type lock_type
)
4482 TALLOC_CTX
*frame
= talloc_stackframe();
4483 struct tevent_context
*ev
= NULL
;
4484 struct tevent_req
*req
= NULL
;
4485 NTSTATUS status
= NT_STATUS_OK
;
4487 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4489 * Can't use sync call while an async call is in flight
4491 status
= NT_STATUS_INVALID_PARAMETER
;
4495 if (lock_type
!= READ_LOCK
&& lock_type
!= WRITE_LOCK
) {
4496 status
= NT_STATUS_INVALID_PARAMETER
;
4500 ev
= samba_tevent_context_init(frame
);
4502 status
= NT_STATUS_NO_MEMORY
;
4506 req
= cli_posix_lock_send(frame
,
4515 status
= NT_STATUS_NO_MEMORY
;
4519 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4523 status
= cli_posix_lock_recv(req
);
4530 /****************************************************************************
4531 POSIX Unlock a file.
4532 ****************************************************************************/
4534 struct tevent_req
*cli_posix_unlock_send(TALLOC_CTX
*mem_ctx
,
4535 struct tevent_context
*ev
,
4536 struct cli_state
*cli
,
4541 return cli_posix_lock_internal_send(mem_ctx
, ev
, cli
, fnum
, offset
, len
,
4542 false, UNLOCK_LOCK
);
4545 NTSTATUS
cli_posix_unlock_recv(struct tevent_req
*req
)
4547 return tevent_req_simple_recv_ntstatus(req
);
4550 NTSTATUS
cli_posix_unlock(struct cli_state
*cli
, uint16_t fnum
, uint64_t offset
, uint64_t len
)
4552 TALLOC_CTX
*frame
= talloc_stackframe();
4553 struct tevent_context
*ev
= NULL
;
4554 struct tevent_req
*req
= NULL
;
4555 NTSTATUS status
= NT_STATUS_OK
;
4557 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4559 * Can't use sync call while an async call is in flight
4561 status
= NT_STATUS_INVALID_PARAMETER
;
4565 ev
= samba_tevent_context_init(frame
);
4567 status
= NT_STATUS_NO_MEMORY
;
4571 req
= cli_posix_unlock_send(frame
,
4578 status
= NT_STATUS_NO_MEMORY
;
4582 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4586 status
= cli_posix_unlock_recv(req
);
4593 /****************************************************************************
4594 Do a SMBgetattrE call.
4595 ****************************************************************************/
4597 static void cli_getattrE_done(struct tevent_req
*subreq
);
4599 struct cli_getattrE_state
{
4609 struct tevent_req
*cli_getattrE_send(TALLOC_CTX
*mem_ctx
,
4610 struct tevent_context
*ev
,
4611 struct cli_state
*cli
,
4614 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4615 struct cli_getattrE_state
*state
= NULL
;
4616 uint8_t additional_flags
= 0;
4618 req
= tevent_req_create(mem_ctx
, &state
, struct cli_getattrE_state
);
4623 state
->zone_offset
= smb1cli_conn_server_time_zone(cli
->conn
);
4624 SSVAL(state
->vwv
+0,0,fnum
);
4626 subreq
= cli_smb_send(state
, ev
, cli
, SMBgetattrE
, additional_flags
, 0,
4627 1, state
->vwv
, 0, NULL
);
4628 if (tevent_req_nomem(subreq
, req
)) {
4629 return tevent_req_post(req
, ev
);
4631 tevent_req_set_callback(subreq
, cli_getattrE_done
, req
);
4635 static void cli_getattrE_done(struct tevent_req
*subreq
)
4637 struct tevent_req
*req
= tevent_req_callback_data(
4638 subreq
, struct tevent_req
);
4639 struct cli_getattrE_state
*state
= tevent_req_data(
4640 req
, struct cli_getattrE_state
);
4642 uint16_t *vwv
= NULL
;
4645 status
= cli_smb_recv(subreq
, state
, NULL
, 11, &wct
, &vwv
,
4647 TALLOC_FREE(subreq
);
4648 if (tevent_req_nterror(req
, status
)) {
4652 state
->size
= (off_t
)IVAL(vwv
+6,0);
4653 state
->attr
= SVAL(vwv
+10,0);
4654 state
->change_time
= make_unix_date2(vwv
+0, state
->zone_offset
);
4655 state
->access_time
= make_unix_date2(vwv
+2, state
->zone_offset
);
4656 state
->write_time
= make_unix_date2(vwv
+4, state
->zone_offset
);
4658 tevent_req_done(req
);
4661 NTSTATUS
cli_getattrE_recv(struct tevent_req
*req
,
4664 time_t *change_time
,
4665 time_t *access_time
,
4668 struct cli_getattrE_state
*state
= tevent_req_data(
4669 req
, struct cli_getattrE_state
);
4672 if (tevent_req_is_nterror(req
, &status
)) {
4676 *pattr
= state
->attr
;
4679 *size
= state
->size
;
4682 *change_time
= state
->change_time
;
4685 *access_time
= state
->access_time
;
4688 *write_time
= state
->write_time
;
4690 return NT_STATUS_OK
;
4693 /****************************************************************************
4695 ****************************************************************************/
4697 static void cli_getatr_done(struct tevent_req
*subreq
);
4699 struct cli_getatr_state
{
4706 struct tevent_req
*cli_getatr_send(TALLOC_CTX
*mem_ctx
,
4707 struct tevent_context
*ev
,
4708 struct cli_state
*cli
,
4711 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4712 struct cli_getatr_state
*state
= NULL
;
4713 uint8_t additional_flags
= 0;
4714 uint16_t additional_flags2
= 0;
4715 uint8_t *bytes
= NULL
;
4716 char *fname_cp
= NULL
;
4718 req
= tevent_req_create(mem_ctx
, &state
, struct cli_getatr_state
);
4723 state
->zone_offset
= smb1cli_conn_server_time_zone(cli
->conn
);
4725 bytes
= talloc_array(state
, uint8_t, 1);
4726 if (tevent_req_nomem(bytes
, req
)) {
4727 return tevent_req_post(req
, ev
);
4730 * SMBgetatr on a DFS share must use DFS names.
4732 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
4733 if (tevent_req_nomem(fname_cp
, req
)) {
4734 return tevent_req_post(req
, ev
);
4737 bytes
= smb_bytes_push_str(bytes
,
4738 smbXcli_conn_use_unicode(cli
->conn
),
4743 if (tevent_req_nomem(bytes
, req
)) {
4744 return tevent_req_post(req
, ev
);
4747 if (clistr_is_previous_version_path(fname
)) {
4748 additional_flags2
= FLAGS2_REPARSE_PATH
;
4751 subreq
= cli_smb_send(state
, ev
, cli
, SMBgetatr
, additional_flags
,
4753 0, NULL
, talloc_get_size(bytes
), bytes
);
4754 if (tevent_req_nomem(subreq
, req
)) {
4755 return tevent_req_post(req
, ev
);
4757 tevent_req_set_callback(subreq
, cli_getatr_done
, req
);
4761 static void cli_getatr_done(struct tevent_req
*subreq
)
4763 struct tevent_req
*req
= tevent_req_callback_data(
4764 subreq
, struct tevent_req
);
4765 struct cli_getatr_state
*state
= tevent_req_data(
4766 req
, struct cli_getatr_state
);
4768 uint16_t *vwv
= NULL
;
4771 status
= cli_smb_recv(subreq
, state
, NULL
, 4, &wct
, &vwv
, NULL
,
4773 TALLOC_FREE(subreq
);
4774 if (tevent_req_nterror(req
, status
)) {
4778 state
->attr
= SVAL(vwv
+0,0);
4779 state
->size
= (off_t
)IVAL(vwv
+3,0);
4780 state
->write_time
= make_unix_date3(vwv
+1, state
->zone_offset
);
4782 tevent_req_done(req
);
4785 NTSTATUS
cli_getatr_recv(struct tevent_req
*req
,
4790 struct cli_getatr_state
*state
= tevent_req_data(
4791 req
, struct cli_getatr_state
);
4794 if (tevent_req_is_nterror(req
, &status
)) {
4798 *pattr
= state
->attr
;
4801 *size
= state
->size
;
4804 *write_time
= state
->write_time
;
4806 return NT_STATUS_OK
;
4809 NTSTATUS
cli_getatr(struct cli_state
*cli
,
4815 TALLOC_CTX
*frame
= NULL
;
4816 struct tevent_context
*ev
= NULL
;
4817 struct tevent_req
*req
= NULL
;
4818 NTSTATUS status
= NT_STATUS_OK
;
4820 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
4821 struct stat_ex sbuf
= {
4826 status
= cli_smb2_qpathinfo_basic(cli
, fname
, &sbuf
, &attr
);
4827 if (!NT_STATUS_IS_OK(status
)) {
4831 if (pattr
!= NULL
) {
4835 *size
= sbuf
.st_ex_size
;
4837 if (write_time
!= NULL
) {
4838 *write_time
= sbuf
.st_ex_mtime
.tv_sec
;
4840 return NT_STATUS_OK
;
4843 frame
= talloc_stackframe();
4845 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4847 * Can't use sync call while an async call is in flight
4849 status
= NT_STATUS_INVALID_PARAMETER
;
4853 ev
= samba_tevent_context_init(frame
);
4855 status
= NT_STATUS_NO_MEMORY
;
4859 req
= cli_getatr_send(frame
, ev
, cli
, fname
);
4861 status
= NT_STATUS_NO_MEMORY
;
4865 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4869 status
= cli_getatr_recv(req
,
4879 /****************************************************************************
4880 Do a SMBsetattrE call.
4881 ****************************************************************************/
4883 static void cli_setattrE_done(struct tevent_req
*subreq
);
4885 struct cli_setattrE_state
{
4889 struct tevent_req
*cli_setattrE_send(TALLOC_CTX
*mem_ctx
,
4890 struct tevent_context
*ev
,
4891 struct cli_state
*cli
,
4897 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4898 struct cli_setattrE_state
*state
= NULL
;
4899 uint8_t additional_flags
= 0;
4901 req
= tevent_req_create(mem_ctx
, &state
, struct cli_setattrE_state
);
4906 SSVAL(state
->vwv
+0, 0, fnum
);
4907 push_dos_date2((uint8_t *)&state
->vwv
[1], 0, change_time
,
4908 smb1cli_conn_server_time_zone(cli
->conn
));
4909 push_dos_date2((uint8_t *)&state
->vwv
[3], 0, access_time
,
4910 smb1cli_conn_server_time_zone(cli
->conn
));
4911 push_dos_date2((uint8_t *)&state
->vwv
[5], 0, write_time
,
4912 smb1cli_conn_server_time_zone(cli
->conn
));
4914 subreq
= cli_smb_send(state
, ev
, cli
, SMBsetattrE
, additional_flags
, 0,
4915 7, state
->vwv
, 0, NULL
);
4916 if (tevent_req_nomem(subreq
, req
)) {
4917 return tevent_req_post(req
, ev
);
4919 tevent_req_set_callback(subreq
, cli_setattrE_done
, req
);
4923 static void cli_setattrE_done(struct tevent_req
*subreq
)
4925 struct tevent_req
*req
= tevent_req_callback_data(
4926 subreq
, struct tevent_req
);
4929 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
4930 TALLOC_FREE(subreq
);
4931 if (tevent_req_nterror(req
, status
)) {
4934 tevent_req_done(req
);
4937 NTSTATUS
cli_setattrE_recv(struct tevent_req
*req
)
4939 return tevent_req_simple_recv_ntstatus(req
);
4942 NTSTATUS
cli_setattrE(struct cli_state
*cli
,
4948 TALLOC_CTX
*frame
= NULL
;
4949 struct tevent_context
*ev
= NULL
;
4950 struct tevent_req
*req
= NULL
;
4951 NTSTATUS status
= NT_STATUS_OK
;
4953 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
4954 return cli_smb2_setattrE(cli
,
4961 frame
= talloc_stackframe();
4963 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4965 * Can't use sync call while an async call is in flight
4967 status
= NT_STATUS_INVALID_PARAMETER
;
4971 ev
= samba_tevent_context_init(frame
);
4973 status
= NT_STATUS_NO_MEMORY
;
4977 req
= cli_setattrE_send(frame
, ev
,
4985 status
= NT_STATUS_NO_MEMORY
;
4989 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4993 status
= cli_setattrE_recv(req
);
5000 /****************************************************************************
5001 Do a SMBsetatr call.
5002 ****************************************************************************/
5004 static void cli_setatr_done(struct tevent_req
*subreq
);
5006 struct cli_setatr_state
{
5010 struct tevent_req
*cli_setatr_send(TALLOC_CTX
*mem_ctx
,
5011 struct tevent_context
*ev
,
5012 struct cli_state
*cli
,
5017 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5018 struct cli_setatr_state
*state
= NULL
;
5019 uint8_t additional_flags
= 0;
5020 uint16_t additional_flags2
= 0;
5021 uint8_t *bytes
= NULL
;
5022 char *fname_cp
= NULL
;
5024 req
= tevent_req_create(mem_ctx
, &state
, struct cli_setatr_state
);
5029 if (attr
& 0xFFFF0000) {
5031 * Don't allow attributes greater than
5032 * 16-bits for a 16-bit protocol value.
5034 if (tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
)) {
5035 return tevent_req_post(req
, ev
);
5039 SSVAL(state
->vwv
+0, 0, attr
);
5040 push_dos_date3((uint8_t *)&state
->vwv
[1], 0, mtime
, smb1cli_conn_server_time_zone(cli
->conn
));
5042 bytes
= talloc_array(state
, uint8_t, 1);
5043 if (tevent_req_nomem(bytes
, req
)) {
5044 return tevent_req_post(req
, ev
);
5047 * SMBsetatr on a DFS share must use DFS names.
5049 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
5050 if (tevent_req_nomem(fname_cp
, req
)) {
5051 return tevent_req_post(req
, ev
);
5054 bytes
= smb_bytes_push_str(bytes
,
5055 smbXcli_conn_use_unicode(cli
->conn
),
5059 if (tevent_req_nomem(bytes
, req
)) {
5060 return tevent_req_post(req
, ev
);
5062 bytes
= talloc_realloc(state
, bytes
, uint8_t,
5063 talloc_get_size(bytes
)+1);
5064 if (tevent_req_nomem(bytes
, req
)) {
5065 return tevent_req_post(req
, ev
);
5068 bytes
[talloc_get_size(bytes
)-1] = 4;
5069 bytes
= smb_bytes_push_str(bytes
, smbXcli_conn_use_unicode(cli
->conn
), "",
5071 if (tevent_req_nomem(bytes
, req
)) {
5072 return tevent_req_post(req
, ev
);
5075 if (clistr_is_previous_version_path(fname
)) {
5076 additional_flags2
= FLAGS2_REPARSE_PATH
;
5079 subreq
= cli_smb_send(state
, ev
, cli
, SMBsetatr
, additional_flags
,
5081 8, state
->vwv
, talloc_get_size(bytes
), bytes
);
5082 if (tevent_req_nomem(subreq
, req
)) {
5083 return tevent_req_post(req
, ev
);
5085 tevent_req_set_callback(subreq
, cli_setatr_done
, req
);
5089 static void cli_setatr_done(struct tevent_req
*subreq
)
5091 struct tevent_req
*req
= tevent_req_callback_data(
5092 subreq
, struct tevent_req
);
5095 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
5096 TALLOC_FREE(subreq
);
5097 if (tevent_req_nterror(req
, status
)) {
5100 tevent_req_done(req
);
5103 NTSTATUS
cli_setatr_recv(struct tevent_req
*req
)
5105 return tevent_req_simple_recv_ntstatus(req
);
5108 NTSTATUS
cli_setatr(struct cli_state
*cli
,
5113 TALLOC_CTX
*frame
= NULL
;
5114 struct tevent_context
*ev
= NULL
;
5115 struct tevent_req
*req
= NULL
;
5116 NTSTATUS status
= NT_STATUS_OK
;
5118 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
5119 return cli_smb2_setatr(cli
,
5125 frame
= talloc_stackframe();
5127 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
5129 * Can't use sync call while an async call is in flight
5131 status
= NT_STATUS_INVALID_PARAMETER
;
5135 ev
= samba_tevent_context_init(frame
);
5137 status
= NT_STATUS_NO_MEMORY
;
5141 req
= cli_setatr_send(frame
, ev
, cli
, fname
, attr
, mtime
);
5143 status
= NT_STATUS_NO_MEMORY
;
5147 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5151 status
= cli_setatr_recv(req
);
5158 /****************************************************************************
5159 Check for existence of a dir.
5160 ****************************************************************************/
5162 static void cli_chkpath_done(struct tevent_req
*subreq
);
5163 static void cli_chkpath_opened(struct tevent_req
*subreq
);
5164 static void cli_chkpath_closed(struct tevent_req
*subreq
);
5166 struct cli_chkpath_state
{
5167 struct tevent_context
*ev
;
5168 struct cli_state
*cli
;
5171 struct tevent_req
*cli_chkpath_send(TALLOC_CTX
*mem_ctx
,
5172 struct tevent_context
*ev
,
5173 struct cli_state
*cli
,
5176 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5177 struct cli_chkpath_state
*state
= NULL
;
5178 uint8_t additional_flags
= 0;
5179 uint16_t additional_flags2
= 0;
5180 uint8_t *bytes
= NULL
;
5181 char *fname_cp
= NULL
;
5183 req
= tevent_req_create(mem_ctx
, &state
, struct cli_chkpath_state
);
5190 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_NT1
) {
5191 subreq
= cli_ntcreate_send(
5192 state
, /* mem_ctx */
5194 state
->cli
, /* cli */
5196 0, /* create_flags */
5197 FILE_READ_ATTRIBUTES
, /* desired_access */
5198 FILE_ATTRIBUTE_DIRECTORY
, /* FileAttributes */
5201 FILE_SHARE_DELETE
, /* share_access */
5202 FILE_OPEN
, /* CreateDisposition */
5203 FILE_DIRECTORY_FILE
, /* CreateOptions */
5204 SMB2_IMPERSONATION_IMPERSONATION
,
5205 0); /* SecurityFlags */
5206 if (tevent_req_nomem(subreq
, req
)) {
5207 return tevent_req_post(req
, ev
);
5209 tevent_req_set_callback(subreq
, cli_chkpath_opened
, req
);
5213 bytes
= talloc_array(state
, uint8_t, 1);
5214 if (tevent_req_nomem(bytes
, req
)) {
5215 return tevent_req_post(req
, ev
);
5218 * SMBcheckpath on a DFS share must use DFS names.
5220 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
5221 if (tevent_req_nomem(fname_cp
, req
)) {
5222 return tevent_req_post(req
, ev
);
5225 bytes
= smb_bytes_push_str(bytes
,
5226 smbXcli_conn_use_unicode(cli
->conn
),
5231 if (tevent_req_nomem(bytes
, req
)) {
5232 return tevent_req_post(req
, ev
);
5235 if (clistr_is_previous_version_path(fname
)) {
5236 additional_flags2
= FLAGS2_REPARSE_PATH
;
5239 subreq
= cli_smb_send(state
, ev
, cli
, SMBcheckpath
, additional_flags
,
5241 0, NULL
, talloc_get_size(bytes
), bytes
);
5242 if (tevent_req_nomem(subreq
, req
)) {
5243 return tevent_req_post(req
, ev
);
5245 tevent_req_set_callback(subreq
, cli_chkpath_done
, req
);
5249 static void cli_chkpath_done(struct tevent_req
*subreq
)
5251 NTSTATUS status
= cli_smb_recv(
5252 subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
5253 tevent_req_simple_finish_ntstatus(subreq
, status
);
5256 static void cli_chkpath_opened(struct tevent_req
*subreq
)
5258 struct tevent_req
*req
= tevent_req_callback_data(
5259 subreq
, struct tevent_req
);
5260 struct cli_chkpath_state
*state
= tevent_req_data(
5261 req
, struct cli_chkpath_state
);
5265 status
= cli_ntcreate_recv(subreq
, &fnum
, NULL
);
5266 TALLOC_FREE(subreq
);
5267 if (tevent_req_nterror(req
, status
)) {
5271 subreq
= cli_close_send(state
, state
->ev
, state
->cli
, fnum
, 0);
5272 if (tevent_req_nomem(subreq
, req
)) {
5275 tevent_req_set_callback(subreq
, cli_chkpath_closed
, req
);
5278 static void cli_chkpath_closed(struct tevent_req
*subreq
)
5280 NTSTATUS status
= cli_close_recv(subreq
);
5281 tevent_req_simple_finish_ntstatus(subreq
, status
);
5284 NTSTATUS
cli_chkpath_recv(struct tevent_req
*req
)
5286 return tevent_req_simple_recv_ntstatus(req
);
5289 NTSTATUS
cli_chkpath(struct cli_state
*cli
, const char *path
)
5291 TALLOC_CTX
*frame
= NULL
;
5292 struct tevent_context
*ev
= NULL
;
5293 struct tevent_req
*req
= NULL
;
5295 NTSTATUS status
= NT_STATUS_OK
;
5297 frame
= talloc_stackframe();
5299 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
5301 * Can't use sync call while an async call is in flight
5303 status
= NT_STATUS_INVALID_PARAMETER
;
5307 path2
= talloc_strdup(frame
, path
);
5309 status
= NT_STATUS_NO_MEMORY
;
5312 trim_char(path2
,'\0','\\');
5314 path2
= talloc_strdup(frame
, "\\");
5316 status
= NT_STATUS_NO_MEMORY
;
5321 ev
= samba_tevent_context_init(frame
);
5323 status
= NT_STATUS_NO_MEMORY
;
5327 req
= cli_chkpath_send(frame
, ev
, cli
, path2
);
5329 status
= NT_STATUS_NO_MEMORY
;
5333 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5337 status
= cli_chkpath_recv(req
);
5343 /****************************************************************************
5345 ****************************************************************************/
5347 static void cli_dskattr_done(struct tevent_req
*subreq
);
5349 struct cli_dskattr_state
{
5355 struct tevent_req
*cli_dskattr_send(TALLOC_CTX
*mem_ctx
,
5356 struct tevent_context
*ev
,
5357 struct cli_state
*cli
)
5359 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5360 struct cli_dskattr_state
*state
= NULL
;
5361 uint8_t additional_flags
= 0;
5363 req
= tevent_req_create(mem_ctx
, &state
, struct cli_dskattr_state
);
5368 subreq
= cli_smb_send(state
, ev
, cli
, SMBdskattr
, additional_flags
, 0,
5370 if (tevent_req_nomem(subreq
, req
)) {
5371 return tevent_req_post(req
, ev
);
5373 tevent_req_set_callback(subreq
, cli_dskattr_done
, req
);
5377 static void cli_dskattr_done(struct tevent_req
*subreq
)
5379 struct tevent_req
*req
= tevent_req_callback_data(
5380 subreq
, struct tevent_req
);
5381 struct cli_dskattr_state
*state
= tevent_req_data(
5382 req
, struct cli_dskattr_state
);
5384 uint16_t *vwv
= NULL
;
5387 status
= cli_smb_recv(subreq
, state
, NULL
, 4, &wct
, &vwv
, NULL
,
5389 TALLOC_FREE(subreq
);
5390 if (tevent_req_nterror(req
, status
)) {
5393 state
->bsize
= SVAL(vwv
+1, 0)*SVAL(vwv
+2,0);
5394 state
->total
= SVAL(vwv
+0, 0);
5395 state
->avail
= SVAL(vwv
+3, 0);
5396 tevent_req_done(req
);
5399 NTSTATUS
cli_dskattr_recv(struct tevent_req
*req
, int *bsize
, int *total
, int *avail
)
5401 struct cli_dskattr_state
*state
= tevent_req_data(
5402 req
, struct cli_dskattr_state
);
5405 if (tevent_req_is_nterror(req
, &status
)) {
5408 *bsize
= state
->bsize
;
5409 *total
= state
->total
;
5410 *avail
= state
->avail
;
5411 return NT_STATUS_OK
;
5414 NTSTATUS
cli_dskattr(struct cli_state
*cli
, int *bsize
, int *total
, int *avail
)
5416 TALLOC_CTX
*frame
= NULL
;
5417 struct tevent_context
*ev
= NULL
;
5418 struct tevent_req
*req
= NULL
;
5419 NTSTATUS status
= NT_STATUS_OK
;
5421 frame
= talloc_stackframe();
5423 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
5425 * Can't use sync call while an async call is in flight
5427 status
= NT_STATUS_INVALID_PARAMETER
;
5431 ev
= samba_tevent_context_init(frame
);
5433 status
= NT_STATUS_NO_MEMORY
;
5437 req
= cli_dskattr_send(frame
, ev
, cli
);
5439 status
= NT_STATUS_NO_MEMORY
;
5443 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5447 status
= cli_dskattr_recv(req
, bsize
, total
, avail
);
5454 NTSTATUS
cli_disk_size(struct cli_state
*cli
, const char *path
, uint64_t *bsize
,
5455 uint64_t *total
, uint64_t *avail
)
5457 uint64_t sectors_per_block
;
5458 uint64_t bytes_per_sector
;
5459 int old_bsize
= 0, old_total
= 0, old_avail
= 0;
5462 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
5463 return cli_smb2_dskattr(cli
, path
, bsize
, total
, avail
);
5467 * Try the trans2 disk full size info call first.
5468 * We already use this in SMBC_fstatvfs_ctx().
5469 * Ignore 'actual_available_units' as we only
5470 * care about the quota for the caller.
5473 status
= cli_get_fs_full_size_info(cli
,
5480 /* Try and cope will all variants of "we don't do this call"
5481 and fall back to cli_dskattr. */
5483 if (NT_STATUS_EQUAL(status
,NT_STATUS_NOT_IMPLEMENTED
) ||
5484 NT_STATUS_EQUAL(status
,NT_STATUS_NOT_SUPPORTED
) ||
5485 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_INFO_CLASS
) ||
5486 NT_STATUS_EQUAL(status
,NT_STATUS_PROCEDURE_NOT_FOUND
) ||
5487 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_LEVEL
) ||
5488 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_PARAMETER
) ||
5489 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_DEVICE_REQUEST
) ||
5490 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_DEVICE_STATE
) ||
5491 NT_STATUS_EQUAL(status
,NT_STATUS_CTL_FILE_NOT_SUPPORTED
) ||
5492 NT_STATUS_EQUAL(status
,NT_STATUS_UNSUCCESSFUL
)) {
5496 if (!NT_STATUS_IS_OK(status
)) {
5501 *bsize
= sectors_per_block
*
5505 return NT_STATUS_OK
;
5509 /* Old SMB1 core protocol fallback. */
5510 status
= cli_dskattr(cli
, &old_bsize
, &old_total
, &old_avail
);
5511 if (!NT_STATUS_IS_OK(status
)) {
5515 *bsize
= (uint64_t)old_bsize
;
5518 *total
= (uint64_t)old_total
;
5521 *avail
= (uint64_t)old_avail
;
5523 return NT_STATUS_OK
;
5526 /****************************************************************************
5527 Create and open a temporary file.
5528 ****************************************************************************/
5530 static void cli_ctemp_done(struct tevent_req
*subreq
);
5532 struct ctemp_state
{
5538 struct tevent_req
*cli_ctemp_send(TALLOC_CTX
*mem_ctx
,
5539 struct tevent_context
*ev
,
5540 struct cli_state
*cli
,
5543 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5544 struct ctemp_state
*state
= NULL
;
5545 uint8_t additional_flags
= 0;
5546 uint16_t additional_flags2
= 0;
5547 uint8_t *bytes
= NULL
;
5548 char *path_cp
= NULL
;
5550 req
= tevent_req_create(mem_ctx
, &state
, struct ctemp_state
);
5555 SSVAL(state
->vwv
,0,0);
5556 SIVALS(state
->vwv
+1,0,-1);
5558 bytes
= talloc_array(state
, uint8_t, 1);
5559 if (tevent_req_nomem(bytes
, req
)) {
5560 return tevent_req_post(req
, ev
);
5563 * SMBctemp on a DFS share must use DFS names.
5565 path_cp
= smb1_dfs_share_path(state
, cli
, path
);
5566 if (tevent_req_nomem(path_cp
, req
)) {
5567 return tevent_req_post(req
, ev
);
5570 bytes
= smb_bytes_push_str(bytes
,
5571 smbXcli_conn_use_unicode(cli
->conn
),
5575 if (tevent_req_nomem(bytes
, req
)) {
5576 return tevent_req_post(req
, ev
);
5579 if (clistr_is_previous_version_path(path
)) {
5580 additional_flags2
= FLAGS2_REPARSE_PATH
;
5583 subreq
= cli_smb_send(state
, ev
, cli
, SMBctemp
, additional_flags
,
5585 3, state
->vwv
, talloc_get_size(bytes
), bytes
);
5586 if (tevent_req_nomem(subreq
, req
)) {
5587 return tevent_req_post(req
, ev
);
5589 tevent_req_set_callback(subreq
, cli_ctemp_done
, req
);
5593 static void cli_ctemp_done(struct tevent_req
*subreq
)
5595 struct tevent_req
*req
= tevent_req_callback_data(
5596 subreq
, struct tevent_req
);
5597 struct ctemp_state
*state
= tevent_req_data(
5598 req
, struct ctemp_state
);
5602 uint32_t num_bytes
= 0;
5603 uint8_t *bytes
= NULL
;
5605 status
= cli_smb_recv(subreq
, state
, NULL
, 1, &wcnt
, &vwv
,
5606 &num_bytes
, &bytes
);
5607 TALLOC_FREE(subreq
);
5608 if (tevent_req_nterror(req
, status
)) {
5612 state
->fnum
= SVAL(vwv
+0, 0);
5614 /* From W2K3, the result is just the ASCII name */
5615 if (num_bytes
< 2) {
5616 tevent_req_nterror(req
, NT_STATUS_DATA_ERROR
);
5620 if (pull_string_talloc(state
,
5627 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
5630 tevent_req_done(req
);
5633 NTSTATUS
cli_ctemp_recv(struct tevent_req
*req
,
5638 struct ctemp_state
*state
= tevent_req_data(req
,
5639 struct ctemp_state
);
5642 if (tevent_req_is_nterror(req
, &status
)) {
5645 *pfnum
= state
->fnum
;
5646 *outfile
= talloc_strdup(ctx
, state
->ret_path
);
5648 return NT_STATUS_NO_MEMORY
;
5650 return NT_STATUS_OK
;
5653 NTSTATUS
cli_ctemp(struct cli_state
*cli
,
5659 TALLOC_CTX
*frame
= talloc_stackframe();
5660 struct tevent_context
*ev
;
5661 struct tevent_req
*req
;
5662 NTSTATUS status
= NT_STATUS_OK
;
5664 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
5666 * Can't use sync call while an async call is in flight
5668 status
= NT_STATUS_INVALID_PARAMETER
;
5672 ev
= samba_tevent_context_init(frame
);
5674 status
= NT_STATUS_NO_MEMORY
;
5678 req
= cli_ctemp_send(frame
, ev
, cli
, path
);
5680 status
= NT_STATUS_NO_MEMORY
;
5684 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5688 status
= cli_ctemp_recv(req
, ctx
, pfnum
, out_path
);
5695 /*********************************************************
5696 Set an extended attribute utility fn.
5697 *********************************************************/
5699 static NTSTATUS
cli_set_ea(struct cli_state
*cli
, uint16_t setup_val
,
5700 uint8_t *param
, unsigned int param_len
,
5701 const char *ea_name
,
5702 const char *ea_val
, size_t ea_len
)
5705 unsigned int data_len
= 0;
5706 uint8_t *data
= NULL
;
5708 size_t ea_namelen
= strlen(ea_name
);
5711 SSVAL(setup
, 0, setup_val
);
5713 if (ea_namelen
== 0 && ea_len
== 0) {
5715 data
= talloc_array(talloc_tos(),
5719 return NT_STATUS_NO_MEMORY
;
5722 SIVAL(p
,0,data_len
);
5724 data_len
= 4 + 4 + ea_namelen
+ 1 + ea_len
;
5725 data
= talloc_array(talloc_tos(),
5729 return NT_STATUS_NO_MEMORY
;
5732 SIVAL(p
,0,data_len
);
5734 SCVAL(p
, 0, 0); /* EA flags. */
5735 SCVAL(p
, 1, ea_namelen
);
5736 SSVAL(p
, 2, ea_len
);
5737 memcpy(p
+4, ea_name
, ea_namelen
+1); /* Copy in the name. */
5738 memcpy(p
+4+ea_namelen
+1, ea_val
, ea_len
);
5742 * FIXME - if we want to do previous version path
5743 * processing on an EA set call we need to turn this
5744 * into calls to cli_trans_send()/cli_trans_recv()
5745 * with a temporary event context, as cli_trans_send()
5746 * have access to the additional_flags2 needed to
5747 * send @GMT- paths. JRA.
5750 status
= cli_trans(talloc_tos(), cli
, SMBtrans2
, NULL
, -1, 0, 0,
5752 param
, param_len
, 2,
5755 NULL
, 0, NULL
, /* rsetup */
5756 NULL
, 0, NULL
, /* rparam */
5757 NULL
, 0, NULL
); /* rdata */
5762 /*********************************************************
5763 Set an extended attribute on a pathname.
5764 *********************************************************/
5766 NTSTATUS
cli_set_ea_path(struct cli_state
*cli
, const char *path
,
5767 const char *ea_name
, const char *ea_val
,
5770 unsigned int param_len
= 0;
5773 TALLOC_CTX
*frame
= NULL
;
5774 char *path_cp
= NULL
;
5776 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
5777 return cli_smb2_set_ea_path(cli
,
5784 frame
= talloc_stackframe();
5786 param
= talloc_array(frame
, uint8_t, 6);
5788 status
= NT_STATUS_NO_MEMORY
;
5791 SSVAL(param
,0,SMB_INFO_SET_EA
);
5796 * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
5798 path_cp
= smb1_dfs_share_path(frame
, cli
, path
);
5799 if (path_cp
== NULL
) {
5800 status
= NT_STATUS_NO_MEMORY
;
5803 param
= trans2_bytes_push_str(param
,
5804 smbXcli_conn_use_unicode(cli
->conn
),
5808 param_len
= talloc_get_size(param
);
5810 status
= cli_set_ea(cli
, TRANSACT2_SETPATHINFO
, param
, param_len
,
5811 ea_name
, ea_val
, ea_len
);
5819 /*********************************************************
5820 Set an extended attribute on an fnum.
5821 *********************************************************/
5823 NTSTATUS
cli_set_ea_fnum(struct cli_state
*cli
, uint16_t fnum
,
5824 const char *ea_name
, const char *ea_val
,
5827 uint8_t param
[6] = { 0, };
5829 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
5830 return cli_smb2_set_ea_fnum(cli
,
5837 SSVAL(param
,0,fnum
);
5838 SSVAL(param
,2,SMB_INFO_SET_EA
);
5840 return cli_set_ea(cli
, TRANSACT2_SETFILEINFO
, param
, 6,
5841 ea_name
, ea_val
, ea_len
);
5844 /*********************************************************
5845 Get an extended attribute list utility fn.
5846 *********************************************************/
5848 static bool parse_ea_blob(TALLOC_CTX
*ctx
, const uint8_t *rdata
,
5850 size_t *pnum_eas
, struct ea_struct
**pea_list
)
5852 struct ea_struct
*ea_list
= NULL
;
5857 if (rdata_len
< 4) {
5861 ea_size
= (size_t)IVAL(rdata
,0);
5862 if (ea_size
> rdata_len
) {
5867 /* No EA's present. */
5876 /* Validate the EA list and count it. */
5877 for (num_eas
= 0; ea_size
>= 4; num_eas
++) {
5878 unsigned int ea_namelen
= CVAL(p
,1);
5879 unsigned int ea_valuelen
= SVAL(p
,2);
5880 if (ea_namelen
== 0) {
5883 if (4 + ea_namelen
+ 1 + ea_valuelen
> ea_size
) {
5886 ea_size
-= 4 + ea_namelen
+ 1 + ea_valuelen
;
5887 p
+= 4 + ea_namelen
+ 1 + ea_valuelen
;
5896 *pnum_eas
= num_eas
;
5898 /* Caller only wants number of EA's. */
5902 ea_list
= talloc_array(ctx
, struct ea_struct
, num_eas
);
5909 for (num_eas
= 0; num_eas
< *pnum_eas
; num_eas
++ ) {
5910 struct ea_struct
*ea
= &ea_list
[num_eas
];
5911 fstring unix_ea_name
;
5912 unsigned int ea_namelen
= CVAL(p
,1);
5913 unsigned int ea_valuelen
= SVAL(p
,2);
5915 ea
->flags
= CVAL(p
,0);
5916 unix_ea_name
[0] = '\0';
5917 pull_ascii(unix_ea_name
, p
+ 4, sizeof(unix_ea_name
), rdata_len
- PTR_DIFF(p
+4, rdata
), STR_TERMINATE
);
5918 ea
->name
= talloc_strdup(ea_list
, unix_ea_name
);
5922 /* Ensure the value is null terminated (in case it's a string). */
5923 ea
->value
= data_blob_talloc(ea_list
, NULL
, ea_valuelen
+ 1);
5924 if (!ea
->value
.data
) {
5928 memcpy(ea
->value
.data
, p
+4+ea_namelen
+1, ea_valuelen
);
5930 ea
->value
.data
[ea_valuelen
] = 0;
5932 p
+= 4 + ea_namelen
+ 1 + ea_valuelen
;
5935 *pea_list
= ea_list
;
5939 TALLOC_FREE(ea_list
);
5943 /*********************************************************
5944 Get an extended attribute list from a pathname.
5945 *********************************************************/
5947 struct cli_get_ea_list_path_state
{
5952 static void cli_get_ea_list_path_done(struct tevent_req
*subreq
);
5954 struct tevent_req
*cli_get_ea_list_path_send(TALLOC_CTX
*mem_ctx
,
5955 struct tevent_context
*ev
,
5956 struct cli_state
*cli
,
5959 struct tevent_req
*req
, *subreq
;
5960 struct cli_get_ea_list_path_state
*state
;
5962 req
= tevent_req_create(mem_ctx
, &state
,
5963 struct cli_get_ea_list_path_state
);
5967 subreq
= cli_qpathinfo_send(state
, ev
, cli
, fname
,
5968 SMB_INFO_QUERY_ALL_EAS
, 4,
5970 if (tevent_req_nomem(subreq
, req
)) {
5971 return tevent_req_post(req
, ev
);
5973 tevent_req_set_callback(subreq
, cli_get_ea_list_path_done
, req
);
5977 static void cli_get_ea_list_path_done(struct tevent_req
*subreq
)
5979 struct tevent_req
*req
= tevent_req_callback_data(
5980 subreq
, struct tevent_req
);
5981 struct cli_get_ea_list_path_state
*state
= tevent_req_data(
5982 req
, struct cli_get_ea_list_path_state
);
5985 status
= cli_qpathinfo_recv(subreq
, state
, &state
->data
,
5987 TALLOC_FREE(subreq
);
5988 if (tevent_req_nterror(req
, status
)) {
5991 tevent_req_done(req
);
5994 NTSTATUS
cli_get_ea_list_path_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
5995 size_t *pnum_eas
, struct ea_struct
**peas
)
5997 struct cli_get_ea_list_path_state
*state
= tevent_req_data(
5998 req
, struct cli_get_ea_list_path_state
);
6001 if (tevent_req_is_nterror(req
, &status
)) {
6004 if (!parse_ea_blob(mem_ctx
, state
->data
, state
->num_data
,
6006 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
6008 return NT_STATUS_OK
;
6011 NTSTATUS
cli_get_ea_list_path(struct cli_state
*cli
, const char *path
,
6014 struct ea_struct
**pea_list
)
6016 TALLOC_CTX
*frame
= NULL
;
6017 struct tevent_context
*ev
= NULL
;
6018 struct tevent_req
*req
= NULL
;
6019 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
6021 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
6022 return cli_smb2_get_ea_list_path(cli
,
6029 frame
= talloc_stackframe();
6031 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6033 * Can't use sync call while an async call is in flight
6035 status
= NT_STATUS_INVALID_PARAMETER
;
6038 ev
= samba_tevent_context_init(frame
);
6042 req
= cli_get_ea_list_path_send(frame
, ev
, cli
, path
);
6046 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6049 status
= cli_get_ea_list_path_recv(req
, ctx
, pnum_eas
, pea_list
);
6055 /****************************************************************************
6056 Convert open "flags" arg to uint32_t on wire.
6057 ****************************************************************************/
6059 static uint32_t open_flags_to_wire(int flags
)
6061 int open_mode
= flags
& O_ACCMODE
;
6064 switch (open_mode
) {
6066 ret
|= SMB_O_WRONLY
;
6073 ret
|= SMB_O_RDONLY
;
6077 if (flags
& O_CREAT
) {
6080 if (flags
& O_EXCL
) {
6083 if (flags
& O_TRUNC
) {
6087 if (flags
& O_SYNC
) {
6091 if (flags
& O_APPEND
) {
6092 ret
|= SMB_O_APPEND
;
6094 #if defined(O_DIRECT)
6095 if (flags
& O_DIRECT
) {
6096 ret
|= SMB_O_DIRECT
;
6099 #if defined(O_DIRECTORY)
6100 if (flags
& O_DIRECTORY
) {
6101 ret
|= SMB_O_DIRECTORY
;
6107 /****************************************************************************
6108 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
6109 ****************************************************************************/
6111 struct cli_posix_open_internal_state
{
6115 uint16_t fnum
; /* Out */
6118 static void cli_posix_open_internal_done(struct tevent_req
*subreq
);
6120 static struct tevent_req
*cli_posix_open_internal_send(TALLOC_CTX
*mem_ctx
,
6121 struct tevent_context
*ev
,
6122 struct cli_state
*cli
,
6124 uint32_t wire_flags
,
6127 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6128 struct cli_posix_open_internal_state
*state
= NULL
;
6129 char *fname_cp
= NULL
;
6131 req
= tevent_req_create(
6132 mem_ctx
, &state
, struct cli_posix_open_internal_state
);
6137 /* Setup setup word. */
6138 SSVAL(&state
->setup
, 0, TRANSACT2_SETPATHINFO
);
6140 /* Setup param array. */
6141 state
->param
= talloc_zero_array(state
, uint8_t, 6);
6142 if (tevent_req_nomem(state
->param
, req
)) {
6143 return tevent_req_post(req
, ev
);
6145 SSVAL(state
->param
, 0, SMB_POSIX_PATH_OPEN
);
6148 * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
6150 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
6151 if (tevent_req_nomem(fname_cp
, req
)) {
6152 return tevent_req_post(req
, ev
);
6154 state
->param
= trans2_bytes_push_str(
6156 smbXcli_conn_use_unicode(cli
->conn
),
6161 if (tevent_req_nomem(state
->param
, req
)) {
6162 return tevent_req_post(req
, ev
);
6165 SIVAL(state
->data
,0,0); /* No oplock. */
6166 SIVAL(state
->data
,4,wire_flags
);
6167 SIVAL(state
->data
,8,unix_perms_to_wire(mode
));
6168 SIVAL(state
->data
,12,0); /* Top bits of perms currently undefined. */
6169 SSVAL(state
->data
,16,SMB_NO_INFO_LEVEL_RETURNED
); /* No info level returned. */
6171 subreq
= cli_trans_send(state
, /* mem ctx. */
6172 ev
, /* event ctx. */
6173 cli
, /* cli_state. */
6174 0, /* additional_flags2 */
6175 SMBtrans2
, /* cmd. */
6176 NULL
, /* pipe name. */
6180 &state
->setup
, /* setup. */
6181 1, /* num setup uint16_t words. */
6182 0, /* max returned setup. */
6183 state
->param
, /* param. */
6184 talloc_get_size(state
->param
),/* num param. */
6185 2, /* max returned param. */
6186 state
->data
, /* data. */
6188 12); /* max returned data. */
6190 if (tevent_req_nomem(subreq
, req
)) {
6191 return tevent_req_post(req
, ev
);
6193 tevent_req_set_callback(subreq
, cli_posix_open_internal_done
, req
);
6197 static void cli_posix_open_internal_done(struct tevent_req
*subreq
)
6199 struct tevent_req
*req
= tevent_req_callback_data(
6200 subreq
, struct tevent_req
);
6201 struct cli_posix_open_internal_state
*state
= tevent_req_data(
6202 req
, struct cli_posix_open_internal_state
);
6207 status
= cli_trans_recv(
6220 TALLOC_FREE(subreq
);
6221 if (tevent_req_nterror(req
, status
)) {
6224 state
->fnum
= SVAL(data
,2);
6225 tevent_req_done(req
);
6228 static NTSTATUS
cli_posix_open_internal_recv(struct tevent_req
*req
,
6231 struct cli_posix_open_internal_state
*state
= tevent_req_data(
6232 req
, struct cli_posix_open_internal_state
);
6235 if (tevent_req_is_nterror(req
, &status
)) {
6238 *pfnum
= state
->fnum
;
6239 return NT_STATUS_OK
;
6242 struct cli_posix_open_state
{
6246 static void cli_posix_open_done(struct tevent_req
*subreq
);
6248 struct tevent_req
*cli_posix_open_send(TALLOC_CTX
*mem_ctx
,
6249 struct tevent_context
*ev
,
6250 struct cli_state
*cli
,
6255 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6256 struct cli_posix_open_state
*state
= NULL
;
6257 uint32_t wire_flags
;
6259 req
= tevent_req_create(mem_ctx
, &state
,
6260 struct cli_posix_open_state
);
6265 wire_flags
= open_flags_to_wire(flags
);
6267 subreq
= cli_posix_open_internal_send(
6268 mem_ctx
, ev
, cli
, fname
, wire_flags
, mode
);
6269 if (tevent_req_nomem(subreq
, req
)) {
6270 return tevent_req_post(req
, ev
);
6272 tevent_req_set_callback(subreq
, cli_posix_open_done
, req
);
6276 static void cli_posix_open_done(struct tevent_req
*subreq
)
6278 struct tevent_req
*req
= tevent_req_callback_data(
6279 subreq
, struct tevent_req
);
6280 struct cli_posix_open_state
*state
= tevent_req_data(
6281 req
, struct cli_posix_open_state
);
6284 status
= cli_posix_open_internal_recv(subreq
, &state
->fnum
);
6285 tevent_req_simple_finish_ntstatus(subreq
, status
);
6288 NTSTATUS
cli_posix_open_recv(struct tevent_req
*req
, uint16_t *pfnum
)
6290 struct cli_posix_open_state
*state
= tevent_req_data(
6291 req
, struct cli_posix_open_state
);
6294 if (tevent_req_is_nterror(req
, &status
)) {
6297 *pfnum
= state
->fnum
;
6298 return NT_STATUS_OK
;
6301 /****************************************************************************
6302 Open - POSIX semantics. Doesn't request oplock.
6303 ****************************************************************************/
6305 NTSTATUS
cli_posix_open(struct cli_state
*cli
, const char *fname
,
6306 int flags
, mode_t mode
, uint16_t *pfnum
)
6309 TALLOC_CTX
*frame
= talloc_stackframe();
6310 struct tevent_context
*ev
= NULL
;
6311 struct tevent_req
*req
= NULL
;
6312 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
6314 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6316 * Can't use sync call while an async call is in flight
6318 status
= NT_STATUS_INVALID_PARAMETER
;
6321 ev
= samba_tevent_context_init(frame
);
6325 req
= cli_posix_open_send(
6326 frame
, ev
, cli
, fname
, flags
, mode
);
6330 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6333 status
= cli_posix_open_recv(req
, pfnum
);
6339 struct cli_posix_mkdir_state
{
6340 struct tevent_context
*ev
;
6341 struct cli_state
*cli
;
6344 static void cli_posix_mkdir_done(struct tevent_req
*subreq
);
6346 struct tevent_req
*cli_posix_mkdir_send(TALLOC_CTX
*mem_ctx
,
6347 struct tevent_context
*ev
,
6348 struct cli_state
*cli
,
6352 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6353 struct cli_posix_mkdir_state
*state
= NULL
;
6354 uint32_t wire_flags
;
6356 req
= tevent_req_create(
6357 mem_ctx
, &state
, struct cli_posix_mkdir_state
);
6364 wire_flags
= SMB_O_CREAT
| SMB_O_DIRECTORY
;
6366 subreq
= cli_posix_open_internal_send(
6367 mem_ctx
, ev
, cli
, fname
, wire_flags
, mode
);
6368 if (tevent_req_nomem(subreq
, req
)) {
6369 return tevent_req_post(req
, ev
);
6371 tevent_req_set_callback(subreq
, cli_posix_mkdir_done
, req
);
6375 static void cli_posix_mkdir_done(struct tevent_req
*subreq
)
6377 struct tevent_req
*req
= tevent_req_callback_data(
6378 subreq
, struct tevent_req
);
6382 status
= cli_posix_open_internal_recv(subreq
, &fnum
);
6383 TALLOC_FREE(subreq
);
6384 if (tevent_req_nterror(req
, status
)) {
6387 tevent_req_done(req
);
6390 NTSTATUS
cli_posix_mkdir_recv(struct tevent_req
*req
)
6392 return tevent_req_simple_recv_ntstatus(req
);
6395 NTSTATUS
cli_posix_mkdir(struct cli_state
*cli
, const char *fname
, mode_t mode
)
6397 TALLOC_CTX
*frame
= talloc_stackframe();
6398 struct tevent_context
*ev
= NULL
;
6399 struct tevent_req
*req
= NULL
;
6400 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
6402 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6404 * Can't use sync call while an async call is in flight
6406 status
= NT_STATUS_INVALID_PARAMETER
;
6410 ev
= samba_tevent_context_init(frame
);
6414 req
= cli_posix_mkdir_send(
6415 frame
, ev
, cli
, fname
, mode
);
6419 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6422 status
= cli_posix_mkdir_recv(req
);
6428 /****************************************************************************
6429 unlink or rmdir - POSIX semantics.
6430 ****************************************************************************/
6432 struct cli_posix_unlink_internal_state
{
6436 static void cli_posix_unlink_internal_done(struct tevent_req
*subreq
);
6438 static struct tevent_req
*cli_posix_unlink_internal_send(TALLOC_CTX
*mem_ctx
,
6439 struct tevent_context
*ev
,
6440 struct cli_state
*cli
,
6444 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6445 struct cli_posix_unlink_internal_state
*state
= NULL
;
6447 req
= tevent_req_create(mem_ctx
, &state
,
6448 struct cli_posix_unlink_internal_state
);
6453 /* Setup data word. */
6454 SSVAL(state
->data
, 0, level
);
6456 subreq
= cli_setpathinfo_send(state
, ev
, cli
,
6457 SMB_POSIX_PATH_UNLINK
,
6459 state
->data
, sizeof(state
->data
));
6460 if (tevent_req_nomem(subreq
, req
)) {
6461 return tevent_req_post(req
, ev
);
6463 tevent_req_set_callback(subreq
, cli_posix_unlink_internal_done
, req
);
6467 static void cli_posix_unlink_internal_done(struct tevent_req
*subreq
)
6469 NTSTATUS status
= cli_setpathinfo_recv(subreq
);
6470 tevent_req_simple_finish_ntstatus(subreq
, status
);
6473 static NTSTATUS
cli_posix_unlink_internal_recv(struct tevent_req
*req
)
6475 return tevent_req_simple_recv_ntstatus(req
);
6478 struct cli_posix_unlink_state
{
6482 static void cli_posix_unlink_done(struct tevent_req
*subreq
);
6484 struct tevent_req
*cli_posix_unlink_send(TALLOC_CTX
*mem_ctx
,
6485 struct tevent_context
*ev
,
6486 struct cli_state
*cli
,
6489 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6490 struct cli_posix_unlink_state
*state
;
6492 req
= tevent_req_create(
6493 mem_ctx
, &state
, struct cli_posix_unlink_state
);
6497 subreq
= cli_posix_unlink_internal_send(
6498 mem_ctx
, ev
, cli
, fname
, SMB_POSIX_UNLINK_FILE_TARGET
);
6499 if (tevent_req_nomem(subreq
, req
)) {
6500 return tevent_req_post(req
, ev
);
6502 tevent_req_set_callback(subreq
, cli_posix_unlink_done
, req
);
6506 static void cli_posix_unlink_done(struct tevent_req
*subreq
)
6508 NTSTATUS status
= cli_posix_unlink_internal_recv(subreq
);
6509 tevent_req_simple_finish_ntstatus(subreq
, status
);
6512 NTSTATUS
cli_posix_unlink_recv(struct tevent_req
*req
)
6514 return tevent_req_simple_recv_ntstatus(req
);
6517 /****************************************************************************
6518 unlink - POSIX semantics.
6519 ****************************************************************************/
6521 NTSTATUS
cli_posix_unlink(struct cli_state
*cli
, const char *fname
)
6523 TALLOC_CTX
*frame
= talloc_stackframe();
6524 struct tevent_context
*ev
= NULL
;
6525 struct tevent_req
*req
= NULL
;
6526 NTSTATUS status
= NT_STATUS_OK
;
6528 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6530 * Can't use sync call while an async call is in flight
6532 status
= NT_STATUS_INVALID_PARAMETER
;
6536 ev
= samba_tevent_context_init(frame
);
6538 status
= NT_STATUS_NO_MEMORY
;
6542 req
= cli_posix_unlink_send(frame
,
6547 status
= NT_STATUS_NO_MEMORY
;
6551 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6555 status
= cli_posix_unlink_recv(req
);
6562 /****************************************************************************
6563 rmdir - POSIX semantics.
6564 ****************************************************************************/
6566 struct cli_posix_rmdir_state
{
6570 static void cli_posix_rmdir_done(struct tevent_req
*subreq
);
6572 struct tevent_req
*cli_posix_rmdir_send(TALLOC_CTX
*mem_ctx
,
6573 struct tevent_context
*ev
,
6574 struct cli_state
*cli
,
6577 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6578 struct cli_posix_rmdir_state
*state
;
6580 req
= tevent_req_create(mem_ctx
, &state
, struct cli_posix_rmdir_state
);
6584 subreq
= cli_posix_unlink_internal_send(
6585 mem_ctx
, ev
, cli
, fname
, SMB_POSIX_UNLINK_DIRECTORY_TARGET
);
6586 if (tevent_req_nomem(subreq
, req
)) {
6587 return tevent_req_post(req
, ev
);
6589 tevent_req_set_callback(subreq
, cli_posix_rmdir_done
, req
);
6593 static void cli_posix_rmdir_done(struct tevent_req
*subreq
)
6595 NTSTATUS status
= cli_posix_unlink_internal_recv(subreq
);
6596 tevent_req_simple_finish_ntstatus(subreq
, status
);
6599 NTSTATUS
cli_posix_rmdir_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
)
6601 return tevent_req_simple_recv_ntstatus(req
);
6604 NTSTATUS
cli_posix_rmdir(struct cli_state
*cli
, const char *fname
)
6606 TALLOC_CTX
*frame
= talloc_stackframe();
6607 struct tevent_context
*ev
= NULL
;
6608 struct tevent_req
*req
= NULL
;
6609 NTSTATUS status
= NT_STATUS_OK
;
6611 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6613 * Can't use sync call while an async call is in flight
6615 status
= NT_STATUS_INVALID_PARAMETER
;
6619 ev
= samba_tevent_context_init(frame
);
6621 status
= NT_STATUS_NO_MEMORY
;
6625 req
= cli_posix_rmdir_send(frame
,
6630 status
= NT_STATUS_NO_MEMORY
;
6634 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6638 status
= cli_posix_rmdir_recv(req
, frame
);
6645 /****************************************************************************
6647 ****************************************************************************/
6649 struct cli_notify_state
{
6650 struct tevent_req
*subreq
;
6652 uint32_t num_changes
;
6653 struct notify_change
*changes
;
6656 static void cli_notify_done(struct tevent_req
*subreq
);
6657 static void cli_notify_done_smb2(struct tevent_req
*subreq
);
6658 static bool cli_notify_cancel(struct tevent_req
*req
);
6660 struct tevent_req
*cli_notify_send(TALLOC_CTX
*mem_ctx
,
6661 struct tevent_context
*ev
,
6662 struct cli_state
*cli
, uint16_t fnum
,
6663 uint32_t buffer_size
,
6664 uint32_t completion_filter
, bool recursive
)
6666 struct tevent_req
*req
;
6667 struct cli_notify_state
*state
;
6668 unsigned old_timeout
;
6670 req
= tevent_req_create(mem_ctx
, &state
, struct cli_notify_state
);
6675 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
6677 * Notifies should not time out
6679 old_timeout
= cli_set_timeout(cli
, 0);
6681 state
->subreq
= cli_smb2_notify_send(
6690 cli_set_timeout(cli
, old_timeout
);
6692 if (tevent_req_nomem(state
->subreq
, req
)) {
6693 return tevent_req_post(req
, ev
);
6695 tevent_req_set_callback(
6696 state
->subreq
, cli_notify_done_smb2
, req
);
6700 SIVAL(state
->setup
, 0, completion_filter
);
6701 SSVAL(state
->setup
, 4, fnum
);
6702 SSVAL(state
->setup
, 6, recursive
);
6705 * Notifies should not time out
6707 old_timeout
= cli_set_timeout(cli
, 0);
6709 state
->subreq
= cli_trans_send(
6710 state
, /* mem ctx. */
6711 ev
, /* event ctx. */
6712 cli
, /* cli_state. */
6713 0, /* additional_flags2 */
6714 SMBnttrans
, /* cmd. */
6715 NULL
, /* pipe name. */
6717 NT_TRANSACT_NOTIFY_CHANGE
, /* function. */
6719 (uint16_t *)state
->setup
, /* setup. */
6720 4, /* num setup uint16_t words. */
6721 0, /* max returned setup. */
6724 buffer_size
, /* max returned param. */
6727 0); /* max returned data. */
6729 cli_set_timeout(cli
, old_timeout
);
6731 if (tevent_req_nomem(state
->subreq
, req
)) {
6732 return tevent_req_post(req
, ev
);
6734 tevent_req_set_callback(state
->subreq
, cli_notify_done
, req
);
6736 tevent_req_set_cancel_fn(req
, cli_notify_cancel
);
6740 static bool cli_notify_cancel(struct tevent_req
*req
)
6742 struct cli_notify_state
*state
= tevent_req_data(
6743 req
, struct cli_notify_state
);
6746 ok
= tevent_req_cancel(state
->subreq
);
6750 static void cli_notify_done(struct tevent_req
*subreq
)
6752 struct tevent_req
*req
= tevent_req_callback_data(
6753 subreq
, struct tevent_req
);
6754 struct cli_notify_state
*state
= tevent_req_data(
6755 req
, struct cli_notify_state
);
6758 uint32_t i
, ofs
, num_params
;
6761 status
= cli_trans_recv(subreq
, talloc_tos(), &flags2
, NULL
, 0, NULL
,
6762 ¶ms
, 0, &num_params
, NULL
, 0, NULL
);
6763 TALLOC_FREE(subreq
);
6764 state
->subreq
= NULL
;
6765 if (tevent_req_nterror(req
, status
)) {
6766 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status
)));
6770 state
->num_changes
= 0;
6773 while (num_params
- ofs
> 12) {
6774 uint32_t next
= IVAL(params
, ofs
);
6775 state
->num_changes
+= 1;
6777 if ((next
== 0) || (ofs
+next
>= num_params
)) {
6783 state
->changes
= talloc_array(state
, struct notify_change
,
6784 state
->num_changes
);
6785 if (tevent_req_nomem(state
->changes
, req
)) {
6786 TALLOC_FREE(params
);
6792 for (i
=0; i
<state
->num_changes
; i
++) {
6793 uint32_t next
= IVAL(params
, ofs
);
6794 uint32_t len
= IVAL(params
, ofs
+8);
6798 if (smb_buffer_oob(num_params
, ofs
+ 12, len
)) {
6799 TALLOC_FREE(params
);
6801 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
6805 state
->changes
[i
].action
= IVAL(params
, ofs
+4);
6806 ret
= pull_string_talloc(state
->changes
,
6812 STR_TERMINATE
|STR_UNICODE
);
6814 TALLOC_FREE(params
);
6815 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
6818 state
->changes
[i
].name
= name
;
6822 TALLOC_FREE(params
);
6823 tevent_req_done(req
);
6826 static void cli_notify_done_smb2(struct tevent_req
*subreq
)
6828 struct tevent_req
*req
= tevent_req_callback_data(
6829 subreq
, struct tevent_req
);
6830 struct cli_notify_state
*state
= tevent_req_data(
6831 req
, struct cli_notify_state
);
6834 status
= cli_smb2_notify_recv(
6838 &state
->num_changes
);
6839 TALLOC_FREE(subreq
);
6840 if (tevent_req_nterror(req
, status
)) {
6843 tevent_req_done(req
);
6846 NTSTATUS
cli_notify_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
6847 uint32_t *pnum_changes
,
6848 struct notify_change
**pchanges
)
6850 struct cli_notify_state
*state
= tevent_req_data(
6851 req
, struct cli_notify_state
);
6854 if (tevent_req_is_nterror(req
, &status
)) {
6858 *pnum_changes
= state
->num_changes
;
6859 *pchanges
= talloc_move(mem_ctx
, &state
->changes
);
6860 return NT_STATUS_OK
;
6863 NTSTATUS
cli_notify(struct cli_state
*cli
, uint16_t fnum
, uint32_t buffer_size
,
6864 uint32_t completion_filter
, bool recursive
,
6865 TALLOC_CTX
*mem_ctx
, uint32_t *pnum_changes
,
6866 struct notify_change
**pchanges
)
6869 struct tevent_context
*ev
;
6870 struct tevent_req
*req
;
6871 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
6873 frame
= talloc_stackframe();
6875 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6877 * Can't use sync call while an async call is in flight
6879 status
= NT_STATUS_INVALID_PARAMETER
;
6882 ev
= samba_tevent_context_init(frame
);
6886 req
= cli_notify_send(ev
, ev
, cli
, fnum
, buffer_size
,
6887 completion_filter
, recursive
);
6891 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6894 status
= cli_notify_recv(req
, mem_ctx
, pnum_changes
, pchanges
);
6900 struct cli_qpathinfo_state
{
6909 static void cli_qpathinfo_done(struct tevent_req
*subreq
);
6910 static void cli_qpathinfo_done2(struct tevent_req
*subreq
);
6912 struct tevent_req
*cli_qpathinfo_send(TALLOC_CTX
*mem_ctx
,
6913 struct tevent_context
*ev
,
6914 struct cli_state
*cli
, const char *fname
,
6915 uint16_t level
, uint32_t min_rdata
,
6918 struct tevent_req
*req
, *subreq
;
6919 struct cli_qpathinfo_state
*state
;
6920 uint16_t additional_flags2
= 0;
6921 char *fname_cp
= NULL
;
6923 req
= tevent_req_create(mem_ctx
, &state
, struct cli_qpathinfo_state
);
6928 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
6929 uint16_t smb2_level
= 0;
6932 case SMB_QUERY_FILE_ALT_NAME_INFO
:
6933 smb2_level
= FSCC_FILE_ALTERNATE_NAME_INFORMATION
;
6936 tevent_req_nterror(req
, NT_STATUS_INVALID_LEVEL
);
6937 return tevent_req_post(req
, ev
);
6940 subreq
= cli_smb2_qpathinfo_send(state
,
6947 if (tevent_req_nomem(subreq
, req
)) {
6948 return tevent_req_post(req
, ev
);
6950 tevent_req_set_callback(subreq
, cli_qpathinfo_done2
, req
);
6954 state
->min_rdata
= min_rdata
;
6955 SSVAL(state
->setup
, 0, TRANSACT2_QPATHINFO
);
6957 state
->param
= talloc_zero_array(state
, uint8_t, 6);
6958 if (tevent_req_nomem(state
->param
, req
)) {
6959 return tevent_req_post(req
, ev
);
6961 SSVAL(state
->param
, 0, level
);
6963 * qpathinfo on a DFS share must use DFS names.
6965 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
6966 if (tevent_req_nomem(fname_cp
, req
)) {
6967 return tevent_req_post(req
, ev
);
6969 state
->param
= trans2_bytes_push_str(state
->param
,
6970 smbXcli_conn_use_unicode(cli
->conn
),
6974 if (tevent_req_nomem(state
->param
, req
)) {
6975 return tevent_req_post(req
, ev
);
6978 if (clistr_is_previous_version_path(fname
) &&
6979 !INFO_LEVEL_IS_UNIX(level
)) {
6980 additional_flags2
= FLAGS2_REPARSE_PATH
;
6983 subreq
= cli_trans_send(
6984 state
, /* mem ctx. */
6985 ev
, /* event ctx. */
6986 cli
, /* cli_state. */
6987 additional_flags2
, /* additional_flags2 */
6988 SMBtrans2
, /* cmd. */
6989 NULL
, /* pipe name. */
6993 state
->setup
, /* setup. */
6994 1, /* num setup uint16_t words. */
6995 0, /* max returned setup. */
6996 state
->param
, /* param. */
6997 talloc_get_size(state
->param
), /* num param. */
6998 2, /* max returned param. */
7001 max_rdata
); /* max returned data. */
7003 if (tevent_req_nomem(subreq
, req
)) {
7004 return tevent_req_post(req
, ev
);
7006 tevent_req_set_callback(subreq
, cli_qpathinfo_done
, req
);
7010 static void cli_qpathinfo_done(struct tevent_req
*subreq
)
7012 struct tevent_req
*req
= tevent_req_callback_data(
7013 subreq
, struct tevent_req
);
7014 struct cli_qpathinfo_state
*state
= tevent_req_data(
7015 req
, struct cli_qpathinfo_state
);
7018 status
= cli_trans_recv(subreq
, state
, NULL
, NULL
, 0, NULL
,
7020 &state
->rdata
, state
->min_rdata
,
7022 if (tevent_req_nterror(req
, status
)) {
7025 tevent_req_done(req
);
7028 static void cli_qpathinfo_done2(struct tevent_req
*subreq
)
7030 struct tevent_req
*req
=
7031 tevent_req_callback_data(subreq
, struct tevent_req
);
7032 struct cli_qpathinfo_state
*state
=
7033 tevent_req_data(req
, struct cli_qpathinfo_state
);
7036 status
= cli_smb2_qpathinfo_recv(subreq
,
7040 if (tevent_req_nterror(req
, status
)) {
7043 tevent_req_done(req
);
7046 NTSTATUS
cli_qpathinfo_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
7047 uint8_t **rdata
, uint32_t *num_rdata
)
7049 struct cli_qpathinfo_state
*state
= tevent_req_data(
7050 req
, struct cli_qpathinfo_state
);
7053 if (tevent_req_is_nterror(req
, &status
)) {
7056 if (rdata
!= NULL
) {
7057 *rdata
= talloc_move(mem_ctx
, &state
->rdata
);
7059 TALLOC_FREE(state
->rdata
);
7061 if (num_rdata
!= NULL
) {
7062 *num_rdata
= state
->num_rdata
;
7064 return NT_STATUS_OK
;
7067 NTSTATUS
cli_qpathinfo(TALLOC_CTX
*mem_ctx
, struct cli_state
*cli
,
7068 const char *fname
, uint16_t level
, uint32_t min_rdata
,
7070 uint8_t **rdata
, uint32_t *num_rdata
)
7072 TALLOC_CTX
*frame
= talloc_stackframe();
7073 struct tevent_context
*ev
;
7074 struct tevent_req
*req
;
7075 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
7077 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
7079 * Can't use sync call while an async call is in flight
7081 status
= NT_STATUS_INVALID_PARAMETER
;
7084 ev
= samba_tevent_context_init(frame
);
7088 req
= cli_qpathinfo_send(frame
, ev
, cli
, fname
, level
, min_rdata
,
7093 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
7096 status
= cli_qpathinfo_recv(req
, mem_ctx
, rdata
, num_rdata
);
7102 struct cli_qfileinfo_state
{
7106 uint16_t recv_flags2
;
7112 static void cli_qfileinfo_done2(struct tevent_req
*subreq
);
7113 static void cli_qfileinfo_done(struct tevent_req
*subreq
);
7115 struct tevent_req
*cli_qfileinfo_send(TALLOC_CTX
*mem_ctx
,
7116 struct tevent_context
*ev
,
7117 struct cli_state
*cli
,
7119 uint16_t fscc_level
,
7123 struct tevent_req
*req
, *subreq
;
7124 struct cli_qfileinfo_state
*state
;
7127 req
= tevent_req_create(mem_ctx
, &state
, struct cli_qfileinfo_state
);
7132 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
7133 max_rdata
= MIN(max_rdata
,
7134 smb2cli_conn_max_trans_size(cli
->conn
));
7136 subreq
= cli_smb2_query_info_fnum_send(
7137 state
, /* mem_ctx */
7141 SMB2_0_INFO_FILE
, /* in_info_type */
7142 fscc_level
, /* in_file_info_class */
7143 max_rdata
, /* in_max_output_length */
7144 NULL
, /* in_input_buffer */
7145 0, /* in_additional_info */
7147 if (tevent_req_nomem(subreq
, req
)) {
7148 return tevent_req_post(req
, ev
);
7150 tevent_req_set_callback(subreq
, cli_qfileinfo_done2
, req
);
7154 max_rdata
= MIN(max_rdata
, UINT16_MAX
);
7156 switch (fscc_level
) {
7157 case FSCC_FILE_BASIC_INFORMATION
:
7158 smb_level
= SMB_QUERY_FILE_BASIC_INFO
;
7160 case FSCC_FILE_STANDARD_INFORMATION
:
7161 smb_level
= SMB_QUERY_FILE_STANDARD_INFO
;
7163 case FSCC_FILE_EA_INFORMATION
:
7164 smb_level
= SMB_QUERY_FILE_EA_INFO
;
7166 case FSCC_FILE_NAME_INFORMATION
:
7167 smb_level
= SMB_QUERY_FILE_NAME_INFO
;
7169 case FSCC_FILE_ALL_INFORMATION
:
7170 smb_level
= SMB_QUERY_FILE_ALL_INFO
;
7172 case FSCC_FILE_ALTERNATE_NAME_INFORMATION
:
7173 smb_level
= SMB_QUERY_FILE_ALT_NAME_INFO
;
7175 case FSCC_FILE_STREAM_INFORMATION
:
7176 smb_level
= SMB_QUERY_FILE_STREAM_INFO
;
7178 case FSCC_FILE_COMPRESSION_INFORMATION
:
7179 smb_level
= SMB_QUERY_COMPRESSION_INFO
;
7182 /* Probably wrong, but the server will tell us */
7183 smb_level
= fscc_level
;
7187 state
->min_rdata
= min_rdata
;
7188 SSVAL(state
->param
, 0, fnum
);
7189 SSVAL(state
->param
, 2, smb_level
);
7190 SSVAL(state
->setup
, 0, TRANSACT2_QFILEINFO
);
7192 subreq
= cli_trans_send(
7193 state
, /* mem ctx. */
7194 ev
, /* event ctx. */
7195 cli
, /* cli_state. */
7196 0, /* additional_flags2 */
7197 SMBtrans2
, /* cmd. */
7198 NULL
, /* pipe name. */
7202 state
->setup
, /* setup. */
7203 1, /* num setup uint16_t words. */
7204 0, /* max returned setup. */
7205 state
->param
, /* param. */
7206 sizeof(state
->param
), /* num param. */
7207 2, /* max returned param. */
7210 max_rdata
); /* max returned data. */
7212 if (tevent_req_nomem(subreq
, req
)) {
7213 return tevent_req_post(req
, ev
);
7215 tevent_req_set_callback(subreq
, cli_qfileinfo_done
, req
);
7219 static void cli_qfileinfo_done2(struct tevent_req
*subreq
)
7221 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
7223 struct cli_qfileinfo_state
*state
= tevent_req_data(
7224 req
, struct cli_qfileinfo_state
);
7225 DATA_BLOB outbuf
= {};
7228 status
= cli_smb2_query_info_fnum_recv(subreq
, state
, &outbuf
);
7229 TALLOC_FREE(subreq
);
7230 if (tevent_req_nterror(req
, status
)) {
7234 if (outbuf
.length
< state
->min_rdata
) {
7235 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
7239 state
->rdata
= outbuf
.data
;
7240 state
->num_rdata
= outbuf
.length
;
7241 tevent_req_done(req
);
7244 static void cli_qfileinfo_done(struct tevent_req
*subreq
)
7246 struct tevent_req
*req
= tevent_req_callback_data(
7247 subreq
, struct tevent_req
);
7248 struct cli_qfileinfo_state
*state
= tevent_req_data(
7249 req
, struct cli_qfileinfo_state
);
7252 status
= cli_trans_recv(subreq
, state
,
7253 &state
->recv_flags2
,
7256 &state
->rdata
, state
->min_rdata
,
7258 if (tevent_req_nterror(req
, status
)) {
7261 tevent_req_done(req
);
7264 NTSTATUS
cli_qfileinfo_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
7265 uint16_t *recv_flags2
,
7266 uint8_t **rdata
, uint32_t *num_rdata
)
7268 struct cli_qfileinfo_state
*state
= tevent_req_data(
7269 req
, struct cli_qfileinfo_state
);
7272 if (tevent_req_is_nterror(req
, &status
)) {
7276 if (recv_flags2
!= NULL
) {
7277 *recv_flags2
= state
->recv_flags2
;
7279 if (rdata
!= NULL
) {
7280 *rdata
= talloc_move(mem_ctx
, &state
->rdata
);
7282 if (num_rdata
!= NULL
) {
7283 *num_rdata
= state
->num_rdata
;
7286 tevent_req_received(req
);
7287 return NT_STATUS_OK
;
7290 NTSTATUS
cli_qfileinfo(TALLOC_CTX
*mem_ctx
,
7291 struct cli_state
*cli
,
7293 uint16_t fscc_level
,
7296 uint16_t *recv_flags2
,
7298 uint32_t *num_rdata
)
7300 TALLOC_CTX
*frame
= talloc_stackframe();
7301 struct tevent_context
*ev
;
7302 struct tevent_req
*req
;
7303 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
7305 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
7307 * Can't use sync call while an async call is in flight
7309 status
= NT_STATUS_INVALID_PARAMETER
;
7312 ev
= samba_tevent_context_init(frame
);
7316 req
= cli_qfileinfo_send(
7317 frame
, ev
, cli
, fnum
, fscc_level
, min_rdata
, max_rdata
);
7321 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
7324 status
= cli_qfileinfo_recv(req
, mem_ctx
, recv_flags2
, rdata
, num_rdata
);
7330 struct cli_flush_state
{
7334 static void cli_flush_done(struct tevent_req
*subreq
);
7336 struct tevent_req
*cli_flush_send(TALLOC_CTX
*mem_ctx
,
7337 struct tevent_context
*ev
,
7338 struct cli_state
*cli
,
7341 struct tevent_req
*req
, *subreq
;
7342 struct cli_flush_state
*state
;
7344 req
= tevent_req_create(mem_ctx
, &state
, struct cli_flush_state
);
7348 SSVAL(state
->vwv
+ 0, 0, fnum
);
7350 subreq
= cli_smb_send(state
, ev
, cli
, SMBflush
, 0, 0, 1, state
->vwv
,
7352 if (tevent_req_nomem(subreq
, req
)) {
7353 return tevent_req_post(req
, ev
);
7355 tevent_req_set_callback(subreq
, cli_flush_done
, req
);
7359 static void cli_flush_done(struct tevent_req
*subreq
)
7361 struct tevent_req
*req
= tevent_req_callback_data(
7362 subreq
, struct tevent_req
);
7365 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
7366 TALLOC_FREE(subreq
);
7367 if (tevent_req_nterror(req
, status
)) {
7370 tevent_req_done(req
);
7373 NTSTATUS
cli_flush_recv(struct tevent_req
*req
)
7375 return tevent_req_simple_recv_ntstatus(req
);
7378 NTSTATUS
cli_flush(TALLOC_CTX
*mem_ctx
, struct cli_state
*cli
, uint16_t fnum
)
7380 TALLOC_CTX
*frame
= talloc_stackframe();
7381 struct tevent_context
*ev
;
7382 struct tevent_req
*req
;
7383 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
7385 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
7387 * Can't use sync call while an async call is in flight
7389 status
= NT_STATUS_INVALID_PARAMETER
;
7392 ev
= samba_tevent_context_init(frame
);
7396 req
= cli_flush_send(frame
, ev
, cli
, fnum
);
7400 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
7403 status
= cli_flush_recv(req
);
7409 struct cli_shadow_copy_data_state
{
7416 static void cli_shadow_copy_data_done(struct tevent_req
*subreq
);
7418 struct tevent_req
*cli_shadow_copy_data_send(TALLOC_CTX
*mem_ctx
,
7419 struct tevent_context
*ev
,
7420 struct cli_state
*cli
,
7424 struct tevent_req
*req
, *subreq
;
7425 struct cli_shadow_copy_data_state
*state
;
7428 req
= tevent_req_create(mem_ctx
, &state
,
7429 struct cli_shadow_copy_data_state
);
7433 state
->get_names
= get_names
;
7434 ret_size
= get_names
? CLI_BUFFER_SIZE
: 16;
7436 SIVAL(state
->setup
+ 0, 0, FSCTL_GET_SHADOW_COPY_DATA
);
7437 SSVAL(state
->setup
+ 2, 0, fnum
);
7438 SCVAL(state
->setup
+ 3, 0, 1); /* isFsctl */
7439 SCVAL(state
->setup
+ 3, 1, 0); /* compfilter, isFlags (WSSP) */
7441 subreq
= cli_trans_send(
7442 state
, ev
, cli
, 0, SMBnttrans
, NULL
, 0, NT_TRANSACT_IOCTL
, 0,
7443 state
->setup
, ARRAY_SIZE(state
->setup
),
7444 ARRAY_SIZE(state
->setup
),
7447 if (tevent_req_nomem(subreq
, req
)) {
7448 return tevent_req_post(req
, ev
);
7450 tevent_req_set_callback(subreq
, cli_shadow_copy_data_done
, req
);
7454 static void cli_shadow_copy_data_done(struct tevent_req
*subreq
)
7456 struct tevent_req
*req
= tevent_req_callback_data(
7457 subreq
, struct tevent_req
);
7458 struct cli_shadow_copy_data_state
*state
= tevent_req_data(
7459 req
, struct cli_shadow_copy_data_state
);
7462 status
= cli_trans_recv(subreq
, state
, NULL
,
7463 NULL
, 0, NULL
, /* setup */
7464 NULL
, 0, NULL
, /* param */
7465 &state
->data
, 12, &state
->num_data
);
7466 TALLOC_FREE(subreq
);
7467 if (tevent_req_nterror(req
, status
)) {
7470 tevent_req_done(req
);
7473 NTSTATUS
cli_shadow_copy_data_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
7474 char ***pnames
, int *pnum_names
)
7476 struct cli_shadow_copy_data_state
*state
= tevent_req_data(
7477 req
, struct cli_shadow_copy_data_state
);
7478 char **names
= NULL
;
7479 uint32_t i
, num_names
;
7481 uint8_t *endp
= NULL
;
7484 if (tevent_req_is_nterror(req
, &status
)) {
7488 if (state
->num_data
< 16) {
7489 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7492 num_names
= IVAL(state
->data
, 4);
7493 dlength
= IVAL(state
->data
, 8);
7495 if (num_names
> 0x7FFFFFFF) {
7496 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7499 if (!state
->get_names
) {
7500 *pnum_names
= (int)num_names
;
7501 return NT_STATUS_OK
;
7504 if (dlength
+ 12 < 12) {
7505 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7507 if (dlength
+ 12 > state
->num_data
) {
7508 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7510 if (state
->num_data
+ (2 * sizeof(SHADOW_COPY_LABEL
)) <
7512 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7515 names
= talloc_array(mem_ctx
, char *, num_names
);
7516 if (names
== NULL
) {
7517 return NT_STATUS_NO_MEMORY
;
7520 endp
= state
->data
+ state
->num_data
;
7522 for (i
=0; i
<num_names
; i
++) {
7525 size_t converted_size
;
7527 src
= state
->data
+ 12 + i
* 2 * sizeof(SHADOW_COPY_LABEL
);
7529 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
7530 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7533 ret
= convert_string_talloc(
7534 names
, CH_UTF16LE
, CH_UNIX
,
7535 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
7536 &names
[i
], &converted_size
);
7539 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7542 *pnum_names
= (int)num_names
;
7544 return NT_STATUS_OK
;
7547 NTSTATUS
cli_shadow_copy_data(TALLOC_CTX
*mem_ctx
, struct cli_state
*cli
,
7548 uint16_t fnum
, bool get_names
,
7549 char ***pnames
, int *pnum_names
)
7551 TALLOC_CTX
*frame
= NULL
;
7552 struct tevent_context
*ev
;
7553 struct tevent_req
*req
;
7554 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
7556 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
7557 return cli_smb2_shadow_copy_data(mem_ctx
,
7565 frame
= talloc_stackframe();
7567 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
7569 * Can't use sync call while an async call is in flight
7571 status
= NT_STATUS_INVALID_PARAMETER
;
7574 ev
= samba_tevent_context_init(frame
);
7578 req
= cli_shadow_copy_data_send(frame
, ev
, cli
, fnum
, get_names
);
7582 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
7585 status
= cli_shadow_copy_data_recv(req
, mem_ctx
, pnames
, pnum_names
);
7591 struct cli_fsctl_state
{
7595 static void cli_fsctl_smb1_done(struct tevent_req
*subreq
);
7596 static void cli_fsctl_smb2_done(struct tevent_req
*subreq
);
7598 struct tevent_req
*cli_fsctl_send(
7599 TALLOC_CTX
*mem_ctx
,
7600 struct tevent_context
*ev
,
7601 struct cli_state
*cli
,
7604 const DATA_BLOB
*in
,
7607 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
7608 struct cli_fsctl_state
*state
= NULL
;
7609 uint16_t *setup
= NULL
;
7610 uint8_t *data
= NULL
;
7611 uint32_t num_data
= 0;
7613 req
= tevent_req_create(mem_ctx
, &state
, struct cli_fsctl_state
);
7618 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
7619 subreq
= cli_smb2_fsctl_send(
7620 state
, ev
, cli
, fnum
, ctl_code
, in
, max_out
);
7621 if (tevent_req_nomem(subreq
, req
)) {
7622 return tevent_req_post(req
, ev
);
7624 tevent_req_set_callback(subreq
, cli_fsctl_smb2_done
, req
);
7628 setup
= talloc_array(state
, uint16_t, 4);
7629 if (tevent_req_nomem(setup
, req
)) {
7630 return tevent_req_post(req
, ev
);
7632 SIVAL(setup
, 0, ctl_code
);
7633 SSVAL(setup
, 4, fnum
);
7634 SCVAL(setup
, 6, 1); /* IsFcntl */
7635 SCVAL(setup
, 7, 0); /* IsFlags */
7639 num_data
= in
->length
;
7642 subreq
= cli_trans_send(state
,
7645 0, /* additional_flags2 */
7646 SMBnttrans
, /* cmd */
7649 NT_TRANSACT_IOCTL
, /* function */
7659 max_out
); /* data */
7661 if (tevent_req_nomem(subreq
, req
)) {
7662 return tevent_req_post(req
, ev
);
7664 tevent_req_set_callback(subreq
, cli_fsctl_smb1_done
, req
);
7668 static void cli_fsctl_smb2_done(struct tevent_req
*subreq
)
7670 struct tevent_req
*req
= tevent_req_callback_data(
7671 subreq
, struct tevent_req
);
7672 struct cli_fsctl_state
*state
= tevent_req_data(
7673 req
, struct cli_fsctl_state
);
7676 status
= cli_smb2_fsctl_recv(subreq
, state
, &state
->out
);
7677 tevent_req_simple_finish_ntstatus(subreq
, status
);
7680 static void cli_fsctl_smb1_done(struct tevent_req
*subreq
)
7682 struct tevent_req
*req
= tevent_req_callback_data(
7683 subreq
, struct tevent_req
);
7684 struct cli_fsctl_state
*state
= tevent_req_data(
7685 req
, struct cli_fsctl_state
);
7686 uint8_t *out
= NULL
;
7690 status
= cli_trans_recv(
7691 subreq
, state
, NULL
,
7692 NULL
, 0, NULL
, /* rsetup */
7693 NULL
, 0, NULL
, /* rparam */
7695 TALLOC_FREE(subreq
);
7696 if (tevent_req_nterror(req
, status
)) {
7699 state
->out
= (DATA_BLOB
) {
7700 .data
= out
, .length
= out_len
,
7702 tevent_req_done(req
);
7705 NTSTATUS
cli_fsctl_recv(
7706 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*out
)
7708 struct cli_fsctl_state
*state
= tevent_req_data(
7709 req
, struct cli_fsctl_state
);
7712 if (tevent_req_is_nterror(req
, &status
)) {
7717 *out
= (DATA_BLOB
) {
7718 .data
= talloc_move(mem_ctx
, &state
->out
.data
),
7719 .length
= state
->out
.length
,
7723 return NT_STATUS_OK
;