ctdb-server: Clean up connection tracking functions
[samba4-gss.git] / source3 / libsmb / clifile.c
blob812050d7e640d0e84dd812e505061f83fb9a88d4
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 if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
2368 return tevent_req_post(req, ev);
2372 SSVAL(state->vwv+0, 0, mayhave_attrs);
2374 bytes = talloc_array(state, uint8_t, 1);
2375 if (tevent_req_nomem(bytes, req)) {
2376 return tevent_req_post(req, ev);
2379 * SMBunlink on a DFS share must use DFS names.
2381 fname_cp = smb1_dfs_share_path(state, cli, fname);
2382 if (tevent_req_nomem(fname_cp, req)) {
2383 return tevent_req_post(req, ev);
2385 bytes[0] = 4;
2386 bytes = smb_bytes_push_str(bytes,
2387 smbXcli_conn_use_unicode(cli->conn),
2388 fname_cp,
2389 strlen(fname_cp)+1,
2390 NULL);
2392 if (tevent_req_nomem(bytes, req)) {
2393 return tevent_req_post(req, ev);
2396 if (clistr_is_previous_version_path(fname)) {
2397 additional_flags2 = FLAGS2_REPARSE_PATH;
2400 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
2401 additional_flags2,
2402 1, state->vwv, talloc_get_size(bytes), bytes);
2403 if (tevent_req_nomem(subreq, req)) {
2404 return tevent_req_post(req, ev);
2406 tevent_req_set_callback(subreq, cli_unlink_done, req);
2407 return req;
2410 static void cli_unlink_done(struct tevent_req *subreq)
2412 NTSTATUS status = cli_smb_recv(
2413 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2414 tevent_req_simple_finish_ntstatus(subreq, status);
2417 static void cli_unlink_done2(struct tevent_req *subreq)
2419 NTSTATUS status = cli_smb2_unlink_recv(subreq);
2420 tevent_req_simple_finish_ntstatus(subreq, status);
2423 NTSTATUS cli_unlink_recv(struct tevent_req *req)
2425 return tevent_req_simple_recv_ntstatus(req);
2428 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint32_t mayhave_attrs)
2430 TALLOC_CTX *frame = NULL;
2431 struct tevent_context *ev;
2432 struct tevent_req *req;
2433 NTSTATUS status = NT_STATUS_OK;
2435 frame = talloc_stackframe();
2437 if (smbXcli_conn_has_async_calls(cli->conn)) {
2439 * Can't use sync call while an async call is in flight
2441 status = NT_STATUS_INVALID_PARAMETER;
2442 goto fail;
2445 ev = samba_tevent_context_init(frame);
2446 if (ev == NULL) {
2447 status = NT_STATUS_NO_MEMORY;
2448 goto fail;
2451 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
2452 if (req == NULL) {
2453 status = NT_STATUS_NO_MEMORY;
2454 goto fail;
2457 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2458 goto fail;
2461 status = cli_unlink_recv(req);
2462 fail:
2463 TALLOC_FREE(frame);
2464 return status;
2467 /****************************************************************************
2468 Create a directory.
2469 ****************************************************************************/
2471 static void cli_mkdir_done(struct tevent_req *subreq);
2472 static void cli_mkdir_done2(struct tevent_req *subreq);
2474 struct cli_mkdir_state {
2475 int dummy;
2478 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
2479 struct tevent_context *ev,
2480 struct cli_state *cli,
2481 const char *dname)
2483 struct tevent_req *req = NULL, *subreq = NULL;
2484 struct cli_mkdir_state *state = NULL;
2485 uint8_t additional_flags = 0;
2486 uint16_t additional_flags2 = 0;
2487 uint8_t *bytes = NULL;
2488 char *dname_cp = NULL;
2490 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
2491 if (req == NULL) {
2492 return NULL;
2495 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2496 subreq = cli_smb2_mkdir_send(state, ev, cli, dname);
2497 if (tevent_req_nomem(subreq, req)) {
2498 return tevent_req_post(req, ev);
2500 tevent_req_set_callback(subreq, cli_mkdir_done2, req);
2501 return req;
2504 bytes = talloc_array(state, uint8_t, 1);
2505 if (tevent_req_nomem(bytes, req)) {
2506 return tevent_req_post(req, ev);
2509 * SMBmkdir on a DFS share must use DFS names.
2511 dname_cp = smb1_dfs_share_path(state, cli, dname);
2512 if (tevent_req_nomem(dname_cp, req)) {
2513 return tevent_req_post(req, ev);
2515 bytes[0] = 4;
2516 bytes = smb_bytes_push_str(bytes,
2517 smbXcli_conn_use_unicode(cli->conn),
2518 dname_cp,
2519 strlen(dname_cp)+1,
2520 NULL);
2522 if (tevent_req_nomem(bytes, req)) {
2523 return tevent_req_post(req, ev);
2526 if (clistr_is_previous_version_path(dname)) {
2527 additional_flags2 = FLAGS2_REPARSE_PATH;
2530 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
2531 additional_flags2,
2532 0, NULL, talloc_get_size(bytes), bytes);
2533 if (tevent_req_nomem(subreq, req)) {
2534 return tevent_req_post(req, ev);
2536 tevent_req_set_callback(subreq, cli_mkdir_done, req);
2537 return req;
2540 static void cli_mkdir_done(struct tevent_req *subreq)
2542 struct tevent_req *req = tevent_req_callback_data(
2543 subreq, struct tevent_req);
2544 NTSTATUS status;
2546 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2547 TALLOC_FREE(subreq);
2548 if (tevent_req_nterror(req, status)) {
2549 return;
2551 tevent_req_done(req);
2554 static void cli_mkdir_done2(struct tevent_req *subreq)
2556 NTSTATUS status = cli_smb2_mkdir_recv(subreq);
2557 tevent_req_simple_finish_ntstatus(subreq, status);
2560 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
2562 return tevent_req_simple_recv_ntstatus(req);
2565 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
2567 TALLOC_CTX *frame = NULL;
2568 struct tevent_context *ev;
2569 struct tevent_req *req;
2570 NTSTATUS status = NT_STATUS_OK;
2572 frame = talloc_stackframe();
2574 if (smbXcli_conn_has_async_calls(cli->conn)) {
2576 * Can't use sync call while an async call is in flight
2578 status = NT_STATUS_INVALID_PARAMETER;
2579 goto fail;
2582 ev = samba_tevent_context_init(frame);
2583 if (ev == NULL) {
2584 status = NT_STATUS_NO_MEMORY;
2585 goto fail;
2588 req = cli_mkdir_send(frame, ev, cli, dname);
2589 if (req == NULL) {
2590 status = NT_STATUS_NO_MEMORY;
2591 goto fail;
2594 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2595 goto fail;
2598 status = cli_mkdir_recv(req);
2599 fail:
2600 TALLOC_FREE(frame);
2601 return status;
2604 /****************************************************************************
2605 Remove a directory.
2606 ****************************************************************************/
2608 static void cli_rmdir_done(struct tevent_req *subreq);
2609 static void cli_rmdir_done2(struct tevent_req *subreq);
2611 struct cli_rmdir_state {
2612 int dummy;
2615 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
2616 struct tevent_context *ev,
2617 struct cli_state *cli,
2618 const char *dname)
2620 struct tevent_req *req = NULL, *subreq = NULL;
2621 struct cli_rmdir_state *state = NULL;
2622 uint8_t additional_flags = 0;
2623 uint16_t additional_flags2 = 0;
2624 uint8_t *bytes = NULL;
2625 char *dname_cp = NULL;
2627 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
2628 if (req == NULL) {
2629 return NULL;
2632 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2633 subreq = cli_smb2_rmdir_send(state, ev, cli, dname, NULL);
2634 if (tevent_req_nomem(subreq, req)) {
2635 return tevent_req_post(req, ev);
2637 tevent_req_set_callback(subreq, cli_rmdir_done2, req);
2638 return req;
2641 bytes = talloc_array(state, uint8_t, 1);
2642 if (tevent_req_nomem(bytes, req)) {
2643 return tevent_req_post(req, ev);
2646 * SMBrmdir on a DFS share must use DFS names.
2648 dname_cp = smb1_dfs_share_path(state, cli, dname);
2649 if (tevent_req_nomem(dname_cp, req)) {
2650 return tevent_req_post(req, ev);
2652 bytes[0] = 4;
2653 bytes = smb_bytes_push_str(bytes,
2654 smbXcli_conn_use_unicode(cli->conn),
2655 dname_cp,
2656 strlen(dname_cp)+1,
2657 NULL);
2659 if (tevent_req_nomem(bytes, req)) {
2660 return tevent_req_post(req, ev);
2663 if (clistr_is_previous_version_path(dname)) {
2664 additional_flags2 = FLAGS2_REPARSE_PATH;
2667 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
2668 additional_flags2,
2669 0, NULL, talloc_get_size(bytes), bytes);
2670 if (tevent_req_nomem(subreq, req)) {
2671 return tevent_req_post(req, ev);
2673 tevent_req_set_callback(subreq, cli_rmdir_done, req);
2674 return req;
2677 static void cli_rmdir_done(struct tevent_req *subreq)
2679 NTSTATUS status = cli_smb_recv(
2680 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2681 tevent_req_simple_finish_ntstatus(subreq, status);
2684 static void cli_rmdir_done2(struct tevent_req *subreq)
2686 NTSTATUS status = cli_smb2_rmdir_recv(subreq);
2687 tevent_req_simple_finish_ntstatus(subreq, status);
2690 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
2692 return tevent_req_simple_recv_ntstatus(req);
2695 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
2697 TALLOC_CTX *frame = NULL;
2698 struct tevent_context *ev;
2699 struct tevent_req *req;
2700 NTSTATUS status = NT_STATUS_OK;
2702 frame = talloc_stackframe();
2704 if (smbXcli_conn_has_async_calls(cli->conn)) {
2706 * Can't use sync call while an async call is in flight
2708 status = NT_STATUS_INVALID_PARAMETER;
2709 goto fail;
2712 ev = samba_tevent_context_init(frame);
2713 if (ev == NULL) {
2714 status = NT_STATUS_NO_MEMORY;
2715 goto fail;
2718 req = cli_rmdir_send(frame, ev, cli, dname);
2719 if (req == NULL) {
2720 status = NT_STATUS_NO_MEMORY;
2721 goto fail;
2724 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2725 goto fail;
2728 status = cli_rmdir_recv(req);
2729 fail:
2730 TALLOC_FREE(frame);
2731 return status;
2734 /****************************************************************************
2735 Set or clear the delete on close flag.
2736 ****************************************************************************/
2738 struct doc_state {
2739 uint8_t data[1];
2742 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
2743 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
2745 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
2746 struct tevent_context *ev,
2747 struct cli_state *cli,
2748 uint16_t fnum,
2749 bool flag)
2751 struct tevent_req *req = NULL, *subreq = NULL;
2752 struct doc_state *state = NULL;
2754 req = tevent_req_create(mem_ctx, &state, struct doc_state);
2755 if (req == NULL) {
2756 return NULL;
2759 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2760 subreq = cli_smb2_delete_on_close_send(state, ev, cli,
2761 fnum, flag);
2762 if (tevent_req_nomem(subreq, req)) {
2763 return tevent_req_post(req, ev);
2765 tevent_req_set_callback(subreq,
2766 cli_nt_delete_on_close_smb2_done,
2767 req);
2768 return req;
2771 /* Setup data array. */
2772 SCVAL(&state->data[0], 0, flag ? 1 : 0);
2774 subreq = cli_setfileinfo_send(
2775 state,
2777 cli,
2778 fnum,
2779 SMB_SET_FILE_DISPOSITION_INFO,
2780 state->data,
2781 sizeof(state->data));
2783 if (tevent_req_nomem(subreq, req)) {
2784 return tevent_req_post(req, ev);
2786 tevent_req_set_callback(subreq,
2787 cli_nt_delete_on_close_smb1_done,
2788 req);
2789 return req;
2792 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
2794 NTSTATUS status = cli_setfileinfo_recv(subreq);
2795 tevent_req_simple_finish_ntstatus(subreq, status);
2798 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
2800 NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
2801 tevent_req_simple_finish_ntstatus(subreq, status);
2804 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
2806 return tevent_req_simple_recv_ntstatus(req);
2809 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
2811 TALLOC_CTX *frame = talloc_stackframe();
2812 struct tevent_context *ev = NULL;
2813 struct tevent_req *req = NULL;
2814 NTSTATUS status = NT_STATUS_OK;
2816 if (smbXcli_conn_has_async_calls(cli->conn)) {
2818 * Can't use sync call while an async call is in flight
2820 status = NT_STATUS_INVALID_PARAMETER;
2821 goto fail;
2824 ev = samba_tevent_context_init(frame);
2825 if (ev == NULL) {
2826 status = NT_STATUS_NO_MEMORY;
2827 goto fail;
2830 req = cli_nt_delete_on_close_send(frame,
2832 cli,
2833 fnum,
2834 flag);
2835 if (req == NULL) {
2836 status = NT_STATUS_NO_MEMORY;
2837 goto fail;
2840 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2841 goto fail;
2844 status = cli_nt_delete_on_close_recv(req);
2846 fail:
2847 TALLOC_FREE(frame);
2848 return status;
2851 struct cli_ntcreate1_state {
2852 uint16_t vwv[24];
2853 uint16_t fnum;
2854 struct smb_create_returns cr;
2855 struct tevent_req *subreq;
2858 static void cli_ntcreate1_done(struct tevent_req *subreq);
2859 static bool cli_ntcreate1_cancel(struct tevent_req *req);
2861 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
2862 struct tevent_context *ev,
2863 struct cli_state *cli,
2864 const char *fname,
2865 uint32_t CreatFlags,
2866 uint32_t DesiredAccess,
2867 uint32_t FileAttributes,
2868 uint32_t ShareAccess,
2869 uint32_t CreateDisposition,
2870 uint32_t CreateOptions,
2871 uint32_t ImpersonationLevel,
2872 uint8_t SecurityFlags)
2874 struct tevent_req *req, *subreq;
2875 struct cli_ntcreate1_state *state;
2876 uint16_t *vwv;
2877 uint8_t *bytes;
2878 size_t converted_len;
2879 uint16_t additional_flags2 = 0;
2880 char *fname_cp = NULL;
2882 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
2883 if (req == NULL) {
2884 return NULL;
2887 vwv = state->vwv;
2889 SCVAL(vwv+0, 0, 0xFF);
2890 SCVAL(vwv+0, 1, 0);
2891 SSVAL(vwv+1, 0, 0);
2892 SCVAL(vwv+2, 0, 0);
2894 if (cli->use_oplocks) {
2895 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
2897 SIVAL(vwv+3, 1, CreatFlags);
2898 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
2899 SIVAL(vwv+7, 1, DesiredAccess);
2900 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
2901 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
2902 SIVAL(vwv+13, 1, FileAttributes);
2903 SIVAL(vwv+15, 1, ShareAccess);
2904 SIVAL(vwv+17, 1, CreateDisposition);
2905 SIVAL(vwv+19, 1, CreateOptions |
2906 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2907 SIVAL(vwv+21, 1, ImpersonationLevel);
2908 SCVAL(vwv+23, 1, SecurityFlags);
2910 bytes = talloc_array(state, uint8_t, 0);
2911 if (tevent_req_nomem(bytes, req)) {
2912 return tevent_req_post(req, ev);
2915 * SMBntcreateX on a DFS share must use DFS names.
2917 fname_cp = smb1_dfs_share_path(state, cli, fname);
2918 if (tevent_req_nomem(fname_cp, req)) {
2919 return tevent_req_post(req, ev);
2921 bytes = smb_bytes_push_str(bytes,
2922 smbXcli_conn_use_unicode(cli->conn),
2923 fname_cp,
2924 strlen(fname_cp)+1,
2925 &converted_len);
2926 if (tevent_req_nomem(bytes, req)) {
2927 return tevent_req_post(req, ev);
2930 if (clistr_is_previous_version_path(fname)) {
2931 additional_flags2 = FLAGS2_REPARSE_PATH;
2934 /* sigh. this copes with broken netapp filer behaviour */
2935 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2937 if (tevent_req_nomem(bytes, req)) {
2938 return tevent_req_post(req, ev);
2941 SSVAL(vwv+2, 1, converted_len);
2943 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2944 additional_flags2, 24, vwv,
2945 talloc_get_size(bytes), bytes);
2946 if (tevent_req_nomem(subreq, req)) {
2947 return tevent_req_post(req, ev);
2949 tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2951 state->subreq = subreq;
2952 tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2954 return req;
2957 static void cli_ntcreate1_done(struct tevent_req *subreq)
2959 struct tevent_req *req = tevent_req_callback_data(
2960 subreq, struct tevent_req);
2961 struct cli_ntcreate1_state *state = tevent_req_data(
2962 req, struct cli_ntcreate1_state);
2963 uint8_t wct;
2964 uint16_t *vwv;
2965 uint32_t num_bytes;
2966 uint8_t *bytes;
2967 NTSTATUS status;
2969 status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2970 &num_bytes, &bytes);
2971 TALLOC_FREE(subreq);
2972 if (tevent_req_nterror(req, status)) {
2973 return;
2975 state->cr.oplock_level = CVAL(vwv+2, 0);
2976 state->fnum = SVAL(vwv+2, 1);
2977 state->cr.create_action = IVAL(vwv+3, 1);
2978 state->cr.creation_time = BVAL(vwv+5, 1);
2979 state->cr.last_access_time = BVAL(vwv+9, 1);
2980 state->cr.last_write_time = BVAL(vwv+13, 1);
2981 state->cr.change_time = BVAL(vwv+17, 1);
2982 state->cr.file_attributes = IVAL(vwv+21, 1);
2983 state->cr.allocation_size = BVAL(vwv+23, 1);
2984 state->cr.end_of_file = BVAL(vwv+27, 1);
2986 tevent_req_done(req);
2989 static bool cli_ntcreate1_cancel(struct tevent_req *req)
2991 struct cli_ntcreate1_state *state = tevent_req_data(
2992 req, struct cli_ntcreate1_state);
2993 return tevent_req_cancel(state->subreq);
2996 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2997 uint16_t *pfnum,
2998 struct smb_create_returns *cr)
3000 struct cli_ntcreate1_state *state = tevent_req_data(
3001 req, struct cli_ntcreate1_state);
3002 NTSTATUS status;
3004 if (tevent_req_is_nterror(req, &status)) {
3005 return status;
3007 *pfnum = state->fnum;
3008 if (cr != NULL) {
3009 *cr = state->cr;
3011 return NT_STATUS_OK;
3014 struct cli_ntcreate_state {
3015 struct smb_create_returns cr;
3016 uint16_t fnum;
3017 struct tevent_req *subreq;
3020 static void cli_ntcreate_done_nt1(struct tevent_req *subreq);
3021 static void cli_ntcreate_done_smb2(struct tevent_req *subreq);
3022 static bool cli_ntcreate_cancel(struct tevent_req *req);
3024 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
3025 struct tevent_context *ev,
3026 struct cli_state *cli,
3027 const char *fname,
3028 uint32_t create_flags,
3029 uint32_t desired_access,
3030 uint32_t file_attributes,
3031 uint32_t share_access,
3032 uint32_t create_disposition,
3033 uint32_t create_options,
3034 uint32_t impersonation_level,
3035 uint8_t security_flags)
3037 struct tevent_req *req, *subreq;
3038 struct cli_ntcreate_state *state;
3040 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
3041 if (req == NULL) {
3042 return NULL;
3045 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3046 struct cli_smb2_create_flags cflags = {0};
3048 if (cli->use_oplocks) {
3049 create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
3052 cflags = (struct cli_smb2_create_flags) {
3053 .batch_oplock = (create_flags & REQUEST_BATCH_OPLOCK),
3054 .exclusive_oplock = (create_flags & REQUEST_OPLOCK),
3057 subreq = cli_smb2_create_fnum_send(
3058 state,
3060 cli,
3061 fname,
3062 cflags,
3063 impersonation_level,
3064 desired_access,
3065 file_attributes,
3066 share_access,
3067 create_disposition,
3068 create_options,
3069 NULL);
3070 if (tevent_req_nomem(subreq, req)) {
3071 return tevent_req_post(req, ev);
3073 tevent_req_set_callback(subreq, cli_ntcreate_done_smb2, req);
3074 } else {
3075 subreq = cli_ntcreate1_send(
3076 state, ev, cli, fname, create_flags, desired_access,
3077 file_attributes, share_access, create_disposition,
3078 create_options, impersonation_level, security_flags);
3079 if (tevent_req_nomem(subreq, req)) {
3080 return tevent_req_post(req, ev);
3082 tevent_req_set_callback(subreq, cli_ntcreate_done_nt1, req);
3085 state->subreq = subreq;
3086 tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
3088 return req;
3091 static void cli_ntcreate_done_nt1(struct tevent_req *subreq)
3093 struct tevent_req *req = tevent_req_callback_data(
3094 subreq, struct tevent_req);
3095 struct cli_ntcreate_state *state = tevent_req_data(
3096 req, struct cli_ntcreate_state);
3097 NTSTATUS status;
3099 status = cli_ntcreate1_recv(subreq, &state->fnum, &state->cr);
3100 TALLOC_FREE(subreq);
3101 if (tevent_req_nterror(req, status)) {
3102 return;
3104 tevent_req_done(req);
3107 static void cli_ntcreate_done_smb2(struct tevent_req *subreq)
3109 struct tevent_req *req = tevent_req_callback_data(
3110 subreq, struct tevent_req);
3111 struct cli_ntcreate_state *state = tevent_req_data(
3112 req, struct cli_ntcreate_state);
3113 NTSTATUS status;
3115 status = cli_smb2_create_fnum_recv(
3116 subreq,
3117 &state->fnum,
3118 &state->cr,
3119 NULL,
3120 NULL,
3121 NULL);
3122 TALLOC_FREE(subreq);
3123 if (tevent_req_nterror(req, status)) {
3124 return;
3126 tevent_req_done(req);
3129 static bool cli_ntcreate_cancel(struct tevent_req *req)
3131 struct cli_ntcreate_state *state = tevent_req_data(
3132 req, struct cli_ntcreate_state);
3133 return tevent_req_cancel(state->subreq);
3136 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
3137 struct smb_create_returns *cr)
3139 struct cli_ntcreate_state *state = tevent_req_data(
3140 req, struct cli_ntcreate_state);
3141 NTSTATUS status;
3143 if (tevent_req_is_nterror(req, &status)) {
3144 return status;
3146 if (fnum != NULL) {
3147 *fnum = state->fnum;
3149 if (cr != NULL) {
3150 *cr = state->cr;
3152 return NT_STATUS_OK;
3155 NTSTATUS cli_ntcreate(struct cli_state *cli,
3156 const char *fname,
3157 uint32_t CreatFlags,
3158 uint32_t DesiredAccess,
3159 uint32_t FileAttributes,
3160 uint32_t ShareAccess,
3161 uint32_t CreateDisposition,
3162 uint32_t CreateOptions,
3163 uint8_t SecurityFlags,
3164 uint16_t *pfid,
3165 struct smb_create_returns *cr)
3167 TALLOC_CTX *frame = talloc_stackframe();
3168 struct tevent_context *ev;
3169 struct tevent_req *req;
3170 uint32_t ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
3171 NTSTATUS status = NT_STATUS_NO_MEMORY;
3173 if (smbXcli_conn_has_async_calls(cli->conn)) {
3175 * Can't use sync call while an async call is in flight
3177 status = NT_STATUS_INVALID_PARAMETER;
3178 goto fail;
3181 ev = samba_tevent_context_init(frame);
3182 if (ev == NULL) {
3183 goto fail;
3186 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
3187 DesiredAccess, FileAttributes, ShareAccess,
3188 CreateDisposition, CreateOptions,
3189 ImpersonationLevel, SecurityFlags);
3190 if (req == NULL) {
3191 goto fail;
3194 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3195 goto fail;
3198 status = cli_ntcreate_recv(req, pfid, cr);
3199 fail:
3200 TALLOC_FREE(frame);
3201 return status;
3204 struct cli_nttrans_create_state {
3205 uint16_t fnum;
3206 struct smb_create_returns cr;
3209 static void cli_nttrans_create_done(struct tevent_req *subreq);
3211 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
3212 struct tevent_context *ev,
3213 struct cli_state *cli,
3214 const char *fname,
3215 uint32_t CreatFlags,
3216 uint32_t DesiredAccess,
3217 uint32_t FileAttributes,
3218 uint32_t ShareAccess,
3219 uint32_t CreateDisposition,
3220 uint32_t CreateOptions,
3221 uint8_t SecurityFlags,
3222 struct security_descriptor *secdesc,
3223 struct ea_struct *eas,
3224 int num_eas)
3226 struct tevent_req *req, *subreq;
3227 struct cli_nttrans_create_state *state;
3228 uint8_t *param;
3229 uint8_t *secdesc_buf;
3230 size_t secdesc_len;
3231 NTSTATUS status;
3232 size_t converted_len;
3233 uint16_t additional_flags2 = 0;
3234 char *fname_cp = NULL;
3236 req = tevent_req_create(mem_ctx,
3237 &state, struct cli_nttrans_create_state);
3238 if (req == NULL) {
3239 return NULL;
3242 if (secdesc != NULL) {
3243 status = marshall_sec_desc(talloc_tos(), secdesc,
3244 &secdesc_buf, &secdesc_len);
3245 if (tevent_req_nterror(req, status)) {
3246 DEBUG(10, ("marshall_sec_desc failed: %s\n",
3247 nt_errstr(status)));
3248 return tevent_req_post(req, ev);
3250 } else {
3251 secdesc_buf = NULL;
3252 secdesc_len = 0;
3255 if (num_eas != 0) {
3257 * TODO ;-)
3259 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
3260 return tevent_req_post(req, ev);
3263 param = talloc_array(state, uint8_t, 53);
3264 if (tevent_req_nomem(param, req)) {
3265 return tevent_req_post(req, ev);
3269 * SMBntcreateX on a DFS share must use DFS names.
3271 fname_cp = smb1_dfs_share_path(state, cli, fname);
3272 if (tevent_req_nomem(fname_cp, req)) {
3273 return tevent_req_post(req, ev);
3275 param = trans2_bytes_push_str(param,
3276 smbXcli_conn_use_unicode(cli->conn),
3277 fname_cp,
3278 strlen(fname_cp),
3279 &converted_len);
3280 if (tevent_req_nomem(param, req)) {
3281 return tevent_req_post(req, ev);
3284 if (clistr_is_previous_version_path(fname)) {
3285 additional_flags2 = FLAGS2_REPARSE_PATH;
3288 SIVAL(param, 0, CreatFlags);
3289 SIVAL(param, 4, 0x0); /* RootDirectoryFid */
3290 SIVAL(param, 8, DesiredAccess);
3291 SIVAL(param, 12, 0x0); /* AllocationSize */
3292 SIVAL(param, 16, 0x0); /* AllocationSize */
3293 SIVAL(param, 20, FileAttributes);
3294 SIVAL(param, 24, ShareAccess);
3295 SIVAL(param, 28, CreateDisposition);
3296 SIVAL(param, 32, CreateOptions |
3297 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
3298 SIVAL(param, 36, secdesc_len);
3299 SIVAL(param, 40, 0); /* EA length*/
3300 SIVAL(param, 44, converted_len);
3301 SIVAL(param, 48, 0x02); /* ImpersonationLevel */
3302 SCVAL(param, 52, SecurityFlags);
3304 subreq = cli_trans_send(state, ev, cli,
3305 additional_flags2, /* additional_flags2 */
3306 SMBnttrans,
3307 NULL, -1, /* name, fid */
3308 NT_TRANSACT_CREATE, 0,
3309 NULL, 0, 0, /* setup */
3310 param, talloc_get_size(param), 128, /* param */
3311 secdesc_buf, secdesc_len, 0); /* data */
3312 if (tevent_req_nomem(subreq, req)) {
3313 return tevent_req_post(req, ev);
3315 tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
3316 return req;
3319 static void cli_nttrans_create_done(struct tevent_req *subreq)
3321 struct tevent_req *req = tevent_req_callback_data(
3322 subreq, struct tevent_req);
3323 struct cli_nttrans_create_state *state = tevent_req_data(
3324 req, struct cli_nttrans_create_state);
3325 uint8_t *param;
3326 uint32_t num_param;
3327 NTSTATUS status;
3329 status = cli_trans_recv(subreq, talloc_tos(), NULL,
3330 NULL, 0, NULL, /* rsetup */
3331 &param, 69, &num_param,
3332 NULL, 0, NULL);
3333 if (tevent_req_nterror(req, status)) {
3334 return;
3336 state->cr.oplock_level = CVAL(param, 0);
3337 state->fnum = SVAL(param, 2);
3338 state->cr.create_action = IVAL(param, 4);
3339 state->cr.creation_time = BVAL(param, 12);
3340 state->cr.last_access_time = BVAL(param, 20);
3341 state->cr.last_write_time = BVAL(param, 28);
3342 state->cr.change_time = BVAL(param, 36);
3343 state->cr.file_attributes = IVAL(param, 44);
3344 state->cr.allocation_size = BVAL(param, 48);
3345 state->cr.end_of_file = BVAL(param, 56);
3347 TALLOC_FREE(param);
3348 tevent_req_done(req);
3351 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
3352 uint16_t *fnum,
3353 struct smb_create_returns *cr)
3355 struct cli_nttrans_create_state *state = tevent_req_data(
3356 req, struct cli_nttrans_create_state);
3357 NTSTATUS status;
3359 if (tevent_req_is_nterror(req, &status)) {
3360 return status;
3362 *fnum = state->fnum;
3363 if (cr != NULL) {
3364 *cr = state->cr;
3366 return NT_STATUS_OK;
3369 NTSTATUS cli_nttrans_create(struct cli_state *cli,
3370 const char *fname,
3371 uint32_t CreatFlags,
3372 uint32_t DesiredAccess,
3373 uint32_t FileAttributes,
3374 uint32_t ShareAccess,
3375 uint32_t CreateDisposition,
3376 uint32_t CreateOptions,
3377 uint8_t SecurityFlags,
3378 struct security_descriptor *secdesc,
3379 struct ea_struct *eas,
3380 int num_eas,
3381 uint16_t *pfid,
3382 struct smb_create_returns *cr)
3384 TALLOC_CTX *frame = talloc_stackframe();
3385 struct tevent_context *ev;
3386 struct tevent_req *req;
3387 NTSTATUS status = NT_STATUS_NO_MEMORY;
3389 if (smbXcli_conn_has_async_calls(cli->conn)) {
3391 * Can't use sync call while an async call is in flight
3393 status = NT_STATUS_INVALID_PARAMETER;
3394 goto fail;
3396 ev = samba_tevent_context_init(frame);
3397 if (ev == NULL) {
3398 goto fail;
3400 req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
3401 DesiredAccess, FileAttributes,
3402 ShareAccess, CreateDisposition,
3403 CreateOptions, SecurityFlags,
3404 secdesc, eas, num_eas);
3405 if (req == NULL) {
3406 goto fail;
3408 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3409 goto fail;
3411 status = cli_nttrans_create_recv(req, pfid, cr);
3412 fail:
3413 TALLOC_FREE(frame);
3414 return status;
3417 /****************************************************************************
3418 Open a file
3419 WARNING: if you open with O_WRONLY then getattrE won't work!
3420 ****************************************************************************/
3422 struct cli_openx_state {
3423 const char *fname;
3424 uint16_t vwv[15];
3425 uint16_t fnum;
3426 struct iovec bytes;
3429 static void cli_openx_done(struct tevent_req *subreq);
3431 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
3432 struct tevent_context *ev,
3433 struct cli_state *cli, const char *fname,
3434 int flags, int share_mode,
3435 struct tevent_req **psmbreq)
3437 struct tevent_req *req, *subreq;
3438 struct cli_openx_state *state;
3439 unsigned openfn;
3440 unsigned accessmode;
3441 uint8_t additional_flags;
3442 uint16_t additional_flags2 = 0;
3443 uint8_t *bytes;
3444 char *fname_cp = NULL;
3446 req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
3447 if (req == NULL) {
3448 return NULL;
3451 openfn = 0;
3452 if (flags & O_CREAT) {
3453 openfn |= (1<<4);
3455 if (!(flags & O_EXCL)) {
3456 if (flags & O_TRUNC)
3457 openfn |= (1<<1);
3458 else
3459 openfn |= (1<<0);
3462 accessmode = (share_mode<<4);
3464 if ((flags & O_ACCMODE) == O_RDWR) {
3465 accessmode |= 2;
3466 } else if ((flags & O_ACCMODE) == O_WRONLY) {
3467 accessmode |= 1;
3470 #if defined(O_SYNC)
3471 if ((flags & O_SYNC) == O_SYNC) {
3472 accessmode |= (1<<14);
3474 #endif /* O_SYNC */
3476 if (share_mode == DENY_FCB) {
3477 accessmode = 0xFF;
3480 SCVAL(state->vwv + 0, 0, 0xFF);
3481 SCVAL(state->vwv + 0, 1, 0);
3482 SSVAL(state->vwv + 1, 0, 0);
3483 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
3484 SSVAL(state->vwv + 3, 0, accessmode);
3485 SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
3486 SSVAL(state->vwv + 5, 0, 0);
3487 SIVAL(state->vwv + 6, 0, 0);
3488 SSVAL(state->vwv + 8, 0, openfn);
3489 SIVAL(state->vwv + 9, 0, 0);
3490 SIVAL(state->vwv + 11, 0, 0);
3491 SIVAL(state->vwv + 13, 0, 0);
3493 additional_flags = 0;
3495 if (cli->use_oplocks) {
3496 /* if using oplocks then ask for a batch oplock via
3497 core and extended methods */
3498 additional_flags =
3499 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
3500 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
3503 bytes = talloc_array(state, uint8_t, 0);
3504 if (tevent_req_nomem(bytes, req)) {
3505 return tevent_req_post(req, ev);
3508 * SMBopenX on a DFS share must use DFS names.
3510 fname_cp = smb1_dfs_share_path(state, cli, fname);
3511 if (tevent_req_nomem(fname_cp, req)) {
3512 return tevent_req_post(req, ev);
3514 bytes = smb_bytes_push_str(bytes,
3515 smbXcli_conn_use_unicode(cli->conn),
3516 fname_cp,
3517 strlen(fname_cp)+1,
3518 NULL);
3520 if (tevent_req_nomem(bytes, req)) {
3521 return tevent_req_post(req, ev);
3524 if (clistr_is_previous_version_path(fname)) {
3525 additional_flags2 = FLAGS2_REPARSE_PATH;
3528 state->bytes.iov_base = (void *)bytes;
3529 state->bytes.iov_len = talloc_get_size(bytes);
3531 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
3532 additional_flags2, 15, state->vwv, 1, &state->bytes);
3533 if (subreq == NULL) {
3534 TALLOC_FREE(req);
3535 return NULL;
3537 tevent_req_set_callback(subreq, cli_openx_done, req);
3538 *psmbreq = subreq;
3539 return req;
3542 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
3543 struct cli_state *cli, const char *fname,
3544 int flags, int share_mode)
3546 struct tevent_req *req, *subreq;
3547 NTSTATUS status;
3549 req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
3550 &subreq);
3551 if (req == NULL) {
3552 return NULL;
3555 status = smb1cli_req_chain_submit(&subreq, 1);
3556 if (tevent_req_nterror(req, status)) {
3557 return tevent_req_post(req, ev);
3559 return req;
3562 static void cli_openx_done(struct tevent_req *subreq)
3564 struct tevent_req *req = tevent_req_callback_data(
3565 subreq, struct tevent_req);
3566 struct cli_openx_state *state = tevent_req_data(
3567 req, struct cli_openx_state);
3568 uint8_t wct;
3569 uint16_t *vwv;
3570 NTSTATUS status;
3572 status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
3573 NULL);
3574 TALLOC_FREE(subreq);
3575 if (tevent_req_nterror(req, status)) {
3576 return;
3578 state->fnum = SVAL(vwv+2, 0);
3579 tevent_req_done(req);
3582 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
3584 struct cli_openx_state *state = tevent_req_data(
3585 req, struct cli_openx_state);
3586 NTSTATUS status;
3588 if (tevent_req_is_nterror(req, &status)) {
3589 return status;
3591 *pfnum = state->fnum;
3592 return NT_STATUS_OK;
3595 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
3596 int share_mode, uint16_t *pfnum)
3598 TALLOC_CTX *frame = talloc_stackframe();
3599 struct tevent_context *ev;
3600 struct tevent_req *req;
3601 NTSTATUS status = NT_STATUS_NO_MEMORY;
3603 if (smbXcli_conn_has_async_calls(cli->conn)) {
3605 * Can't use sync call while an async call is in flight
3607 status = NT_STATUS_INVALID_PARAMETER;
3608 goto fail;
3611 ev = samba_tevent_context_init(frame);
3612 if (ev == NULL) {
3613 goto fail;
3616 req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
3617 if (req == NULL) {
3618 goto fail;
3621 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3622 goto fail;
3625 status = cli_openx_recv(req, pfnum);
3626 fail:
3627 TALLOC_FREE(frame);
3628 return status;
3630 /****************************************************************************
3631 Synchronous wrapper function that does an NtCreateX open by preference
3632 and falls back to openX if this fails.
3633 ****************************************************************************/
3635 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
3636 int share_mode_in, uint16_t *pfnum)
3638 NTSTATUS status;
3639 unsigned int openfn = 0;
3640 unsigned int dos_deny = 0;
3641 uint32_t access_mask, share_mode, create_disposition, create_options;
3642 struct smb_create_returns cr = {0};
3644 /* Do the initial mapping into OpenX parameters. */
3645 if (flags & O_CREAT) {
3646 openfn |= (1<<4);
3648 if (!(flags & O_EXCL)) {
3649 if (flags & O_TRUNC)
3650 openfn |= (1<<1);
3651 else
3652 openfn |= (1<<0);
3655 dos_deny = (share_mode_in<<4);
3657 if ((flags & O_ACCMODE) == O_RDWR) {
3658 dos_deny |= 2;
3659 } else if ((flags & O_ACCMODE) == O_WRONLY) {
3660 dos_deny |= 1;
3663 #if defined(O_SYNC)
3664 if (flags & O_SYNC) {
3665 dos_deny |= (1<<14);
3667 #endif /* O_SYNC */
3669 if (share_mode_in == DENY_FCB) {
3670 dos_deny = 0xFF;
3673 if (!map_open_params_to_ntcreate(fname, dos_deny,
3674 openfn, &access_mask,
3675 &share_mode, &create_disposition,
3676 &create_options, NULL)) {
3677 goto try_openx;
3680 status = cli_ntcreate(cli,
3681 fname,
3683 access_mask,
3685 share_mode,
3686 create_disposition,
3687 create_options,
3689 pfnum,
3690 &cr);
3692 /* Try and cope will all variants of "we don't do this call"
3693 and fall back to openX. */
3695 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
3696 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
3697 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
3698 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
3699 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
3700 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
3701 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
3702 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
3703 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
3704 goto try_openx;
3707 if (NT_STATUS_IS_OK(status) &&
3708 (create_options & FILE_NON_DIRECTORY_FILE) &&
3709 (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
3712 * Some (broken) servers return a valid handle
3713 * for directories even if FILE_NON_DIRECTORY_FILE
3714 * is set. Just close the handle and set the
3715 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
3717 status = cli_close(cli, *pfnum);
3718 if (!NT_STATUS_IS_OK(status)) {
3719 return status;
3721 status = NT_STATUS_FILE_IS_A_DIRECTORY;
3724 return status;
3726 try_openx:
3728 return cli_openx(cli, fname, flags, share_mode_in, pfnum);
3731 /****************************************************************************
3732 Close a file.
3733 ****************************************************************************/
3735 struct cli_smb1_close_state {
3736 uint16_t vwv[3];
3739 static void cli_smb1_close_done(struct tevent_req *subreq);
3741 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
3742 struct tevent_context *ev,
3743 struct cli_state *cli,
3744 uint16_t fnum,
3745 struct tevent_req **psubreq)
3747 struct tevent_req *req, *subreq;
3748 struct cli_smb1_close_state *state;
3750 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
3751 if (req == NULL) {
3752 return NULL;
3755 SSVAL(state->vwv+0, 0, fnum);
3756 SIVALS(state->vwv+1, 0, -1);
3758 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
3759 3, state->vwv, 0, NULL);
3760 if (subreq == NULL) {
3761 TALLOC_FREE(req);
3762 return NULL;
3764 tevent_req_set_callback(subreq, cli_smb1_close_done, req);
3765 *psubreq = subreq;
3766 return req;
3769 static void cli_smb1_close_done(struct tevent_req *subreq)
3771 struct tevent_req *req = tevent_req_callback_data(
3772 subreq, struct tevent_req);
3773 NTSTATUS status;
3775 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3776 TALLOC_FREE(subreq);
3777 if (tevent_req_nterror(req, status)) {
3778 return;
3780 tevent_req_done(req);
3783 struct cli_close_state {
3784 int dummy;
3787 static void cli_close_done(struct tevent_req *subreq);
3789 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
3790 struct tevent_context *ev,
3791 struct cli_state *cli,
3792 uint16_t fnum,
3793 uint16_t flags)
3795 struct tevent_req *req, *subreq;
3796 struct cli_close_state *state;
3797 NTSTATUS status;
3799 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
3800 if (req == NULL) {
3801 return NULL;
3804 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3805 subreq = cli_smb2_close_fnum_send(state, ev, cli, fnum, flags);
3806 if (tevent_req_nomem(subreq, req)) {
3807 return tevent_req_post(req, ev);
3809 } else {
3810 struct tevent_req *ch_req = NULL;
3811 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
3812 if (tevent_req_nomem(subreq, req)) {
3813 return tevent_req_post(req, ev);
3815 status = smb1cli_req_chain_submit(&ch_req, 1);
3816 if (tevent_req_nterror(req, status)) {
3817 return tevent_req_post(req, ev);
3821 tevent_req_set_callback(subreq, cli_close_done, req);
3822 return req;
3825 static void cli_close_done(struct tevent_req *subreq)
3827 struct tevent_req *req = tevent_req_callback_data(
3828 subreq, struct tevent_req);
3829 NTSTATUS status = NT_STATUS_OK;
3830 bool err = tevent_req_is_nterror(subreq, &status);
3832 TALLOC_FREE(subreq);
3833 if (err) {
3834 tevent_req_nterror(req, status);
3835 return;
3837 tevent_req_done(req);
3840 NTSTATUS cli_close_recv(struct tevent_req *req)
3842 return tevent_req_simple_recv_ntstatus(req);
3845 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
3847 TALLOC_CTX *frame = NULL;
3848 struct tevent_context *ev;
3849 struct tevent_req *req;
3850 NTSTATUS status = NT_STATUS_OK;
3852 frame = talloc_stackframe();
3854 if (smbXcli_conn_has_async_calls(cli->conn)) {
3856 * Can't use sync call while an async call is in flight
3858 status = NT_STATUS_INVALID_PARAMETER;
3859 goto fail;
3862 ev = samba_tevent_context_init(frame);
3863 if (ev == NULL) {
3864 status = NT_STATUS_NO_MEMORY;
3865 goto fail;
3868 req = cli_close_send(frame, ev, cli, fnum, 0);
3869 if (req == NULL) {
3870 status = NT_STATUS_NO_MEMORY;
3871 goto fail;
3874 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3875 goto fail;
3878 status = cli_close_recv(req);
3879 fail:
3880 TALLOC_FREE(frame);
3881 return status;
3884 /****************************************************************************
3885 Truncate a file to a specified size
3886 ****************************************************************************/
3888 struct ftrunc_state {
3889 uint8_t data[8];
3892 static void cli_ftruncate_done(struct tevent_req *subreq)
3894 NTSTATUS status = cli_setfileinfo_recv(subreq);
3895 tevent_req_simple_finish_ntstatus(subreq, status);
3898 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
3899 struct tevent_context *ev,
3900 struct cli_state *cli,
3901 uint16_t fnum,
3902 uint64_t size)
3904 struct tevent_req *req = NULL, *subreq = NULL;
3905 struct ftrunc_state *state = NULL;
3907 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
3908 if (req == NULL) {
3909 return NULL;
3912 /* Setup data array. */
3913 SBVAL(state->data, 0, size);
3915 subreq = cli_setfileinfo_send(
3916 state,
3918 cli,
3919 fnum,
3920 SMB_SET_FILE_END_OF_FILE_INFO,
3921 state->data,
3922 sizeof(state->data));
3924 if (tevent_req_nomem(subreq, req)) {
3925 return tevent_req_post(req, ev);
3927 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
3928 return req;
3931 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
3933 return tevent_req_simple_recv_ntstatus(req);
3936 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3938 TALLOC_CTX *frame = NULL;
3939 struct tevent_context *ev = NULL;
3940 struct tevent_req *req = NULL;
3941 NTSTATUS status = NT_STATUS_OK;
3943 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3944 return cli_smb2_ftruncate(cli, fnum, size);
3947 frame = talloc_stackframe();
3949 if (smbXcli_conn_has_async_calls(cli->conn)) {
3951 * Can't use sync call while an async call is in flight
3953 status = NT_STATUS_INVALID_PARAMETER;
3954 goto fail;
3957 ev = samba_tevent_context_init(frame);
3958 if (ev == NULL) {
3959 status = NT_STATUS_NO_MEMORY;
3960 goto fail;
3963 req = cli_ftruncate_send(frame,
3965 cli,
3966 fnum,
3967 size);
3968 if (req == NULL) {
3969 status = NT_STATUS_NO_MEMORY;
3970 goto fail;
3973 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3974 goto fail;
3977 status = cli_ftruncate_recv(req);
3979 fail:
3980 TALLOC_FREE(frame);
3981 return status;
3984 static uint8_t *cli_lockingx_put_locks(
3985 uint8_t *buf,
3986 bool large,
3987 uint16_t num_locks,
3988 const struct smb1_lock_element *locks)
3990 uint16_t i;
3992 for (i=0; i<num_locks; i++) {
3993 const struct smb1_lock_element *e = &locks[i];
3994 if (large) {
3995 SSVAL(buf, 0, e->pid);
3996 SSVAL(buf, 2, 0);
3997 SOFF_T_R(buf, 4, e->offset);
3998 SOFF_T_R(buf, 12, e->length);
3999 buf += 20;
4000 } else {
4001 SSVAL(buf, 0, e->pid);
4002 SIVAL(buf, 2, e->offset);
4003 SIVAL(buf, 6, e->length);
4004 buf += 10;
4007 return buf;
4010 struct cli_lockingx_state {
4011 uint16_t vwv[8];
4012 struct iovec bytes;
4013 struct tevent_req *subreq;
4016 static void cli_lockingx_done(struct tevent_req *subreq);
4017 static bool cli_lockingx_cancel(struct tevent_req *req);
4019 struct tevent_req *cli_lockingx_create(
4020 TALLOC_CTX *mem_ctx,
4021 struct tevent_context *ev,
4022 struct cli_state *cli,
4023 uint16_t fnum,
4024 uint8_t typeoflock,
4025 uint8_t newoplocklevel,
4026 int32_t timeout,
4027 uint16_t num_unlocks,
4028 const struct smb1_lock_element *unlocks,
4029 uint16_t num_locks,
4030 const struct smb1_lock_element *locks,
4031 struct tevent_req **psmbreq)
4033 struct tevent_req *req = NULL, *subreq = NULL;
4034 struct cli_lockingx_state *state = NULL;
4035 uint16_t *vwv;
4036 uint8_t *p;
4037 const bool large = (typeoflock & LOCKING_ANDX_LARGE_FILES);
4038 const size_t element_len = large ? 20 : 10;
4040 /* uint16->size_t, no overflow */
4041 const size_t num_elements = (size_t)num_locks + (size_t)num_unlocks;
4043 /* at most 20*2*65535 = 2621400, no overflow */
4044 const size_t num_bytes = num_elements * element_len;
4046 req = tevent_req_create(mem_ctx, &state, struct cli_lockingx_state);
4047 if (req == NULL) {
4048 return NULL;
4050 vwv = state->vwv;
4052 SCVAL(vwv + 0, 0, 0xFF);
4053 SCVAL(vwv + 0, 1, 0);
4054 SSVAL(vwv + 1, 0, 0);
4055 SSVAL(vwv + 2, 0, fnum);
4056 SCVAL(vwv + 3, 0, typeoflock);
4057 SCVAL(vwv + 3, 1, newoplocklevel);
4058 SIVALS(vwv + 4, 0, timeout);
4059 SSVAL(vwv + 6, 0, num_unlocks);
4060 SSVAL(vwv + 7, 0, num_locks);
4062 state->bytes.iov_len = num_bytes;
4063 state->bytes.iov_base = talloc_array(state, uint8_t, num_bytes);
4064 if (tevent_req_nomem(state->bytes.iov_base, req)) {
4065 return tevent_req_post(req, ev);
4068 p = cli_lockingx_put_locks(
4069 state->bytes.iov_base, large, num_unlocks, unlocks);
4070 cli_lockingx_put_locks(p, large, num_locks, locks);
4072 subreq = cli_smb_req_create(
4073 state, ev, cli, SMBlockingX, 0, 0, 8, vwv, 1, &state->bytes);
4074 if (tevent_req_nomem(subreq, req)) {
4075 return tevent_req_post(req, ev);
4077 tevent_req_set_callback(subreq, cli_lockingx_done, req);
4078 *psmbreq = subreq;
4079 return req;
4082 struct tevent_req *cli_lockingx_send(
4083 TALLOC_CTX *mem_ctx,
4084 struct tevent_context *ev,
4085 struct cli_state *cli,
4086 uint16_t fnum,
4087 uint8_t typeoflock,
4088 uint8_t newoplocklevel,
4089 int32_t timeout,
4090 uint16_t num_unlocks,
4091 const struct smb1_lock_element *unlocks,
4092 uint16_t num_locks,
4093 const struct smb1_lock_element *locks)
4095 struct tevent_req *req = NULL, *subreq = NULL;
4096 struct cli_lockingx_state *state = NULL;
4097 NTSTATUS status;
4099 req = cli_lockingx_create(
4100 mem_ctx,
4102 cli,
4103 fnum,
4104 typeoflock,
4105 newoplocklevel,
4106 timeout,
4107 num_unlocks,
4108 unlocks,
4109 num_locks,
4110 locks,
4111 &subreq);
4112 if (req == NULL) {
4113 return NULL;
4115 state = tevent_req_data(req, struct cli_lockingx_state);
4116 state->subreq = subreq;
4118 status = smb1cli_req_chain_submit(&subreq, 1);
4119 if (tevent_req_nterror(req, status)) {
4120 return tevent_req_post(req, ev);
4122 tevent_req_set_cancel_fn(req, cli_lockingx_cancel);
4123 return req;
4126 static void cli_lockingx_done(struct tevent_req *subreq)
4128 NTSTATUS status = cli_smb_recv(
4129 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4130 tevent_req_simple_finish_ntstatus(subreq, status);
4133 static bool cli_lockingx_cancel(struct tevent_req *req)
4135 struct cli_lockingx_state *state = tevent_req_data(
4136 req, struct cli_lockingx_state);
4137 if (state->subreq == NULL) {
4138 return false;
4140 return tevent_req_cancel(state->subreq);
4143 NTSTATUS cli_lockingx_recv(struct tevent_req *req)
4145 return tevent_req_simple_recv_ntstatus(req);
4148 NTSTATUS cli_lockingx(
4149 struct cli_state *cli,
4150 uint16_t fnum,
4151 uint8_t typeoflock,
4152 uint8_t newoplocklevel,
4153 int32_t timeout,
4154 uint16_t num_unlocks,
4155 const struct smb1_lock_element *unlocks,
4156 uint16_t num_locks,
4157 const struct smb1_lock_element *locks)
4159 TALLOC_CTX *frame = talloc_stackframe();
4160 struct tevent_context *ev = NULL;
4161 struct tevent_req *req = NULL;
4162 NTSTATUS status = NT_STATUS_NO_MEMORY;
4163 unsigned int set_timeout = 0;
4164 unsigned int saved_timeout = 0;
4166 if (smbXcli_conn_has_async_calls(cli->conn)) {
4167 return NT_STATUS_INVALID_PARAMETER;
4169 ev = samba_tevent_context_init(frame);
4170 if (ev == NULL) {
4171 goto fail;
4174 if (timeout != 0) {
4175 if (timeout == -1) {
4176 set_timeout = 0x7FFFFFFF;
4177 } else {
4178 set_timeout = timeout + 2*1000;
4180 saved_timeout = cli_set_timeout(cli, set_timeout);
4183 req = cli_lockingx_send(
4184 frame,
4186 cli,
4187 fnum,
4188 typeoflock,
4189 newoplocklevel,
4190 timeout,
4191 num_unlocks,
4192 unlocks,
4193 num_locks,
4194 locks);
4195 if (req == NULL) {
4196 goto fail;
4198 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4199 goto fail;
4201 status = cli_lockingx_recv(req);
4203 if (saved_timeout != 0) {
4204 cli_set_timeout(cli, saved_timeout);
4206 fail:
4207 TALLOC_FREE(frame);
4208 return status;
4211 /****************************************************************************
4212 send a lock with a specified locktype
4213 this is used for testing LOCKING_ANDX_CANCEL_LOCK
4214 ****************************************************************************/
4216 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
4217 uint32_t offset, uint32_t len,
4218 int timeout, unsigned char locktype)
4220 struct smb1_lock_element lck = {
4221 .pid = cli_getpid(cli),
4222 .offset = offset,
4223 .length = len,
4225 NTSTATUS status;
4227 status = cli_lockingx(
4228 cli, /* cli */
4229 fnum, /* fnum */
4230 locktype, /* typeoflock */
4231 0, /* newoplocklevel */
4232 timeout, /* timeout */
4233 0, /* num_unlocks */
4234 NULL, /* unlocks */
4235 1, /* num_locks */
4236 &lck); /* locks */
4237 return status;
4240 /****************************************************************************
4241 Lock a file.
4242 note that timeout is in units of 2 milliseconds
4243 ****************************************************************************/
4245 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
4246 uint32_t offset, uint32_t len, int timeout,
4247 enum brl_type lock_type)
4249 NTSTATUS status;
4251 status = cli_locktype(cli, fnum, offset, len, timeout,
4252 (lock_type == READ_LOCK? 1 : 0));
4253 return status;
4256 /****************************************************************************
4257 Unlock a file.
4258 ****************************************************************************/
4260 struct cli_unlock_state {
4261 struct smb1_lock_element lck;
4264 static void cli_unlock_done(struct tevent_req *subreq);
4266 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
4267 struct tevent_context *ev,
4268 struct cli_state *cli,
4269 uint16_t fnum,
4270 uint64_t offset,
4271 uint64_t len)
4274 struct tevent_req *req = NULL, *subreq = NULL;
4275 struct cli_unlock_state *state = NULL;
4277 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
4278 if (req == NULL) {
4279 return NULL;
4281 state->lck = (struct smb1_lock_element) {
4282 .pid = cli_getpid(cli),
4283 .offset = offset,
4284 .length = len,
4287 subreq = cli_lockingx_send(
4288 state, /* mem_ctx */
4289 ev, /* tevent_context */
4290 cli, /* cli */
4291 fnum, /* fnum */
4292 0, /* typeoflock */
4293 0, /* newoplocklevel */
4294 0, /* timeout */
4295 1, /* num_unlocks */
4296 &state->lck, /* unlocks */
4297 0, /* num_locks */
4298 NULL); /* locks */
4299 if (tevent_req_nomem(subreq, req)) {
4300 return tevent_req_post(req, ev);
4302 tevent_req_set_callback(subreq, cli_unlock_done, req);
4303 return req;
4306 static void cli_unlock_done(struct tevent_req *subreq)
4308 NTSTATUS status = cli_lockingx_recv(subreq);
4309 tevent_req_simple_finish_ntstatus(subreq, status);
4312 NTSTATUS cli_unlock_recv(struct tevent_req *req)
4314 return tevent_req_simple_recv_ntstatus(req);
4317 NTSTATUS cli_unlock(struct cli_state *cli,
4318 uint16_t fnum,
4319 uint32_t offset,
4320 uint32_t len)
4322 TALLOC_CTX *frame = talloc_stackframe();
4323 struct tevent_context *ev;
4324 struct tevent_req *req;
4325 NTSTATUS status = NT_STATUS_OK;
4327 if (smbXcli_conn_has_async_calls(cli->conn)) {
4329 * Can't use sync call while an async call is in flight
4331 status = NT_STATUS_INVALID_PARAMETER;
4332 goto fail;
4335 ev = samba_tevent_context_init(frame);
4336 if (ev == NULL) {
4337 status = NT_STATUS_NO_MEMORY;
4338 goto fail;
4341 req = cli_unlock_send(frame, ev, cli,
4342 fnum, offset, len);
4343 if (req == NULL) {
4344 status = NT_STATUS_NO_MEMORY;
4345 goto fail;
4348 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4349 goto fail;
4352 status = cli_unlock_recv(req);
4354 fail:
4355 TALLOC_FREE(frame);
4356 return status;
4359 /****************************************************************************
4360 Get/unlock a POSIX lock on a file - internal function.
4361 ****************************************************************************/
4363 struct posix_lock_state {
4364 uint16_t setup;
4365 uint8_t param[4];
4366 uint8_t data[POSIX_LOCK_DATA_SIZE];
4369 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
4371 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
4372 NULL, 0, NULL, NULL, 0, NULL);
4373 tevent_req_simple_finish_ntstatus(subreq, status);
4376 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
4377 struct tevent_context *ev,
4378 struct cli_state *cli,
4379 uint16_t fnum,
4380 uint64_t offset,
4381 uint64_t len,
4382 bool wait_lock,
4383 enum brl_type lock_type)
4385 struct tevent_req *req = NULL, *subreq = NULL;
4386 struct posix_lock_state *state = NULL;
4388 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
4389 if (req == NULL) {
4390 return NULL;
4393 /* Setup setup word. */
4394 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
4396 /* Setup param array. */
4397 SSVAL(&state->param, 0, fnum);
4398 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
4400 /* Setup data array. */
4401 switch (lock_type) {
4402 case READ_LOCK:
4403 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4404 POSIX_LOCK_TYPE_READ);
4405 break;
4406 case WRITE_LOCK:
4407 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4408 POSIX_LOCK_TYPE_WRITE);
4409 break;
4410 case UNLOCK_LOCK:
4411 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4412 POSIX_LOCK_TYPE_UNLOCK);
4413 break;
4414 default:
4415 return NULL;
4418 if (wait_lock) {
4419 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
4420 POSIX_LOCK_FLAG_WAIT);
4421 } else {
4422 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
4423 POSIX_LOCK_FLAG_NOWAIT);
4426 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
4427 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
4428 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
4430 subreq = cli_trans_send(state, /* mem ctx. */
4431 ev, /* event ctx. */
4432 cli, /* cli_state. */
4433 0, /* additional_flags2 */
4434 SMBtrans2, /* cmd. */
4435 NULL, /* pipe name. */
4436 -1, /* fid. */
4437 0, /* function. */
4438 0, /* flags. */
4439 &state->setup, /* setup. */
4440 1, /* num setup uint16_t words. */
4441 0, /* max returned setup. */
4442 state->param, /* param. */
4443 4, /* num param. */
4444 2, /* max returned param. */
4445 state->data, /* data. */
4446 POSIX_LOCK_DATA_SIZE, /* num data. */
4447 0); /* max returned data. */
4449 if (tevent_req_nomem(subreq, req)) {
4450 return tevent_req_post(req, ev);
4452 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
4453 return req;
4456 /****************************************************************************
4457 POSIX Lock a file.
4458 ****************************************************************************/
4460 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
4461 struct tevent_context *ev,
4462 struct cli_state *cli,
4463 uint16_t fnum,
4464 uint64_t offset,
4465 uint64_t len,
4466 bool wait_lock,
4467 enum brl_type lock_type)
4469 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4470 wait_lock, lock_type);
4473 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
4475 return tevent_req_simple_recv_ntstatus(req);
4478 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
4479 uint64_t offset, uint64_t len,
4480 bool wait_lock, enum brl_type lock_type)
4482 TALLOC_CTX *frame = talloc_stackframe();
4483 struct tevent_context *ev = NULL;
4484 struct tevent_req *req = NULL;
4485 NTSTATUS status = NT_STATUS_OK;
4487 if (smbXcli_conn_has_async_calls(cli->conn)) {
4489 * Can't use sync call while an async call is in flight
4491 status = NT_STATUS_INVALID_PARAMETER;
4492 goto fail;
4495 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
4496 status = NT_STATUS_INVALID_PARAMETER;
4497 goto fail;
4500 ev = samba_tevent_context_init(frame);
4501 if (ev == NULL) {
4502 status = NT_STATUS_NO_MEMORY;
4503 goto fail;
4506 req = cli_posix_lock_send(frame,
4508 cli,
4509 fnum,
4510 offset,
4511 len,
4512 wait_lock,
4513 lock_type);
4514 if (req == NULL) {
4515 status = NT_STATUS_NO_MEMORY;
4516 goto fail;
4519 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4520 goto fail;
4523 status = cli_posix_lock_recv(req);
4525 fail:
4526 TALLOC_FREE(frame);
4527 return status;
4530 /****************************************************************************
4531 POSIX Unlock a file.
4532 ****************************************************************************/
4534 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
4535 struct tevent_context *ev,
4536 struct cli_state *cli,
4537 uint16_t fnum,
4538 uint64_t offset,
4539 uint64_t len)
4541 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4542 false, UNLOCK_LOCK);
4545 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
4547 return tevent_req_simple_recv_ntstatus(req);
4550 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
4552 TALLOC_CTX *frame = talloc_stackframe();
4553 struct tevent_context *ev = NULL;
4554 struct tevent_req *req = NULL;
4555 NTSTATUS status = NT_STATUS_OK;
4557 if (smbXcli_conn_has_async_calls(cli->conn)) {
4559 * Can't use sync call while an async call is in flight
4561 status = NT_STATUS_INVALID_PARAMETER;
4562 goto fail;
4565 ev = samba_tevent_context_init(frame);
4566 if (ev == NULL) {
4567 status = NT_STATUS_NO_MEMORY;
4568 goto fail;
4571 req = cli_posix_unlock_send(frame,
4573 cli,
4574 fnum,
4575 offset,
4576 len);
4577 if (req == NULL) {
4578 status = NT_STATUS_NO_MEMORY;
4579 goto fail;
4582 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4583 goto fail;
4586 status = cli_posix_unlock_recv(req);
4588 fail:
4589 TALLOC_FREE(frame);
4590 return status;
4593 /****************************************************************************
4594 Do a SMBgetattrE call.
4595 ****************************************************************************/
4597 static void cli_getattrE_done(struct tevent_req *subreq);
4599 struct cli_getattrE_state {
4600 uint16_t vwv[1];
4601 int zone_offset;
4602 uint32_t attr;
4603 off_t size;
4604 time_t change_time;
4605 time_t access_time;
4606 time_t write_time;
4609 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
4610 struct tevent_context *ev,
4611 struct cli_state *cli,
4612 uint16_t fnum)
4614 struct tevent_req *req = NULL, *subreq = NULL;
4615 struct cli_getattrE_state *state = NULL;
4616 uint8_t additional_flags = 0;
4618 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
4619 if (req == NULL) {
4620 return NULL;
4623 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4624 SSVAL(state->vwv+0,0,fnum);
4626 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
4627 1, state->vwv, 0, NULL);
4628 if (tevent_req_nomem(subreq, req)) {
4629 return tevent_req_post(req, ev);
4631 tevent_req_set_callback(subreq, cli_getattrE_done, req);
4632 return req;
4635 static void cli_getattrE_done(struct tevent_req *subreq)
4637 struct tevent_req *req = tevent_req_callback_data(
4638 subreq, struct tevent_req);
4639 struct cli_getattrE_state *state = tevent_req_data(
4640 req, struct cli_getattrE_state);
4641 uint8_t wct;
4642 uint16_t *vwv = NULL;
4643 NTSTATUS status;
4645 status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
4646 NULL, NULL);
4647 TALLOC_FREE(subreq);
4648 if (tevent_req_nterror(req, status)) {
4649 return;
4652 state->size = (off_t)IVAL(vwv+6,0);
4653 state->attr = SVAL(vwv+10,0);
4654 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
4655 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
4656 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
4658 tevent_req_done(req);
4661 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
4662 uint32_t *pattr,
4663 off_t *size,
4664 time_t *change_time,
4665 time_t *access_time,
4666 time_t *write_time)
4668 struct cli_getattrE_state *state = tevent_req_data(
4669 req, struct cli_getattrE_state);
4670 NTSTATUS status;
4672 if (tevent_req_is_nterror(req, &status)) {
4673 return status;
4675 if (pattr) {
4676 *pattr = state->attr;
4678 if (size) {
4679 *size = state->size;
4681 if (change_time) {
4682 *change_time = state->change_time;
4684 if (access_time) {
4685 *access_time = state->access_time;
4687 if (write_time) {
4688 *write_time = state->write_time;
4690 return NT_STATUS_OK;
4693 /****************************************************************************
4694 Do a SMBgetatr call
4695 ****************************************************************************/
4697 static void cli_getatr_done(struct tevent_req *subreq);
4699 struct cli_getatr_state {
4700 int zone_offset;
4701 uint32_t attr;
4702 off_t size;
4703 time_t write_time;
4706 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
4707 struct tevent_context *ev,
4708 struct cli_state *cli,
4709 const char *fname)
4711 struct tevent_req *req = NULL, *subreq = NULL;
4712 struct cli_getatr_state *state = NULL;
4713 uint8_t additional_flags = 0;
4714 uint16_t additional_flags2 = 0;
4715 uint8_t *bytes = NULL;
4716 char *fname_cp = NULL;
4718 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
4719 if (req == NULL) {
4720 return NULL;
4723 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4725 bytes = talloc_array(state, uint8_t, 1);
4726 if (tevent_req_nomem(bytes, req)) {
4727 return tevent_req_post(req, ev);
4730 * SMBgetatr on a DFS share must use DFS names.
4732 fname_cp = smb1_dfs_share_path(state, cli, fname);
4733 if (tevent_req_nomem(fname_cp, req)) {
4734 return tevent_req_post(req, ev);
4736 bytes[0] = 4;
4737 bytes = smb_bytes_push_str(bytes,
4738 smbXcli_conn_use_unicode(cli->conn),
4739 fname_cp,
4740 strlen(fname_cp)+1,
4741 NULL);
4743 if (tevent_req_nomem(bytes, req)) {
4744 return tevent_req_post(req, ev);
4747 if (clistr_is_previous_version_path(fname)) {
4748 additional_flags2 = FLAGS2_REPARSE_PATH;
4751 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
4752 additional_flags2,
4753 0, NULL, talloc_get_size(bytes), bytes);
4754 if (tevent_req_nomem(subreq, req)) {
4755 return tevent_req_post(req, ev);
4757 tevent_req_set_callback(subreq, cli_getatr_done, req);
4758 return req;
4761 static void cli_getatr_done(struct tevent_req *subreq)
4763 struct tevent_req *req = tevent_req_callback_data(
4764 subreq, struct tevent_req);
4765 struct cli_getatr_state *state = tevent_req_data(
4766 req, struct cli_getatr_state);
4767 uint8_t wct;
4768 uint16_t *vwv = NULL;
4769 NTSTATUS status;
4771 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4772 NULL);
4773 TALLOC_FREE(subreq);
4774 if (tevent_req_nterror(req, status)) {
4775 return;
4778 state->attr = SVAL(vwv+0,0);
4779 state->size = (off_t)IVAL(vwv+3,0);
4780 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
4782 tevent_req_done(req);
4785 NTSTATUS cli_getatr_recv(struct tevent_req *req,
4786 uint32_t *pattr,
4787 off_t *size,
4788 time_t *write_time)
4790 struct cli_getatr_state *state = tevent_req_data(
4791 req, struct cli_getatr_state);
4792 NTSTATUS status;
4794 if (tevent_req_is_nterror(req, &status)) {
4795 return status;
4797 if (pattr) {
4798 *pattr = state->attr;
4800 if (size) {
4801 *size = state->size;
4803 if (write_time) {
4804 *write_time = state->write_time;
4806 return NT_STATUS_OK;
4809 NTSTATUS cli_getatr(struct cli_state *cli,
4810 const char *fname,
4811 uint32_t *pattr,
4812 off_t *size,
4813 time_t *write_time)
4815 TALLOC_CTX *frame = NULL;
4816 struct tevent_context *ev = NULL;
4817 struct tevent_req *req = NULL;
4818 NTSTATUS status = NT_STATUS_OK;
4820 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4821 struct stat_ex sbuf = {
4822 .st_ex_nlink = 0,
4824 uint32_t attr;
4826 status = cli_smb2_qpathinfo_basic(cli, fname, &sbuf, &attr);
4827 if (!NT_STATUS_IS_OK(status)) {
4828 return status;
4831 if (pattr != NULL) {
4832 *pattr = attr;
4834 if (size != NULL) {
4835 *size = sbuf.st_ex_size;
4837 if (write_time != NULL) {
4838 *write_time = sbuf.st_ex_mtime.tv_sec;
4840 return NT_STATUS_OK;
4843 frame = talloc_stackframe();
4845 if (smbXcli_conn_has_async_calls(cli->conn)) {
4847 * Can't use sync call while an async call is in flight
4849 status = NT_STATUS_INVALID_PARAMETER;
4850 goto fail;
4853 ev = samba_tevent_context_init(frame);
4854 if (ev == NULL) {
4855 status = NT_STATUS_NO_MEMORY;
4856 goto fail;
4859 req = cli_getatr_send(frame, ev, cli, fname);
4860 if (req == NULL) {
4861 status = NT_STATUS_NO_MEMORY;
4862 goto fail;
4865 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4866 goto fail;
4869 status = cli_getatr_recv(req,
4870 pattr,
4871 size,
4872 write_time);
4874 fail:
4875 TALLOC_FREE(frame);
4876 return status;
4879 /****************************************************************************
4880 Do a SMBsetattrE call.
4881 ****************************************************************************/
4883 static void cli_setattrE_done(struct tevent_req *subreq);
4885 struct cli_setattrE_state {
4886 uint16_t vwv[7];
4889 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
4890 struct tevent_context *ev,
4891 struct cli_state *cli,
4892 uint16_t fnum,
4893 time_t change_time,
4894 time_t access_time,
4895 time_t write_time)
4897 struct tevent_req *req = NULL, *subreq = NULL;
4898 struct cli_setattrE_state *state = NULL;
4899 uint8_t additional_flags = 0;
4901 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
4902 if (req == NULL) {
4903 return NULL;
4906 SSVAL(state->vwv+0, 0, fnum);
4907 push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
4908 smb1cli_conn_server_time_zone(cli->conn));
4909 push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
4910 smb1cli_conn_server_time_zone(cli->conn));
4911 push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
4912 smb1cli_conn_server_time_zone(cli->conn));
4914 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
4915 7, state->vwv, 0, NULL);
4916 if (tevent_req_nomem(subreq, req)) {
4917 return tevent_req_post(req, ev);
4919 tevent_req_set_callback(subreq, cli_setattrE_done, req);
4920 return req;
4923 static void cli_setattrE_done(struct tevent_req *subreq)
4925 struct tevent_req *req = tevent_req_callback_data(
4926 subreq, struct tevent_req);
4927 NTSTATUS status;
4929 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4930 TALLOC_FREE(subreq);
4931 if (tevent_req_nterror(req, status)) {
4932 return;
4934 tevent_req_done(req);
4937 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4939 return tevent_req_simple_recv_ntstatus(req);
4942 NTSTATUS cli_setattrE(struct cli_state *cli,
4943 uint16_t fnum,
4944 time_t change_time,
4945 time_t access_time,
4946 time_t write_time)
4948 TALLOC_CTX *frame = NULL;
4949 struct tevent_context *ev = NULL;
4950 struct tevent_req *req = NULL;
4951 NTSTATUS status = NT_STATUS_OK;
4953 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4954 return cli_smb2_setattrE(cli,
4955 fnum,
4956 change_time,
4957 access_time,
4958 write_time);
4961 frame = talloc_stackframe();
4963 if (smbXcli_conn_has_async_calls(cli->conn)) {
4965 * Can't use sync call while an async call is in flight
4967 status = NT_STATUS_INVALID_PARAMETER;
4968 goto fail;
4971 ev = samba_tevent_context_init(frame);
4972 if (ev == NULL) {
4973 status = NT_STATUS_NO_MEMORY;
4974 goto fail;
4977 req = cli_setattrE_send(frame, ev,
4978 cli,
4979 fnum,
4980 change_time,
4981 access_time,
4982 write_time);
4984 if (req == NULL) {
4985 status = NT_STATUS_NO_MEMORY;
4986 goto fail;
4989 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4990 goto fail;
4993 status = cli_setattrE_recv(req);
4995 fail:
4996 TALLOC_FREE(frame);
4997 return status;
5000 /****************************************************************************
5001 Do a SMBsetatr call.
5002 ****************************************************************************/
5004 static void cli_setatr_done(struct tevent_req *subreq);
5006 struct cli_setatr_state {
5007 uint16_t vwv[8];
5010 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
5011 struct tevent_context *ev,
5012 struct cli_state *cli,
5013 const char *fname,
5014 uint32_t attr,
5015 time_t mtime)
5017 struct tevent_req *req = NULL, *subreq = NULL;
5018 struct cli_setatr_state *state = NULL;
5019 uint8_t additional_flags = 0;
5020 uint16_t additional_flags2 = 0;
5021 uint8_t *bytes = NULL;
5022 char *fname_cp = NULL;
5024 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
5025 if (req == NULL) {
5026 return NULL;
5029 if (attr & 0xFFFF0000) {
5031 * Don't allow attributes greater than
5032 * 16-bits for a 16-bit protocol value.
5034 if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
5035 return tevent_req_post(req, ev);
5039 SSVAL(state->vwv+0, 0, attr);
5040 push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
5042 bytes = talloc_array(state, uint8_t, 1);
5043 if (tevent_req_nomem(bytes, req)) {
5044 return tevent_req_post(req, ev);
5047 * SMBsetatr on a DFS share must use DFS names.
5049 fname_cp = smb1_dfs_share_path(state, cli, fname);
5050 if (tevent_req_nomem(fname_cp, req)) {
5051 return tevent_req_post(req, ev);
5053 bytes[0] = 4;
5054 bytes = smb_bytes_push_str(bytes,
5055 smbXcli_conn_use_unicode(cli->conn),
5056 fname_cp,
5057 strlen(fname_cp)+1,
5058 NULL);
5059 if (tevent_req_nomem(bytes, req)) {
5060 return tevent_req_post(req, ev);
5062 bytes = talloc_realloc(state, bytes, uint8_t,
5063 talloc_get_size(bytes)+1);
5064 if (tevent_req_nomem(bytes, req)) {
5065 return tevent_req_post(req, ev);
5068 bytes[talloc_get_size(bytes)-1] = 4;
5069 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
5070 1, NULL);
5071 if (tevent_req_nomem(bytes, req)) {
5072 return tevent_req_post(req, ev);
5075 if (clistr_is_previous_version_path(fname)) {
5076 additional_flags2 = FLAGS2_REPARSE_PATH;
5079 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
5080 additional_flags2,
5081 8, state->vwv, talloc_get_size(bytes), bytes);
5082 if (tevent_req_nomem(subreq, req)) {
5083 return tevent_req_post(req, ev);
5085 tevent_req_set_callback(subreq, cli_setatr_done, req);
5086 return req;
5089 static void cli_setatr_done(struct tevent_req *subreq)
5091 struct tevent_req *req = tevent_req_callback_data(
5092 subreq, struct tevent_req);
5093 NTSTATUS status;
5095 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5096 TALLOC_FREE(subreq);
5097 if (tevent_req_nterror(req, status)) {
5098 return;
5100 tevent_req_done(req);
5103 NTSTATUS cli_setatr_recv(struct tevent_req *req)
5105 return tevent_req_simple_recv_ntstatus(req);
5108 NTSTATUS cli_setatr(struct cli_state *cli,
5109 const char *fname,
5110 uint32_t attr,
5111 time_t mtime)
5113 TALLOC_CTX *frame = NULL;
5114 struct tevent_context *ev = NULL;
5115 struct tevent_req *req = NULL;
5116 NTSTATUS status = NT_STATUS_OK;
5118 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5119 return cli_smb2_setatr(cli,
5120 fname,
5121 attr,
5122 mtime);
5125 frame = talloc_stackframe();
5127 if (smbXcli_conn_has_async_calls(cli->conn)) {
5129 * Can't use sync call while an async call is in flight
5131 status = NT_STATUS_INVALID_PARAMETER;
5132 goto fail;
5135 ev = samba_tevent_context_init(frame);
5136 if (ev == NULL) {
5137 status = NT_STATUS_NO_MEMORY;
5138 goto fail;
5141 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
5142 if (req == NULL) {
5143 status = NT_STATUS_NO_MEMORY;
5144 goto fail;
5147 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5148 goto fail;
5151 status = cli_setatr_recv(req);
5153 fail:
5154 TALLOC_FREE(frame);
5155 return status;
5158 /****************************************************************************
5159 Check for existence of a dir.
5160 ****************************************************************************/
5162 static void cli_chkpath_done(struct tevent_req *subreq);
5163 static void cli_chkpath_opened(struct tevent_req *subreq);
5164 static void cli_chkpath_closed(struct tevent_req *subreq);
5166 struct cli_chkpath_state {
5167 struct tevent_context *ev;
5168 struct cli_state *cli;
5171 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
5172 struct tevent_context *ev,
5173 struct cli_state *cli,
5174 const char *fname)
5176 struct tevent_req *req = NULL, *subreq = NULL;
5177 struct cli_chkpath_state *state = NULL;
5178 uint8_t additional_flags = 0;
5179 uint16_t additional_flags2 = 0;
5180 uint8_t *bytes = NULL;
5181 char *fname_cp = NULL;
5183 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
5184 if (req == NULL) {
5185 return NULL;
5187 state->ev = ev;
5188 state->cli = cli;
5190 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_NT1) {
5191 subreq = cli_ntcreate_send(
5192 state, /* mem_ctx */
5193 state->ev, /* ev */
5194 state->cli, /* cli */
5195 fname, /* fname */
5196 0, /* create_flags */
5197 FILE_READ_ATTRIBUTES, /* desired_access */
5198 FILE_ATTRIBUTE_DIRECTORY, /* FileAttributes */
5199 FILE_SHARE_READ|
5200 FILE_SHARE_WRITE|
5201 FILE_SHARE_DELETE, /* share_access */
5202 FILE_OPEN, /* CreateDisposition */
5203 FILE_DIRECTORY_FILE, /* CreateOptions */
5204 SMB2_IMPERSONATION_IMPERSONATION,
5205 0); /* SecurityFlags */
5206 if (tevent_req_nomem(subreq, req)) {
5207 return tevent_req_post(req, ev);
5209 tevent_req_set_callback(subreq, cli_chkpath_opened, req);
5210 return req;
5213 bytes = talloc_array(state, uint8_t, 1);
5214 if (tevent_req_nomem(bytes, req)) {
5215 return tevent_req_post(req, ev);
5218 * SMBcheckpath on a DFS share must use DFS names.
5220 fname_cp = smb1_dfs_share_path(state, cli, fname);
5221 if (tevent_req_nomem(fname_cp, req)) {
5222 return tevent_req_post(req, ev);
5224 bytes[0] = 4;
5225 bytes = smb_bytes_push_str(bytes,
5226 smbXcli_conn_use_unicode(cli->conn),
5227 fname_cp,
5228 strlen(fname_cp)+1,
5229 NULL);
5231 if (tevent_req_nomem(bytes, req)) {
5232 return tevent_req_post(req, ev);
5235 if (clistr_is_previous_version_path(fname)) {
5236 additional_flags2 = FLAGS2_REPARSE_PATH;
5239 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
5240 additional_flags2,
5241 0, NULL, talloc_get_size(bytes), bytes);
5242 if (tevent_req_nomem(subreq, req)) {
5243 return tevent_req_post(req, ev);
5245 tevent_req_set_callback(subreq, cli_chkpath_done, req);
5246 return req;
5249 static void cli_chkpath_done(struct tevent_req *subreq)
5251 NTSTATUS status = cli_smb_recv(
5252 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5253 tevent_req_simple_finish_ntstatus(subreq, status);
5256 static void cli_chkpath_opened(struct tevent_req *subreq)
5258 struct tevent_req *req = tevent_req_callback_data(
5259 subreq, struct tevent_req);
5260 struct cli_chkpath_state *state = tevent_req_data(
5261 req, struct cli_chkpath_state);
5262 NTSTATUS status;
5263 uint16_t fnum;
5265 status = cli_ntcreate_recv(subreq, &fnum, NULL);
5266 TALLOC_FREE(subreq);
5267 if (tevent_req_nterror(req, status)) {
5268 return;
5271 subreq = cli_close_send(state, state->ev, state->cli, fnum, 0);
5272 if (tevent_req_nomem(subreq, req)) {
5273 return;
5275 tevent_req_set_callback(subreq, cli_chkpath_closed, req);
5278 static void cli_chkpath_closed(struct tevent_req *subreq)
5280 NTSTATUS status = cli_close_recv(subreq);
5281 tevent_req_simple_finish_ntstatus(subreq, status);
5284 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
5286 return tevent_req_simple_recv_ntstatus(req);
5289 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
5291 TALLOC_CTX *frame = NULL;
5292 struct tevent_context *ev = NULL;
5293 struct tevent_req *req = NULL;
5294 char *path2 = NULL;
5295 NTSTATUS status = NT_STATUS_OK;
5297 frame = talloc_stackframe();
5299 if (smbXcli_conn_has_async_calls(cli->conn)) {
5301 * Can't use sync call while an async call is in flight
5303 status = NT_STATUS_INVALID_PARAMETER;
5304 goto fail;
5307 path2 = talloc_strdup(frame, path);
5308 if (!path2) {
5309 status = NT_STATUS_NO_MEMORY;
5310 goto fail;
5312 trim_char(path2,'\0','\\');
5313 if (!*path2) {
5314 path2 = talloc_strdup(frame, "\\");
5315 if (!path2) {
5316 status = NT_STATUS_NO_MEMORY;
5317 goto fail;
5321 ev = samba_tevent_context_init(frame);
5322 if (ev == NULL) {
5323 status = NT_STATUS_NO_MEMORY;
5324 goto fail;
5327 req = cli_chkpath_send(frame, ev, cli, path2);
5328 if (req == NULL) {
5329 status = NT_STATUS_NO_MEMORY;
5330 goto fail;
5333 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5334 goto fail;
5337 status = cli_chkpath_recv(req);
5338 fail:
5339 TALLOC_FREE(frame);
5340 return status;
5343 /****************************************************************************
5344 Query disk space.
5345 ****************************************************************************/
5347 static void cli_dskattr_done(struct tevent_req *subreq);
5349 struct cli_dskattr_state {
5350 int bsize;
5351 int total;
5352 int avail;
5355 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
5356 struct tevent_context *ev,
5357 struct cli_state *cli)
5359 struct tevent_req *req = NULL, *subreq = NULL;
5360 struct cli_dskattr_state *state = NULL;
5361 uint8_t additional_flags = 0;
5363 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
5364 if (req == NULL) {
5365 return NULL;
5368 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
5369 0, NULL, 0, NULL);
5370 if (tevent_req_nomem(subreq, req)) {
5371 return tevent_req_post(req, ev);
5373 tevent_req_set_callback(subreq, cli_dskattr_done, req);
5374 return req;
5377 static void cli_dskattr_done(struct tevent_req *subreq)
5379 struct tevent_req *req = tevent_req_callback_data(
5380 subreq, struct tevent_req);
5381 struct cli_dskattr_state *state = tevent_req_data(
5382 req, struct cli_dskattr_state);
5383 uint8_t wct;
5384 uint16_t *vwv = NULL;
5385 NTSTATUS status;
5387 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
5388 NULL);
5389 TALLOC_FREE(subreq);
5390 if (tevent_req_nterror(req, status)) {
5391 return;
5393 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
5394 state->total = SVAL(vwv+0, 0);
5395 state->avail = SVAL(vwv+3, 0);
5396 tevent_req_done(req);
5399 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
5401 struct cli_dskattr_state *state = tevent_req_data(
5402 req, struct cli_dskattr_state);
5403 NTSTATUS status;
5405 if (tevent_req_is_nterror(req, &status)) {
5406 return status;
5408 *bsize = state->bsize;
5409 *total = state->total;
5410 *avail = state->avail;
5411 return NT_STATUS_OK;
5414 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
5416 TALLOC_CTX *frame = NULL;
5417 struct tevent_context *ev = NULL;
5418 struct tevent_req *req = NULL;
5419 NTSTATUS status = NT_STATUS_OK;
5421 frame = talloc_stackframe();
5423 if (smbXcli_conn_has_async_calls(cli->conn)) {
5425 * Can't use sync call while an async call is in flight
5427 status = NT_STATUS_INVALID_PARAMETER;
5428 goto fail;
5431 ev = samba_tevent_context_init(frame);
5432 if (ev == NULL) {
5433 status = NT_STATUS_NO_MEMORY;
5434 goto fail;
5437 req = cli_dskattr_send(frame, ev, cli);
5438 if (req == NULL) {
5439 status = NT_STATUS_NO_MEMORY;
5440 goto fail;
5443 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5444 goto fail;
5447 status = cli_dskattr_recv(req, bsize, total, avail);
5449 fail:
5450 TALLOC_FREE(frame);
5451 return status;
5454 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
5455 uint64_t *total, uint64_t *avail)
5457 uint64_t sectors_per_block;
5458 uint64_t bytes_per_sector;
5459 int old_bsize = 0, old_total = 0, old_avail = 0;
5460 NTSTATUS status;
5462 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5463 return cli_smb2_dskattr(cli, path, bsize, total, avail);
5467 * Try the trans2 disk full size info call first.
5468 * We already use this in SMBC_fstatvfs_ctx().
5469 * Ignore 'actual_available_units' as we only
5470 * care about the quota for the caller.
5473 status = cli_get_fs_full_size_info(cli,
5474 total,
5475 avail,
5476 NULL,
5477 &sectors_per_block,
5478 &bytes_per_sector);
5480 /* Try and cope will all variants of "we don't do this call"
5481 and fall back to cli_dskattr. */
5483 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
5484 NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
5485 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
5486 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
5487 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
5488 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
5489 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
5490 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
5491 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
5492 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
5493 goto try_dskattr;
5496 if (!NT_STATUS_IS_OK(status)) {
5497 return status;
5500 if (bsize) {
5501 *bsize = sectors_per_block *
5502 bytes_per_sector;
5505 return NT_STATUS_OK;
5507 try_dskattr:
5509 /* Old SMB1 core protocol fallback. */
5510 status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
5511 if (!NT_STATUS_IS_OK(status)) {
5512 return status;
5514 if (bsize) {
5515 *bsize = (uint64_t)old_bsize;
5517 if (total) {
5518 *total = (uint64_t)old_total;
5520 if (avail) {
5521 *avail = (uint64_t)old_avail;
5523 return NT_STATUS_OK;
5526 /****************************************************************************
5527 Create and open a temporary file.
5528 ****************************************************************************/
5530 static void cli_ctemp_done(struct tevent_req *subreq);
5532 struct ctemp_state {
5533 uint16_t vwv[3];
5534 char *ret_path;
5535 uint16_t fnum;
5538 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
5539 struct tevent_context *ev,
5540 struct cli_state *cli,
5541 const char *path)
5543 struct tevent_req *req = NULL, *subreq = NULL;
5544 struct ctemp_state *state = NULL;
5545 uint8_t additional_flags = 0;
5546 uint16_t additional_flags2 = 0;
5547 uint8_t *bytes = NULL;
5548 char *path_cp = NULL;
5550 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
5551 if (req == NULL) {
5552 return NULL;
5555 SSVAL(state->vwv,0,0);
5556 SIVALS(state->vwv+1,0,-1);
5558 bytes = talloc_array(state, uint8_t, 1);
5559 if (tevent_req_nomem(bytes, req)) {
5560 return tevent_req_post(req, ev);
5563 * SMBctemp on a DFS share must use DFS names.
5565 path_cp = smb1_dfs_share_path(state, cli, path);
5566 if (tevent_req_nomem(path_cp, req)) {
5567 return tevent_req_post(req, ev);
5569 bytes[0] = 4;
5570 bytes = smb_bytes_push_str(bytes,
5571 smbXcli_conn_use_unicode(cli->conn),
5572 path_cp,
5573 strlen(path_cp)+1,
5574 NULL);
5575 if (tevent_req_nomem(bytes, req)) {
5576 return tevent_req_post(req, ev);
5579 if (clistr_is_previous_version_path(path)) {
5580 additional_flags2 = FLAGS2_REPARSE_PATH;
5583 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
5584 additional_flags2,
5585 3, state->vwv, talloc_get_size(bytes), bytes);
5586 if (tevent_req_nomem(subreq, req)) {
5587 return tevent_req_post(req, ev);
5589 tevent_req_set_callback(subreq, cli_ctemp_done, req);
5590 return req;
5593 static void cli_ctemp_done(struct tevent_req *subreq)
5595 struct tevent_req *req = tevent_req_callback_data(
5596 subreq, struct tevent_req);
5597 struct ctemp_state *state = tevent_req_data(
5598 req, struct ctemp_state);
5599 NTSTATUS status;
5600 uint8_t wcnt;
5601 uint16_t *vwv;
5602 uint32_t num_bytes = 0;
5603 uint8_t *bytes = NULL;
5605 status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
5606 &num_bytes, &bytes);
5607 TALLOC_FREE(subreq);
5608 if (tevent_req_nterror(req, status)) {
5609 return;
5612 state->fnum = SVAL(vwv+0, 0);
5614 /* From W2K3, the result is just the ASCII name */
5615 if (num_bytes < 2) {
5616 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
5617 return;
5620 if (pull_string_talloc(state,
5621 NULL,
5623 &state->ret_path,
5624 bytes,
5625 num_bytes,
5626 STR_ASCII) == 0) {
5627 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5628 return;
5630 tevent_req_done(req);
5633 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
5634 TALLOC_CTX *ctx,
5635 uint16_t *pfnum,
5636 char **outfile)
5638 struct ctemp_state *state = tevent_req_data(req,
5639 struct ctemp_state);
5640 NTSTATUS status;
5642 if (tevent_req_is_nterror(req, &status)) {
5643 return status;
5645 *pfnum = state->fnum;
5646 *outfile = talloc_strdup(ctx, state->ret_path);
5647 if (!*outfile) {
5648 return NT_STATUS_NO_MEMORY;
5650 return NT_STATUS_OK;
5653 NTSTATUS cli_ctemp(struct cli_state *cli,
5654 TALLOC_CTX *ctx,
5655 const char *path,
5656 uint16_t *pfnum,
5657 char **out_path)
5659 TALLOC_CTX *frame = talloc_stackframe();
5660 struct tevent_context *ev;
5661 struct tevent_req *req;
5662 NTSTATUS status = NT_STATUS_OK;
5664 if (smbXcli_conn_has_async_calls(cli->conn)) {
5666 * Can't use sync call while an async call is in flight
5668 status = NT_STATUS_INVALID_PARAMETER;
5669 goto fail;
5672 ev = samba_tevent_context_init(frame);
5673 if (ev == NULL) {
5674 status = NT_STATUS_NO_MEMORY;
5675 goto fail;
5678 req = cli_ctemp_send(frame, ev, cli, path);
5679 if (req == NULL) {
5680 status = NT_STATUS_NO_MEMORY;
5681 goto fail;
5684 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5685 goto fail;
5688 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
5690 fail:
5691 TALLOC_FREE(frame);
5692 return status;
5695 /*********************************************************
5696 Set an extended attribute utility fn.
5697 *********************************************************/
5699 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
5700 uint8_t *param, unsigned int param_len,
5701 const char *ea_name,
5702 const char *ea_val, size_t ea_len)
5704 uint16_t setup[1];
5705 unsigned int data_len = 0;
5706 uint8_t *data = NULL;
5707 char *p;
5708 size_t ea_namelen = strlen(ea_name);
5709 NTSTATUS status;
5711 SSVAL(setup, 0, setup_val);
5713 if (ea_namelen == 0 && ea_len == 0) {
5714 data_len = 4;
5715 data = talloc_array(talloc_tos(),
5716 uint8_t,
5717 data_len);
5718 if (!data) {
5719 return NT_STATUS_NO_MEMORY;
5721 p = (char *)data;
5722 SIVAL(p,0,data_len);
5723 } else {
5724 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
5725 data = talloc_array(talloc_tos(),
5726 uint8_t,
5727 data_len);
5728 if (!data) {
5729 return NT_STATUS_NO_MEMORY;
5731 p = (char *)data;
5732 SIVAL(p,0,data_len);
5733 p += 4;
5734 SCVAL(p, 0, 0); /* EA flags. */
5735 SCVAL(p, 1, ea_namelen);
5736 SSVAL(p, 2, ea_len);
5737 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
5738 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
5742 * FIXME - if we want to do previous version path
5743 * processing on an EA set call we need to turn this
5744 * into calls to cli_trans_send()/cli_trans_recv()
5745 * with a temporary event context, as cli_trans_send()
5746 * have access to the additional_flags2 needed to
5747 * send @GMT- paths. JRA.
5750 status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
5751 setup, 1, 0,
5752 param, param_len, 2,
5753 data, data_len, 0,
5754 NULL,
5755 NULL, 0, NULL, /* rsetup */
5756 NULL, 0, NULL, /* rparam */
5757 NULL, 0, NULL); /* rdata */
5758 talloc_free(data);
5759 return status;
5762 /*********************************************************
5763 Set an extended attribute on a pathname.
5764 *********************************************************/
5766 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
5767 const char *ea_name, const char *ea_val,
5768 size_t ea_len)
5770 unsigned int param_len = 0;
5771 uint8_t *param;
5772 NTSTATUS status;
5773 TALLOC_CTX *frame = NULL;
5774 char *path_cp = NULL;
5776 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5777 return cli_smb2_set_ea_path(cli,
5778 path,
5779 ea_name,
5780 ea_val,
5781 ea_len);
5784 frame = talloc_stackframe();
5786 param = talloc_array(frame, uint8_t, 6);
5787 if (!param) {
5788 status = NT_STATUS_NO_MEMORY;
5789 goto fail;
5791 SSVAL(param,0,SMB_INFO_SET_EA);
5792 SSVAL(param,2,0);
5793 SSVAL(param,4,0);
5796 * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
5798 path_cp = smb1_dfs_share_path(frame, cli, path);
5799 if (path_cp == NULL) {
5800 status = NT_STATUS_NO_MEMORY;
5801 goto fail;
5803 param = trans2_bytes_push_str(param,
5804 smbXcli_conn_use_unicode(cli->conn),
5805 path_cp,
5806 strlen(path_cp)+1,
5807 NULL);
5808 param_len = talloc_get_size(param);
5810 status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
5811 ea_name, ea_val, ea_len);
5813 fail:
5815 TALLOC_FREE(frame);
5816 return status;
5819 /*********************************************************
5820 Set an extended attribute on an fnum.
5821 *********************************************************/
5823 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
5824 const char *ea_name, const char *ea_val,
5825 size_t ea_len)
5827 uint8_t param[6] = { 0, };
5829 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5830 return cli_smb2_set_ea_fnum(cli,
5831 fnum,
5832 ea_name,
5833 ea_val,
5834 ea_len);
5837 SSVAL(param,0,fnum);
5838 SSVAL(param,2,SMB_INFO_SET_EA);
5840 return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
5841 ea_name, ea_val, ea_len);
5844 /*********************************************************
5845 Get an extended attribute list utility fn.
5846 *********************************************************/
5848 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
5849 size_t rdata_len,
5850 size_t *pnum_eas, struct ea_struct **pea_list)
5852 struct ea_struct *ea_list = NULL;
5853 size_t num_eas;
5854 size_t ea_size;
5855 const uint8_t *p;
5857 if (rdata_len < 4) {
5858 return false;
5861 ea_size = (size_t)IVAL(rdata,0);
5862 if (ea_size > rdata_len) {
5863 return false;
5866 if (ea_size == 0) {
5867 /* No EA's present. */
5868 *pnum_eas = 0;
5869 *pea_list = NULL;
5870 return true;
5873 p = rdata + 4;
5874 ea_size -= 4;
5876 /* Validate the EA list and count it. */
5877 for (num_eas = 0; ea_size >= 4; num_eas++) {
5878 unsigned int ea_namelen = CVAL(p,1);
5879 unsigned int ea_valuelen = SVAL(p,2);
5880 if (ea_namelen == 0) {
5881 return false;
5883 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
5884 return false;
5886 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
5887 p += 4 + ea_namelen + 1 + ea_valuelen;
5890 if (num_eas == 0) {
5891 *pnum_eas = 0;
5892 *pea_list = NULL;
5893 return true;
5896 *pnum_eas = num_eas;
5897 if (!pea_list) {
5898 /* Caller only wants number of EA's. */
5899 return true;
5902 ea_list = talloc_array(ctx, struct ea_struct, num_eas);
5903 if (!ea_list) {
5904 return false;
5907 p = rdata + 4;
5909 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
5910 struct ea_struct *ea = &ea_list[num_eas];
5911 fstring unix_ea_name;
5912 unsigned int ea_namelen = CVAL(p,1);
5913 unsigned int ea_valuelen = SVAL(p,2);
5915 ea->flags = CVAL(p,0);
5916 unix_ea_name[0] = '\0';
5917 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
5918 ea->name = talloc_strdup(ea_list, unix_ea_name);
5919 if (!ea->name) {
5920 goto fail;
5922 /* Ensure the value is null terminated (in case it's a string). */
5923 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
5924 if (!ea->value.data) {
5925 goto fail;
5927 if (ea_valuelen) {
5928 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
5930 ea->value.data[ea_valuelen] = 0;
5931 ea->value.length--;
5932 p += 4 + ea_namelen + 1 + ea_valuelen;
5935 *pea_list = ea_list;
5936 return true;
5938 fail:
5939 TALLOC_FREE(ea_list);
5940 return false;
5943 /*********************************************************
5944 Get an extended attribute list from a pathname.
5945 *********************************************************/
5947 struct cli_get_ea_list_path_state {
5948 uint32_t num_data;
5949 uint8_t *data;
5952 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
5954 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
5955 struct tevent_context *ev,
5956 struct cli_state *cli,
5957 const char *fname)
5959 struct tevent_req *req, *subreq;
5960 struct cli_get_ea_list_path_state *state;
5962 req = tevent_req_create(mem_ctx, &state,
5963 struct cli_get_ea_list_path_state);
5964 if (req == NULL) {
5965 return NULL;
5967 subreq = cli_qpathinfo_send(state, ev, cli, fname,
5968 SMB_INFO_QUERY_ALL_EAS, 4,
5969 CLI_BUFFER_SIZE);
5970 if (tevent_req_nomem(subreq, req)) {
5971 return tevent_req_post(req, ev);
5973 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
5974 return req;
5977 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
5979 struct tevent_req *req = tevent_req_callback_data(
5980 subreq, struct tevent_req);
5981 struct cli_get_ea_list_path_state *state = tevent_req_data(
5982 req, struct cli_get_ea_list_path_state);
5983 NTSTATUS status;
5985 status = cli_qpathinfo_recv(subreq, state, &state->data,
5986 &state->num_data);
5987 TALLOC_FREE(subreq);
5988 if (tevent_req_nterror(req, status)) {
5989 return;
5991 tevent_req_done(req);
5994 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5995 size_t *pnum_eas, struct ea_struct **peas)
5997 struct cli_get_ea_list_path_state *state = tevent_req_data(
5998 req, struct cli_get_ea_list_path_state);
5999 NTSTATUS status;
6001 if (tevent_req_is_nterror(req, &status)) {
6002 return status;
6004 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
6005 pnum_eas, peas)) {
6006 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6008 return NT_STATUS_OK;
6011 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
6012 TALLOC_CTX *ctx,
6013 size_t *pnum_eas,
6014 struct ea_struct **pea_list)
6016 TALLOC_CTX *frame = NULL;
6017 struct tevent_context *ev = NULL;
6018 struct tevent_req *req = NULL;
6019 NTSTATUS status = NT_STATUS_NO_MEMORY;
6021 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6022 return cli_smb2_get_ea_list_path(cli,
6023 path,
6024 ctx,
6025 pnum_eas,
6026 pea_list);
6029 frame = talloc_stackframe();
6031 if (smbXcli_conn_has_async_calls(cli->conn)) {
6033 * Can't use sync call while an async call is in flight
6035 status = NT_STATUS_INVALID_PARAMETER;
6036 goto fail;
6038 ev = samba_tevent_context_init(frame);
6039 if (ev == NULL) {
6040 goto fail;
6042 req = cli_get_ea_list_path_send(frame, ev, cli, path);
6043 if (req == NULL) {
6044 goto fail;
6046 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6047 goto fail;
6049 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
6050 fail:
6051 TALLOC_FREE(frame);
6052 return status;
6055 /****************************************************************************
6056 Convert open "flags" arg to uint32_t on wire.
6057 ****************************************************************************/
6059 static uint32_t open_flags_to_wire(int flags)
6061 int open_mode = flags & O_ACCMODE;
6062 uint32_t ret = 0;
6064 switch (open_mode) {
6065 case O_WRONLY:
6066 ret |= SMB_O_WRONLY;
6067 break;
6068 case O_RDWR:
6069 ret |= SMB_O_RDWR;
6070 break;
6071 default:
6072 case O_RDONLY:
6073 ret |= SMB_O_RDONLY;
6074 break;
6077 if (flags & O_CREAT) {
6078 ret |= SMB_O_CREAT;
6080 if (flags & O_EXCL) {
6081 ret |= SMB_O_EXCL;
6083 if (flags & O_TRUNC) {
6084 ret |= SMB_O_TRUNC;
6086 #if defined(O_SYNC)
6087 if (flags & O_SYNC) {
6088 ret |= SMB_O_SYNC;
6090 #endif /* O_SYNC */
6091 if (flags & O_APPEND) {
6092 ret |= SMB_O_APPEND;
6094 #if defined(O_DIRECT)
6095 if (flags & O_DIRECT) {
6096 ret |= SMB_O_DIRECT;
6098 #endif
6099 #if defined(O_DIRECTORY)
6100 if (flags & O_DIRECTORY) {
6101 ret |= SMB_O_DIRECTORY;
6103 #endif
6104 return ret;
6107 /****************************************************************************
6108 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
6109 ****************************************************************************/
6111 struct cli_posix_open_internal_state {
6112 uint16_t setup;
6113 uint8_t *param;
6114 uint8_t data[18];
6115 uint16_t fnum; /* Out */
6118 static void cli_posix_open_internal_done(struct tevent_req *subreq);
6120 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
6121 struct tevent_context *ev,
6122 struct cli_state *cli,
6123 const char *fname,
6124 uint32_t wire_flags,
6125 mode_t mode)
6127 struct tevent_req *req = NULL, *subreq = NULL;
6128 struct cli_posix_open_internal_state *state = NULL;
6129 char *fname_cp = NULL;
6131 req = tevent_req_create(
6132 mem_ctx, &state, struct cli_posix_open_internal_state);
6133 if (req == NULL) {
6134 return NULL;
6137 /* Setup setup word. */
6138 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
6140 /* Setup param array. */
6141 state->param = talloc_zero_array(state, uint8_t, 6);
6142 if (tevent_req_nomem(state->param, req)) {
6143 return tevent_req_post(req, ev);
6145 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
6148 * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
6150 fname_cp = smb1_dfs_share_path(state, cli, fname);
6151 if (tevent_req_nomem(fname_cp, req)) {
6152 return tevent_req_post(req, ev);
6154 state->param = trans2_bytes_push_str(
6155 state->param,
6156 smbXcli_conn_use_unicode(cli->conn),
6157 fname_cp,
6158 strlen(fname_cp)+1,
6159 NULL);
6161 if (tevent_req_nomem(state->param, req)) {
6162 return tevent_req_post(req, ev);
6165 SIVAL(state->data,0,0); /* No oplock. */
6166 SIVAL(state->data,4,wire_flags);
6167 SIVAL(state->data,8,unix_perms_to_wire(mode));
6168 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
6169 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
6171 subreq = cli_trans_send(state, /* mem ctx. */
6172 ev, /* event ctx. */
6173 cli, /* cli_state. */
6174 0, /* additional_flags2 */
6175 SMBtrans2, /* cmd. */
6176 NULL, /* pipe name. */
6177 -1, /* fid. */
6178 0, /* function. */
6179 0, /* flags. */
6180 &state->setup, /* setup. */
6181 1, /* num setup uint16_t words. */
6182 0, /* max returned setup. */
6183 state->param, /* param. */
6184 talloc_get_size(state->param),/* num param. */
6185 2, /* max returned param. */
6186 state->data, /* data. */
6187 18, /* num data. */
6188 12); /* max returned data. */
6190 if (tevent_req_nomem(subreq, req)) {
6191 return tevent_req_post(req, ev);
6193 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
6194 return req;
6197 static void cli_posix_open_internal_done(struct tevent_req *subreq)
6199 struct tevent_req *req = tevent_req_callback_data(
6200 subreq, struct tevent_req);
6201 struct cli_posix_open_internal_state *state = tevent_req_data(
6202 req, struct cli_posix_open_internal_state);
6203 NTSTATUS status;
6204 uint8_t *data;
6205 uint32_t num_data;
6207 status = cli_trans_recv(
6208 subreq,
6209 state,
6210 NULL,
6211 NULL,
6213 NULL,
6214 NULL,
6216 NULL,
6217 &data,
6219 &num_data);
6220 TALLOC_FREE(subreq);
6221 if (tevent_req_nterror(req, status)) {
6222 return;
6224 state->fnum = SVAL(data,2);
6225 tevent_req_done(req);
6228 static NTSTATUS cli_posix_open_internal_recv(struct tevent_req *req,
6229 uint16_t *pfnum)
6231 struct cli_posix_open_internal_state *state = tevent_req_data(
6232 req, struct cli_posix_open_internal_state);
6233 NTSTATUS status;
6235 if (tevent_req_is_nterror(req, &status)) {
6236 return status;
6238 *pfnum = state->fnum;
6239 return NT_STATUS_OK;
6242 struct cli_posix_open_state {
6243 uint16_t fnum;
6246 static void cli_posix_open_done(struct tevent_req *subreq);
6248 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
6249 struct tevent_context *ev,
6250 struct cli_state *cli,
6251 const char *fname,
6252 int flags,
6253 mode_t mode)
6255 struct tevent_req *req = NULL, *subreq = NULL;
6256 struct cli_posix_open_state *state = NULL;
6257 uint32_t wire_flags;
6259 req = tevent_req_create(mem_ctx, &state,
6260 struct cli_posix_open_state);
6261 if (req == NULL) {
6262 return NULL;
6265 wire_flags = open_flags_to_wire(flags);
6267 subreq = cli_posix_open_internal_send(
6268 mem_ctx, ev, cli, fname, wire_flags, mode);
6269 if (tevent_req_nomem(subreq, req)) {
6270 return tevent_req_post(req, ev);
6272 tevent_req_set_callback(subreq, cli_posix_open_done, req);
6273 return req;
6276 static void cli_posix_open_done(struct tevent_req *subreq)
6278 struct tevent_req *req = tevent_req_callback_data(
6279 subreq, struct tevent_req);
6280 struct cli_posix_open_state *state = tevent_req_data(
6281 req, struct cli_posix_open_state);
6282 NTSTATUS status;
6284 status = cli_posix_open_internal_recv(subreq, &state->fnum);
6285 tevent_req_simple_finish_ntstatus(subreq, status);
6288 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
6290 struct cli_posix_open_state *state = tevent_req_data(
6291 req, struct cli_posix_open_state);
6292 NTSTATUS status;
6294 if (tevent_req_is_nterror(req, &status)) {
6295 return status;
6297 *pfnum = state->fnum;
6298 return NT_STATUS_OK;
6301 /****************************************************************************
6302 Open - POSIX semantics. Doesn't request oplock.
6303 ****************************************************************************/
6305 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
6306 int flags, mode_t mode, uint16_t *pfnum)
6309 TALLOC_CTX *frame = talloc_stackframe();
6310 struct tevent_context *ev = NULL;
6311 struct tevent_req *req = NULL;
6312 NTSTATUS status = NT_STATUS_NO_MEMORY;
6314 if (smbXcli_conn_has_async_calls(cli->conn)) {
6316 * Can't use sync call while an async call is in flight
6318 status = NT_STATUS_INVALID_PARAMETER;
6319 goto fail;
6321 ev = samba_tevent_context_init(frame);
6322 if (ev == NULL) {
6323 goto fail;
6325 req = cli_posix_open_send(
6326 frame, ev, cli, fname, flags, mode);
6327 if (req == NULL) {
6328 goto fail;
6330 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6331 goto fail;
6333 status = cli_posix_open_recv(req, pfnum);
6334 fail:
6335 TALLOC_FREE(frame);
6336 return status;
6339 struct cli_posix_mkdir_state {
6340 struct tevent_context *ev;
6341 struct cli_state *cli;
6344 static void cli_posix_mkdir_done(struct tevent_req *subreq);
6346 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
6347 struct tevent_context *ev,
6348 struct cli_state *cli,
6349 const char *fname,
6350 mode_t mode)
6352 struct tevent_req *req = NULL, *subreq = NULL;
6353 struct cli_posix_mkdir_state *state = NULL;
6354 uint32_t wire_flags;
6356 req = tevent_req_create(
6357 mem_ctx, &state, struct cli_posix_mkdir_state);
6358 if (req == NULL) {
6359 return NULL;
6361 state->ev = ev;
6362 state->cli = cli;
6364 wire_flags = SMB_O_CREAT | SMB_O_DIRECTORY;
6366 subreq = cli_posix_open_internal_send(
6367 mem_ctx, ev, cli, fname, wire_flags, mode);
6368 if (tevent_req_nomem(subreq, req)) {
6369 return tevent_req_post(req, ev);
6371 tevent_req_set_callback(subreq, cli_posix_mkdir_done, req);
6372 return req;
6375 static void cli_posix_mkdir_done(struct tevent_req *subreq)
6377 struct tevent_req *req = tevent_req_callback_data(
6378 subreq, struct tevent_req);
6379 NTSTATUS status;
6380 uint16_t fnum;
6382 status = cli_posix_open_internal_recv(subreq, &fnum);
6383 TALLOC_FREE(subreq);
6384 if (tevent_req_nterror(req, status)) {
6385 return;
6387 tevent_req_done(req);
6390 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
6392 return tevent_req_simple_recv_ntstatus(req);
6395 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
6397 TALLOC_CTX *frame = talloc_stackframe();
6398 struct tevent_context *ev = NULL;
6399 struct tevent_req *req = NULL;
6400 NTSTATUS status = NT_STATUS_NO_MEMORY;
6402 if (smbXcli_conn_has_async_calls(cli->conn)) {
6404 * Can't use sync call while an async call is in flight
6406 status = NT_STATUS_INVALID_PARAMETER;
6407 goto fail;
6410 ev = samba_tevent_context_init(frame);
6411 if (ev == NULL) {
6412 goto fail;
6414 req = cli_posix_mkdir_send(
6415 frame, ev, cli, fname, mode);
6416 if (req == NULL) {
6417 goto fail;
6419 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6420 goto fail;
6422 status = cli_posix_mkdir_recv(req);
6423 fail:
6424 TALLOC_FREE(frame);
6425 return status;
6428 /****************************************************************************
6429 unlink or rmdir - POSIX semantics.
6430 ****************************************************************************/
6432 struct cli_posix_unlink_internal_state {
6433 uint8_t data[2];
6436 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
6438 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
6439 struct tevent_context *ev,
6440 struct cli_state *cli,
6441 const char *fname,
6442 uint16_t level)
6444 struct tevent_req *req = NULL, *subreq = NULL;
6445 struct cli_posix_unlink_internal_state *state = NULL;
6447 req = tevent_req_create(mem_ctx, &state,
6448 struct cli_posix_unlink_internal_state);
6449 if (req == NULL) {
6450 return NULL;
6453 /* Setup data word. */
6454 SSVAL(state->data, 0, level);
6456 subreq = cli_setpathinfo_send(state, ev, cli,
6457 SMB_POSIX_PATH_UNLINK,
6458 fname,
6459 state->data, sizeof(state->data));
6460 if (tevent_req_nomem(subreq, req)) {
6461 return tevent_req_post(req, ev);
6463 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
6464 return req;
6467 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
6469 NTSTATUS status = cli_setpathinfo_recv(subreq);
6470 tevent_req_simple_finish_ntstatus(subreq, status);
6473 static NTSTATUS cli_posix_unlink_internal_recv(struct tevent_req *req)
6475 return tevent_req_simple_recv_ntstatus(req);
6478 struct cli_posix_unlink_state {
6479 uint8_t dummy;
6482 static void cli_posix_unlink_done(struct tevent_req *subreq);
6484 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
6485 struct tevent_context *ev,
6486 struct cli_state *cli,
6487 const char *fname)
6489 struct tevent_req *req = NULL, *subreq = NULL;
6490 struct cli_posix_unlink_state *state;
6492 req = tevent_req_create(
6493 mem_ctx, &state, struct cli_posix_unlink_state);
6494 if (req == NULL) {
6495 return NULL;
6497 subreq = cli_posix_unlink_internal_send(
6498 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_FILE_TARGET);
6499 if (tevent_req_nomem(subreq, req)) {
6500 return tevent_req_post(req, ev);
6502 tevent_req_set_callback(subreq, cli_posix_unlink_done, req);
6503 return req;
6506 static void cli_posix_unlink_done(struct tevent_req *subreq)
6508 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6509 tevent_req_simple_finish_ntstatus(subreq, status);
6512 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
6514 return tevent_req_simple_recv_ntstatus(req);
6517 /****************************************************************************
6518 unlink - POSIX semantics.
6519 ****************************************************************************/
6521 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
6523 TALLOC_CTX *frame = talloc_stackframe();
6524 struct tevent_context *ev = NULL;
6525 struct tevent_req *req = NULL;
6526 NTSTATUS status = NT_STATUS_OK;
6528 if (smbXcli_conn_has_async_calls(cli->conn)) {
6530 * Can't use sync call while an async call is in flight
6532 status = NT_STATUS_INVALID_PARAMETER;
6533 goto fail;
6536 ev = samba_tevent_context_init(frame);
6537 if (ev == NULL) {
6538 status = NT_STATUS_NO_MEMORY;
6539 goto fail;
6542 req = cli_posix_unlink_send(frame,
6544 cli,
6545 fname);
6546 if (req == NULL) {
6547 status = NT_STATUS_NO_MEMORY;
6548 goto fail;
6551 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6552 goto fail;
6555 status = cli_posix_unlink_recv(req);
6557 fail:
6558 TALLOC_FREE(frame);
6559 return status;
6562 /****************************************************************************
6563 rmdir - POSIX semantics.
6564 ****************************************************************************/
6566 struct cli_posix_rmdir_state {
6567 uint8_t dummy;
6570 static void cli_posix_rmdir_done(struct tevent_req *subreq);
6572 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
6573 struct tevent_context *ev,
6574 struct cli_state *cli,
6575 const char *fname)
6577 struct tevent_req *req = NULL, *subreq = NULL;
6578 struct cli_posix_rmdir_state *state;
6580 req = tevent_req_create(mem_ctx, &state, struct cli_posix_rmdir_state);
6581 if (req == NULL) {
6582 return NULL;
6584 subreq = cli_posix_unlink_internal_send(
6585 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_DIRECTORY_TARGET);
6586 if (tevent_req_nomem(subreq, req)) {
6587 return tevent_req_post(req, ev);
6589 tevent_req_set_callback(subreq, cli_posix_rmdir_done, req);
6590 return req;
6593 static void cli_posix_rmdir_done(struct tevent_req *subreq)
6595 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6596 tevent_req_simple_finish_ntstatus(subreq, status);
6599 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
6601 return tevent_req_simple_recv_ntstatus(req);
6604 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
6606 TALLOC_CTX *frame = talloc_stackframe();
6607 struct tevent_context *ev = NULL;
6608 struct tevent_req *req = NULL;
6609 NTSTATUS status = NT_STATUS_OK;
6611 if (smbXcli_conn_has_async_calls(cli->conn)) {
6613 * Can't use sync call while an async call is in flight
6615 status = NT_STATUS_INVALID_PARAMETER;
6616 goto fail;
6619 ev = samba_tevent_context_init(frame);
6620 if (ev == NULL) {
6621 status = NT_STATUS_NO_MEMORY;
6622 goto fail;
6625 req = cli_posix_rmdir_send(frame,
6627 cli,
6628 fname);
6629 if (req == NULL) {
6630 status = NT_STATUS_NO_MEMORY;
6631 goto fail;
6634 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6635 goto fail;
6638 status = cli_posix_rmdir_recv(req, frame);
6640 fail:
6641 TALLOC_FREE(frame);
6642 return status;
6645 /****************************************************************************
6646 filechangenotify
6647 ****************************************************************************/
6649 struct cli_notify_state {
6650 struct tevent_req *subreq;
6651 uint8_t setup[8];
6652 uint32_t num_changes;
6653 struct notify_change *changes;
6656 static void cli_notify_done(struct tevent_req *subreq);
6657 static void cli_notify_done_smb2(struct tevent_req *subreq);
6658 static bool cli_notify_cancel(struct tevent_req *req);
6660 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
6661 struct tevent_context *ev,
6662 struct cli_state *cli, uint16_t fnum,
6663 uint32_t buffer_size,
6664 uint32_t completion_filter, bool recursive)
6666 struct tevent_req *req;
6667 struct cli_notify_state *state;
6668 unsigned old_timeout;
6670 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
6671 if (req == NULL) {
6672 return NULL;
6675 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6677 * Notifies should not time out
6679 old_timeout = cli_set_timeout(cli, 0);
6681 state->subreq = cli_smb2_notify_send(
6682 state,
6684 cli,
6685 fnum,
6686 buffer_size,
6687 completion_filter,
6688 recursive);
6690 cli_set_timeout(cli, old_timeout);
6692 if (tevent_req_nomem(state->subreq, req)) {
6693 return tevent_req_post(req, ev);
6695 tevent_req_set_callback(
6696 state->subreq, cli_notify_done_smb2, req);
6697 goto done;
6700 SIVAL(state->setup, 0, completion_filter);
6701 SSVAL(state->setup, 4, fnum);
6702 SSVAL(state->setup, 6, recursive);
6705 * Notifies should not time out
6707 old_timeout = cli_set_timeout(cli, 0);
6709 state->subreq = cli_trans_send(
6710 state, /* mem ctx. */
6711 ev, /* event ctx. */
6712 cli, /* cli_state. */
6713 0, /* additional_flags2 */
6714 SMBnttrans, /* cmd. */
6715 NULL, /* pipe name. */
6716 -1, /* fid. */
6717 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
6718 0, /* flags. */
6719 (uint16_t *)state->setup, /* setup. */
6720 4, /* num setup uint16_t words. */
6721 0, /* max returned setup. */
6722 NULL, /* param. */
6723 0, /* num param. */
6724 buffer_size, /* max returned param. */
6725 NULL, /* data. */
6726 0, /* num data. */
6727 0); /* max returned data. */
6729 cli_set_timeout(cli, old_timeout);
6731 if (tevent_req_nomem(state->subreq, req)) {
6732 return tevent_req_post(req, ev);
6734 tevent_req_set_callback(state->subreq, cli_notify_done, req);
6735 done:
6736 tevent_req_set_cancel_fn(req, cli_notify_cancel);
6737 return req;
6740 static bool cli_notify_cancel(struct tevent_req *req)
6742 struct cli_notify_state *state = tevent_req_data(
6743 req, struct cli_notify_state);
6744 bool ok;
6746 ok = tevent_req_cancel(state->subreq);
6747 return ok;
6750 static void cli_notify_done(struct tevent_req *subreq)
6752 struct tevent_req *req = tevent_req_callback_data(
6753 subreq, struct tevent_req);
6754 struct cli_notify_state *state = tevent_req_data(
6755 req, struct cli_notify_state);
6756 NTSTATUS status;
6757 uint8_t *params;
6758 uint32_t i, ofs, num_params;
6759 uint16_t flags2;
6761 status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
6762 &params, 0, &num_params, NULL, 0, NULL);
6763 TALLOC_FREE(subreq);
6764 state->subreq = NULL;
6765 if (tevent_req_nterror(req, status)) {
6766 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
6767 return;
6770 state->num_changes = 0;
6771 ofs = 0;
6773 while (num_params - ofs > 12) {
6774 uint32_t next = IVAL(params, ofs);
6775 state->num_changes += 1;
6777 if ((next == 0) || (ofs+next >= num_params)) {
6778 break;
6780 ofs += next;
6783 state->changes = talloc_array(state, struct notify_change,
6784 state->num_changes);
6785 if (tevent_req_nomem(state->changes, req)) {
6786 TALLOC_FREE(params);
6787 return;
6790 ofs = 0;
6792 for (i=0; i<state->num_changes; i++) {
6793 uint32_t next = IVAL(params, ofs);
6794 uint32_t len = IVAL(params, ofs+8);
6795 ssize_t ret;
6796 char *name;
6798 if (smb_buffer_oob(num_params, ofs + 12, len)) {
6799 TALLOC_FREE(params);
6800 tevent_req_nterror(
6801 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
6802 return;
6805 state->changes[i].action = IVAL(params, ofs+4);
6806 ret = pull_string_talloc(state->changes,
6807 (char *)params,
6808 flags2,
6809 &name,
6810 params+ofs+12,
6811 len,
6812 STR_TERMINATE|STR_UNICODE);
6813 if (ret == -1) {
6814 TALLOC_FREE(params);
6815 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
6816 return;
6818 state->changes[i].name = name;
6819 ofs += next;
6822 TALLOC_FREE(params);
6823 tevent_req_done(req);
6826 static void cli_notify_done_smb2(struct tevent_req *subreq)
6828 struct tevent_req *req = tevent_req_callback_data(
6829 subreq, struct tevent_req);
6830 struct cli_notify_state *state = tevent_req_data(
6831 req, struct cli_notify_state);
6832 NTSTATUS status;
6834 status = cli_smb2_notify_recv(
6835 subreq,
6836 state,
6837 &state->changes,
6838 &state->num_changes);
6839 TALLOC_FREE(subreq);
6840 if (tevent_req_nterror(req, status)) {
6841 return;
6843 tevent_req_done(req);
6846 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6847 uint32_t *pnum_changes,
6848 struct notify_change **pchanges)
6850 struct cli_notify_state *state = tevent_req_data(
6851 req, struct cli_notify_state);
6852 NTSTATUS status;
6854 if (tevent_req_is_nterror(req, &status)) {
6855 return status;
6858 *pnum_changes = state->num_changes;
6859 *pchanges = talloc_move(mem_ctx, &state->changes);
6860 return NT_STATUS_OK;
6863 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
6864 uint32_t completion_filter, bool recursive,
6865 TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
6866 struct notify_change **pchanges)
6868 TALLOC_CTX *frame;
6869 struct tevent_context *ev;
6870 struct tevent_req *req;
6871 NTSTATUS status = NT_STATUS_NO_MEMORY;
6873 frame = talloc_stackframe();
6875 if (smbXcli_conn_has_async_calls(cli->conn)) {
6877 * Can't use sync call while an async call is in flight
6879 status = NT_STATUS_INVALID_PARAMETER;
6880 goto fail;
6882 ev = samba_tevent_context_init(frame);
6883 if (ev == NULL) {
6884 goto fail;
6886 req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
6887 completion_filter, recursive);
6888 if (req == NULL) {
6889 goto fail;
6891 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6892 goto fail;
6894 status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
6895 fail:
6896 TALLOC_FREE(frame);
6897 return status;
6900 struct cli_qpathinfo_state {
6901 uint8_t *param;
6902 uint8_t *data;
6903 uint16_t setup[1];
6904 uint32_t min_rdata;
6905 uint8_t *rdata;
6906 uint32_t num_rdata;
6909 static void cli_qpathinfo_done(struct tevent_req *subreq);
6910 static void cli_qpathinfo_done2(struct tevent_req *subreq);
6912 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
6913 struct tevent_context *ev,
6914 struct cli_state *cli, const char *fname,
6915 uint16_t level, uint32_t min_rdata,
6916 uint32_t max_rdata)
6918 struct tevent_req *req, *subreq;
6919 struct cli_qpathinfo_state *state;
6920 uint16_t additional_flags2 = 0;
6921 char *fname_cp = NULL;
6923 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
6924 if (req == NULL) {
6925 return NULL;
6928 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6929 uint16_t smb2_level = 0;
6931 switch (level) {
6932 case SMB_QUERY_FILE_ALT_NAME_INFO:
6933 smb2_level = FSCC_FILE_ALTERNATE_NAME_INFORMATION;
6934 break;
6935 default:
6936 tevent_req_nterror(req, NT_STATUS_INVALID_LEVEL);
6937 return tevent_req_post(req, ev);
6940 subreq = cli_smb2_qpathinfo_send(state,
6942 cli,
6943 fname,
6944 smb2_level,
6945 min_rdata,
6946 max_rdata);
6947 if (tevent_req_nomem(subreq, req)) {
6948 return tevent_req_post(req, ev);
6950 tevent_req_set_callback(subreq, cli_qpathinfo_done2, req);
6951 return req;
6954 state->min_rdata = min_rdata;
6955 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
6957 state->param = talloc_zero_array(state, uint8_t, 6);
6958 if (tevent_req_nomem(state->param, req)) {
6959 return tevent_req_post(req, ev);
6961 SSVAL(state->param, 0, level);
6963 * qpathinfo on a DFS share must use DFS names.
6965 fname_cp = smb1_dfs_share_path(state, cli, fname);
6966 if (tevent_req_nomem(fname_cp, req)) {
6967 return tevent_req_post(req, ev);
6969 state->param = trans2_bytes_push_str(state->param,
6970 smbXcli_conn_use_unicode(cli->conn),
6971 fname_cp,
6972 strlen(fname_cp)+1,
6973 NULL);
6974 if (tevent_req_nomem(state->param, req)) {
6975 return tevent_req_post(req, ev);
6978 if (clistr_is_previous_version_path(fname) &&
6979 !INFO_LEVEL_IS_UNIX(level)) {
6980 additional_flags2 = FLAGS2_REPARSE_PATH;
6983 subreq = cli_trans_send(
6984 state, /* mem ctx. */
6985 ev, /* event ctx. */
6986 cli, /* cli_state. */
6987 additional_flags2, /* additional_flags2 */
6988 SMBtrans2, /* cmd. */
6989 NULL, /* pipe name. */
6990 -1, /* fid. */
6991 0, /* function. */
6992 0, /* flags. */
6993 state->setup, /* setup. */
6994 1, /* num setup uint16_t words. */
6995 0, /* max returned setup. */
6996 state->param, /* param. */
6997 talloc_get_size(state->param), /* num param. */
6998 2, /* max returned param. */
6999 NULL, /* data. */
7000 0, /* num data. */
7001 max_rdata); /* max returned data. */
7003 if (tevent_req_nomem(subreq, req)) {
7004 return tevent_req_post(req, ev);
7006 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
7007 return req;
7010 static void cli_qpathinfo_done(struct tevent_req *subreq)
7012 struct tevent_req *req = tevent_req_callback_data(
7013 subreq, struct tevent_req);
7014 struct cli_qpathinfo_state *state = tevent_req_data(
7015 req, struct cli_qpathinfo_state);
7016 NTSTATUS status;
7018 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
7019 NULL, 0, NULL,
7020 &state->rdata, state->min_rdata,
7021 &state->num_rdata);
7022 if (tevent_req_nterror(req, status)) {
7023 return;
7025 tevent_req_done(req);
7028 static void cli_qpathinfo_done2(struct tevent_req *subreq)
7030 struct tevent_req *req =
7031 tevent_req_callback_data(subreq, struct tevent_req);
7032 struct cli_qpathinfo_state *state =
7033 tevent_req_data(req, struct cli_qpathinfo_state);
7034 NTSTATUS status;
7036 status = cli_smb2_qpathinfo_recv(subreq,
7037 state,
7038 &state->rdata,
7039 &state->num_rdata);
7040 if (tevent_req_nterror(req, status)) {
7041 return;
7043 tevent_req_done(req);
7046 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
7047 uint8_t **rdata, uint32_t *num_rdata)
7049 struct cli_qpathinfo_state *state = tevent_req_data(
7050 req, struct cli_qpathinfo_state);
7051 NTSTATUS status;
7053 if (tevent_req_is_nterror(req, &status)) {
7054 return status;
7056 if (rdata != NULL) {
7057 *rdata = talloc_move(mem_ctx, &state->rdata);
7058 } else {
7059 TALLOC_FREE(state->rdata);
7061 if (num_rdata != NULL) {
7062 *num_rdata = state->num_rdata;
7064 return NT_STATUS_OK;
7067 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
7068 const char *fname, uint16_t level, uint32_t min_rdata,
7069 uint32_t max_rdata,
7070 uint8_t **rdata, uint32_t *num_rdata)
7072 TALLOC_CTX *frame = talloc_stackframe();
7073 struct tevent_context *ev;
7074 struct tevent_req *req;
7075 NTSTATUS status = NT_STATUS_NO_MEMORY;
7077 if (smbXcli_conn_has_async_calls(cli->conn)) {
7079 * Can't use sync call while an async call is in flight
7081 status = NT_STATUS_INVALID_PARAMETER;
7082 goto fail;
7084 ev = samba_tevent_context_init(frame);
7085 if (ev == NULL) {
7086 goto fail;
7088 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
7089 max_rdata);
7090 if (req == NULL) {
7091 goto fail;
7093 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7094 goto fail;
7096 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
7097 fail:
7098 TALLOC_FREE(frame);
7099 return status;
7102 struct cli_qfileinfo_state {
7103 uint16_t setup[1];
7104 uint8_t param[4];
7105 uint8_t *data;
7106 uint16_t recv_flags2;
7107 uint32_t min_rdata;
7108 uint8_t *rdata;
7109 uint32_t num_rdata;
7112 static void cli_qfileinfo_done2(struct tevent_req *subreq);
7113 static void cli_qfileinfo_done(struct tevent_req *subreq);
7115 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
7116 struct tevent_context *ev,
7117 struct cli_state *cli,
7118 uint16_t fnum,
7119 uint16_t fscc_level,
7120 uint32_t min_rdata,
7121 uint32_t max_rdata)
7123 struct tevent_req *req, *subreq;
7124 struct cli_qfileinfo_state *state;
7125 uint16_t smb_level;
7127 req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
7128 if (req == NULL) {
7129 return NULL;
7132 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
7133 max_rdata = MIN(max_rdata,
7134 smb2cli_conn_max_trans_size(cli->conn));
7136 subreq = cli_smb2_query_info_fnum_send(
7137 state, /* mem_ctx */
7138 ev, /* ev */
7139 cli, /* cli */
7140 fnum, /* fnum */
7141 SMB2_0_INFO_FILE, /* in_info_type */
7142 fscc_level, /* in_file_info_class */
7143 max_rdata, /* in_max_output_length */
7144 NULL, /* in_input_buffer */
7145 0, /* in_additional_info */
7146 0); /* in_flags */
7147 if (tevent_req_nomem(subreq, req)) {
7148 return tevent_req_post(req, ev);
7150 tevent_req_set_callback(subreq, cli_qfileinfo_done2, req);
7151 return req;
7154 max_rdata = MIN(max_rdata, UINT16_MAX);
7156 switch (fscc_level) {
7157 case FSCC_FILE_BASIC_INFORMATION:
7158 smb_level = SMB_QUERY_FILE_BASIC_INFO;
7159 break;
7160 case FSCC_FILE_STANDARD_INFORMATION:
7161 smb_level = SMB_QUERY_FILE_STANDARD_INFO;
7162 break;
7163 case FSCC_FILE_EA_INFORMATION:
7164 smb_level = SMB_QUERY_FILE_EA_INFO;
7165 break;
7166 case FSCC_FILE_NAME_INFORMATION:
7167 smb_level = SMB_QUERY_FILE_NAME_INFO;
7168 break;
7169 case FSCC_FILE_ALL_INFORMATION:
7170 smb_level = SMB_QUERY_FILE_ALL_INFO;
7171 break;
7172 case FSCC_FILE_ALTERNATE_NAME_INFORMATION:
7173 smb_level = SMB_QUERY_FILE_ALT_NAME_INFO;
7174 break;
7175 case FSCC_FILE_STREAM_INFORMATION:
7176 smb_level = SMB_QUERY_FILE_STREAM_INFO;
7177 break;
7178 case FSCC_FILE_COMPRESSION_INFORMATION:
7179 smb_level = SMB_QUERY_COMPRESSION_INFO;
7180 break;
7181 default:
7182 /* Probably wrong, but the server will tell us */
7183 smb_level = fscc_level;
7184 break;
7187 state->min_rdata = min_rdata;
7188 SSVAL(state->param, 0, fnum);
7189 SSVAL(state->param, 2, smb_level);
7190 SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
7192 subreq = cli_trans_send(
7193 state, /* mem ctx. */
7194 ev, /* event ctx. */
7195 cli, /* cli_state. */
7196 0, /* additional_flags2 */
7197 SMBtrans2, /* cmd. */
7198 NULL, /* pipe name. */
7199 -1, /* fid. */
7200 0, /* function. */
7201 0, /* flags. */
7202 state->setup, /* setup. */
7203 1, /* num setup uint16_t words. */
7204 0, /* max returned setup. */
7205 state->param, /* param. */
7206 sizeof(state->param), /* num param. */
7207 2, /* max returned param. */
7208 NULL, /* data. */
7209 0, /* num data. */
7210 max_rdata); /* max returned data. */
7212 if (tevent_req_nomem(subreq, req)) {
7213 return tevent_req_post(req, ev);
7215 tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
7216 return req;
7219 static void cli_qfileinfo_done2(struct tevent_req *subreq)
7221 struct tevent_req *req = tevent_req_callback_data(subreq,
7222 struct tevent_req);
7223 struct cli_qfileinfo_state *state = tevent_req_data(
7224 req, struct cli_qfileinfo_state);
7225 DATA_BLOB outbuf = {};
7226 NTSTATUS status;
7228 status = cli_smb2_query_info_fnum_recv(subreq, state, &outbuf);
7229 TALLOC_FREE(subreq);
7230 if (tevent_req_nterror(req, status)) {
7231 return;
7234 if (outbuf.length < state->min_rdata) {
7235 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
7236 return;
7239 state->rdata = outbuf.data;
7240 state->num_rdata = outbuf.length;
7241 tevent_req_done(req);
7244 static void cli_qfileinfo_done(struct tevent_req *subreq)
7246 struct tevent_req *req = tevent_req_callback_data(
7247 subreq, struct tevent_req);
7248 struct cli_qfileinfo_state *state = tevent_req_data(
7249 req, struct cli_qfileinfo_state);
7250 NTSTATUS status;
7252 status = cli_trans_recv(subreq, state,
7253 &state->recv_flags2,
7254 NULL, 0, NULL,
7255 NULL, 0, NULL,
7256 &state->rdata, state->min_rdata,
7257 &state->num_rdata);
7258 if (tevent_req_nterror(req, status)) {
7259 return;
7261 tevent_req_done(req);
7264 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
7265 uint16_t *recv_flags2,
7266 uint8_t **rdata, uint32_t *num_rdata)
7268 struct cli_qfileinfo_state *state = tevent_req_data(
7269 req, struct cli_qfileinfo_state);
7270 NTSTATUS status;
7272 if (tevent_req_is_nterror(req, &status)) {
7273 return status;
7276 if (recv_flags2 != NULL) {
7277 *recv_flags2 = state->recv_flags2;
7279 if (rdata != NULL) {
7280 *rdata = talloc_move(mem_ctx, &state->rdata);
7282 if (num_rdata != NULL) {
7283 *num_rdata = state->num_rdata;
7286 tevent_req_received(req);
7287 return NT_STATUS_OK;
7290 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx,
7291 struct cli_state *cli,
7292 uint16_t fnum,
7293 uint16_t fscc_level,
7294 uint32_t min_rdata,
7295 uint32_t max_rdata,
7296 uint16_t *recv_flags2,
7297 uint8_t **rdata,
7298 uint32_t *num_rdata)
7300 TALLOC_CTX *frame = talloc_stackframe();
7301 struct tevent_context *ev;
7302 struct tevent_req *req;
7303 NTSTATUS status = NT_STATUS_NO_MEMORY;
7305 if (smbXcli_conn_has_async_calls(cli->conn)) {
7307 * Can't use sync call while an async call is in flight
7309 status = NT_STATUS_INVALID_PARAMETER;
7310 goto fail;
7312 ev = samba_tevent_context_init(frame);
7313 if (ev == NULL) {
7314 goto fail;
7316 req = cli_qfileinfo_send(
7317 frame, ev, cli, fnum, fscc_level, min_rdata, max_rdata);
7318 if (req == NULL) {
7319 goto fail;
7321 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7322 goto fail;
7324 status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
7325 fail:
7326 TALLOC_FREE(frame);
7327 return status;
7330 struct cli_flush_state {
7331 uint16_t vwv[1];
7334 static void cli_flush_done(struct tevent_req *subreq);
7336 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
7337 struct tevent_context *ev,
7338 struct cli_state *cli,
7339 uint16_t fnum)
7341 struct tevent_req *req, *subreq;
7342 struct cli_flush_state *state;
7344 req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
7345 if (req == NULL) {
7346 return NULL;
7348 SSVAL(state->vwv + 0, 0, fnum);
7350 subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
7351 0, NULL);
7352 if (tevent_req_nomem(subreq, req)) {
7353 return tevent_req_post(req, ev);
7355 tevent_req_set_callback(subreq, cli_flush_done, req);
7356 return req;
7359 static void cli_flush_done(struct tevent_req *subreq)
7361 struct tevent_req *req = tevent_req_callback_data(
7362 subreq, struct tevent_req);
7363 NTSTATUS status;
7365 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
7366 TALLOC_FREE(subreq);
7367 if (tevent_req_nterror(req, status)) {
7368 return;
7370 tevent_req_done(req);
7373 NTSTATUS cli_flush_recv(struct tevent_req *req)
7375 return tevent_req_simple_recv_ntstatus(req);
7378 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
7380 TALLOC_CTX *frame = talloc_stackframe();
7381 struct tevent_context *ev;
7382 struct tevent_req *req;
7383 NTSTATUS status = NT_STATUS_NO_MEMORY;
7385 if (smbXcli_conn_has_async_calls(cli->conn)) {
7387 * Can't use sync call while an async call is in flight
7389 status = NT_STATUS_INVALID_PARAMETER;
7390 goto fail;
7392 ev = samba_tevent_context_init(frame);
7393 if (ev == NULL) {
7394 goto fail;
7396 req = cli_flush_send(frame, ev, cli, fnum);
7397 if (req == NULL) {
7398 goto fail;
7400 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7401 goto fail;
7403 status = cli_flush_recv(req);
7404 fail:
7405 TALLOC_FREE(frame);
7406 return status;
7409 struct cli_shadow_copy_data_state {
7410 uint16_t setup[4];
7411 uint8_t *data;
7412 uint32_t num_data;
7413 bool get_names;
7416 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
7418 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
7419 struct tevent_context *ev,
7420 struct cli_state *cli,
7421 uint16_t fnum,
7422 bool get_names)
7424 struct tevent_req *req, *subreq;
7425 struct cli_shadow_copy_data_state *state;
7426 uint32_t ret_size;
7428 req = tevent_req_create(mem_ctx, &state,
7429 struct cli_shadow_copy_data_state);
7430 if (req == NULL) {
7431 return NULL;
7433 state->get_names = get_names;
7434 ret_size = get_names ? CLI_BUFFER_SIZE : 16;
7436 SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
7437 SSVAL(state->setup + 2, 0, fnum);
7438 SCVAL(state->setup + 3, 0, 1); /* isFsctl */
7439 SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
7441 subreq = cli_trans_send(
7442 state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
7443 state->setup, ARRAY_SIZE(state->setup),
7444 ARRAY_SIZE(state->setup),
7445 NULL, 0, 0,
7446 NULL, 0, ret_size);
7447 if (tevent_req_nomem(subreq, req)) {
7448 return tevent_req_post(req, ev);
7450 tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
7451 return req;
7454 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
7456 struct tevent_req *req = tevent_req_callback_data(
7457 subreq, struct tevent_req);
7458 struct cli_shadow_copy_data_state *state = tevent_req_data(
7459 req, struct cli_shadow_copy_data_state);
7460 NTSTATUS status;
7462 status = cli_trans_recv(subreq, state, NULL,
7463 NULL, 0, NULL, /* setup */
7464 NULL, 0, NULL, /* param */
7465 &state->data, 12, &state->num_data);
7466 TALLOC_FREE(subreq);
7467 if (tevent_req_nterror(req, status)) {
7468 return;
7470 tevent_req_done(req);
7473 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
7474 char ***pnames, int *pnum_names)
7476 struct cli_shadow_copy_data_state *state = tevent_req_data(
7477 req, struct cli_shadow_copy_data_state);
7478 char **names = NULL;
7479 uint32_t i, num_names;
7480 uint32_t dlength;
7481 uint8_t *endp = NULL;
7482 NTSTATUS status;
7484 if (tevent_req_is_nterror(req, &status)) {
7485 return status;
7488 if (state->num_data < 16) {
7489 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7492 num_names = IVAL(state->data, 4);
7493 dlength = IVAL(state->data, 8);
7495 if (num_names > 0x7FFFFFFF) {
7496 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7499 if (!state->get_names) {
7500 *pnum_names = (int)num_names;
7501 return NT_STATUS_OK;
7504 if (dlength + 12 < 12) {
7505 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7507 if (dlength + 12 > state->num_data) {
7508 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7510 if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
7511 state->num_data) {
7512 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7515 names = talloc_array(mem_ctx, char *, num_names);
7516 if (names == NULL) {
7517 return NT_STATUS_NO_MEMORY;
7520 endp = state->data + state->num_data;
7522 for (i=0; i<num_names; i++) {
7523 bool ret;
7524 uint8_t *src;
7525 size_t converted_size;
7527 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
7529 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
7530 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7533 ret = convert_string_talloc(
7534 names, CH_UTF16LE, CH_UNIX,
7535 src, 2 * sizeof(SHADOW_COPY_LABEL),
7536 &names[i], &converted_size);
7537 if (!ret) {
7538 TALLOC_FREE(names);
7539 return NT_STATUS_INVALID_NETWORK_RESPONSE;
7542 *pnum_names = (int)num_names;
7543 *pnames = names;
7544 return NT_STATUS_OK;
7547 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
7548 uint16_t fnum, bool get_names,
7549 char ***pnames, int *pnum_names)
7551 TALLOC_CTX *frame = NULL;
7552 struct tevent_context *ev;
7553 struct tevent_req *req;
7554 NTSTATUS status = NT_STATUS_NO_MEMORY;
7556 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
7557 return cli_smb2_shadow_copy_data(mem_ctx,
7558 cli,
7559 fnum,
7560 get_names,
7561 pnames,
7562 pnum_names);
7565 frame = talloc_stackframe();
7567 if (smbXcli_conn_has_async_calls(cli->conn)) {
7569 * Can't use sync call while an async call is in flight
7571 status = NT_STATUS_INVALID_PARAMETER;
7572 goto fail;
7574 ev = samba_tevent_context_init(frame);
7575 if (ev == NULL) {
7576 goto fail;
7578 req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
7579 if (req == NULL) {
7580 goto fail;
7582 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7583 goto fail;
7585 status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
7586 fail:
7587 TALLOC_FREE(frame);
7588 return status;
7591 struct cli_fsctl_state {
7592 DATA_BLOB out;
7595 static void cli_fsctl_smb1_done(struct tevent_req *subreq);
7596 static void cli_fsctl_smb2_done(struct tevent_req *subreq);
7598 struct tevent_req *cli_fsctl_send(
7599 TALLOC_CTX *mem_ctx,
7600 struct tevent_context *ev,
7601 struct cli_state *cli,
7602 uint16_t fnum,
7603 uint32_t ctl_code,
7604 const DATA_BLOB *in,
7605 uint32_t max_out)
7607 struct tevent_req *req = NULL, *subreq = NULL;
7608 struct cli_fsctl_state *state = NULL;
7609 uint16_t *setup = NULL;
7610 uint8_t *data = NULL;
7611 uint32_t num_data = 0;
7613 req = tevent_req_create(mem_ctx, &state, struct cli_fsctl_state);
7614 if (req == NULL) {
7615 return NULL;
7618 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
7619 subreq = cli_smb2_fsctl_send(
7620 state, ev, cli, fnum, ctl_code, in, max_out);
7621 if (tevent_req_nomem(subreq, req)) {
7622 return tevent_req_post(req, ev);
7624 tevent_req_set_callback(subreq, cli_fsctl_smb2_done, req);
7625 return req;
7628 setup = talloc_array(state, uint16_t, 4);
7629 if (tevent_req_nomem(setup, req)) {
7630 return tevent_req_post(req, ev);
7632 SIVAL(setup, 0, ctl_code);
7633 SSVAL(setup, 4, fnum);
7634 SCVAL(setup, 6, 1); /* IsFcntl */
7635 SCVAL(setup, 7, 0); /* IsFlags */
7637 if (in) {
7638 data = in->data;
7639 num_data = in->length;
7642 subreq = cli_trans_send(state,
7644 cli,
7645 0, /* additional_flags2 */
7646 SMBnttrans, /* cmd */
7647 NULL, /* name */
7648 -1, /* fid */
7649 NT_TRANSACT_IOCTL, /* function */
7650 0, /* flags */
7651 setup,
7653 0, /* setup */
7654 NULL,
7656 0, /* param */
7657 data,
7658 num_data,
7659 max_out); /* data */
7661 if (tevent_req_nomem(subreq, req)) {
7662 return tevent_req_post(req, ev);
7664 tevent_req_set_callback(subreq, cli_fsctl_smb1_done, req);
7665 return req;
7668 static void cli_fsctl_smb2_done(struct tevent_req *subreq)
7670 struct tevent_req *req = tevent_req_callback_data(
7671 subreq, struct tevent_req);
7672 struct cli_fsctl_state *state = tevent_req_data(
7673 req, struct cli_fsctl_state);
7674 NTSTATUS status;
7676 status = cli_smb2_fsctl_recv(subreq, state, &state->out);
7677 tevent_req_simple_finish_ntstatus(subreq, status);
7680 static void cli_fsctl_smb1_done(struct tevent_req *subreq)
7682 struct tevent_req *req = tevent_req_callback_data(
7683 subreq, struct tevent_req);
7684 struct cli_fsctl_state *state = tevent_req_data(
7685 req, struct cli_fsctl_state);
7686 uint8_t *out = NULL;
7687 uint32_t out_len;
7688 NTSTATUS status;
7690 status = cli_trans_recv(
7691 subreq, state, NULL,
7692 NULL, 0, NULL, /* rsetup */
7693 NULL, 0, NULL, /* rparam */
7694 &out, 0, &out_len);
7695 TALLOC_FREE(subreq);
7696 if (tevent_req_nterror(req, status)) {
7697 return;
7699 state->out = (DATA_BLOB) {
7700 .data = out, .length = out_len,
7702 tevent_req_done(req);
7705 NTSTATUS cli_fsctl_recv(
7706 struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out)
7708 struct cli_fsctl_state *state = tevent_req_data(
7709 req, struct cli_fsctl_state);
7710 NTSTATUS status;
7712 if (tevent_req_is_nterror(req, &status)) {
7713 return status;
7716 if (out != NULL) {
7717 *out = (DATA_BLOB) {
7718 .data = talloc_move(mem_ctx, &state->out.data),
7719 .length = state->out.length,
7723 return NT_STATUS_OK;