s4:selftest: explicitly set NSS/RESOLV_WAPPER_* in wait_for_start
[Samba.git] / source3 / libsmb / clifile.c
blob5f6e98ce460b64a0ae6d4102d063402a1b6dbde6
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/secdesc.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 /****************************************************************************
153 Hard/Symlink a file (UNIX extensions).
154 Creates new name (sym)linked to link_target.
155 ****************************************************************************/
157 struct cli_posix_link_internal_state {
158 uint8_t *data;
161 static void cli_posix_link_internal_done(struct tevent_req *subreq);
163 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
164 struct tevent_context *ev,
165 struct cli_state *cli,
166 uint16_t level,
167 const char *link_target,
168 const char *newname)
170 struct tevent_req *req = NULL, *subreq = NULL;
171 struct cli_posix_link_internal_state *state = NULL;
173 req = tevent_req_create(mem_ctx, &state,
174 struct cli_posix_link_internal_state);
175 if (req == NULL) {
176 return NULL;
179 /* Setup data array. */
180 state->data = talloc_array(state, uint8_t, 0);
181 if (tevent_req_nomem(state->data, req)) {
182 return tevent_req_post(req, ev);
184 state->data = trans2_bytes_push_str(
185 state->data, smbXcli_conn_use_unicode(cli->conn),
186 link_target, strlen(link_target)+1, NULL);
188 subreq = cli_setpathinfo_send(
189 state, ev, cli, level, newname,
190 state->data, talloc_get_size(state->data));
191 if (tevent_req_nomem(subreq, req)) {
192 return tevent_req_post(req, ev);
194 tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
195 return req;
198 static void cli_posix_link_internal_done(struct tevent_req *subreq)
200 NTSTATUS status = cli_setpathinfo_recv(subreq);
201 tevent_req_simple_finish_ntstatus(subreq, status);
204 /****************************************************************************
205 Symlink a file (UNIX extensions).
206 ****************************************************************************/
208 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
209 struct tevent_context *ev,
210 struct cli_state *cli,
211 const char *link_target,
212 const char *newname)
214 return cli_posix_link_internal_send(
215 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, link_target, newname);
218 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
220 return tevent_req_simple_recv_ntstatus(req);
223 NTSTATUS cli_posix_symlink(struct cli_state *cli,
224 const char *link_target,
225 const char *newname)
227 TALLOC_CTX *frame = talloc_stackframe();
228 struct tevent_context *ev = NULL;
229 struct tevent_req *req = NULL;
230 NTSTATUS status = NT_STATUS_OK;
232 if (smbXcli_conn_has_async_calls(cli->conn)) {
234 * Can't use sync call while an async call is in flight
236 status = NT_STATUS_INVALID_PARAMETER;
237 goto fail;
240 ev = samba_tevent_context_init(frame);
241 if (ev == NULL) {
242 status = NT_STATUS_NO_MEMORY;
243 goto fail;
246 req = cli_posix_symlink_send(frame,
248 cli,
249 link_target,
250 newname);
251 if (req == NULL) {
252 status = NT_STATUS_NO_MEMORY;
253 goto fail;
256 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
257 goto fail;
260 status = cli_posix_symlink_recv(req);
262 fail:
263 TALLOC_FREE(frame);
264 return status;
267 /****************************************************************************
268 Read a POSIX symlink.
269 ****************************************************************************/
271 struct readlink_state {
272 uint8_t *data;
273 uint32_t num_data;
276 static void cli_posix_readlink_done(struct tevent_req *subreq);
278 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
279 struct tevent_context *ev,
280 struct cli_state *cli,
281 const char *fname,
282 size_t len)
284 struct tevent_req *req = NULL, *subreq = NULL;
285 struct readlink_state *state = NULL;
286 uint32_t maxbytelen = (uint32_t)(smbXcli_conn_use_unicode(cli->conn) ? len*3 : len);
288 req = tevent_req_create(mem_ctx, &state, struct readlink_state);
289 if (req == NULL) {
290 return NULL;
294 * Len is in bytes, we need it in UCS2 units.
296 if ((2*len < len) || (maxbytelen < len)) {
297 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
298 return tevent_req_post(req, ev);
301 subreq = cli_qpathinfo_send(state, ev, cli, fname,
302 SMB_QUERY_FILE_UNIX_LINK, 1, maxbytelen);
303 if (tevent_req_nomem(subreq, req)) {
304 return tevent_req_post(req, ev);
306 tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
307 return req;
310 static void cli_posix_readlink_done(struct tevent_req *subreq)
312 struct tevent_req *req = tevent_req_callback_data(
313 subreq, struct tevent_req);
314 struct readlink_state *state = tevent_req_data(
315 req, struct readlink_state);
316 NTSTATUS status;
318 status = cli_qpathinfo_recv(subreq, state, &state->data,
319 &state->num_data);
320 TALLOC_FREE(subreq);
321 if (tevent_req_nterror(req, status)) {
322 return;
325 * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
327 if (state->data[state->num_data-1] != '\0') {
328 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
329 return;
331 tevent_req_done(req);
334 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
335 char *retpath, size_t len)
337 NTSTATUS status;
338 char *converted = NULL;
339 size_t converted_size = 0;
340 struct readlink_state *state = tevent_req_data(req, struct readlink_state);
342 if (tevent_req_is_nterror(req, &status)) {
343 return status;
345 /* The returned data is a pushed string, not raw data. */
346 if (!convert_string_talloc(state,
347 smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
348 CH_UNIX,
349 state->data,
350 state->num_data,
351 &converted,
352 &converted_size)) {
353 return NT_STATUS_NO_MEMORY;
356 len = MIN(len,converted_size);
357 if (len == 0) {
358 return NT_STATUS_DATA_ERROR;
360 memcpy(retpath, converted, len);
361 return NT_STATUS_OK;
364 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
365 char *linkpath, size_t len)
367 TALLOC_CTX *frame = talloc_stackframe();
368 struct tevent_context *ev = NULL;
369 struct tevent_req *req = NULL;
370 NTSTATUS status = NT_STATUS_OK;
372 if (smbXcli_conn_has_async_calls(cli->conn)) {
374 * Can't use sync call while an async call is in flight
376 status = NT_STATUS_INVALID_PARAMETER;
377 goto fail;
380 ev = samba_tevent_context_init(frame);
381 if (ev == NULL) {
382 status = NT_STATUS_NO_MEMORY;
383 goto fail;
386 req = cli_posix_readlink_send(frame,
388 cli,
389 fname,
390 len);
391 if (req == NULL) {
392 status = NT_STATUS_NO_MEMORY;
393 goto fail;
396 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
397 goto fail;
400 status = cli_posix_readlink_recv(req, cli, linkpath, len);
402 fail:
403 TALLOC_FREE(frame);
404 return status;
407 /****************************************************************************
408 Hard link a file (UNIX extensions).
409 ****************************************************************************/
411 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
412 struct tevent_context *ev,
413 struct cli_state *cli,
414 const char *oldname,
415 const char *newname)
417 return cli_posix_link_internal_send(
418 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
421 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
423 return tevent_req_simple_recv_ntstatus(req);
426 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
427 const char *oldname,
428 const char *newname)
430 TALLOC_CTX *frame = talloc_stackframe();
431 struct tevent_context *ev = NULL;
432 struct tevent_req *req = NULL;
433 NTSTATUS status = NT_STATUS_OK;
435 if (smbXcli_conn_has_async_calls(cli->conn)) {
437 * Can't use sync call while an async call is in flight
439 status = NT_STATUS_INVALID_PARAMETER;
440 goto fail;
443 ev = samba_tevent_context_init(frame);
444 if (ev == NULL) {
445 status = NT_STATUS_NO_MEMORY;
446 goto fail;
449 req = cli_posix_hardlink_send(frame,
451 cli,
452 oldname,
453 newname);
454 if (req == NULL) {
455 status = NT_STATUS_NO_MEMORY;
456 goto fail;
459 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
460 goto fail;
463 status = cli_posix_hardlink_recv(req);
465 fail:
466 TALLOC_FREE(frame);
467 return status;
470 /****************************************************************************
471 Do a POSIX getacl - pathname based ACL get (UNIX extensions).
472 ****************************************************************************/
474 struct getacl_state {
475 uint32_t num_data;
476 uint8_t *data;
479 static void cli_posix_getacl_done(struct tevent_req *subreq);
481 struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
482 struct tevent_context *ev,
483 struct cli_state *cli,
484 const char *fname)
486 struct tevent_req *req = NULL, *subreq = NULL;
487 struct getacl_state *state = NULL;
489 req = tevent_req_create(mem_ctx, &state, struct getacl_state);
490 if (req == NULL) {
491 return NULL;
493 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
494 0, CLI_BUFFER_SIZE);
495 if (tevent_req_nomem(subreq, req)) {
496 return tevent_req_post(req, ev);
498 tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
499 return req;
502 static void cli_posix_getacl_done(struct tevent_req *subreq)
504 struct tevent_req *req = tevent_req_callback_data(
505 subreq, struct tevent_req);
506 struct getacl_state *state = tevent_req_data(
507 req, struct getacl_state);
508 NTSTATUS status;
510 status = cli_qpathinfo_recv(subreq, state, &state->data,
511 &state->num_data);
512 TALLOC_FREE(subreq);
513 if (tevent_req_nterror(req, status)) {
514 return;
516 tevent_req_done(req);
519 NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
520 TALLOC_CTX *mem_ctx,
521 size_t *prb_size,
522 char **retbuf)
524 struct getacl_state *state = tevent_req_data(req, struct getacl_state);
525 NTSTATUS status;
527 if (tevent_req_is_nterror(req, &status)) {
528 return status;
530 *prb_size = (size_t)state->num_data;
531 *retbuf = (char *)talloc_move(mem_ctx, &state->data);
532 return NT_STATUS_OK;
535 NTSTATUS cli_posix_getacl(struct cli_state *cli,
536 const char *fname,
537 TALLOC_CTX *mem_ctx,
538 size_t *prb_size,
539 char **retbuf)
541 TALLOC_CTX *frame = talloc_stackframe();
542 struct tevent_context *ev = NULL;
543 struct tevent_req *req = NULL;
544 NTSTATUS status = NT_STATUS_OK;
546 if (smbXcli_conn_has_async_calls(cli->conn)) {
548 * Can't use sync call while an async call is in flight
550 status = NT_STATUS_INVALID_PARAMETER;
551 goto fail;
554 ev = samba_tevent_context_init(frame);
555 if (ev == NULL) {
556 status = NT_STATUS_NO_MEMORY;
557 goto fail;
560 req = cli_posix_getacl_send(frame,
562 cli,
563 fname);
564 if (req == NULL) {
565 status = NT_STATUS_NO_MEMORY;
566 goto fail;
569 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
570 goto fail;
573 status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
575 fail:
576 TALLOC_FREE(frame);
577 return status;
580 /****************************************************************************
581 Do a POSIX setacl - pathname based ACL set (UNIX extensions).
582 ****************************************************************************/
584 struct setacl_state {
585 uint8_t *data;
588 static void cli_posix_setacl_done(struct tevent_req *subreq);
590 struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
591 struct tevent_context *ev,
592 struct cli_state *cli,
593 const char *fname,
594 const void *data,
595 size_t num_data)
597 struct tevent_req *req = NULL, *subreq = NULL;
598 struct setacl_state *state = NULL;
600 req = tevent_req_create(mem_ctx, &state, struct setacl_state);
601 if (req == NULL) {
602 return NULL;
604 state->data = talloc_memdup(state, data, num_data);
605 if (tevent_req_nomem(state->data, req)) {
606 return tevent_req_post(req, ev);
609 subreq = cli_setpathinfo_send(state,
611 cli,
612 SMB_SET_POSIX_ACL,
613 fname,
614 state->data,
615 num_data);
616 if (tevent_req_nomem(subreq, req)) {
617 return tevent_req_post(req, ev);
619 tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
620 return req;
623 static void cli_posix_setacl_done(struct tevent_req *subreq)
625 NTSTATUS status = cli_setpathinfo_recv(subreq);
626 tevent_req_simple_finish_ntstatus(subreq, status);
629 NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
631 return tevent_req_simple_recv_ntstatus(req);
634 NTSTATUS cli_posix_setacl(struct cli_state *cli,
635 const char *fname,
636 const void *acl_buf,
637 size_t acl_buf_size)
639 TALLOC_CTX *frame = talloc_stackframe();
640 struct tevent_context *ev = NULL;
641 struct tevent_req *req = NULL;
642 NTSTATUS status = NT_STATUS_OK;
644 if (smbXcli_conn_has_async_calls(cli->conn)) {
646 * Can't use sync call while an async call is in flight
648 status = NT_STATUS_INVALID_PARAMETER;
649 goto fail;
652 ev = samba_tevent_context_init(frame);
653 if (ev == NULL) {
654 status = NT_STATUS_NO_MEMORY;
655 goto fail;
658 req = cli_posix_setacl_send(frame,
660 cli,
661 fname,
662 acl_buf,
663 acl_buf_size);
664 if (req == NULL) {
665 status = NT_STATUS_NO_MEMORY;
666 goto fail;
669 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
670 goto fail;
673 status = cli_posix_setacl_recv(req);
675 fail:
676 TALLOC_FREE(frame);
677 return status;
680 /****************************************************************************
681 Stat a file (UNIX extensions).
682 ****************************************************************************/
684 struct stat_state {
685 uint32_t num_data;
686 uint8_t *data;
689 static void cli_posix_stat_done(struct tevent_req *subreq);
691 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
692 struct tevent_context *ev,
693 struct cli_state *cli,
694 const char *fname)
696 struct tevent_req *req = NULL, *subreq = NULL;
697 struct stat_state *state = NULL;
699 req = tevent_req_create(mem_ctx, &state, struct stat_state);
700 if (req == NULL) {
701 return NULL;
703 subreq = cli_qpathinfo_send(state, ev, cli, fname,
704 SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
705 if (tevent_req_nomem(subreq, req)) {
706 return tevent_req_post(req, ev);
708 tevent_req_set_callback(subreq, cli_posix_stat_done, req);
709 return req;
712 static void cli_posix_stat_done(struct tevent_req *subreq)
714 struct tevent_req *req = tevent_req_callback_data(
715 subreq, struct tevent_req);
716 struct stat_state *state = tevent_req_data(req, struct stat_state);
717 NTSTATUS status;
719 status = cli_qpathinfo_recv(subreq, state, &state->data,
720 &state->num_data);
721 TALLOC_FREE(subreq);
722 if (tevent_req_nterror(req, status)) {
723 return;
725 tevent_req_done(req);
728 NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
729 SMB_STRUCT_STAT *sbuf)
731 struct stat_state *state = tevent_req_data(req, struct stat_state);
732 NTSTATUS status;
734 if (tevent_req_is_nterror(req, &status)) {
735 return status;
738 sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0); /* total size, in bytes */
739 sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8); /* number of blocks allocated */
740 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
741 sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
742 #else
743 /* assume 512 byte blocks */
744 sbuf->st_ex_blocks /= 512;
745 #endif
746 sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16)); /* time of last change */
747 sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24)); /* time of last access */
748 sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32)); /* time of last modification */
750 sbuf->st_ex_uid = (uid_t) IVAL(state->data,40); /* user ID of owner */
751 sbuf->st_ex_gid = (gid_t) IVAL(state->data,48); /* group ID of owner */
752 sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
753 #if defined(HAVE_MAKEDEV)
755 uint32_t dev_major = IVAL(state->data,60);
756 uint32_t dev_minor = IVAL(state->data,68);
757 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
759 #endif
760 sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76); /* inode */
761 sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84)); /* protection */
762 sbuf->st_ex_nlink = BIG_UINT(state->data,92); /* number of hard links */
764 return NT_STATUS_OK;
767 NTSTATUS cli_posix_stat(struct cli_state *cli,
768 const char *fname,
769 SMB_STRUCT_STAT *sbuf)
771 TALLOC_CTX *frame = talloc_stackframe();
772 struct tevent_context *ev = NULL;
773 struct tevent_req *req = NULL;
774 NTSTATUS status = NT_STATUS_OK;
776 if (smbXcli_conn_has_async_calls(cli->conn)) {
778 * Can't use sync call while an async call is in flight
780 status = NT_STATUS_INVALID_PARAMETER;
781 goto fail;
784 ev = samba_tevent_context_init(frame);
785 if (ev == NULL) {
786 status = NT_STATUS_NO_MEMORY;
787 goto fail;
790 req = cli_posix_stat_send(frame,
792 cli,
793 fname);
794 if (req == NULL) {
795 status = NT_STATUS_NO_MEMORY;
796 goto fail;
799 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
800 goto fail;
803 status = cli_posix_stat_recv(req, sbuf);
805 fail:
806 TALLOC_FREE(frame);
807 return status;
810 /****************************************************************************
811 Chmod or chown a file internal (UNIX extensions).
812 ****************************************************************************/
814 struct cli_posix_chown_chmod_internal_state {
815 uint8_t data[100];
818 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
820 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
821 struct tevent_context *ev,
822 struct cli_state *cli,
823 const char *fname,
824 uint32_t mode,
825 uint32_t uid,
826 uint32_t gid)
828 struct tevent_req *req = NULL, *subreq = NULL;
829 struct cli_posix_chown_chmod_internal_state *state = NULL;
831 req = tevent_req_create(mem_ctx, &state,
832 struct cli_posix_chown_chmod_internal_state);
833 if (req == NULL) {
834 return NULL;
837 memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
838 memset(&state->data[40], '\0', 60);
839 SIVAL(state->data,40,uid);
840 SIVAL(state->data,48,gid);
841 SIVAL(state->data,84,mode);
843 subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
844 fname, state->data, sizeof(state->data));
845 if (tevent_req_nomem(subreq, req)) {
846 return tevent_req_post(req, ev);
848 tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
849 req);
850 return req;
853 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
855 NTSTATUS status = cli_setpathinfo_recv(subreq);
856 tevent_req_simple_finish_ntstatus(subreq, status);
859 /****************************************************************************
860 chmod a file (UNIX extensions).
861 ****************************************************************************/
863 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
864 struct tevent_context *ev,
865 struct cli_state *cli,
866 const char *fname,
867 mode_t mode)
869 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
870 fname,
871 unix_perms_to_wire(mode),
872 SMB_UID_NO_CHANGE,
873 SMB_GID_NO_CHANGE);
876 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
878 return tevent_req_simple_recv_ntstatus(req);
881 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
883 TALLOC_CTX *frame = talloc_stackframe();
884 struct tevent_context *ev = NULL;
885 struct tevent_req *req = NULL;
886 NTSTATUS status = NT_STATUS_OK;
888 if (smbXcli_conn_has_async_calls(cli->conn)) {
890 * Can't use sync call while an async call is in flight
892 status = NT_STATUS_INVALID_PARAMETER;
893 goto fail;
896 ev = samba_tevent_context_init(frame);
897 if (ev == NULL) {
898 status = NT_STATUS_NO_MEMORY;
899 goto fail;
902 req = cli_posix_chmod_send(frame,
904 cli,
905 fname,
906 mode);
907 if (req == NULL) {
908 status = NT_STATUS_NO_MEMORY;
909 goto fail;
912 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
913 goto fail;
916 status = cli_posix_chmod_recv(req);
918 fail:
919 TALLOC_FREE(frame);
920 return status;
923 /****************************************************************************
924 chown a file (UNIX extensions).
925 ****************************************************************************/
927 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
928 struct tevent_context *ev,
929 struct cli_state *cli,
930 const char *fname,
931 uid_t uid,
932 gid_t gid)
934 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
935 fname,
936 SMB_MODE_NO_CHANGE,
937 (uint32_t)uid,
938 (uint32_t)gid);
941 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
943 return tevent_req_simple_recv_ntstatus(req);
946 NTSTATUS cli_posix_chown(struct cli_state *cli,
947 const char *fname,
948 uid_t uid,
949 gid_t gid)
951 TALLOC_CTX *frame = talloc_stackframe();
952 struct tevent_context *ev = NULL;
953 struct tevent_req *req = NULL;
954 NTSTATUS status = NT_STATUS_OK;
956 if (smbXcli_conn_has_async_calls(cli->conn)) {
958 * Can't use sync call while an async call is in flight
960 status = NT_STATUS_INVALID_PARAMETER;
961 goto fail;
964 ev = samba_tevent_context_init(frame);
965 if (ev == NULL) {
966 status = NT_STATUS_NO_MEMORY;
967 goto fail;
970 req = cli_posix_chown_send(frame,
972 cli,
973 fname,
974 uid,
975 gid);
976 if (req == NULL) {
977 status = NT_STATUS_NO_MEMORY;
978 goto fail;
981 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
982 goto fail;
985 status = cli_posix_chown_recv(req);
987 fail:
988 TALLOC_FREE(frame);
989 return status;
992 /****************************************************************************
993 Rename a file.
994 ****************************************************************************/
996 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
997 struct tevent_context *ev,
998 struct cli_state *cli,
999 const char *fname_src,
1000 const char *fname_dst,
1001 bool replace);
1003 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1004 struct tevent_context *ev,
1005 struct cli_state *cli,
1006 const char *fname_src,
1007 const char *fname_dst,
1008 bool replace);
1010 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1011 struct tevent_context *ev,
1012 struct cli_state *cli,
1013 const char *fname_src,
1014 const char *fname_dst,
1015 bool replace)
1017 if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
1018 return cli_smb1_rename_send(mem_ctx, ev, cli, fname_src,
1019 fname_dst, replace);
1020 } else {
1021 return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src,
1022 fname_dst, replace);
1026 struct cli_smb1_rename_state {
1027 uint8_t *data;
1030 static void cli_smb1_rename_done(struct tevent_req *subreq);
1032 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1033 struct tevent_context *ev,
1034 struct cli_state *cli,
1035 const char *fname_src,
1036 const char *fname_dst,
1037 bool replace)
1039 NTSTATUS status;
1040 struct tevent_req *req = NULL, *subreq = NULL;
1041 struct cli_smb1_rename_state *state = NULL;
1042 smb_ucs2_t *converted_str = NULL;
1043 size_t converted_size_bytes = 0;
1045 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
1046 if (req == NULL) {
1047 return NULL;
1050 if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
1051 &converted_size_bytes)) {
1052 status = NT_STATUS_INVALID_PARAMETER;
1053 goto fail;
1056 /* W2K8 insists the dest name is not null
1057 terminated. Remove the last 2 zero bytes
1058 and reduce the name length. */
1060 if (converted_size_bytes < 2) {
1061 status = NT_STATUS_INVALID_PARAMETER;
1062 goto fail;
1064 converted_size_bytes -= 2;
1066 state->data =
1067 talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
1068 if (state->data == NULL) {
1069 status = NT_STATUS_NO_MEMORY;
1070 goto fail;
1073 if (replace) {
1074 SCVAL(state->data, 0, 1);
1077 SIVAL(state->data, 8, converted_size_bytes);
1078 memcpy(state->data + 12, converted_str, converted_size_bytes);
1080 TALLOC_FREE(converted_str);
1082 subreq = cli_setpathinfo_send(
1083 state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
1084 talloc_get_size(state->data));
1085 if (tevent_req_nomem(subreq, req)) {
1086 status = NT_STATUS_NO_MEMORY;
1087 goto fail;
1089 tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
1090 return req;
1092 fail:
1093 TALLOC_FREE(converted_str);
1094 tevent_req_nterror(req, status);
1095 return tevent_req_post(req, ev);
1098 static void cli_smb1_rename_done(struct tevent_req *subreq)
1100 NTSTATUS status = cli_setpathinfo_recv(subreq);
1101 tevent_req_simple_finish_ntstatus(subreq, status);
1104 static void cli_cifs_rename_done(struct tevent_req *subreq);
1106 struct cli_cifs_rename_state {
1107 uint16_t vwv[1];
1110 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1111 struct tevent_context *ev,
1112 struct cli_state *cli,
1113 const char *fname_src,
1114 const char *fname_dst,
1115 bool replace)
1117 struct tevent_req *req = NULL, *subreq = NULL;
1118 struct cli_cifs_rename_state *state = NULL;
1119 uint8_t additional_flags = 0;
1120 uint16_t additional_flags2 = 0;
1121 uint8_t *bytes = NULL;
1123 req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
1124 if (req == NULL) {
1125 return NULL;
1128 if (replace) {
1130 * CIFS doesn't support replace
1132 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1133 return tevent_req_post(req, ev);
1136 SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1138 bytes = talloc_array(state, uint8_t, 1);
1139 if (tevent_req_nomem(bytes, req)) {
1140 return tevent_req_post(req, ev);
1142 bytes[0] = 4;
1143 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1144 strlen(fname_src)+1, NULL);
1145 if (tevent_req_nomem(bytes, req)) {
1146 return tevent_req_post(req, ev);
1149 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1150 additional_flags2 = FLAGS2_REPARSE_PATH;
1153 bytes = talloc_realloc(state, bytes, uint8_t,
1154 talloc_get_size(bytes)+1);
1155 if (tevent_req_nomem(bytes, req)) {
1156 return tevent_req_post(req, ev);
1159 bytes[talloc_get_size(bytes)-1] = 4;
1160 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1161 strlen(fname_dst)+1, NULL);
1162 if (tevent_req_nomem(bytes, req)) {
1163 return tevent_req_post(req, ev);
1166 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1167 additional_flags2,
1168 1, state->vwv, talloc_get_size(bytes), bytes);
1169 if (tevent_req_nomem(subreq, req)) {
1170 return tevent_req_post(req, ev);
1172 tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
1173 return req;
1176 static void cli_cifs_rename_done(struct tevent_req *subreq)
1178 struct tevent_req *req = tevent_req_callback_data(
1179 subreq, struct tevent_req);
1180 NTSTATUS status;
1182 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1183 TALLOC_FREE(subreq);
1184 if (tevent_req_nterror(req, status)) {
1185 return;
1187 tevent_req_done(req);
1190 NTSTATUS cli_rename_recv(struct tevent_req *req)
1192 return tevent_req_simple_recv_ntstatus(req);
1195 NTSTATUS cli_rename(struct cli_state *cli,
1196 const char *fname_src,
1197 const char *fname_dst,
1198 bool replace)
1200 TALLOC_CTX *frame = NULL;
1201 struct tevent_context *ev;
1202 struct tevent_req *req;
1203 NTSTATUS status = NT_STATUS_OK;
1205 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1206 return cli_smb2_rename(cli, fname_src, fname_dst, replace);
1209 frame = talloc_stackframe();
1211 if (smbXcli_conn_has_async_calls(cli->conn)) {
1213 * Can't use sync call while an async call is in flight
1215 status = NT_STATUS_INVALID_PARAMETER;
1216 goto fail;
1219 ev = samba_tevent_context_init(frame);
1220 if (ev == NULL) {
1221 status = NT_STATUS_NO_MEMORY;
1222 goto fail;
1225 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
1226 if (req == NULL) {
1227 status = NT_STATUS_NO_MEMORY;
1228 goto fail;
1231 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1232 goto fail;
1235 status = cli_rename_recv(req);
1237 fail:
1238 TALLOC_FREE(frame);
1239 return status;
1242 /****************************************************************************
1243 NT Rename a file.
1244 ****************************************************************************/
1246 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1248 struct cli_ntrename_internal_state {
1249 uint16_t vwv[4];
1252 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1253 struct tevent_context *ev,
1254 struct cli_state *cli,
1255 const char *fname_src,
1256 const char *fname_dst,
1257 uint16_t rename_flag)
1259 struct tevent_req *req = NULL, *subreq = NULL;
1260 struct cli_ntrename_internal_state *state = NULL;
1261 uint8_t additional_flags = 0;
1262 uint16_t additional_flags2 = 0;
1263 uint8_t *bytes = NULL;
1265 req = tevent_req_create(mem_ctx, &state,
1266 struct cli_ntrename_internal_state);
1267 if (req == NULL) {
1268 return NULL;
1271 SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1272 SSVAL(state->vwv+1, 0, rename_flag);
1274 bytes = talloc_array(state, uint8_t, 1);
1275 if (tevent_req_nomem(bytes, req)) {
1276 return tevent_req_post(req, ev);
1278 bytes[0] = 4;
1279 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1280 strlen(fname_src)+1, NULL);
1281 if (tevent_req_nomem(bytes, req)) {
1282 return tevent_req_post(req, ev);
1285 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1286 additional_flags2 = FLAGS2_REPARSE_PATH;
1289 bytes = talloc_realloc(state, bytes, uint8_t,
1290 talloc_get_size(bytes)+1);
1291 if (tevent_req_nomem(bytes, req)) {
1292 return tevent_req_post(req, ev);
1295 bytes[talloc_get_size(bytes)-1] = 4;
1296 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1297 strlen(fname_dst)+1, NULL);
1298 if (tevent_req_nomem(bytes, req)) {
1299 return tevent_req_post(req, ev);
1302 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1303 additional_flags2,
1304 4, state->vwv, talloc_get_size(bytes), bytes);
1305 if (tevent_req_nomem(subreq, req)) {
1306 return tevent_req_post(req, ev);
1308 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1309 return req;
1312 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1314 struct tevent_req *req = tevent_req_callback_data(
1315 subreq, struct tevent_req);
1316 NTSTATUS status;
1318 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1319 TALLOC_FREE(subreq);
1320 if (tevent_req_nterror(req, status)) {
1321 return;
1323 tevent_req_done(req);
1326 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1328 return tevent_req_simple_recv_ntstatus(req);
1331 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1332 struct tevent_context *ev,
1333 struct cli_state *cli,
1334 const char *fname_src,
1335 const char *fname_dst)
1337 return cli_ntrename_internal_send(mem_ctx,
1339 cli,
1340 fname_src,
1341 fname_dst,
1342 RENAME_FLAG_RENAME);
1345 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1347 return cli_ntrename_internal_recv(req);
1350 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1352 TALLOC_CTX *frame = talloc_stackframe();
1353 struct tevent_context *ev;
1354 struct tevent_req *req;
1355 NTSTATUS status = NT_STATUS_OK;
1357 if (smbXcli_conn_has_async_calls(cli->conn)) {
1359 * Can't use sync call while an async call is in flight
1361 status = NT_STATUS_INVALID_PARAMETER;
1362 goto fail;
1365 ev = samba_tevent_context_init(frame);
1366 if (ev == NULL) {
1367 status = NT_STATUS_NO_MEMORY;
1368 goto fail;
1371 req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1372 if (req == NULL) {
1373 status = NT_STATUS_NO_MEMORY;
1374 goto fail;
1377 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1378 goto fail;
1381 status = cli_ntrename_recv(req);
1383 fail:
1384 TALLOC_FREE(frame);
1385 return status;
1388 /****************************************************************************
1389 NT hardlink a file.
1390 ****************************************************************************/
1392 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1393 struct tevent_context *ev,
1394 struct cli_state *cli,
1395 const char *fname_src,
1396 const char *fname_dst)
1398 return cli_ntrename_internal_send(mem_ctx,
1400 cli,
1401 fname_src,
1402 fname_dst,
1403 RENAME_FLAG_HARD_LINK);
1406 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1408 return cli_ntrename_internal_recv(req);
1411 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1413 TALLOC_CTX *frame = talloc_stackframe();
1414 struct tevent_context *ev;
1415 struct tevent_req *req;
1416 NTSTATUS status = NT_STATUS_OK;
1418 if (smbXcli_conn_has_async_calls(cli->conn)) {
1420 * Can't use sync call while an async call is in flight
1422 status = NT_STATUS_INVALID_PARAMETER;
1423 goto fail;
1426 ev = samba_tevent_context_init(frame);
1427 if (ev == NULL) {
1428 status = NT_STATUS_NO_MEMORY;
1429 goto fail;
1432 req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1433 if (req == NULL) {
1434 status = NT_STATUS_NO_MEMORY;
1435 goto fail;
1438 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1439 goto fail;
1442 status = cli_nt_hardlink_recv(req);
1444 fail:
1445 TALLOC_FREE(frame);
1446 return status;
1449 /****************************************************************************
1450 Delete a file.
1451 ****************************************************************************/
1453 static void cli_unlink_done(struct tevent_req *subreq);
1455 struct cli_unlink_state {
1456 uint16_t vwv[1];
1459 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1460 struct tevent_context *ev,
1461 struct cli_state *cli,
1462 const char *fname,
1463 uint16_t mayhave_attrs)
1465 struct tevent_req *req = NULL, *subreq = NULL;
1466 struct cli_unlink_state *state = NULL;
1467 uint8_t additional_flags = 0;
1468 uint16_t additional_flags2 = 0;
1469 uint8_t *bytes = NULL;
1471 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1472 if (req == NULL) {
1473 return NULL;
1476 SSVAL(state->vwv+0, 0, mayhave_attrs);
1478 bytes = talloc_array(state, uint8_t, 1);
1479 if (tevent_req_nomem(bytes, req)) {
1480 return tevent_req_post(req, ev);
1482 bytes[0] = 4;
1483 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
1484 strlen(fname)+1, NULL);
1486 if (tevent_req_nomem(bytes, req)) {
1487 return tevent_req_post(req, ev);
1490 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1491 additional_flags2 = FLAGS2_REPARSE_PATH;
1494 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1495 additional_flags2,
1496 1, state->vwv, talloc_get_size(bytes), bytes);
1497 if (tevent_req_nomem(subreq, req)) {
1498 return tevent_req_post(req, ev);
1500 tevent_req_set_callback(subreq, cli_unlink_done, req);
1501 return req;
1504 static void cli_unlink_done(struct tevent_req *subreq)
1506 struct tevent_req *req = tevent_req_callback_data(
1507 subreq, struct tevent_req);
1508 NTSTATUS status;
1510 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1511 TALLOC_FREE(subreq);
1512 if (tevent_req_nterror(req, status)) {
1513 return;
1515 tevent_req_done(req);
1518 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1520 return tevent_req_simple_recv_ntstatus(req);
1523 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1525 TALLOC_CTX *frame = NULL;
1526 struct tevent_context *ev;
1527 struct tevent_req *req;
1528 NTSTATUS status = NT_STATUS_OK;
1530 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1531 return cli_smb2_unlink(cli, fname);
1534 frame = talloc_stackframe();
1536 if (smbXcli_conn_has_async_calls(cli->conn)) {
1538 * Can't use sync call while an async call is in flight
1540 status = NT_STATUS_INVALID_PARAMETER;
1541 goto fail;
1544 ev = samba_tevent_context_init(frame);
1545 if (ev == NULL) {
1546 status = NT_STATUS_NO_MEMORY;
1547 goto fail;
1550 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1551 if (req == NULL) {
1552 status = NT_STATUS_NO_MEMORY;
1553 goto fail;
1556 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1557 goto fail;
1560 status = cli_unlink_recv(req);
1562 fail:
1563 TALLOC_FREE(frame);
1564 return status;
1567 /****************************************************************************
1568 Create a directory.
1569 ****************************************************************************/
1571 static void cli_mkdir_done(struct tevent_req *subreq);
1573 struct cli_mkdir_state {
1574 int dummy;
1577 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1578 struct tevent_context *ev,
1579 struct cli_state *cli,
1580 const char *dname)
1582 struct tevent_req *req = NULL, *subreq = NULL;
1583 struct cli_mkdir_state *state = NULL;
1584 uint8_t additional_flags = 0;
1585 uint16_t additional_flags2 = 0;
1586 uint8_t *bytes = NULL;
1588 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1589 if (req == NULL) {
1590 return NULL;
1593 bytes = talloc_array(state, uint8_t, 1);
1594 if (tevent_req_nomem(bytes, req)) {
1595 return tevent_req_post(req, ev);
1597 bytes[0] = 4;
1598 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1599 strlen(dname)+1, NULL);
1601 if (tevent_req_nomem(bytes, req)) {
1602 return tevent_req_post(req, ev);
1605 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1606 additional_flags2 = FLAGS2_REPARSE_PATH;
1609 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1610 additional_flags2,
1611 0, NULL, talloc_get_size(bytes), bytes);
1612 if (tevent_req_nomem(subreq, req)) {
1613 return tevent_req_post(req, ev);
1615 tevent_req_set_callback(subreq, cli_mkdir_done, req);
1616 return req;
1619 static void cli_mkdir_done(struct tevent_req *subreq)
1621 struct tevent_req *req = tevent_req_callback_data(
1622 subreq, struct tevent_req);
1623 NTSTATUS status;
1625 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1626 TALLOC_FREE(subreq);
1627 if (tevent_req_nterror(req, status)) {
1628 return;
1630 tevent_req_done(req);
1633 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1635 return tevent_req_simple_recv_ntstatus(req);
1638 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1640 TALLOC_CTX *frame = NULL;
1641 struct tevent_context *ev;
1642 struct tevent_req *req;
1643 NTSTATUS status = NT_STATUS_OK;
1645 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1646 return cli_smb2_mkdir(cli, dname);
1649 frame = talloc_stackframe();
1651 if (smbXcli_conn_has_async_calls(cli->conn)) {
1653 * Can't use sync call while an async call is in flight
1655 status = NT_STATUS_INVALID_PARAMETER;
1656 goto fail;
1659 ev = samba_tevent_context_init(frame);
1660 if (ev == NULL) {
1661 status = NT_STATUS_NO_MEMORY;
1662 goto fail;
1665 req = cli_mkdir_send(frame, ev, cli, dname);
1666 if (req == NULL) {
1667 status = NT_STATUS_NO_MEMORY;
1668 goto fail;
1671 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1672 goto fail;
1675 status = cli_mkdir_recv(req);
1677 fail:
1678 TALLOC_FREE(frame);
1679 return status;
1682 /****************************************************************************
1683 Remove a directory.
1684 ****************************************************************************/
1686 static void cli_rmdir_done(struct tevent_req *subreq);
1688 struct cli_rmdir_state {
1689 int dummy;
1692 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1693 struct tevent_context *ev,
1694 struct cli_state *cli,
1695 const char *dname)
1697 struct tevent_req *req = NULL, *subreq = NULL;
1698 struct cli_rmdir_state *state = NULL;
1699 uint8_t additional_flags = 0;
1700 uint16_t additional_flags2 = 0;
1701 uint8_t *bytes = NULL;
1703 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1704 if (req == NULL) {
1705 return NULL;
1708 bytes = talloc_array(state, uint8_t, 1);
1709 if (tevent_req_nomem(bytes, req)) {
1710 return tevent_req_post(req, ev);
1712 bytes[0] = 4;
1713 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1714 strlen(dname)+1, NULL);
1716 if (tevent_req_nomem(bytes, req)) {
1717 return tevent_req_post(req, ev);
1720 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1721 additional_flags2 = FLAGS2_REPARSE_PATH;
1724 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1725 additional_flags2,
1726 0, NULL, talloc_get_size(bytes), bytes);
1727 if (tevent_req_nomem(subreq, req)) {
1728 return tevent_req_post(req, ev);
1730 tevent_req_set_callback(subreq, cli_rmdir_done, req);
1731 return req;
1734 static void cli_rmdir_done(struct tevent_req *subreq)
1736 struct tevent_req *req = tevent_req_callback_data(
1737 subreq, struct tevent_req);
1738 NTSTATUS status;
1740 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1741 TALLOC_FREE(subreq);
1742 if (tevent_req_nterror(req, status)) {
1743 return;
1745 tevent_req_done(req);
1748 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1750 return tevent_req_simple_recv_ntstatus(req);
1753 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1755 TALLOC_CTX *frame = NULL;
1756 struct tevent_context *ev;
1757 struct tevent_req *req;
1758 NTSTATUS status = NT_STATUS_OK;
1760 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1761 return cli_smb2_rmdir(cli, dname);
1764 frame = talloc_stackframe();
1766 if (smbXcli_conn_has_async_calls(cli->conn)) {
1768 * Can't use sync call while an async call is in flight
1770 status = NT_STATUS_INVALID_PARAMETER;
1771 goto fail;
1774 ev = samba_tevent_context_init(frame);
1775 if (ev == NULL) {
1776 status = NT_STATUS_NO_MEMORY;
1777 goto fail;
1780 req = cli_rmdir_send(frame, ev, cli, dname);
1781 if (req == NULL) {
1782 status = NT_STATUS_NO_MEMORY;
1783 goto fail;
1786 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1787 goto fail;
1790 status = cli_rmdir_recv(req);
1792 fail:
1793 TALLOC_FREE(frame);
1794 return status;
1797 /****************************************************************************
1798 Set or clear the delete on close flag.
1799 ****************************************************************************/
1801 struct doc_state {
1802 uint16_t setup;
1803 uint8_t param[6];
1804 uint8_t data[1];
1807 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
1808 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
1810 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1811 struct tevent_context *ev,
1812 struct cli_state *cli,
1813 uint16_t fnum,
1814 bool flag)
1816 struct tevent_req *req = NULL, *subreq = NULL;
1817 struct doc_state *state = NULL;
1819 req = tevent_req_create(mem_ctx, &state, struct doc_state);
1820 if (req == NULL) {
1821 return NULL;
1824 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1825 subreq = cli_smb2_delete_on_close_send(state, ev, cli,
1826 fnum, flag);
1827 if (tevent_req_nomem(subreq, req)) {
1828 return tevent_req_post(req, ev);
1830 tevent_req_set_callback(subreq,
1831 cli_nt_delete_on_close_smb2_done,
1832 req);
1833 return req;
1836 /* Setup setup word. */
1837 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1839 /* Setup param array. */
1840 SSVAL(state->param,0,fnum);
1841 SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1843 /* Setup data array. */
1844 SCVAL(&state->data[0], 0, flag ? 1 : 0);
1846 subreq = cli_trans_send(state, /* mem ctx. */
1847 ev, /* event ctx. */
1848 cli, /* cli_state. */
1849 0, /* additional_flags2 */
1850 SMBtrans2, /* cmd. */
1851 NULL, /* pipe name. */
1852 -1, /* fid. */
1853 0, /* function. */
1854 0, /* flags. */
1855 &state->setup, /* setup. */
1856 1, /* num setup uint16_t words. */
1857 0, /* max returned setup. */
1858 state->param, /* param. */
1859 6, /* num param. */
1860 2, /* max returned param. */
1861 state->data, /* data. */
1862 1, /* num data. */
1863 0); /* max returned data. */
1865 if (tevent_req_nomem(subreq, req)) {
1866 return tevent_req_post(req, ev);
1868 tevent_req_set_callback(subreq,
1869 cli_nt_delete_on_close_smb1_done,
1870 req);
1871 return req;
1874 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
1876 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
1877 NULL, 0, NULL, NULL, 0, NULL);
1878 tevent_req_simple_finish_ntstatus(subreq, status);
1881 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
1883 NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
1884 tevent_req_simple_finish_ntstatus(subreq, status);
1887 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1889 return tevent_req_simple_recv_ntstatus(req);
1892 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1894 TALLOC_CTX *frame = talloc_stackframe();
1895 struct tevent_context *ev = NULL;
1896 struct tevent_req *req = NULL;
1897 NTSTATUS status = NT_STATUS_OK;
1899 if (smbXcli_conn_has_async_calls(cli->conn)) {
1901 * Can't use sync call while an async call is in flight
1903 status = NT_STATUS_INVALID_PARAMETER;
1904 goto fail;
1907 ev = samba_tevent_context_init(frame);
1908 if (ev == NULL) {
1909 status = NT_STATUS_NO_MEMORY;
1910 goto fail;
1913 req = cli_nt_delete_on_close_send(frame,
1915 cli,
1916 fnum,
1917 flag);
1918 if (req == NULL) {
1919 status = NT_STATUS_NO_MEMORY;
1920 goto fail;
1923 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1924 goto fail;
1927 status = cli_nt_delete_on_close_recv(req);
1929 fail:
1930 TALLOC_FREE(frame);
1931 return status;
1934 struct cli_ntcreate1_state {
1935 uint16_t vwv[24];
1936 uint16_t fnum;
1937 struct smb_create_returns cr;
1938 struct tevent_req *subreq;
1941 static void cli_ntcreate1_done(struct tevent_req *subreq);
1942 static bool cli_ntcreate1_cancel(struct tevent_req *req);
1944 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
1945 struct tevent_context *ev,
1946 struct cli_state *cli,
1947 const char *fname,
1948 uint32_t CreatFlags,
1949 uint32_t DesiredAccess,
1950 uint32_t FileAttributes,
1951 uint32_t ShareAccess,
1952 uint32_t CreateDisposition,
1953 uint32_t CreateOptions,
1954 uint8_t SecurityFlags)
1956 struct tevent_req *req, *subreq;
1957 struct cli_ntcreate1_state *state;
1958 uint16_t *vwv;
1959 uint8_t *bytes;
1960 size_t converted_len;
1961 uint16_t additional_flags2 = 0;
1963 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
1964 if (req == NULL) {
1965 return NULL;
1968 vwv = state->vwv;
1970 SCVAL(vwv+0, 0, 0xFF);
1971 SCVAL(vwv+0, 1, 0);
1972 SSVAL(vwv+1, 0, 0);
1973 SCVAL(vwv+2, 0, 0);
1975 if (cli->use_oplocks) {
1976 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1978 SIVAL(vwv+3, 1, CreatFlags);
1979 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
1980 SIVAL(vwv+7, 1, DesiredAccess);
1981 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
1982 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
1983 SIVAL(vwv+13, 1, FileAttributes);
1984 SIVAL(vwv+15, 1, ShareAccess);
1985 SIVAL(vwv+17, 1, CreateDisposition);
1986 SIVAL(vwv+19, 1, CreateOptions |
1987 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
1988 SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1989 SCVAL(vwv+23, 1, SecurityFlags);
1991 bytes = talloc_array(state, uint8_t, 0);
1992 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
1993 fname, strlen(fname)+1,
1994 &converted_len);
1996 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1997 additional_flags2 = FLAGS2_REPARSE_PATH;
2000 /* sigh. this copes with broken netapp filer behaviour */
2001 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2003 if (tevent_req_nomem(bytes, req)) {
2004 return tevent_req_post(req, ev);
2007 SSVAL(vwv+2, 1, converted_len);
2009 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2010 additional_flags2, 24, vwv,
2011 talloc_get_size(bytes), bytes);
2012 if (tevent_req_nomem(subreq, req)) {
2013 return tevent_req_post(req, ev);
2015 tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2017 state->subreq = subreq;
2018 tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2020 return req;
2023 static void cli_ntcreate1_done(struct tevent_req *subreq)
2025 struct tevent_req *req = tevent_req_callback_data(
2026 subreq, struct tevent_req);
2027 struct cli_ntcreate1_state *state = tevent_req_data(
2028 req, struct cli_ntcreate1_state);
2029 uint8_t wct;
2030 uint16_t *vwv;
2031 uint32_t num_bytes;
2032 uint8_t *bytes;
2033 NTSTATUS status;
2035 status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2036 &num_bytes, &bytes);
2037 TALLOC_FREE(subreq);
2038 if (tevent_req_nterror(req, status)) {
2039 return;
2041 state->cr.oplock_level = CVAL(vwv+2, 0);
2042 state->fnum = SVAL(vwv+2, 1);
2043 state->cr.create_action = IVAL(vwv+3, 1);
2044 state->cr.creation_time = BVAL(vwv+5, 1);
2045 state->cr.last_access_time = BVAL(vwv+9, 1);
2046 state->cr.last_write_time = BVAL(vwv+13, 1);
2047 state->cr.change_time = BVAL(vwv+17, 1);
2048 state->cr.file_attributes = IVAL(vwv+21, 1);
2049 state->cr.allocation_size = BVAL(vwv+23, 1);
2050 state->cr.end_of_file = BVAL(vwv+27, 1);
2052 tevent_req_done(req);
2055 static bool cli_ntcreate1_cancel(struct tevent_req *req)
2057 struct cli_ntcreate1_state *state = tevent_req_data(
2058 req, struct cli_ntcreate1_state);
2059 return tevent_req_cancel(state->subreq);
2062 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2063 uint16_t *pfnum,
2064 struct smb_create_returns *cr)
2066 struct cli_ntcreate1_state *state = tevent_req_data(
2067 req, struct cli_ntcreate1_state);
2068 NTSTATUS status;
2070 if (tevent_req_is_nterror(req, &status)) {
2071 return status;
2073 *pfnum = state->fnum;
2074 if (cr != NULL) {
2075 *cr = state->cr;
2077 return NT_STATUS_OK;
2080 struct cli_ntcreate_state {
2081 NTSTATUS (*recv)(struct tevent_req *req, uint16_t *fnum,
2082 struct smb_create_returns *cr);
2083 struct smb_create_returns cr;
2084 uint16_t fnum;
2085 struct tevent_req *subreq;
2088 static void cli_ntcreate_done(struct tevent_req *subreq);
2089 static bool cli_ntcreate_cancel(struct tevent_req *req);
2091 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
2092 struct tevent_context *ev,
2093 struct cli_state *cli,
2094 const char *fname,
2095 uint32_t create_flags,
2096 uint32_t desired_access,
2097 uint32_t file_attributes,
2098 uint32_t share_access,
2099 uint32_t create_disposition,
2100 uint32_t create_options,
2101 uint8_t security_flags)
2103 struct tevent_req *req, *subreq;
2104 struct cli_ntcreate_state *state;
2106 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2107 if (req == NULL) {
2108 return NULL;
2111 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2112 state->recv = cli_smb2_create_fnum_recv;
2114 if (cli->use_oplocks) {
2115 create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2118 subreq = cli_smb2_create_fnum_send(
2119 state, ev, cli, fname, create_flags, desired_access,
2120 file_attributes, share_access, create_disposition,
2121 create_options);
2122 } else {
2123 state->recv = cli_ntcreate1_recv;
2124 subreq = cli_ntcreate1_send(
2125 state, ev, cli, fname, create_flags, desired_access,
2126 file_attributes, share_access, create_disposition,
2127 create_options, security_flags);
2129 if (tevent_req_nomem(subreq, req)) {
2130 return tevent_req_post(req, ev);
2132 tevent_req_set_callback(subreq, cli_ntcreate_done, req);
2134 state->subreq = subreq;
2135 tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2137 return req;
2140 static void cli_ntcreate_done(struct tevent_req *subreq)
2142 struct tevent_req *req = tevent_req_callback_data(
2143 subreq, struct tevent_req);
2144 struct cli_ntcreate_state *state = tevent_req_data(
2145 req, struct cli_ntcreate_state);
2146 NTSTATUS status;
2148 status = state->recv(subreq, &state->fnum, &state->cr);
2149 TALLOC_FREE(subreq);
2150 if (tevent_req_nterror(req, status)) {
2151 return;
2153 tevent_req_done(req);
2156 static bool cli_ntcreate_cancel(struct tevent_req *req)
2158 struct cli_ntcreate_state *state = tevent_req_data(
2159 req, struct cli_ntcreate_state);
2160 return tevent_req_cancel(state->subreq);
2163 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2164 struct smb_create_returns *cr)
2166 struct cli_ntcreate_state *state = tevent_req_data(
2167 req, struct cli_ntcreate_state);
2168 NTSTATUS status;
2170 if (tevent_req_is_nterror(req, &status)) {
2171 return status;
2173 if (fnum != NULL) {
2174 *fnum = state->fnum;
2176 if (cr != NULL) {
2177 *cr = state->cr;
2179 return NT_STATUS_OK;
2182 NTSTATUS cli_ntcreate(struct cli_state *cli,
2183 const char *fname,
2184 uint32_t CreatFlags,
2185 uint32_t DesiredAccess,
2186 uint32_t FileAttributes,
2187 uint32_t ShareAccess,
2188 uint32_t CreateDisposition,
2189 uint32_t CreateOptions,
2190 uint8_t SecurityFlags,
2191 uint16_t *pfid,
2192 struct smb_create_returns *cr)
2194 TALLOC_CTX *frame = talloc_stackframe();
2195 struct tevent_context *ev;
2196 struct tevent_req *req;
2197 NTSTATUS status = NT_STATUS_NO_MEMORY;
2199 if (smbXcli_conn_has_async_calls(cli->conn)) {
2201 * Can't use sync call while an async call is in flight
2203 status = NT_STATUS_INVALID_PARAMETER;
2204 goto fail;
2207 ev = samba_tevent_context_init(frame);
2208 if (ev == NULL) {
2209 goto fail;
2212 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2213 DesiredAccess, FileAttributes, ShareAccess,
2214 CreateDisposition, CreateOptions,
2215 SecurityFlags);
2216 if (req == NULL) {
2217 goto fail;
2220 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2221 goto fail;
2224 status = cli_ntcreate_recv(req, pfid, cr);
2225 fail:
2226 TALLOC_FREE(frame);
2227 return status;
2230 struct cli_nttrans_create_state {
2231 uint16_t fnum;
2232 struct smb_create_returns cr;
2235 static void cli_nttrans_create_done(struct tevent_req *subreq);
2237 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2238 struct tevent_context *ev,
2239 struct cli_state *cli,
2240 const char *fname,
2241 uint32_t CreatFlags,
2242 uint32_t DesiredAccess,
2243 uint32_t FileAttributes,
2244 uint32_t ShareAccess,
2245 uint32_t CreateDisposition,
2246 uint32_t CreateOptions,
2247 uint8_t SecurityFlags,
2248 struct security_descriptor *secdesc,
2249 struct ea_struct *eas,
2250 int num_eas)
2252 struct tevent_req *req, *subreq;
2253 struct cli_nttrans_create_state *state;
2254 uint8_t *param;
2255 uint8_t *secdesc_buf;
2256 size_t secdesc_len;
2257 NTSTATUS status;
2258 size_t converted_len;
2259 uint16_t additional_flags2 = 0;
2261 req = tevent_req_create(mem_ctx,
2262 &state, struct cli_nttrans_create_state);
2263 if (req == NULL) {
2264 return NULL;
2267 if (secdesc != NULL) {
2268 status = marshall_sec_desc(talloc_tos(), secdesc,
2269 &secdesc_buf, &secdesc_len);
2270 if (tevent_req_nterror(req, status)) {
2271 DEBUG(10, ("marshall_sec_desc failed: %s\n",
2272 nt_errstr(status)));
2273 return tevent_req_post(req, ev);
2275 } else {
2276 secdesc_buf = NULL;
2277 secdesc_len = 0;
2280 if (num_eas != 0) {
2282 * TODO ;-)
2284 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2285 return tevent_req_post(req, ev);
2288 param = talloc_array(state, uint8_t, 53);
2289 if (tevent_req_nomem(param, req)) {
2290 return tevent_req_post(req, ev);
2293 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2294 fname, strlen(fname),
2295 &converted_len);
2296 if (tevent_req_nomem(param, req)) {
2297 return tevent_req_post(req, ev);
2300 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2301 additional_flags2 = FLAGS2_REPARSE_PATH;
2304 SIVAL(param, 0, CreatFlags);
2305 SIVAL(param, 4, 0x0); /* RootDirectoryFid */
2306 SIVAL(param, 8, DesiredAccess);
2307 SIVAL(param, 12, 0x0); /* AllocationSize */
2308 SIVAL(param, 16, 0x0); /* AllocationSize */
2309 SIVAL(param, 20, FileAttributes);
2310 SIVAL(param, 24, ShareAccess);
2311 SIVAL(param, 28, CreateDisposition);
2312 SIVAL(param, 32, CreateOptions |
2313 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2314 SIVAL(param, 36, secdesc_len);
2315 SIVAL(param, 40, 0); /* EA length*/
2316 SIVAL(param, 44, converted_len);
2317 SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2318 SCVAL(param, 52, SecurityFlags);
2320 subreq = cli_trans_send(state, ev, cli,
2321 additional_flags2, /* additional_flags2 */
2322 SMBnttrans,
2323 NULL, -1, /* name, fid */
2324 NT_TRANSACT_CREATE, 0,
2325 NULL, 0, 0, /* setup */
2326 param, talloc_get_size(param), 128, /* param */
2327 secdesc_buf, secdesc_len, 0); /* data */
2328 if (tevent_req_nomem(subreq, req)) {
2329 return tevent_req_post(req, ev);
2331 tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2332 return req;
2335 static void cli_nttrans_create_done(struct tevent_req *subreq)
2337 struct tevent_req *req = tevent_req_callback_data(
2338 subreq, struct tevent_req);
2339 struct cli_nttrans_create_state *state = tevent_req_data(
2340 req, struct cli_nttrans_create_state);
2341 uint8_t *param;
2342 uint32_t num_param;
2343 NTSTATUS status;
2345 status = cli_trans_recv(subreq, talloc_tos(), NULL,
2346 NULL, 0, NULL, /* rsetup */
2347 &param, 69, &num_param,
2348 NULL, 0, NULL);
2349 if (tevent_req_nterror(req, status)) {
2350 return;
2352 state->cr.oplock_level = CVAL(param, 0);
2353 state->fnum = SVAL(param, 2);
2354 state->cr.create_action = IVAL(param, 4);
2355 state->cr.creation_time = BVAL(param, 12);
2356 state->cr.last_access_time = BVAL(param, 20);
2357 state->cr.last_write_time = BVAL(param, 28);
2358 state->cr.change_time = BVAL(param, 36);
2359 state->cr.file_attributes = IVAL(param, 44);
2360 state->cr.allocation_size = BVAL(param, 48);
2361 state->cr.end_of_file = BVAL(param, 56);
2363 TALLOC_FREE(param);
2364 tevent_req_done(req);
2367 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2368 uint16_t *fnum,
2369 struct smb_create_returns *cr)
2371 struct cli_nttrans_create_state *state = tevent_req_data(
2372 req, struct cli_nttrans_create_state);
2373 NTSTATUS status;
2375 if (tevent_req_is_nterror(req, &status)) {
2376 return status;
2378 *fnum = state->fnum;
2379 if (cr != NULL) {
2380 *cr = state->cr;
2382 return NT_STATUS_OK;
2385 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2386 const char *fname,
2387 uint32_t CreatFlags,
2388 uint32_t DesiredAccess,
2389 uint32_t FileAttributes,
2390 uint32_t ShareAccess,
2391 uint32_t CreateDisposition,
2392 uint32_t CreateOptions,
2393 uint8_t SecurityFlags,
2394 struct security_descriptor *secdesc,
2395 struct ea_struct *eas,
2396 int num_eas,
2397 uint16_t *pfid,
2398 struct smb_create_returns *cr)
2400 TALLOC_CTX *frame = talloc_stackframe();
2401 struct tevent_context *ev;
2402 struct tevent_req *req;
2403 NTSTATUS status = NT_STATUS_NO_MEMORY;
2405 if (smbXcli_conn_has_async_calls(cli->conn)) {
2407 * Can't use sync call while an async call is in flight
2409 status = NT_STATUS_INVALID_PARAMETER;
2410 goto fail;
2412 ev = samba_tevent_context_init(frame);
2413 if (ev == NULL) {
2414 goto fail;
2416 req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2417 DesiredAccess, FileAttributes,
2418 ShareAccess, CreateDisposition,
2419 CreateOptions, SecurityFlags,
2420 secdesc, eas, num_eas);
2421 if (req == NULL) {
2422 goto fail;
2424 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2425 goto fail;
2427 status = cli_nttrans_create_recv(req, pfid, cr);
2428 fail:
2429 TALLOC_FREE(frame);
2430 return status;
2433 /****************************************************************************
2434 Open a file
2435 WARNING: if you open with O_WRONLY then getattrE won't work!
2436 ****************************************************************************/
2438 struct cli_openx_state {
2439 const char *fname;
2440 uint16_t vwv[15];
2441 uint16_t fnum;
2442 struct iovec bytes;
2445 static void cli_openx_done(struct tevent_req *subreq);
2447 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2448 struct tevent_context *ev,
2449 struct cli_state *cli, const char *fname,
2450 int flags, int share_mode,
2451 struct tevent_req **psmbreq)
2453 struct tevent_req *req, *subreq;
2454 struct cli_openx_state *state;
2455 unsigned openfn;
2456 unsigned accessmode;
2457 uint8_t additional_flags;
2458 uint16_t additional_flags2 = 0;
2459 uint8_t *bytes;
2461 req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2462 if (req == NULL) {
2463 return NULL;
2466 openfn = 0;
2467 if (flags & O_CREAT) {
2468 openfn |= (1<<4);
2470 if (!(flags & O_EXCL)) {
2471 if (flags & O_TRUNC)
2472 openfn |= (1<<1);
2473 else
2474 openfn |= (1<<0);
2477 accessmode = (share_mode<<4);
2479 if ((flags & O_ACCMODE) == O_RDWR) {
2480 accessmode |= 2;
2481 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2482 accessmode |= 1;
2485 #if defined(O_SYNC)
2486 if ((flags & O_SYNC) == O_SYNC) {
2487 accessmode |= (1<<14);
2489 #endif /* O_SYNC */
2491 if (share_mode == DENY_FCB) {
2492 accessmode = 0xFF;
2495 SCVAL(state->vwv + 0, 0, 0xFF);
2496 SCVAL(state->vwv + 0, 1, 0);
2497 SSVAL(state->vwv + 1, 0, 0);
2498 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
2499 SSVAL(state->vwv + 3, 0, accessmode);
2500 SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2501 SSVAL(state->vwv + 5, 0, 0);
2502 SIVAL(state->vwv + 6, 0, 0);
2503 SSVAL(state->vwv + 8, 0, openfn);
2504 SIVAL(state->vwv + 9, 0, 0);
2505 SIVAL(state->vwv + 11, 0, 0);
2506 SIVAL(state->vwv + 13, 0, 0);
2508 additional_flags = 0;
2510 if (cli->use_oplocks) {
2511 /* if using oplocks then ask for a batch oplock via
2512 core and extended methods */
2513 additional_flags =
2514 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2515 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2518 bytes = talloc_array(state, uint8_t, 0);
2519 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2520 strlen(fname)+1, NULL);
2522 if (tevent_req_nomem(bytes, req)) {
2523 return tevent_req_post(req, ev);
2526 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2527 additional_flags2 = FLAGS2_REPARSE_PATH;
2530 state->bytes.iov_base = (void *)bytes;
2531 state->bytes.iov_len = talloc_get_size(bytes);
2533 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2534 additional_flags2, 15, state->vwv, 1, &state->bytes);
2535 if (subreq == NULL) {
2536 TALLOC_FREE(req);
2537 return NULL;
2539 tevent_req_set_callback(subreq, cli_openx_done, req);
2540 *psmbreq = subreq;
2541 return req;
2544 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2545 struct cli_state *cli, const char *fname,
2546 int flags, int share_mode)
2548 struct tevent_req *req, *subreq;
2549 NTSTATUS status;
2551 req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
2552 &subreq);
2553 if (req == NULL) {
2554 return NULL;
2557 status = smb1cli_req_chain_submit(&subreq, 1);
2558 if (tevent_req_nterror(req, status)) {
2559 return tevent_req_post(req, ev);
2561 return req;
2564 static void cli_openx_done(struct tevent_req *subreq)
2566 struct tevent_req *req = tevent_req_callback_data(
2567 subreq, struct tevent_req);
2568 struct cli_openx_state *state = tevent_req_data(
2569 req, struct cli_openx_state);
2570 uint8_t wct;
2571 uint16_t *vwv;
2572 NTSTATUS status;
2574 status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
2575 NULL);
2576 TALLOC_FREE(subreq);
2577 if (tevent_req_nterror(req, status)) {
2578 return;
2580 state->fnum = SVAL(vwv+2, 0);
2581 tevent_req_done(req);
2584 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2586 struct cli_openx_state *state = tevent_req_data(
2587 req, struct cli_openx_state);
2588 NTSTATUS status;
2590 if (tevent_req_is_nterror(req, &status)) {
2591 return status;
2593 *pfnum = state->fnum;
2594 return NT_STATUS_OK;
2597 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
2598 int share_mode, uint16_t *pfnum)
2600 TALLOC_CTX *frame = talloc_stackframe();
2601 struct tevent_context *ev;
2602 struct tevent_req *req;
2603 NTSTATUS status = NT_STATUS_NO_MEMORY;
2605 if (smbXcli_conn_has_async_calls(cli->conn)) {
2607 * Can't use sync call while an async call is in flight
2609 status = NT_STATUS_INVALID_PARAMETER;
2610 goto fail;
2613 ev = samba_tevent_context_init(frame);
2614 if (ev == NULL) {
2615 goto fail;
2618 req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
2619 if (req == NULL) {
2620 goto fail;
2623 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2624 goto fail;
2627 status = cli_openx_recv(req, pfnum);
2628 fail:
2629 TALLOC_FREE(frame);
2630 return status;
2632 /****************************************************************************
2633 Synchronous wrapper function that does an NtCreateX open by preference
2634 and falls back to openX if this fails.
2635 ****************************************************************************/
2637 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2638 int share_mode_in, uint16_t *pfnum)
2640 NTSTATUS status;
2641 unsigned int openfn = 0;
2642 unsigned int dos_deny = 0;
2643 uint32_t access_mask, share_mode, create_disposition, create_options;
2644 struct smb_create_returns cr;
2646 /* Do the initial mapping into OpenX parameters. */
2647 if (flags & O_CREAT) {
2648 openfn |= (1<<4);
2650 if (!(flags & O_EXCL)) {
2651 if (flags & O_TRUNC)
2652 openfn |= (1<<1);
2653 else
2654 openfn |= (1<<0);
2657 dos_deny = (share_mode_in<<4);
2659 if ((flags & O_ACCMODE) == O_RDWR) {
2660 dos_deny |= 2;
2661 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2662 dos_deny |= 1;
2665 #if defined(O_SYNC)
2666 if ((flags & O_SYNC) == O_SYNC) {
2667 dos_deny |= (1<<14);
2669 #endif /* O_SYNC */
2671 if (share_mode_in == DENY_FCB) {
2672 dos_deny = 0xFF;
2675 #if 0
2676 /* Hmmm. This is what I think the above code
2677 should look like if it's using the constants
2678 we #define. JRA. */
2680 if (flags & O_CREAT) {
2681 openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
2683 if (!(flags & O_EXCL)) {
2684 if (flags & O_TRUNC)
2685 openfn |= OPENX_FILE_EXISTS_TRUNCATE;
2686 else
2687 openfn |= OPENX_FILE_EXISTS_OPEN;
2690 dos_deny = SET_DENY_MODE(share_mode_in);
2692 if ((flags & O_ACCMODE) == O_RDWR) {
2693 dos_deny |= DOS_OPEN_RDWR;
2694 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2695 dos_deny |= DOS_OPEN_WRONLY;
2698 #if defined(O_SYNC)
2699 if ((flags & O_SYNC) == O_SYNC) {
2700 dos_deny |= FILE_SYNC_OPENMODE;
2702 #endif /* O_SYNC */
2704 if (share_mode_in == DENY_FCB) {
2705 dos_deny = 0xFF;
2707 #endif
2709 if (!map_open_params_to_ntcreate(fname, dos_deny,
2710 openfn, &access_mask,
2711 &share_mode, &create_disposition,
2712 &create_options, NULL)) {
2713 goto try_openx;
2716 status = cli_ntcreate(cli,
2717 fname,
2719 access_mask,
2721 share_mode,
2722 create_disposition,
2723 create_options,
2725 pfnum,
2726 &cr);
2728 /* Try and cope will all varients of "we don't do this call"
2729 and fall back to openX. */
2731 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
2732 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
2733 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
2734 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
2735 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
2736 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
2737 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
2738 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
2739 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
2740 goto try_openx;
2743 if (NT_STATUS_IS_OK(status) &&
2744 (create_options & FILE_NON_DIRECTORY_FILE) &&
2745 (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
2748 * Some (broken) servers return a valid handle
2749 * for directories even if FILE_NON_DIRECTORY_FILE
2750 * is set. Just close the handle and set the
2751 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
2753 status = cli_close(cli, *pfnum);
2754 if (!NT_STATUS_IS_OK(status)) {
2755 return status;
2757 status = NT_STATUS_FILE_IS_A_DIRECTORY;
2758 /* Set this so libsmbclient can retrieve it. */
2759 cli->raw_status = status;
2762 return status;
2764 try_openx:
2766 return cli_openx(cli, fname, flags, share_mode_in, pfnum);
2769 /****************************************************************************
2770 Close a file.
2771 ****************************************************************************/
2773 struct cli_smb1_close_state {
2774 uint16_t vwv[3];
2777 static void cli_smb1_close_done(struct tevent_req *subreq);
2779 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
2780 struct tevent_context *ev,
2781 struct cli_state *cli,
2782 uint16_t fnum,
2783 struct tevent_req **psubreq)
2785 struct tevent_req *req, *subreq;
2786 struct cli_smb1_close_state *state;
2788 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
2789 if (req == NULL) {
2790 return NULL;
2793 SSVAL(state->vwv+0, 0, fnum);
2794 SIVALS(state->vwv+1, 0, -1);
2796 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
2797 3, state->vwv, 0, NULL);
2798 if (subreq == NULL) {
2799 TALLOC_FREE(req);
2800 return NULL;
2802 tevent_req_set_callback(subreq, cli_smb1_close_done, req);
2803 *psubreq = subreq;
2804 return req;
2807 static void cli_smb1_close_done(struct tevent_req *subreq)
2809 struct tevent_req *req = tevent_req_callback_data(
2810 subreq, struct tevent_req);
2811 NTSTATUS status;
2813 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2814 TALLOC_FREE(subreq);
2815 if (tevent_req_nterror(req, status)) {
2816 return;
2818 tevent_req_done(req);
2821 struct cli_close_state {
2822 int dummy;
2825 static void cli_close_done(struct tevent_req *subreq);
2827 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2828 struct tevent_context *ev,
2829 struct cli_state *cli,
2830 uint16_t fnum)
2832 struct tevent_req *req, *subreq;
2833 struct cli_close_state *state;
2834 NTSTATUS status;
2836 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2837 if (req == NULL) {
2838 return NULL;
2841 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2842 subreq = cli_smb2_close_fnum_send(state,
2844 cli,
2845 fnum);
2846 if (tevent_req_nomem(subreq, req)) {
2847 return tevent_req_post(req, ev);
2849 } else {
2850 struct tevent_req *ch_req = NULL;
2851 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
2852 if (tevent_req_nomem(subreq, req)) {
2853 return tevent_req_post(req, ev);
2855 status = smb1cli_req_chain_submit(&ch_req, 1);
2856 if (tevent_req_nterror(req, status)) {
2857 return tevent_req_post(req, ev);
2861 tevent_req_set_callback(subreq, cli_close_done, req);
2862 return req;
2865 static void cli_close_done(struct tevent_req *subreq)
2867 struct tevent_req *req = tevent_req_callback_data(
2868 subreq, struct tevent_req);
2869 NTSTATUS status = NT_STATUS_OK;
2870 bool err = tevent_req_is_nterror(subreq, &status);
2872 TALLOC_FREE(subreq);
2873 if (err) {
2874 tevent_req_nterror(req, status);
2875 return;
2877 tevent_req_done(req);
2880 NTSTATUS cli_close_recv(struct tevent_req *req)
2882 return tevent_req_simple_recv_ntstatus(req);
2885 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2887 TALLOC_CTX *frame = NULL;
2888 struct tevent_context *ev;
2889 struct tevent_req *req;
2890 NTSTATUS status = NT_STATUS_OK;
2892 frame = talloc_stackframe();
2894 if (smbXcli_conn_has_async_calls(cli->conn)) {
2896 * Can't use sync call while an async call is in flight
2898 status = NT_STATUS_INVALID_PARAMETER;
2899 goto fail;
2902 ev = samba_tevent_context_init(frame);
2903 if (ev == NULL) {
2904 status = NT_STATUS_NO_MEMORY;
2905 goto fail;
2908 req = cli_close_send(frame, ev, cli, fnum);
2909 if (req == NULL) {
2910 status = NT_STATUS_NO_MEMORY;
2911 goto fail;
2914 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2915 goto fail;
2918 status = cli_close_recv(req);
2919 fail:
2920 TALLOC_FREE(frame);
2921 return status;
2924 /****************************************************************************
2925 Truncate a file to a specified size
2926 ****************************************************************************/
2928 struct ftrunc_state {
2929 uint16_t setup;
2930 uint8_t param[6];
2931 uint8_t data[8];
2934 static void cli_ftruncate_done(struct tevent_req *subreq)
2936 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2937 NULL, 0, NULL, NULL, 0, NULL);
2938 tevent_req_simple_finish_ntstatus(subreq, status);
2941 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2942 struct tevent_context *ev,
2943 struct cli_state *cli,
2944 uint16_t fnum,
2945 uint64_t size)
2947 struct tevent_req *req = NULL, *subreq = NULL;
2948 struct ftrunc_state *state = NULL;
2950 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2951 if (req == NULL) {
2952 return NULL;
2955 /* Setup setup word. */
2956 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2958 /* Setup param array. */
2959 SSVAL(state->param,0,fnum);
2960 SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2961 SSVAL(state->param,4,0);
2963 /* Setup data array. */
2964 SBVAL(state->data, 0, size);
2966 subreq = cli_trans_send(state, /* mem ctx. */
2967 ev, /* event ctx. */
2968 cli, /* cli_state. */
2969 0, /* additional_flags2 */
2970 SMBtrans2, /* cmd. */
2971 NULL, /* pipe name. */
2972 -1, /* fid. */
2973 0, /* function. */
2974 0, /* flags. */
2975 &state->setup, /* setup. */
2976 1, /* num setup uint16_t words. */
2977 0, /* max returned setup. */
2978 state->param, /* param. */
2979 6, /* num param. */
2980 2, /* max returned param. */
2981 state->data, /* data. */
2982 8, /* num data. */
2983 0); /* max returned data. */
2985 if (tevent_req_nomem(subreq, req)) {
2986 return tevent_req_post(req, ev);
2988 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2989 return req;
2992 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2994 return tevent_req_simple_recv_ntstatus(req);
2997 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2999 TALLOC_CTX *frame = NULL;
3000 struct tevent_context *ev = NULL;
3001 struct tevent_req *req = NULL;
3002 NTSTATUS status = NT_STATUS_OK;
3004 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3005 return cli_smb2_ftruncate(cli, fnum, size);
3008 frame = talloc_stackframe();
3010 if (smbXcli_conn_has_async_calls(cli->conn)) {
3012 * Can't use sync call while an async call is in flight
3014 status = NT_STATUS_INVALID_PARAMETER;
3015 goto fail;
3018 ev = samba_tevent_context_init(frame);
3019 if (ev == NULL) {
3020 status = NT_STATUS_NO_MEMORY;
3021 goto fail;
3024 req = cli_ftruncate_send(frame,
3026 cli,
3027 fnum,
3028 size);
3029 if (req == NULL) {
3030 status = NT_STATUS_NO_MEMORY;
3031 goto fail;
3034 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3035 goto fail;
3038 status = cli_ftruncate_recv(req);
3040 fail:
3041 TALLOC_FREE(frame);
3042 return status;
3045 /****************************************************************************
3046 send a lock with a specified locktype
3047 this is used for testing LOCKING_ANDX_CANCEL_LOCK
3048 ****************************************************************************/
3050 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
3051 uint32_t offset, uint32_t len,
3052 int timeout, unsigned char locktype)
3054 uint16_t vwv[8];
3055 uint8_t bytes[10];
3056 NTSTATUS status;
3057 unsigned int set_timeout = 0;
3058 unsigned int saved_timeout = 0;
3060 SCVAL(vwv + 0, 0, 0xff);
3061 SCVAL(vwv + 0, 1, 0);
3062 SSVAL(vwv + 1, 0, 0);
3063 SSVAL(vwv + 2, 0, fnum);
3064 SCVAL(vwv + 3, 0, locktype);
3065 SCVAL(vwv + 3, 1, 0);
3066 SIVALS(vwv + 4, 0, timeout);
3067 SSVAL(vwv + 6, 0, 0);
3068 SSVAL(vwv + 7, 0, 1);
3070 SSVAL(bytes, 0, cli_getpid(cli));
3071 SIVAL(bytes, 2, offset);
3072 SIVAL(bytes, 6, len);
3074 if (timeout != 0) {
3075 if (timeout == -1) {
3076 set_timeout = 0x7FFFFFFF;
3077 } else {
3078 set_timeout = timeout + 2*1000;
3080 saved_timeout = cli_set_timeout(cli, set_timeout);
3083 status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3084 10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3086 if (saved_timeout != 0) {
3087 cli_set_timeout(cli, saved_timeout);
3090 return status;
3093 /****************************************************************************
3094 Lock a file.
3095 note that timeout is in units of 2 milliseconds
3096 ****************************************************************************/
3098 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
3099 uint32_t offset, uint32_t len, int timeout,
3100 enum brl_type lock_type)
3102 NTSTATUS status;
3104 status = cli_locktype(cli, fnum, offset, len, timeout,
3105 (lock_type == READ_LOCK? 1 : 0));
3106 return status;
3109 /****************************************************************************
3110 Unlock a file.
3111 ****************************************************************************/
3113 struct cli_unlock_state {
3114 uint16_t vwv[8];
3115 uint8_t data[10];
3118 static void cli_unlock_done(struct tevent_req *subreq);
3120 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3121 struct tevent_context *ev,
3122 struct cli_state *cli,
3123 uint16_t fnum,
3124 uint64_t offset,
3125 uint64_t len)
3128 struct tevent_req *req = NULL, *subreq = NULL;
3129 struct cli_unlock_state *state = NULL;
3130 uint8_t additional_flags = 0;
3132 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3133 if (req == NULL) {
3134 return NULL;
3137 SCVAL(state->vwv+0, 0, 0xFF);
3138 SSVAL(state->vwv+2, 0, fnum);
3139 SCVAL(state->vwv+3, 0, 0);
3140 SIVALS(state->vwv+4, 0, 0);
3141 SSVAL(state->vwv+6, 0, 1);
3142 SSVAL(state->vwv+7, 0, 0);
3144 SSVAL(state->data, 0, cli_getpid(cli));
3145 SIVAL(state->data, 2, offset);
3146 SIVAL(state->data, 6, len);
3148 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3149 8, state->vwv, 10, state->data);
3150 if (tevent_req_nomem(subreq, req)) {
3151 return tevent_req_post(req, ev);
3153 tevent_req_set_callback(subreq, cli_unlock_done, req);
3154 return req;
3157 static void cli_unlock_done(struct tevent_req *subreq)
3159 struct tevent_req *req = tevent_req_callback_data(
3160 subreq, struct tevent_req);
3161 NTSTATUS status;
3163 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3164 TALLOC_FREE(subreq);
3165 if (tevent_req_nterror(req, status)) {
3166 return;
3168 tevent_req_done(req);
3171 NTSTATUS cli_unlock_recv(struct tevent_req *req)
3173 return tevent_req_simple_recv_ntstatus(req);
3176 NTSTATUS cli_unlock(struct cli_state *cli,
3177 uint16_t fnum,
3178 uint32_t offset,
3179 uint32_t len)
3181 TALLOC_CTX *frame = talloc_stackframe();
3182 struct tevent_context *ev;
3183 struct tevent_req *req;
3184 NTSTATUS status = NT_STATUS_OK;
3186 if (smbXcli_conn_has_async_calls(cli->conn)) {
3188 * Can't use sync call while an async call is in flight
3190 status = NT_STATUS_INVALID_PARAMETER;
3191 goto fail;
3194 ev = samba_tevent_context_init(frame);
3195 if (ev == NULL) {
3196 status = NT_STATUS_NO_MEMORY;
3197 goto fail;
3200 req = cli_unlock_send(frame, ev, cli,
3201 fnum, offset, len);
3202 if (req == NULL) {
3203 status = NT_STATUS_NO_MEMORY;
3204 goto fail;
3207 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3208 goto fail;
3211 status = cli_unlock_recv(req);
3213 fail:
3214 TALLOC_FREE(frame);
3215 return status;
3218 /****************************************************************************
3219 Lock a file with 64 bit offsets.
3220 ****************************************************************************/
3222 NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
3223 uint64_t offset, uint64_t len, int timeout,
3224 enum brl_type lock_type)
3226 uint16_t vwv[8];
3227 uint8_t bytes[20];
3228 unsigned int set_timeout = 0;
3229 unsigned int saved_timeout = 0;
3230 int ltype;
3231 NTSTATUS status;
3233 if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3234 return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
3237 ltype = (lock_type == READ_LOCK? 1 : 0);
3238 ltype |= LOCKING_ANDX_LARGE_FILES;
3240 SCVAL(vwv + 0, 0, 0xff);
3241 SCVAL(vwv + 0, 1, 0);
3242 SSVAL(vwv + 1, 0, 0);
3243 SSVAL(vwv + 2, 0, fnum);
3244 SCVAL(vwv + 3, 0, ltype);
3245 SCVAL(vwv + 3, 1, 0);
3246 SIVALS(vwv + 4, 0, timeout);
3247 SSVAL(vwv + 6, 0, 0);
3248 SSVAL(vwv + 7, 0, 1);
3250 SIVAL(bytes, 0, cli_getpid(cli));
3251 SOFF_T_R(bytes, 4, offset);
3252 SOFF_T_R(bytes, 12, len);
3254 if (timeout != 0) {
3255 if (timeout == -1) {
3256 set_timeout = 0x7FFFFFFF;
3257 } else {
3258 set_timeout = timeout + 2*1000;
3260 saved_timeout = cli_set_timeout(cli, set_timeout);
3263 status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3264 20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3266 if (saved_timeout != 0) {
3267 cli_set_timeout(cli, saved_timeout);
3270 return status;
3273 /****************************************************************************
3274 Unlock a file with 64 bit offsets.
3275 ****************************************************************************/
3277 struct cli_unlock64_state {
3278 uint16_t vwv[8];
3279 uint8_t data[20];
3282 static void cli_unlock64_done(struct tevent_req *subreq);
3284 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
3285 struct tevent_context *ev,
3286 struct cli_state *cli,
3287 uint16_t fnum,
3288 uint64_t offset,
3289 uint64_t len)
3292 struct tevent_req *req = NULL, *subreq = NULL;
3293 struct cli_unlock64_state *state = NULL;
3294 uint8_t additional_flags = 0;
3296 req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
3297 if (req == NULL) {
3298 return NULL;
3301 SCVAL(state->vwv+0, 0, 0xff);
3302 SSVAL(state->vwv+2, 0, fnum);
3303 SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
3304 SIVALS(state->vwv+4, 0, 0);
3305 SSVAL(state->vwv+6, 0, 1);
3306 SSVAL(state->vwv+7, 0, 0);
3308 SIVAL(state->data, 0, cli_getpid(cli));
3309 SOFF_T_R(state->data, 4, offset);
3310 SOFF_T_R(state->data, 12, len);
3312 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3313 8, state->vwv, 20, state->data);
3314 if (tevent_req_nomem(subreq, req)) {
3315 return tevent_req_post(req, ev);
3317 tevent_req_set_callback(subreq, cli_unlock64_done, req);
3318 return req;
3321 static void cli_unlock64_done(struct tevent_req *subreq)
3323 struct tevent_req *req = tevent_req_callback_data(
3324 subreq, struct tevent_req);
3325 NTSTATUS status;
3327 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3328 TALLOC_FREE(subreq);
3329 if (tevent_req_nterror(req, status)) {
3330 return;
3332 tevent_req_done(req);
3335 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
3337 return tevent_req_simple_recv_ntstatus(req);
3340 NTSTATUS cli_unlock64(struct cli_state *cli,
3341 uint16_t fnum,
3342 uint64_t offset,
3343 uint64_t len)
3345 TALLOC_CTX *frame = talloc_stackframe();
3346 struct tevent_context *ev;
3347 struct tevent_req *req;
3348 NTSTATUS status = NT_STATUS_OK;
3350 if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3351 return cli_unlock(cli, fnum, offset, len);
3354 if (smbXcli_conn_has_async_calls(cli->conn)) {
3356 * Can't use sync call while an async call is in flight
3358 status = NT_STATUS_INVALID_PARAMETER;
3359 goto fail;
3362 ev = samba_tevent_context_init(frame);
3363 if (ev == NULL) {
3364 status = NT_STATUS_NO_MEMORY;
3365 goto fail;
3368 req = cli_unlock64_send(frame, ev, cli,
3369 fnum, offset, len);
3370 if (req == NULL) {
3371 status = NT_STATUS_NO_MEMORY;
3372 goto fail;
3375 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3376 goto fail;
3379 status = cli_unlock64_recv(req);
3381 fail:
3382 TALLOC_FREE(frame);
3383 return status;
3386 /****************************************************************************
3387 Get/unlock a POSIX lock on a file - internal function.
3388 ****************************************************************************/
3390 struct posix_lock_state {
3391 uint16_t setup;
3392 uint8_t param[4];
3393 uint8_t data[POSIX_LOCK_DATA_SIZE];
3396 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3398 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3399 NULL, 0, NULL, NULL, 0, NULL);
3400 tevent_req_simple_finish_ntstatus(subreq, status);
3403 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3404 struct tevent_context *ev,
3405 struct cli_state *cli,
3406 uint16_t fnum,
3407 uint64_t offset,
3408 uint64_t len,
3409 bool wait_lock,
3410 enum brl_type lock_type)
3412 struct tevent_req *req = NULL, *subreq = NULL;
3413 struct posix_lock_state *state = NULL;
3415 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3416 if (req == NULL) {
3417 return NULL;
3420 /* Setup setup word. */
3421 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3423 /* Setup param array. */
3424 SSVAL(&state->param, 0, fnum);
3425 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3427 /* Setup data array. */
3428 switch (lock_type) {
3429 case READ_LOCK:
3430 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3431 POSIX_LOCK_TYPE_READ);
3432 break;
3433 case WRITE_LOCK:
3434 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3435 POSIX_LOCK_TYPE_WRITE);
3436 break;
3437 case UNLOCK_LOCK:
3438 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3439 POSIX_LOCK_TYPE_UNLOCK);
3440 break;
3441 default:
3442 return NULL;
3445 if (wait_lock) {
3446 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3447 POSIX_LOCK_FLAG_WAIT);
3448 } else {
3449 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3450 POSIX_LOCK_FLAG_NOWAIT);
3453 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3454 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3455 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3457 subreq = cli_trans_send(state, /* mem ctx. */
3458 ev, /* event ctx. */
3459 cli, /* cli_state. */
3460 0, /* additional_flags2 */
3461 SMBtrans2, /* cmd. */
3462 NULL, /* pipe name. */
3463 -1, /* fid. */
3464 0, /* function. */
3465 0, /* flags. */
3466 &state->setup, /* setup. */
3467 1, /* num setup uint16_t words. */
3468 0, /* max returned setup. */
3469 state->param, /* param. */
3470 4, /* num param. */
3471 2, /* max returned param. */
3472 state->data, /* data. */
3473 POSIX_LOCK_DATA_SIZE, /* num data. */
3474 0); /* max returned data. */
3476 if (tevent_req_nomem(subreq, req)) {
3477 return tevent_req_post(req, ev);
3479 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3480 return req;
3483 /****************************************************************************
3484 POSIX Lock a file.
3485 ****************************************************************************/
3487 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3488 struct tevent_context *ev,
3489 struct cli_state *cli,
3490 uint16_t fnum,
3491 uint64_t offset,
3492 uint64_t len,
3493 bool wait_lock,
3494 enum brl_type lock_type)
3496 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3497 wait_lock, lock_type);
3500 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3502 return tevent_req_simple_recv_ntstatus(req);
3505 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3506 uint64_t offset, uint64_t len,
3507 bool wait_lock, enum brl_type lock_type)
3509 TALLOC_CTX *frame = talloc_stackframe();
3510 struct tevent_context *ev = NULL;
3511 struct tevent_req *req = NULL;
3512 NTSTATUS status = NT_STATUS_OK;
3514 if (smbXcli_conn_has_async_calls(cli->conn)) {
3516 * Can't use sync call while an async call is in flight
3518 status = NT_STATUS_INVALID_PARAMETER;
3519 goto fail;
3522 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3523 status = NT_STATUS_INVALID_PARAMETER;
3524 goto fail;
3527 ev = samba_tevent_context_init(frame);
3528 if (ev == NULL) {
3529 status = NT_STATUS_NO_MEMORY;
3530 goto fail;
3533 req = cli_posix_lock_send(frame,
3535 cli,
3536 fnum,
3537 offset,
3538 len,
3539 wait_lock,
3540 lock_type);
3541 if (req == NULL) {
3542 status = NT_STATUS_NO_MEMORY;
3543 goto fail;
3546 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3547 goto fail;
3550 status = cli_posix_lock_recv(req);
3552 fail:
3553 TALLOC_FREE(frame);
3554 return status;
3557 /****************************************************************************
3558 POSIX Unlock a file.
3559 ****************************************************************************/
3561 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3562 struct tevent_context *ev,
3563 struct cli_state *cli,
3564 uint16_t fnum,
3565 uint64_t offset,
3566 uint64_t len)
3568 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3569 false, UNLOCK_LOCK);
3572 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3574 return tevent_req_simple_recv_ntstatus(req);
3577 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3579 TALLOC_CTX *frame = talloc_stackframe();
3580 struct tevent_context *ev = NULL;
3581 struct tevent_req *req = NULL;
3582 NTSTATUS status = NT_STATUS_OK;
3584 if (smbXcli_conn_has_async_calls(cli->conn)) {
3586 * Can't use sync call while an async call is in flight
3588 status = NT_STATUS_INVALID_PARAMETER;
3589 goto fail;
3592 ev = samba_tevent_context_init(frame);
3593 if (ev == NULL) {
3594 status = NT_STATUS_NO_MEMORY;
3595 goto fail;
3598 req = cli_posix_unlock_send(frame,
3600 cli,
3601 fnum,
3602 offset,
3603 len);
3604 if (req == NULL) {
3605 status = NT_STATUS_NO_MEMORY;
3606 goto fail;
3609 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3610 goto fail;
3613 status = cli_posix_unlock_recv(req);
3615 fail:
3616 TALLOC_FREE(frame);
3617 return status;
3620 /****************************************************************************
3621 Do a SMBgetattrE call.
3622 ****************************************************************************/
3624 static void cli_getattrE_done(struct tevent_req *subreq);
3626 struct cli_getattrE_state {
3627 uint16_t vwv[1];
3628 int zone_offset;
3629 uint16_t attr;
3630 off_t size;
3631 time_t change_time;
3632 time_t access_time;
3633 time_t write_time;
3636 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3637 struct tevent_context *ev,
3638 struct cli_state *cli,
3639 uint16_t fnum)
3641 struct tevent_req *req = NULL, *subreq = NULL;
3642 struct cli_getattrE_state *state = NULL;
3643 uint8_t additional_flags = 0;
3645 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3646 if (req == NULL) {
3647 return NULL;
3650 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3651 SSVAL(state->vwv+0,0,fnum);
3653 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
3654 1, state->vwv, 0, NULL);
3655 if (tevent_req_nomem(subreq, req)) {
3656 return tevent_req_post(req, ev);
3658 tevent_req_set_callback(subreq, cli_getattrE_done, req);
3659 return req;
3662 static void cli_getattrE_done(struct tevent_req *subreq)
3664 struct tevent_req *req = tevent_req_callback_data(
3665 subreq, struct tevent_req);
3666 struct cli_getattrE_state *state = tevent_req_data(
3667 req, struct cli_getattrE_state);
3668 uint8_t wct;
3669 uint16_t *vwv = NULL;
3670 NTSTATUS status;
3672 status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
3673 NULL, NULL);
3674 TALLOC_FREE(subreq);
3675 if (tevent_req_nterror(req, status)) {
3676 return;
3679 state->size = (off_t)IVAL(vwv+6,0);
3680 state->attr = SVAL(vwv+10,0);
3681 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3682 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3683 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3685 tevent_req_done(req);
3688 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3689 uint16_t *attr,
3690 off_t *size,
3691 time_t *change_time,
3692 time_t *access_time,
3693 time_t *write_time)
3695 struct cli_getattrE_state *state = tevent_req_data(
3696 req, struct cli_getattrE_state);
3697 NTSTATUS status;
3699 if (tevent_req_is_nterror(req, &status)) {
3700 return status;
3702 if (attr) {
3703 *attr = state->attr;
3705 if (size) {
3706 *size = state->size;
3708 if (change_time) {
3709 *change_time = state->change_time;
3711 if (access_time) {
3712 *access_time = state->access_time;
3714 if (write_time) {
3715 *write_time = state->write_time;
3717 return NT_STATUS_OK;
3720 NTSTATUS cli_getattrE(struct cli_state *cli,
3721 uint16_t fnum,
3722 uint16_t *attr,
3723 off_t *size,
3724 time_t *change_time,
3725 time_t *access_time,
3726 time_t *write_time)
3728 TALLOC_CTX *frame = NULL;
3729 struct tevent_context *ev = NULL;
3730 struct tevent_req *req = NULL;
3731 NTSTATUS status = NT_STATUS_OK;
3733 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3734 return cli_smb2_getattrE(cli,
3735 fnum,
3736 attr,
3737 size,
3738 change_time,
3739 access_time,
3740 write_time);
3743 frame = talloc_stackframe();
3745 if (smbXcli_conn_has_async_calls(cli->conn)) {
3747 * Can't use sync call while an async call is in flight
3749 status = NT_STATUS_INVALID_PARAMETER;
3750 goto fail;
3753 ev = samba_tevent_context_init(frame);
3754 if (ev == NULL) {
3755 status = NT_STATUS_NO_MEMORY;
3756 goto fail;
3759 req = cli_getattrE_send(frame, ev, cli, fnum);
3760 if (req == NULL) {
3761 status = NT_STATUS_NO_MEMORY;
3762 goto fail;
3765 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3766 goto fail;
3769 status = cli_getattrE_recv(req,
3770 attr,
3771 size,
3772 change_time,
3773 access_time,
3774 write_time);
3776 fail:
3777 TALLOC_FREE(frame);
3778 return status;
3781 /****************************************************************************
3782 Do a SMBgetatr call
3783 ****************************************************************************/
3785 static void cli_getatr_done(struct tevent_req *subreq);
3787 struct cli_getatr_state {
3788 int zone_offset;
3789 uint16_t attr;
3790 off_t size;
3791 time_t write_time;
3794 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3795 struct tevent_context *ev,
3796 struct cli_state *cli,
3797 const char *fname)
3799 struct tevent_req *req = NULL, *subreq = NULL;
3800 struct cli_getatr_state *state = NULL;
3801 uint8_t additional_flags = 0;
3802 uint16_t additional_flags2 = 0;
3803 uint8_t *bytes = NULL;
3805 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3806 if (req == NULL) {
3807 return NULL;
3810 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3812 bytes = talloc_array(state, uint8_t, 1);
3813 if (tevent_req_nomem(bytes, req)) {
3814 return tevent_req_post(req, ev);
3816 bytes[0] = 4;
3817 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3818 strlen(fname)+1, NULL);
3820 if (tevent_req_nomem(bytes, req)) {
3821 return tevent_req_post(req, ev);
3824 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
3825 additional_flags2 = FLAGS2_REPARSE_PATH;
3828 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3829 additional_flags2,
3830 0, NULL, talloc_get_size(bytes), bytes);
3831 if (tevent_req_nomem(subreq, req)) {
3832 return tevent_req_post(req, ev);
3834 tevent_req_set_callback(subreq, cli_getatr_done, req);
3835 return req;
3838 static void cli_getatr_done(struct tevent_req *subreq)
3840 struct tevent_req *req = tevent_req_callback_data(
3841 subreq, struct tevent_req);
3842 struct cli_getatr_state *state = tevent_req_data(
3843 req, struct cli_getatr_state);
3844 uint8_t wct;
3845 uint16_t *vwv = NULL;
3846 NTSTATUS status;
3848 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
3849 NULL);
3850 TALLOC_FREE(subreq);
3851 if (tevent_req_nterror(req, status)) {
3852 return;
3855 state->attr = SVAL(vwv+0,0);
3856 state->size = (off_t)IVAL(vwv+3,0);
3857 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3859 tevent_req_done(req);
3862 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3863 uint16_t *attr,
3864 off_t *size,
3865 time_t *write_time)
3867 struct cli_getatr_state *state = tevent_req_data(
3868 req, struct cli_getatr_state);
3869 NTSTATUS status;
3871 if (tevent_req_is_nterror(req, &status)) {
3872 return status;
3874 if (attr) {
3875 *attr = state->attr;
3877 if (size) {
3878 *size = state->size;
3880 if (write_time) {
3881 *write_time = state->write_time;
3883 return NT_STATUS_OK;
3886 NTSTATUS cli_getatr(struct cli_state *cli,
3887 const char *fname,
3888 uint16_t *attr,
3889 off_t *size,
3890 time_t *write_time)
3892 TALLOC_CTX *frame = NULL;
3893 struct tevent_context *ev = NULL;
3894 struct tevent_req *req = NULL;
3895 NTSTATUS status = NT_STATUS_OK;
3897 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3898 return cli_smb2_getatr(cli,
3899 fname,
3900 attr,
3901 size,
3902 write_time);
3905 frame = talloc_stackframe();
3907 if (smbXcli_conn_has_async_calls(cli->conn)) {
3909 * Can't use sync call while an async call is in flight
3911 status = NT_STATUS_INVALID_PARAMETER;
3912 goto fail;
3915 ev = samba_tevent_context_init(frame);
3916 if (ev == NULL) {
3917 status = NT_STATUS_NO_MEMORY;
3918 goto fail;
3921 req = cli_getatr_send(frame, ev, cli, fname);
3922 if (req == NULL) {
3923 status = NT_STATUS_NO_MEMORY;
3924 goto fail;
3927 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3928 goto fail;
3931 status = cli_getatr_recv(req,
3932 attr,
3933 size,
3934 write_time);
3936 fail:
3937 TALLOC_FREE(frame);
3938 return status;
3941 /****************************************************************************
3942 Do a SMBsetattrE call.
3943 ****************************************************************************/
3945 static void cli_setattrE_done(struct tevent_req *subreq);
3947 struct cli_setattrE_state {
3948 uint16_t vwv[7];
3951 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3952 struct tevent_context *ev,
3953 struct cli_state *cli,
3954 uint16_t fnum,
3955 time_t change_time,
3956 time_t access_time,
3957 time_t write_time)
3959 struct tevent_req *req = NULL, *subreq = NULL;
3960 struct cli_setattrE_state *state = NULL;
3961 uint8_t additional_flags = 0;
3963 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3964 if (req == NULL) {
3965 return NULL;
3968 SSVAL(state->vwv+0, 0, fnum);
3969 push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
3970 smb1cli_conn_server_time_zone(cli->conn));
3971 push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
3972 smb1cli_conn_server_time_zone(cli->conn));
3973 push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
3974 smb1cli_conn_server_time_zone(cli->conn));
3976 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
3977 7, state->vwv, 0, NULL);
3978 if (tevent_req_nomem(subreq, req)) {
3979 return tevent_req_post(req, ev);
3981 tevent_req_set_callback(subreq, cli_setattrE_done, req);
3982 return req;
3985 static void cli_setattrE_done(struct tevent_req *subreq)
3987 struct tevent_req *req = tevent_req_callback_data(
3988 subreq, struct tevent_req);
3989 NTSTATUS status;
3991 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3992 TALLOC_FREE(subreq);
3993 if (tevent_req_nterror(req, status)) {
3994 return;
3996 tevent_req_done(req);
3999 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4001 return tevent_req_simple_recv_ntstatus(req);
4004 NTSTATUS cli_setattrE(struct cli_state *cli,
4005 uint16_t fnum,
4006 time_t change_time,
4007 time_t access_time,
4008 time_t write_time)
4010 TALLOC_CTX *frame = NULL;
4011 struct tevent_context *ev = NULL;
4012 struct tevent_req *req = NULL;
4013 NTSTATUS status = NT_STATUS_OK;
4015 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4016 return cli_smb2_setattrE(cli,
4017 fnum,
4018 change_time,
4019 access_time,
4020 write_time);
4023 frame = talloc_stackframe();
4025 if (smbXcli_conn_has_async_calls(cli->conn)) {
4027 * Can't use sync call while an async call is in flight
4029 status = NT_STATUS_INVALID_PARAMETER;
4030 goto fail;
4033 ev = samba_tevent_context_init(frame);
4034 if (ev == NULL) {
4035 status = NT_STATUS_NO_MEMORY;
4036 goto fail;
4039 req = cli_setattrE_send(frame, ev,
4040 cli,
4041 fnum,
4042 change_time,
4043 access_time,
4044 write_time);
4046 if (req == NULL) {
4047 status = NT_STATUS_NO_MEMORY;
4048 goto fail;
4051 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4052 goto fail;
4055 status = cli_setattrE_recv(req);
4057 fail:
4058 TALLOC_FREE(frame);
4059 return status;
4062 /****************************************************************************
4063 Do a SMBsetatr call.
4064 ****************************************************************************/
4066 static void cli_setatr_done(struct tevent_req *subreq);
4068 struct cli_setatr_state {
4069 uint16_t vwv[8];
4072 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
4073 struct tevent_context *ev,
4074 struct cli_state *cli,
4075 const char *fname,
4076 uint16_t attr,
4077 time_t mtime)
4079 struct tevent_req *req = NULL, *subreq = NULL;
4080 struct cli_setatr_state *state = NULL;
4081 uint8_t additional_flags = 0;
4082 uint16_t additional_flags2 = 0;
4083 uint8_t *bytes = NULL;
4085 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
4086 if (req == NULL) {
4087 return NULL;
4090 SSVAL(state->vwv+0, 0, attr);
4091 push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
4093 bytes = talloc_array(state, uint8_t, 1);
4094 if (tevent_req_nomem(bytes, req)) {
4095 return tevent_req_post(req, ev);
4097 bytes[0] = 4;
4098 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4099 strlen(fname)+1, NULL);
4100 if (tevent_req_nomem(bytes, req)) {
4101 return tevent_req_post(req, ev);
4103 bytes = talloc_realloc(state, bytes, uint8_t,
4104 talloc_get_size(bytes)+1);
4105 if (tevent_req_nomem(bytes, req)) {
4106 return tevent_req_post(req, ev);
4109 bytes[talloc_get_size(bytes)-1] = 4;
4110 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
4111 1, NULL);
4112 if (tevent_req_nomem(bytes, req)) {
4113 return tevent_req_post(req, ev);
4116 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4117 additional_flags2 = FLAGS2_REPARSE_PATH;
4120 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
4121 additional_flags2,
4122 8, state->vwv, talloc_get_size(bytes), bytes);
4123 if (tevent_req_nomem(subreq, req)) {
4124 return tevent_req_post(req, ev);
4126 tevent_req_set_callback(subreq, cli_setatr_done, req);
4127 return req;
4130 static void cli_setatr_done(struct tevent_req *subreq)
4132 struct tevent_req *req = tevent_req_callback_data(
4133 subreq, struct tevent_req);
4134 NTSTATUS status;
4136 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4137 TALLOC_FREE(subreq);
4138 if (tevent_req_nterror(req, status)) {
4139 return;
4141 tevent_req_done(req);
4144 NTSTATUS cli_setatr_recv(struct tevent_req *req)
4146 return tevent_req_simple_recv_ntstatus(req);
4149 NTSTATUS cli_setatr(struct cli_state *cli,
4150 const char *fname,
4151 uint16_t attr,
4152 time_t mtime)
4154 TALLOC_CTX *frame = NULL;
4155 struct tevent_context *ev = NULL;
4156 struct tevent_req *req = NULL;
4157 NTSTATUS status = NT_STATUS_OK;
4159 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4160 return cli_smb2_setatr(cli,
4161 fname,
4162 attr,
4163 mtime);
4166 frame = talloc_stackframe();
4168 if (smbXcli_conn_has_async_calls(cli->conn)) {
4170 * Can't use sync call while an async call is in flight
4172 status = NT_STATUS_INVALID_PARAMETER;
4173 goto fail;
4176 ev = samba_tevent_context_init(frame);
4177 if (ev == NULL) {
4178 status = NT_STATUS_NO_MEMORY;
4179 goto fail;
4182 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
4183 if (req == NULL) {
4184 status = NT_STATUS_NO_MEMORY;
4185 goto fail;
4188 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4189 goto fail;
4192 status = cli_setatr_recv(req);
4194 fail:
4195 TALLOC_FREE(frame);
4196 return status;
4199 /****************************************************************************
4200 Check for existence of a dir.
4201 ****************************************************************************/
4203 static void cli_chkpath_done(struct tevent_req *subreq);
4205 struct cli_chkpath_state {
4206 int dummy;
4209 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
4210 struct tevent_context *ev,
4211 struct cli_state *cli,
4212 const char *fname)
4214 struct tevent_req *req = NULL, *subreq = NULL;
4215 struct cli_chkpath_state *state = NULL;
4216 uint8_t additional_flags = 0;
4217 uint16_t additional_flags2 = 0;
4218 uint8_t *bytes = NULL;
4220 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
4221 if (req == NULL) {
4222 return NULL;
4225 bytes = talloc_array(state, uint8_t, 1);
4226 if (tevent_req_nomem(bytes, req)) {
4227 return tevent_req_post(req, ev);
4229 bytes[0] = 4;
4230 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4231 strlen(fname)+1, NULL);
4233 if (tevent_req_nomem(bytes, req)) {
4234 return tevent_req_post(req, ev);
4237 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4238 additional_flags2 = FLAGS2_REPARSE_PATH;
4241 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
4242 additional_flags2,
4243 0, NULL, talloc_get_size(bytes), bytes);
4244 if (tevent_req_nomem(subreq, req)) {
4245 return tevent_req_post(req, ev);
4247 tevent_req_set_callback(subreq, cli_chkpath_done, req);
4248 return req;
4251 static void cli_chkpath_done(struct tevent_req *subreq)
4253 struct tevent_req *req = tevent_req_callback_data(
4254 subreq, struct tevent_req);
4255 NTSTATUS status;
4257 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4258 TALLOC_FREE(subreq);
4259 if (tevent_req_nterror(req, status)) {
4260 return;
4262 tevent_req_done(req);
4265 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
4267 return tevent_req_simple_recv_ntstatus(req);
4270 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
4272 TALLOC_CTX *frame = NULL;
4273 struct tevent_context *ev = NULL;
4274 struct tevent_req *req = NULL;
4275 char *path2 = NULL;
4276 NTSTATUS status = NT_STATUS_OK;
4278 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4279 return cli_smb2_chkpath(cli, path);
4282 frame = talloc_stackframe();
4284 if (smbXcli_conn_has_async_calls(cli->conn)) {
4286 * Can't use sync call while an async call is in flight
4288 status = NT_STATUS_INVALID_PARAMETER;
4289 goto fail;
4292 path2 = talloc_strdup(frame, path);
4293 if (!path2) {
4294 status = NT_STATUS_NO_MEMORY;
4295 goto fail;
4297 trim_char(path2,'\0','\\');
4298 if (!*path2) {
4299 path2 = talloc_strdup(frame, "\\");
4300 if (!path2) {
4301 status = NT_STATUS_NO_MEMORY;
4302 goto fail;
4306 ev = samba_tevent_context_init(frame);
4307 if (ev == NULL) {
4308 status = NT_STATUS_NO_MEMORY;
4309 goto fail;
4312 req = cli_chkpath_send(frame, ev, cli, path2);
4313 if (req == NULL) {
4314 status = NT_STATUS_NO_MEMORY;
4315 goto fail;
4318 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4319 goto fail;
4322 status = cli_chkpath_recv(req);
4324 fail:
4325 TALLOC_FREE(frame);
4326 return status;
4329 /****************************************************************************
4330 Query disk space.
4331 ****************************************************************************/
4333 static void cli_dskattr_done(struct tevent_req *subreq);
4335 struct cli_dskattr_state {
4336 int bsize;
4337 int total;
4338 int avail;
4341 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
4342 struct tevent_context *ev,
4343 struct cli_state *cli)
4345 struct tevent_req *req = NULL, *subreq = NULL;
4346 struct cli_dskattr_state *state = NULL;
4347 uint8_t additional_flags = 0;
4349 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
4350 if (req == NULL) {
4351 return NULL;
4354 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
4355 0, NULL, 0, NULL);
4356 if (tevent_req_nomem(subreq, req)) {
4357 return tevent_req_post(req, ev);
4359 tevent_req_set_callback(subreq, cli_dskattr_done, req);
4360 return req;
4363 static void cli_dskattr_done(struct tevent_req *subreq)
4365 struct tevent_req *req = tevent_req_callback_data(
4366 subreq, struct tevent_req);
4367 struct cli_dskattr_state *state = tevent_req_data(
4368 req, struct cli_dskattr_state);
4369 uint8_t wct;
4370 uint16_t *vwv = NULL;
4371 NTSTATUS status;
4373 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4374 NULL);
4375 TALLOC_FREE(subreq);
4376 if (tevent_req_nterror(req, status)) {
4377 return;
4379 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
4380 state->total = SVAL(vwv+0, 0);
4381 state->avail = SVAL(vwv+3, 0);
4382 tevent_req_done(req);
4385 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
4387 struct cli_dskattr_state *state = tevent_req_data(
4388 req, struct cli_dskattr_state);
4389 NTSTATUS status;
4391 if (tevent_req_is_nterror(req, &status)) {
4392 return status;
4394 *bsize = state->bsize;
4395 *total = state->total;
4396 *avail = state->avail;
4397 return NT_STATUS_OK;
4400 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
4402 TALLOC_CTX *frame = NULL;
4403 struct tevent_context *ev = NULL;
4404 struct tevent_req *req = NULL;
4405 NTSTATUS status = NT_STATUS_OK;
4407 frame = talloc_stackframe();
4409 if (smbXcli_conn_has_async_calls(cli->conn)) {
4411 * Can't use sync call while an async call is in flight
4413 status = NT_STATUS_INVALID_PARAMETER;
4414 goto fail;
4417 ev = samba_tevent_context_init(frame);
4418 if (ev == NULL) {
4419 status = NT_STATUS_NO_MEMORY;
4420 goto fail;
4423 req = cli_dskattr_send(frame, ev, cli);
4424 if (req == NULL) {
4425 status = NT_STATUS_NO_MEMORY;
4426 goto fail;
4429 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4430 goto fail;
4433 status = cli_dskattr_recv(req, bsize, total, avail);
4435 fail:
4436 TALLOC_FREE(frame);
4437 return status;
4440 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
4441 uint64_t *total, uint64_t *avail)
4443 uint64_t sectors_per_block;
4444 uint64_t bytes_per_sector;
4445 int old_bsize, old_total, old_avail;
4446 NTSTATUS status;
4448 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4449 return cli_smb2_dskattr(cli, path, bsize, total, avail);
4453 * Try the trans2 disk full size info call first.
4454 * We already use this in SMBC_fstatvfs_ctx().
4455 * Ignore 'actual_available_units' as we only
4456 * care about the quota for the caller.
4459 status = cli_get_fs_full_size_info(cli,
4460 total,
4461 avail,
4462 NULL,
4463 &sectors_per_block,
4464 &bytes_per_sector);
4466 /* Try and cope will all varients of "we don't do this call"
4467 and fall back to cli_dskattr. */
4469 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
4470 NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
4471 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
4472 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
4473 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
4474 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
4475 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
4476 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
4477 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
4478 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
4479 goto try_dskattr;
4482 if (!NT_STATUS_IS_OK(status)) {
4483 return status;
4486 if (bsize) {
4487 *bsize = sectors_per_block *
4488 bytes_per_sector;
4491 return NT_STATUS_OK;
4493 try_dskattr:
4495 /* Old SMB1 core protocol fallback. */
4496 status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
4497 if (!NT_STATUS_IS_OK(status)) {
4498 return status;
4500 if (bsize) {
4501 *bsize = (uint64_t)old_bsize;
4503 if (total) {
4504 *total = (uint64_t)old_total;
4506 if (avail) {
4507 *avail = (uint64_t)old_avail;
4509 return NT_STATUS_OK;
4512 /****************************************************************************
4513 Create and open a temporary file.
4514 ****************************************************************************/
4516 static void cli_ctemp_done(struct tevent_req *subreq);
4518 struct ctemp_state {
4519 uint16_t vwv[3];
4520 char *ret_path;
4521 uint16_t fnum;
4524 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4525 struct tevent_context *ev,
4526 struct cli_state *cli,
4527 const char *path)
4529 struct tevent_req *req = NULL, *subreq = NULL;
4530 struct ctemp_state *state = NULL;
4531 uint8_t additional_flags = 0;
4532 uint16_t additional_flags2 = 0;
4533 uint8_t *bytes = NULL;
4535 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4536 if (req == NULL) {
4537 return NULL;
4540 SSVAL(state->vwv,0,0);
4541 SIVALS(state->vwv+1,0,-1);
4543 bytes = talloc_array(state, uint8_t, 1);
4544 if (tevent_req_nomem(bytes, req)) {
4545 return tevent_req_post(req, ev);
4547 bytes[0] = 4;
4548 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
4549 strlen(path)+1, NULL);
4550 if (tevent_req_nomem(bytes, req)) {
4551 return tevent_req_post(req, ev);
4554 if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
4555 additional_flags2 = FLAGS2_REPARSE_PATH;
4558 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4559 additional_flags2,
4560 3, state->vwv, talloc_get_size(bytes), bytes);
4561 if (tevent_req_nomem(subreq, req)) {
4562 return tevent_req_post(req, ev);
4564 tevent_req_set_callback(subreq, cli_ctemp_done, req);
4565 return req;
4568 static void cli_ctemp_done(struct tevent_req *subreq)
4570 struct tevent_req *req = tevent_req_callback_data(
4571 subreq, struct tevent_req);
4572 struct ctemp_state *state = tevent_req_data(
4573 req, struct ctemp_state);
4574 NTSTATUS status;
4575 uint8_t wcnt;
4576 uint16_t *vwv;
4577 uint32_t num_bytes = 0;
4578 uint8_t *bytes = NULL;
4580 status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
4581 &num_bytes, &bytes);
4582 TALLOC_FREE(subreq);
4583 if (tevent_req_nterror(req, status)) {
4584 return;
4587 state->fnum = SVAL(vwv+0, 0);
4589 /* From W2K3, the result is just the ASCII name */
4590 if (num_bytes < 2) {
4591 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
4592 return;
4595 if (pull_string_talloc(state,
4596 NULL,
4598 &state->ret_path,
4599 bytes,
4600 num_bytes,
4601 STR_ASCII) == 0) {
4602 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4603 return;
4605 tevent_req_done(req);
4608 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
4609 TALLOC_CTX *ctx,
4610 uint16_t *pfnum,
4611 char **outfile)
4613 struct ctemp_state *state = tevent_req_data(req,
4614 struct ctemp_state);
4615 NTSTATUS status;
4617 if (tevent_req_is_nterror(req, &status)) {
4618 return status;
4620 *pfnum = state->fnum;
4621 *outfile = talloc_strdup(ctx, state->ret_path);
4622 if (!*outfile) {
4623 return NT_STATUS_NO_MEMORY;
4625 return NT_STATUS_OK;
4628 NTSTATUS cli_ctemp(struct cli_state *cli,
4629 TALLOC_CTX *ctx,
4630 const char *path,
4631 uint16_t *pfnum,
4632 char **out_path)
4634 TALLOC_CTX *frame = talloc_stackframe();
4635 struct tevent_context *ev;
4636 struct tevent_req *req;
4637 NTSTATUS status = NT_STATUS_OK;
4639 if (smbXcli_conn_has_async_calls(cli->conn)) {
4641 * Can't use sync call while an async call is in flight
4643 status = NT_STATUS_INVALID_PARAMETER;
4644 goto fail;
4647 ev = samba_tevent_context_init(frame);
4648 if (ev == NULL) {
4649 status = NT_STATUS_NO_MEMORY;
4650 goto fail;
4653 req = cli_ctemp_send(frame, ev, cli, path);
4654 if (req == NULL) {
4655 status = NT_STATUS_NO_MEMORY;
4656 goto fail;
4659 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4660 goto fail;
4663 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4665 fail:
4666 TALLOC_FREE(frame);
4667 return status;
4671 send a raw ioctl - used by the torture code
4673 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4675 uint16_t vwv[3];
4676 NTSTATUS status;
4678 SSVAL(vwv+0, 0, fnum);
4679 SSVAL(vwv+1, 0, code>>16);
4680 SSVAL(vwv+2, 0, (code&0xFFFF));
4682 status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4683 NULL, 0, NULL, NULL, NULL, NULL);
4684 if (!NT_STATUS_IS_OK(status)) {
4685 return status;
4687 *blob = data_blob_null;
4688 return NT_STATUS_OK;
4691 /*********************************************************
4692 Set an extended attribute utility fn.
4693 *********************************************************/
4695 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
4696 uint8_t *param, unsigned int param_len,
4697 const char *ea_name,
4698 const char *ea_val, size_t ea_len)
4700 uint16_t setup[1];
4701 unsigned int data_len = 0;
4702 uint8_t *data = NULL;
4703 char *p;
4704 size_t ea_namelen = strlen(ea_name);
4705 NTSTATUS status;
4707 SSVAL(setup, 0, setup_val);
4709 if (ea_namelen == 0 && ea_len == 0) {
4710 data_len = 4;
4711 data = talloc_array(talloc_tos(),
4712 uint8_t,
4713 data_len);
4714 if (!data) {
4715 return NT_STATUS_NO_MEMORY;
4717 p = (char *)data;
4718 SIVAL(p,0,data_len);
4719 } else {
4720 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4721 data = talloc_array(talloc_tos(),
4722 uint8_t,
4723 data_len);
4724 if (!data) {
4725 return NT_STATUS_NO_MEMORY;
4727 p = (char *)data;
4728 SIVAL(p,0,data_len);
4729 p += 4;
4730 SCVAL(p, 0, 0); /* EA flags. */
4731 SCVAL(p, 1, ea_namelen);
4732 SSVAL(p, 2, ea_len);
4733 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4734 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4738 * FIXME - if we want to do previous version path
4739 * processing on an EA set call we need to turn this
4740 * into calls to cli_trans_send()/cli_trans_recv()
4741 * with a temporary event context, as cli_trans_send()
4742 * have access to the additional_flags2 needed to
4743 * send @GMT- paths. JRA.
4746 status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
4747 setup, 1, 0,
4748 param, param_len, 2,
4749 data, data_len, 0,
4750 NULL,
4751 NULL, 0, NULL, /* rsetup */
4752 NULL, 0, NULL, /* rparam */
4753 NULL, 0, NULL); /* rdata */
4754 talloc_free(data);
4755 return status;
4758 /*********************************************************
4759 Set an extended attribute on a pathname.
4760 *********************************************************/
4762 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
4763 const char *ea_name, const char *ea_val,
4764 size_t ea_len)
4766 unsigned int param_len = 0;
4767 uint8_t *param;
4768 NTSTATUS status;
4769 TALLOC_CTX *frame = NULL;
4771 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4772 return cli_smb2_set_ea_path(cli,
4773 path,
4774 ea_name,
4775 ea_val,
4776 ea_len);
4779 frame = talloc_stackframe();
4781 param = talloc_array(frame, uint8_t, 6);
4782 if (!param) {
4783 status = NT_STATUS_NO_MEMORY;
4784 goto fail;
4786 SSVAL(param,0,SMB_INFO_SET_EA);
4787 SSVAL(param,2,0);
4788 SSVAL(param,4,0);
4790 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
4791 path, strlen(path)+1,
4792 NULL);
4793 param_len = talloc_get_size(param);
4795 status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
4796 ea_name, ea_val, ea_len);
4798 fail:
4800 TALLOC_FREE(frame);
4801 return status;
4804 /*********************************************************
4805 Set an extended attribute on an fnum.
4806 *********************************************************/
4808 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
4809 const char *ea_name, const char *ea_val,
4810 size_t ea_len)
4812 uint8_t param[6];
4814 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4815 return cli_smb2_set_ea_fnum(cli,
4816 fnum,
4817 ea_name,
4818 ea_val,
4819 ea_len);
4822 memset(param, 0, 6);
4823 SSVAL(param,0,fnum);
4824 SSVAL(param,2,SMB_INFO_SET_EA);
4826 return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
4827 ea_name, ea_val, ea_len);
4830 /*********************************************************
4831 Get an extended attribute list utility fn.
4832 *********************************************************/
4834 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4835 size_t rdata_len,
4836 size_t *pnum_eas, struct ea_struct **pea_list)
4838 struct ea_struct *ea_list = NULL;
4839 size_t num_eas;
4840 size_t ea_size;
4841 const uint8_t *p;
4843 if (rdata_len < 4) {
4844 return false;
4847 ea_size = (size_t)IVAL(rdata,0);
4848 if (ea_size > rdata_len) {
4849 return false;
4852 if (ea_size == 0) {
4853 /* No EA's present. */
4854 *pnum_eas = 0;
4855 *pea_list = NULL;
4856 return true;
4859 p = rdata + 4;
4860 ea_size -= 4;
4862 /* Validate the EA list and count it. */
4863 for (num_eas = 0; ea_size >= 4; num_eas++) {
4864 unsigned int ea_namelen = CVAL(p,1);
4865 unsigned int ea_valuelen = SVAL(p,2);
4866 if (ea_namelen == 0) {
4867 return false;
4869 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4870 return false;
4872 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4873 p += 4 + ea_namelen + 1 + ea_valuelen;
4876 if (num_eas == 0) {
4877 *pnum_eas = 0;
4878 *pea_list = NULL;
4879 return true;
4882 *pnum_eas = num_eas;
4883 if (!pea_list) {
4884 /* Caller only wants number of EA's. */
4885 return true;
4888 ea_list = talloc_array(ctx, struct ea_struct, num_eas);
4889 if (!ea_list) {
4890 return false;
4893 ea_size = (size_t)IVAL(rdata,0);
4894 p = rdata + 4;
4896 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4897 struct ea_struct *ea = &ea_list[num_eas];
4898 fstring unix_ea_name;
4899 unsigned int ea_namelen = CVAL(p,1);
4900 unsigned int ea_valuelen = SVAL(p,2);
4902 ea->flags = CVAL(p,0);
4903 unix_ea_name[0] = '\0';
4904 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
4905 ea->name = talloc_strdup(ea_list, unix_ea_name);
4906 if (!ea->name) {
4907 goto fail;
4909 /* Ensure the value is null terminated (in case it's a string). */
4910 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4911 if (!ea->value.data) {
4912 goto fail;
4914 if (ea_valuelen) {
4915 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4917 ea->value.data[ea_valuelen] = 0;
4918 ea->value.length--;
4919 p += 4 + ea_namelen + 1 + ea_valuelen;
4922 *pea_list = ea_list;
4923 return true;
4925 fail:
4926 TALLOC_FREE(ea_list);
4927 return false;
4930 /*********************************************************
4931 Get an extended attribute list from a pathname.
4932 *********************************************************/
4934 struct cli_get_ea_list_path_state {
4935 uint32_t num_data;
4936 uint8_t *data;
4939 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4941 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4942 struct tevent_context *ev,
4943 struct cli_state *cli,
4944 const char *fname)
4946 struct tevent_req *req, *subreq;
4947 struct cli_get_ea_list_path_state *state;
4949 req = tevent_req_create(mem_ctx, &state,
4950 struct cli_get_ea_list_path_state);
4951 if (req == NULL) {
4952 return NULL;
4954 subreq = cli_qpathinfo_send(state, ev, cli, fname,
4955 SMB_INFO_QUERY_ALL_EAS, 4,
4956 CLI_BUFFER_SIZE);
4957 if (tevent_req_nomem(subreq, req)) {
4958 return tevent_req_post(req, ev);
4960 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4961 return req;
4964 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4966 struct tevent_req *req = tevent_req_callback_data(
4967 subreq, struct tevent_req);
4968 struct cli_get_ea_list_path_state *state = tevent_req_data(
4969 req, struct cli_get_ea_list_path_state);
4970 NTSTATUS status;
4972 status = cli_qpathinfo_recv(subreq, state, &state->data,
4973 &state->num_data);
4974 TALLOC_FREE(subreq);
4975 if (tevent_req_nterror(req, status)) {
4976 return;
4978 tevent_req_done(req);
4981 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4982 size_t *pnum_eas, struct ea_struct **peas)
4984 struct cli_get_ea_list_path_state *state = tevent_req_data(
4985 req, struct cli_get_ea_list_path_state);
4986 NTSTATUS status;
4988 if (tevent_req_is_nterror(req, &status)) {
4989 return status;
4991 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4992 pnum_eas, peas)) {
4993 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4995 return NT_STATUS_OK;
4998 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
4999 TALLOC_CTX *ctx,
5000 size_t *pnum_eas,
5001 struct ea_struct **pea_list)
5003 TALLOC_CTX *frame = NULL;
5004 struct tevent_context *ev = NULL;
5005 struct tevent_req *req = NULL;
5006 NTSTATUS status = NT_STATUS_NO_MEMORY;
5008 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5009 return cli_smb2_get_ea_list_path(cli,
5010 path,
5011 ctx,
5012 pnum_eas,
5013 pea_list);
5016 frame = talloc_stackframe();
5018 if (smbXcli_conn_has_async_calls(cli->conn)) {
5020 * Can't use sync call while an async call is in flight
5022 status = NT_STATUS_INVALID_PARAMETER;
5023 goto fail;
5025 ev = samba_tevent_context_init(frame);
5026 if (ev == NULL) {
5027 goto fail;
5029 req = cli_get_ea_list_path_send(frame, ev, cli, path);
5030 if (req == NULL) {
5031 goto fail;
5033 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5034 goto fail;
5036 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
5037 fail:
5038 TALLOC_FREE(frame);
5039 return status;
5042 /****************************************************************************
5043 Convert open "flags" arg to uint32_t on wire.
5044 ****************************************************************************/
5046 static uint32_t open_flags_to_wire(int flags)
5048 int open_mode = flags & O_ACCMODE;
5049 uint32_t ret = 0;
5051 switch (open_mode) {
5052 case O_WRONLY:
5053 ret |= SMB_O_WRONLY;
5054 break;
5055 case O_RDWR:
5056 ret |= SMB_O_RDWR;
5057 break;
5058 default:
5059 case O_RDONLY:
5060 ret |= SMB_O_RDONLY;
5061 break;
5064 if (flags & O_CREAT) {
5065 ret |= SMB_O_CREAT;
5067 if (flags & O_EXCL) {
5068 ret |= SMB_O_EXCL;
5070 if (flags & O_TRUNC) {
5071 ret |= SMB_O_TRUNC;
5073 #if defined(O_SYNC)
5074 if (flags & O_SYNC) {
5075 ret |= SMB_O_SYNC;
5077 #endif /* O_SYNC */
5078 if (flags & O_APPEND) {
5079 ret |= SMB_O_APPEND;
5081 #if defined(O_DIRECT)
5082 if (flags & O_DIRECT) {
5083 ret |= SMB_O_DIRECT;
5085 #endif
5086 #if defined(O_DIRECTORY)
5087 if (flags & O_DIRECTORY) {
5088 ret |= SMB_O_DIRECTORY;
5090 #endif
5091 return ret;
5094 /****************************************************************************
5095 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
5096 ****************************************************************************/
5098 struct posix_open_state {
5099 uint16_t setup;
5100 uint8_t *param;
5101 uint8_t data[18];
5102 uint16_t fnum; /* Out */
5105 static void cli_posix_open_internal_done(struct tevent_req *subreq)
5107 struct tevent_req *req = tevent_req_callback_data(
5108 subreq, struct tevent_req);
5109 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
5110 NTSTATUS status;
5111 uint8_t *data;
5112 uint32_t num_data;
5114 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5115 NULL, 0, NULL, &data, 12, &num_data);
5116 TALLOC_FREE(subreq);
5117 if (tevent_req_nterror(req, status)) {
5118 return;
5120 state->fnum = SVAL(data,2);
5121 tevent_req_done(req);
5124 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
5125 struct tevent_context *ev,
5126 struct cli_state *cli,
5127 const char *fname,
5128 int flags,
5129 mode_t mode,
5130 bool is_dir)
5132 struct tevent_req *req = NULL, *subreq = NULL;
5133 struct posix_open_state *state = NULL;
5134 uint32_t wire_flags = open_flags_to_wire(flags);
5136 req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
5137 if (req == NULL) {
5138 return NULL;
5141 /* Setup setup word. */
5142 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
5144 /* Setup param array. */
5145 state->param = talloc_array(state, uint8_t, 6);
5146 if (tevent_req_nomem(state->param, req)) {
5147 return tevent_req_post(req, ev);
5149 memset(state->param, '\0', 6);
5150 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
5152 state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn), fname,
5153 strlen(fname)+1, NULL);
5155 if (tevent_req_nomem(state->param, req)) {
5156 return tevent_req_post(req, ev);
5159 /* Setup data words. */
5160 if (is_dir) {
5161 wire_flags |= SMB_O_DIRECTORY;
5164 SIVAL(state->data,0,0); /* No oplock. */
5165 SIVAL(state->data,4,wire_flags);
5166 SIVAL(state->data,8,unix_perms_to_wire(mode));
5167 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
5168 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
5170 subreq = cli_trans_send(state, /* mem ctx. */
5171 ev, /* event ctx. */
5172 cli, /* cli_state. */
5173 0, /* additional_flags2 */
5174 SMBtrans2, /* cmd. */
5175 NULL, /* pipe name. */
5176 -1, /* fid. */
5177 0, /* function. */
5178 0, /* flags. */
5179 &state->setup, /* setup. */
5180 1, /* num setup uint16_t words. */
5181 0, /* max returned setup. */
5182 state->param, /* param. */
5183 talloc_get_size(state->param),/* num param. */
5184 2, /* max returned param. */
5185 state->data, /* data. */
5186 18, /* num data. */
5187 12); /* max returned data. */
5189 if (tevent_req_nomem(subreq, req)) {
5190 return tevent_req_post(req, ev);
5192 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
5193 return req;
5196 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
5197 struct tevent_context *ev,
5198 struct cli_state *cli,
5199 const char *fname,
5200 int flags,
5201 mode_t mode)
5203 return cli_posix_open_internal_send(mem_ctx, ev,
5204 cli, fname, flags, mode, false);
5207 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
5209 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
5210 NTSTATUS status;
5212 if (tevent_req_is_nterror(req, &status)) {
5213 return status;
5215 *pfnum = state->fnum;
5216 return NT_STATUS_OK;
5219 /****************************************************************************
5220 Open - POSIX semantics. Doesn't request oplock.
5221 ****************************************************************************/
5223 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
5224 int flags, mode_t mode, uint16_t *pfnum)
5227 TALLOC_CTX *frame = talloc_stackframe();
5228 struct tevent_context *ev = NULL;
5229 struct tevent_req *req = NULL;
5230 NTSTATUS status = NT_STATUS_OK;
5232 if (smbXcli_conn_has_async_calls(cli->conn)) {
5234 * Can't use sync call while an async call is in flight
5236 status = NT_STATUS_INVALID_PARAMETER;
5237 goto fail;
5240 ev = samba_tevent_context_init(frame);
5241 if (ev == NULL) {
5242 status = NT_STATUS_NO_MEMORY;
5243 goto fail;
5246 req = cli_posix_open_send(frame,
5248 cli,
5249 fname,
5250 flags,
5251 mode);
5252 if (req == NULL) {
5253 status = NT_STATUS_NO_MEMORY;
5254 goto fail;
5257 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5258 goto fail;
5261 status = cli_posix_open_recv(req, pfnum);
5263 fail:
5264 TALLOC_FREE(frame);
5265 return status;
5268 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
5269 struct tevent_context *ev,
5270 struct cli_state *cli,
5271 const char *fname,
5272 mode_t mode)
5274 return cli_posix_open_internal_send(mem_ctx, ev,
5275 cli, fname, O_CREAT, mode, true);
5278 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
5280 return tevent_req_simple_recv_ntstatus(req);
5283 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
5285 TALLOC_CTX *frame = talloc_stackframe();
5286 struct tevent_context *ev = NULL;
5287 struct tevent_req *req = NULL;
5288 NTSTATUS status = NT_STATUS_OK;
5290 if (smbXcli_conn_has_async_calls(cli->conn)) {
5292 * Can't use sync call while an async call is in flight
5294 status = NT_STATUS_INVALID_PARAMETER;
5295 goto fail;
5298 ev = samba_tevent_context_init(frame);
5299 if (ev == NULL) {
5300 status = NT_STATUS_NO_MEMORY;
5301 goto fail;
5304 req = cli_posix_mkdir_send(frame,
5306 cli,
5307 fname,
5308 mode);
5309 if (req == NULL) {
5310 status = NT_STATUS_NO_MEMORY;
5311 goto fail;
5314 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5315 goto fail;
5318 status = cli_posix_mkdir_recv(req);
5320 fail:
5321 TALLOC_FREE(frame);
5322 return status;
5325 /****************************************************************************
5326 unlink or rmdir - POSIX semantics.
5327 ****************************************************************************/
5329 struct cli_posix_unlink_internal_state {
5330 uint8_t data[2];
5333 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
5335 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
5336 struct tevent_context *ev,
5337 struct cli_state *cli,
5338 const char *fname,
5339 uint16_t level)
5341 struct tevent_req *req = NULL, *subreq = NULL;
5342 struct cli_posix_unlink_internal_state *state = NULL;
5344 req = tevent_req_create(mem_ctx, &state,
5345 struct cli_posix_unlink_internal_state);
5346 if (req == NULL) {
5347 return NULL;
5350 /* Setup data word. */
5351 SSVAL(state->data, 0, level);
5353 subreq = cli_setpathinfo_send(state, ev, cli,
5354 SMB_POSIX_PATH_UNLINK,
5355 fname,
5356 state->data, sizeof(state->data));
5357 if (tevent_req_nomem(subreq, req)) {
5358 return tevent_req_post(req, ev);
5360 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
5361 return req;
5364 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
5366 NTSTATUS status = cli_setpathinfo_recv(subreq);
5367 tevent_req_simple_finish_ntstatus(subreq, status);
5370 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
5371 struct tevent_context *ev,
5372 struct cli_state *cli,
5373 const char *fname)
5375 return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
5376 SMB_POSIX_UNLINK_FILE_TARGET);
5379 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
5381 return tevent_req_simple_recv_ntstatus(req);
5384 /****************************************************************************
5385 unlink - POSIX semantics.
5386 ****************************************************************************/
5388 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
5390 TALLOC_CTX *frame = talloc_stackframe();
5391 struct tevent_context *ev = NULL;
5392 struct tevent_req *req = NULL;
5393 NTSTATUS status = NT_STATUS_OK;
5395 if (smbXcli_conn_has_async_calls(cli->conn)) {
5397 * Can't use sync call while an async call is in flight
5399 status = NT_STATUS_INVALID_PARAMETER;
5400 goto fail;
5403 ev = samba_tevent_context_init(frame);
5404 if (ev == NULL) {
5405 status = NT_STATUS_NO_MEMORY;
5406 goto fail;
5409 req = cli_posix_unlink_send(frame,
5411 cli,
5412 fname);
5413 if (req == NULL) {
5414 status = NT_STATUS_NO_MEMORY;
5415 goto fail;
5418 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5419 goto fail;
5422 status = cli_posix_unlink_recv(req);
5424 fail:
5425 TALLOC_FREE(frame);
5426 return status;
5429 /****************************************************************************
5430 rmdir - POSIX semantics.
5431 ****************************************************************************/
5433 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
5434 struct tevent_context *ev,
5435 struct cli_state *cli,
5436 const char *fname)
5438 return cli_posix_unlink_internal_send(
5439 mem_ctx, ev, cli, fname,
5440 SMB_POSIX_UNLINK_DIRECTORY_TARGET);
5443 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
5445 return tevent_req_simple_recv_ntstatus(req);
5448 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
5450 TALLOC_CTX *frame = talloc_stackframe();
5451 struct tevent_context *ev = NULL;
5452 struct tevent_req *req = NULL;
5453 NTSTATUS status = NT_STATUS_OK;
5455 if (smbXcli_conn_has_async_calls(cli->conn)) {
5457 * Can't use sync call while an async call is in flight
5459 status = NT_STATUS_INVALID_PARAMETER;
5460 goto fail;
5463 ev = samba_tevent_context_init(frame);
5464 if (ev == NULL) {
5465 status = NT_STATUS_NO_MEMORY;
5466 goto fail;
5469 req = cli_posix_rmdir_send(frame,
5471 cli,
5472 fname);
5473 if (req == NULL) {
5474 status = NT_STATUS_NO_MEMORY;
5475 goto fail;
5478 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5479 goto fail;
5482 status = cli_posix_rmdir_recv(req, frame);
5484 fail:
5485 TALLOC_FREE(frame);
5486 return status;
5489 /****************************************************************************
5490 filechangenotify
5491 ****************************************************************************/
5493 struct cli_notify_state {
5494 uint8_t setup[8];
5495 uint32_t num_changes;
5496 struct notify_change *changes;
5499 static void cli_notify_done(struct tevent_req *subreq);
5501 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
5502 struct tevent_context *ev,
5503 struct cli_state *cli, uint16_t fnum,
5504 uint32_t buffer_size,
5505 uint32_t completion_filter, bool recursive)
5507 struct tevent_req *req, *subreq;
5508 struct cli_notify_state *state;
5509 unsigned old_timeout;
5511 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
5512 if (req == NULL) {
5513 return NULL;
5516 SIVAL(state->setup, 0, completion_filter);
5517 SSVAL(state->setup, 4, fnum);
5518 SSVAL(state->setup, 6, recursive);
5521 * Notifies should not time out
5523 old_timeout = cli_set_timeout(cli, 0);
5525 subreq = cli_trans_send(
5526 state, /* mem ctx. */
5527 ev, /* event ctx. */
5528 cli, /* cli_state. */
5529 0, /* additional_flags2 */
5530 SMBnttrans, /* cmd. */
5531 NULL, /* pipe name. */
5532 -1, /* fid. */
5533 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
5534 0, /* flags. */
5535 (uint16_t *)state->setup, /* setup. */
5536 4, /* num setup uint16_t words. */
5537 0, /* max returned setup. */
5538 NULL, /* param. */
5539 0, /* num param. */
5540 buffer_size, /* max returned param. */
5541 NULL, /* data. */
5542 0, /* num data. */
5543 0); /* max returned data. */
5545 cli_set_timeout(cli, old_timeout);
5547 if (tevent_req_nomem(subreq, req)) {
5548 return tevent_req_post(req, ev);
5550 tevent_req_set_callback(subreq, cli_notify_done, req);
5551 return req;
5554 static void cli_notify_done(struct tevent_req *subreq)
5556 struct tevent_req *req = tevent_req_callback_data(
5557 subreq, struct tevent_req);
5558 struct cli_notify_state *state = tevent_req_data(
5559 req, struct cli_notify_state);
5560 NTSTATUS status;
5561 uint8_t *params;
5562 uint32_t i, ofs, num_params;
5563 uint16_t flags2;
5565 status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
5566 &params, 0, &num_params, NULL, 0, NULL);
5567 TALLOC_FREE(subreq);
5568 if (tevent_req_nterror(req, status)) {
5569 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
5570 return;
5573 state->num_changes = 0;
5574 ofs = 0;
5576 while (num_params - ofs > 12) {
5577 uint32_t next = IVAL(params, ofs);
5578 state->num_changes += 1;
5580 if ((next == 0) || (ofs+next >= num_params)) {
5581 break;
5583 ofs += next;
5586 state->changes = talloc_array(state, struct notify_change,
5587 state->num_changes);
5588 if (tevent_req_nomem(state->changes, req)) {
5589 TALLOC_FREE(params);
5590 return;
5593 ofs = 0;
5595 for (i=0; i<state->num_changes; i++) {
5596 uint32_t next = IVAL(params, ofs);
5597 uint32_t len = IVAL(params, ofs+8);
5598 ssize_t ret;
5599 char *name;
5601 if (trans_oob(num_params, ofs + 12, len)) {
5602 TALLOC_FREE(params);
5603 tevent_req_nterror(
5604 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5605 return;
5608 state->changes[i].action = IVAL(params, ofs+4);
5609 ret = clistr_pull_talloc(state->changes, (char *)params, flags2,
5610 &name, params+ofs+12, len,
5611 STR_TERMINATE|STR_UNICODE);
5612 if (ret == -1) {
5613 TALLOC_FREE(params);
5614 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5615 return;
5617 state->changes[i].name = name;
5618 ofs += next;
5621 TALLOC_FREE(params);
5622 tevent_req_done(req);
5625 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5626 uint32_t *pnum_changes,
5627 struct notify_change **pchanges)
5629 struct cli_notify_state *state = tevent_req_data(
5630 req, struct cli_notify_state);
5631 NTSTATUS status;
5633 if (tevent_req_is_nterror(req, &status)) {
5634 return status;
5637 *pnum_changes = state->num_changes;
5638 *pchanges = talloc_move(mem_ctx, &state->changes);
5639 return NT_STATUS_OK;
5642 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
5643 uint32_t completion_filter, bool recursive,
5644 TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
5645 struct notify_change **pchanges)
5647 TALLOC_CTX *frame;
5648 struct tevent_context *ev;
5649 struct tevent_req *req;
5650 NTSTATUS status = NT_STATUS_NO_MEMORY;
5652 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5653 return cli_smb2_notify(cli, fnum, buffer_size,
5654 completion_filter, recursive,
5655 mem_ctx, pchanges, pnum_changes);
5658 frame = talloc_stackframe();
5660 if (smbXcli_conn_has_async_calls(cli->conn)) {
5662 * Can't use sync call while an async call is in flight
5664 status = NT_STATUS_INVALID_PARAMETER;
5665 goto fail;
5667 ev = samba_tevent_context_init(frame);
5668 if (ev == NULL) {
5669 goto fail;
5671 req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
5672 completion_filter, recursive);
5673 if (req == NULL) {
5674 goto fail;
5676 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5677 goto fail;
5679 status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
5680 fail:
5681 TALLOC_FREE(frame);
5682 return status;
5685 struct cli_qpathinfo_state {
5686 uint8_t *param;
5687 uint8_t *data;
5688 uint16_t setup[1];
5689 uint32_t min_rdata;
5690 uint8_t *rdata;
5691 uint32_t num_rdata;
5694 static void cli_qpathinfo_done(struct tevent_req *subreq);
5696 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
5697 struct tevent_context *ev,
5698 struct cli_state *cli, const char *fname,
5699 uint16_t level, uint32_t min_rdata,
5700 uint32_t max_rdata)
5702 struct tevent_req *req, *subreq;
5703 struct cli_qpathinfo_state *state;
5704 uint16_t additional_flags2 = 0;
5706 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
5707 if (req == NULL) {
5708 return NULL;
5710 state->min_rdata = min_rdata;
5711 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
5713 state->param = talloc_zero_array(state, uint8_t, 6);
5714 if (tevent_req_nomem(state->param, req)) {
5715 return tevent_req_post(req, ev);
5717 SSVAL(state->param, 0, level);
5718 state->param = trans2_bytes_push_str(
5719 state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
5720 if (tevent_req_nomem(state->param, req)) {
5721 return tevent_req_post(req, ev);
5724 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
5725 !INFO_LEVEL_IS_UNIX(level)) {
5726 additional_flags2 = FLAGS2_REPARSE_PATH;
5729 subreq = cli_trans_send(
5730 state, /* mem ctx. */
5731 ev, /* event ctx. */
5732 cli, /* cli_state. */
5733 additional_flags2, /* additional_flags2 */
5734 SMBtrans2, /* cmd. */
5735 NULL, /* pipe name. */
5736 -1, /* fid. */
5737 0, /* function. */
5738 0, /* flags. */
5739 state->setup, /* setup. */
5740 1, /* num setup uint16_t words. */
5741 0, /* max returned setup. */
5742 state->param, /* param. */
5743 talloc_get_size(state->param), /* num param. */
5744 2, /* max returned param. */
5745 NULL, /* data. */
5746 0, /* num data. */
5747 max_rdata); /* max returned data. */
5749 if (tevent_req_nomem(subreq, req)) {
5750 return tevent_req_post(req, ev);
5752 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5753 return req;
5756 static void cli_qpathinfo_done(struct tevent_req *subreq)
5758 struct tevent_req *req = tevent_req_callback_data(
5759 subreq, struct tevent_req);
5760 struct cli_qpathinfo_state *state = tevent_req_data(
5761 req, struct cli_qpathinfo_state);
5762 NTSTATUS status;
5764 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5765 NULL, 0, NULL,
5766 &state->rdata, state->min_rdata,
5767 &state->num_rdata);
5768 if (tevent_req_nterror(req, status)) {
5769 return;
5771 tevent_req_done(req);
5774 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5775 uint8_t **rdata, uint32_t *num_rdata)
5777 struct cli_qpathinfo_state *state = tevent_req_data(
5778 req, struct cli_qpathinfo_state);
5779 NTSTATUS status;
5781 if (tevent_req_is_nterror(req, &status)) {
5782 return status;
5784 if (rdata != NULL) {
5785 *rdata = talloc_move(mem_ctx, &state->rdata);
5786 } else {
5787 TALLOC_FREE(state->rdata);
5789 if (num_rdata != NULL) {
5790 *num_rdata = state->num_rdata;
5792 return NT_STATUS_OK;
5795 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5796 const char *fname, uint16_t level, uint32_t min_rdata,
5797 uint32_t max_rdata,
5798 uint8_t **rdata, uint32_t *num_rdata)
5800 TALLOC_CTX *frame = talloc_stackframe();
5801 struct tevent_context *ev;
5802 struct tevent_req *req;
5803 NTSTATUS status = NT_STATUS_NO_MEMORY;
5805 if (smbXcli_conn_has_async_calls(cli->conn)) {
5807 * Can't use sync call while an async call is in flight
5809 status = NT_STATUS_INVALID_PARAMETER;
5810 goto fail;
5812 ev = samba_tevent_context_init(frame);
5813 if (ev == NULL) {
5814 goto fail;
5816 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5817 max_rdata);
5818 if (req == NULL) {
5819 goto fail;
5821 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5822 goto fail;
5824 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5825 fail:
5826 TALLOC_FREE(frame);
5827 return status;
5830 struct cli_qfileinfo_state {
5831 uint16_t setup[1];
5832 uint8_t param[4];
5833 uint8_t *data;
5834 uint16_t recv_flags2;
5835 uint32_t min_rdata;
5836 uint8_t *rdata;
5837 uint32_t num_rdata;
5840 static void cli_qfileinfo_done(struct tevent_req *subreq);
5842 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
5843 struct tevent_context *ev,
5844 struct cli_state *cli, uint16_t fnum,
5845 uint16_t level, uint32_t min_rdata,
5846 uint32_t max_rdata)
5848 struct tevent_req *req, *subreq;
5849 struct cli_qfileinfo_state *state;
5851 req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
5852 if (req == NULL) {
5853 return NULL;
5855 state->min_rdata = min_rdata;
5856 SSVAL(state->param, 0, fnum);
5857 SSVAL(state->param, 2, level);
5858 SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
5860 subreq = cli_trans_send(
5861 state, /* mem ctx. */
5862 ev, /* event ctx. */
5863 cli, /* cli_state. */
5864 0, /* additional_flags2 */
5865 SMBtrans2, /* cmd. */
5866 NULL, /* pipe name. */
5867 -1, /* fid. */
5868 0, /* function. */
5869 0, /* flags. */
5870 state->setup, /* setup. */
5871 1, /* num setup uint16_t words. */
5872 0, /* max returned setup. */
5873 state->param, /* param. */
5874 sizeof(state->param), /* num param. */
5875 2, /* max returned param. */
5876 NULL, /* data. */
5877 0, /* num data. */
5878 max_rdata); /* max returned data. */
5880 if (tevent_req_nomem(subreq, req)) {
5881 return tevent_req_post(req, ev);
5883 tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
5884 return req;
5887 static void cli_qfileinfo_done(struct tevent_req *subreq)
5889 struct tevent_req *req = tevent_req_callback_data(
5890 subreq, struct tevent_req);
5891 struct cli_qfileinfo_state *state = tevent_req_data(
5892 req, struct cli_qfileinfo_state);
5893 NTSTATUS status;
5895 status = cli_trans_recv(subreq, state,
5896 &state->recv_flags2,
5897 NULL, 0, NULL,
5898 NULL, 0, NULL,
5899 &state->rdata, state->min_rdata,
5900 &state->num_rdata);
5901 if (tevent_req_nterror(req, status)) {
5902 return;
5904 tevent_req_done(req);
5907 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5908 uint16_t *recv_flags2,
5909 uint8_t **rdata, uint32_t *num_rdata)
5911 struct cli_qfileinfo_state *state = tevent_req_data(
5912 req, struct cli_qfileinfo_state);
5913 NTSTATUS status;
5915 if (tevent_req_is_nterror(req, &status)) {
5916 return status;
5919 if (recv_flags2 != NULL) {
5920 *recv_flags2 = state->recv_flags2;
5922 if (rdata != NULL) {
5923 *rdata = talloc_move(mem_ctx, &state->rdata);
5924 } else {
5925 TALLOC_FREE(state->rdata);
5927 if (num_rdata != NULL) {
5928 *num_rdata = state->num_rdata;
5930 return NT_STATUS_OK;
5933 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5934 uint16_t fnum, uint16_t level, uint32_t min_rdata,
5935 uint32_t max_rdata, uint16_t *recv_flags2,
5936 uint8_t **rdata, uint32_t *num_rdata)
5938 TALLOC_CTX *frame = talloc_stackframe();
5939 struct tevent_context *ev;
5940 struct tevent_req *req;
5941 NTSTATUS status = NT_STATUS_NO_MEMORY;
5943 if (smbXcli_conn_has_async_calls(cli->conn)) {
5945 * Can't use sync call while an async call is in flight
5947 status = NT_STATUS_INVALID_PARAMETER;
5948 goto fail;
5950 ev = samba_tevent_context_init(frame);
5951 if (ev == NULL) {
5952 goto fail;
5954 req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
5955 max_rdata);
5956 if (req == NULL) {
5957 goto fail;
5959 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5960 goto fail;
5962 status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
5963 fail:
5964 TALLOC_FREE(frame);
5965 return status;
5968 struct cli_flush_state {
5969 uint16_t vwv[1];
5972 static void cli_flush_done(struct tevent_req *subreq);
5974 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
5975 struct tevent_context *ev,
5976 struct cli_state *cli,
5977 uint16_t fnum)
5979 struct tevent_req *req, *subreq;
5980 struct cli_flush_state *state;
5982 req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
5983 if (req == NULL) {
5984 return NULL;
5986 SSVAL(state->vwv + 0, 0, fnum);
5988 subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
5989 0, NULL);
5990 if (tevent_req_nomem(subreq, req)) {
5991 return tevent_req_post(req, ev);
5993 tevent_req_set_callback(subreq, cli_flush_done, req);
5994 return req;
5997 static void cli_flush_done(struct tevent_req *subreq)
5999 struct tevent_req *req = tevent_req_callback_data(
6000 subreq, struct tevent_req);
6001 NTSTATUS status;
6003 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
6004 TALLOC_FREE(subreq);
6005 if (tevent_req_nterror(req, status)) {
6006 return;
6008 tevent_req_done(req);
6011 NTSTATUS cli_flush_recv(struct tevent_req *req)
6013 return tevent_req_simple_recv_ntstatus(req);
6016 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
6018 TALLOC_CTX *frame = talloc_stackframe();
6019 struct tevent_context *ev;
6020 struct tevent_req *req;
6021 NTSTATUS status = NT_STATUS_NO_MEMORY;
6023 if (smbXcli_conn_has_async_calls(cli->conn)) {
6025 * Can't use sync call while an async call is in flight
6027 status = NT_STATUS_INVALID_PARAMETER;
6028 goto fail;
6030 ev = samba_tevent_context_init(frame);
6031 if (ev == NULL) {
6032 goto fail;
6034 req = cli_flush_send(frame, ev, cli, fnum);
6035 if (req == NULL) {
6036 goto fail;
6038 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6039 goto fail;
6041 status = cli_flush_recv(req);
6042 fail:
6043 TALLOC_FREE(frame);
6044 return status;
6047 struct cli_shadow_copy_data_state {
6048 uint16_t setup[4];
6049 uint8_t *data;
6050 uint32_t num_data;
6051 bool get_names;
6054 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
6056 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
6057 struct tevent_context *ev,
6058 struct cli_state *cli,
6059 uint16_t fnum,
6060 bool get_names)
6062 struct tevent_req *req, *subreq;
6063 struct cli_shadow_copy_data_state *state;
6064 uint32_t ret_size;
6066 req = tevent_req_create(mem_ctx, &state,
6067 struct cli_shadow_copy_data_state);
6068 if (req == NULL) {
6069 return NULL;
6071 state->get_names = get_names;
6072 ret_size = get_names ? CLI_BUFFER_SIZE : 16;
6074 SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
6075 SSVAL(state->setup + 2, 0, fnum);
6076 SCVAL(state->setup + 3, 0, 1); /* isFsctl */
6077 SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
6079 subreq = cli_trans_send(
6080 state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
6081 state->setup, ARRAY_SIZE(state->setup),
6082 ARRAY_SIZE(state->setup),
6083 NULL, 0, 0,
6084 NULL, 0, ret_size);
6085 if (tevent_req_nomem(subreq, req)) {
6086 return tevent_req_post(req, ev);
6088 tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
6089 return req;
6092 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
6094 struct tevent_req *req = tevent_req_callback_data(
6095 subreq, struct tevent_req);
6096 struct cli_shadow_copy_data_state *state = tevent_req_data(
6097 req, struct cli_shadow_copy_data_state);
6098 NTSTATUS status;
6100 status = cli_trans_recv(subreq, state, NULL,
6101 NULL, 0, NULL, /* setup */
6102 NULL, 0, NULL, /* param */
6103 &state->data, 12, &state->num_data);
6104 TALLOC_FREE(subreq);
6105 if (tevent_req_nterror(req, status)) {
6106 return;
6108 tevent_req_done(req);
6111 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6112 char ***pnames, int *pnum_names)
6114 struct cli_shadow_copy_data_state *state = tevent_req_data(
6115 req, struct cli_shadow_copy_data_state);
6116 char **names = NULL;
6117 uint32_t i, num_names;
6118 uint32_t dlength;
6119 uint8_t *endp = NULL;
6120 NTSTATUS status;
6122 if (tevent_req_is_nterror(req, &status)) {
6123 return status;
6126 if (state->num_data < 16) {
6127 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6130 num_names = IVAL(state->data, 4);
6131 dlength = IVAL(state->data, 8);
6133 if (num_names > 0x7FFFFFFF) {
6134 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6137 if (!state->get_names) {
6138 *pnum_names = (int)num_names;
6139 return NT_STATUS_OK;
6142 if (dlength + 12 < 12) {
6143 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6145 if (dlength + 12 > state->num_data) {
6146 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6148 if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
6149 state->num_data) {
6150 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6153 names = talloc_array(mem_ctx, char *, num_names);
6154 if (names == NULL) {
6155 return NT_STATUS_NO_MEMORY;
6158 endp = state->data + state->num_data;
6160 for (i=0; i<num_names; i++) {
6161 bool ret;
6162 uint8_t *src;
6163 size_t converted_size;
6165 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
6167 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
6168 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6171 ret = convert_string_talloc(
6172 names, CH_UTF16LE, CH_UNIX,
6173 src, 2 * sizeof(SHADOW_COPY_LABEL),
6174 &names[i], &converted_size);
6175 if (!ret) {
6176 TALLOC_FREE(names);
6177 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6180 *pnum_names = (int)num_names;
6181 *pnames = names;
6182 return NT_STATUS_OK;
6185 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6186 uint16_t fnum, bool get_names,
6187 char ***pnames, int *pnum_names)
6189 TALLOC_CTX *frame = NULL;
6190 struct tevent_context *ev;
6191 struct tevent_req *req;
6192 NTSTATUS status = NT_STATUS_NO_MEMORY;
6194 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6195 return cli_smb2_shadow_copy_data(mem_ctx,
6196 cli,
6197 fnum,
6198 get_names,
6199 pnames,
6200 pnum_names);
6203 frame = talloc_stackframe();
6205 if (smbXcli_conn_has_async_calls(cli->conn)) {
6207 * Can't use sync call while an async call is in flight
6209 status = NT_STATUS_INVALID_PARAMETER;
6210 goto fail;
6212 ev = samba_tevent_context_init(frame);
6213 if (ev == NULL) {
6214 goto fail;
6216 req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
6217 if (req == NULL) {
6218 goto fail;
6220 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6221 goto fail;
6223 status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
6224 fail:
6225 TALLOC_FREE(frame);
6226 return status;