ctdb-recoverd: Update the local node map before pushing out flags
[samba.git] / source3 / libsmb / clifile.c
blobc619b009ec4732f41072fb5a35cc237f24002428
1 /*
2 Unix SMB/CIFS implementation.
3 client file operations
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Jeremy Allison 2001-2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "libsmb/libsmb.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "async_smb.h"
26 #include "libsmb/clirap.h"
27 #include "trans2.h"
28 #include "ntioctl.h"
29 #include "libcli/security/security.h"
30 #include "../libcli/smb/smbXcli_base.h"
32 struct cli_setpathinfo_state {
33 uint16_t setup;
34 uint8_t *param;
37 static void cli_setpathinfo_done(struct tevent_req *subreq);
39 struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
40 struct tevent_context *ev,
41 struct cli_state *cli,
42 uint16_t level,
43 const char *path,
44 uint8_t *data,
45 size_t data_len)
47 struct tevent_req *req, *subreq;
48 struct cli_setpathinfo_state *state;
49 uint16_t additional_flags2 = 0;
51 req = tevent_req_create(mem_ctx, &state,
52 struct cli_setpathinfo_state);
53 if (req == NULL) {
54 return NULL;
57 /* Setup setup word. */
58 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
60 /* Setup param array. */
61 state->param = talloc_zero_array(state, uint8_t, 6);
62 if (tevent_req_nomem(state->param, req)) {
63 return tevent_req_post(req, ev);
65 SSVAL(state->param, 0, level);
67 state->param = trans2_bytes_push_str(
68 state->param, smbXcli_conn_use_unicode(cli->conn), path, strlen(path)+1, NULL);
69 if (tevent_req_nomem(state->param, req)) {
70 return tevent_req_post(req, ev);
73 if (clistr_is_previous_version_path(path, NULL, NULL, NULL) &&
74 !INFO_LEVEL_IS_UNIX(level)) {
75 additional_flags2 = FLAGS2_REPARSE_PATH;
78 subreq = cli_trans_send(
79 state, /* mem ctx. */
80 ev, /* event ctx. */
81 cli, /* cli_state. */
82 additional_flags2, /* additional_flags2 */
83 SMBtrans2, /* cmd. */
84 NULL, /* pipe name. */
85 -1, /* fid. */
86 0, /* function. */
87 0, /* flags. */
88 &state->setup, /* setup. */
89 1, /* num setup uint16_t words. */
90 0, /* max returned setup. */
91 state->param, /* param. */
92 talloc_get_size(state->param), /* num param. */
93 2, /* max returned param. */
94 data, /* data. */
95 data_len, /* num data. */
96 0); /* max returned data. */
98 if (tevent_req_nomem(subreq, req)) {
99 return tevent_req_post(req, ev);
101 tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
102 return req;
105 static void cli_setpathinfo_done(struct tevent_req *subreq)
107 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
108 NULL, 0, NULL, NULL, 0, NULL);
109 tevent_req_simple_finish_ntstatus(subreq, status);
112 NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
114 return tevent_req_simple_recv_ntstatus(req);
117 NTSTATUS cli_setpathinfo(struct cli_state *cli,
118 uint16_t level,
119 const char *path,
120 uint8_t *data,
121 size_t data_len)
123 TALLOC_CTX *frame = talloc_stackframe();
124 struct tevent_context *ev;
125 struct tevent_req *req;
126 NTSTATUS status = NT_STATUS_NO_MEMORY;
128 if (smbXcli_conn_has_async_calls(cli->conn)) {
130 * Can't use sync call while an async call is in flight
132 status = NT_STATUS_INVALID_PARAMETER;
133 goto fail;
135 ev = samba_tevent_context_init(frame);
136 if (ev == NULL) {
137 goto fail;
139 req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
140 if (req == NULL) {
141 goto fail;
143 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
144 goto fail;
146 status = cli_setpathinfo_recv(req);
147 fail:
148 TALLOC_FREE(frame);
149 return status;
152 struct cli_setfileinfo_state {
153 uint16_t setup;
154 uint8_t param[6];
157 static void cli_setfileinfo_done(struct tevent_req *subreq);
159 struct tevent_req *cli_setfileinfo_send(
160 TALLOC_CTX *mem_ctx,
161 struct tevent_context *ev,
162 struct cli_state *cli,
163 uint16_t fnum,
164 uint16_t level,
165 uint8_t *data,
166 size_t data_len)
168 struct tevent_req *req = NULL, *subreq = NULL;
169 struct cli_setfileinfo_state *state = NULL;
171 req = tevent_req_create(mem_ctx, &state, struct cli_setfileinfo_state);
172 if (req == NULL) {
173 return NULL;
175 PUSH_LE_U16(&state->setup, 0, TRANSACT2_SETFILEINFO);
177 PUSH_LE_U16(state->param, 0, fnum);
178 PUSH_LE_U16(state->param, 2, level);
180 subreq = cli_trans_send(state, /* mem ctx. */
181 ev, /* event ctx. */
182 cli, /* cli_state. */
183 0, /* additional_flags2 */
184 SMBtrans2, /* cmd. */
185 NULL, /* pipe name. */
186 -1, /* fid. */
187 0, /* function. */
188 0, /* flags. */
189 &state->setup, /* setup. */
190 1, /* num setup uint16_t words. */
191 0, /* max returned setup. */
192 state->param, /* param. */
193 6, /* num param. */
194 2, /* max returned param. */
195 data, /* data. */
196 data_len, /* num data. */
197 0); /* max returned data. */
199 if (tevent_req_nomem(subreq, req)) {
200 return tevent_req_post(req, ev);
202 tevent_req_set_callback(subreq, cli_setfileinfo_done, req);
203 return req;
206 static void cli_setfileinfo_done(struct tevent_req *subreq)
208 NTSTATUS status = cli_trans_recv(
209 subreq, /* req */
210 NULL, /* mem_ctx */
211 NULL, /* recv_flags2 */
212 NULL, /* setup */
213 0, /* min_setup */
214 NULL, /* num_setup */
215 NULL, /* param */
216 0, /* min_param */
217 NULL, /* num_param */
218 NULL, /* data */
219 0, /* min_data */
220 NULL); /* num_data */
221 tevent_req_simple_finish_ntstatus(subreq, status);
224 NTSTATUS cli_setfileinfo_recv(struct tevent_req *req)
226 return tevent_req_simple_recv_ntstatus(req);
229 /****************************************************************************
230 Hard/Symlink a file (UNIX extensions).
231 Creates new name (sym)linked to link_target.
232 ****************************************************************************/
234 struct cli_posix_link_internal_state {
235 uint8_t *data;
238 static void cli_posix_link_internal_done(struct tevent_req *subreq);
240 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
241 struct tevent_context *ev,
242 struct cli_state *cli,
243 uint16_t level,
244 const char *link_target,
245 const char *newname)
247 struct tevent_req *req = NULL, *subreq = NULL;
248 struct cli_posix_link_internal_state *state = NULL;
250 req = tevent_req_create(mem_ctx, &state,
251 struct cli_posix_link_internal_state);
252 if (req == NULL) {
253 return NULL;
256 /* Setup data array. */
257 state->data = talloc_array(state, uint8_t, 0);
258 if (tevent_req_nomem(state->data, req)) {
259 return tevent_req_post(req, ev);
261 state->data = trans2_bytes_push_str(
262 state->data, smbXcli_conn_use_unicode(cli->conn),
263 link_target, strlen(link_target)+1, NULL);
265 subreq = cli_setpathinfo_send(
266 state, ev, cli, level, newname,
267 state->data, talloc_get_size(state->data));
268 if (tevent_req_nomem(subreq, req)) {
269 return tevent_req_post(req, ev);
271 tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
272 return req;
275 static void cli_posix_link_internal_done(struct tevent_req *subreq)
277 NTSTATUS status = cli_setpathinfo_recv(subreq);
278 tevent_req_simple_finish_ntstatus(subreq, status);
281 static NTSTATUS cli_posix_link_internal_recv(struct tevent_req *req)
283 return tevent_req_simple_recv_ntstatus(req);
286 /****************************************************************************
287 Symlink a file (UNIX extensions).
288 ****************************************************************************/
290 struct cli_posix_symlink_state {
291 uint8_t dummy;
294 static void cli_posix_symlink_done(struct tevent_req *subreq);
296 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
297 struct tevent_context *ev,
298 struct cli_state *cli,
299 const char *link_target,
300 const char *newname)
302 struct tevent_req *req = NULL, *subreq = NULL;
303 struct cli_posix_symlink_state *state = NULL;
305 req = tevent_req_create(
306 mem_ctx, &state, struct cli_posix_symlink_state);
307 if (req == NULL) {
308 return NULL;
311 subreq = cli_posix_link_internal_send(
312 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, link_target, newname);
313 if (tevent_req_nomem(subreq, req)) {
314 return tevent_req_post(req, ev);
316 tevent_req_set_callback(subreq, cli_posix_symlink_done, req);
317 return req;
320 static void cli_posix_symlink_done(struct tevent_req *subreq)
322 NTSTATUS status = cli_posix_link_internal_recv(subreq);
323 tevent_req_simple_finish_ntstatus(subreq, status);
326 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
328 return tevent_req_simple_recv_ntstatus(req);
331 NTSTATUS cli_posix_symlink(struct cli_state *cli,
332 const char *link_target,
333 const char *newname)
335 TALLOC_CTX *frame = talloc_stackframe();
336 struct tevent_context *ev = NULL;
337 struct tevent_req *req = NULL;
338 NTSTATUS status = NT_STATUS_OK;
340 if (smbXcli_conn_has_async_calls(cli->conn)) {
342 * Can't use sync call while an async call is in flight
344 status = NT_STATUS_INVALID_PARAMETER;
345 goto fail;
348 ev = samba_tevent_context_init(frame);
349 if (ev == NULL) {
350 status = NT_STATUS_NO_MEMORY;
351 goto fail;
354 req = cli_posix_symlink_send(frame,
356 cli,
357 link_target,
358 newname);
359 if (req == NULL) {
360 status = NT_STATUS_NO_MEMORY;
361 goto fail;
364 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
365 goto fail;
368 status = cli_posix_symlink_recv(req);
370 fail:
371 TALLOC_FREE(frame);
372 return status;
375 /****************************************************************************
376 Read a POSIX symlink.
377 ****************************************************************************/
379 struct cli_posix_readlink_state {
380 struct cli_state *cli;
381 char *converted;
384 static void cli_posix_readlink_done(struct tevent_req *subreq);
386 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
387 struct tevent_context *ev,
388 struct cli_state *cli,
389 const char *fname)
391 struct tevent_req *req = NULL, *subreq = NULL;
392 struct cli_posix_readlink_state *state = NULL;
394 req = tevent_req_create(
395 mem_ctx, &state, struct cli_posix_readlink_state);
396 if (req == NULL) {
397 return NULL;
399 state->cli = cli;
401 subreq = cli_qpathinfo_send(
402 state,
404 cli,
405 fname,
406 SMB_QUERY_FILE_UNIX_LINK,
408 UINT16_MAX);
409 if (tevent_req_nomem(subreq, req)) {
410 return tevent_req_post(req, ev);
412 tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
413 return req;
416 static void cli_posix_readlink_done(struct tevent_req *subreq)
418 struct tevent_req *req = tevent_req_callback_data(
419 subreq, struct tevent_req);
420 struct cli_posix_readlink_state *state = tevent_req_data(
421 req, struct cli_posix_readlink_state);
422 NTSTATUS status;
423 uint8_t *data = NULL;
424 uint32_t num_data = 0;
425 charset_t charset;
426 size_t converted_size;
427 bool ok;
429 status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
430 TALLOC_FREE(subreq);
431 if (tevent_req_nterror(req, status)) {
432 return;
435 * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
437 if (data == NULL || data[num_data-1] != '\0') {
438 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
439 return;
442 charset = smbXcli_conn_use_unicode(state->cli->conn) ?
443 CH_UTF16LE : CH_DOS;
445 /* The returned data is a pushed string, not raw data. */
446 ok = convert_string_talloc(
447 state,
448 charset,
449 CH_UNIX,
450 data,
451 num_data,
452 &state->converted,
453 &converted_size);
454 if (!ok) {
455 tevent_req_oom(req);
456 return;
458 tevent_req_done(req);
461 NTSTATUS cli_posix_readlink_recv(
462 struct tevent_req *req, TALLOC_CTX *mem_ctx, char **target)
464 struct cli_posix_readlink_state *state = tevent_req_data(
465 req, struct cli_posix_readlink_state);
466 NTSTATUS status;
468 if (tevent_req_is_nterror(req, &status)) {
469 return status;
471 *target = talloc_move(mem_ctx, &state->converted);
472 return NT_STATUS_OK;
475 NTSTATUS cli_posix_readlink(
476 struct cli_state *cli,
477 const char *fname,
478 TALLOC_CTX *mem_ctx,
479 char **target)
481 TALLOC_CTX *frame = talloc_stackframe();
482 struct tevent_context *ev = NULL;
483 struct tevent_req *req = NULL;
484 NTSTATUS status = NT_STATUS_OK;
486 if (smbXcli_conn_has_async_calls(cli->conn)) {
488 * Can't use sync call while an async call is in flight
490 status = NT_STATUS_INVALID_PARAMETER;
491 goto fail;
494 ev = samba_tevent_context_init(frame);
495 if (ev == NULL) {
496 status = NT_STATUS_NO_MEMORY;
497 goto fail;
500 req = cli_posix_readlink_send(frame, ev, cli, fname);
501 if (req == NULL) {
502 status = NT_STATUS_NO_MEMORY;
503 goto fail;
506 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
507 goto fail;
510 status = cli_posix_readlink_recv(req, mem_ctx, target);
512 fail:
513 TALLOC_FREE(frame);
514 return status;
517 /****************************************************************************
518 Hard link a file (UNIX extensions).
519 ****************************************************************************/
521 struct cli_posix_hardlink_state {
522 uint8_t dummy;
525 static void cli_posix_hardlink_done(struct tevent_req *subreq);
527 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
528 struct tevent_context *ev,
529 struct cli_state *cli,
530 const char *oldname,
531 const char *newname)
533 struct tevent_req *req = NULL, *subreq = NULL;
534 struct cli_posix_hardlink_state *state = NULL;
536 req = tevent_req_create(
537 mem_ctx, &state, struct cli_posix_hardlink_state);
538 if (req == NULL) {
539 return NULL;
542 subreq = cli_posix_link_internal_send(
543 state, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
544 if (tevent_req_nomem(subreq, req)) {
545 return tevent_req_post(req, ev);
547 tevent_req_set_callback(subreq, cli_posix_hardlink_done, req);
548 return req;
551 static void cli_posix_hardlink_done(struct tevent_req *subreq)
553 NTSTATUS status = cli_posix_link_internal_recv(subreq);
554 tevent_req_simple_finish_ntstatus(subreq, status);
557 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
559 return tevent_req_simple_recv_ntstatus(req);
562 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
563 const char *oldname,
564 const char *newname)
566 TALLOC_CTX *frame = talloc_stackframe();
567 struct tevent_context *ev = NULL;
568 struct tevent_req *req = NULL;
569 NTSTATUS status = NT_STATUS_OK;
571 if (smbXcli_conn_has_async_calls(cli->conn)) {
573 * Can't use sync call while an async call is in flight
575 status = NT_STATUS_INVALID_PARAMETER;
576 goto fail;
579 ev = samba_tevent_context_init(frame);
580 if (ev == NULL) {
581 status = NT_STATUS_NO_MEMORY;
582 goto fail;
585 req = cli_posix_hardlink_send(frame,
587 cli,
588 oldname,
589 newname);
590 if (req == NULL) {
591 status = NT_STATUS_NO_MEMORY;
592 goto fail;
595 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
596 goto fail;
599 status = cli_posix_hardlink_recv(req);
601 fail:
602 TALLOC_FREE(frame);
603 return status;
606 /****************************************************************************
607 Do a POSIX getacl - pathname based ACL get (UNIX extensions).
608 ****************************************************************************/
610 struct getacl_state {
611 uint32_t num_data;
612 uint8_t *data;
615 static void cli_posix_getacl_done(struct tevent_req *subreq);
617 struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
618 struct tevent_context *ev,
619 struct cli_state *cli,
620 const char *fname)
622 struct tevent_req *req = NULL, *subreq = NULL;
623 struct getacl_state *state = NULL;
625 req = tevent_req_create(mem_ctx, &state, struct getacl_state);
626 if (req == NULL) {
627 return NULL;
629 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
630 0, CLI_BUFFER_SIZE);
631 if (tevent_req_nomem(subreq, req)) {
632 return tevent_req_post(req, ev);
634 tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
635 return req;
638 static void cli_posix_getacl_done(struct tevent_req *subreq)
640 struct tevent_req *req = tevent_req_callback_data(
641 subreq, struct tevent_req);
642 struct getacl_state *state = tevent_req_data(
643 req, struct getacl_state);
644 NTSTATUS status;
646 status = cli_qpathinfo_recv(subreq, state, &state->data,
647 &state->num_data);
648 TALLOC_FREE(subreq);
649 if (tevent_req_nterror(req, status)) {
650 return;
652 tevent_req_done(req);
655 NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
656 TALLOC_CTX *mem_ctx,
657 size_t *prb_size,
658 char **retbuf)
660 struct getacl_state *state = tevent_req_data(req, struct getacl_state);
661 NTSTATUS status;
663 if (tevent_req_is_nterror(req, &status)) {
664 return status;
666 *prb_size = (size_t)state->num_data;
667 *retbuf = (char *)talloc_move(mem_ctx, &state->data);
668 return NT_STATUS_OK;
671 NTSTATUS cli_posix_getacl(struct cli_state *cli,
672 const char *fname,
673 TALLOC_CTX *mem_ctx,
674 size_t *prb_size,
675 char **retbuf)
677 TALLOC_CTX *frame = talloc_stackframe();
678 struct tevent_context *ev = NULL;
679 struct tevent_req *req = NULL;
680 NTSTATUS status = NT_STATUS_OK;
682 if (smbXcli_conn_has_async_calls(cli->conn)) {
684 * Can't use sync call while an async call is in flight
686 status = NT_STATUS_INVALID_PARAMETER;
687 goto fail;
690 ev = samba_tevent_context_init(frame);
691 if (ev == NULL) {
692 status = NT_STATUS_NO_MEMORY;
693 goto fail;
696 req = cli_posix_getacl_send(frame,
698 cli,
699 fname);
700 if (req == NULL) {
701 status = NT_STATUS_NO_MEMORY;
702 goto fail;
705 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
706 goto fail;
709 status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
711 fail:
712 TALLOC_FREE(frame);
713 return status;
716 /****************************************************************************
717 Do a POSIX setacl - pathname based ACL set (UNIX extensions).
718 ****************************************************************************/
720 struct setacl_state {
721 uint8_t *data;
724 static void cli_posix_setacl_done(struct tevent_req *subreq);
726 struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
727 struct tevent_context *ev,
728 struct cli_state *cli,
729 const char *fname,
730 const void *data,
731 size_t num_data)
733 struct tevent_req *req = NULL, *subreq = NULL;
734 struct setacl_state *state = NULL;
736 req = tevent_req_create(mem_ctx, &state, struct setacl_state);
737 if (req == NULL) {
738 return NULL;
740 state->data = talloc_memdup(state, data, num_data);
741 if (tevent_req_nomem(state->data, req)) {
742 return tevent_req_post(req, ev);
745 subreq = cli_setpathinfo_send(state,
747 cli,
748 SMB_SET_POSIX_ACL,
749 fname,
750 state->data,
751 num_data);
752 if (tevent_req_nomem(subreq, req)) {
753 return tevent_req_post(req, ev);
755 tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
756 return req;
759 static void cli_posix_setacl_done(struct tevent_req *subreq)
761 NTSTATUS status = cli_setpathinfo_recv(subreq);
762 tevent_req_simple_finish_ntstatus(subreq, status);
765 NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
767 return tevent_req_simple_recv_ntstatus(req);
770 NTSTATUS cli_posix_setacl(struct cli_state *cli,
771 const char *fname,
772 const void *acl_buf,
773 size_t acl_buf_size)
775 TALLOC_CTX *frame = talloc_stackframe();
776 struct tevent_context *ev = NULL;
777 struct tevent_req *req = NULL;
778 NTSTATUS status = NT_STATUS_OK;
780 if (smbXcli_conn_has_async_calls(cli->conn)) {
782 * Can't use sync call while an async call is in flight
784 status = NT_STATUS_INVALID_PARAMETER;
785 goto fail;
788 ev = samba_tevent_context_init(frame);
789 if (ev == NULL) {
790 status = NT_STATUS_NO_MEMORY;
791 goto fail;
794 req = cli_posix_setacl_send(frame,
796 cli,
797 fname,
798 acl_buf,
799 acl_buf_size);
800 if (req == NULL) {
801 status = NT_STATUS_NO_MEMORY;
802 goto fail;
805 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
806 goto fail;
809 status = cli_posix_setacl_recv(req);
811 fail:
812 TALLOC_FREE(frame);
813 return status;
816 /****************************************************************************
817 Stat a file (UNIX extensions).
818 ****************************************************************************/
820 struct stat_state {
821 SMB_STRUCT_STAT *sbuf;
824 static void cli_posix_stat_done(struct tevent_req *subreq);
826 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
827 struct tevent_context *ev,
828 struct cli_state *cli,
829 const char *fname,
830 SMB_STRUCT_STAT *sbuf)
832 struct tevent_req *req = NULL, *subreq = NULL;
833 struct stat_state *state = NULL;
835 req = tevent_req_create(mem_ctx, &state, struct stat_state);
836 if (req == NULL) {
837 return NULL;
839 state->sbuf = sbuf;
841 subreq = cli_qpathinfo_send(state, ev, cli, fname,
842 SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
843 if (tevent_req_nomem(subreq, req)) {
844 return tevent_req_post(req, ev);
846 tevent_req_set_callback(subreq, cli_posix_stat_done, req);
847 return req;
850 static void cli_posix_stat_done(struct tevent_req *subreq)
852 struct tevent_req *req = tevent_req_callback_data(
853 subreq, struct tevent_req);
854 struct stat_state *state = tevent_req_data(req, struct stat_state);
855 SMB_STRUCT_STAT *sbuf = state->sbuf;
856 uint8_t *data;
857 uint32_t num_data = 0;
858 NTSTATUS status;
860 status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
861 TALLOC_FREE(subreq);
862 if (tevent_req_nterror(req, status)) {
863 return;
866 if (num_data != 100) {
868 * Paranoia, cli_qpathinfo should have guaranteed
869 * this, but you never know...
871 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
872 return;
875 *sbuf = (SMB_STRUCT_STAT) { 0 };
877 /* total size, in bytes */
878 sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(data, 0);
880 /* number of blocks allocated */
881 sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(data,8);
882 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
883 sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
884 #else
885 /* assume 512 byte blocks */
886 sbuf->st_ex_blocks /= 512;
887 #endif
888 /* time of last change */
889 sbuf->st_ex_ctime = interpret_long_date((char *)(data + 16));
891 /* time of last access */
892 sbuf->st_ex_atime = interpret_long_date((char *)(data + 24));
894 /* time of last modification */
895 sbuf->st_ex_mtime = interpret_long_date((char *)(data + 32));
897 sbuf->st_ex_uid = (uid_t) IVAL(data, 40); /* user ID of owner */
898 sbuf->st_ex_gid = (gid_t) IVAL(data, 48); /* group ID of owner */
899 sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(data, 56));
901 #if defined(HAVE_MAKEDEV)
903 uint32_t dev_major = IVAL(data,60);
904 uint32_t dev_minor = IVAL(data,68);
905 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
907 #endif
908 /* inode */
909 sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(data, 76);
911 /* protection */
912 sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(data, 84));
914 /* number of hard links */
915 sbuf->st_ex_nlink = BIG_UINT(data, 92);
917 tevent_req_done(req);
920 NTSTATUS cli_posix_stat_recv(struct tevent_req *req)
922 return tevent_req_simple_recv_ntstatus(req);
925 NTSTATUS cli_posix_stat(struct cli_state *cli,
926 const char *fname,
927 SMB_STRUCT_STAT *sbuf)
929 TALLOC_CTX *frame = talloc_stackframe();
930 struct tevent_context *ev = NULL;
931 struct tevent_req *req = NULL;
932 NTSTATUS status = NT_STATUS_OK;
934 if (smbXcli_conn_has_async_calls(cli->conn)) {
936 * Can't use sync call while an async call is in flight
938 status = NT_STATUS_INVALID_PARAMETER;
939 goto fail;
942 ev = samba_tevent_context_init(frame);
943 if (ev == NULL) {
944 status = NT_STATUS_NO_MEMORY;
945 goto fail;
948 req = cli_posix_stat_send(frame, ev, cli, fname, sbuf);
949 if (req == NULL) {
950 status = NT_STATUS_NO_MEMORY;
951 goto fail;
954 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
955 goto fail;
958 status = cli_posix_stat_recv(req);
960 fail:
961 TALLOC_FREE(frame);
962 return status;
965 /****************************************************************************
966 Chmod or chown a file internal (UNIX extensions).
967 ****************************************************************************/
969 struct cli_posix_chown_chmod_internal_state {
970 uint8_t data[100];
973 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
975 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
976 struct tevent_context *ev,
977 struct cli_state *cli,
978 const char *fname,
979 uint32_t mode,
980 uint32_t uid,
981 uint32_t gid)
983 struct tevent_req *req = NULL, *subreq = NULL;
984 struct cli_posix_chown_chmod_internal_state *state = NULL;
986 req = tevent_req_create(mem_ctx, &state,
987 struct cli_posix_chown_chmod_internal_state);
988 if (req == NULL) {
989 return NULL;
992 memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
993 memset(&state->data[40], '\0', 60);
994 SIVAL(state->data,40,uid);
995 SIVAL(state->data,48,gid);
996 SIVAL(state->data,84,mode);
998 subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
999 fname, state->data, sizeof(state->data));
1000 if (tevent_req_nomem(subreq, req)) {
1001 return tevent_req_post(req, ev);
1003 tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
1004 req);
1005 return req;
1008 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
1010 NTSTATUS status = cli_setpathinfo_recv(subreq);
1011 tevent_req_simple_finish_ntstatus(subreq, status);
1014 static NTSTATUS cli_posix_chown_chmod_internal_recv(struct tevent_req *req)
1016 return tevent_req_simple_recv_ntstatus(req);
1019 /****************************************************************************
1020 chmod a file (UNIX extensions).
1021 ****************************************************************************/
1023 struct cli_posix_chmod_state {
1024 uint8_t dummy;
1027 static void cli_posix_chmod_done(struct tevent_req *subreq);
1029 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
1030 struct tevent_context *ev,
1031 struct cli_state *cli,
1032 const char *fname,
1033 mode_t mode)
1035 struct tevent_req *req = NULL, *subreq = NULL;
1036 struct cli_posix_chmod_state *state = NULL;
1038 req = tevent_req_create(mem_ctx, &state, struct cli_posix_chmod_state);
1039 if (req == NULL) {
1040 return NULL;
1043 subreq = cli_posix_chown_chmod_internal_send(
1044 state,
1046 cli,
1047 fname,
1048 unix_perms_to_wire(mode),
1049 SMB_UID_NO_CHANGE,
1050 SMB_GID_NO_CHANGE);
1051 if (tevent_req_nomem(subreq, req)) {
1052 return tevent_req_post(req, ev);
1054 tevent_req_set_callback(subreq, cli_posix_chmod_done, req);
1055 return req;
1058 static void cli_posix_chmod_done(struct tevent_req *subreq)
1060 NTSTATUS status = cli_posix_chown_chmod_internal_recv(subreq);
1061 tevent_req_simple_finish_ntstatus(subreq, status);
1064 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
1066 return tevent_req_simple_recv_ntstatus(req);
1069 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
1071 TALLOC_CTX *frame = talloc_stackframe();
1072 struct tevent_context *ev = NULL;
1073 struct tevent_req *req = NULL;
1074 NTSTATUS status = NT_STATUS_OK;
1076 if (smbXcli_conn_has_async_calls(cli->conn)) {
1078 * Can't use sync call while an async call is in flight
1080 status = NT_STATUS_INVALID_PARAMETER;
1081 goto fail;
1084 ev = samba_tevent_context_init(frame);
1085 if (ev == NULL) {
1086 status = NT_STATUS_NO_MEMORY;
1087 goto fail;
1090 req = cli_posix_chmod_send(frame,
1092 cli,
1093 fname,
1094 mode);
1095 if (req == NULL) {
1096 status = NT_STATUS_NO_MEMORY;
1097 goto fail;
1100 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1101 goto fail;
1104 status = cli_posix_chmod_recv(req);
1106 fail:
1107 TALLOC_FREE(frame);
1108 return status;
1111 /****************************************************************************
1112 chown a file (UNIX extensions).
1113 ****************************************************************************/
1115 struct cli_posix_chown_state {
1116 uint8_t dummy;
1119 static void cli_posix_chown_done(struct tevent_req *subreq);
1121 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1122 struct tevent_context *ev,
1123 struct cli_state *cli,
1124 const char *fname,
1125 uid_t uid,
1126 gid_t gid)
1128 struct tevent_req *req = NULL, *subreq = NULL;
1129 struct cli_posix_chown_state *state = NULL;
1131 req = tevent_req_create(
1132 mem_ctx, &state, struct cli_posix_chown_state);
1133 if (req == NULL) {
1134 return NULL;
1137 subreq = cli_posix_chown_chmod_internal_send(
1138 state,
1140 cli,
1141 fname,
1142 SMB_MODE_NO_CHANGE,
1143 (uint32_t)uid,
1144 (uint32_t)gid);
1145 if (tevent_req_nomem(subreq, req)) {
1146 return tevent_req_post(req, ev);
1148 tevent_req_set_callback(subreq, cli_posix_chown_done, req);
1149 return req;
1152 static void cli_posix_chown_done(struct tevent_req *subreq)
1154 NTSTATUS status = cli_posix_chown_chmod_internal_recv(subreq);
1155 tevent_req_simple_finish_ntstatus(subreq, status);
1158 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1160 return tevent_req_simple_recv_ntstatus(req);
1163 NTSTATUS cli_posix_chown(struct cli_state *cli,
1164 const char *fname,
1165 uid_t uid,
1166 gid_t gid)
1168 TALLOC_CTX *frame = talloc_stackframe();
1169 struct tevent_context *ev = NULL;
1170 struct tevent_req *req = NULL;
1171 NTSTATUS status = NT_STATUS_OK;
1173 if (smbXcli_conn_has_async_calls(cli->conn)) {
1175 * Can't use sync call while an async call is in flight
1177 status = NT_STATUS_INVALID_PARAMETER;
1178 goto fail;
1181 ev = samba_tevent_context_init(frame);
1182 if (ev == NULL) {
1183 status = NT_STATUS_NO_MEMORY;
1184 goto fail;
1187 req = cli_posix_chown_send(frame,
1189 cli,
1190 fname,
1191 uid,
1192 gid);
1193 if (req == NULL) {
1194 status = NT_STATUS_NO_MEMORY;
1195 goto fail;
1198 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1199 goto fail;
1202 status = cli_posix_chown_recv(req);
1204 fail:
1205 TALLOC_FREE(frame);
1206 return status;
1209 /****************************************************************************
1210 Rename a file.
1211 ****************************************************************************/
1213 struct cli_smb1_rename_state {
1214 uint8_t *data;
1217 static void cli_smb1_rename_done(struct tevent_req *subreq);
1219 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1220 struct tevent_context *ev,
1221 struct cli_state *cli,
1222 const char *fname_src,
1223 const char *fname_dst,
1224 bool replace)
1226 NTSTATUS status;
1227 struct tevent_req *req = NULL, *subreq = NULL;
1228 struct cli_smb1_rename_state *state = NULL;
1229 smb_ucs2_t *converted_str = NULL;
1230 size_t converted_size_bytes = 0;
1232 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
1233 if (req == NULL) {
1234 return NULL;
1237 if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
1238 &converted_size_bytes)) {
1239 status = NT_STATUS_INVALID_PARAMETER;
1240 goto fail;
1243 /* W2K8 insists the dest name is not null
1244 terminated. Remove the last 2 zero bytes
1245 and reduce the name length. */
1247 if (converted_size_bytes < 2) {
1248 status = NT_STATUS_INVALID_PARAMETER;
1249 goto fail;
1251 converted_size_bytes -= 2;
1253 state->data =
1254 talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
1255 if (state->data == NULL) {
1256 status = NT_STATUS_NO_MEMORY;
1257 goto fail;
1260 if (replace) {
1261 SCVAL(state->data, 0, 1);
1264 SIVAL(state->data, 8, converted_size_bytes);
1265 memcpy(state->data + 12, converted_str, converted_size_bytes);
1267 TALLOC_FREE(converted_str);
1269 subreq = cli_setpathinfo_send(
1270 state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
1271 talloc_get_size(state->data));
1272 if (tevent_req_nomem(subreq, req)) {
1273 status = NT_STATUS_NO_MEMORY;
1274 goto fail;
1276 tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
1277 return req;
1279 fail:
1280 TALLOC_FREE(converted_str);
1281 tevent_req_nterror(req, status);
1282 return tevent_req_post(req, ev);
1285 static void cli_smb1_rename_done(struct tevent_req *subreq)
1287 NTSTATUS status = cli_setpathinfo_recv(subreq);
1288 tevent_req_simple_finish_ntstatus(subreq, status);
1291 static NTSTATUS cli_smb1_rename_recv(struct tevent_req *req)
1293 return tevent_req_simple_recv_ntstatus(req);
1296 static void cli_cifs_rename_done(struct tevent_req *subreq);
1298 struct cli_cifs_rename_state {
1299 uint16_t vwv[1];
1302 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1303 struct tevent_context *ev,
1304 struct cli_state *cli,
1305 const char *fname_src,
1306 const char *fname_dst,
1307 bool replace)
1309 struct tevent_req *req = NULL, *subreq = NULL;
1310 struct cli_cifs_rename_state *state = NULL;
1311 uint8_t additional_flags = 0;
1312 uint16_t additional_flags2 = 0;
1313 uint8_t *bytes = NULL;
1315 req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
1316 if (req == NULL) {
1317 return NULL;
1320 if (replace) {
1322 * CIFS doesn't support replace
1324 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1325 return tevent_req_post(req, ev);
1328 SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1330 bytes = talloc_array(state, uint8_t, 1);
1331 if (tevent_req_nomem(bytes, req)) {
1332 return tevent_req_post(req, ev);
1334 bytes[0] = 4;
1335 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1336 strlen(fname_src)+1, NULL);
1337 if (tevent_req_nomem(bytes, req)) {
1338 return tevent_req_post(req, ev);
1341 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1342 additional_flags2 = FLAGS2_REPARSE_PATH;
1345 bytes = talloc_realloc(state, bytes, uint8_t,
1346 talloc_get_size(bytes)+1);
1347 if (tevent_req_nomem(bytes, req)) {
1348 return tevent_req_post(req, ev);
1351 bytes[talloc_get_size(bytes)-1] = 4;
1352 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1353 strlen(fname_dst)+1, NULL);
1354 if (tevent_req_nomem(bytes, req)) {
1355 return tevent_req_post(req, ev);
1358 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1359 additional_flags2,
1360 1, state->vwv, talloc_get_size(bytes), bytes);
1361 if (tevent_req_nomem(subreq, req)) {
1362 return tevent_req_post(req, ev);
1364 tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
1365 return req;
1368 static void cli_cifs_rename_done(struct tevent_req *subreq)
1370 NTSTATUS status = cli_smb_recv(
1371 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1372 tevent_req_simple_finish_ntstatus(subreq, status);
1375 static NTSTATUS cli_cifs_rename_recv(struct tevent_req *req)
1377 return tevent_req_simple_recv_ntstatus(req);
1380 struct cli_rename_state {
1381 uint8_t dummy;
1384 static void cli_rename_done1(struct tevent_req *subreq);
1385 static void cli_rename_done_cifs(struct tevent_req *subreq);
1386 static void cli_rename_done2(struct tevent_req *subreq);
1388 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1389 struct tevent_context *ev,
1390 struct cli_state *cli,
1391 const char *fname_src,
1392 const char *fname_dst,
1393 bool replace)
1395 struct tevent_req *req = NULL, *subreq = NULL;
1396 struct cli_rename_state *state = NULL;
1398 req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1399 if (req == NULL) {
1400 return NULL;
1403 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1404 subreq = cli_smb2_rename_send(
1405 state, ev, cli, fname_src, fname_dst, replace);
1406 if (tevent_req_nomem(subreq, req)) {
1407 return tevent_req_post(req, ev);
1409 tevent_req_set_callback(subreq, cli_rename_done2, req);
1410 return req;
1413 if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
1414 subreq = cli_smb1_rename_send(
1415 state, ev, cli, fname_src, fname_dst, replace);
1416 if (tevent_req_nomem(subreq, req)) {
1417 return tevent_req_post(req, ev);
1419 tevent_req_set_callback(subreq, cli_rename_done1, req);
1420 return req;
1423 subreq = cli_cifs_rename_send(
1424 state, ev, cli, fname_src,fname_dst, replace);
1425 if (tevent_req_nomem(subreq, req)) {
1426 return tevent_req_post(req, ev);
1428 tevent_req_set_callback(subreq, cli_rename_done_cifs, req);
1429 return req;
1432 static void cli_rename_done1(struct tevent_req *subreq)
1434 NTSTATUS status = cli_smb1_rename_recv(subreq);
1435 tevent_req_simple_finish_ntstatus(subreq, status);
1438 static void cli_rename_done_cifs(struct tevent_req *subreq)
1440 NTSTATUS status = cli_cifs_rename_recv(subreq);
1441 tevent_req_simple_finish_ntstatus(subreq, status);
1444 static void cli_rename_done2(struct tevent_req *subreq)
1446 NTSTATUS status = cli_smb2_rename_recv(subreq);
1447 tevent_req_simple_finish_ntstatus(subreq, status);
1450 NTSTATUS cli_rename_recv(struct tevent_req *req)
1452 return tevent_req_simple_recv_ntstatus(req);
1455 NTSTATUS cli_rename(struct cli_state *cli,
1456 const char *fname_src,
1457 const char *fname_dst,
1458 bool replace)
1460 TALLOC_CTX *frame = NULL;
1461 struct tevent_context *ev;
1462 struct tevent_req *req;
1463 NTSTATUS status = NT_STATUS_OK;
1465 frame = talloc_stackframe();
1467 if (smbXcli_conn_has_async_calls(cli->conn)) {
1469 * Can't use sync call while an async call is in flight
1471 status = NT_STATUS_INVALID_PARAMETER;
1472 goto fail;
1475 ev = samba_tevent_context_init(frame);
1476 if (ev == NULL) {
1477 status = NT_STATUS_NO_MEMORY;
1478 goto fail;
1481 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
1482 if (req == NULL) {
1483 status = NT_STATUS_NO_MEMORY;
1484 goto fail;
1487 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1488 goto fail;
1491 status = cli_rename_recv(req);
1493 fail:
1494 TALLOC_FREE(frame);
1495 return status;
1498 /****************************************************************************
1499 NT Rename a file.
1500 ****************************************************************************/
1502 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1504 struct cli_ntrename_internal_state {
1505 uint16_t vwv[4];
1508 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1509 struct tevent_context *ev,
1510 struct cli_state *cli,
1511 const char *fname_src,
1512 const char *fname_dst,
1513 uint16_t rename_flag)
1515 struct tevent_req *req = NULL, *subreq = NULL;
1516 struct cli_ntrename_internal_state *state = NULL;
1517 uint8_t additional_flags = 0;
1518 uint16_t additional_flags2 = 0;
1519 uint8_t *bytes = NULL;
1521 req = tevent_req_create(mem_ctx, &state,
1522 struct cli_ntrename_internal_state);
1523 if (req == NULL) {
1524 return NULL;
1527 SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1528 SSVAL(state->vwv+1, 0, rename_flag);
1530 bytes = talloc_array(state, uint8_t, 1);
1531 if (tevent_req_nomem(bytes, req)) {
1532 return tevent_req_post(req, ev);
1534 bytes[0] = 4;
1535 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1536 strlen(fname_src)+1, NULL);
1537 if (tevent_req_nomem(bytes, req)) {
1538 return tevent_req_post(req, ev);
1541 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1542 additional_flags2 = FLAGS2_REPARSE_PATH;
1545 bytes = talloc_realloc(state, bytes, uint8_t,
1546 talloc_get_size(bytes)+1);
1547 if (tevent_req_nomem(bytes, req)) {
1548 return tevent_req_post(req, ev);
1551 bytes[talloc_get_size(bytes)-1] = 4;
1552 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1553 strlen(fname_dst)+1, NULL);
1554 if (tevent_req_nomem(bytes, req)) {
1555 return tevent_req_post(req, ev);
1558 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1559 additional_flags2,
1560 4, state->vwv, talloc_get_size(bytes), bytes);
1561 if (tevent_req_nomem(subreq, req)) {
1562 return tevent_req_post(req, ev);
1564 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1565 return req;
1568 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1570 NTSTATUS status = cli_smb_recv(
1571 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1572 tevent_req_simple_finish_ntstatus(subreq, status);
1575 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1577 return tevent_req_simple_recv_ntstatus(req);
1580 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1581 struct tevent_context *ev,
1582 struct cli_state *cli,
1583 const char *fname_src,
1584 const char *fname_dst)
1586 return cli_ntrename_internal_send(mem_ctx,
1588 cli,
1589 fname_src,
1590 fname_dst,
1591 RENAME_FLAG_RENAME);
1594 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1596 return cli_ntrename_internal_recv(req);
1599 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1601 TALLOC_CTX *frame = talloc_stackframe();
1602 struct tevent_context *ev;
1603 struct tevent_req *req;
1604 NTSTATUS status = NT_STATUS_OK;
1606 if (smbXcli_conn_has_async_calls(cli->conn)) {
1608 * Can't use sync call while an async call is in flight
1610 status = NT_STATUS_INVALID_PARAMETER;
1611 goto fail;
1614 ev = samba_tevent_context_init(frame);
1615 if (ev == NULL) {
1616 status = NT_STATUS_NO_MEMORY;
1617 goto fail;
1620 req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1621 if (req == NULL) {
1622 status = NT_STATUS_NO_MEMORY;
1623 goto fail;
1626 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1627 goto fail;
1630 status = cli_ntrename_recv(req);
1632 fail:
1633 TALLOC_FREE(frame);
1634 return status;
1637 /****************************************************************************
1638 NT hardlink a file.
1639 ****************************************************************************/
1641 static struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1642 struct tevent_context *ev,
1643 struct cli_state *cli,
1644 const char *fname_src,
1645 const char *fname_dst)
1647 return cli_ntrename_internal_send(mem_ctx,
1649 cli,
1650 fname_src,
1651 fname_dst,
1652 RENAME_FLAG_HARD_LINK);
1655 static NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1657 return cli_ntrename_internal_recv(req);
1660 struct cli_smb2_hardlink_state {
1661 struct tevent_context *ev;
1662 struct cli_state *cli;
1663 uint16_t fnum_src;
1664 const char *fname_dst;
1665 bool overwrite;
1666 NTSTATUS status;
1669 static void cli_smb2_hardlink_opened(struct tevent_req *subreq);
1670 static void cli_smb2_hardlink_info_set(struct tevent_req *subreq);
1671 static void cli_smb2_hardlink_closed(struct tevent_req *subreq);
1673 static struct tevent_req *cli_smb2_hardlink_send(
1674 TALLOC_CTX *mem_ctx,
1675 struct tevent_context *ev,
1676 struct cli_state *cli,
1677 const char *fname_src,
1678 const char *fname_dst,
1679 bool overwrite,
1680 struct smb2_create_blobs *in_cblobs)
1682 struct tevent_req *req = NULL, *subreq = NULL;
1683 struct cli_smb2_hardlink_state *state = NULL;
1685 req = tevent_req_create(
1686 mem_ctx, &state, struct cli_smb2_hardlink_state);
1687 if (req == NULL) {
1688 return NULL;
1690 state->ev = ev;
1691 state->cli = cli;
1692 state->fname_dst = fname_dst;
1693 state->overwrite = overwrite;
1695 subreq = cli_smb2_create_fnum_send(
1696 state,
1698 cli,
1699 fname_src,
1700 0, /* create_flags */
1701 SMB2_IMPERSONATION_IMPERSONATION,
1702 FILE_WRITE_ATTRIBUTES,
1703 0, /* file attributes */
1704 FILE_SHARE_READ|
1705 FILE_SHARE_WRITE|
1706 FILE_SHARE_DELETE, /* share_access */
1707 FILE_OPEN, /* create_disposition */
1708 FILE_NON_DIRECTORY_FILE, /* no hardlinks on directories */
1709 in_cblobs);
1710 if (tevent_req_nomem(subreq, req)) {
1711 return tevent_req_post(req, ev);
1713 tevent_req_set_callback(subreq, cli_smb2_hardlink_opened, req);
1714 return req;
1717 static void cli_smb2_hardlink_opened(struct tevent_req *subreq)
1719 struct tevent_req *req = tevent_req_callback_data(
1720 subreq, struct tevent_req);
1721 struct cli_smb2_hardlink_state *state = tevent_req_data(
1722 req, struct cli_smb2_hardlink_state);
1723 NTSTATUS status;
1724 smb_ucs2_t *ucs2_dst;
1725 size_t ucs2_len;
1726 DATA_BLOB inbuf;
1727 bool ok;
1729 status = cli_smb2_create_fnum_recv(
1730 subreq, &state->fnum_src, NULL, NULL, NULL);
1731 TALLOC_FREE(subreq);
1732 if (tevent_req_nterror(req, status)) {
1733 return;
1736 ok = push_ucs2_talloc(state, &ucs2_dst, state->fname_dst, &ucs2_len);
1737 if (!ok || (ucs2_len < 2)) {
1738 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1739 return;
1741 /* Don't 0-terminate the name */
1742 ucs2_len -= 2;
1744 inbuf = data_blob_talloc_zero(state, ucs2_len + 20);
1745 if (tevent_req_nomem(inbuf.data, req)) {
1746 return;
1749 if (state->overwrite) {
1750 SCVAL(inbuf.data, 0, 1);
1752 SIVAL(inbuf.data, 16, ucs2_len);
1753 memcpy(inbuf.data + 20, ucs2_dst, ucs2_len);
1754 TALLOC_FREE(ucs2_dst);
1756 subreq = cli_smb2_set_info_fnum_send(
1757 state,
1758 state->ev,
1759 state->cli,
1760 state->fnum_src,
1761 1, /* in_info_type */
1762 SMB_FILE_LINK_INFORMATION - 1000, /* in_file_info_class */
1763 &inbuf,
1764 0); /* in_additional_info */
1765 if (tevent_req_nomem(subreq, req)) {
1766 return;
1768 tevent_req_set_callback(subreq, cli_smb2_hardlink_info_set, req);
1771 static void cli_smb2_hardlink_info_set(struct tevent_req *subreq)
1773 struct tevent_req *req = tevent_req_callback_data(
1774 subreq, struct tevent_req);
1775 struct cli_smb2_hardlink_state *state = tevent_req_data(
1776 req, struct cli_smb2_hardlink_state);
1778 state->status = cli_smb2_set_info_fnum_recv(subreq);
1779 TALLOC_FREE(subreq);
1781 /* ignore error here, we need to close the file */
1783 subreq = cli_smb2_close_fnum_send(
1784 state, state->ev, state->cli, state->fnum_src);
1785 if (tevent_req_nomem(subreq, req)) {
1786 return;
1788 tevent_req_set_callback(subreq, cli_smb2_hardlink_closed, req);
1791 static void cli_smb2_hardlink_closed(struct tevent_req *subreq)
1793 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1794 tevent_req_simple_finish_ntstatus(subreq, status);
1797 static NTSTATUS cli_smb2_hardlink_recv(struct tevent_req *req)
1799 struct cli_smb2_hardlink_state *state = tevent_req_data(
1800 req, struct cli_smb2_hardlink_state);
1801 NTSTATUS status;
1803 if (tevent_req_is_nterror(req, &status)) {
1804 return status;
1806 return state->status;
1809 struct cli_hardlink_state {
1810 uint8_t dummy;
1813 static void cli_hardlink_done(struct tevent_req *subreq);
1814 static void cli_hardlink_done2(struct tevent_req *subreq);
1816 struct tevent_req *cli_hardlink_send(
1817 TALLOC_CTX *mem_ctx,
1818 struct tevent_context *ev,
1819 struct cli_state *cli,
1820 const char *fname_src,
1821 const char *fname_dst)
1823 struct tevent_req *req = NULL, *subreq = NULL;
1824 struct cli_hardlink_state *state;
1826 req = tevent_req_create(mem_ctx, &state, struct cli_hardlink_state);
1827 if (req == NULL) {
1828 return NULL;
1831 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1832 subreq = cli_smb2_hardlink_send(
1833 state, ev, cli, fname_src, fname_dst, false, NULL);
1834 if (tevent_req_nomem(subreq, req)) {
1835 return tevent_req_post(req, ev);
1837 tevent_req_set_callback(subreq, cli_hardlink_done2, req);
1838 return req;
1841 subreq = cli_nt_hardlink_send(state, ev, cli, fname_src, fname_dst);
1842 if (tevent_req_nomem(subreq, req)) {
1843 return tevent_req_post(req, ev);
1845 tevent_req_set_callback(subreq, cli_hardlink_done, req);
1846 return req;
1849 static void cli_hardlink_done(struct tevent_req *subreq)
1851 NTSTATUS status = cli_nt_hardlink_recv(subreq);
1852 tevent_req_simple_finish_ntstatus(subreq, status);
1855 static void cli_hardlink_done2(struct tevent_req *subreq)
1857 NTSTATUS status = cli_smb2_hardlink_recv(subreq);
1858 tevent_req_simple_finish_ntstatus(subreq, status);
1861 NTSTATUS cli_hardlink_recv(struct tevent_req *req)
1863 return tevent_req_simple_recv_ntstatus(req);
1866 NTSTATUS cli_hardlink(
1867 struct cli_state *cli, const char *fname_src, const char *fname_dst)
1869 TALLOC_CTX *frame = talloc_stackframe();
1870 struct tevent_context *ev = NULL;
1871 struct tevent_req *req = NULL;
1872 NTSTATUS status = NT_STATUS_NO_MEMORY;
1874 if (smbXcli_conn_has_async_calls(cli->conn)) {
1875 status = NT_STATUS_INVALID_PARAMETER;
1876 goto fail;
1878 ev = samba_tevent_context_init(frame);
1879 if (ev == NULL) {
1880 goto fail;
1882 req = cli_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1883 if (req == NULL) {
1884 goto fail;
1886 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1887 goto fail;
1889 status = cli_hardlink_recv(req);
1890 fail:
1891 TALLOC_FREE(frame);
1892 return status;
1895 /****************************************************************************
1896 Delete a file.
1897 ****************************************************************************/
1899 static void cli_unlink_done(struct tevent_req *subreq);
1900 static void cli_unlink_done2(struct tevent_req *subreq);
1902 struct cli_unlink_state {
1903 uint16_t vwv[1];
1906 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1907 struct tevent_context *ev,
1908 struct cli_state *cli,
1909 const char *fname,
1910 uint32_t mayhave_attrs)
1912 struct tevent_req *req = NULL, *subreq = NULL;
1913 struct cli_unlink_state *state = NULL;
1914 uint8_t additional_flags = 0;
1915 uint16_t additional_flags2 = 0;
1916 uint8_t *bytes = NULL;
1918 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1919 if (req == NULL) {
1920 return NULL;
1923 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1924 subreq = cli_smb2_unlink_send(state, ev, cli, fname, NULL);
1925 if (tevent_req_nomem(subreq, req)) {
1926 return tevent_req_post(req, ev);
1928 tevent_req_set_callback(subreq, cli_unlink_done2, req);
1929 return req;
1932 if (mayhave_attrs & 0xFFFF0000) {
1934 * Don't allow attributes greater than
1935 * 16-bits for a 16-bit protocol value.
1937 if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
1938 return tevent_req_post(req, ev);
1942 SSVAL(state->vwv+0, 0, mayhave_attrs);
1944 bytes = talloc_array(state, uint8_t, 1);
1945 if (tevent_req_nomem(bytes, req)) {
1946 return tevent_req_post(req, ev);
1948 bytes[0] = 4;
1949 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
1950 strlen(fname)+1, NULL);
1952 if (tevent_req_nomem(bytes, req)) {
1953 return tevent_req_post(req, ev);
1956 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1957 additional_flags2 = FLAGS2_REPARSE_PATH;
1960 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1961 additional_flags2,
1962 1, state->vwv, talloc_get_size(bytes), bytes);
1963 if (tevent_req_nomem(subreq, req)) {
1964 return tevent_req_post(req, ev);
1966 tevent_req_set_callback(subreq, cli_unlink_done, req);
1967 return req;
1970 static void cli_unlink_done(struct tevent_req *subreq)
1972 NTSTATUS status = cli_smb_recv(
1973 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1974 tevent_req_simple_finish_ntstatus(subreq, status);
1977 static void cli_unlink_done2(struct tevent_req *subreq)
1979 NTSTATUS status = cli_smb2_unlink_recv(subreq);
1980 tevent_req_simple_finish_ntstatus(subreq, status);
1983 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1985 return tevent_req_simple_recv_ntstatus(req);
1988 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint32_t mayhave_attrs)
1990 TALLOC_CTX *frame = NULL;
1991 struct tevent_context *ev;
1992 struct tevent_req *req;
1993 NTSTATUS status = NT_STATUS_OK;
1995 frame = talloc_stackframe();
1997 if (smbXcli_conn_has_async_calls(cli->conn)) {
1999 * Can't use sync call while an async call is in flight
2001 status = NT_STATUS_INVALID_PARAMETER;
2002 goto fail;
2005 ev = samba_tevent_context_init(frame);
2006 if (ev == NULL) {
2007 status = NT_STATUS_NO_MEMORY;
2008 goto fail;
2011 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
2012 if (req == NULL) {
2013 status = NT_STATUS_NO_MEMORY;
2014 goto fail;
2017 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2018 goto fail;
2021 status = cli_unlink_recv(req);
2022 cli->raw_status = status; /* cli_smb2_unlink_recv doesn't set this */
2024 fail:
2025 TALLOC_FREE(frame);
2026 return status;
2029 /****************************************************************************
2030 Create a directory.
2031 ****************************************************************************/
2033 static void cli_mkdir_done(struct tevent_req *subreq);
2034 static void cli_mkdir_done2(struct tevent_req *subreq);
2036 struct cli_mkdir_state {
2037 int dummy;
2040 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
2041 struct tevent_context *ev,
2042 struct cli_state *cli,
2043 const char *dname)
2045 struct tevent_req *req = NULL, *subreq = NULL;
2046 struct cli_mkdir_state *state = NULL;
2047 uint8_t additional_flags = 0;
2048 uint16_t additional_flags2 = 0;
2049 uint8_t *bytes = NULL;
2051 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
2052 if (req == NULL) {
2053 return NULL;
2056 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2057 subreq = cli_smb2_mkdir_send(state, ev, cli, dname);
2058 if (tevent_req_nomem(subreq, req)) {
2059 return tevent_req_post(req, ev);
2061 tevent_req_set_callback(subreq, cli_mkdir_done2, req);
2062 return req;
2065 bytes = talloc_array(state, uint8_t, 1);
2066 if (tevent_req_nomem(bytes, req)) {
2067 return tevent_req_post(req, ev);
2069 bytes[0] = 4;
2070 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
2071 strlen(dname)+1, NULL);
2073 if (tevent_req_nomem(bytes, req)) {
2074 return tevent_req_post(req, ev);
2077 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
2078 additional_flags2 = FLAGS2_REPARSE_PATH;
2081 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
2082 additional_flags2,
2083 0, NULL, talloc_get_size(bytes), bytes);
2084 if (tevent_req_nomem(subreq, req)) {
2085 return tevent_req_post(req, ev);
2087 tevent_req_set_callback(subreq, cli_mkdir_done, req);
2088 return req;
2091 static void cli_mkdir_done(struct tevent_req *subreq)
2093 struct tevent_req *req = tevent_req_callback_data(
2094 subreq, struct tevent_req);
2095 NTSTATUS status;
2097 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2098 TALLOC_FREE(subreq);
2099 if (tevent_req_nterror(req, status)) {
2100 return;
2102 tevent_req_done(req);
2105 static void cli_mkdir_done2(struct tevent_req *subreq)
2107 NTSTATUS status = cli_smb2_mkdir_recv(subreq);
2108 tevent_req_simple_finish_ntstatus(subreq, status);
2111 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
2113 return tevent_req_simple_recv_ntstatus(req);
2116 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
2118 TALLOC_CTX *frame = NULL;
2119 struct tevent_context *ev;
2120 struct tevent_req *req;
2121 NTSTATUS status = NT_STATUS_OK;
2123 frame = talloc_stackframe();
2125 if (smbXcli_conn_has_async_calls(cli->conn)) {
2127 * Can't use sync call while an async call is in flight
2129 status = NT_STATUS_INVALID_PARAMETER;
2130 goto fail;
2133 ev = samba_tevent_context_init(frame);
2134 if (ev == NULL) {
2135 status = NT_STATUS_NO_MEMORY;
2136 goto fail;
2139 req = cli_mkdir_send(frame, ev, cli, dname);
2140 if (req == NULL) {
2141 status = NT_STATUS_NO_MEMORY;
2142 goto fail;
2145 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2146 goto fail;
2149 status = cli_mkdir_recv(req);
2150 cli->raw_status = status; /* cli_smb2_mkdir_recv doesn't set this */
2152 fail:
2153 TALLOC_FREE(frame);
2154 return status;
2157 /****************************************************************************
2158 Remove a directory.
2159 ****************************************************************************/
2161 static void cli_rmdir_done(struct tevent_req *subreq);
2162 static void cli_rmdir_done2(struct tevent_req *subreq);
2164 struct cli_rmdir_state {
2165 int dummy;
2168 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
2169 struct tevent_context *ev,
2170 struct cli_state *cli,
2171 const char *dname)
2173 struct tevent_req *req = NULL, *subreq = NULL;
2174 struct cli_rmdir_state *state = NULL;
2175 uint8_t additional_flags = 0;
2176 uint16_t additional_flags2 = 0;
2177 uint8_t *bytes = NULL;
2179 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
2180 if (req == NULL) {
2181 return NULL;
2184 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2185 subreq = cli_smb2_rmdir_send(state, ev, cli, dname, NULL);
2186 if (tevent_req_nomem(subreq, req)) {
2187 return tevent_req_post(req, ev);
2189 tevent_req_set_callback(subreq, cli_rmdir_done2, req);
2190 return req;
2193 bytes = talloc_array(state, uint8_t, 1);
2194 if (tevent_req_nomem(bytes, req)) {
2195 return tevent_req_post(req, ev);
2197 bytes[0] = 4;
2198 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
2199 strlen(dname)+1, NULL);
2201 if (tevent_req_nomem(bytes, req)) {
2202 return tevent_req_post(req, ev);
2205 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
2206 additional_flags2 = FLAGS2_REPARSE_PATH;
2209 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
2210 additional_flags2,
2211 0, NULL, talloc_get_size(bytes), bytes);
2212 if (tevent_req_nomem(subreq, req)) {
2213 return tevent_req_post(req, ev);
2215 tevent_req_set_callback(subreq, cli_rmdir_done, req);
2216 return req;
2219 static void cli_rmdir_done(struct tevent_req *subreq)
2221 NTSTATUS status = cli_smb_recv(
2222 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2223 tevent_req_simple_finish_ntstatus(subreq, status);
2226 static void cli_rmdir_done2(struct tevent_req *subreq)
2228 NTSTATUS status = cli_smb2_rmdir_recv(subreq);
2229 tevent_req_simple_finish_ntstatus(subreq, status);
2232 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
2234 return tevent_req_simple_recv_ntstatus(req);
2237 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
2239 TALLOC_CTX *frame = NULL;
2240 struct tevent_context *ev;
2241 struct tevent_req *req;
2242 NTSTATUS status = NT_STATUS_OK;
2244 frame = talloc_stackframe();
2246 if (smbXcli_conn_has_async_calls(cli->conn)) {
2248 * Can't use sync call while an async call is in flight
2250 status = NT_STATUS_INVALID_PARAMETER;
2251 goto fail;
2254 ev = samba_tevent_context_init(frame);
2255 if (ev == NULL) {
2256 status = NT_STATUS_NO_MEMORY;
2257 goto fail;
2260 req = cli_rmdir_send(frame, ev, cli, dname);
2261 if (req == NULL) {
2262 status = NT_STATUS_NO_MEMORY;
2263 goto fail;
2266 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2267 goto fail;
2270 status = cli_rmdir_recv(req);
2271 cli->raw_status = status; /* cli_smb2_rmdir_recv doesn't set this */
2273 fail:
2274 TALLOC_FREE(frame);
2275 return status;
2278 /****************************************************************************
2279 Set or clear the delete on close flag.
2280 ****************************************************************************/
2282 struct doc_state {
2283 uint8_t data[1];
2286 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
2287 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
2289 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
2290 struct tevent_context *ev,
2291 struct cli_state *cli,
2292 uint16_t fnum,
2293 bool flag)
2295 struct tevent_req *req = NULL, *subreq = NULL;
2296 struct doc_state *state = NULL;
2298 req = tevent_req_create(mem_ctx, &state, struct doc_state);
2299 if (req == NULL) {
2300 return NULL;
2303 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2304 subreq = cli_smb2_delete_on_close_send(state, ev, cli,
2305 fnum, flag);
2306 if (tevent_req_nomem(subreq, req)) {
2307 return tevent_req_post(req, ev);
2309 tevent_req_set_callback(subreq,
2310 cli_nt_delete_on_close_smb2_done,
2311 req);
2312 return req;
2315 /* Setup data array. */
2316 SCVAL(&state->data[0], 0, flag ? 1 : 0);
2318 subreq = cli_setfileinfo_send(
2319 state,
2321 cli,
2322 fnum,
2323 SMB_SET_FILE_DISPOSITION_INFO,
2324 state->data,
2325 sizeof(state->data));
2327 if (tevent_req_nomem(subreq, req)) {
2328 return tevent_req_post(req, ev);
2330 tevent_req_set_callback(subreq,
2331 cli_nt_delete_on_close_smb1_done,
2332 req);
2333 return req;
2336 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
2338 NTSTATUS status = cli_setfileinfo_recv(subreq);
2339 tevent_req_simple_finish_ntstatus(subreq, status);
2342 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
2344 NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
2345 tevent_req_simple_finish_ntstatus(subreq, status);
2348 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
2350 return tevent_req_simple_recv_ntstatus(req);
2353 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
2355 TALLOC_CTX *frame = talloc_stackframe();
2356 struct tevent_context *ev = NULL;
2357 struct tevent_req *req = NULL;
2358 NTSTATUS status = NT_STATUS_OK;
2360 if (smbXcli_conn_has_async_calls(cli->conn)) {
2362 * Can't use sync call while an async call is in flight
2364 status = NT_STATUS_INVALID_PARAMETER;
2365 goto fail;
2368 ev = samba_tevent_context_init(frame);
2369 if (ev == NULL) {
2370 status = NT_STATUS_NO_MEMORY;
2371 goto fail;
2374 req = cli_nt_delete_on_close_send(frame,
2376 cli,
2377 fnum,
2378 flag);
2379 if (req == NULL) {
2380 status = NT_STATUS_NO_MEMORY;
2381 goto fail;
2384 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2385 goto fail;
2388 status = cli_nt_delete_on_close_recv(req);
2390 fail:
2391 TALLOC_FREE(frame);
2392 return status;
2395 struct cli_ntcreate1_state {
2396 uint16_t vwv[24];
2397 uint16_t fnum;
2398 struct smb_create_returns cr;
2399 struct tevent_req *subreq;
2402 static void cli_ntcreate1_done(struct tevent_req *subreq);
2403 static bool cli_ntcreate1_cancel(struct tevent_req *req);
2405 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
2406 struct tevent_context *ev,
2407 struct cli_state *cli,
2408 const char *fname,
2409 uint32_t CreatFlags,
2410 uint32_t DesiredAccess,
2411 uint32_t FileAttributes,
2412 uint32_t ShareAccess,
2413 uint32_t CreateDisposition,
2414 uint32_t CreateOptions,
2415 uint32_t ImpersonationLevel,
2416 uint8_t SecurityFlags)
2418 struct tevent_req *req, *subreq;
2419 struct cli_ntcreate1_state *state;
2420 uint16_t *vwv;
2421 uint8_t *bytes;
2422 size_t converted_len;
2423 uint16_t additional_flags2 = 0;
2425 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
2426 if (req == NULL) {
2427 return NULL;
2430 vwv = state->vwv;
2432 SCVAL(vwv+0, 0, 0xFF);
2433 SCVAL(vwv+0, 1, 0);
2434 SSVAL(vwv+1, 0, 0);
2435 SCVAL(vwv+2, 0, 0);
2437 if (cli->use_oplocks) {
2438 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
2440 SIVAL(vwv+3, 1, CreatFlags);
2441 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
2442 SIVAL(vwv+7, 1, DesiredAccess);
2443 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
2444 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
2445 SIVAL(vwv+13, 1, FileAttributes);
2446 SIVAL(vwv+15, 1, ShareAccess);
2447 SIVAL(vwv+17, 1, CreateDisposition);
2448 SIVAL(vwv+19, 1, CreateOptions |
2449 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2450 SIVAL(vwv+21, 1, ImpersonationLevel);
2451 SCVAL(vwv+23, 1, SecurityFlags);
2453 bytes = talloc_array(state, uint8_t, 0);
2454 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
2455 fname, strlen(fname)+1,
2456 &converted_len);
2458 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2459 additional_flags2 = FLAGS2_REPARSE_PATH;
2462 /* sigh. this copes with broken netapp filer behaviour */
2463 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2465 if (tevent_req_nomem(bytes, req)) {
2466 return tevent_req_post(req, ev);
2469 SSVAL(vwv+2, 1, converted_len);
2471 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2472 additional_flags2, 24, vwv,
2473 talloc_get_size(bytes), bytes);
2474 if (tevent_req_nomem(subreq, req)) {
2475 return tevent_req_post(req, ev);
2477 tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2479 state->subreq = subreq;
2480 tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2482 return req;
2485 static void cli_ntcreate1_done(struct tevent_req *subreq)
2487 struct tevent_req *req = tevent_req_callback_data(
2488 subreq, struct tevent_req);
2489 struct cli_ntcreate1_state *state = tevent_req_data(
2490 req, struct cli_ntcreate1_state);
2491 uint8_t wct;
2492 uint16_t *vwv;
2493 uint32_t num_bytes;
2494 uint8_t *bytes;
2495 NTSTATUS status;
2497 status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2498 &num_bytes, &bytes);
2499 TALLOC_FREE(subreq);
2500 if (tevent_req_nterror(req, status)) {
2501 return;
2503 state->cr.oplock_level = CVAL(vwv+2, 0);
2504 state->fnum = SVAL(vwv+2, 1);
2505 state->cr.create_action = IVAL(vwv+3, 1);
2506 state->cr.creation_time = BVAL(vwv+5, 1);
2507 state->cr.last_access_time = BVAL(vwv+9, 1);
2508 state->cr.last_write_time = BVAL(vwv+13, 1);
2509 state->cr.change_time = BVAL(vwv+17, 1);
2510 state->cr.file_attributes = IVAL(vwv+21, 1);
2511 state->cr.allocation_size = BVAL(vwv+23, 1);
2512 state->cr.end_of_file = BVAL(vwv+27, 1);
2514 tevent_req_done(req);
2517 static bool cli_ntcreate1_cancel(struct tevent_req *req)
2519 struct cli_ntcreate1_state *state = tevent_req_data(
2520 req, struct cli_ntcreate1_state);
2521 return tevent_req_cancel(state->subreq);
2524 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2525 uint16_t *pfnum,
2526 struct smb_create_returns *cr)
2528 struct cli_ntcreate1_state *state = tevent_req_data(
2529 req, struct cli_ntcreate1_state);
2530 NTSTATUS status;
2532 if (tevent_req_is_nterror(req, &status)) {
2533 return status;
2535 *pfnum = state->fnum;
2536 if (cr != NULL) {
2537 *cr = state->cr;
2539 return NT_STATUS_OK;
2542 struct cli_ntcreate_state {
2543 struct smb_create_returns cr;
2544 uint16_t fnum;
2545 struct tevent_req *subreq;
2548 static void cli_ntcreate_done_nt1(struct tevent_req *subreq);
2549 static void cli_ntcreate_done_smb2(struct tevent_req *subreq);
2550 static bool cli_ntcreate_cancel(struct tevent_req *req);
2552 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
2553 struct tevent_context *ev,
2554 struct cli_state *cli,
2555 const char *fname,
2556 uint32_t create_flags,
2557 uint32_t desired_access,
2558 uint32_t file_attributes,
2559 uint32_t share_access,
2560 uint32_t create_disposition,
2561 uint32_t create_options,
2562 uint32_t impersonation_level,
2563 uint8_t security_flags)
2565 struct tevent_req *req, *subreq;
2566 struct cli_ntcreate_state *state;
2568 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2569 if (req == NULL) {
2570 return NULL;
2573 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2574 if (cli->use_oplocks) {
2575 create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2578 subreq = cli_smb2_create_fnum_send(
2579 state,
2581 cli,
2582 fname,
2583 create_flags,
2584 impersonation_level,
2585 desired_access,
2586 file_attributes,
2587 share_access,
2588 create_disposition,
2589 create_options,
2590 NULL);
2591 if (tevent_req_nomem(subreq, req)) {
2592 return tevent_req_post(req, ev);
2594 tevent_req_set_callback(subreq, cli_ntcreate_done_smb2, req);
2595 } else {
2596 subreq = cli_ntcreate1_send(
2597 state, ev, cli, fname, create_flags, desired_access,
2598 file_attributes, share_access, create_disposition,
2599 create_options, impersonation_level, security_flags);
2600 if (tevent_req_nomem(subreq, req)) {
2601 return tevent_req_post(req, ev);
2603 tevent_req_set_callback(subreq, cli_ntcreate_done_nt1, req);
2606 state->subreq = subreq;
2607 tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2609 return req;
2612 static void cli_ntcreate_done_nt1(struct tevent_req *subreq)
2614 struct tevent_req *req = tevent_req_callback_data(
2615 subreq, struct tevent_req);
2616 struct cli_ntcreate_state *state = tevent_req_data(
2617 req, struct cli_ntcreate_state);
2618 NTSTATUS status;
2620 status = cli_ntcreate1_recv(subreq, &state->fnum, &state->cr);
2621 TALLOC_FREE(subreq);
2622 if (tevent_req_nterror(req, status)) {
2623 return;
2625 tevent_req_done(req);
2628 static void cli_ntcreate_done_smb2(struct tevent_req *subreq)
2630 struct tevent_req *req = tevent_req_callback_data(
2631 subreq, struct tevent_req);
2632 struct cli_ntcreate_state *state = tevent_req_data(
2633 req, struct cli_ntcreate_state);
2634 NTSTATUS status;
2636 status = cli_smb2_create_fnum_recv(
2637 subreq,
2638 &state->fnum,
2639 &state->cr,
2640 NULL,
2641 NULL);
2642 TALLOC_FREE(subreq);
2643 if (tevent_req_nterror(req, status)) {
2644 return;
2646 tevent_req_done(req);
2649 static bool cli_ntcreate_cancel(struct tevent_req *req)
2651 struct cli_ntcreate_state *state = tevent_req_data(
2652 req, struct cli_ntcreate_state);
2653 return tevent_req_cancel(state->subreq);
2656 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2657 struct smb_create_returns *cr)
2659 struct cli_ntcreate_state *state = tevent_req_data(
2660 req, struct cli_ntcreate_state);
2661 NTSTATUS status;
2663 if (tevent_req_is_nterror(req, &status)) {
2664 return status;
2666 if (fnum != NULL) {
2667 *fnum = state->fnum;
2669 if (cr != NULL) {
2670 *cr = state->cr;
2672 return NT_STATUS_OK;
2675 NTSTATUS cli_ntcreate(struct cli_state *cli,
2676 const char *fname,
2677 uint32_t CreatFlags,
2678 uint32_t DesiredAccess,
2679 uint32_t FileAttributes,
2680 uint32_t ShareAccess,
2681 uint32_t CreateDisposition,
2682 uint32_t CreateOptions,
2683 uint8_t SecurityFlags,
2684 uint16_t *pfid,
2685 struct smb_create_returns *cr)
2687 TALLOC_CTX *frame = talloc_stackframe();
2688 struct tevent_context *ev;
2689 struct tevent_req *req;
2690 uint32_t ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
2691 NTSTATUS status = NT_STATUS_NO_MEMORY;
2693 if (smbXcli_conn_has_async_calls(cli->conn)) {
2695 * Can't use sync call while an async call is in flight
2697 status = NT_STATUS_INVALID_PARAMETER;
2698 goto fail;
2701 ev = samba_tevent_context_init(frame);
2702 if (ev == NULL) {
2703 goto fail;
2706 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2707 DesiredAccess, FileAttributes, ShareAccess,
2708 CreateDisposition, CreateOptions,
2709 ImpersonationLevel, SecurityFlags);
2710 if (req == NULL) {
2711 goto fail;
2714 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2715 goto fail;
2718 status = cli_ntcreate_recv(req, pfid, cr);
2719 fail:
2720 TALLOC_FREE(frame);
2721 return status;
2724 struct cli_nttrans_create_state {
2725 uint16_t fnum;
2726 struct smb_create_returns cr;
2729 static void cli_nttrans_create_done(struct tevent_req *subreq);
2731 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2732 struct tevent_context *ev,
2733 struct cli_state *cli,
2734 const char *fname,
2735 uint32_t CreatFlags,
2736 uint32_t DesiredAccess,
2737 uint32_t FileAttributes,
2738 uint32_t ShareAccess,
2739 uint32_t CreateDisposition,
2740 uint32_t CreateOptions,
2741 uint8_t SecurityFlags,
2742 struct security_descriptor *secdesc,
2743 struct ea_struct *eas,
2744 int num_eas)
2746 struct tevent_req *req, *subreq;
2747 struct cli_nttrans_create_state *state;
2748 uint8_t *param;
2749 uint8_t *secdesc_buf;
2750 size_t secdesc_len;
2751 NTSTATUS status;
2752 size_t converted_len;
2753 uint16_t additional_flags2 = 0;
2755 req = tevent_req_create(mem_ctx,
2756 &state, struct cli_nttrans_create_state);
2757 if (req == NULL) {
2758 return NULL;
2761 if (secdesc != NULL) {
2762 status = marshall_sec_desc(talloc_tos(), secdesc,
2763 &secdesc_buf, &secdesc_len);
2764 if (tevent_req_nterror(req, status)) {
2765 DEBUG(10, ("marshall_sec_desc failed: %s\n",
2766 nt_errstr(status)));
2767 return tevent_req_post(req, ev);
2769 } else {
2770 secdesc_buf = NULL;
2771 secdesc_len = 0;
2774 if (num_eas != 0) {
2776 * TODO ;-)
2778 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2779 return tevent_req_post(req, ev);
2782 param = talloc_array(state, uint8_t, 53);
2783 if (tevent_req_nomem(param, req)) {
2784 return tevent_req_post(req, ev);
2787 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2788 fname, strlen(fname),
2789 &converted_len);
2790 if (tevent_req_nomem(param, req)) {
2791 return tevent_req_post(req, ev);
2794 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2795 additional_flags2 = FLAGS2_REPARSE_PATH;
2798 SIVAL(param, 0, CreatFlags);
2799 SIVAL(param, 4, 0x0); /* RootDirectoryFid */
2800 SIVAL(param, 8, DesiredAccess);
2801 SIVAL(param, 12, 0x0); /* AllocationSize */
2802 SIVAL(param, 16, 0x0); /* AllocationSize */
2803 SIVAL(param, 20, FileAttributes);
2804 SIVAL(param, 24, ShareAccess);
2805 SIVAL(param, 28, CreateDisposition);
2806 SIVAL(param, 32, CreateOptions |
2807 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2808 SIVAL(param, 36, secdesc_len);
2809 SIVAL(param, 40, 0); /* EA length*/
2810 SIVAL(param, 44, converted_len);
2811 SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2812 SCVAL(param, 52, SecurityFlags);
2814 subreq = cli_trans_send(state, ev, cli,
2815 additional_flags2, /* additional_flags2 */
2816 SMBnttrans,
2817 NULL, -1, /* name, fid */
2818 NT_TRANSACT_CREATE, 0,
2819 NULL, 0, 0, /* setup */
2820 param, talloc_get_size(param), 128, /* param */
2821 secdesc_buf, secdesc_len, 0); /* data */
2822 if (tevent_req_nomem(subreq, req)) {
2823 return tevent_req_post(req, ev);
2825 tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2826 return req;
2829 static void cli_nttrans_create_done(struct tevent_req *subreq)
2831 struct tevent_req *req = tevent_req_callback_data(
2832 subreq, struct tevent_req);
2833 struct cli_nttrans_create_state *state = tevent_req_data(
2834 req, struct cli_nttrans_create_state);
2835 uint8_t *param;
2836 uint32_t num_param;
2837 NTSTATUS status;
2839 status = cli_trans_recv(subreq, talloc_tos(), NULL,
2840 NULL, 0, NULL, /* rsetup */
2841 &param, 69, &num_param,
2842 NULL, 0, NULL);
2843 if (tevent_req_nterror(req, status)) {
2844 return;
2846 state->cr.oplock_level = CVAL(param, 0);
2847 state->fnum = SVAL(param, 2);
2848 state->cr.create_action = IVAL(param, 4);
2849 state->cr.creation_time = BVAL(param, 12);
2850 state->cr.last_access_time = BVAL(param, 20);
2851 state->cr.last_write_time = BVAL(param, 28);
2852 state->cr.change_time = BVAL(param, 36);
2853 state->cr.file_attributes = IVAL(param, 44);
2854 state->cr.allocation_size = BVAL(param, 48);
2855 state->cr.end_of_file = BVAL(param, 56);
2857 TALLOC_FREE(param);
2858 tevent_req_done(req);
2861 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2862 uint16_t *fnum,
2863 struct smb_create_returns *cr)
2865 struct cli_nttrans_create_state *state = tevent_req_data(
2866 req, struct cli_nttrans_create_state);
2867 NTSTATUS status;
2869 if (tevent_req_is_nterror(req, &status)) {
2870 return status;
2872 *fnum = state->fnum;
2873 if (cr != NULL) {
2874 *cr = state->cr;
2876 return NT_STATUS_OK;
2879 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2880 const char *fname,
2881 uint32_t CreatFlags,
2882 uint32_t DesiredAccess,
2883 uint32_t FileAttributes,
2884 uint32_t ShareAccess,
2885 uint32_t CreateDisposition,
2886 uint32_t CreateOptions,
2887 uint8_t SecurityFlags,
2888 struct security_descriptor *secdesc,
2889 struct ea_struct *eas,
2890 int num_eas,
2891 uint16_t *pfid,
2892 struct smb_create_returns *cr)
2894 TALLOC_CTX *frame = talloc_stackframe();
2895 struct tevent_context *ev;
2896 struct tevent_req *req;
2897 NTSTATUS status = NT_STATUS_NO_MEMORY;
2899 if (smbXcli_conn_has_async_calls(cli->conn)) {
2901 * Can't use sync call while an async call is in flight
2903 status = NT_STATUS_INVALID_PARAMETER;
2904 goto fail;
2906 ev = samba_tevent_context_init(frame);
2907 if (ev == NULL) {
2908 goto fail;
2910 req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2911 DesiredAccess, FileAttributes,
2912 ShareAccess, CreateDisposition,
2913 CreateOptions, SecurityFlags,
2914 secdesc, eas, num_eas);
2915 if (req == NULL) {
2916 goto fail;
2918 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2919 goto fail;
2921 status = cli_nttrans_create_recv(req, pfid, cr);
2922 fail:
2923 TALLOC_FREE(frame);
2924 return status;
2927 /****************************************************************************
2928 Open a file
2929 WARNING: if you open with O_WRONLY then getattrE won't work!
2930 ****************************************************************************/
2932 struct cli_openx_state {
2933 const char *fname;
2934 uint16_t vwv[15];
2935 uint16_t fnum;
2936 struct iovec bytes;
2939 static void cli_openx_done(struct tevent_req *subreq);
2941 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2942 struct tevent_context *ev,
2943 struct cli_state *cli, const char *fname,
2944 int flags, int share_mode,
2945 struct tevent_req **psmbreq)
2947 struct tevent_req *req, *subreq;
2948 struct cli_openx_state *state;
2949 unsigned openfn;
2950 unsigned accessmode;
2951 uint8_t additional_flags;
2952 uint16_t additional_flags2 = 0;
2953 uint8_t *bytes;
2955 req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2956 if (req == NULL) {
2957 return NULL;
2960 openfn = 0;
2961 if (flags & O_CREAT) {
2962 openfn |= (1<<4);
2964 if (!(flags & O_EXCL)) {
2965 if (flags & O_TRUNC)
2966 openfn |= (1<<1);
2967 else
2968 openfn |= (1<<0);
2971 accessmode = (share_mode<<4);
2973 if ((flags & O_ACCMODE) == O_RDWR) {
2974 accessmode |= 2;
2975 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2976 accessmode |= 1;
2979 #if defined(O_SYNC)
2980 if ((flags & O_SYNC) == O_SYNC) {
2981 accessmode |= (1<<14);
2983 #endif /* O_SYNC */
2985 if (share_mode == DENY_FCB) {
2986 accessmode = 0xFF;
2989 SCVAL(state->vwv + 0, 0, 0xFF);
2990 SCVAL(state->vwv + 0, 1, 0);
2991 SSVAL(state->vwv + 1, 0, 0);
2992 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
2993 SSVAL(state->vwv + 3, 0, accessmode);
2994 SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2995 SSVAL(state->vwv + 5, 0, 0);
2996 SIVAL(state->vwv + 6, 0, 0);
2997 SSVAL(state->vwv + 8, 0, openfn);
2998 SIVAL(state->vwv + 9, 0, 0);
2999 SIVAL(state->vwv + 11, 0, 0);
3000 SIVAL(state->vwv + 13, 0, 0);
3002 additional_flags = 0;
3004 if (cli->use_oplocks) {
3005 /* if using oplocks then ask for a batch oplock via
3006 core and extended methods */
3007 additional_flags =
3008 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
3009 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
3012 bytes = talloc_array(state, uint8_t, 0);
3013 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3014 strlen(fname)+1, NULL);
3016 if (tevent_req_nomem(bytes, req)) {
3017 return tevent_req_post(req, ev);
3020 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
3021 additional_flags2 = FLAGS2_REPARSE_PATH;
3024 state->bytes.iov_base = (void *)bytes;
3025 state->bytes.iov_len = talloc_get_size(bytes);
3027 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
3028 additional_flags2, 15, state->vwv, 1, &state->bytes);
3029 if (subreq == NULL) {
3030 TALLOC_FREE(req);
3031 return NULL;
3033 tevent_req_set_callback(subreq, cli_openx_done, req);
3034 *psmbreq = subreq;
3035 return req;
3038 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
3039 struct cli_state *cli, const char *fname,
3040 int flags, int share_mode)
3042 struct tevent_req *req, *subreq;
3043 NTSTATUS status;
3045 req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
3046 &subreq);
3047 if (req == NULL) {
3048 return NULL;
3051 status = smb1cli_req_chain_submit(&subreq, 1);
3052 if (tevent_req_nterror(req, status)) {
3053 return tevent_req_post(req, ev);
3055 return req;
3058 static void cli_openx_done(struct tevent_req *subreq)
3060 struct tevent_req *req = tevent_req_callback_data(
3061 subreq, struct tevent_req);
3062 struct cli_openx_state *state = tevent_req_data(
3063 req, struct cli_openx_state);
3064 uint8_t wct;
3065 uint16_t *vwv;
3066 NTSTATUS status;
3068 status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
3069 NULL);
3070 TALLOC_FREE(subreq);
3071 if (tevent_req_nterror(req, status)) {
3072 return;
3074 state->fnum = SVAL(vwv+2, 0);
3075 tevent_req_done(req);
3078 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
3080 struct cli_openx_state *state = tevent_req_data(
3081 req, struct cli_openx_state);
3082 NTSTATUS status;
3084 if (tevent_req_is_nterror(req, &status)) {
3085 return status;
3087 *pfnum = state->fnum;
3088 return NT_STATUS_OK;
3091 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
3092 int share_mode, uint16_t *pfnum)
3094 TALLOC_CTX *frame = talloc_stackframe();
3095 struct tevent_context *ev;
3096 struct tevent_req *req;
3097 NTSTATUS status = NT_STATUS_NO_MEMORY;
3099 if (smbXcli_conn_has_async_calls(cli->conn)) {
3101 * Can't use sync call while an async call is in flight
3103 status = NT_STATUS_INVALID_PARAMETER;
3104 goto fail;
3107 ev = samba_tevent_context_init(frame);
3108 if (ev == NULL) {
3109 goto fail;
3112 req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
3113 if (req == NULL) {
3114 goto fail;
3117 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3118 goto fail;
3121 status = cli_openx_recv(req, pfnum);
3122 fail:
3123 TALLOC_FREE(frame);
3124 return status;
3126 /****************************************************************************
3127 Synchronous wrapper function that does an NtCreateX open by preference
3128 and falls back to openX if this fails.
3129 ****************************************************************************/
3131 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
3132 int share_mode_in, uint16_t *pfnum)
3134 NTSTATUS status;
3135 unsigned int openfn = 0;
3136 unsigned int dos_deny = 0;
3137 uint32_t access_mask, share_mode, create_disposition, create_options;
3138 struct smb_create_returns cr = {0};
3140 /* Do the initial mapping into OpenX parameters. */
3141 if (flags & O_CREAT) {
3142 openfn |= (1<<4);
3144 if (!(flags & O_EXCL)) {
3145 if (flags & O_TRUNC)
3146 openfn |= (1<<1);
3147 else
3148 openfn |= (1<<0);
3151 dos_deny = (share_mode_in<<4);
3153 if ((flags & O_ACCMODE) == O_RDWR) {
3154 dos_deny |= 2;
3155 } else if ((flags & O_ACCMODE) == O_WRONLY) {
3156 dos_deny |= 1;
3159 #if defined(O_SYNC)
3160 if ((flags & O_SYNC) == O_SYNC) {
3161 dos_deny |= (1<<14);
3163 #endif /* O_SYNC */
3165 if (share_mode_in == DENY_FCB) {
3166 dos_deny = 0xFF;
3169 if (!map_open_params_to_ntcreate(fname, dos_deny,
3170 openfn, &access_mask,
3171 &share_mode, &create_disposition,
3172 &create_options, NULL)) {
3173 goto try_openx;
3176 status = cli_ntcreate(cli,
3177 fname,
3179 access_mask,
3181 share_mode,
3182 create_disposition,
3183 create_options,
3185 pfnum,
3186 &cr);
3188 /* Try and cope will all varients of "we don't do this call"
3189 and fall back to openX. */
3191 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
3192 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
3193 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
3194 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
3195 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
3196 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
3197 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
3198 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
3199 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
3200 goto try_openx;
3203 if (NT_STATUS_IS_OK(status) &&
3204 (create_options & FILE_NON_DIRECTORY_FILE) &&
3205 (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
3208 * Some (broken) servers return a valid handle
3209 * for directories even if FILE_NON_DIRECTORY_FILE
3210 * is set. Just close the handle and set the
3211 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
3213 status = cli_close(cli, *pfnum);
3214 if (!NT_STATUS_IS_OK(status)) {
3215 return status;
3217 status = NT_STATUS_FILE_IS_A_DIRECTORY;
3218 /* Set this so libsmbclient can retrieve it. */
3219 cli->raw_status = status;
3222 return status;
3224 try_openx:
3226 return cli_openx(cli, fname, flags, share_mode_in, pfnum);
3229 /****************************************************************************
3230 Close a file.
3231 ****************************************************************************/
3233 struct cli_smb1_close_state {
3234 uint16_t vwv[3];
3237 static void cli_smb1_close_done(struct tevent_req *subreq);
3239 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
3240 struct tevent_context *ev,
3241 struct cli_state *cli,
3242 uint16_t fnum,
3243 struct tevent_req **psubreq)
3245 struct tevent_req *req, *subreq;
3246 struct cli_smb1_close_state *state;
3248 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
3249 if (req == NULL) {
3250 return NULL;
3253 SSVAL(state->vwv+0, 0, fnum);
3254 SIVALS(state->vwv+1, 0, -1);
3256 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
3257 3, state->vwv, 0, NULL);
3258 if (subreq == NULL) {
3259 TALLOC_FREE(req);
3260 return NULL;
3262 tevent_req_set_callback(subreq, cli_smb1_close_done, req);
3263 *psubreq = subreq;
3264 return req;
3267 static void cli_smb1_close_done(struct tevent_req *subreq)
3269 struct tevent_req *req = tevent_req_callback_data(
3270 subreq, struct tevent_req);
3271 NTSTATUS status;
3273 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3274 TALLOC_FREE(subreq);
3275 if (tevent_req_nterror(req, status)) {
3276 return;
3278 tevent_req_done(req);
3281 struct cli_close_state {
3282 int dummy;
3285 static void cli_close_done(struct tevent_req *subreq);
3287 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
3288 struct tevent_context *ev,
3289 struct cli_state *cli,
3290 uint16_t fnum)
3292 struct tevent_req *req, *subreq;
3293 struct cli_close_state *state;
3294 NTSTATUS status;
3296 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
3297 if (req == NULL) {
3298 return NULL;
3301 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3302 subreq = cli_smb2_close_fnum_send(state,
3304 cli,
3305 fnum);
3306 if (tevent_req_nomem(subreq, req)) {
3307 return tevent_req_post(req, ev);
3309 } else {
3310 struct tevent_req *ch_req = NULL;
3311 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
3312 if (tevent_req_nomem(subreq, req)) {
3313 return tevent_req_post(req, ev);
3315 status = smb1cli_req_chain_submit(&ch_req, 1);
3316 if (tevent_req_nterror(req, status)) {
3317 return tevent_req_post(req, ev);
3321 tevent_req_set_callback(subreq, cli_close_done, req);
3322 return req;
3325 static void cli_close_done(struct tevent_req *subreq)
3327 struct tevent_req *req = tevent_req_callback_data(
3328 subreq, struct tevent_req);
3329 NTSTATUS status = NT_STATUS_OK;
3330 bool err = tevent_req_is_nterror(subreq, &status);
3332 TALLOC_FREE(subreq);
3333 if (err) {
3334 tevent_req_nterror(req, status);
3335 return;
3337 tevent_req_done(req);
3340 NTSTATUS cli_close_recv(struct tevent_req *req)
3342 return tevent_req_simple_recv_ntstatus(req);
3345 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
3347 TALLOC_CTX *frame = NULL;
3348 struct tevent_context *ev;
3349 struct tevent_req *req;
3350 NTSTATUS status = NT_STATUS_OK;
3352 frame = talloc_stackframe();
3354 if (smbXcli_conn_has_async_calls(cli->conn)) {
3356 * Can't use sync call while an async call is in flight
3358 status = NT_STATUS_INVALID_PARAMETER;
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_close_send(frame, ev, cli, fnum);
3369 if (req == NULL) {
3370 status = NT_STATUS_NO_MEMORY;
3371 goto fail;
3374 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3375 goto fail;
3378 status = cli_close_recv(req);
3379 fail:
3380 TALLOC_FREE(frame);
3381 return status;
3384 /****************************************************************************
3385 Truncate a file to a specified size
3386 ****************************************************************************/
3388 struct ftrunc_state {
3389 uint8_t data[8];
3392 static void cli_ftruncate_done(struct tevent_req *subreq)
3394 NTSTATUS status = cli_setfileinfo_recv(subreq);
3395 tevent_req_simple_finish_ntstatus(subreq, status);
3398 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
3399 struct tevent_context *ev,
3400 struct cli_state *cli,
3401 uint16_t fnum,
3402 uint64_t size)
3404 struct tevent_req *req = NULL, *subreq = NULL;
3405 struct ftrunc_state *state = NULL;
3407 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
3408 if (req == NULL) {
3409 return NULL;
3412 /* Setup data array. */
3413 SBVAL(state->data, 0, size);
3415 subreq = cli_setfileinfo_send(
3416 state,
3418 cli,
3419 fnum,
3420 SMB_SET_FILE_END_OF_FILE_INFO,
3421 state->data,
3422 sizeof(state->data));
3424 if (tevent_req_nomem(subreq, req)) {
3425 return tevent_req_post(req, ev);
3427 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
3428 return req;
3431 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
3433 return tevent_req_simple_recv_ntstatus(req);
3436 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3438 TALLOC_CTX *frame = NULL;
3439 struct tevent_context *ev = NULL;
3440 struct tevent_req *req = NULL;
3441 NTSTATUS status = NT_STATUS_OK;
3443 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3444 return cli_smb2_ftruncate(cli, fnum, size);
3447 frame = talloc_stackframe();
3449 if (smbXcli_conn_has_async_calls(cli->conn)) {
3451 * Can't use sync call while an async call is in flight
3453 status = NT_STATUS_INVALID_PARAMETER;
3454 goto fail;
3457 ev = samba_tevent_context_init(frame);
3458 if (ev == NULL) {
3459 status = NT_STATUS_NO_MEMORY;
3460 goto fail;
3463 req = cli_ftruncate_send(frame,
3465 cli,
3466 fnum,
3467 size);
3468 if (req == NULL) {
3469 status = NT_STATUS_NO_MEMORY;
3470 goto fail;
3473 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3474 goto fail;
3477 status = cli_ftruncate_recv(req);
3479 fail:
3480 TALLOC_FREE(frame);
3481 return status;
3484 static uint8_t *cli_lockingx_put_locks(
3485 uint8_t *buf,
3486 bool large,
3487 uint16_t num_locks,
3488 const struct smb1_lock_element *locks)
3490 uint16_t i;
3492 for (i=0; i<num_locks; i++) {
3493 const struct smb1_lock_element *e = &locks[i];
3494 if (large) {
3495 SSVAL(buf, 0, e->pid);
3496 SSVAL(buf, 2, 0);
3497 SOFF_T_R(buf, 4, e->offset);
3498 SOFF_T_R(buf, 12, e->length);
3499 buf += 20;
3500 } else {
3501 SSVAL(buf, 0, e->pid);
3502 SIVAL(buf, 2, e->offset);
3503 SIVAL(buf, 6, e->length);
3504 buf += 10;
3507 return buf;
3510 struct cli_lockingx_state {
3511 uint16_t vwv[8];
3512 struct iovec bytes;
3513 struct tevent_req *subreq;
3516 static void cli_lockingx_done(struct tevent_req *subreq);
3517 static bool cli_lockingx_cancel(struct tevent_req *req);
3519 struct tevent_req *cli_lockingx_create(
3520 TALLOC_CTX *mem_ctx,
3521 struct tevent_context *ev,
3522 struct cli_state *cli,
3523 uint16_t fnum,
3524 uint8_t typeoflock,
3525 uint8_t newoplocklevel,
3526 int32_t timeout,
3527 uint16_t num_unlocks,
3528 const struct smb1_lock_element *unlocks,
3529 uint16_t num_locks,
3530 const struct smb1_lock_element *locks,
3531 struct tevent_req **psmbreq)
3533 struct tevent_req *req = NULL, *subreq = NULL;
3534 struct cli_lockingx_state *state = NULL;
3535 uint16_t *vwv;
3536 uint8_t *p;
3537 const bool large = (typeoflock & LOCKING_ANDX_LARGE_FILES);
3538 const size_t element_len = large ? 20 : 10;
3540 /* uint16->size_t, no overflow */
3541 const size_t num_elements = (size_t)num_locks + (size_t)num_unlocks;
3543 /* at most 20*2*65535 = 2621400, no overflow */
3544 const size_t num_bytes = num_elements * element_len;
3546 req = tevent_req_create(mem_ctx, &state, struct cli_lockingx_state);
3547 if (req == NULL) {
3548 return NULL;
3550 vwv = state->vwv;
3552 SCVAL(vwv + 0, 0, 0xFF);
3553 SCVAL(vwv + 0, 1, 0);
3554 SSVAL(vwv + 1, 0, 0);
3555 SSVAL(vwv + 2, 0, fnum);
3556 SCVAL(vwv + 3, 0, typeoflock);
3557 SCVAL(vwv + 3, 1, newoplocklevel);
3558 SIVALS(vwv + 4, 0, timeout);
3559 SSVAL(vwv + 6, 0, num_unlocks);
3560 SSVAL(vwv + 7, 0, num_locks);
3562 state->bytes.iov_len = num_bytes;
3563 state->bytes.iov_base = talloc_array(state, uint8_t, num_bytes);
3564 if (tevent_req_nomem(state->bytes.iov_base, req)) {
3565 return tevent_req_post(req, ev);
3568 p = cli_lockingx_put_locks(
3569 state->bytes.iov_base, large, num_unlocks, unlocks);
3570 cli_lockingx_put_locks(p, large, num_locks, locks);
3572 subreq = cli_smb_req_create(
3573 state, ev, cli, SMBlockingX, 0, 0, 8, vwv, 1, &state->bytes);
3574 if (tevent_req_nomem(subreq, req)) {
3575 return tevent_req_post(req, ev);
3577 tevent_req_set_callback(subreq, cli_lockingx_done, req);
3578 *psmbreq = subreq;
3579 return req;
3582 struct tevent_req *cli_lockingx_send(
3583 TALLOC_CTX *mem_ctx,
3584 struct tevent_context *ev,
3585 struct cli_state *cli,
3586 uint16_t fnum,
3587 uint8_t typeoflock,
3588 uint8_t newoplocklevel,
3589 int32_t timeout,
3590 uint16_t num_unlocks,
3591 const struct smb1_lock_element *unlocks,
3592 uint16_t num_locks,
3593 const struct smb1_lock_element *locks)
3595 struct tevent_req *req = NULL, *subreq = NULL;
3596 struct cli_lockingx_state *state = NULL;
3597 NTSTATUS status;
3599 req = cli_lockingx_create(
3600 mem_ctx,
3602 cli,
3603 fnum,
3604 typeoflock,
3605 newoplocklevel,
3606 timeout,
3607 num_unlocks,
3608 unlocks,
3609 num_locks,
3610 locks,
3611 &subreq);
3612 if (req == NULL) {
3613 return NULL;
3615 state = tevent_req_data(req, struct cli_lockingx_state);
3616 state->subreq = subreq;
3618 status = smb1cli_req_chain_submit(&subreq, 1);
3619 if (tevent_req_nterror(req, status)) {
3620 return tevent_req_post(req, ev);
3622 tevent_req_set_cancel_fn(req, cli_lockingx_cancel);
3623 return req;
3626 static void cli_lockingx_done(struct tevent_req *subreq)
3628 NTSTATUS status = cli_smb_recv(
3629 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3630 tevent_req_simple_finish_ntstatus(subreq, status);
3633 static bool cli_lockingx_cancel(struct tevent_req *req)
3635 struct cli_lockingx_state *state = tevent_req_data(
3636 req, struct cli_lockingx_state);
3637 if (state->subreq == NULL) {
3638 return false;
3640 return tevent_req_cancel(state->subreq);
3643 NTSTATUS cli_lockingx_recv(struct tevent_req *req)
3645 return tevent_req_simple_recv_ntstatus(req);
3648 NTSTATUS cli_lockingx(
3649 struct cli_state *cli,
3650 uint16_t fnum,
3651 uint8_t typeoflock,
3652 uint8_t newoplocklevel,
3653 int32_t timeout,
3654 uint16_t num_unlocks,
3655 const struct smb1_lock_element *unlocks,
3656 uint16_t num_locks,
3657 const struct smb1_lock_element *locks)
3659 TALLOC_CTX *frame = talloc_stackframe();
3660 struct tevent_context *ev = NULL;
3661 struct tevent_req *req = NULL;
3662 NTSTATUS status = NT_STATUS_NO_MEMORY;
3663 unsigned int set_timeout = 0;
3664 unsigned int saved_timeout = 0;
3666 if (smbXcli_conn_has_async_calls(cli->conn)) {
3667 return NT_STATUS_INVALID_PARAMETER;
3669 ev = samba_tevent_context_init(frame);
3670 if (ev == NULL) {
3671 goto fail;
3674 if (timeout != 0) {
3675 if (timeout == -1) {
3676 set_timeout = 0x7FFFFFFF;
3677 } else {
3678 set_timeout = timeout + 2*1000;
3680 saved_timeout = cli_set_timeout(cli, set_timeout);
3683 req = cli_lockingx_send(
3684 frame,
3686 cli,
3687 fnum,
3688 typeoflock,
3689 newoplocklevel,
3690 timeout,
3691 num_unlocks,
3692 unlocks,
3693 num_locks,
3694 locks);
3695 if (req == NULL) {
3696 goto fail;
3698 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3699 goto fail;
3701 status = cli_lockingx_recv(req);
3703 if (saved_timeout != 0) {
3704 cli_set_timeout(cli, saved_timeout);
3706 fail:
3707 TALLOC_FREE(frame);
3708 return status;
3711 /****************************************************************************
3712 send a lock with a specified locktype
3713 this is used for testing LOCKING_ANDX_CANCEL_LOCK
3714 ****************************************************************************/
3716 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
3717 uint32_t offset, uint32_t len,
3718 int timeout, unsigned char locktype)
3720 struct smb1_lock_element lck = {
3721 .pid = cli_getpid(cli),
3722 .offset = offset,
3723 .length = len,
3725 NTSTATUS status;
3727 status = cli_lockingx(
3728 cli, /* cli */
3729 fnum, /* fnum */
3730 locktype, /* typeoflock */
3731 0, /* newoplocklevel */
3732 timeout, /* timeout */
3733 0, /* num_unlocks */
3734 NULL, /* unlocks */
3735 1, /* num_locks */
3736 &lck); /* locks */
3737 return status;
3740 /****************************************************************************
3741 Lock a file.
3742 note that timeout is in units of 2 milliseconds
3743 ****************************************************************************/
3745 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
3746 uint32_t offset, uint32_t len, int timeout,
3747 enum brl_type lock_type)
3749 NTSTATUS status;
3751 status = cli_locktype(cli, fnum, offset, len, timeout,
3752 (lock_type == READ_LOCK? 1 : 0));
3753 return status;
3756 /****************************************************************************
3757 Unlock a file.
3758 ****************************************************************************/
3760 struct cli_unlock_state {
3761 struct smb1_lock_element lck;
3764 static void cli_unlock_done(struct tevent_req *subreq);
3766 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3767 struct tevent_context *ev,
3768 struct cli_state *cli,
3769 uint16_t fnum,
3770 uint64_t offset,
3771 uint64_t len)
3774 struct tevent_req *req = NULL, *subreq = NULL;
3775 struct cli_unlock_state *state = NULL;
3777 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3778 if (req == NULL) {
3779 return NULL;
3781 state->lck = (struct smb1_lock_element) {
3782 .pid = cli_getpid(cli),
3783 .offset = offset,
3784 .length = len,
3787 subreq = cli_lockingx_send(
3788 state, /* mem_ctx */
3789 ev, /* tevent_context */
3790 cli, /* cli */
3791 fnum, /* fnum */
3792 0, /* typeoflock */
3793 0, /* newoplocklevel */
3794 0, /* timeout */
3795 1, /* num_unlocks */
3796 &state->lck, /* unlocks */
3797 0, /* num_locks */
3798 NULL); /* locks */
3799 if (tevent_req_nomem(subreq, req)) {
3800 return tevent_req_post(req, ev);
3802 tevent_req_set_callback(subreq, cli_unlock_done, req);
3803 return req;
3806 static void cli_unlock_done(struct tevent_req *subreq)
3808 NTSTATUS status = cli_lockingx_recv(subreq);
3809 tevent_req_simple_finish_ntstatus(subreq, status);
3812 NTSTATUS cli_unlock_recv(struct tevent_req *req)
3814 return tevent_req_simple_recv_ntstatus(req);
3817 NTSTATUS cli_unlock(struct cli_state *cli,
3818 uint16_t fnum,
3819 uint32_t offset,
3820 uint32_t len)
3822 TALLOC_CTX *frame = talloc_stackframe();
3823 struct tevent_context *ev;
3824 struct tevent_req *req;
3825 NTSTATUS status = NT_STATUS_OK;
3827 if (smbXcli_conn_has_async_calls(cli->conn)) {
3829 * Can't use sync call while an async call is in flight
3831 status = NT_STATUS_INVALID_PARAMETER;
3832 goto fail;
3835 ev = samba_tevent_context_init(frame);
3836 if (ev == NULL) {
3837 status = NT_STATUS_NO_MEMORY;
3838 goto fail;
3841 req = cli_unlock_send(frame, ev, cli,
3842 fnum, offset, len);
3843 if (req == NULL) {
3844 status = NT_STATUS_NO_MEMORY;
3845 goto fail;
3848 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3849 goto fail;
3852 status = cli_unlock_recv(req);
3854 fail:
3855 TALLOC_FREE(frame);
3856 return status;
3859 /****************************************************************************
3860 Get/unlock a POSIX lock on a file - internal function.
3861 ****************************************************************************/
3863 struct posix_lock_state {
3864 uint16_t setup;
3865 uint8_t param[4];
3866 uint8_t data[POSIX_LOCK_DATA_SIZE];
3869 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3871 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3872 NULL, 0, NULL, NULL, 0, NULL);
3873 tevent_req_simple_finish_ntstatus(subreq, status);
3876 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3877 struct tevent_context *ev,
3878 struct cli_state *cli,
3879 uint16_t fnum,
3880 uint64_t offset,
3881 uint64_t len,
3882 bool wait_lock,
3883 enum brl_type lock_type)
3885 struct tevent_req *req = NULL, *subreq = NULL;
3886 struct posix_lock_state *state = NULL;
3888 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3889 if (req == NULL) {
3890 return NULL;
3893 /* Setup setup word. */
3894 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3896 /* Setup param array. */
3897 SSVAL(&state->param, 0, fnum);
3898 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3900 /* Setup data array. */
3901 switch (lock_type) {
3902 case READ_LOCK:
3903 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3904 POSIX_LOCK_TYPE_READ);
3905 break;
3906 case WRITE_LOCK:
3907 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3908 POSIX_LOCK_TYPE_WRITE);
3909 break;
3910 case UNLOCK_LOCK:
3911 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3912 POSIX_LOCK_TYPE_UNLOCK);
3913 break;
3914 default:
3915 return NULL;
3918 if (wait_lock) {
3919 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3920 POSIX_LOCK_FLAG_WAIT);
3921 } else {
3922 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3923 POSIX_LOCK_FLAG_NOWAIT);
3926 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3927 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3928 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3930 subreq = cli_trans_send(state, /* mem ctx. */
3931 ev, /* event ctx. */
3932 cli, /* cli_state. */
3933 0, /* additional_flags2 */
3934 SMBtrans2, /* cmd. */
3935 NULL, /* pipe name. */
3936 -1, /* fid. */
3937 0, /* function. */
3938 0, /* flags. */
3939 &state->setup, /* setup. */
3940 1, /* num setup uint16_t words. */
3941 0, /* max returned setup. */
3942 state->param, /* param. */
3943 4, /* num param. */
3944 2, /* max returned param. */
3945 state->data, /* data. */
3946 POSIX_LOCK_DATA_SIZE, /* num data. */
3947 0); /* max returned data. */
3949 if (tevent_req_nomem(subreq, req)) {
3950 return tevent_req_post(req, ev);
3952 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3953 return req;
3956 /****************************************************************************
3957 POSIX Lock a file.
3958 ****************************************************************************/
3960 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3961 struct tevent_context *ev,
3962 struct cli_state *cli,
3963 uint16_t fnum,
3964 uint64_t offset,
3965 uint64_t len,
3966 bool wait_lock,
3967 enum brl_type lock_type)
3969 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3970 wait_lock, lock_type);
3973 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3975 return tevent_req_simple_recv_ntstatus(req);
3978 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3979 uint64_t offset, uint64_t len,
3980 bool wait_lock, enum brl_type lock_type)
3982 TALLOC_CTX *frame = talloc_stackframe();
3983 struct tevent_context *ev = NULL;
3984 struct tevent_req *req = NULL;
3985 NTSTATUS status = NT_STATUS_OK;
3987 if (smbXcli_conn_has_async_calls(cli->conn)) {
3989 * Can't use sync call while an async call is in flight
3991 status = NT_STATUS_INVALID_PARAMETER;
3992 goto fail;
3995 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3996 status = NT_STATUS_INVALID_PARAMETER;
3997 goto fail;
4000 ev = samba_tevent_context_init(frame);
4001 if (ev == NULL) {
4002 status = NT_STATUS_NO_MEMORY;
4003 goto fail;
4006 req = cli_posix_lock_send(frame,
4008 cli,
4009 fnum,
4010 offset,
4011 len,
4012 wait_lock,
4013 lock_type);
4014 if (req == NULL) {
4015 status = NT_STATUS_NO_MEMORY;
4016 goto fail;
4019 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4020 goto fail;
4023 status = cli_posix_lock_recv(req);
4025 fail:
4026 TALLOC_FREE(frame);
4027 return status;
4030 /****************************************************************************
4031 POSIX Unlock a file.
4032 ****************************************************************************/
4034 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
4035 struct tevent_context *ev,
4036 struct cli_state *cli,
4037 uint16_t fnum,
4038 uint64_t offset,
4039 uint64_t len)
4041 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4042 false, UNLOCK_LOCK);
4045 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
4047 return tevent_req_simple_recv_ntstatus(req);
4050 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
4052 TALLOC_CTX *frame = talloc_stackframe();
4053 struct tevent_context *ev = NULL;
4054 struct tevent_req *req = NULL;
4055 NTSTATUS status = NT_STATUS_OK;
4057 if (smbXcli_conn_has_async_calls(cli->conn)) {
4059 * Can't use sync call while an async call is in flight
4061 status = NT_STATUS_INVALID_PARAMETER;
4062 goto fail;
4065 ev = samba_tevent_context_init(frame);
4066 if (ev == NULL) {
4067 status = NT_STATUS_NO_MEMORY;
4068 goto fail;
4071 req = cli_posix_unlock_send(frame,
4073 cli,
4074 fnum,
4075 offset,
4076 len);
4077 if (req == NULL) {
4078 status = NT_STATUS_NO_MEMORY;
4079 goto fail;
4082 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4083 goto fail;
4086 status = cli_posix_unlock_recv(req);
4088 fail:
4089 TALLOC_FREE(frame);
4090 return status;
4093 /****************************************************************************
4094 Do a SMBgetattrE call.
4095 ****************************************************************************/
4097 static void cli_getattrE_done(struct tevent_req *subreq);
4099 struct cli_getattrE_state {
4100 uint16_t vwv[1];
4101 int zone_offset;
4102 uint32_t attr;
4103 off_t size;
4104 time_t change_time;
4105 time_t access_time;
4106 time_t write_time;
4109 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
4110 struct tevent_context *ev,
4111 struct cli_state *cli,
4112 uint16_t fnum)
4114 struct tevent_req *req = NULL, *subreq = NULL;
4115 struct cli_getattrE_state *state = NULL;
4116 uint8_t additional_flags = 0;
4118 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
4119 if (req == NULL) {
4120 return NULL;
4123 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4124 SSVAL(state->vwv+0,0,fnum);
4126 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
4127 1, state->vwv, 0, NULL);
4128 if (tevent_req_nomem(subreq, req)) {
4129 return tevent_req_post(req, ev);
4131 tevent_req_set_callback(subreq, cli_getattrE_done, req);
4132 return req;
4135 static void cli_getattrE_done(struct tevent_req *subreq)
4137 struct tevent_req *req = tevent_req_callback_data(
4138 subreq, struct tevent_req);
4139 struct cli_getattrE_state *state = tevent_req_data(
4140 req, struct cli_getattrE_state);
4141 uint8_t wct;
4142 uint16_t *vwv = NULL;
4143 NTSTATUS status;
4145 status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
4146 NULL, NULL);
4147 TALLOC_FREE(subreq);
4148 if (tevent_req_nterror(req, status)) {
4149 return;
4152 state->size = (off_t)IVAL(vwv+6,0);
4153 state->attr = SVAL(vwv+10,0);
4154 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
4155 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
4156 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
4158 tevent_req_done(req);
4161 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
4162 uint32_t *pattr,
4163 off_t *size,
4164 time_t *change_time,
4165 time_t *access_time,
4166 time_t *write_time)
4168 struct cli_getattrE_state *state = tevent_req_data(
4169 req, struct cli_getattrE_state);
4170 NTSTATUS status;
4172 if (tevent_req_is_nterror(req, &status)) {
4173 return status;
4175 if (pattr) {
4176 *pattr = state->attr;
4178 if (size) {
4179 *size = state->size;
4181 if (change_time) {
4182 *change_time = state->change_time;
4184 if (access_time) {
4185 *access_time = state->access_time;
4187 if (write_time) {
4188 *write_time = state->write_time;
4190 return NT_STATUS_OK;
4193 /****************************************************************************
4194 Do a SMBgetatr call
4195 ****************************************************************************/
4197 static void cli_getatr_done(struct tevent_req *subreq);
4199 struct cli_getatr_state {
4200 int zone_offset;
4201 uint32_t attr;
4202 off_t size;
4203 time_t write_time;
4206 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
4207 struct tevent_context *ev,
4208 struct cli_state *cli,
4209 const char *fname)
4211 struct tevent_req *req = NULL, *subreq = NULL;
4212 struct cli_getatr_state *state = NULL;
4213 uint8_t additional_flags = 0;
4214 uint16_t additional_flags2 = 0;
4215 uint8_t *bytes = NULL;
4217 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
4218 if (req == NULL) {
4219 return NULL;
4222 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4224 bytes = talloc_array(state, uint8_t, 1);
4225 if (tevent_req_nomem(bytes, req)) {
4226 return tevent_req_post(req, ev);
4228 bytes[0] = 4;
4229 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4230 strlen(fname)+1, NULL);
4232 if (tevent_req_nomem(bytes, req)) {
4233 return tevent_req_post(req, ev);
4236 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4237 additional_flags2 = FLAGS2_REPARSE_PATH;
4240 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
4241 additional_flags2,
4242 0, NULL, talloc_get_size(bytes), bytes);
4243 if (tevent_req_nomem(subreq, req)) {
4244 return tevent_req_post(req, ev);
4246 tevent_req_set_callback(subreq, cli_getatr_done, req);
4247 return req;
4250 static void cli_getatr_done(struct tevent_req *subreq)
4252 struct tevent_req *req = tevent_req_callback_data(
4253 subreq, struct tevent_req);
4254 struct cli_getatr_state *state = tevent_req_data(
4255 req, struct cli_getatr_state);
4256 uint8_t wct;
4257 uint16_t *vwv = NULL;
4258 NTSTATUS status;
4260 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4261 NULL);
4262 TALLOC_FREE(subreq);
4263 if (tevent_req_nterror(req, status)) {
4264 return;
4267 state->attr = SVAL(vwv+0,0);
4268 state->size = (off_t)IVAL(vwv+3,0);
4269 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
4271 tevent_req_done(req);
4274 NTSTATUS cli_getatr_recv(struct tevent_req *req,
4275 uint32_t *pattr,
4276 off_t *size,
4277 time_t *write_time)
4279 struct cli_getatr_state *state = tevent_req_data(
4280 req, struct cli_getatr_state);
4281 NTSTATUS status;
4283 if (tevent_req_is_nterror(req, &status)) {
4284 return status;
4286 if (pattr) {
4287 *pattr = state->attr;
4289 if (size) {
4290 *size = state->size;
4292 if (write_time) {
4293 *write_time = state->write_time;
4295 return NT_STATUS_OK;
4298 NTSTATUS cli_getatr(struct cli_state *cli,
4299 const char *fname,
4300 uint32_t *pattr,
4301 off_t *size,
4302 time_t *write_time)
4304 TALLOC_CTX *frame = NULL;
4305 struct tevent_context *ev = NULL;
4306 struct tevent_req *req = NULL;
4307 NTSTATUS status = NT_STATUS_OK;
4309 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4310 return cli_smb2_getatr(cli,
4311 fname,
4312 pattr,
4313 size,
4314 write_time);
4317 frame = talloc_stackframe();
4319 if (smbXcli_conn_has_async_calls(cli->conn)) {
4321 * Can't use sync call while an async call is in flight
4323 status = NT_STATUS_INVALID_PARAMETER;
4324 goto fail;
4327 ev = samba_tevent_context_init(frame);
4328 if (ev == NULL) {
4329 status = NT_STATUS_NO_MEMORY;
4330 goto fail;
4333 req = cli_getatr_send(frame, ev, cli, fname);
4334 if (req == NULL) {
4335 status = NT_STATUS_NO_MEMORY;
4336 goto fail;
4339 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4340 goto fail;
4343 status = cli_getatr_recv(req,
4344 pattr,
4345 size,
4346 write_time);
4348 fail:
4349 TALLOC_FREE(frame);
4350 return status;
4353 /****************************************************************************
4354 Do a SMBsetattrE call.
4355 ****************************************************************************/
4357 static void cli_setattrE_done(struct tevent_req *subreq);
4359 struct cli_setattrE_state {
4360 uint16_t vwv[7];
4363 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
4364 struct tevent_context *ev,
4365 struct cli_state *cli,
4366 uint16_t fnum,
4367 time_t change_time,
4368 time_t access_time,
4369 time_t write_time)
4371 struct tevent_req *req = NULL, *subreq = NULL;
4372 struct cli_setattrE_state *state = NULL;
4373 uint8_t additional_flags = 0;
4375 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
4376 if (req == NULL) {
4377 return NULL;
4380 SSVAL(state->vwv+0, 0, fnum);
4381 push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
4382 smb1cli_conn_server_time_zone(cli->conn));
4383 push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
4384 smb1cli_conn_server_time_zone(cli->conn));
4385 push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
4386 smb1cli_conn_server_time_zone(cli->conn));
4388 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
4389 7, state->vwv, 0, NULL);
4390 if (tevent_req_nomem(subreq, req)) {
4391 return tevent_req_post(req, ev);
4393 tevent_req_set_callback(subreq, cli_setattrE_done, req);
4394 return req;
4397 static void cli_setattrE_done(struct tevent_req *subreq)
4399 struct tevent_req *req = tevent_req_callback_data(
4400 subreq, struct tevent_req);
4401 NTSTATUS status;
4403 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4404 TALLOC_FREE(subreq);
4405 if (tevent_req_nterror(req, status)) {
4406 return;
4408 tevent_req_done(req);
4411 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4413 return tevent_req_simple_recv_ntstatus(req);
4416 NTSTATUS cli_setattrE(struct cli_state *cli,
4417 uint16_t fnum,
4418 time_t change_time,
4419 time_t access_time,
4420 time_t write_time)
4422 TALLOC_CTX *frame = NULL;
4423 struct tevent_context *ev = NULL;
4424 struct tevent_req *req = NULL;
4425 NTSTATUS status = NT_STATUS_OK;
4427 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4428 return cli_smb2_setattrE(cli,
4429 fnum,
4430 change_time,
4431 access_time,
4432 write_time);
4435 frame = talloc_stackframe();
4437 if (smbXcli_conn_has_async_calls(cli->conn)) {
4439 * Can't use sync call while an async call is in flight
4441 status = NT_STATUS_INVALID_PARAMETER;
4442 goto fail;
4445 ev = samba_tevent_context_init(frame);
4446 if (ev == NULL) {
4447 status = NT_STATUS_NO_MEMORY;
4448 goto fail;
4451 req = cli_setattrE_send(frame, ev,
4452 cli,
4453 fnum,
4454 change_time,
4455 access_time,
4456 write_time);
4458 if (req == NULL) {
4459 status = NT_STATUS_NO_MEMORY;
4460 goto fail;
4463 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4464 goto fail;
4467 status = cli_setattrE_recv(req);
4469 fail:
4470 TALLOC_FREE(frame);
4471 return status;
4474 /****************************************************************************
4475 Do a SMBsetatr call.
4476 ****************************************************************************/
4478 static void cli_setatr_done(struct tevent_req *subreq);
4480 struct cli_setatr_state {
4481 uint16_t vwv[8];
4484 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
4485 struct tevent_context *ev,
4486 struct cli_state *cli,
4487 const char *fname,
4488 uint32_t attr,
4489 time_t mtime)
4491 struct tevent_req *req = NULL, *subreq = NULL;
4492 struct cli_setatr_state *state = NULL;
4493 uint8_t additional_flags = 0;
4494 uint16_t additional_flags2 = 0;
4495 uint8_t *bytes = NULL;
4497 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
4498 if (req == NULL) {
4499 return NULL;
4502 if (attr & 0xFFFF0000) {
4504 * Don't allow attributes greater than
4505 * 16-bits for a 16-bit protocol value.
4507 if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
4508 return tevent_req_post(req, ev);
4512 SSVAL(state->vwv+0, 0, attr);
4513 push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
4515 bytes = talloc_array(state, uint8_t, 1);
4516 if (tevent_req_nomem(bytes, req)) {
4517 return tevent_req_post(req, ev);
4519 bytes[0] = 4;
4520 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4521 strlen(fname)+1, NULL);
4522 if (tevent_req_nomem(bytes, req)) {
4523 return tevent_req_post(req, ev);
4525 bytes = talloc_realloc(state, bytes, uint8_t,
4526 talloc_get_size(bytes)+1);
4527 if (tevent_req_nomem(bytes, req)) {
4528 return tevent_req_post(req, ev);
4531 bytes[talloc_get_size(bytes)-1] = 4;
4532 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
4533 1, NULL);
4534 if (tevent_req_nomem(bytes, req)) {
4535 return tevent_req_post(req, ev);
4538 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4539 additional_flags2 = FLAGS2_REPARSE_PATH;
4542 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
4543 additional_flags2,
4544 8, state->vwv, talloc_get_size(bytes), bytes);
4545 if (tevent_req_nomem(subreq, req)) {
4546 return tevent_req_post(req, ev);
4548 tevent_req_set_callback(subreq, cli_setatr_done, req);
4549 return req;
4552 static void cli_setatr_done(struct tevent_req *subreq)
4554 struct tevent_req *req = tevent_req_callback_data(
4555 subreq, struct tevent_req);
4556 NTSTATUS status;
4558 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4559 TALLOC_FREE(subreq);
4560 if (tevent_req_nterror(req, status)) {
4561 return;
4563 tevent_req_done(req);
4566 NTSTATUS cli_setatr_recv(struct tevent_req *req)
4568 return tevent_req_simple_recv_ntstatus(req);
4571 NTSTATUS cli_setatr(struct cli_state *cli,
4572 const char *fname,
4573 uint32_t attr,
4574 time_t mtime)
4576 TALLOC_CTX *frame = NULL;
4577 struct tevent_context *ev = NULL;
4578 struct tevent_req *req = NULL;
4579 NTSTATUS status = NT_STATUS_OK;
4581 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4582 return cli_smb2_setatr(cli,
4583 fname,
4584 attr,
4585 mtime);
4588 frame = talloc_stackframe();
4590 if (smbXcli_conn_has_async_calls(cli->conn)) {
4592 * Can't use sync call while an async call is in flight
4594 status = NT_STATUS_INVALID_PARAMETER;
4595 goto fail;
4598 ev = samba_tevent_context_init(frame);
4599 if (ev == NULL) {
4600 status = NT_STATUS_NO_MEMORY;
4601 goto fail;
4604 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
4605 if (req == NULL) {
4606 status = NT_STATUS_NO_MEMORY;
4607 goto fail;
4610 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4611 goto fail;
4614 status = cli_setatr_recv(req);
4616 fail:
4617 TALLOC_FREE(frame);
4618 return status;
4621 /****************************************************************************
4622 Check for existence of a dir.
4623 ****************************************************************************/
4625 static void cli_chkpath_done(struct tevent_req *subreq);
4626 static void cli_chkpath_done2(struct tevent_req *subreq);
4628 struct cli_chkpath_state {
4629 int dummy;
4632 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
4633 struct tevent_context *ev,
4634 struct cli_state *cli,
4635 const char *fname)
4637 struct tevent_req *req = NULL, *subreq = NULL;
4638 struct cli_chkpath_state *state = NULL;
4639 uint8_t additional_flags = 0;
4640 uint16_t additional_flags2 = 0;
4641 uint8_t *bytes = NULL;
4643 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
4644 if (req == NULL) {
4645 return NULL;
4648 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4649 subreq = cli_smb2_chkpath_send(state, ev, cli, fname);
4650 if (tevent_req_nomem(subreq, req)) {
4651 return tevent_req_post(req, ev);
4653 tevent_req_set_callback(subreq, cli_chkpath_done2, req);
4654 return req;
4657 bytes = talloc_array(state, uint8_t, 1);
4658 if (tevent_req_nomem(bytes, req)) {
4659 return tevent_req_post(req, ev);
4661 bytes[0] = 4;
4662 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4663 strlen(fname)+1, NULL);
4665 if (tevent_req_nomem(bytes, req)) {
4666 return tevent_req_post(req, ev);
4669 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4670 additional_flags2 = FLAGS2_REPARSE_PATH;
4673 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
4674 additional_flags2,
4675 0, NULL, talloc_get_size(bytes), bytes);
4676 if (tevent_req_nomem(subreq, req)) {
4677 return tevent_req_post(req, ev);
4679 tevent_req_set_callback(subreq, cli_chkpath_done, req);
4680 return req;
4683 static void cli_chkpath_done(struct tevent_req *subreq)
4685 struct tevent_req *req = tevent_req_callback_data(
4686 subreq, struct tevent_req);
4687 NTSTATUS status;
4689 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4690 TALLOC_FREE(subreq);
4691 if (tevent_req_nterror(req, status)) {
4692 return;
4694 tevent_req_done(req);
4697 static void cli_chkpath_done2(struct tevent_req *subreq)
4699 NTSTATUS status = cli_smb2_chkpath_recv(subreq);
4700 tevent_req_simple_finish_ntstatus(subreq, status);
4703 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
4705 return tevent_req_simple_recv_ntstatus(req);
4708 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
4710 TALLOC_CTX *frame = NULL;
4711 struct tevent_context *ev = NULL;
4712 struct tevent_req *req = NULL;
4713 char *path2 = NULL;
4714 NTSTATUS status = NT_STATUS_OK;
4716 frame = talloc_stackframe();
4718 if (smbXcli_conn_has_async_calls(cli->conn)) {
4720 * Can't use sync call while an async call is in flight
4722 status = NT_STATUS_INVALID_PARAMETER;
4723 goto fail;
4726 path2 = talloc_strdup(frame, path);
4727 if (!path2) {
4728 status = NT_STATUS_NO_MEMORY;
4729 goto fail;
4731 trim_char(path2,'\0','\\');
4732 if (!*path2) {
4733 path2 = talloc_strdup(frame, "\\");
4734 if (!path2) {
4735 status = NT_STATUS_NO_MEMORY;
4736 goto fail;
4740 ev = samba_tevent_context_init(frame);
4741 if (ev == NULL) {
4742 status = NT_STATUS_NO_MEMORY;
4743 goto fail;
4746 req = cli_chkpath_send(frame, ev, cli, path2);
4747 if (req == NULL) {
4748 status = NT_STATUS_NO_MEMORY;
4749 goto fail;
4752 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4753 goto fail;
4756 status = cli_chkpath_recv(req);
4757 cli->raw_status = status; /* cli_smb2_chkpath_recv doesn't set this */
4759 fail:
4760 TALLOC_FREE(frame);
4761 return status;
4764 /****************************************************************************
4765 Query disk space.
4766 ****************************************************************************/
4768 static void cli_dskattr_done(struct tevent_req *subreq);
4770 struct cli_dskattr_state {
4771 int bsize;
4772 int total;
4773 int avail;
4776 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
4777 struct tevent_context *ev,
4778 struct cli_state *cli)
4780 struct tevent_req *req = NULL, *subreq = NULL;
4781 struct cli_dskattr_state *state = NULL;
4782 uint8_t additional_flags = 0;
4784 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
4785 if (req == NULL) {
4786 return NULL;
4789 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
4790 0, NULL, 0, NULL);
4791 if (tevent_req_nomem(subreq, req)) {
4792 return tevent_req_post(req, ev);
4794 tevent_req_set_callback(subreq, cli_dskattr_done, req);
4795 return req;
4798 static void cli_dskattr_done(struct tevent_req *subreq)
4800 struct tevent_req *req = tevent_req_callback_data(
4801 subreq, struct tevent_req);
4802 struct cli_dskattr_state *state = tevent_req_data(
4803 req, struct cli_dskattr_state);
4804 uint8_t wct;
4805 uint16_t *vwv = NULL;
4806 NTSTATUS status;
4808 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4809 NULL);
4810 TALLOC_FREE(subreq);
4811 if (tevent_req_nterror(req, status)) {
4812 return;
4814 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
4815 state->total = SVAL(vwv+0, 0);
4816 state->avail = SVAL(vwv+3, 0);
4817 tevent_req_done(req);
4820 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
4822 struct cli_dskattr_state *state = tevent_req_data(
4823 req, struct cli_dskattr_state);
4824 NTSTATUS status;
4826 if (tevent_req_is_nterror(req, &status)) {
4827 return status;
4829 *bsize = state->bsize;
4830 *total = state->total;
4831 *avail = state->avail;
4832 return NT_STATUS_OK;
4835 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
4837 TALLOC_CTX *frame = NULL;
4838 struct tevent_context *ev = NULL;
4839 struct tevent_req *req = NULL;
4840 NTSTATUS status = NT_STATUS_OK;
4842 frame = talloc_stackframe();
4844 if (smbXcli_conn_has_async_calls(cli->conn)) {
4846 * Can't use sync call while an async call is in flight
4848 status = NT_STATUS_INVALID_PARAMETER;
4849 goto fail;
4852 ev = samba_tevent_context_init(frame);
4853 if (ev == NULL) {
4854 status = NT_STATUS_NO_MEMORY;
4855 goto fail;
4858 req = cli_dskattr_send(frame, ev, cli);
4859 if (req == NULL) {
4860 status = NT_STATUS_NO_MEMORY;
4861 goto fail;
4864 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4865 goto fail;
4868 status = cli_dskattr_recv(req, bsize, total, avail);
4870 fail:
4871 TALLOC_FREE(frame);
4872 return status;
4875 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
4876 uint64_t *total, uint64_t *avail)
4878 uint64_t sectors_per_block;
4879 uint64_t bytes_per_sector;
4880 int old_bsize = 0, old_total = 0, old_avail = 0;
4881 NTSTATUS status;
4883 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4884 return cli_smb2_dskattr(cli, path, bsize, total, avail);
4888 * Try the trans2 disk full size info call first.
4889 * We already use this in SMBC_fstatvfs_ctx().
4890 * Ignore 'actual_available_units' as we only
4891 * care about the quota for the caller.
4894 status = cli_get_fs_full_size_info(cli,
4895 total,
4896 avail,
4897 NULL,
4898 &sectors_per_block,
4899 &bytes_per_sector);
4901 /* Try and cope will all varients of "we don't do this call"
4902 and fall back to cli_dskattr. */
4904 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
4905 NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
4906 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
4907 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
4908 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
4909 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
4910 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
4911 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
4912 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
4913 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
4914 goto try_dskattr;
4917 if (!NT_STATUS_IS_OK(status)) {
4918 return status;
4921 if (bsize) {
4922 *bsize = sectors_per_block *
4923 bytes_per_sector;
4926 return NT_STATUS_OK;
4928 try_dskattr:
4930 /* Old SMB1 core protocol fallback. */
4931 status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
4932 if (!NT_STATUS_IS_OK(status)) {
4933 return status;
4935 if (bsize) {
4936 *bsize = (uint64_t)old_bsize;
4938 if (total) {
4939 *total = (uint64_t)old_total;
4941 if (avail) {
4942 *avail = (uint64_t)old_avail;
4944 return NT_STATUS_OK;
4947 /****************************************************************************
4948 Create and open a temporary file.
4949 ****************************************************************************/
4951 static void cli_ctemp_done(struct tevent_req *subreq);
4953 struct ctemp_state {
4954 uint16_t vwv[3];
4955 char *ret_path;
4956 uint16_t fnum;
4959 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4960 struct tevent_context *ev,
4961 struct cli_state *cli,
4962 const char *path)
4964 struct tevent_req *req = NULL, *subreq = NULL;
4965 struct ctemp_state *state = NULL;
4966 uint8_t additional_flags = 0;
4967 uint16_t additional_flags2 = 0;
4968 uint8_t *bytes = NULL;
4970 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4971 if (req == NULL) {
4972 return NULL;
4975 SSVAL(state->vwv,0,0);
4976 SIVALS(state->vwv+1,0,-1);
4978 bytes = talloc_array(state, uint8_t, 1);
4979 if (tevent_req_nomem(bytes, req)) {
4980 return tevent_req_post(req, ev);
4982 bytes[0] = 4;
4983 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
4984 strlen(path)+1, NULL);
4985 if (tevent_req_nomem(bytes, req)) {
4986 return tevent_req_post(req, ev);
4989 if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
4990 additional_flags2 = FLAGS2_REPARSE_PATH;
4993 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4994 additional_flags2,
4995 3, state->vwv, talloc_get_size(bytes), bytes);
4996 if (tevent_req_nomem(subreq, req)) {
4997 return tevent_req_post(req, ev);
4999 tevent_req_set_callback(subreq, cli_ctemp_done, req);
5000 return req;
5003 static void cli_ctemp_done(struct tevent_req *subreq)
5005 struct tevent_req *req = tevent_req_callback_data(
5006 subreq, struct tevent_req);
5007 struct ctemp_state *state = tevent_req_data(
5008 req, struct ctemp_state);
5009 NTSTATUS status;
5010 uint8_t wcnt;
5011 uint16_t *vwv;
5012 uint32_t num_bytes = 0;
5013 uint8_t *bytes = NULL;
5015 status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
5016 &num_bytes, &bytes);
5017 TALLOC_FREE(subreq);
5018 if (tevent_req_nterror(req, status)) {
5019 return;
5022 state->fnum = SVAL(vwv+0, 0);
5024 /* From W2K3, the result is just the ASCII name */
5025 if (num_bytes < 2) {
5026 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
5027 return;
5030 if (pull_string_talloc(state,
5031 NULL,
5033 &state->ret_path,
5034 bytes,
5035 num_bytes,
5036 STR_ASCII) == 0) {
5037 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5038 return;
5040 tevent_req_done(req);
5043 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
5044 TALLOC_CTX *ctx,
5045 uint16_t *pfnum,
5046 char **outfile)
5048 struct ctemp_state *state = tevent_req_data(req,
5049 struct ctemp_state);
5050 NTSTATUS status;
5052 if (tevent_req_is_nterror(req, &status)) {
5053 return status;
5055 *pfnum = state->fnum;
5056 *outfile = talloc_strdup(ctx, state->ret_path);
5057 if (!*outfile) {
5058 return NT_STATUS_NO_MEMORY;
5060 return NT_STATUS_OK;
5063 NTSTATUS cli_ctemp(struct cli_state *cli,
5064 TALLOC_CTX *ctx,
5065 const char *path,
5066 uint16_t *pfnum,
5067 char **out_path)
5069 TALLOC_CTX *frame = talloc_stackframe();
5070 struct tevent_context *ev;
5071 struct tevent_req *req;
5072 NTSTATUS status = NT_STATUS_OK;
5074 if (smbXcli_conn_has_async_calls(cli->conn)) {
5076 * Can't use sync call while an async call is in flight
5078 status = NT_STATUS_INVALID_PARAMETER;
5079 goto fail;
5082 ev = samba_tevent_context_init(frame);
5083 if (ev == NULL) {
5084 status = NT_STATUS_NO_MEMORY;
5085 goto fail;
5088 req = cli_ctemp_send(frame, ev, cli, path);
5089 if (req == NULL) {
5090 status = NT_STATUS_NO_MEMORY;
5091 goto fail;
5094 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5095 goto fail;
5098 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
5100 fail:
5101 TALLOC_FREE(frame);
5102 return status;
5106 send a raw ioctl - used by the torture code
5108 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
5110 uint16_t vwv[3];
5111 NTSTATUS status;
5113 SSVAL(vwv+0, 0, fnum);
5114 SSVAL(vwv+1, 0, code>>16);
5115 SSVAL(vwv+2, 0, (code&0xFFFF));
5117 status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
5118 NULL, 0, NULL, NULL, NULL, NULL);
5119 if (!NT_STATUS_IS_OK(status)) {
5120 return status;
5122 *blob = data_blob_null;
5123 return NT_STATUS_OK;
5126 /*********************************************************
5127 Set an extended attribute utility fn.
5128 *********************************************************/
5130 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
5131 uint8_t *param, unsigned int param_len,
5132 const char *ea_name,
5133 const char *ea_val, size_t ea_len)
5135 uint16_t setup[1];
5136 unsigned int data_len = 0;
5137 uint8_t *data = NULL;
5138 char *p;
5139 size_t ea_namelen = strlen(ea_name);
5140 NTSTATUS status;
5142 SSVAL(setup, 0, setup_val);
5144 if (ea_namelen == 0 && ea_len == 0) {
5145 data_len = 4;
5146 data = talloc_array(talloc_tos(),
5147 uint8_t,
5148 data_len);
5149 if (!data) {
5150 return NT_STATUS_NO_MEMORY;
5152 p = (char *)data;
5153 SIVAL(p,0,data_len);
5154 } else {
5155 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
5156 data = talloc_array(talloc_tos(),
5157 uint8_t,
5158 data_len);
5159 if (!data) {
5160 return NT_STATUS_NO_MEMORY;
5162 p = (char *)data;
5163 SIVAL(p,0,data_len);
5164 p += 4;
5165 SCVAL(p, 0, 0); /* EA flags. */
5166 SCVAL(p, 1, ea_namelen);
5167 SSVAL(p, 2, ea_len);
5168 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
5169 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
5173 * FIXME - if we want to do previous version path
5174 * processing on an EA set call we need to turn this
5175 * into calls to cli_trans_send()/cli_trans_recv()
5176 * with a temporary event context, as cli_trans_send()
5177 * have access to the additional_flags2 needed to
5178 * send @GMT- paths. JRA.
5181 status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
5182 setup, 1, 0,
5183 param, param_len, 2,
5184 data, data_len, 0,
5185 NULL,
5186 NULL, 0, NULL, /* rsetup */
5187 NULL, 0, NULL, /* rparam */
5188 NULL, 0, NULL); /* rdata */
5189 talloc_free(data);
5190 return status;
5193 /*********************************************************
5194 Set an extended attribute on a pathname.
5195 *********************************************************/
5197 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
5198 const char *ea_name, const char *ea_val,
5199 size_t ea_len)
5201 unsigned int param_len = 0;
5202 uint8_t *param;
5203 NTSTATUS status;
5204 TALLOC_CTX *frame = NULL;
5206 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5207 return cli_smb2_set_ea_path(cli,
5208 path,
5209 ea_name,
5210 ea_val,
5211 ea_len);
5214 frame = talloc_stackframe();
5216 param = talloc_array(frame, uint8_t, 6);
5217 if (!param) {
5218 status = NT_STATUS_NO_MEMORY;
5219 goto fail;
5221 SSVAL(param,0,SMB_INFO_SET_EA);
5222 SSVAL(param,2,0);
5223 SSVAL(param,4,0);
5225 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
5226 path, strlen(path)+1,
5227 NULL);
5228 param_len = talloc_get_size(param);
5230 status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
5231 ea_name, ea_val, ea_len);
5233 fail:
5235 TALLOC_FREE(frame);
5236 return status;
5239 /*********************************************************
5240 Set an extended attribute on an fnum.
5241 *********************************************************/
5243 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
5244 const char *ea_name, const char *ea_val,
5245 size_t ea_len)
5247 uint8_t param[6] = { 0, };
5249 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5250 return cli_smb2_set_ea_fnum(cli,
5251 fnum,
5252 ea_name,
5253 ea_val,
5254 ea_len);
5257 SSVAL(param,0,fnum);
5258 SSVAL(param,2,SMB_INFO_SET_EA);
5260 return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
5261 ea_name, ea_val, ea_len);
5264 /*********************************************************
5265 Get an extended attribute list utility fn.
5266 *********************************************************/
5268 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
5269 size_t rdata_len,
5270 size_t *pnum_eas, struct ea_struct **pea_list)
5272 struct ea_struct *ea_list = NULL;
5273 size_t num_eas;
5274 size_t ea_size;
5275 const uint8_t *p;
5277 if (rdata_len < 4) {
5278 return false;
5281 ea_size = (size_t)IVAL(rdata,0);
5282 if (ea_size > rdata_len) {
5283 return false;
5286 if (ea_size == 0) {
5287 /* No EA's present. */
5288 *pnum_eas = 0;
5289 *pea_list = NULL;
5290 return true;
5293 p = rdata + 4;
5294 ea_size -= 4;
5296 /* Validate the EA list and count it. */
5297 for (num_eas = 0; ea_size >= 4; num_eas++) {
5298 unsigned int ea_namelen = CVAL(p,1);
5299 unsigned int ea_valuelen = SVAL(p,2);
5300 if (ea_namelen == 0) {
5301 return false;
5303 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
5304 return false;
5306 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
5307 p += 4 + ea_namelen + 1 + ea_valuelen;
5310 if (num_eas == 0) {
5311 *pnum_eas = 0;
5312 *pea_list = NULL;
5313 return true;
5316 *pnum_eas = num_eas;
5317 if (!pea_list) {
5318 /* Caller only wants number of EA's. */
5319 return true;
5322 ea_list = talloc_array(ctx, struct ea_struct, num_eas);
5323 if (!ea_list) {
5324 return false;
5327 p = rdata + 4;
5329 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
5330 struct ea_struct *ea = &ea_list[num_eas];
5331 fstring unix_ea_name;
5332 unsigned int ea_namelen = CVAL(p,1);
5333 unsigned int ea_valuelen = SVAL(p,2);
5335 ea->flags = CVAL(p,0);
5336 unix_ea_name[0] = '\0';
5337 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
5338 ea->name = talloc_strdup(ea_list, unix_ea_name);
5339 if (!ea->name) {
5340 goto fail;
5342 /* Ensure the value is null terminated (in case it's a string). */
5343 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
5344 if (!ea->value.data) {
5345 goto fail;
5347 if (ea_valuelen) {
5348 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
5350 ea->value.data[ea_valuelen] = 0;
5351 ea->value.length--;
5352 p += 4 + ea_namelen + 1 + ea_valuelen;
5355 *pea_list = ea_list;
5356 return true;
5358 fail:
5359 TALLOC_FREE(ea_list);
5360 return false;
5363 /*********************************************************
5364 Get an extended attribute list from a pathname.
5365 *********************************************************/
5367 struct cli_get_ea_list_path_state {
5368 uint32_t num_data;
5369 uint8_t *data;
5372 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
5374 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
5375 struct tevent_context *ev,
5376 struct cli_state *cli,
5377 const char *fname)
5379 struct tevent_req *req, *subreq;
5380 struct cli_get_ea_list_path_state *state;
5382 req = tevent_req_create(mem_ctx, &state,
5383 struct cli_get_ea_list_path_state);
5384 if (req == NULL) {
5385 return NULL;
5387 subreq = cli_qpathinfo_send(state, ev, cli, fname,
5388 SMB_INFO_QUERY_ALL_EAS, 4,
5389 CLI_BUFFER_SIZE);
5390 if (tevent_req_nomem(subreq, req)) {
5391 return tevent_req_post(req, ev);
5393 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
5394 return req;
5397 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
5399 struct tevent_req *req = tevent_req_callback_data(
5400 subreq, struct tevent_req);
5401 struct cli_get_ea_list_path_state *state = tevent_req_data(
5402 req, struct cli_get_ea_list_path_state);
5403 NTSTATUS status;
5405 status = cli_qpathinfo_recv(subreq, state, &state->data,
5406 &state->num_data);
5407 TALLOC_FREE(subreq);
5408 if (tevent_req_nterror(req, status)) {
5409 return;
5411 tevent_req_done(req);
5414 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5415 size_t *pnum_eas, struct ea_struct **peas)
5417 struct cli_get_ea_list_path_state *state = tevent_req_data(
5418 req, struct cli_get_ea_list_path_state);
5419 NTSTATUS status;
5421 if (tevent_req_is_nterror(req, &status)) {
5422 return status;
5424 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
5425 pnum_eas, peas)) {
5426 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5428 return NT_STATUS_OK;
5431 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
5432 TALLOC_CTX *ctx,
5433 size_t *pnum_eas,
5434 struct ea_struct **pea_list)
5436 TALLOC_CTX *frame = NULL;
5437 struct tevent_context *ev = NULL;
5438 struct tevent_req *req = NULL;
5439 NTSTATUS status = NT_STATUS_NO_MEMORY;
5441 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5442 return cli_smb2_get_ea_list_path(cli,
5443 path,
5444 ctx,
5445 pnum_eas,
5446 pea_list);
5449 frame = talloc_stackframe();
5451 if (smbXcli_conn_has_async_calls(cli->conn)) {
5453 * Can't use sync call while an async call is in flight
5455 status = NT_STATUS_INVALID_PARAMETER;
5456 goto fail;
5458 ev = samba_tevent_context_init(frame);
5459 if (ev == NULL) {
5460 goto fail;
5462 req = cli_get_ea_list_path_send(frame, ev, cli, path);
5463 if (req == NULL) {
5464 goto fail;
5466 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5467 goto fail;
5469 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
5470 fail:
5471 TALLOC_FREE(frame);
5472 return status;
5475 /****************************************************************************
5476 Convert open "flags" arg to uint32_t on wire.
5477 ****************************************************************************/
5479 static uint32_t open_flags_to_wire(int flags)
5481 int open_mode = flags & O_ACCMODE;
5482 uint32_t ret = 0;
5484 switch (open_mode) {
5485 case O_WRONLY:
5486 ret |= SMB_O_WRONLY;
5487 break;
5488 case O_RDWR:
5489 ret |= SMB_O_RDWR;
5490 break;
5491 default:
5492 case O_RDONLY:
5493 ret |= SMB_O_RDONLY;
5494 break;
5497 if (flags & O_CREAT) {
5498 ret |= SMB_O_CREAT;
5500 if (flags & O_EXCL) {
5501 ret |= SMB_O_EXCL;
5503 if (flags & O_TRUNC) {
5504 ret |= SMB_O_TRUNC;
5506 #if defined(O_SYNC)
5507 if (flags & O_SYNC) {
5508 ret |= SMB_O_SYNC;
5510 #endif /* O_SYNC */
5511 if (flags & O_APPEND) {
5512 ret |= SMB_O_APPEND;
5514 #if defined(O_DIRECT)
5515 if (flags & O_DIRECT) {
5516 ret |= SMB_O_DIRECT;
5518 #endif
5519 #if defined(O_DIRECTORY)
5520 if (flags & O_DIRECTORY) {
5521 ret |= SMB_O_DIRECTORY;
5523 #endif
5524 return ret;
5527 /****************************************************************************
5528 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
5529 ****************************************************************************/
5531 struct cli_posix_open_internal_state {
5532 uint16_t setup;
5533 uint8_t *param;
5534 uint8_t data[18];
5535 uint16_t fnum; /* Out */
5538 static void cli_posix_open_internal_done(struct tevent_req *subreq);
5540 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
5541 struct tevent_context *ev,
5542 struct cli_state *cli,
5543 const char *fname,
5544 uint32_t wire_flags,
5545 mode_t mode)
5547 struct tevent_req *req = NULL, *subreq = NULL;
5548 struct cli_posix_open_internal_state *state = NULL;
5550 req = tevent_req_create(
5551 mem_ctx, &state, struct cli_posix_open_internal_state);
5552 if (req == NULL) {
5553 return NULL;
5556 /* Setup setup word. */
5557 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
5559 /* Setup param array. */
5560 state->param = talloc_zero_array(state, uint8_t, 6);
5561 if (tevent_req_nomem(state->param, req)) {
5562 return tevent_req_post(req, ev);
5564 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
5566 state->param = trans2_bytes_push_str(
5567 state->param,
5568 smbXcli_conn_use_unicode(cli->conn),
5569 fname,
5570 strlen(fname)+1,
5571 NULL);
5573 if (tevent_req_nomem(state->param, req)) {
5574 return tevent_req_post(req, ev);
5577 SIVAL(state->data,0,0); /* No oplock. */
5578 SIVAL(state->data,4,wire_flags);
5579 SIVAL(state->data,8,unix_perms_to_wire(mode));
5580 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
5581 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
5583 subreq = cli_trans_send(state, /* mem ctx. */
5584 ev, /* event ctx. */
5585 cli, /* cli_state. */
5586 0, /* additional_flags2 */
5587 SMBtrans2, /* cmd. */
5588 NULL, /* pipe name. */
5589 -1, /* fid. */
5590 0, /* function. */
5591 0, /* flags. */
5592 &state->setup, /* setup. */
5593 1, /* num setup uint16_t words. */
5594 0, /* max returned setup. */
5595 state->param, /* param. */
5596 talloc_get_size(state->param),/* num param. */
5597 2, /* max returned param. */
5598 state->data, /* data. */
5599 18, /* num data. */
5600 12); /* max returned data. */
5602 if (tevent_req_nomem(subreq, req)) {
5603 return tevent_req_post(req, ev);
5605 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
5606 return req;
5609 static void cli_posix_open_internal_done(struct tevent_req *subreq)
5611 struct tevent_req *req = tevent_req_callback_data(
5612 subreq, struct tevent_req);
5613 struct cli_posix_open_internal_state *state = tevent_req_data(
5614 req, struct cli_posix_open_internal_state);
5615 NTSTATUS status;
5616 uint8_t *data;
5617 uint32_t num_data;
5619 status = cli_trans_recv(
5620 subreq,
5621 state,
5622 NULL,
5623 NULL,
5625 NULL,
5626 NULL,
5628 NULL,
5629 &data,
5631 &num_data);
5632 TALLOC_FREE(subreq);
5633 if (tevent_req_nterror(req, status)) {
5634 return;
5636 state->fnum = SVAL(data,2);
5637 tevent_req_done(req);
5640 static NTSTATUS cli_posix_open_internal_recv(struct tevent_req *req,
5641 uint16_t *pfnum)
5643 struct cli_posix_open_internal_state *state = tevent_req_data(
5644 req, struct cli_posix_open_internal_state);
5645 NTSTATUS status;
5647 if (tevent_req_is_nterror(req, &status)) {
5648 return status;
5650 *pfnum = state->fnum;
5651 return NT_STATUS_OK;
5654 struct cli_posix_open_state {
5655 uint16_t fnum;
5658 static void cli_posix_open_done(struct tevent_req *subreq);
5660 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
5661 struct tevent_context *ev,
5662 struct cli_state *cli,
5663 const char *fname,
5664 int flags,
5665 mode_t mode)
5667 struct tevent_req *req = NULL, *subreq = NULL;
5668 struct cli_posix_open_state *state = NULL;
5669 uint32_t wire_flags;
5671 req = tevent_req_create(mem_ctx, &state,
5672 struct cli_posix_open_state);
5673 if (req == NULL) {
5674 return NULL;
5677 wire_flags = open_flags_to_wire(flags);
5679 subreq = cli_posix_open_internal_send(
5680 mem_ctx, ev, cli, fname, wire_flags, mode);
5681 if (tevent_req_nomem(subreq, req)) {
5682 return tevent_req_post(req, ev);
5684 tevent_req_set_callback(subreq, cli_posix_open_done, req);
5685 return req;
5688 static void cli_posix_open_done(struct tevent_req *subreq)
5690 struct tevent_req *req = tevent_req_callback_data(
5691 subreq, struct tevent_req);
5692 struct cli_posix_open_state *state = tevent_req_data(
5693 req, struct cli_posix_open_state);
5694 NTSTATUS status;
5696 status = cli_posix_open_internal_recv(subreq, &state->fnum);
5697 tevent_req_simple_finish_ntstatus(subreq, status);
5700 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
5702 struct cli_posix_open_state *state = tevent_req_data(
5703 req, struct cli_posix_open_state);
5704 NTSTATUS status;
5706 if (tevent_req_is_nterror(req, &status)) {
5707 return status;
5709 *pfnum = state->fnum;
5710 return NT_STATUS_OK;
5713 /****************************************************************************
5714 Open - POSIX semantics. Doesn't request oplock.
5715 ****************************************************************************/
5717 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
5718 int flags, mode_t mode, uint16_t *pfnum)
5721 TALLOC_CTX *frame = talloc_stackframe();
5722 struct tevent_context *ev = NULL;
5723 struct tevent_req *req = NULL;
5724 NTSTATUS status = NT_STATUS_NO_MEMORY;
5726 if (smbXcli_conn_has_async_calls(cli->conn)) {
5728 * Can't use sync call while an async call is in flight
5730 status = NT_STATUS_INVALID_PARAMETER;
5731 goto fail;
5733 ev = samba_tevent_context_init(frame);
5734 if (ev == NULL) {
5735 goto fail;
5737 req = cli_posix_open_send(
5738 frame, ev, cli, fname, flags, mode);
5739 if (req == NULL) {
5740 goto fail;
5742 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5743 goto fail;
5745 status = cli_posix_open_recv(req, pfnum);
5746 fail:
5747 TALLOC_FREE(frame);
5748 return status;
5751 struct cli_posix_mkdir_state {
5752 struct tevent_context *ev;
5753 struct cli_state *cli;
5756 static void cli_posix_mkdir_done(struct tevent_req *subreq);
5758 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
5759 struct tevent_context *ev,
5760 struct cli_state *cli,
5761 const char *fname,
5762 mode_t mode)
5764 struct tevent_req *req = NULL, *subreq = NULL;
5765 struct cli_posix_mkdir_state *state = NULL;
5766 uint32_t wire_flags;
5768 req = tevent_req_create(
5769 mem_ctx, &state, struct cli_posix_mkdir_state);
5770 if (req == NULL) {
5771 return NULL;
5773 state->ev = ev;
5774 state->cli = cli;
5776 wire_flags = SMB_O_CREAT | SMB_O_DIRECTORY;
5778 subreq = cli_posix_open_internal_send(
5779 mem_ctx, ev, cli, fname, wire_flags, mode);
5780 if (tevent_req_nomem(subreq, req)) {
5781 return tevent_req_post(req, ev);
5783 tevent_req_set_callback(subreq, cli_posix_mkdir_done, req);
5784 return req;
5787 static void cli_posix_mkdir_done(struct tevent_req *subreq)
5789 struct tevent_req *req = tevent_req_callback_data(
5790 subreq, struct tevent_req);
5791 NTSTATUS status;
5792 uint16_t fnum;
5794 status = cli_posix_open_internal_recv(subreq, &fnum);
5795 TALLOC_FREE(subreq);
5796 if (tevent_req_nterror(req, status)) {
5797 return;
5799 tevent_req_done(req);
5802 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
5804 return tevent_req_simple_recv_ntstatus(req);
5807 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
5809 TALLOC_CTX *frame = talloc_stackframe();
5810 struct tevent_context *ev = NULL;
5811 struct tevent_req *req = NULL;
5812 NTSTATUS status = NT_STATUS_NO_MEMORY;
5814 if (smbXcli_conn_has_async_calls(cli->conn)) {
5816 * Can't use sync call while an async call is in flight
5818 status = NT_STATUS_INVALID_PARAMETER;
5819 goto fail;
5822 ev = samba_tevent_context_init(frame);
5823 if (ev == NULL) {
5824 goto fail;
5826 req = cli_posix_mkdir_send(
5827 frame, ev, cli, fname, mode);
5828 if (req == NULL) {
5829 goto fail;
5831 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5832 goto fail;
5834 status = cli_posix_mkdir_recv(req);
5835 fail:
5836 TALLOC_FREE(frame);
5837 return status;
5840 /****************************************************************************
5841 unlink or rmdir - POSIX semantics.
5842 ****************************************************************************/
5844 struct cli_posix_unlink_internal_state {
5845 uint8_t data[2];
5848 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
5850 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
5851 struct tevent_context *ev,
5852 struct cli_state *cli,
5853 const char *fname,
5854 uint16_t level)
5856 struct tevent_req *req = NULL, *subreq = NULL;
5857 struct cli_posix_unlink_internal_state *state = NULL;
5859 req = tevent_req_create(mem_ctx, &state,
5860 struct cli_posix_unlink_internal_state);
5861 if (req == NULL) {
5862 return NULL;
5865 /* Setup data word. */
5866 SSVAL(state->data, 0, level);
5868 subreq = cli_setpathinfo_send(state, ev, cli,
5869 SMB_POSIX_PATH_UNLINK,
5870 fname,
5871 state->data, sizeof(state->data));
5872 if (tevent_req_nomem(subreq, req)) {
5873 return tevent_req_post(req, ev);
5875 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
5876 return req;
5879 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
5881 NTSTATUS status = cli_setpathinfo_recv(subreq);
5882 tevent_req_simple_finish_ntstatus(subreq, status);
5885 static NTSTATUS cli_posix_unlink_internal_recv(struct tevent_req *req)
5887 return tevent_req_simple_recv_ntstatus(req);
5890 struct cli_posix_unlink_state {
5891 uint8_t dummy;
5894 static void cli_posix_unlink_done(struct tevent_req *subreq);
5896 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
5897 struct tevent_context *ev,
5898 struct cli_state *cli,
5899 const char *fname)
5901 struct tevent_req *req = NULL, *subreq = NULL;
5902 struct cli_posix_unlink_state *state;
5904 req = tevent_req_create(
5905 mem_ctx, &state, struct cli_posix_unlink_state);
5906 if (req == NULL) {
5907 return NULL;
5909 subreq = cli_posix_unlink_internal_send(
5910 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_FILE_TARGET);
5911 if (tevent_req_nomem(subreq, req)) {
5912 return tevent_req_post(req, ev);
5914 tevent_req_set_callback(subreq, cli_posix_unlink_done, req);
5915 return req;
5918 static void cli_posix_unlink_done(struct tevent_req *subreq)
5920 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
5921 tevent_req_simple_finish_ntstatus(subreq, status);
5924 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
5926 return tevent_req_simple_recv_ntstatus(req);
5929 /****************************************************************************
5930 unlink - POSIX semantics.
5931 ****************************************************************************/
5933 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
5935 TALLOC_CTX *frame = talloc_stackframe();
5936 struct tevent_context *ev = NULL;
5937 struct tevent_req *req = NULL;
5938 NTSTATUS status = NT_STATUS_OK;
5940 if (smbXcli_conn_has_async_calls(cli->conn)) {
5942 * Can't use sync call while an async call is in flight
5944 status = NT_STATUS_INVALID_PARAMETER;
5945 goto fail;
5948 ev = samba_tevent_context_init(frame);
5949 if (ev == NULL) {
5950 status = NT_STATUS_NO_MEMORY;
5951 goto fail;
5954 req = cli_posix_unlink_send(frame,
5956 cli,
5957 fname);
5958 if (req == NULL) {
5959 status = NT_STATUS_NO_MEMORY;
5960 goto fail;
5963 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5964 goto fail;
5967 status = cli_posix_unlink_recv(req);
5969 fail:
5970 TALLOC_FREE(frame);
5971 return status;
5974 /****************************************************************************
5975 rmdir - POSIX semantics.
5976 ****************************************************************************/
5978 struct cli_posix_rmdir_state {
5979 uint8_t dummy;
5982 static void cli_posix_rmdir_done(struct tevent_req *subreq);
5984 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
5985 struct tevent_context *ev,
5986 struct cli_state *cli,
5987 const char *fname)
5989 struct tevent_req *req = NULL, *subreq = NULL;
5990 struct cli_posix_rmdir_state *state;
5992 req = tevent_req_create(mem_ctx, &state, struct cli_posix_rmdir_state);
5993 if (req == NULL) {
5994 return NULL;
5996 subreq = cli_posix_unlink_internal_send(
5997 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_DIRECTORY_TARGET);
5998 if (tevent_req_nomem(subreq, req)) {
5999 return tevent_req_post(req, ev);
6001 tevent_req_set_callback(subreq, cli_posix_rmdir_done, req);
6002 return req;
6005 static void cli_posix_rmdir_done(struct tevent_req *subreq)
6007 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6008 tevent_req_simple_finish_ntstatus(subreq, status);
6011 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
6013 return tevent_req_simple_recv_ntstatus(req);
6016 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
6018 TALLOC_CTX *frame = talloc_stackframe();
6019 struct tevent_context *ev = NULL;
6020 struct tevent_req *req = NULL;
6021 NTSTATUS status = NT_STATUS_OK;
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;
6031 ev = samba_tevent_context_init(frame);
6032 if (ev == NULL) {
6033 status = NT_STATUS_NO_MEMORY;
6034 goto fail;
6037 req = cli_posix_rmdir_send(frame,
6039 cli,
6040 fname);
6041 if (req == NULL) {
6042 status = NT_STATUS_NO_MEMORY;
6043 goto fail;
6046 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6047 goto fail;
6050 status = cli_posix_rmdir_recv(req, frame);
6052 fail:
6053 TALLOC_FREE(frame);
6054 return status;
6057 /****************************************************************************
6058 filechangenotify
6059 ****************************************************************************/
6061 struct cli_notify_state {
6062 struct tevent_req *subreq;
6063 uint8_t setup[8];
6064 uint32_t num_changes;
6065 struct notify_change *changes;
6068 static void cli_notify_done(struct tevent_req *subreq);
6069 static void cli_notify_done_smb2(struct tevent_req *subreq);
6070 static bool cli_notify_cancel(struct tevent_req *req);
6072 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
6073 struct tevent_context *ev,
6074 struct cli_state *cli, uint16_t fnum,
6075 uint32_t buffer_size,
6076 uint32_t completion_filter, bool recursive)
6078 struct tevent_req *req;
6079 struct cli_notify_state *state;
6080 unsigned old_timeout;
6082 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
6083 if (req == NULL) {
6084 return NULL;
6087 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6089 * Notifies should not time out
6091 old_timeout = cli_set_timeout(cli, 0);
6093 state->subreq = cli_smb2_notify_send(
6094 state,
6096 cli,
6097 fnum,
6098 buffer_size,
6099 completion_filter,
6100 recursive);
6102 cli_set_timeout(cli, old_timeout);
6104 if (tevent_req_nomem(state->subreq, req)) {
6105 return tevent_req_post(req, ev);
6107 tevent_req_set_callback(
6108 state->subreq, cli_notify_done_smb2, req);
6109 goto done;
6112 SIVAL(state->setup, 0, completion_filter);
6113 SSVAL(state->setup, 4, fnum);
6114 SSVAL(state->setup, 6, recursive);
6117 * Notifies should not time out
6119 old_timeout = cli_set_timeout(cli, 0);
6121 state->subreq = cli_trans_send(
6122 state, /* mem ctx. */
6123 ev, /* event ctx. */
6124 cli, /* cli_state. */
6125 0, /* additional_flags2 */
6126 SMBnttrans, /* cmd. */
6127 NULL, /* pipe name. */
6128 -1, /* fid. */
6129 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
6130 0, /* flags. */
6131 (uint16_t *)state->setup, /* setup. */
6132 4, /* num setup uint16_t words. */
6133 0, /* max returned setup. */
6134 NULL, /* param. */
6135 0, /* num param. */
6136 buffer_size, /* max returned param. */
6137 NULL, /* data. */
6138 0, /* num data. */
6139 0); /* max returned data. */
6141 cli_set_timeout(cli, old_timeout);
6143 if (tevent_req_nomem(state->subreq, req)) {
6144 return tevent_req_post(req, ev);
6146 tevent_req_set_callback(state->subreq, cli_notify_done, req);
6147 done:
6148 tevent_req_set_cancel_fn(req, cli_notify_cancel);
6149 return req;
6152 static bool cli_notify_cancel(struct tevent_req *req)
6154 struct cli_notify_state *state = tevent_req_data(
6155 req, struct cli_notify_state);
6156 bool ok;
6158 ok = tevent_req_cancel(state->subreq);
6159 return ok;
6162 static void cli_notify_done(struct tevent_req *subreq)
6164 struct tevent_req *req = tevent_req_callback_data(
6165 subreq, struct tevent_req);
6166 struct cli_notify_state *state = tevent_req_data(
6167 req, struct cli_notify_state);
6168 NTSTATUS status;
6169 uint8_t *params;
6170 uint32_t i, ofs, num_params;
6171 uint16_t flags2;
6173 status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
6174 &params, 0, &num_params, NULL, 0, NULL);
6175 TALLOC_FREE(subreq);
6176 state->subreq = NULL;
6177 if (tevent_req_nterror(req, status)) {
6178 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
6179 return;
6182 state->num_changes = 0;
6183 ofs = 0;
6185 while (num_params - ofs > 12) {
6186 uint32_t next = IVAL(params, ofs);
6187 state->num_changes += 1;
6189 if ((next == 0) || (ofs+next >= num_params)) {
6190 break;
6192 ofs += next;
6195 state->changes = talloc_array(state, struct notify_change,
6196 state->num_changes);
6197 if (tevent_req_nomem(state->changes, req)) {
6198 TALLOC_FREE(params);
6199 return;
6202 ofs = 0;
6204 for (i=0; i<state->num_changes; i++) {
6205 uint32_t next = IVAL(params, ofs);
6206 uint32_t len = IVAL(params, ofs+8);
6207 ssize_t ret;
6208 char *name;
6210 if (trans_oob(num_params, ofs + 12, len)) {
6211 TALLOC_FREE(params);
6212 tevent_req_nterror(
6213 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
6214 return;
6217 state->changes[i].action = IVAL(params, ofs+4);
6218 ret = pull_string_talloc(state->changes,
6219 (char *)params,
6220 flags2,
6221 &name,
6222 params+ofs+12,
6223 len,
6224 STR_TERMINATE|STR_UNICODE);
6225 if (ret == -1) {
6226 TALLOC_FREE(params);
6227 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
6228 return;
6230 state->changes[i].name = name;
6231 ofs += next;
6234 TALLOC_FREE(params);
6235 tevent_req_done(req);
6238 static void cli_notify_done_smb2(struct tevent_req *subreq)
6240 struct tevent_req *req = tevent_req_callback_data(
6241 subreq, struct tevent_req);
6242 struct cli_notify_state *state = tevent_req_data(
6243 req, struct cli_notify_state);
6244 NTSTATUS status;
6246 status = cli_smb2_notify_recv(
6247 subreq,
6248 state,
6249 &state->changes,
6250 &state->num_changes);
6251 TALLOC_FREE(subreq);
6252 if (tevent_req_nterror(req, status)) {
6253 return;
6255 tevent_req_done(req);
6258 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6259 uint32_t *pnum_changes,
6260 struct notify_change **pchanges)
6262 struct cli_notify_state *state = tevent_req_data(
6263 req, struct cli_notify_state);
6264 NTSTATUS status;
6266 if (tevent_req_is_nterror(req, &status)) {
6267 return status;
6270 *pnum_changes = state->num_changes;
6271 *pchanges = talloc_move(mem_ctx, &state->changes);
6272 return NT_STATUS_OK;
6275 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
6276 uint32_t completion_filter, bool recursive,
6277 TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
6278 struct notify_change **pchanges)
6280 TALLOC_CTX *frame;
6281 struct tevent_context *ev;
6282 struct tevent_req *req;
6283 NTSTATUS status = NT_STATUS_NO_MEMORY;
6285 frame = talloc_stackframe();
6287 if (smbXcli_conn_has_async_calls(cli->conn)) {
6289 * Can't use sync call while an async call is in flight
6291 status = NT_STATUS_INVALID_PARAMETER;
6292 goto fail;
6294 ev = samba_tevent_context_init(frame);
6295 if (ev == NULL) {
6296 goto fail;
6298 req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
6299 completion_filter, recursive);
6300 if (req == NULL) {
6301 goto fail;
6303 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6304 goto fail;
6306 status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
6307 fail:
6308 TALLOC_FREE(frame);
6309 return status;
6312 struct cli_qpathinfo_state {
6313 uint8_t *param;
6314 uint8_t *data;
6315 uint16_t setup[1];
6316 uint32_t min_rdata;
6317 uint8_t *rdata;
6318 uint32_t num_rdata;
6321 static void cli_qpathinfo_done(struct tevent_req *subreq);
6323 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
6324 struct tevent_context *ev,
6325 struct cli_state *cli, const char *fname,
6326 uint16_t level, uint32_t min_rdata,
6327 uint32_t max_rdata)
6329 struct tevent_req *req, *subreq;
6330 struct cli_qpathinfo_state *state;
6331 uint16_t additional_flags2 = 0;
6333 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
6334 if (req == NULL) {
6335 return NULL;
6337 state->min_rdata = min_rdata;
6338 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
6340 state->param = talloc_zero_array(state, uint8_t, 6);
6341 if (tevent_req_nomem(state->param, req)) {
6342 return tevent_req_post(req, ev);
6344 SSVAL(state->param, 0, level);
6345 state->param = trans2_bytes_push_str(
6346 state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
6347 if (tevent_req_nomem(state->param, req)) {
6348 return tevent_req_post(req, ev);
6351 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
6352 !INFO_LEVEL_IS_UNIX(level)) {
6353 additional_flags2 = FLAGS2_REPARSE_PATH;
6356 subreq = cli_trans_send(
6357 state, /* mem ctx. */
6358 ev, /* event ctx. */
6359 cli, /* cli_state. */
6360 additional_flags2, /* additional_flags2 */
6361 SMBtrans2, /* cmd. */
6362 NULL, /* pipe name. */
6363 -1, /* fid. */
6364 0, /* function. */
6365 0, /* flags. */
6366 state->setup, /* setup. */
6367 1, /* num setup uint16_t words. */
6368 0, /* max returned setup. */
6369 state->param, /* param. */
6370 talloc_get_size(state->param), /* num param. */
6371 2, /* max returned param. */
6372 NULL, /* data. */
6373 0, /* num data. */
6374 max_rdata); /* max returned data. */
6376 if (tevent_req_nomem(subreq, req)) {
6377 return tevent_req_post(req, ev);
6379 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
6380 return req;
6383 static void cli_qpathinfo_done(struct tevent_req *subreq)
6385 struct tevent_req *req = tevent_req_callback_data(
6386 subreq, struct tevent_req);
6387 struct cli_qpathinfo_state *state = tevent_req_data(
6388 req, struct cli_qpathinfo_state);
6389 NTSTATUS status;
6391 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
6392 NULL, 0, NULL,
6393 &state->rdata, state->min_rdata,
6394 &state->num_rdata);
6395 if (tevent_req_nterror(req, status)) {
6396 return;
6398 tevent_req_done(req);
6401 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6402 uint8_t **rdata, uint32_t *num_rdata)
6404 struct cli_qpathinfo_state *state = tevent_req_data(
6405 req, struct cli_qpathinfo_state);
6406 NTSTATUS status;
6408 if (tevent_req_is_nterror(req, &status)) {
6409 return status;
6411 if (rdata != NULL) {
6412 *rdata = talloc_move(mem_ctx, &state->rdata);
6413 } else {
6414 TALLOC_FREE(state->rdata);
6416 if (num_rdata != NULL) {
6417 *num_rdata = state->num_rdata;
6419 return NT_STATUS_OK;
6422 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6423 const char *fname, uint16_t level, uint32_t min_rdata,
6424 uint32_t max_rdata,
6425 uint8_t **rdata, uint32_t *num_rdata)
6427 TALLOC_CTX *frame = talloc_stackframe();
6428 struct tevent_context *ev;
6429 struct tevent_req *req;
6430 NTSTATUS status = NT_STATUS_NO_MEMORY;
6432 if (smbXcli_conn_has_async_calls(cli->conn)) {
6434 * Can't use sync call while an async call is in flight
6436 status = NT_STATUS_INVALID_PARAMETER;
6437 goto fail;
6439 ev = samba_tevent_context_init(frame);
6440 if (ev == NULL) {
6441 goto fail;
6443 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
6444 max_rdata);
6445 if (req == NULL) {
6446 goto fail;
6448 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6449 goto fail;
6451 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
6452 fail:
6453 TALLOC_FREE(frame);
6454 return status;
6457 struct cli_qfileinfo_state {
6458 uint16_t setup[1];
6459 uint8_t param[4];
6460 uint8_t *data;
6461 uint16_t recv_flags2;
6462 uint32_t min_rdata;
6463 uint8_t *rdata;
6464 uint32_t num_rdata;
6467 static void cli_qfileinfo_done(struct tevent_req *subreq);
6469 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
6470 struct tevent_context *ev,
6471 struct cli_state *cli, uint16_t fnum,
6472 uint16_t level, uint32_t min_rdata,
6473 uint32_t max_rdata)
6475 struct tevent_req *req, *subreq;
6476 struct cli_qfileinfo_state *state;
6478 req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
6479 if (req == NULL) {
6480 return NULL;
6482 state->min_rdata = min_rdata;
6483 SSVAL(state->param, 0, fnum);
6484 SSVAL(state->param, 2, level);
6485 SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
6487 subreq = cli_trans_send(
6488 state, /* mem ctx. */
6489 ev, /* event ctx. */
6490 cli, /* cli_state. */
6491 0, /* additional_flags2 */
6492 SMBtrans2, /* cmd. */
6493 NULL, /* pipe name. */
6494 -1, /* fid. */
6495 0, /* function. */
6496 0, /* flags. */
6497 state->setup, /* setup. */
6498 1, /* num setup uint16_t words. */
6499 0, /* max returned setup. */
6500 state->param, /* param. */
6501 sizeof(state->param), /* num param. */
6502 2, /* max returned param. */
6503 NULL, /* data. */
6504 0, /* num data. */
6505 max_rdata); /* max returned data. */
6507 if (tevent_req_nomem(subreq, req)) {
6508 return tevent_req_post(req, ev);
6510 tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
6511 return req;
6514 static void cli_qfileinfo_done(struct tevent_req *subreq)
6516 struct tevent_req *req = tevent_req_callback_data(
6517 subreq, struct tevent_req);
6518 struct cli_qfileinfo_state *state = tevent_req_data(
6519 req, struct cli_qfileinfo_state);
6520 NTSTATUS status;
6522 status = cli_trans_recv(subreq, state,
6523 &state->recv_flags2,
6524 NULL, 0, NULL,
6525 NULL, 0, NULL,
6526 &state->rdata, state->min_rdata,
6527 &state->num_rdata);
6528 if (tevent_req_nterror(req, status)) {
6529 return;
6531 tevent_req_done(req);
6534 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6535 uint16_t *recv_flags2,
6536 uint8_t **rdata, uint32_t *num_rdata)
6538 struct cli_qfileinfo_state *state = tevent_req_data(
6539 req, struct cli_qfileinfo_state);
6540 NTSTATUS status;
6542 if (tevent_req_is_nterror(req, &status)) {
6543 return status;
6546 if (recv_flags2 != NULL) {
6547 *recv_flags2 = state->recv_flags2;
6549 if (rdata != NULL) {
6550 *rdata = talloc_move(mem_ctx, &state->rdata);
6552 if (num_rdata != NULL) {
6553 *num_rdata = state->num_rdata;
6556 tevent_req_received(req);
6557 return NT_STATUS_OK;
6560 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6561 uint16_t fnum, uint16_t level, uint32_t min_rdata,
6562 uint32_t max_rdata, uint16_t *recv_flags2,
6563 uint8_t **rdata, uint32_t *num_rdata)
6565 TALLOC_CTX *frame = talloc_stackframe();
6566 struct tevent_context *ev;
6567 struct tevent_req *req;
6568 NTSTATUS status = NT_STATUS_NO_MEMORY;
6570 if (smbXcli_conn_has_async_calls(cli->conn)) {
6572 * Can't use sync call while an async call is in flight
6574 status = NT_STATUS_INVALID_PARAMETER;
6575 goto fail;
6577 ev = samba_tevent_context_init(frame);
6578 if (ev == NULL) {
6579 goto fail;
6581 req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
6582 max_rdata);
6583 if (req == NULL) {
6584 goto fail;
6586 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6587 goto fail;
6589 status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
6590 fail:
6591 TALLOC_FREE(frame);
6592 return status;
6595 struct cli_flush_state {
6596 uint16_t vwv[1];
6599 static void cli_flush_done(struct tevent_req *subreq);
6601 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
6602 struct tevent_context *ev,
6603 struct cli_state *cli,
6604 uint16_t fnum)
6606 struct tevent_req *req, *subreq;
6607 struct cli_flush_state *state;
6609 req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
6610 if (req == NULL) {
6611 return NULL;
6613 SSVAL(state->vwv + 0, 0, fnum);
6615 subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
6616 0, NULL);
6617 if (tevent_req_nomem(subreq, req)) {
6618 return tevent_req_post(req, ev);
6620 tevent_req_set_callback(subreq, cli_flush_done, req);
6621 return req;
6624 static void cli_flush_done(struct tevent_req *subreq)
6626 struct tevent_req *req = tevent_req_callback_data(
6627 subreq, struct tevent_req);
6628 NTSTATUS status;
6630 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
6631 TALLOC_FREE(subreq);
6632 if (tevent_req_nterror(req, status)) {
6633 return;
6635 tevent_req_done(req);
6638 NTSTATUS cli_flush_recv(struct tevent_req *req)
6640 return tevent_req_simple_recv_ntstatus(req);
6643 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
6645 TALLOC_CTX *frame = talloc_stackframe();
6646 struct tevent_context *ev;
6647 struct tevent_req *req;
6648 NTSTATUS status = NT_STATUS_NO_MEMORY;
6650 if (smbXcli_conn_has_async_calls(cli->conn)) {
6652 * Can't use sync call while an async call is in flight
6654 status = NT_STATUS_INVALID_PARAMETER;
6655 goto fail;
6657 ev = samba_tevent_context_init(frame);
6658 if (ev == NULL) {
6659 goto fail;
6661 req = cli_flush_send(frame, ev, cli, fnum);
6662 if (req == NULL) {
6663 goto fail;
6665 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6666 goto fail;
6668 status = cli_flush_recv(req);
6669 fail:
6670 TALLOC_FREE(frame);
6671 return status;
6674 struct cli_shadow_copy_data_state {
6675 uint16_t setup[4];
6676 uint8_t *data;
6677 uint32_t num_data;
6678 bool get_names;
6681 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
6683 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
6684 struct tevent_context *ev,
6685 struct cli_state *cli,
6686 uint16_t fnum,
6687 bool get_names)
6689 struct tevent_req *req, *subreq;
6690 struct cli_shadow_copy_data_state *state;
6691 uint32_t ret_size;
6693 req = tevent_req_create(mem_ctx, &state,
6694 struct cli_shadow_copy_data_state);
6695 if (req == NULL) {
6696 return NULL;
6698 state->get_names = get_names;
6699 ret_size = get_names ? CLI_BUFFER_SIZE : 16;
6701 SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
6702 SSVAL(state->setup + 2, 0, fnum);
6703 SCVAL(state->setup + 3, 0, 1); /* isFsctl */
6704 SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
6706 subreq = cli_trans_send(
6707 state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
6708 state->setup, ARRAY_SIZE(state->setup),
6709 ARRAY_SIZE(state->setup),
6710 NULL, 0, 0,
6711 NULL, 0, ret_size);
6712 if (tevent_req_nomem(subreq, req)) {
6713 return tevent_req_post(req, ev);
6715 tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
6716 return req;
6719 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
6721 struct tevent_req *req = tevent_req_callback_data(
6722 subreq, struct tevent_req);
6723 struct cli_shadow_copy_data_state *state = tevent_req_data(
6724 req, struct cli_shadow_copy_data_state);
6725 NTSTATUS status;
6727 status = cli_trans_recv(subreq, state, NULL,
6728 NULL, 0, NULL, /* setup */
6729 NULL, 0, NULL, /* param */
6730 &state->data, 12, &state->num_data);
6731 TALLOC_FREE(subreq);
6732 if (tevent_req_nterror(req, status)) {
6733 return;
6735 tevent_req_done(req);
6738 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6739 char ***pnames, int *pnum_names)
6741 struct cli_shadow_copy_data_state *state = tevent_req_data(
6742 req, struct cli_shadow_copy_data_state);
6743 char **names = NULL;
6744 uint32_t i, num_names;
6745 uint32_t dlength;
6746 uint8_t *endp = NULL;
6747 NTSTATUS status;
6749 if (tevent_req_is_nterror(req, &status)) {
6750 return status;
6753 if (state->num_data < 16) {
6754 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6757 num_names = IVAL(state->data, 4);
6758 dlength = IVAL(state->data, 8);
6760 if (num_names > 0x7FFFFFFF) {
6761 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6764 if (!state->get_names) {
6765 *pnum_names = (int)num_names;
6766 return NT_STATUS_OK;
6769 if (dlength + 12 < 12) {
6770 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6772 if (dlength + 12 > state->num_data) {
6773 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6775 if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
6776 state->num_data) {
6777 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6780 names = talloc_array(mem_ctx, char *, num_names);
6781 if (names == NULL) {
6782 return NT_STATUS_NO_MEMORY;
6785 endp = state->data + state->num_data;
6787 for (i=0; i<num_names; i++) {
6788 bool ret;
6789 uint8_t *src;
6790 size_t converted_size;
6792 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
6794 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
6795 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6798 ret = convert_string_talloc(
6799 names, CH_UTF16LE, CH_UNIX,
6800 src, 2 * sizeof(SHADOW_COPY_LABEL),
6801 &names[i], &converted_size);
6802 if (!ret) {
6803 TALLOC_FREE(names);
6804 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6807 *pnum_names = (int)num_names;
6808 *pnames = names;
6809 return NT_STATUS_OK;
6812 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6813 uint16_t fnum, bool get_names,
6814 char ***pnames, int *pnum_names)
6816 TALLOC_CTX *frame = NULL;
6817 struct tevent_context *ev;
6818 struct tevent_req *req;
6819 NTSTATUS status = NT_STATUS_NO_MEMORY;
6821 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6822 return cli_smb2_shadow_copy_data(mem_ctx,
6823 cli,
6824 fnum,
6825 get_names,
6826 pnames,
6827 pnum_names);
6830 frame = talloc_stackframe();
6832 if (smbXcli_conn_has_async_calls(cli->conn)) {
6834 * Can't use sync call while an async call is in flight
6836 status = NT_STATUS_INVALID_PARAMETER;
6837 goto fail;
6839 ev = samba_tevent_context_init(frame);
6840 if (ev == NULL) {
6841 goto fail;
6843 req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
6844 if (req == NULL) {
6845 goto fail;
6847 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6848 goto fail;
6850 status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
6851 fail:
6852 TALLOC_FREE(frame);
6853 return status;