CVE-2020-25722 pytest: Raise an error when adding a dynamic test that would overwrite...
[Samba.git] / source3 / libsmb / clifile.c
blob42b964dbabea9be6e5df88d1dd34ce030e72d114
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 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1214 struct tevent_context *ev,
1215 struct cli_state *cli,
1216 const char *fname_src,
1217 const char *fname_dst,
1218 bool replace);
1220 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1221 struct tevent_context *ev,
1222 struct cli_state *cli,
1223 const char *fname_src,
1224 const char *fname_dst,
1225 bool replace);
1227 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1228 struct tevent_context *ev,
1229 struct cli_state *cli,
1230 const char *fname_src,
1231 const char *fname_dst,
1232 bool replace)
1234 if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
1235 return cli_smb1_rename_send(mem_ctx, ev, cli, fname_src,
1236 fname_dst, replace);
1237 } else {
1238 return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src,
1239 fname_dst, replace);
1243 struct cli_smb1_rename_state {
1244 uint8_t *data;
1247 static void cli_smb1_rename_done(struct tevent_req *subreq);
1249 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1250 struct tevent_context *ev,
1251 struct cli_state *cli,
1252 const char *fname_src,
1253 const char *fname_dst,
1254 bool replace)
1256 NTSTATUS status;
1257 struct tevent_req *req = NULL, *subreq = NULL;
1258 struct cli_smb1_rename_state *state = NULL;
1259 smb_ucs2_t *converted_str = NULL;
1260 size_t converted_size_bytes = 0;
1262 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
1263 if (req == NULL) {
1264 return NULL;
1267 if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
1268 &converted_size_bytes)) {
1269 status = NT_STATUS_INVALID_PARAMETER;
1270 goto fail;
1273 /* W2K8 insists the dest name is not null
1274 terminated. Remove the last 2 zero bytes
1275 and reduce the name length. */
1277 if (converted_size_bytes < 2) {
1278 status = NT_STATUS_INVALID_PARAMETER;
1279 goto fail;
1281 converted_size_bytes -= 2;
1283 state->data =
1284 talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
1285 if (state->data == NULL) {
1286 status = NT_STATUS_NO_MEMORY;
1287 goto fail;
1290 if (replace) {
1291 SCVAL(state->data, 0, 1);
1294 SIVAL(state->data, 8, converted_size_bytes);
1295 memcpy(state->data + 12, converted_str, converted_size_bytes);
1297 TALLOC_FREE(converted_str);
1299 subreq = cli_setpathinfo_send(
1300 state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
1301 talloc_get_size(state->data));
1302 if (tevent_req_nomem(subreq, req)) {
1303 status = NT_STATUS_NO_MEMORY;
1304 goto fail;
1306 tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
1307 return req;
1309 fail:
1310 TALLOC_FREE(converted_str);
1311 tevent_req_nterror(req, status);
1312 return tevent_req_post(req, ev);
1315 static void cli_smb1_rename_done(struct tevent_req *subreq)
1317 NTSTATUS status = cli_setpathinfo_recv(subreq);
1318 tevent_req_simple_finish_ntstatus(subreq, status);
1321 static void cli_cifs_rename_done(struct tevent_req *subreq);
1323 struct cli_cifs_rename_state {
1324 uint16_t vwv[1];
1327 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1328 struct tevent_context *ev,
1329 struct cli_state *cli,
1330 const char *fname_src,
1331 const char *fname_dst,
1332 bool replace)
1334 struct tevent_req *req = NULL, *subreq = NULL;
1335 struct cli_cifs_rename_state *state = NULL;
1336 uint8_t additional_flags = 0;
1337 uint16_t additional_flags2 = 0;
1338 uint8_t *bytes = NULL;
1340 req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
1341 if (req == NULL) {
1342 return NULL;
1345 if (replace) {
1347 * CIFS doesn't support replace
1349 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1350 return tevent_req_post(req, ev);
1353 SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1355 bytes = talloc_array(state, uint8_t, 1);
1356 if (tevent_req_nomem(bytes, req)) {
1357 return tevent_req_post(req, ev);
1359 bytes[0] = 4;
1360 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1361 strlen(fname_src)+1, NULL);
1362 if (tevent_req_nomem(bytes, req)) {
1363 return tevent_req_post(req, ev);
1366 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1367 additional_flags2 = FLAGS2_REPARSE_PATH;
1370 bytes = talloc_realloc(state, bytes, uint8_t,
1371 talloc_get_size(bytes)+1);
1372 if (tevent_req_nomem(bytes, req)) {
1373 return tevent_req_post(req, ev);
1376 bytes[talloc_get_size(bytes)-1] = 4;
1377 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1378 strlen(fname_dst)+1, NULL);
1379 if (tevent_req_nomem(bytes, req)) {
1380 return tevent_req_post(req, ev);
1383 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1384 additional_flags2,
1385 1, state->vwv, talloc_get_size(bytes), bytes);
1386 if (tevent_req_nomem(subreq, req)) {
1387 return tevent_req_post(req, ev);
1389 tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
1390 return req;
1393 static void cli_cifs_rename_done(struct tevent_req *subreq)
1395 struct tevent_req *req = tevent_req_callback_data(
1396 subreq, struct tevent_req);
1397 NTSTATUS status;
1399 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1400 TALLOC_FREE(subreq);
1401 if (tevent_req_nterror(req, status)) {
1402 return;
1404 tevent_req_done(req);
1407 NTSTATUS cli_rename_recv(struct tevent_req *req)
1409 return tevent_req_simple_recv_ntstatus(req);
1412 NTSTATUS cli_rename(struct cli_state *cli,
1413 const char *fname_src,
1414 const char *fname_dst,
1415 bool replace)
1417 TALLOC_CTX *frame = NULL;
1418 struct tevent_context *ev;
1419 struct tevent_req *req;
1420 NTSTATUS status = NT_STATUS_OK;
1422 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1423 return cli_smb2_rename(cli, fname_src, fname_dst, replace);
1426 frame = talloc_stackframe();
1428 if (smbXcli_conn_has_async_calls(cli->conn)) {
1430 * Can't use sync call while an async call is in flight
1432 status = NT_STATUS_INVALID_PARAMETER;
1433 goto fail;
1436 ev = samba_tevent_context_init(frame);
1437 if (ev == NULL) {
1438 status = NT_STATUS_NO_MEMORY;
1439 goto fail;
1442 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
1443 if (req == NULL) {
1444 status = NT_STATUS_NO_MEMORY;
1445 goto fail;
1448 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1449 goto fail;
1452 status = cli_rename_recv(req);
1454 fail:
1455 TALLOC_FREE(frame);
1456 return status;
1459 /****************************************************************************
1460 NT Rename a file.
1461 ****************************************************************************/
1463 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1465 struct cli_ntrename_internal_state {
1466 uint16_t vwv[4];
1469 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1470 struct tevent_context *ev,
1471 struct cli_state *cli,
1472 const char *fname_src,
1473 const char *fname_dst,
1474 uint16_t rename_flag)
1476 struct tevent_req *req = NULL, *subreq = NULL;
1477 struct cli_ntrename_internal_state *state = NULL;
1478 uint8_t additional_flags = 0;
1479 uint16_t additional_flags2 = 0;
1480 uint8_t *bytes = NULL;
1482 req = tevent_req_create(mem_ctx, &state,
1483 struct cli_ntrename_internal_state);
1484 if (req == NULL) {
1485 return NULL;
1488 SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1489 SSVAL(state->vwv+1, 0, rename_flag);
1491 bytes = talloc_array(state, uint8_t, 1);
1492 if (tevent_req_nomem(bytes, req)) {
1493 return tevent_req_post(req, ev);
1495 bytes[0] = 4;
1496 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1497 strlen(fname_src)+1, NULL);
1498 if (tevent_req_nomem(bytes, req)) {
1499 return tevent_req_post(req, ev);
1502 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1503 additional_flags2 = FLAGS2_REPARSE_PATH;
1506 bytes = talloc_realloc(state, bytes, uint8_t,
1507 talloc_get_size(bytes)+1);
1508 if (tevent_req_nomem(bytes, req)) {
1509 return tevent_req_post(req, ev);
1512 bytes[talloc_get_size(bytes)-1] = 4;
1513 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1514 strlen(fname_dst)+1, NULL);
1515 if (tevent_req_nomem(bytes, req)) {
1516 return tevent_req_post(req, ev);
1519 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1520 additional_flags2,
1521 4, state->vwv, talloc_get_size(bytes), bytes);
1522 if (tevent_req_nomem(subreq, req)) {
1523 return tevent_req_post(req, ev);
1525 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1526 return req;
1529 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1531 NTSTATUS status = cli_smb_recv(
1532 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1533 tevent_req_simple_finish_ntstatus(subreq, status);
1536 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1538 return tevent_req_simple_recv_ntstatus(req);
1541 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1542 struct tevent_context *ev,
1543 struct cli_state *cli,
1544 const char *fname_src,
1545 const char *fname_dst)
1547 return cli_ntrename_internal_send(mem_ctx,
1549 cli,
1550 fname_src,
1551 fname_dst,
1552 RENAME_FLAG_RENAME);
1555 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1557 return cli_ntrename_internal_recv(req);
1560 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1562 TALLOC_CTX *frame = talloc_stackframe();
1563 struct tevent_context *ev;
1564 struct tevent_req *req;
1565 NTSTATUS status = NT_STATUS_OK;
1567 if (smbXcli_conn_has_async_calls(cli->conn)) {
1569 * Can't use sync call while an async call is in flight
1571 status = NT_STATUS_INVALID_PARAMETER;
1572 goto fail;
1575 ev = samba_tevent_context_init(frame);
1576 if (ev == NULL) {
1577 status = NT_STATUS_NO_MEMORY;
1578 goto fail;
1581 req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1582 if (req == NULL) {
1583 status = NT_STATUS_NO_MEMORY;
1584 goto fail;
1587 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1588 goto fail;
1591 status = cli_ntrename_recv(req);
1593 fail:
1594 TALLOC_FREE(frame);
1595 return status;
1598 /****************************************************************************
1599 NT hardlink a file.
1600 ****************************************************************************/
1602 static struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1603 struct tevent_context *ev,
1604 struct cli_state *cli,
1605 const char *fname_src,
1606 const char *fname_dst)
1608 return cli_ntrename_internal_send(mem_ctx,
1610 cli,
1611 fname_src,
1612 fname_dst,
1613 RENAME_FLAG_HARD_LINK);
1616 static NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1618 return cli_ntrename_internal_recv(req);
1621 struct cli_smb2_hardlink_state {
1622 struct tevent_context *ev;
1623 struct cli_state *cli;
1624 uint16_t fnum_src;
1625 const char *fname_dst;
1626 bool overwrite;
1627 NTSTATUS status;
1630 static void cli_smb2_hardlink_opened(struct tevent_req *subreq);
1631 static void cli_smb2_hardlink_info_set(struct tevent_req *subreq);
1632 static void cli_smb2_hardlink_closed(struct tevent_req *subreq);
1634 static struct tevent_req *cli_smb2_hardlink_send(
1635 TALLOC_CTX *mem_ctx,
1636 struct tevent_context *ev,
1637 struct cli_state *cli,
1638 const char *fname_src,
1639 const char *fname_dst,
1640 bool overwrite,
1641 struct smb2_create_blobs *in_cblobs)
1643 struct tevent_req *req = NULL, *subreq = NULL;
1644 struct cli_smb2_hardlink_state *state = NULL;
1646 req = tevent_req_create(
1647 mem_ctx, &state, struct cli_smb2_hardlink_state);
1648 if (req == NULL) {
1649 return NULL;
1651 state->ev = ev;
1652 state->cli = cli;
1653 state->fname_dst = fname_dst;
1654 state->overwrite = overwrite;
1656 subreq = cli_smb2_create_fnum_send(
1657 state,
1659 cli,
1660 fname_src,
1661 0, /* create_flags */
1662 SMB2_IMPERSONATION_IMPERSONATION,
1663 FILE_WRITE_ATTRIBUTES,
1664 0, /* file attributes */
1665 FILE_SHARE_READ|
1666 FILE_SHARE_WRITE|
1667 FILE_SHARE_DELETE, /* share_access */
1668 FILE_OPEN, /* create_disposition */
1669 FILE_NON_DIRECTORY_FILE, /* no hardlinks on directories */
1670 in_cblobs);
1671 if (tevent_req_nomem(subreq, req)) {
1672 return tevent_req_post(req, ev);
1674 tevent_req_set_callback(subreq, cli_smb2_hardlink_opened, req);
1675 return req;
1678 static void cli_smb2_hardlink_opened(struct tevent_req *subreq)
1680 struct tevent_req *req = tevent_req_callback_data(
1681 subreq, struct tevent_req);
1682 struct cli_smb2_hardlink_state *state = tevent_req_data(
1683 req, struct cli_smb2_hardlink_state);
1684 NTSTATUS status;
1685 smb_ucs2_t *ucs2_dst;
1686 size_t ucs2_len;
1687 DATA_BLOB inbuf;
1688 bool ok;
1690 status = cli_smb2_create_fnum_recv(
1691 subreq, &state->fnum_src, NULL, NULL, NULL);
1692 TALLOC_FREE(subreq);
1693 if (tevent_req_nterror(req, status)) {
1694 return;
1697 ok = push_ucs2_talloc(state, &ucs2_dst, state->fname_dst, &ucs2_len);
1698 if (!ok || (ucs2_len < 2)) {
1699 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1700 return;
1702 /* Don't 0-terminate the name */
1703 ucs2_len -= 2;
1705 inbuf = data_blob_talloc_zero(state, ucs2_len + 20);
1706 if (tevent_req_nomem(inbuf.data, req)) {
1707 return;
1710 if (state->overwrite) {
1711 SCVAL(inbuf.data, 0, 1);
1713 SIVAL(inbuf.data, 16, ucs2_len);
1714 memcpy(inbuf.data + 20, ucs2_dst, ucs2_len);
1715 TALLOC_FREE(ucs2_dst);
1717 subreq = cli_smb2_set_info_fnum_send(
1718 state,
1719 state->ev,
1720 state->cli,
1721 state->fnum_src,
1722 1, /* in_info_type */
1723 SMB_FILE_LINK_INFORMATION - 1000, /* in_file_info_class */
1724 &inbuf,
1725 0); /* in_additional_info */
1726 if (tevent_req_nomem(subreq, req)) {
1727 return;
1729 tevent_req_set_callback(subreq, cli_smb2_hardlink_info_set, req);
1732 static void cli_smb2_hardlink_info_set(struct tevent_req *subreq)
1734 struct tevent_req *req = tevent_req_callback_data(
1735 subreq, struct tevent_req);
1736 struct cli_smb2_hardlink_state *state = tevent_req_data(
1737 req, struct cli_smb2_hardlink_state);
1739 state->status = cli_smb2_set_info_fnum_recv(subreq);
1740 TALLOC_FREE(subreq);
1742 /* ignore error here, we need to close the file */
1744 subreq = cli_smb2_close_fnum_send(
1745 state, state->ev, state->cli, state->fnum_src);
1746 if (tevent_req_nomem(subreq, req)) {
1747 return;
1749 tevent_req_set_callback(subreq, cli_smb2_hardlink_closed, req);
1752 static void cli_smb2_hardlink_closed(struct tevent_req *subreq)
1754 NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
1755 tevent_req_simple_finish_ntstatus(subreq, status);
1758 static NTSTATUS cli_smb2_hardlink_recv(struct tevent_req *req)
1760 struct cli_smb2_hardlink_state *state = tevent_req_data(
1761 req, struct cli_smb2_hardlink_state);
1762 NTSTATUS status;
1764 if (tevent_req_is_nterror(req, &status)) {
1765 return status;
1767 return state->status;
1770 struct cli_hardlink_state {
1771 uint8_t dummy;
1774 static void cli_hardlink_done(struct tevent_req *subreq);
1775 static void cli_hardlink_done2(struct tevent_req *subreq);
1777 struct tevent_req *cli_hardlink_send(
1778 TALLOC_CTX *mem_ctx,
1779 struct tevent_context *ev,
1780 struct cli_state *cli,
1781 const char *fname_src,
1782 const char *fname_dst)
1784 struct tevent_req *req = NULL, *subreq = NULL;
1785 struct cli_hardlink_state *state;
1787 req = tevent_req_create(mem_ctx, &state, struct cli_hardlink_state);
1788 if (req == NULL) {
1789 return NULL;
1792 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1793 subreq = cli_smb2_hardlink_send(
1794 state, ev, cli, fname_src, fname_dst, false, NULL);
1795 if (tevent_req_nomem(subreq, req)) {
1796 return tevent_req_post(req, ev);
1798 tevent_req_set_callback(subreq, cli_hardlink_done2, req);
1799 return req;
1802 subreq = cli_nt_hardlink_send(state, ev, cli, fname_src, fname_dst);
1803 if (tevent_req_nomem(subreq, req)) {
1804 return tevent_req_post(req, ev);
1806 tevent_req_set_callback(subreq, cli_hardlink_done, req);
1807 return req;
1810 static void cli_hardlink_done(struct tevent_req *subreq)
1812 NTSTATUS status = cli_nt_hardlink_recv(subreq);
1813 tevent_req_simple_finish_ntstatus(subreq, status);
1816 static void cli_hardlink_done2(struct tevent_req *subreq)
1818 NTSTATUS status = cli_smb2_hardlink_recv(subreq);
1819 tevent_req_simple_finish_ntstatus(subreq, status);
1822 NTSTATUS cli_hardlink_recv(struct tevent_req *req)
1824 return tevent_req_simple_recv_ntstatus(req);
1827 NTSTATUS cli_hardlink(
1828 struct cli_state *cli, const char *fname_src, const char *fname_dst)
1830 TALLOC_CTX *frame = talloc_stackframe();
1831 struct tevent_context *ev = NULL;
1832 struct tevent_req *req = NULL;
1833 NTSTATUS status = NT_STATUS_NO_MEMORY;
1835 if (smbXcli_conn_has_async_calls(cli->conn)) {
1836 status = NT_STATUS_INVALID_PARAMETER;
1837 goto fail;
1839 ev = samba_tevent_context_init(frame);
1840 if (ev == NULL) {
1841 goto fail;
1843 req = cli_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1844 if (req == NULL) {
1845 goto fail;
1847 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1848 goto fail;
1850 status = cli_hardlink_recv(req);
1851 fail:
1852 TALLOC_FREE(frame);
1853 return status;
1856 /****************************************************************************
1857 Delete a file.
1858 ****************************************************************************/
1860 static void cli_unlink_done(struct tevent_req *subreq);
1861 static void cli_unlink_done2(struct tevent_req *subreq);
1863 struct cli_unlink_state {
1864 uint16_t vwv[1];
1867 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1868 struct tevent_context *ev,
1869 struct cli_state *cli,
1870 const char *fname,
1871 uint32_t mayhave_attrs)
1873 struct tevent_req *req = NULL, *subreq = NULL;
1874 struct cli_unlink_state *state = NULL;
1875 uint8_t additional_flags = 0;
1876 uint16_t additional_flags2 = 0;
1877 uint8_t *bytes = NULL;
1879 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1880 if (req == NULL) {
1881 return NULL;
1884 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1885 subreq = cli_smb2_unlink_send(state, ev, cli, fname, NULL);
1886 if (tevent_req_nomem(subreq, req)) {
1887 return tevent_req_post(req, ev);
1889 tevent_req_set_callback(subreq, cli_unlink_done2, req);
1890 return req;
1893 if (mayhave_attrs & 0xFFFF0000) {
1895 * Don't allow attributes greater than
1896 * 16-bits for a 16-bit protocol value.
1898 if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
1899 return tevent_req_post(req, ev);
1903 SSVAL(state->vwv+0, 0, mayhave_attrs);
1905 bytes = talloc_array(state, uint8_t, 1);
1906 if (tevent_req_nomem(bytes, req)) {
1907 return tevent_req_post(req, ev);
1909 bytes[0] = 4;
1910 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
1911 strlen(fname)+1, NULL);
1913 if (tevent_req_nomem(bytes, req)) {
1914 return tevent_req_post(req, ev);
1917 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1918 additional_flags2 = FLAGS2_REPARSE_PATH;
1921 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1922 additional_flags2,
1923 1, state->vwv, talloc_get_size(bytes), bytes);
1924 if (tevent_req_nomem(subreq, req)) {
1925 return tevent_req_post(req, ev);
1927 tevent_req_set_callback(subreq, cli_unlink_done, req);
1928 return req;
1931 static void cli_unlink_done(struct tevent_req *subreq)
1933 NTSTATUS status = cli_smb_recv(
1934 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1935 tevent_req_simple_finish_ntstatus(subreq, status);
1938 static void cli_unlink_done2(struct tevent_req *subreq)
1940 NTSTATUS status = cli_smb2_unlink_recv(subreq);
1941 tevent_req_simple_finish_ntstatus(subreq, status);
1944 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1946 return tevent_req_simple_recv_ntstatus(req);
1949 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint32_t mayhave_attrs)
1951 TALLOC_CTX *frame = NULL;
1952 struct tevent_context *ev;
1953 struct tevent_req *req;
1954 NTSTATUS status = NT_STATUS_OK;
1956 frame = talloc_stackframe();
1958 if (smbXcli_conn_has_async_calls(cli->conn)) {
1960 * Can't use sync call while an async call is in flight
1962 status = NT_STATUS_INVALID_PARAMETER;
1963 goto fail;
1966 ev = samba_tevent_context_init(frame);
1967 if (ev == NULL) {
1968 status = NT_STATUS_NO_MEMORY;
1969 goto fail;
1972 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1973 if (req == NULL) {
1974 status = NT_STATUS_NO_MEMORY;
1975 goto fail;
1978 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1979 goto fail;
1982 status = cli_unlink_recv(req);
1983 cli->raw_status = status; /* cli_smb2_unlink_recv doesn't set this */
1985 fail:
1986 TALLOC_FREE(frame);
1987 return status;
1990 /****************************************************************************
1991 Create a directory.
1992 ****************************************************************************/
1994 static void cli_mkdir_done(struct tevent_req *subreq);
1995 static void cli_mkdir_done2(struct tevent_req *subreq);
1997 struct cli_mkdir_state {
1998 int dummy;
2001 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
2002 struct tevent_context *ev,
2003 struct cli_state *cli,
2004 const char *dname)
2006 struct tevent_req *req = NULL, *subreq = NULL;
2007 struct cli_mkdir_state *state = NULL;
2008 uint8_t additional_flags = 0;
2009 uint16_t additional_flags2 = 0;
2010 uint8_t *bytes = NULL;
2012 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
2013 if (req == NULL) {
2014 return NULL;
2017 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2018 subreq = cli_smb2_mkdir_send(state, ev, cli, dname);
2019 if (tevent_req_nomem(subreq, req)) {
2020 return tevent_req_post(req, ev);
2022 tevent_req_set_callback(subreq, cli_mkdir_done2, req);
2023 return req;
2026 bytes = talloc_array(state, uint8_t, 1);
2027 if (tevent_req_nomem(bytes, req)) {
2028 return tevent_req_post(req, ev);
2030 bytes[0] = 4;
2031 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
2032 strlen(dname)+1, NULL);
2034 if (tevent_req_nomem(bytes, req)) {
2035 return tevent_req_post(req, ev);
2038 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
2039 additional_flags2 = FLAGS2_REPARSE_PATH;
2042 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
2043 additional_flags2,
2044 0, NULL, talloc_get_size(bytes), bytes);
2045 if (tevent_req_nomem(subreq, req)) {
2046 return tevent_req_post(req, ev);
2048 tevent_req_set_callback(subreq, cli_mkdir_done, req);
2049 return req;
2052 static void cli_mkdir_done(struct tevent_req *subreq)
2054 struct tevent_req *req = tevent_req_callback_data(
2055 subreq, struct tevent_req);
2056 NTSTATUS status;
2058 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2059 TALLOC_FREE(subreq);
2060 if (tevent_req_nterror(req, status)) {
2061 return;
2063 tevent_req_done(req);
2066 static void cli_mkdir_done2(struct tevent_req *subreq)
2068 NTSTATUS status = cli_smb2_mkdir_recv(subreq);
2069 tevent_req_simple_finish_ntstatus(subreq, status);
2072 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
2074 return tevent_req_simple_recv_ntstatus(req);
2077 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
2079 TALLOC_CTX *frame = NULL;
2080 struct tevent_context *ev;
2081 struct tevent_req *req;
2082 NTSTATUS status = NT_STATUS_OK;
2084 frame = talloc_stackframe();
2086 if (smbXcli_conn_has_async_calls(cli->conn)) {
2088 * Can't use sync call while an async call is in flight
2090 status = NT_STATUS_INVALID_PARAMETER;
2091 goto fail;
2094 ev = samba_tevent_context_init(frame);
2095 if (ev == NULL) {
2096 status = NT_STATUS_NO_MEMORY;
2097 goto fail;
2100 req = cli_mkdir_send(frame, ev, cli, dname);
2101 if (req == NULL) {
2102 status = NT_STATUS_NO_MEMORY;
2103 goto fail;
2106 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2107 goto fail;
2110 status = cli_mkdir_recv(req);
2111 cli->raw_status = status; /* cli_smb2_mkdir_recv doesn't set this */
2113 fail:
2114 TALLOC_FREE(frame);
2115 return status;
2118 /****************************************************************************
2119 Remove a directory.
2120 ****************************************************************************/
2122 static void cli_rmdir_done(struct tevent_req *subreq);
2123 static void cli_rmdir_done2(struct tevent_req *subreq);
2125 struct cli_rmdir_state {
2126 int dummy;
2129 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
2130 struct tevent_context *ev,
2131 struct cli_state *cli,
2132 const char *dname)
2134 struct tevent_req *req = NULL, *subreq = NULL;
2135 struct cli_rmdir_state *state = NULL;
2136 uint8_t additional_flags = 0;
2137 uint16_t additional_flags2 = 0;
2138 uint8_t *bytes = NULL;
2140 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
2141 if (req == NULL) {
2142 return NULL;
2145 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2146 subreq = cli_smb2_rmdir_send(state, ev, cli, dname, NULL);
2147 if (tevent_req_nomem(subreq, req)) {
2148 return tevent_req_post(req, ev);
2150 tevent_req_set_callback(subreq, cli_rmdir_done2, req);
2151 return req;
2154 bytes = talloc_array(state, uint8_t, 1);
2155 if (tevent_req_nomem(bytes, req)) {
2156 return tevent_req_post(req, ev);
2158 bytes[0] = 4;
2159 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
2160 strlen(dname)+1, NULL);
2162 if (tevent_req_nomem(bytes, req)) {
2163 return tevent_req_post(req, ev);
2166 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
2167 additional_flags2 = FLAGS2_REPARSE_PATH;
2170 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
2171 additional_flags2,
2172 0, NULL, talloc_get_size(bytes), bytes);
2173 if (tevent_req_nomem(subreq, req)) {
2174 return tevent_req_post(req, ev);
2176 tevent_req_set_callback(subreq, cli_rmdir_done, req);
2177 return req;
2180 static void cli_rmdir_done(struct tevent_req *subreq)
2182 NTSTATUS status = cli_smb_recv(
2183 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2184 tevent_req_simple_finish_ntstatus(subreq, status);
2187 static void cli_rmdir_done2(struct tevent_req *subreq)
2189 NTSTATUS status = cli_smb2_rmdir_recv(subreq);
2190 tevent_req_simple_finish_ntstatus(subreq, status);
2193 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
2195 return tevent_req_simple_recv_ntstatus(req);
2198 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
2200 TALLOC_CTX *frame = NULL;
2201 struct tevent_context *ev;
2202 struct tevent_req *req;
2203 NTSTATUS status = NT_STATUS_OK;
2205 frame = talloc_stackframe();
2207 if (smbXcli_conn_has_async_calls(cli->conn)) {
2209 * Can't use sync call while an async call is in flight
2211 status = NT_STATUS_INVALID_PARAMETER;
2212 goto fail;
2215 ev = samba_tevent_context_init(frame);
2216 if (ev == NULL) {
2217 status = NT_STATUS_NO_MEMORY;
2218 goto fail;
2221 req = cli_rmdir_send(frame, ev, cli, dname);
2222 if (req == NULL) {
2223 status = NT_STATUS_NO_MEMORY;
2224 goto fail;
2227 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2228 goto fail;
2231 status = cli_rmdir_recv(req);
2232 cli->raw_status = status; /* cli_smb2_rmdir_recv doesn't set this */
2234 fail:
2235 TALLOC_FREE(frame);
2236 return status;
2239 /****************************************************************************
2240 Set or clear the delete on close flag.
2241 ****************************************************************************/
2243 struct doc_state {
2244 uint8_t data[1];
2247 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
2248 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
2250 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
2251 struct tevent_context *ev,
2252 struct cli_state *cli,
2253 uint16_t fnum,
2254 bool flag)
2256 struct tevent_req *req = NULL, *subreq = NULL;
2257 struct doc_state *state = NULL;
2259 req = tevent_req_create(mem_ctx, &state, struct doc_state);
2260 if (req == NULL) {
2261 return NULL;
2264 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2265 subreq = cli_smb2_delete_on_close_send(state, ev, cli,
2266 fnum, flag);
2267 if (tevent_req_nomem(subreq, req)) {
2268 return tevent_req_post(req, ev);
2270 tevent_req_set_callback(subreq,
2271 cli_nt_delete_on_close_smb2_done,
2272 req);
2273 return req;
2276 /* Setup data array. */
2277 SCVAL(&state->data[0], 0, flag ? 1 : 0);
2279 subreq = cli_setfileinfo_send(
2280 state,
2282 cli,
2283 fnum,
2284 SMB_SET_FILE_DISPOSITION_INFO,
2285 state->data,
2286 sizeof(state->data));
2288 if (tevent_req_nomem(subreq, req)) {
2289 return tevent_req_post(req, ev);
2291 tevent_req_set_callback(subreq,
2292 cli_nt_delete_on_close_smb1_done,
2293 req);
2294 return req;
2297 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
2299 NTSTATUS status = cli_setfileinfo_recv(subreq);
2300 tevent_req_simple_finish_ntstatus(subreq, status);
2303 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
2305 NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
2306 tevent_req_simple_finish_ntstatus(subreq, status);
2309 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
2311 return tevent_req_simple_recv_ntstatus(req);
2314 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
2316 TALLOC_CTX *frame = talloc_stackframe();
2317 struct tevent_context *ev = NULL;
2318 struct tevent_req *req = NULL;
2319 NTSTATUS status = NT_STATUS_OK;
2321 if (smbXcli_conn_has_async_calls(cli->conn)) {
2323 * Can't use sync call while an async call is in flight
2325 status = NT_STATUS_INVALID_PARAMETER;
2326 goto fail;
2329 ev = samba_tevent_context_init(frame);
2330 if (ev == NULL) {
2331 status = NT_STATUS_NO_MEMORY;
2332 goto fail;
2335 req = cli_nt_delete_on_close_send(frame,
2337 cli,
2338 fnum,
2339 flag);
2340 if (req == NULL) {
2341 status = NT_STATUS_NO_MEMORY;
2342 goto fail;
2345 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2346 goto fail;
2349 status = cli_nt_delete_on_close_recv(req);
2351 fail:
2352 TALLOC_FREE(frame);
2353 return status;
2356 struct cli_ntcreate1_state {
2357 uint16_t vwv[24];
2358 uint16_t fnum;
2359 struct smb_create_returns cr;
2360 struct tevent_req *subreq;
2363 static void cli_ntcreate1_done(struct tevent_req *subreq);
2364 static bool cli_ntcreate1_cancel(struct tevent_req *req);
2366 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
2367 struct tevent_context *ev,
2368 struct cli_state *cli,
2369 const char *fname,
2370 uint32_t CreatFlags,
2371 uint32_t DesiredAccess,
2372 uint32_t FileAttributes,
2373 uint32_t ShareAccess,
2374 uint32_t CreateDisposition,
2375 uint32_t CreateOptions,
2376 uint32_t ImpersonationLevel,
2377 uint8_t SecurityFlags)
2379 struct tevent_req *req, *subreq;
2380 struct cli_ntcreate1_state *state;
2381 uint16_t *vwv;
2382 uint8_t *bytes;
2383 size_t converted_len;
2384 uint16_t additional_flags2 = 0;
2386 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
2387 if (req == NULL) {
2388 return NULL;
2391 vwv = state->vwv;
2393 SCVAL(vwv+0, 0, 0xFF);
2394 SCVAL(vwv+0, 1, 0);
2395 SSVAL(vwv+1, 0, 0);
2396 SCVAL(vwv+2, 0, 0);
2398 if (cli->use_oplocks) {
2399 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
2401 SIVAL(vwv+3, 1, CreatFlags);
2402 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
2403 SIVAL(vwv+7, 1, DesiredAccess);
2404 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
2405 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
2406 SIVAL(vwv+13, 1, FileAttributes);
2407 SIVAL(vwv+15, 1, ShareAccess);
2408 SIVAL(vwv+17, 1, CreateDisposition);
2409 SIVAL(vwv+19, 1, CreateOptions |
2410 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2411 SIVAL(vwv+21, 1, ImpersonationLevel);
2412 SCVAL(vwv+23, 1, SecurityFlags);
2414 bytes = talloc_array(state, uint8_t, 0);
2415 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
2416 fname, strlen(fname)+1,
2417 &converted_len);
2419 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2420 additional_flags2 = FLAGS2_REPARSE_PATH;
2423 /* sigh. this copes with broken netapp filer behaviour */
2424 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2426 if (tevent_req_nomem(bytes, req)) {
2427 return tevent_req_post(req, ev);
2430 SSVAL(vwv+2, 1, converted_len);
2432 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2433 additional_flags2, 24, vwv,
2434 talloc_get_size(bytes), bytes);
2435 if (tevent_req_nomem(subreq, req)) {
2436 return tevent_req_post(req, ev);
2438 tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2440 state->subreq = subreq;
2441 tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2443 return req;
2446 static void cli_ntcreate1_done(struct tevent_req *subreq)
2448 struct tevent_req *req = tevent_req_callback_data(
2449 subreq, struct tevent_req);
2450 struct cli_ntcreate1_state *state = tevent_req_data(
2451 req, struct cli_ntcreate1_state);
2452 uint8_t wct;
2453 uint16_t *vwv;
2454 uint32_t num_bytes;
2455 uint8_t *bytes;
2456 NTSTATUS status;
2458 status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2459 &num_bytes, &bytes);
2460 TALLOC_FREE(subreq);
2461 if (tevent_req_nterror(req, status)) {
2462 return;
2464 state->cr.oplock_level = CVAL(vwv+2, 0);
2465 state->fnum = SVAL(vwv+2, 1);
2466 state->cr.create_action = IVAL(vwv+3, 1);
2467 state->cr.creation_time = BVAL(vwv+5, 1);
2468 state->cr.last_access_time = BVAL(vwv+9, 1);
2469 state->cr.last_write_time = BVAL(vwv+13, 1);
2470 state->cr.change_time = BVAL(vwv+17, 1);
2471 state->cr.file_attributes = IVAL(vwv+21, 1);
2472 state->cr.allocation_size = BVAL(vwv+23, 1);
2473 state->cr.end_of_file = BVAL(vwv+27, 1);
2475 tevent_req_done(req);
2478 static bool cli_ntcreate1_cancel(struct tevent_req *req)
2480 struct cli_ntcreate1_state *state = tevent_req_data(
2481 req, struct cli_ntcreate1_state);
2482 return tevent_req_cancel(state->subreq);
2485 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2486 uint16_t *pfnum,
2487 struct smb_create_returns *cr)
2489 struct cli_ntcreate1_state *state = tevent_req_data(
2490 req, struct cli_ntcreate1_state);
2491 NTSTATUS status;
2493 if (tevent_req_is_nterror(req, &status)) {
2494 return status;
2496 *pfnum = state->fnum;
2497 if (cr != NULL) {
2498 *cr = state->cr;
2500 return NT_STATUS_OK;
2503 struct cli_ntcreate_state {
2504 struct smb_create_returns cr;
2505 uint16_t fnum;
2506 struct tevent_req *subreq;
2509 static void cli_ntcreate_done_nt1(struct tevent_req *subreq);
2510 static void cli_ntcreate_done_smb2(struct tevent_req *subreq);
2511 static bool cli_ntcreate_cancel(struct tevent_req *req);
2513 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
2514 struct tevent_context *ev,
2515 struct cli_state *cli,
2516 const char *fname,
2517 uint32_t create_flags,
2518 uint32_t desired_access,
2519 uint32_t file_attributes,
2520 uint32_t share_access,
2521 uint32_t create_disposition,
2522 uint32_t create_options,
2523 uint32_t impersonation_level,
2524 uint8_t security_flags)
2526 struct tevent_req *req, *subreq;
2527 struct cli_ntcreate_state *state;
2529 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2530 if (req == NULL) {
2531 return NULL;
2534 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2535 if (cli->use_oplocks) {
2536 create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2539 subreq = cli_smb2_create_fnum_send(
2540 state,
2542 cli,
2543 fname,
2544 create_flags,
2545 impersonation_level,
2546 desired_access,
2547 file_attributes,
2548 share_access,
2549 create_disposition,
2550 create_options,
2551 NULL);
2552 if (tevent_req_nomem(subreq, req)) {
2553 return tevent_req_post(req, ev);
2555 tevent_req_set_callback(subreq, cli_ntcreate_done_smb2, req);
2556 } else {
2557 subreq = cli_ntcreate1_send(
2558 state, ev, cli, fname, create_flags, desired_access,
2559 file_attributes, share_access, create_disposition,
2560 create_options, impersonation_level, security_flags);
2561 if (tevent_req_nomem(subreq, req)) {
2562 return tevent_req_post(req, ev);
2564 tevent_req_set_callback(subreq, cli_ntcreate_done_nt1, req);
2567 state->subreq = subreq;
2568 tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2570 return req;
2573 static void cli_ntcreate_done_nt1(struct tevent_req *subreq)
2575 struct tevent_req *req = tevent_req_callback_data(
2576 subreq, struct tevent_req);
2577 struct cli_ntcreate_state *state = tevent_req_data(
2578 req, struct cli_ntcreate_state);
2579 NTSTATUS status;
2581 status = cli_ntcreate1_recv(subreq, &state->fnum, &state->cr);
2582 TALLOC_FREE(subreq);
2583 if (tevent_req_nterror(req, status)) {
2584 return;
2586 tevent_req_done(req);
2589 static void cli_ntcreate_done_smb2(struct tevent_req *subreq)
2591 struct tevent_req *req = tevent_req_callback_data(
2592 subreq, struct tevent_req);
2593 struct cli_ntcreate_state *state = tevent_req_data(
2594 req, struct cli_ntcreate_state);
2595 NTSTATUS status;
2597 status = cli_smb2_create_fnum_recv(
2598 subreq,
2599 &state->fnum,
2600 &state->cr,
2601 NULL,
2602 NULL);
2603 TALLOC_FREE(subreq);
2604 if (tevent_req_nterror(req, status)) {
2605 return;
2607 tevent_req_done(req);
2610 static bool cli_ntcreate_cancel(struct tevent_req *req)
2612 struct cli_ntcreate_state *state = tevent_req_data(
2613 req, struct cli_ntcreate_state);
2614 return tevent_req_cancel(state->subreq);
2617 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2618 struct smb_create_returns *cr)
2620 struct cli_ntcreate_state *state = tevent_req_data(
2621 req, struct cli_ntcreate_state);
2622 NTSTATUS status;
2624 if (tevent_req_is_nterror(req, &status)) {
2625 return status;
2627 if (fnum != NULL) {
2628 *fnum = state->fnum;
2630 if (cr != NULL) {
2631 *cr = state->cr;
2633 return NT_STATUS_OK;
2636 NTSTATUS cli_ntcreate(struct cli_state *cli,
2637 const char *fname,
2638 uint32_t CreatFlags,
2639 uint32_t DesiredAccess,
2640 uint32_t FileAttributes,
2641 uint32_t ShareAccess,
2642 uint32_t CreateDisposition,
2643 uint32_t CreateOptions,
2644 uint8_t SecurityFlags,
2645 uint16_t *pfid,
2646 struct smb_create_returns *cr)
2648 TALLOC_CTX *frame = talloc_stackframe();
2649 struct tevent_context *ev;
2650 struct tevent_req *req;
2651 uint32_t ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
2652 NTSTATUS status = NT_STATUS_NO_MEMORY;
2654 if (smbXcli_conn_has_async_calls(cli->conn)) {
2656 * Can't use sync call while an async call is in flight
2658 status = NT_STATUS_INVALID_PARAMETER;
2659 goto fail;
2662 ev = samba_tevent_context_init(frame);
2663 if (ev == NULL) {
2664 goto fail;
2667 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2668 DesiredAccess, FileAttributes, ShareAccess,
2669 CreateDisposition, CreateOptions,
2670 ImpersonationLevel, SecurityFlags);
2671 if (req == NULL) {
2672 goto fail;
2675 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2676 goto fail;
2679 status = cli_ntcreate_recv(req, pfid, cr);
2680 fail:
2681 TALLOC_FREE(frame);
2682 return status;
2685 struct cli_nttrans_create_state {
2686 uint16_t fnum;
2687 struct smb_create_returns cr;
2690 static void cli_nttrans_create_done(struct tevent_req *subreq);
2692 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2693 struct tevent_context *ev,
2694 struct cli_state *cli,
2695 const char *fname,
2696 uint32_t CreatFlags,
2697 uint32_t DesiredAccess,
2698 uint32_t FileAttributes,
2699 uint32_t ShareAccess,
2700 uint32_t CreateDisposition,
2701 uint32_t CreateOptions,
2702 uint8_t SecurityFlags,
2703 struct security_descriptor *secdesc,
2704 struct ea_struct *eas,
2705 int num_eas)
2707 struct tevent_req *req, *subreq;
2708 struct cli_nttrans_create_state *state;
2709 uint8_t *param;
2710 uint8_t *secdesc_buf;
2711 size_t secdesc_len;
2712 NTSTATUS status;
2713 size_t converted_len;
2714 uint16_t additional_flags2 = 0;
2716 req = tevent_req_create(mem_ctx,
2717 &state, struct cli_nttrans_create_state);
2718 if (req == NULL) {
2719 return NULL;
2722 if (secdesc != NULL) {
2723 status = marshall_sec_desc(talloc_tos(), secdesc,
2724 &secdesc_buf, &secdesc_len);
2725 if (tevent_req_nterror(req, status)) {
2726 DEBUG(10, ("marshall_sec_desc failed: %s\n",
2727 nt_errstr(status)));
2728 return tevent_req_post(req, ev);
2730 } else {
2731 secdesc_buf = NULL;
2732 secdesc_len = 0;
2735 if (num_eas != 0) {
2737 * TODO ;-)
2739 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2740 return tevent_req_post(req, ev);
2743 param = talloc_array(state, uint8_t, 53);
2744 if (tevent_req_nomem(param, req)) {
2745 return tevent_req_post(req, ev);
2748 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2749 fname, strlen(fname),
2750 &converted_len);
2751 if (tevent_req_nomem(param, req)) {
2752 return tevent_req_post(req, ev);
2755 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2756 additional_flags2 = FLAGS2_REPARSE_PATH;
2759 SIVAL(param, 0, CreatFlags);
2760 SIVAL(param, 4, 0x0); /* RootDirectoryFid */
2761 SIVAL(param, 8, DesiredAccess);
2762 SIVAL(param, 12, 0x0); /* AllocationSize */
2763 SIVAL(param, 16, 0x0); /* AllocationSize */
2764 SIVAL(param, 20, FileAttributes);
2765 SIVAL(param, 24, ShareAccess);
2766 SIVAL(param, 28, CreateDisposition);
2767 SIVAL(param, 32, CreateOptions |
2768 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2769 SIVAL(param, 36, secdesc_len);
2770 SIVAL(param, 40, 0); /* EA length*/
2771 SIVAL(param, 44, converted_len);
2772 SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2773 SCVAL(param, 52, SecurityFlags);
2775 subreq = cli_trans_send(state, ev, cli,
2776 additional_flags2, /* additional_flags2 */
2777 SMBnttrans,
2778 NULL, -1, /* name, fid */
2779 NT_TRANSACT_CREATE, 0,
2780 NULL, 0, 0, /* setup */
2781 param, talloc_get_size(param), 128, /* param */
2782 secdesc_buf, secdesc_len, 0); /* data */
2783 if (tevent_req_nomem(subreq, req)) {
2784 return tevent_req_post(req, ev);
2786 tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2787 return req;
2790 static void cli_nttrans_create_done(struct tevent_req *subreq)
2792 struct tevent_req *req = tevent_req_callback_data(
2793 subreq, struct tevent_req);
2794 struct cli_nttrans_create_state *state = tevent_req_data(
2795 req, struct cli_nttrans_create_state);
2796 uint8_t *param;
2797 uint32_t num_param;
2798 NTSTATUS status;
2800 status = cli_trans_recv(subreq, talloc_tos(), NULL,
2801 NULL, 0, NULL, /* rsetup */
2802 &param, 69, &num_param,
2803 NULL, 0, NULL);
2804 if (tevent_req_nterror(req, status)) {
2805 return;
2807 state->cr.oplock_level = CVAL(param, 0);
2808 state->fnum = SVAL(param, 2);
2809 state->cr.create_action = IVAL(param, 4);
2810 state->cr.creation_time = BVAL(param, 12);
2811 state->cr.last_access_time = BVAL(param, 20);
2812 state->cr.last_write_time = BVAL(param, 28);
2813 state->cr.change_time = BVAL(param, 36);
2814 state->cr.file_attributes = IVAL(param, 44);
2815 state->cr.allocation_size = BVAL(param, 48);
2816 state->cr.end_of_file = BVAL(param, 56);
2818 TALLOC_FREE(param);
2819 tevent_req_done(req);
2822 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2823 uint16_t *fnum,
2824 struct smb_create_returns *cr)
2826 struct cli_nttrans_create_state *state = tevent_req_data(
2827 req, struct cli_nttrans_create_state);
2828 NTSTATUS status;
2830 if (tevent_req_is_nterror(req, &status)) {
2831 return status;
2833 *fnum = state->fnum;
2834 if (cr != NULL) {
2835 *cr = state->cr;
2837 return NT_STATUS_OK;
2840 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2841 const char *fname,
2842 uint32_t CreatFlags,
2843 uint32_t DesiredAccess,
2844 uint32_t FileAttributes,
2845 uint32_t ShareAccess,
2846 uint32_t CreateDisposition,
2847 uint32_t CreateOptions,
2848 uint8_t SecurityFlags,
2849 struct security_descriptor *secdesc,
2850 struct ea_struct *eas,
2851 int num_eas,
2852 uint16_t *pfid,
2853 struct smb_create_returns *cr)
2855 TALLOC_CTX *frame = talloc_stackframe();
2856 struct tevent_context *ev;
2857 struct tevent_req *req;
2858 NTSTATUS status = NT_STATUS_NO_MEMORY;
2860 if (smbXcli_conn_has_async_calls(cli->conn)) {
2862 * Can't use sync call while an async call is in flight
2864 status = NT_STATUS_INVALID_PARAMETER;
2865 goto fail;
2867 ev = samba_tevent_context_init(frame);
2868 if (ev == NULL) {
2869 goto fail;
2871 req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2872 DesiredAccess, FileAttributes,
2873 ShareAccess, CreateDisposition,
2874 CreateOptions, SecurityFlags,
2875 secdesc, eas, num_eas);
2876 if (req == NULL) {
2877 goto fail;
2879 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2880 goto fail;
2882 status = cli_nttrans_create_recv(req, pfid, cr);
2883 fail:
2884 TALLOC_FREE(frame);
2885 return status;
2888 /****************************************************************************
2889 Open a file
2890 WARNING: if you open with O_WRONLY then getattrE won't work!
2891 ****************************************************************************/
2893 struct cli_openx_state {
2894 const char *fname;
2895 uint16_t vwv[15];
2896 uint16_t fnum;
2897 struct iovec bytes;
2900 static void cli_openx_done(struct tevent_req *subreq);
2902 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2903 struct tevent_context *ev,
2904 struct cli_state *cli, const char *fname,
2905 int flags, int share_mode,
2906 struct tevent_req **psmbreq)
2908 struct tevent_req *req, *subreq;
2909 struct cli_openx_state *state;
2910 unsigned openfn;
2911 unsigned accessmode;
2912 uint8_t additional_flags;
2913 uint16_t additional_flags2 = 0;
2914 uint8_t *bytes;
2916 req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2917 if (req == NULL) {
2918 return NULL;
2921 openfn = 0;
2922 if (flags & O_CREAT) {
2923 openfn |= (1<<4);
2925 if (!(flags & O_EXCL)) {
2926 if (flags & O_TRUNC)
2927 openfn |= (1<<1);
2928 else
2929 openfn |= (1<<0);
2932 accessmode = (share_mode<<4);
2934 if ((flags & O_ACCMODE) == O_RDWR) {
2935 accessmode |= 2;
2936 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2937 accessmode |= 1;
2940 #if defined(O_SYNC)
2941 if ((flags & O_SYNC) == O_SYNC) {
2942 accessmode |= (1<<14);
2944 #endif /* O_SYNC */
2946 if (share_mode == DENY_FCB) {
2947 accessmode = 0xFF;
2950 SCVAL(state->vwv + 0, 0, 0xFF);
2951 SCVAL(state->vwv + 0, 1, 0);
2952 SSVAL(state->vwv + 1, 0, 0);
2953 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
2954 SSVAL(state->vwv + 3, 0, accessmode);
2955 SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2956 SSVAL(state->vwv + 5, 0, 0);
2957 SIVAL(state->vwv + 6, 0, 0);
2958 SSVAL(state->vwv + 8, 0, openfn);
2959 SIVAL(state->vwv + 9, 0, 0);
2960 SIVAL(state->vwv + 11, 0, 0);
2961 SIVAL(state->vwv + 13, 0, 0);
2963 additional_flags = 0;
2965 if (cli->use_oplocks) {
2966 /* if using oplocks then ask for a batch oplock via
2967 core and extended methods */
2968 additional_flags =
2969 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2970 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2973 bytes = talloc_array(state, uint8_t, 0);
2974 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2975 strlen(fname)+1, NULL);
2977 if (tevent_req_nomem(bytes, req)) {
2978 return tevent_req_post(req, ev);
2981 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2982 additional_flags2 = FLAGS2_REPARSE_PATH;
2985 state->bytes.iov_base = (void *)bytes;
2986 state->bytes.iov_len = talloc_get_size(bytes);
2988 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2989 additional_flags2, 15, state->vwv, 1, &state->bytes);
2990 if (subreq == NULL) {
2991 TALLOC_FREE(req);
2992 return NULL;
2994 tevent_req_set_callback(subreq, cli_openx_done, req);
2995 *psmbreq = subreq;
2996 return req;
2999 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
3000 struct cli_state *cli, const char *fname,
3001 int flags, int share_mode)
3003 struct tevent_req *req, *subreq;
3004 NTSTATUS status;
3006 req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
3007 &subreq);
3008 if (req == NULL) {
3009 return NULL;
3012 status = smb1cli_req_chain_submit(&subreq, 1);
3013 if (tevent_req_nterror(req, status)) {
3014 return tevent_req_post(req, ev);
3016 return req;
3019 static void cli_openx_done(struct tevent_req *subreq)
3021 struct tevent_req *req = tevent_req_callback_data(
3022 subreq, struct tevent_req);
3023 struct cli_openx_state *state = tevent_req_data(
3024 req, struct cli_openx_state);
3025 uint8_t wct;
3026 uint16_t *vwv;
3027 NTSTATUS status;
3029 status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
3030 NULL);
3031 TALLOC_FREE(subreq);
3032 if (tevent_req_nterror(req, status)) {
3033 return;
3035 state->fnum = SVAL(vwv+2, 0);
3036 tevent_req_done(req);
3039 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
3041 struct cli_openx_state *state = tevent_req_data(
3042 req, struct cli_openx_state);
3043 NTSTATUS status;
3045 if (tevent_req_is_nterror(req, &status)) {
3046 return status;
3048 *pfnum = state->fnum;
3049 return NT_STATUS_OK;
3052 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
3053 int share_mode, uint16_t *pfnum)
3055 TALLOC_CTX *frame = talloc_stackframe();
3056 struct tevent_context *ev;
3057 struct tevent_req *req;
3058 NTSTATUS status = NT_STATUS_NO_MEMORY;
3060 if (smbXcli_conn_has_async_calls(cli->conn)) {
3062 * Can't use sync call while an async call is in flight
3064 status = NT_STATUS_INVALID_PARAMETER;
3065 goto fail;
3068 ev = samba_tevent_context_init(frame);
3069 if (ev == NULL) {
3070 goto fail;
3073 req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
3074 if (req == NULL) {
3075 goto fail;
3078 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3079 goto fail;
3082 status = cli_openx_recv(req, pfnum);
3083 fail:
3084 TALLOC_FREE(frame);
3085 return status;
3087 /****************************************************************************
3088 Synchronous wrapper function that does an NtCreateX open by preference
3089 and falls back to openX if this fails.
3090 ****************************************************************************/
3092 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
3093 int share_mode_in, uint16_t *pfnum)
3095 NTSTATUS status;
3096 unsigned int openfn = 0;
3097 unsigned int dos_deny = 0;
3098 uint32_t access_mask, share_mode, create_disposition, create_options;
3099 struct smb_create_returns cr = {0};
3101 /* Do the initial mapping into OpenX parameters. */
3102 if (flags & O_CREAT) {
3103 openfn |= (1<<4);
3105 if (!(flags & O_EXCL)) {
3106 if (flags & O_TRUNC)
3107 openfn |= (1<<1);
3108 else
3109 openfn |= (1<<0);
3112 dos_deny = (share_mode_in<<4);
3114 if ((flags & O_ACCMODE) == O_RDWR) {
3115 dos_deny |= 2;
3116 } else if ((flags & O_ACCMODE) == O_WRONLY) {
3117 dos_deny |= 1;
3120 #if defined(O_SYNC)
3121 if ((flags & O_SYNC) == O_SYNC) {
3122 dos_deny |= (1<<14);
3124 #endif /* O_SYNC */
3126 if (share_mode_in == DENY_FCB) {
3127 dos_deny = 0xFF;
3130 if (!map_open_params_to_ntcreate(fname, dos_deny,
3131 openfn, &access_mask,
3132 &share_mode, &create_disposition,
3133 &create_options, NULL)) {
3134 goto try_openx;
3137 status = cli_ntcreate(cli,
3138 fname,
3140 access_mask,
3142 share_mode,
3143 create_disposition,
3144 create_options,
3146 pfnum,
3147 &cr);
3149 /* Try and cope will all varients of "we don't do this call"
3150 and fall back to openX. */
3152 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
3153 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
3154 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
3155 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
3156 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
3157 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
3158 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
3159 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
3160 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
3161 goto try_openx;
3164 if (NT_STATUS_IS_OK(status) &&
3165 (create_options & FILE_NON_DIRECTORY_FILE) &&
3166 (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
3169 * Some (broken) servers return a valid handle
3170 * for directories even if FILE_NON_DIRECTORY_FILE
3171 * is set. Just close the handle and set the
3172 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
3174 status = cli_close(cli, *pfnum);
3175 if (!NT_STATUS_IS_OK(status)) {
3176 return status;
3178 status = NT_STATUS_FILE_IS_A_DIRECTORY;
3179 /* Set this so libsmbclient can retrieve it. */
3180 cli->raw_status = status;
3183 return status;
3185 try_openx:
3187 return cli_openx(cli, fname, flags, share_mode_in, pfnum);
3190 /****************************************************************************
3191 Close a file.
3192 ****************************************************************************/
3194 struct cli_smb1_close_state {
3195 uint16_t vwv[3];
3198 static void cli_smb1_close_done(struct tevent_req *subreq);
3200 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
3201 struct tevent_context *ev,
3202 struct cli_state *cli,
3203 uint16_t fnum,
3204 struct tevent_req **psubreq)
3206 struct tevent_req *req, *subreq;
3207 struct cli_smb1_close_state *state;
3209 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
3210 if (req == NULL) {
3211 return NULL;
3214 SSVAL(state->vwv+0, 0, fnum);
3215 SIVALS(state->vwv+1, 0, -1);
3217 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
3218 3, state->vwv, 0, NULL);
3219 if (subreq == NULL) {
3220 TALLOC_FREE(req);
3221 return NULL;
3223 tevent_req_set_callback(subreq, cli_smb1_close_done, req);
3224 *psubreq = subreq;
3225 return req;
3228 static void cli_smb1_close_done(struct tevent_req *subreq)
3230 struct tevent_req *req = tevent_req_callback_data(
3231 subreq, struct tevent_req);
3232 NTSTATUS status;
3234 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3235 TALLOC_FREE(subreq);
3236 if (tevent_req_nterror(req, status)) {
3237 return;
3239 tevent_req_done(req);
3242 struct cli_close_state {
3243 int dummy;
3246 static void cli_close_done(struct tevent_req *subreq);
3248 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
3249 struct tevent_context *ev,
3250 struct cli_state *cli,
3251 uint16_t fnum)
3253 struct tevent_req *req, *subreq;
3254 struct cli_close_state *state;
3255 NTSTATUS status;
3257 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
3258 if (req == NULL) {
3259 return NULL;
3262 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3263 subreq = cli_smb2_close_fnum_send(state,
3265 cli,
3266 fnum);
3267 if (tevent_req_nomem(subreq, req)) {
3268 return tevent_req_post(req, ev);
3270 } else {
3271 struct tevent_req *ch_req = NULL;
3272 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
3273 if (tevent_req_nomem(subreq, req)) {
3274 return tevent_req_post(req, ev);
3276 status = smb1cli_req_chain_submit(&ch_req, 1);
3277 if (tevent_req_nterror(req, status)) {
3278 return tevent_req_post(req, ev);
3282 tevent_req_set_callback(subreq, cli_close_done, req);
3283 return req;
3286 static void cli_close_done(struct tevent_req *subreq)
3288 struct tevent_req *req = tevent_req_callback_data(
3289 subreq, struct tevent_req);
3290 NTSTATUS status = NT_STATUS_OK;
3291 bool err = tevent_req_is_nterror(subreq, &status);
3293 TALLOC_FREE(subreq);
3294 if (err) {
3295 tevent_req_nterror(req, status);
3296 return;
3298 tevent_req_done(req);
3301 NTSTATUS cli_close_recv(struct tevent_req *req)
3303 return tevent_req_simple_recv_ntstatus(req);
3306 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
3308 TALLOC_CTX *frame = NULL;
3309 struct tevent_context *ev;
3310 struct tevent_req *req;
3311 NTSTATUS status = NT_STATUS_OK;
3313 frame = talloc_stackframe();
3315 if (smbXcli_conn_has_async_calls(cli->conn)) {
3317 * Can't use sync call while an async call is in flight
3319 status = NT_STATUS_INVALID_PARAMETER;
3320 goto fail;
3323 ev = samba_tevent_context_init(frame);
3324 if (ev == NULL) {
3325 status = NT_STATUS_NO_MEMORY;
3326 goto fail;
3329 req = cli_close_send(frame, ev, cli, fnum);
3330 if (req == NULL) {
3331 status = NT_STATUS_NO_MEMORY;
3332 goto fail;
3335 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3336 goto fail;
3339 status = cli_close_recv(req);
3340 fail:
3341 TALLOC_FREE(frame);
3342 return status;
3345 /****************************************************************************
3346 Truncate a file to a specified size
3347 ****************************************************************************/
3349 struct ftrunc_state {
3350 uint8_t data[8];
3353 static void cli_ftruncate_done(struct tevent_req *subreq)
3355 NTSTATUS status = cli_setfileinfo_recv(subreq);
3356 tevent_req_simple_finish_ntstatus(subreq, status);
3359 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
3360 struct tevent_context *ev,
3361 struct cli_state *cli,
3362 uint16_t fnum,
3363 uint64_t size)
3365 struct tevent_req *req = NULL, *subreq = NULL;
3366 struct ftrunc_state *state = NULL;
3368 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
3369 if (req == NULL) {
3370 return NULL;
3373 /* Setup data array. */
3374 SBVAL(state->data, 0, size);
3376 subreq = cli_setfileinfo_send(
3377 state,
3379 cli,
3380 fnum,
3381 SMB_SET_FILE_END_OF_FILE_INFO,
3382 state->data,
3383 sizeof(state->data));
3385 if (tevent_req_nomem(subreq, req)) {
3386 return tevent_req_post(req, ev);
3388 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
3389 return req;
3392 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
3394 return tevent_req_simple_recv_ntstatus(req);
3397 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3399 TALLOC_CTX *frame = NULL;
3400 struct tevent_context *ev = NULL;
3401 struct tevent_req *req = NULL;
3402 NTSTATUS status = NT_STATUS_OK;
3404 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3405 return cli_smb2_ftruncate(cli, fnum, size);
3408 frame = talloc_stackframe();
3410 if (smbXcli_conn_has_async_calls(cli->conn)) {
3412 * Can't use sync call while an async call is in flight
3414 status = NT_STATUS_INVALID_PARAMETER;
3415 goto fail;
3418 ev = samba_tevent_context_init(frame);
3419 if (ev == NULL) {
3420 status = NT_STATUS_NO_MEMORY;
3421 goto fail;
3424 req = cli_ftruncate_send(frame,
3426 cli,
3427 fnum,
3428 size);
3429 if (req == NULL) {
3430 status = NT_STATUS_NO_MEMORY;
3431 goto fail;
3434 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3435 goto fail;
3438 status = cli_ftruncate_recv(req);
3440 fail:
3441 TALLOC_FREE(frame);
3442 return status;
3445 static uint8_t *cli_lockingx_put_locks(
3446 uint8_t *buf,
3447 bool large,
3448 uint16_t num_locks,
3449 const struct smb1_lock_element *locks)
3451 uint16_t i;
3453 for (i=0; i<num_locks; i++) {
3454 const struct smb1_lock_element *e = &locks[i];
3455 if (large) {
3456 SSVAL(buf, 0, e->pid);
3457 SSVAL(buf, 2, 0);
3458 SOFF_T_R(buf, 4, e->offset);
3459 SOFF_T_R(buf, 12, e->length);
3460 buf += 20;
3461 } else {
3462 SSVAL(buf, 0, e->pid);
3463 SIVAL(buf, 2, e->offset);
3464 SIVAL(buf, 6, e->length);
3465 buf += 10;
3468 return buf;
3471 struct cli_lockingx_state {
3472 uint16_t vwv[8];
3473 struct iovec bytes;
3474 struct tevent_req *subreq;
3477 static void cli_lockingx_done(struct tevent_req *subreq);
3478 static bool cli_lockingx_cancel(struct tevent_req *req);
3480 struct tevent_req *cli_lockingx_create(
3481 TALLOC_CTX *mem_ctx,
3482 struct tevent_context *ev,
3483 struct cli_state *cli,
3484 uint16_t fnum,
3485 uint8_t typeoflock,
3486 uint8_t newoplocklevel,
3487 int32_t timeout,
3488 uint16_t num_unlocks,
3489 const struct smb1_lock_element *unlocks,
3490 uint16_t num_locks,
3491 const struct smb1_lock_element *locks,
3492 struct tevent_req **psmbreq)
3494 struct tevent_req *req = NULL, *subreq = NULL;
3495 struct cli_lockingx_state *state = NULL;
3496 uint16_t *vwv;
3497 uint8_t *p;
3498 const bool large = (typeoflock & LOCKING_ANDX_LARGE_FILES);
3499 const size_t element_len = large ? 20 : 10;
3501 /* uint16->size_t, no overflow */
3502 const size_t num_elements = (size_t)num_locks + (size_t)num_unlocks;
3504 /* at most 20*2*65535 = 2621400, no overflow */
3505 const size_t num_bytes = num_elements * element_len;
3507 req = tevent_req_create(mem_ctx, &state, struct cli_lockingx_state);
3508 if (req == NULL) {
3509 return NULL;
3511 vwv = state->vwv;
3513 SCVAL(vwv + 0, 0, 0xFF);
3514 SCVAL(vwv + 0, 1, 0);
3515 SSVAL(vwv + 1, 0, 0);
3516 SSVAL(vwv + 2, 0, fnum);
3517 SCVAL(vwv + 3, 0, typeoflock);
3518 SCVAL(vwv + 3, 1, newoplocklevel);
3519 SIVALS(vwv + 4, 0, timeout);
3520 SSVAL(vwv + 6, 0, num_unlocks);
3521 SSVAL(vwv + 7, 0, num_locks);
3523 state->bytes.iov_len = num_bytes;
3524 state->bytes.iov_base = talloc_array(state, uint8_t, num_bytes);
3525 if (tevent_req_nomem(state->bytes.iov_base, req)) {
3526 return tevent_req_post(req, ev);
3529 p = cli_lockingx_put_locks(
3530 state->bytes.iov_base, large, num_unlocks, unlocks);
3531 cli_lockingx_put_locks(p, large, num_locks, locks);
3533 subreq = cli_smb_req_create(
3534 state, ev, cli, SMBlockingX, 0, 0, 8, vwv, 1, &state->bytes);
3535 if (tevent_req_nomem(subreq, req)) {
3536 return tevent_req_post(req, ev);
3538 tevent_req_set_callback(subreq, cli_lockingx_done, req);
3539 *psmbreq = subreq;
3540 return req;
3543 struct tevent_req *cli_lockingx_send(
3544 TALLOC_CTX *mem_ctx,
3545 struct tevent_context *ev,
3546 struct cli_state *cli,
3547 uint16_t fnum,
3548 uint8_t typeoflock,
3549 uint8_t newoplocklevel,
3550 int32_t timeout,
3551 uint16_t num_unlocks,
3552 const struct smb1_lock_element *unlocks,
3553 uint16_t num_locks,
3554 const struct smb1_lock_element *locks)
3556 struct tevent_req *req = NULL, *subreq = NULL;
3557 struct cli_lockingx_state *state = NULL;
3558 NTSTATUS status;
3560 req = cli_lockingx_create(
3561 mem_ctx,
3563 cli,
3564 fnum,
3565 typeoflock,
3566 newoplocklevel,
3567 timeout,
3568 num_unlocks,
3569 unlocks,
3570 num_locks,
3571 locks,
3572 &subreq);
3573 if (req == NULL) {
3574 return NULL;
3576 state = tevent_req_data(req, struct cli_lockingx_state);
3577 state->subreq = subreq;
3579 status = smb1cli_req_chain_submit(&subreq, 1);
3580 if (tevent_req_nterror(req, status)) {
3581 return tevent_req_post(req, ev);
3583 tevent_req_set_cancel_fn(req, cli_lockingx_cancel);
3584 return req;
3587 static void cli_lockingx_done(struct tevent_req *subreq)
3589 NTSTATUS status = cli_smb_recv(
3590 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3591 tevent_req_simple_finish_ntstatus(subreq, status);
3594 static bool cli_lockingx_cancel(struct tevent_req *req)
3596 struct cli_lockingx_state *state = tevent_req_data(
3597 req, struct cli_lockingx_state);
3598 if (state->subreq == NULL) {
3599 return false;
3601 return tevent_req_cancel(state->subreq);
3604 NTSTATUS cli_lockingx_recv(struct tevent_req *req)
3606 return tevent_req_simple_recv_ntstatus(req);
3609 NTSTATUS cli_lockingx(
3610 struct cli_state *cli,
3611 uint16_t fnum,
3612 uint8_t typeoflock,
3613 uint8_t newoplocklevel,
3614 int32_t timeout,
3615 uint16_t num_unlocks,
3616 const struct smb1_lock_element *unlocks,
3617 uint16_t num_locks,
3618 const struct smb1_lock_element *locks)
3620 TALLOC_CTX *frame = talloc_stackframe();
3621 struct tevent_context *ev = NULL;
3622 struct tevent_req *req = NULL;
3623 NTSTATUS status = NT_STATUS_NO_MEMORY;
3624 unsigned int set_timeout = 0;
3625 unsigned int saved_timeout = 0;
3627 if (smbXcli_conn_has_async_calls(cli->conn)) {
3628 return NT_STATUS_INVALID_PARAMETER;
3630 ev = samba_tevent_context_init(frame);
3631 if (ev == NULL) {
3632 goto fail;
3635 if (timeout != 0) {
3636 if (timeout == -1) {
3637 set_timeout = 0x7FFFFFFF;
3638 } else {
3639 set_timeout = timeout + 2*1000;
3641 saved_timeout = cli_set_timeout(cli, set_timeout);
3644 req = cli_lockingx_send(
3645 frame,
3647 cli,
3648 fnum,
3649 typeoflock,
3650 newoplocklevel,
3651 timeout,
3652 num_unlocks,
3653 unlocks,
3654 num_locks,
3655 locks);
3656 if (req == NULL) {
3657 goto fail;
3659 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3660 goto fail;
3662 status = cli_lockingx_recv(req);
3664 if (saved_timeout != 0) {
3665 cli_set_timeout(cli, saved_timeout);
3667 fail:
3668 TALLOC_FREE(frame);
3669 return status;
3672 /****************************************************************************
3673 send a lock with a specified locktype
3674 this is used for testing LOCKING_ANDX_CANCEL_LOCK
3675 ****************************************************************************/
3677 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
3678 uint32_t offset, uint32_t len,
3679 int timeout, unsigned char locktype)
3681 struct smb1_lock_element lck = {
3682 .pid = cli_getpid(cli),
3683 .offset = offset,
3684 .length = len,
3686 NTSTATUS status;
3688 status = cli_lockingx(
3689 cli, /* cli */
3690 fnum, /* fnum */
3691 locktype, /* typeoflock */
3692 0, /* newoplocklevel */
3693 timeout, /* timeout */
3694 0, /* num_unlocks */
3695 NULL, /* unlocks */
3696 1, /* num_locks */
3697 &lck); /* locks */
3698 return status;
3701 /****************************************************************************
3702 Lock a file.
3703 note that timeout is in units of 2 milliseconds
3704 ****************************************************************************/
3706 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
3707 uint32_t offset, uint32_t len, int timeout,
3708 enum brl_type lock_type)
3710 NTSTATUS status;
3712 status = cli_locktype(cli, fnum, offset, len, timeout,
3713 (lock_type == READ_LOCK? 1 : 0));
3714 return status;
3717 /****************************************************************************
3718 Unlock a file.
3719 ****************************************************************************/
3721 struct cli_unlock_state {
3722 struct smb1_lock_element lck;
3725 static void cli_unlock_done(struct tevent_req *subreq);
3727 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3728 struct tevent_context *ev,
3729 struct cli_state *cli,
3730 uint16_t fnum,
3731 uint64_t offset,
3732 uint64_t len)
3735 struct tevent_req *req = NULL, *subreq = NULL;
3736 struct cli_unlock_state *state = NULL;
3738 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3739 if (req == NULL) {
3740 return NULL;
3742 state->lck = (struct smb1_lock_element) {
3743 .pid = cli_getpid(cli),
3744 .offset = offset,
3745 .length = len,
3748 subreq = cli_lockingx_send(
3749 state, /* mem_ctx */
3750 ev, /* tevent_context */
3751 cli, /* cli */
3752 fnum, /* fnum */
3753 0, /* typeoflock */
3754 0, /* newoplocklevel */
3755 0, /* timeout */
3756 1, /* num_unlocks */
3757 &state->lck, /* unlocks */
3758 0, /* num_locks */
3759 NULL); /* locks */
3760 if (tevent_req_nomem(subreq, req)) {
3761 return tevent_req_post(req, ev);
3763 tevent_req_set_callback(subreq, cli_unlock_done, req);
3764 return req;
3767 static void cli_unlock_done(struct tevent_req *subreq)
3769 NTSTATUS status = cli_lockingx_recv(subreq);
3770 tevent_req_simple_finish_ntstatus(subreq, status);
3773 NTSTATUS cli_unlock_recv(struct tevent_req *req)
3775 return tevent_req_simple_recv_ntstatus(req);
3778 NTSTATUS cli_unlock(struct cli_state *cli,
3779 uint16_t fnum,
3780 uint32_t offset,
3781 uint32_t len)
3783 TALLOC_CTX *frame = talloc_stackframe();
3784 struct tevent_context *ev;
3785 struct tevent_req *req;
3786 NTSTATUS status = NT_STATUS_OK;
3788 if (smbXcli_conn_has_async_calls(cli->conn)) {
3790 * Can't use sync call while an async call is in flight
3792 status = NT_STATUS_INVALID_PARAMETER;
3793 goto fail;
3796 ev = samba_tevent_context_init(frame);
3797 if (ev == NULL) {
3798 status = NT_STATUS_NO_MEMORY;
3799 goto fail;
3802 req = cli_unlock_send(frame, ev, cli,
3803 fnum, offset, len);
3804 if (req == NULL) {
3805 status = NT_STATUS_NO_MEMORY;
3806 goto fail;
3809 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3810 goto fail;
3813 status = cli_unlock_recv(req);
3815 fail:
3816 TALLOC_FREE(frame);
3817 return status;
3820 /****************************************************************************
3821 Get/unlock a POSIX lock on a file - internal function.
3822 ****************************************************************************/
3824 struct posix_lock_state {
3825 uint16_t setup;
3826 uint8_t param[4];
3827 uint8_t data[POSIX_LOCK_DATA_SIZE];
3830 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3832 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3833 NULL, 0, NULL, NULL, 0, NULL);
3834 tevent_req_simple_finish_ntstatus(subreq, status);
3837 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3838 struct tevent_context *ev,
3839 struct cli_state *cli,
3840 uint16_t fnum,
3841 uint64_t offset,
3842 uint64_t len,
3843 bool wait_lock,
3844 enum brl_type lock_type)
3846 struct tevent_req *req = NULL, *subreq = NULL;
3847 struct posix_lock_state *state = NULL;
3849 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3850 if (req == NULL) {
3851 return NULL;
3854 /* Setup setup word. */
3855 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3857 /* Setup param array. */
3858 SSVAL(&state->param, 0, fnum);
3859 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3861 /* Setup data array. */
3862 switch (lock_type) {
3863 case READ_LOCK:
3864 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3865 POSIX_LOCK_TYPE_READ);
3866 break;
3867 case WRITE_LOCK:
3868 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3869 POSIX_LOCK_TYPE_WRITE);
3870 break;
3871 case UNLOCK_LOCK:
3872 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3873 POSIX_LOCK_TYPE_UNLOCK);
3874 break;
3875 default:
3876 return NULL;
3879 if (wait_lock) {
3880 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3881 POSIX_LOCK_FLAG_WAIT);
3882 } else {
3883 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3884 POSIX_LOCK_FLAG_NOWAIT);
3887 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3888 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3889 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3891 subreq = cli_trans_send(state, /* mem ctx. */
3892 ev, /* event ctx. */
3893 cli, /* cli_state. */
3894 0, /* additional_flags2 */
3895 SMBtrans2, /* cmd. */
3896 NULL, /* pipe name. */
3897 -1, /* fid. */
3898 0, /* function. */
3899 0, /* flags. */
3900 &state->setup, /* setup. */
3901 1, /* num setup uint16_t words. */
3902 0, /* max returned setup. */
3903 state->param, /* param. */
3904 4, /* num param. */
3905 2, /* max returned param. */
3906 state->data, /* data. */
3907 POSIX_LOCK_DATA_SIZE, /* num data. */
3908 0); /* max returned data. */
3910 if (tevent_req_nomem(subreq, req)) {
3911 return tevent_req_post(req, ev);
3913 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3914 return req;
3917 /****************************************************************************
3918 POSIX Lock a file.
3919 ****************************************************************************/
3921 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3922 struct tevent_context *ev,
3923 struct cli_state *cli,
3924 uint16_t fnum,
3925 uint64_t offset,
3926 uint64_t len,
3927 bool wait_lock,
3928 enum brl_type lock_type)
3930 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3931 wait_lock, lock_type);
3934 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3936 return tevent_req_simple_recv_ntstatus(req);
3939 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3940 uint64_t offset, uint64_t len,
3941 bool wait_lock, enum brl_type lock_type)
3943 TALLOC_CTX *frame = talloc_stackframe();
3944 struct tevent_context *ev = NULL;
3945 struct tevent_req *req = NULL;
3946 NTSTATUS status = NT_STATUS_OK;
3948 if (smbXcli_conn_has_async_calls(cli->conn)) {
3950 * Can't use sync call while an async call is in flight
3952 status = NT_STATUS_INVALID_PARAMETER;
3953 goto fail;
3956 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3957 status = NT_STATUS_INVALID_PARAMETER;
3958 goto fail;
3961 ev = samba_tevent_context_init(frame);
3962 if (ev == NULL) {
3963 status = NT_STATUS_NO_MEMORY;
3964 goto fail;
3967 req = cli_posix_lock_send(frame,
3969 cli,
3970 fnum,
3971 offset,
3972 len,
3973 wait_lock,
3974 lock_type);
3975 if (req == NULL) {
3976 status = NT_STATUS_NO_MEMORY;
3977 goto fail;
3980 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3981 goto fail;
3984 status = cli_posix_lock_recv(req);
3986 fail:
3987 TALLOC_FREE(frame);
3988 return status;
3991 /****************************************************************************
3992 POSIX Unlock a file.
3993 ****************************************************************************/
3995 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3996 struct tevent_context *ev,
3997 struct cli_state *cli,
3998 uint16_t fnum,
3999 uint64_t offset,
4000 uint64_t len)
4002 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4003 false, UNLOCK_LOCK);
4006 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
4008 return tevent_req_simple_recv_ntstatus(req);
4011 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
4013 TALLOC_CTX *frame = talloc_stackframe();
4014 struct tevent_context *ev = NULL;
4015 struct tevent_req *req = NULL;
4016 NTSTATUS status = NT_STATUS_OK;
4018 if (smbXcli_conn_has_async_calls(cli->conn)) {
4020 * Can't use sync call while an async call is in flight
4022 status = NT_STATUS_INVALID_PARAMETER;
4023 goto fail;
4026 ev = samba_tevent_context_init(frame);
4027 if (ev == NULL) {
4028 status = NT_STATUS_NO_MEMORY;
4029 goto fail;
4032 req = cli_posix_unlock_send(frame,
4034 cli,
4035 fnum,
4036 offset,
4037 len);
4038 if (req == NULL) {
4039 status = NT_STATUS_NO_MEMORY;
4040 goto fail;
4043 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4044 goto fail;
4047 status = cli_posix_unlock_recv(req);
4049 fail:
4050 TALLOC_FREE(frame);
4051 return status;
4054 /****************************************************************************
4055 Do a SMBgetattrE call.
4056 ****************************************************************************/
4058 static void cli_getattrE_done(struct tevent_req *subreq);
4060 struct cli_getattrE_state {
4061 uint16_t vwv[1];
4062 int zone_offset;
4063 uint32_t attr;
4064 off_t size;
4065 time_t change_time;
4066 time_t access_time;
4067 time_t write_time;
4070 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
4071 struct tevent_context *ev,
4072 struct cli_state *cli,
4073 uint16_t fnum)
4075 struct tevent_req *req = NULL, *subreq = NULL;
4076 struct cli_getattrE_state *state = NULL;
4077 uint8_t additional_flags = 0;
4079 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
4080 if (req == NULL) {
4081 return NULL;
4084 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4085 SSVAL(state->vwv+0,0,fnum);
4087 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
4088 1, state->vwv, 0, NULL);
4089 if (tevent_req_nomem(subreq, req)) {
4090 return tevent_req_post(req, ev);
4092 tevent_req_set_callback(subreq, cli_getattrE_done, req);
4093 return req;
4096 static void cli_getattrE_done(struct tevent_req *subreq)
4098 struct tevent_req *req = tevent_req_callback_data(
4099 subreq, struct tevent_req);
4100 struct cli_getattrE_state *state = tevent_req_data(
4101 req, struct cli_getattrE_state);
4102 uint8_t wct;
4103 uint16_t *vwv = NULL;
4104 NTSTATUS status;
4106 status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
4107 NULL, NULL);
4108 TALLOC_FREE(subreq);
4109 if (tevent_req_nterror(req, status)) {
4110 return;
4113 state->size = (off_t)IVAL(vwv+6,0);
4114 state->attr = SVAL(vwv+10,0);
4115 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
4116 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
4117 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
4119 tevent_req_done(req);
4122 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
4123 uint32_t *pattr,
4124 off_t *size,
4125 time_t *change_time,
4126 time_t *access_time,
4127 time_t *write_time)
4129 struct cli_getattrE_state *state = tevent_req_data(
4130 req, struct cli_getattrE_state);
4131 NTSTATUS status;
4133 if (tevent_req_is_nterror(req, &status)) {
4134 return status;
4136 if (pattr) {
4137 *pattr = state->attr;
4139 if (size) {
4140 *size = state->size;
4142 if (change_time) {
4143 *change_time = state->change_time;
4145 if (access_time) {
4146 *access_time = state->access_time;
4148 if (write_time) {
4149 *write_time = state->write_time;
4151 return NT_STATUS_OK;
4154 /****************************************************************************
4155 Do a SMBgetatr call
4156 ****************************************************************************/
4158 static void cli_getatr_done(struct tevent_req *subreq);
4160 struct cli_getatr_state {
4161 int zone_offset;
4162 uint32_t attr;
4163 off_t size;
4164 time_t write_time;
4167 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
4168 struct tevent_context *ev,
4169 struct cli_state *cli,
4170 const char *fname)
4172 struct tevent_req *req = NULL, *subreq = NULL;
4173 struct cli_getatr_state *state = NULL;
4174 uint8_t additional_flags = 0;
4175 uint16_t additional_flags2 = 0;
4176 uint8_t *bytes = NULL;
4178 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
4179 if (req == NULL) {
4180 return NULL;
4183 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4185 bytes = talloc_array(state, uint8_t, 1);
4186 if (tevent_req_nomem(bytes, req)) {
4187 return tevent_req_post(req, ev);
4189 bytes[0] = 4;
4190 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4191 strlen(fname)+1, NULL);
4193 if (tevent_req_nomem(bytes, req)) {
4194 return tevent_req_post(req, ev);
4197 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4198 additional_flags2 = FLAGS2_REPARSE_PATH;
4201 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
4202 additional_flags2,
4203 0, NULL, talloc_get_size(bytes), bytes);
4204 if (tevent_req_nomem(subreq, req)) {
4205 return tevent_req_post(req, ev);
4207 tevent_req_set_callback(subreq, cli_getatr_done, req);
4208 return req;
4211 static void cli_getatr_done(struct tevent_req *subreq)
4213 struct tevent_req *req = tevent_req_callback_data(
4214 subreq, struct tevent_req);
4215 struct cli_getatr_state *state = tevent_req_data(
4216 req, struct cli_getatr_state);
4217 uint8_t wct;
4218 uint16_t *vwv = NULL;
4219 NTSTATUS status;
4221 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4222 NULL);
4223 TALLOC_FREE(subreq);
4224 if (tevent_req_nterror(req, status)) {
4225 return;
4228 state->attr = SVAL(vwv+0,0);
4229 state->size = (off_t)IVAL(vwv+3,0);
4230 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
4232 tevent_req_done(req);
4235 NTSTATUS cli_getatr_recv(struct tevent_req *req,
4236 uint32_t *pattr,
4237 off_t *size,
4238 time_t *write_time)
4240 struct cli_getatr_state *state = tevent_req_data(
4241 req, struct cli_getatr_state);
4242 NTSTATUS status;
4244 if (tevent_req_is_nterror(req, &status)) {
4245 return status;
4247 if (pattr) {
4248 *pattr = state->attr;
4250 if (size) {
4251 *size = state->size;
4253 if (write_time) {
4254 *write_time = state->write_time;
4256 return NT_STATUS_OK;
4259 NTSTATUS cli_getatr(struct cli_state *cli,
4260 const char *fname,
4261 uint32_t *pattr,
4262 off_t *size,
4263 time_t *write_time)
4265 TALLOC_CTX *frame = NULL;
4266 struct tevent_context *ev = NULL;
4267 struct tevent_req *req = NULL;
4268 NTSTATUS status = NT_STATUS_OK;
4270 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4271 return cli_smb2_getatr(cli,
4272 fname,
4273 pattr,
4274 size,
4275 write_time);
4278 frame = talloc_stackframe();
4280 if (smbXcli_conn_has_async_calls(cli->conn)) {
4282 * Can't use sync call while an async call is in flight
4284 status = NT_STATUS_INVALID_PARAMETER;
4285 goto fail;
4288 ev = samba_tevent_context_init(frame);
4289 if (ev == NULL) {
4290 status = NT_STATUS_NO_MEMORY;
4291 goto fail;
4294 req = cli_getatr_send(frame, ev, cli, fname);
4295 if (req == NULL) {
4296 status = NT_STATUS_NO_MEMORY;
4297 goto fail;
4300 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4301 goto fail;
4304 status = cli_getatr_recv(req,
4305 pattr,
4306 size,
4307 write_time);
4309 fail:
4310 TALLOC_FREE(frame);
4311 return status;
4314 /****************************************************************************
4315 Do a SMBsetattrE call.
4316 ****************************************************************************/
4318 static void cli_setattrE_done(struct tevent_req *subreq);
4320 struct cli_setattrE_state {
4321 uint16_t vwv[7];
4324 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
4325 struct tevent_context *ev,
4326 struct cli_state *cli,
4327 uint16_t fnum,
4328 time_t change_time,
4329 time_t access_time,
4330 time_t write_time)
4332 struct tevent_req *req = NULL, *subreq = NULL;
4333 struct cli_setattrE_state *state = NULL;
4334 uint8_t additional_flags = 0;
4336 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
4337 if (req == NULL) {
4338 return NULL;
4341 SSVAL(state->vwv+0, 0, fnum);
4342 push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
4343 smb1cli_conn_server_time_zone(cli->conn));
4344 push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
4345 smb1cli_conn_server_time_zone(cli->conn));
4346 push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
4347 smb1cli_conn_server_time_zone(cli->conn));
4349 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
4350 7, state->vwv, 0, NULL);
4351 if (tevent_req_nomem(subreq, req)) {
4352 return tevent_req_post(req, ev);
4354 tevent_req_set_callback(subreq, cli_setattrE_done, req);
4355 return req;
4358 static void cli_setattrE_done(struct tevent_req *subreq)
4360 struct tevent_req *req = tevent_req_callback_data(
4361 subreq, struct tevent_req);
4362 NTSTATUS status;
4364 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4365 TALLOC_FREE(subreq);
4366 if (tevent_req_nterror(req, status)) {
4367 return;
4369 tevent_req_done(req);
4372 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4374 return tevent_req_simple_recv_ntstatus(req);
4377 NTSTATUS cli_setattrE(struct cli_state *cli,
4378 uint16_t fnum,
4379 time_t change_time,
4380 time_t access_time,
4381 time_t write_time)
4383 TALLOC_CTX *frame = NULL;
4384 struct tevent_context *ev = NULL;
4385 struct tevent_req *req = NULL;
4386 NTSTATUS status = NT_STATUS_OK;
4388 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4389 return cli_smb2_setattrE(cli,
4390 fnum,
4391 change_time,
4392 access_time,
4393 write_time);
4396 frame = talloc_stackframe();
4398 if (smbXcli_conn_has_async_calls(cli->conn)) {
4400 * Can't use sync call while an async call is in flight
4402 status = NT_STATUS_INVALID_PARAMETER;
4403 goto fail;
4406 ev = samba_tevent_context_init(frame);
4407 if (ev == NULL) {
4408 status = NT_STATUS_NO_MEMORY;
4409 goto fail;
4412 req = cli_setattrE_send(frame, ev,
4413 cli,
4414 fnum,
4415 change_time,
4416 access_time,
4417 write_time);
4419 if (req == NULL) {
4420 status = NT_STATUS_NO_MEMORY;
4421 goto fail;
4424 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4425 goto fail;
4428 status = cli_setattrE_recv(req);
4430 fail:
4431 TALLOC_FREE(frame);
4432 return status;
4435 /****************************************************************************
4436 Do a SMBsetatr call.
4437 ****************************************************************************/
4439 static void cli_setatr_done(struct tevent_req *subreq);
4441 struct cli_setatr_state {
4442 uint16_t vwv[8];
4445 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
4446 struct tevent_context *ev,
4447 struct cli_state *cli,
4448 const char *fname,
4449 uint32_t attr,
4450 time_t mtime)
4452 struct tevent_req *req = NULL, *subreq = NULL;
4453 struct cli_setatr_state *state = NULL;
4454 uint8_t additional_flags = 0;
4455 uint16_t additional_flags2 = 0;
4456 uint8_t *bytes = NULL;
4458 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
4459 if (req == NULL) {
4460 return NULL;
4463 if (attr & 0xFFFF0000) {
4465 * Don't allow attributes greater than
4466 * 16-bits for a 16-bit protocol value.
4468 if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
4469 return tevent_req_post(req, ev);
4473 SSVAL(state->vwv+0, 0, attr);
4474 push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
4476 bytes = talloc_array(state, uint8_t, 1);
4477 if (tevent_req_nomem(bytes, req)) {
4478 return tevent_req_post(req, ev);
4480 bytes[0] = 4;
4481 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4482 strlen(fname)+1, NULL);
4483 if (tevent_req_nomem(bytes, req)) {
4484 return tevent_req_post(req, ev);
4486 bytes = talloc_realloc(state, bytes, uint8_t,
4487 talloc_get_size(bytes)+1);
4488 if (tevent_req_nomem(bytes, req)) {
4489 return tevent_req_post(req, ev);
4492 bytes[talloc_get_size(bytes)-1] = 4;
4493 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
4494 1, NULL);
4495 if (tevent_req_nomem(bytes, req)) {
4496 return tevent_req_post(req, ev);
4499 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4500 additional_flags2 = FLAGS2_REPARSE_PATH;
4503 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
4504 additional_flags2,
4505 8, state->vwv, talloc_get_size(bytes), bytes);
4506 if (tevent_req_nomem(subreq, req)) {
4507 return tevent_req_post(req, ev);
4509 tevent_req_set_callback(subreq, cli_setatr_done, req);
4510 return req;
4513 static void cli_setatr_done(struct tevent_req *subreq)
4515 struct tevent_req *req = tevent_req_callback_data(
4516 subreq, struct tevent_req);
4517 NTSTATUS status;
4519 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4520 TALLOC_FREE(subreq);
4521 if (tevent_req_nterror(req, status)) {
4522 return;
4524 tevent_req_done(req);
4527 NTSTATUS cli_setatr_recv(struct tevent_req *req)
4529 return tevent_req_simple_recv_ntstatus(req);
4532 NTSTATUS cli_setatr(struct cli_state *cli,
4533 const char *fname,
4534 uint32_t attr,
4535 time_t mtime)
4537 TALLOC_CTX *frame = NULL;
4538 struct tevent_context *ev = NULL;
4539 struct tevent_req *req = NULL;
4540 NTSTATUS status = NT_STATUS_OK;
4542 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4543 return cli_smb2_setatr(cli,
4544 fname,
4545 attr,
4546 mtime);
4549 frame = talloc_stackframe();
4551 if (smbXcli_conn_has_async_calls(cli->conn)) {
4553 * Can't use sync call while an async call is in flight
4555 status = NT_STATUS_INVALID_PARAMETER;
4556 goto fail;
4559 ev = samba_tevent_context_init(frame);
4560 if (ev == NULL) {
4561 status = NT_STATUS_NO_MEMORY;
4562 goto fail;
4565 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
4566 if (req == NULL) {
4567 status = NT_STATUS_NO_MEMORY;
4568 goto fail;
4571 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4572 goto fail;
4575 status = cli_setatr_recv(req);
4577 fail:
4578 TALLOC_FREE(frame);
4579 return status;
4582 /****************************************************************************
4583 Check for existence of a dir.
4584 ****************************************************************************/
4586 static void cli_chkpath_done(struct tevent_req *subreq);
4587 static void cli_chkpath_done2(struct tevent_req *subreq);
4589 struct cli_chkpath_state {
4590 int dummy;
4593 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
4594 struct tevent_context *ev,
4595 struct cli_state *cli,
4596 const char *fname)
4598 struct tevent_req *req = NULL, *subreq = NULL;
4599 struct cli_chkpath_state *state = NULL;
4600 uint8_t additional_flags = 0;
4601 uint16_t additional_flags2 = 0;
4602 uint8_t *bytes = NULL;
4604 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
4605 if (req == NULL) {
4606 return NULL;
4609 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4610 subreq = cli_smb2_chkpath_send(state, ev, cli, fname);
4611 if (tevent_req_nomem(subreq, req)) {
4612 return tevent_req_post(req, ev);
4614 tevent_req_set_callback(subreq, cli_chkpath_done2, req);
4615 return req;
4618 bytes = talloc_array(state, uint8_t, 1);
4619 if (tevent_req_nomem(bytes, req)) {
4620 return tevent_req_post(req, ev);
4622 bytes[0] = 4;
4623 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4624 strlen(fname)+1, NULL);
4626 if (tevent_req_nomem(bytes, req)) {
4627 return tevent_req_post(req, ev);
4630 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4631 additional_flags2 = FLAGS2_REPARSE_PATH;
4634 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
4635 additional_flags2,
4636 0, NULL, talloc_get_size(bytes), bytes);
4637 if (tevent_req_nomem(subreq, req)) {
4638 return tevent_req_post(req, ev);
4640 tevent_req_set_callback(subreq, cli_chkpath_done, req);
4641 return req;
4644 static void cli_chkpath_done(struct tevent_req *subreq)
4646 struct tevent_req *req = tevent_req_callback_data(
4647 subreq, struct tevent_req);
4648 NTSTATUS status;
4650 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4651 TALLOC_FREE(subreq);
4652 if (tevent_req_nterror(req, status)) {
4653 return;
4655 tevent_req_done(req);
4658 static void cli_chkpath_done2(struct tevent_req *subreq)
4660 NTSTATUS status = cli_smb2_chkpath_recv(subreq);
4661 tevent_req_simple_finish_ntstatus(subreq, status);
4664 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
4666 return tevent_req_simple_recv_ntstatus(req);
4669 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
4671 TALLOC_CTX *frame = NULL;
4672 struct tevent_context *ev = NULL;
4673 struct tevent_req *req = NULL;
4674 char *path2 = NULL;
4675 NTSTATUS status = NT_STATUS_OK;
4677 frame = talloc_stackframe();
4679 if (smbXcli_conn_has_async_calls(cli->conn)) {
4681 * Can't use sync call while an async call is in flight
4683 status = NT_STATUS_INVALID_PARAMETER;
4684 goto fail;
4687 path2 = talloc_strdup(frame, path);
4688 if (!path2) {
4689 status = NT_STATUS_NO_MEMORY;
4690 goto fail;
4692 trim_char(path2,'\0','\\');
4693 if (!*path2) {
4694 path2 = talloc_strdup(frame, "\\");
4695 if (!path2) {
4696 status = NT_STATUS_NO_MEMORY;
4697 goto fail;
4701 ev = samba_tevent_context_init(frame);
4702 if (ev == NULL) {
4703 status = NT_STATUS_NO_MEMORY;
4704 goto fail;
4707 req = cli_chkpath_send(frame, ev, cli, path2);
4708 if (req == NULL) {
4709 status = NT_STATUS_NO_MEMORY;
4710 goto fail;
4713 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4714 goto fail;
4717 status = cli_chkpath_recv(req);
4718 cli->raw_status = status; /* cli_smb2_chkpath_recv doesn't set this */
4720 fail:
4721 TALLOC_FREE(frame);
4722 return status;
4725 /****************************************************************************
4726 Query disk space.
4727 ****************************************************************************/
4729 static void cli_dskattr_done(struct tevent_req *subreq);
4731 struct cli_dskattr_state {
4732 int bsize;
4733 int total;
4734 int avail;
4737 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
4738 struct tevent_context *ev,
4739 struct cli_state *cli)
4741 struct tevent_req *req = NULL, *subreq = NULL;
4742 struct cli_dskattr_state *state = NULL;
4743 uint8_t additional_flags = 0;
4745 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
4746 if (req == NULL) {
4747 return NULL;
4750 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
4751 0, NULL, 0, NULL);
4752 if (tevent_req_nomem(subreq, req)) {
4753 return tevent_req_post(req, ev);
4755 tevent_req_set_callback(subreq, cli_dskattr_done, req);
4756 return req;
4759 static void cli_dskattr_done(struct tevent_req *subreq)
4761 struct tevent_req *req = tevent_req_callback_data(
4762 subreq, struct tevent_req);
4763 struct cli_dskattr_state *state = tevent_req_data(
4764 req, struct cli_dskattr_state);
4765 uint8_t wct;
4766 uint16_t *vwv = NULL;
4767 NTSTATUS status;
4769 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4770 NULL);
4771 TALLOC_FREE(subreq);
4772 if (tevent_req_nterror(req, status)) {
4773 return;
4775 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
4776 state->total = SVAL(vwv+0, 0);
4777 state->avail = SVAL(vwv+3, 0);
4778 tevent_req_done(req);
4781 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
4783 struct cli_dskattr_state *state = tevent_req_data(
4784 req, struct cli_dskattr_state);
4785 NTSTATUS status;
4787 if (tevent_req_is_nterror(req, &status)) {
4788 return status;
4790 *bsize = state->bsize;
4791 *total = state->total;
4792 *avail = state->avail;
4793 return NT_STATUS_OK;
4796 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
4798 TALLOC_CTX *frame = NULL;
4799 struct tevent_context *ev = NULL;
4800 struct tevent_req *req = NULL;
4801 NTSTATUS status = NT_STATUS_OK;
4803 frame = talloc_stackframe();
4805 if (smbXcli_conn_has_async_calls(cli->conn)) {
4807 * Can't use sync call while an async call is in flight
4809 status = NT_STATUS_INVALID_PARAMETER;
4810 goto fail;
4813 ev = samba_tevent_context_init(frame);
4814 if (ev == NULL) {
4815 status = NT_STATUS_NO_MEMORY;
4816 goto fail;
4819 req = cli_dskattr_send(frame, ev, cli);
4820 if (req == NULL) {
4821 status = NT_STATUS_NO_MEMORY;
4822 goto fail;
4825 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4826 goto fail;
4829 status = cli_dskattr_recv(req, bsize, total, avail);
4831 fail:
4832 TALLOC_FREE(frame);
4833 return status;
4836 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
4837 uint64_t *total, uint64_t *avail)
4839 uint64_t sectors_per_block;
4840 uint64_t bytes_per_sector;
4841 int old_bsize = 0, old_total = 0, old_avail = 0;
4842 NTSTATUS status;
4844 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4845 return cli_smb2_dskattr(cli, path, bsize, total, avail);
4849 * Try the trans2 disk full size info call first.
4850 * We already use this in SMBC_fstatvfs_ctx().
4851 * Ignore 'actual_available_units' as we only
4852 * care about the quota for the caller.
4855 status = cli_get_fs_full_size_info(cli,
4856 total,
4857 avail,
4858 NULL,
4859 &sectors_per_block,
4860 &bytes_per_sector);
4862 /* Try and cope will all varients of "we don't do this call"
4863 and fall back to cli_dskattr. */
4865 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
4866 NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
4867 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
4868 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
4869 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
4870 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
4871 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
4872 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
4873 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
4874 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
4875 goto try_dskattr;
4878 if (!NT_STATUS_IS_OK(status)) {
4879 return status;
4882 if (bsize) {
4883 *bsize = sectors_per_block *
4884 bytes_per_sector;
4887 return NT_STATUS_OK;
4889 try_dskattr:
4891 /* Old SMB1 core protocol fallback. */
4892 status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
4893 if (!NT_STATUS_IS_OK(status)) {
4894 return status;
4896 if (bsize) {
4897 *bsize = (uint64_t)old_bsize;
4899 if (total) {
4900 *total = (uint64_t)old_total;
4902 if (avail) {
4903 *avail = (uint64_t)old_avail;
4905 return NT_STATUS_OK;
4908 /****************************************************************************
4909 Create and open a temporary file.
4910 ****************************************************************************/
4912 static void cli_ctemp_done(struct tevent_req *subreq);
4914 struct ctemp_state {
4915 uint16_t vwv[3];
4916 char *ret_path;
4917 uint16_t fnum;
4920 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4921 struct tevent_context *ev,
4922 struct cli_state *cli,
4923 const char *path)
4925 struct tevent_req *req = NULL, *subreq = NULL;
4926 struct ctemp_state *state = NULL;
4927 uint8_t additional_flags = 0;
4928 uint16_t additional_flags2 = 0;
4929 uint8_t *bytes = NULL;
4931 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4932 if (req == NULL) {
4933 return NULL;
4936 SSVAL(state->vwv,0,0);
4937 SIVALS(state->vwv+1,0,-1);
4939 bytes = talloc_array(state, uint8_t, 1);
4940 if (tevent_req_nomem(bytes, req)) {
4941 return tevent_req_post(req, ev);
4943 bytes[0] = 4;
4944 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
4945 strlen(path)+1, NULL);
4946 if (tevent_req_nomem(bytes, req)) {
4947 return tevent_req_post(req, ev);
4950 if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
4951 additional_flags2 = FLAGS2_REPARSE_PATH;
4954 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4955 additional_flags2,
4956 3, state->vwv, talloc_get_size(bytes), bytes);
4957 if (tevent_req_nomem(subreq, req)) {
4958 return tevent_req_post(req, ev);
4960 tevent_req_set_callback(subreq, cli_ctemp_done, req);
4961 return req;
4964 static void cli_ctemp_done(struct tevent_req *subreq)
4966 struct tevent_req *req = tevent_req_callback_data(
4967 subreq, struct tevent_req);
4968 struct ctemp_state *state = tevent_req_data(
4969 req, struct ctemp_state);
4970 NTSTATUS status;
4971 uint8_t wcnt;
4972 uint16_t *vwv;
4973 uint32_t num_bytes = 0;
4974 uint8_t *bytes = NULL;
4976 status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
4977 &num_bytes, &bytes);
4978 TALLOC_FREE(subreq);
4979 if (tevent_req_nterror(req, status)) {
4980 return;
4983 state->fnum = SVAL(vwv+0, 0);
4985 /* From W2K3, the result is just the ASCII name */
4986 if (num_bytes < 2) {
4987 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
4988 return;
4991 if (pull_string_talloc(state,
4992 NULL,
4994 &state->ret_path,
4995 bytes,
4996 num_bytes,
4997 STR_ASCII) == 0) {
4998 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4999 return;
5001 tevent_req_done(req);
5004 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
5005 TALLOC_CTX *ctx,
5006 uint16_t *pfnum,
5007 char **outfile)
5009 struct ctemp_state *state = tevent_req_data(req,
5010 struct ctemp_state);
5011 NTSTATUS status;
5013 if (tevent_req_is_nterror(req, &status)) {
5014 return status;
5016 *pfnum = state->fnum;
5017 *outfile = talloc_strdup(ctx, state->ret_path);
5018 if (!*outfile) {
5019 return NT_STATUS_NO_MEMORY;
5021 return NT_STATUS_OK;
5024 NTSTATUS cli_ctemp(struct cli_state *cli,
5025 TALLOC_CTX *ctx,
5026 const char *path,
5027 uint16_t *pfnum,
5028 char **out_path)
5030 TALLOC_CTX *frame = talloc_stackframe();
5031 struct tevent_context *ev;
5032 struct tevent_req *req;
5033 NTSTATUS status = NT_STATUS_OK;
5035 if (smbXcli_conn_has_async_calls(cli->conn)) {
5037 * Can't use sync call while an async call is in flight
5039 status = NT_STATUS_INVALID_PARAMETER;
5040 goto fail;
5043 ev = samba_tevent_context_init(frame);
5044 if (ev == NULL) {
5045 status = NT_STATUS_NO_MEMORY;
5046 goto fail;
5049 req = cli_ctemp_send(frame, ev, cli, path);
5050 if (req == NULL) {
5051 status = NT_STATUS_NO_MEMORY;
5052 goto fail;
5055 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5056 goto fail;
5059 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
5061 fail:
5062 TALLOC_FREE(frame);
5063 return status;
5067 send a raw ioctl - used by the torture code
5069 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
5071 uint16_t vwv[3];
5072 NTSTATUS status;
5074 SSVAL(vwv+0, 0, fnum);
5075 SSVAL(vwv+1, 0, code>>16);
5076 SSVAL(vwv+2, 0, (code&0xFFFF));
5078 status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
5079 NULL, 0, NULL, NULL, NULL, NULL);
5080 if (!NT_STATUS_IS_OK(status)) {
5081 return status;
5083 *blob = data_blob_null;
5084 return NT_STATUS_OK;
5087 /*********************************************************
5088 Set an extended attribute utility fn.
5089 *********************************************************/
5091 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
5092 uint8_t *param, unsigned int param_len,
5093 const char *ea_name,
5094 const char *ea_val, size_t ea_len)
5096 uint16_t setup[1];
5097 unsigned int data_len = 0;
5098 uint8_t *data = NULL;
5099 char *p;
5100 size_t ea_namelen = strlen(ea_name);
5101 NTSTATUS status;
5103 SSVAL(setup, 0, setup_val);
5105 if (ea_namelen == 0 && ea_len == 0) {
5106 data_len = 4;
5107 data = talloc_array(talloc_tos(),
5108 uint8_t,
5109 data_len);
5110 if (!data) {
5111 return NT_STATUS_NO_MEMORY;
5113 p = (char *)data;
5114 SIVAL(p,0,data_len);
5115 } else {
5116 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
5117 data = talloc_array(talloc_tos(),
5118 uint8_t,
5119 data_len);
5120 if (!data) {
5121 return NT_STATUS_NO_MEMORY;
5123 p = (char *)data;
5124 SIVAL(p,0,data_len);
5125 p += 4;
5126 SCVAL(p, 0, 0); /* EA flags. */
5127 SCVAL(p, 1, ea_namelen);
5128 SSVAL(p, 2, ea_len);
5129 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
5130 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
5134 * FIXME - if we want to do previous version path
5135 * processing on an EA set call we need to turn this
5136 * into calls to cli_trans_send()/cli_trans_recv()
5137 * with a temporary event context, as cli_trans_send()
5138 * have access to the additional_flags2 needed to
5139 * send @GMT- paths. JRA.
5142 status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
5143 setup, 1, 0,
5144 param, param_len, 2,
5145 data, data_len, 0,
5146 NULL,
5147 NULL, 0, NULL, /* rsetup */
5148 NULL, 0, NULL, /* rparam */
5149 NULL, 0, NULL); /* rdata */
5150 talloc_free(data);
5151 return status;
5154 /*********************************************************
5155 Set an extended attribute on a pathname.
5156 *********************************************************/
5158 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
5159 const char *ea_name, const char *ea_val,
5160 size_t ea_len)
5162 unsigned int param_len = 0;
5163 uint8_t *param;
5164 NTSTATUS status;
5165 TALLOC_CTX *frame = NULL;
5167 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5168 return cli_smb2_set_ea_path(cli,
5169 path,
5170 ea_name,
5171 ea_val,
5172 ea_len);
5175 frame = talloc_stackframe();
5177 param = talloc_array(frame, uint8_t, 6);
5178 if (!param) {
5179 status = NT_STATUS_NO_MEMORY;
5180 goto fail;
5182 SSVAL(param,0,SMB_INFO_SET_EA);
5183 SSVAL(param,2,0);
5184 SSVAL(param,4,0);
5186 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
5187 path, strlen(path)+1,
5188 NULL);
5189 param_len = talloc_get_size(param);
5191 status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
5192 ea_name, ea_val, ea_len);
5194 fail:
5196 TALLOC_FREE(frame);
5197 return status;
5200 /*********************************************************
5201 Set an extended attribute on an fnum.
5202 *********************************************************/
5204 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
5205 const char *ea_name, const char *ea_val,
5206 size_t ea_len)
5208 uint8_t param[6];
5210 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5211 return cli_smb2_set_ea_fnum(cli,
5212 fnum,
5213 ea_name,
5214 ea_val,
5215 ea_len);
5218 memset(param, 0, 6);
5219 SSVAL(param,0,fnum);
5220 SSVAL(param,2,SMB_INFO_SET_EA);
5222 return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
5223 ea_name, ea_val, ea_len);
5226 /*********************************************************
5227 Get an extended attribute list utility fn.
5228 *********************************************************/
5230 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
5231 size_t rdata_len,
5232 size_t *pnum_eas, struct ea_struct **pea_list)
5234 struct ea_struct *ea_list = NULL;
5235 size_t num_eas;
5236 size_t ea_size;
5237 const uint8_t *p;
5239 if (rdata_len < 4) {
5240 return false;
5243 ea_size = (size_t)IVAL(rdata,0);
5244 if (ea_size > rdata_len) {
5245 return false;
5248 if (ea_size == 0) {
5249 /* No EA's present. */
5250 *pnum_eas = 0;
5251 *pea_list = NULL;
5252 return true;
5255 p = rdata + 4;
5256 ea_size -= 4;
5258 /* Validate the EA list and count it. */
5259 for (num_eas = 0; ea_size >= 4; num_eas++) {
5260 unsigned int ea_namelen = CVAL(p,1);
5261 unsigned int ea_valuelen = SVAL(p,2);
5262 if (ea_namelen == 0) {
5263 return false;
5265 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
5266 return false;
5268 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
5269 p += 4 + ea_namelen + 1 + ea_valuelen;
5272 if (num_eas == 0) {
5273 *pnum_eas = 0;
5274 *pea_list = NULL;
5275 return true;
5278 *pnum_eas = num_eas;
5279 if (!pea_list) {
5280 /* Caller only wants number of EA's. */
5281 return true;
5284 ea_list = talloc_array(ctx, struct ea_struct, num_eas);
5285 if (!ea_list) {
5286 return false;
5289 p = rdata + 4;
5291 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
5292 struct ea_struct *ea = &ea_list[num_eas];
5293 fstring unix_ea_name;
5294 unsigned int ea_namelen = CVAL(p,1);
5295 unsigned int ea_valuelen = SVAL(p,2);
5297 ea->flags = CVAL(p,0);
5298 unix_ea_name[0] = '\0';
5299 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
5300 ea->name = talloc_strdup(ea_list, unix_ea_name);
5301 if (!ea->name) {
5302 goto fail;
5304 /* Ensure the value is null terminated (in case it's a string). */
5305 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
5306 if (!ea->value.data) {
5307 goto fail;
5309 if (ea_valuelen) {
5310 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
5312 ea->value.data[ea_valuelen] = 0;
5313 ea->value.length--;
5314 p += 4 + ea_namelen + 1 + ea_valuelen;
5317 *pea_list = ea_list;
5318 return true;
5320 fail:
5321 TALLOC_FREE(ea_list);
5322 return false;
5325 /*********************************************************
5326 Get an extended attribute list from a pathname.
5327 *********************************************************/
5329 struct cli_get_ea_list_path_state {
5330 uint32_t num_data;
5331 uint8_t *data;
5334 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
5336 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
5337 struct tevent_context *ev,
5338 struct cli_state *cli,
5339 const char *fname)
5341 struct tevent_req *req, *subreq;
5342 struct cli_get_ea_list_path_state *state;
5344 req = tevent_req_create(mem_ctx, &state,
5345 struct cli_get_ea_list_path_state);
5346 if (req == NULL) {
5347 return NULL;
5349 subreq = cli_qpathinfo_send(state, ev, cli, fname,
5350 SMB_INFO_QUERY_ALL_EAS, 4,
5351 CLI_BUFFER_SIZE);
5352 if (tevent_req_nomem(subreq, req)) {
5353 return tevent_req_post(req, ev);
5355 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
5356 return req;
5359 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
5361 struct tevent_req *req = tevent_req_callback_data(
5362 subreq, struct tevent_req);
5363 struct cli_get_ea_list_path_state *state = tevent_req_data(
5364 req, struct cli_get_ea_list_path_state);
5365 NTSTATUS status;
5367 status = cli_qpathinfo_recv(subreq, state, &state->data,
5368 &state->num_data);
5369 TALLOC_FREE(subreq);
5370 if (tevent_req_nterror(req, status)) {
5371 return;
5373 tevent_req_done(req);
5376 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5377 size_t *pnum_eas, struct ea_struct **peas)
5379 struct cli_get_ea_list_path_state *state = tevent_req_data(
5380 req, struct cli_get_ea_list_path_state);
5381 NTSTATUS status;
5383 if (tevent_req_is_nterror(req, &status)) {
5384 return status;
5386 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
5387 pnum_eas, peas)) {
5388 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5390 return NT_STATUS_OK;
5393 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
5394 TALLOC_CTX *ctx,
5395 size_t *pnum_eas,
5396 struct ea_struct **pea_list)
5398 TALLOC_CTX *frame = NULL;
5399 struct tevent_context *ev = NULL;
5400 struct tevent_req *req = NULL;
5401 NTSTATUS status = NT_STATUS_NO_MEMORY;
5403 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5404 return cli_smb2_get_ea_list_path(cli,
5405 path,
5406 ctx,
5407 pnum_eas,
5408 pea_list);
5411 frame = talloc_stackframe();
5413 if (smbXcli_conn_has_async_calls(cli->conn)) {
5415 * Can't use sync call while an async call is in flight
5417 status = NT_STATUS_INVALID_PARAMETER;
5418 goto fail;
5420 ev = samba_tevent_context_init(frame);
5421 if (ev == NULL) {
5422 goto fail;
5424 req = cli_get_ea_list_path_send(frame, ev, cli, path);
5425 if (req == NULL) {
5426 goto fail;
5428 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5429 goto fail;
5431 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
5432 fail:
5433 TALLOC_FREE(frame);
5434 return status;
5437 /****************************************************************************
5438 Convert open "flags" arg to uint32_t on wire.
5439 ****************************************************************************/
5441 static uint32_t open_flags_to_wire(int flags)
5443 int open_mode = flags & O_ACCMODE;
5444 uint32_t ret = 0;
5446 switch (open_mode) {
5447 case O_WRONLY:
5448 ret |= SMB_O_WRONLY;
5449 break;
5450 case O_RDWR:
5451 ret |= SMB_O_RDWR;
5452 break;
5453 default:
5454 case O_RDONLY:
5455 ret |= SMB_O_RDONLY;
5456 break;
5459 if (flags & O_CREAT) {
5460 ret |= SMB_O_CREAT;
5462 if (flags & O_EXCL) {
5463 ret |= SMB_O_EXCL;
5465 if (flags & O_TRUNC) {
5466 ret |= SMB_O_TRUNC;
5468 #if defined(O_SYNC)
5469 if (flags & O_SYNC) {
5470 ret |= SMB_O_SYNC;
5472 #endif /* O_SYNC */
5473 if (flags & O_APPEND) {
5474 ret |= SMB_O_APPEND;
5476 #if defined(O_DIRECT)
5477 if (flags & O_DIRECT) {
5478 ret |= SMB_O_DIRECT;
5480 #endif
5481 #if defined(O_DIRECTORY)
5482 if (flags & O_DIRECTORY) {
5483 ret |= SMB_O_DIRECTORY;
5485 #endif
5486 return ret;
5489 /****************************************************************************
5490 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
5491 ****************************************************************************/
5493 struct cli_posix_open_internal_state {
5494 uint16_t setup;
5495 uint8_t *param;
5496 uint8_t data[18];
5497 uint16_t fnum; /* Out */
5500 static void cli_posix_open_internal_done(struct tevent_req *subreq);
5502 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
5503 struct tevent_context *ev,
5504 struct cli_state *cli,
5505 const char *fname,
5506 uint32_t wire_flags,
5507 mode_t mode)
5509 struct tevent_req *req = NULL, *subreq = NULL;
5510 struct cli_posix_open_internal_state *state = NULL;
5512 req = tevent_req_create(
5513 mem_ctx, &state, struct cli_posix_open_internal_state);
5514 if (req == NULL) {
5515 return NULL;
5518 /* Setup setup word. */
5519 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
5521 /* Setup param array. */
5522 state->param = talloc_zero_array(state, uint8_t, 6);
5523 if (tevent_req_nomem(state->param, req)) {
5524 return tevent_req_post(req, ev);
5526 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
5528 state->param = trans2_bytes_push_str(
5529 state->param,
5530 smbXcli_conn_use_unicode(cli->conn),
5531 fname,
5532 strlen(fname)+1,
5533 NULL);
5535 if (tevent_req_nomem(state->param, req)) {
5536 return tevent_req_post(req, ev);
5539 SIVAL(state->data,0,0); /* No oplock. */
5540 SIVAL(state->data,4,wire_flags);
5541 SIVAL(state->data,8,unix_perms_to_wire(mode));
5542 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
5543 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
5545 subreq = cli_trans_send(state, /* mem ctx. */
5546 ev, /* event ctx. */
5547 cli, /* cli_state. */
5548 0, /* additional_flags2 */
5549 SMBtrans2, /* cmd. */
5550 NULL, /* pipe name. */
5551 -1, /* fid. */
5552 0, /* function. */
5553 0, /* flags. */
5554 &state->setup, /* setup. */
5555 1, /* num setup uint16_t words. */
5556 0, /* max returned setup. */
5557 state->param, /* param. */
5558 talloc_get_size(state->param),/* num param. */
5559 2, /* max returned param. */
5560 state->data, /* data. */
5561 18, /* num data. */
5562 12); /* max returned data. */
5564 if (tevent_req_nomem(subreq, req)) {
5565 return tevent_req_post(req, ev);
5567 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
5568 return req;
5571 static void cli_posix_open_internal_done(struct tevent_req *subreq)
5573 struct tevent_req *req = tevent_req_callback_data(
5574 subreq, struct tevent_req);
5575 struct cli_posix_open_internal_state *state = tevent_req_data(
5576 req, struct cli_posix_open_internal_state);
5577 NTSTATUS status;
5578 uint8_t *data;
5579 uint32_t num_data;
5581 status = cli_trans_recv(
5582 subreq,
5583 state,
5584 NULL,
5585 NULL,
5587 NULL,
5588 NULL,
5590 NULL,
5591 &data,
5593 &num_data);
5594 TALLOC_FREE(subreq);
5595 if (tevent_req_nterror(req, status)) {
5596 return;
5598 state->fnum = SVAL(data,2);
5599 tevent_req_done(req);
5602 static NTSTATUS cli_posix_open_internal_recv(struct tevent_req *req,
5603 uint16_t *pfnum)
5605 struct cli_posix_open_internal_state *state = tevent_req_data(
5606 req, struct cli_posix_open_internal_state);
5607 NTSTATUS status;
5609 if (tevent_req_is_nterror(req, &status)) {
5610 return status;
5612 *pfnum = state->fnum;
5613 return NT_STATUS_OK;
5616 struct cli_posix_open_state {
5617 uint16_t fnum;
5620 static void cli_posix_open_done(struct tevent_req *subreq);
5622 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
5623 struct tevent_context *ev,
5624 struct cli_state *cli,
5625 const char *fname,
5626 int flags,
5627 mode_t mode)
5629 struct tevent_req *req = NULL, *subreq = NULL;
5630 struct cli_posix_open_state *state = NULL;
5631 uint32_t wire_flags;
5633 req = tevent_req_create(mem_ctx, &state,
5634 struct cli_posix_open_state);
5635 if (req == NULL) {
5636 return NULL;
5639 wire_flags = open_flags_to_wire(flags);
5641 subreq = cli_posix_open_internal_send(
5642 mem_ctx, ev, cli, fname, wire_flags, mode);
5643 if (tevent_req_nomem(subreq, req)) {
5644 return tevent_req_post(req, ev);
5646 tevent_req_set_callback(subreq, cli_posix_open_done, req);
5647 return req;
5650 static void cli_posix_open_done(struct tevent_req *subreq)
5652 struct tevent_req *req = tevent_req_callback_data(
5653 subreq, struct tevent_req);
5654 struct cli_posix_open_state *state = tevent_req_data(
5655 req, struct cli_posix_open_state);
5656 NTSTATUS status;
5658 status = cli_posix_open_internal_recv(subreq, &state->fnum);
5659 tevent_req_simple_finish_ntstatus(subreq, status);
5662 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
5664 struct cli_posix_open_state *state = tevent_req_data(
5665 req, struct cli_posix_open_state);
5666 NTSTATUS status;
5668 if (tevent_req_is_nterror(req, &status)) {
5669 return status;
5671 *pfnum = state->fnum;
5672 return NT_STATUS_OK;
5675 /****************************************************************************
5676 Open - POSIX semantics. Doesn't request oplock.
5677 ****************************************************************************/
5679 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
5680 int flags, mode_t mode, uint16_t *pfnum)
5683 TALLOC_CTX *frame = talloc_stackframe();
5684 struct tevent_context *ev = NULL;
5685 struct tevent_req *req = NULL;
5686 NTSTATUS status = NT_STATUS_NO_MEMORY;
5688 if (smbXcli_conn_has_async_calls(cli->conn)) {
5690 * Can't use sync call while an async call is in flight
5692 status = NT_STATUS_INVALID_PARAMETER;
5693 goto fail;
5695 ev = samba_tevent_context_init(frame);
5696 if (ev == NULL) {
5697 goto fail;
5699 req = cli_posix_open_send(
5700 frame, ev, cli, fname, flags, mode);
5701 if (req == NULL) {
5702 goto fail;
5704 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5705 goto fail;
5707 status = cli_posix_open_recv(req, pfnum);
5708 fail:
5709 TALLOC_FREE(frame);
5710 return status;
5713 struct cli_posix_mkdir_state {
5714 struct tevent_context *ev;
5715 struct cli_state *cli;
5718 static void cli_posix_mkdir_done(struct tevent_req *subreq);
5720 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
5721 struct tevent_context *ev,
5722 struct cli_state *cli,
5723 const char *fname,
5724 mode_t mode)
5726 struct tevent_req *req = NULL, *subreq = NULL;
5727 struct cli_posix_mkdir_state *state = NULL;
5728 uint32_t wire_flags;
5730 req = tevent_req_create(
5731 mem_ctx, &state, struct cli_posix_mkdir_state);
5732 if (req == NULL) {
5733 return NULL;
5735 state->ev = ev;
5736 state->cli = cli;
5738 wire_flags = SMB_O_CREAT | SMB_O_DIRECTORY;
5740 subreq = cli_posix_open_internal_send(
5741 mem_ctx, ev, cli, fname, wire_flags, mode);
5742 if (tevent_req_nomem(subreq, req)) {
5743 return tevent_req_post(req, ev);
5745 tevent_req_set_callback(subreq, cli_posix_mkdir_done, req);
5746 return req;
5749 static void cli_posix_mkdir_done(struct tevent_req *subreq)
5751 struct tevent_req *req = tevent_req_callback_data(
5752 subreq, struct tevent_req);
5753 NTSTATUS status;
5754 uint16_t fnum;
5756 status = cli_posix_open_internal_recv(subreq, &fnum);
5757 TALLOC_FREE(subreq);
5758 if (tevent_req_nterror(req, status)) {
5759 return;
5761 tevent_req_done(req);
5764 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
5766 return tevent_req_simple_recv_ntstatus(req);
5769 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
5771 TALLOC_CTX *frame = talloc_stackframe();
5772 struct tevent_context *ev = NULL;
5773 struct tevent_req *req = NULL;
5774 NTSTATUS status = NT_STATUS_NO_MEMORY;
5776 if (smbXcli_conn_has_async_calls(cli->conn)) {
5778 * Can't use sync call while an async call is in flight
5780 status = NT_STATUS_INVALID_PARAMETER;
5781 goto fail;
5784 ev = samba_tevent_context_init(frame);
5785 if (ev == NULL) {
5786 goto fail;
5788 req = cli_posix_mkdir_send(
5789 frame, ev, cli, fname, mode);
5790 if (req == NULL) {
5791 goto fail;
5793 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5794 goto fail;
5796 status = cli_posix_mkdir_recv(req);
5797 fail:
5798 TALLOC_FREE(frame);
5799 return status;
5802 /****************************************************************************
5803 unlink or rmdir - POSIX semantics.
5804 ****************************************************************************/
5806 struct cli_posix_unlink_internal_state {
5807 uint8_t data[2];
5810 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
5812 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
5813 struct tevent_context *ev,
5814 struct cli_state *cli,
5815 const char *fname,
5816 uint16_t level)
5818 struct tevent_req *req = NULL, *subreq = NULL;
5819 struct cli_posix_unlink_internal_state *state = NULL;
5821 req = tevent_req_create(mem_ctx, &state,
5822 struct cli_posix_unlink_internal_state);
5823 if (req == NULL) {
5824 return NULL;
5827 /* Setup data word. */
5828 SSVAL(state->data, 0, level);
5830 subreq = cli_setpathinfo_send(state, ev, cli,
5831 SMB_POSIX_PATH_UNLINK,
5832 fname,
5833 state->data, sizeof(state->data));
5834 if (tevent_req_nomem(subreq, req)) {
5835 return tevent_req_post(req, ev);
5837 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
5838 return req;
5841 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
5843 NTSTATUS status = cli_setpathinfo_recv(subreq);
5844 tevent_req_simple_finish_ntstatus(subreq, status);
5847 static NTSTATUS cli_posix_unlink_internal_recv(struct tevent_req *req)
5849 return tevent_req_simple_recv_ntstatus(req);
5852 struct cli_posix_unlink_state {
5853 uint8_t dummy;
5856 static void cli_posix_unlink_done(struct tevent_req *subreq);
5858 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
5859 struct tevent_context *ev,
5860 struct cli_state *cli,
5861 const char *fname)
5863 struct tevent_req *req = NULL, *subreq = NULL;
5864 struct cli_posix_unlink_state *state;
5866 req = tevent_req_create(
5867 mem_ctx, &state, struct cli_posix_unlink_state);
5868 if (req == NULL) {
5869 return NULL;
5871 subreq = cli_posix_unlink_internal_send(
5872 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_FILE_TARGET);
5873 if (tevent_req_nomem(subreq, req)) {
5874 return tevent_req_post(req, ev);
5876 tevent_req_set_callback(subreq, cli_posix_unlink_done, req);
5877 return req;
5880 static void cli_posix_unlink_done(struct tevent_req *subreq)
5882 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
5883 tevent_req_simple_finish_ntstatus(subreq, status);
5886 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
5888 return tevent_req_simple_recv_ntstatus(req);
5891 /****************************************************************************
5892 unlink - POSIX semantics.
5893 ****************************************************************************/
5895 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
5897 TALLOC_CTX *frame = talloc_stackframe();
5898 struct tevent_context *ev = NULL;
5899 struct tevent_req *req = NULL;
5900 NTSTATUS status = NT_STATUS_OK;
5902 if (smbXcli_conn_has_async_calls(cli->conn)) {
5904 * Can't use sync call while an async call is in flight
5906 status = NT_STATUS_INVALID_PARAMETER;
5907 goto fail;
5910 ev = samba_tevent_context_init(frame);
5911 if (ev == NULL) {
5912 status = NT_STATUS_NO_MEMORY;
5913 goto fail;
5916 req = cli_posix_unlink_send(frame,
5918 cli,
5919 fname);
5920 if (req == NULL) {
5921 status = NT_STATUS_NO_MEMORY;
5922 goto fail;
5925 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5926 goto fail;
5929 status = cli_posix_unlink_recv(req);
5931 fail:
5932 TALLOC_FREE(frame);
5933 return status;
5936 /****************************************************************************
5937 rmdir - POSIX semantics.
5938 ****************************************************************************/
5940 struct cli_posix_rmdir_state {
5941 uint8_t dummy;
5944 static void cli_posix_rmdir_done(struct tevent_req *subreq);
5946 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
5947 struct tevent_context *ev,
5948 struct cli_state *cli,
5949 const char *fname)
5951 struct tevent_req *req = NULL, *subreq = NULL;
5952 struct cli_posix_rmdir_state *state;
5954 req = tevent_req_create(mem_ctx, &state, struct cli_posix_rmdir_state);
5955 if (req == NULL) {
5956 return NULL;
5958 subreq = cli_posix_unlink_internal_send(
5959 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_DIRECTORY_TARGET);
5960 if (tevent_req_nomem(subreq, req)) {
5961 return tevent_req_post(req, ev);
5963 tevent_req_set_callback(subreq, cli_posix_rmdir_done, req);
5964 return req;
5967 static void cli_posix_rmdir_done(struct tevent_req *subreq)
5969 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
5970 tevent_req_simple_finish_ntstatus(subreq, status);
5973 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
5975 return tevent_req_simple_recv_ntstatus(req);
5978 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
5980 TALLOC_CTX *frame = talloc_stackframe();
5981 struct tevent_context *ev = NULL;
5982 struct tevent_req *req = NULL;
5983 NTSTATUS status = NT_STATUS_OK;
5985 if (smbXcli_conn_has_async_calls(cli->conn)) {
5987 * Can't use sync call while an async call is in flight
5989 status = NT_STATUS_INVALID_PARAMETER;
5990 goto fail;
5993 ev = samba_tevent_context_init(frame);
5994 if (ev == NULL) {
5995 status = NT_STATUS_NO_MEMORY;
5996 goto fail;
5999 req = cli_posix_rmdir_send(frame,
6001 cli,
6002 fname);
6003 if (req == NULL) {
6004 status = NT_STATUS_NO_MEMORY;
6005 goto fail;
6008 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6009 goto fail;
6012 status = cli_posix_rmdir_recv(req, frame);
6014 fail:
6015 TALLOC_FREE(frame);
6016 return status;
6019 /****************************************************************************
6020 filechangenotify
6021 ****************************************************************************/
6023 struct cli_notify_state {
6024 struct tevent_req *subreq;
6025 uint8_t setup[8];
6026 uint32_t num_changes;
6027 struct notify_change *changes;
6030 static void cli_notify_done(struct tevent_req *subreq);
6031 static void cli_notify_done_smb2(struct tevent_req *subreq);
6032 static bool cli_notify_cancel(struct tevent_req *req);
6034 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
6035 struct tevent_context *ev,
6036 struct cli_state *cli, uint16_t fnum,
6037 uint32_t buffer_size,
6038 uint32_t completion_filter, bool recursive)
6040 struct tevent_req *req;
6041 struct cli_notify_state *state;
6042 unsigned old_timeout;
6044 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
6045 if (req == NULL) {
6046 return NULL;
6049 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6051 * Notifies should not time out
6053 old_timeout = cli_set_timeout(cli, 0);
6055 state->subreq = cli_smb2_notify_send(
6056 state,
6058 cli,
6059 fnum,
6060 buffer_size,
6061 completion_filter,
6062 recursive);
6064 cli_set_timeout(cli, old_timeout);
6066 if (tevent_req_nomem(state->subreq, req)) {
6067 return tevent_req_post(req, ev);
6069 tevent_req_set_callback(
6070 state->subreq, cli_notify_done_smb2, req);
6071 goto done;
6074 SIVAL(state->setup, 0, completion_filter);
6075 SSVAL(state->setup, 4, fnum);
6076 SSVAL(state->setup, 6, recursive);
6079 * Notifies should not time out
6081 old_timeout = cli_set_timeout(cli, 0);
6083 state->subreq = cli_trans_send(
6084 state, /* mem ctx. */
6085 ev, /* event ctx. */
6086 cli, /* cli_state. */
6087 0, /* additional_flags2 */
6088 SMBnttrans, /* cmd. */
6089 NULL, /* pipe name. */
6090 -1, /* fid. */
6091 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
6092 0, /* flags. */
6093 (uint16_t *)state->setup, /* setup. */
6094 4, /* num setup uint16_t words. */
6095 0, /* max returned setup. */
6096 NULL, /* param. */
6097 0, /* num param. */
6098 buffer_size, /* max returned param. */
6099 NULL, /* data. */
6100 0, /* num data. */
6101 0); /* max returned data. */
6103 cli_set_timeout(cli, old_timeout);
6105 if (tevent_req_nomem(state->subreq, req)) {
6106 return tevent_req_post(req, ev);
6108 tevent_req_set_callback(state->subreq, cli_notify_done, req);
6109 done:
6110 tevent_req_set_cancel_fn(req, cli_notify_cancel);
6111 return req;
6114 static bool cli_notify_cancel(struct tevent_req *req)
6116 struct cli_notify_state *state = tevent_req_data(
6117 req, struct cli_notify_state);
6118 bool ok;
6120 ok = tevent_req_cancel(state->subreq);
6121 return ok;
6124 static void cli_notify_done(struct tevent_req *subreq)
6126 struct tevent_req *req = tevent_req_callback_data(
6127 subreq, struct tevent_req);
6128 struct cli_notify_state *state = tevent_req_data(
6129 req, struct cli_notify_state);
6130 NTSTATUS status;
6131 uint8_t *params;
6132 uint32_t i, ofs, num_params;
6133 uint16_t flags2;
6135 status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
6136 &params, 0, &num_params, NULL, 0, NULL);
6137 TALLOC_FREE(subreq);
6138 state->subreq = NULL;
6139 if (tevent_req_nterror(req, status)) {
6140 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
6141 return;
6144 state->num_changes = 0;
6145 ofs = 0;
6147 while (num_params - ofs > 12) {
6148 uint32_t next = IVAL(params, ofs);
6149 state->num_changes += 1;
6151 if ((next == 0) || (ofs+next >= num_params)) {
6152 break;
6154 ofs += next;
6157 state->changes = talloc_array(state, struct notify_change,
6158 state->num_changes);
6159 if (tevent_req_nomem(state->changes, req)) {
6160 TALLOC_FREE(params);
6161 return;
6164 ofs = 0;
6166 for (i=0; i<state->num_changes; i++) {
6167 uint32_t next = IVAL(params, ofs);
6168 uint32_t len = IVAL(params, ofs+8);
6169 ssize_t ret;
6170 char *name;
6172 if (trans_oob(num_params, ofs + 12, len)) {
6173 TALLOC_FREE(params);
6174 tevent_req_nterror(
6175 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
6176 return;
6179 state->changes[i].action = IVAL(params, ofs+4);
6180 ret = pull_string_talloc(state->changes,
6181 (char *)params,
6182 flags2,
6183 &name,
6184 params+ofs+12,
6185 len,
6186 STR_TERMINATE|STR_UNICODE);
6187 if (ret == -1) {
6188 TALLOC_FREE(params);
6189 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
6190 return;
6192 state->changes[i].name = name;
6193 ofs += next;
6196 TALLOC_FREE(params);
6197 tevent_req_done(req);
6200 static void cli_notify_done_smb2(struct tevent_req *subreq)
6202 struct tevent_req *req = tevent_req_callback_data(
6203 subreq, struct tevent_req);
6204 struct cli_notify_state *state = tevent_req_data(
6205 req, struct cli_notify_state);
6206 NTSTATUS status;
6208 status = cli_smb2_notify_recv(
6209 subreq,
6210 state,
6211 &state->changes,
6212 &state->num_changes);
6213 TALLOC_FREE(subreq);
6214 if (tevent_req_nterror(req, status)) {
6215 return;
6217 tevent_req_done(req);
6220 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6221 uint32_t *pnum_changes,
6222 struct notify_change **pchanges)
6224 struct cli_notify_state *state = tevent_req_data(
6225 req, struct cli_notify_state);
6226 NTSTATUS status;
6228 if (tevent_req_is_nterror(req, &status)) {
6229 return status;
6232 *pnum_changes = state->num_changes;
6233 *pchanges = talloc_move(mem_ctx, &state->changes);
6234 return NT_STATUS_OK;
6237 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
6238 uint32_t completion_filter, bool recursive,
6239 TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
6240 struct notify_change **pchanges)
6242 TALLOC_CTX *frame;
6243 struct tevent_context *ev;
6244 struct tevent_req *req;
6245 NTSTATUS status = NT_STATUS_NO_MEMORY;
6247 frame = talloc_stackframe();
6249 if (smbXcli_conn_has_async_calls(cli->conn)) {
6251 * Can't use sync call while an async call is in flight
6253 status = NT_STATUS_INVALID_PARAMETER;
6254 goto fail;
6256 ev = samba_tevent_context_init(frame);
6257 if (ev == NULL) {
6258 goto fail;
6260 req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
6261 completion_filter, recursive);
6262 if (req == NULL) {
6263 goto fail;
6265 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6266 goto fail;
6268 status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
6269 fail:
6270 TALLOC_FREE(frame);
6271 return status;
6274 struct cli_qpathinfo_state {
6275 uint8_t *param;
6276 uint8_t *data;
6277 uint16_t setup[1];
6278 uint32_t min_rdata;
6279 uint8_t *rdata;
6280 uint32_t num_rdata;
6283 static void cli_qpathinfo_done(struct tevent_req *subreq);
6285 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
6286 struct tevent_context *ev,
6287 struct cli_state *cli, const char *fname,
6288 uint16_t level, uint32_t min_rdata,
6289 uint32_t max_rdata)
6291 struct tevent_req *req, *subreq;
6292 struct cli_qpathinfo_state *state;
6293 uint16_t additional_flags2 = 0;
6295 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
6296 if (req == NULL) {
6297 return NULL;
6299 state->min_rdata = min_rdata;
6300 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
6302 state->param = talloc_zero_array(state, uint8_t, 6);
6303 if (tevent_req_nomem(state->param, req)) {
6304 return tevent_req_post(req, ev);
6306 SSVAL(state->param, 0, level);
6307 state->param = trans2_bytes_push_str(
6308 state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
6309 if (tevent_req_nomem(state->param, req)) {
6310 return tevent_req_post(req, ev);
6313 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
6314 !INFO_LEVEL_IS_UNIX(level)) {
6315 additional_flags2 = FLAGS2_REPARSE_PATH;
6318 subreq = cli_trans_send(
6319 state, /* mem ctx. */
6320 ev, /* event ctx. */
6321 cli, /* cli_state. */
6322 additional_flags2, /* additional_flags2 */
6323 SMBtrans2, /* cmd. */
6324 NULL, /* pipe name. */
6325 -1, /* fid. */
6326 0, /* function. */
6327 0, /* flags. */
6328 state->setup, /* setup. */
6329 1, /* num setup uint16_t words. */
6330 0, /* max returned setup. */
6331 state->param, /* param. */
6332 talloc_get_size(state->param), /* num param. */
6333 2, /* max returned param. */
6334 NULL, /* data. */
6335 0, /* num data. */
6336 max_rdata); /* max returned data. */
6338 if (tevent_req_nomem(subreq, req)) {
6339 return tevent_req_post(req, ev);
6341 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
6342 return req;
6345 static void cli_qpathinfo_done(struct tevent_req *subreq)
6347 struct tevent_req *req = tevent_req_callback_data(
6348 subreq, struct tevent_req);
6349 struct cli_qpathinfo_state *state = tevent_req_data(
6350 req, struct cli_qpathinfo_state);
6351 NTSTATUS status;
6353 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
6354 NULL, 0, NULL,
6355 &state->rdata, state->min_rdata,
6356 &state->num_rdata);
6357 if (tevent_req_nterror(req, status)) {
6358 return;
6360 tevent_req_done(req);
6363 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6364 uint8_t **rdata, uint32_t *num_rdata)
6366 struct cli_qpathinfo_state *state = tevent_req_data(
6367 req, struct cli_qpathinfo_state);
6368 NTSTATUS status;
6370 if (tevent_req_is_nterror(req, &status)) {
6371 return status;
6373 if (rdata != NULL) {
6374 *rdata = talloc_move(mem_ctx, &state->rdata);
6375 } else {
6376 TALLOC_FREE(state->rdata);
6378 if (num_rdata != NULL) {
6379 *num_rdata = state->num_rdata;
6381 return NT_STATUS_OK;
6384 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6385 const char *fname, uint16_t level, uint32_t min_rdata,
6386 uint32_t max_rdata,
6387 uint8_t **rdata, uint32_t *num_rdata)
6389 TALLOC_CTX *frame = talloc_stackframe();
6390 struct tevent_context *ev;
6391 struct tevent_req *req;
6392 NTSTATUS status = NT_STATUS_NO_MEMORY;
6394 if (smbXcli_conn_has_async_calls(cli->conn)) {
6396 * Can't use sync call while an async call is in flight
6398 status = NT_STATUS_INVALID_PARAMETER;
6399 goto fail;
6401 ev = samba_tevent_context_init(frame);
6402 if (ev == NULL) {
6403 goto fail;
6405 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
6406 max_rdata);
6407 if (req == NULL) {
6408 goto fail;
6410 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6411 goto fail;
6413 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
6414 fail:
6415 TALLOC_FREE(frame);
6416 return status;
6419 struct cli_qfileinfo_state {
6420 uint16_t setup[1];
6421 uint8_t param[4];
6422 uint8_t *data;
6423 uint16_t recv_flags2;
6424 uint32_t min_rdata;
6425 uint8_t *rdata;
6426 uint32_t num_rdata;
6429 static void cli_qfileinfo_done(struct tevent_req *subreq);
6431 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
6432 struct tevent_context *ev,
6433 struct cli_state *cli, uint16_t fnum,
6434 uint16_t level, uint32_t min_rdata,
6435 uint32_t max_rdata)
6437 struct tevent_req *req, *subreq;
6438 struct cli_qfileinfo_state *state;
6440 req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
6441 if (req == NULL) {
6442 return NULL;
6444 state->min_rdata = min_rdata;
6445 SSVAL(state->param, 0, fnum);
6446 SSVAL(state->param, 2, level);
6447 SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
6449 subreq = cli_trans_send(
6450 state, /* mem ctx. */
6451 ev, /* event ctx. */
6452 cli, /* cli_state. */
6453 0, /* additional_flags2 */
6454 SMBtrans2, /* cmd. */
6455 NULL, /* pipe name. */
6456 -1, /* fid. */
6457 0, /* function. */
6458 0, /* flags. */
6459 state->setup, /* setup. */
6460 1, /* num setup uint16_t words. */
6461 0, /* max returned setup. */
6462 state->param, /* param. */
6463 sizeof(state->param), /* num param. */
6464 2, /* max returned param. */
6465 NULL, /* data. */
6466 0, /* num data. */
6467 max_rdata); /* max returned data. */
6469 if (tevent_req_nomem(subreq, req)) {
6470 return tevent_req_post(req, ev);
6472 tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
6473 return req;
6476 static void cli_qfileinfo_done(struct tevent_req *subreq)
6478 struct tevent_req *req = tevent_req_callback_data(
6479 subreq, struct tevent_req);
6480 struct cli_qfileinfo_state *state = tevent_req_data(
6481 req, struct cli_qfileinfo_state);
6482 NTSTATUS status;
6484 status = cli_trans_recv(subreq, state,
6485 &state->recv_flags2,
6486 NULL, 0, NULL,
6487 NULL, 0, NULL,
6488 &state->rdata, state->min_rdata,
6489 &state->num_rdata);
6490 if (tevent_req_nterror(req, status)) {
6491 return;
6493 tevent_req_done(req);
6496 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6497 uint16_t *recv_flags2,
6498 uint8_t **rdata, uint32_t *num_rdata)
6500 struct cli_qfileinfo_state *state = tevent_req_data(
6501 req, struct cli_qfileinfo_state);
6502 NTSTATUS status;
6504 if (tevent_req_is_nterror(req, &status)) {
6505 return status;
6508 if (recv_flags2 != NULL) {
6509 *recv_flags2 = state->recv_flags2;
6511 if (rdata != NULL) {
6512 *rdata = talloc_move(mem_ctx, &state->rdata);
6514 if (num_rdata != NULL) {
6515 *num_rdata = state->num_rdata;
6518 tevent_req_received(req);
6519 return NT_STATUS_OK;
6522 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6523 uint16_t fnum, uint16_t level, uint32_t min_rdata,
6524 uint32_t max_rdata, uint16_t *recv_flags2,
6525 uint8_t **rdata, uint32_t *num_rdata)
6527 TALLOC_CTX *frame = talloc_stackframe();
6528 struct tevent_context *ev;
6529 struct tevent_req *req;
6530 NTSTATUS status = NT_STATUS_NO_MEMORY;
6532 if (smbXcli_conn_has_async_calls(cli->conn)) {
6534 * Can't use sync call while an async call is in flight
6536 status = NT_STATUS_INVALID_PARAMETER;
6537 goto fail;
6539 ev = samba_tevent_context_init(frame);
6540 if (ev == NULL) {
6541 goto fail;
6543 req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
6544 max_rdata);
6545 if (req == NULL) {
6546 goto fail;
6548 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6549 goto fail;
6551 status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
6552 fail:
6553 TALLOC_FREE(frame);
6554 return status;
6557 struct cli_flush_state {
6558 uint16_t vwv[1];
6561 static void cli_flush_done(struct tevent_req *subreq);
6563 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
6564 struct tevent_context *ev,
6565 struct cli_state *cli,
6566 uint16_t fnum)
6568 struct tevent_req *req, *subreq;
6569 struct cli_flush_state *state;
6571 req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
6572 if (req == NULL) {
6573 return NULL;
6575 SSVAL(state->vwv + 0, 0, fnum);
6577 subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
6578 0, NULL);
6579 if (tevent_req_nomem(subreq, req)) {
6580 return tevent_req_post(req, ev);
6582 tevent_req_set_callback(subreq, cli_flush_done, req);
6583 return req;
6586 static void cli_flush_done(struct tevent_req *subreq)
6588 struct tevent_req *req = tevent_req_callback_data(
6589 subreq, struct tevent_req);
6590 NTSTATUS status;
6592 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
6593 TALLOC_FREE(subreq);
6594 if (tevent_req_nterror(req, status)) {
6595 return;
6597 tevent_req_done(req);
6600 NTSTATUS cli_flush_recv(struct tevent_req *req)
6602 return tevent_req_simple_recv_ntstatus(req);
6605 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
6607 TALLOC_CTX *frame = talloc_stackframe();
6608 struct tevent_context *ev;
6609 struct tevent_req *req;
6610 NTSTATUS status = NT_STATUS_NO_MEMORY;
6612 if (smbXcli_conn_has_async_calls(cli->conn)) {
6614 * Can't use sync call while an async call is in flight
6616 status = NT_STATUS_INVALID_PARAMETER;
6617 goto fail;
6619 ev = samba_tevent_context_init(frame);
6620 if (ev == NULL) {
6621 goto fail;
6623 req = cli_flush_send(frame, ev, cli, fnum);
6624 if (req == NULL) {
6625 goto fail;
6627 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6628 goto fail;
6630 status = cli_flush_recv(req);
6631 fail:
6632 TALLOC_FREE(frame);
6633 return status;
6636 struct cli_shadow_copy_data_state {
6637 uint16_t setup[4];
6638 uint8_t *data;
6639 uint32_t num_data;
6640 bool get_names;
6643 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
6645 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
6646 struct tevent_context *ev,
6647 struct cli_state *cli,
6648 uint16_t fnum,
6649 bool get_names)
6651 struct tevent_req *req, *subreq;
6652 struct cli_shadow_copy_data_state *state;
6653 uint32_t ret_size;
6655 req = tevent_req_create(mem_ctx, &state,
6656 struct cli_shadow_copy_data_state);
6657 if (req == NULL) {
6658 return NULL;
6660 state->get_names = get_names;
6661 ret_size = get_names ? CLI_BUFFER_SIZE : 16;
6663 SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
6664 SSVAL(state->setup + 2, 0, fnum);
6665 SCVAL(state->setup + 3, 0, 1); /* isFsctl */
6666 SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
6668 subreq = cli_trans_send(
6669 state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
6670 state->setup, ARRAY_SIZE(state->setup),
6671 ARRAY_SIZE(state->setup),
6672 NULL, 0, 0,
6673 NULL, 0, ret_size);
6674 if (tevent_req_nomem(subreq, req)) {
6675 return tevent_req_post(req, ev);
6677 tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
6678 return req;
6681 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
6683 struct tevent_req *req = tevent_req_callback_data(
6684 subreq, struct tevent_req);
6685 struct cli_shadow_copy_data_state *state = tevent_req_data(
6686 req, struct cli_shadow_copy_data_state);
6687 NTSTATUS status;
6689 status = cli_trans_recv(subreq, state, NULL,
6690 NULL, 0, NULL, /* setup */
6691 NULL, 0, NULL, /* param */
6692 &state->data, 12, &state->num_data);
6693 TALLOC_FREE(subreq);
6694 if (tevent_req_nterror(req, status)) {
6695 return;
6697 tevent_req_done(req);
6700 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6701 char ***pnames, int *pnum_names)
6703 struct cli_shadow_copy_data_state *state = tevent_req_data(
6704 req, struct cli_shadow_copy_data_state);
6705 char **names = NULL;
6706 uint32_t i, num_names;
6707 uint32_t dlength;
6708 uint8_t *endp = NULL;
6709 NTSTATUS status;
6711 if (tevent_req_is_nterror(req, &status)) {
6712 return status;
6715 if (state->num_data < 16) {
6716 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6719 num_names = IVAL(state->data, 4);
6720 dlength = IVAL(state->data, 8);
6722 if (num_names > 0x7FFFFFFF) {
6723 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6726 if (!state->get_names) {
6727 *pnum_names = (int)num_names;
6728 return NT_STATUS_OK;
6731 if (dlength + 12 < 12) {
6732 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6734 if (dlength + 12 > state->num_data) {
6735 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6737 if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
6738 state->num_data) {
6739 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6742 names = talloc_array(mem_ctx, char *, num_names);
6743 if (names == NULL) {
6744 return NT_STATUS_NO_MEMORY;
6747 endp = state->data + state->num_data;
6749 for (i=0; i<num_names; i++) {
6750 bool ret;
6751 uint8_t *src;
6752 size_t converted_size;
6754 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
6756 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
6757 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6760 ret = convert_string_talloc(
6761 names, CH_UTF16LE, CH_UNIX,
6762 src, 2 * sizeof(SHADOW_COPY_LABEL),
6763 &names[i], &converted_size);
6764 if (!ret) {
6765 TALLOC_FREE(names);
6766 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6769 *pnum_names = (int)num_names;
6770 *pnames = names;
6771 return NT_STATUS_OK;
6774 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6775 uint16_t fnum, bool get_names,
6776 char ***pnames, int *pnum_names)
6778 TALLOC_CTX *frame = NULL;
6779 struct tevent_context *ev;
6780 struct tevent_req *req;
6781 NTSTATUS status = NT_STATUS_NO_MEMORY;
6783 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6784 return cli_smb2_shadow_copy_data(mem_ctx,
6785 cli,
6786 fnum,
6787 get_names,
6788 pnames,
6789 pnum_names);
6792 frame = talloc_stackframe();
6794 if (smbXcli_conn_has_async_calls(cli->conn)) {
6796 * Can't use sync call while an async call is in flight
6798 status = NT_STATUS_INVALID_PARAMETER;
6799 goto fail;
6801 ev = samba_tevent_context_init(frame);
6802 if (ev == NULL) {
6803 goto fail;
6805 req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
6806 if (req == NULL) {
6807 goto fail;
6809 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6810 goto fail;
6812 status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
6813 fail:
6814 TALLOC_FREE(frame);
6815 return status;