2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "lib/util_ea.h"
41 #include "librpc/gen_ndr/ndr_ioctl.h"
44 uint64_t fid_persistent
;
45 uint64_t fid_volatile
;
49 * Handle mapping code.
52 /***************************************************************
53 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
54 Ensures handle is owned by cli struct.
55 ***************************************************************/
57 static NTSTATUS
map_smb2_handle_to_fnum(struct cli_state
*cli
,
58 const struct smb2_hnd
*ph
, /* In */
59 uint16_t *pfnum
) /* Out */
62 struct idr_context
*idp
= cli
->smb2
.open_handles
;
63 struct smb2_hnd
*owned_h
= talloc_memdup(cli
,
65 sizeof(struct smb2_hnd
));
67 if (owned_h
== NULL
) {
68 return NT_STATUS_NO_MEMORY
;
73 cli
->smb2
.open_handles
= idr_init(cli
);
74 if (cli
->smb2
.open_handles
== NULL
) {
76 return NT_STATUS_NO_MEMORY
;
78 idp
= cli
->smb2
.open_handles
;
81 ret
= idr_get_new_above(idp
, owned_h
, 1, 0xFFFE);
84 return NT_STATUS_NO_MEMORY
;
87 *pfnum
= (uint16_t)ret
;
91 /***************************************************************
92 Return the smb2_hnd pointer associated with the given fnum.
93 ***************************************************************/
95 static NTSTATUS
map_fnum_to_smb2_handle(struct cli_state
*cli
,
96 uint16_t fnum
, /* In */
97 struct smb2_hnd
**pph
) /* Out */
99 struct idr_context
*idp
= cli
->smb2
.open_handles
;
102 return NT_STATUS_INVALID_PARAMETER
;
104 *pph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
106 return NT_STATUS_INVALID_HANDLE
;
111 /***************************************************************
112 Delete the fnum to smb2_hnd mapping. Zeros out handle on
114 ***************************************************************/
116 static NTSTATUS
delete_smb2_handle_mapping(struct cli_state
*cli
,
117 struct smb2_hnd
**pph
, /* In */
118 uint16_t fnum
) /* In */
120 struct idr_context
*idp
= cli
->smb2
.open_handles
;
124 return NT_STATUS_INVALID_PARAMETER
;
127 ph
= (struct smb2_hnd
*)idr_find(idp
, fnum
);
129 return NT_STATUS_INVALID_PARAMETER
;
131 idr_remove(idp
, fnum
);
136 /***************************************************************
138 ***************************************************************/
140 static uint8_t flags_to_smb2_oplock(uint32_t create_flags
)
142 if (create_flags
& REQUEST_BATCH_OPLOCK
) {
143 return SMB2_OPLOCK_LEVEL_BATCH
;
144 } else if (create_flags
& REQUEST_OPLOCK
) {
145 return SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
148 /* create_flags doesn't do a level2 request. */
149 return SMB2_OPLOCK_LEVEL_NONE
;
152 /***************************************************************
153 Small wrapper that allows SMB2 create to return a uint16_t fnum.
154 ***************************************************************/
156 struct cli_smb2_create_fnum_state
{
157 struct cli_state
*cli
;
158 struct smb_create_returns cr
;
160 struct tevent_req
*subreq
;
163 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
);
164 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
);
166 struct tevent_req
*cli_smb2_create_fnum_send(TALLOC_CTX
*mem_ctx
,
167 struct tevent_context
*ev
,
168 struct cli_state
*cli
,
170 uint32_t create_flags
,
171 uint32_t desired_access
,
172 uint32_t file_attributes
,
173 uint32_t share_access
,
174 uint32_t create_disposition
,
175 uint32_t create_options
)
177 struct tevent_req
*req
, *subreq
;
178 struct cli_smb2_create_fnum_state
*state
;
180 req
= tevent_req_create(mem_ctx
, &state
,
181 struct cli_smb2_create_fnum_state
);
187 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
188 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
189 return tevent_req_post(req
, ev
);
192 if (cli
->backup_intent
) {
193 create_options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
196 /* SMB2 is pickier about pathnames. Ensure it doesn't
198 if (*fname
== '\\') {
202 subreq
= smb2cli_create_send(state
, ev
,
208 flags_to_smb2_oplock(create_flags
),
209 SMB2_IMPERSONATION_IMPERSONATION
,
216 if (tevent_req_nomem(subreq
, req
)) {
217 return tevent_req_post(req
, ev
);
219 tevent_req_set_callback(subreq
, cli_smb2_create_fnum_done
, req
);
221 state
->subreq
= subreq
;
222 tevent_req_set_cancel_fn(req
, cli_smb2_create_fnum_cancel
);
227 static void cli_smb2_create_fnum_done(struct tevent_req
*subreq
)
229 struct tevent_req
*req
= tevent_req_callback_data(
230 subreq
, struct tevent_req
);
231 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
232 req
, struct cli_smb2_create_fnum_state
);
236 status
= smb2cli_create_recv(subreq
, &h
.fid_persistent
,
237 &h
.fid_volatile
, &state
->cr
, NULL
, NULL
);
239 if (tevent_req_nterror(req
, status
)) {
243 status
= map_smb2_handle_to_fnum(state
->cli
, &h
, &state
->fnum
);
244 if (tevent_req_nterror(req
, status
)) {
247 tevent_req_done(req
);
250 static bool cli_smb2_create_fnum_cancel(struct tevent_req
*req
)
252 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
253 req
, struct cli_smb2_create_fnum_state
);
254 return tevent_req_cancel(state
->subreq
);
257 NTSTATUS
cli_smb2_create_fnum_recv(struct tevent_req
*req
, uint16_t *pfnum
,
258 struct smb_create_returns
*cr
)
260 struct cli_smb2_create_fnum_state
*state
= tevent_req_data(
261 req
, struct cli_smb2_create_fnum_state
);
264 if (tevent_req_is_nterror(req
, &status
)) {
268 *pfnum
= state
->fnum
;
276 NTSTATUS
cli_smb2_create_fnum(struct cli_state
*cli
,
278 uint32_t create_flags
,
279 uint32_t desired_access
,
280 uint32_t file_attributes
,
281 uint32_t share_access
,
282 uint32_t create_disposition
,
283 uint32_t create_options
,
285 struct smb_create_returns
*cr
)
287 TALLOC_CTX
*frame
= talloc_stackframe();
288 struct tevent_context
*ev
;
289 struct tevent_req
*req
;
290 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
292 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
294 * Can't use sync call while an async call is in flight
296 status
= NT_STATUS_INVALID_PARAMETER
;
299 ev
= samba_tevent_context_init(frame
);
303 req
= cli_smb2_create_fnum_send(frame
, ev
, cli
, fname
, create_flags
,
304 desired_access
, file_attributes
,
305 share_access
, create_disposition
,
310 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
313 status
= cli_smb2_create_fnum_recv(req
, pfid
, cr
);
319 /***************************************************************
320 Small wrapper that allows SMB2 close to use a uint16_t fnum.
321 ***************************************************************/
323 struct cli_smb2_close_fnum_state
{
324 struct cli_state
*cli
;
329 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
);
331 struct tevent_req
*cli_smb2_close_fnum_send(TALLOC_CTX
*mem_ctx
,
332 struct tevent_context
*ev
,
333 struct cli_state
*cli
,
336 struct tevent_req
*req
, *subreq
;
337 struct cli_smb2_close_fnum_state
*state
;
340 req
= tevent_req_create(mem_ctx
, &state
,
341 struct cli_smb2_close_fnum_state
);
348 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
349 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
350 return tevent_req_post(req
, ev
);
353 status
= map_fnum_to_smb2_handle(cli
, fnum
, &state
->ph
);
354 if (tevent_req_nterror(req
, status
)) {
355 return tevent_req_post(req
, ev
);
358 subreq
= smb2cli_close_send(state
, ev
, cli
->conn
, cli
->timeout
,
359 cli
->smb2
.session
, cli
->smb2
.tcon
,
360 0, state
->ph
->fid_persistent
,
361 state
->ph
->fid_volatile
);
362 if (tevent_req_nomem(subreq
, req
)) {
363 return tevent_req_post(req
, ev
);
365 tevent_req_set_callback(subreq
, cli_smb2_close_fnum_done
, req
);
369 static void cli_smb2_close_fnum_done(struct tevent_req
*subreq
)
371 struct tevent_req
*req
= tevent_req_callback_data(
372 subreq
, struct tevent_req
);
373 struct cli_smb2_close_fnum_state
*state
= tevent_req_data(
374 req
, struct cli_smb2_close_fnum_state
);
377 status
= smb2cli_close_recv(subreq
);
378 if (tevent_req_nterror(req
, status
)) {
382 /* Delete the fnum -> handle mapping. */
383 status
= delete_smb2_handle_mapping(state
->cli
, &state
->ph
,
385 if (tevent_req_nterror(req
, status
)) {
388 tevent_req_done(req
);
391 NTSTATUS
cli_smb2_close_fnum_recv(struct tevent_req
*req
)
393 return tevent_req_simple_recv_ntstatus(req
);
396 NTSTATUS
cli_smb2_close_fnum(struct cli_state
*cli
, uint16_t fnum
)
398 TALLOC_CTX
*frame
= talloc_stackframe();
399 struct tevent_context
*ev
;
400 struct tevent_req
*req
;
401 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
403 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
405 * Can't use sync call while an async call is in flight
407 status
= NT_STATUS_INVALID_PARAMETER
;
410 ev
= samba_tevent_context_init(frame
);
414 req
= cli_smb2_close_fnum_send(frame
, ev
, cli
, fnum
);
418 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
421 status
= cli_smb2_close_fnum_recv(req
);
427 /***************************************************************
428 Small wrapper that allows SMB2 to create a directory
430 ***************************************************************/
432 NTSTATUS
cli_smb2_mkdir(struct cli_state
*cli
, const char *dname
)
437 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
439 * Can't use sync call while an async call is in flight
441 return NT_STATUS_INVALID_PARAMETER
;
444 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
445 return NT_STATUS_INVALID_PARAMETER
;
448 status
= cli_smb2_create_fnum(cli
,
450 0, /* create_flags */
451 FILE_READ_ATTRIBUTES
, /* desired_access */
452 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
453 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
454 FILE_CREATE
, /* create_disposition */
455 FILE_DIRECTORY_FILE
, /* create_options */
459 if (!NT_STATUS_IS_OK(status
)) {
462 return cli_smb2_close_fnum(cli
, fnum
);
465 /***************************************************************
466 Small wrapper that allows SMB2 to delete a directory
468 ***************************************************************/
470 NTSTATUS
cli_smb2_rmdir(struct cli_state
*cli
, const char *dname
)
475 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
477 * Can't use sync call while an async call is in flight
479 return NT_STATUS_INVALID_PARAMETER
;
482 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
483 return NT_STATUS_INVALID_PARAMETER
;
486 status
= cli_smb2_create_fnum(cli
,
488 0, /* create_flags */
489 DELETE_ACCESS
, /* desired_access */
490 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
491 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
492 FILE_OPEN
, /* create_disposition */
493 FILE_DIRECTORY_FILE
|FILE_DELETE_ON_CLOSE
, /* create_options */
497 if (!NT_STATUS_IS_OK(status
)) {
500 return cli_smb2_close_fnum(cli
, fnum
);
503 /***************************************************************
504 Small wrapper that allows SMB2 to unlink a pathname.
506 ***************************************************************/
508 NTSTATUS
cli_smb2_unlink(struct cli_state
*cli
, const char *fname
)
513 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
515 * Can't use sync call while an async call is in flight
517 return NT_STATUS_INVALID_PARAMETER
;
520 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
521 return NT_STATUS_INVALID_PARAMETER
;
524 status
= cli_smb2_create_fnum(cli
,
526 0, /* create_flags */
527 DELETE_ACCESS
, /* desired_access */
528 FILE_ATTRIBUTE_NORMAL
, /* file attributes */
529 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
530 FILE_OPEN
, /* create_disposition */
531 FILE_DELETE_ON_CLOSE
, /* create_options */
535 if (!NT_STATUS_IS_OK(status
)) {
538 return cli_smb2_close_fnum(cli
, fnum
);
541 /***************************************************************
542 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
543 ***************************************************************/
545 static NTSTATUS
parse_finfo_id_both_directory_info(uint8_t *dir_data
,
546 uint32_t dir_data_length
,
547 struct file_info
*finfo
,
548 uint32_t *next_offset
)
554 if (dir_data_length
< 4) {
555 return NT_STATUS_INFO_LENGTH_MISMATCH
;
558 *next_offset
= IVAL(dir_data
, 0);
560 if (*next_offset
> dir_data_length
) {
561 return NT_STATUS_INFO_LENGTH_MISMATCH
;
564 if (*next_offset
!= 0) {
565 /* Ensure we only read what in this record. */
566 dir_data_length
= *next_offset
;
569 if (dir_data_length
< 105) {
570 return NT_STATUS_INFO_LENGTH_MISMATCH
;
573 finfo
->atime_ts
= interpret_long_date((const char *)dir_data
+ 16);
574 finfo
->mtime_ts
= interpret_long_date((const char *)dir_data
+ 24);
575 finfo
->ctime_ts
= interpret_long_date((const char *)dir_data
+ 32);
576 finfo
->size
= IVAL2_TO_SMB_BIG_UINT(dir_data
+ 40, 0);
577 finfo
->mode
= CVAL(dir_data
+ 56, 0);
578 namelen
= IVAL(dir_data
+ 60,0);
579 if (namelen
> (dir_data_length
- 104)) {
580 return NT_STATUS_INFO_LENGTH_MISMATCH
;
582 slen
= CVAL(dir_data
+ 68, 0);
584 return NT_STATUS_INFO_LENGTH_MISMATCH
;
586 ret
= pull_string_talloc(finfo
,
588 FLAGS2_UNICODE_STRINGS
,
593 if (ret
== (size_t)-1) {
594 /* Bad conversion. */
595 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
598 ret
= pull_string_talloc(finfo
,
600 FLAGS2_UNICODE_STRINGS
,
605 if (ret
== (size_t)-1) {
606 /* Bad conversion. */
607 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
612 /*******************************************************************
613 Given a filename - get its directory name
614 ********************************************************************/
616 static bool windows_parent_dirname(TALLOC_CTX
*mem_ctx
,
624 p
= strrchr_m(dir
, '\\'); /* Find final '\\', if any */
627 if (!(*parent
= talloc_strdup(mem_ctx
, "\\"))) {
638 if (!(*parent
= (char *)talloc_memdup(mem_ctx
, dir
, len
+1))) {
641 (*parent
)[len
] = '\0';
649 /***************************************************************
650 Wrapper that allows SMB2 to list a directory.
652 ***************************************************************/
654 NTSTATUS
cli_smb2_list(struct cli_state
*cli
,
655 const char *pathname
,
657 NTSTATUS (*fn
)(const char *,
664 uint16_t fnum
= 0xffff;
665 char *parent_dir
= NULL
;
666 const char *mask
= NULL
;
667 struct smb2_hnd
*ph
= NULL
;
668 bool processed_file
= false;
669 TALLOC_CTX
*frame
= talloc_stackframe();
670 TALLOC_CTX
*subframe
= NULL
;
673 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
675 * Can't use sync call while an async call is in flight
677 status
= NT_STATUS_INVALID_PARAMETER
;
681 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
682 status
= NT_STATUS_INVALID_PARAMETER
;
686 /* Get the directory name. */
687 if (!windows_parent_dirname(frame
,
691 status
= NT_STATUS_NO_MEMORY
;
695 mask_has_wild
= ms_has_wild(mask
);
697 status
= cli_smb2_create_fnum(cli
,
699 0, /* create_flags */
700 SEC_DIR_LIST
|SEC_DIR_READ_ATTRIBUTE
,/* desired_access */
701 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
702 FILE_SHARE_READ
|FILE_SHARE_WRITE
, /* share_access */
703 FILE_OPEN
, /* create_disposition */
704 FILE_DIRECTORY_FILE
, /* create_options */
708 if (!NT_STATUS_IS_OK(status
)) {
712 status
= map_fnum_to_smb2_handle(cli
,
715 if (!NT_STATUS_IS_OK(status
)) {
720 uint8_t *dir_data
= NULL
;
721 uint32_t dir_data_length
= 0;
722 uint32_t next_offset
= 0;
723 subframe
= talloc_stackframe();
725 status
= smb2cli_query_directory(cli
->conn
,
729 SMB2_FIND_ID_BOTH_DIRECTORY_INFO
,
740 if (!NT_STATUS_IS_OK(status
)) {
741 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
748 struct file_info
*finfo
= talloc_zero(subframe
,
752 status
= NT_STATUS_NO_MEMORY
;
756 status
= parse_finfo_id_both_directory_info(dir_data
,
761 if (!NT_STATUS_IS_OK(status
)) {
765 if (dir_check_ftype((uint32_t)finfo
->mode
,
766 (uint32_t)attribute
)) {
768 * Only process if attributes match.
769 * On SMB1 server does this, so on
770 * SMB2 we need to emulate in the
773 * https://bugzilla.samba.org/show_bug.cgi?id=10260
775 processed_file
= true;
777 status
= fn(cli
->dfs_mountpoint
,
782 if (!NT_STATUS_IS_OK(status
)) {
789 /* Move to next entry. */
791 dir_data
+= next_offset
;
792 dir_data_length
-= next_offset
;
794 } while (next_offset
!= 0);
796 TALLOC_FREE(subframe
);
798 if (!mask_has_wild
) {
800 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
801 * when handed a non-wildcard path. Do it
802 * for the server (with a non-wildcard path
803 * there should only ever be one file returned.
805 status
= STATUS_NO_MORE_FILES
;
809 } while (NT_STATUS_IS_OK(status
));
811 if (NT_STATUS_EQUAL(status
, STATUS_NO_MORE_FILES
)) {
812 status
= NT_STATUS_OK
;
815 if (NT_STATUS_IS_OK(status
) && !processed_file
) {
817 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
818 * if no files match. Emulate this in the client.
820 status
= NT_STATUS_NO_SUCH_FILE
;
825 if (fnum
!= 0xffff) {
826 cli_smb2_close_fnum(cli
, fnum
);
828 TALLOC_FREE(subframe
);
833 /***************************************************************
834 Wrapper that allows SMB2 to query a path info (basic level).
836 ***************************************************************/
838 NTSTATUS
cli_smb2_qpathinfo_basic(struct cli_state
*cli
,
840 SMB_STRUCT_STAT
*sbuf
,
841 uint32_t *attributes
)
844 struct smb_create_returns cr
;
845 uint16_t fnum
= 0xffff;
846 size_t namelen
= strlen(name
);
848 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
850 * Can't use sync call while an async call is in flight
852 return NT_STATUS_INVALID_PARAMETER
;
855 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
856 return NT_STATUS_INVALID_PARAMETER
;
859 /* SMB2 is pickier about pathnames. Ensure it doesn't
861 if (namelen
> 0 && name
[namelen
-1] == '\\') {
862 char *modname
= talloc_strdup(talloc_tos(), name
);
863 modname
[namelen
-1] = '\0';
867 /* This is commonly used as a 'cd'. Try qpathinfo on
868 a directory handle first. */
870 status
= cli_smb2_create_fnum(cli
,
872 0, /* create_flags */
873 FILE_READ_ATTRIBUTES
, /* desired_access */
874 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
875 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
876 FILE_OPEN
, /* create_disposition */
877 FILE_DIRECTORY_FILE
, /* create_options */
881 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_A_DIRECTORY
)) {
883 status
= cli_smb2_create_fnum(cli
,
885 0, /* create_flags */
886 FILE_READ_ATTRIBUTES
, /* desired_access */
887 0, /* file attributes */
888 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
889 FILE_OPEN
, /* create_disposition */
890 0, /* create_options */
895 if (!NT_STATUS_IS_OK(status
)) {
899 cli_smb2_close_fnum(cli
, fnum
);
903 sbuf
->st_ex_atime
= nt_time_to_unix_timespec(cr
.last_access_time
);
904 sbuf
->st_ex_mtime
= nt_time_to_unix_timespec(cr
.last_write_time
);
905 sbuf
->st_ex_ctime
= nt_time_to_unix_timespec(cr
.change_time
);
906 sbuf
->st_ex_size
= cr
.end_of_file
;
907 *attributes
= cr
.file_attributes
;
912 /***************************************************************
913 Helper function for pathname operations.
914 ***************************************************************/
916 static NTSTATUS
get_fnum_from_path(struct cli_state
*cli
,
918 uint32_t desired_access
,
922 size_t namelen
= strlen(name
);
923 TALLOC_CTX
*frame
= talloc_stackframe();
925 /* SMB2 is pickier about pathnames. Ensure it doesn't
927 if (namelen
> 0 && name
[namelen
-1] == '\\') {
928 char *modname
= talloc_strdup(frame
, name
);
929 if (modname
== NULL
) {
930 status
= NT_STATUS_NO_MEMORY
;
933 modname
[namelen
-1] = '\0';
937 /* Try to open a file handle first. */
938 status
= cli_smb2_create_fnum(cli
,
940 0, /* create_flags */
942 0, /* file attributes */
943 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
944 FILE_OPEN
, /* create_disposition */
945 0, /* create_options */
949 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
950 status
= cli_smb2_create_fnum(cli
,
952 0, /* create_flags */
954 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
955 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
956 FILE_OPEN
, /* create_disposition */
957 FILE_DIRECTORY_FILE
, /* create_options */
968 /***************************************************************
969 Wrapper that allows SMB2 to query a path info (ALTNAME level).
971 ***************************************************************/
973 NTSTATUS
cli_smb2_qpathinfo_alt_name(struct cli_state
*cli
,
978 DATA_BLOB outbuf
= data_blob_null
;
979 uint16_t fnum
= 0xffff;
980 struct smb2_hnd
*ph
= NULL
;
981 uint32_t altnamelen
= 0;
982 TALLOC_CTX
*frame
= talloc_stackframe();
984 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
986 * Can't use sync call while an async call is in flight
988 status
= NT_STATUS_INVALID_PARAMETER
;
992 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
993 status
= NT_STATUS_INVALID_PARAMETER
;
997 status
= get_fnum_from_path(cli
,
999 FILE_READ_ATTRIBUTES
,
1002 if (!NT_STATUS_IS_OK(status
)) {
1006 status
= map_fnum_to_smb2_handle(cli
,
1009 if (!NT_STATUS_IS_OK(status
)) {
1013 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1014 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1016 status
= smb2cli_query_info(cli
->conn
,
1020 1, /* in_info_type */
1021 (SMB_FILE_ALTERNATE_NAME_INFORMATION
- 1000), /* in_file_info_class */
1022 0xFFFF, /* in_max_output_length */
1023 NULL
, /* in_input_buffer */
1024 0, /* in_additional_info */
1031 if (!NT_STATUS_IS_OK(status
)) {
1035 /* Parse the reply. */
1036 if (outbuf
.length
< 4) {
1037 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1041 altnamelen
= IVAL(outbuf
.data
, 0);
1042 if (altnamelen
> outbuf
.length
- 4) {
1043 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1047 if (altnamelen
> 0) {
1049 char *short_name
= NULL
;
1050 ret
= pull_string_talloc(frame
,
1052 FLAGS2_UNICODE_STRINGS
,
1057 if (ret
== (size_t)-1) {
1058 /* Bad conversion. */
1059 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1063 fstrcpy(alt_name
, short_name
);
1068 status
= NT_STATUS_OK
;
1072 if (fnum
!= 0xffff) {
1073 cli_smb2_close_fnum(cli
, fnum
);
1080 /***************************************************************
1081 Wrapper that allows SMB2 to query a fnum info (basic level).
1083 ***************************************************************/
1085 NTSTATUS
cli_smb2_qfileinfo_basic(struct cli_state
*cli
,
1089 struct timespec
*create_time
,
1090 struct timespec
*access_time
,
1091 struct timespec
*write_time
,
1092 struct timespec
*change_time
,
1096 DATA_BLOB outbuf
= data_blob_null
;
1097 struct smb2_hnd
*ph
= NULL
;
1098 TALLOC_CTX
*frame
= talloc_stackframe();
1100 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1102 * Can't use sync call while an async call is in flight
1104 status
= NT_STATUS_INVALID_PARAMETER
;
1108 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1109 status
= NT_STATUS_INVALID_PARAMETER
;
1113 status
= map_fnum_to_smb2_handle(cli
,
1116 if (!NT_STATUS_IS_OK(status
)) {
1120 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1121 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1123 status
= smb2cli_query_info(cli
->conn
,
1127 1, /* in_info_type */
1128 (SMB_FILE_ALL_INFORMATION
- 1000), /* in_file_info_class */
1129 0xFFFF, /* in_max_output_length */
1130 NULL
, /* in_input_buffer */
1131 0, /* in_additional_info */
1137 if (!NT_STATUS_IS_OK(status
)) {
1141 /* Parse the reply. */
1142 if (outbuf
.length
< 0x60) {
1143 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1148 *create_time
= interpret_long_date((const char *)outbuf
.data
+ 0x0);
1151 *access_time
= interpret_long_date((const char *)outbuf
.data
+ 0x8);
1154 *write_time
= interpret_long_date((const char *)outbuf
.data
+ 0x10);
1157 *change_time
= interpret_long_date((const char *)outbuf
.data
+ 0x18);
1160 uint32_t attr
= IVAL(outbuf
.data
, 0x20);
1161 *mode
= (uint16_t)attr
;
1164 uint64_t file_size
= BVAL(outbuf
.data
, 0x30);
1165 *size
= (off_t
)file_size
;
1168 uint64_t file_index
= BVAL(outbuf
.data
, 0x40);
1169 *ino
= (SMB_INO_T
)file_index
;
1178 /***************************************************************
1179 Wrapper that allows SMB2 to query an fnum.
1180 Implement on top of cli_smb2_qfileinfo_basic().
1182 ***************************************************************/
1184 NTSTATUS
cli_smb2_getattrE(struct cli_state
*cli
,
1188 time_t *change_time
,
1189 time_t *access_time
,
1192 struct timespec access_time_ts
;
1193 struct timespec write_time_ts
;
1194 struct timespec change_time_ts
;
1195 NTSTATUS status
= cli_smb2_qfileinfo_basic(cli
,
1205 if (!NT_STATUS_IS_OK(status
)) {
1210 *change_time
= change_time_ts
.tv_sec
;
1213 *access_time
= access_time_ts
.tv_sec
;
1216 *write_time
= write_time_ts
.tv_sec
;
1218 return NT_STATUS_OK
;
1221 /***************************************************************
1222 Wrapper that allows SMB2 to get pathname attributes.
1224 ***************************************************************/
1226 NTSTATUS
cli_smb2_getatr(struct cli_state
*cli
,
1233 uint16_t fnum
= 0xffff;
1234 struct smb2_hnd
*ph
= NULL
;
1235 TALLOC_CTX
*frame
= talloc_stackframe();
1237 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1239 * Can't use sync call while an async call is in flight
1241 status
= NT_STATUS_INVALID_PARAMETER
;
1245 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1246 status
= NT_STATUS_INVALID_PARAMETER
;
1250 status
= get_fnum_from_path(cli
,
1252 FILE_READ_ATTRIBUTES
,
1255 if (!NT_STATUS_IS_OK(status
)) {
1259 status
= map_fnum_to_smb2_handle(cli
,
1262 if (!NT_STATUS_IS_OK(status
)) {
1265 status
= cli_smb2_getattrE(cli
,
1272 if (!NT_STATUS_IS_OK(status
)) {
1278 if (fnum
!= 0xffff) {
1279 cli_smb2_close_fnum(cli
, fnum
);
1286 /***************************************************************
1287 Wrapper that allows SMB2 to query a pathname info (basic level).
1288 Implement on top of cli_smb2_qfileinfo_basic().
1290 ***************************************************************/
1292 NTSTATUS
cli_smb2_qpathinfo2(struct cli_state
*cli
,
1294 struct timespec
*create_time
,
1295 struct timespec
*access_time
,
1296 struct timespec
*write_time
,
1297 struct timespec
*change_time
,
1303 struct smb2_hnd
*ph
= NULL
;
1304 uint16_t fnum
= 0xffff;
1305 TALLOC_CTX
*frame
= talloc_stackframe();
1307 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1309 * Can't use sync call while an async call is in flight
1311 status
= NT_STATUS_INVALID_PARAMETER
;
1315 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1316 status
= NT_STATUS_INVALID_PARAMETER
;
1320 status
= get_fnum_from_path(cli
,
1322 FILE_READ_ATTRIBUTES
,
1325 if (!NT_STATUS_IS_OK(status
)) {
1329 status
= map_fnum_to_smb2_handle(cli
,
1332 if (!NT_STATUS_IS_OK(status
)) {
1336 status
= cli_smb2_qfileinfo_basic(cli
,
1348 if (fnum
!= 0xffff) {
1349 cli_smb2_close_fnum(cli
, fnum
);
1356 /***************************************************************
1357 Wrapper that allows SMB2 to query pathname streams.
1359 ***************************************************************/
1361 NTSTATUS
cli_smb2_qpathinfo_streams(struct cli_state
*cli
,
1363 TALLOC_CTX
*mem_ctx
,
1364 unsigned int *pnum_streams
,
1365 struct stream_struct
**pstreams
)
1368 struct smb2_hnd
*ph
= NULL
;
1369 uint16_t fnum
= 0xffff;
1370 DATA_BLOB outbuf
= data_blob_null
;
1371 TALLOC_CTX
*frame
= talloc_stackframe();
1373 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1375 * Can't use sync call while an async call is in flight
1377 status
= NT_STATUS_INVALID_PARAMETER
;
1381 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1382 status
= NT_STATUS_INVALID_PARAMETER
;
1386 status
= get_fnum_from_path(cli
,
1388 FILE_READ_ATTRIBUTES
,
1391 if (!NT_STATUS_IS_OK(status
)) {
1395 status
= map_fnum_to_smb2_handle(cli
,
1398 if (!NT_STATUS_IS_OK(status
)) {
1402 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1403 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1405 status
= smb2cli_query_info(cli
->conn
,
1409 1, /* in_info_type */
1410 (SMB_FILE_STREAM_INFORMATION
- 1000), /* in_file_info_class */
1411 0xFFFF, /* in_max_output_length */
1412 NULL
, /* in_input_buffer */
1413 0, /* in_additional_info */
1420 if (!NT_STATUS_IS_OK(status
)) {
1424 /* Parse the reply. */
1425 if (!parse_streams_blob(mem_ctx
,
1430 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1436 if (fnum
!= 0xffff) {
1437 cli_smb2_close_fnum(cli
, fnum
);
1444 /***************************************************************
1445 Wrapper that allows SMB2 to set pathname attributes.
1447 ***************************************************************/
1449 NTSTATUS
cli_smb2_setatr(struct cli_state
*cli
,
1455 uint16_t fnum
= 0xffff;
1456 struct smb2_hnd
*ph
= NULL
;
1457 uint8_t inbuf_store
[40];
1458 DATA_BLOB inbuf
= data_blob_null
;
1459 TALLOC_CTX
*frame
= talloc_stackframe();
1461 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1463 * Can't use sync call while an async call is in flight
1465 status
= NT_STATUS_INVALID_PARAMETER
;
1469 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1470 status
= NT_STATUS_INVALID_PARAMETER
;
1474 status
= get_fnum_from_path(cli
,
1476 FILE_WRITE_ATTRIBUTES
,
1479 if (!NT_STATUS_IS_OK(status
)) {
1483 status
= map_fnum_to_smb2_handle(cli
,
1486 if (!NT_STATUS_IS_OK(status
)) {
1490 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1491 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1493 inbuf
.data
= inbuf_store
;
1494 inbuf
.length
= sizeof(inbuf_store
);
1495 data_blob_clear(&inbuf
);
1497 SSVAL(inbuf
.data
, 32, attr
);
1499 put_long_date((char *)inbuf
.data
+ 16,mtime
);
1501 /* Set all the other times to -1. */
1502 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1503 SBVAL(inbuf
.data
, 8, 0xFFFFFFFFFFFFFFFFLL
);
1504 SBVAL(inbuf
.data
, 24, 0xFFFFFFFFFFFFFFFFLL
);
1506 status
= smb2cli_set_info(cli
->conn
,
1510 1, /* in_info_type */
1511 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1512 &inbuf
, /* in_input_buffer */
1513 0, /* in_additional_info */
1518 if (fnum
!= 0xffff) {
1519 cli_smb2_close_fnum(cli
, fnum
);
1526 /***************************************************************
1527 Wrapper that allows SMB2 to set file handle times.
1529 ***************************************************************/
1531 NTSTATUS
cli_smb2_setattrE(struct cli_state
*cli
,
1538 struct smb2_hnd
*ph
= NULL
;
1539 uint8_t inbuf_store
[40];
1540 DATA_BLOB inbuf
= data_blob_null
;
1542 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1544 * Can't use sync call while an async call is in flight
1546 return NT_STATUS_INVALID_PARAMETER
;
1549 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1550 return NT_STATUS_INVALID_PARAMETER
;
1553 status
= map_fnum_to_smb2_handle(cli
,
1556 if (!NT_STATUS_IS_OK(status
)) {
1560 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1561 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1563 inbuf
.data
= inbuf_store
;
1564 inbuf
.length
= sizeof(inbuf_store
);
1565 data_blob_clear(&inbuf
);
1567 SBVAL(inbuf
.data
, 0, 0xFFFFFFFFFFFFFFFFLL
);
1568 if (change_time
!= 0) {
1569 put_long_date((char *)inbuf
.data
+ 24, change_time
);
1571 if (access_time
!= 0) {
1572 put_long_date((char *)inbuf
.data
+ 8, access_time
);
1574 if (write_time
!= 0) {
1575 put_long_date((char *)inbuf
.data
+ 16, write_time
);
1578 return smb2cli_set_info(cli
->conn
,
1582 1, /* in_info_type */
1583 SMB_FILE_BASIC_INFORMATION
- 1000, /* in_file_info_class */
1584 &inbuf
, /* in_input_buffer */
1585 0, /* in_additional_info */
1590 /***************************************************************
1591 Wrapper that allows SMB2 to query disk attributes (size).
1593 ***************************************************************/
1595 NTSTATUS
cli_smb2_dskattr(struct cli_state
*cli
, uint64_t *bsize
, uint64_t *total
, uint64_t *avail
)
1598 uint16_t fnum
= 0xffff;
1599 DATA_BLOB outbuf
= data_blob_null
;
1600 struct smb2_hnd
*ph
= NULL
;
1601 uint32_t sectors_per_unit
= 0;
1602 uint32_t bytes_per_sector
= 0;
1603 uint64_t total_size
= 0;
1604 uint64_t size_free
= 0;
1605 TALLOC_CTX
*frame
= talloc_stackframe();
1607 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1609 * Can't use sync call while an async call is in flight
1611 status
= NT_STATUS_INVALID_PARAMETER
;
1615 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1616 status
= NT_STATUS_INVALID_PARAMETER
;
1620 /* First open the top level directory. */
1621 status
= cli_smb2_create_fnum(cli
,
1623 0, /* create_flags */
1624 FILE_READ_ATTRIBUTES
, /* desired_access */
1625 FILE_ATTRIBUTE_DIRECTORY
, /* file attributes */
1626 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
, /* share_access */
1627 FILE_OPEN
, /* create_disposition */
1628 FILE_DIRECTORY_FILE
, /* create_options */
1632 if (!NT_STATUS_IS_OK(status
)) {
1636 status
= map_fnum_to_smb2_handle(cli
,
1639 if (!NT_STATUS_IS_OK(status
)) {
1643 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1644 level 3 (SMB_FS_SIZE_INFORMATION). */
1646 status
= smb2cli_query_info(cli
->conn
,
1650 2, /* in_info_type */
1651 3, /* in_file_info_class */
1652 0xFFFF, /* in_max_output_length */
1653 NULL
, /* in_input_buffer */
1654 0, /* in_additional_info */
1660 if (!NT_STATUS_IS_OK(status
)) {
1664 /* Parse the reply. */
1665 if (outbuf
.length
!= 24) {
1666 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
1670 total_size
= BVAL(outbuf
.data
, 0);
1671 size_free
= BVAL(outbuf
.data
, 8);
1672 sectors_per_unit
= IVAL(outbuf
.data
, 16);
1673 bytes_per_sector
= IVAL(outbuf
.data
, 20);
1676 *bsize
= (uint64_t)sectors_per_unit
* (uint64_t)bytes_per_sector
;
1679 *total
= total_size
;
1685 status
= NT_STATUS_OK
;
1689 if (fnum
!= 0xffff) {
1690 cli_smb2_close_fnum(cli
, fnum
);
1697 /***************************************************************
1698 Wrapper that allows SMB2 to query a security descriptor.
1700 ***************************************************************/
1702 NTSTATUS
cli_smb2_query_security_descriptor(struct cli_state
*cli
,
1705 TALLOC_CTX
*mem_ctx
,
1706 struct security_descriptor
**ppsd
)
1709 DATA_BLOB outbuf
= data_blob_null
;
1710 struct smb2_hnd
*ph
= NULL
;
1711 struct security_descriptor
*lsd
= NULL
;
1712 TALLOC_CTX
*frame
= talloc_stackframe();
1714 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1716 * Can't use sync call while an async call is in flight
1718 status
= NT_STATUS_INVALID_PARAMETER
;
1722 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1723 status
= NT_STATUS_INVALID_PARAMETER
;
1727 status
= map_fnum_to_smb2_handle(cli
,
1730 if (!NT_STATUS_IS_OK(status
)) {
1734 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1736 status
= smb2cli_query_info(cli
->conn
,
1740 3, /* in_info_type */
1741 0, /* in_file_info_class */
1742 0xFFFF, /* in_max_output_length */
1743 NULL
, /* in_input_buffer */
1744 sec_info
, /* in_additional_info */
1751 if (!NT_STATUS_IS_OK(status
)) {
1755 /* Parse the reply. */
1756 status
= unmarshall_sec_desc(mem_ctx
,
1761 if (!NT_STATUS_IS_OK(status
)) {
1777 /***************************************************************
1778 Wrapper that allows SMB2 to set a security descriptor.
1780 ***************************************************************/
1782 NTSTATUS
cli_smb2_set_security_descriptor(struct cli_state
*cli
,
1785 const struct security_descriptor
*sd
)
1788 DATA_BLOB inbuf
= data_blob_null
;
1789 struct smb2_hnd
*ph
= NULL
;
1790 TALLOC_CTX
*frame
= talloc_stackframe();
1792 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1794 * Can't use sync call while an async call is in flight
1796 status
= NT_STATUS_INVALID_PARAMETER
;
1800 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1801 status
= NT_STATUS_INVALID_PARAMETER
;
1805 status
= map_fnum_to_smb2_handle(cli
,
1808 if (!NT_STATUS_IS_OK(status
)) {
1812 status
= marshall_sec_desc(frame
,
1817 if (!NT_STATUS_IS_OK(status
)) {
1821 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1823 status
= smb2cli_set_info(cli
->conn
,
1827 3, /* in_info_type */
1828 0, /* in_file_info_class */
1829 &inbuf
, /* in_input_buffer */
1830 sec_info
, /* in_additional_info */
1840 /***************************************************************
1841 Wrapper that allows SMB2 to rename a file.
1843 ***************************************************************/
1845 NTSTATUS
cli_smb2_rename(struct cli_state
*cli
,
1846 const char *fname_src
,
1847 const char *fname_dst
)
1850 DATA_BLOB inbuf
= data_blob_null
;
1851 uint16_t fnum
= 0xffff;
1852 struct smb2_hnd
*ph
= NULL
;
1853 smb_ucs2_t
*converted_str
= NULL
;
1854 size_t converted_size_bytes
= 0;
1856 TALLOC_CTX
*frame
= talloc_stackframe();
1858 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1860 * Can't use sync call while an async call is in flight
1862 status
= NT_STATUS_INVALID_PARAMETER
;
1866 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1867 status
= NT_STATUS_INVALID_PARAMETER
;
1871 status
= get_fnum_from_path(cli
,
1876 if (!NT_STATUS_IS_OK(status
)) {
1880 status
= map_fnum_to_smb2_handle(cli
,
1883 if (!NT_STATUS_IS_OK(status
)) {
1887 /* SMB2 is pickier about pathnames. Ensure it doesn't
1889 if (*fname_dst
== '\\') {
1893 /* SMB2 is pickier about pathnames. Ensure it doesn't
1895 namelen
= strlen(fname_dst
);
1896 if (namelen
> 0 && fname_dst
[namelen
-1] == '\\') {
1897 char *modname
= talloc_strdup(frame
, fname_dst
);
1898 modname
[namelen
-1] = '\0';
1899 fname_dst
= modname
;
1902 if (!push_ucs2_talloc(frame
,
1905 &converted_size_bytes
)) {
1906 status
= NT_STATUS_INVALID_PARAMETER
;
1910 /* W2K8 insists the dest name is not null
1911 terminated. Remove the last 2 zero bytes
1912 and reduce the name length. */
1914 if (converted_size_bytes
< 2) {
1915 status
= NT_STATUS_INVALID_PARAMETER
;
1918 converted_size_bytes
-= 2;
1920 inbuf
= data_blob_talloc_zero(frame
,
1921 20 + converted_size_bytes
);
1922 if (inbuf
.data
== NULL
) {
1923 status
= NT_STATUS_NO_MEMORY
;
1927 SIVAL(inbuf
.data
, 16, converted_size_bytes
);
1928 memcpy(inbuf
.data
+ 20, converted_str
, converted_size_bytes
);
1930 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1931 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1933 status
= smb2cli_set_info(cli
->conn
,
1937 1, /* in_info_type */
1938 SMB_FILE_RENAME_INFORMATION
- 1000, /* in_file_info_class */
1939 &inbuf
, /* in_input_buffer */
1940 0, /* in_additional_info */
1946 if (fnum
!= 0xffff) {
1947 cli_smb2_close_fnum(cli
, fnum
);
1954 /***************************************************************
1955 Wrapper that allows SMB2 to set an EA on a fnum.
1957 ***************************************************************/
1959 NTSTATUS
cli_smb2_set_ea_fnum(struct cli_state
*cli
,
1961 const char *ea_name
,
1966 DATA_BLOB inbuf
= data_blob_null
;
1968 char *ea_name_ascii
= NULL
;
1970 struct smb2_hnd
*ph
= NULL
;
1971 TALLOC_CTX
*frame
= talloc_stackframe();
1973 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
1975 * Can't use sync call while an async call is in flight
1977 status
= NT_STATUS_INVALID_PARAMETER
;
1981 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
1982 status
= NT_STATUS_INVALID_PARAMETER
;
1986 status
= map_fnum_to_smb2_handle(cli
,
1989 if (!NT_STATUS_IS_OK(status
)) {
1993 /* Marshall the SMB2 EA data. */
1994 if (ea_len
> 0xFFFF) {
1995 status
= NT_STATUS_INVALID_PARAMETER
;
1999 if (!push_ascii_talloc(frame
,
2003 status
= NT_STATUS_INVALID_PARAMETER
;
2007 if (namelen
< 2 || namelen
> 0xFF) {
2008 status
= NT_STATUS_INVALID_PARAMETER
;
2012 bloblen
= 8 + ea_len
+ namelen
;
2013 /* Round up to a 4 byte boundary. */
2014 bloblen
= ((bloblen
+ 3)&~3);
2016 inbuf
= data_blob_talloc_zero(frame
, bloblen
);
2017 if (inbuf
.data
== NULL
) {
2018 status
= NT_STATUS_NO_MEMORY
;
2021 /* namelen doesn't include the NULL byte. */
2022 SCVAL(inbuf
.data
, 5, namelen
- 1);
2023 SSVAL(inbuf
.data
, 6, ea_len
);
2024 memcpy(inbuf
.data
+ 8, ea_name_ascii
, namelen
);
2025 memcpy(inbuf
.data
+ 8 + namelen
, ea_val
, ea_len
);
2027 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2028 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2030 status
= smb2cli_set_info(cli
->conn
,
2034 1, /* in_info_type */
2035 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2036 &inbuf
, /* in_input_buffer */
2037 0, /* in_additional_info */
2047 /***************************************************************
2048 Wrapper that allows SMB2 to set an EA on a pathname.
2050 ***************************************************************/
2052 NTSTATUS
cli_smb2_set_ea_path(struct cli_state
*cli
,
2054 const char *ea_name
,
2059 uint16_t fnum
= 0xffff;
2061 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2063 * Can't use sync call while an async call is in flight
2065 status
= NT_STATUS_INVALID_PARAMETER
;
2069 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2070 status
= NT_STATUS_INVALID_PARAMETER
;
2074 status
= get_fnum_from_path(cli
,
2079 if (!NT_STATUS_IS_OK(status
)) {
2083 status
= cli_set_ea_fnum(cli
,
2088 if (!NT_STATUS_IS_OK(status
)) {
2094 if (fnum
!= 0xffff) {
2095 cli_smb2_close_fnum(cli
, fnum
);
2101 /***************************************************************
2102 Wrapper that allows SMB2 to get an EA list on a pathname.
2104 ***************************************************************/
2106 NTSTATUS
cli_smb2_get_ea_list_path(struct cli_state
*cli
,
2110 struct ea_struct
**pea_array
)
2113 uint16_t fnum
= 0xffff;
2114 DATA_BLOB outbuf
= data_blob_null
;
2115 struct smb2_hnd
*ph
= NULL
;
2116 struct ea_list
*ea_list
= NULL
;
2117 struct ea_list
*eal
= NULL
;
2118 size_t ea_count
= 0;
2119 TALLOC_CTX
*frame
= talloc_stackframe();
2124 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
2126 * Can't use sync call while an async call is in flight
2128 status
= NT_STATUS_INVALID_PARAMETER
;
2132 if (smbXcli_conn_protocol(cli
->conn
) < PROTOCOL_SMB2_02
) {
2133 status
= NT_STATUS_INVALID_PARAMETER
;
2137 status
= get_fnum_from_path(cli
,
2142 if (!NT_STATUS_IS_OK(status
)) {
2146 status
= map_fnum_to_smb2_handle(cli
,
2149 if (!NT_STATUS_IS_OK(status
)) {
2153 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2154 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2156 status
= smb2cli_query_info(cli
->conn
,
2160 1, /* in_info_type */
2161 SMB_FILE_FULL_EA_INFORMATION
- 1000, /* in_file_info_class */
2162 0xFFFF, /* in_max_output_length */
2163 NULL
, /* in_input_buffer */
2164 0, /* in_additional_info */
2171 if (!NT_STATUS_IS_OK(status
)) {
2175 /* Parse the reply. */
2176 ea_list
= read_nttrans_ea_list(ctx
,
2177 (const char *)outbuf
.data
,
2179 if (ea_list
== NULL
) {
2180 status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
2184 /* Convert to an array. */
2185 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2190 *pea_array
= talloc_array(ctx
, struct ea_struct
, ea_count
);
2191 if (*pea_array
== NULL
) {
2192 status
= NT_STATUS_NO_MEMORY
;
2196 for (eal
= ea_list
; eal
; eal
= eal
->next
) {
2197 (*pea_array
)[ea_count
++] = eal
->ea
;
2199 *pnum_eas
= ea_count
;
2204 if (fnum
!= 0xffff) {
2205 cli_smb2_close_fnum(cli
, fnum
);
2212 struct cli_smb2_read_state
{
2213 struct tevent_context
*ev
;
2214 struct cli_state
*cli
;
2215 struct smb2_hnd
*ph
;
2216 uint64_t start_offset
;
2222 static void cli_smb2_read_done(struct tevent_req
*subreq
);
2224 struct tevent_req
*cli_smb2_read_send(TALLOC_CTX
*mem_ctx
,
2225 struct tevent_context
*ev
,
2226 struct cli_state
*cli
,
2232 struct tevent_req
*req
, *subreq
;
2233 struct cli_smb2_read_state
*state
;
2235 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_read_state
);
2241 state
->start_offset
= (uint64_t)offset
;
2242 state
->size
= (uint32_t)size
;
2243 state
->received
= 0;
2246 status
= map_fnum_to_smb2_handle(cli
,
2249 if (tevent_req_nterror(req
, status
)) {
2250 return tevent_req_post(req
, ev
);
2253 subreq
= smb2cli_read_send(state
,
2256 state
->cli
->timeout
,
2257 state
->cli
->smb2
.session
,
2258 state
->cli
->smb2
.tcon
,
2260 state
->start_offset
,
2261 state
->ph
->fid_persistent
,
2262 state
->ph
->fid_volatile
,
2263 0, /* minimum_count */
2264 0); /* remaining_bytes */
2266 if (tevent_req_nomem(subreq
, req
)) {
2267 return tevent_req_post(req
, ev
);
2269 tevent_req_set_callback(subreq
, cli_smb2_read_done
, req
);
2273 static void cli_smb2_read_done(struct tevent_req
*subreq
)
2275 struct tevent_req
*req
= tevent_req_callback_data(
2276 subreq
, struct tevent_req
);
2277 struct cli_smb2_read_state
*state
= tevent_req_data(
2278 req
, struct cli_smb2_read_state
);
2281 status
= smb2cli_read_recv(subreq
, state
,
2282 &state
->buf
, &state
->received
);
2283 if (tevent_req_nterror(req
, status
)) {
2287 if (state
->received
> state
->size
) {
2288 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2292 tevent_req_done(req
);
2295 NTSTATUS
cli_smb2_read_recv(struct tevent_req
*req
,
2300 struct cli_smb2_read_state
*state
= tevent_req_data(
2301 req
, struct cli_smb2_read_state
);
2303 if (tevent_req_is_nterror(req
, &status
)) {
2307 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2308 * better make sure that you copy it away before you talloc_free(req).
2309 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2311 *received
= (ssize_t
)state
->received
;
2312 *rcvbuf
= state
->buf
;
2313 return NT_STATUS_OK
;
2316 struct cli_smb2_write_state
{
2317 struct tevent_context
*ev
;
2318 struct cli_state
*cli
;
2319 struct smb2_hnd
*ph
;
2327 static void cli_smb2_write_written(struct tevent_req
*req
);
2329 struct tevent_req
*cli_smb2_write_send(TALLOC_CTX
*mem_ctx
,
2330 struct tevent_context
*ev
,
2331 struct cli_state
*cli
,
2339 struct tevent_req
*req
, *subreq
= NULL
;
2340 struct cli_smb2_write_state
*state
= NULL
;
2342 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_write_state
);
2348 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2349 state
->flags
= (uint32_t)mode
;
2351 state
->offset
= (uint64_t)offset
;
2352 state
->size
= (uint32_t)size
;
2355 status
= map_fnum_to_smb2_handle(cli
,
2358 if (tevent_req_nterror(req
, status
)) {
2359 return tevent_req_post(req
, ev
);
2362 subreq
= smb2cli_write_send(state
,
2365 state
->cli
->timeout
,
2366 state
->cli
->smb2
.session
,
2367 state
->cli
->smb2
.tcon
,
2370 state
->ph
->fid_persistent
,
2371 state
->ph
->fid_volatile
,
2372 0, /* remaining_bytes */
2373 state
->flags
, /* flags */
2376 if (tevent_req_nomem(subreq
, req
)) {
2377 return tevent_req_post(req
, ev
);
2379 tevent_req_set_callback(subreq
, cli_smb2_write_written
, req
);
2383 static void cli_smb2_write_written(struct tevent_req
*subreq
)
2385 struct tevent_req
*req
= tevent_req_callback_data(
2386 subreq
, struct tevent_req
);
2387 struct cli_smb2_write_state
*state
= tevent_req_data(
2388 req
, struct cli_smb2_write_state
);
2392 status
= smb2cli_write_recv(subreq
, &written
);
2393 TALLOC_FREE(subreq
);
2394 if (tevent_req_nterror(req
, status
)) {
2398 state
->written
= written
;
2400 tevent_req_done(req
);
2403 NTSTATUS
cli_smb2_write_recv(struct tevent_req
*req
,
2406 struct cli_smb2_write_state
*state
= tevent_req_data(
2407 req
, struct cli_smb2_write_state
);
2410 if (tevent_req_is_nterror(req
, &status
)) {
2411 tevent_req_received(req
);
2415 if (pwritten
!= NULL
) {
2416 *pwritten
= (size_t)state
->written
;
2418 tevent_req_received(req
);
2419 return NT_STATUS_OK
;
2422 /***************************************************************
2423 Wrapper that allows SMB2 async write using an fnum.
2424 This is mostly cut-and-paste from Volker's code inside
2425 source3/libsmb/clireadwrite.c, adapted for SMB2.
2427 Done this way so I can reuse all the logic inside cli_push()
2429 ***************************************************************/
2431 struct cli_smb2_writeall_state
{
2432 struct tevent_context
*ev
;
2433 struct cli_state
*cli
;
2434 struct smb2_hnd
*ph
;
2442 static void cli_smb2_writeall_written(struct tevent_req
*req
);
2444 struct tevent_req
*cli_smb2_writeall_send(TALLOC_CTX
*mem_ctx
,
2445 struct tevent_context
*ev
,
2446 struct cli_state
*cli
,
2454 struct tevent_req
*req
, *subreq
= NULL
;
2455 struct cli_smb2_writeall_state
*state
= NULL
;
2460 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_writeall_state
);
2466 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2467 state
->flags
= (uint32_t)mode
;
2469 state
->offset
= (uint64_t)offset
;
2470 state
->size
= (uint32_t)size
;
2473 status
= map_fnum_to_smb2_handle(cli
,
2476 if (tevent_req_nterror(req
, status
)) {
2477 return tevent_req_post(req
, ev
);
2480 to_write
= state
->size
;
2481 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2482 to_write
= MIN(max_size
, to_write
);
2483 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2485 to_write
= MIN(max_size
, to_write
);
2488 subreq
= smb2cli_write_send(state
,
2491 state
->cli
->timeout
,
2492 state
->cli
->smb2
.session
,
2493 state
->cli
->smb2
.tcon
,
2496 state
->ph
->fid_persistent
,
2497 state
->ph
->fid_volatile
,
2498 0, /* remaining_bytes */
2499 state
->flags
, /* flags */
2500 state
->buf
+ state
->written
);
2502 if (tevent_req_nomem(subreq
, req
)) {
2503 return tevent_req_post(req
, ev
);
2505 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2509 static void cli_smb2_writeall_written(struct tevent_req
*subreq
)
2511 struct tevent_req
*req
= tevent_req_callback_data(
2512 subreq
, struct tevent_req
);
2513 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2514 req
, struct cli_smb2_writeall_state
);
2516 uint32_t written
, to_write
;
2520 status
= smb2cli_write_recv(subreq
, &written
);
2521 TALLOC_FREE(subreq
);
2522 if (tevent_req_nterror(req
, status
)) {
2526 state
->written
+= written
;
2528 if (state
->written
> state
->size
) {
2529 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2533 to_write
= state
->size
- state
->written
;
2535 if (to_write
== 0) {
2536 tevent_req_done(req
);
2540 max_size
= smb2cli_conn_max_write_size(state
->cli
->conn
);
2541 to_write
= MIN(max_size
, to_write
);
2542 ok
= smb2cli_conn_req_possible(state
->cli
->conn
, &max_size
);
2544 to_write
= MIN(max_size
, to_write
);
2547 subreq
= smb2cli_write_send(state
,
2550 state
->cli
->timeout
,
2551 state
->cli
->smb2
.session
,
2552 state
->cli
->smb2
.tcon
,
2554 state
->offset
+ state
->written
,
2555 state
->ph
->fid_persistent
,
2556 state
->ph
->fid_volatile
,
2557 0, /* remaining_bytes */
2558 state
->flags
, /* flags */
2559 state
->buf
+ state
->written
);
2561 if (tevent_req_nomem(subreq
, req
)) {
2564 tevent_req_set_callback(subreq
, cli_smb2_writeall_written
, req
);
2567 NTSTATUS
cli_smb2_writeall_recv(struct tevent_req
*req
,
2570 struct cli_smb2_writeall_state
*state
= tevent_req_data(
2571 req
, struct cli_smb2_writeall_state
);
2574 if (tevent_req_is_nterror(req
, &status
)) {
2577 if (pwritten
!= NULL
) {
2578 *pwritten
= (size_t)state
->written
;
2580 return NT_STATUS_OK
;
2583 struct cli_smb2_splice_state
{
2584 struct tevent_context
*ev
;
2585 struct cli_state
*cli
;
2586 struct smb2_hnd
*src_ph
;
2587 struct smb2_hnd
*dst_ph
;
2588 int (*splice_cb
)(off_t n
, void *priv
);
2595 struct req_resume_key_rsp resume_rsp
;
2596 struct srv_copychunk_copy cc_copy
;
2599 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
2600 struct tevent_req
*req
);
2602 static void cli_splice_copychunk_done(struct tevent_req
*subreq
)
2604 struct tevent_req
*req
= tevent_req_callback_data(
2605 subreq
, struct tevent_req
);
2606 struct cli_smb2_splice_state
*state
=
2607 tevent_req_data(req
,
2608 struct cli_smb2_splice_state
);
2609 struct smbXcli_conn
*conn
= state
->cli
->conn
;
2610 DATA_BLOB out_input_buffer
= data_blob_null
;
2611 DATA_BLOB out_output_buffer
= data_blob_null
;
2612 struct srv_copychunk_rsp cc_copy_rsp
;
2613 enum ndr_err_code ndr_ret
;
2616 status
= smb2cli_ioctl_recv(subreq
, state
,
2618 &out_output_buffer
);
2619 TALLOC_FREE(subreq
);
2620 if ((!NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
) ||
2621 state
->resized
) && tevent_req_nterror(req
, status
)) {
2625 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
, state
, &cc_copy_rsp
,
2626 (ndr_pull_flags_fn_t
)ndr_pull_srv_copychunk_rsp
);
2627 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
2628 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
2629 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2633 if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
2634 uint32_t max_chunks
= MIN(cc_copy_rsp
.chunks_written
,
2635 cc_copy_rsp
.total_bytes_written
/ cc_copy_rsp
.chunk_bytes_written
);
2636 if ((cc_copy_rsp
.chunk_bytes_written
> smb2cli_conn_cc_chunk_len(conn
) ||
2637 max_chunks
> smb2cli_conn_cc_max_chunks(conn
)) &&
2638 tevent_req_nterror(req
, status
)) {
2642 state
->resized
= true;
2643 smb2cli_conn_set_cc_chunk_len(conn
, cc_copy_rsp
.chunk_bytes_written
);
2644 smb2cli_conn_set_cc_max_chunks(conn
, max_chunks
);
2646 if ((state
->src_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
2647 (state
->dst_offset
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
) ||
2648 (state
->written
> INT64_MAX
- cc_copy_rsp
.total_bytes_written
)) {
2649 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
2652 state
->src_offset
+= cc_copy_rsp
.total_bytes_written
;
2653 state
->dst_offset
+= cc_copy_rsp
.total_bytes_written
;
2654 state
->written
+= cc_copy_rsp
.total_bytes_written
;
2655 if (!state
->splice_cb(state
->written
, state
->priv
)) {
2656 tevent_req_nterror(req
, NT_STATUS_CANCELLED
);
2661 cli_splice_copychunk_send(state
, req
);
2664 static void cli_splice_copychunk_send(struct cli_smb2_splice_state
*state
,
2665 struct tevent_req
*req
)
2667 struct tevent_req
*subreq
;
2668 enum ndr_err_code ndr_ret
;
2669 struct smbXcli_conn
*conn
= state
->cli
->conn
;
2670 struct srv_copychunk_copy
*cc_copy
= &state
->cc_copy
;
2671 off_t src_offset
= state
->src_offset
;
2672 off_t dst_offset
= state
->dst_offset
;
2673 uint32_t req_len
= MIN(smb2cli_conn_cc_chunk_len(conn
) * smb2cli_conn_cc_max_chunks(conn
),
2674 state
->size
- state
->written
);
2675 DATA_BLOB in_input_buffer
= data_blob_null
;
2676 DATA_BLOB in_output_buffer
= data_blob_null
;
2678 if (state
->size
- state
->written
== 0) {
2679 tevent_req_done(req
);
2683 cc_copy
->chunk_count
= 0;
2685 cc_copy
->chunks
[cc_copy
->chunk_count
].source_off
= src_offset
;
2686 cc_copy
->chunks
[cc_copy
->chunk_count
].target_off
= dst_offset
;
2687 cc_copy
->chunks
[cc_copy
->chunk_count
].length
= MIN(req_len
,
2688 smb2cli_conn_cc_chunk_len(conn
));
2689 if (req_len
< cc_copy
->chunks
[cc_copy
->chunk_count
].length
) {
2690 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
2693 req_len
-= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
2694 if ((src_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
) ||
2695 (dst_offset
> INT64_MAX
- cc_copy
->chunks
[cc_copy
->chunk_count
].length
)) {
2696 tevent_req_nterror(req
, NT_STATUS_FILE_TOO_LARGE
);
2699 src_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
2700 dst_offset
+= cc_copy
->chunks
[cc_copy
->chunk_count
].length
;
2701 cc_copy
->chunk_count
++;
2704 ndr_ret
= ndr_push_struct_blob(&in_input_buffer
, state
, cc_copy
,
2705 (ndr_push_flags_fn_t
)ndr_push_srv_copychunk_copy
);
2706 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
2707 DEBUG(0, ("failed to marshall copy chunk req\n"));
2708 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
2712 subreq
= smb2cli_ioctl_send(state
, state
->ev
, state
->cli
->conn
,
2713 state
->cli
->timeout
,
2714 state
->cli
->smb2
.session
,
2715 state
->cli
->smb2
.tcon
,
2716 state
->dst_ph
->fid_persistent
, /* in_fid_persistent */
2717 state
->dst_ph
->fid_volatile
, /* in_fid_volatile */
2718 FSCTL_SRV_COPYCHUNK_WRITE
,
2719 0, /* in_max_input_length */
2721 12, /* in_max_output_length */
2723 SMB2_IOCTL_FLAG_IS_FSCTL
);
2724 if (tevent_req_nomem(subreq
, req
)) {
2727 tevent_req_set_callback(subreq
,
2728 cli_splice_copychunk_done
,
2732 static void cli_splice_key_done(struct tevent_req
*subreq
)
2734 struct tevent_req
*req
= tevent_req_callback_data(
2735 subreq
, struct tevent_req
);
2736 struct cli_smb2_splice_state
*state
=
2737 tevent_req_data(req
,
2738 struct cli_smb2_splice_state
);
2739 enum ndr_err_code ndr_ret
;
2742 DATA_BLOB out_input_buffer
= data_blob_null
;
2743 DATA_BLOB out_output_buffer
= data_blob_null
;
2745 status
= smb2cli_ioctl_recv(subreq
, state
,
2747 &out_output_buffer
);
2748 TALLOC_FREE(subreq
);
2749 if (tevent_req_nterror(req
, status
)) {
2753 ndr_ret
= ndr_pull_struct_blob(&out_output_buffer
,
2754 state
, &state
->resume_rsp
,
2755 (ndr_pull_flags_fn_t
)ndr_pull_req_resume_key_rsp
);
2756 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
2757 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
2758 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
2762 memcpy(&state
->cc_copy
.source_key
,
2763 &state
->resume_rsp
.resume_key
,
2764 sizeof state
->resume_rsp
.resume_key
);
2766 cli_splice_copychunk_send(state
, req
);
2769 struct tevent_req
*cli_smb2_splice_send(TALLOC_CTX
*mem_ctx
,
2770 struct tevent_context
*ev
,
2771 struct cli_state
*cli
,
2772 uint16_t src_fnum
, uint16_t dst_fnum
,
2773 off_t size
, off_t src_offset
, off_t dst_offset
,
2774 int (*splice_cb
)(off_t n
, void *priv
),
2777 struct tevent_req
*req
;
2778 struct tevent_req
*subreq
;
2779 struct cli_smb2_splice_state
*state
;
2781 DATA_BLOB in_input_buffer
= data_blob_null
;
2782 DATA_BLOB in_output_buffer
= data_blob_null
;
2784 req
= tevent_req_create(mem_ctx
, &state
, struct cli_smb2_splice_state
);
2790 state
->splice_cb
= splice_cb
;
2794 state
->src_offset
= src_offset
;
2795 state
->dst_offset
= dst_offset
;
2796 state
->cc_copy
.chunks
= talloc_array(state
,
2797 struct srv_copychunk
,
2798 smb2cli_conn_cc_max_chunks(cli
->conn
));
2799 if (state
->cc_copy
.chunks
== NULL
) {
2803 status
= map_fnum_to_smb2_handle(cli
, src_fnum
, &state
->src_ph
);
2804 if (tevent_req_nterror(req
, status
))
2805 return tevent_req_post(req
, ev
);
2807 status
= map_fnum_to_smb2_handle(cli
, dst_fnum
, &state
->dst_ph
);
2808 if (tevent_req_nterror(req
, status
))
2809 return tevent_req_post(req
, ev
);
2811 subreq
= smb2cli_ioctl_send(state
, ev
, cli
->conn
,
2815 state
->src_ph
->fid_persistent
, /* in_fid_persistent */
2816 state
->src_ph
->fid_volatile
, /* in_fid_volatile */
2817 FSCTL_SRV_REQUEST_RESUME_KEY
,
2818 0, /* in_max_input_length */
2820 32, /* in_max_output_length */
2822 SMB2_IOCTL_FLAG_IS_FSCTL
);
2823 if (tevent_req_nomem(subreq
, req
)) {
2826 tevent_req_set_callback(subreq
,
2827 cli_splice_key_done
,
2833 NTSTATUS
cli_smb2_splice_recv(struct tevent_req
*req
, off_t
*written
)
2835 struct cli_smb2_splice_state
*state
= tevent_req_data(
2836 req
, struct cli_smb2_splice_state
);
2839 if (tevent_req_is_nterror(req
, &status
)) {
2840 tevent_req_received(req
);
2843 if (written
!= NULL
) {
2844 *written
= state
->written
;
2846 tevent_req_received(req
);
2847 return NT_STATUS_OK
;