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"
32 struct cli_setpathinfo_state {
37 static void cli_setpathinfo_done(struct tevent_req *subreq);
39 struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
40 struct tevent_context *ev,
41 struct cli_state *cli,
47 struct tevent_req *req, *subreq;
48 struct cli_setpathinfo_state *state;
49 uint16_t additional_flags2 = 0;
51 req = tevent_req_create(mem_ctx, &state,
52 struct cli_setpathinfo_state);
57 /* Setup setup word. */
58 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
60 /* Setup param array. */
61 state->param = talloc_zero_array(state, uint8_t, 6);
62 if (tevent_req_nomem(state->param, req)) {
63 return tevent_req_post(req, ev);
65 SSVAL(state->param, 0, level);
67 state->param = trans2_bytes_push_str(
68 state->param, smbXcli_conn_use_unicode(cli->conn), path, strlen(path)+1, NULL);
69 if (tevent_req_nomem(state->param, req)) {
70 return tevent_req_post(req, ev);
73 if (clistr_is_previous_version_path(path, NULL, NULL, NULL) &&
74 !INFO_LEVEL_IS_UNIX(level)) {
75 additional_flags2 = FLAGS2_REPARSE_PATH;
78 subreq = cli_trans_send(
82 additional_flags2, /* additional_flags2 */
84 NULL, /* pipe name. */
88 &state->setup, /* setup. */
89 1, /* num setup uint16_t words. */
90 0, /* max returned setup. */
91 state->param, /* param. */
92 talloc_get_size(state->param), /* num param. */
93 2, /* max returned param. */
95 data_len, /* num data. */
96 0); /* max returned data. */
98 if (tevent_req_nomem(subreq, req)) {
99 return tevent_req_post(req, ev);
101 tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
105 static void cli_setpathinfo_done(struct tevent_req *subreq)
107 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
108 NULL, 0, NULL, NULL, 0, NULL);
109 tevent_req_simple_finish_ntstatus(subreq, status);
112 NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
114 return tevent_req_simple_recv_ntstatus(req);
117 NTSTATUS cli_setpathinfo(struct cli_state *cli,
123 TALLOC_CTX *frame = talloc_stackframe();
124 struct tevent_context *ev;
125 struct tevent_req *req;
126 NTSTATUS status = NT_STATUS_NO_MEMORY;
128 if (smbXcli_conn_has_async_calls(cli->conn)) {
130 * Can't use sync call while an async call is in flight
132 status = NT_STATUS_INVALID_PARAMETER;
135 ev = samba_tevent_context_init(frame);
139 req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
143 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
146 status = cli_setpathinfo_recv(req);
152 struct cli_setfileinfo_state {
157 static void cli_setfileinfo_done(struct tevent_req *subreq);
159 struct tevent_req *cli_setfileinfo_send(
161 struct tevent_context *ev,
162 struct cli_state *cli,
168 struct tevent_req *req = NULL, *subreq = NULL;
169 struct cli_setfileinfo_state *state = NULL;
171 req = tevent_req_create(mem_ctx, &state, struct cli_setfileinfo_state);
175 PUSH_LE_U16(&state->setup, 0, TRANSACT2_SETFILEINFO);
177 PUSH_LE_U16(state->param, 0, fnum);
178 PUSH_LE_U16(state->param, 2, level);
180 subreq = cli_trans_send(state, /* mem ctx. */
182 cli, /* cli_state. */
183 0, /* additional_flags2 */
184 SMBtrans2, /* cmd. */
185 NULL, /* pipe name. */
189 &state->setup, /* setup. */
190 1, /* num setup uint16_t words. */
191 0, /* max returned setup. */
192 state->param, /* param. */
194 2, /* max returned param. */
196 data_len, /* num data. */
197 0); /* max returned data. */
199 if (tevent_req_nomem(subreq, req)) {
200 return tevent_req_post(req, ev);
202 tevent_req_set_callback(subreq, cli_setfileinfo_done, req);
206 static void cli_setfileinfo_done(struct tevent_req *subreq)
208 NTSTATUS status = cli_trans_recv(
211 NULL, /* recv_flags2 */
214 NULL, /* num_setup */
217 NULL, /* num_param */
220 NULL); /* num_data */
221 tevent_req_simple_finish_ntstatus(subreq, status);
224 NTSTATUS cli_setfileinfo_recv(struct tevent_req *req)
226 return tevent_req_simple_recv_ntstatus(req);
229 /****************************************************************************
230 Hard/Symlink a file (UNIX extensions).
231 Creates new name (sym)linked to link_target.
232 ****************************************************************************/
234 struct cli_posix_link_internal_state {
238 static void cli_posix_link_internal_done(struct tevent_req *subreq);
240 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
241 struct tevent_context *ev,
242 struct cli_state *cli,
244 const char *link_target,
247 struct tevent_req *req = NULL, *subreq = NULL;
248 struct cli_posix_link_internal_state *state = NULL;
250 req = tevent_req_create(mem_ctx, &state,
251 struct cli_posix_link_internal_state);
256 /* Setup data array. */
257 state->data = talloc_array(state, uint8_t, 0);
258 if (tevent_req_nomem(state->data, req)) {
259 return tevent_req_post(req, ev);
261 state->data = trans2_bytes_push_str(
262 state->data, smbXcli_conn_use_unicode(cli->conn),
263 link_target, strlen(link_target)+1, NULL);
265 subreq = cli_setpathinfo_send(
266 state, ev, cli, level, newname,
267 state->data, talloc_get_size(state->data));
268 if (tevent_req_nomem(subreq, req)) {
269 return tevent_req_post(req, ev);
271 tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
275 static void cli_posix_link_internal_done(struct tevent_req *subreq)
277 NTSTATUS status = cli_setpathinfo_recv(subreq);
278 tevent_req_simple_finish_ntstatus(subreq, status);
281 static NTSTATUS cli_posix_link_internal_recv(struct tevent_req *req)
283 return tevent_req_simple_recv_ntstatus(req);
286 /****************************************************************************
287 Symlink a file (UNIX extensions).
288 ****************************************************************************/
290 struct cli_posix_symlink_state {
294 static void cli_posix_symlink_done(struct tevent_req *subreq);
296 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
297 struct tevent_context *ev,
298 struct cli_state *cli,
299 const char *link_target,
302 struct tevent_req *req = NULL, *subreq = NULL;
303 struct cli_posix_symlink_state *state = NULL;
305 req = tevent_req_create(
306 mem_ctx, &state, struct cli_posix_symlink_state);
311 subreq = cli_posix_link_internal_send(
312 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, link_target, newname);
313 if (tevent_req_nomem(subreq, req)) {
314 return tevent_req_post(req, ev);
316 tevent_req_set_callback(subreq, cli_posix_symlink_done, req);
320 static void cli_posix_symlink_done(struct tevent_req *subreq)
322 NTSTATUS status = cli_posix_link_internal_recv(subreq);
323 tevent_req_simple_finish_ntstatus(subreq, status);
326 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
328 return tevent_req_simple_recv_ntstatus(req);
331 NTSTATUS cli_posix_symlink(struct cli_state *cli,
332 const char *link_target,
335 TALLOC_CTX *frame = talloc_stackframe();
336 struct tevent_context *ev = NULL;
337 struct tevent_req *req = NULL;
338 NTSTATUS status = NT_STATUS_OK;
340 if (smbXcli_conn_has_async_calls(cli->conn)) {
342 * Can't use sync call while an async call is in flight
344 status = NT_STATUS_INVALID_PARAMETER;
348 ev = samba_tevent_context_init(frame);
350 status = NT_STATUS_NO_MEMORY;
354 req = cli_posix_symlink_send(frame,
360 status = NT_STATUS_NO_MEMORY;
364 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
368 status = cli_posix_symlink_recv(req);
375 /****************************************************************************
376 Read a POSIX symlink.
377 ****************************************************************************/
379 struct cli_posix_readlink_state {
380 struct cli_state *cli;
384 static void cli_posix_readlink_done(struct tevent_req *subreq);
386 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
387 struct tevent_context *ev,
388 struct cli_state *cli,
391 struct tevent_req *req = NULL, *subreq = NULL;
392 struct cli_posix_readlink_state *state = NULL;
394 req = tevent_req_create(
395 mem_ctx, &state, struct cli_posix_readlink_state);
401 subreq = cli_qpathinfo_send(
406 SMB_QUERY_FILE_UNIX_LINK,
409 if (tevent_req_nomem(subreq, req)) {
410 return tevent_req_post(req, ev);
412 tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
416 static void cli_posix_readlink_done(struct tevent_req *subreq)
418 struct tevent_req *req = tevent_req_callback_data(
419 subreq, struct tevent_req);
420 struct cli_posix_readlink_state *state = tevent_req_data(
421 req, struct cli_posix_readlink_state);
423 uint8_t *data = NULL;
424 uint32_t num_data = 0;
426 size_t converted_size;
429 status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
431 if (tevent_req_nterror(req, status)) {
435 * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
437 if (data == NULL || data[num_data-1] != '\0') {
438 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
442 charset = smbXcli_conn_use_unicode(state->cli->conn) ?
445 /* The returned data is a pushed string, not raw data. */
446 ok = convert_string_talloc(
458 tevent_req_done(req);
461 NTSTATUS cli_posix_readlink_recv(
462 struct tevent_req *req, TALLOC_CTX *mem_ctx, char **target)
464 struct cli_posix_readlink_state *state = tevent_req_data(
465 req, struct cli_posix_readlink_state);
468 if (tevent_req_is_nterror(req, &status)) {
471 *target = talloc_move(mem_ctx, &state->converted);
475 NTSTATUS cli_posix_readlink(
476 struct cli_state *cli,
481 TALLOC_CTX *frame = talloc_stackframe();
482 struct tevent_context *ev = NULL;
483 struct tevent_req *req = NULL;
484 NTSTATUS status = NT_STATUS_OK;
486 if (smbXcli_conn_has_async_calls(cli->conn)) {
488 * Can't use sync call while an async call is in flight
490 status = NT_STATUS_INVALID_PARAMETER;
494 ev = samba_tevent_context_init(frame);
496 status = NT_STATUS_NO_MEMORY;
500 req = cli_posix_readlink_send(frame, ev, cli, fname);
502 status = NT_STATUS_NO_MEMORY;
506 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
510 status = cli_posix_readlink_recv(req, mem_ctx, target);
517 /****************************************************************************
518 Hard link a file (UNIX extensions).
519 ****************************************************************************/
521 struct cli_posix_hardlink_state {
525 static void cli_posix_hardlink_done(struct tevent_req *subreq);
527 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
528 struct tevent_context *ev,
529 struct cli_state *cli,
533 struct tevent_req *req = NULL, *subreq = NULL;
534 struct cli_posix_hardlink_state *state = NULL;
536 req = tevent_req_create(
537 mem_ctx, &state, struct cli_posix_hardlink_state);
542 subreq = cli_posix_link_internal_send(
543 state, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
544 if (tevent_req_nomem(subreq, req)) {
545 return tevent_req_post(req, ev);
547 tevent_req_set_callback(subreq, cli_posix_hardlink_done, req);
551 static void cli_posix_hardlink_done(struct tevent_req *subreq)
553 NTSTATUS status = cli_posix_link_internal_recv(subreq);
554 tevent_req_simple_finish_ntstatus(subreq, status);
557 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
559 return tevent_req_simple_recv_ntstatus(req);
562 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
566 TALLOC_CTX *frame = talloc_stackframe();
567 struct tevent_context *ev = NULL;
568 struct tevent_req *req = NULL;
569 NTSTATUS status = NT_STATUS_OK;
571 if (smbXcli_conn_has_async_calls(cli->conn)) {
573 * Can't use sync call while an async call is in flight
575 status = NT_STATUS_INVALID_PARAMETER;
579 ev = samba_tevent_context_init(frame);
581 status = NT_STATUS_NO_MEMORY;
585 req = cli_posix_hardlink_send(frame,
591 status = NT_STATUS_NO_MEMORY;
595 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
599 status = cli_posix_hardlink_recv(req);
606 /****************************************************************************
607 Do a POSIX getacl - pathname based ACL get (UNIX extensions).
608 ****************************************************************************/
610 struct getacl_state {
615 static void cli_posix_getacl_done(struct tevent_req *subreq);
617 struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
618 struct tevent_context *ev,
619 struct cli_state *cli,
622 struct tevent_req *req = NULL, *subreq = NULL;
623 struct getacl_state *state = NULL;
625 req = tevent_req_create(mem_ctx, &state, struct getacl_state);
629 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
631 if (tevent_req_nomem(subreq, req)) {
632 return tevent_req_post(req, ev);
634 tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
638 static void cli_posix_getacl_done(struct tevent_req *subreq)
640 struct tevent_req *req = tevent_req_callback_data(
641 subreq, struct tevent_req);
642 struct getacl_state *state = tevent_req_data(
643 req, struct getacl_state);
646 status = cli_qpathinfo_recv(subreq, state, &state->data,
649 if (tevent_req_nterror(req, status)) {
652 tevent_req_done(req);
655 NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
660 struct getacl_state *state = tevent_req_data(req, struct getacl_state);
663 if (tevent_req_is_nterror(req, &status)) {
666 *prb_size = (size_t)state->num_data;
667 *retbuf = (char *)talloc_move(mem_ctx, &state->data);
671 NTSTATUS cli_posix_getacl(struct cli_state *cli,
677 TALLOC_CTX *frame = talloc_stackframe();
678 struct tevent_context *ev = NULL;
679 struct tevent_req *req = NULL;
680 NTSTATUS status = NT_STATUS_OK;
682 if (smbXcli_conn_has_async_calls(cli->conn)) {
684 * Can't use sync call while an async call is in flight
686 status = NT_STATUS_INVALID_PARAMETER;
690 ev = samba_tevent_context_init(frame);
692 status = NT_STATUS_NO_MEMORY;
696 req = cli_posix_getacl_send(frame,
701 status = NT_STATUS_NO_MEMORY;
705 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
709 status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
716 /****************************************************************************
717 Do a POSIX setacl - pathname based ACL set (UNIX extensions).
718 ****************************************************************************/
720 struct setacl_state {
724 static void cli_posix_setacl_done(struct tevent_req *subreq);
726 struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
727 struct tevent_context *ev,
728 struct cli_state *cli,
733 struct tevent_req *req = NULL, *subreq = NULL;
734 struct setacl_state *state = NULL;
736 req = tevent_req_create(mem_ctx, &state, struct setacl_state);
740 state->data = talloc_memdup(state, data, num_data);
741 if (tevent_req_nomem(state->data, req)) {
742 return tevent_req_post(req, ev);
745 subreq = cli_setpathinfo_send(state,
752 if (tevent_req_nomem(subreq, req)) {
753 return tevent_req_post(req, ev);
755 tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
759 static void cli_posix_setacl_done(struct tevent_req *subreq)
761 NTSTATUS status = cli_setpathinfo_recv(subreq);
762 tevent_req_simple_finish_ntstatus(subreq, status);
765 NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
767 return tevent_req_simple_recv_ntstatus(req);
770 NTSTATUS cli_posix_setacl(struct cli_state *cli,
775 TALLOC_CTX *frame = talloc_stackframe();
776 struct tevent_context *ev = NULL;
777 struct tevent_req *req = NULL;
778 NTSTATUS status = NT_STATUS_OK;
780 if (smbXcli_conn_has_async_calls(cli->conn)) {
782 * Can't use sync call while an async call is in flight
784 status = NT_STATUS_INVALID_PARAMETER;
788 ev = samba_tevent_context_init(frame);
790 status = NT_STATUS_NO_MEMORY;
794 req = cli_posix_setacl_send(frame,
801 status = NT_STATUS_NO_MEMORY;
805 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
809 status = cli_posix_setacl_recv(req);
816 /****************************************************************************
817 Stat a file (UNIX extensions).
818 ****************************************************************************/
821 SMB_STRUCT_STAT *sbuf;
824 static void cli_posix_stat_done(struct tevent_req *subreq);
826 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
827 struct tevent_context *ev,
828 struct cli_state *cli,
830 SMB_STRUCT_STAT *sbuf)
832 struct tevent_req *req = NULL, *subreq = NULL;
833 struct stat_state *state = NULL;
835 req = tevent_req_create(mem_ctx, &state, struct stat_state);
841 subreq = cli_qpathinfo_send(state, ev, cli, fname,
842 SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
843 if (tevent_req_nomem(subreq, req)) {
844 return tevent_req_post(req, ev);
846 tevent_req_set_callback(subreq, cli_posix_stat_done, req);
850 static void cli_posix_stat_done(struct tevent_req *subreq)
852 struct tevent_req *req = tevent_req_callback_data(
853 subreq, struct tevent_req);
854 struct stat_state *state = tevent_req_data(req, struct stat_state);
855 SMB_STRUCT_STAT *sbuf = state->sbuf;
857 uint32_t num_data = 0;
860 status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
862 if (tevent_req_nterror(req, status)) {
866 if (num_data != 100) {
868 * Paranoia, cli_qpathinfo should have guaranteed
869 * this, but you never know...
871 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
875 *sbuf = (SMB_STRUCT_STAT) { 0 };
877 /* total size, in bytes */
878 sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(data, 0);
880 /* number of blocks allocated */
881 sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(data,8);
882 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
883 sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
885 /* assume 512 byte blocks */
886 sbuf->st_ex_blocks /= 512;
888 /* time of last change */
889 sbuf->st_ex_ctime = interpret_long_date((char *)(data + 16));
891 /* time of last access */
892 sbuf->st_ex_atime = interpret_long_date((char *)(data + 24));
894 /* time of last modification */
895 sbuf->st_ex_mtime = interpret_long_date((char *)(data + 32));
897 sbuf->st_ex_uid = (uid_t) IVAL(data, 40); /* user ID of owner */
898 sbuf->st_ex_gid = (gid_t) IVAL(data, 48); /* group ID of owner */
899 sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(data, 56));
901 #if defined(HAVE_MAKEDEV)
903 uint32_t dev_major = IVAL(data,60);
904 uint32_t dev_minor = IVAL(data,68);
905 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
909 sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(data, 76);
912 sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(data, 84));
914 /* number of hard links */
915 sbuf->st_ex_nlink = BIG_UINT(data, 92);
917 tevent_req_done(req);
920 NTSTATUS cli_posix_stat_recv(struct tevent_req *req)
922 return tevent_req_simple_recv_ntstatus(req);
925 NTSTATUS cli_posix_stat(struct cli_state *cli,
927 SMB_STRUCT_STAT *sbuf)
929 TALLOC_CTX *frame = talloc_stackframe();
930 struct tevent_context *ev = NULL;
931 struct tevent_req *req = NULL;
932 NTSTATUS status = NT_STATUS_OK;
934 if (smbXcli_conn_has_async_calls(cli->conn)) {
936 * Can't use sync call while an async call is in flight
938 status = NT_STATUS_INVALID_PARAMETER;
942 ev = samba_tevent_context_init(frame);
944 status = NT_STATUS_NO_MEMORY;
948 req = cli_posix_stat_send(frame, ev, cli, fname, sbuf);
950 status = NT_STATUS_NO_MEMORY;
954 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
958 status = cli_posix_stat_recv(req);
965 /****************************************************************************
966 Chmod or chown a file internal (UNIX extensions).
967 ****************************************************************************/
969 struct cli_posix_chown_chmod_internal_state {
973 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
975 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
976 struct tevent_context *ev,
977 struct cli_state *cli,
983 struct tevent_req *req = NULL, *subreq = NULL;
984 struct cli_posix_chown_chmod_internal_state *state = NULL;
986 req = tevent_req_create(mem_ctx, &state,
987 struct cli_posix_chown_chmod_internal_state);
992 memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
993 memset(&state->data[40], '\0', 60);
994 SIVAL(state->data,40,uid);
995 SIVAL(state->data,48,gid);
996 SIVAL(state->data,84,mode);
998 subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
999 fname, state->data, sizeof(state->data));
1000 if (tevent_req_nomem(subreq, req)) {
1001 return tevent_req_post(req, ev);
1003 tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
1008 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
1010 NTSTATUS status = cli_setpathinfo_recv(subreq);
1011 tevent_req_simple_finish_ntstatus(subreq, status);
1014 static NTSTATUS cli_posix_chown_chmod_internal_recv(struct tevent_req *req)
1016 return tevent_req_simple_recv_ntstatus(req);
1019 /****************************************************************************
1020 chmod a file (UNIX extensions).
1021 ****************************************************************************/
1023 struct cli_posix_chmod_state {
1027 static void cli_posix_chmod_done(struct tevent_req *subreq);
1029 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
1030 struct tevent_context *ev,
1031 struct cli_state *cli,
1035 struct tevent_req *req = NULL, *subreq = NULL;
1036 struct cli_posix_chmod_state *state = NULL;
1038 req = tevent_req_create(mem_ctx, &state, struct cli_posix_chmod_state);
1043 subreq = cli_posix_chown_chmod_internal_send(
1048 unix_perms_to_wire(mode),
1051 if (tevent_req_nomem(subreq, req)) {
1052 return tevent_req_post(req, ev);
1054 tevent_req_set_callback(subreq, cli_posix_chmod_done, req);
1058 static void cli_posix_chmod_done(struct tevent_req *subreq)
1060 NTSTATUS status = cli_posix_chown_chmod_internal_recv(subreq);
1061 tevent_req_simple_finish_ntstatus(subreq, status);
1064 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
1066 return tevent_req_simple_recv_ntstatus(req);
1069 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
1071 TALLOC_CTX *frame = talloc_stackframe();
1072 struct tevent_context *ev = NULL;
1073 struct tevent_req *req = NULL;
1074 NTSTATUS status = NT_STATUS_OK;
1076 if (smbXcli_conn_has_async_calls(cli->conn)) {
1078 * Can't use sync call while an async call is in flight
1080 status = NT_STATUS_INVALID_PARAMETER;
1084 ev = samba_tevent_context_init(frame);
1086 status = NT_STATUS_NO_MEMORY;
1090 req = cli_posix_chmod_send(frame,
1096 status = NT_STATUS_NO_MEMORY;
1100 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1104 status = cli_posix_chmod_recv(req);
1111 /****************************************************************************
1112 chown a file (UNIX extensions).
1113 ****************************************************************************/
1115 struct cli_posix_chown_state {
1119 static void cli_posix_chown_done(struct tevent_req *subreq);
1121 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1122 struct tevent_context *ev,
1123 struct cli_state *cli,
1128 struct tevent_req *req = NULL, *subreq = NULL;
1129 struct cli_posix_chown_state *state = NULL;
1131 req = tevent_req_create(
1132 mem_ctx, &state, struct cli_posix_chown_state);
1137 subreq = cli_posix_chown_chmod_internal_send(
1145 if (tevent_req_nomem(subreq, req)) {
1146 return tevent_req_post(req, ev);
1148 tevent_req_set_callback(subreq, cli_posix_chown_done, req);
1152 static void cli_posix_chown_done(struct tevent_req *subreq)
1154 NTSTATUS status = cli_posix_chown_chmod_internal_recv(subreq);
1155 tevent_req_simple_finish_ntstatus(subreq, status);
1158 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1160 return tevent_req_simple_recv_ntstatus(req);
1163 NTSTATUS cli_posix_chown(struct cli_state *cli,
1168 TALLOC_CTX *frame = talloc_stackframe();
1169 struct tevent_context *ev = NULL;
1170 struct tevent_req *req = NULL;
1171 NTSTATUS status = NT_STATUS_OK;
1173 if (smbXcli_conn_has_async_calls(cli->conn)) {
1175 * Can't use sync call while an async call is in flight
1177 status = NT_STATUS_INVALID_PARAMETER;
1181 ev = samba_tevent_context_init(frame);
1183 status = NT_STATUS_NO_MEMORY;
1187 req = cli_posix_chown_send(frame,
1194 status = NT_STATUS_NO_MEMORY;
1198 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1202 status = cli_posix_chown_recv(req);
1209 /****************************************************************************
1211 ****************************************************************************/
1213 struct cli_smb1_rename_state {
1217 static void cli_smb1_rename_done(struct tevent_req *subreq);
1219 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1220 struct tevent_context *ev,
1221 struct cli_state *cli,
1222 const char *fname_src,
1223 const char *fname_dst,
1227 struct tevent_req *req = NULL, *subreq = NULL;
1228 struct cli_smb1_rename_state *state = NULL;
1229 smb_ucs2_t *converted_str = NULL;
1230 size_t converted_size_bytes = 0;
1232 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
1237 if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
1238 &converted_size_bytes)) {
1239 status = NT_STATUS_INVALID_PARAMETER;
1243 /* W2K8 insists the dest name is not null
1244 terminated. Remove the last 2 zero bytes
1245 and reduce the name length. */
1247 if (converted_size_bytes < 2) {
1248 status = NT_STATUS_INVALID_PARAMETER;
1251 converted_size_bytes -= 2;
1254 talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
1255 if (state->data == NULL) {
1256 status = NT_STATUS_NO_MEMORY;
1261 SCVAL(state->data, 0, 1);
1264 SIVAL(state->data, 8, converted_size_bytes);
1265 memcpy(state->data + 12, converted_str, converted_size_bytes);
1267 TALLOC_FREE(converted_str);
1269 subreq = cli_setpathinfo_send(
1270 state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
1271 talloc_get_size(state->data));
1272 if (tevent_req_nomem(subreq, req)) {
1273 status = NT_STATUS_NO_MEMORY;
1276 tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
1280 TALLOC_FREE(converted_str);
1281 tevent_req_nterror(req, status);
1282 return tevent_req_post(req, ev);
1285 static void cli_smb1_rename_done(struct tevent_req *subreq)
1287 NTSTATUS status = cli_setpathinfo_recv(subreq);
1288 tevent_req_simple_finish_ntstatus(subreq, status);
1291 static NTSTATUS cli_smb1_rename_recv(struct tevent_req *req)
1293 return tevent_req_simple_recv_ntstatus(req);
1296 static void cli_cifs_rename_done(struct tevent_req *subreq);
1298 struct cli_cifs_rename_state {
1302 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1303 struct tevent_context *ev,
1304 struct cli_state *cli,
1305 const char *fname_src,
1306 const char *fname_dst,
1309 struct tevent_req *req = NULL, *subreq = NULL;
1310 struct cli_cifs_rename_state *state = NULL;
1311 uint8_t additional_flags = 0;
1312 uint16_t additional_flags2 = 0;
1313 uint8_t *bytes = NULL;
1315 req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
1322 * CIFS doesn't support replace
1324 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1325 return tevent_req_post(req, ev);
1328 SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1330 bytes = talloc_array(state, uint8_t, 1);
1331 if (tevent_req_nomem(bytes, req)) {
1332 return tevent_req_post(req, ev);
1335 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1336 strlen(fname_src)+1, NULL);
1337 if (tevent_req_nomem(bytes, req)) {
1338 return tevent_req_post(req, ev);
1341 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1342 additional_flags2 = FLAGS2_REPARSE_PATH;
1345 bytes = talloc_realloc(state, bytes, uint8_t,
1346 talloc_get_size(bytes)+1);
1347 if (tevent_req_nomem(bytes, req)) {
1348 return tevent_req_post(req, ev);
1351 bytes[talloc_get_size(bytes)-1] = 4;
1352 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1353 strlen(fname_dst)+1, NULL);
1354 if (tevent_req_nomem(bytes, req)) {
1355 return tevent_req_post(req, ev);
1358 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1360 1, state->vwv, talloc_get_size(bytes), bytes);
1361 if (tevent_req_nomem(subreq, req)) {
1362 return tevent_req_post(req, ev);
1364 tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
1368 static void cli_cifs_rename_done(struct tevent_req *subreq)
1370 NTSTATUS status = cli_smb_recv(
1371 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1372 tevent_req_simple_finish_ntstatus(subreq, status);
1375 static NTSTATUS cli_cifs_rename_recv(struct tevent_req *req)
1377 return tevent_req_simple_recv_ntstatus(req);
1380 struct cli_rename_state {
1384 static void cli_rename_done1(struct tevent_req *subreq);
1385 static void cli_rename_done_cifs(struct tevent_req *subreq);
1386 static void cli_rename_done2(struct tevent_req *subreq);
1388 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1389 struct tevent_context *ev,
1390 struct cli_state *cli,
1391 const char *fname_src,
1392 const char *fname_dst,
1395 struct tevent_req *req = NULL, *subreq = NULL;
1396 struct cli_rename_state *state = NULL;
1398 req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1403 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1404 subreq = cli_smb2_rename_send(
1405 state, ev, cli, fname_src, fname_dst, replace);
1406 if (tevent_req_nomem(subreq, req)) {
1407 return tevent_req_post(req, ev);
1409 tevent_req_set_callback(subreq, cli_rename_done2, req);
1413 if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
1414 subreq = cli_smb1_rename_send(
1415 state, ev, cli, fname_src, fname_dst, replace);
1416 if (tevent_req_nomem(subreq, req)) {
1417 return tevent_req_post(req, ev);
1419 tevent_req_set_callback(subreq, cli_rename_done1, req);
1423 subreq = cli_cifs_rename_send(
1424 state, ev, cli, fname_src,fname_dst, replace);
1425 if (tevent_req_nomem(subreq, req)) {
1426 return tevent_req_post(req, ev);
1428 tevent_req_set_callback(subreq, cli_rename_done_cifs, req);
1432 static void cli_rename_done1(struct tevent_req *subreq)
1434 NTSTATUS status = cli_smb1_rename_recv(subreq);
1435 tevent_req_simple_finish_ntstatus(subreq, status);
1438 static void cli_rename_done_cifs(struct tevent_req *subreq)
1440 NTSTATUS status = cli_cifs_rename_recv(subreq);
1441 tevent_req_simple_finish_ntstatus(subreq, status);
1444 static void cli_rename_done2(struct tevent_req *subreq)
1446 NTSTATUS status = cli_smb2_rename_recv(subreq);
1447 tevent_req_simple_finish_ntstatus(subreq, status);
1450 NTSTATUS cli_rename_recv(struct tevent_req *req)
1452 return tevent_req_simple_recv_ntstatus(req);
1455 NTSTATUS cli_rename(struct cli_state *cli,
1456 const char *fname_src,
1457 const char *fname_dst,
1460 TALLOC_CTX *frame = NULL;
1461 struct tevent_context *ev;
1462 struct tevent_req *req;
1463 NTSTATUS status = NT_STATUS_OK;
1465 frame = talloc_stackframe();
1467 if (smbXcli_conn_has_async_calls(cli->conn)) {
1469 * Can't use sync call while an async call is in flight
1471 status = NT_STATUS_INVALID_PARAMETER;
1475 ev = samba_tevent_context_init(frame);
1477 status = NT_STATUS_NO_MEMORY;
1481 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
1483 status = NT_STATUS_NO_MEMORY;
1487 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1491 status = cli_rename_recv(req);
1498 /****************************************************************************
1500 ****************************************************************************/
1502 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1504 struct cli_ntrename_internal_state {
1508 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1509 struct tevent_context *ev,
1510 struct cli_state *cli,
1511 const char *fname_src,
1512 const char *fname_dst,
1513 uint16_t rename_flag)
1515 struct tevent_req *req = NULL, *subreq = NULL;
1516 struct cli_ntrename_internal_state *state = NULL;
1517 uint8_t additional_flags = 0;
1518 uint16_t additional_flags2 = 0;
1519 uint8_t *bytes = NULL;
1521 req = tevent_req_create(mem_ctx, &state,
1522 struct cli_ntrename_internal_state);
1527 SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1528 SSVAL(state->vwv+1, 0, rename_flag);
1530 bytes = talloc_array(state, uint8_t, 1);
1531 if (tevent_req_nomem(bytes, req)) {
1532 return tevent_req_post(req, ev);
1535 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1536 strlen(fname_src)+1, NULL);
1537 if (tevent_req_nomem(bytes, req)) {
1538 return tevent_req_post(req, ev);
1541 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1542 additional_flags2 = FLAGS2_REPARSE_PATH;
1545 bytes = talloc_realloc(state, bytes, uint8_t,
1546 talloc_get_size(bytes)+1);
1547 if (tevent_req_nomem(bytes, req)) {
1548 return tevent_req_post(req, ev);
1551 bytes[talloc_get_size(bytes)-1] = 4;
1552 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1553 strlen(fname_dst)+1, NULL);
1554 if (tevent_req_nomem(bytes, req)) {
1555 return tevent_req_post(req, ev);
1558 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1560 4, state->vwv, talloc_get_size(bytes), bytes);
1561 if (tevent_req_nomem(subreq, req)) {
1562 return tevent_req_post(req, ev);
1564 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1568 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1570 NTSTATUS status = cli_smb_recv(
1571 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1572 tevent_req_simple_finish_ntstatus(subreq, status);
1575 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1577 return tevent_req_simple_recv_ntstatus(req);
1580 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1581 struct tevent_context *ev,
1582 struct cli_state *cli,
1583 const char *fname_src,
1584 const char *fname_dst)
1586 return cli_ntrename_internal_send(mem_ctx,
1591 RENAME_FLAG_RENAME);
1594 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1596 return cli_ntrename_internal_recv(req);
1599 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1601 TALLOC_CTX *frame = talloc_stackframe();
1602 struct tevent_context *ev;
1603 struct tevent_req *req;
1604 NTSTATUS status = NT_STATUS_OK;
1606 if (smbXcli_conn_has_async_calls(cli->conn)) {
1608 * Can't use sync call while an async call is in flight
1610 status = NT_STATUS_INVALID_PARAMETER;
1614 ev = samba_tevent_context_init(frame);
1616 status = NT_STATUS_NO_MEMORY;
1620 req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1622 status = NT_STATUS_NO_MEMORY;
1626 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1630 status = cli_ntrename_recv(req);
1637 /****************************************************************************
1639 ****************************************************************************/
1641 static struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1642 struct tevent_context *ev,
1643 struct cli_state *cli,
1644 const char *fname_src,
1645 const char *fname_dst)
1647 return cli_ntrename_internal_send(mem_ctx,
1652 RENAME_FLAG_HARD_LINK);
1655 static NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1657 return cli_ntrename_internal_recv(req);
1660 struct cli_smb2_hardlink_state {
1661 struct tevent_context *ev;
1662 struct cli_state *cli;
1664 const char *fname_dst;
1669 static void cli_smb2_hardlink_opened(struct tevent_req *subreq);
1670 static void cli_smb2_hardlink_info_set(struct tevent_req *subreq);
1671 static void cli_smb2_hardlink_closed(struct tevent_req *subreq);
1673 static struct tevent_req *cli_smb2_hardlink_send(
1674 TALLOC_CTX *mem_ctx,
1675 struct tevent_context *ev,
1676 struct cli_state *cli,
1677 const char *fname_src,
1678 const char *fname_dst,
1680 struct smb2_create_blobs *in_cblobs)
1682 struct tevent_req *req = NULL, *subreq = NULL;
1683 struct cli_smb2_hardlink_state *state = NULL;
1685 req = tevent_req_create(
1686 mem_ctx, &state, struct cli_smb2_hardlink_state);
1692 state->fname_dst = fname_dst;
1693 state->overwrite = overwrite;
1695 subreq = cli_smb2_create_fnum_send(
1700 0, /* create_flags */
1701 SMB2_IMPERSONATION_IMPERSONATION,
1702 FILE_WRITE_ATTRIBUTES,
1703 0, /* file attributes */
1706 FILE_SHARE_DELETE, /* share_access */
1707 FILE_OPEN, /* create_disposition */
1708 FILE_NON_DIRECTORY_FILE, /* no hardlinks on directories */
1710 if (tevent_req_nomem(subreq, req)) {
1711 return tevent_req_post(req, ev);
1713 tevent_req_set_callback(subreq, cli_smb2_hardlink_opened, req);
1717 static void cli_smb2_hardlink_opened(struct tevent_req *subreq)
1719 struct tevent_req *req = tevent_req_callback_data(
1720 subreq, struct tevent_req);
1721 struct cli_smb2_hardlink_state *state = tevent_req_data(
1722 req, struct cli_smb2_hardlink_state);
1724 smb_ucs2_t *ucs2_dst;
1729 status = cli_smb2_create_fnum_recv(
1730 subreq, &state->fnum_src, NULL, NULL, NULL);
1731 TALLOC_FREE(subreq);
1732 if (tevent_req_nterror(req, status)) {
1736 ok = push_ucs2_talloc(state, &ucs2_dst, state->fname_dst, &ucs2_len);
1737 if (!ok || (ucs2_len < 2)) {
1738 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1741 /* Don't 0-terminate the name */
1744 inbuf = data_blob_talloc_zero(state, ucs2_len + 20);
1745 if (tevent_req_nomem(inbuf.data, req)) {
1749 if (state->overwrite) {
1750 SCVAL(inbuf.data, 0, 1);
1752 SIVAL(inbuf.data, 16, ucs2_len);
1753 memcpy(inbuf.data + 20, ucs2_dst, ucs2_len);
1754 TALLOC_FREE(ucs2_dst);
1756 subreq = cli_smb2_set_info_fnum_send(
1761 1, /* in_info_type */
1762 SMB_FILE_LINK_INFORMATION - 1000, /* in_file_info_class */
1764 0); /* in_additional_info */
1765 if (tevent_req_nomem(subreq, req)) {
1768 tevent_req_set_callback(subreq, cli_smb2_hardlink_info_set, req);
1771 static void cli_smb2_hardlink_info_set(struct tevent_req *subreq)
1773 struct tevent_req *req = tevent_req_callback_data(
1774 subreq, struct tevent_req);
1775 struct cli_smb2_hardlink_state *state = tevent_req_data(
1776 req, struct cli_smb2_hardlink_state);
1778 state->status = cli_smb2_set_info_fnum_recv(subreq);
1779 TALLOC_FREE(subreq);
1781 /* ignore error here, we need to close the file */
1783 subreq = cli_smb2_close_fnum_send(
1784 state, state->ev, state->cli, state->fnum_src);
1785 if (tevent_req_nomem(subreq, req)) {
1788 tevent_req_set_callback(subreq, cli_smb2_hardlink_closed, req);
1791 static void cli_smb2_hardlink_closed(struct tevent_req *subreq)
1793 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1794 tevent_req_simple_finish_ntstatus(subreq, status);
1797 static NTSTATUS cli_smb2_hardlink_recv(struct tevent_req *req)
1799 struct cli_smb2_hardlink_state *state = tevent_req_data(
1800 req, struct cli_smb2_hardlink_state);
1803 if (tevent_req_is_nterror(req, &status)) {
1806 return state->status;
1809 struct cli_hardlink_state {
1813 static void cli_hardlink_done(struct tevent_req *subreq);
1814 static void cli_hardlink_done2(struct tevent_req *subreq);
1816 struct tevent_req *cli_hardlink_send(
1817 TALLOC_CTX *mem_ctx,
1818 struct tevent_context *ev,
1819 struct cli_state *cli,
1820 const char *fname_src,
1821 const char *fname_dst)
1823 struct tevent_req *req = NULL, *subreq = NULL;
1824 struct cli_hardlink_state *state;
1826 req = tevent_req_create(mem_ctx, &state, struct cli_hardlink_state);
1831 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1832 subreq = cli_smb2_hardlink_send(
1833 state, ev, cli, fname_src, fname_dst, false, NULL);
1834 if (tevent_req_nomem(subreq, req)) {
1835 return tevent_req_post(req, ev);
1837 tevent_req_set_callback(subreq, cli_hardlink_done2, req);
1841 subreq = cli_nt_hardlink_send(state, ev, cli, fname_src, fname_dst);
1842 if (tevent_req_nomem(subreq, req)) {
1843 return tevent_req_post(req, ev);
1845 tevent_req_set_callback(subreq, cli_hardlink_done, req);
1849 static void cli_hardlink_done(struct tevent_req *subreq)
1851 NTSTATUS status = cli_nt_hardlink_recv(subreq);
1852 tevent_req_simple_finish_ntstatus(subreq, status);
1855 static void cli_hardlink_done2(struct tevent_req *subreq)
1857 NTSTATUS status = cli_smb2_hardlink_recv(subreq);
1858 tevent_req_simple_finish_ntstatus(subreq, status);
1861 NTSTATUS cli_hardlink_recv(struct tevent_req *req)
1863 return tevent_req_simple_recv_ntstatus(req);
1866 NTSTATUS cli_hardlink(
1867 struct cli_state *cli, const char *fname_src, const char *fname_dst)
1869 TALLOC_CTX *frame = talloc_stackframe();
1870 struct tevent_context *ev = NULL;
1871 struct tevent_req *req = NULL;
1872 NTSTATUS status = NT_STATUS_NO_MEMORY;
1874 if (smbXcli_conn_has_async_calls(cli->conn)) {
1875 status = NT_STATUS_INVALID_PARAMETER;
1878 ev = samba_tevent_context_init(frame);
1882 req = cli_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1886 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1889 status = cli_hardlink_recv(req);
1895 /****************************************************************************
1897 ****************************************************************************/
1899 static void cli_unlink_done(struct tevent_req *subreq);
1900 static void cli_unlink_done2(struct tevent_req *subreq);
1902 struct cli_unlink_state {
1906 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1907 struct tevent_context *ev,
1908 struct cli_state *cli,
1910 uint32_t mayhave_attrs)
1912 struct tevent_req *req = NULL, *subreq = NULL;
1913 struct cli_unlink_state *state = NULL;
1914 uint8_t additional_flags = 0;
1915 uint16_t additional_flags2 = 0;
1916 uint8_t *bytes = NULL;
1918 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1923 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1924 subreq = cli_smb2_unlink_send(state, ev, cli, fname, NULL);
1925 if (tevent_req_nomem(subreq, req)) {
1926 return tevent_req_post(req, ev);
1928 tevent_req_set_callback(subreq, cli_unlink_done2, req);
1932 if (mayhave_attrs & 0xFFFF0000) {
1934 * Don't allow attributes greater than
1935 * 16-bits for a 16-bit protocol value.
1937 if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
1938 return tevent_req_post(req, ev);
1942 SSVAL(state->vwv+0, 0, mayhave_attrs);
1944 bytes = talloc_array(state, uint8_t, 1);
1945 if (tevent_req_nomem(bytes, req)) {
1946 return tevent_req_post(req, ev);
1949 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
1950 strlen(fname)+1, NULL);
1952 if (tevent_req_nomem(bytes, req)) {
1953 return tevent_req_post(req, ev);
1956 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1957 additional_flags2 = FLAGS2_REPARSE_PATH;
1960 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1962 1, state->vwv, talloc_get_size(bytes), bytes);
1963 if (tevent_req_nomem(subreq, req)) {
1964 return tevent_req_post(req, ev);
1966 tevent_req_set_callback(subreq, cli_unlink_done, req);
1970 static void cli_unlink_done(struct tevent_req *subreq)
1972 NTSTATUS status = cli_smb_recv(
1973 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1974 tevent_req_simple_finish_ntstatus(subreq, status);
1977 static void cli_unlink_done2(struct tevent_req *subreq)
1979 NTSTATUS status = cli_smb2_unlink_recv(subreq);
1980 tevent_req_simple_finish_ntstatus(subreq, status);
1983 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1985 return tevent_req_simple_recv_ntstatus(req);
1988 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint32_t mayhave_attrs)
1990 TALLOC_CTX *frame = NULL;
1991 struct tevent_context *ev;
1992 struct tevent_req *req;
1993 NTSTATUS status = NT_STATUS_OK;
1995 frame = talloc_stackframe();
1997 if (smbXcli_conn_has_async_calls(cli->conn)) {
1999 * Can't use sync call while an async call is in flight
2001 status = NT_STATUS_INVALID_PARAMETER;
2005 ev = samba_tevent_context_init(frame);
2007 status = NT_STATUS_NO_MEMORY;
2011 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
2013 status = NT_STATUS_NO_MEMORY;
2017 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2021 status = cli_unlink_recv(req);
2022 cli->raw_status = status; /* cli_smb2_unlink_recv doesn't set this */
2029 /****************************************************************************
2031 ****************************************************************************/
2033 static void cli_mkdir_done(struct tevent_req *subreq);
2034 static void cli_mkdir_done2(struct tevent_req *subreq);
2036 struct cli_mkdir_state {
2040 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
2041 struct tevent_context *ev,
2042 struct cli_state *cli,
2045 struct tevent_req *req = NULL, *subreq = NULL;
2046 struct cli_mkdir_state *state = NULL;
2047 uint8_t additional_flags = 0;
2048 uint16_t additional_flags2 = 0;
2049 uint8_t *bytes = NULL;
2051 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
2056 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2057 subreq = cli_smb2_mkdir_send(state, ev, cli, dname);
2058 if (tevent_req_nomem(subreq, req)) {
2059 return tevent_req_post(req, ev);
2061 tevent_req_set_callback(subreq, cli_mkdir_done2, req);
2065 bytes = talloc_array(state, uint8_t, 1);
2066 if (tevent_req_nomem(bytes, req)) {
2067 return tevent_req_post(req, ev);
2070 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
2071 strlen(dname)+1, NULL);
2073 if (tevent_req_nomem(bytes, req)) {
2074 return tevent_req_post(req, ev);
2077 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
2078 additional_flags2 = FLAGS2_REPARSE_PATH;
2081 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
2083 0, NULL, talloc_get_size(bytes), bytes);
2084 if (tevent_req_nomem(subreq, req)) {
2085 return tevent_req_post(req, ev);
2087 tevent_req_set_callback(subreq, cli_mkdir_done, req);
2091 static void cli_mkdir_done(struct tevent_req *subreq)
2093 struct tevent_req *req = tevent_req_callback_data(
2094 subreq, struct tevent_req);
2097 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2098 TALLOC_FREE(subreq);
2099 if (tevent_req_nterror(req, status)) {
2102 tevent_req_done(req);
2105 static void cli_mkdir_done2(struct tevent_req *subreq)
2107 NTSTATUS status = cli_smb2_mkdir_recv(subreq);
2108 tevent_req_simple_finish_ntstatus(subreq, status);
2111 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
2113 return tevent_req_simple_recv_ntstatus(req);
2116 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
2118 TALLOC_CTX *frame = NULL;
2119 struct tevent_context *ev;
2120 struct tevent_req *req;
2121 NTSTATUS status = NT_STATUS_OK;
2123 frame = talloc_stackframe();
2125 if (smbXcli_conn_has_async_calls(cli->conn)) {
2127 * Can't use sync call while an async call is in flight
2129 status = NT_STATUS_INVALID_PARAMETER;
2133 ev = samba_tevent_context_init(frame);
2135 status = NT_STATUS_NO_MEMORY;
2139 req = cli_mkdir_send(frame, ev, cli, dname);
2141 status = NT_STATUS_NO_MEMORY;
2145 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2149 status = cli_mkdir_recv(req);
2150 cli->raw_status = status; /* cli_smb2_mkdir_recv doesn't set this */
2157 /****************************************************************************
2159 ****************************************************************************/
2161 static void cli_rmdir_done(struct tevent_req *subreq);
2162 static void cli_rmdir_done2(struct tevent_req *subreq);
2164 struct cli_rmdir_state {
2168 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
2169 struct tevent_context *ev,
2170 struct cli_state *cli,
2173 struct tevent_req *req = NULL, *subreq = NULL;
2174 struct cli_rmdir_state *state = NULL;
2175 uint8_t additional_flags = 0;
2176 uint16_t additional_flags2 = 0;
2177 uint8_t *bytes = NULL;
2179 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
2184 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2185 subreq = cli_smb2_rmdir_send(state, ev, cli, dname, NULL);
2186 if (tevent_req_nomem(subreq, req)) {
2187 return tevent_req_post(req, ev);
2189 tevent_req_set_callback(subreq, cli_rmdir_done2, req);
2193 bytes = talloc_array(state, uint8_t, 1);
2194 if (tevent_req_nomem(bytes, req)) {
2195 return tevent_req_post(req, ev);
2198 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
2199 strlen(dname)+1, NULL);
2201 if (tevent_req_nomem(bytes, req)) {
2202 return tevent_req_post(req, ev);
2205 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
2206 additional_flags2 = FLAGS2_REPARSE_PATH;
2209 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
2211 0, NULL, talloc_get_size(bytes), bytes);
2212 if (tevent_req_nomem(subreq, req)) {
2213 return tevent_req_post(req, ev);
2215 tevent_req_set_callback(subreq, cli_rmdir_done, req);
2219 static void cli_rmdir_done(struct tevent_req *subreq)
2221 NTSTATUS status = cli_smb_recv(
2222 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2223 tevent_req_simple_finish_ntstatus(subreq, status);
2226 static void cli_rmdir_done2(struct tevent_req *subreq)
2228 NTSTATUS status = cli_smb2_rmdir_recv(subreq);
2229 tevent_req_simple_finish_ntstatus(subreq, status);
2232 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
2234 return tevent_req_simple_recv_ntstatus(req);
2237 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
2239 TALLOC_CTX *frame = NULL;
2240 struct tevent_context *ev;
2241 struct tevent_req *req;
2242 NTSTATUS status = NT_STATUS_OK;
2244 frame = talloc_stackframe();
2246 if (smbXcli_conn_has_async_calls(cli->conn)) {
2248 * Can't use sync call while an async call is in flight
2250 status = NT_STATUS_INVALID_PARAMETER;
2254 ev = samba_tevent_context_init(frame);
2256 status = NT_STATUS_NO_MEMORY;
2260 req = cli_rmdir_send(frame, ev, cli, dname);
2262 status = NT_STATUS_NO_MEMORY;
2266 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2270 status = cli_rmdir_recv(req);
2271 cli->raw_status = status; /* cli_smb2_rmdir_recv doesn't set this */
2278 /****************************************************************************
2279 Set or clear the delete on close flag.
2280 ****************************************************************************/
2286 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
2287 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
2289 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
2290 struct tevent_context *ev,
2291 struct cli_state *cli,
2295 struct tevent_req *req = NULL, *subreq = NULL;
2296 struct doc_state *state = NULL;
2298 req = tevent_req_create(mem_ctx, &state, struct doc_state);
2303 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2304 subreq = cli_smb2_delete_on_close_send(state, ev, cli,
2306 if (tevent_req_nomem(subreq, req)) {
2307 return tevent_req_post(req, ev);
2309 tevent_req_set_callback(subreq,
2310 cli_nt_delete_on_close_smb2_done,
2315 /* Setup data array. */
2316 SCVAL(&state->data[0], 0, flag ? 1 : 0);
2318 subreq = cli_setfileinfo_send(
2323 SMB_SET_FILE_DISPOSITION_INFO,
2325 sizeof(state->data));
2327 if (tevent_req_nomem(subreq, req)) {
2328 return tevent_req_post(req, ev);
2330 tevent_req_set_callback(subreq,
2331 cli_nt_delete_on_close_smb1_done,
2336 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
2338 NTSTATUS status = cli_setfileinfo_recv(subreq);
2339 tevent_req_simple_finish_ntstatus(subreq, status);
2342 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
2344 NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
2345 tevent_req_simple_finish_ntstatus(subreq, status);
2348 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
2350 return tevent_req_simple_recv_ntstatus(req);
2353 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
2355 TALLOC_CTX *frame = talloc_stackframe();
2356 struct tevent_context *ev = NULL;
2357 struct tevent_req *req = NULL;
2358 NTSTATUS status = NT_STATUS_OK;
2360 if (smbXcli_conn_has_async_calls(cli->conn)) {
2362 * Can't use sync call while an async call is in flight
2364 status = NT_STATUS_INVALID_PARAMETER;
2368 ev = samba_tevent_context_init(frame);
2370 status = NT_STATUS_NO_MEMORY;
2374 req = cli_nt_delete_on_close_send(frame,
2380 status = NT_STATUS_NO_MEMORY;
2384 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2388 status = cli_nt_delete_on_close_recv(req);
2395 struct cli_ntcreate1_state {
2398 struct smb_create_returns cr;
2399 struct tevent_req *subreq;
2402 static void cli_ntcreate1_done(struct tevent_req *subreq);
2403 static bool cli_ntcreate1_cancel(struct tevent_req *req);
2405 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
2406 struct tevent_context *ev,
2407 struct cli_state *cli,
2409 uint32_t CreatFlags,
2410 uint32_t DesiredAccess,
2411 uint32_t FileAttributes,
2412 uint32_t ShareAccess,
2413 uint32_t CreateDisposition,
2414 uint32_t CreateOptions,
2415 uint32_t ImpersonationLevel,
2416 uint8_t SecurityFlags)
2418 struct tevent_req *req, *subreq;
2419 struct cli_ntcreate1_state *state;
2422 size_t converted_len;
2423 uint16_t additional_flags2 = 0;
2425 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
2432 SCVAL(vwv+0, 0, 0xFF);
2437 if (cli->use_oplocks) {
2438 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
2440 SIVAL(vwv+3, 1, CreatFlags);
2441 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
2442 SIVAL(vwv+7, 1, DesiredAccess);
2443 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
2444 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
2445 SIVAL(vwv+13, 1, FileAttributes);
2446 SIVAL(vwv+15, 1, ShareAccess);
2447 SIVAL(vwv+17, 1, CreateDisposition);
2448 SIVAL(vwv+19, 1, CreateOptions |
2449 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2450 SIVAL(vwv+21, 1, ImpersonationLevel);
2451 SCVAL(vwv+23, 1, SecurityFlags);
2453 bytes = talloc_array(state, uint8_t, 0);
2454 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
2455 fname, strlen(fname)+1,
2458 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2459 additional_flags2 = FLAGS2_REPARSE_PATH;
2462 /* sigh. this copes with broken netapp filer behaviour */
2463 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2465 if (tevent_req_nomem(bytes, req)) {
2466 return tevent_req_post(req, ev);
2469 SSVAL(vwv+2, 1, converted_len);
2471 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2472 additional_flags2, 24, vwv,
2473 talloc_get_size(bytes), bytes);
2474 if (tevent_req_nomem(subreq, req)) {
2475 return tevent_req_post(req, ev);
2477 tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2479 state->subreq = subreq;
2480 tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2485 static void cli_ntcreate1_done(struct tevent_req *subreq)
2487 struct tevent_req *req = tevent_req_callback_data(
2488 subreq, struct tevent_req);
2489 struct cli_ntcreate1_state *state = tevent_req_data(
2490 req, struct cli_ntcreate1_state);
2497 status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2498 &num_bytes, &bytes);
2499 TALLOC_FREE(subreq);
2500 if (tevent_req_nterror(req, status)) {
2503 state->cr.oplock_level = CVAL(vwv+2, 0);
2504 state->fnum = SVAL(vwv+2, 1);
2505 state->cr.create_action = IVAL(vwv+3, 1);
2506 state->cr.creation_time = BVAL(vwv+5, 1);
2507 state->cr.last_access_time = BVAL(vwv+9, 1);
2508 state->cr.last_write_time = BVAL(vwv+13, 1);
2509 state->cr.change_time = BVAL(vwv+17, 1);
2510 state->cr.file_attributes = IVAL(vwv+21, 1);
2511 state->cr.allocation_size = BVAL(vwv+23, 1);
2512 state->cr.end_of_file = BVAL(vwv+27, 1);
2514 tevent_req_done(req);
2517 static bool cli_ntcreate1_cancel(struct tevent_req *req)
2519 struct cli_ntcreate1_state *state = tevent_req_data(
2520 req, struct cli_ntcreate1_state);
2521 return tevent_req_cancel(state->subreq);
2524 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2526 struct smb_create_returns *cr)
2528 struct cli_ntcreate1_state *state = tevent_req_data(
2529 req, struct cli_ntcreate1_state);
2532 if (tevent_req_is_nterror(req, &status)) {
2535 *pfnum = state->fnum;
2539 return NT_STATUS_OK;
2542 struct cli_ntcreate_state {
2543 struct smb_create_returns cr;
2545 struct tevent_req *subreq;
2548 static void cli_ntcreate_done_nt1(struct tevent_req *subreq);
2549 static void cli_ntcreate_done_smb2(struct tevent_req *subreq);
2550 static bool cli_ntcreate_cancel(struct tevent_req *req);
2552 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
2553 struct tevent_context *ev,
2554 struct cli_state *cli,
2556 uint32_t create_flags,
2557 uint32_t desired_access,
2558 uint32_t file_attributes,
2559 uint32_t share_access,
2560 uint32_t create_disposition,
2561 uint32_t create_options,
2562 uint32_t impersonation_level,
2563 uint8_t security_flags)
2565 struct tevent_req *req, *subreq;
2566 struct cli_ntcreate_state *state;
2568 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2573 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2574 if (cli->use_oplocks) {
2575 create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2578 subreq = cli_smb2_create_fnum_send(
2584 impersonation_level,
2591 if (tevent_req_nomem(subreq, req)) {
2592 return tevent_req_post(req, ev);
2594 tevent_req_set_callback(subreq, cli_ntcreate_done_smb2, req);
2596 subreq = cli_ntcreate1_send(
2597 state, ev, cli, fname, create_flags, desired_access,
2598 file_attributes, share_access, create_disposition,
2599 create_options, impersonation_level, security_flags);
2600 if (tevent_req_nomem(subreq, req)) {
2601 return tevent_req_post(req, ev);
2603 tevent_req_set_callback(subreq, cli_ntcreate_done_nt1, req);
2606 state->subreq = subreq;
2607 tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2612 static void cli_ntcreate_done_nt1(struct tevent_req *subreq)
2614 struct tevent_req *req = tevent_req_callback_data(
2615 subreq, struct tevent_req);
2616 struct cli_ntcreate_state *state = tevent_req_data(
2617 req, struct cli_ntcreate_state);
2620 status = cli_ntcreate1_recv(subreq, &state->fnum, &state->cr);
2621 TALLOC_FREE(subreq);
2622 if (tevent_req_nterror(req, status)) {
2625 tevent_req_done(req);
2628 static void cli_ntcreate_done_smb2(struct tevent_req *subreq)
2630 struct tevent_req *req = tevent_req_callback_data(
2631 subreq, struct tevent_req);
2632 struct cli_ntcreate_state *state = tevent_req_data(
2633 req, struct cli_ntcreate_state);
2636 status = cli_smb2_create_fnum_recv(
2642 TALLOC_FREE(subreq);
2643 if (tevent_req_nterror(req, status)) {
2646 tevent_req_done(req);
2649 static bool cli_ntcreate_cancel(struct tevent_req *req)
2651 struct cli_ntcreate_state *state = tevent_req_data(
2652 req, struct cli_ntcreate_state);
2653 return tevent_req_cancel(state->subreq);
2656 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2657 struct smb_create_returns *cr)
2659 struct cli_ntcreate_state *state = tevent_req_data(
2660 req, struct cli_ntcreate_state);
2663 if (tevent_req_is_nterror(req, &status)) {
2667 *fnum = state->fnum;
2672 return NT_STATUS_OK;
2675 NTSTATUS cli_ntcreate(struct cli_state *cli,
2677 uint32_t CreatFlags,
2678 uint32_t DesiredAccess,
2679 uint32_t FileAttributes,
2680 uint32_t ShareAccess,
2681 uint32_t CreateDisposition,
2682 uint32_t CreateOptions,
2683 uint8_t SecurityFlags,
2685 struct smb_create_returns *cr)
2687 TALLOC_CTX *frame = talloc_stackframe();
2688 struct tevent_context *ev;
2689 struct tevent_req *req;
2690 uint32_t ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
2691 NTSTATUS status = NT_STATUS_NO_MEMORY;
2693 if (smbXcli_conn_has_async_calls(cli->conn)) {
2695 * Can't use sync call while an async call is in flight
2697 status = NT_STATUS_INVALID_PARAMETER;
2701 ev = samba_tevent_context_init(frame);
2706 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2707 DesiredAccess, FileAttributes, ShareAccess,
2708 CreateDisposition, CreateOptions,
2709 ImpersonationLevel, SecurityFlags);
2714 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2718 status = cli_ntcreate_recv(req, pfid, cr);
2724 struct cli_nttrans_create_state {
2726 struct smb_create_returns cr;
2729 static void cli_nttrans_create_done(struct tevent_req *subreq);
2731 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2732 struct tevent_context *ev,
2733 struct cli_state *cli,
2735 uint32_t CreatFlags,
2736 uint32_t DesiredAccess,
2737 uint32_t FileAttributes,
2738 uint32_t ShareAccess,
2739 uint32_t CreateDisposition,
2740 uint32_t CreateOptions,
2741 uint8_t SecurityFlags,
2742 struct security_descriptor *secdesc,
2743 struct ea_struct *eas,
2746 struct tevent_req *req, *subreq;
2747 struct cli_nttrans_create_state *state;
2749 uint8_t *secdesc_buf;
2752 size_t converted_len;
2753 uint16_t additional_flags2 = 0;
2755 req = tevent_req_create(mem_ctx,
2756 &state, struct cli_nttrans_create_state);
2761 if (secdesc != NULL) {
2762 status = marshall_sec_desc(talloc_tos(), secdesc,
2763 &secdesc_buf, &secdesc_len);
2764 if (tevent_req_nterror(req, status)) {
2765 DEBUG(10, ("marshall_sec_desc failed: %s\n",
2766 nt_errstr(status)));
2767 return tevent_req_post(req, ev);
2778 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2779 return tevent_req_post(req, ev);
2782 param = talloc_array(state, uint8_t, 53);
2783 if (tevent_req_nomem(param, req)) {
2784 return tevent_req_post(req, ev);
2787 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2788 fname, strlen(fname),
2790 if (tevent_req_nomem(param, req)) {
2791 return tevent_req_post(req, ev);
2794 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2795 additional_flags2 = FLAGS2_REPARSE_PATH;
2798 SIVAL(param, 0, CreatFlags);
2799 SIVAL(param, 4, 0x0); /* RootDirectoryFid */
2800 SIVAL(param, 8, DesiredAccess);
2801 SIVAL(param, 12, 0x0); /* AllocationSize */
2802 SIVAL(param, 16, 0x0); /* AllocationSize */
2803 SIVAL(param, 20, FileAttributes);
2804 SIVAL(param, 24, ShareAccess);
2805 SIVAL(param, 28, CreateDisposition);
2806 SIVAL(param, 32, CreateOptions |
2807 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2808 SIVAL(param, 36, secdesc_len);
2809 SIVAL(param, 40, 0); /* EA length*/
2810 SIVAL(param, 44, converted_len);
2811 SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2812 SCVAL(param, 52, SecurityFlags);
2814 subreq = cli_trans_send(state, ev, cli,
2815 additional_flags2, /* additional_flags2 */
2817 NULL, -1, /* name, fid */
2818 NT_TRANSACT_CREATE, 0,
2819 NULL, 0, 0, /* setup */
2820 param, talloc_get_size(param), 128, /* param */
2821 secdesc_buf, secdesc_len, 0); /* data */
2822 if (tevent_req_nomem(subreq, req)) {
2823 return tevent_req_post(req, ev);
2825 tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2829 static void cli_nttrans_create_done(struct tevent_req *subreq)
2831 struct tevent_req *req = tevent_req_callback_data(
2832 subreq, struct tevent_req);
2833 struct cli_nttrans_create_state *state = tevent_req_data(
2834 req, struct cli_nttrans_create_state);
2839 status = cli_trans_recv(subreq, talloc_tos(), NULL,
2840 NULL, 0, NULL, /* rsetup */
2841 ¶m, 69, &num_param,
2843 if (tevent_req_nterror(req, status)) {
2846 state->cr.oplock_level = CVAL(param, 0);
2847 state->fnum = SVAL(param, 2);
2848 state->cr.create_action = IVAL(param, 4);
2849 state->cr.creation_time = BVAL(param, 12);
2850 state->cr.last_access_time = BVAL(param, 20);
2851 state->cr.last_write_time = BVAL(param, 28);
2852 state->cr.change_time = BVAL(param, 36);
2853 state->cr.file_attributes = IVAL(param, 44);
2854 state->cr.allocation_size = BVAL(param, 48);
2855 state->cr.end_of_file = BVAL(param, 56);
2858 tevent_req_done(req);
2861 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2863 struct smb_create_returns *cr)
2865 struct cli_nttrans_create_state *state = tevent_req_data(
2866 req, struct cli_nttrans_create_state);
2869 if (tevent_req_is_nterror(req, &status)) {
2872 *fnum = state->fnum;
2876 return NT_STATUS_OK;
2879 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2881 uint32_t CreatFlags,
2882 uint32_t DesiredAccess,
2883 uint32_t FileAttributes,
2884 uint32_t ShareAccess,
2885 uint32_t CreateDisposition,
2886 uint32_t CreateOptions,
2887 uint8_t SecurityFlags,
2888 struct security_descriptor *secdesc,
2889 struct ea_struct *eas,
2892 struct smb_create_returns *cr)
2894 TALLOC_CTX *frame = talloc_stackframe();
2895 struct tevent_context *ev;
2896 struct tevent_req *req;
2897 NTSTATUS status = NT_STATUS_NO_MEMORY;
2899 if (smbXcli_conn_has_async_calls(cli->conn)) {
2901 * Can't use sync call while an async call is in flight
2903 status = NT_STATUS_INVALID_PARAMETER;
2906 ev = samba_tevent_context_init(frame);
2910 req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2911 DesiredAccess, FileAttributes,
2912 ShareAccess, CreateDisposition,
2913 CreateOptions, SecurityFlags,
2914 secdesc, eas, num_eas);
2918 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2921 status = cli_nttrans_create_recv(req, pfid, cr);
2927 /****************************************************************************
2929 WARNING: if you open with O_WRONLY then getattrE won't work!
2930 ****************************************************************************/
2932 struct cli_openx_state {
2939 static void cli_openx_done(struct tevent_req *subreq);
2941 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2942 struct tevent_context *ev,
2943 struct cli_state *cli, const char *fname,
2944 int flags, int share_mode,
2945 struct tevent_req **psmbreq)
2947 struct tevent_req *req, *subreq;
2948 struct cli_openx_state *state;
2950 unsigned accessmode;
2951 uint8_t additional_flags;
2952 uint16_t additional_flags2 = 0;
2955 req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2961 if (flags & O_CREAT) {
2964 if (!(flags & O_EXCL)) {
2965 if (flags & O_TRUNC)
2971 accessmode = (share_mode<<4);
2973 if ((flags & O_ACCMODE) == O_RDWR) {
2975 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2980 if ((flags & O_SYNC) == O_SYNC) {
2981 accessmode |= (1<<14);
2985 if (share_mode == DENY_FCB) {
2989 SCVAL(state->vwv + 0, 0, 0xFF);
2990 SCVAL(state->vwv + 0, 1, 0);
2991 SSVAL(state->vwv + 1, 0, 0);
2992 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
2993 SSVAL(state->vwv + 3, 0, accessmode);
2994 SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2995 SSVAL(state->vwv + 5, 0, 0);
2996 SIVAL(state->vwv + 6, 0, 0);
2997 SSVAL(state->vwv + 8, 0, openfn);
2998 SIVAL(state->vwv + 9, 0, 0);
2999 SIVAL(state->vwv + 11, 0, 0);
3000 SIVAL(state->vwv + 13, 0, 0);
3002 additional_flags = 0;
3004 if (cli->use_oplocks) {
3005 /* if using oplocks then ask for a batch oplock via
3006 core and extended methods */
3008 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
3009 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
3012 bytes = talloc_array(state, uint8_t, 0);
3013 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3014 strlen(fname)+1, NULL);
3016 if (tevent_req_nomem(bytes, req)) {
3017 return tevent_req_post(req, ev);
3020 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
3021 additional_flags2 = FLAGS2_REPARSE_PATH;
3024 state->bytes.iov_base = (void *)bytes;
3025 state->bytes.iov_len = talloc_get_size(bytes);
3027 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
3028 additional_flags2, 15, state->vwv, 1, &state->bytes);
3029 if (subreq == NULL) {
3033 tevent_req_set_callback(subreq, cli_openx_done, req);
3038 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
3039 struct cli_state *cli, const char *fname,
3040 int flags, int share_mode)
3042 struct tevent_req *req, *subreq;
3045 req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
3051 status = smb1cli_req_chain_submit(&subreq, 1);
3052 if (tevent_req_nterror(req, status)) {
3053 return tevent_req_post(req, ev);
3058 static void cli_openx_done(struct tevent_req *subreq)
3060 struct tevent_req *req = tevent_req_callback_data(
3061 subreq, struct tevent_req);
3062 struct cli_openx_state *state = tevent_req_data(
3063 req, struct cli_openx_state);
3068 status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
3070 TALLOC_FREE(subreq);
3071 if (tevent_req_nterror(req, status)) {
3074 state->fnum = SVAL(vwv+2, 0);
3075 tevent_req_done(req);
3078 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
3080 struct cli_openx_state *state = tevent_req_data(
3081 req, struct cli_openx_state);
3084 if (tevent_req_is_nterror(req, &status)) {
3087 *pfnum = state->fnum;
3088 return NT_STATUS_OK;
3091 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
3092 int share_mode, uint16_t *pfnum)
3094 TALLOC_CTX *frame = talloc_stackframe();
3095 struct tevent_context *ev;
3096 struct tevent_req *req;
3097 NTSTATUS status = NT_STATUS_NO_MEMORY;
3099 if (smbXcli_conn_has_async_calls(cli->conn)) {
3101 * Can't use sync call while an async call is in flight
3103 status = NT_STATUS_INVALID_PARAMETER;
3107 ev = samba_tevent_context_init(frame);
3112 req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
3117 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3121 status = cli_openx_recv(req, pfnum);
3126 /****************************************************************************
3127 Synchronous wrapper function that does an NtCreateX open by preference
3128 and falls back to openX if this fails.
3129 ****************************************************************************/
3131 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
3132 int share_mode_in, uint16_t *pfnum)
3135 unsigned int openfn = 0;
3136 unsigned int dos_deny = 0;
3137 uint32_t access_mask, share_mode, create_disposition, create_options;
3138 struct smb_create_returns cr = {0};
3140 /* Do the initial mapping into OpenX parameters. */
3141 if (flags & O_CREAT) {
3144 if (!(flags & O_EXCL)) {
3145 if (flags & O_TRUNC)
3151 dos_deny = (share_mode_in<<4);
3153 if ((flags & O_ACCMODE) == O_RDWR) {
3155 } else if ((flags & O_ACCMODE) == O_WRONLY) {
3160 if ((flags & O_SYNC) == O_SYNC) {
3161 dos_deny |= (1<<14);
3165 if (share_mode_in == DENY_FCB) {
3169 if (!map_open_params_to_ntcreate(fname, dos_deny,
3170 openfn, &access_mask,
3171 &share_mode, &create_disposition,
3172 &create_options, NULL)) {
3176 status = cli_ntcreate(cli,
3188 /* Try and cope will all varients of "we don't do this call"
3189 and fall back to openX. */
3191 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
3192 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
3193 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
3194 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
3195 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
3196 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
3197 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
3198 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
3199 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
3203 if (NT_STATUS_IS_OK(status) &&
3204 (create_options & FILE_NON_DIRECTORY_FILE) &&
3205 (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
3208 * Some (broken) servers return a valid handle
3209 * for directories even if FILE_NON_DIRECTORY_FILE
3210 * is set. Just close the handle and set the
3211 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
3213 status = cli_close(cli, *pfnum);
3214 if (!NT_STATUS_IS_OK(status)) {
3217 status = NT_STATUS_FILE_IS_A_DIRECTORY;
3218 /* Set this so libsmbclient can retrieve it. */
3219 cli->raw_status = status;
3226 return cli_openx(cli, fname, flags, share_mode_in, pfnum);
3229 /****************************************************************************
3231 ****************************************************************************/
3233 struct cli_smb1_close_state {
3237 static void cli_smb1_close_done(struct tevent_req *subreq);
3239 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
3240 struct tevent_context *ev,
3241 struct cli_state *cli,
3243 struct tevent_req **psubreq)
3245 struct tevent_req *req, *subreq;
3246 struct cli_smb1_close_state *state;
3248 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
3253 SSVAL(state->vwv+0, 0, fnum);
3254 SIVALS(state->vwv+1, 0, -1);
3256 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
3257 3, state->vwv, 0, NULL);
3258 if (subreq == NULL) {
3262 tevent_req_set_callback(subreq, cli_smb1_close_done, req);
3267 static void cli_smb1_close_done(struct tevent_req *subreq)
3269 struct tevent_req *req = tevent_req_callback_data(
3270 subreq, struct tevent_req);
3273 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3274 TALLOC_FREE(subreq);
3275 if (tevent_req_nterror(req, status)) {
3278 tevent_req_done(req);
3281 struct cli_close_state {
3285 static void cli_close_done(struct tevent_req *subreq);
3287 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
3288 struct tevent_context *ev,
3289 struct cli_state *cli,
3292 struct tevent_req *req, *subreq;
3293 struct cli_close_state *state;
3296 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
3301 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3302 subreq = cli_smb2_close_fnum_send(state,
3306 if (tevent_req_nomem(subreq, req)) {
3307 return tevent_req_post(req, ev);
3310 struct tevent_req *ch_req = NULL;
3311 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
3312 if (tevent_req_nomem(subreq, req)) {
3313 return tevent_req_post(req, ev);
3315 status = smb1cli_req_chain_submit(&ch_req, 1);
3316 if (tevent_req_nterror(req, status)) {
3317 return tevent_req_post(req, ev);
3321 tevent_req_set_callback(subreq, cli_close_done, req);
3325 static void cli_close_done(struct tevent_req *subreq)
3327 struct tevent_req *req = tevent_req_callback_data(
3328 subreq, struct tevent_req);
3329 NTSTATUS status = NT_STATUS_OK;
3330 bool err = tevent_req_is_nterror(subreq, &status);
3332 TALLOC_FREE(subreq);
3334 tevent_req_nterror(req, status);
3337 tevent_req_done(req);
3340 NTSTATUS cli_close_recv(struct tevent_req *req)
3342 return tevent_req_simple_recv_ntstatus(req);
3345 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
3347 TALLOC_CTX *frame = NULL;
3348 struct tevent_context *ev;
3349 struct tevent_req *req;
3350 NTSTATUS status = NT_STATUS_OK;
3352 frame = talloc_stackframe();
3354 if (smbXcli_conn_has_async_calls(cli->conn)) {
3356 * Can't use sync call while an async call is in flight
3358 status = NT_STATUS_INVALID_PARAMETER;
3362 ev = samba_tevent_context_init(frame);
3364 status = NT_STATUS_NO_MEMORY;
3368 req = cli_close_send(frame, ev, cli, fnum);
3370 status = NT_STATUS_NO_MEMORY;
3374 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3378 status = cli_close_recv(req);
3384 /****************************************************************************
3385 Truncate a file to a specified size
3386 ****************************************************************************/
3388 struct ftrunc_state {
3392 static void cli_ftruncate_done(struct tevent_req *subreq)
3394 NTSTATUS status = cli_setfileinfo_recv(subreq);
3395 tevent_req_simple_finish_ntstatus(subreq, status);
3398 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
3399 struct tevent_context *ev,
3400 struct cli_state *cli,
3404 struct tevent_req *req = NULL, *subreq = NULL;
3405 struct ftrunc_state *state = NULL;
3407 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
3412 /* Setup data array. */
3413 SBVAL(state->data, 0, size);
3415 subreq = cli_setfileinfo_send(
3420 SMB_SET_FILE_END_OF_FILE_INFO,
3422 sizeof(state->data));
3424 if (tevent_req_nomem(subreq, req)) {
3425 return tevent_req_post(req, ev);
3427 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
3431 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
3433 return tevent_req_simple_recv_ntstatus(req);
3436 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3438 TALLOC_CTX *frame = NULL;
3439 struct tevent_context *ev = NULL;
3440 struct tevent_req *req = NULL;
3441 NTSTATUS status = NT_STATUS_OK;
3443 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3444 return cli_smb2_ftruncate(cli, fnum, size);
3447 frame = talloc_stackframe();
3449 if (smbXcli_conn_has_async_calls(cli->conn)) {
3451 * Can't use sync call while an async call is in flight
3453 status = NT_STATUS_INVALID_PARAMETER;
3457 ev = samba_tevent_context_init(frame);
3459 status = NT_STATUS_NO_MEMORY;
3463 req = cli_ftruncate_send(frame,
3469 status = NT_STATUS_NO_MEMORY;
3473 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3477 status = cli_ftruncate_recv(req);
3484 static uint8_t *cli_lockingx_put_locks(
3488 const struct smb1_lock_element *locks)
3492 for (i=0; i<num_locks; i++) {
3493 const struct smb1_lock_element *e = &locks[i];
3495 SSVAL(buf, 0, e->pid);
3497 SOFF_T_R(buf, 4, e->offset);
3498 SOFF_T_R(buf, 12, e->length);
3501 SSVAL(buf, 0, e->pid);
3502 SIVAL(buf, 2, e->offset);
3503 SIVAL(buf, 6, e->length);
3510 struct cli_lockingx_state {
3513 struct tevent_req *subreq;
3516 static void cli_lockingx_done(struct tevent_req *subreq);
3517 static bool cli_lockingx_cancel(struct tevent_req *req);
3519 struct tevent_req *cli_lockingx_create(
3520 TALLOC_CTX *mem_ctx,
3521 struct tevent_context *ev,
3522 struct cli_state *cli,
3525 uint8_t newoplocklevel,
3527 uint16_t num_unlocks,
3528 const struct smb1_lock_element *unlocks,
3530 const struct smb1_lock_element *locks,
3531 struct tevent_req **psmbreq)
3533 struct tevent_req *req = NULL, *subreq = NULL;
3534 struct cli_lockingx_state *state = NULL;
3537 const bool large = (typeoflock & LOCKING_ANDX_LARGE_FILES);
3538 const size_t element_len = large ? 20 : 10;
3540 /* uint16->size_t, no overflow */
3541 const size_t num_elements = (size_t)num_locks + (size_t)num_unlocks;
3543 /* at most 20*2*65535 = 2621400, no overflow */
3544 const size_t num_bytes = num_elements * element_len;
3546 req = tevent_req_create(mem_ctx, &state, struct cli_lockingx_state);
3552 SCVAL(vwv + 0, 0, 0xFF);
3553 SCVAL(vwv + 0, 1, 0);
3554 SSVAL(vwv + 1, 0, 0);
3555 SSVAL(vwv + 2, 0, fnum);
3556 SCVAL(vwv + 3, 0, typeoflock);
3557 SCVAL(vwv + 3, 1, newoplocklevel);
3558 SIVALS(vwv + 4, 0, timeout);
3559 SSVAL(vwv + 6, 0, num_unlocks);
3560 SSVAL(vwv + 7, 0, num_locks);
3562 state->bytes.iov_len = num_bytes;
3563 state->bytes.iov_base = talloc_array(state, uint8_t, num_bytes);
3564 if (tevent_req_nomem(state->bytes.iov_base, req)) {
3565 return tevent_req_post(req, ev);
3568 p = cli_lockingx_put_locks(
3569 state->bytes.iov_base, large, num_unlocks, unlocks);
3570 cli_lockingx_put_locks(p, large, num_locks, locks);
3572 subreq = cli_smb_req_create(
3573 state, ev, cli, SMBlockingX, 0, 0, 8, vwv, 1, &state->bytes);
3574 if (tevent_req_nomem(subreq, req)) {
3575 return tevent_req_post(req, ev);
3577 tevent_req_set_callback(subreq, cli_lockingx_done, req);
3582 struct tevent_req *cli_lockingx_send(
3583 TALLOC_CTX *mem_ctx,
3584 struct tevent_context *ev,
3585 struct cli_state *cli,
3588 uint8_t newoplocklevel,
3590 uint16_t num_unlocks,
3591 const struct smb1_lock_element *unlocks,
3593 const struct smb1_lock_element *locks)
3595 struct tevent_req *req = NULL, *subreq = NULL;
3596 struct cli_lockingx_state *state = NULL;
3599 req = cli_lockingx_create(
3615 state = tevent_req_data(req, struct cli_lockingx_state);
3616 state->subreq = subreq;
3618 status = smb1cli_req_chain_submit(&subreq, 1);
3619 if (tevent_req_nterror(req, status)) {
3620 return tevent_req_post(req, ev);
3622 tevent_req_set_cancel_fn(req, cli_lockingx_cancel);
3626 static void cli_lockingx_done(struct tevent_req *subreq)
3628 NTSTATUS status = cli_smb_recv(
3629 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3630 tevent_req_simple_finish_ntstatus(subreq, status);
3633 static bool cli_lockingx_cancel(struct tevent_req *req)
3635 struct cli_lockingx_state *state = tevent_req_data(
3636 req, struct cli_lockingx_state);
3637 if (state->subreq == NULL) {
3640 return tevent_req_cancel(state->subreq);
3643 NTSTATUS cli_lockingx_recv(struct tevent_req *req)
3645 return tevent_req_simple_recv_ntstatus(req);
3648 NTSTATUS cli_lockingx(
3649 struct cli_state *cli,
3652 uint8_t newoplocklevel,
3654 uint16_t num_unlocks,
3655 const struct smb1_lock_element *unlocks,
3657 const struct smb1_lock_element *locks)
3659 TALLOC_CTX *frame = talloc_stackframe();
3660 struct tevent_context *ev = NULL;
3661 struct tevent_req *req = NULL;
3662 NTSTATUS status = NT_STATUS_NO_MEMORY;
3663 unsigned int set_timeout = 0;
3664 unsigned int saved_timeout = 0;
3666 if (smbXcli_conn_has_async_calls(cli->conn)) {
3667 return NT_STATUS_INVALID_PARAMETER;
3669 ev = samba_tevent_context_init(frame);
3675 if (timeout == -1) {
3676 set_timeout = 0x7FFFFFFF;
3678 set_timeout = timeout + 2*1000;
3680 saved_timeout = cli_set_timeout(cli, set_timeout);
3683 req = cli_lockingx_send(
3698 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3701 status = cli_lockingx_recv(req);
3703 if (saved_timeout != 0) {
3704 cli_set_timeout(cli, saved_timeout);
3711 /****************************************************************************
3712 send a lock with a specified locktype
3713 this is used for testing LOCKING_ANDX_CANCEL_LOCK
3714 ****************************************************************************/
3716 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
3717 uint32_t offset, uint32_t len,
3718 int timeout, unsigned char locktype)
3720 struct smb1_lock_element lck = {
3721 .pid = cli_getpid(cli),
3727 status = cli_lockingx(
3730 locktype, /* typeoflock */
3731 0, /* newoplocklevel */
3732 timeout, /* timeout */
3733 0, /* num_unlocks */
3740 /****************************************************************************
3742 note that timeout is in units of 2 milliseconds
3743 ****************************************************************************/
3745 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
3746 uint32_t offset, uint32_t len, int timeout,
3747 enum brl_type lock_type)
3751 status = cli_locktype(cli, fnum, offset, len, timeout,
3752 (lock_type == READ_LOCK? 1 : 0));
3756 /****************************************************************************
3758 ****************************************************************************/
3760 struct cli_unlock_state {
3761 struct smb1_lock_element lck;
3764 static void cli_unlock_done(struct tevent_req *subreq);
3766 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3767 struct tevent_context *ev,
3768 struct cli_state *cli,
3774 struct tevent_req *req = NULL, *subreq = NULL;
3775 struct cli_unlock_state *state = NULL;
3777 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3781 state->lck = (struct smb1_lock_element) {
3782 .pid = cli_getpid(cli),
3787 subreq = cli_lockingx_send(
3788 state, /* mem_ctx */
3789 ev, /* tevent_context */
3793 0, /* newoplocklevel */
3795 1, /* num_unlocks */
3796 &state->lck, /* unlocks */
3799 if (tevent_req_nomem(subreq, req)) {
3800 return tevent_req_post(req, ev);
3802 tevent_req_set_callback(subreq, cli_unlock_done, req);
3806 static void cli_unlock_done(struct tevent_req *subreq)
3808 NTSTATUS status = cli_lockingx_recv(subreq);
3809 tevent_req_simple_finish_ntstatus(subreq, status);
3812 NTSTATUS cli_unlock_recv(struct tevent_req *req)
3814 return tevent_req_simple_recv_ntstatus(req);
3817 NTSTATUS cli_unlock(struct cli_state *cli,
3822 TALLOC_CTX *frame = talloc_stackframe();
3823 struct tevent_context *ev;
3824 struct tevent_req *req;
3825 NTSTATUS status = NT_STATUS_OK;
3827 if (smbXcli_conn_has_async_calls(cli->conn)) {
3829 * Can't use sync call while an async call is in flight
3831 status = NT_STATUS_INVALID_PARAMETER;
3835 ev = samba_tevent_context_init(frame);
3837 status = NT_STATUS_NO_MEMORY;
3841 req = cli_unlock_send(frame, ev, cli,
3844 status = NT_STATUS_NO_MEMORY;
3848 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3852 status = cli_unlock_recv(req);
3859 /****************************************************************************
3860 Get/unlock a POSIX lock on a file - internal function.
3861 ****************************************************************************/
3863 struct posix_lock_state {
3866 uint8_t data[POSIX_LOCK_DATA_SIZE];
3869 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3871 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3872 NULL, 0, NULL, NULL, 0, NULL);
3873 tevent_req_simple_finish_ntstatus(subreq, status);
3876 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3877 struct tevent_context *ev,
3878 struct cli_state *cli,
3883 enum brl_type lock_type)
3885 struct tevent_req *req = NULL, *subreq = NULL;
3886 struct posix_lock_state *state = NULL;
3888 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3893 /* Setup setup word. */
3894 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3896 /* Setup param array. */
3897 SSVAL(&state->param, 0, fnum);
3898 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3900 /* Setup data array. */
3901 switch (lock_type) {
3903 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3904 POSIX_LOCK_TYPE_READ);
3907 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3908 POSIX_LOCK_TYPE_WRITE);
3911 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3912 POSIX_LOCK_TYPE_UNLOCK);
3919 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3920 POSIX_LOCK_FLAG_WAIT);
3922 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3923 POSIX_LOCK_FLAG_NOWAIT);
3926 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3927 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3928 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3930 subreq = cli_trans_send(state, /* mem ctx. */
3931 ev, /* event ctx. */
3932 cli, /* cli_state. */
3933 0, /* additional_flags2 */
3934 SMBtrans2, /* cmd. */
3935 NULL, /* pipe name. */
3939 &state->setup, /* setup. */
3940 1, /* num setup uint16_t words. */
3941 0, /* max returned setup. */
3942 state->param, /* param. */
3944 2, /* max returned param. */
3945 state->data, /* data. */
3946 POSIX_LOCK_DATA_SIZE, /* num data. */
3947 0); /* max returned data. */
3949 if (tevent_req_nomem(subreq, req)) {
3950 return tevent_req_post(req, ev);
3952 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3956 /****************************************************************************
3958 ****************************************************************************/
3960 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3961 struct tevent_context *ev,
3962 struct cli_state *cli,
3967 enum brl_type lock_type)
3969 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3970 wait_lock, lock_type);
3973 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3975 return tevent_req_simple_recv_ntstatus(req);
3978 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3979 uint64_t offset, uint64_t len,
3980 bool wait_lock, enum brl_type lock_type)
3982 TALLOC_CTX *frame = talloc_stackframe();
3983 struct tevent_context *ev = NULL;
3984 struct tevent_req *req = NULL;
3985 NTSTATUS status = NT_STATUS_OK;
3987 if (smbXcli_conn_has_async_calls(cli->conn)) {
3989 * Can't use sync call while an async call is in flight
3991 status = NT_STATUS_INVALID_PARAMETER;
3995 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3996 status = NT_STATUS_INVALID_PARAMETER;
4000 ev = samba_tevent_context_init(frame);
4002 status = NT_STATUS_NO_MEMORY;
4006 req = cli_posix_lock_send(frame,
4015 status = NT_STATUS_NO_MEMORY;
4019 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4023 status = cli_posix_lock_recv(req);
4030 /****************************************************************************
4031 POSIX Unlock a file.
4032 ****************************************************************************/
4034 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
4035 struct tevent_context *ev,
4036 struct cli_state *cli,
4041 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4042 false, UNLOCK_LOCK);
4045 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
4047 return tevent_req_simple_recv_ntstatus(req);
4050 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
4052 TALLOC_CTX *frame = talloc_stackframe();
4053 struct tevent_context *ev = NULL;
4054 struct tevent_req *req = NULL;
4055 NTSTATUS status = NT_STATUS_OK;
4057 if (smbXcli_conn_has_async_calls(cli->conn)) {
4059 * Can't use sync call while an async call is in flight
4061 status = NT_STATUS_INVALID_PARAMETER;
4065 ev = samba_tevent_context_init(frame);
4067 status = NT_STATUS_NO_MEMORY;
4071 req = cli_posix_unlock_send(frame,
4078 status = NT_STATUS_NO_MEMORY;
4082 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4086 status = cli_posix_unlock_recv(req);
4093 /****************************************************************************
4094 Do a SMBgetattrE call.
4095 ****************************************************************************/
4097 static void cli_getattrE_done(struct tevent_req *subreq);
4099 struct cli_getattrE_state {
4109 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
4110 struct tevent_context *ev,
4111 struct cli_state *cli,
4114 struct tevent_req *req = NULL, *subreq = NULL;
4115 struct cli_getattrE_state *state = NULL;
4116 uint8_t additional_flags = 0;
4118 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
4123 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4124 SSVAL(state->vwv+0,0,fnum);
4126 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
4127 1, state->vwv, 0, NULL);
4128 if (tevent_req_nomem(subreq, req)) {
4129 return tevent_req_post(req, ev);
4131 tevent_req_set_callback(subreq, cli_getattrE_done, req);
4135 static void cli_getattrE_done(struct tevent_req *subreq)
4137 struct tevent_req *req = tevent_req_callback_data(
4138 subreq, struct tevent_req);
4139 struct cli_getattrE_state *state = tevent_req_data(
4140 req, struct cli_getattrE_state);
4142 uint16_t *vwv = NULL;
4145 status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
4147 TALLOC_FREE(subreq);
4148 if (tevent_req_nterror(req, status)) {
4152 state->size = (off_t)IVAL(vwv+6,0);
4153 state->attr = SVAL(vwv+10,0);
4154 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
4155 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
4156 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
4158 tevent_req_done(req);
4161 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
4164 time_t *change_time,
4165 time_t *access_time,
4168 struct cli_getattrE_state *state = tevent_req_data(
4169 req, struct cli_getattrE_state);
4172 if (tevent_req_is_nterror(req, &status)) {
4176 *pattr = state->attr;
4179 *size = state->size;
4182 *change_time = state->change_time;
4185 *access_time = state->access_time;
4188 *write_time = state->write_time;
4190 return NT_STATUS_OK;
4193 /****************************************************************************
4195 ****************************************************************************/
4197 static void cli_getatr_done(struct tevent_req *subreq);
4199 struct cli_getatr_state {
4206 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
4207 struct tevent_context *ev,
4208 struct cli_state *cli,
4211 struct tevent_req *req = NULL, *subreq = NULL;
4212 struct cli_getatr_state *state = NULL;
4213 uint8_t additional_flags = 0;
4214 uint16_t additional_flags2 = 0;
4215 uint8_t *bytes = NULL;
4217 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
4222 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4224 bytes = talloc_array(state, uint8_t, 1);
4225 if (tevent_req_nomem(bytes, req)) {
4226 return tevent_req_post(req, ev);
4229 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4230 strlen(fname)+1, NULL);
4232 if (tevent_req_nomem(bytes, req)) {
4233 return tevent_req_post(req, ev);
4236 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4237 additional_flags2 = FLAGS2_REPARSE_PATH;
4240 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
4242 0, NULL, talloc_get_size(bytes), bytes);
4243 if (tevent_req_nomem(subreq, req)) {
4244 return tevent_req_post(req, ev);
4246 tevent_req_set_callback(subreq, cli_getatr_done, req);
4250 static void cli_getatr_done(struct tevent_req *subreq)
4252 struct tevent_req *req = tevent_req_callback_data(
4253 subreq, struct tevent_req);
4254 struct cli_getatr_state *state = tevent_req_data(
4255 req, struct cli_getatr_state);
4257 uint16_t *vwv = NULL;
4260 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4262 TALLOC_FREE(subreq);
4263 if (tevent_req_nterror(req, status)) {
4267 state->attr = SVAL(vwv+0,0);
4268 state->size = (off_t)IVAL(vwv+3,0);
4269 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
4271 tevent_req_done(req);
4274 NTSTATUS cli_getatr_recv(struct tevent_req *req,
4279 struct cli_getatr_state *state = tevent_req_data(
4280 req, struct cli_getatr_state);
4283 if (tevent_req_is_nterror(req, &status)) {
4287 *pattr = state->attr;
4290 *size = state->size;
4293 *write_time = state->write_time;
4295 return NT_STATUS_OK;
4298 NTSTATUS cli_getatr(struct cli_state *cli,
4304 TALLOC_CTX *frame = NULL;
4305 struct tevent_context *ev = NULL;
4306 struct tevent_req *req = NULL;
4307 NTSTATUS status = NT_STATUS_OK;
4309 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4310 return cli_smb2_getatr(cli,
4317 frame = talloc_stackframe();
4319 if (smbXcli_conn_has_async_calls(cli->conn)) {
4321 * Can't use sync call while an async call is in flight
4323 status = NT_STATUS_INVALID_PARAMETER;
4327 ev = samba_tevent_context_init(frame);
4329 status = NT_STATUS_NO_MEMORY;
4333 req = cli_getatr_send(frame, ev, cli, fname);
4335 status = NT_STATUS_NO_MEMORY;
4339 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4343 status = cli_getatr_recv(req,
4353 /****************************************************************************
4354 Do a SMBsetattrE call.
4355 ****************************************************************************/
4357 static void cli_setattrE_done(struct tevent_req *subreq);
4359 struct cli_setattrE_state {
4363 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
4364 struct tevent_context *ev,
4365 struct cli_state *cli,
4371 struct tevent_req *req = NULL, *subreq = NULL;
4372 struct cli_setattrE_state *state = NULL;
4373 uint8_t additional_flags = 0;
4375 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
4380 SSVAL(state->vwv+0, 0, fnum);
4381 push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
4382 smb1cli_conn_server_time_zone(cli->conn));
4383 push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
4384 smb1cli_conn_server_time_zone(cli->conn));
4385 push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
4386 smb1cli_conn_server_time_zone(cli->conn));
4388 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
4389 7, state->vwv, 0, NULL);
4390 if (tevent_req_nomem(subreq, req)) {
4391 return tevent_req_post(req, ev);
4393 tevent_req_set_callback(subreq, cli_setattrE_done, req);
4397 static void cli_setattrE_done(struct tevent_req *subreq)
4399 struct tevent_req *req = tevent_req_callback_data(
4400 subreq, struct tevent_req);
4403 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4404 TALLOC_FREE(subreq);
4405 if (tevent_req_nterror(req, status)) {
4408 tevent_req_done(req);
4411 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4413 return tevent_req_simple_recv_ntstatus(req);
4416 NTSTATUS cli_setattrE(struct cli_state *cli,
4422 TALLOC_CTX *frame = NULL;
4423 struct tevent_context *ev = NULL;
4424 struct tevent_req *req = NULL;
4425 NTSTATUS status = NT_STATUS_OK;
4427 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4428 return cli_smb2_setattrE(cli,
4435 frame = talloc_stackframe();
4437 if (smbXcli_conn_has_async_calls(cli->conn)) {
4439 * Can't use sync call while an async call is in flight
4441 status = NT_STATUS_INVALID_PARAMETER;
4445 ev = samba_tevent_context_init(frame);
4447 status = NT_STATUS_NO_MEMORY;
4451 req = cli_setattrE_send(frame, ev,
4459 status = NT_STATUS_NO_MEMORY;
4463 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4467 status = cli_setattrE_recv(req);
4474 /****************************************************************************
4475 Do a SMBsetatr call.
4476 ****************************************************************************/
4478 static void cli_setatr_done(struct tevent_req *subreq);
4480 struct cli_setatr_state {
4484 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
4485 struct tevent_context *ev,
4486 struct cli_state *cli,
4491 struct tevent_req *req = NULL, *subreq = NULL;
4492 struct cli_setatr_state *state = NULL;
4493 uint8_t additional_flags = 0;
4494 uint16_t additional_flags2 = 0;
4495 uint8_t *bytes = NULL;
4497 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
4502 if (attr & 0xFFFF0000) {
4504 * Don't allow attributes greater than
4505 * 16-bits for a 16-bit protocol value.
4507 if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
4508 return tevent_req_post(req, ev);
4512 SSVAL(state->vwv+0, 0, attr);
4513 push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
4515 bytes = talloc_array(state, uint8_t, 1);
4516 if (tevent_req_nomem(bytes, req)) {
4517 return tevent_req_post(req, ev);
4520 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4521 strlen(fname)+1, NULL);
4522 if (tevent_req_nomem(bytes, req)) {
4523 return tevent_req_post(req, ev);
4525 bytes = talloc_realloc(state, bytes, uint8_t,
4526 talloc_get_size(bytes)+1);
4527 if (tevent_req_nomem(bytes, req)) {
4528 return tevent_req_post(req, ev);
4531 bytes[talloc_get_size(bytes)-1] = 4;
4532 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
4534 if (tevent_req_nomem(bytes, req)) {
4535 return tevent_req_post(req, ev);
4538 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4539 additional_flags2 = FLAGS2_REPARSE_PATH;
4542 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
4544 8, state->vwv, talloc_get_size(bytes), bytes);
4545 if (tevent_req_nomem(subreq, req)) {
4546 return tevent_req_post(req, ev);
4548 tevent_req_set_callback(subreq, cli_setatr_done, req);
4552 static void cli_setatr_done(struct tevent_req *subreq)
4554 struct tevent_req *req = tevent_req_callback_data(
4555 subreq, struct tevent_req);
4558 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4559 TALLOC_FREE(subreq);
4560 if (tevent_req_nterror(req, status)) {
4563 tevent_req_done(req);
4566 NTSTATUS cli_setatr_recv(struct tevent_req *req)
4568 return tevent_req_simple_recv_ntstatus(req);
4571 NTSTATUS cli_setatr(struct cli_state *cli,
4576 TALLOC_CTX *frame = NULL;
4577 struct tevent_context *ev = NULL;
4578 struct tevent_req *req = NULL;
4579 NTSTATUS status = NT_STATUS_OK;
4581 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4582 return cli_smb2_setatr(cli,
4588 frame = talloc_stackframe();
4590 if (smbXcli_conn_has_async_calls(cli->conn)) {
4592 * Can't use sync call while an async call is in flight
4594 status = NT_STATUS_INVALID_PARAMETER;
4598 ev = samba_tevent_context_init(frame);
4600 status = NT_STATUS_NO_MEMORY;
4604 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
4606 status = NT_STATUS_NO_MEMORY;
4610 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4614 status = cli_setatr_recv(req);
4621 /****************************************************************************
4622 Check for existence of a dir.
4623 ****************************************************************************/
4625 static void cli_chkpath_done(struct tevent_req *subreq);
4626 static void cli_chkpath_opened(struct tevent_req *subreq);
4627 static void cli_chkpath_closed(struct tevent_req *subreq);
4629 struct cli_chkpath_state {
4630 struct tevent_context *ev;
4631 struct cli_state *cli;
4634 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
4635 struct tevent_context *ev,
4636 struct cli_state *cli,
4639 struct tevent_req *req = NULL, *subreq = NULL;
4640 struct cli_chkpath_state *state = NULL;
4641 uint8_t additional_flags = 0;
4642 uint16_t additional_flags2 = 0;
4643 uint8_t *bytes = NULL;
4645 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
4652 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_NT1) {
4653 subreq = cli_ntcreate_send(
4654 state, /* mem_ctx */
4656 state->cli, /* cli */
4658 0, /* create_flags */
4659 FILE_READ_ATTRIBUTES, /* desired_access */
4660 FILE_ATTRIBUTE_DIRECTORY, /* FileAttributes */
4663 FILE_SHARE_DELETE, /* share_access */
4664 FILE_OPEN, /* CreateDisposition */
4665 FILE_DIRECTORY_FILE, /* CreateOptions */
4666 SMB2_IMPERSONATION_IMPERSONATION,
4667 0); /* SecurityFlags */
4668 if (tevent_req_nomem(subreq, req)) {
4669 return tevent_req_post(req, ev);
4671 tevent_req_set_callback(subreq, cli_chkpath_opened, req);
4675 bytes = talloc_array(state, uint8_t, 1);
4676 if (tevent_req_nomem(bytes, req)) {
4677 return tevent_req_post(req, ev);
4680 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4681 strlen(fname)+1, NULL);
4683 if (tevent_req_nomem(bytes, req)) {
4684 return tevent_req_post(req, ev);
4687 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4688 additional_flags2 = FLAGS2_REPARSE_PATH;
4691 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
4693 0, NULL, talloc_get_size(bytes), bytes);
4694 if (tevent_req_nomem(subreq, req)) {
4695 return tevent_req_post(req, ev);
4697 tevent_req_set_callback(subreq, cli_chkpath_done, req);
4701 static void cli_chkpath_done(struct tevent_req *subreq)
4703 NTSTATUS status = cli_smb_recv(
4704 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4705 tevent_req_simple_finish_ntstatus(subreq, status);
4708 static void cli_chkpath_opened(struct tevent_req *subreq)
4710 struct tevent_req *req = tevent_req_callback_data(
4711 subreq, struct tevent_req);
4712 struct cli_chkpath_state *state = tevent_req_data(
4713 req, struct cli_chkpath_state);
4717 status = cli_ntcreate_recv(subreq, &fnum, NULL);
4718 TALLOC_FREE(subreq);
4719 if (tevent_req_nterror(req, status)) {
4723 subreq = cli_close_send(state, state->ev, state->cli, fnum);
4724 if (tevent_req_nomem(subreq, req)) {
4727 tevent_req_set_callback(subreq, cli_chkpath_closed, req);
4730 static void cli_chkpath_closed(struct tevent_req *subreq)
4732 NTSTATUS status = cli_close_recv(subreq);
4733 tevent_req_simple_finish_ntstatus(subreq, status);
4736 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
4738 return tevent_req_simple_recv_ntstatus(req);
4741 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
4743 TALLOC_CTX *frame = NULL;
4744 struct tevent_context *ev = NULL;
4745 struct tevent_req *req = NULL;
4747 NTSTATUS status = NT_STATUS_OK;
4749 frame = talloc_stackframe();
4751 if (smbXcli_conn_has_async_calls(cli->conn)) {
4753 * Can't use sync call while an async call is in flight
4755 status = NT_STATUS_INVALID_PARAMETER;
4759 path2 = talloc_strdup(frame, path);
4761 status = NT_STATUS_NO_MEMORY;
4764 trim_char(path2,'\0','\\');
4766 path2 = talloc_strdup(frame, "\\");
4768 status = NT_STATUS_NO_MEMORY;
4773 ev = samba_tevent_context_init(frame);
4775 status = NT_STATUS_NO_MEMORY;
4779 req = cli_chkpath_send(frame, ev, cli, path2);
4781 status = NT_STATUS_NO_MEMORY;
4785 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4789 status = cli_chkpath_recv(req);
4790 cli->raw_status = status; /* cli_smb2_chkpath_recv doesn't set this */
4797 /****************************************************************************
4799 ****************************************************************************/
4801 static void cli_dskattr_done(struct tevent_req *subreq);
4803 struct cli_dskattr_state {
4809 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
4810 struct tevent_context *ev,
4811 struct cli_state *cli)
4813 struct tevent_req *req = NULL, *subreq = NULL;
4814 struct cli_dskattr_state *state = NULL;
4815 uint8_t additional_flags = 0;
4817 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
4822 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
4824 if (tevent_req_nomem(subreq, req)) {
4825 return tevent_req_post(req, ev);
4827 tevent_req_set_callback(subreq, cli_dskattr_done, req);
4831 static void cli_dskattr_done(struct tevent_req *subreq)
4833 struct tevent_req *req = tevent_req_callback_data(
4834 subreq, struct tevent_req);
4835 struct cli_dskattr_state *state = tevent_req_data(
4836 req, struct cli_dskattr_state);
4838 uint16_t *vwv = NULL;
4841 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4843 TALLOC_FREE(subreq);
4844 if (tevent_req_nterror(req, status)) {
4847 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
4848 state->total = SVAL(vwv+0, 0);
4849 state->avail = SVAL(vwv+3, 0);
4850 tevent_req_done(req);
4853 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
4855 struct cli_dskattr_state *state = tevent_req_data(
4856 req, struct cli_dskattr_state);
4859 if (tevent_req_is_nterror(req, &status)) {
4862 *bsize = state->bsize;
4863 *total = state->total;
4864 *avail = state->avail;
4865 return NT_STATUS_OK;
4868 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
4870 TALLOC_CTX *frame = NULL;
4871 struct tevent_context *ev = NULL;
4872 struct tevent_req *req = NULL;
4873 NTSTATUS status = NT_STATUS_OK;
4875 frame = talloc_stackframe();
4877 if (smbXcli_conn_has_async_calls(cli->conn)) {
4879 * Can't use sync call while an async call is in flight
4881 status = NT_STATUS_INVALID_PARAMETER;
4885 ev = samba_tevent_context_init(frame);
4887 status = NT_STATUS_NO_MEMORY;
4891 req = cli_dskattr_send(frame, ev, cli);
4893 status = NT_STATUS_NO_MEMORY;
4897 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4901 status = cli_dskattr_recv(req, bsize, total, avail);
4908 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
4909 uint64_t *total, uint64_t *avail)
4911 uint64_t sectors_per_block;
4912 uint64_t bytes_per_sector;
4913 int old_bsize = 0, old_total = 0, old_avail = 0;
4916 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4917 return cli_smb2_dskattr(cli, path, bsize, total, avail);
4921 * Try the trans2 disk full size info call first.
4922 * We already use this in SMBC_fstatvfs_ctx().
4923 * Ignore 'actual_available_units' as we only
4924 * care about the quota for the caller.
4927 status = cli_get_fs_full_size_info(cli,
4934 /* Try and cope will all varients of "we don't do this call"
4935 and fall back to cli_dskattr. */
4937 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
4938 NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
4939 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
4940 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
4941 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
4942 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
4943 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
4944 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
4945 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
4946 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
4950 if (!NT_STATUS_IS_OK(status)) {
4955 *bsize = sectors_per_block *
4959 return NT_STATUS_OK;
4963 /* Old SMB1 core protocol fallback. */
4964 status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
4965 if (!NT_STATUS_IS_OK(status)) {
4969 *bsize = (uint64_t)old_bsize;
4972 *total = (uint64_t)old_total;
4975 *avail = (uint64_t)old_avail;
4977 return NT_STATUS_OK;
4980 /****************************************************************************
4981 Create and open a temporary file.
4982 ****************************************************************************/
4984 static void cli_ctemp_done(struct tevent_req *subreq);
4986 struct ctemp_state {
4992 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4993 struct tevent_context *ev,
4994 struct cli_state *cli,
4997 struct tevent_req *req = NULL, *subreq = NULL;
4998 struct ctemp_state *state = NULL;
4999 uint8_t additional_flags = 0;
5000 uint16_t additional_flags2 = 0;
5001 uint8_t *bytes = NULL;
5003 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
5008 SSVAL(state->vwv,0,0);
5009 SIVALS(state->vwv+1,0,-1);
5011 bytes = talloc_array(state, uint8_t, 1);
5012 if (tevent_req_nomem(bytes, req)) {
5013 return tevent_req_post(req, ev);
5016 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
5017 strlen(path)+1, NULL);
5018 if (tevent_req_nomem(bytes, req)) {
5019 return tevent_req_post(req, ev);
5022 if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
5023 additional_flags2 = FLAGS2_REPARSE_PATH;
5026 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
5028 3, state->vwv, talloc_get_size(bytes), bytes);
5029 if (tevent_req_nomem(subreq, req)) {
5030 return tevent_req_post(req, ev);
5032 tevent_req_set_callback(subreq, cli_ctemp_done, req);
5036 static void cli_ctemp_done(struct tevent_req *subreq)
5038 struct tevent_req *req = tevent_req_callback_data(
5039 subreq, struct tevent_req);
5040 struct ctemp_state *state = tevent_req_data(
5041 req, struct ctemp_state);
5045 uint32_t num_bytes = 0;
5046 uint8_t *bytes = NULL;
5048 status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
5049 &num_bytes, &bytes);
5050 TALLOC_FREE(subreq);
5051 if (tevent_req_nterror(req, status)) {
5055 state->fnum = SVAL(vwv+0, 0);
5057 /* From W2K3, the result is just the ASCII name */
5058 if (num_bytes < 2) {
5059 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
5063 if (pull_string_talloc(state,
5070 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5073 tevent_req_done(req);
5076 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
5081 struct ctemp_state *state = tevent_req_data(req,
5082 struct ctemp_state);
5085 if (tevent_req_is_nterror(req, &status)) {
5088 *pfnum = state->fnum;
5089 *outfile = talloc_strdup(ctx, state->ret_path);
5091 return NT_STATUS_NO_MEMORY;
5093 return NT_STATUS_OK;
5096 NTSTATUS cli_ctemp(struct cli_state *cli,
5102 TALLOC_CTX *frame = talloc_stackframe();
5103 struct tevent_context *ev;
5104 struct tevent_req *req;
5105 NTSTATUS status = NT_STATUS_OK;
5107 if (smbXcli_conn_has_async_calls(cli->conn)) {
5109 * Can't use sync call while an async call is in flight
5111 status = NT_STATUS_INVALID_PARAMETER;
5115 ev = samba_tevent_context_init(frame);
5117 status = NT_STATUS_NO_MEMORY;
5121 req = cli_ctemp_send(frame, ev, cli, path);
5123 status = NT_STATUS_NO_MEMORY;
5127 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5131 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
5139 send a raw ioctl - used by the torture code
5141 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
5146 SSVAL(vwv+0, 0, fnum);
5147 SSVAL(vwv+1, 0, code>>16);
5148 SSVAL(vwv+2, 0, (code&0xFFFF));
5150 status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
5151 NULL, 0, NULL, NULL, NULL, NULL);
5152 if (!NT_STATUS_IS_OK(status)) {
5155 *blob = data_blob_null;
5156 return NT_STATUS_OK;
5159 /*********************************************************
5160 Set an extended attribute utility fn.
5161 *********************************************************/
5163 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
5164 uint8_t *param, unsigned int param_len,
5165 const char *ea_name,
5166 const char *ea_val, size_t ea_len)
5169 unsigned int data_len = 0;
5170 uint8_t *data = NULL;
5172 size_t ea_namelen = strlen(ea_name);
5175 SSVAL(setup, 0, setup_val);
5177 if (ea_namelen == 0 && ea_len == 0) {
5179 data = talloc_array(talloc_tos(),
5183 return NT_STATUS_NO_MEMORY;
5186 SIVAL(p,0,data_len);
5188 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
5189 data = talloc_array(talloc_tos(),
5193 return NT_STATUS_NO_MEMORY;
5196 SIVAL(p,0,data_len);
5198 SCVAL(p, 0, 0); /* EA flags. */
5199 SCVAL(p, 1, ea_namelen);
5200 SSVAL(p, 2, ea_len);
5201 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
5202 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
5206 * FIXME - if we want to do previous version path
5207 * processing on an EA set call we need to turn this
5208 * into calls to cli_trans_send()/cli_trans_recv()
5209 * with a temporary event context, as cli_trans_send()
5210 * have access to the additional_flags2 needed to
5211 * send @GMT- paths. JRA.
5214 status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
5216 param, param_len, 2,
5219 NULL, 0, NULL, /* rsetup */
5220 NULL, 0, NULL, /* rparam */
5221 NULL, 0, NULL); /* rdata */
5226 /*********************************************************
5227 Set an extended attribute on a pathname.
5228 *********************************************************/
5230 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
5231 const char *ea_name, const char *ea_val,
5234 unsigned int param_len = 0;
5237 TALLOC_CTX *frame = NULL;
5239 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5240 return cli_smb2_set_ea_path(cli,
5247 frame = talloc_stackframe();
5249 param = talloc_array(frame, uint8_t, 6);
5251 status = NT_STATUS_NO_MEMORY;
5254 SSVAL(param,0,SMB_INFO_SET_EA);
5258 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
5259 path, strlen(path)+1,
5261 param_len = talloc_get_size(param);
5263 status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
5264 ea_name, ea_val, ea_len);
5272 /*********************************************************
5273 Set an extended attribute on an fnum.
5274 *********************************************************/
5276 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
5277 const char *ea_name, const char *ea_val,
5280 uint8_t param[6] = { 0, };
5282 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5283 return cli_smb2_set_ea_fnum(cli,
5290 SSVAL(param,0,fnum);
5291 SSVAL(param,2,SMB_INFO_SET_EA);
5293 return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
5294 ea_name, ea_val, ea_len);
5297 /*********************************************************
5298 Get an extended attribute list utility fn.
5299 *********************************************************/
5301 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
5303 size_t *pnum_eas, struct ea_struct **pea_list)
5305 struct ea_struct *ea_list = NULL;
5310 if (rdata_len < 4) {
5314 ea_size = (size_t)IVAL(rdata,0);
5315 if (ea_size > rdata_len) {
5320 /* No EA's present. */
5329 /* Validate the EA list and count it. */
5330 for (num_eas = 0; ea_size >= 4; num_eas++) {
5331 unsigned int ea_namelen = CVAL(p,1);
5332 unsigned int ea_valuelen = SVAL(p,2);
5333 if (ea_namelen == 0) {
5336 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
5339 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
5340 p += 4 + ea_namelen + 1 + ea_valuelen;
5349 *pnum_eas = num_eas;
5351 /* Caller only wants number of EA's. */
5355 ea_list = talloc_array(ctx, struct ea_struct, num_eas);
5362 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
5363 struct ea_struct *ea = &ea_list[num_eas];
5364 fstring unix_ea_name;
5365 unsigned int ea_namelen = CVAL(p,1);
5366 unsigned int ea_valuelen = SVAL(p,2);
5368 ea->flags = CVAL(p,0);
5369 unix_ea_name[0] = '\0';
5370 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
5371 ea->name = talloc_strdup(ea_list, unix_ea_name);
5375 /* Ensure the value is null terminated (in case it's a string). */
5376 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
5377 if (!ea->value.data) {
5381 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
5383 ea->value.data[ea_valuelen] = 0;
5385 p += 4 + ea_namelen + 1 + ea_valuelen;
5388 *pea_list = ea_list;
5392 TALLOC_FREE(ea_list);
5396 /*********************************************************
5397 Get an extended attribute list from a pathname.
5398 *********************************************************/
5400 struct cli_get_ea_list_path_state {
5405 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
5407 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
5408 struct tevent_context *ev,
5409 struct cli_state *cli,
5412 struct tevent_req *req, *subreq;
5413 struct cli_get_ea_list_path_state *state;
5415 req = tevent_req_create(mem_ctx, &state,
5416 struct cli_get_ea_list_path_state);
5420 subreq = cli_qpathinfo_send(state, ev, cli, fname,
5421 SMB_INFO_QUERY_ALL_EAS, 4,
5423 if (tevent_req_nomem(subreq, req)) {
5424 return tevent_req_post(req, ev);
5426 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
5430 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
5432 struct tevent_req *req = tevent_req_callback_data(
5433 subreq, struct tevent_req);
5434 struct cli_get_ea_list_path_state *state = tevent_req_data(
5435 req, struct cli_get_ea_list_path_state);
5438 status = cli_qpathinfo_recv(subreq, state, &state->data,
5440 TALLOC_FREE(subreq);
5441 if (tevent_req_nterror(req, status)) {
5444 tevent_req_done(req);
5447 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5448 size_t *pnum_eas, struct ea_struct **peas)
5450 struct cli_get_ea_list_path_state *state = tevent_req_data(
5451 req, struct cli_get_ea_list_path_state);
5454 if (tevent_req_is_nterror(req, &status)) {
5457 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
5459 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5461 return NT_STATUS_OK;
5464 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
5467 struct ea_struct **pea_list)
5469 TALLOC_CTX *frame = NULL;
5470 struct tevent_context *ev = NULL;
5471 struct tevent_req *req = NULL;
5472 NTSTATUS status = NT_STATUS_NO_MEMORY;
5474 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5475 return cli_smb2_get_ea_list_path(cli,
5482 frame = talloc_stackframe();
5484 if (smbXcli_conn_has_async_calls(cli->conn)) {
5486 * Can't use sync call while an async call is in flight
5488 status = NT_STATUS_INVALID_PARAMETER;
5491 ev = samba_tevent_context_init(frame);
5495 req = cli_get_ea_list_path_send(frame, ev, cli, path);
5499 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5502 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
5508 /****************************************************************************
5509 Convert open "flags" arg to uint32_t on wire.
5510 ****************************************************************************/
5512 static uint32_t open_flags_to_wire(int flags)
5514 int open_mode = flags & O_ACCMODE;
5517 switch (open_mode) {
5519 ret |= SMB_O_WRONLY;
5526 ret |= SMB_O_RDONLY;
5530 if (flags & O_CREAT) {
5533 if (flags & O_EXCL) {
5536 if (flags & O_TRUNC) {
5540 if (flags & O_SYNC) {
5544 if (flags & O_APPEND) {
5545 ret |= SMB_O_APPEND;
5547 #if defined(O_DIRECT)
5548 if (flags & O_DIRECT) {
5549 ret |= SMB_O_DIRECT;
5552 #if defined(O_DIRECTORY)
5553 if (flags & O_DIRECTORY) {
5554 ret |= SMB_O_DIRECTORY;
5560 /****************************************************************************
5561 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
5562 ****************************************************************************/
5564 struct cli_posix_open_internal_state {
5568 uint16_t fnum; /* Out */
5571 static void cli_posix_open_internal_done(struct tevent_req *subreq);
5573 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
5574 struct tevent_context *ev,
5575 struct cli_state *cli,
5577 uint32_t wire_flags,
5580 struct tevent_req *req = NULL, *subreq = NULL;
5581 struct cli_posix_open_internal_state *state = NULL;
5583 req = tevent_req_create(
5584 mem_ctx, &state, struct cli_posix_open_internal_state);
5589 /* Setup setup word. */
5590 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
5592 /* Setup param array. */
5593 state->param = talloc_zero_array(state, uint8_t, 6);
5594 if (tevent_req_nomem(state->param, req)) {
5595 return tevent_req_post(req, ev);
5597 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
5599 state->param = trans2_bytes_push_str(
5601 smbXcli_conn_use_unicode(cli->conn),
5606 if (tevent_req_nomem(state->param, req)) {
5607 return tevent_req_post(req, ev);
5610 SIVAL(state->data,0,0); /* No oplock. */
5611 SIVAL(state->data,4,wire_flags);
5612 SIVAL(state->data,8,unix_perms_to_wire(mode));
5613 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
5614 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
5616 subreq = cli_trans_send(state, /* mem ctx. */
5617 ev, /* event ctx. */
5618 cli, /* cli_state. */
5619 0, /* additional_flags2 */
5620 SMBtrans2, /* cmd. */
5621 NULL, /* pipe name. */
5625 &state->setup, /* setup. */
5626 1, /* num setup uint16_t words. */
5627 0, /* max returned setup. */
5628 state->param, /* param. */
5629 talloc_get_size(state->param),/* num param. */
5630 2, /* max returned param. */
5631 state->data, /* data. */
5633 12); /* max returned data. */
5635 if (tevent_req_nomem(subreq, req)) {
5636 return tevent_req_post(req, ev);
5638 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
5642 static void cli_posix_open_internal_done(struct tevent_req *subreq)
5644 struct tevent_req *req = tevent_req_callback_data(
5645 subreq, struct tevent_req);
5646 struct cli_posix_open_internal_state *state = tevent_req_data(
5647 req, struct cli_posix_open_internal_state);
5652 status = cli_trans_recv(
5665 TALLOC_FREE(subreq);
5666 if (tevent_req_nterror(req, status)) {
5669 state->fnum = SVAL(data,2);
5670 tevent_req_done(req);
5673 static NTSTATUS cli_posix_open_internal_recv(struct tevent_req *req,
5676 struct cli_posix_open_internal_state *state = tevent_req_data(
5677 req, struct cli_posix_open_internal_state);
5680 if (tevent_req_is_nterror(req, &status)) {
5683 *pfnum = state->fnum;
5684 return NT_STATUS_OK;
5687 struct cli_posix_open_state {
5691 static void cli_posix_open_done(struct tevent_req *subreq);
5693 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
5694 struct tevent_context *ev,
5695 struct cli_state *cli,
5700 struct tevent_req *req = NULL, *subreq = NULL;
5701 struct cli_posix_open_state *state = NULL;
5702 uint32_t wire_flags;
5704 req = tevent_req_create(mem_ctx, &state,
5705 struct cli_posix_open_state);
5710 wire_flags = open_flags_to_wire(flags);
5712 subreq = cli_posix_open_internal_send(
5713 mem_ctx, ev, cli, fname, wire_flags, mode);
5714 if (tevent_req_nomem(subreq, req)) {
5715 return tevent_req_post(req, ev);
5717 tevent_req_set_callback(subreq, cli_posix_open_done, req);
5721 static void cli_posix_open_done(struct tevent_req *subreq)
5723 struct tevent_req *req = tevent_req_callback_data(
5724 subreq, struct tevent_req);
5725 struct cli_posix_open_state *state = tevent_req_data(
5726 req, struct cli_posix_open_state);
5729 status = cli_posix_open_internal_recv(subreq, &state->fnum);
5730 tevent_req_simple_finish_ntstatus(subreq, status);
5733 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
5735 struct cli_posix_open_state *state = tevent_req_data(
5736 req, struct cli_posix_open_state);
5739 if (tevent_req_is_nterror(req, &status)) {
5742 *pfnum = state->fnum;
5743 return NT_STATUS_OK;
5746 /****************************************************************************
5747 Open - POSIX semantics. Doesn't request oplock.
5748 ****************************************************************************/
5750 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
5751 int flags, mode_t mode, uint16_t *pfnum)
5754 TALLOC_CTX *frame = talloc_stackframe();
5755 struct tevent_context *ev = NULL;
5756 struct tevent_req *req = NULL;
5757 NTSTATUS status = NT_STATUS_NO_MEMORY;
5759 if (smbXcli_conn_has_async_calls(cli->conn)) {
5761 * Can't use sync call while an async call is in flight
5763 status = NT_STATUS_INVALID_PARAMETER;
5766 ev = samba_tevent_context_init(frame);
5770 req = cli_posix_open_send(
5771 frame, ev, cli, fname, flags, mode);
5775 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5778 status = cli_posix_open_recv(req, pfnum);
5784 struct cli_posix_mkdir_state {
5785 struct tevent_context *ev;
5786 struct cli_state *cli;
5789 static void cli_posix_mkdir_done(struct tevent_req *subreq);
5791 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
5792 struct tevent_context *ev,
5793 struct cli_state *cli,
5797 struct tevent_req *req = NULL, *subreq = NULL;
5798 struct cli_posix_mkdir_state *state = NULL;
5799 uint32_t wire_flags;
5801 req = tevent_req_create(
5802 mem_ctx, &state, struct cli_posix_mkdir_state);
5809 wire_flags = SMB_O_CREAT | SMB_O_DIRECTORY;
5811 subreq = cli_posix_open_internal_send(
5812 mem_ctx, ev, cli, fname, wire_flags, mode);
5813 if (tevent_req_nomem(subreq, req)) {
5814 return tevent_req_post(req, ev);
5816 tevent_req_set_callback(subreq, cli_posix_mkdir_done, req);
5820 static void cli_posix_mkdir_done(struct tevent_req *subreq)
5822 struct tevent_req *req = tevent_req_callback_data(
5823 subreq, struct tevent_req);
5827 status = cli_posix_open_internal_recv(subreq, &fnum);
5828 TALLOC_FREE(subreq);
5829 if (tevent_req_nterror(req, status)) {
5832 tevent_req_done(req);
5835 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
5837 return tevent_req_simple_recv_ntstatus(req);
5840 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
5842 TALLOC_CTX *frame = talloc_stackframe();
5843 struct tevent_context *ev = NULL;
5844 struct tevent_req *req = NULL;
5845 NTSTATUS status = NT_STATUS_NO_MEMORY;
5847 if (smbXcli_conn_has_async_calls(cli->conn)) {
5849 * Can't use sync call while an async call is in flight
5851 status = NT_STATUS_INVALID_PARAMETER;
5855 ev = samba_tevent_context_init(frame);
5859 req = cli_posix_mkdir_send(
5860 frame, ev, cli, fname, mode);
5864 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5867 status = cli_posix_mkdir_recv(req);
5873 /****************************************************************************
5874 unlink or rmdir - POSIX semantics.
5875 ****************************************************************************/
5877 struct cli_posix_unlink_internal_state {
5881 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
5883 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
5884 struct tevent_context *ev,
5885 struct cli_state *cli,
5889 struct tevent_req *req = NULL, *subreq = NULL;
5890 struct cli_posix_unlink_internal_state *state = NULL;
5892 req = tevent_req_create(mem_ctx, &state,
5893 struct cli_posix_unlink_internal_state);
5898 /* Setup data word. */
5899 SSVAL(state->data, 0, level);
5901 subreq = cli_setpathinfo_send(state, ev, cli,
5902 SMB_POSIX_PATH_UNLINK,
5904 state->data, sizeof(state->data));
5905 if (tevent_req_nomem(subreq, req)) {
5906 return tevent_req_post(req, ev);
5908 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
5912 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
5914 NTSTATUS status = cli_setpathinfo_recv(subreq);
5915 tevent_req_simple_finish_ntstatus(subreq, status);
5918 static NTSTATUS cli_posix_unlink_internal_recv(struct tevent_req *req)
5920 return tevent_req_simple_recv_ntstatus(req);
5923 struct cli_posix_unlink_state {
5927 static void cli_posix_unlink_done(struct tevent_req *subreq);
5929 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
5930 struct tevent_context *ev,
5931 struct cli_state *cli,
5934 struct tevent_req *req = NULL, *subreq = NULL;
5935 struct cli_posix_unlink_state *state;
5937 req = tevent_req_create(
5938 mem_ctx, &state, struct cli_posix_unlink_state);
5942 subreq = cli_posix_unlink_internal_send(
5943 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_FILE_TARGET);
5944 if (tevent_req_nomem(subreq, req)) {
5945 return tevent_req_post(req, ev);
5947 tevent_req_set_callback(subreq, cli_posix_unlink_done, req);
5951 static void cli_posix_unlink_done(struct tevent_req *subreq)
5953 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
5954 tevent_req_simple_finish_ntstatus(subreq, status);
5957 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
5959 return tevent_req_simple_recv_ntstatus(req);
5962 /****************************************************************************
5963 unlink - POSIX semantics.
5964 ****************************************************************************/
5966 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
5968 TALLOC_CTX *frame = talloc_stackframe();
5969 struct tevent_context *ev = NULL;
5970 struct tevent_req *req = NULL;
5971 NTSTATUS status = NT_STATUS_OK;
5973 if (smbXcli_conn_has_async_calls(cli->conn)) {
5975 * Can't use sync call while an async call is in flight
5977 status = NT_STATUS_INVALID_PARAMETER;
5981 ev = samba_tevent_context_init(frame);
5983 status = NT_STATUS_NO_MEMORY;
5987 req = cli_posix_unlink_send(frame,
5992 status = NT_STATUS_NO_MEMORY;
5996 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6000 status = cli_posix_unlink_recv(req);
6007 /****************************************************************************
6008 rmdir - POSIX semantics.
6009 ****************************************************************************/
6011 struct cli_posix_rmdir_state {
6015 static void cli_posix_rmdir_done(struct tevent_req *subreq);
6017 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
6018 struct tevent_context *ev,
6019 struct cli_state *cli,
6022 struct tevent_req *req = NULL, *subreq = NULL;
6023 struct cli_posix_rmdir_state *state;
6025 req = tevent_req_create(mem_ctx, &state, struct cli_posix_rmdir_state);
6029 subreq = cli_posix_unlink_internal_send(
6030 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_DIRECTORY_TARGET);
6031 if (tevent_req_nomem(subreq, req)) {
6032 return tevent_req_post(req, ev);
6034 tevent_req_set_callback(subreq, cli_posix_rmdir_done, req);
6038 static void cli_posix_rmdir_done(struct tevent_req *subreq)
6040 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6041 tevent_req_simple_finish_ntstatus(subreq, status);
6044 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
6046 return tevent_req_simple_recv_ntstatus(req);
6049 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
6051 TALLOC_CTX *frame = talloc_stackframe();
6052 struct tevent_context *ev = NULL;
6053 struct tevent_req *req = NULL;
6054 NTSTATUS status = NT_STATUS_OK;
6056 if (smbXcli_conn_has_async_calls(cli->conn)) {
6058 * Can't use sync call while an async call is in flight
6060 status = NT_STATUS_INVALID_PARAMETER;
6064 ev = samba_tevent_context_init(frame);
6066 status = NT_STATUS_NO_MEMORY;
6070 req = cli_posix_rmdir_send(frame,
6075 status = NT_STATUS_NO_MEMORY;
6079 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6083 status = cli_posix_rmdir_recv(req, frame);
6090 /****************************************************************************
6092 ****************************************************************************/
6094 struct cli_notify_state {
6095 struct tevent_req *subreq;
6097 uint32_t num_changes;
6098 struct notify_change *changes;
6101 static void cli_notify_done(struct tevent_req *subreq);
6102 static void cli_notify_done_smb2(struct tevent_req *subreq);
6103 static bool cli_notify_cancel(struct tevent_req *req);
6105 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
6106 struct tevent_context *ev,
6107 struct cli_state *cli, uint16_t fnum,
6108 uint32_t buffer_size,
6109 uint32_t completion_filter, bool recursive)
6111 struct tevent_req *req;
6112 struct cli_notify_state *state;
6113 unsigned old_timeout;
6115 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
6120 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6122 * Notifies should not time out
6124 old_timeout = cli_set_timeout(cli, 0);
6126 state->subreq = cli_smb2_notify_send(
6135 cli_set_timeout(cli, old_timeout);
6137 if (tevent_req_nomem(state->subreq, req)) {
6138 return tevent_req_post(req, ev);
6140 tevent_req_set_callback(
6141 state->subreq, cli_notify_done_smb2, req);
6145 SIVAL(state->setup, 0, completion_filter);
6146 SSVAL(state->setup, 4, fnum);
6147 SSVAL(state->setup, 6, recursive);
6150 * Notifies should not time out
6152 old_timeout = cli_set_timeout(cli, 0);
6154 state->subreq = cli_trans_send(
6155 state, /* mem ctx. */
6156 ev, /* event ctx. */
6157 cli, /* cli_state. */
6158 0, /* additional_flags2 */
6159 SMBnttrans, /* cmd. */
6160 NULL, /* pipe name. */
6162 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
6164 (uint16_t *)state->setup, /* setup. */
6165 4, /* num setup uint16_t words. */
6166 0, /* max returned setup. */
6169 buffer_size, /* max returned param. */
6172 0); /* max returned data. */
6174 cli_set_timeout(cli, old_timeout);
6176 if (tevent_req_nomem(state->subreq, req)) {
6177 return tevent_req_post(req, ev);
6179 tevent_req_set_callback(state->subreq, cli_notify_done, req);
6181 tevent_req_set_cancel_fn(req, cli_notify_cancel);
6185 static bool cli_notify_cancel(struct tevent_req *req)
6187 struct cli_notify_state *state = tevent_req_data(
6188 req, struct cli_notify_state);
6191 ok = tevent_req_cancel(state->subreq);
6195 static void cli_notify_done(struct tevent_req *subreq)
6197 struct tevent_req *req = tevent_req_callback_data(
6198 subreq, struct tevent_req);
6199 struct cli_notify_state *state = tevent_req_data(
6200 req, struct cli_notify_state);
6203 uint32_t i, ofs, num_params;
6206 status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
6207 ¶ms, 0, &num_params, NULL, 0, NULL);
6208 TALLOC_FREE(subreq);
6209 state->subreq = NULL;
6210 if (tevent_req_nterror(req, status)) {
6211 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
6215 state->num_changes = 0;
6218 while (num_params - ofs > 12) {
6219 uint32_t next = IVAL(params, ofs);
6220 state->num_changes += 1;
6222 if ((next == 0) || (ofs+next >= num_params)) {
6228 state->changes = talloc_array(state, struct notify_change,
6229 state->num_changes);
6230 if (tevent_req_nomem(state->changes, req)) {
6231 TALLOC_FREE(params);
6237 for (i=0; i<state->num_changes; i++) {
6238 uint32_t next = IVAL(params, ofs);
6239 uint32_t len = IVAL(params, ofs+8);
6243 if (trans_oob(num_params, ofs + 12, len)) {
6244 TALLOC_FREE(params);
6246 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
6250 state->changes[i].action = IVAL(params, ofs+4);
6251 ret = pull_string_talloc(state->changes,
6257 STR_TERMINATE|STR_UNICODE);
6259 TALLOC_FREE(params);
6260 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
6263 state->changes[i].name = name;
6267 TALLOC_FREE(params);
6268 tevent_req_done(req);
6271 static void cli_notify_done_smb2(struct tevent_req *subreq)
6273 struct tevent_req *req = tevent_req_callback_data(
6274 subreq, struct tevent_req);
6275 struct cli_notify_state *state = tevent_req_data(
6276 req, struct cli_notify_state);
6279 status = cli_smb2_notify_recv(
6283 &state->num_changes);
6284 TALLOC_FREE(subreq);
6285 if (tevent_req_nterror(req, status)) {
6288 tevent_req_done(req);
6291 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6292 uint32_t *pnum_changes,
6293 struct notify_change **pchanges)
6295 struct cli_notify_state *state = tevent_req_data(
6296 req, struct cli_notify_state);
6299 if (tevent_req_is_nterror(req, &status)) {
6303 *pnum_changes = state->num_changes;
6304 *pchanges = talloc_move(mem_ctx, &state->changes);
6305 return NT_STATUS_OK;
6308 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
6309 uint32_t completion_filter, bool recursive,
6310 TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
6311 struct notify_change **pchanges)
6314 struct tevent_context *ev;
6315 struct tevent_req *req;
6316 NTSTATUS status = NT_STATUS_NO_MEMORY;
6318 frame = talloc_stackframe();
6320 if (smbXcli_conn_has_async_calls(cli->conn)) {
6322 * Can't use sync call while an async call is in flight
6324 status = NT_STATUS_INVALID_PARAMETER;
6327 ev = samba_tevent_context_init(frame);
6331 req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
6332 completion_filter, recursive);
6336 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6339 status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
6345 struct cli_qpathinfo_state {
6354 static void cli_qpathinfo_done(struct tevent_req *subreq);
6356 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
6357 struct tevent_context *ev,
6358 struct cli_state *cli, const char *fname,
6359 uint16_t level, uint32_t min_rdata,
6362 struct tevent_req *req, *subreq;
6363 struct cli_qpathinfo_state *state;
6364 uint16_t additional_flags2 = 0;
6366 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
6370 state->min_rdata = min_rdata;
6371 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
6373 state->param = talloc_zero_array(state, uint8_t, 6);
6374 if (tevent_req_nomem(state->param, req)) {
6375 return tevent_req_post(req, ev);
6377 SSVAL(state->param, 0, level);
6378 state->param = trans2_bytes_push_str(
6379 state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
6380 if (tevent_req_nomem(state->param, req)) {
6381 return tevent_req_post(req, ev);
6384 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
6385 !INFO_LEVEL_IS_UNIX(level)) {
6386 additional_flags2 = FLAGS2_REPARSE_PATH;
6389 subreq = cli_trans_send(
6390 state, /* mem ctx. */
6391 ev, /* event ctx. */
6392 cli, /* cli_state. */
6393 additional_flags2, /* additional_flags2 */
6394 SMBtrans2, /* cmd. */
6395 NULL, /* pipe name. */
6399 state->setup, /* setup. */
6400 1, /* num setup uint16_t words. */
6401 0, /* max returned setup. */
6402 state->param, /* param. */
6403 talloc_get_size(state->param), /* num param. */
6404 2, /* max returned param. */
6407 max_rdata); /* max returned data. */
6409 if (tevent_req_nomem(subreq, req)) {
6410 return tevent_req_post(req, ev);
6412 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
6416 static void cli_qpathinfo_done(struct tevent_req *subreq)
6418 struct tevent_req *req = tevent_req_callback_data(
6419 subreq, struct tevent_req);
6420 struct cli_qpathinfo_state *state = tevent_req_data(
6421 req, struct cli_qpathinfo_state);
6424 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
6426 &state->rdata, state->min_rdata,
6428 if (tevent_req_nterror(req, status)) {
6431 tevent_req_done(req);
6434 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6435 uint8_t **rdata, uint32_t *num_rdata)
6437 struct cli_qpathinfo_state *state = tevent_req_data(
6438 req, struct cli_qpathinfo_state);
6441 if (tevent_req_is_nterror(req, &status)) {
6444 if (rdata != NULL) {
6445 *rdata = talloc_move(mem_ctx, &state->rdata);
6447 TALLOC_FREE(state->rdata);
6449 if (num_rdata != NULL) {
6450 *num_rdata = state->num_rdata;
6452 return NT_STATUS_OK;
6455 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6456 const char *fname, uint16_t level, uint32_t min_rdata,
6458 uint8_t **rdata, uint32_t *num_rdata)
6460 TALLOC_CTX *frame = talloc_stackframe();
6461 struct tevent_context *ev;
6462 struct tevent_req *req;
6463 NTSTATUS status = NT_STATUS_NO_MEMORY;
6465 if (smbXcli_conn_has_async_calls(cli->conn)) {
6467 * Can't use sync call while an async call is in flight
6469 status = NT_STATUS_INVALID_PARAMETER;
6472 ev = samba_tevent_context_init(frame);
6476 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
6481 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6484 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
6490 struct cli_qfileinfo_state {
6494 uint16_t recv_flags2;
6500 static void cli_qfileinfo_done(struct tevent_req *subreq);
6502 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
6503 struct tevent_context *ev,
6504 struct cli_state *cli, uint16_t fnum,
6505 uint16_t level, uint32_t min_rdata,
6508 struct tevent_req *req, *subreq;
6509 struct cli_qfileinfo_state *state;
6511 req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
6515 state->min_rdata = min_rdata;
6516 SSVAL(state->param, 0, fnum);
6517 SSVAL(state->param, 2, level);
6518 SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
6520 subreq = cli_trans_send(
6521 state, /* mem ctx. */
6522 ev, /* event ctx. */
6523 cli, /* cli_state. */
6524 0, /* additional_flags2 */
6525 SMBtrans2, /* cmd. */
6526 NULL, /* pipe name. */
6530 state->setup, /* setup. */
6531 1, /* num setup uint16_t words. */
6532 0, /* max returned setup. */
6533 state->param, /* param. */
6534 sizeof(state->param), /* num param. */
6535 2, /* max returned param. */
6538 max_rdata); /* max returned data. */
6540 if (tevent_req_nomem(subreq, req)) {
6541 return tevent_req_post(req, ev);
6543 tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
6547 static void cli_qfileinfo_done(struct tevent_req *subreq)
6549 struct tevent_req *req = tevent_req_callback_data(
6550 subreq, struct tevent_req);
6551 struct cli_qfileinfo_state *state = tevent_req_data(
6552 req, struct cli_qfileinfo_state);
6555 status = cli_trans_recv(subreq, state,
6556 &state->recv_flags2,
6559 &state->rdata, state->min_rdata,
6561 if (tevent_req_nterror(req, status)) {
6564 tevent_req_done(req);
6567 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6568 uint16_t *recv_flags2,
6569 uint8_t **rdata, uint32_t *num_rdata)
6571 struct cli_qfileinfo_state *state = tevent_req_data(
6572 req, struct cli_qfileinfo_state);
6575 if (tevent_req_is_nterror(req, &status)) {
6579 if (recv_flags2 != NULL) {
6580 *recv_flags2 = state->recv_flags2;
6582 if (rdata != NULL) {
6583 *rdata = talloc_move(mem_ctx, &state->rdata);
6585 if (num_rdata != NULL) {
6586 *num_rdata = state->num_rdata;
6589 tevent_req_received(req);
6590 return NT_STATUS_OK;
6593 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6594 uint16_t fnum, uint16_t level, uint32_t min_rdata,
6595 uint32_t max_rdata, uint16_t *recv_flags2,
6596 uint8_t **rdata, uint32_t *num_rdata)
6598 TALLOC_CTX *frame = talloc_stackframe();
6599 struct tevent_context *ev;
6600 struct tevent_req *req;
6601 NTSTATUS status = NT_STATUS_NO_MEMORY;
6603 if (smbXcli_conn_has_async_calls(cli->conn)) {
6605 * Can't use sync call while an async call is in flight
6607 status = NT_STATUS_INVALID_PARAMETER;
6610 ev = samba_tevent_context_init(frame);
6614 req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
6619 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6622 status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
6628 struct cli_flush_state {
6632 static void cli_flush_done(struct tevent_req *subreq);
6634 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
6635 struct tevent_context *ev,
6636 struct cli_state *cli,
6639 struct tevent_req *req, *subreq;
6640 struct cli_flush_state *state;
6642 req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
6646 SSVAL(state->vwv + 0, 0, fnum);
6648 subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
6650 if (tevent_req_nomem(subreq, req)) {
6651 return tevent_req_post(req, ev);
6653 tevent_req_set_callback(subreq, cli_flush_done, req);
6657 static void cli_flush_done(struct tevent_req *subreq)
6659 struct tevent_req *req = tevent_req_callback_data(
6660 subreq, struct tevent_req);
6663 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
6664 TALLOC_FREE(subreq);
6665 if (tevent_req_nterror(req, status)) {
6668 tevent_req_done(req);
6671 NTSTATUS cli_flush_recv(struct tevent_req *req)
6673 return tevent_req_simple_recv_ntstatus(req);
6676 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
6678 TALLOC_CTX *frame = talloc_stackframe();
6679 struct tevent_context *ev;
6680 struct tevent_req *req;
6681 NTSTATUS status = NT_STATUS_NO_MEMORY;
6683 if (smbXcli_conn_has_async_calls(cli->conn)) {
6685 * Can't use sync call while an async call is in flight
6687 status = NT_STATUS_INVALID_PARAMETER;
6690 ev = samba_tevent_context_init(frame);
6694 req = cli_flush_send(frame, ev, cli, fnum);
6698 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6701 status = cli_flush_recv(req);
6707 struct cli_shadow_copy_data_state {
6714 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
6716 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
6717 struct tevent_context *ev,
6718 struct cli_state *cli,
6722 struct tevent_req *req, *subreq;
6723 struct cli_shadow_copy_data_state *state;
6726 req = tevent_req_create(mem_ctx, &state,
6727 struct cli_shadow_copy_data_state);
6731 state->get_names = get_names;
6732 ret_size = get_names ? CLI_BUFFER_SIZE : 16;
6734 SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
6735 SSVAL(state->setup + 2, 0, fnum);
6736 SCVAL(state->setup + 3, 0, 1); /* isFsctl */
6737 SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
6739 subreq = cli_trans_send(
6740 state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
6741 state->setup, ARRAY_SIZE(state->setup),
6742 ARRAY_SIZE(state->setup),
6745 if (tevent_req_nomem(subreq, req)) {
6746 return tevent_req_post(req, ev);
6748 tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
6752 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
6754 struct tevent_req *req = tevent_req_callback_data(
6755 subreq, struct tevent_req);
6756 struct cli_shadow_copy_data_state *state = tevent_req_data(
6757 req, struct cli_shadow_copy_data_state);
6760 status = cli_trans_recv(subreq, state, NULL,
6761 NULL, 0, NULL, /* setup */
6762 NULL, 0, NULL, /* param */
6763 &state->data, 12, &state->num_data);
6764 TALLOC_FREE(subreq);
6765 if (tevent_req_nterror(req, status)) {
6768 tevent_req_done(req);
6771 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6772 char ***pnames, int *pnum_names)
6774 struct cli_shadow_copy_data_state *state = tevent_req_data(
6775 req, struct cli_shadow_copy_data_state);
6776 char **names = NULL;
6777 uint32_t i, num_names;
6779 uint8_t *endp = NULL;
6782 if (tevent_req_is_nterror(req, &status)) {
6786 if (state->num_data < 16) {
6787 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6790 num_names = IVAL(state->data, 4);
6791 dlength = IVAL(state->data, 8);
6793 if (num_names > 0x7FFFFFFF) {
6794 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6797 if (!state->get_names) {
6798 *pnum_names = (int)num_names;
6799 return NT_STATUS_OK;
6802 if (dlength + 12 < 12) {
6803 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6805 if (dlength + 12 > state->num_data) {
6806 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6808 if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
6810 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6813 names = talloc_array(mem_ctx, char *, num_names);
6814 if (names == NULL) {
6815 return NT_STATUS_NO_MEMORY;
6818 endp = state->data + state->num_data;
6820 for (i=0; i<num_names; i++) {
6823 size_t converted_size;
6825 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
6827 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
6828 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6831 ret = convert_string_talloc(
6832 names, CH_UTF16LE, CH_UNIX,
6833 src, 2 * sizeof(SHADOW_COPY_LABEL),
6834 &names[i], &converted_size);
6837 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6840 *pnum_names = (int)num_names;
6842 return NT_STATUS_OK;
6845 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6846 uint16_t fnum, bool get_names,
6847 char ***pnames, int *pnum_names)
6849 TALLOC_CTX *frame = NULL;
6850 struct tevent_context *ev;
6851 struct tevent_req *req;
6852 NTSTATUS status = NT_STATUS_NO_MEMORY;
6854 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6855 return cli_smb2_shadow_copy_data(mem_ctx,
6863 frame = talloc_stackframe();
6865 if (smbXcli_conn_has_async_calls(cli->conn)) {
6867 * Can't use sync call while an async call is in flight
6869 status = NT_STATUS_INVALID_PARAMETER;
6872 ev = samba_tevent_context_init(frame);
6876 req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
6880 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6883 status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);