s3:utils: Fix 'Usage:' for 'net ads enctypes'
[samba4-gss.git] / source3 / libsmb / clifile.c
blobc079f84049e52211504465c3a5597cec79ef574e
1 /*
2 Unix SMB/CIFS implementation.
3 client file operations
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/>.
21 #include "includes.h"
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"
27 #include "trans2.h"
28 #include "ntioctl.h"
29 #include "libcli/security/security.h"
30 #include "../libcli/smb/smbXcli_base.h"
31 #include "libcli/smb/reparse.h"
33 struct cli_setpathinfo_state {
34 uint16_t setup;
35 uint8_t *param;
38 static void cli_setpathinfo_done(struct tevent_req *subreq);
40 struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
41 struct tevent_context *ev,
42 struct cli_state *cli,
43 uint16_t level,
44 const char *path,
45 uint8_t *data,
46 size_t data_len)
48 struct tevent_req *req, *subreq;
49 struct cli_setpathinfo_state *state;
50 uint16_t additional_flags2 = 0;
51 char *path_cp = NULL;
53 req = tevent_req_create(mem_ctx, &state,
54 struct cli_setpathinfo_state);
55 if (req == NULL) {
56 return NULL;
59 /* Setup setup word. */
60 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
62 /* Setup param array. */
63 state->param = talloc_zero_array(state, uint8_t, 6);
64 if (tevent_req_nomem(state->param, req)) {
65 return tevent_req_post(req, ev);
67 SSVAL(state->param, 0, level);
69 /* Check for DFS. */
70 path_cp = smb1_dfs_share_path(state, cli, path);
71 if (tevent_req_nomem(path_cp, req)) {
72 return tevent_req_post(req, ev);
74 state->param = trans2_bytes_push_str(state->param,
75 smbXcli_conn_use_unicode(cli->conn),
76 path_cp,
77 strlen(path_cp)+1,
78 NULL);
79 if (tevent_req_nomem(state->param, req)) {
80 return tevent_req_post(req, ev);
83 if (clistr_is_previous_version_path(path) &&
84 !INFO_LEVEL_IS_UNIX(level)) {
85 additional_flags2 = FLAGS2_REPARSE_PATH;
88 subreq = cli_trans_send(
89 state, /* mem ctx. */
90 ev, /* event ctx. */
91 cli, /* cli_state. */
92 additional_flags2, /* additional_flags2 */
93 SMBtrans2, /* cmd. */
94 NULL, /* pipe name. */
95 -1, /* fid. */
96 0, /* function. */
97 0, /* flags. */
98 &state->setup, /* setup. */
99 1, /* num setup uint16_t words. */
100 0, /* max returned setup. */
101 state->param, /* param. */
102 talloc_get_size(state->param), /* num param. */
103 2, /* max returned param. */
104 data, /* data. */
105 data_len, /* num data. */
106 0); /* max returned data. */
108 if (tevent_req_nomem(subreq, req)) {
109 return tevent_req_post(req, ev);
111 tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
112 return req;
115 static void cli_setpathinfo_done(struct tevent_req *subreq)
117 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
118 NULL, 0, NULL, NULL, 0, NULL);
119 tevent_req_simple_finish_ntstatus(subreq, status);
122 NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
124 return tevent_req_simple_recv_ntstatus(req);
127 NTSTATUS cli_setpathinfo(struct cli_state *cli,
128 uint16_t level,
129 const char *path,
130 uint8_t *data,
131 size_t data_len)
133 TALLOC_CTX *frame = talloc_stackframe();
134 struct tevent_context *ev;
135 struct tevent_req *req;
136 NTSTATUS status = NT_STATUS_NO_MEMORY;
138 if (smbXcli_conn_has_async_calls(cli->conn)) {
140 * Can't use sync call while an async call is in flight
142 status = NT_STATUS_INVALID_PARAMETER;
143 goto fail;
145 ev = samba_tevent_context_init(frame);
146 if (ev == NULL) {
147 goto fail;
149 req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
150 if (req == NULL) {
151 goto fail;
153 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
154 goto fail;
156 status = cli_setpathinfo_recv(req);
157 fail:
158 TALLOC_FREE(frame);
159 return status;
162 struct cli_setfileinfo_state {
163 uint16_t setup;
164 uint8_t param[6];
167 static void cli_setfileinfo_done(struct tevent_req *subreq);
169 struct tevent_req *cli_setfileinfo_send(
170 TALLOC_CTX *mem_ctx,
171 struct tevent_context *ev,
172 struct cli_state *cli,
173 uint16_t fnum,
174 uint16_t level,
175 uint8_t *data,
176 size_t data_len)
178 struct tevent_req *req = NULL, *subreq = NULL;
179 struct cli_setfileinfo_state *state = NULL;
181 req = tevent_req_create(mem_ctx, &state, struct cli_setfileinfo_state);
182 if (req == NULL) {
183 return NULL;
185 PUSH_LE_U16(&state->setup, 0, TRANSACT2_SETFILEINFO);
187 PUSH_LE_U16(state->param, 0, fnum);
188 PUSH_LE_U16(state->param, 2, level);
190 subreq = cli_trans_send(state, /* mem ctx. */
191 ev, /* event ctx. */
192 cli, /* cli_state. */
193 0, /* additional_flags2 */
194 SMBtrans2, /* cmd. */
195 NULL, /* pipe name. */
196 -1, /* fid. */
197 0, /* function. */
198 0, /* flags. */
199 &state->setup, /* setup. */
200 1, /* num setup uint16_t words. */
201 0, /* max returned setup. */
202 state->param, /* param. */
203 6, /* num param. */
204 2, /* max returned param. */
205 data, /* data. */
206 data_len, /* num data. */
207 0); /* max returned data. */
209 if (tevent_req_nomem(subreq, req)) {
210 return tevent_req_post(req, ev);
212 tevent_req_set_callback(subreq, cli_setfileinfo_done, req);
213 return req;
216 static void cli_setfileinfo_done(struct tevent_req *subreq)
218 NTSTATUS status = cli_trans_recv(
219 subreq, /* req */
220 NULL, /* mem_ctx */
221 NULL, /* recv_flags2 */
222 NULL, /* setup */
223 0, /* min_setup */
224 NULL, /* num_setup */
225 NULL, /* param */
226 0, /* min_param */
227 NULL, /* num_param */
228 NULL, /* data */
229 0, /* min_data */
230 NULL); /* num_data */
231 tevent_req_simple_finish_ntstatus(subreq, status);
234 NTSTATUS cli_setfileinfo_recv(struct tevent_req *req)
236 return tevent_req_simple_recv_ntstatus(req);
239 /****************************************************************************
240 Hard/Symlink a file (UNIX extensions).
241 Creates new name (sym)linked to link_target.
242 ****************************************************************************/
244 struct cli_posix_link_internal_state {
245 uint8_t *data;
248 static void cli_posix_link_internal_done(struct tevent_req *subreq);
250 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
251 struct tevent_context *ev,
252 struct cli_state *cli,
253 uint16_t level,
254 const char *link_target,
255 const char *newname)
257 struct tevent_req *req = NULL, *subreq = NULL;
258 struct cli_posix_link_internal_state *state = NULL;
260 req = tevent_req_create(mem_ctx, &state,
261 struct cli_posix_link_internal_state);
262 if (req == NULL) {
263 return NULL;
266 /* Setup data array. */
267 state->data = talloc_array(state, uint8_t, 0);
268 if (tevent_req_nomem(state->data, req)) {
269 return tevent_req_post(req, ev);
271 state->data = trans2_bytes_push_str(
272 state->data, smbXcli_conn_use_unicode(cli->conn),
273 link_target, strlen(link_target)+1, NULL);
275 subreq = cli_setpathinfo_send(
276 state, ev, cli, level, newname,
277 state->data, talloc_get_size(state->data));
278 if (tevent_req_nomem(subreq, req)) {
279 return tevent_req_post(req, ev);
281 tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
282 return req;
285 static void cli_posix_link_internal_done(struct tevent_req *subreq)
287 NTSTATUS status = cli_setpathinfo_recv(subreq);
288 tevent_req_simple_finish_ntstatus(subreq, status);
291 static NTSTATUS cli_posix_link_internal_recv(struct tevent_req *req)
293 return tevent_req_simple_recv_ntstatus(req);
296 /****************************************************************************
297 Symlink a file (UNIX extensions).
298 ****************************************************************************/
300 struct cli_posix_symlink_state {
301 uint8_t dummy;
304 static void cli_posix_symlink_done(struct tevent_req *subreq);
306 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
307 struct tevent_context *ev,
308 struct cli_state *cli,
309 const char *link_target,
310 const char *newname)
312 struct tevent_req *req = NULL, *subreq = NULL;
313 struct cli_posix_symlink_state *state = NULL;
315 req = tevent_req_create(
316 mem_ctx, &state, struct cli_posix_symlink_state);
317 if (req == NULL) {
318 return NULL;
321 subreq = cli_posix_link_internal_send(
322 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, link_target, newname);
323 if (tevent_req_nomem(subreq, req)) {
324 return tevent_req_post(req, ev);
326 tevent_req_set_callback(subreq, cli_posix_symlink_done, req);
327 return req;
330 static void cli_posix_symlink_done(struct tevent_req *subreq)
332 NTSTATUS status = cli_posix_link_internal_recv(subreq);
333 tevent_req_simple_finish_ntstatus(subreq, status);
336 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
338 return tevent_req_simple_recv_ntstatus(req);
341 NTSTATUS cli_posix_symlink(struct cli_state *cli,
342 const char *link_target,
343 const char *newname)
345 TALLOC_CTX *frame = talloc_stackframe();
346 struct tevent_context *ev = NULL;
347 struct tevent_req *req = NULL;
348 NTSTATUS status = NT_STATUS_OK;
350 if (smbXcli_conn_has_async_calls(cli->conn)) {
352 * Can't use sync call while an async call is in flight
354 status = NT_STATUS_INVALID_PARAMETER;
355 goto fail;
358 ev = samba_tevent_context_init(frame);
359 if (ev == NULL) {
360 status = NT_STATUS_NO_MEMORY;
361 goto fail;
364 req = cli_posix_symlink_send(frame,
366 cli,
367 link_target,
368 newname);
369 if (req == NULL) {
370 status = NT_STATUS_NO_MEMORY;
371 goto fail;
374 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
375 goto fail;
378 status = cli_posix_symlink_recv(req);
380 fail:
381 TALLOC_FREE(frame);
382 return status;
385 /****************************************************************************
386 Read a POSIX symlink.
387 ****************************************************************************/
389 struct cli_posix_readlink_state {
390 struct cli_state *cli;
391 char *converted;
394 static void cli_posix_readlink_done(struct tevent_req *subreq);
396 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
397 struct tevent_context *ev,
398 struct cli_state *cli,
399 const char *fname)
401 struct tevent_req *req = NULL, *subreq = NULL;
402 struct cli_posix_readlink_state *state = NULL;
404 req = tevent_req_create(
405 mem_ctx, &state, struct cli_posix_readlink_state);
406 if (req == NULL) {
407 return NULL;
409 state->cli = cli;
411 subreq = cli_qpathinfo_send(
412 state,
414 cli,
415 fname,
416 SMB_QUERY_FILE_UNIX_LINK,
418 UINT16_MAX);
419 if (tevent_req_nomem(subreq, req)) {
420 return tevent_req_post(req, ev);
422 tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
423 return req;
426 static void cli_posix_readlink_done(struct tevent_req *subreq)
428 struct tevent_req *req = tevent_req_callback_data(
429 subreq, struct tevent_req);
430 struct cli_posix_readlink_state *state = tevent_req_data(
431 req, struct cli_posix_readlink_state);
432 NTSTATUS status;
433 uint8_t *data = NULL;
434 uint32_t num_data = 0;
435 charset_t charset;
436 size_t converted_size;
437 bool ok;
439 status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
440 TALLOC_FREE(subreq);
441 if (tevent_req_nterror(req, status)) {
442 return;
445 * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
447 if (data == NULL || data[num_data-1] != '\0') {
448 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
449 return;
452 charset = smbXcli_conn_use_unicode(state->cli->conn) ?
453 CH_UTF16LE : CH_DOS;
455 /* The returned data is a pushed string, not raw data. */
456 ok = convert_string_talloc(
457 state,
458 charset,
459 CH_UNIX,
460 data,
461 num_data,
462 &state->converted,
463 &converted_size);
464 if (!ok) {
465 tevent_req_oom(req);
466 return;
468 tevent_req_done(req);
471 NTSTATUS cli_posix_readlink_recv(
472 struct tevent_req *req, TALLOC_CTX *mem_ctx, char **target)
474 struct cli_posix_readlink_state *state = tevent_req_data(
475 req, struct cli_posix_readlink_state);
476 NTSTATUS status;
478 if (tevent_req_is_nterror(req, &status)) {
479 return status;
481 *target = talloc_move(mem_ctx, &state->converted);
482 tevent_req_received(req);
483 return NT_STATUS_OK;
486 /****************************************************************************
487 Hard link a file (UNIX extensions).
488 ****************************************************************************/
490 struct cli_posix_hardlink_state {
491 uint8_t dummy;
494 static void cli_posix_hardlink_done(struct tevent_req *subreq);
496 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
497 struct tevent_context *ev,
498 struct cli_state *cli,
499 const char *oldname,
500 const char *newname)
502 struct tevent_req *req = NULL, *subreq = NULL;
503 struct cli_posix_hardlink_state *state = NULL;
505 req = tevent_req_create(
506 mem_ctx, &state, struct cli_posix_hardlink_state);
507 if (req == NULL) {
508 return NULL;
511 subreq = cli_posix_link_internal_send(
512 state, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
513 if (tevent_req_nomem(subreq, req)) {
514 return tevent_req_post(req, ev);
516 tevent_req_set_callback(subreq, cli_posix_hardlink_done, req);
517 return req;
520 static void cli_posix_hardlink_done(struct tevent_req *subreq)
522 NTSTATUS status = cli_posix_link_internal_recv(subreq);
523 tevent_req_simple_finish_ntstatus(subreq, status);
526 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
528 return tevent_req_simple_recv_ntstatus(req);
531 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
532 const char *oldname,
533 const char *newname)
535 TALLOC_CTX *frame = talloc_stackframe();
536 struct tevent_context *ev = NULL;
537 struct tevent_req *req = NULL;
538 NTSTATUS status = NT_STATUS_OK;
540 if (smbXcli_conn_has_async_calls(cli->conn)) {
542 * Can't use sync call while an async call is in flight
544 status = NT_STATUS_INVALID_PARAMETER;
545 goto fail;
548 ev = samba_tevent_context_init(frame);
549 if (ev == NULL) {
550 status = NT_STATUS_NO_MEMORY;
551 goto fail;
554 req = cli_posix_hardlink_send(frame,
556 cli,
557 oldname,
558 newname);
559 if (req == NULL) {
560 status = NT_STATUS_NO_MEMORY;
561 goto fail;
564 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
565 goto fail;
568 status = cli_posix_hardlink_recv(req);
570 fail:
571 TALLOC_FREE(frame);
572 return status;
575 /****************************************************************************
576 Do a POSIX getacl - pathname based ACL get (UNIX extensions).
577 ****************************************************************************/
579 struct getacl_state {
580 uint32_t num_data;
581 uint8_t *data;
584 static void cli_posix_getacl_done(struct tevent_req *subreq);
586 struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
587 struct tevent_context *ev,
588 struct cli_state *cli,
589 const char *fname)
591 struct tevent_req *req = NULL, *subreq = NULL;
592 struct getacl_state *state = NULL;
594 req = tevent_req_create(mem_ctx, &state, struct getacl_state);
595 if (req == NULL) {
596 return NULL;
598 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
599 0, CLI_BUFFER_SIZE);
600 if (tevent_req_nomem(subreq, req)) {
601 return tevent_req_post(req, ev);
603 tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
604 return req;
607 static void cli_posix_getacl_done(struct tevent_req *subreq)
609 struct tevent_req *req = tevent_req_callback_data(
610 subreq, struct tevent_req);
611 struct getacl_state *state = tevent_req_data(
612 req, struct getacl_state);
613 NTSTATUS status;
615 status = cli_qpathinfo_recv(subreq, state, &state->data,
616 &state->num_data);
617 TALLOC_FREE(subreq);
618 if (tevent_req_nterror(req, status)) {
619 return;
621 tevent_req_done(req);
624 NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
625 TALLOC_CTX *mem_ctx,
626 size_t *prb_size,
627 char **retbuf)
629 struct getacl_state *state = tevent_req_data(req, struct getacl_state);
630 NTSTATUS status;
632 if (tevent_req_is_nterror(req, &status)) {
633 return status;
635 *prb_size = (size_t)state->num_data;
636 *retbuf = (char *)talloc_move(mem_ctx, &state->data);
637 return NT_STATUS_OK;
640 NTSTATUS cli_posix_getacl(struct cli_state *cli,
641 const char *fname,
642 TALLOC_CTX *mem_ctx,
643 size_t *prb_size,
644 char **retbuf)
646 TALLOC_CTX *frame = talloc_stackframe();
647 struct tevent_context *ev = NULL;
648 struct tevent_req *req = NULL;
649 NTSTATUS status = NT_STATUS_OK;
651 if (smbXcli_conn_has_async_calls(cli->conn)) {
653 * Can't use sync call while an async call is in flight
655 status = NT_STATUS_INVALID_PARAMETER;
656 goto fail;
659 ev = samba_tevent_context_init(frame);
660 if (ev == NULL) {
661 status = NT_STATUS_NO_MEMORY;
662 goto fail;
665 req = cli_posix_getacl_send(frame,
667 cli,
668 fname);
669 if (req == NULL) {
670 status = NT_STATUS_NO_MEMORY;
671 goto fail;
674 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
675 goto fail;
678 status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
680 fail:
681 TALLOC_FREE(frame);
682 return status;
685 /****************************************************************************
686 Do a POSIX setacl - pathname based ACL set (UNIX extensions).
687 ****************************************************************************/
689 struct setacl_state {
690 uint8_t *data;
693 static void cli_posix_setacl_done(struct tevent_req *subreq);
695 struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
696 struct tevent_context *ev,
697 struct cli_state *cli,
698 const char *fname,
699 const void *data,
700 size_t num_data)
702 struct tevent_req *req = NULL, *subreq = NULL;
703 struct setacl_state *state = NULL;
705 req = tevent_req_create(mem_ctx, &state, struct setacl_state);
706 if (req == NULL) {
707 return NULL;
709 state->data = talloc_memdup(state, data, num_data);
710 if (tevent_req_nomem(state->data, req)) {
711 return tevent_req_post(req, ev);
714 subreq = cli_setpathinfo_send(state,
716 cli,
717 SMB_SET_POSIX_ACL,
718 fname,
719 state->data,
720 num_data);
721 if (tevent_req_nomem(subreq, req)) {
722 return tevent_req_post(req, ev);
724 tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
725 return req;
728 static void cli_posix_setacl_done(struct tevent_req *subreq)
730 NTSTATUS status = cli_setpathinfo_recv(subreq);
731 tevent_req_simple_finish_ntstatus(subreq, status);
734 NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
736 return tevent_req_simple_recv_ntstatus(req);
739 NTSTATUS cli_posix_setacl(struct cli_state *cli,
740 const char *fname,
741 const void *acl_buf,
742 size_t acl_buf_size)
744 TALLOC_CTX *frame = talloc_stackframe();
745 struct tevent_context *ev = NULL;
746 struct tevent_req *req = NULL;
747 NTSTATUS status = NT_STATUS_OK;
749 if (smbXcli_conn_has_async_calls(cli->conn)) {
751 * Can't use sync call while an async call is in flight
753 status = NT_STATUS_INVALID_PARAMETER;
754 goto fail;
757 ev = samba_tevent_context_init(frame);
758 if (ev == NULL) {
759 status = NT_STATUS_NO_MEMORY;
760 goto fail;
763 req = cli_posix_setacl_send(frame,
765 cli,
766 fname,
767 acl_buf,
768 acl_buf_size);
769 if (req == NULL) {
770 status = NT_STATUS_NO_MEMORY;
771 goto fail;
774 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
775 goto fail;
778 status = cli_posix_setacl_recv(req);
780 fail:
781 TALLOC_FREE(frame);
782 return status;
785 /****************************************************************************
786 Stat a file (UNIX extensions).
787 ****************************************************************************/
789 struct cli_posix_stat_state {
790 struct stat_ex sbuf;
793 static void cli_posix_stat_done(struct tevent_req *subreq);
795 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
796 struct tevent_context *ev,
797 struct cli_state *cli,
798 const char *fname)
800 struct tevent_req *req = NULL, *subreq = NULL;
801 struct stat_state *state = NULL;
803 req = tevent_req_create(mem_ctx, &state, struct cli_posix_stat_state);
804 if (req == NULL) {
805 return NULL;
808 subreq = cli_qpathinfo_send(state, ev, cli, fname,
809 SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
810 if (tevent_req_nomem(subreq, req)) {
811 return tevent_req_post(req, ev);
813 tevent_req_set_callback(subreq, cli_posix_stat_done, req);
814 return req;
817 static void cli_posix_stat_done(struct tevent_req *subreq)
819 struct tevent_req *req = tevent_req_callback_data(
820 subreq, struct tevent_req);
821 struct cli_posix_stat_state *state = tevent_req_data(
822 req, struct cli_posix_stat_state);
823 SMB_STRUCT_STAT *sbuf = &state->sbuf;
824 uint8_t *data;
825 uint32_t num_data = 0;
826 NTSTATUS status;
828 status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
829 TALLOC_FREE(subreq);
830 if (tevent_req_nterror(req, status)) {
831 return;
834 if (num_data != 100) {
836 * Paranoia, cli_qpathinfo should have guaranteed
837 * this, but you never know...
839 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
840 return;
843 /* total size, in bytes */
844 sbuf->st_ex_size = BVAL(data, 0);
846 /* number of blocks allocated */
847 sbuf->st_ex_blocks = BVAL(data,8);
848 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
849 sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
850 #else
851 /* assume 512 byte blocks */
852 sbuf->st_ex_blocks /= 512;
853 #endif
854 /* time of last change */
855 sbuf->st_ex_ctime = interpret_long_date(BVAL(data, 16));
857 /* time of last access */
858 sbuf->st_ex_atime = interpret_long_date(BVAL(data, 24));
860 /* time of last modification */
861 sbuf->st_ex_mtime = interpret_long_date(BVAL(data, 32));
863 sbuf->st_ex_uid = (uid_t) IVAL(data, 40); /* user ID of owner */
864 sbuf->st_ex_gid = (gid_t) IVAL(data, 48); /* group ID of owner */
865 sbuf->st_ex_mode = wire_filetype_to_unix(IVAL(data, 56));
867 #if defined(HAVE_MAKEDEV)
869 uint32_t dev_major = IVAL(data,60);
870 uint32_t dev_minor = IVAL(data,68);
871 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
873 #endif
874 /* inode */
875 sbuf->st_ex_ino = (SMB_INO_T)BVAL(data, 76);
877 /* protection */
878 sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(data, 84));
880 /* number of hard links */
881 sbuf->st_ex_nlink = BIG_UINT(data, 92);
883 tevent_req_done(req);
886 NTSTATUS cli_posix_stat_recv(struct tevent_req *req, struct stat_ex *sbuf)
888 struct cli_posix_stat_state *state = tevent_req_data(
889 req, struct cli_posix_stat_state);
890 NTSTATUS status;
892 if (tevent_req_is_nterror(req, &status)) {
893 return status;
895 *sbuf = state->sbuf;
896 return NT_STATUS_OK;
899 NTSTATUS cli_posix_stat(struct cli_state *cli,
900 const char *fname,
901 struct stat_ex *sbuf)
903 TALLOC_CTX *frame = talloc_stackframe();
904 struct tevent_context *ev = NULL;
905 struct tevent_req *req = NULL;
906 NTSTATUS status = NT_STATUS_OK;
908 if (smbXcli_conn_has_async_calls(cli->conn)) {
910 * Can't use sync call while an async call is in flight
912 status = NT_STATUS_INVALID_PARAMETER;
913 goto fail;
916 ev = samba_tevent_context_init(frame);
917 if (ev == NULL) {
918 status = NT_STATUS_NO_MEMORY;
919 goto fail;
922 req = cli_posix_stat_send(frame, ev, cli, fname);
923 if (req == NULL) {
924 status = NT_STATUS_NO_MEMORY;
925 goto fail;
928 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
929 goto fail;
932 status = cli_posix_stat_recv(req, sbuf);
934 fail:
935 TALLOC_FREE(frame);
936 return status;
939 /****************************************************************************
940 Chmod or chown a file internal (UNIX extensions).
941 ****************************************************************************/
943 struct cli_posix_chown_chmod_internal_state {
944 uint8_t data[100];
947 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
949 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
950 struct tevent_context *ev,
951 struct cli_state *cli,
952 const char *fname,
953 uint32_t mode,
954 uint32_t uid,
955 uint32_t gid)
957 struct tevent_req *req = NULL, *subreq = NULL;
958 struct cli_posix_chown_chmod_internal_state *state = NULL;
960 req = tevent_req_create(mem_ctx, &state,
961 struct cli_posix_chown_chmod_internal_state);
962 if (req == NULL) {
963 return NULL;
966 memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
967 SIVAL(state->data,40,uid);
968 SIVAL(state->data,48,gid);
969 SIVAL(state->data,84,mode);
971 subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
972 fname, state->data, sizeof(state->data));
973 if (tevent_req_nomem(subreq, req)) {
974 return tevent_req_post(req, ev);
976 tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
977 req);
978 return req;
981 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
983 NTSTATUS status = cli_setpathinfo_recv(subreq);
984 tevent_req_simple_finish_ntstatus(subreq, status);
987 static NTSTATUS cli_posix_chown_chmod_internal_recv(struct tevent_req *req)
989 return tevent_req_simple_recv_ntstatus(req);
992 struct cli_fchmod_state {
993 uint8_t data[100]; /* smb1 posix extensions */
996 static void cli_fchmod_done1(struct tevent_req *subreq);
997 static void cli_fchmod_done2(struct tevent_req *subreq);
999 struct tevent_req *cli_fchmod_send(TALLOC_CTX *mem_ctx,
1000 struct tevent_context *ev,
1001 struct cli_state *cli,
1002 uint16_t fnum,
1003 mode_t mode)
1005 struct tevent_req *req = NULL, *subreq = NULL;
1006 struct cli_fchmod_state *state = NULL;
1007 const enum protocol_types proto = smbXcli_conn_protocol(cli->conn);
1009 req = tevent_req_create(mem_ctx, &state, struct cli_fchmod_state);
1010 if (req == NULL) {
1011 return NULL;
1014 if ((proto < PROTOCOL_SMB2_02) && SERVER_HAS_UNIX_CIFS(cli)) {
1015 memset(state->data,
1016 0xff,
1017 40); /* Set all sizes/times to no change. */
1018 PUSH_LE_U32(state->data, 40, SMB_UID_NO_CHANGE);
1019 PUSH_LE_U32(state->data, 48, SMB_GID_NO_CHANGE);
1020 PUSH_LE_U32(state->data, 84, mode);
1022 subreq = cli_setfileinfo_send(state,
1024 cli,
1025 fnum,
1026 SMB_SET_FILE_UNIX_BASIC,
1027 state->data,
1028 sizeof(state->data));
1029 if (tevent_req_nomem(subreq, req)) {
1030 return tevent_req_post(req, ev);
1032 tevent_req_set_callback(subreq, cli_fchmod_done1, req);
1033 return req;
1036 if ((proto >= PROTOCOL_SMB3_11) && cli_smb2_fnum_is_posix(cli, fnum)) {
1037 struct security_ace ace = {
1038 .type = SEC_ACE_TYPE_ACCESS_ALLOWED,
1039 .trustee = global_sid_Unix_NFS_Mode,
1041 struct security_acl acl = {
1042 .revision = SECURITY_ACL_REVISION_NT4,
1043 .num_aces = 1,
1044 .aces = &ace,
1046 struct security_descriptor *sd = NULL;
1048 sid_append_rid(&ace.trustee, mode);
1050 sd = make_sec_desc(state,
1051 SECURITY_DESCRIPTOR_REVISION_1,
1052 SEC_DESC_SELF_RELATIVE |
1053 SEC_DESC_DACL_PRESENT,
1054 NULL,
1055 NULL,
1056 NULL,
1057 &acl,
1058 NULL);
1059 if (tevent_req_nomem(sd, req)) {
1060 return tevent_req_post(req, ev);
1063 subreq = cli_set_security_descriptor_send(
1064 state, ev, cli, fnum, SECINFO_DACL, sd);
1065 if (tevent_req_nomem(subreq, req)) {
1066 return tevent_req_post(req, ev);
1068 tevent_req_set_callback(subreq, cli_fchmod_done2, req);
1069 return req;
1072 tevent_req_nterror(req, NT_STATUS_INVALID_LEVEL);
1073 return tevent_req_post(req, ev);
1076 static void cli_fchmod_done1(struct tevent_req *subreq)
1078 NTSTATUS status = cli_setfileinfo_recv(subreq);
1079 tevent_req_simple_finish_ntstatus(subreq, status);
1082 static void cli_fchmod_done2(struct tevent_req *subreq)
1084 NTSTATUS status = cli_set_security_descriptor_recv(subreq);
1085 tevent_req_simple_finish_ntstatus(subreq, status);
1088 NTSTATUS cli_fchmod_recv(struct tevent_req *req)
1090 return tevent_req_simple_recv_ntstatus(req);
1093 struct cli_chmod_state {
1094 struct tevent_context *ev;
1095 struct cli_state *cli;
1096 mode_t mode;
1098 uint16_t fnum;
1100 NTSTATUS fchmod_status;
1102 uint8_t data[100]; /* smb1 posix extensions */
1105 static void cli_chmod_opened(struct tevent_req *subreq);
1106 static void cli_chmod_done(struct tevent_req *subreq);
1107 static void cli_chmod_closed(struct tevent_req *subreq);
1109 struct tevent_req *cli_chmod_send(TALLOC_CTX *mem_ctx,
1110 struct tevent_context *ev,
1111 struct cli_state *cli,
1112 const char *fname,
1113 mode_t mode)
1115 struct tevent_req *req = NULL, *subreq = NULL;
1116 struct cli_chmod_state *state = NULL;
1118 req = tevent_req_create(mem_ctx, &state, struct cli_chmod_state);
1119 if (req == NULL) {
1120 return NULL;
1122 state->ev = ev;
1123 state->cli = cli;
1124 state->mode = mode;
1126 subreq = cli_ntcreate_send(
1127 state, /* mem_ctx */
1128 ev, /* ev */
1129 cli, /* cli */
1130 fname, /* fname */
1131 0, /* create_flags */
1132 SEC_STD_WRITE_DAC, /* desired_access */
1133 0, /* file_attributes */
1134 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
1135 FILE_OPEN, /* create_disposition */
1136 0x0, /* create_options */
1137 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
1138 0x0); /* SecurityFlags */
1139 if (tevent_req_nomem(subreq, req)) {
1140 return tevent_req_post(req, ev);
1142 tevent_req_set_callback(subreq, cli_chmod_opened, req);
1143 return req;
1146 static void cli_chmod_opened(struct tevent_req *subreq)
1148 struct tevent_req *req = tevent_req_callback_data(subreq,
1149 struct tevent_req);
1150 struct cli_chmod_state *state = tevent_req_data(
1151 req, struct cli_chmod_state);
1152 NTSTATUS status;
1154 status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
1155 TALLOC_FREE(subreq);
1156 if (tevent_req_nterror(req, status)) {
1157 return;
1160 subreq = cli_fchmod_send(
1161 state, state->ev, state->cli, state->fnum, state->mode);
1162 if (tevent_req_nomem(subreq, req)) {
1163 return;
1165 tevent_req_set_callback(subreq, cli_chmod_done, req);
1168 static void cli_chmod_done(struct tevent_req *subreq)
1170 struct tevent_req *req = tevent_req_callback_data(subreq,
1171 struct tevent_req);
1172 struct cli_chmod_state *state = tevent_req_data(
1173 req, struct cli_chmod_state);
1175 state->fchmod_status = cli_fchmod_recv(subreq);
1176 TALLOC_FREE(subreq);
1178 subreq = cli_close_send(state, state->ev, state->cli, state->fnum, 0);
1179 if (tevent_req_nomem(subreq, req)) {
1180 return;
1182 tevent_req_set_callback(subreq, cli_chmod_closed, req);
1185 static void cli_chmod_closed(struct tevent_req *subreq)
1187 struct tevent_req *req = tevent_req_callback_data(subreq,
1188 struct tevent_req);
1189 NTSTATUS status;
1191 status = cli_close_recv(subreq);
1192 TALLOC_FREE(subreq);
1193 if (tevent_req_nterror(req, status)) {
1194 return;
1196 tevent_req_done(req);
1199 NTSTATUS cli_chmod_recv(struct tevent_req *req)
1201 struct cli_chmod_state *state = tevent_req_data(
1202 req, struct cli_chmod_state);
1203 NTSTATUS status;
1205 if (tevent_req_is_nterror(req, &status)) {
1206 tevent_req_received(req);
1207 return status;
1209 tevent_req_received(req);
1210 return state->fchmod_status;
1213 NTSTATUS cli_chmod(struct cli_state *cli, const char *fname, mode_t mode)
1215 TALLOC_CTX *frame = talloc_stackframe();
1216 struct tevent_context *ev = NULL;
1217 struct tevent_req *req = NULL;
1218 NTSTATUS status = NT_STATUS_NO_MEMORY;
1220 if (smbXcli_conn_has_async_calls(cli->conn)) {
1222 * Can't use sync call while an async call is in flight
1224 status = NT_STATUS_INVALID_PARAMETER;
1225 goto fail;
1227 ev = samba_tevent_context_init(frame);
1228 if (ev == NULL) {
1229 goto fail;
1231 req = cli_chmod_send(frame, ev, cli, fname, mode);
1232 if (req == NULL) {
1233 goto fail;
1235 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1236 goto fail;
1238 status = cli_chmod_recv(req);
1239 fail:
1240 TALLOC_FREE(frame);
1241 return status;
1244 /****************************************************************************
1245 chown a file (UNIX extensions).
1246 ****************************************************************************/
1248 struct cli_posix_chown_state {
1249 uint8_t dummy;
1252 static void cli_posix_chown_done(struct tevent_req *subreq);
1254 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1255 struct tevent_context *ev,
1256 struct cli_state *cli,
1257 const char *fname,
1258 uid_t uid,
1259 gid_t gid)
1261 struct tevent_req *req = NULL, *subreq = NULL;
1262 struct cli_posix_chown_state *state = NULL;
1264 req = tevent_req_create(
1265 mem_ctx, &state, struct cli_posix_chown_state);
1266 if (req == NULL) {
1267 return NULL;
1270 subreq = cli_posix_chown_chmod_internal_send(
1271 state,
1273 cli,
1274 fname,
1275 SMB_MODE_NO_CHANGE,
1276 (uint32_t)uid,
1277 (uint32_t)gid);
1278 if (tevent_req_nomem(subreq, req)) {
1279 return tevent_req_post(req, ev);
1281 tevent_req_set_callback(subreq, cli_posix_chown_done, req);
1282 return req;
1285 static void cli_posix_chown_done(struct tevent_req *subreq)
1287 NTSTATUS status = cli_posix_chown_chmod_internal_recv(subreq);
1288 tevent_req_simple_finish_ntstatus(subreq, status);
1291 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1293 return tevent_req_simple_recv_ntstatus(req);
1296 NTSTATUS cli_posix_chown(struct cli_state *cli,
1297 const char *fname,
1298 uid_t uid,
1299 gid_t gid)
1301 TALLOC_CTX *frame = talloc_stackframe();
1302 struct tevent_context *ev = NULL;
1303 struct tevent_req *req = NULL;
1304 NTSTATUS status = NT_STATUS_OK;
1306 if (smbXcli_conn_has_async_calls(cli->conn)) {
1308 * Can't use sync call while an async call is in flight
1310 status = NT_STATUS_INVALID_PARAMETER;
1311 goto fail;
1314 ev = samba_tevent_context_init(frame);
1315 if (ev == NULL) {
1316 status = NT_STATUS_NO_MEMORY;
1317 goto fail;
1320 req = cli_posix_chown_send(frame,
1322 cli,
1323 fname,
1324 uid,
1325 gid);
1326 if (req == NULL) {
1327 status = NT_STATUS_NO_MEMORY;
1328 goto fail;
1331 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1332 goto fail;
1335 status = cli_posix_chown_recv(req);
1337 fail:
1338 TALLOC_FREE(frame);
1339 return status;
1342 struct cli_smb1_posix_mknod_state {
1343 uint8_t data[100];
1346 static void cli_smb1_posix_mknod_done(struct tevent_req *subreq);
1348 static struct tevent_req *cli_smb1_posix_mknod_send(
1349 TALLOC_CTX *mem_ctx,
1350 struct tevent_context *ev,
1351 struct cli_state *cli,
1352 const char *fname,
1353 mode_t mode,
1354 dev_t dev)
1356 struct tevent_req *req = NULL, *subreq = NULL;
1357 struct cli_smb1_posix_mknod_state *state = NULL;
1358 mode_t type = mode & S_IFMT;
1359 uint32_t smb_unix_type = 0xFFFFFFFF;
1361 req = tevent_req_create(
1362 mem_ctx, &state, struct cli_smb1_posix_mknod_state);
1363 if (req == NULL) {
1364 return NULL;
1367 * Set all sizes/times/ids to no change.
1369 memset(state->data, 0xff, 56);
1371 switch (type) {
1372 case S_IFREG:
1373 smb_unix_type = UNIX_TYPE_FILE;
1374 break;
1375 case S_IFDIR:
1376 smb_unix_type = UNIX_TYPE_DIR;
1377 break;
1378 case S_IFLNK:
1379 smb_unix_type = UNIX_TYPE_SYMLINK;
1380 break;
1381 case S_IFCHR:
1382 smb_unix_type = UNIX_TYPE_CHARDEV;
1383 break;
1384 case S_IFBLK:
1385 smb_unix_type = UNIX_TYPE_BLKDEV;
1386 break;
1387 case S_IFIFO:
1388 smb_unix_type = UNIX_TYPE_FIFO;
1389 break;
1390 case S_IFSOCK:
1391 smb_unix_type = UNIX_TYPE_SOCKET;
1392 break;
1394 PUSH_LE_U32(state->data, 56, smb_unix_type);
1396 if ((type == S_IFCHR) || (type == S_IFBLK)) {
1397 PUSH_LE_U64(state->data, 60, unix_dev_major(dev));
1398 PUSH_LE_U64(state->data, 68, unix_dev_minor(dev));
1401 PUSH_LE_U32(state->data, 84, unix_perms_to_wire(mode));
1403 subreq = cli_setpathinfo_send(
1404 state,
1406 cli,
1407 SMB_SET_FILE_UNIX_BASIC,
1408 fname,
1409 state->data,
1410 sizeof(state->data));
1411 if (tevent_req_nomem(subreq, req)) {
1412 return tevent_req_post(req, ev);
1414 tevent_req_set_callback(subreq, cli_smb1_posix_mknod_done, req);
1415 return req;
1418 static void cli_smb1_posix_mknod_done(struct tevent_req *subreq)
1420 NTSTATUS status = cli_setpathinfo_recv(subreq);
1421 tevent_req_simple_finish_ntstatus(subreq, status);
1424 static NTSTATUS cli_smb1_posix_mknod_recv(struct tevent_req *req)
1426 return tevent_req_simple_recv_ntstatus(req);
1429 struct cli_mknod_state {
1430 uint8_t buf[24];
1433 static void cli_mknod_done1(struct tevent_req *subreq);
1434 static void cli_mknod_reparse_done(struct tevent_req *subreq);
1436 struct tevent_req *cli_mknod_send(
1437 TALLOC_CTX *mem_ctx,
1438 struct tevent_context *ev,
1439 struct cli_state *cli,
1440 const char *fname,
1441 mode_t mode,
1442 dev_t dev)
1444 struct tevent_req *req = NULL, *subreq = NULL;
1445 struct cli_mknod_state *state = NULL;
1446 struct reparse_data_buffer reparse_buf = {
1447 .tag = IO_REPARSE_TAG_NFS,
1449 struct nfs_reparse_data_buffer *nfs = &reparse_buf.parsed.nfs;
1450 ssize_t buflen;
1452 req = tevent_req_create(mem_ctx, &state, struct cli_mknod_state);
1453 if (req == NULL) {
1454 return NULL;
1457 if (cli->requested_posix_capabilities != 0) {
1458 subreq = cli_smb1_posix_mknod_send(
1459 state, ev, cli, fname, mode, dev);
1460 if (tevent_req_nomem(subreq, req)) {
1461 return tevent_req_post(req, ev);
1463 tevent_req_set_callback(subreq, cli_mknod_done1, req);
1464 return req;
1468 * Ignored for all but BLK and CHR
1470 nfs->data.dev.major = major(dev);
1471 nfs->data.dev.minor = minor(dev);
1473 switch (mode & S_IFMT) {
1474 case S_IFIFO:
1475 nfs->type = NFS_SPECFILE_FIFO;
1476 break;
1477 case S_IFSOCK:
1478 nfs->type = NFS_SPECFILE_SOCK;
1479 break;
1480 case S_IFCHR:
1481 nfs->type = NFS_SPECFILE_CHR;
1482 break;
1483 case S_IFBLK:
1484 nfs->type = NFS_SPECFILE_BLK;
1485 break;
1488 buflen = reparse_data_buffer_marshall(&reparse_buf,
1489 state->buf,
1490 sizeof(state->buf));
1491 if ((buflen == -1) || (buflen > sizeof(state->buf))) {
1492 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1493 return tevent_req_post(req, ev);
1496 subreq = cli_create_reparse_point_send(state,
1498 cli,
1499 fname,
1500 (DATA_BLOB){
1501 .data = state->buf,
1502 .length = buflen,
1504 if (tevent_req_nomem(subreq, req)) {
1505 return tevent_req_post(req, ev);
1507 tevent_req_set_callback(subreq, cli_mknod_reparse_done, req);
1508 return req;
1511 static void cli_mknod_done1(struct tevent_req *subreq)
1513 NTSTATUS status = cli_smb1_posix_mknod_recv(subreq);
1514 tevent_req_simple_finish_ntstatus(subreq, status);
1517 static void cli_mknod_reparse_done(struct tevent_req *subreq)
1519 NTSTATUS status = cli_create_reparse_point_recv(subreq);
1520 tevent_req_simple_finish_ntstatus(subreq, status);
1523 NTSTATUS cli_mknod_recv(struct tevent_req *req)
1525 return tevent_req_simple_recv_ntstatus(req);
1528 NTSTATUS
1529 cli_mknod(struct cli_state *cli, const char *fname, mode_t mode, dev_t dev)
1531 TALLOC_CTX *frame = talloc_stackframe();
1532 struct tevent_context *ev;
1533 struct tevent_req *req;
1534 NTSTATUS status = NT_STATUS_NO_MEMORY;
1536 if (smbXcli_conn_has_async_calls(cli->conn)) {
1538 * Can't use sync call while an async call is in flight
1540 status = NT_STATUS_INVALID_PARAMETER;
1541 goto fail;
1543 ev = samba_tevent_context_init(frame);
1544 if (ev == NULL) {
1545 goto fail;
1547 req = cli_mknod_send(ev, ev, cli, fname, mode, dev);
1548 if (req == NULL) {
1549 goto fail;
1551 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1552 goto fail;
1554 status = cli_mknod_recv(req);
1555 fail:
1556 TALLOC_FREE(frame);
1557 return status;
1560 /****************************************************************************
1561 Rename a file.
1562 ****************************************************************************/
1564 struct cli_smb1_rename_state {
1565 uint8_t *data;
1568 static void cli_smb1_rename_done(struct tevent_req *subreq);
1570 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1571 struct tevent_context *ev,
1572 struct cli_state *cli,
1573 const char *fname_src,
1574 const char *fname_dst,
1575 bool replace)
1577 NTSTATUS status;
1578 struct tevent_req *req = NULL, *subreq = NULL;
1579 struct cli_smb1_rename_state *state = NULL;
1580 smb_ucs2_t *converted_str = NULL;
1581 size_t converted_size_bytes = 0;
1583 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
1584 if (req == NULL) {
1585 return NULL;
1589 * Strip a MSDFS path from fname_dst if we were given one.
1591 status = cli_dfs_target_check(state,
1592 cli,
1593 fname_dst,
1594 &fname_dst);
1595 if (!NT_STATUS_IS_OK(status)) {
1596 goto fail;
1599 if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
1600 &converted_size_bytes)) {
1601 status = NT_STATUS_INVALID_PARAMETER;
1602 goto fail;
1605 /* W2K8 insists the dest name is not null
1606 terminated. Remove the last 2 zero bytes
1607 and reduce the name length. */
1609 if (converted_size_bytes < 2) {
1610 status = NT_STATUS_INVALID_PARAMETER;
1611 goto fail;
1613 converted_size_bytes -= 2;
1615 state->data =
1616 talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
1617 if (state->data == NULL) {
1618 status = NT_STATUS_NO_MEMORY;
1619 goto fail;
1622 if (replace) {
1623 SCVAL(state->data, 0, 1);
1626 SIVAL(state->data, 8, converted_size_bytes);
1627 memcpy(state->data + 12, converted_str, converted_size_bytes);
1629 TALLOC_FREE(converted_str);
1631 subreq = cli_setpathinfo_send(
1632 state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
1633 talloc_get_size(state->data));
1634 if (tevent_req_nomem(subreq, req)) {
1635 status = NT_STATUS_NO_MEMORY;
1636 goto fail;
1638 tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
1639 return req;
1641 fail:
1642 TALLOC_FREE(converted_str);
1643 tevent_req_nterror(req, status);
1644 return tevent_req_post(req, ev);
1647 static void cli_smb1_rename_done(struct tevent_req *subreq)
1649 NTSTATUS status = cli_setpathinfo_recv(subreq);
1650 tevent_req_simple_finish_ntstatus(subreq, status);
1653 static NTSTATUS cli_smb1_rename_recv(struct tevent_req *req)
1655 return tevent_req_simple_recv_ntstatus(req);
1658 static void cli_cifs_rename_done(struct tevent_req *subreq);
1660 struct cli_cifs_rename_state {
1661 uint16_t vwv[1];
1664 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1665 struct tevent_context *ev,
1666 struct cli_state *cli,
1667 const char *fname_src,
1668 const char *fname_dst,
1669 bool replace)
1671 struct tevent_req *req = NULL, *subreq = NULL;
1672 struct cli_cifs_rename_state *state = NULL;
1673 uint8_t additional_flags = 0;
1674 uint16_t additional_flags2 = 0;
1675 uint8_t *bytes = NULL;
1676 char *fname_src_cp = NULL;
1677 char *fname_dst_cp = NULL;
1679 req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
1680 if (req == NULL) {
1681 return NULL;
1684 if (replace) {
1686 * CIFS doesn't support replace
1688 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1689 return tevent_req_post(req, ev);
1692 SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1694 bytes = talloc_array(state, uint8_t, 1);
1695 if (tevent_req_nomem(bytes, req)) {
1696 return tevent_req_post(req, ev);
1700 * SMBmv on a DFS share uses DFS names for src and dst.
1701 * See smbtorture3: SMB1-DFS-PATHS: test_smb1_mv().
1704 fname_src_cp = smb1_dfs_share_path(state, cli, fname_src);
1705 if (tevent_req_nomem(fname_src_cp, req)) {
1706 return tevent_req_post(req, ev);
1708 bytes[0] = 4;
1709 bytes = smb_bytes_push_str(bytes,
1710 smbXcli_conn_use_unicode(cli->conn),
1711 fname_src_cp,
1712 strlen(fname_src_cp)+1,
1713 NULL);
1714 if (tevent_req_nomem(bytes, req)) {
1715 return tevent_req_post(req, ev);
1718 if (clistr_is_previous_version_path(fname_src)) {
1719 additional_flags2 = FLAGS2_REPARSE_PATH;
1722 bytes = talloc_realloc(state, bytes, uint8_t,
1723 talloc_get_size(bytes)+1);
1724 if (tevent_req_nomem(bytes, req)) {
1725 return tevent_req_post(req, ev);
1729 * SMBmv on a DFS share uses DFS names for src and dst.
1730 * See smbtorture3: SMB1-DFS-PATHS: test_smb1_mv().
1733 fname_dst_cp = smb1_dfs_share_path(state, cli, fname_dst);
1734 if (tevent_req_nomem(fname_dst_cp, req)) {
1735 return tevent_req_post(req, ev);
1737 bytes[talloc_get_size(bytes)-1] = 4;
1738 bytes = smb_bytes_push_str(bytes,
1739 smbXcli_conn_use_unicode(cli->conn),
1740 fname_dst_cp,
1741 strlen(fname_dst_cp)+1,
1742 NULL);
1743 if (tevent_req_nomem(bytes, req)) {
1744 return tevent_req_post(req, ev);
1747 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1748 additional_flags2,
1749 1, state->vwv, talloc_get_size(bytes), bytes);
1750 if (tevent_req_nomem(subreq, req)) {
1751 return tevent_req_post(req, ev);
1753 tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
1754 return req;
1757 static void cli_cifs_rename_done(struct tevent_req *subreq)
1759 NTSTATUS status = cli_smb_recv(
1760 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1761 tevent_req_simple_finish_ntstatus(subreq, status);
1764 static NTSTATUS cli_cifs_rename_recv(struct tevent_req *req)
1766 return tevent_req_simple_recv_ntstatus(req);
1769 struct cli_rename_state {
1770 uint8_t dummy;
1773 static void cli_rename_done1(struct tevent_req *subreq);
1774 static void cli_rename_done_cifs(struct tevent_req *subreq);
1775 static void cli_rename_done2(struct tevent_req *subreq);
1777 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1778 struct tevent_context *ev,
1779 struct cli_state *cli,
1780 const char *fname_src,
1781 const char *fname_dst,
1782 bool replace)
1784 struct tevent_req *req = NULL, *subreq = NULL;
1785 struct cli_rename_state *state = NULL;
1787 req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1788 if (req == NULL) {
1789 return NULL;
1792 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1793 subreq = cli_smb2_rename_send(
1794 state, ev, cli, fname_src, fname_dst, replace);
1795 if (tevent_req_nomem(subreq, req)) {
1796 return tevent_req_post(req, ev);
1798 tevent_req_set_callback(subreq, cli_rename_done2, req);
1799 return req;
1802 if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
1803 subreq = cli_smb1_rename_send(
1804 state, ev, cli, fname_src, fname_dst, replace);
1805 if (tevent_req_nomem(subreq, req)) {
1806 return tevent_req_post(req, ev);
1808 tevent_req_set_callback(subreq, cli_rename_done1, req);
1809 return req;
1812 subreq = cli_cifs_rename_send(
1813 state, ev, cli, fname_src,fname_dst, replace);
1814 if (tevent_req_nomem(subreq, req)) {
1815 return tevent_req_post(req, ev);
1817 tevent_req_set_callback(subreq, cli_rename_done_cifs, req);
1818 return req;
1821 static void cli_rename_done1(struct tevent_req *subreq)
1823 NTSTATUS status = cli_smb1_rename_recv(subreq);
1824 tevent_req_simple_finish_ntstatus(subreq, status);
1827 static void cli_rename_done_cifs(struct tevent_req *subreq)
1829 NTSTATUS status = cli_cifs_rename_recv(subreq);
1830 tevent_req_simple_finish_ntstatus(subreq, status);
1833 static void cli_rename_done2(struct tevent_req *subreq)
1835 NTSTATUS status = cli_smb2_rename_recv(subreq);
1836 tevent_req_simple_finish_ntstatus(subreq, status);
1839 NTSTATUS cli_rename_recv(struct tevent_req *req)
1841 return tevent_req_simple_recv_ntstatus(req);
1844 NTSTATUS cli_rename(struct cli_state *cli,
1845 const char *fname_src,
1846 const char *fname_dst,
1847 bool replace)
1849 TALLOC_CTX *frame = NULL;
1850 struct tevent_context *ev;
1851 struct tevent_req *req;
1852 NTSTATUS status = NT_STATUS_OK;
1854 frame = talloc_stackframe();
1856 if (smbXcli_conn_has_async_calls(cli->conn)) {
1858 * Can't use sync call while an async call is in flight
1860 status = NT_STATUS_INVALID_PARAMETER;
1861 goto fail;
1864 ev = samba_tevent_context_init(frame);
1865 if (ev == NULL) {
1866 status = NT_STATUS_NO_MEMORY;
1867 goto fail;
1870 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
1871 if (req == NULL) {
1872 status = NT_STATUS_NO_MEMORY;
1873 goto fail;
1876 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1877 goto fail;
1880 status = cli_rename_recv(req);
1881 fail:
1882 TALLOC_FREE(frame);
1883 return status;
1886 /****************************************************************************
1887 NT Rename a file.
1888 ****************************************************************************/
1890 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1892 struct cli_ntrename_internal_state {
1893 uint16_t vwv[4];
1896 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1897 struct tevent_context *ev,
1898 struct cli_state *cli,
1899 const char *fname_src,
1900 const char *fname_dst,
1901 uint16_t rename_flag)
1903 struct tevent_req *req = NULL, *subreq = NULL;
1904 struct cli_ntrename_internal_state *state = NULL;
1905 uint8_t additional_flags = 0;
1906 uint16_t additional_flags2 = 0;
1907 uint8_t *bytes = NULL;
1908 char *fname_src_cp = NULL;
1909 char *fname_dst_cp = NULL;
1911 req = tevent_req_create(mem_ctx, &state,
1912 struct cli_ntrename_internal_state);
1913 if (req == NULL) {
1914 return NULL;
1917 SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1918 SSVAL(state->vwv+1, 0, rename_flag);
1920 bytes = talloc_array(state, uint8_t, 1);
1921 if (tevent_req_nomem(bytes, req)) {
1922 return tevent_req_post(req, ev);
1925 * SMBntrename on a DFS share uses DFS names for src and dst.
1926 * See smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_rename().
1928 fname_src_cp = smb1_dfs_share_path(state, cli, fname_src);
1929 if (tevent_req_nomem(fname_src_cp, req)) {
1930 return tevent_req_post(req, ev);
1932 bytes[0] = 4;
1933 bytes = smb_bytes_push_str(bytes,
1934 smbXcli_conn_use_unicode(cli->conn),
1935 fname_src_cp,
1936 strlen(fname_src_cp)+1,
1937 NULL);
1938 if (tevent_req_nomem(bytes, req)) {
1939 return tevent_req_post(req, ev);
1942 if (clistr_is_previous_version_path(fname_src)) {
1943 additional_flags2 = FLAGS2_REPARSE_PATH;
1946 bytes = talloc_realloc(state, bytes, uint8_t,
1947 talloc_get_size(bytes)+1);
1948 if (tevent_req_nomem(bytes, req)) {
1949 return tevent_req_post(req, ev);
1953 * SMBntrename on a DFS share uses DFS names for src and dst.
1954 * See smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_rename().
1955 * and smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_hardlink()
1957 fname_dst_cp = smb1_dfs_share_path(state, cli, fname_dst);
1958 if (tevent_req_nomem(fname_dst_cp, req)) {
1959 return tevent_req_post(req, ev);
1961 bytes[talloc_get_size(bytes)-1] = 4;
1962 bytes = smb_bytes_push_str(bytes,
1963 smbXcli_conn_use_unicode(cli->conn),
1964 fname_dst_cp,
1965 strlen(fname_dst_cp)+1,
1966 NULL);
1967 if (tevent_req_nomem(bytes, req)) {
1968 return tevent_req_post(req, ev);
1971 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1972 additional_flags2,
1973 4, state->vwv, talloc_get_size(bytes), bytes);
1974 if (tevent_req_nomem(subreq, req)) {
1975 return tevent_req_post(req, ev);
1977 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1978 return req;
1981 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1983 NTSTATUS status = cli_smb_recv(
1984 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1985 tevent_req_simple_finish_ntstatus(subreq, status);
1988 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1990 return tevent_req_simple_recv_ntstatus(req);
1993 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1994 struct tevent_context *ev,
1995 struct cli_state *cli,
1996 const char *fname_src,
1997 const char *fname_dst)
1999 return cli_ntrename_internal_send(mem_ctx,
2001 cli,
2002 fname_src,
2003 fname_dst,
2004 RENAME_FLAG_RENAME);
2007 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
2009 return cli_ntrename_internal_recv(req);
2012 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
2014 TALLOC_CTX *frame = talloc_stackframe();
2015 struct tevent_context *ev;
2016 struct tevent_req *req;
2017 NTSTATUS status = NT_STATUS_OK;
2019 if (smbXcli_conn_has_async_calls(cli->conn)) {
2021 * Can't use sync call while an async call is in flight
2023 status = NT_STATUS_INVALID_PARAMETER;
2024 goto fail;
2027 ev = samba_tevent_context_init(frame);
2028 if (ev == NULL) {
2029 status = NT_STATUS_NO_MEMORY;
2030 goto fail;
2033 req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
2034 if (req == NULL) {
2035 status = NT_STATUS_NO_MEMORY;
2036 goto fail;
2039 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2040 goto fail;
2043 status = cli_ntrename_recv(req);
2045 fail:
2046 TALLOC_FREE(frame);
2047 return status;
2050 /****************************************************************************
2051 NT hardlink a file.
2052 ****************************************************************************/
2054 static struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
2055 struct tevent_context *ev,
2056 struct cli_state *cli,
2057 const char *fname_src,
2058 const char *fname_dst)
2060 return cli_ntrename_internal_send(mem_ctx,
2062 cli,
2063 fname_src,
2064 fname_dst,
2065 RENAME_FLAG_HARD_LINK);
2068 static NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
2070 return cli_ntrename_internal_recv(req);
2073 struct cli_smb2_hardlink_state {
2074 struct tevent_context *ev;
2075 struct cli_state *cli;
2076 uint16_t fnum_src;
2077 const char *fname_dst;
2078 bool overwrite;
2079 NTSTATUS status;
2082 static void cli_smb2_hardlink_opened(struct tevent_req *subreq);
2083 static void cli_smb2_hardlink_info_set(struct tevent_req *subreq);
2084 static void cli_smb2_hardlink_closed(struct tevent_req *subreq);
2086 static struct tevent_req *cli_smb2_hardlink_send(
2087 TALLOC_CTX *mem_ctx,
2088 struct tevent_context *ev,
2089 struct cli_state *cli,
2090 const char *fname_src,
2091 const char *fname_dst,
2092 bool overwrite,
2093 struct smb2_create_blobs *in_cblobs)
2095 struct tevent_req *req = NULL, *subreq = NULL;
2096 struct cli_smb2_hardlink_state *state = NULL;
2097 NTSTATUS status;
2099 req = tevent_req_create(
2100 mem_ctx, &state, struct cli_smb2_hardlink_state);
2101 if (req == NULL) {
2102 return NULL;
2106 * Strip a MSDFS path from fname_dst if we were given one.
2108 status = cli_dfs_target_check(state,
2109 cli,
2110 fname_dst,
2111 &fname_dst);
2112 if (tevent_req_nterror(req, status)) {
2113 return tevent_req_post(req, ev);
2116 state->ev = ev;
2117 state->cli = cli;
2118 state->fname_dst = fname_dst;
2119 state->overwrite = overwrite;
2121 subreq = cli_smb2_create_fnum_send(
2122 state,
2124 cli,
2125 fname_src,
2126 (struct cli_smb2_create_flags){0},
2127 SMB2_IMPERSONATION_IMPERSONATION,
2128 FILE_WRITE_ATTRIBUTES,
2129 0, /* file attributes */
2130 FILE_SHARE_READ|
2131 FILE_SHARE_WRITE|
2132 FILE_SHARE_DELETE, /* share_access */
2133 FILE_OPEN, /* create_disposition */
2134 FILE_NON_DIRECTORY_FILE, /* no hardlinks on directories */
2135 in_cblobs);
2136 if (tevent_req_nomem(subreq, req)) {
2137 return tevent_req_post(req, ev);
2139 tevent_req_set_callback(subreq, cli_smb2_hardlink_opened, req);
2140 return req;
2143 static void cli_smb2_hardlink_opened(struct tevent_req *subreq)
2145 struct tevent_req *req = tevent_req_callback_data(
2146 subreq, struct tevent_req);
2147 struct cli_smb2_hardlink_state *state = tevent_req_data(
2148 req, struct cli_smb2_hardlink_state);
2149 NTSTATUS status;
2150 smb_ucs2_t *ucs2_dst;
2151 size_t ucs2_len;
2152 DATA_BLOB inbuf;
2153 bool ok;
2155 status = cli_smb2_create_fnum_recv(
2156 subreq, &state->fnum_src, NULL, NULL, NULL, NULL);
2157 TALLOC_FREE(subreq);
2158 if (tevent_req_nterror(req, status)) {
2159 return;
2162 ok = push_ucs2_talloc(state, &ucs2_dst, state->fname_dst, &ucs2_len);
2163 if (!ok || (ucs2_len < 2)) {
2164 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2165 return;
2167 /* Don't 0-terminate the name */
2168 ucs2_len -= 2;
2170 inbuf = data_blob_talloc_zero(state, ucs2_len + 20);
2171 if (tevent_req_nomem(inbuf.data, req)) {
2172 return;
2175 if (state->overwrite) {
2176 SCVAL(inbuf.data, 0, 1);
2178 SIVAL(inbuf.data, 16, ucs2_len);
2179 memcpy(inbuf.data + 20, ucs2_dst, ucs2_len);
2180 TALLOC_FREE(ucs2_dst);
2182 subreq = cli_smb2_set_info_fnum_send(
2183 state,
2184 state->ev,
2185 state->cli,
2186 state->fnum_src,
2187 SMB2_0_INFO_FILE, /* in_info_type */
2188 FSCC_FILE_LINK_INFORMATION, /* in_file_info_class */
2189 &inbuf,
2190 0); /* in_additional_info */
2191 if (tevent_req_nomem(subreq, req)) {
2192 return;
2194 tevent_req_set_callback(subreq, cli_smb2_hardlink_info_set, req);
2197 static void cli_smb2_hardlink_info_set(struct tevent_req *subreq)
2199 struct tevent_req *req = tevent_req_callback_data(
2200 subreq, struct tevent_req);
2201 struct cli_smb2_hardlink_state *state = tevent_req_data(
2202 req, struct cli_smb2_hardlink_state);
2204 state->status = cli_smb2_set_info_fnum_recv(subreq);
2205 TALLOC_FREE(subreq);
2207 /* ignore error here, we need to close the file */
2209 subreq = cli_smb2_close_fnum_send(state,
2210 state->ev,
2211 state->cli,
2212 state->fnum_src,
2214 if (tevent_req_nomem(subreq, req)) {
2215 return;
2217 tevent_req_set_callback(subreq, cli_smb2_hardlink_closed, req);
2220 static void cli_smb2_hardlink_closed(struct tevent_req *subreq)
2222 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
2223 tevent_req_simple_finish_ntstatus(subreq, status);
2226 static NTSTATUS cli_smb2_hardlink_recv(struct tevent_req *req)
2228 struct cli_smb2_hardlink_state *state = tevent_req_data(
2229 req, struct cli_smb2_hardlink_state);
2230 NTSTATUS status;
2232 if (tevent_req_is_nterror(req, &status)) {
2233 return status;
2235 return state->status;
2238 struct cli_hardlink_state {
2239 uint8_t dummy;
2242 static void cli_hardlink_done(struct tevent_req *subreq);
2243 static void cli_hardlink_done2(struct tevent_req *subreq);
2245 struct tevent_req *cli_hardlink_send(
2246 TALLOC_CTX *mem_ctx,
2247 struct tevent_context *ev,
2248 struct cli_state *cli,
2249 const char *fname_src,
2250 const char *fname_dst)
2252 struct tevent_req *req = NULL, *subreq = NULL;
2253 struct cli_hardlink_state *state;
2255 req = tevent_req_create(mem_ctx, &state, struct cli_hardlink_state);
2256 if (req == NULL) {
2257 return NULL;
2260 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2261 subreq = cli_smb2_hardlink_send(
2262 state, ev, cli, fname_src, fname_dst, false, NULL);
2263 if (tevent_req_nomem(subreq, req)) {
2264 return tevent_req_post(req, ev);
2266 tevent_req_set_callback(subreq, cli_hardlink_done2, req);
2267 return req;
2270 subreq = cli_nt_hardlink_send(state, ev, cli, fname_src, fname_dst);
2271 if (tevent_req_nomem(subreq, req)) {
2272 return tevent_req_post(req, ev);
2274 tevent_req_set_callback(subreq, cli_hardlink_done, req);
2275 return req;
2278 static void cli_hardlink_done(struct tevent_req *subreq)
2280 NTSTATUS status = cli_nt_hardlink_recv(subreq);
2281 tevent_req_simple_finish_ntstatus(subreq, status);
2284 static void cli_hardlink_done2(struct tevent_req *subreq)
2286 NTSTATUS status = cli_smb2_hardlink_recv(subreq);
2287 tevent_req_simple_finish_ntstatus(subreq, status);
2290 NTSTATUS cli_hardlink_recv(struct tevent_req *req)
2292 return tevent_req_simple_recv_ntstatus(req);
2295 NTSTATUS cli_hardlink(
2296 struct cli_state *cli, const char *fname_src, const char *fname_dst)
2298 TALLOC_CTX *frame = talloc_stackframe();
2299 struct tevent_context *ev = NULL;
2300 struct tevent_req *req = NULL;
2301 NTSTATUS status = NT_STATUS_NO_MEMORY;
2303 if (smbXcli_conn_has_async_calls(cli->conn)) {
2304 status = NT_STATUS_INVALID_PARAMETER;
2305 goto fail;
2307 ev = samba_tevent_context_init(frame);
2308 if (ev == NULL) {
2309 goto fail;
2311 req = cli_hardlink_send(frame, ev, cli, fname_src, fname_dst);
2312 if (req == NULL) {
2313 goto fail;
2315 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2316 goto fail;
2318 status = cli_hardlink_recv(req);
2319 fail:
2320 TALLOC_FREE(frame);
2321 return status;
2324 /****************************************************************************
2325 Delete a file.
2326 ****************************************************************************/
2328 static void cli_unlink_done(struct tevent_req *subreq);
2329 static void cli_unlink_done2(struct tevent_req *subreq);
2331 struct cli_unlink_state {
2332 uint16_t vwv[1];
2335 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
2336 struct tevent_context *ev,
2337 struct cli_state *cli,
2338 const char *fname,
2339 uint32_t mayhave_attrs)
2341 struct tevent_req *req = NULL, *subreq = NULL;
2342 struct cli_unlink_state *state = NULL;
2343 uint8_t additional_flags = 0;
2344 uint16_t additional_flags2 = 0;
2345 uint8_t *bytes = NULL;
2346 char *fname_cp = NULL;
2348 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
2349 if (req == NULL) {
2350 return NULL;
2353 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2354 subreq = cli_smb2_unlink_send(state, ev, cli, fname, NULL);
2355 if (tevent_req_nomem(subreq, req)) {
2356 return tevent_req_post(req, ev);
2358 tevent_req_set_callback(subreq, cli_unlink_done2, req);
2359 return req;
2362 if (mayhave_attrs & 0xFFFF0000) {
2364 * Don't allow attributes greater than
2365 * 16-bits for a 16-bit protocol value.
2367 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2368 return tevent_req_post(req, ev);
2371 SSVAL(state->vwv+0, 0, mayhave_attrs);
2373 bytes = talloc_array(state, uint8_t, 1);
2374 if (tevent_req_nomem(bytes, req)) {
2375 return tevent_req_post(req, ev);
2378 * SMBunlink on a DFS share must use DFS names.
2380 fname_cp = smb1_dfs_share_path(state, cli, fname);
2381 if (tevent_req_nomem(fname_cp, req)) {
2382 return tevent_req_post(req, ev);
2384 bytes[0] = 4;
2385 bytes = smb_bytes_push_str(bytes,
2386 smbXcli_conn_use_unicode(cli->conn),
2387 fname_cp,
2388 strlen(fname_cp)+1,
2389 NULL);
2391 if (tevent_req_nomem(bytes, req)) {
2392 return tevent_req_post(req, ev);
2395 if (clistr_is_previous_version_path(fname)) {
2396 additional_flags2 = FLAGS2_REPARSE_PATH;
2399 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
2400 additional_flags2,
2401 1, state->vwv, talloc_get_size(bytes), bytes);
2402 if (tevent_req_nomem(subreq, req)) {
2403 return tevent_req_post(req, ev);
2405 tevent_req_set_callback(subreq, cli_unlink_done, req);
2406 return req;
2409 static void cli_unlink_done(struct tevent_req *subreq)
2411 NTSTATUS status = cli_smb_recv(
2412 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2413 tevent_req_simple_finish_ntstatus(subreq, status);
2416 static void cli_unlink_done2(struct tevent_req *subreq)
2418 NTSTATUS status = cli_smb2_unlink_recv(subreq);
2419 tevent_req_simple_finish_ntstatus(subreq, status);
2422 NTSTATUS cli_unlink_recv(struct tevent_req *req)
2424 return tevent_req_simple_recv_ntstatus(req);
2427 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint32_t mayhave_attrs)
2429 TALLOC_CTX *frame = NULL;
2430 struct tevent_context *ev;
2431 struct tevent_req *req;
2432 NTSTATUS status = NT_STATUS_OK;
2434 frame = talloc_stackframe();
2436 if (smbXcli_conn_has_async_calls(cli->conn)) {
2438 * Can't use sync call while an async call is in flight
2440 status = NT_STATUS_INVALID_PARAMETER;
2441 goto fail;
2444 ev = samba_tevent_context_init(frame);
2445 if (ev == NULL) {
2446 status = NT_STATUS_NO_MEMORY;
2447 goto fail;
2450 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
2451 if (req == NULL) {
2452 status = NT_STATUS_NO_MEMORY;
2453 goto fail;
2456 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2457 goto fail;
2460 status = cli_unlink_recv(req);
2461 fail:
2462 TALLOC_FREE(frame);
2463 return status;
2466 /****************************************************************************
2467 Create a directory.
2468 ****************************************************************************/
2470 static void cli_mkdir_done(struct tevent_req *subreq);
2471 static void cli_mkdir_done2(struct tevent_req *subreq);
2473 struct cli_mkdir_state {
2474 int dummy;
2477 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
2478 struct tevent_context *ev,
2479 struct cli_state *cli,
2480 const char *dname)
2482 struct tevent_req *req = NULL, *subreq = NULL;
2483 struct cli_mkdir_state *state = NULL;
2484 uint8_t additional_flags = 0;
2485 uint16_t additional_flags2 = 0;
2486 uint8_t *bytes = NULL;
2487 char *dname_cp = NULL;
2489 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
2490 if (req == NULL) {
2491 return NULL;
2494 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2495 subreq = cli_smb2_mkdir_send(state, ev, cli, dname);
2496 if (tevent_req_nomem(subreq, req)) {
2497 return tevent_req_post(req, ev);
2499 tevent_req_set_callback(subreq, cli_mkdir_done2, req);
2500 return req;
2503 bytes = talloc_array(state, uint8_t, 1);
2504 if (tevent_req_nomem(bytes, req)) {
2505 return tevent_req_post(req, ev);
2508 * SMBmkdir on a DFS share must use DFS names.
2510 dname_cp = smb1_dfs_share_path(state, cli, dname);
2511 if (tevent_req_nomem(dname_cp, req)) {
2512 return tevent_req_post(req, ev);
2514 bytes[0] = 4;
2515 bytes = smb_bytes_push_str(bytes,
2516 smbXcli_conn_use_unicode(cli->conn),
2517 dname_cp,
2518 strlen(dname_cp)+1,
2519 NULL);
2521 if (tevent_req_nomem(bytes, req)) {
2522 return tevent_req_post(req, ev);
2525 if (clistr_is_previous_version_path(dname)) {
2526 additional_flags2 = FLAGS2_REPARSE_PATH;
2529 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
2530 additional_flags2,
2531 0, NULL, talloc_get_size(bytes), bytes);
2532 if (tevent_req_nomem(subreq, req)) {
2533 return tevent_req_post(req, ev);
2535 tevent_req_set_callback(subreq, cli_mkdir_done, req);
2536 return req;
2539 static void cli_mkdir_done(struct tevent_req *subreq)
2541 struct tevent_req *req = tevent_req_callback_data(
2542 subreq, struct tevent_req);
2543 NTSTATUS status;
2545 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2546 TALLOC_FREE(subreq);
2547 if (tevent_req_nterror(req, status)) {
2548 return;
2550 tevent_req_done(req);
2553 static void cli_mkdir_done2(struct tevent_req *subreq)
2555 NTSTATUS status = cli_smb2_mkdir_recv(subreq);
2556 tevent_req_simple_finish_ntstatus(subreq, status);
2559 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
2561 return tevent_req_simple_recv_ntstatus(req);
2564 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
2566 TALLOC_CTX *frame = NULL;
2567 struct tevent_context *ev;
2568 struct tevent_req *req;
2569 NTSTATUS status = NT_STATUS_OK;
2571 frame = talloc_stackframe();
2573 if (smbXcli_conn_has_async_calls(cli->conn)) {
2575 * Can't use sync call while an async call is in flight
2577 status = NT_STATUS_INVALID_PARAMETER;
2578 goto fail;
2581 ev = samba_tevent_context_init(frame);
2582 if (ev == NULL) {
2583 status = NT_STATUS_NO_MEMORY;
2584 goto fail;
2587 req = cli_mkdir_send(frame, ev, cli, dname);
2588 if (req == NULL) {
2589 status = NT_STATUS_NO_MEMORY;
2590 goto fail;
2593 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2594 goto fail;
2597 status = cli_mkdir_recv(req);
2598 fail:
2599 TALLOC_FREE(frame);
2600 return status;
2603 /****************************************************************************
2604 Remove a directory.
2605 ****************************************************************************/
2607 static void cli_rmdir_done(struct tevent_req *subreq);
2608 static void cli_rmdir_done2(struct tevent_req *subreq);
2610 struct cli_rmdir_state {
2611 int dummy;
2614 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
2615 struct tevent_context *ev,
2616 struct cli_state *cli,
2617 const char *dname)
2619 struct tevent_req *req = NULL, *subreq = NULL;
2620 struct cli_rmdir_state *state = NULL;
2621 uint8_t additional_flags = 0;
2622 uint16_t additional_flags2 = 0;
2623 uint8_t *bytes = NULL;
2624 char *dname_cp = NULL;
2626 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
2627 if (req == NULL) {
2628 return NULL;
2631 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2632 subreq = cli_smb2_rmdir_send(state, ev, cli, dname, NULL);
2633 if (tevent_req_nomem(subreq, req)) {
2634 return tevent_req_post(req, ev);
2636 tevent_req_set_callback(subreq, cli_rmdir_done2, req);
2637 return req;
2640 bytes = talloc_array(state, uint8_t, 1);
2641 if (tevent_req_nomem(bytes, req)) {
2642 return tevent_req_post(req, ev);
2645 * SMBrmdir on a DFS share must use DFS names.
2647 dname_cp = smb1_dfs_share_path(state, cli, dname);
2648 if (tevent_req_nomem(dname_cp, req)) {
2649 return tevent_req_post(req, ev);
2651 bytes[0] = 4;
2652 bytes = smb_bytes_push_str(bytes,
2653 smbXcli_conn_use_unicode(cli->conn),
2654 dname_cp,
2655 strlen(dname_cp)+1,
2656 NULL);
2658 if (tevent_req_nomem(bytes, req)) {
2659 return tevent_req_post(req, ev);
2662 if (clistr_is_previous_version_path(dname)) {
2663 additional_flags2 = FLAGS2_REPARSE_PATH;
2666 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
2667 additional_flags2,
2668 0, NULL, talloc_get_size(bytes), bytes);
2669 if (tevent_req_nomem(subreq, req)) {
2670 return tevent_req_post(req, ev);
2672 tevent_req_set_callback(subreq, cli_rmdir_done, req);
2673 return req;
2676 static void cli_rmdir_done(struct tevent_req *subreq)
2678 NTSTATUS status = cli_smb_recv(
2679 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2680 tevent_req_simple_finish_ntstatus(subreq, status);
2683 static void cli_rmdir_done2(struct tevent_req *subreq)
2685 NTSTATUS status = cli_smb2_rmdir_recv(subreq);
2686 tevent_req_simple_finish_ntstatus(subreq, status);
2689 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
2691 return tevent_req_simple_recv_ntstatus(req);
2694 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
2696 TALLOC_CTX *frame = NULL;
2697 struct tevent_context *ev;
2698 struct tevent_req *req;
2699 NTSTATUS status = NT_STATUS_OK;
2701 frame = talloc_stackframe();
2703 if (smbXcli_conn_has_async_calls(cli->conn)) {
2705 * Can't use sync call while an async call is in flight
2707 status = NT_STATUS_INVALID_PARAMETER;
2708 goto fail;
2711 ev = samba_tevent_context_init(frame);
2712 if (ev == NULL) {
2713 status = NT_STATUS_NO_MEMORY;
2714 goto fail;
2717 req = cli_rmdir_send(frame, ev, cli, dname);
2718 if (req == NULL) {
2719 status = NT_STATUS_NO_MEMORY;
2720 goto fail;
2723 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2724 goto fail;
2727 status = cli_rmdir_recv(req);
2728 fail:
2729 TALLOC_FREE(frame);
2730 return status;
2733 /****************************************************************************
2734 Set or clear the delete on close flag.
2735 ****************************************************************************/
2737 struct doc_state {
2738 uint8_t data[1];
2741 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
2742 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
2744 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
2745 struct tevent_context *ev,
2746 struct cli_state *cli,
2747 uint16_t fnum,
2748 bool flag)
2750 struct tevent_req *req = NULL, *subreq = NULL;
2751 struct doc_state *state = NULL;
2753 req = tevent_req_create(mem_ctx, &state, struct doc_state);
2754 if (req == NULL) {
2755 return NULL;
2758 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2759 subreq = cli_smb2_delete_on_close_send(state, ev, cli,
2760 fnum, flag);
2761 if (tevent_req_nomem(subreq, req)) {
2762 return tevent_req_post(req, ev);
2764 tevent_req_set_callback(subreq,
2765 cli_nt_delete_on_close_smb2_done,
2766 req);
2767 return req;
2770 /* Setup data array. */
2771 SCVAL(&state->data[0], 0, flag ? 1 : 0);
2773 subreq = cli_setfileinfo_send(
2774 state,
2776 cli,
2777 fnum,
2778 SMB_SET_FILE_DISPOSITION_INFO,
2779 state->data,
2780 sizeof(state->data));
2782 if (tevent_req_nomem(subreq, req)) {
2783 return tevent_req_post(req, ev);
2785 tevent_req_set_callback(subreq,
2786 cli_nt_delete_on_close_smb1_done,
2787 req);
2788 return req;
2791 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
2793 NTSTATUS status = cli_setfileinfo_recv(subreq);
2794 tevent_req_simple_finish_ntstatus(subreq, status);
2797 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
2799 NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
2800 tevent_req_simple_finish_ntstatus(subreq, status);
2803 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
2805 return tevent_req_simple_recv_ntstatus(req);
2808 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
2810 TALLOC_CTX *frame = talloc_stackframe();
2811 struct tevent_context *ev = NULL;
2812 struct tevent_req *req = NULL;
2813 NTSTATUS status = NT_STATUS_OK;
2815 if (smbXcli_conn_has_async_calls(cli->conn)) {
2817 * Can't use sync call while an async call is in flight
2819 status = NT_STATUS_INVALID_PARAMETER;
2820 goto fail;
2823 ev = samba_tevent_context_init(frame);
2824 if (ev == NULL) {
2825 status = NT_STATUS_NO_MEMORY;
2826 goto fail;
2829 req = cli_nt_delete_on_close_send(frame,
2831 cli,
2832 fnum,
2833 flag);
2834 if (req == NULL) {
2835 status = NT_STATUS_NO_MEMORY;
2836 goto fail;
2839 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2840 goto fail;
2843 status = cli_nt_delete_on_close_recv(req);
2845 fail:
2846 TALLOC_FREE(frame);
2847 return status;
2850 struct cli_ntcreate1_state {
2851 uint16_t vwv[24];
2852 uint16_t fnum;
2853 struct smb_create_returns cr;
2854 struct tevent_req *subreq;
2857 static void cli_ntcreate1_done(struct tevent_req *subreq);
2858 static bool cli_ntcreate1_cancel(struct tevent_req *req);
2860 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
2861 struct tevent_context *ev,
2862 struct cli_state *cli,
2863 const char *fname,
2864 uint32_t CreatFlags,
2865 uint32_t DesiredAccess,
2866 uint32_t FileAttributes,
2867 uint32_t ShareAccess,
2868 uint32_t CreateDisposition,
2869 uint32_t CreateOptions,
2870 uint32_t ImpersonationLevel,
2871 uint8_t SecurityFlags)
2873 struct tevent_req *req, *subreq;
2874 struct cli_ntcreate1_state *state;
2875 uint16_t *vwv;
2876 uint8_t *bytes;
2877 size_t converted_len;
2878 uint16_t additional_flags2 = 0;
2879 char *fname_cp = NULL;
2881 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
2882 if (req == NULL) {
2883 return NULL;
2886 vwv = state->vwv;
2888 SCVAL(vwv+0, 0, 0xFF);
2889 SCVAL(vwv+0, 1, 0);
2890 SSVAL(vwv+1, 0, 0);
2891 SCVAL(vwv+2, 0, 0);
2893 if (cli->use_oplocks) {
2894 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
2896 SIVAL(vwv+3, 1, CreatFlags);
2897 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
2898 SIVAL(vwv+7, 1, DesiredAccess);
2899 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
2900 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
2901 SIVAL(vwv+13, 1, FileAttributes);
2902 SIVAL(vwv+15, 1, ShareAccess);
2903 SIVAL(vwv+17, 1, CreateDisposition);
2904 SIVAL(vwv+19, 1, CreateOptions |
2905 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2906 SIVAL(vwv+21, 1, ImpersonationLevel);
2907 SCVAL(vwv+23, 1, SecurityFlags);
2909 bytes = talloc_array(state, uint8_t, 0);
2910 if (tevent_req_nomem(bytes, req)) {
2911 return tevent_req_post(req, ev);
2914 * SMBntcreateX on a DFS share must use DFS names.
2916 fname_cp = smb1_dfs_share_path(state, cli, fname);
2917 if (tevent_req_nomem(fname_cp, req)) {
2918 return tevent_req_post(req, ev);
2920 bytes = smb_bytes_push_str(bytes,
2921 smbXcli_conn_use_unicode(cli->conn),
2922 fname_cp,
2923 strlen(fname_cp)+1,
2924 &converted_len);
2925 if (tevent_req_nomem(bytes, req)) {
2926 return tevent_req_post(req, ev);
2929 if (clistr_is_previous_version_path(fname)) {
2930 additional_flags2 = FLAGS2_REPARSE_PATH;
2933 /* sigh. this copes with broken netapp filer behaviour */
2934 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2936 if (tevent_req_nomem(bytes, req)) {
2937 return tevent_req_post(req, ev);
2940 SSVAL(vwv+2, 1, converted_len);
2942 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2943 additional_flags2, 24, vwv,
2944 talloc_get_size(bytes), bytes);
2945 if (tevent_req_nomem(subreq, req)) {
2946 return tevent_req_post(req, ev);
2948 tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2950 state->subreq = subreq;
2951 tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2953 return req;
2956 static void cli_ntcreate1_done(struct tevent_req *subreq)
2958 struct tevent_req *req = tevent_req_callback_data(
2959 subreq, struct tevent_req);
2960 struct cli_ntcreate1_state *state = tevent_req_data(
2961 req, struct cli_ntcreate1_state);
2962 uint8_t wct;
2963 uint16_t *vwv;
2964 uint32_t num_bytes;
2965 uint8_t *bytes;
2966 NTSTATUS status;
2968 status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2969 &num_bytes, &bytes);
2970 TALLOC_FREE(subreq);
2971 if (tevent_req_nterror(req, status)) {
2972 return;
2974 state->cr.oplock_level = CVAL(vwv+2, 0);
2975 state->fnum = SVAL(vwv+2, 1);
2976 state->cr.create_action = IVAL(vwv+3, 1);
2977 state->cr.creation_time = BVAL(vwv+5, 1);
2978 state->cr.last_access_time = BVAL(vwv+9, 1);
2979 state->cr.last_write_time = BVAL(vwv+13, 1);
2980 state->cr.change_time = BVAL(vwv+17, 1);
2981 state->cr.file_attributes = IVAL(vwv+21, 1);
2982 state->cr.allocation_size = BVAL(vwv+23, 1);
2983 state->cr.end_of_file = BVAL(vwv+27, 1);
2985 tevent_req_done(req);
2988 static bool cli_ntcreate1_cancel(struct tevent_req *req)
2990 struct cli_ntcreate1_state *state = tevent_req_data(
2991 req, struct cli_ntcreate1_state);
2992 return tevent_req_cancel(state->subreq);
2995 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2996 uint16_t *pfnum,
2997 struct smb_create_returns *cr)
2999 struct cli_ntcreate1_state *state = tevent_req_data(
3000 req, struct cli_ntcreate1_state);
3001 NTSTATUS status;
3003 if (tevent_req_is_nterror(req, &status)) {
3004 return status;
3006 *pfnum = state->fnum;
3007 if (cr != NULL) {
3008 *cr = state->cr;
3010 return NT_STATUS_OK;
3013 struct cli_ntcreate_state {
3014 struct smb_create_returns cr;
3015 uint16_t fnum;
3016 struct tevent_req *subreq;
3019 static void cli_ntcreate_done_nt1(struct tevent_req *subreq);
3020 static void cli_ntcreate_done_smb2(struct tevent_req *subreq);
3021 static bool cli_ntcreate_cancel(struct tevent_req *req);
3023 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
3024 struct tevent_context *ev,
3025 struct cli_state *cli,
3026 const char *fname,
3027 uint32_t create_flags,
3028 uint32_t desired_access,
3029 uint32_t file_attributes,
3030 uint32_t share_access,
3031 uint32_t create_disposition,
3032 uint32_t create_options,
3033 uint32_t impersonation_level,
3034 uint8_t security_flags)
3036 struct tevent_req *req, *subreq;
3037 struct cli_ntcreate_state *state;
3039 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
3040 if (req == NULL) {
3041 return NULL;
3044 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3045 struct cli_smb2_create_flags cflags = {0};
3047 if (cli->use_oplocks) {
3048 create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
3051 cflags = (struct cli_smb2_create_flags) {
3052 .batch_oplock = (create_flags & REQUEST_BATCH_OPLOCK),
3053 .exclusive_oplock = (create_flags & REQUEST_OPLOCK),
3056 subreq = cli_smb2_create_fnum_send(
3057 state,
3059 cli,
3060 fname,
3061 cflags,
3062 impersonation_level,
3063 desired_access,
3064 file_attributes,
3065 share_access,
3066 create_disposition,
3067 create_options,
3068 NULL);
3069 if (tevent_req_nomem(subreq, req)) {
3070 return tevent_req_post(req, ev);
3072 tevent_req_set_callback(subreq, cli_ntcreate_done_smb2, req);
3073 } else {
3074 subreq = cli_ntcreate1_send(
3075 state, ev, cli, fname, create_flags, desired_access,
3076 file_attributes, share_access, create_disposition,
3077 create_options, impersonation_level, security_flags);
3078 if (tevent_req_nomem(subreq, req)) {
3079 return tevent_req_post(req, ev);
3081 tevent_req_set_callback(subreq, cli_ntcreate_done_nt1, req);
3084 state->subreq = subreq;
3085 tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
3087 return req;
3090 static void cli_ntcreate_done_nt1(struct tevent_req *subreq)
3092 struct tevent_req *req = tevent_req_callback_data(
3093 subreq, struct tevent_req);
3094 struct cli_ntcreate_state *state = tevent_req_data(
3095 req, struct cli_ntcreate_state);
3096 NTSTATUS status;
3098 status = cli_ntcreate1_recv(subreq, &state->fnum, &state->cr);
3099 TALLOC_FREE(subreq);
3100 if (tevent_req_nterror(req, status)) {
3101 return;
3103 tevent_req_done(req);
3106 static void cli_ntcreate_done_smb2(struct tevent_req *subreq)
3108 struct tevent_req *req = tevent_req_callback_data(
3109 subreq, struct tevent_req);
3110 struct cli_ntcreate_state *state = tevent_req_data(
3111 req, struct cli_ntcreate_state);
3112 NTSTATUS status;
3114 status = cli_smb2_create_fnum_recv(
3115 subreq,
3116 &state->fnum,
3117 &state->cr,
3118 NULL,
3119 NULL,
3120 NULL);
3121 TALLOC_FREE(subreq);
3122 if (tevent_req_nterror(req, status)) {
3123 return;
3125 tevent_req_done(req);
3128 static bool cli_ntcreate_cancel(struct tevent_req *req)
3130 struct cli_ntcreate_state *state = tevent_req_data(
3131 req, struct cli_ntcreate_state);
3132 return tevent_req_cancel(state->subreq);
3135 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
3136 struct smb_create_returns *cr)
3138 struct cli_ntcreate_state *state = tevent_req_data(
3139 req, struct cli_ntcreate_state);
3140 NTSTATUS status;
3142 if (tevent_req_is_nterror(req, &status)) {
3143 return status;
3145 if (fnum != NULL) {
3146 *fnum = state->fnum;
3148 if (cr != NULL) {
3149 *cr = state->cr;
3151 return NT_STATUS_OK;
3154 NTSTATUS cli_ntcreate(struct cli_state *cli,
3155 const char *fname,
3156 uint32_t CreatFlags,
3157 uint32_t DesiredAccess,
3158 uint32_t FileAttributes,
3159 uint32_t ShareAccess,
3160 uint32_t CreateDisposition,
3161 uint32_t CreateOptions,
3162 uint8_t SecurityFlags,
3163 uint16_t *pfid,
3164 struct smb_create_returns *cr)
3166 TALLOC_CTX *frame = talloc_stackframe();
3167 struct tevent_context *ev;
3168 struct tevent_req *req;
3169 uint32_t ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
3170 NTSTATUS status = NT_STATUS_NO_MEMORY;
3172 if (smbXcli_conn_has_async_calls(cli->conn)) {
3174 * Can't use sync call while an async call is in flight
3176 status = NT_STATUS_INVALID_PARAMETER;
3177 goto fail;
3180 ev = samba_tevent_context_init(frame);
3181 if (ev == NULL) {
3182 goto fail;
3185 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
3186 DesiredAccess, FileAttributes, ShareAccess,
3187 CreateDisposition, CreateOptions,
3188 ImpersonationLevel, SecurityFlags);
3189 if (req == NULL) {
3190 goto fail;
3193 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3194 goto fail;
3197 status = cli_ntcreate_recv(req, pfid, cr);
3198 fail:
3199 TALLOC_FREE(frame);
3200 return status;
3203 struct cli_nttrans_create_state {
3204 uint16_t fnum;
3205 struct smb_create_returns cr;
3208 static void cli_nttrans_create_done(struct tevent_req *subreq);
3210 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
3211 struct tevent_context *ev,
3212 struct cli_state *cli,
3213 const char *fname,
3214 uint32_t CreatFlags,
3215 uint32_t DesiredAccess,
3216 uint32_t FileAttributes,
3217 uint32_t ShareAccess,
3218 uint32_t CreateDisposition,
3219 uint32_t CreateOptions,
3220 uint8_t SecurityFlags,
3221 struct security_descriptor *secdesc,
3222 struct ea_struct *eas,
3223 int num_eas)
3225 struct tevent_req *req, *subreq;
3226 struct cli_nttrans_create_state *state;
3227 uint8_t *param;
3228 uint8_t *secdesc_buf;
3229 size_t secdesc_len;
3230 NTSTATUS status;
3231 size_t converted_len;
3232 uint16_t additional_flags2 = 0;
3233 char *fname_cp = NULL;
3235 req = tevent_req_create(mem_ctx,
3236 &state, struct cli_nttrans_create_state);
3237 if (req == NULL) {
3238 return NULL;
3241 if (secdesc != NULL) {
3242 status = marshall_sec_desc(talloc_tos(), secdesc,
3243 &secdesc_buf, &secdesc_len);
3244 if (tevent_req_nterror(req, status)) {
3245 DEBUG(10, ("marshall_sec_desc failed: %s\n",
3246 nt_errstr(status)));
3247 return tevent_req_post(req, ev);
3249 } else {
3250 secdesc_buf = NULL;
3251 secdesc_len = 0;
3254 if (num_eas != 0) {
3256 * TODO ;-)
3258 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
3259 return tevent_req_post(req, ev);
3262 param = talloc_array(state, uint8_t, 53);
3263 if (tevent_req_nomem(param, req)) {
3264 return tevent_req_post(req, ev);
3268 * SMBntcreateX on a DFS share must use DFS names.
3270 fname_cp = smb1_dfs_share_path(state, cli, fname);
3271 if (tevent_req_nomem(fname_cp, req)) {
3272 return tevent_req_post(req, ev);
3274 param = trans2_bytes_push_str(param,
3275 smbXcli_conn_use_unicode(cli->conn),
3276 fname_cp,
3277 strlen(fname_cp),
3278 &converted_len);
3279 if (tevent_req_nomem(param, req)) {
3280 return tevent_req_post(req, ev);
3283 if (clistr_is_previous_version_path(fname)) {
3284 additional_flags2 = FLAGS2_REPARSE_PATH;
3287 SIVAL(param, 0, CreatFlags);
3288 SIVAL(param, 4, 0x0); /* RootDirectoryFid */
3289 SIVAL(param, 8, DesiredAccess);
3290 SIVAL(param, 12, 0x0); /* AllocationSize */
3291 SIVAL(param, 16, 0x0); /* AllocationSize */
3292 SIVAL(param, 20, FileAttributes);
3293 SIVAL(param, 24, ShareAccess);
3294 SIVAL(param, 28, CreateDisposition);
3295 SIVAL(param, 32, CreateOptions |
3296 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
3297 SIVAL(param, 36, secdesc_len);
3298 SIVAL(param, 40, 0); /* EA length*/
3299 SIVAL(param, 44, converted_len);
3300 SIVAL(param, 48, 0x02); /* ImpersonationLevel */
3301 SCVAL(param, 52, SecurityFlags);
3303 subreq = cli_trans_send(state, ev, cli,
3304 additional_flags2, /* additional_flags2 */
3305 SMBnttrans,
3306 NULL, -1, /* name, fid */
3307 NT_TRANSACT_CREATE, 0,
3308 NULL, 0, 0, /* setup */
3309 param, talloc_get_size(param), 128, /* param */
3310 secdesc_buf, secdesc_len, 0); /* data */
3311 if (tevent_req_nomem(subreq, req)) {
3312 return tevent_req_post(req, ev);
3314 tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
3315 return req;
3318 static void cli_nttrans_create_done(struct tevent_req *subreq)
3320 struct tevent_req *req = tevent_req_callback_data(
3321 subreq, struct tevent_req);
3322 struct cli_nttrans_create_state *state = tevent_req_data(
3323 req, struct cli_nttrans_create_state);
3324 uint8_t *param;
3325 uint32_t num_param;
3326 NTSTATUS status;
3328 status = cli_trans_recv(subreq, talloc_tos(), NULL,
3329 NULL, 0, NULL, /* rsetup */
3330 &param, 69, &num_param,
3331 NULL, 0, NULL);
3332 if (tevent_req_nterror(req, status)) {
3333 return;
3335 state->cr.oplock_level = CVAL(param, 0);
3336 state->fnum = SVAL(param, 2);
3337 state->cr.create_action = IVAL(param, 4);
3338 state->cr.creation_time = BVAL(param, 12);
3339 state->cr.last_access_time = BVAL(param, 20);
3340 state->cr.last_write_time = BVAL(param, 28);
3341 state->cr.change_time = BVAL(param, 36);
3342 state->cr.file_attributes = IVAL(param, 44);
3343 state->cr.allocation_size = BVAL(param, 48);
3344 state->cr.end_of_file = BVAL(param, 56);
3346 TALLOC_FREE(param);
3347 tevent_req_done(req);
3350 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
3351 uint16_t *fnum,
3352 struct smb_create_returns *cr)
3354 struct cli_nttrans_create_state *state = tevent_req_data(
3355 req, struct cli_nttrans_create_state);
3356 NTSTATUS status;
3358 if (tevent_req_is_nterror(req, &status)) {
3359 return status;
3361 *fnum = state->fnum;
3362 if (cr != NULL) {
3363 *cr = state->cr;
3365 return NT_STATUS_OK;
3368 NTSTATUS cli_nttrans_create(struct cli_state *cli,
3369 const char *fname,
3370 uint32_t CreatFlags,
3371 uint32_t DesiredAccess,
3372 uint32_t FileAttributes,
3373 uint32_t ShareAccess,
3374 uint32_t CreateDisposition,
3375 uint32_t CreateOptions,
3376 uint8_t SecurityFlags,
3377 struct security_descriptor *secdesc,
3378 struct ea_struct *eas,
3379 int num_eas,
3380 uint16_t *pfid,
3381 struct smb_create_returns *cr)
3383 TALLOC_CTX *frame = talloc_stackframe();
3384 struct tevent_context *ev;
3385 struct tevent_req *req;
3386 NTSTATUS status = NT_STATUS_NO_MEMORY;
3388 if (smbXcli_conn_has_async_calls(cli->conn)) {
3390 * Can't use sync call while an async call is in flight
3392 status = NT_STATUS_INVALID_PARAMETER;
3393 goto fail;
3395 ev = samba_tevent_context_init(frame);
3396 if (ev == NULL) {
3397 goto fail;
3399 req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
3400 DesiredAccess, FileAttributes,
3401 ShareAccess, CreateDisposition,
3402 CreateOptions, SecurityFlags,
3403 secdesc, eas, num_eas);
3404 if (req == NULL) {
3405 goto fail;
3407 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3408 goto fail;
3410 status = cli_nttrans_create_recv(req, pfid, cr);
3411 fail:
3412 TALLOC_FREE(frame);
3413 return status;
3416 /****************************************************************************
3417 Open a file
3418 WARNING: if you open with O_WRONLY then getattrE won't work!
3419 ****************************************************************************/
3421 struct cli_openx_state {
3422 const char *fname;
3423 uint16_t vwv[15];
3424 uint16_t fnum;
3425 struct iovec bytes;
3428 static void cli_openx_done(struct tevent_req *subreq);
3430 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
3431 struct tevent_context *ev,
3432 struct cli_state *cli, const char *fname,
3433 int flags, int share_mode,
3434 struct tevent_req **psmbreq)
3436 struct tevent_req *req, *subreq;
3437 struct cli_openx_state *state;
3438 unsigned openfn;
3439 unsigned accessmode;
3440 uint8_t additional_flags;
3441 uint16_t additional_flags2 = 0;
3442 uint8_t *bytes;
3443 char *fname_cp = NULL;
3445 req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
3446 if (req == NULL) {
3447 return NULL;
3450 openfn = 0;
3451 if (flags & O_CREAT) {
3452 openfn |= (1<<4);
3454 if (!(flags & O_EXCL)) {
3455 if (flags & O_TRUNC)
3456 openfn |= (1<<1);
3457 else
3458 openfn |= (1<<0);
3461 accessmode = (share_mode<<4);
3463 if ((flags & O_ACCMODE) == O_RDWR) {
3464 accessmode |= 2;
3465 } else if ((flags & O_ACCMODE) == O_WRONLY) {
3466 accessmode |= 1;
3469 #if defined(O_SYNC)
3470 if ((flags & O_SYNC) == O_SYNC) {
3471 accessmode |= (1<<14);
3473 #endif /* O_SYNC */
3475 if (share_mode == DENY_FCB) {
3476 accessmode = 0xFF;
3479 SCVAL(state->vwv + 0, 0, 0xFF);
3480 SCVAL(state->vwv + 0, 1, 0);
3481 SSVAL(state->vwv + 1, 0, 0);
3482 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
3483 SSVAL(state->vwv + 3, 0, accessmode);
3484 SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
3485 SSVAL(state->vwv + 5, 0, 0);
3486 SIVAL(state->vwv + 6, 0, 0);
3487 SSVAL(state->vwv + 8, 0, openfn);
3488 SIVAL(state->vwv + 9, 0, 0);
3489 SIVAL(state->vwv + 11, 0, 0);
3490 SIVAL(state->vwv + 13, 0, 0);
3492 additional_flags = 0;
3494 if (cli->use_oplocks) {
3495 /* if using oplocks then ask for a batch oplock via
3496 core and extended methods */
3497 additional_flags =
3498 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
3499 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
3502 bytes = talloc_array(state, uint8_t, 0);
3503 if (tevent_req_nomem(bytes, req)) {
3504 return tevent_req_post(req, ev);
3507 * SMBopenX on a DFS share must use DFS names.
3509 fname_cp = smb1_dfs_share_path(state, cli, fname);
3510 if (tevent_req_nomem(fname_cp, req)) {
3511 return tevent_req_post(req, ev);
3513 bytes = smb_bytes_push_str(bytes,
3514 smbXcli_conn_use_unicode(cli->conn),
3515 fname_cp,
3516 strlen(fname_cp)+1,
3517 NULL);
3519 if (tevent_req_nomem(bytes, req)) {
3520 return tevent_req_post(req, ev);
3523 if (clistr_is_previous_version_path(fname)) {
3524 additional_flags2 = FLAGS2_REPARSE_PATH;
3527 state->bytes.iov_base = (void *)bytes;
3528 state->bytes.iov_len = talloc_get_size(bytes);
3530 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
3531 additional_flags2, 15, state->vwv, 1, &state->bytes);
3532 if (subreq == NULL) {
3533 TALLOC_FREE(req);
3534 return NULL;
3536 tevent_req_set_callback(subreq, cli_openx_done, req);
3537 *psmbreq = subreq;
3538 return req;
3541 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
3542 struct cli_state *cli, const char *fname,
3543 int flags, int share_mode)
3545 struct tevent_req *req, *subreq;
3546 NTSTATUS status;
3548 req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
3549 &subreq);
3550 if (req == NULL) {
3551 return NULL;
3554 status = smb1cli_req_chain_submit(&subreq, 1);
3555 if (tevent_req_nterror(req, status)) {
3556 return tevent_req_post(req, ev);
3558 return req;
3561 static void cli_openx_done(struct tevent_req *subreq)
3563 struct tevent_req *req = tevent_req_callback_data(
3564 subreq, struct tevent_req);
3565 struct cli_openx_state *state = tevent_req_data(
3566 req, struct cli_openx_state);
3567 uint8_t wct;
3568 uint16_t *vwv;
3569 NTSTATUS status;
3571 status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
3572 NULL);
3573 TALLOC_FREE(subreq);
3574 if (tevent_req_nterror(req, status)) {
3575 return;
3577 state->fnum = SVAL(vwv+2, 0);
3578 tevent_req_done(req);
3581 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
3583 struct cli_openx_state *state = tevent_req_data(
3584 req, struct cli_openx_state);
3585 NTSTATUS status;
3587 if (tevent_req_is_nterror(req, &status)) {
3588 return status;
3590 *pfnum = state->fnum;
3591 return NT_STATUS_OK;
3594 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
3595 int share_mode, uint16_t *pfnum)
3597 TALLOC_CTX *frame = talloc_stackframe();
3598 struct tevent_context *ev;
3599 struct tevent_req *req;
3600 NTSTATUS status = NT_STATUS_NO_MEMORY;
3602 if (smbXcli_conn_has_async_calls(cli->conn)) {
3604 * Can't use sync call while an async call is in flight
3606 status = NT_STATUS_INVALID_PARAMETER;
3607 goto fail;
3610 ev = samba_tevent_context_init(frame);
3611 if (ev == NULL) {
3612 goto fail;
3615 req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
3616 if (req == NULL) {
3617 goto fail;
3620 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3621 goto fail;
3624 status = cli_openx_recv(req, pfnum);
3625 fail:
3626 TALLOC_FREE(frame);
3627 return status;
3629 /****************************************************************************
3630 Synchronous wrapper function that does an NtCreateX open by preference
3631 and falls back to openX if this fails.
3632 ****************************************************************************/
3634 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
3635 int share_mode_in, uint16_t *pfnum)
3637 NTSTATUS status;
3638 unsigned int openfn = 0;
3639 unsigned int dos_deny = 0;
3640 uint32_t access_mask, share_mode, create_disposition, create_options;
3641 struct smb_create_returns cr = {0};
3643 /* Do the initial mapping into OpenX parameters. */
3644 if (flags & O_CREAT) {
3645 openfn |= (1<<4);
3647 if (!(flags & O_EXCL)) {
3648 if (flags & O_TRUNC)
3649 openfn |= (1<<1);
3650 else
3651 openfn |= (1<<0);
3654 dos_deny = (share_mode_in<<4);
3656 if ((flags & O_ACCMODE) == O_RDWR) {
3657 dos_deny |= 2;
3658 } else if ((flags & O_ACCMODE) == O_WRONLY) {
3659 dos_deny |= 1;
3662 #if defined(O_SYNC)
3663 if (flags & O_SYNC) {
3664 dos_deny |= (1<<14);
3666 #endif /* O_SYNC */
3668 if (share_mode_in == DENY_FCB) {
3669 dos_deny = 0xFF;
3672 if (!map_open_params_to_ntcreate(fname, dos_deny,
3673 openfn, &access_mask,
3674 &share_mode, &create_disposition,
3675 &create_options, NULL)) {
3676 goto try_openx;
3679 status = cli_ntcreate(cli,
3680 fname,
3682 access_mask,
3684 share_mode,
3685 create_disposition,
3686 create_options,
3688 pfnum,
3689 &cr);
3691 /* Try and cope will all variants of "we don't do this call"
3692 and fall back to openX. */
3694 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
3695 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
3696 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
3697 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
3698 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
3699 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
3700 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
3701 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
3702 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
3703 goto try_openx;
3706 if (NT_STATUS_IS_OK(status) &&
3707 (create_options & FILE_NON_DIRECTORY_FILE) &&
3708 (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
3711 * Some (broken) servers return a valid handle
3712 * for directories even if FILE_NON_DIRECTORY_FILE
3713 * is set. Just close the handle and set the
3714 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
3716 status = cli_close(cli, *pfnum);
3717 if (!NT_STATUS_IS_OK(status)) {
3718 return status;
3720 status = NT_STATUS_FILE_IS_A_DIRECTORY;
3723 return status;
3725 try_openx:
3727 return cli_openx(cli, fname, flags, share_mode_in, pfnum);
3730 /****************************************************************************
3731 Close a file.
3732 ****************************************************************************/
3734 struct cli_smb1_close_state {
3735 uint16_t vwv[3];
3738 static void cli_smb1_close_done(struct tevent_req *subreq);
3740 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
3741 struct tevent_context *ev,
3742 struct cli_state *cli,
3743 uint16_t fnum,
3744 struct tevent_req **psubreq)
3746 struct tevent_req *req, *subreq;
3747 struct cli_smb1_close_state *state;
3749 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
3750 if (req == NULL) {
3751 return NULL;
3754 SSVAL(state->vwv+0, 0, fnum);
3755 SIVALS(state->vwv+1, 0, -1);
3757 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
3758 3, state->vwv, 0, NULL);
3759 if (subreq == NULL) {
3760 TALLOC_FREE(req);
3761 return NULL;
3763 tevent_req_set_callback(subreq, cli_smb1_close_done, req);
3764 *psubreq = subreq;
3765 return req;
3768 static void cli_smb1_close_done(struct tevent_req *subreq)
3770 struct tevent_req *req = tevent_req_callback_data(
3771 subreq, struct tevent_req);
3772 NTSTATUS status;
3774 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3775 TALLOC_FREE(subreq);
3776 if (tevent_req_nterror(req, status)) {
3777 return;
3779 tevent_req_done(req);
3782 struct cli_close_state {
3783 int dummy;
3786 static void cli_close_done(struct tevent_req *subreq);
3788 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
3789 struct tevent_context *ev,
3790 struct cli_state *cli,
3791 uint16_t fnum,
3792 uint16_t flags)
3794 struct tevent_req *req, *subreq;
3795 struct cli_close_state *state;
3796 NTSTATUS status;
3798 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
3799 if (req == NULL) {
3800 return NULL;
3803 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3804 subreq = cli_smb2_close_fnum_send(state, ev, cli, fnum, flags);
3805 if (tevent_req_nomem(subreq, req)) {
3806 return tevent_req_post(req, ev);
3808 } else {
3809 struct tevent_req *ch_req = NULL;
3810 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
3811 if (tevent_req_nomem(subreq, req)) {
3812 return tevent_req_post(req, ev);
3814 status = smb1cli_req_chain_submit(&ch_req, 1);
3815 if (tevent_req_nterror(req, status)) {
3816 return tevent_req_post(req, ev);
3820 tevent_req_set_callback(subreq, cli_close_done, req);
3821 return req;
3824 static void cli_close_done(struct tevent_req *subreq)
3826 struct tevent_req *req = tevent_req_callback_data(
3827 subreq, struct tevent_req);
3828 NTSTATUS status = NT_STATUS_OK;
3829 bool err = tevent_req_is_nterror(subreq, &status);
3831 TALLOC_FREE(subreq);
3832 if (err) {
3833 tevent_req_nterror(req, status);
3834 return;
3836 tevent_req_done(req);
3839 NTSTATUS cli_close_recv(struct tevent_req *req)
3841 return tevent_req_simple_recv_ntstatus(req);
3844 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
3846 TALLOC_CTX *frame = NULL;
3847 struct tevent_context *ev;
3848 struct tevent_req *req;
3849 NTSTATUS status = NT_STATUS_OK;
3851 frame = talloc_stackframe();
3853 if (smbXcli_conn_has_async_calls(cli->conn)) {
3855 * Can't use sync call while an async call is in flight
3857 status = NT_STATUS_INVALID_PARAMETER;
3858 goto fail;
3861 ev = samba_tevent_context_init(frame);
3862 if (ev == NULL) {
3863 status = NT_STATUS_NO_MEMORY;
3864 goto fail;
3867 req = cli_close_send(frame, ev, cli, fnum, 0);
3868 if (req == NULL) {
3869 status = NT_STATUS_NO_MEMORY;
3870 goto fail;
3873 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3874 goto fail;
3877 status = cli_close_recv(req);
3878 fail:
3879 TALLOC_FREE(frame);
3880 return status;
3883 /****************************************************************************
3884 Truncate a file to a specified size
3885 ****************************************************************************/
3887 struct ftrunc_state {
3888 uint8_t data[8];
3891 static void cli_ftruncate_done(struct tevent_req *subreq)
3893 NTSTATUS status = cli_setfileinfo_recv(subreq);
3894 tevent_req_simple_finish_ntstatus(subreq, status);
3897 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
3898 struct tevent_context *ev,
3899 struct cli_state *cli,
3900 uint16_t fnum,
3901 uint64_t size)
3903 struct tevent_req *req = NULL, *subreq = NULL;
3904 struct ftrunc_state *state = NULL;
3906 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
3907 if (req == NULL) {
3908 return NULL;
3911 /* Setup data array. */
3912 SBVAL(state->data, 0, size);
3914 subreq = cli_setfileinfo_send(
3915 state,
3917 cli,
3918 fnum,
3919 SMB_SET_FILE_END_OF_FILE_INFO,
3920 state->data,
3921 sizeof(state->data));
3923 if (tevent_req_nomem(subreq, req)) {
3924 return tevent_req_post(req, ev);
3926 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
3927 return req;
3930 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
3932 return tevent_req_simple_recv_ntstatus(req);
3935 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3937 TALLOC_CTX *frame = NULL;
3938 struct tevent_context *ev = NULL;
3939 struct tevent_req *req = NULL;
3940 NTSTATUS status = NT_STATUS_OK;
3942 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3943 return cli_smb2_ftruncate(cli, fnum, size);
3946 frame = talloc_stackframe();
3948 if (smbXcli_conn_has_async_calls(cli->conn)) {
3950 * Can't use sync call while an async call is in flight
3952 status = NT_STATUS_INVALID_PARAMETER;
3953 goto fail;
3956 ev = samba_tevent_context_init(frame);
3957 if (ev == NULL) {
3958 status = NT_STATUS_NO_MEMORY;
3959 goto fail;
3962 req = cli_ftruncate_send(frame,
3964 cli,
3965 fnum,
3966 size);
3967 if (req == NULL) {
3968 status = NT_STATUS_NO_MEMORY;
3969 goto fail;
3972 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3973 goto fail;
3976 status = cli_ftruncate_recv(req);
3978 fail:
3979 TALLOC_FREE(frame);
3980 return status;
3983 static uint8_t *cli_lockingx_put_locks(
3984 uint8_t *buf,
3985 bool large,
3986 uint16_t num_locks,
3987 const struct smb1_lock_element *locks)
3989 uint16_t i;
3991 for (i=0; i<num_locks; i++) {
3992 const struct smb1_lock_element *e = &locks[i];
3993 if (large) {
3994 SSVAL(buf, 0, e->pid);
3995 SSVAL(buf, 2, 0);
3996 SOFF_T_R(buf, 4, e->offset);
3997 SOFF_T_R(buf, 12, e->length);
3998 buf += 20;
3999 } else {
4000 SSVAL(buf, 0, e->pid);
4001 SIVAL(buf, 2, e->offset);
4002 SIVAL(buf, 6, e->length);
4003 buf += 10;
4006 return buf;
4009 struct cli_lockingx_state {
4010 uint16_t vwv[8];
4011 struct iovec bytes;
4012 struct tevent_req *subreq;
4015 static void cli_lockingx_done(struct tevent_req *subreq);
4016 static bool cli_lockingx_cancel(struct tevent_req *req);
4018 struct tevent_req *cli_lockingx_create(
4019 TALLOC_CTX *mem_ctx,
4020 struct tevent_context *ev,
4021 struct cli_state *cli,
4022 uint16_t fnum,
4023 uint8_t typeoflock,
4024 uint8_t newoplocklevel,
4025 int32_t timeout,
4026 uint16_t num_unlocks,
4027 const struct smb1_lock_element *unlocks,
4028 uint16_t num_locks,
4029 const struct smb1_lock_element *locks,
4030 struct tevent_req **psmbreq)
4032 struct tevent_req *req = NULL, *subreq = NULL;
4033 struct cli_lockingx_state *state = NULL;
4034 uint16_t *vwv;
4035 uint8_t *p;
4036 const bool large = (typeoflock & LOCKING_ANDX_LARGE_FILES);
4037 const size_t element_len = large ? 20 : 10;
4039 /* uint16->size_t, no overflow */
4040 const size_t num_elements = (size_t)num_locks + (size_t)num_unlocks;
4042 /* at most 20*2*65535 = 2621400, no overflow */
4043 const size_t num_bytes = num_elements * element_len;
4045 req = tevent_req_create(mem_ctx, &state, struct cli_lockingx_state);
4046 if (req == NULL) {
4047 return NULL;
4049 vwv = state->vwv;
4051 SCVAL(vwv + 0, 0, 0xFF);
4052 SCVAL(vwv + 0, 1, 0);
4053 SSVAL(vwv + 1, 0, 0);
4054 SSVAL(vwv + 2, 0, fnum);
4055 SCVAL(vwv + 3, 0, typeoflock);
4056 SCVAL(vwv + 3, 1, newoplocklevel);
4057 SIVALS(vwv + 4, 0, timeout);
4058 SSVAL(vwv + 6, 0, num_unlocks);
4059 SSVAL(vwv + 7, 0, num_locks);
4061 state->bytes.iov_len = num_bytes;
4062 state->bytes.iov_base = talloc_array(state, uint8_t, num_bytes);
4063 if (tevent_req_nomem(state->bytes.iov_base, req)) {
4064 return tevent_req_post(req, ev);
4067 p = cli_lockingx_put_locks(
4068 state->bytes.iov_base, large, num_unlocks, unlocks);
4069 cli_lockingx_put_locks(p, large, num_locks, locks);
4071 subreq = cli_smb_req_create(
4072 state, ev, cli, SMBlockingX, 0, 0, 8, vwv, 1, &state->bytes);
4073 if (tevent_req_nomem(subreq, req)) {
4074 return tevent_req_post(req, ev);
4076 tevent_req_set_callback(subreq, cli_lockingx_done, req);
4077 *psmbreq = subreq;
4078 return req;
4081 struct tevent_req *cli_lockingx_send(
4082 TALLOC_CTX *mem_ctx,
4083 struct tevent_context *ev,
4084 struct cli_state *cli,
4085 uint16_t fnum,
4086 uint8_t typeoflock,
4087 uint8_t newoplocklevel,
4088 int32_t timeout,
4089 uint16_t num_unlocks,
4090 const struct smb1_lock_element *unlocks,
4091 uint16_t num_locks,
4092 const struct smb1_lock_element *locks)
4094 struct tevent_req *req = NULL, *subreq = NULL;
4095 struct cli_lockingx_state *state = NULL;
4096 NTSTATUS status;
4098 req = cli_lockingx_create(
4099 mem_ctx,
4101 cli,
4102 fnum,
4103 typeoflock,
4104 newoplocklevel,
4105 timeout,
4106 num_unlocks,
4107 unlocks,
4108 num_locks,
4109 locks,
4110 &subreq);
4111 if (req == NULL) {
4112 return NULL;
4114 state = tevent_req_data(req, struct cli_lockingx_state);
4115 state->subreq = subreq;
4117 status = smb1cli_req_chain_submit(&subreq, 1);
4118 if (tevent_req_nterror(req, status)) {
4119 return tevent_req_post(req, ev);
4121 tevent_req_set_cancel_fn(req, cli_lockingx_cancel);
4122 return req;
4125 static void cli_lockingx_done(struct tevent_req *subreq)
4127 NTSTATUS status = cli_smb_recv(
4128 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4129 tevent_req_simple_finish_ntstatus(subreq, status);
4132 static bool cli_lockingx_cancel(struct tevent_req *req)
4134 struct cli_lockingx_state *state = tevent_req_data(
4135 req, struct cli_lockingx_state);
4136 if (state->subreq == NULL) {
4137 return false;
4139 return tevent_req_cancel(state->subreq);
4142 NTSTATUS cli_lockingx_recv(struct tevent_req *req)
4144 return tevent_req_simple_recv_ntstatus(req);
4147 NTSTATUS cli_lockingx(
4148 struct cli_state *cli,
4149 uint16_t fnum,
4150 uint8_t typeoflock,
4151 uint8_t newoplocklevel,
4152 int32_t timeout,
4153 uint16_t num_unlocks,
4154 const struct smb1_lock_element *unlocks,
4155 uint16_t num_locks,
4156 const struct smb1_lock_element *locks)
4158 TALLOC_CTX *frame = talloc_stackframe();
4159 struct tevent_context *ev = NULL;
4160 struct tevent_req *req = NULL;
4161 NTSTATUS status = NT_STATUS_NO_MEMORY;
4162 unsigned int set_timeout = 0;
4163 unsigned int saved_timeout = 0;
4165 if (smbXcli_conn_has_async_calls(cli->conn)) {
4166 return NT_STATUS_INVALID_PARAMETER;
4168 ev = samba_tevent_context_init(frame);
4169 if (ev == NULL) {
4170 goto fail;
4173 if (timeout != 0) {
4174 if (timeout == -1) {
4175 set_timeout = 0x7FFFFFFF;
4176 } else {
4177 set_timeout = timeout + 2*1000;
4179 saved_timeout = cli_set_timeout(cli, set_timeout);
4182 req = cli_lockingx_send(
4183 frame,
4185 cli,
4186 fnum,
4187 typeoflock,
4188 newoplocklevel,
4189 timeout,
4190 num_unlocks,
4191 unlocks,
4192 num_locks,
4193 locks);
4194 if (req == NULL) {
4195 goto fail;
4197 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4198 goto fail;
4200 status = cli_lockingx_recv(req);
4202 if (saved_timeout != 0) {
4203 cli_set_timeout(cli, saved_timeout);
4205 fail:
4206 TALLOC_FREE(frame);
4207 return status;
4210 /****************************************************************************
4211 send a lock with a specified locktype
4212 this is used for testing LOCKING_ANDX_CANCEL_LOCK
4213 ****************************************************************************/
4215 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
4216 uint32_t offset, uint32_t len,
4217 int timeout, unsigned char locktype)
4219 struct smb1_lock_element lck = {
4220 .pid = cli_getpid(cli),
4221 .offset = offset,
4222 .length = len,
4224 NTSTATUS status;
4226 status = cli_lockingx(
4227 cli, /* cli */
4228 fnum, /* fnum */
4229 locktype, /* typeoflock */
4230 0, /* newoplocklevel */
4231 timeout, /* timeout */
4232 0, /* num_unlocks */
4233 NULL, /* unlocks */
4234 1, /* num_locks */
4235 &lck); /* locks */
4236 return status;
4239 /****************************************************************************
4240 Lock a file.
4241 note that timeout is in units of 2 milliseconds
4242 ****************************************************************************/
4244 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
4245 uint32_t offset, uint32_t len, int timeout,
4246 enum brl_type lock_type)
4248 NTSTATUS status;
4250 status = cli_locktype(cli, fnum, offset, len, timeout,
4251 (lock_type == READ_LOCK? 1 : 0));
4252 return status;
4255 /****************************************************************************
4256 Unlock a file.
4257 ****************************************************************************/
4259 struct cli_unlock_state {
4260 struct smb1_lock_element lck;
4263 static void cli_unlock_done(struct tevent_req *subreq);
4265 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
4266 struct tevent_context *ev,
4267 struct cli_state *cli,
4268 uint16_t fnum,
4269 uint64_t offset,
4270 uint64_t len)
4273 struct tevent_req *req = NULL, *subreq = NULL;
4274 struct cli_unlock_state *state = NULL;
4276 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
4277 if (req == NULL) {
4278 return NULL;
4280 state->lck = (struct smb1_lock_element) {
4281 .pid = cli_getpid(cli),
4282 .offset = offset,
4283 .length = len,
4286 subreq = cli_lockingx_send(
4287 state, /* mem_ctx */
4288 ev, /* tevent_context */
4289 cli, /* cli */
4290 fnum, /* fnum */
4291 0, /* typeoflock */
4292 0, /* newoplocklevel */
4293 0, /* timeout */
4294 1, /* num_unlocks */
4295 &state->lck, /* unlocks */
4296 0, /* num_locks */
4297 NULL); /* locks */
4298 if (tevent_req_nomem(subreq, req)) {
4299 return tevent_req_post(req, ev);
4301 tevent_req_set_callback(subreq, cli_unlock_done, req);
4302 return req;
4305 static void cli_unlock_done(struct tevent_req *subreq)
4307 NTSTATUS status = cli_lockingx_recv(subreq);
4308 tevent_req_simple_finish_ntstatus(subreq, status);
4311 NTSTATUS cli_unlock_recv(struct tevent_req *req)
4313 return tevent_req_simple_recv_ntstatus(req);
4316 NTSTATUS cli_unlock(struct cli_state *cli,
4317 uint16_t fnum,
4318 uint32_t offset,
4319 uint32_t len)
4321 TALLOC_CTX *frame = talloc_stackframe();
4322 struct tevent_context *ev;
4323 struct tevent_req *req;
4324 NTSTATUS status = NT_STATUS_OK;
4326 if (smbXcli_conn_has_async_calls(cli->conn)) {
4328 * Can't use sync call while an async call is in flight
4330 status = NT_STATUS_INVALID_PARAMETER;
4331 goto fail;
4334 ev = samba_tevent_context_init(frame);
4335 if (ev == NULL) {
4336 status = NT_STATUS_NO_MEMORY;
4337 goto fail;
4340 req = cli_unlock_send(frame, ev, cli,
4341 fnum, offset, len);
4342 if (req == NULL) {
4343 status = NT_STATUS_NO_MEMORY;
4344 goto fail;
4347 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4348 goto fail;
4351 status = cli_unlock_recv(req);
4353 fail:
4354 TALLOC_FREE(frame);
4355 return status;
4358 /****************************************************************************
4359 Get/unlock a POSIX lock on a file - internal function.
4360 ****************************************************************************/
4362 struct posix_lock_state {
4363 uint16_t setup;
4364 uint8_t param[4];
4365 uint8_t data[POSIX_LOCK_DATA_SIZE];
4368 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
4370 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
4371 NULL, 0, NULL, NULL, 0, NULL);
4372 tevent_req_simple_finish_ntstatus(subreq, status);
4375 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
4376 struct tevent_context *ev,
4377 struct cli_state *cli,
4378 uint16_t fnum,
4379 uint64_t offset,
4380 uint64_t len,
4381 bool wait_lock,
4382 enum brl_type lock_type)
4384 struct tevent_req *req = NULL, *subreq = NULL;
4385 struct posix_lock_state *state = NULL;
4387 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
4388 if (req == NULL) {
4389 return NULL;
4392 /* Setup setup word. */
4393 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
4395 /* Setup param array. */
4396 SSVAL(&state->param, 0, fnum);
4397 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
4399 /* Setup data array. */
4400 switch (lock_type) {
4401 case READ_LOCK:
4402 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4403 POSIX_LOCK_TYPE_READ);
4404 break;
4405 case WRITE_LOCK:
4406 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4407 POSIX_LOCK_TYPE_WRITE);
4408 break;
4409 case UNLOCK_LOCK:
4410 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4411 POSIX_LOCK_TYPE_UNLOCK);
4412 break;
4413 default:
4414 return NULL;
4417 if (wait_lock) {
4418 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
4419 POSIX_LOCK_FLAG_WAIT);
4420 } else {
4421 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
4422 POSIX_LOCK_FLAG_NOWAIT);
4425 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
4426 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
4427 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
4429 subreq = cli_trans_send(state, /* mem ctx. */
4430 ev, /* event ctx. */
4431 cli, /* cli_state. */
4432 0, /* additional_flags2 */
4433 SMBtrans2, /* cmd. */
4434 NULL, /* pipe name. */
4435 -1, /* fid. */
4436 0, /* function. */
4437 0, /* flags. */
4438 &state->setup, /* setup. */
4439 1, /* num setup uint16_t words. */
4440 0, /* max returned setup. */
4441 state->param, /* param. */
4442 4, /* num param. */
4443 2, /* max returned param. */
4444 state->data, /* data. */
4445 POSIX_LOCK_DATA_SIZE, /* num data. */
4446 0); /* max returned data. */
4448 if (tevent_req_nomem(subreq, req)) {
4449 return tevent_req_post(req, ev);
4451 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
4452 return req;
4455 /****************************************************************************
4456 POSIX Lock a file.
4457 ****************************************************************************/
4459 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
4460 struct tevent_context *ev,
4461 struct cli_state *cli,
4462 uint16_t fnum,
4463 uint64_t offset,
4464 uint64_t len,
4465 bool wait_lock,
4466 enum brl_type lock_type)
4468 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4469 wait_lock, lock_type);
4472 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
4474 return tevent_req_simple_recv_ntstatus(req);
4477 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
4478 uint64_t offset, uint64_t len,
4479 bool wait_lock, enum brl_type lock_type)
4481 TALLOC_CTX *frame = talloc_stackframe();
4482 struct tevent_context *ev = NULL;
4483 struct tevent_req *req = NULL;
4484 NTSTATUS status = NT_STATUS_OK;
4486 if (smbXcli_conn_has_async_calls(cli->conn)) {
4488 * Can't use sync call while an async call is in flight
4490 status = NT_STATUS_INVALID_PARAMETER;
4491 goto fail;
4494 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
4495 status = NT_STATUS_INVALID_PARAMETER;
4496 goto fail;
4499 ev = samba_tevent_context_init(frame);
4500 if (ev == NULL) {
4501 status = NT_STATUS_NO_MEMORY;
4502 goto fail;
4505 req = cli_posix_lock_send(frame,
4507 cli,
4508 fnum,
4509 offset,
4510 len,
4511 wait_lock,
4512 lock_type);
4513 if (req == NULL) {
4514 status = NT_STATUS_NO_MEMORY;
4515 goto fail;
4518 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4519 goto fail;
4522 status = cli_posix_lock_recv(req);
4524 fail:
4525 TALLOC_FREE(frame);
4526 return status;
4529 /****************************************************************************
4530 POSIX Unlock a file.
4531 ****************************************************************************/
4533 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
4534 struct tevent_context *ev,
4535 struct cli_state *cli,
4536 uint16_t fnum,
4537 uint64_t offset,
4538 uint64_t len)
4540 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4541 false, UNLOCK_LOCK);
4544 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
4546 return tevent_req_simple_recv_ntstatus(req);
4549 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
4551 TALLOC_CTX *frame = talloc_stackframe();
4552 struct tevent_context *ev = NULL;
4553 struct tevent_req *req = NULL;
4554 NTSTATUS status = NT_STATUS_OK;
4556 if (smbXcli_conn_has_async_calls(cli->conn)) {
4558 * Can't use sync call while an async call is in flight
4560 status = NT_STATUS_INVALID_PARAMETER;
4561 goto fail;
4564 ev = samba_tevent_context_init(frame);
4565 if (ev == NULL) {
4566 status = NT_STATUS_NO_MEMORY;
4567 goto fail;
4570 req = cli_posix_unlock_send(frame,
4572 cli,
4573 fnum,
4574 offset,
4575 len);
4576 if (req == NULL) {
4577 status = NT_STATUS_NO_MEMORY;
4578 goto fail;
4581 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4582 goto fail;
4585 status = cli_posix_unlock_recv(req);
4587 fail:
4588 TALLOC_FREE(frame);
4589 return status;
4592 /****************************************************************************
4593 Do a SMBgetattrE call.
4594 ****************************************************************************/
4596 static void cli_getattrE_done(struct tevent_req *subreq);
4598 struct cli_getattrE_state {
4599 uint16_t vwv[1];
4600 int zone_offset;
4601 uint32_t attr;
4602 off_t size;
4603 time_t change_time;
4604 time_t access_time;
4605 time_t write_time;
4608 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
4609 struct tevent_context *ev,
4610 struct cli_state *cli,
4611 uint16_t fnum)
4613 struct tevent_req *req = NULL, *subreq = NULL;
4614 struct cli_getattrE_state *state = NULL;
4615 uint8_t additional_flags = 0;
4617 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
4618 if (req == NULL) {
4619 return NULL;
4622 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4623 SSVAL(state->vwv+0,0,fnum);
4625 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
4626 1, state->vwv, 0, NULL);
4627 if (tevent_req_nomem(subreq, req)) {
4628 return tevent_req_post(req, ev);
4630 tevent_req_set_callback(subreq, cli_getattrE_done, req);
4631 return req;
4634 static void cli_getattrE_done(struct tevent_req *subreq)
4636 struct tevent_req *req = tevent_req_callback_data(
4637 subreq, struct tevent_req);
4638 struct cli_getattrE_state *state = tevent_req_data(
4639 req, struct cli_getattrE_state);
4640 uint8_t wct;
4641 uint16_t *vwv = NULL;
4642 NTSTATUS status;
4644 status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
4645 NULL, NULL);
4646 TALLOC_FREE(subreq);
4647 if (tevent_req_nterror(req, status)) {
4648 return;
4651 state->size = (off_t)IVAL(vwv+6,0);
4652 state->attr = SVAL(vwv+10,0);
4653 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
4654 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
4655 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
4657 tevent_req_done(req);
4660 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
4661 uint32_t *pattr,
4662 off_t *size,
4663 time_t *change_time,
4664 time_t *access_time,
4665 time_t *write_time)
4667 struct cli_getattrE_state *state = tevent_req_data(
4668 req, struct cli_getattrE_state);
4669 NTSTATUS status;
4671 if (tevent_req_is_nterror(req, &status)) {
4672 return status;
4674 if (pattr) {
4675 *pattr = state->attr;
4677 if (size) {
4678 *size = state->size;
4680 if (change_time) {
4681 *change_time = state->change_time;
4683 if (access_time) {
4684 *access_time = state->access_time;
4686 if (write_time) {
4687 *write_time = state->write_time;
4689 return NT_STATUS_OK;
4692 /****************************************************************************
4693 Do a SMBgetatr call
4694 ****************************************************************************/
4696 static void cli_getatr_done(struct tevent_req *subreq);
4698 struct cli_getatr_state {
4699 int zone_offset;
4700 uint32_t attr;
4701 off_t size;
4702 time_t write_time;
4705 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
4706 struct tevent_context *ev,
4707 struct cli_state *cli,
4708 const char *fname)
4710 struct tevent_req *req = NULL, *subreq = NULL;
4711 struct cli_getatr_state *state = NULL;
4712 uint8_t additional_flags = 0;
4713 uint16_t additional_flags2 = 0;
4714 uint8_t *bytes = NULL;
4715 char *fname_cp = NULL;
4717 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
4718 if (req == NULL) {
4719 return NULL;
4722 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4724 bytes = talloc_array(state, uint8_t, 1);
4725 if (tevent_req_nomem(bytes, req)) {
4726 return tevent_req_post(req, ev);
4729 * SMBgetatr on a DFS share must use DFS names.
4731 fname_cp = smb1_dfs_share_path(state, cli, fname);
4732 if (tevent_req_nomem(fname_cp, req)) {
4733 return tevent_req_post(req, ev);
4735 bytes[0] = 4;
4736 bytes = smb_bytes_push_str(bytes,
4737 smbXcli_conn_use_unicode(cli->conn),
4738 fname_cp,
4739 strlen(fname_cp)+1,
4740 NULL);
4742 if (tevent_req_nomem(bytes, req)) {
4743 return tevent_req_post(req, ev);
4746 if (clistr_is_previous_version_path(fname)) {
4747 additional_flags2 = FLAGS2_REPARSE_PATH;
4750 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
4751 additional_flags2,
4752 0, NULL, talloc_get_size(bytes), bytes);
4753 if (tevent_req_nomem(subreq, req)) {
4754 return tevent_req_post(req, ev);
4756 tevent_req_set_callback(subreq, cli_getatr_done, req);
4757 return req;
4760 static void cli_getatr_done(struct tevent_req *subreq)
4762 struct tevent_req *req = tevent_req_callback_data(
4763 subreq, struct tevent_req);
4764 struct cli_getatr_state *state = tevent_req_data(
4765 req, struct cli_getatr_state);
4766 uint8_t wct;
4767 uint16_t *vwv = NULL;
4768 NTSTATUS status;
4770 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4771 NULL);
4772 TALLOC_FREE(subreq);
4773 if (tevent_req_nterror(req, status)) {
4774 return;
4777 state->attr = SVAL(vwv+0,0);
4778 state->size = (off_t)IVAL(vwv+3,0);
4779 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
4781 tevent_req_done(req);
4784 NTSTATUS cli_getatr_recv(struct tevent_req *req,
4785 uint32_t *pattr,
4786 off_t *size,
4787 time_t *write_time)
4789 struct cli_getatr_state *state = tevent_req_data(
4790 req, struct cli_getatr_state);
4791 NTSTATUS status;
4793 if (tevent_req_is_nterror(req, &status)) {
4794 return status;
4796 if (pattr) {
4797 *pattr = state->attr;
4799 if (size) {
4800 *size = state->size;
4802 if (write_time) {
4803 *write_time = state->write_time;
4805 return NT_STATUS_OK;
4808 NTSTATUS cli_getatr(struct cli_state *cli,
4809 const char *fname,
4810 uint32_t *pattr,
4811 off_t *size,
4812 time_t *write_time)
4814 TALLOC_CTX *frame = NULL;
4815 struct tevent_context *ev = NULL;
4816 struct tevent_req *req = NULL;
4817 NTSTATUS status = NT_STATUS_OK;
4819 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4820 struct stat_ex sbuf = {
4821 .st_ex_nlink = 0,
4823 uint32_t attr;
4825 status = cli_smb2_qpathinfo_basic(cli, fname, &sbuf, &attr);
4826 if (!NT_STATUS_IS_OK(status)) {
4827 return status;
4830 if (pattr != NULL) {
4831 *pattr = attr;
4833 if (size != NULL) {
4834 *size = sbuf.st_ex_size;
4836 if (write_time != NULL) {
4837 *write_time = sbuf.st_ex_mtime.tv_sec;
4839 return NT_STATUS_OK;
4842 frame = talloc_stackframe();
4844 if (smbXcli_conn_has_async_calls(cli->conn)) {
4846 * Can't use sync call while an async call is in flight
4848 status = NT_STATUS_INVALID_PARAMETER;
4849 goto fail;
4852 ev = samba_tevent_context_init(frame);
4853 if (ev == NULL) {
4854 status = NT_STATUS_NO_MEMORY;
4855 goto fail;
4858 req = cli_getatr_send(frame, ev, cli, fname);
4859 if (req == NULL) {
4860 status = NT_STATUS_NO_MEMORY;
4861 goto fail;
4864 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4865 goto fail;
4868 status = cli_getatr_recv(req,
4869 pattr,
4870 size,
4871 write_time);
4873 fail:
4874 TALLOC_FREE(frame);
4875 return status;
4878 /****************************************************************************
4879 Do a SMBsetattrE call.
4880 ****************************************************************************/
4882 static void cli_setattrE_done(struct tevent_req *subreq);
4884 struct cli_setattrE_state {
4885 uint16_t vwv[7];
4888 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
4889 struct tevent_context *ev,
4890 struct cli_state *cli,
4891 uint16_t fnum,
4892 time_t change_time,
4893 time_t access_time,
4894 time_t write_time)
4896 struct tevent_req *req = NULL, *subreq = NULL;
4897 struct cli_setattrE_state *state = NULL;
4898 uint8_t additional_flags = 0;
4900 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
4901 if (req == NULL) {
4902 return NULL;
4905 SSVAL(state->vwv+0, 0, fnum);
4906 push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
4907 smb1cli_conn_server_time_zone(cli->conn));
4908 push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
4909 smb1cli_conn_server_time_zone(cli->conn));
4910 push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
4911 smb1cli_conn_server_time_zone(cli->conn));
4913 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
4914 7, state->vwv, 0, NULL);
4915 if (tevent_req_nomem(subreq, req)) {
4916 return tevent_req_post(req, ev);
4918 tevent_req_set_callback(subreq, cli_setattrE_done, req);
4919 return req;
4922 static void cli_setattrE_done(struct tevent_req *subreq)
4924 struct tevent_req *req = tevent_req_callback_data(
4925 subreq, struct tevent_req);
4926 NTSTATUS status;
4928 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4929 TALLOC_FREE(subreq);
4930 if (tevent_req_nterror(req, status)) {
4931 return;
4933 tevent_req_done(req);
4936 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4938 return tevent_req_simple_recv_ntstatus(req);
4941 NTSTATUS cli_setattrE(struct cli_state *cli,
4942 uint16_t fnum,
4943 time_t change_time,
4944 time_t access_time,
4945 time_t write_time)
4947 TALLOC_CTX *frame = NULL;
4948 struct tevent_context *ev = NULL;
4949 struct tevent_req *req = NULL;
4950 NTSTATUS status = NT_STATUS_OK;
4952 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4953 return cli_smb2_setattrE(cli,
4954 fnum,
4955 change_time,
4956 access_time,
4957 write_time);
4960 frame = talloc_stackframe();
4962 if (smbXcli_conn_has_async_calls(cli->conn)) {
4964 * Can't use sync call while an async call is in flight
4966 status = NT_STATUS_INVALID_PARAMETER;
4967 goto fail;
4970 ev = samba_tevent_context_init(frame);
4971 if (ev == NULL) {
4972 status = NT_STATUS_NO_MEMORY;
4973 goto fail;
4976 req = cli_setattrE_send(frame, ev,
4977 cli,
4978 fnum,
4979 change_time,
4980 access_time,
4981 write_time);
4983 if (req == NULL) {
4984 status = NT_STATUS_NO_MEMORY;
4985 goto fail;
4988 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4989 goto fail;
4992 status = cli_setattrE_recv(req);
4994 fail:
4995 TALLOC_FREE(frame);
4996 return status;
4999 /****************************************************************************
5000 Do a SMBsetatr call.
5001 ****************************************************************************/
5003 static void cli_setatr_done(struct tevent_req *subreq);
5005 struct cli_setatr_state {
5006 uint16_t vwv[8];
5009 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
5010 struct tevent_context *ev,
5011 struct cli_state *cli,
5012 const char *fname,
5013 uint32_t attr,
5014 time_t mtime)
5016 struct tevent_req *req = NULL, *subreq = NULL;
5017 struct cli_setatr_state *state = NULL;
5018 uint8_t additional_flags = 0;
5019 uint16_t additional_flags2 = 0;
5020 uint8_t *bytes = NULL;
5021 char *fname_cp = NULL;
5023 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
5024 if (req == NULL) {
5025 return NULL;
5028 if (attr & 0xFFFF0000) {
5030 * Don't allow attributes greater than
5031 * 16-bits for a 16-bit protocol value.
5033 if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
5034 return tevent_req_post(req, ev);
5038 SSVAL(state->vwv+0, 0, attr);
5039 push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
5041 bytes = talloc_array(state, uint8_t, 1);
5042 if (tevent_req_nomem(bytes, req)) {
5043 return tevent_req_post(req, ev);
5046 * SMBsetatr on a DFS share must use DFS names.
5048 fname_cp = smb1_dfs_share_path(state, cli, fname);
5049 if (tevent_req_nomem(fname_cp, req)) {
5050 return tevent_req_post(req, ev);
5052 bytes[0] = 4;
5053 bytes = smb_bytes_push_str(bytes,
5054 smbXcli_conn_use_unicode(cli->conn),
5055 fname_cp,
5056 strlen(fname_cp)+1,
5057 NULL);
5058 if (tevent_req_nomem(bytes, req)) {
5059 return tevent_req_post(req, ev);
5061 bytes = talloc_realloc(state, bytes, uint8_t,
5062 talloc_get_size(bytes)+1);
5063 if (tevent_req_nomem(bytes, req)) {
5064 return tevent_req_post(req, ev);
5067 bytes[talloc_get_size(bytes)-1] = 4;
5068 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
5069 1, NULL);
5070 if (tevent_req_nomem(bytes, req)) {
5071 return tevent_req_post(req, ev);
5074 if (clistr_is_previous_version_path(fname)) {
5075 additional_flags2 = FLAGS2_REPARSE_PATH;
5078 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
5079 additional_flags2,
5080 8, state->vwv, talloc_get_size(bytes), bytes);
5081 if (tevent_req_nomem(subreq, req)) {
5082 return tevent_req_post(req, ev);
5084 tevent_req_set_callback(subreq, cli_setatr_done, req);
5085 return req;
5088 static void cli_setatr_done(struct tevent_req *subreq)
5090 struct tevent_req *req = tevent_req_callback_data(
5091 subreq, struct tevent_req);
5092 NTSTATUS status;
5094 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5095 TALLOC_FREE(subreq);
5096 if (tevent_req_nterror(req, status)) {
5097 return;
5099 tevent_req_done(req);
5102 NTSTATUS cli_setatr_recv(struct tevent_req *req)
5104 return tevent_req_simple_recv_ntstatus(req);
5107 NTSTATUS cli_setatr(struct cli_state *cli,
5108 const char *fname,
5109 uint32_t attr,
5110 time_t mtime)
5112 TALLOC_CTX *frame = NULL;
5113 struct tevent_context *ev = NULL;
5114 struct tevent_req *req = NULL;
5115 NTSTATUS status = NT_STATUS_OK;
5117 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5118 return cli_smb2_setatr(cli,
5119 fname,
5120 attr,
5121 mtime);
5124 frame = talloc_stackframe();
5126 if (smbXcli_conn_has_async_calls(cli->conn)) {
5128 * Can't use sync call while an async call is in flight
5130 status = NT_STATUS_INVALID_PARAMETER;
5131 goto fail;
5134 ev = samba_tevent_context_init(frame);
5135 if (ev == NULL) {
5136 status = NT_STATUS_NO_MEMORY;
5137 goto fail;
5140 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
5141 if (req == NULL) {
5142 status = NT_STATUS_NO_MEMORY;
5143 goto fail;
5146 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5147 goto fail;
5150 status = cli_setatr_recv(req);
5152 fail:
5153 TALLOC_FREE(frame);
5154 return status;
5157 /****************************************************************************
5158 Check for existence of a dir.
5159 ****************************************************************************/
5161 static void cli_chkpath_done(struct tevent_req *subreq);
5162 static void cli_chkpath_opened(struct tevent_req *subreq);
5163 static void cli_chkpath_closed(struct tevent_req *subreq);
5165 struct cli_chkpath_state {
5166 struct tevent_context *ev;
5167 struct cli_state *cli;
5170 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
5171 struct tevent_context *ev,
5172 struct cli_state *cli,
5173 const char *fname)
5175 struct tevent_req *req = NULL, *subreq = NULL;
5176 struct cli_chkpath_state *state = NULL;
5177 uint8_t additional_flags = 0;
5178 uint16_t additional_flags2 = 0;
5179 uint8_t *bytes = NULL;
5180 char *fname_cp = NULL;
5182 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
5183 if (req == NULL) {
5184 return NULL;
5186 state->ev = ev;
5187 state->cli = cli;
5189 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_NT1) {
5190 subreq = cli_ntcreate_send(
5191 state, /* mem_ctx */
5192 state->ev, /* ev */
5193 state->cli, /* cli */
5194 fname, /* fname */
5195 0, /* create_flags */
5196 FILE_READ_ATTRIBUTES, /* desired_access */
5197 FILE_ATTRIBUTE_DIRECTORY, /* FileAttributes */
5198 FILE_SHARE_READ|
5199 FILE_SHARE_WRITE|
5200 FILE_SHARE_DELETE, /* share_access */
5201 FILE_OPEN, /* CreateDisposition */
5202 FILE_DIRECTORY_FILE, /* CreateOptions */
5203 SMB2_IMPERSONATION_IMPERSONATION,
5204 0); /* SecurityFlags */
5205 if (tevent_req_nomem(subreq, req)) {
5206 return tevent_req_post(req, ev);
5208 tevent_req_set_callback(subreq, cli_chkpath_opened, req);
5209 return req;
5212 bytes = talloc_array(state, uint8_t, 1);
5213 if (tevent_req_nomem(bytes, req)) {
5214 return tevent_req_post(req, ev);
5217 * SMBcheckpath on a DFS share must use DFS names.
5219 fname_cp = smb1_dfs_share_path(state, cli, fname);
5220 if (tevent_req_nomem(fname_cp, req)) {
5221 return tevent_req_post(req, ev);
5223 bytes[0] = 4;
5224 bytes = smb_bytes_push_str(bytes,
5225 smbXcli_conn_use_unicode(cli->conn),
5226 fname_cp,
5227 strlen(fname_cp)+1,
5228 NULL);
5230 if (tevent_req_nomem(bytes, req)) {
5231 return tevent_req_post(req, ev);
5234 if (clistr_is_previous_version_path(fname)) {
5235 additional_flags2 = FLAGS2_REPARSE_PATH;
5238 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
5239 additional_flags2,
5240 0, NULL, talloc_get_size(bytes), bytes);
5241 if (tevent_req_nomem(subreq, req)) {
5242 return tevent_req_post(req, ev);
5244 tevent_req_set_callback(subreq, cli_chkpath_done, req);
5245 return req;
5248 static void cli_chkpath_done(struct tevent_req *subreq)
5250 NTSTATUS status = cli_smb_recv(
5251 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5252 tevent_req_simple_finish_ntstatus(subreq, status);
5255 static void cli_chkpath_opened(struct tevent_req *subreq)
5257 struct tevent_req *req = tevent_req_callback_data(
5258 subreq, struct tevent_req);
5259 struct cli_chkpath_state *state = tevent_req_data(
5260 req, struct cli_chkpath_state);
5261 NTSTATUS status;
5262 uint16_t fnum;
5264 status = cli_ntcreate_recv(subreq, &fnum, NULL);
5265 TALLOC_FREE(subreq);
5266 if (tevent_req_nterror(req, status)) {
5267 return;
5270 subreq = cli_close_send(state, state->ev, state->cli, fnum, 0);
5271 if (tevent_req_nomem(subreq, req)) {
5272 return;
5274 tevent_req_set_callback(subreq, cli_chkpath_closed, req);
5277 static void cli_chkpath_closed(struct tevent_req *subreq)
5279 NTSTATUS status = cli_close_recv(subreq);
5280 tevent_req_simple_finish_ntstatus(subreq, status);
5283 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
5285 return tevent_req_simple_recv_ntstatus(req);
5288 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
5290 TALLOC_CTX *frame = NULL;
5291 struct tevent_context *ev = NULL;
5292 struct tevent_req *req = NULL;
5293 char *path2 = NULL;
5294 NTSTATUS status = NT_STATUS_OK;
5296 frame = talloc_stackframe();
5298 if (smbXcli_conn_has_async_calls(cli->conn)) {
5300 * Can't use sync call while an async call is in flight
5302 status = NT_STATUS_INVALID_PARAMETER;
5303 goto fail;
5306 path2 = talloc_strdup(frame, path);
5307 if (!path2) {
5308 status = NT_STATUS_NO_MEMORY;
5309 goto fail;
5311 trim_char(path2,'\0','\\');
5312 if (!*path2) {
5313 path2 = talloc_strdup(frame, "\\");
5314 if (!path2) {
5315 status = NT_STATUS_NO_MEMORY;
5316 goto fail;
5320 ev = samba_tevent_context_init(frame);
5321 if (ev == NULL) {
5322 status = NT_STATUS_NO_MEMORY;
5323 goto fail;
5326 req = cli_chkpath_send(frame, ev, cli, path2);
5327 if (req == NULL) {
5328 status = NT_STATUS_NO_MEMORY;
5329 goto fail;
5332 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5333 goto fail;
5336 status = cli_chkpath_recv(req);
5337 fail:
5338 TALLOC_FREE(frame);
5339 return status;
5342 /****************************************************************************
5343 Query disk space.
5344 ****************************************************************************/
5346 static void cli_dskattr_done(struct tevent_req *subreq);
5348 struct cli_dskattr_state {
5349 int bsize;
5350 int total;
5351 int avail;
5354 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
5355 struct tevent_context *ev,
5356 struct cli_state *cli)
5358 struct tevent_req *req = NULL, *subreq = NULL;
5359 struct cli_dskattr_state *state = NULL;
5360 uint8_t additional_flags = 0;
5362 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
5363 if (req == NULL) {
5364 return NULL;
5367 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
5368 0, NULL, 0, NULL);
5369 if (tevent_req_nomem(subreq, req)) {
5370 return tevent_req_post(req, ev);
5372 tevent_req_set_callback(subreq, cli_dskattr_done, req);
5373 return req;
5376 static void cli_dskattr_done(struct tevent_req *subreq)
5378 struct tevent_req *req = tevent_req_callback_data(
5379 subreq, struct tevent_req);
5380 struct cli_dskattr_state *state = tevent_req_data(
5381 req, struct cli_dskattr_state);
5382 uint8_t wct;
5383 uint16_t *vwv = NULL;
5384 NTSTATUS status;
5386 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
5387 NULL);
5388 TALLOC_FREE(subreq);
5389 if (tevent_req_nterror(req, status)) {
5390 return;
5392 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
5393 state->total = SVAL(vwv+0, 0);
5394 state->avail = SVAL(vwv+3, 0);
5395 tevent_req_done(req);
5398 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
5400 struct cli_dskattr_state *state = tevent_req_data(
5401 req, struct cli_dskattr_state);
5402 NTSTATUS status;
5404 if (tevent_req_is_nterror(req, &status)) {
5405 return status;
5407 *bsize = state->bsize;
5408 *total = state->total;
5409 *avail = state->avail;
5410 return NT_STATUS_OK;
5413 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
5415 TALLOC_CTX *frame = NULL;
5416 struct tevent_context *ev = NULL;
5417 struct tevent_req *req = NULL;
5418 NTSTATUS status = NT_STATUS_OK;
5420 frame = talloc_stackframe();
5422 if (smbXcli_conn_has_async_calls(cli->conn)) {
5424 * Can't use sync call while an async call is in flight
5426 status = NT_STATUS_INVALID_PARAMETER;
5427 goto fail;
5430 ev = samba_tevent_context_init(frame);
5431 if (ev == NULL) {
5432 status = NT_STATUS_NO_MEMORY;
5433 goto fail;
5436 req = cli_dskattr_send(frame, ev, cli);
5437 if (req == NULL) {
5438 status = NT_STATUS_NO_MEMORY;
5439 goto fail;
5442 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5443 goto fail;
5446 status = cli_dskattr_recv(req, bsize, total, avail);
5448 fail:
5449 TALLOC_FREE(frame);
5450 return status;
5453 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
5454 uint64_t *total, uint64_t *avail)
5456 uint64_t sectors_per_block;
5457 uint64_t bytes_per_sector;
5458 int old_bsize = 0, old_total = 0, old_avail = 0;
5459 NTSTATUS status;
5461 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5462 return cli_smb2_dskattr(cli, path, bsize, total, avail);
5466 * Try the trans2 disk full size info call first.
5467 * We already use this in SMBC_fstatvfs_ctx().
5468 * Ignore 'actual_available_units' as we only
5469 * care about the quota for the caller.
5472 status = cli_get_fs_full_size_info(cli,
5473 total,
5474 avail,
5475 NULL,
5476 &sectors_per_block,
5477 &bytes_per_sector);
5479 /* Try and cope will all variants of "we don't do this call"
5480 and fall back to cli_dskattr. */
5482 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
5483 NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
5484 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
5485 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
5486 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
5487 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
5488 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
5489 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
5490 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
5491 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
5492 goto try_dskattr;
5495 if (!NT_STATUS_IS_OK(status)) {
5496 return status;
5499 if (bsize) {
5500 *bsize = sectors_per_block *
5501 bytes_per_sector;
5504 return NT_STATUS_OK;
5506 try_dskattr:
5508 /* Old SMB1 core protocol fallback. */
5509 status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
5510 if (!NT_STATUS_IS_OK(status)) {
5511 return status;
5513 if (bsize) {
5514 *bsize = (uint64_t)old_bsize;
5516 if (total) {
5517 *total = (uint64_t)old_total;
5519 if (avail) {
5520 *avail = (uint64_t)old_avail;
5522 return NT_STATUS_OK;
5525 /****************************************************************************
5526 Create and open a temporary file.
5527 ****************************************************************************/
5529 static void cli_ctemp_done(struct tevent_req *subreq);
5531 struct ctemp_state {
5532 uint16_t vwv[3];
5533 char *ret_path;
5534 uint16_t fnum;
5537 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
5538 struct tevent_context *ev,
5539 struct cli_state *cli,
5540 const char *path)
5542 struct tevent_req *req = NULL, *subreq = NULL;
5543 struct ctemp_state *state = NULL;
5544 uint8_t additional_flags = 0;
5545 uint16_t additional_flags2 = 0;
5546 uint8_t *bytes = NULL;
5547 char *path_cp = NULL;
5549 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
5550 if (req == NULL) {
5551 return NULL;
5554 SSVAL(state->vwv,0,0);
5555 SIVALS(state->vwv+1,0,-1);
5557 bytes = talloc_array(state, uint8_t, 1);
5558 if (tevent_req_nomem(bytes, req)) {
5559 return tevent_req_post(req, ev);
5562 * SMBctemp on a DFS share must use DFS names.
5564 path_cp = smb1_dfs_share_path(state, cli, path);
5565 if (tevent_req_nomem(path_cp, req)) {
5566 return tevent_req_post(req, ev);
5568 bytes[0] = 4;
5569 bytes = smb_bytes_push_str(bytes,
5570 smbXcli_conn_use_unicode(cli->conn),
5571 path_cp,
5572 strlen(path_cp)+1,
5573 NULL);
5574 if (tevent_req_nomem(bytes, req)) {
5575 return tevent_req_post(req, ev);
5578 if (clistr_is_previous_version_path(path)) {
5579 additional_flags2 = FLAGS2_REPARSE_PATH;
5582 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
5583 additional_flags2,
5584 3, state->vwv, talloc_get_size(bytes), bytes);
5585 if (tevent_req_nomem(subreq, req)) {
5586 return tevent_req_post(req, ev);
5588 tevent_req_set_callback(subreq, cli_ctemp_done, req);
5589 return req;
5592 static void cli_ctemp_done(struct tevent_req *subreq)
5594 struct tevent_req *req = tevent_req_callback_data(
5595 subreq, struct tevent_req);
5596 struct ctemp_state *state = tevent_req_data(
5597 req, struct ctemp_state);
5598 NTSTATUS status;
5599 uint8_t wcnt;
5600 uint16_t *vwv;
5601 uint32_t num_bytes = 0;
5602 uint8_t *bytes = NULL;
5604 status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
5605 &num_bytes, &bytes);
5606 TALLOC_FREE(subreq);
5607 if (tevent_req_nterror(req, status)) {
5608 return;
5611 state->fnum = SVAL(vwv+0, 0);
5613 /* From W2K3, the result is just the ASCII name */
5614 if (num_bytes < 2) {
5615 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
5616 return;
5619 if (pull_string_talloc(state,
5620 NULL,
5622 &state->ret_path,
5623 bytes,
5624 num_bytes,
5625 STR_ASCII) == 0) {
5626 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5627 return;
5629 tevent_req_done(req);
5632 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
5633 TALLOC_CTX *ctx,
5634 uint16_t *pfnum,
5635 char **outfile)
5637 struct ctemp_state *state = tevent_req_data(req,
5638 struct ctemp_state);
5639 NTSTATUS status;
5641 if (tevent_req_is_nterror(req, &status)) {
5642 return status;
5644 *pfnum = state->fnum;
5645 *outfile = talloc_strdup(ctx, state->ret_path);
5646 if (!*outfile) {
5647 return NT_STATUS_NO_MEMORY;
5649 return NT_STATUS_OK;
5652 NTSTATUS cli_ctemp(struct cli_state *cli,
5653 TALLOC_CTX *ctx,
5654 const char *path,
5655 uint16_t *pfnum,
5656 char **out_path)
5658 TALLOC_CTX *frame = talloc_stackframe();
5659 struct tevent_context *ev;
5660 struct tevent_req *req;
5661 NTSTATUS status = NT_STATUS_OK;
5663 if (smbXcli_conn_has_async_calls(cli->conn)) {
5665 * Can't use sync call while an async call is in flight
5667 status = NT_STATUS_INVALID_PARAMETER;
5668 goto fail;
5671 ev = samba_tevent_context_init(frame);
5672 if (ev == NULL) {
5673 status = NT_STATUS_NO_MEMORY;
5674 goto fail;
5677 req = cli_ctemp_send(frame, ev, cli, path);
5678 if (req == NULL) {
5679 status = NT_STATUS_NO_MEMORY;
5680 goto fail;
5683 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5684 goto fail;
5687 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
5689 fail:
5690 TALLOC_FREE(frame);
5691 return status;
5694 /*********************************************************
5695 Set an extended attribute utility fn.
5696 *********************************************************/
5698 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
5699 uint8_t *param, unsigned int param_len,
5700 const char *ea_name,
5701 const char *ea_val, size_t ea_len)
5703 uint16_t setup[1];
5704 unsigned int data_len = 0;
5705 uint8_t *data = NULL;
5706 char *p;
5707 size_t ea_namelen = strlen(ea_name);
5708 NTSTATUS status;
5710 SSVAL(setup, 0, setup_val);
5712 if (ea_namelen == 0 && ea_len == 0) {
5713 data_len = 4;
5714 data = talloc_array(talloc_tos(),
5715 uint8_t,
5716 data_len);
5717 if (!data) {
5718 return NT_STATUS_NO_MEMORY;
5720 p = (char *)data;
5721 SIVAL(p,0,data_len);
5722 } else {
5723 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
5724 data = talloc_array(talloc_tos(),
5725 uint8_t,
5726 data_len);
5727 if (!data) {
5728 return NT_STATUS_NO_MEMORY;
5730 p = (char *)data;
5731 SIVAL(p,0,data_len);
5732 p += 4;
5733 SCVAL(p, 0, 0); /* EA flags. */
5734 SCVAL(p, 1, ea_namelen);
5735 SSVAL(p, 2, ea_len);
5736 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
5737 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
5741 * FIXME - if we want to do previous version path
5742 * processing on an EA set call we need to turn this
5743 * into calls to cli_trans_send()/cli_trans_recv()
5744 * with a temporary event context, as cli_trans_send()
5745 * have access to the additional_flags2 needed to
5746 * send @GMT- paths. JRA.
5749 status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
5750 setup, 1, 0,
5751 param, param_len, 2,
5752 data, data_len, 0,
5753 NULL,
5754 NULL, 0, NULL, /* rsetup */
5755 NULL, 0, NULL, /* rparam */
5756 NULL, 0, NULL); /* rdata */
5757 talloc_free(data);
5758 return status;
5761 /*********************************************************
5762 Set an extended attribute on a pathname.
5763 *********************************************************/
5765 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
5766 const char *ea_name, const char *ea_val,
5767 size_t ea_len)
5769 unsigned int param_len = 0;
5770 uint8_t *param;
5771 NTSTATUS status;
5772 TALLOC_CTX *frame = NULL;
5773 char *path_cp = NULL;
5775 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5776 return cli_smb2_set_ea_path(cli,
5777 path,
5778 ea_name,
5779 ea_val,
5780 ea_len);
5783 frame = talloc_stackframe();
5785 param = talloc_array(frame, uint8_t, 6);
5786 if (!param) {
5787 status = NT_STATUS_NO_MEMORY;
5788 goto fail;
5790 SSVAL(param,0,SMB_INFO_SET_EA);
5791 SSVAL(param,2,0);
5792 SSVAL(param,4,0);
5795 * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
5797 path_cp = smb1_dfs_share_path(frame, cli, path);
5798 if (path_cp == NULL) {
5799 status = NT_STATUS_NO_MEMORY;
5800 goto fail;
5802 param = trans2_bytes_push_str(param,
5803 smbXcli_conn_use_unicode(cli->conn),
5804 path_cp,
5805 strlen(path_cp)+1,
5806 NULL);
5807 param_len = talloc_get_size(param);
5809 status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
5810 ea_name, ea_val, ea_len);
5812 fail:
5814 TALLOC_FREE(frame);
5815 return status;
5818 /*********************************************************
5819 Set an extended attribute on an fnum.
5820 *********************************************************/
5822 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
5823 const char *ea_name, const char *ea_val,
5824 size_t ea_len)
5826 uint8_t param[6] = { 0, };
5828 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5829 return cli_smb2_set_ea_fnum(cli,
5830 fnum,
5831 ea_name,
5832 ea_val,
5833 ea_len);
5836 SSVAL(param,0,fnum);
5837 SSVAL(param,2,SMB_INFO_SET_EA);
5839 return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
5840 ea_name, ea_val, ea_len);
5843 /*********************************************************
5844 Get an extended attribute list utility fn.
5845 *********************************************************/
5847 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
5848 size_t rdata_len,
5849 size_t *pnum_eas, struct ea_struct **pea_list)
5851 struct ea_struct *ea_list = NULL;
5852 size_t num_eas;
5853 size_t ea_size;
5854 const uint8_t *p;
5856 if (rdata_len < 4) {
5857 return false;
5860 ea_size = (size_t)IVAL(rdata,0);
5861 if (ea_size > rdata_len) {
5862 return false;
5865 if (ea_size == 0) {
5866 /* No EA's present. */
5867 *pnum_eas = 0;
5868 *pea_list = NULL;
5869 return true;
5872 p = rdata + 4;
5873 ea_size -= 4;
5875 /* Validate the EA list and count it. */
5876 for (num_eas = 0; ea_size >= 4; num_eas++) {
5877 unsigned int ea_namelen = CVAL(p,1);
5878 unsigned int ea_valuelen = SVAL(p,2);
5879 if (ea_namelen == 0) {
5880 return false;
5882 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
5883 return false;
5885 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
5886 p += 4 + ea_namelen + 1 + ea_valuelen;
5889 if (num_eas == 0) {
5890 *pnum_eas = 0;
5891 *pea_list = NULL;
5892 return true;
5895 *pnum_eas = num_eas;
5896 if (!pea_list) {
5897 /* Caller only wants number of EA's. */
5898 return true;
5901 ea_list = talloc_array(ctx, struct ea_struct, num_eas);
5902 if (!ea_list) {
5903 return false;
5906 p = rdata + 4;
5908 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
5909 struct ea_struct *ea = &ea_list[num_eas];
5910 fstring unix_ea_name;
5911 unsigned int ea_namelen = CVAL(p,1);
5912 unsigned int ea_valuelen = SVAL(p,2);
5914 ea->flags = CVAL(p,0);
5915 unix_ea_name[0] = '\0';
5916 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
5917 ea->name = talloc_strdup(ea_list, unix_ea_name);
5918 if (!ea->name) {
5919 goto fail;
5921 /* Ensure the value is null terminated (in case it's a string). */
5922 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
5923 if (!ea->value.data) {
5924 goto fail;
5926 if (ea_valuelen) {
5927 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
5929 ea->value.data[ea_valuelen] = 0;
5930 ea->value.length--;
5931 p += 4 + ea_namelen + 1 + ea_valuelen;
5934 *pea_list = ea_list;
5935 return true;
5937 fail:
5938 TALLOC_FREE(ea_list);
5939 return false;
5942 /*********************************************************
5943 Get an extended attribute list from a pathname.
5944 *********************************************************/
5946 struct cli_get_ea_list_path_state {
5947 uint32_t num_data;
5948 uint8_t *data;
5951 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
5953 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
5954 struct tevent_context *ev,
5955 struct cli_state *cli,
5956 const char *fname)
5958 struct tevent_req *req, *subreq;
5959 struct cli_get_ea_list_path_state *state;
5961 req = tevent_req_create(mem_ctx, &state,
5962 struct cli_get_ea_list_path_state);
5963 if (req == NULL) {
5964 return NULL;
5966 subreq = cli_qpathinfo_send(state, ev, cli, fname,
5967 SMB_INFO_QUERY_ALL_EAS, 4,
5968 CLI_BUFFER_SIZE);
5969 if (tevent_req_nomem(subreq, req)) {
5970 return tevent_req_post(req, ev);
5972 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
5973 return req;
5976 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
5978 struct tevent_req *req = tevent_req_callback_data(
5979 subreq, struct tevent_req);
5980 struct cli_get_ea_list_path_state *state = tevent_req_data(
5981 req, struct cli_get_ea_list_path_state);
5982 NTSTATUS status;
5984 status = cli_qpathinfo_recv(subreq, state, &state->data,
5985 &state->num_data);
5986 TALLOC_FREE(subreq);
5987 if (tevent_req_nterror(req, status)) {
5988 return;
5990 tevent_req_done(req);
5993 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5994 size_t *pnum_eas, struct ea_struct **peas)
5996 struct cli_get_ea_list_path_state *state = tevent_req_data(
5997 req, struct cli_get_ea_list_path_state);
5998 NTSTATUS status;
6000 if (tevent_req_is_nterror(req, &status)) {
6001 return status;
6003 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
6004 pnum_eas, peas)) {
6005 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6007 return NT_STATUS_OK;
6010 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
6011 TALLOC_CTX *ctx,
6012 size_t *pnum_eas,
6013 struct ea_struct **pea_list)
6015 TALLOC_CTX *frame = NULL;
6016 struct tevent_context *ev = NULL;
6017 struct tevent_req *req = NULL;
6018 NTSTATUS status = NT_STATUS_NO_MEMORY;
6020 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6021 return cli_smb2_get_ea_list_path(cli,
6022 path,
6023 ctx,
6024 pnum_eas,
6025 pea_list);
6028 frame = talloc_stackframe();
6030 if (smbXcli_conn_has_async_calls(cli->conn)) {
6032 * Can't use sync call while an async call is in flight
6034 status = NT_STATUS_INVALID_PARAMETER;
6035 goto fail;
6037 ev = samba_tevent_context_init(frame);
6038 if (ev == NULL) {
6039 goto fail;
6041 req = cli_get_ea_list_path_send(frame, ev, cli, path);
6042 if (req == NULL) {
6043 goto fail;
6045 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6046 goto fail;
6048 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
6049 fail:
6050 TALLOC_FREE(frame);
6051 return status;
6054 /****************************************************************************
6055 Convert open "flags" arg to uint32_t on wire.
6056 ****************************************************************************/
6058 static uint32_t open_flags_to_wire(int flags)
6060 int open_mode = flags & O_ACCMODE;
6061 uint32_t ret = 0;
6063 switch (open_mode) {
6064 case O_WRONLY:
6065 ret |= SMB_O_WRONLY;
6066 break;
6067 case O_RDWR:
6068 ret |= SMB_O_RDWR;
6069 break;
6070 default:
6071 case O_RDONLY:
6072 ret |= SMB_O_RDONLY;
6073 break;
6076 if (flags & O_CREAT) {
6077 ret |= SMB_O_CREAT;
6079 if (flags & O_EXCL) {
6080 ret |= SMB_O_EXCL;
6082 if (flags & O_TRUNC) {
6083 ret |= SMB_O_TRUNC;
6085 #if defined(O_SYNC)
6086 if (flags & O_SYNC) {
6087 ret |= SMB_O_SYNC;
6089 #endif /* O_SYNC */
6090 if (flags & O_APPEND) {
6091 ret |= SMB_O_APPEND;
6093 #if defined(O_DIRECT)
6094 if (flags & O_DIRECT) {
6095 ret |= SMB_O_DIRECT;
6097 #endif
6098 #if defined(O_DIRECTORY)
6099 if (flags & O_DIRECTORY) {
6100 ret |= SMB_O_DIRECTORY;
6102 #endif
6103 return ret;
6106 /****************************************************************************
6107 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
6108 ****************************************************************************/
6110 struct cli_posix_open_internal_state {
6111 uint16_t setup;
6112 uint8_t *param;
6113 uint8_t data[18];
6114 uint16_t fnum; /* Out */
6117 static void cli_posix_open_internal_done(struct tevent_req *subreq);
6119 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
6120 struct tevent_context *ev,
6121 struct cli_state *cli,
6122 const char *fname,
6123 uint32_t wire_flags,
6124 mode_t mode)
6126 struct tevent_req *req = NULL, *subreq = NULL;
6127 struct cli_posix_open_internal_state *state = NULL;
6128 char *fname_cp = NULL;
6130 req = tevent_req_create(
6131 mem_ctx, &state, struct cli_posix_open_internal_state);
6132 if (req == NULL) {
6133 return NULL;
6136 /* Setup setup word. */
6137 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
6139 /* Setup param array. */
6140 state->param = talloc_zero_array(state, uint8_t, 6);
6141 if (tevent_req_nomem(state->param, req)) {
6142 return tevent_req_post(req, ev);
6144 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
6147 * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
6149 fname_cp = smb1_dfs_share_path(state, cli, fname);
6150 if (tevent_req_nomem(fname_cp, req)) {
6151 return tevent_req_post(req, ev);
6153 state->param = trans2_bytes_push_str(
6154 state->param,
6155 smbXcli_conn_use_unicode(cli->conn),
6156 fname_cp,
6157 strlen(fname_cp)+1,
6158 NULL);
6160 if (tevent_req_nomem(state->param, req)) {
6161 return tevent_req_post(req, ev);
6164 SIVAL(state->data,0,0); /* No oplock. */
6165 SIVAL(state->data,4,wire_flags);
6166 SIVAL(state->data,8,unix_perms_to_wire(mode));
6167 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
6168 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
6170 subreq = cli_trans_send(state, /* mem ctx. */
6171 ev, /* event ctx. */
6172 cli, /* cli_state. */
6173 0, /* additional_flags2 */
6174 SMBtrans2, /* cmd. */
6175 NULL, /* pipe name. */
6176 -1, /* fid. */
6177 0, /* function. */
6178 0, /* flags. */
6179 &state->setup, /* setup. */
6180 1, /* num setup uint16_t words. */
6181 0, /* max returned setup. */
6182 state->param, /* param. */
6183 talloc_get_size(state->param),/* num param. */
6184 2, /* max returned param. */
6185 state->data, /* data. */
6186 18, /* num data. */
6187 12); /* max returned data. */
6189 if (tevent_req_nomem(subreq, req)) {
6190 return tevent_req_post(req, ev);
6192 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
6193 return req;
6196 static void cli_posix_open_internal_done(struct tevent_req *subreq)
6198 struct tevent_req *req = tevent_req_callback_data(
6199 subreq, struct tevent_req);
6200 struct cli_posix_open_internal_state *state = tevent_req_data(
6201 req, struct cli_posix_open_internal_state);
6202 NTSTATUS status;
6203 uint8_t *data;
6204 uint32_t num_data;
6206 status = cli_trans_recv(
6207 subreq,
6208 state,
6209 NULL,
6210 NULL,
6212 NULL,
6213 NULL,
6215 NULL,
6216 &data,
6218 &num_data);
6219 TALLOC_FREE(subreq);
6220 if (tevent_req_nterror(req, status)) {
6221 return;
6223 state->fnum = SVAL(data,2);
6224 tevent_req_done(req);
6227 static NTSTATUS cli_posix_open_internal_recv(struct tevent_req *req,
6228 uint16_t *pfnum)
6230 struct cli_posix_open_internal_state *state = tevent_req_data(
6231 req, struct cli_posix_open_internal_state);
6232 NTSTATUS status;
6234 if (tevent_req_is_nterror(req, &status)) {
6235 return status;
6237 *pfnum = state->fnum;
6238 return NT_STATUS_OK;
6241 struct cli_posix_open_state {
6242 uint16_t fnum;
6245 static void cli_posix_open_done(struct tevent_req *subreq);
6247 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
6248 struct tevent_context *ev,
6249 struct cli_state *cli,
6250 const char *fname,
6251 int flags,
6252 mode_t mode)
6254 struct tevent_req *req = NULL, *subreq = NULL;
6255 struct cli_posix_open_state *state = NULL;
6256 uint32_t wire_flags;
6258 req = tevent_req_create(mem_ctx, &state,
6259 struct cli_posix_open_state);
6260 if (req == NULL) {
6261 return NULL;
6264 wire_flags = open_flags_to_wire(flags);
6266 subreq = cli_posix_open_internal_send(
6267 mem_ctx, ev, cli, fname, wire_flags, mode);
6268 if (tevent_req_nomem(subreq, req)) {
6269 return tevent_req_post(req, ev);
6271 tevent_req_set_callback(subreq, cli_posix_open_done, req);
6272 return req;
6275 static void cli_posix_open_done(struct tevent_req *subreq)
6277 struct tevent_req *req = tevent_req_callback_data(
6278 subreq, struct tevent_req);
6279 struct cli_posix_open_state *state = tevent_req_data(
6280 req, struct cli_posix_open_state);
6281 NTSTATUS status;
6283 status = cli_posix_open_internal_recv(subreq, &state->fnum);
6284 tevent_req_simple_finish_ntstatus(subreq, status);
6287 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
6289 struct cli_posix_open_state *state = tevent_req_data(
6290 req, struct cli_posix_open_state);
6291 NTSTATUS status;
6293 if (tevent_req_is_nterror(req, &status)) {
6294 return status;
6296 *pfnum = state->fnum;
6297 return NT_STATUS_OK;
6300 /****************************************************************************
6301 Open - POSIX semantics. Doesn't request oplock.
6302 ****************************************************************************/
6304 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
6305 int flags, mode_t mode, uint16_t *pfnum)
6308 TALLOC_CTX *frame = talloc_stackframe();
6309 struct tevent_context *ev = NULL;
6310 struct tevent_req *req = NULL;
6311 NTSTATUS status = NT_STATUS_NO_MEMORY;
6313 if (smbXcli_conn_has_async_calls(cli->conn)) {
6315 * Can't use sync call while an async call is in flight
6317 status = NT_STATUS_INVALID_PARAMETER;
6318 goto fail;
6320 ev = samba_tevent_context_init(frame);
6321 if (ev == NULL) {
6322 goto fail;
6324 req = cli_posix_open_send(
6325 frame, ev, cli, fname, flags, mode);
6326 if (req == NULL) {
6327 goto fail;
6329 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6330 goto fail;
6332 status = cli_posix_open_recv(req, pfnum);
6333 fail:
6334 TALLOC_FREE(frame);
6335 return status;
6338 struct cli_posix_mkdir_state {
6339 struct tevent_context *ev;
6340 struct cli_state *cli;
6343 static void cli_posix_mkdir_done(struct tevent_req *subreq);
6345 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
6346 struct tevent_context *ev,
6347 struct cli_state *cli,
6348 const char *fname,
6349 mode_t mode)
6351 struct tevent_req *req = NULL, *subreq = NULL;
6352 struct cli_posix_mkdir_state *state = NULL;
6353 uint32_t wire_flags;
6355 req = tevent_req_create(
6356 mem_ctx, &state, struct cli_posix_mkdir_state);
6357 if (req == NULL) {
6358 return NULL;
6360 state->ev = ev;
6361 state->cli = cli;
6363 wire_flags = SMB_O_CREAT | SMB_O_DIRECTORY;
6365 subreq = cli_posix_open_internal_send(
6366 mem_ctx, ev, cli, fname, wire_flags, mode);
6367 if (tevent_req_nomem(subreq, req)) {
6368 return tevent_req_post(req, ev);
6370 tevent_req_set_callback(subreq, cli_posix_mkdir_done, req);
6371 return req;
6374 static void cli_posix_mkdir_done(struct tevent_req *subreq)
6376 struct tevent_req *req = tevent_req_callback_data(
6377 subreq, struct tevent_req);
6378 NTSTATUS status;
6379 uint16_t fnum;
6381 status = cli_posix_open_internal_recv(subreq, &fnum);
6382 TALLOC_FREE(subreq);
6383 if (tevent_req_nterror(req, status)) {
6384 return;
6386 tevent_req_done(req);
6389 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
6391 return tevent_req_simple_recv_ntstatus(req);
6394 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
6396 TALLOC_CTX *frame = talloc_stackframe();
6397 struct tevent_context *ev = NULL;
6398 struct tevent_req *req = NULL;
6399 NTSTATUS status = NT_STATUS_NO_MEMORY;
6401 if (smbXcli_conn_has_async_calls(cli->conn)) {
6403 * Can't use sync call while an async call is in flight
6405 status = NT_STATUS_INVALID_PARAMETER;
6406 goto fail;
6409 ev = samba_tevent_context_init(frame);
6410 if (ev == NULL) {
6411 goto fail;
6413 req = cli_posix_mkdir_send(
6414 frame, ev, cli, fname, mode);
6415 if (req == NULL) {
6416 goto fail;
6418 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6419 goto fail;
6421 status = cli_posix_mkdir_recv(req);
6422 fail:
6423 TALLOC_FREE(frame);
6424 return status;
6427 /****************************************************************************
6428 unlink or rmdir - POSIX semantics.
6429 ****************************************************************************/
6431 struct cli_posix_unlink_internal_state {
6432 uint8_t data[2];
6435 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
6437 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
6438 struct tevent_context *ev,
6439 struct cli_state *cli,
6440 const char *fname,
6441 uint16_t level)
6443 struct tevent_req *req = NULL, *subreq = NULL;
6444 struct cli_posix_unlink_internal_state *state = NULL;
6446 req = tevent_req_create(mem_ctx, &state,
6447 struct cli_posix_unlink_internal_state);
6448 if (req == NULL) {
6449 return NULL;
6452 /* Setup data word. */
6453 SSVAL(state->data, 0, level);
6455 subreq = cli_setpathinfo_send(state, ev, cli,
6456 SMB_POSIX_PATH_UNLINK,
6457 fname,
6458 state->data, sizeof(state->data));
6459 if (tevent_req_nomem(subreq, req)) {
6460 return tevent_req_post(req, ev);
6462 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
6463 return req;
6466 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
6468 NTSTATUS status = cli_setpathinfo_recv(subreq);
6469 tevent_req_simple_finish_ntstatus(subreq, status);
6472 static NTSTATUS cli_posix_unlink_internal_recv(struct tevent_req *req)
6474 return tevent_req_simple_recv_ntstatus(req);
6477 struct cli_posix_unlink_state {
6478 uint8_t dummy;
6481 static void cli_posix_unlink_done(struct tevent_req *subreq);
6483 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
6484 struct tevent_context *ev,
6485 struct cli_state *cli,
6486 const char *fname)
6488 struct tevent_req *req = NULL, *subreq = NULL;
6489 struct cli_posix_unlink_state *state;
6491 req = tevent_req_create(
6492 mem_ctx, &state, struct cli_posix_unlink_state);
6493 if (req == NULL) {
6494 return NULL;
6496 subreq = cli_posix_unlink_internal_send(
6497 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_FILE_TARGET);
6498 if (tevent_req_nomem(subreq, req)) {
6499 return tevent_req_post(req, ev);
6501 tevent_req_set_callback(subreq, cli_posix_unlink_done, req);
6502 return req;
6505 static void cli_posix_unlink_done(struct tevent_req *subreq)
6507 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6508 tevent_req_simple_finish_ntstatus(subreq, status);
6511 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
6513 return tevent_req_simple_recv_ntstatus(req);
6516 /****************************************************************************
6517 unlink - POSIX semantics.
6518 ****************************************************************************/
6520 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
6522 TALLOC_CTX *frame = talloc_stackframe();
6523 struct tevent_context *ev = NULL;
6524 struct tevent_req *req = NULL;
6525 NTSTATUS status = NT_STATUS_OK;
6527 if (smbXcli_conn_has_async_calls(cli->conn)) {
6529 * Can't use sync call while an async call is in flight
6531 status = NT_STATUS_INVALID_PARAMETER;
6532 goto fail;
6535 ev = samba_tevent_context_init(frame);
6536 if (ev == NULL) {
6537 status = NT_STATUS_NO_MEMORY;
6538 goto fail;
6541 req = cli_posix_unlink_send(frame,
6543 cli,
6544 fname);
6545 if (req == NULL) {
6546 status = NT_STATUS_NO_MEMORY;
6547 goto fail;
6550 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6551 goto fail;
6554 status = cli_posix_unlink_recv(req);
6556 fail:
6557 TALLOC_FREE(frame);
6558 return status;
6561 /****************************************************************************
6562 rmdir - POSIX semantics.
6563 ****************************************************************************/
6565 struct cli_posix_rmdir_state {
6566 uint8_t dummy;
6569 static void cli_posix_rmdir_done(struct tevent_req *subreq);
6571 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
6572 struct tevent_context *ev,
6573 struct cli_state *cli,
6574 const char *fname)
6576 struct tevent_req *req = NULL, *subreq = NULL;
6577 struct cli_posix_rmdir_state *state;
6579 req = tevent_req_create(mem_ctx, &state, struct cli_posix_rmdir_state);
6580 if (req == NULL) {
6581 return NULL;
6583 subreq = cli_posix_unlink_internal_send(
6584 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_DIRECTORY_TARGET);
6585 if (tevent_req_nomem(subreq, req)) {
6586 return tevent_req_post(req, ev);
6588 tevent_req_set_callback(subreq, cli_posix_rmdir_done, req);
6589 return req;
6592 static void cli_posix_rmdir_done(struct tevent_req *subreq)
6594 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6595 tevent_req_simple_finish_ntstatus(subreq, status);
6598 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
6600 return tevent_req_simple_recv_ntstatus(req);
6603 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
6605 TALLOC_CTX *frame = talloc_stackframe();
6606 struct tevent_context *ev = NULL;
6607 struct tevent_req *req = NULL;
6608 NTSTATUS status = NT_STATUS_OK;
6610 if (smbXcli_conn_has_async_calls(cli->conn)) {
6612 * Can't use sync call while an async call is in flight
6614 status = NT_STATUS_INVALID_PARAMETER;
6615 goto fail;
6618 ev = samba_tevent_context_init(frame);
6619 if (ev == NULL) {
6620 status = NT_STATUS_NO_MEMORY;
6621 goto fail;
6624 req = cli_posix_rmdir_send(frame,
6626 cli,
6627 fname);
6628 if (req == NULL) {
6629 status = NT_STATUS_NO_MEMORY;
6630 goto fail;
6633 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6634 goto fail;
6637 status = cli_posix_rmdir_recv(req, frame);
6639 fail:
6640 TALLOC_FREE(frame);
6641 return status;
6644 /****************************************************************************
6645 filechangenotify
6646 ****************************************************************************/
6648 struct cli_notify_state {
6649 struct tevent_req *subreq;
6650 uint16_t setup[4];
6651 uint32_t num_changes;
6652 struct notify_change *changes;
6655 static void cli_notify_done(struct tevent_req *subreq);
6656 static void cli_notify_done_smb2(struct tevent_req *subreq);
6657 static bool cli_notify_cancel(struct tevent_req *req);
6659 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
6660 struct tevent_context *ev,
6661 struct cli_state *cli, uint16_t fnum,
6662 uint32_t buffer_size,
6663 uint32_t completion_filter, bool recursive)
6665 struct tevent_req *req;
6666 struct cli_notify_state *state;
6667 unsigned old_timeout;
6669 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
6670 if (req == NULL) {
6671 return NULL;
6674 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6676 * Notifies should not time out
6678 old_timeout = cli_set_timeout(cli, 0);
6680 state->subreq = cli_smb2_notify_send(
6681 state,
6683 cli,
6684 fnum,
6685 buffer_size,
6686 completion_filter,
6687 recursive);
6689 cli_set_timeout(cli, old_timeout);
6691 if (tevent_req_nomem(state->subreq, req)) {
6692 return tevent_req_post(req, ev);
6694 tevent_req_set_callback(
6695 state->subreq, cli_notify_done_smb2, req);
6696 goto done;
6699 SIVAL(state->setup, 0, completion_filter);
6700 SSVAL(state->setup, 4, fnum);
6701 SSVAL(state->setup, 6, recursive);
6704 * Notifies should not time out
6706 old_timeout = cli_set_timeout(cli, 0);
6708 state->subreq = cli_trans_send(
6709 state, /* mem ctx. */
6710 ev, /* event ctx. */
6711 cli, /* cli_state. */
6712 0, /* additional_flags2 */
6713 SMBnttrans, /* cmd. */
6714 NULL, /* pipe name. */
6715 -1, /* fid. */
6716 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
6717 0, /* flags. */
6718 (uint16_t *)state->setup, /* setup. */
6719 4, /* num setup uint16_t words. */
6720 0, /* max returned setup. */
6721 NULL, /* param. */
6722 0, /* num param. */
6723 buffer_size, /* max returned param. */
6724 NULL, /* data. */
6725 0, /* num data. */
6726 0); /* max returned data. */
6728 cli_set_timeout(cli, old_timeout);
6730 if (tevent_req_nomem(state->subreq, req)) {
6731 return tevent_req_post(req, ev);
6733 tevent_req_set_callback(state->subreq, cli_notify_done, req);
6734 done:
6735 tevent_req_set_cancel_fn(req, cli_notify_cancel);
6736 return req;
6739 static bool cli_notify_cancel(struct tevent_req *req)
6741 struct cli_notify_state *state = tevent_req_data(
6742 req, struct cli_notify_state);
6743 bool ok;
6745 ok = tevent_req_cancel(state->subreq);
6746 return ok;
6749 static void cli_notify_done(struct tevent_req *subreq)
6751 struct tevent_req *req = tevent_req_callback_data(
6752 subreq, struct tevent_req);
6753 struct cli_notify_state *state = tevent_req_data(
6754 req, struct cli_notify_state);
6755 NTSTATUS status;
6756 uint8_t *params;
6757 uint32_t i, ofs, num_params;
6758 uint16_t flags2;
6760 status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
6761 &params, 0, &num_params, NULL, 0, NULL);
6762 TALLOC_FREE(subreq);
6763 state->subreq = NULL;
6764 if (tevent_req_nterror(req, status)) {
6765 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
6766 return;
6769 state->num_changes = 0;
6770 ofs = 0;
6772 while (num_params - ofs > 12) {
6773 uint32_t next = IVAL(params, ofs);
6774 state->num_changes += 1;
6776 if ((next == 0) || (ofs+next >= num_params)) {
6777 break;
6779 ofs += next;
6782 state->changes = talloc_array(state, struct notify_change,
6783 state->num_changes);
6784 if (tevent_req_nomem(state->changes, req)) {
6785 TALLOC_FREE(params);
6786 return;
6789 ofs = 0;
6791 for (i=0; i<state->num_changes; i++) {
6792 uint32_t next = IVAL(params, ofs);
6793 uint32_t len = IVAL(params, ofs+8);
6794 ssize_t ret;
6795 char *name;
6797 if (smb_buffer_oob(num_params, ofs + 12, len)) {
6798 TALLOC_FREE(params);
6799 tevent_req_nterror(
6800 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
6801 return;
6804 state->changes[i].action = IVAL(params, ofs+4);
6805 ret = pull_string_talloc(state->changes,
6806 (char *)params,
6807 flags2,
6808 &name,
6809 params+ofs+12,
6810 len,
6811 STR_TERMINATE|STR_UNICODE);
6812 if (ret == -1) {
6813 TALLOC_FREE(params);
6814 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
6815 return;
6817 state->changes[i].name = name;
6818 ofs += next;
6821 TALLOC_FREE(params);
6822 tevent_req_done(req);
6825 static void cli_notify_done_smb2(struct tevent_req *subreq)
6827 struct tevent_req *req = tevent_req_callback_data(
6828 subreq, struct tevent_req);
6829 struct cli_notify_state *state = tevent_req_data(
6830 req, struct cli_notify_state);
6831 NTSTATUS status;
6833 status = cli_smb2_notify_recv(
6834 subreq,
6835 state,
6836 &state->changes,
6837 &state->num_changes);
6838 TALLOC_FREE(subreq);
6839 if (tevent_req_nterror(req, status)) {
6840 return;
6842 tevent_req_done(req);
6845 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6846 uint32_t *pnum_changes,
6847 struct notify_change **pchanges)
6849 struct cli_notify_state *state = tevent_req_data(
6850 req, struct cli_notify_state);
6851 NTSTATUS status;
6853 if (tevent_req_is_nterror(req, &status)) {
6854 return status;
6857 *pnum_changes = state->num_changes;
6858 *pchanges = talloc_move(mem_ctx, &state->changes);
6859 return NT_STATUS_OK;
6862 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
6863 uint32_t completion_filter, bool recursive,
6864 TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
6865 struct notify_change **pchanges)
6867 TALLOC_CTX *frame;
6868 struct tevent_context *ev;
6869 struct tevent_req *req;
6870 NTSTATUS status = NT_STATUS_NO_MEMORY;
6872 frame = talloc_stackframe();
6874 if (smbXcli_conn_has_async_calls(cli->conn)) {
6876 * Can't use sync call while an async call is in flight
6878 status = NT_STATUS_INVALID_PARAMETER;
6879 goto fail;
6881 ev = samba_tevent_context_init(frame);
6882 if (ev == NULL) {
6883 goto fail;
6885 req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
6886 completion_filter, recursive);
6887 if (req == NULL) {
6888 goto fail;
6890 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6891 goto fail;
6893 status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
6894 fail:
6895 TALLOC_FREE(frame);
6896 return status;
6899 struct cli_qpathinfo_state {
6900 uint8_t *param;
6901 uint8_t *data;
6902 uint16_t setup[1];
6903 uint32_t min_rdata;
6904 uint8_t *rdata;
6905 uint32_t num_rdata;
6908 static void cli_qpathinfo_done(struct tevent_req *subreq);
6909 static void cli_qpathinfo_done2(struct tevent_req *subreq);
6911 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
6912 struct tevent_context *ev,
6913 struct cli_state *cli, const char *fname,
6914 uint16_t level, uint32_t min_rdata,
6915 uint32_t max_rdata)
6917 struct tevent_req *req, *subreq;
6918 struct cli_qpathinfo_state *state;
6919 uint16_t additional_flags2 = 0;
6920 char *fname_cp = NULL;
6922 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
6923 if (req == NULL) {
6924 return NULL;
6927 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6928 uint16_t smb2_level = 0;
6930 switch (level) {
6931 case SMB_QUERY_FILE_ALT_NAME_INFO:
6932 smb2_level = FSCC_FILE_ALTERNATE_NAME_INFORMATION;
6933 break;
6934 default:
6935 tevent_req_nterror(req, NT_STATUS_INVALID_LEVEL);
6936 return tevent_req_post(req, ev);
6939 subreq = cli_smb2_qpathinfo_send(state,
6941 cli,
6942 fname,
6943 smb2_level,
6944 min_rdata,
6945 max_rdata);
6946 if (tevent_req_nomem(subreq, req)) {
6947 return tevent_req_post(req, ev);
6949 tevent_req_set_callback(subreq, cli_qpathinfo_done2, req);
6950 return req;
6953 state->min_rdata = min_rdata;
6954 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
6956 state->param = talloc_zero_array(state, uint8_t, 6);
6957 if (tevent_req_nomem(state->param, req)) {
6958 return tevent_req_post(req, ev);
6960 SSVAL(state->param, 0, level);
6962 * qpathinfo on a DFS share must use DFS names.
6964 fname_cp = smb1_dfs_share_path(state, cli, fname);
6965 if (tevent_req_nomem(fname_cp, req)) {
6966 return tevent_req_post(req, ev);
6968 state->param = trans2_bytes_push_str(state->param,
6969 smbXcli_conn_use_unicode(cli->conn),
6970 fname_cp,
6971 strlen(fname_cp)+1,
6972 NULL);
6973 if (tevent_req_nomem(state->param, req)) {
6974 return tevent_req_post(req, ev);
6977 if (clistr_is_previous_version_path(fname) &&
6978 !INFO_LEVEL_IS_UNIX(level)) {
6979 additional_flags2 = FLAGS2_REPARSE_PATH;
6982 subreq = cli_trans_send(
6983 state, /* mem ctx. */
6984 ev, /* event ctx. */
6985 cli, /* cli_state. */
6986 additional_flags2, /* additional_flags2 */
6987 SMBtrans2, /* cmd. */
6988 NULL, /* pipe name. */
6989 -1, /* fid. */
6990 0, /* function. */
6991 0, /* flags. */
6992 state->setup, /* setup. */
6993 1, /* num setup uint16_t words. */
6994 0, /* max returned setup. */
6995 state->param, /* param. */
6996 talloc_get_size(state->param), /* num param. */
6997 2, /* max returned param. */
6998 NULL, /* data. */
6999 0, /* num data. */
7000 max_rdata); /* max returned data. */
7002 if (tevent_req_nomem(subreq, req)) {
7003 return tevent_req_post(req, ev);
7005 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
7006 return req;
7009 static void cli_qpathinfo_done(struct tevent_req *subreq)
7011 struct tevent_req *req = tevent_req_callback_data(
7012 subreq, struct tevent_req);
7013 struct cli_qpathinfo_state *state = tevent_req_data(
7014 req, struct cli_qpathinfo_state);
7015 NTSTATUS status;
7017 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
7018 NULL, 0, NULL,
7019 &state->rdata, state->min_rdata,
7020 &state->num_rdata);
7021 if (tevent_req_nterror(req, status)) {
7022 return;
7024 tevent_req_done(req);
7027 static void cli_qpathinfo_done2(struct tevent_req *subreq)
7029 struct tevent_req *req =
7030 tevent_req_callback_data(subreq, struct tevent_req);
7031 struct cli_qpathinfo_state *state =
7032 tevent_req_data(req, struct cli_qpathinfo_state);
7033 NTSTATUS status;
7035 status = cli_smb2_qpathinfo_recv(subreq,
7036 state,
7037 &state->rdata,
7038 &state->num_rdata);
7039 if (tevent_req_nterror(req, status)) {
7040 return;
7042 tevent_req_done(req);
7045 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
7046 uint8_t **rdata, uint32_t *num_rdata)
7048 struct cli_qpathinfo_state *state = tevent_req_data(
7049 req, struct cli_qpathinfo_state);
7050 NTSTATUS status;
7052 if (tevent_req_is_nterror(req, &status)) {
7053 return status;
7055 if (rdata != NULL) {
7056 *rdata = talloc_move(mem_ctx, &state->rdata);
7057 } else {
7058 TALLOC_FREE(state->rdata);
7060 if (num_rdata != NULL) {
7061 *num_rdata = state->num_rdata;
7063 return NT_STATUS_OK;
7066 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
7067 const char *fname, uint16_t level, uint32_t min_rdata,
7068 uint32_t max_rdata,
7069 uint8_t **rdata, uint32_t *num_rdata)
7071 TALLOC_CTX *frame = talloc_stackframe();
7072 struct tevent_context *ev;
7073 struct tevent_req *req;
7074 NTSTATUS status = NT_STATUS_NO_MEMORY;
7076 if (smbXcli_conn_has_async_calls(cli->conn)) {
7078 * Can't use sync call while an async call is in flight
7080 status = NT_STATUS_INVALID_PARAMETER;
7081 goto fail;
7083 ev = samba_tevent_context_init(frame);
7084 if (ev == NULL) {
7085 goto fail;
7087 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
7088 max_rdata);
7089 if (req == NULL) {
7090 goto fail;
7092 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7093 goto fail;
7095 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
7096 fail:
7097 TALLOC_FREE(frame);
7098 return status;
7101 struct cli_qfileinfo_state {
7102 uint16_t setup[1];
7103 uint8_t param[4];
7104 uint8_t *data;
7105 uint16_t recv_flags2;
7106 uint32_t min_rdata;
7107 uint8_t *rdata;
7108 uint32_t num_rdata;
7111 static void cli_qfileinfo_done2(struct tevent_req *subreq);
7112 static void cli_qfileinfo_done(struct tevent_req *subreq);
7114 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
7115 struct tevent_context *ev,
7116 struct cli_state *cli,
7117 uint16_t fnum,
7118 uint16_t fscc_level,
7119 uint32_t min_rdata,
7120 uint32_t max_rdata)
7122 struct tevent_req *req, *subreq;
7123 struct cli_qfileinfo_state *state;
7124 uint16_t smb_level;
7126 req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
7127 if (req == NULL) {
7128 return NULL;
7131 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
7132 max_rdata = MIN(max_rdata,
7133 smb2cli_conn_max_trans_size(cli->conn));
7135 subreq = cli_smb2_query_info_fnum_send(
7136 state, /* mem_ctx */
7137 ev, /* ev */
7138 cli, /* cli */
7139 fnum, /* fnum */
7140 SMB2_0_INFO_FILE, /* in_info_type */
7141 fscc_level, /* in_file_info_class */
7142 max_rdata, /* in_max_output_length */
7143 NULL, /* in_input_buffer */
7144 0, /* in_additional_info */
7145 0); /* in_flags */
7146 if (tevent_req_nomem(subreq, req)) {
7147 return tevent_req_post(req, ev);
7149 tevent_req_set_callback(subreq, cli_qfileinfo_done2, req);
7150 return req;
7153 max_rdata = MIN(max_rdata, UINT16_MAX);
7155 switch (fscc_level) {
7156 case FSCC_FILE_BASIC_INFORMATION:
7157 smb_level = SMB_QUERY_FILE_BASIC_INFO;
7158 break;
7159 case FSCC_FILE_STANDARD_INFORMATION:
7160 smb_level = SMB_QUERY_FILE_STANDARD_INFO;
7161 break;
7162 case FSCC_FILE_EA_INFORMATION:
7163 smb_level = SMB_QUERY_FILE_EA_INFO;
7164 break;
7165 case FSCC_FILE_NAME_INFORMATION:
7166 smb_level = SMB_QUERY_FILE_NAME_INFO;
7167 break;
7168 case FSCC_FILE_ALL_INFORMATION:
7169 smb_level = SMB_QUERY_FILE_ALL_INFO;
7170 break;
7171 case FSCC_FILE_ALTERNATE_NAME_INFORMATION:
7172 smb_level = SMB_QUERY_FILE_ALT_NAME_INFO;
7173 break;
7174 case FSCC_FILE_STREAM_INFORMATION:
7175 smb_level = SMB_QUERY_FILE_STREAM_INFO;
7176 break;
7177 case FSCC_FILE_COMPRESSION_INFORMATION:
7178 smb_level = SMB_QUERY_COMPRESSION_INFO;
7179 break;
7180 default:
7181 /* Probably wrong, but the server will tell us */
7182 smb_level = fscc_level;
7183 break;
7186 state->min_rdata = min_rdata;
7187 SSVAL(state->param, 0, fnum);
7188 SSVAL(state->param, 2, smb_level);
7189 SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
7191 subreq = cli_trans_send(
7192 state, /* mem ctx. */
7193 ev, /* event ctx. */
7194 cli, /* cli_state. */
7195 0, /* additional_flags2 */
7196 SMBtrans2, /* cmd. */
7197 NULL, /* pipe name. */
7198 -1, /* fid. */
7199 0, /* function. */
7200 0, /* flags. */
7201 state->setup, /* setup. */
7202 1, /* num setup uint16_t words. */
7203 0, /* max returned setup. */
7204 state->param, /* param. */
7205 sizeof(state->param), /* num param. */
7206 2, /* max returned param. */
7207 NULL, /* data. */
7208 0, /* num data. */
7209 max_rdata); /* max returned data. */
7211 if (tevent_req_nomem(subreq, req)) {
7212 return tevent_req_post(req, ev);
7214 tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
7215 return req;
7218 static void cli_qfileinfo_done2(struct tevent_req *subreq)
7220 struct tevent_req *req = tevent_req_callback_data(subreq,
7221 struct tevent_req);
7222 struct cli_qfileinfo_state *state = tevent_req_data(
7223 req, struct cli_qfileinfo_state);
7224 DATA_BLOB outbuf = {};
7225 NTSTATUS status;
7227 status = cli_smb2_query_info_fnum_recv(subreq, state, &outbuf);
7228 TALLOC_FREE(subreq);
7229 if (tevent_req_nterror(req, status)) {
7230 return;
7233 if (outbuf.length < state->min_rdata) {
7234 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
7235 return;
7238 state->rdata = outbuf.data;
7239 state->num_rdata = outbuf.length;
7240 tevent_req_done(req);
7243 static void cli_qfileinfo_done(struct tevent_req *subreq)
7245 struct tevent_req *req = tevent_req_callback_data(
7246 subreq, struct tevent_req);
7247 struct cli_qfileinfo_state *state = tevent_req_data(
7248 req, struct cli_qfileinfo_state);
7249 NTSTATUS status;
7251 status = cli_trans_recv(subreq, state,
7252 &state->recv_flags2,
7253 NULL, 0, NULL,
7254 NULL, 0, NULL,
7255 &state->rdata, state->min_rdata,
7256 &state->num_rdata);
7257 if (tevent_req_nterror(req, status)) {
7258 return;
7260 tevent_req_done(req);
7263 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
7264 uint16_t *recv_flags2,
7265 uint8_t **rdata, uint32_t *num_rdata)
7267 struct cli_qfileinfo_state *state = tevent_req_data(
7268 req, struct cli_qfileinfo_state);
7269 NTSTATUS status;
7271 if (tevent_req_is_nterror(req, &status)) {
7272 return status;
7275 if (recv_flags2 != NULL) {
7276 *recv_flags2 = state->recv_flags2;
7278 if (rdata != NULL) {
7279 *rdata = talloc_move(mem_ctx, &state->rdata);
7281 if (num_rdata != NULL) {
7282 *num_rdata = state->num_rdata;
7285 tevent_req_received(req);
7286 return NT_STATUS_OK;
7289 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx,
7290 struct cli_state *cli,
7291 uint16_t fnum,
7292 uint16_t fscc_level,
7293 uint32_t min_rdata,
7294 uint32_t max_rdata,
7295 uint16_t *recv_flags2,
7296 uint8_t **rdata,
7297 uint32_t *num_rdata)
7299 TALLOC_CTX *frame = talloc_stackframe();
7300 struct tevent_context *ev;
7301 struct tevent_req *req;
7302 NTSTATUS status = NT_STATUS_NO_MEMORY;
7304 if (smbXcli_conn_has_async_calls(cli->conn)) {
7306 * Can't use sync call while an async call is in flight
7308 status = NT_STATUS_INVALID_PARAMETER;
7309 goto fail;
7311 ev = samba_tevent_context_init(frame);
7312 if (ev == NULL) {
7313 goto fail;
7315 req = cli_qfileinfo_send(
7316 frame, ev, cli, fnum, fscc_level, min_rdata, max_rdata);
7317 if (req == NULL) {
7318 goto fail;
7320 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7321 goto fail;
7323 status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
7324 fail:
7325 TALLOC_FREE(frame);
7326 return status;
7329 struct cli_flush_state {
7330 uint16_t vwv[1];
7333 static void cli_flush_done(struct tevent_req *subreq);
7335 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
7336 struct tevent_context *ev,
7337 struct cli_state *cli,
7338 uint16_t fnum)
7340 struct tevent_req *req, *subreq;
7341 struct cli_flush_state *state;
7343 req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
7344 if (req == NULL) {
7345 return NULL;
7347 SSVAL(state->vwv + 0, 0, fnum);
7349 subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
7350 0, NULL);
7351 if (tevent_req_nomem(subreq, req)) {
7352 return tevent_req_post(req, ev);
7354 tevent_req_set_callback(subreq, cli_flush_done, req);
7355 return req;
7358 static void cli_flush_done(struct tevent_req *subreq)
7360 struct tevent_req *req = tevent_req_callback_data(
7361 subreq, struct tevent_req);
7362 NTSTATUS status;
7364 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
7365 TALLOC_FREE(subreq);
7366 if (tevent_req_nterror(req, status)) {
7367 return;
7369 tevent_req_done(req);
7372 NTSTATUS cli_flush_recv(struct tevent_req *req)
7374 return tevent_req_simple_recv_ntstatus(req);
7377 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
7379 TALLOC_CTX *frame = talloc_stackframe();
7380 struct tevent_context *ev;
7381 struct tevent_req *req;
7382 NTSTATUS status = NT_STATUS_NO_MEMORY;
7384 if (smbXcli_conn_has_async_calls(cli->conn)) {
7386 * Can't use sync call while an async call is in flight
7388 status = NT_STATUS_INVALID_PARAMETER;
7389 goto fail;
7391 ev = samba_tevent_context_init(frame);
7392 if (ev == NULL) {
7393 goto fail;
7395 req = cli_flush_send(frame, ev, cli, fnum);
7396 if (req == NULL) {
7397 goto fail;
7399 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7400 goto fail;
7402 status = cli_flush_recv(req);
7403 fail:
7404 TALLOC_FREE(frame);
7405 return status;
7408 struct cli_shadow_copy_data_state {
7409 uint16_t setup[4];
7410 uint8_t *data;
7411 uint32_t num_data;
7412 bool get_names;
7415 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
7417 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
7418 struct tevent_context *ev,
7419 struct cli_state *cli,
7420 uint16_t fnum,
7421 bool get_names)
7423 struct tevent_req *req, *subreq;
7424 struct cli_shadow_copy_data_state *state;
7425 uint32_t ret_size;
7427 req = tevent_req_create(mem_ctx, &state,
7428 struct cli_shadow_copy_data_state);
7429 if (req == NULL) {
7430 return NULL;
7432 state->get_names = get_names;
7433 ret_size = get_names ? CLI_BUFFER_SIZE : 16;
7435 SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
7436 SSVAL(state->setup + 2, 0, fnum);
7437 SCVAL(state->setup + 3, 0, 1); /* isFsctl */
7438 SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
7440 subreq = cli_trans_send(
7441 state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
7442 state->setup, ARRAY_SIZE(state->setup),
7443 ARRAY_SIZE(state->setup),
7444 NULL, 0, 0,
7445 NULL, 0, ret_size);
7446 if (tevent_req_nomem(subreq, req)) {
7447 return tevent_req_post(req, ev);
7449 tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
7450 return req;
7453 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
7455 struct tevent_req *req = tevent_req_callback_data(
7456 subreq, struct tevent_req);
7457 struct cli_shadow_copy_data_state *state = tevent_req_data(
7458 req, struct cli_shadow_copy_data_state);
7459 NTSTATUS status;
7461 status = cli_trans_recv(subreq, state, NULL,
7462 NULL, 0, NULL, /* setup */
7463 NULL, 0, NULL, /* param */
7464 &state->data, 12, &state->num_data);
7465 TALLOC_FREE(subreq);
7466 if (tevent_req_nterror(req, status)) {
7467 return;
7469 tevent_req_done(req);
7472 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
7473 char ***pnames, int *pnum_names)
7475 struct cli_shadow_copy_data_state *state = tevent_req_data(
7476 req, struct cli_shadow_copy_data_state);
7477 char **names = NULL;
7478 uint32_t i, num_names;
7479 uint32_t dlength;
7480 uint8_t *endp = NULL;
7481 NTSTATUS status;
7483 if (tevent_req_is_nterror(req, &status)) {
7484 return status;
7487 if (state->num_data < 16) {
7488 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7491 num_names = IVAL(state->data, 4);
7492 dlength = IVAL(state->data, 8);
7494 if (num_names > 0x7FFFFFFF) {
7495 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7498 if (!state->get_names) {
7499 *pnum_names = (int)num_names;
7500 return NT_STATUS_OK;
7503 if (dlength + 12 < 12) {
7504 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7506 if (dlength + 12 > state->num_data) {
7507 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7509 if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
7510 state->num_data) {
7511 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7514 names = talloc_array(mem_ctx, char *, num_names);
7515 if (names == NULL) {
7516 return NT_STATUS_NO_MEMORY;
7519 endp = state->data + state->num_data;
7521 for (i=0; i<num_names; i++) {
7522 bool ret;
7523 uint8_t *src;
7524 size_t converted_size;
7526 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
7528 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
7529 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7532 ret = convert_string_talloc(
7533 names, CH_UTF16LE, CH_UNIX,
7534 src, 2 * sizeof(SHADOW_COPY_LABEL),
7535 &names[i], &converted_size);
7536 if (!ret) {
7537 TALLOC_FREE(names);
7538 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7541 *pnum_names = (int)num_names;
7542 *pnames = names;
7543 return NT_STATUS_OK;
7546 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
7547 uint16_t fnum, bool get_names,
7548 char ***pnames, int *pnum_names)
7550 TALLOC_CTX *frame = NULL;
7551 struct tevent_context *ev;
7552 struct tevent_req *req;
7553 NTSTATUS status = NT_STATUS_NO_MEMORY;
7555 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
7556 return cli_smb2_shadow_copy_data(mem_ctx,
7557 cli,
7558 fnum,
7559 get_names,
7560 pnames,
7561 pnum_names);
7564 frame = talloc_stackframe();
7566 if (smbXcli_conn_has_async_calls(cli->conn)) {
7568 * Can't use sync call while an async call is in flight
7570 status = NT_STATUS_INVALID_PARAMETER;
7571 goto fail;
7573 ev = samba_tevent_context_init(frame);
7574 if (ev == NULL) {
7575 goto fail;
7577 req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
7578 if (req == NULL) {
7579 goto fail;
7581 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7582 goto fail;
7584 status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
7585 fail:
7586 TALLOC_FREE(frame);
7587 return status;
7590 struct cli_fsctl_state {
7591 DATA_BLOB out;
7594 static void cli_fsctl_smb1_done(struct tevent_req *subreq);
7595 static void cli_fsctl_smb2_done(struct tevent_req *subreq);
7597 struct tevent_req *cli_fsctl_send(
7598 TALLOC_CTX *mem_ctx,
7599 struct tevent_context *ev,
7600 struct cli_state *cli,
7601 uint16_t fnum,
7602 uint32_t ctl_code,
7603 const DATA_BLOB *in,
7604 uint32_t max_out)
7606 struct tevent_req *req = NULL, *subreq = NULL;
7607 struct cli_fsctl_state *state = NULL;
7608 uint16_t *setup = NULL;
7609 uint8_t *data = NULL;
7610 uint32_t num_data = 0;
7612 req = tevent_req_create(mem_ctx, &state, struct cli_fsctl_state);
7613 if (req == NULL) {
7614 return NULL;
7617 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
7618 subreq = cli_smb2_fsctl_send(
7619 state, ev, cli, fnum, ctl_code, in, max_out);
7620 if (tevent_req_nomem(subreq, req)) {
7621 return tevent_req_post(req, ev);
7623 tevent_req_set_callback(subreq, cli_fsctl_smb2_done, req);
7624 return req;
7627 setup = talloc_array(state, uint16_t, 4);
7628 if (tevent_req_nomem(setup, req)) {
7629 return tevent_req_post(req, ev);
7631 SIVAL(setup, 0, ctl_code);
7632 SSVAL(setup, 4, fnum);
7633 SCVAL(setup, 6, 1); /* IsFcntl */
7634 SCVAL(setup, 7, 0); /* IsFlags */
7636 if (in) {
7637 data = in->data;
7638 num_data = in->length;
7641 subreq = cli_trans_send(state,
7643 cli,
7644 0, /* additional_flags2 */
7645 SMBnttrans, /* cmd */
7646 NULL, /* name */
7647 -1, /* fid */
7648 NT_TRANSACT_IOCTL, /* function */
7649 0, /* flags */
7650 setup,
7652 0, /* setup */
7653 NULL,
7655 0, /* param */
7656 data,
7657 num_data,
7658 max_out); /* data */
7660 if (tevent_req_nomem(subreq, req)) {
7661 return tevent_req_post(req, ev);
7663 tevent_req_set_callback(subreq, cli_fsctl_smb1_done, req);
7664 return req;
7667 static void cli_fsctl_smb2_done(struct tevent_req *subreq)
7669 struct tevent_req *req = tevent_req_callback_data(
7670 subreq, struct tevent_req);
7671 struct cli_fsctl_state *state = tevent_req_data(
7672 req, struct cli_fsctl_state);
7673 NTSTATUS status;
7675 status = cli_smb2_fsctl_recv(subreq, state, &state->out);
7676 tevent_req_simple_finish_ntstatus(subreq, status);
7679 static void cli_fsctl_smb1_done(struct tevent_req *subreq)
7681 struct tevent_req *req = tevent_req_callback_data(
7682 subreq, struct tevent_req);
7683 struct cli_fsctl_state *state = tevent_req_data(
7684 req, struct cli_fsctl_state);
7685 uint8_t *out = NULL;
7686 uint32_t out_len;
7687 NTSTATUS status;
7689 status = cli_trans_recv(
7690 subreq, state, NULL,
7691 NULL, 0, NULL, /* rsetup */
7692 NULL, 0, NULL, /* rparam */
7693 &out, 0, &out_len);
7694 TALLOC_FREE(subreq);
7695 if (tevent_req_nterror(req, status)) {
7696 return;
7698 state->out = (DATA_BLOB) {
7699 .data = out, .length = out_len,
7701 tevent_req_done(req);
7704 NTSTATUS cli_fsctl_recv(
7705 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out)
7707 struct cli_fsctl_state *state = tevent_req_data(
7708 req, struct cli_fsctl_state);
7709 NTSTATUS status;
7711 if (tevent_req_is_nterror(req, &status)) {
7712 return status;
7715 if (out != NULL) {
7716 *out = (DATA_BLOB) {
7717 .data = talloc_move(mem_ctx, &state->out.data),
7718 .length = state->out.length,
7722 return NT_STATUS_OK;