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 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
2368 return tevent_req_post(req
, ev
);
2371 SSVAL(state
->vwv
+0, 0, mayhave_attrs
);
2373 bytes
= talloc_array(state
, uint8_t, 1);
2374 if (tevent_req_nomem(bytes
, req
)) {
2375 return tevent_req_post(req
, ev
);
2378 * SMBunlink on a DFS share must use DFS names.
2380 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
2381 if (tevent_req_nomem(fname_cp
, req
)) {
2382 return tevent_req_post(req
, ev
);
2385 bytes
= smb_bytes_push_str(bytes
,
2386 smbXcli_conn_use_unicode(cli
->conn
),
2391 if (tevent_req_nomem(bytes
, req
)) {
2392 return tevent_req_post(req
, ev
);
2395 if (clistr_is_previous_version_path(fname
)) {
2396 additional_flags2
= FLAGS2_REPARSE_PATH
;
2399 subreq
= cli_smb_send(state
, ev
, cli
, SMBunlink
, additional_flags
,
2401 1, state
->vwv
, talloc_get_size(bytes
), bytes
);
2402 if (tevent_req_nomem(subreq
, req
)) {
2403 return tevent_req_post(req
, ev
);
2405 tevent_req_set_callback(subreq
, cli_unlink_done
, req
);
2409 static void cli_unlink_done(struct tevent_req
*subreq
)
2411 NTSTATUS status
= cli_smb_recv(
2412 subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
2413 tevent_req_simple_finish_ntstatus(subreq
, status
);
2416 static void cli_unlink_done2(struct tevent_req
*subreq
)
2418 NTSTATUS status
= cli_smb2_unlink_recv(subreq
);
2419 tevent_req_simple_finish_ntstatus(subreq
, status
);
2422 NTSTATUS
cli_unlink_recv(struct tevent_req
*req
)
2424 return tevent_req_simple_recv_ntstatus(req
);
2427 NTSTATUS
cli_unlink(struct cli_state
*cli
, const char *fname
, uint32_t mayhave_attrs
)
2429 TALLOC_CTX
*frame
= NULL
;
2430 struct tevent_context
*ev
;
2431 struct tevent_req
*req
;
2432 NTSTATUS status
= NT_STATUS_OK
;
2434 frame
= talloc_stackframe();
2436 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2438 * Can't use sync call while an async call is in flight
2440 status
= NT_STATUS_INVALID_PARAMETER
;
2444 ev
= samba_tevent_context_init(frame
);
2446 status
= NT_STATUS_NO_MEMORY
;
2450 req
= cli_unlink_send(frame
, ev
, cli
, fname
, mayhave_attrs
);
2452 status
= NT_STATUS_NO_MEMORY
;
2456 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2460 status
= cli_unlink_recv(req
);
2466 /****************************************************************************
2468 ****************************************************************************/
2470 static void cli_mkdir_done(struct tevent_req
*subreq
);
2471 static void cli_mkdir_done2(struct tevent_req
*subreq
);
2473 struct cli_mkdir_state
{
2477 struct tevent_req
*cli_mkdir_send(TALLOC_CTX
*mem_ctx
,
2478 struct tevent_context
*ev
,
2479 struct cli_state
*cli
,
2482 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2483 struct cli_mkdir_state
*state
= NULL
;
2484 uint8_t additional_flags
= 0;
2485 uint16_t additional_flags2
= 0;
2486 uint8_t *bytes
= NULL
;
2487 char *dname_cp
= NULL
;
2489 req
= tevent_req_create(mem_ctx
, &state
, struct cli_mkdir_state
);
2494 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
2495 subreq
= cli_smb2_mkdir_send(state
, ev
, cli
, dname
);
2496 if (tevent_req_nomem(subreq
, req
)) {
2497 return tevent_req_post(req
, ev
);
2499 tevent_req_set_callback(subreq
, cli_mkdir_done2
, req
);
2503 bytes
= talloc_array(state
, uint8_t, 1);
2504 if (tevent_req_nomem(bytes
, req
)) {
2505 return tevent_req_post(req
, ev
);
2508 * SMBmkdir on a DFS share must use DFS names.
2510 dname_cp
= smb1_dfs_share_path(state
, cli
, dname
);
2511 if (tevent_req_nomem(dname_cp
, req
)) {
2512 return tevent_req_post(req
, ev
);
2515 bytes
= smb_bytes_push_str(bytes
,
2516 smbXcli_conn_use_unicode(cli
->conn
),
2521 if (tevent_req_nomem(bytes
, req
)) {
2522 return tevent_req_post(req
, ev
);
2525 if (clistr_is_previous_version_path(dname
)) {
2526 additional_flags2
= FLAGS2_REPARSE_PATH
;
2529 subreq
= cli_smb_send(state
, ev
, cli
, SMBmkdir
, additional_flags
,
2531 0, NULL
, talloc_get_size(bytes
), bytes
);
2532 if (tevent_req_nomem(subreq
, req
)) {
2533 return tevent_req_post(req
, ev
);
2535 tevent_req_set_callback(subreq
, cli_mkdir_done
, req
);
2539 static void cli_mkdir_done(struct tevent_req
*subreq
)
2541 struct tevent_req
*req
= tevent_req_callback_data(
2542 subreq
, struct tevent_req
);
2545 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
2546 TALLOC_FREE(subreq
);
2547 if (tevent_req_nterror(req
, status
)) {
2550 tevent_req_done(req
);
2553 static void cli_mkdir_done2(struct tevent_req
*subreq
)
2555 NTSTATUS status
= cli_smb2_mkdir_recv(subreq
);
2556 tevent_req_simple_finish_ntstatus(subreq
, status
);
2559 NTSTATUS
cli_mkdir_recv(struct tevent_req
*req
)
2561 return tevent_req_simple_recv_ntstatus(req
);
2564 NTSTATUS
cli_mkdir(struct cli_state
*cli
, const char *dname
)
2566 TALLOC_CTX
*frame
= NULL
;
2567 struct tevent_context
*ev
;
2568 struct tevent_req
*req
;
2569 NTSTATUS status
= NT_STATUS_OK
;
2571 frame
= talloc_stackframe();
2573 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2575 * Can't use sync call while an async call is in flight
2577 status
= NT_STATUS_INVALID_PARAMETER
;
2581 ev
= samba_tevent_context_init(frame
);
2583 status
= NT_STATUS_NO_MEMORY
;
2587 req
= cli_mkdir_send(frame
, ev
, cli
, dname
);
2589 status
= NT_STATUS_NO_MEMORY
;
2593 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2597 status
= cli_mkdir_recv(req
);
2603 /****************************************************************************
2605 ****************************************************************************/
2607 static void cli_rmdir_done(struct tevent_req
*subreq
);
2608 static void cli_rmdir_done2(struct tevent_req
*subreq
);
2610 struct cli_rmdir_state
{
2614 struct tevent_req
*cli_rmdir_send(TALLOC_CTX
*mem_ctx
,
2615 struct tevent_context
*ev
,
2616 struct cli_state
*cli
,
2619 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2620 struct cli_rmdir_state
*state
= NULL
;
2621 uint8_t additional_flags
= 0;
2622 uint16_t additional_flags2
= 0;
2623 uint8_t *bytes
= NULL
;
2624 char *dname_cp
= NULL
;
2626 req
= tevent_req_create(mem_ctx
, &state
, struct cli_rmdir_state
);
2631 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
2632 subreq
= cli_smb2_rmdir_send(state
, ev
, cli
, dname
, NULL
);
2633 if (tevent_req_nomem(subreq
, req
)) {
2634 return tevent_req_post(req
, ev
);
2636 tevent_req_set_callback(subreq
, cli_rmdir_done2
, req
);
2640 bytes
= talloc_array(state
, uint8_t, 1);
2641 if (tevent_req_nomem(bytes
, req
)) {
2642 return tevent_req_post(req
, ev
);
2645 * SMBrmdir on a DFS share must use DFS names.
2647 dname_cp
= smb1_dfs_share_path(state
, cli
, dname
);
2648 if (tevent_req_nomem(dname_cp
, req
)) {
2649 return tevent_req_post(req
, ev
);
2652 bytes
= smb_bytes_push_str(bytes
,
2653 smbXcli_conn_use_unicode(cli
->conn
),
2658 if (tevent_req_nomem(bytes
, req
)) {
2659 return tevent_req_post(req
, ev
);
2662 if (clistr_is_previous_version_path(dname
)) {
2663 additional_flags2
= FLAGS2_REPARSE_PATH
;
2666 subreq
= cli_smb_send(state
, ev
, cli
, SMBrmdir
, additional_flags
,
2668 0, NULL
, talloc_get_size(bytes
), bytes
);
2669 if (tevent_req_nomem(subreq
, req
)) {
2670 return tevent_req_post(req
, ev
);
2672 tevent_req_set_callback(subreq
, cli_rmdir_done
, req
);
2676 static void cli_rmdir_done(struct tevent_req
*subreq
)
2678 NTSTATUS status
= cli_smb_recv(
2679 subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
2680 tevent_req_simple_finish_ntstatus(subreq
, status
);
2683 static void cli_rmdir_done2(struct tevent_req
*subreq
)
2685 NTSTATUS status
= cli_smb2_rmdir_recv(subreq
);
2686 tevent_req_simple_finish_ntstatus(subreq
, status
);
2689 NTSTATUS
cli_rmdir_recv(struct tevent_req
*req
)
2691 return tevent_req_simple_recv_ntstatus(req
);
2694 NTSTATUS
cli_rmdir(struct cli_state
*cli
, const char *dname
)
2696 TALLOC_CTX
*frame
= NULL
;
2697 struct tevent_context
*ev
;
2698 struct tevent_req
*req
;
2699 NTSTATUS status
= NT_STATUS_OK
;
2701 frame
= talloc_stackframe();
2703 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2705 * Can't use sync call while an async call is in flight
2707 status
= NT_STATUS_INVALID_PARAMETER
;
2711 ev
= samba_tevent_context_init(frame
);
2713 status
= NT_STATUS_NO_MEMORY
;
2717 req
= cli_rmdir_send(frame
, ev
, cli
, dname
);
2719 status
= NT_STATUS_NO_MEMORY
;
2723 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2727 status
= cli_rmdir_recv(req
);
2733 /****************************************************************************
2734 Set or clear the delete on close flag.
2735 ****************************************************************************/
2741 static void cli_nt_delete_on_close_smb1_done(struct tevent_req
*subreq
);
2742 static void cli_nt_delete_on_close_smb2_done(struct tevent_req
*subreq
);
2744 struct tevent_req
*cli_nt_delete_on_close_send(TALLOC_CTX
*mem_ctx
,
2745 struct tevent_context
*ev
,
2746 struct cli_state
*cli
,
2750 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2751 struct doc_state
*state
= NULL
;
2753 req
= tevent_req_create(mem_ctx
, &state
, struct doc_state
);
2758 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
2759 subreq
= cli_smb2_delete_on_close_send(state
, ev
, cli
,
2761 if (tevent_req_nomem(subreq
, req
)) {
2762 return tevent_req_post(req
, ev
);
2764 tevent_req_set_callback(subreq
,
2765 cli_nt_delete_on_close_smb2_done
,
2770 /* Setup data array. */
2771 SCVAL(&state
->data
[0], 0, flag
? 1 : 0);
2773 subreq
= cli_setfileinfo_send(
2778 SMB_SET_FILE_DISPOSITION_INFO
,
2780 sizeof(state
->data
));
2782 if (tevent_req_nomem(subreq
, req
)) {
2783 return tevent_req_post(req
, ev
);
2785 tevent_req_set_callback(subreq
,
2786 cli_nt_delete_on_close_smb1_done
,
2791 static void cli_nt_delete_on_close_smb1_done(struct tevent_req
*subreq
)
2793 NTSTATUS status
= cli_setfileinfo_recv(subreq
);
2794 tevent_req_simple_finish_ntstatus(subreq
, status
);
2797 static void cli_nt_delete_on_close_smb2_done(struct tevent_req
*subreq
)
2799 NTSTATUS status
= cli_smb2_delete_on_close_recv(subreq
);
2800 tevent_req_simple_finish_ntstatus(subreq
, status
);
2803 NTSTATUS
cli_nt_delete_on_close_recv(struct tevent_req
*req
)
2805 return tevent_req_simple_recv_ntstatus(req
);
2808 NTSTATUS
cli_nt_delete_on_close(struct cli_state
*cli
, uint16_t fnum
, bool flag
)
2810 TALLOC_CTX
*frame
= talloc_stackframe();
2811 struct tevent_context
*ev
= NULL
;
2812 struct tevent_req
*req
= NULL
;
2813 NTSTATUS status
= NT_STATUS_OK
;
2815 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2817 * Can't use sync call while an async call is in flight
2819 status
= NT_STATUS_INVALID_PARAMETER
;
2823 ev
= samba_tevent_context_init(frame
);
2825 status
= NT_STATUS_NO_MEMORY
;
2829 req
= cli_nt_delete_on_close_send(frame
,
2835 status
= NT_STATUS_NO_MEMORY
;
2839 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2843 status
= cli_nt_delete_on_close_recv(req
);
2850 struct cli_ntcreate1_state
{
2853 struct smb_create_returns cr
;
2854 struct tevent_req
*subreq
;
2857 static void cli_ntcreate1_done(struct tevent_req
*subreq
);
2858 static bool cli_ntcreate1_cancel(struct tevent_req
*req
);
2860 static struct tevent_req
*cli_ntcreate1_send(TALLOC_CTX
*mem_ctx
,
2861 struct tevent_context
*ev
,
2862 struct cli_state
*cli
,
2864 uint32_t CreatFlags
,
2865 uint32_t DesiredAccess
,
2866 uint32_t FileAttributes
,
2867 uint32_t ShareAccess
,
2868 uint32_t CreateDisposition
,
2869 uint32_t CreateOptions
,
2870 uint32_t ImpersonationLevel
,
2871 uint8_t SecurityFlags
)
2873 struct tevent_req
*req
, *subreq
;
2874 struct cli_ntcreate1_state
*state
;
2877 size_t converted_len
;
2878 uint16_t additional_flags2
= 0;
2879 char *fname_cp
= NULL
;
2881 req
= tevent_req_create(mem_ctx
, &state
, struct cli_ntcreate1_state
);
2888 SCVAL(vwv
+0, 0, 0xFF);
2893 if (cli
->use_oplocks
) {
2894 CreatFlags
|= (REQUEST_OPLOCK
|REQUEST_BATCH_OPLOCK
);
2896 SIVAL(vwv
+3, 1, CreatFlags
);
2897 SIVAL(vwv
+5, 1, 0x0); /* RootDirectoryFid */
2898 SIVAL(vwv
+7, 1, DesiredAccess
);
2899 SIVAL(vwv
+9, 1, 0x0); /* AllocationSize */
2900 SIVAL(vwv
+11, 1, 0x0); /* AllocationSize */
2901 SIVAL(vwv
+13, 1, FileAttributes
);
2902 SIVAL(vwv
+15, 1, ShareAccess
);
2903 SIVAL(vwv
+17, 1, CreateDisposition
);
2904 SIVAL(vwv
+19, 1, CreateOptions
|
2905 (cli
->backup_intent
? FILE_OPEN_FOR_BACKUP_INTENT
: 0));
2906 SIVAL(vwv
+21, 1, ImpersonationLevel
);
2907 SCVAL(vwv
+23, 1, SecurityFlags
);
2909 bytes
= talloc_array(state
, uint8_t, 0);
2910 if (tevent_req_nomem(bytes
, req
)) {
2911 return tevent_req_post(req
, ev
);
2914 * SMBntcreateX on a DFS share must use DFS names.
2916 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
2917 if (tevent_req_nomem(fname_cp
, req
)) {
2918 return tevent_req_post(req
, ev
);
2920 bytes
= smb_bytes_push_str(bytes
,
2921 smbXcli_conn_use_unicode(cli
->conn
),
2925 if (tevent_req_nomem(bytes
, req
)) {
2926 return tevent_req_post(req
, ev
);
2929 if (clistr_is_previous_version_path(fname
)) {
2930 additional_flags2
= FLAGS2_REPARSE_PATH
;
2933 /* sigh. this copes with broken netapp filer behaviour */
2934 bytes
= smb_bytes_push_str(bytes
, smbXcli_conn_use_unicode(cli
->conn
), "", 1, NULL
);
2936 if (tevent_req_nomem(bytes
, req
)) {
2937 return tevent_req_post(req
, ev
);
2940 SSVAL(vwv
+2, 1, converted_len
);
2942 subreq
= cli_smb_send(state
, ev
, cli
, SMBntcreateX
, 0,
2943 additional_flags2
, 24, vwv
,
2944 talloc_get_size(bytes
), bytes
);
2945 if (tevent_req_nomem(subreq
, req
)) {
2946 return tevent_req_post(req
, ev
);
2948 tevent_req_set_callback(subreq
, cli_ntcreate1_done
, req
);
2950 state
->subreq
= subreq
;
2951 tevent_req_set_cancel_fn(req
, cli_ntcreate1_cancel
);
2956 static void cli_ntcreate1_done(struct tevent_req
*subreq
)
2958 struct tevent_req
*req
= tevent_req_callback_data(
2959 subreq
, struct tevent_req
);
2960 struct cli_ntcreate1_state
*state
= tevent_req_data(
2961 req
, struct cli_ntcreate1_state
);
2968 status
= cli_smb_recv(subreq
, state
, NULL
, 34, &wct
, &vwv
,
2969 &num_bytes
, &bytes
);
2970 TALLOC_FREE(subreq
);
2971 if (tevent_req_nterror(req
, status
)) {
2974 state
->cr
.oplock_level
= CVAL(vwv
+2, 0);
2975 state
->fnum
= SVAL(vwv
+2, 1);
2976 state
->cr
.create_action
= IVAL(vwv
+3, 1);
2977 state
->cr
.creation_time
= BVAL(vwv
+5, 1);
2978 state
->cr
.last_access_time
= BVAL(vwv
+9, 1);
2979 state
->cr
.last_write_time
= BVAL(vwv
+13, 1);
2980 state
->cr
.change_time
= BVAL(vwv
+17, 1);
2981 state
->cr
.file_attributes
= IVAL(vwv
+21, 1);
2982 state
->cr
.allocation_size
= BVAL(vwv
+23, 1);
2983 state
->cr
.end_of_file
= BVAL(vwv
+27, 1);
2985 tevent_req_done(req
);
2988 static bool cli_ntcreate1_cancel(struct tevent_req
*req
)
2990 struct cli_ntcreate1_state
*state
= tevent_req_data(
2991 req
, struct cli_ntcreate1_state
);
2992 return tevent_req_cancel(state
->subreq
);
2995 static NTSTATUS
cli_ntcreate1_recv(struct tevent_req
*req
,
2997 struct smb_create_returns
*cr
)
2999 struct cli_ntcreate1_state
*state
= tevent_req_data(
3000 req
, struct cli_ntcreate1_state
);
3003 if (tevent_req_is_nterror(req
, &status
)) {
3006 *pfnum
= state
->fnum
;
3010 return NT_STATUS_OK
;
3013 struct cli_ntcreate_state
{
3014 struct smb_create_returns cr
;
3016 struct tevent_req
*subreq
;
3019 static void cli_ntcreate_done_nt1(struct tevent_req
*subreq
);
3020 static void cli_ntcreate_done_smb2(struct tevent_req
*subreq
);
3021 static bool cli_ntcreate_cancel(struct tevent_req
*req
);
3023 struct tevent_req
*cli_ntcreate_send(TALLOC_CTX
*mem_ctx
,
3024 struct tevent_context
*ev
,
3025 struct cli_state
*cli
,
3027 uint32_t create_flags
,
3028 uint32_t desired_access
,
3029 uint32_t file_attributes
,
3030 uint32_t share_access
,
3031 uint32_t create_disposition
,
3032 uint32_t create_options
,
3033 uint32_t impersonation_level
,
3034 uint8_t security_flags
)
3036 struct tevent_req
*req
, *subreq
;
3037 struct cli_ntcreate_state
*state
;
3039 req
= tevent_req_create(mem_ctx
, &state
, struct cli_ntcreate_state
);
3044 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
3045 struct cli_smb2_create_flags cflags
= {0};
3047 if (cli
->use_oplocks
) {
3048 create_flags
|= REQUEST_OPLOCK
|REQUEST_BATCH_OPLOCK
;
3051 cflags
= (struct cli_smb2_create_flags
) {
3052 .batch_oplock
= (create_flags
& REQUEST_BATCH_OPLOCK
),
3053 .exclusive_oplock
= (create_flags
& REQUEST_OPLOCK
),
3056 subreq
= cli_smb2_create_fnum_send(
3062 impersonation_level
,
3069 if (tevent_req_nomem(subreq
, req
)) {
3070 return tevent_req_post(req
, ev
);
3072 tevent_req_set_callback(subreq
, cli_ntcreate_done_smb2
, req
);
3074 subreq
= cli_ntcreate1_send(
3075 state
, ev
, cli
, fname
, create_flags
, desired_access
,
3076 file_attributes
, share_access
, create_disposition
,
3077 create_options
, impersonation_level
, security_flags
);
3078 if (tevent_req_nomem(subreq
, req
)) {
3079 return tevent_req_post(req
, ev
);
3081 tevent_req_set_callback(subreq
, cli_ntcreate_done_nt1
, req
);
3084 state
->subreq
= subreq
;
3085 tevent_req_set_cancel_fn(req
, cli_ntcreate_cancel
);
3090 static void cli_ntcreate_done_nt1(struct tevent_req
*subreq
)
3092 struct tevent_req
*req
= tevent_req_callback_data(
3093 subreq
, struct tevent_req
);
3094 struct cli_ntcreate_state
*state
= tevent_req_data(
3095 req
, struct cli_ntcreate_state
);
3098 status
= cli_ntcreate1_recv(subreq
, &state
->fnum
, &state
->cr
);
3099 TALLOC_FREE(subreq
);
3100 if (tevent_req_nterror(req
, status
)) {
3103 tevent_req_done(req
);
3106 static void cli_ntcreate_done_smb2(struct tevent_req
*subreq
)
3108 struct tevent_req
*req
= tevent_req_callback_data(
3109 subreq
, struct tevent_req
);
3110 struct cli_ntcreate_state
*state
= tevent_req_data(
3111 req
, struct cli_ntcreate_state
);
3114 status
= cli_smb2_create_fnum_recv(
3121 TALLOC_FREE(subreq
);
3122 if (tevent_req_nterror(req
, status
)) {
3125 tevent_req_done(req
);
3128 static bool cli_ntcreate_cancel(struct tevent_req
*req
)
3130 struct cli_ntcreate_state
*state
= tevent_req_data(
3131 req
, struct cli_ntcreate_state
);
3132 return tevent_req_cancel(state
->subreq
);
3135 NTSTATUS
cli_ntcreate_recv(struct tevent_req
*req
, uint16_t *fnum
,
3136 struct smb_create_returns
*cr
)
3138 struct cli_ntcreate_state
*state
= tevent_req_data(
3139 req
, struct cli_ntcreate_state
);
3142 if (tevent_req_is_nterror(req
, &status
)) {
3146 *fnum
= state
->fnum
;
3151 return NT_STATUS_OK
;
3154 NTSTATUS
cli_ntcreate(struct cli_state
*cli
,
3156 uint32_t CreatFlags
,
3157 uint32_t DesiredAccess
,
3158 uint32_t FileAttributes
,
3159 uint32_t ShareAccess
,
3160 uint32_t CreateDisposition
,
3161 uint32_t CreateOptions
,
3162 uint8_t SecurityFlags
,
3164 struct smb_create_returns
*cr
)
3166 TALLOC_CTX
*frame
= talloc_stackframe();
3167 struct tevent_context
*ev
;
3168 struct tevent_req
*req
;
3169 uint32_t ImpersonationLevel
= SMB2_IMPERSONATION_IMPERSONATION
;
3170 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3172 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3174 * Can't use sync call while an async call is in flight
3176 status
= NT_STATUS_INVALID_PARAMETER
;
3180 ev
= samba_tevent_context_init(frame
);
3185 req
= cli_ntcreate_send(frame
, ev
, cli
, fname
, CreatFlags
,
3186 DesiredAccess
, FileAttributes
, ShareAccess
,
3187 CreateDisposition
, CreateOptions
,
3188 ImpersonationLevel
, SecurityFlags
);
3193 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3197 status
= cli_ntcreate_recv(req
, pfid
, cr
);
3203 struct cli_nttrans_create_state
{
3205 struct smb_create_returns cr
;
3208 static void cli_nttrans_create_done(struct tevent_req
*subreq
);
3210 struct tevent_req
*cli_nttrans_create_send(TALLOC_CTX
*mem_ctx
,
3211 struct tevent_context
*ev
,
3212 struct cli_state
*cli
,
3214 uint32_t CreatFlags
,
3215 uint32_t DesiredAccess
,
3216 uint32_t FileAttributes
,
3217 uint32_t ShareAccess
,
3218 uint32_t CreateDisposition
,
3219 uint32_t CreateOptions
,
3220 uint8_t SecurityFlags
,
3221 struct security_descriptor
*secdesc
,
3222 struct ea_struct
*eas
,
3225 struct tevent_req
*req
, *subreq
;
3226 struct cli_nttrans_create_state
*state
;
3228 uint8_t *secdesc_buf
;
3231 size_t converted_len
;
3232 uint16_t additional_flags2
= 0;
3233 char *fname_cp
= NULL
;
3235 req
= tevent_req_create(mem_ctx
,
3236 &state
, struct cli_nttrans_create_state
);
3241 if (secdesc
!= NULL
) {
3242 status
= marshall_sec_desc(talloc_tos(), secdesc
,
3243 &secdesc_buf
, &secdesc_len
);
3244 if (tevent_req_nterror(req
, status
)) {
3245 DEBUG(10, ("marshall_sec_desc failed: %s\n",
3246 nt_errstr(status
)));
3247 return tevent_req_post(req
, ev
);
3258 tevent_req_nterror(req
, NT_STATUS_NOT_IMPLEMENTED
);
3259 return tevent_req_post(req
, ev
);
3262 param
= talloc_array(state
, uint8_t, 53);
3263 if (tevent_req_nomem(param
, req
)) {
3264 return tevent_req_post(req
, ev
);
3268 * SMBntcreateX on a DFS share must use DFS names.
3270 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
3271 if (tevent_req_nomem(fname_cp
, req
)) {
3272 return tevent_req_post(req
, ev
);
3274 param
= trans2_bytes_push_str(param
,
3275 smbXcli_conn_use_unicode(cli
->conn
),
3279 if (tevent_req_nomem(param
, req
)) {
3280 return tevent_req_post(req
, ev
);
3283 if (clistr_is_previous_version_path(fname
)) {
3284 additional_flags2
= FLAGS2_REPARSE_PATH
;
3287 SIVAL(param
, 0, CreatFlags
);
3288 SIVAL(param
, 4, 0x0); /* RootDirectoryFid */
3289 SIVAL(param
, 8, DesiredAccess
);
3290 SIVAL(param
, 12, 0x0); /* AllocationSize */
3291 SIVAL(param
, 16, 0x0); /* AllocationSize */
3292 SIVAL(param
, 20, FileAttributes
);
3293 SIVAL(param
, 24, ShareAccess
);
3294 SIVAL(param
, 28, CreateDisposition
);
3295 SIVAL(param
, 32, CreateOptions
|
3296 (cli
->backup_intent
? FILE_OPEN_FOR_BACKUP_INTENT
: 0));
3297 SIVAL(param
, 36, secdesc_len
);
3298 SIVAL(param
, 40, 0); /* EA length*/
3299 SIVAL(param
, 44, converted_len
);
3300 SIVAL(param
, 48, 0x02); /* ImpersonationLevel */
3301 SCVAL(param
, 52, SecurityFlags
);
3303 subreq
= cli_trans_send(state
, ev
, cli
,
3304 additional_flags2
, /* additional_flags2 */
3306 NULL
, -1, /* name, fid */
3307 NT_TRANSACT_CREATE
, 0,
3308 NULL
, 0, 0, /* setup */
3309 param
, talloc_get_size(param
), 128, /* param */
3310 secdesc_buf
, secdesc_len
, 0); /* data */
3311 if (tevent_req_nomem(subreq
, req
)) {
3312 return tevent_req_post(req
, ev
);
3314 tevent_req_set_callback(subreq
, cli_nttrans_create_done
, req
);
3318 static void cli_nttrans_create_done(struct tevent_req
*subreq
)
3320 struct tevent_req
*req
= tevent_req_callback_data(
3321 subreq
, struct tevent_req
);
3322 struct cli_nttrans_create_state
*state
= tevent_req_data(
3323 req
, struct cli_nttrans_create_state
);
3328 status
= cli_trans_recv(subreq
, talloc_tos(), NULL
,
3329 NULL
, 0, NULL
, /* rsetup */
3330 ¶m
, 69, &num_param
,
3332 if (tevent_req_nterror(req
, status
)) {
3335 state
->cr
.oplock_level
= CVAL(param
, 0);
3336 state
->fnum
= SVAL(param
, 2);
3337 state
->cr
.create_action
= IVAL(param
, 4);
3338 state
->cr
.creation_time
= BVAL(param
, 12);
3339 state
->cr
.last_access_time
= BVAL(param
, 20);
3340 state
->cr
.last_write_time
= BVAL(param
, 28);
3341 state
->cr
.change_time
= BVAL(param
, 36);
3342 state
->cr
.file_attributes
= IVAL(param
, 44);
3343 state
->cr
.allocation_size
= BVAL(param
, 48);
3344 state
->cr
.end_of_file
= BVAL(param
, 56);
3347 tevent_req_done(req
);
3350 NTSTATUS
cli_nttrans_create_recv(struct tevent_req
*req
,
3352 struct smb_create_returns
*cr
)
3354 struct cli_nttrans_create_state
*state
= tevent_req_data(
3355 req
, struct cli_nttrans_create_state
);
3358 if (tevent_req_is_nterror(req
, &status
)) {
3361 *fnum
= state
->fnum
;
3365 return NT_STATUS_OK
;
3368 NTSTATUS
cli_nttrans_create(struct cli_state
*cli
,
3370 uint32_t CreatFlags
,
3371 uint32_t DesiredAccess
,
3372 uint32_t FileAttributes
,
3373 uint32_t ShareAccess
,
3374 uint32_t CreateDisposition
,
3375 uint32_t CreateOptions
,
3376 uint8_t SecurityFlags
,
3377 struct security_descriptor
*secdesc
,
3378 struct ea_struct
*eas
,
3381 struct smb_create_returns
*cr
)
3383 TALLOC_CTX
*frame
= talloc_stackframe();
3384 struct tevent_context
*ev
;
3385 struct tevent_req
*req
;
3386 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3388 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3390 * Can't use sync call while an async call is in flight
3392 status
= NT_STATUS_INVALID_PARAMETER
;
3395 ev
= samba_tevent_context_init(frame
);
3399 req
= cli_nttrans_create_send(frame
, ev
, cli
, fname
, CreatFlags
,
3400 DesiredAccess
, FileAttributes
,
3401 ShareAccess
, CreateDisposition
,
3402 CreateOptions
, SecurityFlags
,
3403 secdesc
, eas
, num_eas
);
3407 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3410 status
= cli_nttrans_create_recv(req
, pfid
, cr
);
3416 /****************************************************************************
3418 WARNING: if you open with O_WRONLY then getattrE won't work!
3419 ****************************************************************************/
3421 struct cli_openx_state
{
3428 static void cli_openx_done(struct tevent_req
*subreq
);
3430 struct tevent_req
*cli_openx_create(TALLOC_CTX
*mem_ctx
,
3431 struct tevent_context
*ev
,
3432 struct cli_state
*cli
, const char *fname
,
3433 int flags
, int share_mode
,
3434 struct tevent_req
**psmbreq
)
3436 struct tevent_req
*req
, *subreq
;
3437 struct cli_openx_state
*state
;
3439 unsigned accessmode
;
3440 uint8_t additional_flags
;
3441 uint16_t additional_flags2
= 0;
3443 char *fname_cp
= NULL
;
3445 req
= tevent_req_create(mem_ctx
, &state
, struct cli_openx_state
);
3451 if (flags
& O_CREAT
) {
3454 if (!(flags
& O_EXCL
)) {
3455 if (flags
& O_TRUNC
)
3461 accessmode
= (share_mode
<<4);
3463 if ((flags
& O_ACCMODE
) == O_RDWR
) {
3465 } else if ((flags
& O_ACCMODE
) == O_WRONLY
) {
3470 if ((flags
& O_SYNC
) == O_SYNC
) {
3471 accessmode
|= (1<<14);
3475 if (share_mode
== DENY_FCB
) {
3479 SCVAL(state
->vwv
+ 0, 0, 0xFF);
3480 SCVAL(state
->vwv
+ 0, 1, 0);
3481 SSVAL(state
->vwv
+ 1, 0, 0);
3482 SSVAL(state
->vwv
+ 2, 0, 0); /* no additional info */
3483 SSVAL(state
->vwv
+ 3, 0, accessmode
);
3484 SSVAL(state
->vwv
+ 4, 0, FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
);
3485 SSVAL(state
->vwv
+ 5, 0, 0);
3486 SIVAL(state
->vwv
+ 6, 0, 0);
3487 SSVAL(state
->vwv
+ 8, 0, openfn
);
3488 SIVAL(state
->vwv
+ 9, 0, 0);
3489 SIVAL(state
->vwv
+ 11, 0, 0);
3490 SIVAL(state
->vwv
+ 13, 0, 0);
3492 additional_flags
= 0;
3494 if (cli
->use_oplocks
) {
3495 /* if using oplocks then ask for a batch oplock via
3496 core and extended methods */
3498 FLAG_REQUEST_OPLOCK
|FLAG_REQUEST_BATCH_OPLOCK
;
3499 SSVAL(state
->vwv
+2, 0, SVAL(state
->vwv
+2, 0) | 6);
3502 bytes
= talloc_array(state
, uint8_t, 0);
3503 if (tevent_req_nomem(bytes
, req
)) {
3504 return tevent_req_post(req
, ev
);
3507 * SMBopenX on a DFS share must use DFS names.
3509 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
3510 if (tevent_req_nomem(fname_cp
, req
)) {
3511 return tevent_req_post(req
, ev
);
3513 bytes
= smb_bytes_push_str(bytes
,
3514 smbXcli_conn_use_unicode(cli
->conn
),
3519 if (tevent_req_nomem(bytes
, req
)) {
3520 return tevent_req_post(req
, ev
);
3523 if (clistr_is_previous_version_path(fname
)) {
3524 additional_flags2
= FLAGS2_REPARSE_PATH
;
3527 state
->bytes
.iov_base
= (void *)bytes
;
3528 state
->bytes
.iov_len
= talloc_get_size(bytes
);
3530 subreq
= cli_smb_req_create(state
, ev
, cli
, SMBopenX
, additional_flags
,
3531 additional_flags2
, 15, state
->vwv
, 1, &state
->bytes
);
3532 if (subreq
== NULL
) {
3536 tevent_req_set_callback(subreq
, cli_openx_done
, req
);
3541 struct tevent_req
*cli_openx_send(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
3542 struct cli_state
*cli
, const char *fname
,
3543 int flags
, int share_mode
)
3545 struct tevent_req
*req
, *subreq
;
3548 req
= cli_openx_create(mem_ctx
, ev
, cli
, fname
, flags
, share_mode
,
3554 status
= smb1cli_req_chain_submit(&subreq
, 1);
3555 if (tevent_req_nterror(req
, status
)) {
3556 return tevent_req_post(req
, ev
);
3561 static void cli_openx_done(struct tevent_req
*subreq
)
3563 struct tevent_req
*req
= tevent_req_callback_data(
3564 subreq
, struct tevent_req
);
3565 struct cli_openx_state
*state
= tevent_req_data(
3566 req
, struct cli_openx_state
);
3571 status
= cli_smb_recv(subreq
, state
, NULL
, 3, &wct
, &vwv
, NULL
,
3573 TALLOC_FREE(subreq
);
3574 if (tevent_req_nterror(req
, status
)) {
3577 state
->fnum
= SVAL(vwv
+2, 0);
3578 tevent_req_done(req
);
3581 NTSTATUS
cli_openx_recv(struct tevent_req
*req
, uint16_t *pfnum
)
3583 struct cli_openx_state
*state
= tevent_req_data(
3584 req
, struct cli_openx_state
);
3587 if (tevent_req_is_nterror(req
, &status
)) {
3590 *pfnum
= state
->fnum
;
3591 return NT_STATUS_OK
;
3594 NTSTATUS
cli_openx(struct cli_state
*cli
, const char *fname
, int flags
,
3595 int share_mode
, uint16_t *pfnum
)
3597 TALLOC_CTX
*frame
= talloc_stackframe();
3598 struct tevent_context
*ev
;
3599 struct tevent_req
*req
;
3600 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3602 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3604 * Can't use sync call while an async call is in flight
3606 status
= NT_STATUS_INVALID_PARAMETER
;
3610 ev
= samba_tevent_context_init(frame
);
3615 req
= cli_openx_send(frame
, ev
, cli
, fname
, flags
, share_mode
);
3620 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3624 status
= cli_openx_recv(req
, pfnum
);
3629 /****************************************************************************
3630 Synchronous wrapper function that does an NtCreateX open by preference
3631 and falls back to openX if this fails.
3632 ****************************************************************************/
3634 NTSTATUS
cli_open(struct cli_state
*cli
, const char *fname
, int flags
,
3635 int share_mode_in
, uint16_t *pfnum
)
3638 unsigned int openfn
= 0;
3639 unsigned int dos_deny
= 0;
3640 uint32_t access_mask
, share_mode
, create_disposition
, create_options
;
3641 struct smb_create_returns cr
= {0};
3643 /* Do the initial mapping into OpenX parameters. */
3644 if (flags
& O_CREAT
) {
3647 if (!(flags
& O_EXCL
)) {
3648 if (flags
& O_TRUNC
)
3654 dos_deny
= (share_mode_in
<<4);
3656 if ((flags
& O_ACCMODE
) == O_RDWR
) {
3658 } else if ((flags
& O_ACCMODE
) == O_WRONLY
) {
3663 if (flags
& O_SYNC
) {
3664 dos_deny
|= (1<<14);
3668 if (share_mode_in
== DENY_FCB
) {
3672 if (!map_open_params_to_ntcreate(fname
, dos_deny
,
3673 openfn
, &access_mask
,
3674 &share_mode
, &create_disposition
,
3675 &create_options
, NULL
)) {
3679 status
= cli_ntcreate(cli
,
3691 /* Try and cope will all variants of "we don't do this call"
3692 and fall back to openX. */
3694 if (NT_STATUS_EQUAL(status
,NT_STATUS_NOT_IMPLEMENTED
) ||
3695 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_INFO_CLASS
) ||
3696 NT_STATUS_EQUAL(status
,NT_STATUS_PROCEDURE_NOT_FOUND
) ||
3697 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_LEVEL
) ||
3698 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_PARAMETER
) ||
3699 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_DEVICE_REQUEST
) ||
3700 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_DEVICE_STATE
) ||
3701 NT_STATUS_EQUAL(status
,NT_STATUS_CTL_FILE_NOT_SUPPORTED
) ||
3702 NT_STATUS_EQUAL(status
,NT_STATUS_UNSUCCESSFUL
)) {
3706 if (NT_STATUS_IS_OK(status
) &&
3707 (create_options
& FILE_NON_DIRECTORY_FILE
) &&
3708 (cr
.file_attributes
& FILE_ATTRIBUTE_DIRECTORY
))
3711 * Some (broken) servers return a valid handle
3712 * for directories even if FILE_NON_DIRECTORY_FILE
3713 * is set. Just close the handle and set the
3714 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
3716 status
= cli_close(cli
, *pfnum
);
3717 if (!NT_STATUS_IS_OK(status
)) {
3720 status
= NT_STATUS_FILE_IS_A_DIRECTORY
;
3727 return cli_openx(cli
, fname
, flags
, share_mode_in
, pfnum
);
3730 /****************************************************************************
3732 ****************************************************************************/
3734 struct cli_smb1_close_state
{
3738 static void cli_smb1_close_done(struct tevent_req
*subreq
);
3740 struct tevent_req
*cli_smb1_close_create(TALLOC_CTX
*mem_ctx
,
3741 struct tevent_context
*ev
,
3742 struct cli_state
*cli
,
3744 struct tevent_req
**psubreq
)
3746 struct tevent_req
*req
, *subreq
;
3747 struct cli_smb1_close_state
*state
;
3749 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb1_close_state
);
3754 SSVAL(state
->vwv
+0, 0, fnum
);
3755 SIVALS(state
->vwv
+1, 0, -1);
3757 subreq
= cli_smb_req_create(state
, ev
, cli
, SMBclose
, 0, 0,
3758 3, state
->vwv
, 0, NULL
);
3759 if (subreq
== NULL
) {
3763 tevent_req_set_callback(subreq
, cli_smb1_close_done
, req
);
3768 static void cli_smb1_close_done(struct tevent_req
*subreq
)
3770 struct tevent_req
*req
= tevent_req_callback_data(
3771 subreq
, struct tevent_req
);
3774 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
3775 TALLOC_FREE(subreq
);
3776 if (tevent_req_nterror(req
, status
)) {
3779 tevent_req_done(req
);
3782 struct cli_close_state
{
3786 static void cli_close_done(struct tevent_req
*subreq
);
3788 struct tevent_req
*cli_close_send(TALLOC_CTX
*mem_ctx
,
3789 struct tevent_context
*ev
,
3790 struct cli_state
*cli
,
3794 struct tevent_req
*req
, *subreq
;
3795 struct cli_close_state
*state
;
3798 req
= tevent_req_create(mem_ctx
, &state
, struct cli_close_state
);
3803 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
3804 subreq
= cli_smb2_close_fnum_send(state
, ev
, cli
, fnum
, flags
);
3805 if (tevent_req_nomem(subreq
, req
)) {
3806 return tevent_req_post(req
, ev
);
3809 struct tevent_req
*ch_req
= NULL
;
3810 subreq
= cli_smb1_close_create(state
, ev
, cli
, fnum
, &ch_req
);
3811 if (tevent_req_nomem(subreq
, req
)) {
3812 return tevent_req_post(req
, ev
);
3814 status
= smb1cli_req_chain_submit(&ch_req
, 1);
3815 if (tevent_req_nterror(req
, status
)) {
3816 return tevent_req_post(req
, ev
);
3820 tevent_req_set_callback(subreq
, cli_close_done
, req
);
3824 static void cli_close_done(struct tevent_req
*subreq
)
3826 struct tevent_req
*req
= tevent_req_callback_data(
3827 subreq
, struct tevent_req
);
3828 NTSTATUS status
= NT_STATUS_OK
;
3829 bool err
= tevent_req_is_nterror(subreq
, &status
);
3831 TALLOC_FREE(subreq
);
3833 tevent_req_nterror(req
, status
);
3836 tevent_req_done(req
);
3839 NTSTATUS
cli_close_recv(struct tevent_req
*req
)
3841 return tevent_req_simple_recv_ntstatus(req
);
3844 NTSTATUS
cli_close(struct cli_state
*cli
, uint16_t fnum
)
3846 TALLOC_CTX
*frame
= NULL
;
3847 struct tevent_context
*ev
;
3848 struct tevent_req
*req
;
3849 NTSTATUS status
= NT_STATUS_OK
;
3851 frame
= talloc_stackframe();
3853 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3855 * Can't use sync call while an async call is in flight
3857 status
= NT_STATUS_INVALID_PARAMETER
;
3861 ev
= samba_tevent_context_init(frame
);
3863 status
= NT_STATUS_NO_MEMORY
;
3867 req
= cli_close_send(frame
, ev
, cli
, fnum
, 0);
3869 status
= NT_STATUS_NO_MEMORY
;
3873 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3877 status
= cli_close_recv(req
);
3883 /****************************************************************************
3884 Truncate a file to a specified size
3885 ****************************************************************************/
3887 struct ftrunc_state
{
3891 static void cli_ftruncate_done(struct tevent_req
*subreq
)
3893 NTSTATUS status
= cli_setfileinfo_recv(subreq
);
3894 tevent_req_simple_finish_ntstatus(subreq
, status
);
3897 struct tevent_req
*cli_ftruncate_send(TALLOC_CTX
*mem_ctx
,
3898 struct tevent_context
*ev
,
3899 struct cli_state
*cli
,
3903 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
3904 struct ftrunc_state
*state
= NULL
;
3906 req
= tevent_req_create(mem_ctx
, &state
, struct ftrunc_state
);
3911 /* Setup data array. */
3912 SBVAL(state
->data
, 0, size
);
3914 subreq
= cli_setfileinfo_send(
3919 SMB_SET_FILE_END_OF_FILE_INFO
,
3921 sizeof(state
->data
));
3923 if (tevent_req_nomem(subreq
, req
)) {
3924 return tevent_req_post(req
, ev
);
3926 tevent_req_set_callback(subreq
, cli_ftruncate_done
, req
);
3930 NTSTATUS
cli_ftruncate_recv(struct tevent_req
*req
)
3932 return tevent_req_simple_recv_ntstatus(req
);
3935 NTSTATUS
cli_ftruncate(struct cli_state
*cli
, uint16_t fnum
, uint64_t size
)
3937 TALLOC_CTX
*frame
= NULL
;
3938 struct tevent_context
*ev
= NULL
;
3939 struct tevent_req
*req
= NULL
;
3940 NTSTATUS status
= NT_STATUS_OK
;
3942 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
3943 return cli_smb2_ftruncate(cli
, fnum
, size
);
3946 frame
= talloc_stackframe();
3948 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
3950 * Can't use sync call while an async call is in flight
3952 status
= NT_STATUS_INVALID_PARAMETER
;
3956 ev
= samba_tevent_context_init(frame
);
3958 status
= NT_STATUS_NO_MEMORY
;
3962 req
= cli_ftruncate_send(frame
,
3968 status
= NT_STATUS_NO_MEMORY
;
3972 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3976 status
= cli_ftruncate_recv(req
);
3983 static uint8_t *cli_lockingx_put_locks(
3987 const struct smb1_lock_element
*locks
)
3991 for (i
=0; i
<num_locks
; i
++) {
3992 const struct smb1_lock_element
*e
= &locks
[i
];
3994 SSVAL(buf
, 0, e
->pid
);
3996 SOFF_T_R(buf
, 4, e
->offset
);
3997 SOFF_T_R(buf
, 12, e
->length
);
4000 SSVAL(buf
, 0, e
->pid
);
4001 SIVAL(buf
, 2, e
->offset
);
4002 SIVAL(buf
, 6, e
->length
);
4009 struct cli_lockingx_state
{
4012 struct tevent_req
*subreq
;
4015 static void cli_lockingx_done(struct tevent_req
*subreq
);
4016 static bool cli_lockingx_cancel(struct tevent_req
*req
);
4018 struct tevent_req
*cli_lockingx_create(
4019 TALLOC_CTX
*mem_ctx
,
4020 struct tevent_context
*ev
,
4021 struct cli_state
*cli
,
4024 uint8_t newoplocklevel
,
4026 uint16_t num_unlocks
,
4027 const struct smb1_lock_element
*unlocks
,
4029 const struct smb1_lock_element
*locks
,
4030 struct tevent_req
**psmbreq
)
4032 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4033 struct cli_lockingx_state
*state
= NULL
;
4036 const bool large
= (typeoflock
& LOCKING_ANDX_LARGE_FILES
);
4037 const size_t element_len
= large
? 20 : 10;
4039 /* uint16->size_t, no overflow */
4040 const size_t num_elements
= (size_t)num_locks
+ (size_t)num_unlocks
;
4042 /* at most 20*2*65535 = 2621400, no overflow */
4043 const size_t num_bytes
= num_elements
* element_len
;
4045 req
= tevent_req_create(mem_ctx
, &state
, struct cli_lockingx_state
);
4051 SCVAL(vwv
+ 0, 0, 0xFF);
4052 SCVAL(vwv
+ 0, 1, 0);
4053 SSVAL(vwv
+ 1, 0, 0);
4054 SSVAL(vwv
+ 2, 0, fnum
);
4055 SCVAL(vwv
+ 3, 0, typeoflock
);
4056 SCVAL(vwv
+ 3, 1, newoplocklevel
);
4057 SIVALS(vwv
+ 4, 0, timeout
);
4058 SSVAL(vwv
+ 6, 0, num_unlocks
);
4059 SSVAL(vwv
+ 7, 0, num_locks
);
4061 state
->bytes
.iov_len
= num_bytes
;
4062 state
->bytes
.iov_base
= talloc_array(state
, uint8_t, num_bytes
);
4063 if (tevent_req_nomem(state
->bytes
.iov_base
, req
)) {
4064 return tevent_req_post(req
, ev
);
4067 p
= cli_lockingx_put_locks(
4068 state
->bytes
.iov_base
, large
, num_unlocks
, unlocks
);
4069 cli_lockingx_put_locks(p
, large
, num_locks
, locks
);
4071 subreq
= cli_smb_req_create(
4072 state
, ev
, cli
, SMBlockingX
, 0, 0, 8, vwv
, 1, &state
->bytes
);
4073 if (tevent_req_nomem(subreq
, req
)) {
4074 return tevent_req_post(req
, ev
);
4076 tevent_req_set_callback(subreq
, cli_lockingx_done
, req
);
4081 struct tevent_req
*cli_lockingx_send(
4082 TALLOC_CTX
*mem_ctx
,
4083 struct tevent_context
*ev
,
4084 struct cli_state
*cli
,
4087 uint8_t newoplocklevel
,
4089 uint16_t num_unlocks
,
4090 const struct smb1_lock_element
*unlocks
,
4092 const struct smb1_lock_element
*locks
)
4094 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4095 struct cli_lockingx_state
*state
= NULL
;
4098 req
= cli_lockingx_create(
4114 state
= tevent_req_data(req
, struct cli_lockingx_state
);
4115 state
->subreq
= subreq
;
4117 status
= smb1cli_req_chain_submit(&subreq
, 1);
4118 if (tevent_req_nterror(req
, status
)) {
4119 return tevent_req_post(req
, ev
);
4121 tevent_req_set_cancel_fn(req
, cli_lockingx_cancel
);
4125 static void cli_lockingx_done(struct tevent_req
*subreq
)
4127 NTSTATUS status
= cli_smb_recv(
4128 subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
4129 tevent_req_simple_finish_ntstatus(subreq
, status
);
4132 static bool cli_lockingx_cancel(struct tevent_req
*req
)
4134 struct cli_lockingx_state
*state
= tevent_req_data(
4135 req
, struct cli_lockingx_state
);
4136 if (state
->subreq
== NULL
) {
4139 return tevent_req_cancel(state
->subreq
);
4142 NTSTATUS
cli_lockingx_recv(struct tevent_req
*req
)
4144 return tevent_req_simple_recv_ntstatus(req
);
4147 NTSTATUS
cli_lockingx(
4148 struct cli_state
*cli
,
4151 uint8_t newoplocklevel
,
4153 uint16_t num_unlocks
,
4154 const struct smb1_lock_element
*unlocks
,
4156 const struct smb1_lock_element
*locks
)
4158 TALLOC_CTX
*frame
= talloc_stackframe();
4159 struct tevent_context
*ev
= NULL
;
4160 struct tevent_req
*req
= NULL
;
4161 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4162 unsigned int set_timeout
= 0;
4163 unsigned int saved_timeout
= 0;
4165 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4166 return NT_STATUS_INVALID_PARAMETER
;
4168 ev
= samba_tevent_context_init(frame
);
4174 if (timeout
== -1) {
4175 set_timeout
= 0x7FFFFFFF;
4177 set_timeout
= timeout
+ 2*1000;
4179 saved_timeout
= cli_set_timeout(cli
, set_timeout
);
4182 req
= cli_lockingx_send(
4197 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4200 status
= cli_lockingx_recv(req
);
4202 if (saved_timeout
!= 0) {
4203 cli_set_timeout(cli
, saved_timeout
);
4210 /****************************************************************************
4211 send a lock with a specified locktype
4212 this is used for testing LOCKING_ANDX_CANCEL_LOCK
4213 ****************************************************************************/
4215 NTSTATUS
cli_locktype(struct cli_state
*cli
, uint16_t fnum
,
4216 uint32_t offset
, uint32_t len
,
4217 int timeout
, unsigned char locktype
)
4219 struct smb1_lock_element lck
= {
4220 .pid
= cli_getpid(cli
),
4226 status
= cli_lockingx(
4229 locktype
, /* typeoflock */
4230 0, /* newoplocklevel */
4231 timeout
, /* timeout */
4232 0, /* num_unlocks */
4239 /****************************************************************************
4241 note that timeout is in units of 2 milliseconds
4242 ****************************************************************************/
4244 NTSTATUS
cli_lock32(struct cli_state
*cli
, uint16_t fnum
,
4245 uint32_t offset
, uint32_t len
, int timeout
,
4246 enum brl_type lock_type
)
4250 status
= cli_locktype(cli
, fnum
, offset
, len
, timeout
,
4251 (lock_type
== READ_LOCK
? 1 : 0));
4255 /****************************************************************************
4257 ****************************************************************************/
4259 struct cli_unlock_state
{
4260 struct smb1_lock_element lck
;
4263 static void cli_unlock_done(struct tevent_req
*subreq
);
4265 struct tevent_req
*cli_unlock_send(TALLOC_CTX
*mem_ctx
,
4266 struct tevent_context
*ev
,
4267 struct cli_state
*cli
,
4273 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4274 struct cli_unlock_state
*state
= NULL
;
4276 req
= tevent_req_create(mem_ctx
, &state
, struct cli_unlock_state
);
4280 state
->lck
= (struct smb1_lock_element
) {
4281 .pid
= cli_getpid(cli
),
4286 subreq
= cli_lockingx_send(
4287 state
, /* mem_ctx */
4288 ev
, /* tevent_context */
4292 0, /* newoplocklevel */
4294 1, /* num_unlocks */
4295 &state
->lck
, /* unlocks */
4298 if (tevent_req_nomem(subreq
, req
)) {
4299 return tevent_req_post(req
, ev
);
4301 tevent_req_set_callback(subreq
, cli_unlock_done
, req
);
4305 static void cli_unlock_done(struct tevent_req
*subreq
)
4307 NTSTATUS status
= cli_lockingx_recv(subreq
);
4308 tevent_req_simple_finish_ntstatus(subreq
, status
);
4311 NTSTATUS
cli_unlock_recv(struct tevent_req
*req
)
4313 return tevent_req_simple_recv_ntstatus(req
);
4316 NTSTATUS
cli_unlock(struct cli_state
*cli
,
4321 TALLOC_CTX
*frame
= talloc_stackframe();
4322 struct tevent_context
*ev
;
4323 struct tevent_req
*req
;
4324 NTSTATUS status
= NT_STATUS_OK
;
4326 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4328 * Can't use sync call while an async call is in flight
4330 status
= NT_STATUS_INVALID_PARAMETER
;
4334 ev
= samba_tevent_context_init(frame
);
4336 status
= NT_STATUS_NO_MEMORY
;
4340 req
= cli_unlock_send(frame
, ev
, cli
,
4343 status
= NT_STATUS_NO_MEMORY
;
4347 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4351 status
= cli_unlock_recv(req
);
4358 /****************************************************************************
4359 Get/unlock a POSIX lock on a file - internal function.
4360 ****************************************************************************/
4362 struct posix_lock_state
{
4365 uint8_t data
[POSIX_LOCK_DATA_SIZE
];
4368 static void cli_posix_unlock_internal_done(struct tevent_req
*subreq
)
4370 NTSTATUS status
= cli_trans_recv(subreq
, NULL
, NULL
, NULL
, 0, NULL
,
4371 NULL
, 0, NULL
, NULL
, 0, NULL
);
4372 tevent_req_simple_finish_ntstatus(subreq
, status
);
4375 static struct tevent_req
*cli_posix_lock_internal_send(TALLOC_CTX
*mem_ctx
,
4376 struct tevent_context
*ev
,
4377 struct cli_state
*cli
,
4382 enum brl_type lock_type
)
4384 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4385 struct posix_lock_state
*state
= NULL
;
4387 req
= tevent_req_create(mem_ctx
, &state
, struct posix_lock_state
);
4392 /* Setup setup word. */
4393 SSVAL(&state
->setup
, 0, TRANSACT2_SETFILEINFO
);
4395 /* Setup param array. */
4396 SSVAL(&state
->param
, 0, fnum
);
4397 SSVAL(&state
->param
, 2, SMB_SET_POSIX_LOCK
);
4399 /* Setup data array. */
4400 switch (lock_type
) {
4402 SSVAL(&state
->data
, POSIX_LOCK_TYPE_OFFSET
,
4403 POSIX_LOCK_TYPE_READ
);
4406 SSVAL(&state
->data
, POSIX_LOCK_TYPE_OFFSET
,
4407 POSIX_LOCK_TYPE_WRITE
);
4410 SSVAL(&state
->data
, POSIX_LOCK_TYPE_OFFSET
,
4411 POSIX_LOCK_TYPE_UNLOCK
);
4418 SSVAL(&state
->data
, POSIX_LOCK_FLAGS_OFFSET
,
4419 POSIX_LOCK_FLAG_WAIT
);
4421 SSVAL(state
->data
, POSIX_LOCK_FLAGS_OFFSET
,
4422 POSIX_LOCK_FLAG_NOWAIT
);
4425 SIVAL(&state
->data
, POSIX_LOCK_PID_OFFSET
, cli_getpid(cli
));
4426 SOFF_T(&state
->data
, POSIX_LOCK_START_OFFSET
, offset
);
4427 SOFF_T(&state
->data
, POSIX_LOCK_LEN_OFFSET
, len
);
4429 subreq
= cli_trans_send(state
, /* mem ctx. */
4430 ev
, /* event ctx. */
4431 cli
, /* cli_state. */
4432 0, /* additional_flags2 */
4433 SMBtrans2
, /* cmd. */
4434 NULL
, /* pipe name. */
4438 &state
->setup
, /* setup. */
4439 1, /* num setup uint16_t words. */
4440 0, /* max returned setup. */
4441 state
->param
, /* param. */
4443 2, /* max returned param. */
4444 state
->data
, /* data. */
4445 POSIX_LOCK_DATA_SIZE
, /* num data. */
4446 0); /* max returned data. */
4448 if (tevent_req_nomem(subreq
, req
)) {
4449 return tevent_req_post(req
, ev
);
4451 tevent_req_set_callback(subreq
, cli_posix_unlock_internal_done
, req
);
4455 /****************************************************************************
4457 ****************************************************************************/
4459 struct tevent_req
*cli_posix_lock_send(TALLOC_CTX
*mem_ctx
,
4460 struct tevent_context
*ev
,
4461 struct cli_state
*cli
,
4466 enum brl_type lock_type
)
4468 return cli_posix_lock_internal_send(mem_ctx
, ev
, cli
, fnum
, offset
, len
,
4469 wait_lock
, lock_type
);
4472 NTSTATUS
cli_posix_lock_recv(struct tevent_req
*req
)
4474 return tevent_req_simple_recv_ntstatus(req
);
4477 NTSTATUS
cli_posix_lock(struct cli_state
*cli
, uint16_t fnum
,
4478 uint64_t offset
, uint64_t len
,
4479 bool wait_lock
, enum brl_type lock_type
)
4481 TALLOC_CTX
*frame
= talloc_stackframe();
4482 struct tevent_context
*ev
= NULL
;
4483 struct tevent_req
*req
= NULL
;
4484 NTSTATUS status
= NT_STATUS_OK
;
4486 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4488 * Can't use sync call while an async call is in flight
4490 status
= NT_STATUS_INVALID_PARAMETER
;
4494 if (lock_type
!= READ_LOCK
&& lock_type
!= WRITE_LOCK
) {
4495 status
= NT_STATUS_INVALID_PARAMETER
;
4499 ev
= samba_tevent_context_init(frame
);
4501 status
= NT_STATUS_NO_MEMORY
;
4505 req
= cli_posix_lock_send(frame
,
4514 status
= NT_STATUS_NO_MEMORY
;
4518 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4522 status
= cli_posix_lock_recv(req
);
4529 /****************************************************************************
4530 POSIX Unlock a file.
4531 ****************************************************************************/
4533 struct tevent_req
*cli_posix_unlock_send(TALLOC_CTX
*mem_ctx
,
4534 struct tevent_context
*ev
,
4535 struct cli_state
*cli
,
4540 return cli_posix_lock_internal_send(mem_ctx
, ev
, cli
, fnum
, offset
, len
,
4541 false, UNLOCK_LOCK
);
4544 NTSTATUS
cli_posix_unlock_recv(struct tevent_req
*req
)
4546 return tevent_req_simple_recv_ntstatus(req
);
4549 NTSTATUS
cli_posix_unlock(struct cli_state
*cli
, uint16_t fnum
, uint64_t offset
, uint64_t len
)
4551 TALLOC_CTX
*frame
= talloc_stackframe();
4552 struct tevent_context
*ev
= NULL
;
4553 struct tevent_req
*req
= NULL
;
4554 NTSTATUS status
= NT_STATUS_OK
;
4556 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4558 * Can't use sync call while an async call is in flight
4560 status
= NT_STATUS_INVALID_PARAMETER
;
4564 ev
= samba_tevent_context_init(frame
);
4566 status
= NT_STATUS_NO_MEMORY
;
4570 req
= cli_posix_unlock_send(frame
,
4577 status
= NT_STATUS_NO_MEMORY
;
4581 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4585 status
= cli_posix_unlock_recv(req
);
4592 /****************************************************************************
4593 Do a SMBgetattrE call.
4594 ****************************************************************************/
4596 static void cli_getattrE_done(struct tevent_req
*subreq
);
4598 struct cli_getattrE_state
{
4608 struct tevent_req
*cli_getattrE_send(TALLOC_CTX
*mem_ctx
,
4609 struct tevent_context
*ev
,
4610 struct cli_state
*cli
,
4613 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4614 struct cli_getattrE_state
*state
= NULL
;
4615 uint8_t additional_flags
= 0;
4617 req
= tevent_req_create(mem_ctx
, &state
, struct cli_getattrE_state
);
4622 state
->zone_offset
= smb1cli_conn_server_time_zone(cli
->conn
);
4623 SSVAL(state
->vwv
+0,0,fnum
);
4625 subreq
= cli_smb_send(state
, ev
, cli
, SMBgetattrE
, additional_flags
, 0,
4626 1, state
->vwv
, 0, NULL
);
4627 if (tevent_req_nomem(subreq
, req
)) {
4628 return tevent_req_post(req
, ev
);
4630 tevent_req_set_callback(subreq
, cli_getattrE_done
, req
);
4634 static void cli_getattrE_done(struct tevent_req
*subreq
)
4636 struct tevent_req
*req
= tevent_req_callback_data(
4637 subreq
, struct tevent_req
);
4638 struct cli_getattrE_state
*state
= tevent_req_data(
4639 req
, struct cli_getattrE_state
);
4641 uint16_t *vwv
= NULL
;
4644 status
= cli_smb_recv(subreq
, state
, NULL
, 11, &wct
, &vwv
,
4646 TALLOC_FREE(subreq
);
4647 if (tevent_req_nterror(req
, status
)) {
4651 state
->size
= (off_t
)IVAL(vwv
+6,0);
4652 state
->attr
= SVAL(vwv
+10,0);
4653 state
->change_time
= make_unix_date2(vwv
+0, state
->zone_offset
);
4654 state
->access_time
= make_unix_date2(vwv
+2, state
->zone_offset
);
4655 state
->write_time
= make_unix_date2(vwv
+4, state
->zone_offset
);
4657 tevent_req_done(req
);
4660 NTSTATUS
cli_getattrE_recv(struct tevent_req
*req
,
4663 time_t *change_time
,
4664 time_t *access_time
,
4667 struct cli_getattrE_state
*state
= tevent_req_data(
4668 req
, struct cli_getattrE_state
);
4671 if (tevent_req_is_nterror(req
, &status
)) {
4675 *pattr
= state
->attr
;
4678 *size
= state
->size
;
4681 *change_time
= state
->change_time
;
4684 *access_time
= state
->access_time
;
4687 *write_time
= state
->write_time
;
4689 return NT_STATUS_OK
;
4692 /****************************************************************************
4694 ****************************************************************************/
4696 static void cli_getatr_done(struct tevent_req
*subreq
);
4698 struct cli_getatr_state
{
4705 struct tevent_req
*cli_getatr_send(TALLOC_CTX
*mem_ctx
,
4706 struct tevent_context
*ev
,
4707 struct cli_state
*cli
,
4710 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4711 struct cli_getatr_state
*state
= NULL
;
4712 uint8_t additional_flags
= 0;
4713 uint16_t additional_flags2
= 0;
4714 uint8_t *bytes
= NULL
;
4715 char *fname_cp
= NULL
;
4717 req
= tevent_req_create(mem_ctx
, &state
, struct cli_getatr_state
);
4722 state
->zone_offset
= smb1cli_conn_server_time_zone(cli
->conn
);
4724 bytes
= talloc_array(state
, uint8_t, 1);
4725 if (tevent_req_nomem(bytes
, req
)) {
4726 return tevent_req_post(req
, ev
);
4729 * SMBgetatr on a DFS share must use DFS names.
4731 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
4732 if (tevent_req_nomem(fname_cp
, req
)) {
4733 return tevent_req_post(req
, ev
);
4736 bytes
= smb_bytes_push_str(bytes
,
4737 smbXcli_conn_use_unicode(cli
->conn
),
4742 if (tevent_req_nomem(bytes
, req
)) {
4743 return tevent_req_post(req
, ev
);
4746 if (clistr_is_previous_version_path(fname
)) {
4747 additional_flags2
= FLAGS2_REPARSE_PATH
;
4750 subreq
= cli_smb_send(state
, ev
, cli
, SMBgetatr
, additional_flags
,
4752 0, NULL
, talloc_get_size(bytes
), bytes
);
4753 if (tevent_req_nomem(subreq
, req
)) {
4754 return tevent_req_post(req
, ev
);
4756 tevent_req_set_callback(subreq
, cli_getatr_done
, req
);
4760 static void cli_getatr_done(struct tevent_req
*subreq
)
4762 struct tevent_req
*req
= tevent_req_callback_data(
4763 subreq
, struct tevent_req
);
4764 struct cli_getatr_state
*state
= tevent_req_data(
4765 req
, struct cli_getatr_state
);
4767 uint16_t *vwv
= NULL
;
4770 status
= cli_smb_recv(subreq
, state
, NULL
, 4, &wct
, &vwv
, NULL
,
4772 TALLOC_FREE(subreq
);
4773 if (tevent_req_nterror(req
, status
)) {
4777 state
->attr
= SVAL(vwv
+0,0);
4778 state
->size
= (off_t
)IVAL(vwv
+3,0);
4779 state
->write_time
= make_unix_date3(vwv
+1, state
->zone_offset
);
4781 tevent_req_done(req
);
4784 NTSTATUS
cli_getatr_recv(struct tevent_req
*req
,
4789 struct cli_getatr_state
*state
= tevent_req_data(
4790 req
, struct cli_getatr_state
);
4793 if (tevent_req_is_nterror(req
, &status
)) {
4797 *pattr
= state
->attr
;
4800 *size
= state
->size
;
4803 *write_time
= state
->write_time
;
4805 return NT_STATUS_OK
;
4808 NTSTATUS
cli_getatr(struct cli_state
*cli
,
4814 TALLOC_CTX
*frame
= NULL
;
4815 struct tevent_context
*ev
= NULL
;
4816 struct tevent_req
*req
= NULL
;
4817 NTSTATUS status
= NT_STATUS_OK
;
4819 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
4820 struct stat_ex sbuf
= {
4825 status
= cli_smb2_qpathinfo_basic(cli
, fname
, &sbuf
, &attr
);
4826 if (!NT_STATUS_IS_OK(status
)) {
4830 if (pattr
!= NULL
) {
4834 *size
= sbuf
.st_ex_size
;
4836 if (write_time
!= NULL
) {
4837 *write_time
= sbuf
.st_ex_mtime
.tv_sec
;
4839 return NT_STATUS_OK
;
4842 frame
= talloc_stackframe();
4844 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4846 * Can't use sync call while an async call is in flight
4848 status
= NT_STATUS_INVALID_PARAMETER
;
4852 ev
= samba_tevent_context_init(frame
);
4854 status
= NT_STATUS_NO_MEMORY
;
4858 req
= cli_getatr_send(frame
, ev
, cli
, fname
);
4860 status
= NT_STATUS_NO_MEMORY
;
4864 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4868 status
= cli_getatr_recv(req
,
4878 /****************************************************************************
4879 Do a SMBsetattrE call.
4880 ****************************************************************************/
4882 static void cli_setattrE_done(struct tevent_req
*subreq
);
4884 struct cli_setattrE_state
{
4888 struct tevent_req
*cli_setattrE_send(TALLOC_CTX
*mem_ctx
,
4889 struct tevent_context
*ev
,
4890 struct cli_state
*cli
,
4896 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
4897 struct cli_setattrE_state
*state
= NULL
;
4898 uint8_t additional_flags
= 0;
4900 req
= tevent_req_create(mem_ctx
, &state
, struct cli_setattrE_state
);
4905 SSVAL(state
->vwv
+0, 0, fnum
);
4906 push_dos_date2((uint8_t *)&state
->vwv
[1], 0, change_time
,
4907 smb1cli_conn_server_time_zone(cli
->conn
));
4908 push_dos_date2((uint8_t *)&state
->vwv
[3], 0, access_time
,
4909 smb1cli_conn_server_time_zone(cli
->conn
));
4910 push_dos_date2((uint8_t *)&state
->vwv
[5], 0, write_time
,
4911 smb1cli_conn_server_time_zone(cli
->conn
));
4913 subreq
= cli_smb_send(state
, ev
, cli
, SMBsetattrE
, additional_flags
, 0,
4914 7, state
->vwv
, 0, NULL
);
4915 if (tevent_req_nomem(subreq
, req
)) {
4916 return tevent_req_post(req
, ev
);
4918 tevent_req_set_callback(subreq
, cli_setattrE_done
, req
);
4922 static void cli_setattrE_done(struct tevent_req
*subreq
)
4924 struct tevent_req
*req
= tevent_req_callback_data(
4925 subreq
, struct tevent_req
);
4928 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
4929 TALLOC_FREE(subreq
);
4930 if (tevent_req_nterror(req
, status
)) {
4933 tevent_req_done(req
);
4936 NTSTATUS
cli_setattrE_recv(struct tevent_req
*req
)
4938 return tevent_req_simple_recv_ntstatus(req
);
4941 NTSTATUS
cli_setattrE(struct cli_state
*cli
,
4947 TALLOC_CTX
*frame
= NULL
;
4948 struct tevent_context
*ev
= NULL
;
4949 struct tevent_req
*req
= NULL
;
4950 NTSTATUS status
= NT_STATUS_OK
;
4952 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
4953 return cli_smb2_setattrE(cli
,
4960 frame
= talloc_stackframe();
4962 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
4964 * Can't use sync call while an async call is in flight
4966 status
= NT_STATUS_INVALID_PARAMETER
;
4970 ev
= samba_tevent_context_init(frame
);
4972 status
= NT_STATUS_NO_MEMORY
;
4976 req
= cli_setattrE_send(frame
, ev
,
4984 status
= NT_STATUS_NO_MEMORY
;
4988 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4992 status
= cli_setattrE_recv(req
);
4999 /****************************************************************************
5000 Do a SMBsetatr call.
5001 ****************************************************************************/
5003 static void cli_setatr_done(struct tevent_req
*subreq
);
5005 struct cli_setatr_state
{
5009 struct tevent_req
*cli_setatr_send(TALLOC_CTX
*mem_ctx
,
5010 struct tevent_context
*ev
,
5011 struct cli_state
*cli
,
5016 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5017 struct cli_setatr_state
*state
= NULL
;
5018 uint8_t additional_flags
= 0;
5019 uint16_t additional_flags2
= 0;
5020 uint8_t *bytes
= NULL
;
5021 char *fname_cp
= NULL
;
5023 req
= tevent_req_create(mem_ctx
, &state
, struct cli_setatr_state
);
5028 if (attr
& 0xFFFF0000) {
5030 * Don't allow attributes greater than
5031 * 16-bits for a 16-bit protocol value.
5033 if (tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
)) {
5034 return tevent_req_post(req
, ev
);
5038 SSVAL(state
->vwv
+0, 0, attr
);
5039 push_dos_date3((uint8_t *)&state
->vwv
[1], 0, mtime
, smb1cli_conn_server_time_zone(cli
->conn
));
5041 bytes
= talloc_array(state
, uint8_t, 1);
5042 if (tevent_req_nomem(bytes
, req
)) {
5043 return tevent_req_post(req
, ev
);
5046 * SMBsetatr on a DFS share must use DFS names.
5048 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
5049 if (tevent_req_nomem(fname_cp
, req
)) {
5050 return tevent_req_post(req
, ev
);
5053 bytes
= smb_bytes_push_str(bytes
,
5054 smbXcli_conn_use_unicode(cli
->conn
),
5058 if (tevent_req_nomem(bytes
, req
)) {
5059 return tevent_req_post(req
, ev
);
5061 bytes
= talloc_realloc(state
, bytes
, uint8_t,
5062 talloc_get_size(bytes
)+1);
5063 if (tevent_req_nomem(bytes
, req
)) {
5064 return tevent_req_post(req
, ev
);
5067 bytes
[talloc_get_size(bytes
)-1] = 4;
5068 bytes
= smb_bytes_push_str(bytes
, smbXcli_conn_use_unicode(cli
->conn
), "",
5070 if (tevent_req_nomem(bytes
, req
)) {
5071 return tevent_req_post(req
, ev
);
5074 if (clistr_is_previous_version_path(fname
)) {
5075 additional_flags2
= FLAGS2_REPARSE_PATH
;
5078 subreq
= cli_smb_send(state
, ev
, cli
, SMBsetatr
, additional_flags
,
5080 8, state
->vwv
, talloc_get_size(bytes
), bytes
);
5081 if (tevent_req_nomem(subreq
, req
)) {
5082 return tevent_req_post(req
, ev
);
5084 tevent_req_set_callback(subreq
, cli_setatr_done
, req
);
5088 static void cli_setatr_done(struct tevent_req
*subreq
)
5090 struct tevent_req
*req
= tevent_req_callback_data(
5091 subreq
, struct tevent_req
);
5094 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
5095 TALLOC_FREE(subreq
);
5096 if (tevent_req_nterror(req
, status
)) {
5099 tevent_req_done(req
);
5102 NTSTATUS
cli_setatr_recv(struct tevent_req
*req
)
5104 return tevent_req_simple_recv_ntstatus(req
);
5107 NTSTATUS
cli_setatr(struct cli_state
*cli
,
5112 TALLOC_CTX
*frame
= NULL
;
5113 struct tevent_context
*ev
= NULL
;
5114 struct tevent_req
*req
= NULL
;
5115 NTSTATUS status
= NT_STATUS_OK
;
5117 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
5118 return cli_smb2_setatr(cli
,
5124 frame
= talloc_stackframe();
5126 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
5128 * Can't use sync call while an async call is in flight
5130 status
= NT_STATUS_INVALID_PARAMETER
;
5134 ev
= samba_tevent_context_init(frame
);
5136 status
= NT_STATUS_NO_MEMORY
;
5140 req
= cli_setatr_send(frame
, ev
, cli
, fname
, attr
, mtime
);
5142 status
= NT_STATUS_NO_MEMORY
;
5146 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5150 status
= cli_setatr_recv(req
);
5157 /****************************************************************************
5158 Check for existence of a dir.
5159 ****************************************************************************/
5161 static void cli_chkpath_done(struct tevent_req
*subreq
);
5162 static void cli_chkpath_opened(struct tevent_req
*subreq
);
5163 static void cli_chkpath_closed(struct tevent_req
*subreq
);
5165 struct cli_chkpath_state
{
5166 struct tevent_context
*ev
;
5167 struct cli_state
*cli
;
5170 struct tevent_req
*cli_chkpath_send(TALLOC_CTX
*mem_ctx
,
5171 struct tevent_context
*ev
,
5172 struct cli_state
*cli
,
5175 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5176 struct cli_chkpath_state
*state
= NULL
;
5177 uint8_t additional_flags
= 0;
5178 uint16_t additional_flags2
= 0;
5179 uint8_t *bytes
= NULL
;
5180 char *fname_cp
= NULL
;
5182 req
= tevent_req_create(mem_ctx
, &state
, struct cli_chkpath_state
);
5189 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_NT1
) {
5190 subreq
= cli_ntcreate_send(
5191 state
, /* mem_ctx */
5193 state
->cli
, /* cli */
5195 0, /* create_flags */
5196 FILE_READ_ATTRIBUTES
, /* desired_access */
5197 FILE_ATTRIBUTE_DIRECTORY
, /* FileAttributes */
5200 FILE_SHARE_DELETE
, /* share_access */
5201 FILE_OPEN
, /* CreateDisposition */
5202 FILE_DIRECTORY_FILE
, /* CreateOptions */
5203 SMB2_IMPERSONATION_IMPERSONATION
,
5204 0); /* SecurityFlags */
5205 if (tevent_req_nomem(subreq
, req
)) {
5206 return tevent_req_post(req
, ev
);
5208 tevent_req_set_callback(subreq
, cli_chkpath_opened
, req
);
5212 bytes
= talloc_array(state
, uint8_t, 1);
5213 if (tevent_req_nomem(bytes
, req
)) {
5214 return tevent_req_post(req
, ev
);
5217 * SMBcheckpath on a DFS share must use DFS names.
5219 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
5220 if (tevent_req_nomem(fname_cp
, req
)) {
5221 return tevent_req_post(req
, ev
);
5224 bytes
= smb_bytes_push_str(bytes
,
5225 smbXcli_conn_use_unicode(cli
->conn
),
5230 if (tevent_req_nomem(bytes
, req
)) {
5231 return tevent_req_post(req
, ev
);
5234 if (clistr_is_previous_version_path(fname
)) {
5235 additional_flags2
= FLAGS2_REPARSE_PATH
;
5238 subreq
= cli_smb_send(state
, ev
, cli
, SMBcheckpath
, additional_flags
,
5240 0, NULL
, talloc_get_size(bytes
), bytes
);
5241 if (tevent_req_nomem(subreq
, req
)) {
5242 return tevent_req_post(req
, ev
);
5244 tevent_req_set_callback(subreq
, cli_chkpath_done
, req
);
5248 static void cli_chkpath_done(struct tevent_req
*subreq
)
5250 NTSTATUS status
= cli_smb_recv(
5251 subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
5252 tevent_req_simple_finish_ntstatus(subreq
, status
);
5255 static void cli_chkpath_opened(struct tevent_req
*subreq
)
5257 struct tevent_req
*req
= tevent_req_callback_data(
5258 subreq
, struct tevent_req
);
5259 struct cli_chkpath_state
*state
= tevent_req_data(
5260 req
, struct cli_chkpath_state
);
5264 status
= cli_ntcreate_recv(subreq
, &fnum
, NULL
);
5265 TALLOC_FREE(subreq
);
5266 if (tevent_req_nterror(req
, status
)) {
5270 subreq
= cli_close_send(state
, state
->ev
, state
->cli
, fnum
, 0);
5271 if (tevent_req_nomem(subreq
, req
)) {
5274 tevent_req_set_callback(subreq
, cli_chkpath_closed
, req
);
5277 static void cli_chkpath_closed(struct tevent_req
*subreq
)
5279 NTSTATUS status
= cli_close_recv(subreq
);
5280 tevent_req_simple_finish_ntstatus(subreq
, status
);
5283 NTSTATUS
cli_chkpath_recv(struct tevent_req
*req
)
5285 return tevent_req_simple_recv_ntstatus(req
);
5288 NTSTATUS
cli_chkpath(struct cli_state
*cli
, const char *path
)
5290 TALLOC_CTX
*frame
= NULL
;
5291 struct tevent_context
*ev
= NULL
;
5292 struct tevent_req
*req
= NULL
;
5294 NTSTATUS status
= NT_STATUS_OK
;
5296 frame
= talloc_stackframe();
5298 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
5300 * Can't use sync call while an async call is in flight
5302 status
= NT_STATUS_INVALID_PARAMETER
;
5306 path2
= talloc_strdup(frame
, path
);
5308 status
= NT_STATUS_NO_MEMORY
;
5311 trim_char(path2
,'\0','\\');
5313 path2
= talloc_strdup(frame
, "\\");
5315 status
= NT_STATUS_NO_MEMORY
;
5320 ev
= samba_tevent_context_init(frame
);
5322 status
= NT_STATUS_NO_MEMORY
;
5326 req
= cli_chkpath_send(frame
, ev
, cli
, path2
);
5328 status
= NT_STATUS_NO_MEMORY
;
5332 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5336 status
= cli_chkpath_recv(req
);
5342 /****************************************************************************
5344 ****************************************************************************/
5346 static void cli_dskattr_done(struct tevent_req
*subreq
);
5348 struct cli_dskattr_state
{
5354 struct tevent_req
*cli_dskattr_send(TALLOC_CTX
*mem_ctx
,
5355 struct tevent_context
*ev
,
5356 struct cli_state
*cli
)
5358 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5359 struct cli_dskattr_state
*state
= NULL
;
5360 uint8_t additional_flags
= 0;
5362 req
= tevent_req_create(mem_ctx
, &state
, struct cli_dskattr_state
);
5367 subreq
= cli_smb_send(state
, ev
, cli
, SMBdskattr
, additional_flags
, 0,
5369 if (tevent_req_nomem(subreq
, req
)) {
5370 return tevent_req_post(req
, ev
);
5372 tevent_req_set_callback(subreq
, cli_dskattr_done
, req
);
5376 static void cli_dskattr_done(struct tevent_req
*subreq
)
5378 struct tevent_req
*req
= tevent_req_callback_data(
5379 subreq
, struct tevent_req
);
5380 struct cli_dskattr_state
*state
= tevent_req_data(
5381 req
, struct cli_dskattr_state
);
5383 uint16_t *vwv
= NULL
;
5386 status
= cli_smb_recv(subreq
, state
, NULL
, 4, &wct
, &vwv
, NULL
,
5388 TALLOC_FREE(subreq
);
5389 if (tevent_req_nterror(req
, status
)) {
5392 state
->bsize
= SVAL(vwv
+1, 0)*SVAL(vwv
+2,0);
5393 state
->total
= SVAL(vwv
+0, 0);
5394 state
->avail
= SVAL(vwv
+3, 0);
5395 tevent_req_done(req
);
5398 NTSTATUS
cli_dskattr_recv(struct tevent_req
*req
, int *bsize
, int *total
, int *avail
)
5400 struct cli_dskattr_state
*state
= tevent_req_data(
5401 req
, struct cli_dskattr_state
);
5404 if (tevent_req_is_nterror(req
, &status
)) {
5407 *bsize
= state
->bsize
;
5408 *total
= state
->total
;
5409 *avail
= state
->avail
;
5410 return NT_STATUS_OK
;
5413 NTSTATUS
cli_dskattr(struct cli_state
*cli
, int *bsize
, int *total
, int *avail
)
5415 TALLOC_CTX
*frame
= NULL
;
5416 struct tevent_context
*ev
= NULL
;
5417 struct tevent_req
*req
= NULL
;
5418 NTSTATUS status
= NT_STATUS_OK
;
5420 frame
= talloc_stackframe();
5422 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
5424 * Can't use sync call while an async call is in flight
5426 status
= NT_STATUS_INVALID_PARAMETER
;
5430 ev
= samba_tevent_context_init(frame
);
5432 status
= NT_STATUS_NO_MEMORY
;
5436 req
= cli_dskattr_send(frame
, ev
, cli
);
5438 status
= NT_STATUS_NO_MEMORY
;
5442 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5446 status
= cli_dskattr_recv(req
, bsize
, total
, avail
);
5453 NTSTATUS
cli_disk_size(struct cli_state
*cli
, const char *path
, uint64_t *bsize
,
5454 uint64_t *total
, uint64_t *avail
)
5456 uint64_t sectors_per_block
;
5457 uint64_t bytes_per_sector
;
5458 int old_bsize
= 0, old_total
= 0, old_avail
= 0;
5461 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
5462 return cli_smb2_dskattr(cli
, path
, bsize
, total
, avail
);
5466 * Try the trans2 disk full size info call first.
5467 * We already use this in SMBC_fstatvfs_ctx().
5468 * Ignore 'actual_available_units' as we only
5469 * care about the quota for the caller.
5472 status
= cli_get_fs_full_size_info(cli
,
5479 /* Try and cope will all variants of "we don't do this call"
5480 and fall back to cli_dskattr. */
5482 if (NT_STATUS_EQUAL(status
,NT_STATUS_NOT_IMPLEMENTED
) ||
5483 NT_STATUS_EQUAL(status
,NT_STATUS_NOT_SUPPORTED
) ||
5484 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_INFO_CLASS
) ||
5485 NT_STATUS_EQUAL(status
,NT_STATUS_PROCEDURE_NOT_FOUND
) ||
5486 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_LEVEL
) ||
5487 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_PARAMETER
) ||
5488 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_DEVICE_REQUEST
) ||
5489 NT_STATUS_EQUAL(status
,NT_STATUS_INVALID_DEVICE_STATE
) ||
5490 NT_STATUS_EQUAL(status
,NT_STATUS_CTL_FILE_NOT_SUPPORTED
) ||
5491 NT_STATUS_EQUAL(status
,NT_STATUS_UNSUCCESSFUL
)) {
5495 if (!NT_STATUS_IS_OK(status
)) {
5500 *bsize
= sectors_per_block
*
5504 return NT_STATUS_OK
;
5508 /* Old SMB1 core protocol fallback. */
5509 status
= cli_dskattr(cli
, &old_bsize
, &old_total
, &old_avail
);
5510 if (!NT_STATUS_IS_OK(status
)) {
5514 *bsize
= (uint64_t)old_bsize
;
5517 *total
= (uint64_t)old_total
;
5520 *avail
= (uint64_t)old_avail
;
5522 return NT_STATUS_OK
;
5525 /****************************************************************************
5526 Create and open a temporary file.
5527 ****************************************************************************/
5529 static void cli_ctemp_done(struct tevent_req
*subreq
);
5531 struct ctemp_state
{
5537 struct tevent_req
*cli_ctemp_send(TALLOC_CTX
*mem_ctx
,
5538 struct tevent_context
*ev
,
5539 struct cli_state
*cli
,
5542 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
5543 struct ctemp_state
*state
= NULL
;
5544 uint8_t additional_flags
= 0;
5545 uint16_t additional_flags2
= 0;
5546 uint8_t *bytes
= NULL
;
5547 char *path_cp
= NULL
;
5549 req
= tevent_req_create(mem_ctx
, &state
, struct ctemp_state
);
5554 SSVAL(state
->vwv
,0,0);
5555 SIVALS(state
->vwv
+1,0,-1);
5557 bytes
= talloc_array(state
, uint8_t, 1);
5558 if (tevent_req_nomem(bytes
, req
)) {
5559 return tevent_req_post(req
, ev
);
5562 * SMBctemp on a DFS share must use DFS names.
5564 path_cp
= smb1_dfs_share_path(state
, cli
, path
);
5565 if (tevent_req_nomem(path_cp
, req
)) {
5566 return tevent_req_post(req
, ev
);
5569 bytes
= smb_bytes_push_str(bytes
,
5570 smbXcli_conn_use_unicode(cli
->conn
),
5574 if (tevent_req_nomem(bytes
, req
)) {
5575 return tevent_req_post(req
, ev
);
5578 if (clistr_is_previous_version_path(path
)) {
5579 additional_flags2
= FLAGS2_REPARSE_PATH
;
5582 subreq
= cli_smb_send(state
, ev
, cli
, SMBctemp
, additional_flags
,
5584 3, state
->vwv
, talloc_get_size(bytes
), bytes
);
5585 if (tevent_req_nomem(subreq
, req
)) {
5586 return tevent_req_post(req
, ev
);
5588 tevent_req_set_callback(subreq
, cli_ctemp_done
, req
);
5592 static void cli_ctemp_done(struct tevent_req
*subreq
)
5594 struct tevent_req
*req
= tevent_req_callback_data(
5595 subreq
, struct tevent_req
);
5596 struct ctemp_state
*state
= tevent_req_data(
5597 req
, struct ctemp_state
);
5601 uint32_t num_bytes
= 0;
5602 uint8_t *bytes
= NULL
;
5604 status
= cli_smb_recv(subreq
, state
, NULL
, 1, &wcnt
, &vwv
,
5605 &num_bytes
, &bytes
);
5606 TALLOC_FREE(subreq
);
5607 if (tevent_req_nterror(req
, status
)) {
5611 state
->fnum
= SVAL(vwv
+0, 0);
5613 /* From W2K3, the result is just the ASCII name */
5614 if (num_bytes
< 2) {
5615 tevent_req_nterror(req
, NT_STATUS_DATA_ERROR
);
5619 if (pull_string_talloc(state
,
5626 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
5629 tevent_req_done(req
);
5632 NTSTATUS
cli_ctemp_recv(struct tevent_req
*req
,
5637 struct ctemp_state
*state
= tevent_req_data(req
,
5638 struct ctemp_state
);
5641 if (tevent_req_is_nterror(req
, &status
)) {
5644 *pfnum
= state
->fnum
;
5645 *outfile
= talloc_strdup(ctx
, state
->ret_path
);
5647 return NT_STATUS_NO_MEMORY
;
5649 return NT_STATUS_OK
;
5652 NTSTATUS
cli_ctemp(struct cli_state
*cli
,
5658 TALLOC_CTX
*frame
= talloc_stackframe();
5659 struct tevent_context
*ev
;
5660 struct tevent_req
*req
;
5661 NTSTATUS status
= NT_STATUS_OK
;
5663 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
5665 * Can't use sync call while an async call is in flight
5667 status
= NT_STATUS_INVALID_PARAMETER
;
5671 ev
= samba_tevent_context_init(frame
);
5673 status
= NT_STATUS_NO_MEMORY
;
5677 req
= cli_ctemp_send(frame
, ev
, cli
, path
);
5679 status
= NT_STATUS_NO_MEMORY
;
5683 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
5687 status
= cli_ctemp_recv(req
, ctx
, pfnum
, out_path
);
5694 /*********************************************************
5695 Set an extended attribute utility fn.
5696 *********************************************************/
5698 static NTSTATUS
cli_set_ea(struct cli_state
*cli
, uint16_t setup_val
,
5699 uint8_t *param
, unsigned int param_len
,
5700 const char *ea_name
,
5701 const char *ea_val
, size_t ea_len
)
5704 unsigned int data_len
= 0;
5705 uint8_t *data
= NULL
;
5707 size_t ea_namelen
= strlen(ea_name
);
5710 SSVAL(setup
, 0, setup_val
);
5712 if (ea_namelen
== 0 && ea_len
== 0) {
5714 data
= talloc_array(talloc_tos(),
5718 return NT_STATUS_NO_MEMORY
;
5721 SIVAL(p
,0,data_len
);
5723 data_len
= 4 + 4 + ea_namelen
+ 1 + ea_len
;
5724 data
= talloc_array(talloc_tos(),
5728 return NT_STATUS_NO_MEMORY
;
5731 SIVAL(p
,0,data_len
);
5733 SCVAL(p
, 0, 0); /* EA flags. */
5734 SCVAL(p
, 1, ea_namelen
);
5735 SSVAL(p
, 2, ea_len
);
5736 memcpy(p
+4, ea_name
, ea_namelen
+1); /* Copy in the name. */
5737 memcpy(p
+4+ea_namelen
+1, ea_val
, ea_len
);
5741 * FIXME - if we want to do previous version path
5742 * processing on an EA set call we need to turn this
5743 * into calls to cli_trans_send()/cli_trans_recv()
5744 * with a temporary event context, as cli_trans_send()
5745 * have access to the additional_flags2 needed to
5746 * send @GMT- paths. JRA.
5749 status
= cli_trans(talloc_tos(), cli
, SMBtrans2
, NULL
, -1, 0, 0,
5751 param
, param_len
, 2,
5754 NULL
, 0, NULL
, /* rsetup */
5755 NULL
, 0, NULL
, /* rparam */
5756 NULL
, 0, NULL
); /* rdata */
5761 /*********************************************************
5762 Set an extended attribute on a pathname.
5763 *********************************************************/
5765 NTSTATUS
cli_set_ea_path(struct cli_state
*cli
, const char *path
,
5766 const char *ea_name
, const char *ea_val
,
5769 unsigned int param_len
= 0;
5772 TALLOC_CTX
*frame
= NULL
;
5773 char *path_cp
= NULL
;
5775 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
5776 return cli_smb2_set_ea_path(cli
,
5783 frame
= talloc_stackframe();
5785 param
= talloc_array(frame
, uint8_t, 6);
5787 status
= NT_STATUS_NO_MEMORY
;
5790 SSVAL(param
,0,SMB_INFO_SET_EA
);
5795 * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
5797 path_cp
= smb1_dfs_share_path(frame
, cli
, path
);
5798 if (path_cp
== NULL
) {
5799 status
= NT_STATUS_NO_MEMORY
;
5802 param
= trans2_bytes_push_str(param
,
5803 smbXcli_conn_use_unicode(cli
->conn
),
5807 param_len
= talloc_get_size(param
);
5809 status
= cli_set_ea(cli
, TRANSACT2_SETPATHINFO
, param
, param_len
,
5810 ea_name
, ea_val
, ea_len
);
5818 /*********************************************************
5819 Set an extended attribute on an fnum.
5820 *********************************************************/
5822 NTSTATUS
cli_set_ea_fnum(struct cli_state
*cli
, uint16_t fnum
,
5823 const char *ea_name
, const char *ea_val
,
5826 uint8_t param
[6] = { 0, };
5828 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
5829 return cli_smb2_set_ea_fnum(cli
,
5836 SSVAL(param
,0,fnum
);
5837 SSVAL(param
,2,SMB_INFO_SET_EA
);
5839 return cli_set_ea(cli
, TRANSACT2_SETFILEINFO
, param
, 6,
5840 ea_name
, ea_val
, ea_len
);
5843 /*********************************************************
5844 Get an extended attribute list utility fn.
5845 *********************************************************/
5847 static bool parse_ea_blob(TALLOC_CTX
*ctx
, const uint8_t *rdata
,
5849 size_t *pnum_eas
, struct ea_struct
**pea_list
)
5851 struct ea_struct
*ea_list
= NULL
;
5856 if (rdata_len
< 4) {
5860 ea_size
= (size_t)IVAL(rdata
,0);
5861 if (ea_size
> rdata_len
) {
5866 /* No EA's present. */
5875 /* Validate the EA list and count it. */
5876 for (num_eas
= 0; ea_size
>= 4; num_eas
++) {
5877 unsigned int ea_namelen
= CVAL(p
,1);
5878 unsigned int ea_valuelen
= SVAL(p
,2);
5879 if (ea_namelen
== 0) {
5882 if (4 + ea_namelen
+ 1 + ea_valuelen
> ea_size
) {
5885 ea_size
-= 4 + ea_namelen
+ 1 + ea_valuelen
;
5886 p
+= 4 + ea_namelen
+ 1 + ea_valuelen
;
5895 *pnum_eas
= num_eas
;
5897 /* Caller only wants number of EA's. */
5901 ea_list
= talloc_array(ctx
, struct ea_struct
, num_eas
);
5908 for (num_eas
= 0; num_eas
< *pnum_eas
; num_eas
++ ) {
5909 struct ea_struct
*ea
= &ea_list
[num_eas
];
5910 fstring unix_ea_name
;
5911 unsigned int ea_namelen
= CVAL(p
,1);
5912 unsigned int ea_valuelen
= SVAL(p
,2);
5914 ea
->flags
= CVAL(p
,0);
5915 unix_ea_name
[0] = '\0';
5916 pull_ascii(unix_ea_name
, p
+ 4, sizeof(unix_ea_name
), rdata_len
- PTR_DIFF(p
+4, rdata
), STR_TERMINATE
);
5917 ea
->name
= talloc_strdup(ea_list
, unix_ea_name
);
5921 /* Ensure the value is null terminated (in case it's a string). */
5922 ea
->value
= data_blob_talloc(ea_list
, NULL
, ea_valuelen
+ 1);
5923 if (!ea
->value
.data
) {
5927 memcpy(ea
->value
.data
, p
+4+ea_namelen
+1, ea_valuelen
);
5929 ea
->value
.data
[ea_valuelen
] = 0;
5931 p
+= 4 + ea_namelen
+ 1 + ea_valuelen
;
5934 *pea_list
= ea_list
;
5938 TALLOC_FREE(ea_list
);
5942 /*********************************************************
5943 Get an extended attribute list from a pathname.
5944 *********************************************************/
5946 struct cli_get_ea_list_path_state
{
5951 static void cli_get_ea_list_path_done(struct tevent_req
*subreq
);
5953 struct tevent_req
*cli_get_ea_list_path_send(TALLOC_CTX
*mem_ctx
,
5954 struct tevent_context
*ev
,
5955 struct cli_state
*cli
,
5958 struct tevent_req
*req
, *subreq
;
5959 struct cli_get_ea_list_path_state
*state
;
5961 req
= tevent_req_create(mem_ctx
, &state
,
5962 struct cli_get_ea_list_path_state
);
5966 subreq
= cli_qpathinfo_send(state
, ev
, cli
, fname
,
5967 SMB_INFO_QUERY_ALL_EAS
, 4,
5969 if (tevent_req_nomem(subreq
, req
)) {
5970 return tevent_req_post(req
, ev
);
5972 tevent_req_set_callback(subreq
, cli_get_ea_list_path_done
, req
);
5976 static void cli_get_ea_list_path_done(struct tevent_req
*subreq
)
5978 struct tevent_req
*req
= tevent_req_callback_data(
5979 subreq
, struct tevent_req
);
5980 struct cli_get_ea_list_path_state
*state
= tevent_req_data(
5981 req
, struct cli_get_ea_list_path_state
);
5984 status
= cli_qpathinfo_recv(subreq
, state
, &state
->data
,
5986 TALLOC_FREE(subreq
);
5987 if (tevent_req_nterror(req
, status
)) {
5990 tevent_req_done(req
);
5993 NTSTATUS
cli_get_ea_list_path_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
5994 size_t *pnum_eas
, struct ea_struct
**peas
)
5996 struct cli_get_ea_list_path_state
*state
= tevent_req_data(
5997 req
, struct cli_get_ea_list_path_state
);
6000 if (tevent_req_is_nterror(req
, &status
)) {
6003 if (!parse_ea_blob(mem_ctx
, state
->data
, state
->num_data
,
6005 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
6007 return NT_STATUS_OK
;
6010 NTSTATUS
cli_get_ea_list_path(struct cli_state
*cli
, const char *path
,
6013 struct ea_struct
**pea_list
)
6015 TALLOC_CTX
*frame
= NULL
;
6016 struct tevent_context
*ev
= NULL
;
6017 struct tevent_req
*req
= NULL
;
6018 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
6020 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
6021 return cli_smb2_get_ea_list_path(cli
,
6028 frame
= talloc_stackframe();
6030 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6032 * Can't use sync call while an async call is in flight
6034 status
= NT_STATUS_INVALID_PARAMETER
;
6037 ev
= samba_tevent_context_init(frame
);
6041 req
= cli_get_ea_list_path_send(frame
, ev
, cli
, path
);
6045 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6048 status
= cli_get_ea_list_path_recv(req
, ctx
, pnum_eas
, pea_list
);
6054 /****************************************************************************
6055 Convert open "flags" arg to uint32_t on wire.
6056 ****************************************************************************/
6058 static uint32_t open_flags_to_wire(int flags
)
6060 int open_mode
= flags
& O_ACCMODE
;
6063 switch (open_mode
) {
6065 ret
|= SMB_O_WRONLY
;
6072 ret
|= SMB_O_RDONLY
;
6076 if (flags
& O_CREAT
) {
6079 if (flags
& O_EXCL
) {
6082 if (flags
& O_TRUNC
) {
6086 if (flags
& O_SYNC
) {
6090 if (flags
& O_APPEND
) {
6091 ret
|= SMB_O_APPEND
;
6093 #if defined(O_DIRECT)
6094 if (flags
& O_DIRECT
) {
6095 ret
|= SMB_O_DIRECT
;
6098 #if defined(O_DIRECTORY)
6099 if (flags
& O_DIRECTORY
) {
6100 ret
|= SMB_O_DIRECTORY
;
6106 /****************************************************************************
6107 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
6108 ****************************************************************************/
6110 struct cli_posix_open_internal_state
{
6114 uint16_t fnum
; /* Out */
6117 static void cli_posix_open_internal_done(struct tevent_req
*subreq
);
6119 static struct tevent_req
*cli_posix_open_internal_send(TALLOC_CTX
*mem_ctx
,
6120 struct tevent_context
*ev
,
6121 struct cli_state
*cli
,
6123 uint32_t wire_flags
,
6126 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6127 struct cli_posix_open_internal_state
*state
= NULL
;
6128 char *fname_cp
= NULL
;
6130 req
= tevent_req_create(
6131 mem_ctx
, &state
, struct cli_posix_open_internal_state
);
6136 /* Setup setup word. */
6137 SSVAL(&state
->setup
, 0, TRANSACT2_SETPATHINFO
);
6139 /* Setup param array. */
6140 state
->param
= talloc_zero_array(state
, uint8_t, 6);
6141 if (tevent_req_nomem(state
->param
, req
)) {
6142 return tevent_req_post(req
, ev
);
6144 SSVAL(state
->param
, 0, SMB_POSIX_PATH_OPEN
);
6147 * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
6149 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
6150 if (tevent_req_nomem(fname_cp
, req
)) {
6151 return tevent_req_post(req
, ev
);
6153 state
->param
= trans2_bytes_push_str(
6155 smbXcli_conn_use_unicode(cli
->conn
),
6160 if (tevent_req_nomem(state
->param
, req
)) {
6161 return tevent_req_post(req
, ev
);
6164 SIVAL(state
->data
,0,0); /* No oplock. */
6165 SIVAL(state
->data
,4,wire_flags
);
6166 SIVAL(state
->data
,8,unix_perms_to_wire(mode
));
6167 SIVAL(state
->data
,12,0); /* Top bits of perms currently undefined. */
6168 SSVAL(state
->data
,16,SMB_NO_INFO_LEVEL_RETURNED
); /* No info level returned. */
6170 subreq
= cli_trans_send(state
, /* mem ctx. */
6171 ev
, /* event ctx. */
6172 cli
, /* cli_state. */
6173 0, /* additional_flags2 */
6174 SMBtrans2
, /* cmd. */
6175 NULL
, /* pipe name. */
6179 &state
->setup
, /* setup. */
6180 1, /* num setup uint16_t words. */
6181 0, /* max returned setup. */
6182 state
->param
, /* param. */
6183 talloc_get_size(state
->param
),/* num param. */
6184 2, /* max returned param. */
6185 state
->data
, /* data. */
6187 12); /* max returned data. */
6189 if (tevent_req_nomem(subreq
, req
)) {
6190 return tevent_req_post(req
, ev
);
6192 tevent_req_set_callback(subreq
, cli_posix_open_internal_done
, req
);
6196 static void cli_posix_open_internal_done(struct tevent_req
*subreq
)
6198 struct tevent_req
*req
= tevent_req_callback_data(
6199 subreq
, struct tevent_req
);
6200 struct cli_posix_open_internal_state
*state
= tevent_req_data(
6201 req
, struct cli_posix_open_internal_state
);
6206 status
= cli_trans_recv(
6219 TALLOC_FREE(subreq
);
6220 if (tevent_req_nterror(req
, status
)) {
6223 state
->fnum
= SVAL(data
,2);
6224 tevent_req_done(req
);
6227 static NTSTATUS
cli_posix_open_internal_recv(struct tevent_req
*req
,
6230 struct cli_posix_open_internal_state
*state
= tevent_req_data(
6231 req
, struct cli_posix_open_internal_state
);
6234 if (tevent_req_is_nterror(req
, &status
)) {
6237 *pfnum
= state
->fnum
;
6238 return NT_STATUS_OK
;
6241 struct cli_posix_open_state
{
6245 static void cli_posix_open_done(struct tevent_req
*subreq
);
6247 struct tevent_req
*cli_posix_open_send(TALLOC_CTX
*mem_ctx
,
6248 struct tevent_context
*ev
,
6249 struct cli_state
*cli
,
6254 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6255 struct cli_posix_open_state
*state
= NULL
;
6256 uint32_t wire_flags
;
6258 req
= tevent_req_create(mem_ctx
, &state
,
6259 struct cli_posix_open_state
);
6264 wire_flags
= open_flags_to_wire(flags
);
6266 subreq
= cli_posix_open_internal_send(
6267 mem_ctx
, ev
, cli
, fname
, wire_flags
, mode
);
6268 if (tevent_req_nomem(subreq
, req
)) {
6269 return tevent_req_post(req
, ev
);
6271 tevent_req_set_callback(subreq
, cli_posix_open_done
, req
);
6275 static void cli_posix_open_done(struct tevent_req
*subreq
)
6277 struct tevent_req
*req
= tevent_req_callback_data(
6278 subreq
, struct tevent_req
);
6279 struct cli_posix_open_state
*state
= tevent_req_data(
6280 req
, struct cli_posix_open_state
);
6283 status
= cli_posix_open_internal_recv(subreq
, &state
->fnum
);
6284 tevent_req_simple_finish_ntstatus(subreq
, status
);
6287 NTSTATUS
cli_posix_open_recv(struct tevent_req
*req
, uint16_t *pfnum
)
6289 struct cli_posix_open_state
*state
= tevent_req_data(
6290 req
, struct cli_posix_open_state
);
6293 if (tevent_req_is_nterror(req
, &status
)) {
6296 *pfnum
= state
->fnum
;
6297 return NT_STATUS_OK
;
6300 /****************************************************************************
6301 Open - POSIX semantics. Doesn't request oplock.
6302 ****************************************************************************/
6304 NTSTATUS
cli_posix_open(struct cli_state
*cli
, const char *fname
,
6305 int flags
, mode_t mode
, uint16_t *pfnum
)
6308 TALLOC_CTX
*frame
= talloc_stackframe();
6309 struct tevent_context
*ev
= NULL
;
6310 struct tevent_req
*req
= NULL
;
6311 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
6313 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6315 * Can't use sync call while an async call is in flight
6317 status
= NT_STATUS_INVALID_PARAMETER
;
6320 ev
= samba_tevent_context_init(frame
);
6324 req
= cli_posix_open_send(
6325 frame
, ev
, cli
, fname
, flags
, mode
);
6329 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6332 status
= cli_posix_open_recv(req
, pfnum
);
6338 struct cli_posix_mkdir_state
{
6339 struct tevent_context
*ev
;
6340 struct cli_state
*cli
;
6343 static void cli_posix_mkdir_done(struct tevent_req
*subreq
);
6345 struct tevent_req
*cli_posix_mkdir_send(TALLOC_CTX
*mem_ctx
,
6346 struct tevent_context
*ev
,
6347 struct cli_state
*cli
,
6351 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6352 struct cli_posix_mkdir_state
*state
= NULL
;
6353 uint32_t wire_flags
;
6355 req
= tevent_req_create(
6356 mem_ctx
, &state
, struct cli_posix_mkdir_state
);
6363 wire_flags
= SMB_O_CREAT
| SMB_O_DIRECTORY
;
6365 subreq
= cli_posix_open_internal_send(
6366 mem_ctx
, ev
, cli
, fname
, wire_flags
, mode
);
6367 if (tevent_req_nomem(subreq
, req
)) {
6368 return tevent_req_post(req
, ev
);
6370 tevent_req_set_callback(subreq
, cli_posix_mkdir_done
, req
);
6374 static void cli_posix_mkdir_done(struct tevent_req
*subreq
)
6376 struct tevent_req
*req
= tevent_req_callback_data(
6377 subreq
, struct tevent_req
);
6381 status
= cli_posix_open_internal_recv(subreq
, &fnum
);
6382 TALLOC_FREE(subreq
);
6383 if (tevent_req_nterror(req
, status
)) {
6386 tevent_req_done(req
);
6389 NTSTATUS
cli_posix_mkdir_recv(struct tevent_req
*req
)
6391 return tevent_req_simple_recv_ntstatus(req
);
6394 NTSTATUS
cli_posix_mkdir(struct cli_state
*cli
, const char *fname
, mode_t mode
)
6396 TALLOC_CTX
*frame
= talloc_stackframe();
6397 struct tevent_context
*ev
= NULL
;
6398 struct tevent_req
*req
= NULL
;
6399 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
6401 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6403 * Can't use sync call while an async call is in flight
6405 status
= NT_STATUS_INVALID_PARAMETER
;
6409 ev
= samba_tevent_context_init(frame
);
6413 req
= cli_posix_mkdir_send(
6414 frame
, ev
, cli
, fname
, mode
);
6418 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6421 status
= cli_posix_mkdir_recv(req
);
6427 /****************************************************************************
6428 unlink or rmdir - POSIX semantics.
6429 ****************************************************************************/
6431 struct cli_posix_unlink_internal_state
{
6435 static void cli_posix_unlink_internal_done(struct tevent_req
*subreq
);
6437 static struct tevent_req
*cli_posix_unlink_internal_send(TALLOC_CTX
*mem_ctx
,
6438 struct tevent_context
*ev
,
6439 struct cli_state
*cli
,
6443 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6444 struct cli_posix_unlink_internal_state
*state
= NULL
;
6446 req
= tevent_req_create(mem_ctx
, &state
,
6447 struct cli_posix_unlink_internal_state
);
6452 /* Setup data word. */
6453 SSVAL(state
->data
, 0, level
);
6455 subreq
= cli_setpathinfo_send(state
, ev
, cli
,
6456 SMB_POSIX_PATH_UNLINK
,
6458 state
->data
, sizeof(state
->data
));
6459 if (tevent_req_nomem(subreq
, req
)) {
6460 return tevent_req_post(req
, ev
);
6462 tevent_req_set_callback(subreq
, cli_posix_unlink_internal_done
, req
);
6466 static void cli_posix_unlink_internal_done(struct tevent_req
*subreq
)
6468 NTSTATUS status
= cli_setpathinfo_recv(subreq
);
6469 tevent_req_simple_finish_ntstatus(subreq
, status
);
6472 static NTSTATUS
cli_posix_unlink_internal_recv(struct tevent_req
*req
)
6474 return tevent_req_simple_recv_ntstatus(req
);
6477 struct cli_posix_unlink_state
{
6481 static void cli_posix_unlink_done(struct tevent_req
*subreq
);
6483 struct tevent_req
*cli_posix_unlink_send(TALLOC_CTX
*mem_ctx
,
6484 struct tevent_context
*ev
,
6485 struct cli_state
*cli
,
6488 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6489 struct cli_posix_unlink_state
*state
;
6491 req
= tevent_req_create(
6492 mem_ctx
, &state
, struct cli_posix_unlink_state
);
6496 subreq
= cli_posix_unlink_internal_send(
6497 mem_ctx
, ev
, cli
, fname
, SMB_POSIX_UNLINK_FILE_TARGET
);
6498 if (tevent_req_nomem(subreq
, req
)) {
6499 return tevent_req_post(req
, ev
);
6501 tevent_req_set_callback(subreq
, cli_posix_unlink_done
, req
);
6505 static void cli_posix_unlink_done(struct tevent_req
*subreq
)
6507 NTSTATUS status
= cli_posix_unlink_internal_recv(subreq
);
6508 tevent_req_simple_finish_ntstatus(subreq
, status
);
6511 NTSTATUS
cli_posix_unlink_recv(struct tevent_req
*req
)
6513 return tevent_req_simple_recv_ntstatus(req
);
6516 /****************************************************************************
6517 unlink - POSIX semantics.
6518 ****************************************************************************/
6520 NTSTATUS
cli_posix_unlink(struct cli_state
*cli
, const char *fname
)
6522 TALLOC_CTX
*frame
= talloc_stackframe();
6523 struct tevent_context
*ev
= NULL
;
6524 struct tevent_req
*req
= NULL
;
6525 NTSTATUS status
= NT_STATUS_OK
;
6527 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6529 * Can't use sync call while an async call is in flight
6531 status
= NT_STATUS_INVALID_PARAMETER
;
6535 ev
= samba_tevent_context_init(frame
);
6537 status
= NT_STATUS_NO_MEMORY
;
6541 req
= cli_posix_unlink_send(frame
,
6546 status
= NT_STATUS_NO_MEMORY
;
6550 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6554 status
= cli_posix_unlink_recv(req
);
6561 /****************************************************************************
6562 rmdir - POSIX semantics.
6563 ****************************************************************************/
6565 struct cli_posix_rmdir_state
{
6569 static void cli_posix_rmdir_done(struct tevent_req
*subreq
);
6571 struct tevent_req
*cli_posix_rmdir_send(TALLOC_CTX
*mem_ctx
,
6572 struct tevent_context
*ev
,
6573 struct cli_state
*cli
,
6576 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
6577 struct cli_posix_rmdir_state
*state
;
6579 req
= tevent_req_create(mem_ctx
, &state
, struct cli_posix_rmdir_state
);
6583 subreq
= cli_posix_unlink_internal_send(
6584 mem_ctx
, ev
, cli
, fname
, SMB_POSIX_UNLINK_DIRECTORY_TARGET
);
6585 if (tevent_req_nomem(subreq
, req
)) {
6586 return tevent_req_post(req
, ev
);
6588 tevent_req_set_callback(subreq
, cli_posix_rmdir_done
, req
);
6592 static void cli_posix_rmdir_done(struct tevent_req
*subreq
)
6594 NTSTATUS status
= cli_posix_unlink_internal_recv(subreq
);
6595 tevent_req_simple_finish_ntstatus(subreq
, status
);
6598 NTSTATUS
cli_posix_rmdir_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
)
6600 return tevent_req_simple_recv_ntstatus(req
);
6603 NTSTATUS
cli_posix_rmdir(struct cli_state
*cli
, const char *fname
)
6605 TALLOC_CTX
*frame
= talloc_stackframe();
6606 struct tevent_context
*ev
= NULL
;
6607 struct tevent_req
*req
= NULL
;
6608 NTSTATUS status
= NT_STATUS_OK
;
6610 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6612 * Can't use sync call while an async call is in flight
6614 status
= NT_STATUS_INVALID_PARAMETER
;
6618 ev
= samba_tevent_context_init(frame
);
6620 status
= NT_STATUS_NO_MEMORY
;
6624 req
= cli_posix_rmdir_send(frame
,
6629 status
= NT_STATUS_NO_MEMORY
;
6633 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6637 status
= cli_posix_rmdir_recv(req
, frame
);
6644 /****************************************************************************
6646 ****************************************************************************/
6648 struct cli_notify_state
{
6649 struct tevent_req
*subreq
;
6651 uint32_t num_changes
;
6652 struct notify_change
*changes
;
6655 static void cli_notify_done(struct tevent_req
*subreq
);
6656 static void cli_notify_done_smb2(struct tevent_req
*subreq
);
6657 static bool cli_notify_cancel(struct tevent_req
*req
);
6659 struct tevent_req
*cli_notify_send(TALLOC_CTX
*mem_ctx
,
6660 struct tevent_context
*ev
,
6661 struct cli_state
*cli
, uint16_t fnum
,
6662 uint32_t buffer_size
,
6663 uint32_t completion_filter
, bool recursive
)
6665 struct tevent_req
*req
;
6666 struct cli_notify_state
*state
;
6667 unsigned old_timeout
;
6669 req
= tevent_req_create(mem_ctx
, &state
, struct cli_notify_state
);
6674 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
6676 * Notifies should not time out
6678 old_timeout
= cli_set_timeout(cli
, 0);
6680 state
->subreq
= cli_smb2_notify_send(
6689 cli_set_timeout(cli
, old_timeout
);
6691 if (tevent_req_nomem(state
->subreq
, req
)) {
6692 return tevent_req_post(req
, ev
);
6694 tevent_req_set_callback(
6695 state
->subreq
, cli_notify_done_smb2
, req
);
6699 SIVAL(state
->setup
, 0, completion_filter
);
6700 SSVAL(state
->setup
, 4, fnum
);
6701 SSVAL(state
->setup
, 6, recursive
);
6704 * Notifies should not time out
6706 old_timeout
= cli_set_timeout(cli
, 0);
6708 state
->subreq
= cli_trans_send(
6709 state
, /* mem ctx. */
6710 ev
, /* event ctx. */
6711 cli
, /* cli_state. */
6712 0, /* additional_flags2 */
6713 SMBnttrans
, /* cmd. */
6714 NULL
, /* pipe name. */
6716 NT_TRANSACT_NOTIFY_CHANGE
, /* function. */
6718 (uint16_t *)state
->setup
, /* setup. */
6719 4, /* num setup uint16_t words. */
6720 0, /* max returned setup. */
6723 buffer_size
, /* max returned param. */
6726 0); /* max returned data. */
6728 cli_set_timeout(cli
, old_timeout
);
6730 if (tevent_req_nomem(state
->subreq
, req
)) {
6731 return tevent_req_post(req
, ev
);
6733 tevent_req_set_callback(state
->subreq
, cli_notify_done
, req
);
6735 tevent_req_set_cancel_fn(req
, cli_notify_cancel
);
6739 static bool cli_notify_cancel(struct tevent_req
*req
)
6741 struct cli_notify_state
*state
= tevent_req_data(
6742 req
, struct cli_notify_state
);
6745 ok
= tevent_req_cancel(state
->subreq
);
6749 static void cli_notify_done(struct tevent_req
*subreq
)
6751 struct tevent_req
*req
= tevent_req_callback_data(
6752 subreq
, struct tevent_req
);
6753 struct cli_notify_state
*state
= tevent_req_data(
6754 req
, struct cli_notify_state
);
6757 uint32_t i
, ofs
, num_params
;
6760 status
= cli_trans_recv(subreq
, talloc_tos(), &flags2
, NULL
, 0, NULL
,
6761 ¶ms
, 0, &num_params
, NULL
, 0, NULL
);
6762 TALLOC_FREE(subreq
);
6763 state
->subreq
= NULL
;
6764 if (tevent_req_nterror(req
, status
)) {
6765 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status
)));
6769 state
->num_changes
= 0;
6772 while (num_params
- ofs
> 12) {
6773 uint32_t next
= IVAL(params
, ofs
);
6774 state
->num_changes
+= 1;
6776 if ((next
== 0) || (ofs
+next
>= num_params
)) {
6782 state
->changes
= talloc_array(state
, struct notify_change
,
6783 state
->num_changes
);
6784 if (tevent_req_nomem(state
->changes
, req
)) {
6785 TALLOC_FREE(params
);
6791 for (i
=0; i
<state
->num_changes
; i
++) {
6792 uint32_t next
= IVAL(params
, ofs
);
6793 uint32_t len
= IVAL(params
, ofs
+8);
6797 if (smb_buffer_oob(num_params
, ofs
+ 12, len
)) {
6798 TALLOC_FREE(params
);
6800 req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
6804 state
->changes
[i
].action
= IVAL(params
, ofs
+4);
6805 ret
= pull_string_talloc(state
->changes
,
6811 STR_TERMINATE
|STR_UNICODE
);
6813 TALLOC_FREE(params
);
6814 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
6817 state
->changes
[i
].name
= name
;
6821 TALLOC_FREE(params
);
6822 tevent_req_done(req
);
6825 static void cli_notify_done_smb2(struct tevent_req
*subreq
)
6827 struct tevent_req
*req
= tevent_req_callback_data(
6828 subreq
, struct tevent_req
);
6829 struct cli_notify_state
*state
= tevent_req_data(
6830 req
, struct cli_notify_state
);
6833 status
= cli_smb2_notify_recv(
6837 &state
->num_changes
);
6838 TALLOC_FREE(subreq
);
6839 if (tevent_req_nterror(req
, status
)) {
6842 tevent_req_done(req
);
6845 NTSTATUS
cli_notify_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
6846 uint32_t *pnum_changes
,
6847 struct notify_change
**pchanges
)
6849 struct cli_notify_state
*state
= tevent_req_data(
6850 req
, struct cli_notify_state
);
6853 if (tevent_req_is_nterror(req
, &status
)) {
6857 *pnum_changes
= state
->num_changes
;
6858 *pchanges
= talloc_move(mem_ctx
, &state
->changes
);
6859 return NT_STATUS_OK
;
6862 NTSTATUS
cli_notify(struct cli_state
*cli
, uint16_t fnum
, uint32_t buffer_size
,
6863 uint32_t completion_filter
, bool recursive
,
6864 TALLOC_CTX
*mem_ctx
, uint32_t *pnum_changes
,
6865 struct notify_change
**pchanges
)
6868 struct tevent_context
*ev
;
6869 struct tevent_req
*req
;
6870 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
6872 frame
= talloc_stackframe();
6874 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
6876 * Can't use sync call while an async call is in flight
6878 status
= NT_STATUS_INVALID_PARAMETER
;
6881 ev
= samba_tevent_context_init(frame
);
6885 req
= cli_notify_send(ev
, ev
, cli
, fnum
, buffer_size
,
6886 completion_filter
, recursive
);
6890 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
6893 status
= cli_notify_recv(req
, mem_ctx
, pnum_changes
, pchanges
);
6899 struct cli_qpathinfo_state
{
6908 static void cli_qpathinfo_done(struct tevent_req
*subreq
);
6909 static void cli_qpathinfo_done2(struct tevent_req
*subreq
);
6911 struct tevent_req
*cli_qpathinfo_send(TALLOC_CTX
*mem_ctx
,
6912 struct tevent_context
*ev
,
6913 struct cli_state
*cli
, const char *fname
,
6914 uint16_t level
, uint32_t min_rdata
,
6917 struct tevent_req
*req
, *subreq
;
6918 struct cli_qpathinfo_state
*state
;
6919 uint16_t additional_flags2
= 0;
6920 char *fname_cp
= NULL
;
6922 req
= tevent_req_create(mem_ctx
, &state
, struct cli_qpathinfo_state
);
6927 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
6928 uint16_t smb2_level
= 0;
6931 case SMB_QUERY_FILE_ALT_NAME_INFO
:
6932 smb2_level
= FSCC_FILE_ALTERNATE_NAME_INFORMATION
;
6935 tevent_req_nterror(req
, NT_STATUS_INVALID_LEVEL
);
6936 return tevent_req_post(req
, ev
);
6939 subreq
= cli_smb2_qpathinfo_send(state
,
6946 if (tevent_req_nomem(subreq
, req
)) {
6947 return tevent_req_post(req
, ev
);
6949 tevent_req_set_callback(subreq
, cli_qpathinfo_done2
, req
);
6953 state
->min_rdata
= min_rdata
;
6954 SSVAL(state
->setup
, 0, TRANSACT2_QPATHINFO
);
6956 state
->param
= talloc_zero_array(state
, uint8_t, 6);
6957 if (tevent_req_nomem(state
->param
, req
)) {
6958 return tevent_req_post(req
, ev
);
6960 SSVAL(state
->param
, 0, level
);
6962 * qpathinfo on a DFS share must use DFS names.
6964 fname_cp
= smb1_dfs_share_path(state
, cli
, fname
);
6965 if (tevent_req_nomem(fname_cp
, req
)) {
6966 return tevent_req_post(req
, ev
);
6968 state
->param
= trans2_bytes_push_str(state
->param
,
6969 smbXcli_conn_use_unicode(cli
->conn
),
6973 if (tevent_req_nomem(state
->param
, req
)) {
6974 return tevent_req_post(req
, ev
);
6977 if (clistr_is_previous_version_path(fname
) &&
6978 !INFO_LEVEL_IS_UNIX(level
)) {
6979 additional_flags2
= FLAGS2_REPARSE_PATH
;
6982 subreq
= cli_trans_send(
6983 state
, /* mem ctx. */
6984 ev
, /* event ctx. */
6985 cli
, /* cli_state. */
6986 additional_flags2
, /* additional_flags2 */
6987 SMBtrans2
, /* cmd. */
6988 NULL
, /* pipe name. */
6992 state
->setup
, /* setup. */
6993 1, /* num setup uint16_t words. */
6994 0, /* max returned setup. */
6995 state
->param
, /* param. */
6996 talloc_get_size(state
->param
), /* num param. */
6997 2, /* max returned param. */
7000 max_rdata
); /* max returned data. */
7002 if (tevent_req_nomem(subreq
, req
)) {
7003 return tevent_req_post(req
, ev
);
7005 tevent_req_set_callback(subreq
, cli_qpathinfo_done
, req
);
7009 static void cli_qpathinfo_done(struct tevent_req
*subreq
)
7011 struct tevent_req
*req
= tevent_req_callback_data(
7012 subreq
, struct tevent_req
);
7013 struct cli_qpathinfo_state
*state
= tevent_req_data(
7014 req
, struct cli_qpathinfo_state
);
7017 status
= cli_trans_recv(subreq
, state
, NULL
, NULL
, 0, NULL
,
7019 &state
->rdata
, state
->min_rdata
,
7021 if (tevent_req_nterror(req
, status
)) {
7024 tevent_req_done(req
);
7027 static void cli_qpathinfo_done2(struct tevent_req
*subreq
)
7029 struct tevent_req
*req
=
7030 tevent_req_callback_data(subreq
, struct tevent_req
);
7031 struct cli_qpathinfo_state
*state
=
7032 tevent_req_data(req
, struct cli_qpathinfo_state
);
7035 status
= cli_smb2_qpathinfo_recv(subreq
,
7039 if (tevent_req_nterror(req
, status
)) {
7042 tevent_req_done(req
);
7045 NTSTATUS
cli_qpathinfo_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
7046 uint8_t **rdata
, uint32_t *num_rdata
)
7048 struct cli_qpathinfo_state
*state
= tevent_req_data(
7049 req
, struct cli_qpathinfo_state
);
7052 if (tevent_req_is_nterror(req
, &status
)) {
7055 if (rdata
!= NULL
) {
7056 *rdata
= talloc_move(mem_ctx
, &state
->rdata
);
7058 TALLOC_FREE(state
->rdata
);
7060 if (num_rdata
!= NULL
) {
7061 *num_rdata
= state
->num_rdata
;
7063 return NT_STATUS_OK
;
7066 NTSTATUS
cli_qpathinfo(TALLOC_CTX
*mem_ctx
, struct cli_state
*cli
,
7067 const char *fname
, uint16_t level
, uint32_t min_rdata
,
7069 uint8_t **rdata
, uint32_t *num_rdata
)
7071 TALLOC_CTX
*frame
= talloc_stackframe();
7072 struct tevent_context
*ev
;
7073 struct tevent_req
*req
;
7074 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
7076 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
7078 * Can't use sync call while an async call is in flight
7080 status
= NT_STATUS_INVALID_PARAMETER
;
7083 ev
= samba_tevent_context_init(frame
);
7087 req
= cli_qpathinfo_send(frame
, ev
, cli
, fname
, level
, min_rdata
,
7092 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
7095 status
= cli_qpathinfo_recv(req
, mem_ctx
, rdata
, num_rdata
);
7101 struct cli_qfileinfo_state
{
7105 uint16_t recv_flags2
;
7111 static void cli_qfileinfo_done2(struct tevent_req
*subreq
);
7112 static void cli_qfileinfo_done(struct tevent_req
*subreq
);
7114 struct tevent_req
*cli_qfileinfo_send(TALLOC_CTX
*mem_ctx
,
7115 struct tevent_context
*ev
,
7116 struct cli_state
*cli
,
7118 uint16_t fscc_level
,
7122 struct tevent_req
*req
, *subreq
;
7123 struct cli_qfileinfo_state
*state
;
7126 req
= tevent_req_create(mem_ctx
, &state
, struct cli_qfileinfo_state
);
7131 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
7132 max_rdata
= MIN(max_rdata
,
7133 smb2cli_conn_max_trans_size(cli
->conn
));
7135 subreq
= cli_smb2_query_info_fnum_send(
7136 state
, /* mem_ctx */
7140 SMB2_0_INFO_FILE
, /* in_info_type */
7141 fscc_level
, /* in_file_info_class */
7142 max_rdata
, /* in_max_output_length */
7143 NULL
, /* in_input_buffer */
7144 0, /* in_additional_info */
7146 if (tevent_req_nomem(subreq
, req
)) {
7147 return tevent_req_post(req
, ev
);
7149 tevent_req_set_callback(subreq
, cli_qfileinfo_done2
, req
);
7153 max_rdata
= MIN(max_rdata
, UINT16_MAX
);
7155 switch (fscc_level
) {
7156 case FSCC_FILE_BASIC_INFORMATION
:
7157 smb_level
= SMB_QUERY_FILE_BASIC_INFO
;
7159 case FSCC_FILE_STANDARD_INFORMATION
:
7160 smb_level
= SMB_QUERY_FILE_STANDARD_INFO
;
7162 case FSCC_FILE_EA_INFORMATION
:
7163 smb_level
= SMB_QUERY_FILE_EA_INFO
;
7165 case FSCC_FILE_NAME_INFORMATION
:
7166 smb_level
= SMB_QUERY_FILE_NAME_INFO
;
7168 case FSCC_FILE_ALL_INFORMATION
:
7169 smb_level
= SMB_QUERY_FILE_ALL_INFO
;
7171 case FSCC_FILE_ALTERNATE_NAME_INFORMATION
:
7172 smb_level
= SMB_QUERY_FILE_ALT_NAME_INFO
;
7174 case FSCC_FILE_STREAM_INFORMATION
:
7175 smb_level
= SMB_QUERY_FILE_STREAM_INFO
;
7177 case FSCC_FILE_COMPRESSION_INFORMATION
:
7178 smb_level
= SMB_QUERY_COMPRESSION_INFO
;
7181 /* Probably wrong, but the server will tell us */
7182 smb_level
= fscc_level
;
7186 state
->min_rdata
= min_rdata
;
7187 SSVAL(state
->param
, 0, fnum
);
7188 SSVAL(state
->param
, 2, smb_level
);
7189 SSVAL(state
->setup
, 0, TRANSACT2_QFILEINFO
);
7191 subreq
= cli_trans_send(
7192 state
, /* mem ctx. */
7193 ev
, /* event ctx. */
7194 cli
, /* cli_state. */
7195 0, /* additional_flags2 */
7196 SMBtrans2
, /* cmd. */
7197 NULL
, /* pipe name. */
7201 state
->setup
, /* setup. */
7202 1, /* num setup uint16_t words. */
7203 0, /* max returned setup. */
7204 state
->param
, /* param. */
7205 sizeof(state
->param
), /* num param. */
7206 2, /* max returned param. */
7209 max_rdata
); /* max returned data. */
7211 if (tevent_req_nomem(subreq
, req
)) {
7212 return tevent_req_post(req
, ev
);
7214 tevent_req_set_callback(subreq
, cli_qfileinfo_done
, req
);
7218 static void cli_qfileinfo_done2(struct tevent_req
*subreq
)
7220 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
7222 struct cli_qfileinfo_state
*state
= tevent_req_data(
7223 req
, struct cli_qfileinfo_state
);
7224 DATA_BLOB outbuf
= {};
7227 status
= cli_smb2_query_info_fnum_recv(subreq
, state
, &outbuf
);
7228 TALLOC_FREE(subreq
);
7229 if (tevent_req_nterror(req
, status
)) {
7233 if (outbuf
.length
< state
->min_rdata
) {
7234 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
7238 state
->rdata
= outbuf
.data
;
7239 state
->num_rdata
= outbuf
.length
;
7240 tevent_req_done(req
);
7243 static void cli_qfileinfo_done(struct tevent_req
*subreq
)
7245 struct tevent_req
*req
= tevent_req_callback_data(
7246 subreq
, struct tevent_req
);
7247 struct cli_qfileinfo_state
*state
= tevent_req_data(
7248 req
, struct cli_qfileinfo_state
);
7251 status
= cli_trans_recv(subreq
, state
,
7252 &state
->recv_flags2
,
7255 &state
->rdata
, state
->min_rdata
,
7257 if (tevent_req_nterror(req
, status
)) {
7260 tevent_req_done(req
);
7263 NTSTATUS
cli_qfileinfo_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
7264 uint16_t *recv_flags2
,
7265 uint8_t **rdata
, uint32_t *num_rdata
)
7267 struct cli_qfileinfo_state
*state
= tevent_req_data(
7268 req
, struct cli_qfileinfo_state
);
7271 if (tevent_req_is_nterror(req
, &status
)) {
7275 if (recv_flags2
!= NULL
) {
7276 *recv_flags2
= state
->recv_flags2
;
7278 if (rdata
!= NULL
) {
7279 *rdata
= talloc_move(mem_ctx
, &state
->rdata
);
7281 if (num_rdata
!= NULL
) {
7282 *num_rdata
= state
->num_rdata
;
7285 tevent_req_received(req
);
7286 return NT_STATUS_OK
;
7289 NTSTATUS
cli_qfileinfo(TALLOC_CTX
*mem_ctx
,
7290 struct cli_state
*cli
,
7292 uint16_t fscc_level
,
7295 uint16_t *recv_flags2
,
7297 uint32_t *num_rdata
)
7299 TALLOC_CTX
*frame
= talloc_stackframe();
7300 struct tevent_context
*ev
;
7301 struct tevent_req
*req
;
7302 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
7304 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
7306 * Can't use sync call while an async call is in flight
7308 status
= NT_STATUS_INVALID_PARAMETER
;
7311 ev
= samba_tevent_context_init(frame
);
7315 req
= cli_qfileinfo_send(
7316 frame
, ev
, cli
, fnum
, fscc_level
, min_rdata
, max_rdata
);
7320 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
7323 status
= cli_qfileinfo_recv(req
, mem_ctx
, recv_flags2
, rdata
, num_rdata
);
7329 struct cli_flush_state
{
7333 static void cli_flush_done(struct tevent_req
*subreq
);
7335 struct tevent_req
*cli_flush_send(TALLOC_CTX
*mem_ctx
,
7336 struct tevent_context
*ev
,
7337 struct cli_state
*cli
,
7340 struct tevent_req
*req
, *subreq
;
7341 struct cli_flush_state
*state
;
7343 req
= tevent_req_create(mem_ctx
, &state
, struct cli_flush_state
);
7347 SSVAL(state
->vwv
+ 0, 0, fnum
);
7349 subreq
= cli_smb_send(state
, ev
, cli
, SMBflush
, 0, 0, 1, state
->vwv
,
7351 if (tevent_req_nomem(subreq
, req
)) {
7352 return tevent_req_post(req
, ev
);
7354 tevent_req_set_callback(subreq
, cli_flush_done
, req
);
7358 static void cli_flush_done(struct tevent_req
*subreq
)
7360 struct tevent_req
*req
= tevent_req_callback_data(
7361 subreq
, struct tevent_req
);
7364 status
= cli_smb_recv(subreq
, NULL
, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
7365 TALLOC_FREE(subreq
);
7366 if (tevent_req_nterror(req
, status
)) {
7369 tevent_req_done(req
);
7372 NTSTATUS
cli_flush_recv(struct tevent_req
*req
)
7374 return tevent_req_simple_recv_ntstatus(req
);
7377 NTSTATUS
cli_flush(TALLOC_CTX
*mem_ctx
, struct cli_state
*cli
, uint16_t fnum
)
7379 TALLOC_CTX
*frame
= talloc_stackframe();
7380 struct tevent_context
*ev
;
7381 struct tevent_req
*req
;
7382 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
7384 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
7386 * Can't use sync call while an async call is in flight
7388 status
= NT_STATUS_INVALID_PARAMETER
;
7391 ev
= samba_tevent_context_init(frame
);
7395 req
= cli_flush_send(frame
, ev
, cli
, fnum
);
7399 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
7402 status
= cli_flush_recv(req
);
7408 struct cli_shadow_copy_data_state
{
7415 static void cli_shadow_copy_data_done(struct tevent_req
*subreq
);
7417 struct tevent_req
*cli_shadow_copy_data_send(TALLOC_CTX
*mem_ctx
,
7418 struct tevent_context
*ev
,
7419 struct cli_state
*cli
,
7423 struct tevent_req
*req
, *subreq
;
7424 struct cli_shadow_copy_data_state
*state
;
7427 req
= tevent_req_create(mem_ctx
, &state
,
7428 struct cli_shadow_copy_data_state
);
7432 state
->get_names
= get_names
;
7433 ret_size
= get_names
? CLI_BUFFER_SIZE
: 16;
7435 SIVAL(state
->setup
+ 0, 0, FSCTL_GET_SHADOW_COPY_DATA
);
7436 SSVAL(state
->setup
+ 2, 0, fnum
);
7437 SCVAL(state
->setup
+ 3, 0, 1); /* isFsctl */
7438 SCVAL(state
->setup
+ 3, 1, 0); /* compfilter, isFlags (WSSP) */
7440 subreq
= cli_trans_send(
7441 state
, ev
, cli
, 0, SMBnttrans
, NULL
, 0, NT_TRANSACT_IOCTL
, 0,
7442 state
->setup
, ARRAY_SIZE(state
->setup
),
7443 ARRAY_SIZE(state
->setup
),
7446 if (tevent_req_nomem(subreq
, req
)) {
7447 return tevent_req_post(req
, ev
);
7449 tevent_req_set_callback(subreq
, cli_shadow_copy_data_done
, req
);
7453 static void cli_shadow_copy_data_done(struct tevent_req
*subreq
)
7455 struct tevent_req
*req
= tevent_req_callback_data(
7456 subreq
, struct tevent_req
);
7457 struct cli_shadow_copy_data_state
*state
= tevent_req_data(
7458 req
, struct cli_shadow_copy_data_state
);
7461 status
= cli_trans_recv(subreq
, state
, NULL
,
7462 NULL
, 0, NULL
, /* setup */
7463 NULL
, 0, NULL
, /* param */
7464 &state
->data
, 12, &state
->num_data
);
7465 TALLOC_FREE(subreq
);
7466 if (tevent_req_nterror(req
, status
)) {
7469 tevent_req_done(req
);
7472 NTSTATUS
cli_shadow_copy_data_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
7473 char ***pnames
, int *pnum_names
)
7475 struct cli_shadow_copy_data_state
*state
= tevent_req_data(
7476 req
, struct cli_shadow_copy_data_state
);
7477 char **names
= NULL
;
7478 uint32_t i
, num_names
;
7480 uint8_t *endp
= NULL
;
7483 if (tevent_req_is_nterror(req
, &status
)) {
7487 if (state
->num_data
< 16) {
7488 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7491 num_names
= IVAL(state
->data
, 4);
7492 dlength
= IVAL(state
->data
, 8);
7494 if (num_names
> 0x7FFFFFFF) {
7495 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7498 if (!state
->get_names
) {
7499 *pnum_names
= (int)num_names
;
7500 return NT_STATUS_OK
;
7503 if (dlength
+ 12 < 12) {
7504 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7506 if (dlength
+ 12 > state
->num_data
) {
7507 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7509 if (state
->num_data
+ (2 * sizeof(SHADOW_COPY_LABEL
)) <
7511 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7514 names
= talloc_array(mem_ctx
, char *, num_names
);
7515 if (names
== NULL
) {
7516 return NT_STATUS_NO_MEMORY
;
7519 endp
= state
->data
+ state
->num_data
;
7521 for (i
=0; i
<num_names
; i
++) {
7524 size_t converted_size
;
7526 src
= state
->data
+ 12 + i
* 2 * sizeof(SHADOW_COPY_LABEL
);
7528 if (src
+ (2 * sizeof(SHADOW_COPY_LABEL
)) > endp
) {
7529 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7532 ret
= convert_string_talloc(
7533 names
, CH_UTF16LE
, CH_UNIX
,
7534 src
, 2 * sizeof(SHADOW_COPY_LABEL
),
7535 &names
[i
], &converted_size
);
7538 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
7541 *pnum_names
= (int)num_names
;
7543 return NT_STATUS_OK
;
7546 NTSTATUS
cli_shadow_copy_data(TALLOC_CTX
*mem_ctx
, struct cli_state
*cli
,
7547 uint16_t fnum
, bool get_names
,
7548 char ***pnames
, int *pnum_names
)
7550 TALLOC_CTX
*frame
= NULL
;
7551 struct tevent_context
*ev
;
7552 struct tevent_req
*req
;
7553 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
7555 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
7556 return cli_smb2_shadow_copy_data(mem_ctx
,
7564 frame
= talloc_stackframe();
7566 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
7568 * Can't use sync call while an async call is in flight
7570 status
= NT_STATUS_INVALID_PARAMETER
;
7573 ev
= samba_tevent_context_init(frame
);
7577 req
= cli_shadow_copy_data_send(frame
, ev
, cli
, fnum
, get_names
);
7581 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
7584 status
= cli_shadow_copy_data_recv(req
, mem_ctx
, pnames
, pnum_names
);
7590 struct cli_fsctl_state
{
7594 static void cli_fsctl_smb1_done(struct tevent_req
*subreq
);
7595 static void cli_fsctl_smb2_done(struct tevent_req
*subreq
);
7597 struct tevent_req
*cli_fsctl_send(
7598 TALLOC_CTX
*mem_ctx
,
7599 struct tevent_context
*ev
,
7600 struct cli_state
*cli
,
7603 const DATA_BLOB
*in
,
7606 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
7607 struct cli_fsctl_state
*state
= NULL
;
7608 uint16_t *setup
= NULL
;
7609 uint8_t *data
= NULL
;
7610 uint32_t num_data
= 0;
7612 req
= tevent_req_create(mem_ctx
, &state
, struct cli_fsctl_state
);
7617 if (smbXcli_conn_protocol(cli
->conn
) >= PROTOCOL_SMB2_02
) {
7618 subreq
= cli_smb2_fsctl_send(
7619 state
, ev
, cli
, fnum
, ctl_code
, in
, max_out
);
7620 if (tevent_req_nomem(subreq
, req
)) {
7621 return tevent_req_post(req
, ev
);
7623 tevent_req_set_callback(subreq
, cli_fsctl_smb2_done
, req
);
7627 setup
= talloc_array(state
, uint16_t, 4);
7628 if (tevent_req_nomem(setup
, req
)) {
7629 return tevent_req_post(req
, ev
);
7631 SIVAL(setup
, 0, ctl_code
);
7632 SSVAL(setup
, 4, fnum
);
7633 SCVAL(setup
, 6, 1); /* IsFcntl */
7634 SCVAL(setup
, 7, 0); /* IsFlags */
7638 num_data
= in
->length
;
7641 subreq
= cli_trans_send(state
,
7644 0, /* additional_flags2 */
7645 SMBnttrans
, /* cmd */
7648 NT_TRANSACT_IOCTL
, /* function */
7658 max_out
); /* data */
7660 if (tevent_req_nomem(subreq
, req
)) {
7661 return tevent_req_post(req
, ev
);
7663 tevent_req_set_callback(subreq
, cli_fsctl_smb1_done
, req
);
7667 static void cli_fsctl_smb2_done(struct tevent_req
*subreq
)
7669 struct tevent_req
*req
= tevent_req_callback_data(
7670 subreq
, struct tevent_req
);
7671 struct cli_fsctl_state
*state
= tevent_req_data(
7672 req
, struct cli_fsctl_state
);
7675 status
= cli_smb2_fsctl_recv(subreq
, state
, &state
->out
);
7676 tevent_req_simple_finish_ntstatus(subreq
, status
);
7679 static void cli_fsctl_smb1_done(struct tevent_req
*subreq
)
7681 struct tevent_req
*req
= tevent_req_callback_data(
7682 subreq
, struct tevent_req
);
7683 struct cli_fsctl_state
*state
= tevent_req_data(
7684 req
, struct cli_fsctl_state
);
7685 uint8_t *out
= NULL
;
7689 status
= cli_trans_recv(
7690 subreq
, state
, NULL
,
7691 NULL
, 0, NULL
, /* rsetup */
7692 NULL
, 0, NULL
, /* rparam */
7694 TALLOC_FREE(subreq
);
7695 if (tevent_req_nterror(req
, status
)) {
7698 state
->out
= (DATA_BLOB
) {
7699 .data
= out
, .length
= out_len
,
7701 tevent_req_done(req
);
7704 NTSTATUS
cli_fsctl_recv(
7705 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
, DATA_BLOB
*out
)
7707 struct cli_fsctl_state
*state
= tevent_req_data(
7708 req
, struct cli_fsctl_state
);
7711 if (tevent_req_is_nterror(req
, &status
)) {
7716 *out
= (DATA_BLOB
) {
7717 .data
= talloc_move(mem_ctx
, &state
->out
.data
),
7718 .length
= state
->out
.length
,
7722 return NT_STATUS_OK
;