s3: libsmb: Cleanup - remove unused fname_src parameter from cli_dfs_target_check().
[Samba.git] / source3 / libsmb / clifile.c
blob2831d0457f1d8b34fa9bea6ad41c96e8530aa341
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"
32 struct cli_setpathinfo_state {
33 uint16_t setup;
34 uint8_t *param;
37 static void cli_setpathinfo_done(struct tevent_req *subreq);
39 struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
40 struct tevent_context *ev,
41 struct cli_state *cli,
42 uint16_t level,
43 const char *path,
44 uint8_t *data,
45 size_t data_len)
47 struct tevent_req *req, *subreq;
48 struct cli_setpathinfo_state *state;
49 uint16_t additional_flags2 = 0;
51 req = tevent_req_create(mem_ctx, &state,
52 struct cli_setpathinfo_state);
53 if (req == NULL) {
54 return NULL;
57 /* Setup setup word. */
58 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
60 /* Setup param array. */
61 state->param = talloc_zero_array(state, uint8_t, 6);
62 if (tevent_req_nomem(state->param, req)) {
63 return tevent_req_post(req, ev);
65 SSVAL(state->param, 0, level);
67 state->param = trans2_bytes_push_str(
68 state->param, smbXcli_conn_use_unicode(cli->conn), path, strlen(path)+1, NULL);
69 if (tevent_req_nomem(state->param, req)) {
70 return tevent_req_post(req, ev);
73 if (clistr_is_previous_version_path(path, NULL, NULL, NULL) &&
74 !INFO_LEVEL_IS_UNIX(level)) {
75 additional_flags2 = FLAGS2_REPARSE_PATH;
78 subreq = cli_trans_send(
79 state, /* mem ctx. */
80 ev, /* event ctx. */
81 cli, /* cli_state. */
82 additional_flags2, /* additional_flags2 */
83 SMBtrans2, /* cmd. */
84 NULL, /* pipe name. */
85 -1, /* fid. */
86 0, /* function. */
87 0, /* flags. */
88 &state->setup, /* setup. */
89 1, /* num setup uint16_t words. */
90 0, /* max returned setup. */
91 state->param, /* param. */
92 talloc_get_size(state->param), /* num param. */
93 2, /* max returned param. */
94 data, /* data. */
95 data_len, /* num data. */
96 0); /* max returned data. */
98 if (tevent_req_nomem(subreq, req)) {
99 return tevent_req_post(req, ev);
101 tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
102 return req;
105 static void cli_setpathinfo_done(struct tevent_req *subreq)
107 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
108 NULL, 0, NULL, NULL, 0, NULL);
109 tevent_req_simple_finish_ntstatus(subreq, status);
112 NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
114 return tevent_req_simple_recv_ntstatus(req);
117 NTSTATUS cli_setpathinfo(struct cli_state *cli,
118 uint16_t level,
119 const char *path,
120 uint8_t *data,
121 size_t data_len)
123 TALLOC_CTX *frame = talloc_stackframe();
124 struct tevent_context *ev;
125 struct tevent_req *req;
126 NTSTATUS status = NT_STATUS_NO_MEMORY;
128 if (smbXcli_conn_has_async_calls(cli->conn)) {
130 * Can't use sync call while an async call is in flight
132 status = NT_STATUS_INVALID_PARAMETER;
133 goto fail;
135 ev = samba_tevent_context_init(frame);
136 if (ev == NULL) {
137 goto fail;
139 req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
140 if (req == NULL) {
141 goto fail;
143 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
144 goto fail;
146 status = cli_setpathinfo_recv(req);
147 fail:
148 TALLOC_FREE(frame);
149 return status;
152 struct cli_setfileinfo_state {
153 uint16_t setup;
154 uint8_t param[6];
157 static void cli_setfileinfo_done(struct tevent_req *subreq);
159 struct tevent_req *cli_setfileinfo_send(
160 TALLOC_CTX *mem_ctx,
161 struct tevent_context *ev,
162 struct cli_state *cli,
163 uint16_t fnum,
164 uint16_t level,
165 uint8_t *data,
166 size_t data_len)
168 struct tevent_req *req = NULL, *subreq = NULL;
169 struct cli_setfileinfo_state *state = NULL;
171 req = tevent_req_create(mem_ctx, &state, struct cli_setfileinfo_state);
172 if (req == NULL) {
173 return NULL;
175 PUSH_LE_U16(&state->setup, 0, TRANSACT2_SETFILEINFO);
177 PUSH_LE_U16(state->param, 0, fnum);
178 PUSH_LE_U16(state->param, 2, level);
180 subreq = cli_trans_send(state, /* mem ctx. */
181 ev, /* event ctx. */
182 cli, /* cli_state. */
183 0, /* additional_flags2 */
184 SMBtrans2, /* cmd. */
185 NULL, /* pipe name. */
186 -1, /* fid. */
187 0, /* function. */
188 0, /* flags. */
189 &state->setup, /* setup. */
190 1, /* num setup uint16_t words. */
191 0, /* max returned setup. */
192 state->param, /* param. */
193 6, /* num param. */
194 2, /* max returned param. */
195 data, /* data. */
196 data_len, /* num data. */
197 0); /* max returned data. */
199 if (tevent_req_nomem(subreq, req)) {
200 return tevent_req_post(req, ev);
202 tevent_req_set_callback(subreq, cli_setfileinfo_done, req);
203 return req;
206 static void cli_setfileinfo_done(struct tevent_req *subreq)
208 NTSTATUS status = cli_trans_recv(
209 subreq, /* req */
210 NULL, /* mem_ctx */
211 NULL, /* recv_flags2 */
212 NULL, /* setup */
213 0, /* min_setup */
214 NULL, /* num_setup */
215 NULL, /* param */
216 0, /* min_param */
217 NULL, /* num_param */
218 NULL, /* data */
219 0, /* min_data */
220 NULL); /* num_data */
221 tevent_req_simple_finish_ntstatus(subreq, status);
224 NTSTATUS cli_setfileinfo_recv(struct tevent_req *req)
226 return tevent_req_simple_recv_ntstatus(req);
229 /****************************************************************************
230 Hard/Symlink a file (UNIX extensions).
231 Creates new name (sym)linked to link_target.
232 ****************************************************************************/
234 struct cli_posix_link_internal_state {
235 uint8_t *data;
238 static void cli_posix_link_internal_done(struct tevent_req *subreq);
240 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
241 struct tevent_context *ev,
242 struct cli_state *cli,
243 uint16_t level,
244 const char *link_target,
245 const char *newname)
247 struct tevent_req *req = NULL, *subreq = NULL;
248 struct cli_posix_link_internal_state *state = NULL;
250 req = tevent_req_create(mem_ctx, &state,
251 struct cli_posix_link_internal_state);
252 if (req == NULL) {
253 return NULL;
256 /* Setup data array. */
257 state->data = talloc_array(state, uint8_t, 0);
258 if (tevent_req_nomem(state->data, req)) {
259 return tevent_req_post(req, ev);
261 state->data = trans2_bytes_push_str(
262 state->data, smbXcli_conn_use_unicode(cli->conn),
263 link_target, strlen(link_target)+1, NULL);
265 subreq = cli_setpathinfo_send(
266 state, ev, cli, level, newname,
267 state->data, talloc_get_size(state->data));
268 if (tevent_req_nomem(subreq, req)) {
269 return tevent_req_post(req, ev);
271 tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
272 return req;
275 static void cli_posix_link_internal_done(struct tevent_req *subreq)
277 NTSTATUS status = cli_setpathinfo_recv(subreq);
278 tevent_req_simple_finish_ntstatus(subreq, status);
281 static NTSTATUS cli_posix_link_internal_recv(struct tevent_req *req)
283 return tevent_req_simple_recv_ntstatus(req);
286 /****************************************************************************
287 Symlink a file (UNIX extensions).
288 ****************************************************************************/
290 struct cli_posix_symlink_state {
291 uint8_t dummy;
294 static void cli_posix_symlink_done(struct tevent_req *subreq);
296 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
297 struct tevent_context *ev,
298 struct cli_state *cli,
299 const char *link_target,
300 const char *newname)
302 struct tevent_req *req = NULL, *subreq = NULL;
303 struct cli_posix_symlink_state *state = NULL;
305 req = tevent_req_create(
306 mem_ctx, &state, struct cli_posix_symlink_state);
307 if (req == NULL) {
308 return NULL;
311 subreq = cli_posix_link_internal_send(
312 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, link_target, newname);
313 if (tevent_req_nomem(subreq, req)) {
314 return tevent_req_post(req, ev);
316 tevent_req_set_callback(subreq, cli_posix_symlink_done, req);
317 return req;
320 static void cli_posix_symlink_done(struct tevent_req *subreq)
322 NTSTATUS status = cli_posix_link_internal_recv(subreq);
323 tevent_req_simple_finish_ntstatus(subreq, status);
326 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
328 return tevent_req_simple_recv_ntstatus(req);
331 NTSTATUS cli_posix_symlink(struct cli_state *cli,
332 const char *link_target,
333 const char *newname)
335 TALLOC_CTX *frame = talloc_stackframe();
336 struct tevent_context *ev = NULL;
337 struct tevent_req *req = NULL;
338 NTSTATUS status = NT_STATUS_OK;
340 if (smbXcli_conn_has_async_calls(cli->conn)) {
342 * Can't use sync call while an async call is in flight
344 status = NT_STATUS_INVALID_PARAMETER;
345 goto fail;
348 ev = samba_tevent_context_init(frame);
349 if (ev == NULL) {
350 status = NT_STATUS_NO_MEMORY;
351 goto fail;
354 req = cli_posix_symlink_send(frame,
356 cli,
357 link_target,
358 newname);
359 if (req == NULL) {
360 status = NT_STATUS_NO_MEMORY;
361 goto fail;
364 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
365 goto fail;
368 status = cli_posix_symlink_recv(req);
370 fail:
371 TALLOC_FREE(frame);
372 return status;
375 /****************************************************************************
376 Read a POSIX symlink.
377 ****************************************************************************/
379 struct cli_posix_readlink_state {
380 struct cli_state *cli;
381 char *converted;
384 static void cli_posix_readlink_done(struct tevent_req *subreq);
386 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
387 struct tevent_context *ev,
388 struct cli_state *cli,
389 const char *fname)
391 struct tevent_req *req = NULL, *subreq = NULL;
392 struct cli_posix_readlink_state *state = NULL;
394 req = tevent_req_create(
395 mem_ctx, &state, struct cli_posix_readlink_state);
396 if (req == NULL) {
397 return NULL;
399 state->cli = cli;
401 subreq = cli_qpathinfo_send(
402 state,
404 cli,
405 fname,
406 SMB_QUERY_FILE_UNIX_LINK,
408 UINT16_MAX);
409 if (tevent_req_nomem(subreq, req)) {
410 return tevent_req_post(req, ev);
412 tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
413 return req;
416 static void cli_posix_readlink_done(struct tevent_req *subreq)
418 struct tevent_req *req = tevent_req_callback_data(
419 subreq, struct tevent_req);
420 struct cli_posix_readlink_state *state = tevent_req_data(
421 req, struct cli_posix_readlink_state);
422 NTSTATUS status;
423 uint8_t *data = NULL;
424 uint32_t num_data = 0;
425 charset_t charset;
426 size_t converted_size;
427 bool ok;
429 status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
430 TALLOC_FREE(subreq);
431 if (tevent_req_nterror(req, status)) {
432 return;
435 * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
437 if (data == NULL || data[num_data-1] != '\0') {
438 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
439 return;
442 charset = smbXcli_conn_use_unicode(state->cli->conn) ?
443 CH_UTF16LE : CH_DOS;
445 /* The returned data is a pushed string, not raw data. */
446 ok = convert_string_talloc(
447 state,
448 charset,
449 CH_UNIX,
450 data,
451 num_data,
452 &state->converted,
453 &converted_size);
454 if (!ok) {
455 tevent_req_oom(req);
456 return;
458 tevent_req_done(req);
461 NTSTATUS cli_posix_readlink_recv(
462 struct tevent_req *req, TALLOC_CTX *mem_ctx, char **target)
464 struct cli_posix_readlink_state *state = tevent_req_data(
465 req, struct cli_posix_readlink_state);
466 NTSTATUS status;
468 if (tevent_req_is_nterror(req, &status)) {
469 return status;
471 *target = talloc_move(mem_ctx, &state->converted);
472 tevent_req_received(req);
473 return NT_STATUS_OK;
476 NTSTATUS cli_posix_readlink(
477 struct cli_state *cli,
478 const char *fname,
479 TALLOC_CTX *mem_ctx,
480 char **target)
482 TALLOC_CTX *frame = talloc_stackframe();
483 struct tevent_context *ev = NULL;
484 struct tevent_req *req = NULL;
485 NTSTATUS status = NT_STATUS_OK;
487 if (smbXcli_conn_has_async_calls(cli->conn)) {
489 * Can't use sync call while an async call is in flight
491 status = NT_STATUS_INVALID_PARAMETER;
492 goto fail;
495 ev = samba_tevent_context_init(frame);
496 if (ev == NULL) {
497 status = NT_STATUS_NO_MEMORY;
498 goto fail;
501 req = cli_posix_readlink_send(frame, ev, cli, fname);
502 if (req == NULL) {
503 status = NT_STATUS_NO_MEMORY;
504 goto fail;
507 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
508 goto fail;
511 status = cli_posix_readlink_recv(req, mem_ctx, target);
513 fail:
514 TALLOC_FREE(frame);
515 return status;
518 /****************************************************************************
519 Hard link a file (UNIX extensions).
520 ****************************************************************************/
522 struct cli_posix_hardlink_state {
523 uint8_t dummy;
526 static void cli_posix_hardlink_done(struct tevent_req *subreq);
528 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
529 struct tevent_context *ev,
530 struct cli_state *cli,
531 const char *oldname,
532 const char *newname)
534 struct tevent_req *req = NULL, *subreq = NULL;
535 struct cli_posix_hardlink_state *state = NULL;
537 req = tevent_req_create(
538 mem_ctx, &state, struct cli_posix_hardlink_state);
539 if (req == NULL) {
540 return NULL;
543 subreq = cli_posix_link_internal_send(
544 state, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
545 if (tevent_req_nomem(subreq, req)) {
546 return tevent_req_post(req, ev);
548 tevent_req_set_callback(subreq, cli_posix_hardlink_done, req);
549 return req;
552 static void cli_posix_hardlink_done(struct tevent_req *subreq)
554 NTSTATUS status = cli_posix_link_internal_recv(subreq);
555 tevent_req_simple_finish_ntstatus(subreq, status);
558 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
560 return tevent_req_simple_recv_ntstatus(req);
563 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
564 const char *oldname,
565 const char *newname)
567 TALLOC_CTX *frame = talloc_stackframe();
568 struct tevent_context *ev = NULL;
569 struct tevent_req *req = NULL;
570 NTSTATUS status = NT_STATUS_OK;
572 if (smbXcli_conn_has_async_calls(cli->conn)) {
574 * Can't use sync call while an async call is in flight
576 status = NT_STATUS_INVALID_PARAMETER;
577 goto fail;
580 ev = samba_tevent_context_init(frame);
581 if (ev == NULL) {
582 status = NT_STATUS_NO_MEMORY;
583 goto fail;
586 req = cli_posix_hardlink_send(frame,
588 cli,
589 oldname,
590 newname);
591 if (req == NULL) {
592 status = NT_STATUS_NO_MEMORY;
593 goto fail;
596 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
597 goto fail;
600 status = cli_posix_hardlink_recv(req);
602 fail:
603 TALLOC_FREE(frame);
604 return status;
607 /****************************************************************************
608 Do a POSIX getacl - pathname based ACL get (UNIX extensions).
609 ****************************************************************************/
611 struct getacl_state {
612 uint32_t num_data;
613 uint8_t *data;
616 static void cli_posix_getacl_done(struct tevent_req *subreq);
618 struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
619 struct tevent_context *ev,
620 struct cli_state *cli,
621 const char *fname)
623 struct tevent_req *req = NULL, *subreq = NULL;
624 struct getacl_state *state = NULL;
626 req = tevent_req_create(mem_ctx, &state, struct getacl_state);
627 if (req == NULL) {
628 return NULL;
630 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
631 0, CLI_BUFFER_SIZE);
632 if (tevent_req_nomem(subreq, req)) {
633 return tevent_req_post(req, ev);
635 tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
636 return req;
639 static void cli_posix_getacl_done(struct tevent_req *subreq)
641 struct tevent_req *req = tevent_req_callback_data(
642 subreq, struct tevent_req);
643 struct getacl_state *state = tevent_req_data(
644 req, struct getacl_state);
645 NTSTATUS status;
647 status = cli_qpathinfo_recv(subreq, state, &state->data,
648 &state->num_data);
649 TALLOC_FREE(subreq);
650 if (tevent_req_nterror(req, status)) {
651 return;
653 tevent_req_done(req);
656 NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
657 TALLOC_CTX *mem_ctx,
658 size_t *prb_size,
659 char **retbuf)
661 struct getacl_state *state = tevent_req_data(req, struct getacl_state);
662 NTSTATUS status;
664 if (tevent_req_is_nterror(req, &status)) {
665 return status;
667 *prb_size = (size_t)state->num_data;
668 *retbuf = (char *)talloc_move(mem_ctx, &state->data);
669 return NT_STATUS_OK;
672 NTSTATUS cli_posix_getacl(struct cli_state *cli,
673 const char *fname,
674 TALLOC_CTX *mem_ctx,
675 size_t *prb_size,
676 char **retbuf)
678 TALLOC_CTX *frame = talloc_stackframe();
679 struct tevent_context *ev = NULL;
680 struct tevent_req *req = NULL;
681 NTSTATUS status = NT_STATUS_OK;
683 if (smbXcli_conn_has_async_calls(cli->conn)) {
685 * Can't use sync call while an async call is in flight
687 status = NT_STATUS_INVALID_PARAMETER;
688 goto fail;
691 ev = samba_tevent_context_init(frame);
692 if (ev == NULL) {
693 status = NT_STATUS_NO_MEMORY;
694 goto fail;
697 req = cli_posix_getacl_send(frame,
699 cli,
700 fname);
701 if (req == NULL) {
702 status = NT_STATUS_NO_MEMORY;
703 goto fail;
706 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
707 goto fail;
710 status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
712 fail:
713 TALLOC_FREE(frame);
714 return status;
717 /****************************************************************************
718 Do a POSIX setacl - pathname based ACL set (UNIX extensions).
719 ****************************************************************************/
721 struct setacl_state {
722 uint8_t *data;
725 static void cli_posix_setacl_done(struct tevent_req *subreq);
727 struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
728 struct tevent_context *ev,
729 struct cli_state *cli,
730 const char *fname,
731 const void *data,
732 size_t num_data)
734 struct tevent_req *req = NULL, *subreq = NULL;
735 struct setacl_state *state = NULL;
737 req = tevent_req_create(mem_ctx, &state, struct setacl_state);
738 if (req == NULL) {
739 return NULL;
741 state->data = talloc_memdup(state, data, num_data);
742 if (tevent_req_nomem(state->data, req)) {
743 return tevent_req_post(req, ev);
746 subreq = cli_setpathinfo_send(state,
748 cli,
749 SMB_SET_POSIX_ACL,
750 fname,
751 state->data,
752 num_data);
753 if (tevent_req_nomem(subreq, req)) {
754 return tevent_req_post(req, ev);
756 tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
757 return req;
760 static void cli_posix_setacl_done(struct tevent_req *subreq)
762 NTSTATUS status = cli_setpathinfo_recv(subreq);
763 tevent_req_simple_finish_ntstatus(subreq, status);
766 NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
768 return tevent_req_simple_recv_ntstatus(req);
771 NTSTATUS cli_posix_setacl(struct cli_state *cli,
772 const char *fname,
773 const void *acl_buf,
774 size_t acl_buf_size)
776 TALLOC_CTX *frame = talloc_stackframe();
777 struct tevent_context *ev = NULL;
778 struct tevent_req *req = NULL;
779 NTSTATUS status = NT_STATUS_OK;
781 if (smbXcli_conn_has_async_calls(cli->conn)) {
783 * Can't use sync call while an async call is in flight
785 status = NT_STATUS_INVALID_PARAMETER;
786 goto fail;
789 ev = samba_tevent_context_init(frame);
790 if (ev == NULL) {
791 status = NT_STATUS_NO_MEMORY;
792 goto fail;
795 req = cli_posix_setacl_send(frame,
797 cli,
798 fname,
799 acl_buf,
800 acl_buf_size);
801 if (req == NULL) {
802 status = NT_STATUS_NO_MEMORY;
803 goto fail;
806 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
807 goto fail;
810 status = cli_posix_setacl_recv(req);
812 fail:
813 TALLOC_FREE(frame);
814 return status;
817 /****************************************************************************
818 Stat a file (UNIX extensions).
819 ****************************************************************************/
821 struct stat_state {
822 SMB_STRUCT_STAT *sbuf;
825 static void cli_posix_stat_done(struct tevent_req *subreq);
827 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
828 struct tevent_context *ev,
829 struct cli_state *cli,
830 const char *fname,
831 SMB_STRUCT_STAT *sbuf)
833 struct tevent_req *req = NULL, *subreq = NULL;
834 struct stat_state *state = NULL;
836 req = tevent_req_create(mem_ctx, &state, struct stat_state);
837 if (req == NULL) {
838 return NULL;
840 state->sbuf = sbuf;
842 subreq = cli_qpathinfo_send(state, ev, cli, fname,
843 SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
844 if (tevent_req_nomem(subreq, req)) {
845 return tevent_req_post(req, ev);
847 tevent_req_set_callback(subreq, cli_posix_stat_done, req);
848 return req;
851 static void cli_posix_stat_done(struct tevent_req *subreq)
853 struct tevent_req *req = tevent_req_callback_data(
854 subreq, struct tevent_req);
855 struct stat_state *state = tevent_req_data(req, struct stat_state);
856 SMB_STRUCT_STAT *sbuf = state->sbuf;
857 uint8_t *data;
858 uint32_t num_data = 0;
859 NTSTATUS status;
861 status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
862 TALLOC_FREE(subreq);
863 if (tevent_req_nterror(req, status)) {
864 return;
867 if (num_data != 100) {
869 * Paranoia, cli_qpathinfo should have guaranteed
870 * this, but you never know...
872 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
873 return;
876 *sbuf = (SMB_STRUCT_STAT) { 0 };
878 /* total size, in bytes */
879 sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(data, 0);
881 /* number of blocks allocated */
882 sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(data,8);
883 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
884 sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
885 #else
886 /* assume 512 byte blocks */
887 sbuf->st_ex_blocks /= 512;
888 #endif
889 /* time of last change */
890 sbuf->st_ex_ctime = interpret_long_date((char *)(data + 16));
892 /* time of last access */
893 sbuf->st_ex_atime = interpret_long_date((char *)(data + 24));
895 /* time of last modification */
896 sbuf->st_ex_mtime = interpret_long_date((char *)(data + 32));
898 sbuf->st_ex_uid = (uid_t) IVAL(data, 40); /* user ID of owner */
899 sbuf->st_ex_gid = (gid_t) IVAL(data, 48); /* group ID of owner */
900 sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(data, 56));
902 #if defined(HAVE_MAKEDEV)
904 uint32_t dev_major = IVAL(data,60);
905 uint32_t dev_minor = IVAL(data,68);
906 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
908 #endif
909 /* inode */
910 sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(data, 76);
912 /* protection */
913 sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(data, 84));
915 /* number of hard links */
916 sbuf->st_ex_nlink = BIG_UINT(data, 92);
918 tevent_req_done(req);
921 NTSTATUS cli_posix_stat_recv(struct tevent_req *req)
923 return tevent_req_simple_recv_ntstatus(req);
926 NTSTATUS cli_posix_stat(struct cli_state *cli,
927 const char *fname,
928 SMB_STRUCT_STAT *sbuf)
930 TALLOC_CTX *frame = talloc_stackframe();
931 struct tevent_context *ev = NULL;
932 struct tevent_req *req = NULL;
933 NTSTATUS status = NT_STATUS_OK;
935 if (smbXcli_conn_has_async_calls(cli->conn)) {
937 * Can't use sync call while an async call is in flight
939 status = NT_STATUS_INVALID_PARAMETER;
940 goto fail;
943 ev = samba_tevent_context_init(frame);
944 if (ev == NULL) {
945 status = NT_STATUS_NO_MEMORY;
946 goto fail;
949 req = cli_posix_stat_send(frame, ev, cli, fname, sbuf);
950 if (req == NULL) {
951 status = NT_STATUS_NO_MEMORY;
952 goto fail;
955 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
956 goto fail;
959 status = cli_posix_stat_recv(req);
961 fail:
962 TALLOC_FREE(frame);
963 return status;
966 /****************************************************************************
967 Chmod or chown a file internal (UNIX extensions).
968 ****************************************************************************/
970 struct cli_posix_chown_chmod_internal_state {
971 uint8_t data[100];
974 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
976 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
977 struct tevent_context *ev,
978 struct cli_state *cli,
979 const char *fname,
980 uint32_t mode,
981 uint32_t uid,
982 uint32_t gid)
984 struct tevent_req *req = NULL, *subreq = NULL;
985 struct cli_posix_chown_chmod_internal_state *state = NULL;
987 req = tevent_req_create(mem_ctx, &state,
988 struct cli_posix_chown_chmod_internal_state);
989 if (req == NULL) {
990 return NULL;
993 memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
994 memset(&state->data[40], '\0', 60);
995 SIVAL(state->data,40,uid);
996 SIVAL(state->data,48,gid);
997 SIVAL(state->data,84,mode);
999 subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
1000 fname, state->data, sizeof(state->data));
1001 if (tevent_req_nomem(subreq, req)) {
1002 return tevent_req_post(req, ev);
1004 tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
1005 req);
1006 return req;
1009 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
1011 NTSTATUS status = cli_setpathinfo_recv(subreq);
1012 tevent_req_simple_finish_ntstatus(subreq, status);
1015 static NTSTATUS cli_posix_chown_chmod_internal_recv(struct tevent_req *req)
1017 return tevent_req_simple_recv_ntstatus(req);
1020 /****************************************************************************
1021 chmod a file (UNIX extensions).
1022 ****************************************************************************/
1024 struct cli_posix_chmod_state {
1025 uint8_t dummy;
1028 static void cli_posix_chmod_done(struct tevent_req *subreq);
1030 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
1031 struct tevent_context *ev,
1032 struct cli_state *cli,
1033 const char *fname,
1034 mode_t mode)
1036 struct tevent_req *req = NULL, *subreq = NULL;
1037 struct cli_posix_chmod_state *state = NULL;
1039 req = tevent_req_create(mem_ctx, &state, struct cli_posix_chmod_state);
1040 if (req == NULL) {
1041 return NULL;
1044 subreq = cli_posix_chown_chmod_internal_send(
1045 state,
1047 cli,
1048 fname,
1049 unix_perms_to_wire(mode),
1050 SMB_UID_NO_CHANGE,
1051 SMB_GID_NO_CHANGE);
1052 if (tevent_req_nomem(subreq, req)) {
1053 return tevent_req_post(req, ev);
1055 tevent_req_set_callback(subreq, cli_posix_chmod_done, req);
1056 return req;
1059 static void cli_posix_chmod_done(struct tevent_req *subreq)
1061 NTSTATUS status = cli_posix_chown_chmod_internal_recv(subreq);
1062 tevent_req_simple_finish_ntstatus(subreq, status);
1065 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
1067 return tevent_req_simple_recv_ntstatus(req);
1070 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
1072 TALLOC_CTX *frame = talloc_stackframe();
1073 struct tevent_context *ev = NULL;
1074 struct tevent_req *req = NULL;
1075 NTSTATUS status = NT_STATUS_OK;
1077 if (smbXcli_conn_has_async_calls(cli->conn)) {
1079 * Can't use sync call while an async call is in flight
1081 status = NT_STATUS_INVALID_PARAMETER;
1082 goto fail;
1085 ev = samba_tevent_context_init(frame);
1086 if (ev == NULL) {
1087 status = NT_STATUS_NO_MEMORY;
1088 goto fail;
1091 req = cli_posix_chmod_send(frame,
1093 cli,
1094 fname,
1095 mode);
1096 if (req == NULL) {
1097 status = NT_STATUS_NO_MEMORY;
1098 goto fail;
1101 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1102 goto fail;
1105 status = cli_posix_chmod_recv(req);
1107 fail:
1108 TALLOC_FREE(frame);
1109 return status;
1112 /****************************************************************************
1113 chown a file (UNIX extensions).
1114 ****************************************************************************/
1116 struct cli_posix_chown_state {
1117 uint8_t dummy;
1120 static void cli_posix_chown_done(struct tevent_req *subreq);
1122 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1123 struct tevent_context *ev,
1124 struct cli_state *cli,
1125 const char *fname,
1126 uid_t uid,
1127 gid_t gid)
1129 struct tevent_req *req = NULL, *subreq = NULL;
1130 struct cli_posix_chown_state *state = NULL;
1132 req = tevent_req_create(
1133 mem_ctx, &state, struct cli_posix_chown_state);
1134 if (req == NULL) {
1135 return NULL;
1138 subreq = cli_posix_chown_chmod_internal_send(
1139 state,
1141 cli,
1142 fname,
1143 SMB_MODE_NO_CHANGE,
1144 (uint32_t)uid,
1145 (uint32_t)gid);
1146 if (tevent_req_nomem(subreq, req)) {
1147 return tevent_req_post(req, ev);
1149 tevent_req_set_callback(subreq, cli_posix_chown_done, req);
1150 return req;
1153 static void cli_posix_chown_done(struct tevent_req *subreq)
1155 NTSTATUS status = cli_posix_chown_chmod_internal_recv(subreq);
1156 tevent_req_simple_finish_ntstatus(subreq, status);
1159 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1161 return tevent_req_simple_recv_ntstatus(req);
1164 NTSTATUS cli_posix_chown(struct cli_state *cli,
1165 const char *fname,
1166 uid_t uid,
1167 gid_t gid)
1169 TALLOC_CTX *frame = talloc_stackframe();
1170 struct tevent_context *ev = NULL;
1171 struct tevent_req *req = NULL;
1172 NTSTATUS status = NT_STATUS_OK;
1174 if (smbXcli_conn_has_async_calls(cli->conn)) {
1176 * Can't use sync call while an async call is in flight
1178 status = NT_STATUS_INVALID_PARAMETER;
1179 goto fail;
1182 ev = samba_tevent_context_init(frame);
1183 if (ev == NULL) {
1184 status = NT_STATUS_NO_MEMORY;
1185 goto fail;
1188 req = cli_posix_chown_send(frame,
1190 cli,
1191 fname,
1192 uid,
1193 gid);
1194 if (req == NULL) {
1195 status = NT_STATUS_NO_MEMORY;
1196 goto fail;
1199 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1200 goto fail;
1203 status = cli_posix_chown_recv(req);
1205 fail:
1206 TALLOC_FREE(frame);
1207 return status;
1210 /****************************************************************************
1211 Rename a file.
1212 ****************************************************************************/
1214 struct cli_smb1_rename_state {
1215 uint8_t *data;
1218 static void cli_smb1_rename_done(struct tevent_req *subreq);
1220 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1221 struct tevent_context *ev,
1222 struct cli_state *cli,
1223 const char *fname_src,
1224 const char *fname_dst,
1225 bool replace)
1227 NTSTATUS status;
1228 struct tevent_req *req = NULL, *subreq = NULL;
1229 struct cli_smb1_rename_state *state = NULL;
1230 smb_ucs2_t *converted_str = NULL;
1231 size_t converted_size_bytes = 0;
1233 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
1234 if (req == NULL) {
1235 return NULL;
1239 * Strip a MSDFS path from fname_dst if we were given one.
1241 status = cli_dfs_target_check(state,
1242 cli,
1243 fname_dst,
1244 &fname_dst);
1245 if (!NT_STATUS_IS_OK(status)) {
1246 goto fail;
1249 if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
1250 &converted_size_bytes)) {
1251 status = NT_STATUS_INVALID_PARAMETER;
1252 goto fail;
1255 /* W2K8 insists the dest name is not null
1256 terminated. Remove the last 2 zero bytes
1257 and reduce the name length. */
1259 if (converted_size_bytes < 2) {
1260 status = NT_STATUS_INVALID_PARAMETER;
1261 goto fail;
1263 converted_size_bytes -= 2;
1265 state->data =
1266 talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
1267 if (state->data == NULL) {
1268 status = NT_STATUS_NO_MEMORY;
1269 goto fail;
1272 if (replace) {
1273 SCVAL(state->data, 0, 1);
1276 SIVAL(state->data, 8, converted_size_bytes);
1277 memcpy(state->data + 12, converted_str, converted_size_bytes);
1279 TALLOC_FREE(converted_str);
1281 subreq = cli_setpathinfo_send(
1282 state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
1283 talloc_get_size(state->data));
1284 if (tevent_req_nomem(subreq, req)) {
1285 status = NT_STATUS_NO_MEMORY;
1286 goto fail;
1288 tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
1289 return req;
1291 fail:
1292 TALLOC_FREE(converted_str);
1293 tevent_req_nterror(req, status);
1294 return tevent_req_post(req, ev);
1297 static void cli_smb1_rename_done(struct tevent_req *subreq)
1299 NTSTATUS status = cli_setpathinfo_recv(subreq);
1300 tevent_req_simple_finish_ntstatus(subreq, status);
1303 static NTSTATUS cli_smb1_rename_recv(struct tevent_req *req)
1305 return tevent_req_simple_recv_ntstatus(req);
1308 static void cli_cifs_rename_done(struct tevent_req *subreq);
1310 struct cli_cifs_rename_state {
1311 uint16_t vwv[1];
1314 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1315 struct tevent_context *ev,
1316 struct cli_state *cli,
1317 const char *fname_src,
1318 const char *fname_dst,
1319 bool replace)
1321 struct tevent_req *req = NULL, *subreq = NULL;
1322 struct cli_cifs_rename_state *state = NULL;
1323 uint8_t additional_flags = 0;
1324 uint16_t additional_flags2 = 0;
1325 uint8_t *bytes = NULL;
1326 NTSTATUS status;
1328 req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
1329 if (req == NULL) {
1330 return NULL;
1333 if (replace) {
1335 * CIFS doesn't support replace
1337 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1338 return tevent_req_post(req, ev);
1342 * Strip a MSDFS path from fname_dst if we were given one.
1344 status = cli_dfs_target_check(state,
1345 cli,
1346 fname_dst,
1347 &fname_dst);
1348 if (tevent_req_nterror(req, status)) {
1349 return tevent_req_post(req, ev);
1352 SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1354 bytes = talloc_array(state, uint8_t, 1);
1355 if (tevent_req_nomem(bytes, req)) {
1356 return tevent_req_post(req, ev);
1358 bytes[0] = 4;
1359 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1360 strlen(fname_src)+1, NULL);
1361 if (tevent_req_nomem(bytes, req)) {
1362 return tevent_req_post(req, ev);
1365 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1366 additional_flags2 = FLAGS2_REPARSE_PATH;
1369 bytes = talloc_realloc(state, bytes, uint8_t,
1370 talloc_get_size(bytes)+1);
1371 if (tevent_req_nomem(bytes, req)) {
1372 return tevent_req_post(req, ev);
1375 bytes[talloc_get_size(bytes)-1] = 4;
1376 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1377 strlen(fname_dst)+1, NULL);
1378 if (tevent_req_nomem(bytes, req)) {
1379 return tevent_req_post(req, ev);
1382 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1383 additional_flags2,
1384 1, state->vwv, talloc_get_size(bytes), bytes);
1385 if (tevent_req_nomem(subreq, req)) {
1386 return tevent_req_post(req, ev);
1388 tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
1389 return req;
1392 static void cli_cifs_rename_done(struct tevent_req *subreq)
1394 NTSTATUS status = cli_smb_recv(
1395 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1396 tevent_req_simple_finish_ntstatus(subreq, status);
1399 static NTSTATUS cli_cifs_rename_recv(struct tevent_req *req)
1401 return tevent_req_simple_recv_ntstatus(req);
1404 struct cli_rename_state {
1405 uint8_t dummy;
1408 static void cli_rename_done1(struct tevent_req *subreq);
1409 static void cli_rename_done_cifs(struct tevent_req *subreq);
1410 static void cli_rename_done2(struct tevent_req *subreq);
1412 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1413 struct tevent_context *ev,
1414 struct cli_state *cli,
1415 const char *fname_src,
1416 const char *fname_dst,
1417 bool replace)
1419 struct tevent_req *req = NULL, *subreq = NULL;
1420 struct cli_rename_state *state = NULL;
1422 req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1423 if (req == NULL) {
1424 return NULL;
1427 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1428 subreq = cli_smb2_rename_send(
1429 state, ev, cli, fname_src, fname_dst, replace);
1430 if (tevent_req_nomem(subreq, req)) {
1431 return tevent_req_post(req, ev);
1433 tevent_req_set_callback(subreq, cli_rename_done2, req);
1434 return req;
1437 if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
1438 subreq = cli_smb1_rename_send(
1439 state, ev, cli, fname_src, fname_dst, replace);
1440 if (tevent_req_nomem(subreq, req)) {
1441 return tevent_req_post(req, ev);
1443 tevent_req_set_callback(subreq, cli_rename_done1, req);
1444 return req;
1447 subreq = cli_cifs_rename_send(
1448 state, ev, cli, fname_src,fname_dst, replace);
1449 if (tevent_req_nomem(subreq, req)) {
1450 return tevent_req_post(req, ev);
1452 tevent_req_set_callback(subreq, cli_rename_done_cifs, req);
1453 return req;
1456 static void cli_rename_done1(struct tevent_req *subreq)
1458 NTSTATUS status = cli_smb1_rename_recv(subreq);
1459 tevent_req_simple_finish_ntstatus(subreq, status);
1462 static void cli_rename_done_cifs(struct tevent_req *subreq)
1464 NTSTATUS status = cli_cifs_rename_recv(subreq);
1465 tevent_req_simple_finish_ntstatus(subreq, status);
1468 static void cli_rename_done2(struct tevent_req *subreq)
1470 NTSTATUS status = cli_smb2_rename_recv(subreq);
1471 tevent_req_simple_finish_ntstatus(subreq, status);
1474 NTSTATUS cli_rename_recv(struct tevent_req *req)
1476 return tevent_req_simple_recv_ntstatus(req);
1479 NTSTATUS cli_rename(struct cli_state *cli,
1480 const char *fname_src,
1481 const char *fname_dst,
1482 bool replace)
1484 TALLOC_CTX *frame = NULL;
1485 struct tevent_context *ev;
1486 struct tevent_req *req;
1487 NTSTATUS status = NT_STATUS_OK;
1489 frame = talloc_stackframe();
1491 if (smbXcli_conn_has_async_calls(cli->conn)) {
1493 * Can't use sync call while an async call is in flight
1495 status = NT_STATUS_INVALID_PARAMETER;
1496 goto fail;
1499 ev = samba_tevent_context_init(frame);
1500 if (ev == NULL) {
1501 status = NT_STATUS_NO_MEMORY;
1502 goto fail;
1505 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
1506 if (req == NULL) {
1507 status = NT_STATUS_NO_MEMORY;
1508 goto fail;
1511 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1512 goto fail;
1515 status = cli_rename_recv(req);
1516 cli->raw_status = status; /* cli_smb2_rename_recv doesn't set this */
1518 fail:
1519 TALLOC_FREE(frame);
1520 return status;
1523 /****************************************************************************
1524 NT Rename a file.
1525 ****************************************************************************/
1527 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1529 struct cli_ntrename_internal_state {
1530 uint16_t vwv[4];
1533 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1534 struct tevent_context *ev,
1535 struct cli_state *cli,
1536 const char *fname_src,
1537 const char *fname_dst,
1538 uint16_t rename_flag)
1540 struct tevent_req *req = NULL, *subreq = NULL;
1541 struct cli_ntrename_internal_state *state = NULL;
1542 uint8_t additional_flags = 0;
1543 uint16_t additional_flags2 = 0;
1544 uint8_t *bytes = NULL;
1545 NTSTATUS status;
1547 req = tevent_req_create(mem_ctx, &state,
1548 struct cli_ntrename_internal_state);
1549 if (req == NULL) {
1550 return NULL;
1554 * Strip a MSDFS path from fname_dst if we were given one.
1556 status = cli_dfs_target_check(state,
1557 cli,
1558 fname_dst,
1559 &fname_dst);
1560 if (tevent_req_nterror(req, status)) {
1561 return tevent_req_post(req, ev);
1564 SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1565 SSVAL(state->vwv+1, 0, rename_flag);
1567 bytes = talloc_array(state, uint8_t, 1);
1568 if (tevent_req_nomem(bytes, req)) {
1569 return tevent_req_post(req, ev);
1571 bytes[0] = 4;
1572 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1573 strlen(fname_src)+1, NULL);
1574 if (tevent_req_nomem(bytes, req)) {
1575 return tevent_req_post(req, ev);
1578 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1579 additional_flags2 = FLAGS2_REPARSE_PATH;
1582 bytes = talloc_realloc(state, bytes, uint8_t,
1583 talloc_get_size(bytes)+1);
1584 if (tevent_req_nomem(bytes, req)) {
1585 return tevent_req_post(req, ev);
1588 bytes[talloc_get_size(bytes)-1] = 4;
1589 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1590 strlen(fname_dst)+1, NULL);
1591 if (tevent_req_nomem(bytes, req)) {
1592 return tevent_req_post(req, ev);
1595 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1596 additional_flags2,
1597 4, state->vwv, talloc_get_size(bytes), bytes);
1598 if (tevent_req_nomem(subreq, req)) {
1599 return tevent_req_post(req, ev);
1601 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1602 return req;
1605 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1607 NTSTATUS status = cli_smb_recv(
1608 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1609 tevent_req_simple_finish_ntstatus(subreq, status);
1612 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1614 return tevent_req_simple_recv_ntstatus(req);
1617 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1618 struct tevent_context *ev,
1619 struct cli_state *cli,
1620 const char *fname_src,
1621 const char *fname_dst)
1623 return cli_ntrename_internal_send(mem_ctx,
1625 cli,
1626 fname_src,
1627 fname_dst,
1628 RENAME_FLAG_RENAME);
1631 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1633 return cli_ntrename_internal_recv(req);
1636 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1638 TALLOC_CTX *frame = talloc_stackframe();
1639 struct tevent_context *ev;
1640 struct tevent_req *req;
1641 NTSTATUS status = NT_STATUS_OK;
1643 if (smbXcli_conn_has_async_calls(cli->conn)) {
1645 * Can't use sync call while an async call is in flight
1647 status = NT_STATUS_INVALID_PARAMETER;
1648 goto fail;
1651 ev = samba_tevent_context_init(frame);
1652 if (ev == NULL) {
1653 status = NT_STATUS_NO_MEMORY;
1654 goto fail;
1657 req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1658 if (req == NULL) {
1659 status = NT_STATUS_NO_MEMORY;
1660 goto fail;
1663 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1664 goto fail;
1667 status = cli_ntrename_recv(req);
1669 fail:
1670 TALLOC_FREE(frame);
1671 return status;
1674 /****************************************************************************
1675 NT hardlink a file.
1676 ****************************************************************************/
1678 static struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1679 struct tevent_context *ev,
1680 struct cli_state *cli,
1681 const char *fname_src,
1682 const char *fname_dst)
1684 return cli_ntrename_internal_send(mem_ctx,
1686 cli,
1687 fname_src,
1688 fname_dst,
1689 RENAME_FLAG_HARD_LINK);
1692 static NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1694 return cli_ntrename_internal_recv(req);
1697 struct cli_smb2_hardlink_state {
1698 struct tevent_context *ev;
1699 struct cli_state *cli;
1700 uint16_t fnum_src;
1701 const char *fname_dst;
1702 bool overwrite;
1703 NTSTATUS status;
1706 static void cli_smb2_hardlink_opened(struct tevent_req *subreq);
1707 static void cli_smb2_hardlink_info_set(struct tevent_req *subreq);
1708 static void cli_smb2_hardlink_closed(struct tevent_req *subreq);
1710 static struct tevent_req *cli_smb2_hardlink_send(
1711 TALLOC_CTX *mem_ctx,
1712 struct tevent_context *ev,
1713 struct cli_state *cli,
1714 const char *fname_src,
1715 const char *fname_dst,
1716 bool overwrite,
1717 struct smb2_create_blobs *in_cblobs)
1719 struct tevent_req *req = NULL, *subreq = NULL;
1720 struct cli_smb2_hardlink_state *state = NULL;
1721 NTSTATUS status;
1723 req = tevent_req_create(
1724 mem_ctx, &state, struct cli_smb2_hardlink_state);
1725 if (req == NULL) {
1726 return NULL;
1730 * Strip a MSDFS path from fname_dst if we were given one.
1732 status = cli_dfs_target_check(state,
1733 cli,
1734 fname_dst,
1735 &fname_dst);
1736 if (tevent_req_nterror(req, status)) {
1737 return tevent_req_post(req, ev);
1740 state->ev = ev;
1741 state->cli = cli;
1742 state->fname_dst = fname_dst;
1743 state->overwrite = overwrite;
1745 subreq = cli_smb2_create_fnum_send(
1746 state,
1748 cli,
1749 fname_src,
1750 0, /* create_flags */
1751 SMB2_IMPERSONATION_IMPERSONATION,
1752 FILE_WRITE_ATTRIBUTES,
1753 0, /* file attributes */
1754 FILE_SHARE_READ|
1755 FILE_SHARE_WRITE|
1756 FILE_SHARE_DELETE, /* share_access */
1757 FILE_OPEN, /* create_disposition */
1758 FILE_NON_DIRECTORY_FILE, /* no hardlinks on directories */
1759 in_cblobs);
1760 if (tevent_req_nomem(subreq, req)) {
1761 return tevent_req_post(req, ev);
1763 tevent_req_set_callback(subreq, cli_smb2_hardlink_opened, req);
1764 return req;
1767 static void cli_smb2_hardlink_opened(struct tevent_req *subreq)
1769 struct tevent_req *req = tevent_req_callback_data(
1770 subreq, struct tevent_req);
1771 struct cli_smb2_hardlink_state *state = tevent_req_data(
1772 req, struct cli_smb2_hardlink_state);
1773 NTSTATUS status;
1774 smb_ucs2_t *ucs2_dst;
1775 size_t ucs2_len;
1776 DATA_BLOB inbuf;
1777 bool ok;
1779 status = cli_smb2_create_fnum_recv(
1780 subreq, &state->fnum_src, NULL, NULL, NULL);
1781 TALLOC_FREE(subreq);
1782 if (tevent_req_nterror(req, status)) {
1783 return;
1786 ok = push_ucs2_talloc(state, &ucs2_dst, state->fname_dst, &ucs2_len);
1787 if (!ok || (ucs2_len < 2)) {
1788 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1789 return;
1791 /* Don't 0-terminate the name */
1792 ucs2_len -= 2;
1794 inbuf = data_blob_talloc_zero(state, ucs2_len + 20);
1795 if (tevent_req_nomem(inbuf.data, req)) {
1796 return;
1799 if (state->overwrite) {
1800 SCVAL(inbuf.data, 0, 1);
1802 SIVAL(inbuf.data, 16, ucs2_len);
1803 memcpy(inbuf.data + 20, ucs2_dst, ucs2_len);
1804 TALLOC_FREE(ucs2_dst);
1806 subreq = cli_smb2_set_info_fnum_send(
1807 state,
1808 state->ev,
1809 state->cli,
1810 state->fnum_src,
1811 1, /* in_info_type */
1812 SMB_FILE_LINK_INFORMATION - 1000, /* in_file_info_class */
1813 &inbuf,
1814 0); /* in_additional_info */
1815 if (tevent_req_nomem(subreq, req)) {
1816 return;
1818 tevent_req_set_callback(subreq, cli_smb2_hardlink_info_set, req);
1821 static void cli_smb2_hardlink_info_set(struct tevent_req *subreq)
1823 struct tevent_req *req = tevent_req_callback_data(
1824 subreq, struct tevent_req);
1825 struct cli_smb2_hardlink_state *state = tevent_req_data(
1826 req, struct cli_smb2_hardlink_state);
1828 state->status = cli_smb2_set_info_fnum_recv(subreq);
1829 TALLOC_FREE(subreq);
1831 /* ignore error here, we need to close the file */
1833 subreq = cli_smb2_close_fnum_send(
1834 state, state->ev, state->cli, state->fnum_src);
1835 if (tevent_req_nomem(subreq, req)) {
1836 return;
1838 tevent_req_set_callback(subreq, cli_smb2_hardlink_closed, req);
1841 static void cli_smb2_hardlink_closed(struct tevent_req *subreq)
1843 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1844 tevent_req_simple_finish_ntstatus(subreq, status);
1847 static NTSTATUS cli_smb2_hardlink_recv(struct tevent_req *req)
1849 struct cli_smb2_hardlink_state *state = tevent_req_data(
1850 req, struct cli_smb2_hardlink_state);
1851 NTSTATUS status;
1853 if (tevent_req_is_nterror(req, &status)) {
1854 return status;
1856 return state->status;
1859 struct cli_hardlink_state {
1860 uint8_t dummy;
1863 static void cli_hardlink_done(struct tevent_req *subreq);
1864 static void cli_hardlink_done2(struct tevent_req *subreq);
1866 struct tevent_req *cli_hardlink_send(
1867 TALLOC_CTX *mem_ctx,
1868 struct tevent_context *ev,
1869 struct cli_state *cli,
1870 const char *fname_src,
1871 const char *fname_dst)
1873 struct tevent_req *req = NULL, *subreq = NULL;
1874 struct cli_hardlink_state *state;
1876 req = tevent_req_create(mem_ctx, &state, struct cli_hardlink_state);
1877 if (req == NULL) {
1878 return NULL;
1881 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1882 subreq = cli_smb2_hardlink_send(
1883 state, ev, cli, fname_src, fname_dst, false, NULL);
1884 if (tevent_req_nomem(subreq, req)) {
1885 return tevent_req_post(req, ev);
1887 tevent_req_set_callback(subreq, cli_hardlink_done2, req);
1888 return req;
1891 subreq = cli_nt_hardlink_send(state, ev, cli, fname_src, fname_dst);
1892 if (tevent_req_nomem(subreq, req)) {
1893 return tevent_req_post(req, ev);
1895 tevent_req_set_callback(subreq, cli_hardlink_done, req);
1896 return req;
1899 static void cli_hardlink_done(struct tevent_req *subreq)
1901 NTSTATUS status = cli_nt_hardlink_recv(subreq);
1902 tevent_req_simple_finish_ntstatus(subreq, status);
1905 static void cli_hardlink_done2(struct tevent_req *subreq)
1907 NTSTATUS status = cli_smb2_hardlink_recv(subreq);
1908 tevent_req_simple_finish_ntstatus(subreq, status);
1911 NTSTATUS cli_hardlink_recv(struct tevent_req *req)
1913 return tevent_req_simple_recv_ntstatus(req);
1916 NTSTATUS cli_hardlink(
1917 struct cli_state *cli, const char *fname_src, const char *fname_dst)
1919 TALLOC_CTX *frame = talloc_stackframe();
1920 struct tevent_context *ev = NULL;
1921 struct tevent_req *req = NULL;
1922 NTSTATUS status = NT_STATUS_NO_MEMORY;
1924 if (smbXcli_conn_has_async_calls(cli->conn)) {
1925 status = NT_STATUS_INVALID_PARAMETER;
1926 goto fail;
1928 ev = samba_tevent_context_init(frame);
1929 if (ev == NULL) {
1930 goto fail;
1932 req = cli_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1933 if (req == NULL) {
1934 goto fail;
1936 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1937 goto fail;
1939 status = cli_hardlink_recv(req);
1940 fail:
1941 TALLOC_FREE(frame);
1942 return status;
1945 /****************************************************************************
1946 Delete a file.
1947 ****************************************************************************/
1949 static void cli_unlink_done(struct tevent_req *subreq);
1950 static void cli_unlink_done2(struct tevent_req *subreq);
1952 struct cli_unlink_state {
1953 uint16_t vwv[1];
1956 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1957 struct tevent_context *ev,
1958 struct cli_state *cli,
1959 const char *fname,
1960 uint32_t mayhave_attrs)
1962 struct tevent_req *req = NULL, *subreq = NULL;
1963 struct cli_unlink_state *state = NULL;
1964 uint8_t additional_flags = 0;
1965 uint16_t additional_flags2 = 0;
1966 uint8_t *bytes = NULL;
1968 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1969 if (req == NULL) {
1970 return NULL;
1973 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1974 subreq = cli_smb2_unlink_send(state, ev, cli, fname, NULL);
1975 if (tevent_req_nomem(subreq, req)) {
1976 return tevent_req_post(req, ev);
1978 tevent_req_set_callback(subreq, cli_unlink_done2, req);
1979 return req;
1982 if (mayhave_attrs & 0xFFFF0000) {
1984 * Don't allow attributes greater than
1985 * 16-bits for a 16-bit protocol value.
1987 if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
1988 return tevent_req_post(req, ev);
1992 SSVAL(state->vwv+0, 0, mayhave_attrs);
1994 bytes = talloc_array(state, uint8_t, 1);
1995 if (tevent_req_nomem(bytes, req)) {
1996 return tevent_req_post(req, ev);
1998 bytes[0] = 4;
1999 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2000 strlen(fname)+1, NULL);
2002 if (tevent_req_nomem(bytes, req)) {
2003 return tevent_req_post(req, ev);
2006 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2007 additional_flags2 = FLAGS2_REPARSE_PATH;
2010 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
2011 additional_flags2,
2012 1, state->vwv, talloc_get_size(bytes), bytes);
2013 if (tevent_req_nomem(subreq, req)) {
2014 return tevent_req_post(req, ev);
2016 tevent_req_set_callback(subreq, cli_unlink_done, req);
2017 return req;
2020 static void cli_unlink_done(struct tevent_req *subreq)
2022 NTSTATUS status = cli_smb_recv(
2023 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2024 tevent_req_simple_finish_ntstatus(subreq, status);
2027 static void cli_unlink_done2(struct tevent_req *subreq)
2029 NTSTATUS status = cli_smb2_unlink_recv(subreq);
2030 tevent_req_simple_finish_ntstatus(subreq, status);
2033 NTSTATUS cli_unlink_recv(struct tevent_req *req)
2035 return tevent_req_simple_recv_ntstatus(req);
2038 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint32_t mayhave_attrs)
2040 TALLOC_CTX *frame = NULL;
2041 struct tevent_context *ev;
2042 struct tevent_req *req;
2043 NTSTATUS status = NT_STATUS_OK;
2045 frame = talloc_stackframe();
2047 if (smbXcli_conn_has_async_calls(cli->conn)) {
2049 * Can't use sync call while an async call is in flight
2051 status = NT_STATUS_INVALID_PARAMETER;
2052 goto fail;
2055 ev = samba_tevent_context_init(frame);
2056 if (ev == NULL) {
2057 status = NT_STATUS_NO_MEMORY;
2058 goto fail;
2061 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
2062 if (req == NULL) {
2063 status = NT_STATUS_NO_MEMORY;
2064 goto fail;
2067 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2068 goto fail;
2071 status = cli_unlink_recv(req);
2072 cli->raw_status = status; /* cli_smb2_unlink_recv doesn't set this */
2074 fail:
2075 TALLOC_FREE(frame);
2076 return status;
2079 /****************************************************************************
2080 Create a directory.
2081 ****************************************************************************/
2083 static void cli_mkdir_done(struct tevent_req *subreq);
2084 static void cli_mkdir_done2(struct tevent_req *subreq);
2086 struct cli_mkdir_state {
2087 int dummy;
2090 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
2091 struct tevent_context *ev,
2092 struct cli_state *cli,
2093 const char *dname)
2095 struct tevent_req *req = NULL, *subreq = NULL;
2096 struct cli_mkdir_state *state = NULL;
2097 uint8_t additional_flags = 0;
2098 uint16_t additional_flags2 = 0;
2099 uint8_t *bytes = NULL;
2101 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
2102 if (req == NULL) {
2103 return NULL;
2106 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2107 subreq = cli_smb2_mkdir_send(state, ev, cli, dname);
2108 if (tevent_req_nomem(subreq, req)) {
2109 return tevent_req_post(req, ev);
2111 tevent_req_set_callback(subreq, cli_mkdir_done2, req);
2112 return req;
2115 bytes = talloc_array(state, uint8_t, 1);
2116 if (tevent_req_nomem(bytes, req)) {
2117 return tevent_req_post(req, ev);
2119 bytes[0] = 4;
2120 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
2121 strlen(dname)+1, NULL);
2123 if (tevent_req_nomem(bytes, req)) {
2124 return tevent_req_post(req, ev);
2127 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
2128 additional_flags2 = FLAGS2_REPARSE_PATH;
2131 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
2132 additional_flags2,
2133 0, NULL, talloc_get_size(bytes), bytes);
2134 if (tevent_req_nomem(subreq, req)) {
2135 return tevent_req_post(req, ev);
2137 tevent_req_set_callback(subreq, cli_mkdir_done, req);
2138 return req;
2141 static void cli_mkdir_done(struct tevent_req *subreq)
2143 struct tevent_req *req = tevent_req_callback_data(
2144 subreq, struct tevent_req);
2145 NTSTATUS status;
2147 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2148 TALLOC_FREE(subreq);
2149 if (tevent_req_nterror(req, status)) {
2150 return;
2152 tevent_req_done(req);
2155 static void cli_mkdir_done2(struct tevent_req *subreq)
2157 NTSTATUS status = cli_smb2_mkdir_recv(subreq);
2158 tevent_req_simple_finish_ntstatus(subreq, status);
2161 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
2163 return tevent_req_simple_recv_ntstatus(req);
2166 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
2168 TALLOC_CTX *frame = NULL;
2169 struct tevent_context *ev;
2170 struct tevent_req *req;
2171 NTSTATUS status = NT_STATUS_OK;
2173 frame = talloc_stackframe();
2175 if (smbXcli_conn_has_async_calls(cli->conn)) {
2177 * Can't use sync call while an async call is in flight
2179 status = NT_STATUS_INVALID_PARAMETER;
2180 goto fail;
2183 ev = samba_tevent_context_init(frame);
2184 if (ev == NULL) {
2185 status = NT_STATUS_NO_MEMORY;
2186 goto fail;
2189 req = cli_mkdir_send(frame, ev, cli, dname);
2190 if (req == NULL) {
2191 status = NT_STATUS_NO_MEMORY;
2192 goto fail;
2195 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2196 goto fail;
2199 status = cli_mkdir_recv(req);
2200 cli->raw_status = status; /* cli_smb2_mkdir_recv doesn't set this */
2202 fail:
2203 TALLOC_FREE(frame);
2204 return status;
2207 /****************************************************************************
2208 Remove a directory.
2209 ****************************************************************************/
2211 static void cli_rmdir_done(struct tevent_req *subreq);
2212 static void cli_rmdir_done2(struct tevent_req *subreq);
2214 struct cli_rmdir_state {
2215 int dummy;
2218 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
2219 struct tevent_context *ev,
2220 struct cli_state *cli,
2221 const char *dname)
2223 struct tevent_req *req = NULL, *subreq = NULL;
2224 struct cli_rmdir_state *state = NULL;
2225 uint8_t additional_flags = 0;
2226 uint16_t additional_flags2 = 0;
2227 uint8_t *bytes = NULL;
2229 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
2230 if (req == NULL) {
2231 return NULL;
2234 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2235 subreq = cli_smb2_rmdir_send(state, ev, cli, dname, NULL);
2236 if (tevent_req_nomem(subreq, req)) {
2237 return tevent_req_post(req, ev);
2239 tevent_req_set_callback(subreq, cli_rmdir_done2, req);
2240 return req;
2243 bytes = talloc_array(state, uint8_t, 1);
2244 if (tevent_req_nomem(bytes, req)) {
2245 return tevent_req_post(req, ev);
2247 bytes[0] = 4;
2248 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
2249 strlen(dname)+1, NULL);
2251 if (tevent_req_nomem(bytes, req)) {
2252 return tevent_req_post(req, ev);
2255 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
2256 additional_flags2 = FLAGS2_REPARSE_PATH;
2259 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
2260 additional_flags2,
2261 0, NULL, talloc_get_size(bytes), bytes);
2262 if (tevent_req_nomem(subreq, req)) {
2263 return tevent_req_post(req, ev);
2265 tevent_req_set_callback(subreq, cli_rmdir_done, req);
2266 return req;
2269 static void cli_rmdir_done(struct tevent_req *subreq)
2271 NTSTATUS status = cli_smb_recv(
2272 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2273 tevent_req_simple_finish_ntstatus(subreq, status);
2276 static void cli_rmdir_done2(struct tevent_req *subreq)
2278 NTSTATUS status = cli_smb2_rmdir_recv(subreq);
2279 tevent_req_simple_finish_ntstatus(subreq, status);
2282 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
2284 return tevent_req_simple_recv_ntstatus(req);
2287 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
2289 TALLOC_CTX *frame = NULL;
2290 struct tevent_context *ev;
2291 struct tevent_req *req;
2292 NTSTATUS status = NT_STATUS_OK;
2294 frame = talloc_stackframe();
2296 if (smbXcli_conn_has_async_calls(cli->conn)) {
2298 * Can't use sync call while an async call is in flight
2300 status = NT_STATUS_INVALID_PARAMETER;
2301 goto fail;
2304 ev = samba_tevent_context_init(frame);
2305 if (ev == NULL) {
2306 status = NT_STATUS_NO_MEMORY;
2307 goto fail;
2310 req = cli_rmdir_send(frame, ev, cli, dname);
2311 if (req == NULL) {
2312 status = NT_STATUS_NO_MEMORY;
2313 goto fail;
2316 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2317 goto fail;
2320 status = cli_rmdir_recv(req);
2321 cli->raw_status = status; /* cli_smb2_rmdir_recv doesn't set this */
2323 fail:
2324 TALLOC_FREE(frame);
2325 return status;
2328 /****************************************************************************
2329 Set or clear the delete on close flag.
2330 ****************************************************************************/
2332 struct doc_state {
2333 uint8_t data[1];
2336 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
2337 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
2339 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
2340 struct tevent_context *ev,
2341 struct cli_state *cli,
2342 uint16_t fnum,
2343 bool flag)
2345 struct tevent_req *req = NULL, *subreq = NULL;
2346 struct doc_state *state = NULL;
2348 req = tevent_req_create(mem_ctx, &state, struct doc_state);
2349 if (req == NULL) {
2350 return NULL;
2353 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2354 subreq = cli_smb2_delete_on_close_send(state, ev, cli,
2355 fnum, flag);
2356 if (tevent_req_nomem(subreq, req)) {
2357 return tevent_req_post(req, ev);
2359 tevent_req_set_callback(subreq,
2360 cli_nt_delete_on_close_smb2_done,
2361 req);
2362 return req;
2365 /* Setup data array. */
2366 SCVAL(&state->data[0], 0, flag ? 1 : 0);
2368 subreq = cli_setfileinfo_send(
2369 state,
2371 cli,
2372 fnum,
2373 SMB_SET_FILE_DISPOSITION_INFO,
2374 state->data,
2375 sizeof(state->data));
2377 if (tevent_req_nomem(subreq, req)) {
2378 return tevent_req_post(req, ev);
2380 tevent_req_set_callback(subreq,
2381 cli_nt_delete_on_close_smb1_done,
2382 req);
2383 return req;
2386 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
2388 NTSTATUS status = cli_setfileinfo_recv(subreq);
2389 tevent_req_simple_finish_ntstatus(subreq, status);
2392 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
2394 NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
2395 tevent_req_simple_finish_ntstatus(subreq, status);
2398 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
2400 return tevent_req_simple_recv_ntstatus(req);
2403 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
2405 TALLOC_CTX *frame = talloc_stackframe();
2406 struct tevent_context *ev = NULL;
2407 struct tevent_req *req = NULL;
2408 NTSTATUS status = NT_STATUS_OK;
2410 if (smbXcli_conn_has_async_calls(cli->conn)) {
2412 * Can't use sync call while an async call is in flight
2414 status = NT_STATUS_INVALID_PARAMETER;
2415 goto fail;
2418 ev = samba_tevent_context_init(frame);
2419 if (ev == NULL) {
2420 status = NT_STATUS_NO_MEMORY;
2421 goto fail;
2424 req = cli_nt_delete_on_close_send(frame,
2426 cli,
2427 fnum,
2428 flag);
2429 if (req == NULL) {
2430 status = NT_STATUS_NO_MEMORY;
2431 goto fail;
2434 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2435 goto fail;
2438 status = cli_nt_delete_on_close_recv(req);
2440 fail:
2441 TALLOC_FREE(frame);
2442 return status;
2445 struct cli_ntcreate1_state {
2446 uint16_t vwv[24];
2447 uint16_t fnum;
2448 struct smb_create_returns cr;
2449 struct tevent_req *subreq;
2452 static void cli_ntcreate1_done(struct tevent_req *subreq);
2453 static bool cli_ntcreate1_cancel(struct tevent_req *req);
2455 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
2456 struct tevent_context *ev,
2457 struct cli_state *cli,
2458 const char *fname,
2459 uint32_t CreatFlags,
2460 uint32_t DesiredAccess,
2461 uint32_t FileAttributes,
2462 uint32_t ShareAccess,
2463 uint32_t CreateDisposition,
2464 uint32_t CreateOptions,
2465 uint32_t ImpersonationLevel,
2466 uint8_t SecurityFlags)
2468 struct tevent_req *req, *subreq;
2469 struct cli_ntcreate1_state *state;
2470 uint16_t *vwv;
2471 uint8_t *bytes;
2472 size_t converted_len;
2473 uint16_t additional_flags2 = 0;
2475 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
2476 if (req == NULL) {
2477 return NULL;
2480 vwv = state->vwv;
2482 SCVAL(vwv+0, 0, 0xFF);
2483 SCVAL(vwv+0, 1, 0);
2484 SSVAL(vwv+1, 0, 0);
2485 SCVAL(vwv+2, 0, 0);
2487 if (cli->use_oplocks) {
2488 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
2490 SIVAL(vwv+3, 1, CreatFlags);
2491 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
2492 SIVAL(vwv+7, 1, DesiredAccess);
2493 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
2494 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
2495 SIVAL(vwv+13, 1, FileAttributes);
2496 SIVAL(vwv+15, 1, ShareAccess);
2497 SIVAL(vwv+17, 1, CreateDisposition);
2498 SIVAL(vwv+19, 1, CreateOptions |
2499 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2500 SIVAL(vwv+21, 1, ImpersonationLevel);
2501 SCVAL(vwv+23, 1, SecurityFlags);
2503 bytes = talloc_array(state, uint8_t, 0);
2504 if (tevent_req_nomem(bytes, req)) {
2505 return tevent_req_post(req, ev);
2507 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
2508 fname, strlen(fname)+1,
2509 &converted_len);
2510 if (tevent_req_nomem(bytes, req)) {
2511 return tevent_req_post(req, ev);
2514 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2515 additional_flags2 = FLAGS2_REPARSE_PATH;
2518 /* sigh. this copes with broken netapp filer behaviour */
2519 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2521 if (tevent_req_nomem(bytes, req)) {
2522 return tevent_req_post(req, ev);
2525 SSVAL(vwv+2, 1, converted_len);
2527 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2528 additional_flags2, 24, vwv,
2529 talloc_get_size(bytes), bytes);
2530 if (tevent_req_nomem(subreq, req)) {
2531 return tevent_req_post(req, ev);
2533 tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2535 state->subreq = subreq;
2536 tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2538 return req;
2541 static void cli_ntcreate1_done(struct tevent_req *subreq)
2543 struct tevent_req *req = tevent_req_callback_data(
2544 subreq, struct tevent_req);
2545 struct cli_ntcreate1_state *state = tevent_req_data(
2546 req, struct cli_ntcreate1_state);
2547 uint8_t wct;
2548 uint16_t *vwv;
2549 uint32_t num_bytes;
2550 uint8_t *bytes;
2551 NTSTATUS status;
2553 status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2554 &num_bytes, &bytes);
2555 TALLOC_FREE(subreq);
2556 if (tevent_req_nterror(req, status)) {
2557 return;
2559 state->cr.oplock_level = CVAL(vwv+2, 0);
2560 state->fnum = SVAL(vwv+2, 1);
2561 state->cr.create_action = IVAL(vwv+3, 1);
2562 state->cr.creation_time = BVAL(vwv+5, 1);
2563 state->cr.last_access_time = BVAL(vwv+9, 1);
2564 state->cr.last_write_time = BVAL(vwv+13, 1);
2565 state->cr.change_time = BVAL(vwv+17, 1);
2566 state->cr.file_attributes = IVAL(vwv+21, 1);
2567 state->cr.allocation_size = BVAL(vwv+23, 1);
2568 state->cr.end_of_file = BVAL(vwv+27, 1);
2570 tevent_req_done(req);
2573 static bool cli_ntcreate1_cancel(struct tevent_req *req)
2575 struct cli_ntcreate1_state *state = tevent_req_data(
2576 req, struct cli_ntcreate1_state);
2577 return tevent_req_cancel(state->subreq);
2580 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2581 uint16_t *pfnum,
2582 struct smb_create_returns *cr)
2584 struct cli_ntcreate1_state *state = tevent_req_data(
2585 req, struct cli_ntcreate1_state);
2586 NTSTATUS status;
2588 if (tevent_req_is_nterror(req, &status)) {
2589 return status;
2591 *pfnum = state->fnum;
2592 if (cr != NULL) {
2593 *cr = state->cr;
2595 return NT_STATUS_OK;
2598 struct cli_ntcreate_state {
2599 struct smb_create_returns cr;
2600 uint16_t fnum;
2601 struct tevent_req *subreq;
2604 static void cli_ntcreate_done_nt1(struct tevent_req *subreq);
2605 static void cli_ntcreate_done_smb2(struct tevent_req *subreq);
2606 static bool cli_ntcreate_cancel(struct tevent_req *req);
2608 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
2609 struct tevent_context *ev,
2610 struct cli_state *cli,
2611 const char *fname,
2612 uint32_t create_flags,
2613 uint32_t desired_access,
2614 uint32_t file_attributes,
2615 uint32_t share_access,
2616 uint32_t create_disposition,
2617 uint32_t create_options,
2618 uint32_t impersonation_level,
2619 uint8_t security_flags)
2621 struct tevent_req *req, *subreq;
2622 struct cli_ntcreate_state *state;
2624 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2625 if (req == NULL) {
2626 return NULL;
2629 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2630 if (cli->use_oplocks) {
2631 create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2634 subreq = cli_smb2_create_fnum_send(
2635 state,
2637 cli,
2638 fname,
2639 create_flags,
2640 impersonation_level,
2641 desired_access,
2642 file_attributes,
2643 share_access,
2644 create_disposition,
2645 create_options,
2646 NULL);
2647 if (tevent_req_nomem(subreq, req)) {
2648 return tevent_req_post(req, ev);
2650 tevent_req_set_callback(subreq, cli_ntcreate_done_smb2, req);
2651 } else {
2652 subreq = cli_ntcreate1_send(
2653 state, ev, cli, fname, create_flags, desired_access,
2654 file_attributes, share_access, create_disposition,
2655 create_options, impersonation_level, security_flags);
2656 if (tevent_req_nomem(subreq, req)) {
2657 return tevent_req_post(req, ev);
2659 tevent_req_set_callback(subreq, cli_ntcreate_done_nt1, req);
2662 state->subreq = subreq;
2663 tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2665 return req;
2668 static void cli_ntcreate_done_nt1(struct tevent_req *subreq)
2670 struct tevent_req *req = tevent_req_callback_data(
2671 subreq, struct tevent_req);
2672 struct cli_ntcreate_state *state = tevent_req_data(
2673 req, struct cli_ntcreate_state);
2674 NTSTATUS status;
2676 status = cli_ntcreate1_recv(subreq, &state->fnum, &state->cr);
2677 TALLOC_FREE(subreq);
2678 if (tevent_req_nterror(req, status)) {
2679 return;
2681 tevent_req_done(req);
2684 static void cli_ntcreate_done_smb2(struct tevent_req *subreq)
2686 struct tevent_req *req = tevent_req_callback_data(
2687 subreq, struct tevent_req);
2688 struct cli_ntcreate_state *state = tevent_req_data(
2689 req, struct cli_ntcreate_state);
2690 NTSTATUS status;
2692 status = cli_smb2_create_fnum_recv(
2693 subreq,
2694 &state->fnum,
2695 &state->cr,
2696 NULL,
2697 NULL);
2698 TALLOC_FREE(subreq);
2699 if (tevent_req_nterror(req, status)) {
2700 return;
2702 tevent_req_done(req);
2705 static bool cli_ntcreate_cancel(struct tevent_req *req)
2707 struct cli_ntcreate_state *state = tevent_req_data(
2708 req, struct cli_ntcreate_state);
2709 return tevent_req_cancel(state->subreq);
2712 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2713 struct smb_create_returns *cr)
2715 struct cli_ntcreate_state *state = tevent_req_data(
2716 req, struct cli_ntcreate_state);
2717 NTSTATUS status;
2719 if (tevent_req_is_nterror(req, &status)) {
2720 return status;
2722 if (fnum != NULL) {
2723 *fnum = state->fnum;
2725 if (cr != NULL) {
2726 *cr = state->cr;
2728 return NT_STATUS_OK;
2731 NTSTATUS cli_ntcreate(struct cli_state *cli,
2732 const char *fname,
2733 uint32_t CreatFlags,
2734 uint32_t DesiredAccess,
2735 uint32_t FileAttributes,
2736 uint32_t ShareAccess,
2737 uint32_t CreateDisposition,
2738 uint32_t CreateOptions,
2739 uint8_t SecurityFlags,
2740 uint16_t *pfid,
2741 struct smb_create_returns *cr)
2743 TALLOC_CTX *frame = talloc_stackframe();
2744 struct tevent_context *ev;
2745 struct tevent_req *req;
2746 uint32_t ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
2747 NTSTATUS status = NT_STATUS_NO_MEMORY;
2749 if (smbXcli_conn_has_async_calls(cli->conn)) {
2751 * Can't use sync call while an async call is in flight
2753 status = NT_STATUS_INVALID_PARAMETER;
2754 goto fail;
2757 ev = samba_tevent_context_init(frame);
2758 if (ev == NULL) {
2759 goto fail;
2762 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2763 DesiredAccess, FileAttributes, ShareAccess,
2764 CreateDisposition, CreateOptions,
2765 ImpersonationLevel, SecurityFlags);
2766 if (req == NULL) {
2767 goto fail;
2770 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2771 goto fail;
2774 status = cli_ntcreate_recv(req, pfid, cr);
2775 fail:
2776 TALLOC_FREE(frame);
2777 return status;
2780 struct cli_nttrans_create_state {
2781 uint16_t fnum;
2782 struct smb_create_returns cr;
2785 static void cli_nttrans_create_done(struct tevent_req *subreq);
2787 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2788 struct tevent_context *ev,
2789 struct cli_state *cli,
2790 const char *fname,
2791 uint32_t CreatFlags,
2792 uint32_t DesiredAccess,
2793 uint32_t FileAttributes,
2794 uint32_t ShareAccess,
2795 uint32_t CreateDisposition,
2796 uint32_t CreateOptions,
2797 uint8_t SecurityFlags,
2798 struct security_descriptor *secdesc,
2799 struct ea_struct *eas,
2800 int num_eas)
2802 struct tevent_req *req, *subreq;
2803 struct cli_nttrans_create_state *state;
2804 uint8_t *param;
2805 uint8_t *secdesc_buf;
2806 size_t secdesc_len;
2807 NTSTATUS status;
2808 size_t converted_len;
2809 uint16_t additional_flags2 = 0;
2811 req = tevent_req_create(mem_ctx,
2812 &state, struct cli_nttrans_create_state);
2813 if (req == NULL) {
2814 return NULL;
2817 if (secdesc != NULL) {
2818 status = marshall_sec_desc(talloc_tos(), secdesc,
2819 &secdesc_buf, &secdesc_len);
2820 if (tevent_req_nterror(req, status)) {
2821 DEBUG(10, ("marshall_sec_desc failed: %s\n",
2822 nt_errstr(status)));
2823 return tevent_req_post(req, ev);
2825 } else {
2826 secdesc_buf = NULL;
2827 secdesc_len = 0;
2830 if (num_eas != 0) {
2832 * TODO ;-)
2834 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2835 return tevent_req_post(req, ev);
2838 param = talloc_array(state, uint8_t, 53);
2839 if (tevent_req_nomem(param, req)) {
2840 return tevent_req_post(req, ev);
2843 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2844 fname, strlen(fname),
2845 &converted_len);
2846 if (tevent_req_nomem(param, req)) {
2847 return tevent_req_post(req, ev);
2850 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2851 additional_flags2 = FLAGS2_REPARSE_PATH;
2854 SIVAL(param, 0, CreatFlags);
2855 SIVAL(param, 4, 0x0); /* RootDirectoryFid */
2856 SIVAL(param, 8, DesiredAccess);
2857 SIVAL(param, 12, 0x0); /* AllocationSize */
2858 SIVAL(param, 16, 0x0); /* AllocationSize */
2859 SIVAL(param, 20, FileAttributes);
2860 SIVAL(param, 24, ShareAccess);
2861 SIVAL(param, 28, CreateDisposition);
2862 SIVAL(param, 32, CreateOptions |
2863 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2864 SIVAL(param, 36, secdesc_len);
2865 SIVAL(param, 40, 0); /* EA length*/
2866 SIVAL(param, 44, converted_len);
2867 SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2868 SCVAL(param, 52, SecurityFlags);
2870 subreq = cli_trans_send(state, ev, cli,
2871 additional_flags2, /* additional_flags2 */
2872 SMBnttrans,
2873 NULL, -1, /* name, fid */
2874 NT_TRANSACT_CREATE, 0,
2875 NULL, 0, 0, /* setup */
2876 param, talloc_get_size(param), 128, /* param */
2877 secdesc_buf, secdesc_len, 0); /* data */
2878 if (tevent_req_nomem(subreq, req)) {
2879 return tevent_req_post(req, ev);
2881 tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2882 return req;
2885 static void cli_nttrans_create_done(struct tevent_req *subreq)
2887 struct tevent_req *req = tevent_req_callback_data(
2888 subreq, struct tevent_req);
2889 struct cli_nttrans_create_state *state = tevent_req_data(
2890 req, struct cli_nttrans_create_state);
2891 uint8_t *param;
2892 uint32_t num_param;
2893 NTSTATUS status;
2895 status = cli_trans_recv(subreq, talloc_tos(), NULL,
2896 NULL, 0, NULL, /* rsetup */
2897 &param, 69, &num_param,
2898 NULL, 0, NULL);
2899 if (tevent_req_nterror(req, status)) {
2900 return;
2902 state->cr.oplock_level = CVAL(param, 0);
2903 state->fnum = SVAL(param, 2);
2904 state->cr.create_action = IVAL(param, 4);
2905 state->cr.creation_time = BVAL(param, 12);
2906 state->cr.last_access_time = BVAL(param, 20);
2907 state->cr.last_write_time = BVAL(param, 28);
2908 state->cr.change_time = BVAL(param, 36);
2909 state->cr.file_attributes = IVAL(param, 44);
2910 state->cr.allocation_size = BVAL(param, 48);
2911 state->cr.end_of_file = BVAL(param, 56);
2913 TALLOC_FREE(param);
2914 tevent_req_done(req);
2917 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2918 uint16_t *fnum,
2919 struct smb_create_returns *cr)
2921 struct cli_nttrans_create_state *state = tevent_req_data(
2922 req, struct cli_nttrans_create_state);
2923 NTSTATUS status;
2925 if (tevent_req_is_nterror(req, &status)) {
2926 return status;
2928 *fnum = state->fnum;
2929 if (cr != NULL) {
2930 *cr = state->cr;
2932 return NT_STATUS_OK;
2935 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2936 const char *fname,
2937 uint32_t CreatFlags,
2938 uint32_t DesiredAccess,
2939 uint32_t FileAttributes,
2940 uint32_t ShareAccess,
2941 uint32_t CreateDisposition,
2942 uint32_t CreateOptions,
2943 uint8_t SecurityFlags,
2944 struct security_descriptor *secdesc,
2945 struct ea_struct *eas,
2946 int num_eas,
2947 uint16_t *pfid,
2948 struct smb_create_returns *cr)
2950 TALLOC_CTX *frame = talloc_stackframe();
2951 struct tevent_context *ev;
2952 struct tevent_req *req;
2953 NTSTATUS status = NT_STATUS_NO_MEMORY;
2955 if (smbXcli_conn_has_async_calls(cli->conn)) {
2957 * Can't use sync call while an async call is in flight
2959 status = NT_STATUS_INVALID_PARAMETER;
2960 goto fail;
2962 ev = samba_tevent_context_init(frame);
2963 if (ev == NULL) {
2964 goto fail;
2966 req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2967 DesiredAccess, FileAttributes,
2968 ShareAccess, CreateDisposition,
2969 CreateOptions, SecurityFlags,
2970 secdesc, eas, num_eas);
2971 if (req == NULL) {
2972 goto fail;
2974 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2975 goto fail;
2977 status = cli_nttrans_create_recv(req, pfid, cr);
2978 fail:
2979 TALLOC_FREE(frame);
2980 return status;
2983 /****************************************************************************
2984 Open a file
2985 WARNING: if you open with O_WRONLY then getattrE won't work!
2986 ****************************************************************************/
2988 struct cli_openx_state {
2989 const char *fname;
2990 uint16_t vwv[15];
2991 uint16_t fnum;
2992 struct iovec bytes;
2995 static void cli_openx_done(struct tevent_req *subreq);
2997 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2998 struct tevent_context *ev,
2999 struct cli_state *cli, const char *fname,
3000 int flags, int share_mode,
3001 struct tevent_req **psmbreq)
3003 struct tevent_req *req, *subreq;
3004 struct cli_openx_state *state;
3005 unsigned openfn;
3006 unsigned accessmode;
3007 uint8_t additional_flags;
3008 uint16_t additional_flags2 = 0;
3009 uint8_t *bytes;
3011 req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
3012 if (req == NULL) {
3013 return NULL;
3016 openfn = 0;
3017 if (flags & O_CREAT) {
3018 openfn |= (1<<4);
3020 if (!(flags & O_EXCL)) {
3021 if (flags & O_TRUNC)
3022 openfn |= (1<<1);
3023 else
3024 openfn |= (1<<0);
3027 accessmode = (share_mode<<4);
3029 if ((flags & O_ACCMODE) == O_RDWR) {
3030 accessmode |= 2;
3031 } else if ((flags & O_ACCMODE) == O_WRONLY) {
3032 accessmode |= 1;
3035 #if defined(O_SYNC)
3036 if ((flags & O_SYNC) == O_SYNC) {
3037 accessmode |= (1<<14);
3039 #endif /* O_SYNC */
3041 if (share_mode == DENY_FCB) {
3042 accessmode = 0xFF;
3045 SCVAL(state->vwv + 0, 0, 0xFF);
3046 SCVAL(state->vwv + 0, 1, 0);
3047 SSVAL(state->vwv + 1, 0, 0);
3048 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
3049 SSVAL(state->vwv + 3, 0, accessmode);
3050 SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
3051 SSVAL(state->vwv + 5, 0, 0);
3052 SIVAL(state->vwv + 6, 0, 0);
3053 SSVAL(state->vwv + 8, 0, openfn);
3054 SIVAL(state->vwv + 9, 0, 0);
3055 SIVAL(state->vwv + 11, 0, 0);
3056 SIVAL(state->vwv + 13, 0, 0);
3058 additional_flags = 0;
3060 if (cli->use_oplocks) {
3061 /* if using oplocks then ask for a batch oplock via
3062 core and extended methods */
3063 additional_flags =
3064 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
3065 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
3068 bytes = talloc_array(state, uint8_t, 0);
3069 if (tevent_req_nomem(bytes, req)) {
3070 return tevent_req_post(req, ev);
3072 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3073 strlen(fname)+1, NULL);
3075 if (tevent_req_nomem(bytes, req)) {
3076 return tevent_req_post(req, ev);
3079 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
3080 additional_flags2 = FLAGS2_REPARSE_PATH;
3083 state->bytes.iov_base = (void *)bytes;
3084 state->bytes.iov_len = talloc_get_size(bytes);
3086 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
3087 additional_flags2, 15, state->vwv, 1, &state->bytes);
3088 if (subreq == NULL) {
3089 TALLOC_FREE(req);
3090 return NULL;
3092 tevent_req_set_callback(subreq, cli_openx_done, req);
3093 *psmbreq = subreq;
3094 return req;
3097 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
3098 struct cli_state *cli, const char *fname,
3099 int flags, int share_mode)
3101 struct tevent_req *req, *subreq;
3102 NTSTATUS status;
3104 req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
3105 &subreq);
3106 if (req == NULL) {
3107 return NULL;
3110 status = smb1cli_req_chain_submit(&subreq, 1);
3111 if (tevent_req_nterror(req, status)) {
3112 return tevent_req_post(req, ev);
3114 return req;
3117 static void cli_openx_done(struct tevent_req *subreq)
3119 struct tevent_req *req = tevent_req_callback_data(
3120 subreq, struct tevent_req);
3121 struct cli_openx_state *state = tevent_req_data(
3122 req, struct cli_openx_state);
3123 uint8_t wct;
3124 uint16_t *vwv;
3125 NTSTATUS status;
3127 status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
3128 NULL);
3129 TALLOC_FREE(subreq);
3130 if (tevent_req_nterror(req, status)) {
3131 return;
3133 state->fnum = SVAL(vwv+2, 0);
3134 tevent_req_done(req);
3137 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
3139 struct cli_openx_state *state = tevent_req_data(
3140 req, struct cli_openx_state);
3141 NTSTATUS status;
3143 if (tevent_req_is_nterror(req, &status)) {
3144 return status;
3146 *pfnum = state->fnum;
3147 return NT_STATUS_OK;
3150 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
3151 int share_mode, uint16_t *pfnum)
3153 TALLOC_CTX *frame = talloc_stackframe();
3154 struct tevent_context *ev;
3155 struct tevent_req *req;
3156 NTSTATUS status = NT_STATUS_NO_MEMORY;
3158 if (smbXcli_conn_has_async_calls(cli->conn)) {
3160 * Can't use sync call while an async call is in flight
3162 status = NT_STATUS_INVALID_PARAMETER;
3163 goto fail;
3166 ev = samba_tevent_context_init(frame);
3167 if (ev == NULL) {
3168 goto fail;
3171 req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
3172 if (req == NULL) {
3173 goto fail;
3176 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3177 goto fail;
3180 status = cli_openx_recv(req, pfnum);
3181 fail:
3182 TALLOC_FREE(frame);
3183 return status;
3185 /****************************************************************************
3186 Synchronous wrapper function that does an NtCreateX open by preference
3187 and falls back to openX if this fails.
3188 ****************************************************************************/
3190 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
3191 int share_mode_in, uint16_t *pfnum)
3193 NTSTATUS status;
3194 unsigned int openfn = 0;
3195 unsigned int dos_deny = 0;
3196 uint32_t access_mask, share_mode, create_disposition, create_options;
3197 struct smb_create_returns cr = {0};
3199 /* Do the initial mapping into OpenX parameters. */
3200 if (flags & O_CREAT) {
3201 openfn |= (1<<4);
3203 if (!(flags & O_EXCL)) {
3204 if (flags & O_TRUNC)
3205 openfn |= (1<<1);
3206 else
3207 openfn |= (1<<0);
3210 dos_deny = (share_mode_in<<4);
3212 if ((flags & O_ACCMODE) == O_RDWR) {
3213 dos_deny |= 2;
3214 } else if ((flags & O_ACCMODE) == O_WRONLY) {
3215 dos_deny |= 1;
3218 #if defined(O_SYNC)
3219 if ((flags & O_SYNC) == O_SYNC) {
3220 dos_deny |= (1<<14);
3222 #endif /* O_SYNC */
3224 if (share_mode_in == DENY_FCB) {
3225 dos_deny = 0xFF;
3228 if (!map_open_params_to_ntcreate(fname, dos_deny,
3229 openfn, &access_mask,
3230 &share_mode, &create_disposition,
3231 &create_options, NULL)) {
3232 goto try_openx;
3235 status = cli_ntcreate(cli,
3236 fname,
3238 access_mask,
3240 share_mode,
3241 create_disposition,
3242 create_options,
3244 pfnum,
3245 &cr);
3247 /* Try and cope will all varients of "we don't do this call"
3248 and fall back to openX. */
3250 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
3251 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
3252 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
3253 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
3254 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
3255 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
3256 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
3257 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
3258 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
3259 goto try_openx;
3262 if (NT_STATUS_IS_OK(status) &&
3263 (create_options & FILE_NON_DIRECTORY_FILE) &&
3264 (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
3267 * Some (broken) servers return a valid handle
3268 * for directories even if FILE_NON_DIRECTORY_FILE
3269 * is set. Just close the handle and set the
3270 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
3272 status = cli_close(cli, *pfnum);
3273 if (!NT_STATUS_IS_OK(status)) {
3274 return status;
3276 status = NT_STATUS_FILE_IS_A_DIRECTORY;
3277 /* Set this so libsmbclient can retrieve it. */
3278 cli->raw_status = status;
3281 return status;
3283 try_openx:
3285 return cli_openx(cli, fname, flags, share_mode_in, pfnum);
3288 /****************************************************************************
3289 Close a file.
3290 ****************************************************************************/
3292 struct cli_smb1_close_state {
3293 uint16_t vwv[3];
3296 static void cli_smb1_close_done(struct tevent_req *subreq);
3298 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
3299 struct tevent_context *ev,
3300 struct cli_state *cli,
3301 uint16_t fnum,
3302 struct tevent_req **psubreq)
3304 struct tevent_req *req, *subreq;
3305 struct cli_smb1_close_state *state;
3307 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
3308 if (req == NULL) {
3309 return NULL;
3312 SSVAL(state->vwv+0, 0, fnum);
3313 SIVALS(state->vwv+1, 0, -1);
3315 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
3316 3, state->vwv, 0, NULL);
3317 if (subreq == NULL) {
3318 TALLOC_FREE(req);
3319 return NULL;
3321 tevent_req_set_callback(subreq, cli_smb1_close_done, req);
3322 *psubreq = subreq;
3323 return req;
3326 static void cli_smb1_close_done(struct tevent_req *subreq)
3328 struct tevent_req *req = tevent_req_callback_data(
3329 subreq, struct tevent_req);
3330 NTSTATUS status;
3332 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3333 TALLOC_FREE(subreq);
3334 if (tevent_req_nterror(req, status)) {
3335 return;
3337 tevent_req_done(req);
3340 struct cli_close_state {
3341 int dummy;
3344 static void cli_close_done(struct tevent_req *subreq);
3346 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
3347 struct tevent_context *ev,
3348 struct cli_state *cli,
3349 uint16_t fnum)
3351 struct tevent_req *req, *subreq;
3352 struct cli_close_state *state;
3353 NTSTATUS status;
3355 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
3356 if (req == NULL) {
3357 return NULL;
3360 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3361 subreq = cli_smb2_close_fnum_send(state,
3363 cli,
3364 fnum);
3365 if (tevent_req_nomem(subreq, req)) {
3366 return tevent_req_post(req, ev);
3368 } else {
3369 struct tevent_req *ch_req = NULL;
3370 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
3371 if (tevent_req_nomem(subreq, req)) {
3372 return tevent_req_post(req, ev);
3374 status = smb1cli_req_chain_submit(&ch_req, 1);
3375 if (tevent_req_nterror(req, status)) {
3376 return tevent_req_post(req, ev);
3380 tevent_req_set_callback(subreq, cli_close_done, req);
3381 return req;
3384 static void cli_close_done(struct tevent_req *subreq)
3386 struct tevent_req *req = tevent_req_callback_data(
3387 subreq, struct tevent_req);
3388 NTSTATUS status = NT_STATUS_OK;
3389 bool err = tevent_req_is_nterror(subreq, &status);
3391 TALLOC_FREE(subreq);
3392 if (err) {
3393 tevent_req_nterror(req, status);
3394 return;
3396 tevent_req_done(req);
3399 NTSTATUS cli_close_recv(struct tevent_req *req)
3401 return tevent_req_simple_recv_ntstatus(req);
3404 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
3406 TALLOC_CTX *frame = NULL;
3407 struct tevent_context *ev;
3408 struct tevent_req *req;
3409 NTSTATUS status = NT_STATUS_OK;
3411 frame = talloc_stackframe();
3413 if (smbXcli_conn_has_async_calls(cli->conn)) {
3415 * Can't use sync call while an async call is in flight
3417 status = NT_STATUS_INVALID_PARAMETER;
3418 goto fail;
3421 ev = samba_tevent_context_init(frame);
3422 if (ev == NULL) {
3423 status = NT_STATUS_NO_MEMORY;
3424 goto fail;
3427 req = cli_close_send(frame, ev, cli, fnum);
3428 if (req == NULL) {
3429 status = NT_STATUS_NO_MEMORY;
3430 goto fail;
3433 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3434 goto fail;
3437 status = cli_close_recv(req);
3438 fail:
3439 TALLOC_FREE(frame);
3440 return status;
3443 /****************************************************************************
3444 Truncate a file to a specified size
3445 ****************************************************************************/
3447 struct ftrunc_state {
3448 uint8_t data[8];
3451 static void cli_ftruncate_done(struct tevent_req *subreq)
3453 NTSTATUS status = cli_setfileinfo_recv(subreq);
3454 tevent_req_simple_finish_ntstatus(subreq, status);
3457 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
3458 struct tevent_context *ev,
3459 struct cli_state *cli,
3460 uint16_t fnum,
3461 uint64_t size)
3463 struct tevent_req *req = NULL, *subreq = NULL;
3464 struct ftrunc_state *state = NULL;
3466 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
3467 if (req == NULL) {
3468 return NULL;
3471 /* Setup data array. */
3472 SBVAL(state->data, 0, size);
3474 subreq = cli_setfileinfo_send(
3475 state,
3477 cli,
3478 fnum,
3479 SMB_SET_FILE_END_OF_FILE_INFO,
3480 state->data,
3481 sizeof(state->data));
3483 if (tevent_req_nomem(subreq, req)) {
3484 return tevent_req_post(req, ev);
3486 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
3487 return req;
3490 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
3492 return tevent_req_simple_recv_ntstatus(req);
3495 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3497 TALLOC_CTX *frame = NULL;
3498 struct tevent_context *ev = NULL;
3499 struct tevent_req *req = NULL;
3500 NTSTATUS status = NT_STATUS_OK;
3502 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3503 return cli_smb2_ftruncate(cli, fnum, size);
3506 frame = talloc_stackframe();
3508 if (smbXcli_conn_has_async_calls(cli->conn)) {
3510 * Can't use sync call while an async call is in flight
3512 status = NT_STATUS_INVALID_PARAMETER;
3513 goto fail;
3516 ev = samba_tevent_context_init(frame);
3517 if (ev == NULL) {
3518 status = NT_STATUS_NO_MEMORY;
3519 goto fail;
3522 req = cli_ftruncate_send(frame,
3524 cli,
3525 fnum,
3526 size);
3527 if (req == NULL) {
3528 status = NT_STATUS_NO_MEMORY;
3529 goto fail;
3532 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3533 goto fail;
3536 status = cli_ftruncate_recv(req);
3538 fail:
3539 TALLOC_FREE(frame);
3540 return status;
3543 static uint8_t *cli_lockingx_put_locks(
3544 uint8_t *buf,
3545 bool large,
3546 uint16_t num_locks,
3547 const struct smb1_lock_element *locks)
3549 uint16_t i;
3551 for (i=0; i<num_locks; i++) {
3552 const struct smb1_lock_element *e = &locks[i];
3553 if (large) {
3554 SSVAL(buf, 0, e->pid);
3555 SSVAL(buf, 2, 0);
3556 SOFF_T_R(buf, 4, e->offset);
3557 SOFF_T_R(buf, 12, e->length);
3558 buf += 20;
3559 } else {
3560 SSVAL(buf, 0, e->pid);
3561 SIVAL(buf, 2, e->offset);
3562 SIVAL(buf, 6, e->length);
3563 buf += 10;
3566 return buf;
3569 struct cli_lockingx_state {
3570 uint16_t vwv[8];
3571 struct iovec bytes;
3572 struct tevent_req *subreq;
3575 static void cli_lockingx_done(struct tevent_req *subreq);
3576 static bool cli_lockingx_cancel(struct tevent_req *req);
3578 struct tevent_req *cli_lockingx_create(
3579 TALLOC_CTX *mem_ctx,
3580 struct tevent_context *ev,
3581 struct cli_state *cli,
3582 uint16_t fnum,
3583 uint8_t typeoflock,
3584 uint8_t newoplocklevel,
3585 int32_t timeout,
3586 uint16_t num_unlocks,
3587 const struct smb1_lock_element *unlocks,
3588 uint16_t num_locks,
3589 const struct smb1_lock_element *locks,
3590 struct tevent_req **psmbreq)
3592 struct tevent_req *req = NULL, *subreq = NULL;
3593 struct cli_lockingx_state *state = NULL;
3594 uint16_t *vwv;
3595 uint8_t *p;
3596 const bool large = (typeoflock & LOCKING_ANDX_LARGE_FILES);
3597 const size_t element_len = large ? 20 : 10;
3599 /* uint16->size_t, no overflow */
3600 const size_t num_elements = (size_t)num_locks + (size_t)num_unlocks;
3602 /* at most 20*2*65535 = 2621400, no overflow */
3603 const size_t num_bytes = num_elements * element_len;
3605 req = tevent_req_create(mem_ctx, &state, struct cli_lockingx_state);
3606 if (req == NULL) {
3607 return NULL;
3609 vwv = state->vwv;
3611 SCVAL(vwv + 0, 0, 0xFF);
3612 SCVAL(vwv + 0, 1, 0);
3613 SSVAL(vwv + 1, 0, 0);
3614 SSVAL(vwv + 2, 0, fnum);
3615 SCVAL(vwv + 3, 0, typeoflock);
3616 SCVAL(vwv + 3, 1, newoplocklevel);
3617 SIVALS(vwv + 4, 0, timeout);
3618 SSVAL(vwv + 6, 0, num_unlocks);
3619 SSVAL(vwv + 7, 0, num_locks);
3621 state->bytes.iov_len = num_bytes;
3622 state->bytes.iov_base = talloc_array(state, uint8_t, num_bytes);
3623 if (tevent_req_nomem(state->bytes.iov_base, req)) {
3624 return tevent_req_post(req, ev);
3627 p = cli_lockingx_put_locks(
3628 state->bytes.iov_base, large, num_unlocks, unlocks);
3629 cli_lockingx_put_locks(p, large, num_locks, locks);
3631 subreq = cli_smb_req_create(
3632 state, ev, cli, SMBlockingX, 0, 0, 8, vwv, 1, &state->bytes);
3633 if (tevent_req_nomem(subreq, req)) {
3634 return tevent_req_post(req, ev);
3636 tevent_req_set_callback(subreq, cli_lockingx_done, req);
3637 *psmbreq = subreq;
3638 return req;
3641 struct tevent_req *cli_lockingx_send(
3642 TALLOC_CTX *mem_ctx,
3643 struct tevent_context *ev,
3644 struct cli_state *cli,
3645 uint16_t fnum,
3646 uint8_t typeoflock,
3647 uint8_t newoplocklevel,
3648 int32_t timeout,
3649 uint16_t num_unlocks,
3650 const struct smb1_lock_element *unlocks,
3651 uint16_t num_locks,
3652 const struct smb1_lock_element *locks)
3654 struct tevent_req *req = NULL, *subreq = NULL;
3655 struct cli_lockingx_state *state = NULL;
3656 NTSTATUS status;
3658 req = cli_lockingx_create(
3659 mem_ctx,
3661 cli,
3662 fnum,
3663 typeoflock,
3664 newoplocklevel,
3665 timeout,
3666 num_unlocks,
3667 unlocks,
3668 num_locks,
3669 locks,
3670 &subreq);
3671 if (req == NULL) {
3672 return NULL;
3674 state = tevent_req_data(req, struct cli_lockingx_state);
3675 state->subreq = subreq;
3677 status = smb1cli_req_chain_submit(&subreq, 1);
3678 if (tevent_req_nterror(req, status)) {
3679 return tevent_req_post(req, ev);
3681 tevent_req_set_cancel_fn(req, cli_lockingx_cancel);
3682 return req;
3685 static void cli_lockingx_done(struct tevent_req *subreq)
3687 NTSTATUS status = cli_smb_recv(
3688 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3689 tevent_req_simple_finish_ntstatus(subreq, status);
3692 static bool cli_lockingx_cancel(struct tevent_req *req)
3694 struct cli_lockingx_state *state = tevent_req_data(
3695 req, struct cli_lockingx_state);
3696 if (state->subreq == NULL) {
3697 return false;
3699 return tevent_req_cancel(state->subreq);
3702 NTSTATUS cli_lockingx_recv(struct tevent_req *req)
3704 return tevent_req_simple_recv_ntstatus(req);
3707 NTSTATUS cli_lockingx(
3708 struct cli_state *cli,
3709 uint16_t fnum,
3710 uint8_t typeoflock,
3711 uint8_t newoplocklevel,
3712 int32_t timeout,
3713 uint16_t num_unlocks,
3714 const struct smb1_lock_element *unlocks,
3715 uint16_t num_locks,
3716 const struct smb1_lock_element *locks)
3718 TALLOC_CTX *frame = talloc_stackframe();
3719 struct tevent_context *ev = NULL;
3720 struct tevent_req *req = NULL;
3721 NTSTATUS status = NT_STATUS_NO_MEMORY;
3722 unsigned int set_timeout = 0;
3723 unsigned int saved_timeout = 0;
3725 if (smbXcli_conn_has_async_calls(cli->conn)) {
3726 return NT_STATUS_INVALID_PARAMETER;
3728 ev = samba_tevent_context_init(frame);
3729 if (ev == NULL) {
3730 goto fail;
3733 if (timeout != 0) {
3734 if (timeout == -1) {
3735 set_timeout = 0x7FFFFFFF;
3736 } else {
3737 set_timeout = timeout + 2*1000;
3739 saved_timeout = cli_set_timeout(cli, set_timeout);
3742 req = cli_lockingx_send(
3743 frame,
3745 cli,
3746 fnum,
3747 typeoflock,
3748 newoplocklevel,
3749 timeout,
3750 num_unlocks,
3751 unlocks,
3752 num_locks,
3753 locks);
3754 if (req == NULL) {
3755 goto fail;
3757 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3758 goto fail;
3760 status = cli_lockingx_recv(req);
3762 if (saved_timeout != 0) {
3763 cli_set_timeout(cli, saved_timeout);
3765 fail:
3766 TALLOC_FREE(frame);
3767 return status;
3770 /****************************************************************************
3771 send a lock with a specified locktype
3772 this is used for testing LOCKING_ANDX_CANCEL_LOCK
3773 ****************************************************************************/
3775 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
3776 uint32_t offset, uint32_t len,
3777 int timeout, unsigned char locktype)
3779 struct smb1_lock_element lck = {
3780 .pid = cli_getpid(cli),
3781 .offset = offset,
3782 .length = len,
3784 NTSTATUS status;
3786 status = cli_lockingx(
3787 cli, /* cli */
3788 fnum, /* fnum */
3789 locktype, /* typeoflock */
3790 0, /* newoplocklevel */
3791 timeout, /* timeout */
3792 0, /* num_unlocks */
3793 NULL, /* unlocks */
3794 1, /* num_locks */
3795 &lck); /* locks */
3796 return status;
3799 /****************************************************************************
3800 Lock a file.
3801 note that timeout is in units of 2 milliseconds
3802 ****************************************************************************/
3804 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
3805 uint32_t offset, uint32_t len, int timeout,
3806 enum brl_type lock_type)
3808 NTSTATUS status;
3810 status = cli_locktype(cli, fnum, offset, len, timeout,
3811 (lock_type == READ_LOCK? 1 : 0));
3812 return status;
3815 /****************************************************************************
3816 Unlock a file.
3817 ****************************************************************************/
3819 struct cli_unlock_state {
3820 struct smb1_lock_element lck;
3823 static void cli_unlock_done(struct tevent_req *subreq);
3825 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3826 struct tevent_context *ev,
3827 struct cli_state *cli,
3828 uint16_t fnum,
3829 uint64_t offset,
3830 uint64_t len)
3833 struct tevent_req *req = NULL, *subreq = NULL;
3834 struct cli_unlock_state *state = NULL;
3836 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3837 if (req == NULL) {
3838 return NULL;
3840 state->lck = (struct smb1_lock_element) {
3841 .pid = cli_getpid(cli),
3842 .offset = offset,
3843 .length = len,
3846 subreq = cli_lockingx_send(
3847 state, /* mem_ctx */
3848 ev, /* tevent_context */
3849 cli, /* cli */
3850 fnum, /* fnum */
3851 0, /* typeoflock */
3852 0, /* newoplocklevel */
3853 0, /* timeout */
3854 1, /* num_unlocks */
3855 &state->lck, /* unlocks */
3856 0, /* num_locks */
3857 NULL); /* locks */
3858 if (tevent_req_nomem(subreq, req)) {
3859 return tevent_req_post(req, ev);
3861 tevent_req_set_callback(subreq, cli_unlock_done, req);
3862 return req;
3865 static void cli_unlock_done(struct tevent_req *subreq)
3867 NTSTATUS status = cli_lockingx_recv(subreq);
3868 tevent_req_simple_finish_ntstatus(subreq, status);
3871 NTSTATUS cli_unlock_recv(struct tevent_req *req)
3873 return tevent_req_simple_recv_ntstatus(req);
3876 NTSTATUS cli_unlock(struct cli_state *cli,
3877 uint16_t fnum,
3878 uint32_t offset,
3879 uint32_t len)
3881 TALLOC_CTX *frame = talloc_stackframe();
3882 struct tevent_context *ev;
3883 struct tevent_req *req;
3884 NTSTATUS status = NT_STATUS_OK;
3886 if (smbXcli_conn_has_async_calls(cli->conn)) {
3888 * Can't use sync call while an async call is in flight
3890 status = NT_STATUS_INVALID_PARAMETER;
3891 goto fail;
3894 ev = samba_tevent_context_init(frame);
3895 if (ev == NULL) {
3896 status = NT_STATUS_NO_MEMORY;
3897 goto fail;
3900 req = cli_unlock_send(frame, ev, cli,
3901 fnum, offset, len);
3902 if (req == NULL) {
3903 status = NT_STATUS_NO_MEMORY;
3904 goto fail;
3907 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3908 goto fail;
3911 status = cli_unlock_recv(req);
3913 fail:
3914 TALLOC_FREE(frame);
3915 return status;
3918 /****************************************************************************
3919 Get/unlock a POSIX lock on a file - internal function.
3920 ****************************************************************************/
3922 struct posix_lock_state {
3923 uint16_t setup;
3924 uint8_t param[4];
3925 uint8_t data[POSIX_LOCK_DATA_SIZE];
3928 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3930 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3931 NULL, 0, NULL, NULL, 0, NULL);
3932 tevent_req_simple_finish_ntstatus(subreq, status);
3935 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3936 struct tevent_context *ev,
3937 struct cli_state *cli,
3938 uint16_t fnum,
3939 uint64_t offset,
3940 uint64_t len,
3941 bool wait_lock,
3942 enum brl_type lock_type)
3944 struct tevent_req *req = NULL, *subreq = NULL;
3945 struct posix_lock_state *state = NULL;
3947 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3948 if (req == NULL) {
3949 return NULL;
3952 /* Setup setup word. */
3953 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3955 /* Setup param array. */
3956 SSVAL(&state->param, 0, fnum);
3957 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3959 /* Setup data array. */
3960 switch (lock_type) {
3961 case READ_LOCK:
3962 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3963 POSIX_LOCK_TYPE_READ);
3964 break;
3965 case WRITE_LOCK:
3966 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3967 POSIX_LOCK_TYPE_WRITE);
3968 break;
3969 case UNLOCK_LOCK:
3970 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3971 POSIX_LOCK_TYPE_UNLOCK);
3972 break;
3973 default:
3974 return NULL;
3977 if (wait_lock) {
3978 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3979 POSIX_LOCK_FLAG_WAIT);
3980 } else {
3981 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3982 POSIX_LOCK_FLAG_NOWAIT);
3985 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3986 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3987 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3989 subreq = cli_trans_send(state, /* mem ctx. */
3990 ev, /* event ctx. */
3991 cli, /* cli_state. */
3992 0, /* additional_flags2 */
3993 SMBtrans2, /* cmd. */
3994 NULL, /* pipe name. */
3995 -1, /* fid. */
3996 0, /* function. */
3997 0, /* flags. */
3998 &state->setup, /* setup. */
3999 1, /* num setup uint16_t words. */
4000 0, /* max returned setup. */
4001 state->param, /* param. */
4002 4, /* num param. */
4003 2, /* max returned param. */
4004 state->data, /* data. */
4005 POSIX_LOCK_DATA_SIZE, /* num data. */
4006 0); /* max returned data. */
4008 if (tevent_req_nomem(subreq, req)) {
4009 return tevent_req_post(req, ev);
4011 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
4012 return req;
4015 /****************************************************************************
4016 POSIX Lock a file.
4017 ****************************************************************************/
4019 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
4020 struct tevent_context *ev,
4021 struct cli_state *cli,
4022 uint16_t fnum,
4023 uint64_t offset,
4024 uint64_t len,
4025 bool wait_lock,
4026 enum brl_type lock_type)
4028 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4029 wait_lock, lock_type);
4032 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
4034 return tevent_req_simple_recv_ntstatus(req);
4037 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
4038 uint64_t offset, uint64_t len,
4039 bool wait_lock, enum brl_type lock_type)
4041 TALLOC_CTX *frame = talloc_stackframe();
4042 struct tevent_context *ev = NULL;
4043 struct tevent_req *req = NULL;
4044 NTSTATUS status = NT_STATUS_OK;
4046 if (smbXcli_conn_has_async_calls(cli->conn)) {
4048 * Can't use sync call while an async call is in flight
4050 status = NT_STATUS_INVALID_PARAMETER;
4051 goto fail;
4054 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
4055 status = NT_STATUS_INVALID_PARAMETER;
4056 goto fail;
4059 ev = samba_tevent_context_init(frame);
4060 if (ev == NULL) {
4061 status = NT_STATUS_NO_MEMORY;
4062 goto fail;
4065 req = cli_posix_lock_send(frame,
4067 cli,
4068 fnum,
4069 offset,
4070 len,
4071 wait_lock,
4072 lock_type);
4073 if (req == NULL) {
4074 status = NT_STATUS_NO_MEMORY;
4075 goto fail;
4078 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4079 goto fail;
4082 status = cli_posix_lock_recv(req);
4084 fail:
4085 TALLOC_FREE(frame);
4086 return status;
4089 /****************************************************************************
4090 POSIX Unlock a file.
4091 ****************************************************************************/
4093 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
4094 struct tevent_context *ev,
4095 struct cli_state *cli,
4096 uint16_t fnum,
4097 uint64_t offset,
4098 uint64_t len)
4100 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4101 false, UNLOCK_LOCK);
4104 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
4106 return tevent_req_simple_recv_ntstatus(req);
4109 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
4111 TALLOC_CTX *frame = talloc_stackframe();
4112 struct tevent_context *ev = NULL;
4113 struct tevent_req *req = NULL;
4114 NTSTATUS status = NT_STATUS_OK;
4116 if (smbXcli_conn_has_async_calls(cli->conn)) {
4118 * Can't use sync call while an async call is in flight
4120 status = NT_STATUS_INVALID_PARAMETER;
4121 goto fail;
4124 ev = samba_tevent_context_init(frame);
4125 if (ev == NULL) {
4126 status = NT_STATUS_NO_MEMORY;
4127 goto fail;
4130 req = cli_posix_unlock_send(frame,
4132 cli,
4133 fnum,
4134 offset,
4135 len);
4136 if (req == NULL) {
4137 status = NT_STATUS_NO_MEMORY;
4138 goto fail;
4141 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4142 goto fail;
4145 status = cli_posix_unlock_recv(req);
4147 fail:
4148 TALLOC_FREE(frame);
4149 return status;
4152 /****************************************************************************
4153 Do a SMBgetattrE call.
4154 ****************************************************************************/
4156 static void cli_getattrE_done(struct tevent_req *subreq);
4158 struct cli_getattrE_state {
4159 uint16_t vwv[1];
4160 int zone_offset;
4161 uint32_t attr;
4162 off_t size;
4163 time_t change_time;
4164 time_t access_time;
4165 time_t write_time;
4168 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
4169 struct tevent_context *ev,
4170 struct cli_state *cli,
4171 uint16_t fnum)
4173 struct tevent_req *req = NULL, *subreq = NULL;
4174 struct cli_getattrE_state *state = NULL;
4175 uint8_t additional_flags = 0;
4177 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
4178 if (req == NULL) {
4179 return NULL;
4182 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4183 SSVAL(state->vwv+0,0,fnum);
4185 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
4186 1, state->vwv, 0, NULL);
4187 if (tevent_req_nomem(subreq, req)) {
4188 return tevent_req_post(req, ev);
4190 tevent_req_set_callback(subreq, cli_getattrE_done, req);
4191 return req;
4194 static void cli_getattrE_done(struct tevent_req *subreq)
4196 struct tevent_req *req = tevent_req_callback_data(
4197 subreq, struct tevent_req);
4198 struct cli_getattrE_state *state = tevent_req_data(
4199 req, struct cli_getattrE_state);
4200 uint8_t wct;
4201 uint16_t *vwv = NULL;
4202 NTSTATUS status;
4204 status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
4205 NULL, NULL);
4206 TALLOC_FREE(subreq);
4207 if (tevent_req_nterror(req, status)) {
4208 return;
4211 state->size = (off_t)IVAL(vwv+6,0);
4212 state->attr = SVAL(vwv+10,0);
4213 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
4214 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
4215 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
4217 tevent_req_done(req);
4220 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
4221 uint32_t *pattr,
4222 off_t *size,
4223 time_t *change_time,
4224 time_t *access_time,
4225 time_t *write_time)
4227 struct cli_getattrE_state *state = tevent_req_data(
4228 req, struct cli_getattrE_state);
4229 NTSTATUS status;
4231 if (tevent_req_is_nterror(req, &status)) {
4232 return status;
4234 if (pattr) {
4235 *pattr = state->attr;
4237 if (size) {
4238 *size = state->size;
4240 if (change_time) {
4241 *change_time = state->change_time;
4243 if (access_time) {
4244 *access_time = state->access_time;
4246 if (write_time) {
4247 *write_time = state->write_time;
4249 return NT_STATUS_OK;
4252 /****************************************************************************
4253 Do a SMBgetatr call
4254 ****************************************************************************/
4256 static void cli_getatr_done(struct tevent_req *subreq);
4258 struct cli_getatr_state {
4259 int zone_offset;
4260 uint32_t attr;
4261 off_t size;
4262 time_t write_time;
4265 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
4266 struct tevent_context *ev,
4267 struct cli_state *cli,
4268 const char *fname)
4270 struct tevent_req *req = NULL, *subreq = NULL;
4271 struct cli_getatr_state *state = NULL;
4272 uint8_t additional_flags = 0;
4273 uint16_t additional_flags2 = 0;
4274 uint8_t *bytes = NULL;
4276 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
4277 if (req == NULL) {
4278 return NULL;
4281 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4283 bytes = talloc_array(state, uint8_t, 1);
4284 if (tevent_req_nomem(bytes, req)) {
4285 return tevent_req_post(req, ev);
4287 bytes[0] = 4;
4288 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4289 strlen(fname)+1, NULL);
4291 if (tevent_req_nomem(bytes, req)) {
4292 return tevent_req_post(req, ev);
4295 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4296 additional_flags2 = FLAGS2_REPARSE_PATH;
4299 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
4300 additional_flags2,
4301 0, NULL, talloc_get_size(bytes), bytes);
4302 if (tevent_req_nomem(subreq, req)) {
4303 return tevent_req_post(req, ev);
4305 tevent_req_set_callback(subreq, cli_getatr_done, req);
4306 return req;
4309 static void cli_getatr_done(struct tevent_req *subreq)
4311 struct tevent_req *req = tevent_req_callback_data(
4312 subreq, struct tevent_req);
4313 struct cli_getatr_state *state = tevent_req_data(
4314 req, struct cli_getatr_state);
4315 uint8_t wct;
4316 uint16_t *vwv = NULL;
4317 NTSTATUS status;
4319 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4320 NULL);
4321 TALLOC_FREE(subreq);
4322 if (tevent_req_nterror(req, status)) {
4323 return;
4326 state->attr = SVAL(vwv+0,0);
4327 state->size = (off_t)IVAL(vwv+3,0);
4328 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
4330 tevent_req_done(req);
4333 NTSTATUS cli_getatr_recv(struct tevent_req *req,
4334 uint32_t *pattr,
4335 off_t *size,
4336 time_t *write_time)
4338 struct cli_getatr_state *state = tevent_req_data(
4339 req, struct cli_getatr_state);
4340 NTSTATUS status;
4342 if (tevent_req_is_nterror(req, &status)) {
4343 return status;
4345 if (pattr) {
4346 *pattr = state->attr;
4348 if (size) {
4349 *size = state->size;
4351 if (write_time) {
4352 *write_time = state->write_time;
4354 return NT_STATUS_OK;
4357 NTSTATUS cli_getatr(struct cli_state *cli,
4358 const char *fname,
4359 uint32_t *pattr,
4360 off_t *size,
4361 time_t *write_time)
4363 TALLOC_CTX *frame = NULL;
4364 struct tevent_context *ev = NULL;
4365 struct tevent_req *req = NULL;
4366 NTSTATUS status = NT_STATUS_OK;
4368 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4369 return cli_smb2_getatr(cli,
4370 fname,
4371 pattr,
4372 size,
4373 write_time);
4376 frame = talloc_stackframe();
4378 if (smbXcli_conn_has_async_calls(cli->conn)) {
4380 * Can't use sync call while an async call is in flight
4382 status = NT_STATUS_INVALID_PARAMETER;
4383 goto fail;
4386 ev = samba_tevent_context_init(frame);
4387 if (ev == NULL) {
4388 status = NT_STATUS_NO_MEMORY;
4389 goto fail;
4392 req = cli_getatr_send(frame, ev, cli, fname);
4393 if (req == NULL) {
4394 status = NT_STATUS_NO_MEMORY;
4395 goto fail;
4398 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4399 goto fail;
4402 status = cli_getatr_recv(req,
4403 pattr,
4404 size,
4405 write_time);
4407 fail:
4408 TALLOC_FREE(frame);
4409 return status;
4412 /****************************************************************************
4413 Do a SMBsetattrE call.
4414 ****************************************************************************/
4416 static void cli_setattrE_done(struct tevent_req *subreq);
4418 struct cli_setattrE_state {
4419 uint16_t vwv[7];
4422 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
4423 struct tevent_context *ev,
4424 struct cli_state *cli,
4425 uint16_t fnum,
4426 time_t change_time,
4427 time_t access_time,
4428 time_t write_time)
4430 struct tevent_req *req = NULL, *subreq = NULL;
4431 struct cli_setattrE_state *state = NULL;
4432 uint8_t additional_flags = 0;
4434 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
4435 if (req == NULL) {
4436 return NULL;
4439 SSVAL(state->vwv+0, 0, fnum);
4440 push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
4441 smb1cli_conn_server_time_zone(cli->conn));
4442 push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
4443 smb1cli_conn_server_time_zone(cli->conn));
4444 push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
4445 smb1cli_conn_server_time_zone(cli->conn));
4447 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
4448 7, state->vwv, 0, NULL);
4449 if (tevent_req_nomem(subreq, req)) {
4450 return tevent_req_post(req, ev);
4452 tevent_req_set_callback(subreq, cli_setattrE_done, req);
4453 return req;
4456 static void cli_setattrE_done(struct tevent_req *subreq)
4458 struct tevent_req *req = tevent_req_callback_data(
4459 subreq, struct tevent_req);
4460 NTSTATUS status;
4462 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4463 TALLOC_FREE(subreq);
4464 if (tevent_req_nterror(req, status)) {
4465 return;
4467 tevent_req_done(req);
4470 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4472 return tevent_req_simple_recv_ntstatus(req);
4475 NTSTATUS cli_setattrE(struct cli_state *cli,
4476 uint16_t fnum,
4477 time_t change_time,
4478 time_t access_time,
4479 time_t write_time)
4481 TALLOC_CTX *frame = NULL;
4482 struct tevent_context *ev = NULL;
4483 struct tevent_req *req = NULL;
4484 NTSTATUS status = NT_STATUS_OK;
4486 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4487 return cli_smb2_setattrE(cli,
4488 fnum,
4489 change_time,
4490 access_time,
4491 write_time);
4494 frame = talloc_stackframe();
4496 if (smbXcli_conn_has_async_calls(cli->conn)) {
4498 * Can't use sync call while an async call is in flight
4500 status = NT_STATUS_INVALID_PARAMETER;
4501 goto fail;
4504 ev = samba_tevent_context_init(frame);
4505 if (ev == NULL) {
4506 status = NT_STATUS_NO_MEMORY;
4507 goto fail;
4510 req = cli_setattrE_send(frame, ev,
4511 cli,
4512 fnum,
4513 change_time,
4514 access_time,
4515 write_time);
4517 if (req == NULL) {
4518 status = NT_STATUS_NO_MEMORY;
4519 goto fail;
4522 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4523 goto fail;
4526 status = cli_setattrE_recv(req);
4528 fail:
4529 TALLOC_FREE(frame);
4530 return status;
4533 /****************************************************************************
4534 Do a SMBsetatr call.
4535 ****************************************************************************/
4537 static void cli_setatr_done(struct tevent_req *subreq);
4539 struct cli_setatr_state {
4540 uint16_t vwv[8];
4543 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
4544 struct tevent_context *ev,
4545 struct cli_state *cli,
4546 const char *fname,
4547 uint32_t attr,
4548 time_t mtime)
4550 struct tevent_req *req = NULL, *subreq = NULL;
4551 struct cli_setatr_state *state = NULL;
4552 uint8_t additional_flags = 0;
4553 uint16_t additional_flags2 = 0;
4554 uint8_t *bytes = NULL;
4556 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
4557 if (req == NULL) {
4558 return NULL;
4561 if (attr & 0xFFFF0000) {
4563 * Don't allow attributes greater than
4564 * 16-bits for a 16-bit protocol value.
4566 if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
4567 return tevent_req_post(req, ev);
4571 SSVAL(state->vwv+0, 0, attr);
4572 push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
4574 bytes = talloc_array(state, uint8_t, 1);
4575 if (tevent_req_nomem(bytes, req)) {
4576 return tevent_req_post(req, ev);
4578 bytes[0] = 4;
4579 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4580 strlen(fname)+1, NULL);
4581 if (tevent_req_nomem(bytes, req)) {
4582 return tevent_req_post(req, ev);
4584 bytes = talloc_realloc(state, bytes, uint8_t,
4585 talloc_get_size(bytes)+1);
4586 if (tevent_req_nomem(bytes, req)) {
4587 return tevent_req_post(req, ev);
4590 bytes[talloc_get_size(bytes)-1] = 4;
4591 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
4592 1, NULL);
4593 if (tevent_req_nomem(bytes, req)) {
4594 return tevent_req_post(req, ev);
4597 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4598 additional_flags2 = FLAGS2_REPARSE_PATH;
4601 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
4602 additional_flags2,
4603 8, state->vwv, talloc_get_size(bytes), bytes);
4604 if (tevent_req_nomem(subreq, req)) {
4605 return tevent_req_post(req, ev);
4607 tevent_req_set_callback(subreq, cli_setatr_done, req);
4608 return req;
4611 static void cli_setatr_done(struct tevent_req *subreq)
4613 struct tevent_req *req = tevent_req_callback_data(
4614 subreq, struct tevent_req);
4615 NTSTATUS status;
4617 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4618 TALLOC_FREE(subreq);
4619 if (tevent_req_nterror(req, status)) {
4620 return;
4622 tevent_req_done(req);
4625 NTSTATUS cli_setatr_recv(struct tevent_req *req)
4627 return tevent_req_simple_recv_ntstatus(req);
4630 NTSTATUS cli_setatr(struct cli_state *cli,
4631 const char *fname,
4632 uint32_t attr,
4633 time_t mtime)
4635 TALLOC_CTX *frame = NULL;
4636 struct tevent_context *ev = NULL;
4637 struct tevent_req *req = NULL;
4638 NTSTATUS status = NT_STATUS_OK;
4640 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4641 return cli_smb2_setatr(cli,
4642 fname,
4643 attr,
4644 mtime);
4647 frame = talloc_stackframe();
4649 if (smbXcli_conn_has_async_calls(cli->conn)) {
4651 * Can't use sync call while an async call is in flight
4653 status = NT_STATUS_INVALID_PARAMETER;
4654 goto fail;
4657 ev = samba_tevent_context_init(frame);
4658 if (ev == NULL) {
4659 status = NT_STATUS_NO_MEMORY;
4660 goto fail;
4663 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
4664 if (req == NULL) {
4665 status = NT_STATUS_NO_MEMORY;
4666 goto fail;
4669 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4670 goto fail;
4673 status = cli_setatr_recv(req);
4675 fail:
4676 TALLOC_FREE(frame);
4677 return status;
4680 /****************************************************************************
4681 Check for existence of a dir.
4682 ****************************************************************************/
4684 static void cli_chkpath_done(struct tevent_req *subreq);
4685 static void cli_chkpath_opened(struct tevent_req *subreq);
4686 static void cli_chkpath_closed(struct tevent_req *subreq);
4688 struct cli_chkpath_state {
4689 struct tevent_context *ev;
4690 struct cli_state *cli;
4693 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
4694 struct tevent_context *ev,
4695 struct cli_state *cli,
4696 const char *fname)
4698 struct tevent_req *req = NULL, *subreq = NULL;
4699 struct cli_chkpath_state *state = NULL;
4700 uint8_t additional_flags = 0;
4701 uint16_t additional_flags2 = 0;
4702 uint8_t *bytes = NULL;
4704 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
4705 if (req == NULL) {
4706 return NULL;
4708 state->ev = ev;
4709 state->cli = cli;
4711 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_NT1) {
4712 subreq = cli_ntcreate_send(
4713 state, /* mem_ctx */
4714 state->ev, /* ev */
4715 state->cli, /* cli */
4716 fname, /* fname */
4717 0, /* create_flags */
4718 FILE_READ_ATTRIBUTES, /* desired_access */
4719 FILE_ATTRIBUTE_DIRECTORY, /* FileAttributes */
4720 FILE_SHARE_READ|
4721 FILE_SHARE_WRITE|
4722 FILE_SHARE_DELETE, /* share_access */
4723 FILE_OPEN, /* CreateDisposition */
4724 FILE_DIRECTORY_FILE, /* CreateOptions */
4725 SMB2_IMPERSONATION_IMPERSONATION,
4726 0); /* SecurityFlags */
4727 if (tevent_req_nomem(subreq, req)) {
4728 return tevent_req_post(req, ev);
4730 tevent_req_set_callback(subreq, cli_chkpath_opened, req);
4731 return req;
4734 bytes = talloc_array(state, uint8_t, 1);
4735 if (tevent_req_nomem(bytes, req)) {
4736 return tevent_req_post(req, ev);
4738 bytes[0] = 4;
4739 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4740 strlen(fname)+1, NULL);
4742 if (tevent_req_nomem(bytes, req)) {
4743 return tevent_req_post(req, ev);
4746 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4747 additional_flags2 = FLAGS2_REPARSE_PATH;
4750 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
4751 additional_flags2,
4752 0, NULL, talloc_get_size(bytes), bytes);
4753 if (tevent_req_nomem(subreq, req)) {
4754 return tevent_req_post(req, ev);
4756 tevent_req_set_callback(subreq, cli_chkpath_done, req);
4757 return req;
4760 static void cli_chkpath_done(struct tevent_req *subreq)
4762 NTSTATUS status = cli_smb_recv(
4763 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4764 tevent_req_simple_finish_ntstatus(subreq, status);
4767 static void cli_chkpath_opened(struct tevent_req *subreq)
4769 struct tevent_req *req = tevent_req_callback_data(
4770 subreq, struct tevent_req);
4771 struct cli_chkpath_state *state = tevent_req_data(
4772 req, struct cli_chkpath_state);
4773 NTSTATUS status;
4774 uint16_t fnum;
4776 status = cli_ntcreate_recv(subreq, &fnum, NULL);
4777 TALLOC_FREE(subreq);
4778 if (tevent_req_nterror(req, status)) {
4779 return;
4782 subreq = cli_close_send(state, state->ev, state->cli, fnum);
4783 if (tevent_req_nomem(subreq, req)) {
4784 return;
4786 tevent_req_set_callback(subreq, cli_chkpath_closed, req);
4789 static void cli_chkpath_closed(struct tevent_req *subreq)
4791 NTSTATUS status = cli_close_recv(subreq);
4792 tevent_req_simple_finish_ntstatus(subreq, status);
4795 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
4797 return tevent_req_simple_recv_ntstatus(req);
4800 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
4802 TALLOC_CTX *frame = NULL;
4803 struct tevent_context *ev = NULL;
4804 struct tevent_req *req = NULL;
4805 char *path2 = NULL;
4806 NTSTATUS status = NT_STATUS_OK;
4808 frame = talloc_stackframe();
4810 if (smbXcli_conn_has_async_calls(cli->conn)) {
4812 * Can't use sync call while an async call is in flight
4814 status = NT_STATUS_INVALID_PARAMETER;
4815 goto fail;
4818 path2 = talloc_strdup(frame, path);
4819 if (!path2) {
4820 status = NT_STATUS_NO_MEMORY;
4821 goto fail;
4823 trim_char(path2,'\0','\\');
4824 if (!*path2) {
4825 path2 = talloc_strdup(frame, "\\");
4826 if (!path2) {
4827 status = NT_STATUS_NO_MEMORY;
4828 goto fail;
4832 ev = samba_tevent_context_init(frame);
4833 if (ev == NULL) {
4834 status = NT_STATUS_NO_MEMORY;
4835 goto fail;
4838 req = cli_chkpath_send(frame, ev, cli, path2);
4839 if (req == NULL) {
4840 status = NT_STATUS_NO_MEMORY;
4841 goto fail;
4844 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4845 goto fail;
4848 status = cli_chkpath_recv(req);
4849 cli->raw_status = status; /* cli_smb2_chkpath_recv doesn't set this */
4851 fail:
4852 TALLOC_FREE(frame);
4853 return status;
4856 /****************************************************************************
4857 Query disk space.
4858 ****************************************************************************/
4860 static void cli_dskattr_done(struct tevent_req *subreq);
4862 struct cli_dskattr_state {
4863 int bsize;
4864 int total;
4865 int avail;
4868 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
4869 struct tevent_context *ev,
4870 struct cli_state *cli)
4872 struct tevent_req *req = NULL, *subreq = NULL;
4873 struct cli_dskattr_state *state = NULL;
4874 uint8_t additional_flags = 0;
4876 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
4877 if (req == NULL) {
4878 return NULL;
4881 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
4882 0, NULL, 0, NULL);
4883 if (tevent_req_nomem(subreq, req)) {
4884 return tevent_req_post(req, ev);
4886 tevent_req_set_callback(subreq, cli_dskattr_done, req);
4887 return req;
4890 static void cli_dskattr_done(struct tevent_req *subreq)
4892 struct tevent_req *req = tevent_req_callback_data(
4893 subreq, struct tevent_req);
4894 struct cli_dskattr_state *state = tevent_req_data(
4895 req, struct cli_dskattr_state);
4896 uint8_t wct;
4897 uint16_t *vwv = NULL;
4898 NTSTATUS status;
4900 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4901 NULL);
4902 TALLOC_FREE(subreq);
4903 if (tevent_req_nterror(req, status)) {
4904 return;
4906 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
4907 state->total = SVAL(vwv+0, 0);
4908 state->avail = SVAL(vwv+3, 0);
4909 tevent_req_done(req);
4912 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
4914 struct cli_dskattr_state *state = tevent_req_data(
4915 req, struct cli_dskattr_state);
4916 NTSTATUS status;
4918 if (tevent_req_is_nterror(req, &status)) {
4919 return status;
4921 *bsize = state->bsize;
4922 *total = state->total;
4923 *avail = state->avail;
4924 return NT_STATUS_OK;
4927 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
4929 TALLOC_CTX *frame = NULL;
4930 struct tevent_context *ev = NULL;
4931 struct tevent_req *req = NULL;
4932 NTSTATUS status = NT_STATUS_OK;
4934 frame = talloc_stackframe();
4936 if (smbXcli_conn_has_async_calls(cli->conn)) {
4938 * Can't use sync call while an async call is in flight
4940 status = NT_STATUS_INVALID_PARAMETER;
4941 goto fail;
4944 ev = samba_tevent_context_init(frame);
4945 if (ev == NULL) {
4946 status = NT_STATUS_NO_MEMORY;
4947 goto fail;
4950 req = cli_dskattr_send(frame, ev, cli);
4951 if (req == NULL) {
4952 status = NT_STATUS_NO_MEMORY;
4953 goto fail;
4956 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4957 goto fail;
4960 status = cli_dskattr_recv(req, bsize, total, avail);
4962 fail:
4963 TALLOC_FREE(frame);
4964 return status;
4967 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
4968 uint64_t *total, uint64_t *avail)
4970 uint64_t sectors_per_block;
4971 uint64_t bytes_per_sector;
4972 int old_bsize = 0, old_total = 0, old_avail = 0;
4973 NTSTATUS status;
4975 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4976 return cli_smb2_dskattr(cli, path, bsize, total, avail);
4980 * Try the trans2 disk full size info call first.
4981 * We already use this in SMBC_fstatvfs_ctx().
4982 * Ignore 'actual_available_units' as we only
4983 * care about the quota for the caller.
4986 status = cli_get_fs_full_size_info(cli,
4987 total,
4988 avail,
4989 NULL,
4990 &sectors_per_block,
4991 &bytes_per_sector);
4993 /* Try and cope will all varients of "we don't do this call"
4994 and fall back to cli_dskattr. */
4996 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
4997 NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
4998 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
4999 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
5000 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
5001 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
5002 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
5003 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
5004 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
5005 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
5006 goto try_dskattr;
5009 if (!NT_STATUS_IS_OK(status)) {
5010 return status;
5013 if (bsize) {
5014 *bsize = sectors_per_block *
5015 bytes_per_sector;
5018 return NT_STATUS_OK;
5020 try_dskattr:
5022 /* Old SMB1 core protocol fallback. */
5023 status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
5024 if (!NT_STATUS_IS_OK(status)) {
5025 return status;
5027 if (bsize) {
5028 *bsize = (uint64_t)old_bsize;
5030 if (total) {
5031 *total = (uint64_t)old_total;
5033 if (avail) {
5034 *avail = (uint64_t)old_avail;
5036 return NT_STATUS_OK;
5039 /****************************************************************************
5040 Create and open a temporary file.
5041 ****************************************************************************/
5043 static void cli_ctemp_done(struct tevent_req *subreq);
5045 struct ctemp_state {
5046 uint16_t vwv[3];
5047 char *ret_path;
5048 uint16_t fnum;
5051 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
5052 struct tevent_context *ev,
5053 struct cli_state *cli,
5054 const char *path)
5056 struct tevent_req *req = NULL, *subreq = NULL;
5057 struct ctemp_state *state = NULL;
5058 uint8_t additional_flags = 0;
5059 uint16_t additional_flags2 = 0;
5060 uint8_t *bytes = NULL;
5062 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
5063 if (req == NULL) {
5064 return NULL;
5067 SSVAL(state->vwv,0,0);
5068 SIVALS(state->vwv+1,0,-1);
5070 bytes = talloc_array(state, uint8_t, 1);
5071 if (tevent_req_nomem(bytes, req)) {
5072 return tevent_req_post(req, ev);
5074 bytes[0] = 4;
5075 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
5076 strlen(path)+1, NULL);
5077 if (tevent_req_nomem(bytes, req)) {
5078 return tevent_req_post(req, ev);
5081 if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
5082 additional_flags2 = FLAGS2_REPARSE_PATH;
5085 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
5086 additional_flags2,
5087 3, state->vwv, talloc_get_size(bytes), bytes);
5088 if (tevent_req_nomem(subreq, req)) {
5089 return tevent_req_post(req, ev);
5091 tevent_req_set_callback(subreq, cli_ctemp_done, req);
5092 return req;
5095 static void cli_ctemp_done(struct tevent_req *subreq)
5097 struct tevent_req *req = tevent_req_callback_data(
5098 subreq, struct tevent_req);
5099 struct ctemp_state *state = tevent_req_data(
5100 req, struct ctemp_state);
5101 NTSTATUS status;
5102 uint8_t wcnt;
5103 uint16_t *vwv;
5104 uint32_t num_bytes = 0;
5105 uint8_t *bytes = NULL;
5107 status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
5108 &num_bytes, &bytes);
5109 TALLOC_FREE(subreq);
5110 if (tevent_req_nterror(req, status)) {
5111 return;
5114 state->fnum = SVAL(vwv+0, 0);
5116 /* From W2K3, the result is just the ASCII name */
5117 if (num_bytes < 2) {
5118 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
5119 return;
5122 if (pull_string_talloc(state,
5123 NULL,
5125 &state->ret_path,
5126 bytes,
5127 num_bytes,
5128 STR_ASCII) == 0) {
5129 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5130 return;
5132 tevent_req_done(req);
5135 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
5136 TALLOC_CTX *ctx,
5137 uint16_t *pfnum,
5138 char **outfile)
5140 struct ctemp_state *state = tevent_req_data(req,
5141 struct ctemp_state);
5142 NTSTATUS status;
5144 if (tevent_req_is_nterror(req, &status)) {
5145 return status;
5147 *pfnum = state->fnum;
5148 *outfile = talloc_strdup(ctx, state->ret_path);
5149 if (!*outfile) {
5150 return NT_STATUS_NO_MEMORY;
5152 return NT_STATUS_OK;
5155 NTSTATUS cli_ctemp(struct cli_state *cli,
5156 TALLOC_CTX *ctx,
5157 const char *path,
5158 uint16_t *pfnum,
5159 char **out_path)
5161 TALLOC_CTX *frame = talloc_stackframe();
5162 struct tevent_context *ev;
5163 struct tevent_req *req;
5164 NTSTATUS status = NT_STATUS_OK;
5166 if (smbXcli_conn_has_async_calls(cli->conn)) {
5168 * Can't use sync call while an async call is in flight
5170 status = NT_STATUS_INVALID_PARAMETER;
5171 goto fail;
5174 ev = samba_tevent_context_init(frame);
5175 if (ev == NULL) {
5176 status = NT_STATUS_NO_MEMORY;
5177 goto fail;
5180 req = cli_ctemp_send(frame, ev, cli, path);
5181 if (req == NULL) {
5182 status = NT_STATUS_NO_MEMORY;
5183 goto fail;
5186 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5187 goto fail;
5190 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
5192 fail:
5193 TALLOC_FREE(frame);
5194 return status;
5198 send a raw ioctl - used by the torture code
5200 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
5202 uint16_t vwv[3];
5203 NTSTATUS status;
5205 SSVAL(vwv+0, 0, fnum);
5206 SSVAL(vwv+1, 0, code>>16);
5207 SSVAL(vwv+2, 0, (code&0xFFFF));
5209 status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
5210 NULL, 0, NULL, NULL, NULL, NULL);
5211 if (!NT_STATUS_IS_OK(status)) {
5212 return status;
5214 *blob = data_blob_null;
5215 return NT_STATUS_OK;
5218 /*********************************************************
5219 Set an extended attribute utility fn.
5220 *********************************************************/
5222 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
5223 uint8_t *param, unsigned int param_len,
5224 const char *ea_name,
5225 const char *ea_val, size_t ea_len)
5227 uint16_t setup[1];
5228 unsigned int data_len = 0;
5229 uint8_t *data = NULL;
5230 char *p;
5231 size_t ea_namelen = strlen(ea_name);
5232 NTSTATUS status;
5234 SSVAL(setup, 0, setup_val);
5236 if (ea_namelen == 0 && ea_len == 0) {
5237 data_len = 4;
5238 data = talloc_array(talloc_tos(),
5239 uint8_t,
5240 data_len);
5241 if (!data) {
5242 return NT_STATUS_NO_MEMORY;
5244 p = (char *)data;
5245 SIVAL(p,0,data_len);
5246 } else {
5247 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
5248 data = talloc_array(talloc_tos(),
5249 uint8_t,
5250 data_len);
5251 if (!data) {
5252 return NT_STATUS_NO_MEMORY;
5254 p = (char *)data;
5255 SIVAL(p,0,data_len);
5256 p += 4;
5257 SCVAL(p, 0, 0); /* EA flags. */
5258 SCVAL(p, 1, ea_namelen);
5259 SSVAL(p, 2, ea_len);
5260 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
5261 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
5265 * FIXME - if we want to do previous version path
5266 * processing on an EA set call we need to turn this
5267 * into calls to cli_trans_send()/cli_trans_recv()
5268 * with a temporary event context, as cli_trans_send()
5269 * have access to the additional_flags2 needed to
5270 * send @GMT- paths. JRA.
5273 status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
5274 setup, 1, 0,
5275 param, param_len, 2,
5276 data, data_len, 0,
5277 NULL,
5278 NULL, 0, NULL, /* rsetup */
5279 NULL, 0, NULL, /* rparam */
5280 NULL, 0, NULL); /* rdata */
5281 talloc_free(data);
5282 return status;
5285 /*********************************************************
5286 Set an extended attribute on a pathname.
5287 *********************************************************/
5289 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
5290 const char *ea_name, const char *ea_val,
5291 size_t ea_len)
5293 unsigned int param_len = 0;
5294 uint8_t *param;
5295 NTSTATUS status;
5296 TALLOC_CTX *frame = NULL;
5298 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5299 return cli_smb2_set_ea_path(cli,
5300 path,
5301 ea_name,
5302 ea_val,
5303 ea_len);
5306 frame = talloc_stackframe();
5308 param = talloc_array(frame, uint8_t, 6);
5309 if (!param) {
5310 status = NT_STATUS_NO_MEMORY;
5311 goto fail;
5313 SSVAL(param,0,SMB_INFO_SET_EA);
5314 SSVAL(param,2,0);
5315 SSVAL(param,4,0);
5317 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
5318 path, strlen(path)+1,
5319 NULL);
5320 param_len = talloc_get_size(param);
5322 status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
5323 ea_name, ea_val, ea_len);
5325 fail:
5327 TALLOC_FREE(frame);
5328 return status;
5331 /*********************************************************
5332 Set an extended attribute on an fnum.
5333 *********************************************************/
5335 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
5336 const char *ea_name, const char *ea_val,
5337 size_t ea_len)
5339 uint8_t param[6] = { 0, };
5341 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5342 return cli_smb2_set_ea_fnum(cli,
5343 fnum,
5344 ea_name,
5345 ea_val,
5346 ea_len);
5349 SSVAL(param,0,fnum);
5350 SSVAL(param,2,SMB_INFO_SET_EA);
5352 return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
5353 ea_name, ea_val, ea_len);
5356 /*********************************************************
5357 Get an extended attribute list utility fn.
5358 *********************************************************/
5360 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
5361 size_t rdata_len,
5362 size_t *pnum_eas, struct ea_struct **pea_list)
5364 struct ea_struct *ea_list = NULL;
5365 size_t num_eas;
5366 size_t ea_size;
5367 const uint8_t *p;
5369 if (rdata_len < 4) {
5370 return false;
5373 ea_size = (size_t)IVAL(rdata,0);
5374 if (ea_size > rdata_len) {
5375 return false;
5378 if (ea_size == 0) {
5379 /* No EA's present. */
5380 *pnum_eas = 0;
5381 *pea_list = NULL;
5382 return true;
5385 p = rdata + 4;
5386 ea_size -= 4;
5388 /* Validate the EA list and count it. */
5389 for (num_eas = 0; ea_size >= 4; num_eas++) {
5390 unsigned int ea_namelen = CVAL(p,1);
5391 unsigned int ea_valuelen = SVAL(p,2);
5392 if (ea_namelen == 0) {
5393 return false;
5395 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
5396 return false;
5398 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
5399 p += 4 + ea_namelen + 1 + ea_valuelen;
5402 if (num_eas == 0) {
5403 *pnum_eas = 0;
5404 *pea_list = NULL;
5405 return true;
5408 *pnum_eas = num_eas;
5409 if (!pea_list) {
5410 /* Caller only wants number of EA's. */
5411 return true;
5414 ea_list = talloc_array(ctx, struct ea_struct, num_eas);
5415 if (!ea_list) {
5416 return false;
5419 p = rdata + 4;
5421 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
5422 struct ea_struct *ea = &ea_list[num_eas];
5423 fstring unix_ea_name;
5424 unsigned int ea_namelen = CVAL(p,1);
5425 unsigned int ea_valuelen = SVAL(p,2);
5427 ea->flags = CVAL(p,0);
5428 unix_ea_name[0] = '\0';
5429 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
5430 ea->name = talloc_strdup(ea_list, unix_ea_name);
5431 if (!ea->name) {
5432 goto fail;
5434 /* Ensure the value is null terminated (in case it's a string). */
5435 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
5436 if (!ea->value.data) {
5437 goto fail;
5439 if (ea_valuelen) {
5440 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
5442 ea->value.data[ea_valuelen] = 0;
5443 ea->value.length--;
5444 p += 4 + ea_namelen + 1 + ea_valuelen;
5447 *pea_list = ea_list;
5448 return true;
5450 fail:
5451 TALLOC_FREE(ea_list);
5452 return false;
5455 /*********************************************************
5456 Get an extended attribute list from a pathname.
5457 *********************************************************/
5459 struct cli_get_ea_list_path_state {
5460 uint32_t num_data;
5461 uint8_t *data;
5464 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
5466 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
5467 struct tevent_context *ev,
5468 struct cli_state *cli,
5469 const char *fname)
5471 struct tevent_req *req, *subreq;
5472 struct cli_get_ea_list_path_state *state;
5474 req = tevent_req_create(mem_ctx, &state,
5475 struct cli_get_ea_list_path_state);
5476 if (req == NULL) {
5477 return NULL;
5479 subreq = cli_qpathinfo_send(state, ev, cli, fname,
5480 SMB_INFO_QUERY_ALL_EAS, 4,
5481 CLI_BUFFER_SIZE);
5482 if (tevent_req_nomem(subreq, req)) {
5483 return tevent_req_post(req, ev);
5485 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
5486 return req;
5489 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
5491 struct tevent_req *req = tevent_req_callback_data(
5492 subreq, struct tevent_req);
5493 struct cli_get_ea_list_path_state *state = tevent_req_data(
5494 req, struct cli_get_ea_list_path_state);
5495 NTSTATUS status;
5497 status = cli_qpathinfo_recv(subreq, state, &state->data,
5498 &state->num_data);
5499 TALLOC_FREE(subreq);
5500 if (tevent_req_nterror(req, status)) {
5501 return;
5503 tevent_req_done(req);
5506 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5507 size_t *pnum_eas, struct ea_struct **peas)
5509 struct cli_get_ea_list_path_state *state = tevent_req_data(
5510 req, struct cli_get_ea_list_path_state);
5511 NTSTATUS status;
5513 if (tevent_req_is_nterror(req, &status)) {
5514 return status;
5516 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
5517 pnum_eas, peas)) {
5518 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5520 return NT_STATUS_OK;
5523 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
5524 TALLOC_CTX *ctx,
5525 size_t *pnum_eas,
5526 struct ea_struct **pea_list)
5528 TALLOC_CTX *frame = NULL;
5529 struct tevent_context *ev = NULL;
5530 struct tevent_req *req = NULL;
5531 NTSTATUS status = NT_STATUS_NO_MEMORY;
5533 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5534 return cli_smb2_get_ea_list_path(cli,
5535 path,
5536 ctx,
5537 pnum_eas,
5538 pea_list);
5541 frame = talloc_stackframe();
5543 if (smbXcli_conn_has_async_calls(cli->conn)) {
5545 * Can't use sync call while an async call is in flight
5547 status = NT_STATUS_INVALID_PARAMETER;
5548 goto fail;
5550 ev = samba_tevent_context_init(frame);
5551 if (ev == NULL) {
5552 goto fail;
5554 req = cli_get_ea_list_path_send(frame, ev, cli, path);
5555 if (req == NULL) {
5556 goto fail;
5558 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5559 goto fail;
5561 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
5562 fail:
5563 TALLOC_FREE(frame);
5564 return status;
5567 /****************************************************************************
5568 Convert open "flags" arg to uint32_t on wire.
5569 ****************************************************************************/
5571 static uint32_t open_flags_to_wire(int flags)
5573 int open_mode = flags & O_ACCMODE;
5574 uint32_t ret = 0;
5576 switch (open_mode) {
5577 case O_WRONLY:
5578 ret |= SMB_O_WRONLY;
5579 break;
5580 case O_RDWR:
5581 ret |= SMB_O_RDWR;
5582 break;
5583 default:
5584 case O_RDONLY:
5585 ret |= SMB_O_RDONLY;
5586 break;
5589 if (flags & O_CREAT) {
5590 ret |= SMB_O_CREAT;
5592 if (flags & O_EXCL) {
5593 ret |= SMB_O_EXCL;
5595 if (flags & O_TRUNC) {
5596 ret |= SMB_O_TRUNC;
5598 #if defined(O_SYNC)
5599 if (flags & O_SYNC) {
5600 ret |= SMB_O_SYNC;
5602 #endif /* O_SYNC */
5603 if (flags & O_APPEND) {
5604 ret |= SMB_O_APPEND;
5606 #if defined(O_DIRECT)
5607 if (flags & O_DIRECT) {
5608 ret |= SMB_O_DIRECT;
5610 #endif
5611 #if defined(O_DIRECTORY)
5612 if (flags & O_DIRECTORY) {
5613 ret |= SMB_O_DIRECTORY;
5615 #endif
5616 return ret;
5619 /****************************************************************************
5620 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
5621 ****************************************************************************/
5623 struct cli_posix_open_internal_state {
5624 uint16_t setup;
5625 uint8_t *param;
5626 uint8_t data[18];
5627 uint16_t fnum; /* Out */
5630 static void cli_posix_open_internal_done(struct tevent_req *subreq);
5632 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
5633 struct tevent_context *ev,
5634 struct cli_state *cli,
5635 const char *fname,
5636 uint32_t wire_flags,
5637 mode_t mode)
5639 struct tevent_req *req = NULL, *subreq = NULL;
5640 struct cli_posix_open_internal_state *state = NULL;
5642 req = tevent_req_create(
5643 mem_ctx, &state, struct cli_posix_open_internal_state);
5644 if (req == NULL) {
5645 return NULL;
5648 /* Setup setup word. */
5649 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
5651 /* Setup param array. */
5652 state->param = talloc_zero_array(state, uint8_t, 6);
5653 if (tevent_req_nomem(state->param, req)) {
5654 return tevent_req_post(req, ev);
5656 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
5658 state->param = trans2_bytes_push_str(
5659 state->param,
5660 smbXcli_conn_use_unicode(cli->conn),
5661 fname,
5662 strlen(fname)+1,
5663 NULL);
5665 if (tevent_req_nomem(state->param, req)) {
5666 return tevent_req_post(req, ev);
5669 SIVAL(state->data,0,0); /* No oplock. */
5670 SIVAL(state->data,4,wire_flags);
5671 SIVAL(state->data,8,unix_perms_to_wire(mode));
5672 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
5673 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
5675 subreq = cli_trans_send(state, /* mem ctx. */
5676 ev, /* event ctx. */
5677 cli, /* cli_state. */
5678 0, /* additional_flags2 */
5679 SMBtrans2, /* cmd. */
5680 NULL, /* pipe name. */
5681 -1, /* fid. */
5682 0, /* function. */
5683 0, /* flags. */
5684 &state->setup, /* setup. */
5685 1, /* num setup uint16_t words. */
5686 0, /* max returned setup. */
5687 state->param, /* param. */
5688 talloc_get_size(state->param),/* num param. */
5689 2, /* max returned param. */
5690 state->data, /* data. */
5691 18, /* num data. */
5692 12); /* max returned data. */
5694 if (tevent_req_nomem(subreq, req)) {
5695 return tevent_req_post(req, ev);
5697 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
5698 return req;
5701 static void cli_posix_open_internal_done(struct tevent_req *subreq)
5703 struct tevent_req *req = tevent_req_callback_data(
5704 subreq, struct tevent_req);
5705 struct cli_posix_open_internal_state *state = tevent_req_data(
5706 req, struct cli_posix_open_internal_state);
5707 NTSTATUS status;
5708 uint8_t *data;
5709 uint32_t num_data;
5711 status = cli_trans_recv(
5712 subreq,
5713 state,
5714 NULL,
5715 NULL,
5717 NULL,
5718 NULL,
5720 NULL,
5721 &data,
5723 &num_data);
5724 TALLOC_FREE(subreq);
5725 if (tevent_req_nterror(req, status)) {
5726 return;
5728 state->fnum = SVAL(data,2);
5729 tevent_req_done(req);
5732 static NTSTATUS cli_posix_open_internal_recv(struct tevent_req *req,
5733 uint16_t *pfnum)
5735 struct cli_posix_open_internal_state *state = tevent_req_data(
5736 req, struct cli_posix_open_internal_state);
5737 NTSTATUS status;
5739 if (tevent_req_is_nterror(req, &status)) {
5740 return status;
5742 *pfnum = state->fnum;
5743 return NT_STATUS_OK;
5746 struct cli_posix_open_state {
5747 uint16_t fnum;
5750 static void cli_posix_open_done(struct tevent_req *subreq);
5752 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
5753 struct tevent_context *ev,
5754 struct cli_state *cli,
5755 const char *fname,
5756 int flags,
5757 mode_t mode)
5759 struct tevent_req *req = NULL, *subreq = NULL;
5760 struct cli_posix_open_state *state = NULL;
5761 uint32_t wire_flags;
5763 req = tevent_req_create(mem_ctx, &state,
5764 struct cli_posix_open_state);
5765 if (req == NULL) {
5766 return NULL;
5769 wire_flags = open_flags_to_wire(flags);
5771 subreq = cli_posix_open_internal_send(
5772 mem_ctx, ev, cli, fname, wire_flags, mode);
5773 if (tevent_req_nomem(subreq, req)) {
5774 return tevent_req_post(req, ev);
5776 tevent_req_set_callback(subreq, cli_posix_open_done, req);
5777 return req;
5780 static void cli_posix_open_done(struct tevent_req *subreq)
5782 struct tevent_req *req = tevent_req_callback_data(
5783 subreq, struct tevent_req);
5784 struct cli_posix_open_state *state = tevent_req_data(
5785 req, struct cli_posix_open_state);
5786 NTSTATUS status;
5788 status = cli_posix_open_internal_recv(subreq, &state->fnum);
5789 tevent_req_simple_finish_ntstatus(subreq, status);
5792 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
5794 struct cli_posix_open_state *state = tevent_req_data(
5795 req, struct cli_posix_open_state);
5796 NTSTATUS status;
5798 if (tevent_req_is_nterror(req, &status)) {
5799 return status;
5801 *pfnum = state->fnum;
5802 return NT_STATUS_OK;
5805 /****************************************************************************
5806 Open - POSIX semantics. Doesn't request oplock.
5807 ****************************************************************************/
5809 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
5810 int flags, mode_t mode, uint16_t *pfnum)
5813 TALLOC_CTX *frame = talloc_stackframe();
5814 struct tevent_context *ev = NULL;
5815 struct tevent_req *req = NULL;
5816 NTSTATUS status = NT_STATUS_NO_MEMORY;
5818 if (smbXcli_conn_has_async_calls(cli->conn)) {
5820 * Can't use sync call while an async call is in flight
5822 status = NT_STATUS_INVALID_PARAMETER;
5823 goto fail;
5825 ev = samba_tevent_context_init(frame);
5826 if (ev == NULL) {
5827 goto fail;
5829 req = cli_posix_open_send(
5830 frame, ev, cli, fname, flags, mode);
5831 if (req == NULL) {
5832 goto fail;
5834 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5835 goto fail;
5837 status = cli_posix_open_recv(req, pfnum);
5838 fail:
5839 TALLOC_FREE(frame);
5840 return status;
5843 struct cli_posix_mkdir_state {
5844 struct tevent_context *ev;
5845 struct cli_state *cli;
5848 static void cli_posix_mkdir_done(struct tevent_req *subreq);
5850 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
5851 struct tevent_context *ev,
5852 struct cli_state *cli,
5853 const char *fname,
5854 mode_t mode)
5856 struct tevent_req *req = NULL, *subreq = NULL;
5857 struct cli_posix_mkdir_state *state = NULL;
5858 uint32_t wire_flags;
5860 req = tevent_req_create(
5861 mem_ctx, &state, struct cli_posix_mkdir_state);
5862 if (req == NULL) {
5863 return NULL;
5865 state->ev = ev;
5866 state->cli = cli;
5868 wire_flags = SMB_O_CREAT | SMB_O_DIRECTORY;
5870 subreq = cli_posix_open_internal_send(
5871 mem_ctx, ev, cli, fname, wire_flags, mode);
5872 if (tevent_req_nomem(subreq, req)) {
5873 return tevent_req_post(req, ev);
5875 tevent_req_set_callback(subreq, cli_posix_mkdir_done, req);
5876 return req;
5879 static void cli_posix_mkdir_done(struct tevent_req *subreq)
5881 struct tevent_req *req = tevent_req_callback_data(
5882 subreq, struct tevent_req);
5883 NTSTATUS status;
5884 uint16_t fnum;
5886 status = cli_posix_open_internal_recv(subreq, &fnum);
5887 TALLOC_FREE(subreq);
5888 if (tevent_req_nterror(req, status)) {
5889 return;
5891 tevent_req_done(req);
5894 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
5896 return tevent_req_simple_recv_ntstatus(req);
5899 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
5901 TALLOC_CTX *frame = talloc_stackframe();
5902 struct tevent_context *ev = NULL;
5903 struct tevent_req *req = NULL;
5904 NTSTATUS status = NT_STATUS_NO_MEMORY;
5906 if (smbXcli_conn_has_async_calls(cli->conn)) {
5908 * Can't use sync call while an async call is in flight
5910 status = NT_STATUS_INVALID_PARAMETER;
5911 goto fail;
5914 ev = samba_tevent_context_init(frame);
5915 if (ev == NULL) {
5916 goto fail;
5918 req = cli_posix_mkdir_send(
5919 frame, ev, cli, fname, mode);
5920 if (req == NULL) {
5921 goto fail;
5923 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5924 goto fail;
5926 status = cli_posix_mkdir_recv(req);
5927 fail:
5928 TALLOC_FREE(frame);
5929 return status;
5932 /****************************************************************************
5933 unlink or rmdir - POSIX semantics.
5934 ****************************************************************************/
5936 struct cli_posix_unlink_internal_state {
5937 uint8_t data[2];
5940 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
5942 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
5943 struct tevent_context *ev,
5944 struct cli_state *cli,
5945 const char *fname,
5946 uint16_t level)
5948 struct tevent_req *req = NULL, *subreq = NULL;
5949 struct cli_posix_unlink_internal_state *state = NULL;
5951 req = tevent_req_create(mem_ctx, &state,
5952 struct cli_posix_unlink_internal_state);
5953 if (req == NULL) {
5954 return NULL;
5957 /* Setup data word. */
5958 SSVAL(state->data, 0, level);
5960 subreq = cli_setpathinfo_send(state, ev, cli,
5961 SMB_POSIX_PATH_UNLINK,
5962 fname,
5963 state->data, sizeof(state->data));
5964 if (tevent_req_nomem(subreq, req)) {
5965 return tevent_req_post(req, ev);
5967 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
5968 return req;
5971 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
5973 NTSTATUS status = cli_setpathinfo_recv(subreq);
5974 tevent_req_simple_finish_ntstatus(subreq, status);
5977 static NTSTATUS cli_posix_unlink_internal_recv(struct tevent_req *req)
5979 return tevent_req_simple_recv_ntstatus(req);
5982 struct cli_posix_unlink_state {
5983 uint8_t dummy;
5986 static void cli_posix_unlink_done(struct tevent_req *subreq);
5988 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
5989 struct tevent_context *ev,
5990 struct cli_state *cli,
5991 const char *fname)
5993 struct tevent_req *req = NULL, *subreq = NULL;
5994 struct cli_posix_unlink_state *state;
5996 req = tevent_req_create(
5997 mem_ctx, &state, struct cli_posix_unlink_state);
5998 if (req == NULL) {
5999 return NULL;
6001 subreq = cli_posix_unlink_internal_send(
6002 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_FILE_TARGET);
6003 if (tevent_req_nomem(subreq, req)) {
6004 return tevent_req_post(req, ev);
6006 tevent_req_set_callback(subreq, cli_posix_unlink_done, req);
6007 return req;
6010 static void cli_posix_unlink_done(struct tevent_req *subreq)
6012 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6013 tevent_req_simple_finish_ntstatus(subreq, status);
6016 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
6018 return tevent_req_simple_recv_ntstatus(req);
6021 /****************************************************************************
6022 unlink - POSIX semantics.
6023 ****************************************************************************/
6025 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
6027 TALLOC_CTX *frame = talloc_stackframe();
6028 struct tevent_context *ev = NULL;
6029 struct tevent_req *req = NULL;
6030 NTSTATUS status = NT_STATUS_OK;
6032 if (smbXcli_conn_has_async_calls(cli->conn)) {
6034 * Can't use sync call while an async call is in flight
6036 status = NT_STATUS_INVALID_PARAMETER;
6037 goto fail;
6040 ev = samba_tevent_context_init(frame);
6041 if (ev == NULL) {
6042 status = NT_STATUS_NO_MEMORY;
6043 goto fail;
6046 req = cli_posix_unlink_send(frame,
6048 cli,
6049 fname);
6050 if (req == NULL) {
6051 status = NT_STATUS_NO_MEMORY;
6052 goto fail;
6055 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6056 goto fail;
6059 status = cli_posix_unlink_recv(req);
6061 fail:
6062 TALLOC_FREE(frame);
6063 return status;
6066 /****************************************************************************
6067 rmdir - POSIX semantics.
6068 ****************************************************************************/
6070 struct cli_posix_rmdir_state {
6071 uint8_t dummy;
6074 static void cli_posix_rmdir_done(struct tevent_req *subreq);
6076 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
6077 struct tevent_context *ev,
6078 struct cli_state *cli,
6079 const char *fname)
6081 struct tevent_req *req = NULL, *subreq = NULL;
6082 struct cli_posix_rmdir_state *state;
6084 req = tevent_req_create(mem_ctx, &state, struct cli_posix_rmdir_state);
6085 if (req == NULL) {
6086 return NULL;
6088 subreq = cli_posix_unlink_internal_send(
6089 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_DIRECTORY_TARGET);
6090 if (tevent_req_nomem(subreq, req)) {
6091 return tevent_req_post(req, ev);
6093 tevent_req_set_callback(subreq, cli_posix_rmdir_done, req);
6094 return req;
6097 static void cli_posix_rmdir_done(struct tevent_req *subreq)
6099 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6100 tevent_req_simple_finish_ntstatus(subreq, status);
6103 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
6105 return tevent_req_simple_recv_ntstatus(req);
6108 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
6110 TALLOC_CTX *frame = talloc_stackframe();
6111 struct tevent_context *ev = NULL;
6112 struct tevent_req *req = NULL;
6113 NTSTATUS status = NT_STATUS_OK;
6115 if (smbXcli_conn_has_async_calls(cli->conn)) {
6117 * Can't use sync call while an async call is in flight
6119 status = NT_STATUS_INVALID_PARAMETER;
6120 goto fail;
6123 ev = samba_tevent_context_init(frame);
6124 if (ev == NULL) {
6125 status = NT_STATUS_NO_MEMORY;
6126 goto fail;
6129 req = cli_posix_rmdir_send(frame,
6131 cli,
6132 fname);
6133 if (req == NULL) {
6134 status = NT_STATUS_NO_MEMORY;
6135 goto fail;
6138 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6139 goto fail;
6142 status = cli_posix_rmdir_recv(req, frame);
6144 fail:
6145 TALLOC_FREE(frame);
6146 return status;
6149 /****************************************************************************
6150 filechangenotify
6151 ****************************************************************************/
6153 struct cli_notify_state {
6154 struct tevent_req *subreq;
6155 uint8_t setup[8];
6156 uint32_t num_changes;
6157 struct notify_change *changes;
6160 static void cli_notify_done(struct tevent_req *subreq);
6161 static void cli_notify_done_smb2(struct tevent_req *subreq);
6162 static bool cli_notify_cancel(struct tevent_req *req);
6164 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
6165 struct tevent_context *ev,
6166 struct cli_state *cli, uint16_t fnum,
6167 uint32_t buffer_size,
6168 uint32_t completion_filter, bool recursive)
6170 struct tevent_req *req;
6171 struct cli_notify_state *state;
6172 unsigned old_timeout;
6174 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
6175 if (req == NULL) {
6176 return NULL;
6179 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6181 * Notifies should not time out
6183 old_timeout = cli_set_timeout(cli, 0);
6185 state->subreq = cli_smb2_notify_send(
6186 state,
6188 cli,
6189 fnum,
6190 buffer_size,
6191 completion_filter,
6192 recursive);
6194 cli_set_timeout(cli, old_timeout);
6196 if (tevent_req_nomem(state->subreq, req)) {
6197 return tevent_req_post(req, ev);
6199 tevent_req_set_callback(
6200 state->subreq, cli_notify_done_smb2, req);
6201 goto done;
6204 SIVAL(state->setup, 0, completion_filter);
6205 SSVAL(state->setup, 4, fnum);
6206 SSVAL(state->setup, 6, recursive);
6209 * Notifies should not time out
6211 old_timeout = cli_set_timeout(cli, 0);
6213 state->subreq = cli_trans_send(
6214 state, /* mem ctx. */
6215 ev, /* event ctx. */
6216 cli, /* cli_state. */
6217 0, /* additional_flags2 */
6218 SMBnttrans, /* cmd. */
6219 NULL, /* pipe name. */
6220 -1, /* fid. */
6221 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
6222 0, /* flags. */
6223 (uint16_t *)state->setup, /* setup. */
6224 4, /* num setup uint16_t words. */
6225 0, /* max returned setup. */
6226 NULL, /* param. */
6227 0, /* num param. */
6228 buffer_size, /* max returned param. */
6229 NULL, /* data. */
6230 0, /* num data. */
6231 0); /* max returned data. */
6233 cli_set_timeout(cli, old_timeout);
6235 if (tevent_req_nomem(state->subreq, req)) {
6236 return tevent_req_post(req, ev);
6238 tevent_req_set_callback(state->subreq, cli_notify_done, req);
6239 done:
6240 tevent_req_set_cancel_fn(req, cli_notify_cancel);
6241 return req;
6244 static bool cli_notify_cancel(struct tevent_req *req)
6246 struct cli_notify_state *state = tevent_req_data(
6247 req, struct cli_notify_state);
6248 bool ok;
6250 ok = tevent_req_cancel(state->subreq);
6251 return ok;
6254 static void cli_notify_done(struct tevent_req *subreq)
6256 struct tevent_req *req = tevent_req_callback_data(
6257 subreq, struct tevent_req);
6258 struct cli_notify_state *state = tevent_req_data(
6259 req, struct cli_notify_state);
6260 NTSTATUS status;
6261 uint8_t *params;
6262 uint32_t i, ofs, num_params;
6263 uint16_t flags2;
6265 status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
6266 &params, 0, &num_params, NULL, 0, NULL);
6267 TALLOC_FREE(subreq);
6268 state->subreq = NULL;
6269 if (tevent_req_nterror(req, status)) {
6270 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
6271 return;
6274 state->num_changes = 0;
6275 ofs = 0;
6277 while (num_params - ofs > 12) {
6278 uint32_t next = IVAL(params, ofs);
6279 state->num_changes += 1;
6281 if ((next == 0) || (ofs+next >= num_params)) {
6282 break;
6284 ofs += next;
6287 state->changes = talloc_array(state, struct notify_change,
6288 state->num_changes);
6289 if (tevent_req_nomem(state->changes, req)) {
6290 TALLOC_FREE(params);
6291 return;
6294 ofs = 0;
6296 for (i=0; i<state->num_changes; i++) {
6297 uint32_t next = IVAL(params, ofs);
6298 uint32_t len = IVAL(params, ofs+8);
6299 ssize_t ret;
6300 char *name;
6302 if (smb_buffer_oob(num_params, ofs + 12, len)) {
6303 TALLOC_FREE(params);
6304 tevent_req_nterror(
6305 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
6306 return;
6309 state->changes[i].action = IVAL(params, ofs+4);
6310 ret = pull_string_talloc(state->changes,
6311 (char *)params,
6312 flags2,
6313 &name,
6314 params+ofs+12,
6315 len,
6316 STR_TERMINATE|STR_UNICODE);
6317 if (ret == -1) {
6318 TALLOC_FREE(params);
6319 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
6320 return;
6322 state->changes[i].name = name;
6323 ofs += next;
6326 TALLOC_FREE(params);
6327 tevent_req_done(req);
6330 static void cli_notify_done_smb2(struct tevent_req *subreq)
6332 struct tevent_req *req = tevent_req_callback_data(
6333 subreq, struct tevent_req);
6334 struct cli_notify_state *state = tevent_req_data(
6335 req, struct cli_notify_state);
6336 NTSTATUS status;
6338 status = cli_smb2_notify_recv(
6339 subreq,
6340 state,
6341 &state->changes,
6342 &state->num_changes);
6343 TALLOC_FREE(subreq);
6344 if (tevent_req_nterror(req, status)) {
6345 return;
6347 tevent_req_done(req);
6350 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6351 uint32_t *pnum_changes,
6352 struct notify_change **pchanges)
6354 struct cli_notify_state *state = tevent_req_data(
6355 req, struct cli_notify_state);
6356 NTSTATUS status;
6358 if (tevent_req_is_nterror(req, &status)) {
6359 return status;
6362 *pnum_changes = state->num_changes;
6363 *pchanges = talloc_move(mem_ctx, &state->changes);
6364 return NT_STATUS_OK;
6367 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
6368 uint32_t completion_filter, bool recursive,
6369 TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
6370 struct notify_change **pchanges)
6372 TALLOC_CTX *frame;
6373 struct tevent_context *ev;
6374 struct tevent_req *req;
6375 NTSTATUS status = NT_STATUS_NO_MEMORY;
6377 frame = talloc_stackframe();
6379 if (smbXcli_conn_has_async_calls(cli->conn)) {
6381 * Can't use sync call while an async call is in flight
6383 status = NT_STATUS_INVALID_PARAMETER;
6384 goto fail;
6386 ev = samba_tevent_context_init(frame);
6387 if (ev == NULL) {
6388 goto fail;
6390 req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
6391 completion_filter, recursive);
6392 if (req == NULL) {
6393 goto fail;
6395 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6396 goto fail;
6398 status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
6399 fail:
6400 TALLOC_FREE(frame);
6401 return status;
6404 struct cli_qpathinfo_state {
6405 uint8_t *param;
6406 uint8_t *data;
6407 uint16_t setup[1];
6408 uint32_t min_rdata;
6409 uint8_t *rdata;
6410 uint32_t num_rdata;
6413 static void cli_qpathinfo_done(struct tevent_req *subreq);
6415 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
6416 struct tevent_context *ev,
6417 struct cli_state *cli, const char *fname,
6418 uint16_t level, uint32_t min_rdata,
6419 uint32_t max_rdata)
6421 struct tevent_req *req, *subreq;
6422 struct cli_qpathinfo_state *state;
6423 uint16_t additional_flags2 = 0;
6425 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
6426 if (req == NULL) {
6427 return NULL;
6429 state->min_rdata = min_rdata;
6430 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
6432 state->param = talloc_zero_array(state, uint8_t, 6);
6433 if (tevent_req_nomem(state->param, req)) {
6434 return tevent_req_post(req, ev);
6436 SSVAL(state->param, 0, level);
6437 state->param = trans2_bytes_push_str(
6438 state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
6439 if (tevent_req_nomem(state->param, req)) {
6440 return tevent_req_post(req, ev);
6443 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
6444 !INFO_LEVEL_IS_UNIX(level)) {
6445 additional_flags2 = FLAGS2_REPARSE_PATH;
6448 subreq = cli_trans_send(
6449 state, /* mem ctx. */
6450 ev, /* event ctx. */
6451 cli, /* cli_state. */
6452 additional_flags2, /* additional_flags2 */
6453 SMBtrans2, /* cmd. */
6454 NULL, /* pipe name. */
6455 -1, /* fid. */
6456 0, /* function. */
6457 0, /* flags. */
6458 state->setup, /* setup. */
6459 1, /* num setup uint16_t words. */
6460 0, /* max returned setup. */
6461 state->param, /* param. */
6462 talloc_get_size(state->param), /* num param. */
6463 2, /* max returned param. */
6464 NULL, /* data. */
6465 0, /* num data. */
6466 max_rdata); /* max returned data. */
6468 if (tevent_req_nomem(subreq, req)) {
6469 return tevent_req_post(req, ev);
6471 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
6472 return req;
6475 static void cli_qpathinfo_done(struct tevent_req *subreq)
6477 struct tevent_req *req = tevent_req_callback_data(
6478 subreq, struct tevent_req);
6479 struct cli_qpathinfo_state *state = tevent_req_data(
6480 req, struct cli_qpathinfo_state);
6481 NTSTATUS status;
6483 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
6484 NULL, 0, NULL,
6485 &state->rdata, state->min_rdata,
6486 &state->num_rdata);
6487 if (tevent_req_nterror(req, status)) {
6488 return;
6490 tevent_req_done(req);
6493 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6494 uint8_t **rdata, uint32_t *num_rdata)
6496 struct cli_qpathinfo_state *state = tevent_req_data(
6497 req, struct cli_qpathinfo_state);
6498 NTSTATUS status;
6500 if (tevent_req_is_nterror(req, &status)) {
6501 return status;
6503 if (rdata != NULL) {
6504 *rdata = talloc_move(mem_ctx, &state->rdata);
6505 } else {
6506 TALLOC_FREE(state->rdata);
6508 if (num_rdata != NULL) {
6509 *num_rdata = state->num_rdata;
6511 return NT_STATUS_OK;
6514 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6515 const char *fname, uint16_t level, uint32_t min_rdata,
6516 uint32_t max_rdata,
6517 uint8_t **rdata, uint32_t *num_rdata)
6519 TALLOC_CTX *frame = talloc_stackframe();
6520 struct tevent_context *ev;
6521 struct tevent_req *req;
6522 NTSTATUS status = NT_STATUS_NO_MEMORY;
6524 if (smbXcli_conn_has_async_calls(cli->conn)) {
6526 * Can't use sync call while an async call is in flight
6528 status = NT_STATUS_INVALID_PARAMETER;
6529 goto fail;
6531 ev = samba_tevent_context_init(frame);
6532 if (ev == NULL) {
6533 goto fail;
6535 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
6536 max_rdata);
6537 if (req == NULL) {
6538 goto fail;
6540 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6541 goto fail;
6543 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
6544 fail:
6545 TALLOC_FREE(frame);
6546 return status;
6549 struct cli_qfileinfo_state {
6550 uint16_t setup[1];
6551 uint8_t param[4];
6552 uint8_t *data;
6553 uint16_t recv_flags2;
6554 uint32_t min_rdata;
6555 uint8_t *rdata;
6556 uint32_t num_rdata;
6559 static void cli_qfileinfo_done(struct tevent_req *subreq);
6561 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
6562 struct tevent_context *ev,
6563 struct cli_state *cli, uint16_t fnum,
6564 uint16_t level, uint32_t min_rdata,
6565 uint32_t max_rdata)
6567 struct tevent_req *req, *subreq;
6568 struct cli_qfileinfo_state *state;
6570 req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
6571 if (req == NULL) {
6572 return NULL;
6574 state->min_rdata = min_rdata;
6575 SSVAL(state->param, 0, fnum);
6576 SSVAL(state->param, 2, level);
6577 SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
6579 subreq = cli_trans_send(
6580 state, /* mem ctx. */
6581 ev, /* event ctx. */
6582 cli, /* cli_state. */
6583 0, /* additional_flags2 */
6584 SMBtrans2, /* cmd. */
6585 NULL, /* pipe name. */
6586 -1, /* fid. */
6587 0, /* function. */
6588 0, /* flags. */
6589 state->setup, /* setup. */
6590 1, /* num setup uint16_t words. */
6591 0, /* max returned setup. */
6592 state->param, /* param. */
6593 sizeof(state->param), /* num param. */
6594 2, /* max returned param. */
6595 NULL, /* data. */
6596 0, /* num data. */
6597 max_rdata); /* max returned data. */
6599 if (tevent_req_nomem(subreq, req)) {
6600 return tevent_req_post(req, ev);
6602 tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
6603 return req;
6606 static void cli_qfileinfo_done(struct tevent_req *subreq)
6608 struct tevent_req *req = tevent_req_callback_data(
6609 subreq, struct tevent_req);
6610 struct cli_qfileinfo_state *state = tevent_req_data(
6611 req, struct cli_qfileinfo_state);
6612 NTSTATUS status;
6614 status = cli_trans_recv(subreq, state,
6615 &state->recv_flags2,
6616 NULL, 0, NULL,
6617 NULL, 0, NULL,
6618 &state->rdata, state->min_rdata,
6619 &state->num_rdata);
6620 if (tevent_req_nterror(req, status)) {
6621 return;
6623 tevent_req_done(req);
6626 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6627 uint16_t *recv_flags2,
6628 uint8_t **rdata, uint32_t *num_rdata)
6630 struct cli_qfileinfo_state *state = tevent_req_data(
6631 req, struct cli_qfileinfo_state);
6632 NTSTATUS status;
6634 if (tevent_req_is_nterror(req, &status)) {
6635 return status;
6638 if (recv_flags2 != NULL) {
6639 *recv_flags2 = state->recv_flags2;
6641 if (rdata != NULL) {
6642 *rdata = talloc_move(mem_ctx, &state->rdata);
6644 if (num_rdata != NULL) {
6645 *num_rdata = state->num_rdata;
6648 tevent_req_received(req);
6649 return NT_STATUS_OK;
6652 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6653 uint16_t fnum, uint16_t level, uint32_t min_rdata,
6654 uint32_t max_rdata, uint16_t *recv_flags2,
6655 uint8_t **rdata, uint32_t *num_rdata)
6657 TALLOC_CTX *frame = talloc_stackframe();
6658 struct tevent_context *ev;
6659 struct tevent_req *req;
6660 NTSTATUS status = NT_STATUS_NO_MEMORY;
6662 if (smbXcli_conn_has_async_calls(cli->conn)) {
6664 * Can't use sync call while an async call is in flight
6666 status = NT_STATUS_INVALID_PARAMETER;
6667 goto fail;
6669 ev = samba_tevent_context_init(frame);
6670 if (ev == NULL) {
6671 goto fail;
6673 req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
6674 max_rdata);
6675 if (req == NULL) {
6676 goto fail;
6678 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6679 goto fail;
6681 status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
6682 fail:
6683 TALLOC_FREE(frame);
6684 return status;
6687 struct cli_flush_state {
6688 uint16_t vwv[1];
6691 static void cli_flush_done(struct tevent_req *subreq);
6693 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
6694 struct tevent_context *ev,
6695 struct cli_state *cli,
6696 uint16_t fnum)
6698 struct tevent_req *req, *subreq;
6699 struct cli_flush_state *state;
6701 req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
6702 if (req == NULL) {
6703 return NULL;
6705 SSVAL(state->vwv + 0, 0, fnum);
6707 subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
6708 0, NULL);
6709 if (tevent_req_nomem(subreq, req)) {
6710 return tevent_req_post(req, ev);
6712 tevent_req_set_callback(subreq, cli_flush_done, req);
6713 return req;
6716 static void cli_flush_done(struct tevent_req *subreq)
6718 struct tevent_req *req = tevent_req_callback_data(
6719 subreq, struct tevent_req);
6720 NTSTATUS status;
6722 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
6723 TALLOC_FREE(subreq);
6724 if (tevent_req_nterror(req, status)) {
6725 return;
6727 tevent_req_done(req);
6730 NTSTATUS cli_flush_recv(struct tevent_req *req)
6732 return tevent_req_simple_recv_ntstatus(req);
6735 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
6737 TALLOC_CTX *frame = talloc_stackframe();
6738 struct tevent_context *ev;
6739 struct tevent_req *req;
6740 NTSTATUS status = NT_STATUS_NO_MEMORY;
6742 if (smbXcli_conn_has_async_calls(cli->conn)) {
6744 * Can't use sync call while an async call is in flight
6746 status = NT_STATUS_INVALID_PARAMETER;
6747 goto fail;
6749 ev = samba_tevent_context_init(frame);
6750 if (ev == NULL) {
6751 goto fail;
6753 req = cli_flush_send(frame, ev, cli, fnum);
6754 if (req == NULL) {
6755 goto fail;
6757 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6758 goto fail;
6760 status = cli_flush_recv(req);
6761 fail:
6762 TALLOC_FREE(frame);
6763 return status;
6766 struct cli_shadow_copy_data_state {
6767 uint16_t setup[4];
6768 uint8_t *data;
6769 uint32_t num_data;
6770 bool get_names;
6773 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
6775 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
6776 struct tevent_context *ev,
6777 struct cli_state *cli,
6778 uint16_t fnum,
6779 bool get_names)
6781 struct tevent_req *req, *subreq;
6782 struct cli_shadow_copy_data_state *state;
6783 uint32_t ret_size;
6785 req = tevent_req_create(mem_ctx, &state,
6786 struct cli_shadow_copy_data_state);
6787 if (req == NULL) {
6788 return NULL;
6790 state->get_names = get_names;
6791 ret_size = get_names ? CLI_BUFFER_SIZE : 16;
6793 SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
6794 SSVAL(state->setup + 2, 0, fnum);
6795 SCVAL(state->setup + 3, 0, 1); /* isFsctl */
6796 SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
6798 subreq = cli_trans_send(
6799 state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
6800 state->setup, ARRAY_SIZE(state->setup),
6801 ARRAY_SIZE(state->setup),
6802 NULL, 0, 0,
6803 NULL, 0, ret_size);
6804 if (tevent_req_nomem(subreq, req)) {
6805 return tevent_req_post(req, ev);
6807 tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
6808 return req;
6811 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
6813 struct tevent_req *req = tevent_req_callback_data(
6814 subreq, struct tevent_req);
6815 struct cli_shadow_copy_data_state *state = tevent_req_data(
6816 req, struct cli_shadow_copy_data_state);
6817 NTSTATUS status;
6819 status = cli_trans_recv(subreq, state, NULL,
6820 NULL, 0, NULL, /* setup */
6821 NULL, 0, NULL, /* param */
6822 &state->data, 12, &state->num_data);
6823 TALLOC_FREE(subreq);
6824 if (tevent_req_nterror(req, status)) {
6825 return;
6827 tevent_req_done(req);
6830 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6831 char ***pnames, int *pnum_names)
6833 struct cli_shadow_copy_data_state *state = tevent_req_data(
6834 req, struct cli_shadow_copy_data_state);
6835 char **names = NULL;
6836 uint32_t i, num_names;
6837 uint32_t dlength;
6838 uint8_t *endp = NULL;
6839 NTSTATUS status;
6841 if (tevent_req_is_nterror(req, &status)) {
6842 return status;
6845 if (state->num_data < 16) {
6846 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6849 num_names = IVAL(state->data, 4);
6850 dlength = IVAL(state->data, 8);
6852 if (num_names > 0x7FFFFFFF) {
6853 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6856 if (!state->get_names) {
6857 *pnum_names = (int)num_names;
6858 return NT_STATUS_OK;
6861 if (dlength + 12 < 12) {
6862 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6864 if (dlength + 12 > state->num_data) {
6865 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6867 if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
6868 state->num_data) {
6869 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6872 names = talloc_array(mem_ctx, char *, num_names);
6873 if (names == NULL) {
6874 return NT_STATUS_NO_MEMORY;
6877 endp = state->data + state->num_data;
6879 for (i=0; i<num_names; i++) {
6880 bool ret;
6881 uint8_t *src;
6882 size_t converted_size;
6884 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
6886 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
6887 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6890 ret = convert_string_talloc(
6891 names, CH_UTF16LE, CH_UNIX,
6892 src, 2 * sizeof(SHADOW_COPY_LABEL),
6893 &names[i], &converted_size);
6894 if (!ret) {
6895 TALLOC_FREE(names);
6896 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6899 *pnum_names = (int)num_names;
6900 *pnames = names;
6901 return NT_STATUS_OK;
6904 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6905 uint16_t fnum, bool get_names,
6906 char ***pnames, int *pnum_names)
6908 TALLOC_CTX *frame = NULL;
6909 struct tevent_context *ev;
6910 struct tevent_req *req;
6911 NTSTATUS status = NT_STATUS_NO_MEMORY;
6913 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6914 return cli_smb2_shadow_copy_data(mem_ctx,
6915 cli,
6916 fnum,
6917 get_names,
6918 pnames,
6919 pnum_names);
6922 frame = talloc_stackframe();
6924 if (smbXcli_conn_has_async_calls(cli->conn)) {
6926 * Can't use sync call while an async call is in flight
6928 status = NT_STATUS_INVALID_PARAMETER;
6929 goto fail;
6931 ev = samba_tevent_context_init(frame);
6932 if (ev == NULL) {
6933 goto fail;
6935 req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
6936 if (req == NULL) {
6937 goto fail;
6939 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6940 goto fail;
6942 status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
6943 fail:
6944 TALLOC_FREE(frame);
6945 return status;