libsmb: Change cli_posix_stat_send to take a pointer to sbuf
[Samba.git] / source3 / libsmb / clifile.c
blobe4eb3f286f904bb8b884d745c356c39c7494eb53
1 /*
2 Unix SMB/CIFS implementation.
3 client file operations
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Jeremy Allison 2001-2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "libsmb/libsmb.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "async_smb.h"
26 #include "libsmb/clirap.h"
27 #include "trans2.h"
28 #include "ntioctl.h"
29 #include "libcli/security/secdesc.h"
30 #include "../libcli/smb/smbXcli_base.h"
32 struct cli_setpathinfo_state {
33 uint16_t setup;
34 uint8_t *param;
37 static void cli_setpathinfo_done(struct tevent_req *subreq);
39 struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
40 struct tevent_context *ev,
41 struct cli_state *cli,
42 uint16_t level,
43 const char *path,
44 uint8_t *data,
45 size_t data_len)
47 struct tevent_req *req, *subreq;
48 struct cli_setpathinfo_state *state;
49 uint16_t additional_flags2 = 0;
51 req = tevent_req_create(mem_ctx, &state,
52 struct cli_setpathinfo_state);
53 if (req == NULL) {
54 return NULL;
57 /* Setup setup word. */
58 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
60 /* Setup param array. */
61 state->param = talloc_zero_array(state, uint8_t, 6);
62 if (tevent_req_nomem(state->param, req)) {
63 return tevent_req_post(req, ev);
65 SSVAL(state->param, 0, level);
67 state->param = trans2_bytes_push_str(
68 state->param, smbXcli_conn_use_unicode(cli->conn), path, strlen(path)+1, NULL);
69 if (tevent_req_nomem(state->param, req)) {
70 return tevent_req_post(req, ev);
73 if (clistr_is_previous_version_path(path, NULL, NULL, NULL) &&
74 !INFO_LEVEL_IS_UNIX(level)) {
75 additional_flags2 = FLAGS2_REPARSE_PATH;
78 subreq = cli_trans_send(
79 state, /* mem ctx. */
80 ev, /* event ctx. */
81 cli, /* cli_state. */
82 additional_flags2, /* additional_flags2 */
83 SMBtrans2, /* cmd. */
84 NULL, /* pipe name. */
85 -1, /* fid. */
86 0, /* function. */
87 0, /* flags. */
88 &state->setup, /* setup. */
89 1, /* num setup uint16_t words. */
90 0, /* max returned setup. */
91 state->param, /* param. */
92 talloc_get_size(state->param), /* num param. */
93 2, /* max returned param. */
94 data, /* data. */
95 data_len, /* num data. */
96 0); /* max returned data. */
98 if (tevent_req_nomem(subreq, req)) {
99 return tevent_req_post(req, ev);
101 tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
102 return req;
105 static void cli_setpathinfo_done(struct tevent_req *subreq)
107 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
108 NULL, 0, NULL, NULL, 0, NULL);
109 tevent_req_simple_finish_ntstatus(subreq, status);
112 NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
114 return tevent_req_simple_recv_ntstatus(req);
117 NTSTATUS cli_setpathinfo(struct cli_state *cli,
118 uint16_t level,
119 const char *path,
120 uint8_t *data,
121 size_t data_len)
123 TALLOC_CTX *frame = talloc_stackframe();
124 struct tevent_context *ev;
125 struct tevent_req *req;
126 NTSTATUS status = NT_STATUS_NO_MEMORY;
128 if (smbXcli_conn_has_async_calls(cli->conn)) {
130 * Can't use sync call while an async call is in flight
132 status = NT_STATUS_INVALID_PARAMETER;
133 goto fail;
135 ev = samba_tevent_context_init(frame);
136 if (ev == NULL) {
137 goto fail;
139 req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
140 if (req == NULL) {
141 goto fail;
143 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
144 goto fail;
146 status = cli_setpathinfo_recv(req);
147 fail:
148 TALLOC_FREE(frame);
149 return status;
152 /****************************************************************************
153 Hard/Symlink a file (UNIX extensions).
154 Creates new name (sym)linked to link_target.
155 ****************************************************************************/
157 struct cli_posix_link_internal_state {
158 uint8_t *data;
161 static void cli_posix_link_internal_done(struct tevent_req *subreq);
163 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
164 struct tevent_context *ev,
165 struct cli_state *cli,
166 uint16_t level,
167 const char *link_target,
168 const char *newname)
170 struct tevent_req *req = NULL, *subreq = NULL;
171 struct cli_posix_link_internal_state *state = NULL;
173 req = tevent_req_create(mem_ctx, &state,
174 struct cli_posix_link_internal_state);
175 if (req == NULL) {
176 return NULL;
179 /* Setup data array. */
180 state->data = talloc_array(state, uint8_t, 0);
181 if (tevent_req_nomem(state->data, req)) {
182 return tevent_req_post(req, ev);
184 state->data = trans2_bytes_push_str(
185 state->data, smbXcli_conn_use_unicode(cli->conn),
186 link_target, strlen(link_target)+1, NULL);
188 subreq = cli_setpathinfo_send(
189 state, ev, cli, level, newname,
190 state->data, talloc_get_size(state->data));
191 if (tevent_req_nomem(subreq, req)) {
192 return tevent_req_post(req, ev);
194 tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
195 return req;
198 static void cli_posix_link_internal_done(struct tevent_req *subreq)
200 NTSTATUS status = cli_setpathinfo_recv(subreq);
201 tevent_req_simple_finish_ntstatus(subreq, status);
204 static NTSTATUS cli_posix_link_internal_recv(struct tevent_req *req)
206 return tevent_req_simple_recv_ntstatus(req);
209 /****************************************************************************
210 Symlink a file (UNIX extensions).
211 ****************************************************************************/
213 struct cli_posix_symlink_state {
214 uint8_t dummy;
217 static void cli_posix_symlink_done(struct tevent_req *subreq);
219 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
220 struct tevent_context *ev,
221 struct cli_state *cli,
222 const char *link_target,
223 const char *newname)
225 struct tevent_req *req = NULL, *subreq = NULL;
226 struct cli_posix_symlink_state *state = NULL;
228 req = tevent_req_create(
229 mem_ctx, &state, struct cli_posix_symlink_state);
230 if (req == NULL) {
231 return NULL;
234 subreq = cli_posix_link_internal_send(
235 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, link_target, newname);
236 if (tevent_req_nomem(subreq, req)) {
237 return tevent_req_post(req, ev);
239 tevent_req_set_callback(subreq, cli_posix_symlink_done, req);
240 return req;
243 static void cli_posix_symlink_done(struct tevent_req *subreq)
245 NTSTATUS status = cli_posix_link_internal_recv(subreq);
246 tevent_req_simple_finish_ntstatus(subreq, status);
249 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
251 return tevent_req_simple_recv_ntstatus(req);
254 NTSTATUS cli_posix_symlink(struct cli_state *cli,
255 const char *link_target,
256 const char *newname)
258 TALLOC_CTX *frame = talloc_stackframe();
259 struct tevent_context *ev = NULL;
260 struct tevent_req *req = NULL;
261 NTSTATUS status = NT_STATUS_OK;
263 if (smbXcli_conn_has_async_calls(cli->conn)) {
265 * Can't use sync call while an async call is in flight
267 status = NT_STATUS_INVALID_PARAMETER;
268 goto fail;
271 ev = samba_tevent_context_init(frame);
272 if (ev == NULL) {
273 status = NT_STATUS_NO_MEMORY;
274 goto fail;
277 req = cli_posix_symlink_send(frame,
279 cli,
280 link_target,
281 newname);
282 if (req == NULL) {
283 status = NT_STATUS_NO_MEMORY;
284 goto fail;
287 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
288 goto fail;
291 status = cli_posix_symlink_recv(req);
293 fail:
294 TALLOC_FREE(frame);
295 return status;
298 /****************************************************************************
299 Read a POSIX symlink.
300 ****************************************************************************/
302 struct readlink_state {
303 uint8_t *data;
304 uint32_t num_data;
307 static void cli_posix_readlink_done(struct tevent_req *subreq);
309 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
310 struct tevent_context *ev,
311 struct cli_state *cli,
312 const char *fname,
313 size_t len)
315 struct tevent_req *req = NULL, *subreq = NULL;
316 struct readlink_state *state = NULL;
317 uint32_t maxbytelen = (uint32_t)(smbXcli_conn_use_unicode(cli->conn) ? len*3 : len);
319 req = tevent_req_create(mem_ctx, &state, struct readlink_state);
320 if (req == NULL) {
321 return NULL;
325 * Len is in bytes, we need it in UCS2 units.
327 if ((2*len < len) || (maxbytelen < len)) {
328 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
329 return tevent_req_post(req, ev);
332 subreq = cli_qpathinfo_send(state, ev, cli, fname,
333 SMB_QUERY_FILE_UNIX_LINK, 1, maxbytelen);
334 if (tevent_req_nomem(subreq, req)) {
335 return tevent_req_post(req, ev);
337 tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
338 return req;
341 static void cli_posix_readlink_done(struct tevent_req *subreq)
343 struct tevent_req *req = tevent_req_callback_data(
344 subreq, struct tevent_req);
345 struct readlink_state *state = tevent_req_data(
346 req, struct readlink_state);
347 NTSTATUS status;
349 status = cli_qpathinfo_recv(subreq, state, &state->data,
350 &state->num_data);
351 TALLOC_FREE(subreq);
352 if (tevent_req_nterror(req, status)) {
353 return;
356 * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
358 if (state->data[state->num_data-1] != '\0') {
359 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
360 return;
362 tevent_req_done(req);
365 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
366 char *retpath, size_t len)
368 NTSTATUS status;
369 char *converted = NULL;
370 size_t converted_size = 0;
371 struct readlink_state *state = tevent_req_data(req, struct readlink_state);
373 if (tevent_req_is_nterror(req, &status)) {
374 return status;
376 /* The returned data is a pushed string, not raw data. */
377 if (!convert_string_talloc(state,
378 smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
379 CH_UNIX,
380 state->data,
381 state->num_data,
382 &converted,
383 &converted_size)) {
384 return NT_STATUS_NO_MEMORY;
387 len = MIN(len,converted_size);
388 if (len == 0) {
389 return NT_STATUS_DATA_ERROR;
391 memcpy(retpath, converted, len);
392 return NT_STATUS_OK;
395 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
396 char *linkpath, size_t len)
398 TALLOC_CTX *frame = talloc_stackframe();
399 struct tevent_context *ev = NULL;
400 struct tevent_req *req = NULL;
401 NTSTATUS status = NT_STATUS_OK;
403 if (smbXcli_conn_has_async_calls(cli->conn)) {
405 * Can't use sync call while an async call is in flight
407 status = NT_STATUS_INVALID_PARAMETER;
408 goto fail;
411 ev = samba_tevent_context_init(frame);
412 if (ev == NULL) {
413 status = NT_STATUS_NO_MEMORY;
414 goto fail;
417 req = cli_posix_readlink_send(frame,
419 cli,
420 fname,
421 len);
422 if (req == NULL) {
423 status = NT_STATUS_NO_MEMORY;
424 goto fail;
427 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
428 goto fail;
431 status = cli_posix_readlink_recv(req, cli, linkpath, len);
433 fail:
434 TALLOC_FREE(frame);
435 return status;
438 /****************************************************************************
439 Hard link a file (UNIX extensions).
440 ****************************************************************************/
442 struct cli_posix_hardlink_state {
443 uint8_t dummy;
446 static void cli_posix_hardlink_done(struct tevent_req *subreq);
448 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
449 struct tevent_context *ev,
450 struct cli_state *cli,
451 const char *oldname,
452 const char *newname)
454 struct tevent_req *req = NULL, *subreq = NULL;
455 struct cli_posix_hardlink_state *state = NULL;
457 req = tevent_req_create(
458 mem_ctx, &state, struct cli_posix_hardlink_state);
459 if (req == NULL) {
460 return NULL;
463 subreq = cli_posix_link_internal_send(
464 state, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
465 if (tevent_req_nomem(subreq, req)) {
466 return tevent_req_post(req, ev);
468 tevent_req_set_callback(subreq, cli_posix_hardlink_done, req);
469 return req;
472 static void cli_posix_hardlink_done(struct tevent_req *subreq)
474 NTSTATUS status = cli_posix_link_internal_recv(subreq);
475 tevent_req_simple_finish_ntstatus(subreq, status);
478 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
480 return tevent_req_simple_recv_ntstatus(req);
483 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
484 const char *oldname,
485 const char *newname)
487 TALLOC_CTX *frame = talloc_stackframe();
488 struct tevent_context *ev = NULL;
489 struct tevent_req *req = NULL;
490 NTSTATUS status = NT_STATUS_OK;
492 if (smbXcli_conn_has_async_calls(cli->conn)) {
494 * Can't use sync call while an async call is in flight
496 status = NT_STATUS_INVALID_PARAMETER;
497 goto fail;
500 ev = samba_tevent_context_init(frame);
501 if (ev == NULL) {
502 status = NT_STATUS_NO_MEMORY;
503 goto fail;
506 req = cli_posix_hardlink_send(frame,
508 cli,
509 oldname,
510 newname);
511 if (req == NULL) {
512 status = NT_STATUS_NO_MEMORY;
513 goto fail;
516 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
517 goto fail;
520 status = cli_posix_hardlink_recv(req);
522 fail:
523 TALLOC_FREE(frame);
524 return status;
527 /****************************************************************************
528 Do a POSIX getacl - pathname based ACL get (UNIX extensions).
529 ****************************************************************************/
531 struct getacl_state {
532 uint32_t num_data;
533 uint8_t *data;
536 static void cli_posix_getacl_done(struct tevent_req *subreq);
538 struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
539 struct tevent_context *ev,
540 struct cli_state *cli,
541 const char *fname)
543 struct tevent_req *req = NULL, *subreq = NULL;
544 struct getacl_state *state = NULL;
546 req = tevent_req_create(mem_ctx, &state, struct getacl_state);
547 if (req == NULL) {
548 return NULL;
550 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
551 0, CLI_BUFFER_SIZE);
552 if (tevent_req_nomem(subreq, req)) {
553 return tevent_req_post(req, ev);
555 tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
556 return req;
559 static void cli_posix_getacl_done(struct tevent_req *subreq)
561 struct tevent_req *req = tevent_req_callback_data(
562 subreq, struct tevent_req);
563 struct getacl_state *state = tevent_req_data(
564 req, struct getacl_state);
565 NTSTATUS status;
567 status = cli_qpathinfo_recv(subreq, state, &state->data,
568 &state->num_data);
569 TALLOC_FREE(subreq);
570 if (tevent_req_nterror(req, status)) {
571 return;
573 tevent_req_done(req);
576 NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
577 TALLOC_CTX *mem_ctx,
578 size_t *prb_size,
579 char **retbuf)
581 struct getacl_state *state = tevent_req_data(req, struct getacl_state);
582 NTSTATUS status;
584 if (tevent_req_is_nterror(req, &status)) {
585 return status;
587 *prb_size = (size_t)state->num_data;
588 *retbuf = (char *)talloc_move(mem_ctx, &state->data);
589 return NT_STATUS_OK;
592 NTSTATUS cli_posix_getacl(struct cli_state *cli,
593 const char *fname,
594 TALLOC_CTX *mem_ctx,
595 size_t *prb_size,
596 char **retbuf)
598 TALLOC_CTX *frame = talloc_stackframe();
599 struct tevent_context *ev = NULL;
600 struct tevent_req *req = NULL;
601 NTSTATUS status = NT_STATUS_OK;
603 if (smbXcli_conn_has_async_calls(cli->conn)) {
605 * Can't use sync call while an async call is in flight
607 status = NT_STATUS_INVALID_PARAMETER;
608 goto fail;
611 ev = samba_tevent_context_init(frame);
612 if (ev == NULL) {
613 status = NT_STATUS_NO_MEMORY;
614 goto fail;
617 req = cli_posix_getacl_send(frame,
619 cli,
620 fname);
621 if (req == NULL) {
622 status = NT_STATUS_NO_MEMORY;
623 goto fail;
626 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
627 goto fail;
630 status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
632 fail:
633 TALLOC_FREE(frame);
634 return status;
637 /****************************************************************************
638 Do a POSIX setacl - pathname based ACL set (UNIX extensions).
639 ****************************************************************************/
641 struct setacl_state {
642 uint8_t *data;
645 static void cli_posix_setacl_done(struct tevent_req *subreq);
647 struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
648 struct tevent_context *ev,
649 struct cli_state *cli,
650 const char *fname,
651 const void *data,
652 size_t num_data)
654 struct tevent_req *req = NULL, *subreq = NULL;
655 struct setacl_state *state = NULL;
657 req = tevent_req_create(mem_ctx, &state, struct setacl_state);
658 if (req == NULL) {
659 return NULL;
661 state->data = talloc_memdup(state, data, num_data);
662 if (tevent_req_nomem(state->data, req)) {
663 return tevent_req_post(req, ev);
666 subreq = cli_setpathinfo_send(state,
668 cli,
669 SMB_SET_POSIX_ACL,
670 fname,
671 state->data,
672 num_data);
673 if (tevent_req_nomem(subreq, req)) {
674 return tevent_req_post(req, ev);
676 tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
677 return req;
680 static void cli_posix_setacl_done(struct tevent_req *subreq)
682 NTSTATUS status = cli_setpathinfo_recv(subreq);
683 tevent_req_simple_finish_ntstatus(subreq, status);
686 NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
688 return tevent_req_simple_recv_ntstatus(req);
691 NTSTATUS cli_posix_setacl(struct cli_state *cli,
692 const char *fname,
693 const void *acl_buf,
694 size_t acl_buf_size)
696 TALLOC_CTX *frame = talloc_stackframe();
697 struct tevent_context *ev = NULL;
698 struct tevent_req *req = NULL;
699 NTSTATUS status = NT_STATUS_OK;
701 if (smbXcli_conn_has_async_calls(cli->conn)) {
703 * Can't use sync call while an async call is in flight
705 status = NT_STATUS_INVALID_PARAMETER;
706 goto fail;
709 ev = samba_tevent_context_init(frame);
710 if (ev == NULL) {
711 status = NT_STATUS_NO_MEMORY;
712 goto fail;
715 req = cli_posix_setacl_send(frame,
717 cli,
718 fname,
719 acl_buf,
720 acl_buf_size);
721 if (req == NULL) {
722 status = NT_STATUS_NO_MEMORY;
723 goto fail;
726 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
727 goto fail;
730 status = cli_posix_setacl_recv(req);
732 fail:
733 TALLOC_FREE(frame);
734 return status;
737 /****************************************************************************
738 Stat a file (UNIX extensions).
739 ****************************************************************************/
741 struct stat_state {
742 SMB_STRUCT_STAT *sbuf;
745 static void cli_posix_stat_done(struct tevent_req *subreq);
747 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
748 struct tevent_context *ev,
749 struct cli_state *cli,
750 const char *fname,
751 SMB_STRUCT_STAT *sbuf)
753 struct tevent_req *req = NULL, *subreq = NULL;
754 struct stat_state *state = NULL;
756 req = tevent_req_create(mem_ctx, &state, struct stat_state);
757 if (req == NULL) {
758 return NULL;
760 state->sbuf = sbuf;
762 subreq = cli_qpathinfo_send(state, ev, cli, fname,
763 SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
764 if (tevent_req_nomem(subreq, req)) {
765 return tevent_req_post(req, ev);
767 tevent_req_set_callback(subreq, cli_posix_stat_done, req);
768 return req;
771 static void cli_posix_stat_done(struct tevent_req *subreq)
773 struct tevent_req *req = tevent_req_callback_data(
774 subreq, struct tevent_req);
775 struct stat_state *state = tevent_req_data(req, struct stat_state);
776 SMB_STRUCT_STAT *sbuf = state->sbuf;
777 uint8_t *data;
778 uint32_t num_data;
779 NTSTATUS status;
781 status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
782 TALLOC_FREE(subreq);
783 if (tevent_req_nterror(req, status)) {
784 return;
787 if (num_data != 100) {
789 * Paranoia, cli_qpathinfo should have guaranteed
790 * this, but you never know...
792 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
793 return;
796 *sbuf = (SMB_STRUCT_STAT) { 0 };
798 /* total size, in bytes */
799 sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(data, 0);
801 /* number of blocks allocated */
802 sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(data,8);
803 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
804 sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
805 #else
806 /* assume 512 byte blocks */
807 sbuf->st_ex_blocks /= 512;
808 #endif
809 /* time of last change */
810 sbuf->st_ex_ctime = interpret_long_date((char *)(data + 16));
812 /* time of last access */
813 sbuf->st_ex_atime = interpret_long_date((char *)(data + 24));
815 /* time of last modification */
816 sbuf->st_ex_mtime = interpret_long_date((char *)(data + 32));
818 sbuf->st_ex_uid = (uid_t) IVAL(data, 40); /* user ID of owner */
819 sbuf->st_ex_gid = (gid_t) IVAL(data, 48); /* group ID of owner */
820 sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(data, 56));
822 #if defined(HAVE_MAKEDEV)
824 uint32_t dev_major = IVAL(data,60);
825 uint32_t dev_minor = IVAL(data,68);
826 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
828 #endif
829 /* inode */
830 sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(data, 76);
832 /* protection */
833 sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(data, 84));
835 /* number of hard links */
836 sbuf->st_ex_nlink = BIG_UINT(data, 92);
838 tevent_req_done(req);
841 NTSTATUS cli_posix_stat_recv(struct tevent_req *req)
843 return tevent_req_simple_recv_ntstatus(req);
846 NTSTATUS cli_posix_stat(struct cli_state *cli,
847 const char *fname,
848 SMB_STRUCT_STAT *sbuf)
850 TALLOC_CTX *frame = talloc_stackframe();
851 struct tevent_context *ev = NULL;
852 struct tevent_req *req = NULL;
853 NTSTATUS status = NT_STATUS_OK;
855 if (smbXcli_conn_has_async_calls(cli->conn)) {
857 * Can't use sync call while an async call is in flight
859 status = NT_STATUS_INVALID_PARAMETER;
860 goto fail;
863 ev = samba_tevent_context_init(frame);
864 if (ev == NULL) {
865 status = NT_STATUS_NO_MEMORY;
866 goto fail;
869 req = cli_posix_stat_send(frame, ev, cli, fname, sbuf);
870 if (req == NULL) {
871 status = NT_STATUS_NO_MEMORY;
872 goto fail;
875 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
876 goto fail;
879 status = cli_posix_stat_recv(req);
881 fail:
882 TALLOC_FREE(frame);
883 return status;
886 /****************************************************************************
887 Chmod or chown a file internal (UNIX extensions).
888 ****************************************************************************/
890 struct cli_posix_chown_chmod_internal_state {
891 uint8_t data[100];
894 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
896 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
897 struct tevent_context *ev,
898 struct cli_state *cli,
899 const char *fname,
900 uint32_t mode,
901 uint32_t uid,
902 uint32_t gid)
904 struct tevent_req *req = NULL, *subreq = NULL;
905 struct cli_posix_chown_chmod_internal_state *state = NULL;
907 req = tevent_req_create(mem_ctx, &state,
908 struct cli_posix_chown_chmod_internal_state);
909 if (req == NULL) {
910 return NULL;
913 memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
914 memset(&state->data[40], '\0', 60);
915 SIVAL(state->data,40,uid);
916 SIVAL(state->data,48,gid);
917 SIVAL(state->data,84,mode);
919 subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
920 fname, state->data, sizeof(state->data));
921 if (tevent_req_nomem(subreq, req)) {
922 return tevent_req_post(req, ev);
924 tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
925 req);
926 return req;
929 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
931 NTSTATUS status = cli_setpathinfo_recv(subreq);
932 tevent_req_simple_finish_ntstatus(subreq, status);
935 /****************************************************************************
936 chmod a file (UNIX extensions).
937 ****************************************************************************/
939 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
940 struct tevent_context *ev,
941 struct cli_state *cli,
942 const char *fname,
943 mode_t mode)
945 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
946 fname,
947 unix_perms_to_wire(mode),
948 SMB_UID_NO_CHANGE,
949 SMB_GID_NO_CHANGE);
952 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
954 return tevent_req_simple_recv_ntstatus(req);
957 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
959 TALLOC_CTX *frame = talloc_stackframe();
960 struct tevent_context *ev = NULL;
961 struct tevent_req *req = NULL;
962 NTSTATUS status = NT_STATUS_OK;
964 if (smbXcli_conn_has_async_calls(cli->conn)) {
966 * Can't use sync call while an async call is in flight
968 status = NT_STATUS_INVALID_PARAMETER;
969 goto fail;
972 ev = samba_tevent_context_init(frame);
973 if (ev == NULL) {
974 status = NT_STATUS_NO_MEMORY;
975 goto fail;
978 req = cli_posix_chmod_send(frame,
980 cli,
981 fname,
982 mode);
983 if (req == NULL) {
984 status = NT_STATUS_NO_MEMORY;
985 goto fail;
988 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
989 goto fail;
992 status = cli_posix_chmod_recv(req);
994 fail:
995 TALLOC_FREE(frame);
996 return status;
999 /****************************************************************************
1000 chown a file (UNIX extensions).
1001 ****************************************************************************/
1003 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1004 struct tevent_context *ev,
1005 struct cli_state *cli,
1006 const char *fname,
1007 uid_t uid,
1008 gid_t gid)
1010 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
1011 fname,
1012 SMB_MODE_NO_CHANGE,
1013 (uint32_t)uid,
1014 (uint32_t)gid);
1017 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1019 return tevent_req_simple_recv_ntstatus(req);
1022 NTSTATUS cli_posix_chown(struct cli_state *cli,
1023 const char *fname,
1024 uid_t uid,
1025 gid_t gid)
1027 TALLOC_CTX *frame = talloc_stackframe();
1028 struct tevent_context *ev = NULL;
1029 struct tevent_req *req = NULL;
1030 NTSTATUS status = NT_STATUS_OK;
1032 if (smbXcli_conn_has_async_calls(cli->conn)) {
1034 * Can't use sync call while an async call is in flight
1036 status = NT_STATUS_INVALID_PARAMETER;
1037 goto fail;
1040 ev = samba_tevent_context_init(frame);
1041 if (ev == NULL) {
1042 status = NT_STATUS_NO_MEMORY;
1043 goto fail;
1046 req = cli_posix_chown_send(frame,
1048 cli,
1049 fname,
1050 uid,
1051 gid);
1052 if (req == NULL) {
1053 status = NT_STATUS_NO_MEMORY;
1054 goto fail;
1057 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1058 goto fail;
1061 status = cli_posix_chown_recv(req);
1063 fail:
1064 TALLOC_FREE(frame);
1065 return status;
1068 /****************************************************************************
1069 Rename a file.
1070 ****************************************************************************/
1072 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1073 struct tevent_context *ev,
1074 struct cli_state *cli,
1075 const char *fname_src,
1076 const char *fname_dst,
1077 bool replace);
1079 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1080 struct tevent_context *ev,
1081 struct cli_state *cli,
1082 const char *fname_src,
1083 const char *fname_dst,
1084 bool replace);
1086 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1087 struct tevent_context *ev,
1088 struct cli_state *cli,
1089 const char *fname_src,
1090 const char *fname_dst,
1091 bool replace)
1093 if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
1094 return cli_smb1_rename_send(mem_ctx, ev, cli, fname_src,
1095 fname_dst, replace);
1096 } else {
1097 return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src,
1098 fname_dst, replace);
1102 struct cli_smb1_rename_state {
1103 uint8_t *data;
1106 static void cli_smb1_rename_done(struct tevent_req *subreq);
1108 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1109 struct tevent_context *ev,
1110 struct cli_state *cli,
1111 const char *fname_src,
1112 const char *fname_dst,
1113 bool replace)
1115 NTSTATUS status;
1116 struct tevent_req *req = NULL, *subreq = NULL;
1117 struct cli_smb1_rename_state *state = NULL;
1118 smb_ucs2_t *converted_str = NULL;
1119 size_t converted_size_bytes = 0;
1121 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
1122 if (req == NULL) {
1123 return NULL;
1126 if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
1127 &converted_size_bytes)) {
1128 status = NT_STATUS_INVALID_PARAMETER;
1129 goto fail;
1132 /* W2K8 insists the dest name is not null
1133 terminated. Remove the last 2 zero bytes
1134 and reduce the name length. */
1136 if (converted_size_bytes < 2) {
1137 status = NT_STATUS_INVALID_PARAMETER;
1138 goto fail;
1140 converted_size_bytes -= 2;
1142 state->data =
1143 talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
1144 if (state->data == NULL) {
1145 status = NT_STATUS_NO_MEMORY;
1146 goto fail;
1149 if (replace) {
1150 SCVAL(state->data, 0, 1);
1153 SIVAL(state->data, 8, converted_size_bytes);
1154 memcpy(state->data + 12, converted_str, converted_size_bytes);
1156 TALLOC_FREE(converted_str);
1158 subreq = cli_setpathinfo_send(
1159 state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
1160 talloc_get_size(state->data));
1161 if (tevent_req_nomem(subreq, req)) {
1162 status = NT_STATUS_NO_MEMORY;
1163 goto fail;
1165 tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
1166 return req;
1168 fail:
1169 TALLOC_FREE(converted_str);
1170 tevent_req_nterror(req, status);
1171 return tevent_req_post(req, ev);
1174 static void cli_smb1_rename_done(struct tevent_req *subreq)
1176 NTSTATUS status = cli_setpathinfo_recv(subreq);
1177 tevent_req_simple_finish_ntstatus(subreq, status);
1180 static void cli_cifs_rename_done(struct tevent_req *subreq);
1182 struct cli_cifs_rename_state {
1183 uint16_t vwv[1];
1186 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1187 struct tevent_context *ev,
1188 struct cli_state *cli,
1189 const char *fname_src,
1190 const char *fname_dst,
1191 bool replace)
1193 struct tevent_req *req = NULL, *subreq = NULL;
1194 struct cli_cifs_rename_state *state = NULL;
1195 uint8_t additional_flags = 0;
1196 uint16_t additional_flags2 = 0;
1197 uint8_t *bytes = NULL;
1199 req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
1200 if (req == NULL) {
1201 return NULL;
1204 if (replace) {
1206 * CIFS doesn't support replace
1208 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1209 return tevent_req_post(req, ev);
1212 SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1214 bytes = talloc_array(state, uint8_t, 1);
1215 if (tevent_req_nomem(bytes, req)) {
1216 return tevent_req_post(req, ev);
1218 bytes[0] = 4;
1219 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1220 strlen(fname_src)+1, NULL);
1221 if (tevent_req_nomem(bytes, req)) {
1222 return tevent_req_post(req, ev);
1225 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1226 additional_flags2 = FLAGS2_REPARSE_PATH;
1229 bytes = talloc_realloc(state, bytes, uint8_t,
1230 talloc_get_size(bytes)+1);
1231 if (tevent_req_nomem(bytes, req)) {
1232 return tevent_req_post(req, ev);
1235 bytes[talloc_get_size(bytes)-1] = 4;
1236 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1237 strlen(fname_dst)+1, NULL);
1238 if (tevent_req_nomem(bytes, req)) {
1239 return tevent_req_post(req, ev);
1242 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1243 additional_flags2,
1244 1, state->vwv, talloc_get_size(bytes), bytes);
1245 if (tevent_req_nomem(subreq, req)) {
1246 return tevent_req_post(req, ev);
1248 tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
1249 return req;
1252 static void cli_cifs_rename_done(struct tevent_req *subreq)
1254 struct tevent_req *req = tevent_req_callback_data(
1255 subreq, struct tevent_req);
1256 NTSTATUS status;
1258 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1259 TALLOC_FREE(subreq);
1260 if (tevent_req_nterror(req, status)) {
1261 return;
1263 tevent_req_done(req);
1266 NTSTATUS cli_rename_recv(struct tevent_req *req)
1268 return tevent_req_simple_recv_ntstatus(req);
1271 NTSTATUS cli_rename(struct cli_state *cli,
1272 const char *fname_src,
1273 const char *fname_dst,
1274 bool replace)
1276 TALLOC_CTX *frame = NULL;
1277 struct tevent_context *ev;
1278 struct tevent_req *req;
1279 NTSTATUS status = NT_STATUS_OK;
1281 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1282 return cli_smb2_rename(cli, fname_src, fname_dst, replace);
1285 frame = talloc_stackframe();
1287 if (smbXcli_conn_has_async_calls(cli->conn)) {
1289 * Can't use sync call while an async call is in flight
1291 status = NT_STATUS_INVALID_PARAMETER;
1292 goto fail;
1295 ev = samba_tevent_context_init(frame);
1296 if (ev == NULL) {
1297 status = NT_STATUS_NO_MEMORY;
1298 goto fail;
1301 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
1302 if (req == NULL) {
1303 status = NT_STATUS_NO_MEMORY;
1304 goto fail;
1307 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1308 goto fail;
1311 status = cli_rename_recv(req);
1313 fail:
1314 TALLOC_FREE(frame);
1315 return status;
1318 /****************************************************************************
1319 NT Rename a file.
1320 ****************************************************************************/
1322 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1324 struct cli_ntrename_internal_state {
1325 uint16_t vwv[4];
1328 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1329 struct tevent_context *ev,
1330 struct cli_state *cli,
1331 const char *fname_src,
1332 const char *fname_dst,
1333 uint16_t rename_flag)
1335 struct tevent_req *req = NULL, *subreq = NULL;
1336 struct cli_ntrename_internal_state *state = NULL;
1337 uint8_t additional_flags = 0;
1338 uint16_t additional_flags2 = 0;
1339 uint8_t *bytes = NULL;
1341 req = tevent_req_create(mem_ctx, &state,
1342 struct cli_ntrename_internal_state);
1343 if (req == NULL) {
1344 return NULL;
1347 SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1348 SSVAL(state->vwv+1, 0, rename_flag);
1350 bytes = talloc_array(state, uint8_t, 1);
1351 if (tevent_req_nomem(bytes, req)) {
1352 return tevent_req_post(req, ev);
1354 bytes[0] = 4;
1355 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1356 strlen(fname_src)+1, NULL);
1357 if (tevent_req_nomem(bytes, req)) {
1358 return tevent_req_post(req, ev);
1361 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1362 additional_flags2 = FLAGS2_REPARSE_PATH;
1365 bytes = talloc_realloc(state, bytes, uint8_t,
1366 talloc_get_size(bytes)+1);
1367 if (tevent_req_nomem(bytes, req)) {
1368 return tevent_req_post(req, ev);
1371 bytes[talloc_get_size(bytes)-1] = 4;
1372 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1373 strlen(fname_dst)+1, NULL);
1374 if (tevent_req_nomem(bytes, req)) {
1375 return tevent_req_post(req, ev);
1378 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1379 additional_flags2,
1380 4, state->vwv, talloc_get_size(bytes), bytes);
1381 if (tevent_req_nomem(subreq, req)) {
1382 return tevent_req_post(req, ev);
1384 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1385 return req;
1388 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1390 NTSTATUS status = cli_smb_recv(
1391 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1392 tevent_req_simple_finish_ntstatus(subreq, status);
1395 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1397 return tevent_req_simple_recv_ntstatus(req);
1400 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1401 struct tevent_context *ev,
1402 struct cli_state *cli,
1403 const char *fname_src,
1404 const char *fname_dst)
1406 return cli_ntrename_internal_send(mem_ctx,
1408 cli,
1409 fname_src,
1410 fname_dst,
1411 RENAME_FLAG_RENAME);
1414 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1416 return cli_ntrename_internal_recv(req);
1419 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1421 TALLOC_CTX *frame = talloc_stackframe();
1422 struct tevent_context *ev;
1423 struct tevent_req *req;
1424 NTSTATUS status = NT_STATUS_OK;
1426 if (smbXcli_conn_has_async_calls(cli->conn)) {
1428 * Can't use sync call while an async call is in flight
1430 status = NT_STATUS_INVALID_PARAMETER;
1431 goto fail;
1434 ev = samba_tevent_context_init(frame);
1435 if (ev == NULL) {
1436 status = NT_STATUS_NO_MEMORY;
1437 goto fail;
1440 req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1441 if (req == NULL) {
1442 status = NT_STATUS_NO_MEMORY;
1443 goto fail;
1446 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1447 goto fail;
1450 status = cli_ntrename_recv(req);
1452 fail:
1453 TALLOC_FREE(frame);
1454 return status;
1457 /****************************************************************************
1458 NT hardlink a file.
1459 ****************************************************************************/
1461 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1462 struct tevent_context *ev,
1463 struct cli_state *cli,
1464 const char *fname_src,
1465 const char *fname_dst)
1467 return cli_ntrename_internal_send(mem_ctx,
1469 cli,
1470 fname_src,
1471 fname_dst,
1472 RENAME_FLAG_HARD_LINK);
1475 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1477 return cli_ntrename_internal_recv(req);
1480 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1482 TALLOC_CTX *frame = talloc_stackframe();
1483 struct tevent_context *ev;
1484 struct tevent_req *req;
1485 NTSTATUS status = NT_STATUS_OK;
1487 if (smbXcli_conn_has_async_calls(cli->conn)) {
1489 * Can't use sync call while an async call is in flight
1491 status = NT_STATUS_INVALID_PARAMETER;
1492 goto fail;
1495 ev = samba_tevent_context_init(frame);
1496 if (ev == NULL) {
1497 status = NT_STATUS_NO_MEMORY;
1498 goto fail;
1501 req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1502 if (req == NULL) {
1503 status = NT_STATUS_NO_MEMORY;
1504 goto fail;
1507 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1508 goto fail;
1511 status = cli_nt_hardlink_recv(req);
1513 fail:
1514 TALLOC_FREE(frame);
1515 return status;
1518 /****************************************************************************
1519 Delete a file.
1520 ****************************************************************************/
1522 static void cli_unlink_done(struct tevent_req *subreq);
1524 struct cli_unlink_state {
1525 uint16_t vwv[1];
1528 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1529 struct tevent_context *ev,
1530 struct cli_state *cli,
1531 const char *fname,
1532 uint16_t mayhave_attrs)
1534 struct tevent_req *req = NULL, *subreq = NULL;
1535 struct cli_unlink_state *state = NULL;
1536 uint8_t additional_flags = 0;
1537 uint16_t additional_flags2 = 0;
1538 uint8_t *bytes = NULL;
1540 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1541 if (req == NULL) {
1542 return NULL;
1545 SSVAL(state->vwv+0, 0, mayhave_attrs);
1547 bytes = talloc_array(state, uint8_t, 1);
1548 if (tevent_req_nomem(bytes, req)) {
1549 return tevent_req_post(req, ev);
1551 bytes[0] = 4;
1552 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
1553 strlen(fname)+1, NULL);
1555 if (tevent_req_nomem(bytes, req)) {
1556 return tevent_req_post(req, ev);
1559 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1560 additional_flags2 = FLAGS2_REPARSE_PATH;
1563 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1564 additional_flags2,
1565 1, state->vwv, talloc_get_size(bytes), bytes);
1566 if (tevent_req_nomem(subreq, req)) {
1567 return tevent_req_post(req, ev);
1569 tevent_req_set_callback(subreq, cli_unlink_done, req);
1570 return req;
1573 static void cli_unlink_done(struct tevent_req *subreq)
1575 struct tevent_req *req = tevent_req_callback_data(
1576 subreq, struct tevent_req);
1577 NTSTATUS status;
1579 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1580 TALLOC_FREE(subreq);
1581 if (tevent_req_nterror(req, status)) {
1582 return;
1584 tevent_req_done(req);
1587 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1589 return tevent_req_simple_recv_ntstatus(req);
1592 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1594 TALLOC_CTX *frame = NULL;
1595 struct tevent_context *ev;
1596 struct tevent_req *req;
1597 NTSTATUS status = NT_STATUS_OK;
1599 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1600 return cli_smb2_unlink(cli, fname, NULL);
1603 frame = talloc_stackframe();
1605 if (smbXcli_conn_has_async_calls(cli->conn)) {
1607 * Can't use sync call while an async call is in flight
1609 status = NT_STATUS_INVALID_PARAMETER;
1610 goto fail;
1613 ev = samba_tevent_context_init(frame);
1614 if (ev == NULL) {
1615 status = NT_STATUS_NO_MEMORY;
1616 goto fail;
1619 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1620 if (req == NULL) {
1621 status = NT_STATUS_NO_MEMORY;
1622 goto fail;
1625 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1626 goto fail;
1629 status = cli_unlink_recv(req);
1631 fail:
1632 TALLOC_FREE(frame);
1633 return status;
1636 /****************************************************************************
1637 Create a directory.
1638 ****************************************************************************/
1640 static void cli_mkdir_done(struct tevent_req *subreq);
1642 struct cli_mkdir_state {
1643 int dummy;
1646 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1647 struct tevent_context *ev,
1648 struct cli_state *cli,
1649 const char *dname)
1651 struct tevent_req *req = NULL, *subreq = NULL;
1652 struct cli_mkdir_state *state = NULL;
1653 uint8_t additional_flags = 0;
1654 uint16_t additional_flags2 = 0;
1655 uint8_t *bytes = NULL;
1657 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1658 if (req == NULL) {
1659 return NULL;
1662 bytes = talloc_array(state, uint8_t, 1);
1663 if (tevent_req_nomem(bytes, req)) {
1664 return tevent_req_post(req, ev);
1666 bytes[0] = 4;
1667 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1668 strlen(dname)+1, NULL);
1670 if (tevent_req_nomem(bytes, req)) {
1671 return tevent_req_post(req, ev);
1674 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1675 additional_flags2 = FLAGS2_REPARSE_PATH;
1678 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1679 additional_flags2,
1680 0, NULL, talloc_get_size(bytes), bytes);
1681 if (tevent_req_nomem(subreq, req)) {
1682 return tevent_req_post(req, ev);
1684 tevent_req_set_callback(subreq, cli_mkdir_done, req);
1685 return req;
1688 static void cli_mkdir_done(struct tevent_req *subreq)
1690 struct tevent_req *req = tevent_req_callback_data(
1691 subreq, struct tevent_req);
1692 NTSTATUS status;
1694 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1695 TALLOC_FREE(subreq);
1696 if (tevent_req_nterror(req, status)) {
1697 return;
1699 tevent_req_done(req);
1702 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1704 return tevent_req_simple_recv_ntstatus(req);
1707 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1709 TALLOC_CTX *frame = NULL;
1710 struct tevent_context *ev;
1711 struct tevent_req *req;
1712 NTSTATUS status = NT_STATUS_OK;
1714 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1715 return cli_smb2_mkdir(cli, dname);
1718 frame = talloc_stackframe();
1720 if (smbXcli_conn_has_async_calls(cli->conn)) {
1722 * Can't use sync call while an async call is in flight
1724 status = NT_STATUS_INVALID_PARAMETER;
1725 goto fail;
1728 ev = samba_tevent_context_init(frame);
1729 if (ev == NULL) {
1730 status = NT_STATUS_NO_MEMORY;
1731 goto fail;
1734 req = cli_mkdir_send(frame, ev, cli, dname);
1735 if (req == NULL) {
1736 status = NT_STATUS_NO_MEMORY;
1737 goto fail;
1740 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1741 goto fail;
1744 status = cli_mkdir_recv(req);
1746 fail:
1747 TALLOC_FREE(frame);
1748 return status;
1751 /****************************************************************************
1752 Remove a directory.
1753 ****************************************************************************/
1755 static void cli_rmdir_done(struct tevent_req *subreq);
1757 struct cli_rmdir_state {
1758 int dummy;
1761 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1762 struct tevent_context *ev,
1763 struct cli_state *cli,
1764 const char *dname)
1766 struct tevent_req *req = NULL, *subreq = NULL;
1767 struct cli_rmdir_state *state = NULL;
1768 uint8_t additional_flags = 0;
1769 uint16_t additional_flags2 = 0;
1770 uint8_t *bytes = NULL;
1772 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1773 if (req == NULL) {
1774 return NULL;
1777 bytes = talloc_array(state, uint8_t, 1);
1778 if (tevent_req_nomem(bytes, req)) {
1779 return tevent_req_post(req, ev);
1781 bytes[0] = 4;
1782 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1783 strlen(dname)+1, NULL);
1785 if (tevent_req_nomem(bytes, req)) {
1786 return tevent_req_post(req, ev);
1789 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1790 additional_flags2 = FLAGS2_REPARSE_PATH;
1793 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1794 additional_flags2,
1795 0, NULL, talloc_get_size(bytes), bytes);
1796 if (tevent_req_nomem(subreq, req)) {
1797 return tevent_req_post(req, ev);
1799 tevent_req_set_callback(subreq, cli_rmdir_done, req);
1800 return req;
1803 static void cli_rmdir_done(struct tevent_req *subreq)
1805 struct tevent_req *req = tevent_req_callback_data(
1806 subreq, struct tevent_req);
1807 NTSTATUS status;
1809 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1810 TALLOC_FREE(subreq);
1811 if (tevent_req_nterror(req, status)) {
1812 return;
1814 tevent_req_done(req);
1817 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1819 return tevent_req_simple_recv_ntstatus(req);
1822 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1824 TALLOC_CTX *frame = NULL;
1825 struct tevent_context *ev;
1826 struct tevent_req *req;
1827 NTSTATUS status = NT_STATUS_OK;
1829 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1830 return cli_smb2_rmdir(cli, dname, NULL);
1833 frame = talloc_stackframe();
1835 if (smbXcli_conn_has_async_calls(cli->conn)) {
1837 * Can't use sync call while an async call is in flight
1839 status = NT_STATUS_INVALID_PARAMETER;
1840 goto fail;
1843 ev = samba_tevent_context_init(frame);
1844 if (ev == NULL) {
1845 status = NT_STATUS_NO_MEMORY;
1846 goto fail;
1849 req = cli_rmdir_send(frame, ev, cli, dname);
1850 if (req == NULL) {
1851 status = NT_STATUS_NO_MEMORY;
1852 goto fail;
1855 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1856 goto fail;
1859 status = cli_rmdir_recv(req);
1861 fail:
1862 TALLOC_FREE(frame);
1863 return status;
1866 /****************************************************************************
1867 Set or clear the delete on close flag.
1868 ****************************************************************************/
1870 struct doc_state {
1871 uint16_t setup;
1872 uint8_t param[6];
1873 uint8_t data[1];
1876 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
1877 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
1879 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1880 struct tevent_context *ev,
1881 struct cli_state *cli,
1882 uint16_t fnum,
1883 bool flag)
1885 struct tevent_req *req = NULL, *subreq = NULL;
1886 struct doc_state *state = NULL;
1888 req = tevent_req_create(mem_ctx, &state, struct doc_state);
1889 if (req == NULL) {
1890 return NULL;
1893 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1894 subreq = cli_smb2_delete_on_close_send(state, ev, cli,
1895 fnum, flag);
1896 if (tevent_req_nomem(subreq, req)) {
1897 return tevent_req_post(req, ev);
1899 tevent_req_set_callback(subreq,
1900 cli_nt_delete_on_close_smb2_done,
1901 req);
1902 return req;
1905 /* Setup setup word. */
1906 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1908 /* Setup param array. */
1909 SSVAL(state->param,0,fnum);
1910 SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1912 /* Setup data array. */
1913 SCVAL(&state->data[0], 0, flag ? 1 : 0);
1915 subreq = cli_trans_send(state, /* mem ctx. */
1916 ev, /* event ctx. */
1917 cli, /* cli_state. */
1918 0, /* additional_flags2 */
1919 SMBtrans2, /* cmd. */
1920 NULL, /* pipe name. */
1921 -1, /* fid. */
1922 0, /* function. */
1923 0, /* flags. */
1924 &state->setup, /* setup. */
1925 1, /* num setup uint16_t words. */
1926 0, /* max returned setup. */
1927 state->param, /* param. */
1928 6, /* num param. */
1929 2, /* max returned param. */
1930 state->data, /* data. */
1931 1, /* num data. */
1932 0); /* max returned data. */
1934 if (tevent_req_nomem(subreq, req)) {
1935 return tevent_req_post(req, ev);
1937 tevent_req_set_callback(subreq,
1938 cli_nt_delete_on_close_smb1_done,
1939 req);
1940 return req;
1943 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
1945 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
1946 NULL, 0, NULL, NULL, 0, NULL);
1947 tevent_req_simple_finish_ntstatus(subreq, status);
1950 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
1952 NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
1953 tevent_req_simple_finish_ntstatus(subreq, status);
1956 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1958 return tevent_req_simple_recv_ntstatus(req);
1961 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1963 TALLOC_CTX *frame = talloc_stackframe();
1964 struct tevent_context *ev = NULL;
1965 struct tevent_req *req = NULL;
1966 NTSTATUS status = NT_STATUS_OK;
1968 if (smbXcli_conn_has_async_calls(cli->conn)) {
1970 * Can't use sync call while an async call is in flight
1972 status = NT_STATUS_INVALID_PARAMETER;
1973 goto fail;
1976 ev = samba_tevent_context_init(frame);
1977 if (ev == NULL) {
1978 status = NT_STATUS_NO_MEMORY;
1979 goto fail;
1982 req = cli_nt_delete_on_close_send(frame,
1984 cli,
1985 fnum,
1986 flag);
1987 if (req == NULL) {
1988 status = NT_STATUS_NO_MEMORY;
1989 goto fail;
1992 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1993 goto fail;
1996 status = cli_nt_delete_on_close_recv(req);
1998 fail:
1999 TALLOC_FREE(frame);
2000 return status;
2003 struct cli_ntcreate1_state {
2004 uint16_t vwv[24];
2005 uint16_t fnum;
2006 struct smb_create_returns cr;
2007 struct tevent_req *subreq;
2010 static void cli_ntcreate1_done(struct tevent_req *subreq);
2011 static bool cli_ntcreate1_cancel(struct tevent_req *req);
2013 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
2014 struct tevent_context *ev,
2015 struct cli_state *cli,
2016 const char *fname,
2017 uint32_t CreatFlags,
2018 uint32_t DesiredAccess,
2019 uint32_t FileAttributes,
2020 uint32_t ShareAccess,
2021 uint32_t CreateDisposition,
2022 uint32_t CreateOptions,
2023 uint32_t ImpersonationLevel,
2024 uint8_t SecurityFlags)
2026 struct tevent_req *req, *subreq;
2027 struct cli_ntcreate1_state *state;
2028 uint16_t *vwv;
2029 uint8_t *bytes;
2030 size_t converted_len;
2031 uint16_t additional_flags2 = 0;
2033 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
2034 if (req == NULL) {
2035 return NULL;
2038 vwv = state->vwv;
2040 SCVAL(vwv+0, 0, 0xFF);
2041 SCVAL(vwv+0, 1, 0);
2042 SSVAL(vwv+1, 0, 0);
2043 SCVAL(vwv+2, 0, 0);
2045 if (cli->use_oplocks) {
2046 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
2048 SIVAL(vwv+3, 1, CreatFlags);
2049 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
2050 SIVAL(vwv+7, 1, DesiredAccess);
2051 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
2052 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
2053 SIVAL(vwv+13, 1, FileAttributes);
2054 SIVAL(vwv+15, 1, ShareAccess);
2055 SIVAL(vwv+17, 1, CreateDisposition);
2056 SIVAL(vwv+19, 1, CreateOptions |
2057 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2058 SIVAL(vwv+21, 1, ImpersonationLevel);
2059 SCVAL(vwv+23, 1, SecurityFlags);
2061 bytes = talloc_array(state, uint8_t, 0);
2062 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
2063 fname, strlen(fname)+1,
2064 &converted_len);
2066 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2067 additional_flags2 = FLAGS2_REPARSE_PATH;
2070 /* sigh. this copes with broken netapp filer behaviour */
2071 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2073 if (tevent_req_nomem(bytes, req)) {
2074 return tevent_req_post(req, ev);
2077 SSVAL(vwv+2, 1, converted_len);
2079 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2080 additional_flags2, 24, vwv,
2081 talloc_get_size(bytes), bytes);
2082 if (tevent_req_nomem(subreq, req)) {
2083 return tevent_req_post(req, ev);
2085 tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2087 state->subreq = subreq;
2088 tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2090 return req;
2093 static void cli_ntcreate1_done(struct tevent_req *subreq)
2095 struct tevent_req *req = tevent_req_callback_data(
2096 subreq, struct tevent_req);
2097 struct cli_ntcreate1_state *state = tevent_req_data(
2098 req, struct cli_ntcreate1_state);
2099 uint8_t wct;
2100 uint16_t *vwv;
2101 uint32_t num_bytes;
2102 uint8_t *bytes;
2103 NTSTATUS status;
2105 status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2106 &num_bytes, &bytes);
2107 TALLOC_FREE(subreq);
2108 if (tevent_req_nterror(req, status)) {
2109 return;
2111 state->cr.oplock_level = CVAL(vwv+2, 0);
2112 state->fnum = SVAL(vwv+2, 1);
2113 state->cr.create_action = IVAL(vwv+3, 1);
2114 state->cr.creation_time = BVAL(vwv+5, 1);
2115 state->cr.last_access_time = BVAL(vwv+9, 1);
2116 state->cr.last_write_time = BVAL(vwv+13, 1);
2117 state->cr.change_time = BVAL(vwv+17, 1);
2118 state->cr.file_attributes = IVAL(vwv+21, 1);
2119 state->cr.allocation_size = BVAL(vwv+23, 1);
2120 state->cr.end_of_file = BVAL(vwv+27, 1);
2122 tevent_req_done(req);
2125 static bool cli_ntcreate1_cancel(struct tevent_req *req)
2127 struct cli_ntcreate1_state *state = tevent_req_data(
2128 req, struct cli_ntcreate1_state);
2129 return tevent_req_cancel(state->subreq);
2132 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2133 uint16_t *pfnum,
2134 struct smb_create_returns *cr)
2136 struct cli_ntcreate1_state *state = tevent_req_data(
2137 req, struct cli_ntcreate1_state);
2138 NTSTATUS status;
2140 if (tevent_req_is_nterror(req, &status)) {
2141 return status;
2143 *pfnum = state->fnum;
2144 if (cr != NULL) {
2145 *cr = state->cr;
2147 return NT_STATUS_OK;
2150 struct cli_ntcreate_state {
2151 struct smb_create_returns cr;
2152 uint16_t fnum;
2153 struct tevent_req *subreq;
2156 static void cli_ntcreate_done_nt1(struct tevent_req *subreq);
2157 static void cli_ntcreate_done_smb2(struct tevent_req *subreq);
2158 static bool cli_ntcreate_cancel(struct tevent_req *req);
2160 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
2161 struct tevent_context *ev,
2162 struct cli_state *cli,
2163 const char *fname,
2164 uint32_t create_flags,
2165 uint32_t desired_access,
2166 uint32_t file_attributes,
2167 uint32_t share_access,
2168 uint32_t create_disposition,
2169 uint32_t create_options,
2170 uint32_t impersonation_level,
2171 uint8_t security_flags)
2173 struct tevent_req *req, *subreq;
2174 struct cli_ntcreate_state *state;
2176 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2177 if (req == NULL) {
2178 return NULL;
2181 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2182 if (cli->use_oplocks) {
2183 create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2186 subreq = cli_smb2_create_fnum_send(
2187 state,
2189 cli,
2190 fname,
2191 create_flags,
2192 impersonation_level,
2193 desired_access,
2194 file_attributes,
2195 share_access,
2196 create_disposition,
2197 create_options,
2198 NULL);
2199 if (tevent_req_nomem(subreq, req)) {
2200 return tevent_req_post(req, ev);
2202 tevent_req_set_callback(subreq, cli_ntcreate_done_smb2, req);
2203 } else {
2204 subreq = cli_ntcreate1_send(
2205 state, ev, cli, fname, create_flags, desired_access,
2206 file_attributes, share_access, create_disposition,
2207 create_options, impersonation_level, security_flags);
2208 if (tevent_req_nomem(subreq, req)) {
2209 return tevent_req_post(req, ev);
2211 tevent_req_set_callback(subreq, cli_ntcreate_done_nt1, req);
2214 state->subreq = subreq;
2215 tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2217 return req;
2220 static void cli_ntcreate_done_nt1(struct tevent_req *subreq)
2222 struct tevent_req *req = tevent_req_callback_data(
2223 subreq, struct tevent_req);
2224 struct cli_ntcreate_state *state = tevent_req_data(
2225 req, struct cli_ntcreate_state);
2226 NTSTATUS status;
2228 status = cli_ntcreate1_recv(subreq, &state->fnum, &state->cr);
2229 TALLOC_FREE(subreq);
2230 if (tevent_req_nterror(req, status)) {
2231 return;
2233 tevent_req_done(req);
2236 static void cli_ntcreate_done_smb2(struct tevent_req *subreq)
2238 struct tevent_req *req = tevent_req_callback_data(
2239 subreq, struct tevent_req);
2240 struct cli_ntcreate_state *state = tevent_req_data(
2241 req, struct cli_ntcreate_state);
2242 NTSTATUS status;
2244 status = cli_smb2_create_fnum_recv(
2245 subreq,
2246 &state->fnum,
2247 &state->cr,
2248 NULL,
2249 NULL);
2250 TALLOC_FREE(subreq);
2251 if (tevent_req_nterror(req, status)) {
2252 return;
2254 tevent_req_done(req);
2257 static bool cli_ntcreate_cancel(struct tevent_req *req)
2259 struct cli_ntcreate_state *state = tevent_req_data(
2260 req, struct cli_ntcreate_state);
2261 return tevent_req_cancel(state->subreq);
2264 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2265 struct smb_create_returns *cr)
2267 struct cli_ntcreate_state *state = tevent_req_data(
2268 req, struct cli_ntcreate_state);
2269 NTSTATUS status;
2271 if (tevent_req_is_nterror(req, &status)) {
2272 return status;
2274 if (fnum != NULL) {
2275 *fnum = state->fnum;
2277 if (cr != NULL) {
2278 *cr = state->cr;
2280 return NT_STATUS_OK;
2283 NTSTATUS cli_ntcreate(struct cli_state *cli,
2284 const char *fname,
2285 uint32_t CreatFlags,
2286 uint32_t DesiredAccess,
2287 uint32_t FileAttributes,
2288 uint32_t ShareAccess,
2289 uint32_t CreateDisposition,
2290 uint32_t CreateOptions,
2291 uint8_t SecurityFlags,
2292 uint16_t *pfid,
2293 struct smb_create_returns *cr)
2295 TALLOC_CTX *frame = talloc_stackframe();
2296 struct tevent_context *ev;
2297 struct tevent_req *req;
2298 uint32_t ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
2299 NTSTATUS status = NT_STATUS_NO_MEMORY;
2301 if (smbXcli_conn_has_async_calls(cli->conn)) {
2303 * Can't use sync call while an async call is in flight
2305 status = NT_STATUS_INVALID_PARAMETER;
2306 goto fail;
2309 ev = samba_tevent_context_init(frame);
2310 if (ev == NULL) {
2311 goto fail;
2314 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2315 DesiredAccess, FileAttributes, ShareAccess,
2316 CreateDisposition, CreateOptions,
2317 ImpersonationLevel, SecurityFlags);
2318 if (req == NULL) {
2319 goto fail;
2322 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2323 goto fail;
2326 status = cli_ntcreate_recv(req, pfid, cr);
2327 fail:
2328 TALLOC_FREE(frame);
2329 return status;
2332 struct cli_nttrans_create_state {
2333 uint16_t fnum;
2334 struct smb_create_returns cr;
2337 static void cli_nttrans_create_done(struct tevent_req *subreq);
2339 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2340 struct tevent_context *ev,
2341 struct cli_state *cli,
2342 const char *fname,
2343 uint32_t CreatFlags,
2344 uint32_t DesiredAccess,
2345 uint32_t FileAttributes,
2346 uint32_t ShareAccess,
2347 uint32_t CreateDisposition,
2348 uint32_t CreateOptions,
2349 uint8_t SecurityFlags,
2350 struct security_descriptor *secdesc,
2351 struct ea_struct *eas,
2352 int num_eas)
2354 struct tevent_req *req, *subreq;
2355 struct cli_nttrans_create_state *state;
2356 uint8_t *param;
2357 uint8_t *secdesc_buf;
2358 size_t secdesc_len;
2359 NTSTATUS status;
2360 size_t converted_len;
2361 uint16_t additional_flags2 = 0;
2363 req = tevent_req_create(mem_ctx,
2364 &state, struct cli_nttrans_create_state);
2365 if (req == NULL) {
2366 return NULL;
2369 if (secdesc != NULL) {
2370 status = marshall_sec_desc(talloc_tos(), secdesc,
2371 &secdesc_buf, &secdesc_len);
2372 if (tevent_req_nterror(req, status)) {
2373 DEBUG(10, ("marshall_sec_desc failed: %s\n",
2374 nt_errstr(status)));
2375 return tevent_req_post(req, ev);
2377 } else {
2378 secdesc_buf = NULL;
2379 secdesc_len = 0;
2382 if (num_eas != 0) {
2384 * TODO ;-)
2386 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2387 return tevent_req_post(req, ev);
2390 param = talloc_array(state, uint8_t, 53);
2391 if (tevent_req_nomem(param, req)) {
2392 return tevent_req_post(req, ev);
2395 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2396 fname, strlen(fname),
2397 &converted_len);
2398 if (tevent_req_nomem(param, req)) {
2399 return tevent_req_post(req, ev);
2402 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2403 additional_flags2 = FLAGS2_REPARSE_PATH;
2406 SIVAL(param, 0, CreatFlags);
2407 SIVAL(param, 4, 0x0); /* RootDirectoryFid */
2408 SIVAL(param, 8, DesiredAccess);
2409 SIVAL(param, 12, 0x0); /* AllocationSize */
2410 SIVAL(param, 16, 0x0); /* AllocationSize */
2411 SIVAL(param, 20, FileAttributes);
2412 SIVAL(param, 24, ShareAccess);
2413 SIVAL(param, 28, CreateDisposition);
2414 SIVAL(param, 32, CreateOptions |
2415 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2416 SIVAL(param, 36, secdesc_len);
2417 SIVAL(param, 40, 0); /* EA length*/
2418 SIVAL(param, 44, converted_len);
2419 SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2420 SCVAL(param, 52, SecurityFlags);
2422 subreq = cli_trans_send(state, ev, cli,
2423 additional_flags2, /* additional_flags2 */
2424 SMBnttrans,
2425 NULL, -1, /* name, fid */
2426 NT_TRANSACT_CREATE, 0,
2427 NULL, 0, 0, /* setup */
2428 param, talloc_get_size(param), 128, /* param */
2429 secdesc_buf, secdesc_len, 0); /* data */
2430 if (tevent_req_nomem(subreq, req)) {
2431 return tevent_req_post(req, ev);
2433 tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2434 return req;
2437 static void cli_nttrans_create_done(struct tevent_req *subreq)
2439 struct tevent_req *req = tevent_req_callback_data(
2440 subreq, struct tevent_req);
2441 struct cli_nttrans_create_state *state = tevent_req_data(
2442 req, struct cli_nttrans_create_state);
2443 uint8_t *param;
2444 uint32_t num_param;
2445 NTSTATUS status;
2447 status = cli_trans_recv(subreq, talloc_tos(), NULL,
2448 NULL, 0, NULL, /* rsetup */
2449 &param, 69, &num_param,
2450 NULL, 0, NULL);
2451 if (tevent_req_nterror(req, status)) {
2452 return;
2454 state->cr.oplock_level = CVAL(param, 0);
2455 state->fnum = SVAL(param, 2);
2456 state->cr.create_action = IVAL(param, 4);
2457 state->cr.creation_time = BVAL(param, 12);
2458 state->cr.last_access_time = BVAL(param, 20);
2459 state->cr.last_write_time = BVAL(param, 28);
2460 state->cr.change_time = BVAL(param, 36);
2461 state->cr.file_attributes = IVAL(param, 44);
2462 state->cr.allocation_size = BVAL(param, 48);
2463 state->cr.end_of_file = BVAL(param, 56);
2465 TALLOC_FREE(param);
2466 tevent_req_done(req);
2469 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2470 uint16_t *fnum,
2471 struct smb_create_returns *cr)
2473 struct cli_nttrans_create_state *state = tevent_req_data(
2474 req, struct cli_nttrans_create_state);
2475 NTSTATUS status;
2477 if (tevent_req_is_nterror(req, &status)) {
2478 return status;
2480 *fnum = state->fnum;
2481 if (cr != NULL) {
2482 *cr = state->cr;
2484 return NT_STATUS_OK;
2487 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2488 const char *fname,
2489 uint32_t CreatFlags,
2490 uint32_t DesiredAccess,
2491 uint32_t FileAttributes,
2492 uint32_t ShareAccess,
2493 uint32_t CreateDisposition,
2494 uint32_t CreateOptions,
2495 uint8_t SecurityFlags,
2496 struct security_descriptor *secdesc,
2497 struct ea_struct *eas,
2498 int num_eas,
2499 uint16_t *pfid,
2500 struct smb_create_returns *cr)
2502 TALLOC_CTX *frame = talloc_stackframe();
2503 struct tevent_context *ev;
2504 struct tevent_req *req;
2505 NTSTATUS status = NT_STATUS_NO_MEMORY;
2507 if (smbXcli_conn_has_async_calls(cli->conn)) {
2509 * Can't use sync call while an async call is in flight
2511 status = NT_STATUS_INVALID_PARAMETER;
2512 goto fail;
2514 ev = samba_tevent_context_init(frame);
2515 if (ev == NULL) {
2516 goto fail;
2518 req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2519 DesiredAccess, FileAttributes,
2520 ShareAccess, CreateDisposition,
2521 CreateOptions, SecurityFlags,
2522 secdesc, eas, num_eas);
2523 if (req == NULL) {
2524 goto fail;
2526 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2527 goto fail;
2529 status = cli_nttrans_create_recv(req, pfid, cr);
2530 fail:
2531 TALLOC_FREE(frame);
2532 return status;
2535 /****************************************************************************
2536 Open a file
2537 WARNING: if you open with O_WRONLY then getattrE won't work!
2538 ****************************************************************************/
2540 struct cli_openx_state {
2541 const char *fname;
2542 uint16_t vwv[15];
2543 uint16_t fnum;
2544 struct iovec bytes;
2547 static void cli_openx_done(struct tevent_req *subreq);
2549 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2550 struct tevent_context *ev,
2551 struct cli_state *cli, const char *fname,
2552 int flags, int share_mode,
2553 struct tevent_req **psmbreq)
2555 struct tevent_req *req, *subreq;
2556 struct cli_openx_state *state;
2557 unsigned openfn;
2558 unsigned accessmode;
2559 uint8_t additional_flags;
2560 uint16_t additional_flags2 = 0;
2561 uint8_t *bytes;
2563 req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2564 if (req == NULL) {
2565 return NULL;
2568 openfn = 0;
2569 if (flags & O_CREAT) {
2570 openfn |= (1<<4);
2572 if (!(flags & O_EXCL)) {
2573 if (flags & O_TRUNC)
2574 openfn |= (1<<1);
2575 else
2576 openfn |= (1<<0);
2579 accessmode = (share_mode<<4);
2581 if ((flags & O_ACCMODE) == O_RDWR) {
2582 accessmode |= 2;
2583 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2584 accessmode |= 1;
2587 #if defined(O_SYNC)
2588 if ((flags & O_SYNC) == O_SYNC) {
2589 accessmode |= (1<<14);
2591 #endif /* O_SYNC */
2593 if (share_mode == DENY_FCB) {
2594 accessmode = 0xFF;
2597 SCVAL(state->vwv + 0, 0, 0xFF);
2598 SCVAL(state->vwv + 0, 1, 0);
2599 SSVAL(state->vwv + 1, 0, 0);
2600 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
2601 SSVAL(state->vwv + 3, 0, accessmode);
2602 SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2603 SSVAL(state->vwv + 5, 0, 0);
2604 SIVAL(state->vwv + 6, 0, 0);
2605 SSVAL(state->vwv + 8, 0, openfn);
2606 SIVAL(state->vwv + 9, 0, 0);
2607 SIVAL(state->vwv + 11, 0, 0);
2608 SIVAL(state->vwv + 13, 0, 0);
2610 additional_flags = 0;
2612 if (cli->use_oplocks) {
2613 /* if using oplocks then ask for a batch oplock via
2614 core and extended methods */
2615 additional_flags =
2616 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2617 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2620 bytes = talloc_array(state, uint8_t, 0);
2621 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2622 strlen(fname)+1, NULL);
2624 if (tevent_req_nomem(bytes, req)) {
2625 return tevent_req_post(req, ev);
2628 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2629 additional_flags2 = FLAGS2_REPARSE_PATH;
2632 state->bytes.iov_base = (void *)bytes;
2633 state->bytes.iov_len = talloc_get_size(bytes);
2635 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2636 additional_flags2, 15, state->vwv, 1, &state->bytes);
2637 if (subreq == NULL) {
2638 TALLOC_FREE(req);
2639 return NULL;
2641 tevent_req_set_callback(subreq, cli_openx_done, req);
2642 *psmbreq = subreq;
2643 return req;
2646 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2647 struct cli_state *cli, const char *fname,
2648 int flags, int share_mode)
2650 struct tevent_req *req, *subreq;
2651 NTSTATUS status;
2653 req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
2654 &subreq);
2655 if (req == NULL) {
2656 return NULL;
2659 status = smb1cli_req_chain_submit(&subreq, 1);
2660 if (tevent_req_nterror(req, status)) {
2661 return tevent_req_post(req, ev);
2663 return req;
2666 static void cli_openx_done(struct tevent_req *subreq)
2668 struct tevent_req *req = tevent_req_callback_data(
2669 subreq, struct tevent_req);
2670 struct cli_openx_state *state = tevent_req_data(
2671 req, struct cli_openx_state);
2672 uint8_t wct;
2673 uint16_t *vwv;
2674 NTSTATUS status;
2676 status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
2677 NULL);
2678 TALLOC_FREE(subreq);
2679 if (tevent_req_nterror(req, status)) {
2680 return;
2682 state->fnum = SVAL(vwv+2, 0);
2683 tevent_req_done(req);
2686 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2688 struct cli_openx_state *state = tevent_req_data(
2689 req, struct cli_openx_state);
2690 NTSTATUS status;
2692 if (tevent_req_is_nterror(req, &status)) {
2693 return status;
2695 *pfnum = state->fnum;
2696 return NT_STATUS_OK;
2699 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
2700 int share_mode, uint16_t *pfnum)
2702 TALLOC_CTX *frame = talloc_stackframe();
2703 struct tevent_context *ev;
2704 struct tevent_req *req;
2705 NTSTATUS status = NT_STATUS_NO_MEMORY;
2707 if (smbXcli_conn_has_async_calls(cli->conn)) {
2709 * Can't use sync call while an async call is in flight
2711 status = NT_STATUS_INVALID_PARAMETER;
2712 goto fail;
2715 ev = samba_tevent_context_init(frame);
2716 if (ev == NULL) {
2717 goto fail;
2720 req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
2721 if (req == NULL) {
2722 goto fail;
2725 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2726 goto fail;
2729 status = cli_openx_recv(req, pfnum);
2730 fail:
2731 TALLOC_FREE(frame);
2732 return status;
2734 /****************************************************************************
2735 Synchronous wrapper function that does an NtCreateX open by preference
2736 and falls back to openX if this fails.
2737 ****************************************************************************/
2739 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2740 int share_mode_in, uint16_t *pfnum)
2742 NTSTATUS status;
2743 unsigned int openfn = 0;
2744 unsigned int dos_deny = 0;
2745 uint32_t access_mask, share_mode, create_disposition, create_options;
2746 struct smb_create_returns cr;
2748 /* Do the initial mapping into OpenX parameters. */
2749 if (flags & O_CREAT) {
2750 openfn |= (1<<4);
2752 if (!(flags & O_EXCL)) {
2753 if (flags & O_TRUNC)
2754 openfn |= (1<<1);
2755 else
2756 openfn |= (1<<0);
2759 dos_deny = (share_mode_in<<4);
2761 if ((flags & O_ACCMODE) == O_RDWR) {
2762 dos_deny |= 2;
2763 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2764 dos_deny |= 1;
2767 #if defined(O_SYNC)
2768 if ((flags & O_SYNC) == O_SYNC) {
2769 dos_deny |= (1<<14);
2771 #endif /* O_SYNC */
2773 if (share_mode_in == DENY_FCB) {
2774 dos_deny = 0xFF;
2777 #if 0
2778 /* Hmmm. This is what I think the above code
2779 should look like if it's using the constants
2780 we #define. JRA. */
2782 if (flags & O_CREAT) {
2783 openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
2785 if (!(flags & O_EXCL)) {
2786 if (flags & O_TRUNC)
2787 openfn |= OPENX_FILE_EXISTS_TRUNCATE;
2788 else
2789 openfn |= OPENX_FILE_EXISTS_OPEN;
2792 dos_deny = SET_DENY_MODE(share_mode_in);
2794 if ((flags & O_ACCMODE) == O_RDWR) {
2795 dos_deny |= DOS_OPEN_RDWR;
2796 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2797 dos_deny |= DOS_OPEN_WRONLY;
2800 #if defined(O_SYNC)
2801 if ((flags & O_SYNC) == O_SYNC) {
2802 dos_deny |= FILE_SYNC_OPENMODE;
2804 #endif /* O_SYNC */
2806 if (share_mode_in == DENY_FCB) {
2807 dos_deny = 0xFF;
2809 #endif
2811 if (!map_open_params_to_ntcreate(fname, dos_deny,
2812 openfn, &access_mask,
2813 &share_mode, &create_disposition,
2814 &create_options, NULL)) {
2815 goto try_openx;
2818 status = cli_ntcreate(cli,
2819 fname,
2821 access_mask,
2823 share_mode,
2824 create_disposition,
2825 create_options,
2827 pfnum,
2828 &cr);
2830 /* Try and cope will all varients of "we don't do this call"
2831 and fall back to openX. */
2833 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
2834 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
2835 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
2836 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
2837 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
2838 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
2839 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
2840 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
2841 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
2842 goto try_openx;
2845 if (NT_STATUS_IS_OK(status) &&
2846 (create_options & FILE_NON_DIRECTORY_FILE) &&
2847 (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
2850 * Some (broken) servers return a valid handle
2851 * for directories even if FILE_NON_DIRECTORY_FILE
2852 * is set. Just close the handle and set the
2853 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
2855 status = cli_close(cli, *pfnum);
2856 if (!NT_STATUS_IS_OK(status)) {
2857 return status;
2859 status = NT_STATUS_FILE_IS_A_DIRECTORY;
2860 /* Set this so libsmbclient can retrieve it. */
2861 cli->raw_status = status;
2864 return status;
2866 try_openx:
2868 return cli_openx(cli, fname, flags, share_mode_in, pfnum);
2871 /****************************************************************************
2872 Close a file.
2873 ****************************************************************************/
2875 struct cli_smb1_close_state {
2876 uint16_t vwv[3];
2879 static void cli_smb1_close_done(struct tevent_req *subreq);
2881 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
2882 struct tevent_context *ev,
2883 struct cli_state *cli,
2884 uint16_t fnum,
2885 struct tevent_req **psubreq)
2887 struct tevent_req *req, *subreq;
2888 struct cli_smb1_close_state *state;
2890 req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
2891 if (req == NULL) {
2892 return NULL;
2895 SSVAL(state->vwv+0, 0, fnum);
2896 SIVALS(state->vwv+1, 0, -1);
2898 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
2899 3, state->vwv, 0, NULL);
2900 if (subreq == NULL) {
2901 TALLOC_FREE(req);
2902 return NULL;
2904 tevent_req_set_callback(subreq, cli_smb1_close_done, req);
2905 *psubreq = subreq;
2906 return req;
2909 static void cli_smb1_close_done(struct tevent_req *subreq)
2911 struct tevent_req *req = tevent_req_callback_data(
2912 subreq, struct tevent_req);
2913 NTSTATUS status;
2915 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2916 TALLOC_FREE(subreq);
2917 if (tevent_req_nterror(req, status)) {
2918 return;
2920 tevent_req_done(req);
2923 struct cli_close_state {
2924 int dummy;
2927 static void cli_close_done(struct tevent_req *subreq);
2929 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2930 struct tevent_context *ev,
2931 struct cli_state *cli,
2932 uint16_t fnum)
2934 struct tevent_req *req, *subreq;
2935 struct cli_close_state *state;
2936 NTSTATUS status;
2938 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2939 if (req == NULL) {
2940 return NULL;
2943 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2944 subreq = cli_smb2_close_fnum_send(state,
2946 cli,
2947 fnum);
2948 if (tevent_req_nomem(subreq, req)) {
2949 return tevent_req_post(req, ev);
2951 } else {
2952 struct tevent_req *ch_req = NULL;
2953 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
2954 if (tevent_req_nomem(subreq, req)) {
2955 return tevent_req_post(req, ev);
2957 status = smb1cli_req_chain_submit(&ch_req, 1);
2958 if (tevent_req_nterror(req, status)) {
2959 return tevent_req_post(req, ev);
2963 tevent_req_set_callback(subreq, cli_close_done, req);
2964 return req;
2967 static void cli_close_done(struct tevent_req *subreq)
2969 struct tevent_req *req = tevent_req_callback_data(
2970 subreq, struct tevent_req);
2971 NTSTATUS status = NT_STATUS_OK;
2972 bool err = tevent_req_is_nterror(subreq, &status);
2974 TALLOC_FREE(subreq);
2975 if (err) {
2976 tevent_req_nterror(req, status);
2977 return;
2979 tevent_req_done(req);
2982 NTSTATUS cli_close_recv(struct tevent_req *req)
2984 return tevent_req_simple_recv_ntstatus(req);
2987 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2989 TALLOC_CTX *frame = NULL;
2990 struct tevent_context *ev;
2991 struct tevent_req *req;
2992 NTSTATUS status = NT_STATUS_OK;
2994 frame = talloc_stackframe();
2996 if (smbXcli_conn_has_async_calls(cli->conn)) {
2998 * Can't use sync call while an async call is in flight
3000 status = NT_STATUS_INVALID_PARAMETER;
3001 goto fail;
3004 ev = samba_tevent_context_init(frame);
3005 if (ev == NULL) {
3006 status = NT_STATUS_NO_MEMORY;
3007 goto fail;
3010 req = cli_close_send(frame, ev, cli, fnum);
3011 if (req == NULL) {
3012 status = NT_STATUS_NO_MEMORY;
3013 goto fail;
3016 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3017 goto fail;
3020 status = cli_close_recv(req);
3021 fail:
3022 TALLOC_FREE(frame);
3023 return status;
3026 /****************************************************************************
3027 Truncate a file to a specified size
3028 ****************************************************************************/
3030 struct ftrunc_state {
3031 uint16_t setup;
3032 uint8_t param[6];
3033 uint8_t data[8];
3036 static void cli_ftruncate_done(struct tevent_req *subreq)
3038 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3039 NULL, 0, NULL, NULL, 0, NULL);
3040 tevent_req_simple_finish_ntstatus(subreq, status);
3043 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
3044 struct tevent_context *ev,
3045 struct cli_state *cli,
3046 uint16_t fnum,
3047 uint64_t size)
3049 struct tevent_req *req = NULL, *subreq = NULL;
3050 struct ftrunc_state *state = NULL;
3052 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
3053 if (req == NULL) {
3054 return NULL;
3057 /* Setup setup word. */
3058 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3060 /* Setup param array. */
3061 SSVAL(state->param,0,fnum);
3062 SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
3063 SSVAL(state->param,4,0);
3065 /* Setup data array. */
3066 SBVAL(state->data, 0, size);
3068 subreq = cli_trans_send(state, /* mem ctx. */
3069 ev, /* event ctx. */
3070 cli, /* cli_state. */
3071 0, /* additional_flags2 */
3072 SMBtrans2, /* cmd. */
3073 NULL, /* pipe name. */
3074 -1, /* fid. */
3075 0, /* function. */
3076 0, /* flags. */
3077 &state->setup, /* setup. */
3078 1, /* num setup uint16_t words. */
3079 0, /* max returned setup. */
3080 state->param, /* param. */
3081 6, /* num param. */
3082 2, /* max returned param. */
3083 state->data, /* data. */
3084 8, /* num data. */
3085 0); /* max returned data. */
3087 if (tevent_req_nomem(subreq, req)) {
3088 return tevent_req_post(req, ev);
3090 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
3091 return req;
3094 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
3096 return tevent_req_simple_recv_ntstatus(req);
3099 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3101 TALLOC_CTX *frame = NULL;
3102 struct tevent_context *ev = NULL;
3103 struct tevent_req *req = NULL;
3104 NTSTATUS status = NT_STATUS_OK;
3106 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3107 return cli_smb2_ftruncate(cli, fnum, size);
3110 frame = talloc_stackframe();
3112 if (smbXcli_conn_has_async_calls(cli->conn)) {
3114 * Can't use sync call while an async call is in flight
3116 status = NT_STATUS_INVALID_PARAMETER;
3117 goto fail;
3120 ev = samba_tevent_context_init(frame);
3121 if (ev == NULL) {
3122 status = NT_STATUS_NO_MEMORY;
3123 goto fail;
3126 req = cli_ftruncate_send(frame,
3128 cli,
3129 fnum,
3130 size);
3131 if (req == NULL) {
3132 status = NT_STATUS_NO_MEMORY;
3133 goto fail;
3136 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3137 goto fail;
3140 status = cli_ftruncate_recv(req);
3142 fail:
3143 TALLOC_FREE(frame);
3144 return status;
3147 /****************************************************************************
3148 send a lock with a specified locktype
3149 this is used for testing LOCKING_ANDX_CANCEL_LOCK
3150 ****************************************************************************/
3152 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
3153 uint32_t offset, uint32_t len,
3154 int timeout, unsigned char locktype)
3156 uint16_t vwv[8];
3157 uint8_t bytes[10];
3158 NTSTATUS status;
3159 unsigned int set_timeout = 0;
3160 unsigned int saved_timeout = 0;
3162 SCVAL(vwv + 0, 0, 0xff);
3163 SCVAL(vwv + 0, 1, 0);
3164 SSVAL(vwv + 1, 0, 0);
3165 SSVAL(vwv + 2, 0, fnum);
3166 SCVAL(vwv + 3, 0, locktype);
3167 SCVAL(vwv + 3, 1, 0);
3168 SIVALS(vwv + 4, 0, timeout);
3169 SSVAL(vwv + 6, 0, 0);
3170 SSVAL(vwv + 7, 0, 1);
3172 SSVAL(bytes, 0, cli_getpid(cli));
3173 SIVAL(bytes, 2, offset);
3174 SIVAL(bytes, 6, len);
3176 if (timeout != 0) {
3177 if (timeout == -1) {
3178 set_timeout = 0x7FFFFFFF;
3179 } else {
3180 set_timeout = timeout + 2*1000;
3182 saved_timeout = cli_set_timeout(cli, set_timeout);
3185 status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3186 10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3188 if (saved_timeout != 0) {
3189 cli_set_timeout(cli, saved_timeout);
3192 return status;
3195 /****************************************************************************
3196 Lock a file.
3197 note that timeout is in units of 2 milliseconds
3198 ****************************************************************************/
3200 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
3201 uint32_t offset, uint32_t len, int timeout,
3202 enum brl_type lock_type)
3204 NTSTATUS status;
3206 status = cli_locktype(cli, fnum, offset, len, timeout,
3207 (lock_type == READ_LOCK? 1 : 0));
3208 return status;
3211 /****************************************************************************
3212 Unlock a file.
3213 ****************************************************************************/
3215 struct cli_unlock_state {
3216 uint16_t vwv[8];
3217 uint8_t data[10];
3220 static void cli_unlock_done(struct tevent_req *subreq);
3222 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3223 struct tevent_context *ev,
3224 struct cli_state *cli,
3225 uint16_t fnum,
3226 uint64_t offset,
3227 uint64_t len)
3230 struct tevent_req *req = NULL, *subreq = NULL;
3231 struct cli_unlock_state *state = NULL;
3232 uint8_t additional_flags = 0;
3234 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3235 if (req == NULL) {
3236 return NULL;
3239 SCVAL(state->vwv+0, 0, 0xFF);
3240 SSVAL(state->vwv+2, 0, fnum);
3241 SCVAL(state->vwv+3, 0, 0);
3242 SIVALS(state->vwv+4, 0, 0);
3243 SSVAL(state->vwv+6, 0, 1);
3244 SSVAL(state->vwv+7, 0, 0);
3246 SSVAL(state->data, 0, cli_getpid(cli));
3247 SIVAL(state->data, 2, offset);
3248 SIVAL(state->data, 6, len);
3250 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3251 8, state->vwv, 10, state->data);
3252 if (tevent_req_nomem(subreq, req)) {
3253 return tevent_req_post(req, ev);
3255 tevent_req_set_callback(subreq, cli_unlock_done, req);
3256 return req;
3259 static void cli_unlock_done(struct tevent_req *subreq)
3261 struct tevent_req *req = tevent_req_callback_data(
3262 subreq, struct tevent_req);
3263 NTSTATUS status;
3265 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3266 TALLOC_FREE(subreq);
3267 if (tevent_req_nterror(req, status)) {
3268 return;
3270 tevent_req_done(req);
3273 NTSTATUS cli_unlock_recv(struct tevent_req *req)
3275 return tevent_req_simple_recv_ntstatus(req);
3278 NTSTATUS cli_unlock(struct cli_state *cli,
3279 uint16_t fnum,
3280 uint32_t offset,
3281 uint32_t len)
3283 TALLOC_CTX *frame = talloc_stackframe();
3284 struct tevent_context *ev;
3285 struct tevent_req *req;
3286 NTSTATUS status = NT_STATUS_OK;
3288 if (smbXcli_conn_has_async_calls(cli->conn)) {
3290 * Can't use sync call while an async call is in flight
3292 status = NT_STATUS_INVALID_PARAMETER;
3293 goto fail;
3296 ev = samba_tevent_context_init(frame);
3297 if (ev == NULL) {
3298 status = NT_STATUS_NO_MEMORY;
3299 goto fail;
3302 req = cli_unlock_send(frame, ev, cli,
3303 fnum, offset, len);
3304 if (req == NULL) {
3305 status = NT_STATUS_NO_MEMORY;
3306 goto fail;
3309 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3310 goto fail;
3313 status = cli_unlock_recv(req);
3315 fail:
3316 TALLOC_FREE(frame);
3317 return status;
3320 /****************************************************************************
3321 Lock a file with 64 bit offsets.
3322 ****************************************************************************/
3324 NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
3325 uint64_t offset, uint64_t len, int timeout,
3326 enum brl_type lock_type)
3328 uint16_t vwv[8];
3329 uint8_t bytes[20];
3330 unsigned int set_timeout = 0;
3331 unsigned int saved_timeout = 0;
3332 int ltype;
3333 NTSTATUS status;
3335 if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3336 return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
3339 ltype = (lock_type == READ_LOCK? 1 : 0);
3340 ltype |= LOCKING_ANDX_LARGE_FILES;
3342 SCVAL(vwv + 0, 0, 0xff);
3343 SCVAL(vwv + 0, 1, 0);
3344 SSVAL(vwv + 1, 0, 0);
3345 SSVAL(vwv + 2, 0, fnum);
3346 SCVAL(vwv + 3, 0, ltype);
3347 SCVAL(vwv + 3, 1, 0);
3348 SIVALS(vwv + 4, 0, timeout);
3349 SSVAL(vwv + 6, 0, 0);
3350 SSVAL(vwv + 7, 0, 1);
3352 SIVAL(bytes, 0, cli_getpid(cli));
3353 SOFF_T_R(bytes, 4, offset);
3354 SOFF_T_R(bytes, 12, len);
3356 if (timeout != 0) {
3357 if (timeout == -1) {
3358 set_timeout = 0x7FFFFFFF;
3359 } else {
3360 set_timeout = timeout + 2*1000;
3362 saved_timeout = cli_set_timeout(cli, set_timeout);
3365 status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3366 20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3368 if (saved_timeout != 0) {
3369 cli_set_timeout(cli, saved_timeout);
3372 return status;
3375 /****************************************************************************
3376 Unlock a file with 64 bit offsets.
3377 ****************************************************************************/
3379 struct cli_unlock64_state {
3380 uint16_t vwv[8];
3381 uint8_t data[20];
3384 static void cli_unlock64_done(struct tevent_req *subreq);
3386 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
3387 struct tevent_context *ev,
3388 struct cli_state *cli,
3389 uint16_t fnum,
3390 uint64_t offset,
3391 uint64_t len)
3394 struct tevent_req *req = NULL, *subreq = NULL;
3395 struct cli_unlock64_state *state = NULL;
3396 uint8_t additional_flags = 0;
3398 req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
3399 if (req == NULL) {
3400 return NULL;
3403 SCVAL(state->vwv+0, 0, 0xff);
3404 SSVAL(state->vwv+2, 0, fnum);
3405 SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
3406 SIVALS(state->vwv+4, 0, 0);
3407 SSVAL(state->vwv+6, 0, 1);
3408 SSVAL(state->vwv+7, 0, 0);
3410 SIVAL(state->data, 0, cli_getpid(cli));
3411 SOFF_T_R(state->data, 4, offset);
3412 SOFF_T_R(state->data, 12, len);
3414 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3415 8, state->vwv, 20, state->data);
3416 if (tevent_req_nomem(subreq, req)) {
3417 return tevent_req_post(req, ev);
3419 tevent_req_set_callback(subreq, cli_unlock64_done, req);
3420 return req;
3423 static void cli_unlock64_done(struct tevent_req *subreq)
3425 struct tevent_req *req = tevent_req_callback_data(
3426 subreq, struct tevent_req);
3427 NTSTATUS status;
3429 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3430 TALLOC_FREE(subreq);
3431 if (tevent_req_nterror(req, status)) {
3432 return;
3434 tevent_req_done(req);
3437 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
3439 return tevent_req_simple_recv_ntstatus(req);
3442 NTSTATUS cli_unlock64(struct cli_state *cli,
3443 uint16_t fnum,
3444 uint64_t offset,
3445 uint64_t len)
3447 TALLOC_CTX *frame = talloc_stackframe();
3448 struct tevent_context *ev;
3449 struct tevent_req *req;
3450 NTSTATUS status = NT_STATUS_OK;
3452 if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3453 return cli_unlock(cli, fnum, offset, len);
3456 if (smbXcli_conn_has_async_calls(cli->conn)) {
3458 * Can't use sync call while an async call is in flight
3460 status = NT_STATUS_INVALID_PARAMETER;
3461 goto fail;
3464 ev = samba_tevent_context_init(frame);
3465 if (ev == NULL) {
3466 status = NT_STATUS_NO_MEMORY;
3467 goto fail;
3470 req = cli_unlock64_send(frame, ev, cli,
3471 fnum, offset, len);
3472 if (req == NULL) {
3473 status = NT_STATUS_NO_MEMORY;
3474 goto fail;
3477 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3478 goto fail;
3481 status = cli_unlock64_recv(req);
3483 fail:
3484 TALLOC_FREE(frame);
3485 return status;
3488 /****************************************************************************
3489 Get/unlock a POSIX lock on a file - internal function.
3490 ****************************************************************************/
3492 struct posix_lock_state {
3493 uint16_t setup;
3494 uint8_t param[4];
3495 uint8_t data[POSIX_LOCK_DATA_SIZE];
3498 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3500 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3501 NULL, 0, NULL, NULL, 0, NULL);
3502 tevent_req_simple_finish_ntstatus(subreq, status);
3505 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3506 struct tevent_context *ev,
3507 struct cli_state *cli,
3508 uint16_t fnum,
3509 uint64_t offset,
3510 uint64_t len,
3511 bool wait_lock,
3512 enum brl_type lock_type)
3514 struct tevent_req *req = NULL, *subreq = NULL;
3515 struct posix_lock_state *state = NULL;
3517 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3518 if (req == NULL) {
3519 return NULL;
3522 /* Setup setup word. */
3523 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3525 /* Setup param array. */
3526 SSVAL(&state->param, 0, fnum);
3527 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3529 /* Setup data array. */
3530 switch (lock_type) {
3531 case READ_LOCK:
3532 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3533 POSIX_LOCK_TYPE_READ);
3534 break;
3535 case WRITE_LOCK:
3536 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3537 POSIX_LOCK_TYPE_WRITE);
3538 break;
3539 case UNLOCK_LOCK:
3540 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3541 POSIX_LOCK_TYPE_UNLOCK);
3542 break;
3543 default:
3544 return NULL;
3547 if (wait_lock) {
3548 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3549 POSIX_LOCK_FLAG_WAIT);
3550 } else {
3551 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3552 POSIX_LOCK_FLAG_NOWAIT);
3555 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3556 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3557 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3559 subreq = cli_trans_send(state, /* mem ctx. */
3560 ev, /* event ctx. */
3561 cli, /* cli_state. */
3562 0, /* additional_flags2 */
3563 SMBtrans2, /* cmd. */
3564 NULL, /* pipe name. */
3565 -1, /* fid. */
3566 0, /* function. */
3567 0, /* flags. */
3568 &state->setup, /* setup. */
3569 1, /* num setup uint16_t words. */
3570 0, /* max returned setup. */
3571 state->param, /* param. */
3572 4, /* num param. */
3573 2, /* max returned param. */
3574 state->data, /* data. */
3575 POSIX_LOCK_DATA_SIZE, /* num data. */
3576 0); /* max returned data. */
3578 if (tevent_req_nomem(subreq, req)) {
3579 return tevent_req_post(req, ev);
3581 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3582 return req;
3585 /****************************************************************************
3586 POSIX Lock a file.
3587 ****************************************************************************/
3589 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3590 struct tevent_context *ev,
3591 struct cli_state *cli,
3592 uint16_t fnum,
3593 uint64_t offset,
3594 uint64_t len,
3595 bool wait_lock,
3596 enum brl_type lock_type)
3598 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3599 wait_lock, lock_type);
3602 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3604 return tevent_req_simple_recv_ntstatus(req);
3607 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3608 uint64_t offset, uint64_t len,
3609 bool wait_lock, enum brl_type lock_type)
3611 TALLOC_CTX *frame = talloc_stackframe();
3612 struct tevent_context *ev = NULL;
3613 struct tevent_req *req = NULL;
3614 NTSTATUS status = NT_STATUS_OK;
3616 if (smbXcli_conn_has_async_calls(cli->conn)) {
3618 * Can't use sync call while an async call is in flight
3620 status = NT_STATUS_INVALID_PARAMETER;
3621 goto fail;
3624 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3625 status = NT_STATUS_INVALID_PARAMETER;
3626 goto fail;
3629 ev = samba_tevent_context_init(frame);
3630 if (ev == NULL) {
3631 status = NT_STATUS_NO_MEMORY;
3632 goto fail;
3635 req = cli_posix_lock_send(frame,
3637 cli,
3638 fnum,
3639 offset,
3640 len,
3641 wait_lock,
3642 lock_type);
3643 if (req == NULL) {
3644 status = NT_STATUS_NO_MEMORY;
3645 goto fail;
3648 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3649 goto fail;
3652 status = cli_posix_lock_recv(req);
3654 fail:
3655 TALLOC_FREE(frame);
3656 return status;
3659 /****************************************************************************
3660 POSIX Unlock a file.
3661 ****************************************************************************/
3663 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3664 struct tevent_context *ev,
3665 struct cli_state *cli,
3666 uint16_t fnum,
3667 uint64_t offset,
3668 uint64_t len)
3670 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3671 false, UNLOCK_LOCK);
3674 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3676 return tevent_req_simple_recv_ntstatus(req);
3679 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3681 TALLOC_CTX *frame = talloc_stackframe();
3682 struct tevent_context *ev = NULL;
3683 struct tevent_req *req = NULL;
3684 NTSTATUS status = NT_STATUS_OK;
3686 if (smbXcli_conn_has_async_calls(cli->conn)) {
3688 * Can't use sync call while an async call is in flight
3690 status = NT_STATUS_INVALID_PARAMETER;
3691 goto fail;
3694 ev = samba_tevent_context_init(frame);
3695 if (ev == NULL) {
3696 status = NT_STATUS_NO_MEMORY;
3697 goto fail;
3700 req = cli_posix_unlock_send(frame,
3702 cli,
3703 fnum,
3704 offset,
3705 len);
3706 if (req == NULL) {
3707 status = NT_STATUS_NO_MEMORY;
3708 goto fail;
3711 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3712 goto fail;
3715 status = cli_posix_unlock_recv(req);
3717 fail:
3718 TALLOC_FREE(frame);
3719 return status;
3722 /****************************************************************************
3723 Do a SMBgetattrE call.
3724 ****************************************************************************/
3726 static void cli_getattrE_done(struct tevent_req *subreq);
3728 struct cli_getattrE_state {
3729 uint16_t vwv[1];
3730 int zone_offset;
3731 uint16_t attr;
3732 off_t size;
3733 time_t change_time;
3734 time_t access_time;
3735 time_t write_time;
3738 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3739 struct tevent_context *ev,
3740 struct cli_state *cli,
3741 uint16_t fnum)
3743 struct tevent_req *req = NULL, *subreq = NULL;
3744 struct cli_getattrE_state *state = NULL;
3745 uint8_t additional_flags = 0;
3747 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3748 if (req == NULL) {
3749 return NULL;
3752 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3753 SSVAL(state->vwv+0,0,fnum);
3755 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
3756 1, state->vwv, 0, NULL);
3757 if (tevent_req_nomem(subreq, req)) {
3758 return tevent_req_post(req, ev);
3760 tevent_req_set_callback(subreq, cli_getattrE_done, req);
3761 return req;
3764 static void cli_getattrE_done(struct tevent_req *subreq)
3766 struct tevent_req *req = tevent_req_callback_data(
3767 subreq, struct tevent_req);
3768 struct cli_getattrE_state *state = tevent_req_data(
3769 req, struct cli_getattrE_state);
3770 uint8_t wct;
3771 uint16_t *vwv = NULL;
3772 NTSTATUS status;
3774 status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
3775 NULL, NULL);
3776 TALLOC_FREE(subreq);
3777 if (tevent_req_nterror(req, status)) {
3778 return;
3781 state->size = (off_t)IVAL(vwv+6,0);
3782 state->attr = SVAL(vwv+10,0);
3783 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3784 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3785 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3787 tevent_req_done(req);
3790 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3791 uint16_t *attr,
3792 off_t *size,
3793 time_t *change_time,
3794 time_t *access_time,
3795 time_t *write_time)
3797 struct cli_getattrE_state *state = tevent_req_data(
3798 req, struct cli_getattrE_state);
3799 NTSTATUS status;
3801 if (tevent_req_is_nterror(req, &status)) {
3802 return status;
3804 if (attr) {
3805 *attr = state->attr;
3807 if (size) {
3808 *size = state->size;
3810 if (change_time) {
3811 *change_time = state->change_time;
3813 if (access_time) {
3814 *access_time = state->access_time;
3816 if (write_time) {
3817 *write_time = state->write_time;
3819 return NT_STATUS_OK;
3822 NTSTATUS cli_getattrE(struct cli_state *cli,
3823 uint16_t fnum,
3824 uint16_t *attr,
3825 off_t *size,
3826 time_t *change_time,
3827 time_t *access_time,
3828 time_t *write_time)
3830 TALLOC_CTX *frame = NULL;
3831 struct tevent_context *ev = NULL;
3832 struct tevent_req *req = NULL;
3833 NTSTATUS status = NT_STATUS_OK;
3835 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3836 return cli_smb2_getattrE(cli,
3837 fnum,
3838 attr,
3839 size,
3840 change_time,
3841 access_time,
3842 write_time);
3845 frame = talloc_stackframe();
3847 if (smbXcli_conn_has_async_calls(cli->conn)) {
3849 * Can't use sync call while an async call is in flight
3851 status = NT_STATUS_INVALID_PARAMETER;
3852 goto fail;
3855 ev = samba_tevent_context_init(frame);
3856 if (ev == NULL) {
3857 status = NT_STATUS_NO_MEMORY;
3858 goto fail;
3861 req = cli_getattrE_send(frame, ev, cli, fnum);
3862 if (req == NULL) {
3863 status = NT_STATUS_NO_MEMORY;
3864 goto fail;
3867 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3868 goto fail;
3871 status = cli_getattrE_recv(req,
3872 attr,
3873 size,
3874 change_time,
3875 access_time,
3876 write_time);
3878 fail:
3879 TALLOC_FREE(frame);
3880 return status;
3883 /****************************************************************************
3884 Do a SMBgetatr call
3885 ****************************************************************************/
3887 static void cli_getatr_done(struct tevent_req *subreq);
3889 struct cli_getatr_state {
3890 int zone_offset;
3891 uint16_t attr;
3892 off_t size;
3893 time_t write_time;
3896 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3897 struct tevent_context *ev,
3898 struct cli_state *cli,
3899 const char *fname)
3901 struct tevent_req *req = NULL, *subreq = NULL;
3902 struct cli_getatr_state *state = NULL;
3903 uint8_t additional_flags = 0;
3904 uint16_t additional_flags2 = 0;
3905 uint8_t *bytes = NULL;
3907 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3908 if (req == NULL) {
3909 return NULL;
3912 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3914 bytes = talloc_array(state, uint8_t, 1);
3915 if (tevent_req_nomem(bytes, req)) {
3916 return tevent_req_post(req, ev);
3918 bytes[0] = 4;
3919 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3920 strlen(fname)+1, NULL);
3922 if (tevent_req_nomem(bytes, req)) {
3923 return tevent_req_post(req, ev);
3926 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
3927 additional_flags2 = FLAGS2_REPARSE_PATH;
3930 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3931 additional_flags2,
3932 0, NULL, talloc_get_size(bytes), bytes);
3933 if (tevent_req_nomem(subreq, req)) {
3934 return tevent_req_post(req, ev);
3936 tevent_req_set_callback(subreq, cli_getatr_done, req);
3937 return req;
3940 static void cli_getatr_done(struct tevent_req *subreq)
3942 struct tevent_req *req = tevent_req_callback_data(
3943 subreq, struct tevent_req);
3944 struct cli_getatr_state *state = tevent_req_data(
3945 req, struct cli_getatr_state);
3946 uint8_t wct;
3947 uint16_t *vwv = NULL;
3948 NTSTATUS status;
3950 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
3951 NULL);
3952 TALLOC_FREE(subreq);
3953 if (tevent_req_nterror(req, status)) {
3954 return;
3957 state->attr = SVAL(vwv+0,0);
3958 state->size = (off_t)IVAL(vwv+3,0);
3959 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3961 tevent_req_done(req);
3964 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3965 uint16_t *attr,
3966 off_t *size,
3967 time_t *write_time)
3969 struct cli_getatr_state *state = tevent_req_data(
3970 req, struct cli_getatr_state);
3971 NTSTATUS status;
3973 if (tevent_req_is_nterror(req, &status)) {
3974 return status;
3976 if (attr) {
3977 *attr = state->attr;
3979 if (size) {
3980 *size = state->size;
3982 if (write_time) {
3983 *write_time = state->write_time;
3985 return NT_STATUS_OK;
3988 NTSTATUS cli_getatr(struct cli_state *cli,
3989 const char *fname,
3990 uint16_t *attr,
3991 off_t *size,
3992 time_t *write_time)
3994 TALLOC_CTX *frame = NULL;
3995 struct tevent_context *ev = NULL;
3996 struct tevent_req *req = NULL;
3997 NTSTATUS status = NT_STATUS_OK;
3999 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4000 return cli_smb2_getatr(cli,
4001 fname,
4002 attr,
4003 size,
4004 write_time);
4007 frame = talloc_stackframe();
4009 if (smbXcli_conn_has_async_calls(cli->conn)) {
4011 * Can't use sync call while an async call is in flight
4013 status = NT_STATUS_INVALID_PARAMETER;
4014 goto fail;
4017 ev = samba_tevent_context_init(frame);
4018 if (ev == NULL) {
4019 status = NT_STATUS_NO_MEMORY;
4020 goto fail;
4023 req = cli_getatr_send(frame, ev, cli, fname);
4024 if (req == NULL) {
4025 status = NT_STATUS_NO_MEMORY;
4026 goto fail;
4029 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4030 goto fail;
4033 status = cli_getatr_recv(req,
4034 attr,
4035 size,
4036 write_time);
4038 fail:
4039 TALLOC_FREE(frame);
4040 return status;
4043 /****************************************************************************
4044 Do a SMBsetattrE call.
4045 ****************************************************************************/
4047 static void cli_setattrE_done(struct tevent_req *subreq);
4049 struct cli_setattrE_state {
4050 uint16_t vwv[7];
4053 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
4054 struct tevent_context *ev,
4055 struct cli_state *cli,
4056 uint16_t fnum,
4057 time_t change_time,
4058 time_t access_time,
4059 time_t write_time)
4061 struct tevent_req *req = NULL, *subreq = NULL;
4062 struct cli_setattrE_state *state = NULL;
4063 uint8_t additional_flags = 0;
4065 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
4066 if (req == NULL) {
4067 return NULL;
4070 SSVAL(state->vwv+0, 0, fnum);
4071 push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
4072 smb1cli_conn_server_time_zone(cli->conn));
4073 push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
4074 smb1cli_conn_server_time_zone(cli->conn));
4075 push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
4076 smb1cli_conn_server_time_zone(cli->conn));
4078 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
4079 7, state->vwv, 0, NULL);
4080 if (tevent_req_nomem(subreq, req)) {
4081 return tevent_req_post(req, ev);
4083 tevent_req_set_callback(subreq, cli_setattrE_done, req);
4084 return req;
4087 static void cli_setattrE_done(struct tevent_req *subreq)
4089 struct tevent_req *req = tevent_req_callback_data(
4090 subreq, struct tevent_req);
4091 NTSTATUS status;
4093 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4094 TALLOC_FREE(subreq);
4095 if (tevent_req_nterror(req, status)) {
4096 return;
4098 tevent_req_done(req);
4101 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4103 return tevent_req_simple_recv_ntstatus(req);
4106 NTSTATUS cli_setattrE(struct cli_state *cli,
4107 uint16_t fnum,
4108 time_t change_time,
4109 time_t access_time,
4110 time_t write_time)
4112 TALLOC_CTX *frame = NULL;
4113 struct tevent_context *ev = NULL;
4114 struct tevent_req *req = NULL;
4115 NTSTATUS status = NT_STATUS_OK;
4117 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4118 return cli_smb2_setattrE(cli,
4119 fnum,
4120 change_time,
4121 access_time,
4122 write_time);
4125 frame = talloc_stackframe();
4127 if (smbXcli_conn_has_async_calls(cli->conn)) {
4129 * Can't use sync call while an async call is in flight
4131 status = NT_STATUS_INVALID_PARAMETER;
4132 goto fail;
4135 ev = samba_tevent_context_init(frame);
4136 if (ev == NULL) {
4137 status = NT_STATUS_NO_MEMORY;
4138 goto fail;
4141 req = cli_setattrE_send(frame, ev,
4142 cli,
4143 fnum,
4144 change_time,
4145 access_time,
4146 write_time);
4148 if (req == NULL) {
4149 status = NT_STATUS_NO_MEMORY;
4150 goto fail;
4153 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4154 goto fail;
4157 status = cli_setattrE_recv(req);
4159 fail:
4160 TALLOC_FREE(frame);
4161 return status;
4164 /****************************************************************************
4165 Do a SMBsetatr call.
4166 ****************************************************************************/
4168 static void cli_setatr_done(struct tevent_req *subreq);
4170 struct cli_setatr_state {
4171 uint16_t vwv[8];
4174 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
4175 struct tevent_context *ev,
4176 struct cli_state *cli,
4177 const char *fname,
4178 uint16_t attr,
4179 time_t mtime)
4181 struct tevent_req *req = NULL, *subreq = NULL;
4182 struct cli_setatr_state *state = NULL;
4183 uint8_t additional_flags = 0;
4184 uint16_t additional_flags2 = 0;
4185 uint8_t *bytes = NULL;
4187 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
4188 if (req == NULL) {
4189 return NULL;
4192 SSVAL(state->vwv+0, 0, attr);
4193 push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
4195 bytes = talloc_array(state, uint8_t, 1);
4196 if (tevent_req_nomem(bytes, req)) {
4197 return tevent_req_post(req, ev);
4199 bytes[0] = 4;
4200 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4201 strlen(fname)+1, NULL);
4202 if (tevent_req_nomem(bytes, req)) {
4203 return tevent_req_post(req, ev);
4205 bytes = talloc_realloc(state, bytes, uint8_t,
4206 talloc_get_size(bytes)+1);
4207 if (tevent_req_nomem(bytes, req)) {
4208 return tevent_req_post(req, ev);
4211 bytes[talloc_get_size(bytes)-1] = 4;
4212 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
4213 1, NULL);
4214 if (tevent_req_nomem(bytes, req)) {
4215 return tevent_req_post(req, ev);
4218 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4219 additional_flags2 = FLAGS2_REPARSE_PATH;
4222 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
4223 additional_flags2,
4224 8, state->vwv, talloc_get_size(bytes), bytes);
4225 if (tevent_req_nomem(subreq, req)) {
4226 return tevent_req_post(req, ev);
4228 tevent_req_set_callback(subreq, cli_setatr_done, req);
4229 return req;
4232 static void cli_setatr_done(struct tevent_req *subreq)
4234 struct tevent_req *req = tevent_req_callback_data(
4235 subreq, struct tevent_req);
4236 NTSTATUS status;
4238 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4239 TALLOC_FREE(subreq);
4240 if (tevent_req_nterror(req, status)) {
4241 return;
4243 tevent_req_done(req);
4246 NTSTATUS cli_setatr_recv(struct tevent_req *req)
4248 return tevent_req_simple_recv_ntstatus(req);
4251 NTSTATUS cli_setatr(struct cli_state *cli,
4252 const char *fname,
4253 uint16_t attr,
4254 time_t mtime)
4256 TALLOC_CTX *frame = NULL;
4257 struct tevent_context *ev = NULL;
4258 struct tevent_req *req = NULL;
4259 NTSTATUS status = NT_STATUS_OK;
4261 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4262 return cli_smb2_setatr(cli,
4263 fname,
4264 attr,
4265 mtime);
4268 frame = talloc_stackframe();
4270 if (smbXcli_conn_has_async_calls(cli->conn)) {
4272 * Can't use sync call while an async call is in flight
4274 status = NT_STATUS_INVALID_PARAMETER;
4275 goto fail;
4278 ev = samba_tevent_context_init(frame);
4279 if (ev == NULL) {
4280 status = NT_STATUS_NO_MEMORY;
4281 goto fail;
4284 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
4285 if (req == NULL) {
4286 status = NT_STATUS_NO_MEMORY;
4287 goto fail;
4290 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4291 goto fail;
4294 status = cli_setatr_recv(req);
4296 fail:
4297 TALLOC_FREE(frame);
4298 return status;
4301 /****************************************************************************
4302 Check for existence of a dir.
4303 ****************************************************************************/
4305 static void cli_chkpath_done(struct tevent_req *subreq);
4307 struct cli_chkpath_state {
4308 int dummy;
4311 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
4312 struct tevent_context *ev,
4313 struct cli_state *cli,
4314 const char *fname)
4316 struct tevent_req *req = NULL, *subreq = NULL;
4317 struct cli_chkpath_state *state = NULL;
4318 uint8_t additional_flags = 0;
4319 uint16_t additional_flags2 = 0;
4320 uint8_t *bytes = NULL;
4322 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
4323 if (req == NULL) {
4324 return NULL;
4327 bytes = talloc_array(state, uint8_t, 1);
4328 if (tevent_req_nomem(bytes, req)) {
4329 return tevent_req_post(req, ev);
4331 bytes[0] = 4;
4332 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4333 strlen(fname)+1, NULL);
4335 if (tevent_req_nomem(bytes, req)) {
4336 return tevent_req_post(req, ev);
4339 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4340 additional_flags2 = FLAGS2_REPARSE_PATH;
4343 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
4344 additional_flags2,
4345 0, NULL, talloc_get_size(bytes), bytes);
4346 if (tevent_req_nomem(subreq, req)) {
4347 return tevent_req_post(req, ev);
4349 tevent_req_set_callback(subreq, cli_chkpath_done, req);
4350 return req;
4353 static void cli_chkpath_done(struct tevent_req *subreq)
4355 struct tevent_req *req = tevent_req_callback_data(
4356 subreq, struct tevent_req);
4357 NTSTATUS status;
4359 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4360 TALLOC_FREE(subreq);
4361 if (tevent_req_nterror(req, status)) {
4362 return;
4364 tevent_req_done(req);
4367 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
4369 return tevent_req_simple_recv_ntstatus(req);
4372 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
4374 TALLOC_CTX *frame = NULL;
4375 struct tevent_context *ev = NULL;
4376 struct tevent_req *req = NULL;
4377 char *path2 = NULL;
4378 NTSTATUS status = NT_STATUS_OK;
4380 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4381 return cli_smb2_chkpath(cli, path);
4384 frame = talloc_stackframe();
4386 if (smbXcli_conn_has_async_calls(cli->conn)) {
4388 * Can't use sync call while an async call is in flight
4390 status = NT_STATUS_INVALID_PARAMETER;
4391 goto fail;
4394 path2 = talloc_strdup(frame, path);
4395 if (!path2) {
4396 status = NT_STATUS_NO_MEMORY;
4397 goto fail;
4399 trim_char(path2,'\0','\\');
4400 if (!*path2) {
4401 path2 = talloc_strdup(frame, "\\");
4402 if (!path2) {
4403 status = NT_STATUS_NO_MEMORY;
4404 goto fail;
4408 ev = samba_tevent_context_init(frame);
4409 if (ev == NULL) {
4410 status = NT_STATUS_NO_MEMORY;
4411 goto fail;
4414 req = cli_chkpath_send(frame, ev, cli, path2);
4415 if (req == NULL) {
4416 status = NT_STATUS_NO_MEMORY;
4417 goto fail;
4420 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4421 goto fail;
4424 status = cli_chkpath_recv(req);
4426 fail:
4427 TALLOC_FREE(frame);
4428 return status;
4431 /****************************************************************************
4432 Query disk space.
4433 ****************************************************************************/
4435 static void cli_dskattr_done(struct tevent_req *subreq);
4437 struct cli_dskattr_state {
4438 int bsize;
4439 int total;
4440 int avail;
4443 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
4444 struct tevent_context *ev,
4445 struct cli_state *cli)
4447 struct tevent_req *req = NULL, *subreq = NULL;
4448 struct cli_dskattr_state *state = NULL;
4449 uint8_t additional_flags = 0;
4451 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
4452 if (req == NULL) {
4453 return NULL;
4456 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
4457 0, NULL, 0, NULL);
4458 if (tevent_req_nomem(subreq, req)) {
4459 return tevent_req_post(req, ev);
4461 tevent_req_set_callback(subreq, cli_dskattr_done, req);
4462 return req;
4465 static void cli_dskattr_done(struct tevent_req *subreq)
4467 struct tevent_req *req = tevent_req_callback_data(
4468 subreq, struct tevent_req);
4469 struct cli_dskattr_state *state = tevent_req_data(
4470 req, struct cli_dskattr_state);
4471 uint8_t wct;
4472 uint16_t *vwv = NULL;
4473 NTSTATUS status;
4475 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4476 NULL);
4477 TALLOC_FREE(subreq);
4478 if (tevent_req_nterror(req, status)) {
4479 return;
4481 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
4482 state->total = SVAL(vwv+0, 0);
4483 state->avail = SVAL(vwv+3, 0);
4484 tevent_req_done(req);
4487 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
4489 struct cli_dskattr_state *state = tevent_req_data(
4490 req, struct cli_dskattr_state);
4491 NTSTATUS status;
4493 if (tevent_req_is_nterror(req, &status)) {
4494 return status;
4496 *bsize = state->bsize;
4497 *total = state->total;
4498 *avail = state->avail;
4499 return NT_STATUS_OK;
4502 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
4504 TALLOC_CTX *frame = NULL;
4505 struct tevent_context *ev = NULL;
4506 struct tevent_req *req = NULL;
4507 NTSTATUS status = NT_STATUS_OK;
4509 frame = talloc_stackframe();
4511 if (smbXcli_conn_has_async_calls(cli->conn)) {
4513 * Can't use sync call while an async call is in flight
4515 status = NT_STATUS_INVALID_PARAMETER;
4516 goto fail;
4519 ev = samba_tevent_context_init(frame);
4520 if (ev == NULL) {
4521 status = NT_STATUS_NO_MEMORY;
4522 goto fail;
4525 req = cli_dskattr_send(frame, ev, cli);
4526 if (req == NULL) {
4527 status = NT_STATUS_NO_MEMORY;
4528 goto fail;
4531 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4532 goto fail;
4535 status = cli_dskattr_recv(req, bsize, total, avail);
4537 fail:
4538 TALLOC_FREE(frame);
4539 return status;
4542 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
4543 uint64_t *total, uint64_t *avail)
4545 uint64_t sectors_per_block;
4546 uint64_t bytes_per_sector;
4547 int old_bsize, old_total, old_avail;
4548 NTSTATUS status;
4550 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4551 return cli_smb2_dskattr(cli, path, bsize, total, avail);
4555 * Try the trans2 disk full size info call first.
4556 * We already use this in SMBC_fstatvfs_ctx().
4557 * Ignore 'actual_available_units' as we only
4558 * care about the quota for the caller.
4561 status = cli_get_fs_full_size_info(cli,
4562 total,
4563 avail,
4564 NULL,
4565 &sectors_per_block,
4566 &bytes_per_sector);
4568 /* Try and cope will all varients of "we don't do this call"
4569 and fall back to cli_dskattr. */
4571 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
4572 NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
4573 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
4574 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
4575 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
4576 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
4577 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
4578 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
4579 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
4580 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
4581 goto try_dskattr;
4584 if (!NT_STATUS_IS_OK(status)) {
4585 return status;
4588 if (bsize) {
4589 *bsize = sectors_per_block *
4590 bytes_per_sector;
4593 return NT_STATUS_OK;
4595 try_dskattr:
4597 /* Old SMB1 core protocol fallback. */
4598 status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
4599 if (!NT_STATUS_IS_OK(status)) {
4600 return status;
4602 if (bsize) {
4603 *bsize = (uint64_t)old_bsize;
4605 if (total) {
4606 *total = (uint64_t)old_total;
4608 if (avail) {
4609 *avail = (uint64_t)old_avail;
4611 return NT_STATUS_OK;
4614 /****************************************************************************
4615 Create and open a temporary file.
4616 ****************************************************************************/
4618 static void cli_ctemp_done(struct tevent_req *subreq);
4620 struct ctemp_state {
4621 uint16_t vwv[3];
4622 char *ret_path;
4623 uint16_t fnum;
4626 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4627 struct tevent_context *ev,
4628 struct cli_state *cli,
4629 const char *path)
4631 struct tevent_req *req = NULL, *subreq = NULL;
4632 struct ctemp_state *state = NULL;
4633 uint8_t additional_flags = 0;
4634 uint16_t additional_flags2 = 0;
4635 uint8_t *bytes = NULL;
4637 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4638 if (req == NULL) {
4639 return NULL;
4642 SSVAL(state->vwv,0,0);
4643 SIVALS(state->vwv+1,0,-1);
4645 bytes = talloc_array(state, uint8_t, 1);
4646 if (tevent_req_nomem(bytes, req)) {
4647 return tevent_req_post(req, ev);
4649 bytes[0] = 4;
4650 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
4651 strlen(path)+1, NULL);
4652 if (tevent_req_nomem(bytes, req)) {
4653 return tevent_req_post(req, ev);
4656 if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
4657 additional_flags2 = FLAGS2_REPARSE_PATH;
4660 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4661 additional_flags2,
4662 3, state->vwv, talloc_get_size(bytes), bytes);
4663 if (tevent_req_nomem(subreq, req)) {
4664 return tevent_req_post(req, ev);
4666 tevent_req_set_callback(subreq, cli_ctemp_done, req);
4667 return req;
4670 static void cli_ctemp_done(struct tevent_req *subreq)
4672 struct tevent_req *req = tevent_req_callback_data(
4673 subreq, struct tevent_req);
4674 struct ctemp_state *state = tevent_req_data(
4675 req, struct ctemp_state);
4676 NTSTATUS status;
4677 uint8_t wcnt;
4678 uint16_t *vwv;
4679 uint32_t num_bytes = 0;
4680 uint8_t *bytes = NULL;
4682 status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
4683 &num_bytes, &bytes);
4684 TALLOC_FREE(subreq);
4685 if (tevent_req_nterror(req, status)) {
4686 return;
4689 state->fnum = SVAL(vwv+0, 0);
4691 /* From W2K3, the result is just the ASCII name */
4692 if (num_bytes < 2) {
4693 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
4694 return;
4697 if (pull_string_talloc(state,
4698 NULL,
4700 &state->ret_path,
4701 bytes,
4702 num_bytes,
4703 STR_ASCII) == 0) {
4704 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4705 return;
4707 tevent_req_done(req);
4710 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
4711 TALLOC_CTX *ctx,
4712 uint16_t *pfnum,
4713 char **outfile)
4715 struct ctemp_state *state = tevent_req_data(req,
4716 struct ctemp_state);
4717 NTSTATUS status;
4719 if (tevent_req_is_nterror(req, &status)) {
4720 return status;
4722 *pfnum = state->fnum;
4723 *outfile = talloc_strdup(ctx, state->ret_path);
4724 if (!*outfile) {
4725 return NT_STATUS_NO_MEMORY;
4727 return NT_STATUS_OK;
4730 NTSTATUS cli_ctemp(struct cli_state *cli,
4731 TALLOC_CTX *ctx,
4732 const char *path,
4733 uint16_t *pfnum,
4734 char **out_path)
4736 TALLOC_CTX *frame = talloc_stackframe();
4737 struct tevent_context *ev;
4738 struct tevent_req *req;
4739 NTSTATUS status = NT_STATUS_OK;
4741 if (smbXcli_conn_has_async_calls(cli->conn)) {
4743 * Can't use sync call while an async call is in flight
4745 status = NT_STATUS_INVALID_PARAMETER;
4746 goto fail;
4749 ev = samba_tevent_context_init(frame);
4750 if (ev == NULL) {
4751 status = NT_STATUS_NO_MEMORY;
4752 goto fail;
4755 req = cli_ctemp_send(frame, ev, cli, path);
4756 if (req == NULL) {
4757 status = NT_STATUS_NO_MEMORY;
4758 goto fail;
4761 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4762 goto fail;
4765 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4767 fail:
4768 TALLOC_FREE(frame);
4769 return status;
4773 send a raw ioctl - used by the torture code
4775 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4777 uint16_t vwv[3];
4778 NTSTATUS status;
4780 SSVAL(vwv+0, 0, fnum);
4781 SSVAL(vwv+1, 0, code>>16);
4782 SSVAL(vwv+2, 0, (code&0xFFFF));
4784 status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4785 NULL, 0, NULL, NULL, NULL, NULL);
4786 if (!NT_STATUS_IS_OK(status)) {
4787 return status;
4789 *blob = data_blob_null;
4790 return NT_STATUS_OK;
4793 /*********************************************************
4794 Set an extended attribute utility fn.
4795 *********************************************************/
4797 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
4798 uint8_t *param, unsigned int param_len,
4799 const char *ea_name,
4800 const char *ea_val, size_t ea_len)
4802 uint16_t setup[1];
4803 unsigned int data_len = 0;
4804 uint8_t *data = NULL;
4805 char *p;
4806 size_t ea_namelen = strlen(ea_name);
4807 NTSTATUS status;
4809 SSVAL(setup, 0, setup_val);
4811 if (ea_namelen == 0 && ea_len == 0) {
4812 data_len = 4;
4813 data = talloc_array(talloc_tos(),
4814 uint8_t,
4815 data_len);
4816 if (!data) {
4817 return NT_STATUS_NO_MEMORY;
4819 p = (char *)data;
4820 SIVAL(p,0,data_len);
4821 } else {
4822 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4823 data = talloc_array(talloc_tos(),
4824 uint8_t,
4825 data_len);
4826 if (!data) {
4827 return NT_STATUS_NO_MEMORY;
4829 p = (char *)data;
4830 SIVAL(p,0,data_len);
4831 p += 4;
4832 SCVAL(p, 0, 0); /* EA flags. */
4833 SCVAL(p, 1, ea_namelen);
4834 SSVAL(p, 2, ea_len);
4835 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4836 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4840 * FIXME - if we want to do previous version path
4841 * processing on an EA set call we need to turn this
4842 * into calls to cli_trans_send()/cli_trans_recv()
4843 * with a temporary event context, as cli_trans_send()
4844 * have access to the additional_flags2 needed to
4845 * send @GMT- paths. JRA.
4848 status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
4849 setup, 1, 0,
4850 param, param_len, 2,
4851 data, data_len, 0,
4852 NULL,
4853 NULL, 0, NULL, /* rsetup */
4854 NULL, 0, NULL, /* rparam */
4855 NULL, 0, NULL); /* rdata */
4856 talloc_free(data);
4857 return status;
4860 /*********************************************************
4861 Set an extended attribute on a pathname.
4862 *********************************************************/
4864 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
4865 const char *ea_name, const char *ea_val,
4866 size_t ea_len)
4868 unsigned int param_len = 0;
4869 uint8_t *param;
4870 NTSTATUS status;
4871 TALLOC_CTX *frame = NULL;
4873 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4874 return cli_smb2_set_ea_path(cli,
4875 path,
4876 ea_name,
4877 ea_val,
4878 ea_len);
4881 frame = talloc_stackframe();
4883 param = talloc_array(frame, uint8_t, 6);
4884 if (!param) {
4885 status = NT_STATUS_NO_MEMORY;
4886 goto fail;
4888 SSVAL(param,0,SMB_INFO_SET_EA);
4889 SSVAL(param,2,0);
4890 SSVAL(param,4,0);
4892 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
4893 path, strlen(path)+1,
4894 NULL);
4895 param_len = talloc_get_size(param);
4897 status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
4898 ea_name, ea_val, ea_len);
4900 fail:
4902 TALLOC_FREE(frame);
4903 return status;
4906 /*********************************************************
4907 Set an extended attribute on an fnum.
4908 *********************************************************/
4910 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
4911 const char *ea_name, const char *ea_val,
4912 size_t ea_len)
4914 uint8_t param[6];
4916 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4917 return cli_smb2_set_ea_fnum(cli,
4918 fnum,
4919 ea_name,
4920 ea_val,
4921 ea_len);
4924 memset(param, 0, 6);
4925 SSVAL(param,0,fnum);
4926 SSVAL(param,2,SMB_INFO_SET_EA);
4928 return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
4929 ea_name, ea_val, ea_len);
4932 /*********************************************************
4933 Get an extended attribute list utility fn.
4934 *********************************************************/
4936 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4937 size_t rdata_len,
4938 size_t *pnum_eas, struct ea_struct **pea_list)
4940 struct ea_struct *ea_list = NULL;
4941 size_t num_eas;
4942 size_t ea_size;
4943 const uint8_t *p;
4945 if (rdata_len < 4) {
4946 return false;
4949 ea_size = (size_t)IVAL(rdata,0);
4950 if (ea_size > rdata_len) {
4951 return false;
4954 if (ea_size == 0) {
4955 /* No EA's present. */
4956 *pnum_eas = 0;
4957 *pea_list = NULL;
4958 return true;
4961 p = rdata + 4;
4962 ea_size -= 4;
4964 /* Validate the EA list and count it. */
4965 for (num_eas = 0; ea_size >= 4; num_eas++) {
4966 unsigned int ea_namelen = CVAL(p,1);
4967 unsigned int ea_valuelen = SVAL(p,2);
4968 if (ea_namelen == 0) {
4969 return false;
4971 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4972 return false;
4974 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4975 p += 4 + ea_namelen + 1 + ea_valuelen;
4978 if (num_eas == 0) {
4979 *pnum_eas = 0;
4980 *pea_list = NULL;
4981 return true;
4984 *pnum_eas = num_eas;
4985 if (!pea_list) {
4986 /* Caller only wants number of EA's. */
4987 return true;
4990 ea_list = talloc_array(ctx, struct ea_struct, num_eas);
4991 if (!ea_list) {
4992 return false;
4995 ea_size = (size_t)IVAL(rdata,0);
4996 p = rdata + 4;
4998 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4999 struct ea_struct *ea = &ea_list[num_eas];
5000 fstring unix_ea_name;
5001 unsigned int ea_namelen = CVAL(p,1);
5002 unsigned int ea_valuelen = SVAL(p,2);
5004 ea->flags = CVAL(p,0);
5005 unix_ea_name[0] = '\0';
5006 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
5007 ea->name = talloc_strdup(ea_list, unix_ea_name);
5008 if (!ea->name) {
5009 goto fail;
5011 /* Ensure the value is null terminated (in case it's a string). */
5012 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
5013 if (!ea->value.data) {
5014 goto fail;
5016 if (ea_valuelen) {
5017 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
5019 ea->value.data[ea_valuelen] = 0;
5020 ea->value.length--;
5021 p += 4 + ea_namelen + 1 + ea_valuelen;
5024 *pea_list = ea_list;
5025 return true;
5027 fail:
5028 TALLOC_FREE(ea_list);
5029 return false;
5032 /*********************************************************
5033 Get an extended attribute list from a pathname.
5034 *********************************************************/
5036 struct cli_get_ea_list_path_state {
5037 uint32_t num_data;
5038 uint8_t *data;
5041 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
5043 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
5044 struct tevent_context *ev,
5045 struct cli_state *cli,
5046 const char *fname)
5048 struct tevent_req *req, *subreq;
5049 struct cli_get_ea_list_path_state *state;
5051 req = tevent_req_create(mem_ctx, &state,
5052 struct cli_get_ea_list_path_state);
5053 if (req == NULL) {
5054 return NULL;
5056 subreq = cli_qpathinfo_send(state, ev, cli, fname,
5057 SMB_INFO_QUERY_ALL_EAS, 4,
5058 CLI_BUFFER_SIZE);
5059 if (tevent_req_nomem(subreq, req)) {
5060 return tevent_req_post(req, ev);
5062 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
5063 return req;
5066 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
5068 struct tevent_req *req = tevent_req_callback_data(
5069 subreq, struct tevent_req);
5070 struct cli_get_ea_list_path_state *state = tevent_req_data(
5071 req, struct cli_get_ea_list_path_state);
5072 NTSTATUS status;
5074 status = cli_qpathinfo_recv(subreq, state, &state->data,
5075 &state->num_data);
5076 TALLOC_FREE(subreq);
5077 if (tevent_req_nterror(req, status)) {
5078 return;
5080 tevent_req_done(req);
5083 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5084 size_t *pnum_eas, struct ea_struct **peas)
5086 struct cli_get_ea_list_path_state *state = tevent_req_data(
5087 req, struct cli_get_ea_list_path_state);
5088 NTSTATUS status;
5090 if (tevent_req_is_nterror(req, &status)) {
5091 return status;
5093 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
5094 pnum_eas, peas)) {
5095 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5097 return NT_STATUS_OK;
5100 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
5101 TALLOC_CTX *ctx,
5102 size_t *pnum_eas,
5103 struct ea_struct **pea_list)
5105 TALLOC_CTX *frame = NULL;
5106 struct tevent_context *ev = NULL;
5107 struct tevent_req *req = NULL;
5108 NTSTATUS status = NT_STATUS_NO_MEMORY;
5110 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5111 return cli_smb2_get_ea_list_path(cli,
5112 path,
5113 ctx,
5114 pnum_eas,
5115 pea_list);
5118 frame = talloc_stackframe();
5120 if (smbXcli_conn_has_async_calls(cli->conn)) {
5122 * Can't use sync call while an async call is in flight
5124 status = NT_STATUS_INVALID_PARAMETER;
5125 goto fail;
5127 ev = samba_tevent_context_init(frame);
5128 if (ev == NULL) {
5129 goto fail;
5131 req = cli_get_ea_list_path_send(frame, ev, cli, path);
5132 if (req == NULL) {
5133 goto fail;
5135 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5136 goto fail;
5138 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
5139 fail:
5140 TALLOC_FREE(frame);
5141 return status;
5144 /****************************************************************************
5145 Convert open "flags" arg to uint32_t on wire.
5146 ****************************************************************************/
5148 static uint32_t open_flags_to_wire(int flags)
5150 int open_mode = flags & O_ACCMODE;
5151 uint32_t ret = 0;
5153 switch (open_mode) {
5154 case O_WRONLY:
5155 ret |= SMB_O_WRONLY;
5156 break;
5157 case O_RDWR:
5158 ret |= SMB_O_RDWR;
5159 break;
5160 default:
5161 case O_RDONLY:
5162 ret |= SMB_O_RDONLY;
5163 break;
5166 if (flags & O_CREAT) {
5167 ret |= SMB_O_CREAT;
5169 if (flags & O_EXCL) {
5170 ret |= SMB_O_EXCL;
5172 if (flags & O_TRUNC) {
5173 ret |= SMB_O_TRUNC;
5175 #if defined(O_SYNC)
5176 if (flags & O_SYNC) {
5177 ret |= SMB_O_SYNC;
5179 #endif /* O_SYNC */
5180 if (flags & O_APPEND) {
5181 ret |= SMB_O_APPEND;
5183 #if defined(O_DIRECT)
5184 if (flags & O_DIRECT) {
5185 ret |= SMB_O_DIRECT;
5187 #endif
5188 #if defined(O_DIRECTORY)
5189 if (flags & O_DIRECTORY) {
5190 ret |= SMB_O_DIRECTORY;
5192 #endif
5193 return ret;
5196 /****************************************************************************
5197 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
5198 ****************************************************************************/
5200 struct cli_posix_open_internal_state {
5201 uint16_t setup;
5202 uint8_t *param;
5203 uint8_t data[18];
5204 uint16_t fnum; /* Out */
5207 static void cli_posix_open_internal_done(struct tevent_req *subreq);
5209 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
5210 struct tevent_context *ev,
5211 struct cli_state *cli,
5212 const char *fname,
5213 uint32_t wire_flags,
5214 mode_t mode)
5216 struct tevent_req *req = NULL, *subreq = NULL;
5217 struct cli_posix_open_internal_state *state = NULL;
5219 req = tevent_req_create(
5220 mem_ctx, &state, struct cli_posix_open_internal_state);
5221 if (req == NULL) {
5222 return NULL;
5225 /* Setup setup word. */
5226 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
5228 /* Setup param array. */
5229 state->param = talloc_zero_array(state, uint8_t, 6);
5230 if (tevent_req_nomem(state->param, req)) {
5231 return tevent_req_post(req, ev);
5233 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
5235 state->param = trans2_bytes_push_str(
5236 state->param,
5237 smbXcli_conn_use_unicode(cli->conn),
5238 fname,
5239 strlen(fname)+1,
5240 NULL);
5242 if (tevent_req_nomem(state->param, req)) {
5243 return tevent_req_post(req, ev);
5246 SIVAL(state->data,0,0); /* No oplock. */
5247 SIVAL(state->data,4,wire_flags);
5248 SIVAL(state->data,8,unix_perms_to_wire(mode));
5249 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
5250 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
5252 subreq = cli_trans_send(state, /* mem ctx. */
5253 ev, /* event ctx. */
5254 cli, /* cli_state. */
5255 0, /* additional_flags2 */
5256 SMBtrans2, /* cmd. */
5257 NULL, /* pipe name. */
5258 -1, /* fid. */
5259 0, /* function. */
5260 0, /* flags. */
5261 &state->setup, /* setup. */
5262 1, /* num setup uint16_t words. */
5263 0, /* max returned setup. */
5264 state->param, /* param. */
5265 talloc_get_size(state->param),/* num param. */
5266 2, /* max returned param. */
5267 state->data, /* data. */
5268 18, /* num data. */
5269 12); /* max returned data. */
5271 if (tevent_req_nomem(subreq, req)) {
5272 return tevent_req_post(req, ev);
5274 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
5275 return req;
5278 static void cli_posix_open_internal_done(struct tevent_req *subreq)
5280 struct tevent_req *req = tevent_req_callback_data(
5281 subreq, struct tevent_req);
5282 struct cli_posix_open_internal_state *state = tevent_req_data(
5283 req, struct cli_posix_open_internal_state);
5284 NTSTATUS status;
5285 uint8_t *data;
5286 uint32_t num_data;
5288 status = cli_trans_recv(
5289 subreq,
5290 state,
5291 NULL,
5292 NULL,
5294 NULL,
5295 NULL,
5297 NULL,
5298 &data,
5300 &num_data);
5301 TALLOC_FREE(subreq);
5302 if (tevent_req_nterror(req, status)) {
5303 return;
5305 state->fnum = SVAL(data,2);
5306 tevent_req_done(req);
5309 static NTSTATUS cli_posix_open_internal_recv(struct tevent_req *req,
5310 uint16_t *pfnum)
5312 struct cli_posix_open_internal_state *state = tevent_req_data(
5313 req, struct cli_posix_open_internal_state);
5314 NTSTATUS status;
5316 if (tevent_req_is_nterror(req, &status)) {
5317 return status;
5319 *pfnum = state->fnum;
5320 return NT_STATUS_OK;
5323 struct cli_posix_open_state {
5324 uint16_t fnum;
5327 static void cli_posix_open_done(struct tevent_req *subreq);
5329 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
5330 struct tevent_context *ev,
5331 struct cli_state *cli,
5332 const char *fname,
5333 int flags,
5334 mode_t mode)
5336 struct tevent_req *req = NULL, *subreq = NULL;
5337 struct cli_posix_open_state *state = NULL;
5338 uint32_t wire_flags;
5340 req = tevent_req_create(mem_ctx, &state,
5341 struct cli_posix_open_state);
5342 if (req == NULL) {
5343 return NULL;
5346 wire_flags = open_flags_to_wire(flags);
5348 subreq = cli_posix_open_internal_send(
5349 mem_ctx, ev, cli, fname, wire_flags, mode);
5350 if (tevent_req_nomem(subreq, req)) {
5351 return tevent_req_post(req, ev);
5353 tevent_req_set_callback(subreq, cli_posix_open_done, req);
5354 return req;
5357 static void cli_posix_open_done(struct tevent_req *subreq)
5359 struct tevent_req *req = tevent_req_callback_data(
5360 subreq, struct tevent_req);
5361 struct cli_posix_open_state *state = tevent_req_data(
5362 req, struct cli_posix_open_state);
5363 NTSTATUS status;
5365 status = cli_posix_open_internal_recv(subreq, &state->fnum);
5366 tevent_req_simple_finish_ntstatus(subreq, status);
5369 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
5371 struct cli_posix_open_state *state = tevent_req_data(
5372 req, struct cli_posix_open_state);
5373 NTSTATUS status;
5375 if (tevent_req_is_nterror(req, &status)) {
5376 return status;
5378 *pfnum = state->fnum;
5379 return NT_STATUS_OK;
5382 /****************************************************************************
5383 Open - POSIX semantics. Doesn't request oplock.
5384 ****************************************************************************/
5386 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
5387 int flags, mode_t mode, uint16_t *pfnum)
5390 TALLOC_CTX *frame = talloc_stackframe();
5391 struct tevent_context *ev = NULL;
5392 struct tevent_req *req = NULL;
5393 NTSTATUS status = NT_STATUS_NO_MEMORY;
5395 if (smbXcli_conn_has_async_calls(cli->conn)) {
5397 * Can't use sync call while an async call is in flight
5399 status = NT_STATUS_INVALID_PARAMETER;
5400 goto fail;
5402 ev = samba_tevent_context_init(frame);
5403 if (ev == NULL) {
5404 goto fail;
5406 req = cli_posix_open_send(
5407 frame, ev, cli, fname, flags, mode);
5408 if (req == NULL) {
5409 goto fail;
5411 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5412 goto fail;
5414 status = cli_posix_open_recv(req, pfnum);
5415 fail:
5416 TALLOC_FREE(frame);
5417 return status;
5420 struct cli_posix_mkdir_state {
5421 struct tevent_context *ev;
5422 struct cli_state *cli;
5425 static void cli_posix_mkdir_done(struct tevent_req *subreq);
5427 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
5428 struct tevent_context *ev,
5429 struct cli_state *cli,
5430 const char *fname,
5431 mode_t mode)
5433 struct tevent_req *req = NULL, *subreq = NULL;
5434 struct cli_posix_mkdir_state *state = NULL;
5435 uint32_t wire_flags;
5437 req = tevent_req_create(
5438 mem_ctx, &state, struct cli_posix_mkdir_state);
5439 if (req == NULL) {
5440 return NULL;
5442 state->ev = ev;
5443 state->cli = cli;
5445 wire_flags = SMB_O_CREAT | SMB_O_DIRECTORY;
5447 subreq = cli_posix_open_internal_send(
5448 mem_ctx, ev, cli, fname, wire_flags, mode);
5449 if (tevent_req_nomem(subreq, req)) {
5450 return tevent_req_post(req, ev);
5452 tevent_req_set_callback(subreq, cli_posix_mkdir_done, req);
5453 return req;
5456 static void cli_posix_mkdir_done(struct tevent_req *subreq)
5458 struct tevent_req *req = tevent_req_callback_data(
5459 subreq, struct tevent_req);
5460 NTSTATUS status;
5461 uint16_t fnum;
5463 status = cli_posix_open_internal_recv(subreq, &fnum);
5464 TALLOC_FREE(subreq);
5465 if (tevent_req_nterror(req, status)) {
5466 return;
5468 tevent_req_done(req);
5471 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
5473 return tevent_req_simple_recv_ntstatus(req);
5476 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
5478 TALLOC_CTX *frame = talloc_stackframe();
5479 struct tevent_context *ev = NULL;
5480 struct tevent_req *req = NULL;
5481 NTSTATUS status = NT_STATUS_NO_MEMORY;
5483 if (smbXcli_conn_has_async_calls(cli->conn)) {
5485 * Can't use sync call while an async call is in flight
5487 status = NT_STATUS_INVALID_PARAMETER;
5488 goto fail;
5491 ev = samba_tevent_context_init(frame);
5492 if (ev == NULL) {
5493 goto fail;
5495 req = cli_posix_mkdir_send(
5496 frame, ev, cli, fname, mode);
5497 if (req == NULL) {
5498 goto fail;
5500 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5501 goto fail;
5503 status = cli_posix_mkdir_recv(req);
5504 fail:
5505 TALLOC_FREE(frame);
5506 return status;
5509 /****************************************************************************
5510 unlink or rmdir - POSIX semantics.
5511 ****************************************************************************/
5513 struct cli_posix_unlink_internal_state {
5514 uint8_t data[2];
5517 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
5519 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
5520 struct tevent_context *ev,
5521 struct cli_state *cli,
5522 const char *fname,
5523 uint16_t level)
5525 struct tevent_req *req = NULL, *subreq = NULL;
5526 struct cli_posix_unlink_internal_state *state = NULL;
5528 req = tevent_req_create(mem_ctx, &state,
5529 struct cli_posix_unlink_internal_state);
5530 if (req == NULL) {
5531 return NULL;
5534 /* Setup data word. */
5535 SSVAL(state->data, 0, level);
5537 subreq = cli_setpathinfo_send(state, ev, cli,
5538 SMB_POSIX_PATH_UNLINK,
5539 fname,
5540 state->data, sizeof(state->data));
5541 if (tevent_req_nomem(subreq, req)) {
5542 return tevent_req_post(req, ev);
5544 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
5545 return req;
5548 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
5550 NTSTATUS status = cli_setpathinfo_recv(subreq);
5551 tevent_req_simple_finish_ntstatus(subreq, status);
5554 static NTSTATUS cli_posix_unlink_internal_recv(struct tevent_req *req)
5556 return tevent_req_simple_recv_ntstatus(req);
5559 struct cli_posix_unlink_state {
5560 uint8_t dummy;
5563 static void cli_posix_unlink_done(struct tevent_req *subreq);
5565 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
5566 struct tevent_context *ev,
5567 struct cli_state *cli,
5568 const char *fname)
5570 struct tevent_req *req = NULL, *subreq = NULL;
5571 struct cli_posix_unlink_state *state;
5573 req = tevent_req_create(
5574 mem_ctx, &state, struct cli_posix_unlink_state);
5575 if (req == NULL) {
5576 return NULL;
5578 subreq = cli_posix_unlink_internal_send(
5579 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_FILE_TARGET);
5580 if (tevent_req_nomem(subreq, req)) {
5581 return tevent_req_post(req, ev);
5583 tevent_req_set_callback(subreq, cli_posix_unlink_done, req);
5584 return req;
5587 static void cli_posix_unlink_done(struct tevent_req *subreq)
5589 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
5590 tevent_req_simple_finish_ntstatus(subreq, status);
5593 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
5595 return tevent_req_simple_recv_ntstatus(req);
5598 /****************************************************************************
5599 unlink - POSIX semantics.
5600 ****************************************************************************/
5602 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
5604 TALLOC_CTX *frame = talloc_stackframe();
5605 struct tevent_context *ev = NULL;
5606 struct tevent_req *req = NULL;
5607 NTSTATUS status = NT_STATUS_OK;
5609 if (smbXcli_conn_has_async_calls(cli->conn)) {
5611 * Can't use sync call while an async call is in flight
5613 status = NT_STATUS_INVALID_PARAMETER;
5614 goto fail;
5617 ev = samba_tevent_context_init(frame);
5618 if (ev == NULL) {
5619 status = NT_STATUS_NO_MEMORY;
5620 goto fail;
5623 req = cli_posix_unlink_send(frame,
5625 cli,
5626 fname);
5627 if (req == NULL) {
5628 status = NT_STATUS_NO_MEMORY;
5629 goto fail;
5632 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5633 goto fail;
5636 status = cli_posix_unlink_recv(req);
5638 fail:
5639 TALLOC_FREE(frame);
5640 return status;
5643 /****************************************************************************
5644 rmdir - POSIX semantics.
5645 ****************************************************************************/
5647 struct cli_posix_rmdir_state {
5648 uint8_t dummy;
5651 static void cli_posix_rmdir_done(struct tevent_req *subreq);
5653 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
5654 struct tevent_context *ev,
5655 struct cli_state *cli,
5656 const char *fname)
5658 struct tevent_req *req = NULL, *subreq = NULL;
5659 struct cli_posix_rmdir_state *state;
5661 req = tevent_req_create(mem_ctx, &state, struct cli_posix_rmdir_state);
5662 if (req == NULL) {
5663 return NULL;
5665 subreq = cli_posix_unlink_internal_send(
5666 mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_DIRECTORY_TARGET);
5667 if (tevent_req_nomem(subreq, req)) {
5668 return tevent_req_post(req, ev);
5670 tevent_req_set_callback(subreq, cli_posix_rmdir_done, req);
5671 return req;
5674 static void cli_posix_rmdir_done(struct tevent_req *subreq)
5676 NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
5677 tevent_req_simple_finish_ntstatus(subreq, status);
5680 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
5682 return tevent_req_simple_recv_ntstatus(req);
5685 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
5687 TALLOC_CTX *frame = talloc_stackframe();
5688 struct tevent_context *ev = NULL;
5689 struct tevent_req *req = NULL;
5690 NTSTATUS status = NT_STATUS_OK;
5692 if (smbXcli_conn_has_async_calls(cli->conn)) {
5694 * Can't use sync call while an async call is in flight
5696 status = NT_STATUS_INVALID_PARAMETER;
5697 goto fail;
5700 ev = samba_tevent_context_init(frame);
5701 if (ev == NULL) {
5702 status = NT_STATUS_NO_MEMORY;
5703 goto fail;
5706 req = cli_posix_rmdir_send(frame,
5708 cli,
5709 fname);
5710 if (req == NULL) {
5711 status = NT_STATUS_NO_MEMORY;
5712 goto fail;
5715 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5716 goto fail;
5719 status = cli_posix_rmdir_recv(req, frame);
5721 fail:
5722 TALLOC_FREE(frame);
5723 return status;
5726 /****************************************************************************
5727 filechangenotify
5728 ****************************************************************************/
5730 struct cli_notify_state {
5731 struct tevent_req *subreq;
5732 uint8_t setup[8];
5733 uint32_t num_changes;
5734 struct notify_change *changes;
5737 static void cli_notify_done(struct tevent_req *subreq);
5738 static void cli_notify_done_smb2(struct tevent_req *subreq);
5739 static bool cli_notify_cancel(struct tevent_req *req);
5741 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
5742 struct tevent_context *ev,
5743 struct cli_state *cli, uint16_t fnum,
5744 uint32_t buffer_size,
5745 uint32_t completion_filter, bool recursive)
5747 struct tevent_req *req;
5748 struct cli_notify_state *state;
5749 unsigned old_timeout;
5751 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
5752 if (req == NULL) {
5753 return NULL;
5756 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5758 * Notifies should not time out
5760 old_timeout = cli_set_timeout(cli, 0);
5762 state->subreq = cli_smb2_notify_send(
5763 state,
5765 cli,
5766 fnum,
5767 buffer_size,
5768 completion_filter,
5769 recursive);
5771 cli_set_timeout(cli, old_timeout);
5773 if (tevent_req_nomem(state->subreq, req)) {
5774 return tevent_req_post(req, ev);
5776 tevent_req_set_callback(
5777 state->subreq, cli_notify_done_smb2, req);
5778 goto done;
5781 SIVAL(state->setup, 0, completion_filter);
5782 SSVAL(state->setup, 4, fnum);
5783 SSVAL(state->setup, 6, recursive);
5786 * Notifies should not time out
5788 old_timeout = cli_set_timeout(cli, 0);
5790 state->subreq = cli_trans_send(
5791 state, /* mem ctx. */
5792 ev, /* event ctx. */
5793 cli, /* cli_state. */
5794 0, /* additional_flags2 */
5795 SMBnttrans, /* cmd. */
5796 NULL, /* pipe name. */
5797 -1, /* fid. */
5798 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
5799 0, /* flags. */
5800 (uint16_t *)state->setup, /* setup. */
5801 4, /* num setup uint16_t words. */
5802 0, /* max returned setup. */
5803 NULL, /* param. */
5804 0, /* num param. */
5805 buffer_size, /* max returned param. */
5806 NULL, /* data. */
5807 0, /* num data. */
5808 0); /* max returned data. */
5810 cli_set_timeout(cli, old_timeout);
5812 if (tevent_req_nomem(state->subreq, req)) {
5813 return tevent_req_post(req, ev);
5815 tevent_req_set_callback(state->subreq, cli_notify_done, req);
5816 done:
5817 tevent_req_set_cancel_fn(req, cli_notify_cancel);
5818 return req;
5821 static bool cli_notify_cancel(struct tevent_req *req)
5823 struct cli_notify_state *state = tevent_req_data(
5824 req, struct cli_notify_state);
5825 bool ok;
5827 ok = tevent_req_cancel(state->subreq);
5828 return ok;
5831 static void cli_notify_done(struct tevent_req *subreq)
5833 struct tevent_req *req = tevent_req_callback_data(
5834 subreq, struct tevent_req);
5835 struct cli_notify_state *state = tevent_req_data(
5836 req, struct cli_notify_state);
5837 NTSTATUS status;
5838 uint8_t *params;
5839 uint32_t i, ofs, num_params;
5840 uint16_t flags2;
5842 status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
5843 &params, 0, &num_params, NULL, 0, NULL);
5844 TALLOC_FREE(subreq);
5845 state->subreq = NULL;
5846 if (tevent_req_nterror(req, status)) {
5847 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
5848 return;
5851 state->num_changes = 0;
5852 ofs = 0;
5854 while (num_params - ofs > 12) {
5855 uint32_t next = IVAL(params, ofs);
5856 state->num_changes += 1;
5858 if ((next == 0) || (ofs+next >= num_params)) {
5859 break;
5861 ofs += next;
5864 state->changes = talloc_array(state, struct notify_change,
5865 state->num_changes);
5866 if (tevent_req_nomem(state->changes, req)) {
5867 TALLOC_FREE(params);
5868 return;
5871 ofs = 0;
5873 for (i=0; i<state->num_changes; i++) {
5874 uint32_t next = IVAL(params, ofs);
5875 uint32_t len = IVAL(params, ofs+8);
5876 ssize_t ret;
5877 char *name;
5879 if (trans_oob(num_params, ofs + 12, len)) {
5880 TALLOC_FREE(params);
5881 tevent_req_nterror(
5882 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5883 return;
5886 state->changes[i].action = IVAL(params, ofs+4);
5887 ret = clistr_pull_talloc(state->changes, (char *)params, flags2,
5888 &name, params+ofs+12, len,
5889 STR_TERMINATE|STR_UNICODE);
5890 if (ret == -1) {
5891 TALLOC_FREE(params);
5892 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5893 return;
5895 state->changes[i].name = name;
5896 ofs += next;
5899 TALLOC_FREE(params);
5900 tevent_req_done(req);
5903 static void cli_notify_done_smb2(struct tevent_req *subreq)
5905 struct tevent_req *req = tevent_req_callback_data(
5906 subreq, struct tevent_req);
5907 struct cli_notify_state *state = tevent_req_data(
5908 req, struct cli_notify_state);
5909 NTSTATUS status;
5911 status = cli_smb2_notify_recv(
5912 subreq,
5913 state,
5914 &state->changes,
5915 &state->num_changes);
5916 TALLOC_FREE(subreq);
5917 if (tevent_req_nterror(req, status)) {
5918 return;
5920 tevent_req_done(req);
5923 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5924 uint32_t *pnum_changes,
5925 struct notify_change **pchanges)
5927 struct cli_notify_state *state = tevent_req_data(
5928 req, struct cli_notify_state);
5929 NTSTATUS status;
5931 if (tevent_req_is_nterror(req, &status)) {
5932 return status;
5935 *pnum_changes = state->num_changes;
5936 *pchanges = talloc_move(mem_ctx, &state->changes);
5937 return NT_STATUS_OK;
5940 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
5941 uint32_t completion_filter, bool recursive,
5942 TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
5943 struct notify_change **pchanges)
5945 TALLOC_CTX *frame;
5946 struct tevent_context *ev;
5947 struct tevent_req *req;
5948 NTSTATUS status = NT_STATUS_NO_MEMORY;
5950 frame = talloc_stackframe();
5952 if (smbXcli_conn_has_async_calls(cli->conn)) {
5954 * Can't use sync call while an async call is in flight
5956 status = NT_STATUS_INVALID_PARAMETER;
5957 goto fail;
5959 ev = samba_tevent_context_init(frame);
5960 if (ev == NULL) {
5961 goto fail;
5963 req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
5964 completion_filter, recursive);
5965 if (req == NULL) {
5966 goto fail;
5968 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5969 goto fail;
5971 status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
5972 fail:
5973 TALLOC_FREE(frame);
5974 return status;
5977 struct cli_qpathinfo_state {
5978 uint8_t *param;
5979 uint8_t *data;
5980 uint16_t setup[1];
5981 uint32_t min_rdata;
5982 uint8_t *rdata;
5983 uint32_t num_rdata;
5986 static void cli_qpathinfo_done(struct tevent_req *subreq);
5988 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
5989 struct tevent_context *ev,
5990 struct cli_state *cli, const char *fname,
5991 uint16_t level, uint32_t min_rdata,
5992 uint32_t max_rdata)
5994 struct tevent_req *req, *subreq;
5995 struct cli_qpathinfo_state *state;
5996 uint16_t additional_flags2 = 0;
5998 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
5999 if (req == NULL) {
6000 return NULL;
6002 state->min_rdata = min_rdata;
6003 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
6005 state->param = talloc_zero_array(state, uint8_t, 6);
6006 if (tevent_req_nomem(state->param, req)) {
6007 return tevent_req_post(req, ev);
6009 SSVAL(state->param, 0, level);
6010 state->param = trans2_bytes_push_str(
6011 state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
6012 if (tevent_req_nomem(state->param, req)) {
6013 return tevent_req_post(req, ev);
6016 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
6017 !INFO_LEVEL_IS_UNIX(level)) {
6018 additional_flags2 = FLAGS2_REPARSE_PATH;
6021 subreq = cli_trans_send(
6022 state, /* mem ctx. */
6023 ev, /* event ctx. */
6024 cli, /* cli_state. */
6025 additional_flags2, /* additional_flags2 */
6026 SMBtrans2, /* cmd. */
6027 NULL, /* pipe name. */
6028 -1, /* fid. */
6029 0, /* function. */
6030 0, /* flags. */
6031 state->setup, /* setup. */
6032 1, /* num setup uint16_t words. */
6033 0, /* max returned setup. */
6034 state->param, /* param. */
6035 talloc_get_size(state->param), /* num param. */
6036 2, /* max returned param. */
6037 NULL, /* data. */
6038 0, /* num data. */
6039 max_rdata); /* max returned data. */
6041 if (tevent_req_nomem(subreq, req)) {
6042 return tevent_req_post(req, ev);
6044 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
6045 return req;
6048 static void cli_qpathinfo_done(struct tevent_req *subreq)
6050 struct tevent_req *req = tevent_req_callback_data(
6051 subreq, struct tevent_req);
6052 struct cli_qpathinfo_state *state = tevent_req_data(
6053 req, struct cli_qpathinfo_state);
6054 NTSTATUS status;
6056 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
6057 NULL, 0, NULL,
6058 &state->rdata, state->min_rdata,
6059 &state->num_rdata);
6060 if (tevent_req_nterror(req, status)) {
6061 return;
6063 tevent_req_done(req);
6066 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6067 uint8_t **rdata, uint32_t *num_rdata)
6069 struct cli_qpathinfo_state *state = tevent_req_data(
6070 req, struct cli_qpathinfo_state);
6071 NTSTATUS status;
6073 if (tevent_req_is_nterror(req, &status)) {
6074 return status;
6076 if (rdata != NULL) {
6077 *rdata = talloc_move(mem_ctx, &state->rdata);
6078 } else {
6079 TALLOC_FREE(state->rdata);
6081 if (num_rdata != NULL) {
6082 *num_rdata = state->num_rdata;
6084 return NT_STATUS_OK;
6087 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6088 const char *fname, uint16_t level, uint32_t min_rdata,
6089 uint32_t max_rdata,
6090 uint8_t **rdata, uint32_t *num_rdata)
6092 TALLOC_CTX *frame = talloc_stackframe();
6093 struct tevent_context *ev;
6094 struct tevent_req *req;
6095 NTSTATUS status = NT_STATUS_NO_MEMORY;
6097 if (smbXcli_conn_has_async_calls(cli->conn)) {
6099 * Can't use sync call while an async call is in flight
6101 status = NT_STATUS_INVALID_PARAMETER;
6102 goto fail;
6104 ev = samba_tevent_context_init(frame);
6105 if (ev == NULL) {
6106 goto fail;
6108 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
6109 max_rdata);
6110 if (req == NULL) {
6111 goto fail;
6113 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6114 goto fail;
6116 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
6117 fail:
6118 TALLOC_FREE(frame);
6119 return status;
6122 struct cli_qfileinfo_state {
6123 uint16_t setup[1];
6124 uint8_t param[4];
6125 uint8_t *data;
6126 uint16_t recv_flags2;
6127 uint32_t min_rdata;
6128 uint8_t *rdata;
6129 uint32_t num_rdata;
6132 static void cli_qfileinfo_done(struct tevent_req *subreq);
6134 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
6135 struct tevent_context *ev,
6136 struct cli_state *cli, uint16_t fnum,
6137 uint16_t level, uint32_t min_rdata,
6138 uint32_t max_rdata)
6140 struct tevent_req *req, *subreq;
6141 struct cli_qfileinfo_state *state;
6143 req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
6144 if (req == NULL) {
6145 return NULL;
6147 state->min_rdata = min_rdata;
6148 SSVAL(state->param, 0, fnum);
6149 SSVAL(state->param, 2, level);
6150 SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
6152 subreq = cli_trans_send(
6153 state, /* mem ctx. */
6154 ev, /* event ctx. */
6155 cli, /* cli_state. */
6156 0, /* additional_flags2 */
6157 SMBtrans2, /* cmd. */
6158 NULL, /* pipe name. */
6159 -1, /* fid. */
6160 0, /* function. */
6161 0, /* flags. */
6162 state->setup, /* setup. */
6163 1, /* num setup uint16_t words. */
6164 0, /* max returned setup. */
6165 state->param, /* param. */
6166 sizeof(state->param), /* num param. */
6167 2, /* max returned param. */
6168 NULL, /* data. */
6169 0, /* num data. */
6170 max_rdata); /* max returned data. */
6172 if (tevent_req_nomem(subreq, req)) {
6173 return tevent_req_post(req, ev);
6175 tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
6176 return req;
6179 static void cli_qfileinfo_done(struct tevent_req *subreq)
6181 struct tevent_req *req = tevent_req_callback_data(
6182 subreq, struct tevent_req);
6183 struct cli_qfileinfo_state *state = tevent_req_data(
6184 req, struct cli_qfileinfo_state);
6185 NTSTATUS status;
6187 status = cli_trans_recv(subreq, state,
6188 &state->recv_flags2,
6189 NULL, 0, NULL,
6190 NULL, 0, NULL,
6191 &state->rdata, state->min_rdata,
6192 &state->num_rdata);
6193 if (tevent_req_nterror(req, status)) {
6194 return;
6196 tevent_req_done(req);
6199 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6200 uint16_t *recv_flags2,
6201 uint8_t **rdata, uint32_t *num_rdata)
6203 struct cli_qfileinfo_state *state = tevent_req_data(
6204 req, struct cli_qfileinfo_state);
6205 NTSTATUS status;
6207 if (tevent_req_is_nterror(req, &status)) {
6208 return status;
6211 if (recv_flags2 != NULL) {
6212 *recv_flags2 = state->recv_flags2;
6214 if (rdata != NULL) {
6215 *rdata = talloc_move(mem_ctx, &state->rdata);
6216 } else {
6217 TALLOC_FREE(state->rdata);
6219 if (num_rdata != NULL) {
6220 *num_rdata = state->num_rdata;
6222 return NT_STATUS_OK;
6225 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6226 uint16_t fnum, uint16_t level, uint32_t min_rdata,
6227 uint32_t max_rdata, uint16_t *recv_flags2,
6228 uint8_t **rdata, uint32_t *num_rdata)
6230 TALLOC_CTX *frame = talloc_stackframe();
6231 struct tevent_context *ev;
6232 struct tevent_req *req;
6233 NTSTATUS status = NT_STATUS_NO_MEMORY;
6235 if (smbXcli_conn_has_async_calls(cli->conn)) {
6237 * Can't use sync call while an async call is in flight
6239 status = NT_STATUS_INVALID_PARAMETER;
6240 goto fail;
6242 ev = samba_tevent_context_init(frame);
6243 if (ev == NULL) {
6244 goto fail;
6246 req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
6247 max_rdata);
6248 if (req == NULL) {
6249 goto fail;
6251 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6252 goto fail;
6254 status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
6255 fail:
6256 TALLOC_FREE(frame);
6257 return status;
6260 struct cli_flush_state {
6261 uint16_t vwv[1];
6264 static void cli_flush_done(struct tevent_req *subreq);
6266 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
6267 struct tevent_context *ev,
6268 struct cli_state *cli,
6269 uint16_t fnum)
6271 struct tevent_req *req, *subreq;
6272 struct cli_flush_state *state;
6274 req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
6275 if (req == NULL) {
6276 return NULL;
6278 SSVAL(state->vwv + 0, 0, fnum);
6280 subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
6281 0, NULL);
6282 if (tevent_req_nomem(subreq, req)) {
6283 return tevent_req_post(req, ev);
6285 tevent_req_set_callback(subreq, cli_flush_done, req);
6286 return req;
6289 static void cli_flush_done(struct tevent_req *subreq)
6291 struct tevent_req *req = tevent_req_callback_data(
6292 subreq, struct tevent_req);
6293 NTSTATUS status;
6295 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
6296 TALLOC_FREE(subreq);
6297 if (tevent_req_nterror(req, status)) {
6298 return;
6300 tevent_req_done(req);
6303 NTSTATUS cli_flush_recv(struct tevent_req *req)
6305 return tevent_req_simple_recv_ntstatus(req);
6308 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
6310 TALLOC_CTX *frame = talloc_stackframe();
6311 struct tevent_context *ev;
6312 struct tevent_req *req;
6313 NTSTATUS status = NT_STATUS_NO_MEMORY;
6315 if (smbXcli_conn_has_async_calls(cli->conn)) {
6317 * Can't use sync call while an async call is in flight
6319 status = NT_STATUS_INVALID_PARAMETER;
6320 goto fail;
6322 ev = samba_tevent_context_init(frame);
6323 if (ev == NULL) {
6324 goto fail;
6326 req = cli_flush_send(frame, ev, cli, fnum);
6327 if (req == NULL) {
6328 goto fail;
6330 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6331 goto fail;
6333 status = cli_flush_recv(req);
6334 fail:
6335 TALLOC_FREE(frame);
6336 return status;
6339 struct cli_shadow_copy_data_state {
6340 uint16_t setup[4];
6341 uint8_t *data;
6342 uint32_t num_data;
6343 bool get_names;
6346 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
6348 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
6349 struct tevent_context *ev,
6350 struct cli_state *cli,
6351 uint16_t fnum,
6352 bool get_names)
6354 struct tevent_req *req, *subreq;
6355 struct cli_shadow_copy_data_state *state;
6356 uint32_t ret_size;
6358 req = tevent_req_create(mem_ctx, &state,
6359 struct cli_shadow_copy_data_state);
6360 if (req == NULL) {
6361 return NULL;
6363 state->get_names = get_names;
6364 ret_size = get_names ? CLI_BUFFER_SIZE : 16;
6366 SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
6367 SSVAL(state->setup + 2, 0, fnum);
6368 SCVAL(state->setup + 3, 0, 1); /* isFsctl */
6369 SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
6371 subreq = cli_trans_send(
6372 state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
6373 state->setup, ARRAY_SIZE(state->setup),
6374 ARRAY_SIZE(state->setup),
6375 NULL, 0, 0,
6376 NULL, 0, ret_size);
6377 if (tevent_req_nomem(subreq, req)) {
6378 return tevent_req_post(req, ev);
6380 tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
6381 return req;
6384 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
6386 struct tevent_req *req = tevent_req_callback_data(
6387 subreq, struct tevent_req);
6388 struct cli_shadow_copy_data_state *state = tevent_req_data(
6389 req, struct cli_shadow_copy_data_state);
6390 NTSTATUS status;
6392 status = cli_trans_recv(subreq, state, NULL,
6393 NULL, 0, NULL, /* setup */
6394 NULL, 0, NULL, /* param */
6395 &state->data, 12, &state->num_data);
6396 TALLOC_FREE(subreq);
6397 if (tevent_req_nterror(req, status)) {
6398 return;
6400 tevent_req_done(req);
6403 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6404 char ***pnames, int *pnum_names)
6406 struct cli_shadow_copy_data_state *state = tevent_req_data(
6407 req, struct cli_shadow_copy_data_state);
6408 char **names = NULL;
6409 uint32_t i, num_names;
6410 uint32_t dlength;
6411 uint8_t *endp = NULL;
6412 NTSTATUS status;
6414 if (tevent_req_is_nterror(req, &status)) {
6415 return status;
6418 if (state->num_data < 16) {
6419 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6422 num_names = IVAL(state->data, 4);
6423 dlength = IVAL(state->data, 8);
6425 if (num_names > 0x7FFFFFFF) {
6426 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6429 if (!state->get_names) {
6430 *pnum_names = (int)num_names;
6431 return NT_STATUS_OK;
6434 if (dlength + 12 < 12) {
6435 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6437 if (dlength + 12 > state->num_data) {
6438 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6440 if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
6441 state->num_data) {
6442 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6445 names = talloc_array(mem_ctx, char *, num_names);
6446 if (names == NULL) {
6447 return NT_STATUS_NO_MEMORY;
6450 endp = state->data + state->num_data;
6452 for (i=0; i<num_names; i++) {
6453 bool ret;
6454 uint8_t *src;
6455 size_t converted_size;
6457 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
6459 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
6460 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6463 ret = convert_string_talloc(
6464 names, CH_UTF16LE, CH_UNIX,
6465 src, 2 * sizeof(SHADOW_COPY_LABEL),
6466 &names[i], &converted_size);
6467 if (!ret) {
6468 TALLOC_FREE(names);
6469 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6472 *pnum_names = (int)num_names;
6473 *pnames = names;
6474 return NT_STATUS_OK;
6477 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6478 uint16_t fnum, bool get_names,
6479 char ***pnames, int *pnum_names)
6481 TALLOC_CTX *frame = NULL;
6482 struct tevent_context *ev;
6483 struct tevent_req *req;
6484 NTSTATUS status = NT_STATUS_NO_MEMORY;
6486 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6487 return cli_smb2_shadow_copy_data(mem_ctx,
6488 cli,
6489 fnum,
6490 get_names,
6491 pnames,
6492 pnum_names);
6495 frame = talloc_stackframe();
6497 if (smbXcli_conn_has_async_calls(cli->conn)) {
6499 * Can't use sync call while an async call is in flight
6501 status = NT_STATUS_INVALID_PARAMETER;
6502 goto fail;
6504 ev = samba_tevent_context_init(frame);
6505 if (ev == NULL) {
6506 goto fail;
6508 req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
6509 if (req == NULL) {
6510 goto fail;
6512 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6513 goto fail;
6515 status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
6516 fail:
6517 TALLOC_FREE(frame);
6518 return status;