libcli/smb: move {smb,trans2}_bytes_push_{str,bytes}() to common code
[Samba.git] / source3 / libsmb / clifile.c
blob5e667bdca93ca2146f79f104d2ab4eedcfbb8317
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 oldname.
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 *oldname,
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), oldname, strlen(oldname)+1, NULL);
187 subreq = cli_setpathinfo_send(
188 state, ev, cli, level, newname,
189 state->data, talloc_get_size(state->data));
190 if (tevent_req_nomem(subreq, req)) {
191 return tevent_req_post(req, ev);
193 tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
194 return req;
197 static void cli_posix_link_internal_done(struct tevent_req *subreq)
199 NTSTATUS status = cli_setpathinfo_recv(subreq);
200 tevent_req_simple_finish_ntstatus(subreq, status);
203 /****************************************************************************
204 Symlink a file (UNIX extensions).
205 ****************************************************************************/
207 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
208 struct tevent_context *ev,
209 struct cli_state *cli,
210 const char *oldname,
211 const char *newname)
213 return cli_posix_link_internal_send(
214 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, oldname, newname);
217 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
219 return tevent_req_simple_recv_ntstatus(req);
222 NTSTATUS cli_posix_symlink(struct cli_state *cli,
223 const char *oldname,
224 const char *newname)
226 TALLOC_CTX *frame = talloc_stackframe();
227 struct tevent_context *ev = NULL;
228 struct tevent_req *req = NULL;
229 NTSTATUS status = NT_STATUS_OK;
231 if (smbXcli_conn_has_async_calls(cli->conn)) {
233 * Can't use sync call while an async call is in flight
235 status = NT_STATUS_INVALID_PARAMETER;
236 goto fail;
239 ev = samba_tevent_context_init(frame);
240 if (ev == NULL) {
241 status = NT_STATUS_NO_MEMORY;
242 goto fail;
245 req = cli_posix_symlink_send(frame,
247 cli,
248 oldname,
249 newname);
250 if (req == NULL) {
251 status = NT_STATUS_NO_MEMORY;
252 goto fail;
255 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
256 goto fail;
259 status = cli_posix_symlink_recv(req);
261 fail:
262 TALLOC_FREE(frame);
263 return status;
266 /****************************************************************************
267 Read a POSIX symlink.
268 ****************************************************************************/
270 struct readlink_state {
271 uint8_t *data;
272 uint32_t num_data;
275 static void cli_posix_readlink_done(struct tevent_req *subreq);
277 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
278 struct tevent_context *ev,
279 struct cli_state *cli,
280 const char *fname,
281 size_t len)
283 struct tevent_req *req = NULL, *subreq = NULL;
284 struct readlink_state *state = NULL;
285 uint32_t maxbytelen = (uint32_t)(smbXcli_conn_use_unicode(cli->conn) ? len*3 : len);
287 req = tevent_req_create(mem_ctx, &state, struct readlink_state);
288 if (req == NULL) {
289 return NULL;
293 * Len is in bytes, we need it in UCS2 units.
295 if ((2*len < len) || (maxbytelen < len)) {
296 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
297 return tevent_req_post(req, ev);
300 subreq = cli_qpathinfo_send(state, ev, cli, fname,
301 SMB_QUERY_FILE_UNIX_LINK, 1, maxbytelen);
302 if (tevent_req_nomem(subreq, req)) {
303 return tevent_req_post(req, ev);
305 tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
306 return req;
309 static void cli_posix_readlink_done(struct tevent_req *subreq)
311 struct tevent_req *req = tevent_req_callback_data(
312 subreq, struct tevent_req);
313 struct readlink_state *state = tevent_req_data(
314 req, struct readlink_state);
315 NTSTATUS status;
317 status = cli_qpathinfo_recv(subreq, state, &state->data,
318 &state->num_data);
319 TALLOC_FREE(subreq);
320 if (tevent_req_nterror(req, status)) {
321 return;
324 * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
326 if (state->data[state->num_data-1] != '\0') {
327 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
328 return;
330 tevent_req_done(req);
333 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
334 char *retpath, size_t len)
336 NTSTATUS status;
337 char *converted = NULL;
338 size_t converted_size = 0;
339 struct readlink_state *state = tevent_req_data(req, struct readlink_state);
341 if (tevent_req_is_nterror(req, &status)) {
342 return status;
344 /* The returned data is a pushed string, not raw data. */
345 if (!convert_string_talloc(state,
346 smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
347 CH_UNIX,
348 state->data,
349 state->num_data,
350 &converted,
351 &converted_size)) {
352 return NT_STATUS_NO_MEMORY;
355 len = MIN(len,converted_size);
356 if (len == 0) {
357 return NT_STATUS_DATA_ERROR;
359 memcpy(retpath, converted, len);
360 return NT_STATUS_OK;
363 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
364 char *linkpath, size_t len)
366 TALLOC_CTX *frame = talloc_stackframe();
367 struct tevent_context *ev = NULL;
368 struct tevent_req *req = NULL;
369 NTSTATUS status = NT_STATUS_OK;
371 if (smbXcli_conn_has_async_calls(cli->conn)) {
373 * Can't use sync call while an async call is in flight
375 status = NT_STATUS_INVALID_PARAMETER;
376 goto fail;
379 ev = samba_tevent_context_init(frame);
380 if (ev == NULL) {
381 status = NT_STATUS_NO_MEMORY;
382 goto fail;
385 req = cli_posix_readlink_send(frame,
387 cli,
388 fname,
389 len);
390 if (req == NULL) {
391 status = NT_STATUS_NO_MEMORY;
392 goto fail;
395 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
396 goto fail;
399 status = cli_posix_readlink_recv(req, cli, linkpath, len);
401 fail:
402 TALLOC_FREE(frame);
403 return status;
406 /****************************************************************************
407 Hard link a file (UNIX extensions).
408 ****************************************************************************/
410 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
411 struct tevent_context *ev,
412 struct cli_state *cli,
413 const char *oldname,
414 const char *newname)
416 return cli_posix_link_internal_send(
417 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
420 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
422 return tevent_req_simple_recv_ntstatus(req);
425 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
426 const char *oldname,
427 const char *newname)
429 TALLOC_CTX *frame = talloc_stackframe();
430 struct tevent_context *ev = NULL;
431 struct tevent_req *req = NULL;
432 NTSTATUS status = NT_STATUS_OK;
434 if (smbXcli_conn_has_async_calls(cli->conn)) {
436 * Can't use sync call while an async call is in flight
438 status = NT_STATUS_INVALID_PARAMETER;
439 goto fail;
442 ev = samba_tevent_context_init(frame);
443 if (ev == NULL) {
444 status = NT_STATUS_NO_MEMORY;
445 goto fail;
448 req = cli_posix_hardlink_send(frame,
450 cli,
451 oldname,
452 newname);
453 if (req == NULL) {
454 status = NT_STATUS_NO_MEMORY;
455 goto fail;
458 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
459 goto fail;
462 status = cli_posix_hardlink_recv(req);
464 fail:
465 TALLOC_FREE(frame);
466 return status;
469 /****************************************************************************
470 Do a POSIX getacl - pathname based ACL get (UNIX extensions).
471 ****************************************************************************/
473 struct getacl_state {
474 uint32_t num_data;
475 uint8_t *data;
478 static void cli_posix_getacl_done(struct tevent_req *subreq);
480 struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
481 struct tevent_context *ev,
482 struct cli_state *cli,
483 const char *fname)
485 struct tevent_req *req = NULL, *subreq = NULL;
486 struct getacl_state *state = NULL;
488 req = tevent_req_create(mem_ctx, &state, struct getacl_state);
489 if (req == NULL) {
490 return NULL;
492 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
493 0, CLI_BUFFER_SIZE);
494 if (tevent_req_nomem(subreq, req)) {
495 return tevent_req_post(req, ev);
497 tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
498 return req;
501 static void cli_posix_getacl_done(struct tevent_req *subreq)
503 struct tevent_req *req = tevent_req_callback_data(
504 subreq, struct tevent_req);
505 struct getacl_state *state = tevent_req_data(
506 req, struct getacl_state);
507 NTSTATUS status;
509 status = cli_qpathinfo_recv(subreq, state, &state->data,
510 &state->num_data);
511 TALLOC_FREE(subreq);
512 if (tevent_req_nterror(req, status)) {
513 return;
515 tevent_req_done(req);
518 NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
519 TALLOC_CTX *mem_ctx,
520 size_t *prb_size,
521 char **retbuf)
523 struct getacl_state *state = tevent_req_data(req, struct getacl_state);
524 NTSTATUS status;
526 if (tevent_req_is_nterror(req, &status)) {
527 return status;
529 *prb_size = (size_t)state->num_data;
530 *retbuf = (char *)talloc_move(mem_ctx, &state->data);
531 return NT_STATUS_OK;
534 NTSTATUS cli_posix_getacl(struct cli_state *cli,
535 const char *fname,
536 TALLOC_CTX *mem_ctx,
537 size_t *prb_size,
538 char **retbuf)
540 TALLOC_CTX *frame = talloc_stackframe();
541 struct tevent_context *ev = NULL;
542 struct tevent_req *req = NULL;
543 NTSTATUS status = NT_STATUS_OK;
545 if (smbXcli_conn_has_async_calls(cli->conn)) {
547 * Can't use sync call while an async call is in flight
549 status = NT_STATUS_INVALID_PARAMETER;
550 goto fail;
553 ev = samba_tevent_context_init(frame);
554 if (ev == NULL) {
555 status = NT_STATUS_NO_MEMORY;
556 goto fail;
559 req = cli_posix_getacl_send(frame,
561 cli,
562 fname);
563 if (req == NULL) {
564 status = NT_STATUS_NO_MEMORY;
565 goto fail;
568 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
569 goto fail;
572 status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
574 fail:
575 TALLOC_FREE(frame);
576 return status;
579 /****************************************************************************
580 Do a POSIX setacl - pathname based ACL set (UNIX extensions).
581 ****************************************************************************/
583 struct setacl_state {
584 uint8_t *data;
587 static void cli_posix_setacl_done(struct tevent_req *subreq);
589 struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
590 struct tevent_context *ev,
591 struct cli_state *cli,
592 const char *fname,
593 const void *data,
594 size_t num_data)
596 struct tevent_req *req = NULL, *subreq = NULL;
597 struct setacl_state *state = NULL;
599 req = tevent_req_create(mem_ctx, &state, struct setacl_state);
600 if (req == NULL) {
601 return NULL;
603 state->data = talloc_memdup(state, data, num_data);
604 if (tevent_req_nomem(state->data, req)) {
605 return tevent_req_post(req, ev);
608 subreq = cli_setpathinfo_send(state,
610 cli,
611 SMB_SET_POSIX_ACL,
612 fname,
613 state->data,
614 num_data);
615 if (tevent_req_nomem(subreq, req)) {
616 return tevent_req_post(req, ev);
618 tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
619 return req;
622 static void cli_posix_setacl_done(struct tevent_req *subreq)
624 NTSTATUS status = cli_setpathinfo_recv(subreq);
625 tevent_req_simple_finish_ntstatus(subreq, status);
628 NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
630 return tevent_req_simple_recv_ntstatus(req);
633 NTSTATUS cli_posix_setacl(struct cli_state *cli,
634 const char *fname,
635 const void *acl_buf,
636 size_t acl_buf_size)
638 TALLOC_CTX *frame = talloc_stackframe();
639 struct tevent_context *ev = NULL;
640 struct tevent_req *req = NULL;
641 NTSTATUS status = NT_STATUS_OK;
643 if (smbXcli_conn_has_async_calls(cli->conn)) {
645 * Can't use sync call while an async call is in flight
647 status = NT_STATUS_INVALID_PARAMETER;
648 goto fail;
651 ev = samba_tevent_context_init(frame);
652 if (ev == NULL) {
653 status = NT_STATUS_NO_MEMORY;
654 goto fail;
657 req = cli_posix_setacl_send(frame,
659 cli,
660 fname,
661 acl_buf,
662 acl_buf_size);
663 if (req == NULL) {
664 status = NT_STATUS_NO_MEMORY;
665 goto fail;
668 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
669 goto fail;
672 status = cli_posix_setacl_recv(req);
674 fail:
675 TALLOC_FREE(frame);
676 return status;
679 /****************************************************************************
680 Stat a file (UNIX extensions).
681 ****************************************************************************/
683 struct stat_state {
684 uint32_t num_data;
685 uint8_t *data;
688 static void cli_posix_stat_done(struct tevent_req *subreq);
690 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
691 struct tevent_context *ev,
692 struct cli_state *cli,
693 const char *fname)
695 struct tevent_req *req = NULL, *subreq = NULL;
696 struct stat_state *state = NULL;
698 req = tevent_req_create(mem_ctx, &state, struct stat_state);
699 if (req == NULL) {
700 return NULL;
702 subreq = cli_qpathinfo_send(state, ev, cli, fname,
703 SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
704 if (tevent_req_nomem(subreq, req)) {
705 return tevent_req_post(req, ev);
707 tevent_req_set_callback(subreq, cli_posix_stat_done, req);
708 return req;
711 static void cli_posix_stat_done(struct tevent_req *subreq)
713 struct tevent_req *req = tevent_req_callback_data(
714 subreq, struct tevent_req);
715 struct stat_state *state = tevent_req_data(req, struct stat_state);
716 NTSTATUS status;
718 status = cli_qpathinfo_recv(subreq, state, &state->data,
719 &state->num_data);
720 TALLOC_FREE(subreq);
721 if (tevent_req_nterror(req, status)) {
722 return;
724 tevent_req_done(req);
727 NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
728 SMB_STRUCT_STAT *sbuf)
730 struct stat_state *state = tevent_req_data(req, struct stat_state);
731 NTSTATUS status;
733 if (tevent_req_is_nterror(req, &status)) {
734 return status;
737 sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0); /* total size, in bytes */
738 sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8); /* number of blocks allocated */
739 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
740 sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
741 #else
742 /* assume 512 byte blocks */
743 sbuf->st_ex_blocks /= 512;
744 #endif
745 sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16)); /* time of last change */
746 sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24)); /* time of last access */
747 sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32)); /* time of last modification */
749 sbuf->st_ex_uid = (uid_t) IVAL(state->data,40); /* user ID of owner */
750 sbuf->st_ex_gid = (gid_t) IVAL(state->data,48); /* group ID of owner */
751 sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
752 #if defined(HAVE_MAKEDEV)
754 uint32_t dev_major = IVAL(state->data,60);
755 uint32_t dev_minor = IVAL(state->data,68);
756 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
758 #endif
759 sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76); /* inode */
760 sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84)); /* protection */
761 sbuf->st_ex_nlink = BIG_UINT(state->data,92); /* number of hard links */
763 return NT_STATUS_OK;
766 NTSTATUS cli_posix_stat(struct cli_state *cli,
767 const char *fname,
768 SMB_STRUCT_STAT *sbuf)
770 TALLOC_CTX *frame = talloc_stackframe();
771 struct tevent_context *ev = NULL;
772 struct tevent_req *req = NULL;
773 NTSTATUS status = NT_STATUS_OK;
775 if (smbXcli_conn_has_async_calls(cli->conn)) {
777 * Can't use sync call while an async call is in flight
779 status = NT_STATUS_INVALID_PARAMETER;
780 goto fail;
783 ev = samba_tevent_context_init(frame);
784 if (ev == NULL) {
785 status = NT_STATUS_NO_MEMORY;
786 goto fail;
789 req = cli_posix_stat_send(frame,
791 cli,
792 fname);
793 if (req == NULL) {
794 status = NT_STATUS_NO_MEMORY;
795 goto fail;
798 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
799 goto fail;
802 status = cli_posix_stat_recv(req, sbuf);
804 fail:
805 TALLOC_FREE(frame);
806 return status;
809 /****************************************************************************
810 Chmod or chown a file internal (UNIX extensions).
811 ****************************************************************************/
813 struct cli_posix_chown_chmod_internal_state {
814 uint8_t data[100];
817 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
819 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
820 struct tevent_context *ev,
821 struct cli_state *cli,
822 const char *fname,
823 uint32_t mode,
824 uint32_t uid,
825 uint32_t gid)
827 struct tevent_req *req = NULL, *subreq = NULL;
828 struct cli_posix_chown_chmod_internal_state *state = NULL;
830 req = tevent_req_create(mem_ctx, &state,
831 struct cli_posix_chown_chmod_internal_state);
832 if (req == NULL) {
833 return NULL;
836 memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
837 memset(&state->data[40], '\0', 60);
838 SIVAL(state->data,40,uid);
839 SIVAL(state->data,48,gid);
840 SIVAL(state->data,84,mode);
842 subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
843 fname, state->data, sizeof(state->data));
844 if (tevent_req_nomem(subreq, req)) {
845 return tevent_req_post(req, ev);
847 tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
848 req);
849 return req;
852 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
854 NTSTATUS status = cli_setpathinfo_recv(subreq);
855 tevent_req_simple_finish_ntstatus(subreq, status);
858 /****************************************************************************
859 chmod a file (UNIX extensions).
860 ****************************************************************************/
862 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
863 struct tevent_context *ev,
864 struct cli_state *cli,
865 const char *fname,
866 mode_t mode)
868 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
869 fname,
870 unix_perms_to_wire(mode),
871 SMB_UID_NO_CHANGE,
872 SMB_GID_NO_CHANGE);
875 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
877 return tevent_req_simple_recv_ntstatus(req);
880 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
882 TALLOC_CTX *frame = talloc_stackframe();
883 struct tevent_context *ev = NULL;
884 struct tevent_req *req = NULL;
885 NTSTATUS status = NT_STATUS_OK;
887 if (smbXcli_conn_has_async_calls(cli->conn)) {
889 * Can't use sync call while an async call is in flight
891 status = NT_STATUS_INVALID_PARAMETER;
892 goto fail;
895 ev = samba_tevent_context_init(frame);
896 if (ev == NULL) {
897 status = NT_STATUS_NO_MEMORY;
898 goto fail;
901 req = cli_posix_chmod_send(frame,
903 cli,
904 fname,
905 mode);
906 if (req == NULL) {
907 status = NT_STATUS_NO_MEMORY;
908 goto fail;
911 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
912 goto fail;
915 status = cli_posix_chmod_recv(req);
917 fail:
918 TALLOC_FREE(frame);
919 return status;
922 /****************************************************************************
923 chown a file (UNIX extensions).
924 ****************************************************************************/
926 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
927 struct tevent_context *ev,
928 struct cli_state *cli,
929 const char *fname,
930 uid_t uid,
931 gid_t gid)
933 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
934 fname,
935 SMB_MODE_NO_CHANGE,
936 (uint32_t)uid,
937 (uint32_t)gid);
940 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
942 return tevent_req_simple_recv_ntstatus(req);
945 NTSTATUS cli_posix_chown(struct cli_state *cli,
946 const char *fname,
947 uid_t uid,
948 gid_t gid)
950 TALLOC_CTX *frame = talloc_stackframe();
951 struct tevent_context *ev = NULL;
952 struct tevent_req *req = NULL;
953 NTSTATUS status = NT_STATUS_OK;
955 if (smbXcli_conn_has_async_calls(cli->conn)) {
957 * Can't use sync call while an async call is in flight
959 status = NT_STATUS_INVALID_PARAMETER;
960 goto fail;
963 ev = samba_tevent_context_init(frame);
964 if (ev == NULL) {
965 status = NT_STATUS_NO_MEMORY;
966 goto fail;
969 req = cli_posix_chown_send(frame,
971 cli,
972 fname,
973 uid,
974 gid);
975 if (req == NULL) {
976 status = NT_STATUS_NO_MEMORY;
977 goto fail;
980 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
981 goto fail;
984 status = cli_posix_chown_recv(req);
986 fail:
987 TALLOC_FREE(frame);
988 return status;
991 /****************************************************************************
992 Rename a file.
993 ****************************************************************************/
995 static void cli_rename_done(struct tevent_req *subreq);
997 struct cli_rename_state {
998 uint16_t vwv[1];
1001 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1002 struct tevent_context *ev,
1003 struct cli_state *cli,
1004 const char *fname_src,
1005 const char *fname_dst)
1007 struct tevent_req *req = NULL, *subreq = NULL;
1008 struct cli_rename_state *state = NULL;
1009 uint8_t additional_flags = 0;
1010 uint16_t additional_flags2 = 0;
1011 uint8_t *bytes = NULL;
1013 req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1014 if (req == NULL) {
1015 return NULL;
1018 SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1020 bytes = talloc_array(state, uint8_t, 1);
1021 if (tevent_req_nomem(bytes, req)) {
1022 return tevent_req_post(req, ev);
1024 bytes[0] = 4;
1025 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1026 strlen(fname_src)+1, NULL);
1027 if (tevent_req_nomem(bytes, req)) {
1028 return tevent_req_post(req, ev);
1031 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1032 additional_flags2 = FLAGS2_REPARSE_PATH;
1035 bytes = talloc_realloc(state, bytes, uint8_t,
1036 talloc_get_size(bytes)+1);
1037 if (tevent_req_nomem(bytes, req)) {
1038 return tevent_req_post(req, ev);
1041 bytes[talloc_get_size(bytes)-1] = 4;
1042 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1043 strlen(fname_dst)+1, NULL);
1044 if (tevent_req_nomem(bytes, req)) {
1045 return tevent_req_post(req, ev);
1048 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1049 additional_flags2,
1050 1, state->vwv, talloc_get_size(bytes), bytes);
1051 if (tevent_req_nomem(subreq, req)) {
1052 return tevent_req_post(req, ev);
1054 tevent_req_set_callback(subreq, cli_rename_done, req);
1055 return req;
1058 static void cli_rename_done(struct tevent_req *subreq)
1060 struct tevent_req *req = tevent_req_callback_data(
1061 subreq, struct tevent_req);
1062 NTSTATUS status;
1064 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1065 TALLOC_FREE(subreq);
1066 if (tevent_req_nterror(req, status)) {
1067 return;
1069 tevent_req_done(req);
1072 NTSTATUS cli_rename_recv(struct tevent_req *req)
1074 return tevent_req_simple_recv_ntstatus(req);
1077 NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1079 TALLOC_CTX *frame = NULL;
1080 struct tevent_context *ev;
1081 struct tevent_req *req;
1082 NTSTATUS status = NT_STATUS_OK;
1084 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1085 return cli_smb2_rename(cli,
1086 fname_src,
1087 fname_dst);
1090 frame = talloc_stackframe();
1092 if (smbXcli_conn_has_async_calls(cli->conn)) {
1094 * Can't use sync call while an async call is in flight
1096 status = NT_STATUS_INVALID_PARAMETER;
1097 goto fail;
1100 ev = samba_tevent_context_init(frame);
1101 if (ev == NULL) {
1102 status = NT_STATUS_NO_MEMORY;
1103 goto fail;
1106 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
1107 if (req == NULL) {
1108 status = NT_STATUS_NO_MEMORY;
1109 goto fail;
1112 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1113 goto fail;
1116 status = cli_rename_recv(req);
1118 fail:
1119 TALLOC_FREE(frame);
1120 return status;
1123 /****************************************************************************
1124 NT Rename a file.
1125 ****************************************************************************/
1127 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1129 struct cli_ntrename_internal_state {
1130 uint16_t vwv[4];
1133 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1134 struct tevent_context *ev,
1135 struct cli_state *cli,
1136 const char *fname_src,
1137 const char *fname_dst,
1138 uint16_t rename_flag)
1140 struct tevent_req *req = NULL, *subreq = NULL;
1141 struct cli_ntrename_internal_state *state = NULL;
1142 uint8_t additional_flags = 0;
1143 uint16_t additional_flags2 = 0;
1144 uint8_t *bytes = NULL;
1146 req = tevent_req_create(mem_ctx, &state,
1147 struct cli_ntrename_internal_state);
1148 if (req == NULL) {
1149 return NULL;
1152 SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1153 SSVAL(state->vwv+1, 0, rename_flag);
1155 bytes = talloc_array(state, uint8_t, 1);
1156 if (tevent_req_nomem(bytes, req)) {
1157 return tevent_req_post(req, ev);
1159 bytes[0] = 4;
1160 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1161 strlen(fname_src)+1, NULL);
1162 if (tevent_req_nomem(bytes, req)) {
1163 return tevent_req_post(req, ev);
1166 if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1167 additional_flags2 = FLAGS2_REPARSE_PATH;
1170 bytes = talloc_realloc(state, bytes, uint8_t,
1171 talloc_get_size(bytes)+1);
1172 if (tevent_req_nomem(bytes, req)) {
1173 return tevent_req_post(req, ev);
1176 bytes[talloc_get_size(bytes)-1] = 4;
1177 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1178 strlen(fname_dst)+1, NULL);
1179 if (tevent_req_nomem(bytes, req)) {
1180 return tevent_req_post(req, ev);
1183 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1184 additional_flags2,
1185 4, state->vwv, talloc_get_size(bytes), bytes);
1186 if (tevent_req_nomem(subreq, req)) {
1187 return tevent_req_post(req, ev);
1189 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1190 return req;
1193 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1195 struct tevent_req *req = tevent_req_callback_data(
1196 subreq, struct tevent_req);
1197 NTSTATUS status;
1199 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1200 TALLOC_FREE(subreq);
1201 if (tevent_req_nterror(req, status)) {
1202 return;
1204 tevent_req_done(req);
1207 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1209 return tevent_req_simple_recv_ntstatus(req);
1212 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1213 struct tevent_context *ev,
1214 struct cli_state *cli,
1215 const char *fname_src,
1216 const char *fname_dst)
1218 return cli_ntrename_internal_send(mem_ctx,
1220 cli,
1221 fname_src,
1222 fname_dst,
1223 RENAME_FLAG_RENAME);
1226 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1228 return cli_ntrename_internal_recv(req);
1231 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1233 TALLOC_CTX *frame = talloc_stackframe();
1234 struct tevent_context *ev;
1235 struct tevent_req *req;
1236 NTSTATUS status = NT_STATUS_OK;
1238 if (smbXcli_conn_has_async_calls(cli->conn)) {
1240 * Can't use sync call while an async call is in flight
1242 status = NT_STATUS_INVALID_PARAMETER;
1243 goto fail;
1246 ev = samba_tevent_context_init(frame);
1247 if (ev == NULL) {
1248 status = NT_STATUS_NO_MEMORY;
1249 goto fail;
1252 req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1253 if (req == NULL) {
1254 status = NT_STATUS_NO_MEMORY;
1255 goto fail;
1258 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1259 goto fail;
1262 status = cli_ntrename_recv(req);
1264 fail:
1265 TALLOC_FREE(frame);
1266 return status;
1269 /****************************************************************************
1270 NT hardlink a file.
1271 ****************************************************************************/
1273 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1274 struct tevent_context *ev,
1275 struct cli_state *cli,
1276 const char *fname_src,
1277 const char *fname_dst)
1279 return cli_ntrename_internal_send(mem_ctx,
1281 cli,
1282 fname_src,
1283 fname_dst,
1284 RENAME_FLAG_HARD_LINK);
1287 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1289 return cli_ntrename_internal_recv(req);
1292 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1294 TALLOC_CTX *frame = talloc_stackframe();
1295 struct tevent_context *ev;
1296 struct tevent_req *req;
1297 NTSTATUS status = NT_STATUS_OK;
1299 if (smbXcli_conn_has_async_calls(cli->conn)) {
1301 * Can't use sync call while an async call is in flight
1303 status = NT_STATUS_INVALID_PARAMETER;
1304 goto fail;
1307 ev = samba_tevent_context_init(frame);
1308 if (ev == NULL) {
1309 status = NT_STATUS_NO_MEMORY;
1310 goto fail;
1313 req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1314 if (req == NULL) {
1315 status = NT_STATUS_NO_MEMORY;
1316 goto fail;
1319 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1320 goto fail;
1323 status = cli_nt_hardlink_recv(req);
1325 fail:
1326 TALLOC_FREE(frame);
1327 return status;
1330 /****************************************************************************
1331 Delete a file.
1332 ****************************************************************************/
1334 static void cli_unlink_done(struct tevent_req *subreq);
1336 struct cli_unlink_state {
1337 uint16_t vwv[1];
1340 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1341 struct tevent_context *ev,
1342 struct cli_state *cli,
1343 const char *fname,
1344 uint16_t mayhave_attrs)
1346 struct tevent_req *req = NULL, *subreq = NULL;
1347 struct cli_unlink_state *state = NULL;
1348 uint8_t additional_flags = 0;
1349 uint16_t additional_flags2 = 0;
1350 uint8_t *bytes = NULL;
1352 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1353 if (req == NULL) {
1354 return NULL;
1357 SSVAL(state->vwv+0, 0, mayhave_attrs);
1359 bytes = talloc_array(state, uint8_t, 1);
1360 if (tevent_req_nomem(bytes, req)) {
1361 return tevent_req_post(req, ev);
1363 bytes[0] = 4;
1364 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
1365 strlen(fname)+1, NULL);
1367 if (tevent_req_nomem(bytes, req)) {
1368 return tevent_req_post(req, ev);
1371 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1372 additional_flags2 = FLAGS2_REPARSE_PATH;
1375 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1376 additional_flags2,
1377 1, state->vwv, talloc_get_size(bytes), bytes);
1378 if (tevent_req_nomem(subreq, req)) {
1379 return tevent_req_post(req, ev);
1381 tevent_req_set_callback(subreq, cli_unlink_done, req);
1382 return req;
1385 static void cli_unlink_done(struct tevent_req *subreq)
1387 struct tevent_req *req = tevent_req_callback_data(
1388 subreq, struct tevent_req);
1389 NTSTATUS status;
1391 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1392 TALLOC_FREE(subreq);
1393 if (tevent_req_nterror(req, status)) {
1394 return;
1396 tevent_req_done(req);
1399 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1401 return tevent_req_simple_recv_ntstatus(req);
1404 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1406 TALLOC_CTX *frame = NULL;
1407 struct tevent_context *ev;
1408 struct tevent_req *req;
1409 NTSTATUS status = NT_STATUS_OK;
1411 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1412 return cli_smb2_unlink(cli, fname);
1415 frame = talloc_stackframe();
1417 if (smbXcli_conn_has_async_calls(cli->conn)) {
1419 * Can't use sync call while an async call is in flight
1421 status = NT_STATUS_INVALID_PARAMETER;
1422 goto fail;
1425 ev = samba_tevent_context_init(frame);
1426 if (ev == NULL) {
1427 status = NT_STATUS_NO_MEMORY;
1428 goto fail;
1431 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1432 if (req == NULL) {
1433 status = NT_STATUS_NO_MEMORY;
1434 goto fail;
1437 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1438 goto fail;
1441 status = cli_unlink_recv(req);
1443 fail:
1444 TALLOC_FREE(frame);
1445 return status;
1448 /****************************************************************************
1449 Create a directory.
1450 ****************************************************************************/
1452 static void cli_mkdir_done(struct tevent_req *subreq);
1454 struct cli_mkdir_state {
1455 int dummy;
1458 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1459 struct tevent_context *ev,
1460 struct cli_state *cli,
1461 const char *dname)
1463 struct tevent_req *req = NULL, *subreq = NULL;
1464 struct cli_mkdir_state *state = NULL;
1465 uint8_t additional_flags = 0;
1466 uint16_t additional_flags2 = 0;
1467 uint8_t *bytes = NULL;
1469 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1470 if (req == NULL) {
1471 return NULL;
1474 bytes = talloc_array(state, uint8_t, 1);
1475 if (tevent_req_nomem(bytes, req)) {
1476 return tevent_req_post(req, ev);
1478 bytes[0] = 4;
1479 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1480 strlen(dname)+1, NULL);
1482 if (tevent_req_nomem(bytes, req)) {
1483 return tevent_req_post(req, ev);
1486 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1487 additional_flags2 = FLAGS2_REPARSE_PATH;
1490 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1491 additional_flags2,
1492 0, NULL, talloc_get_size(bytes), bytes);
1493 if (tevent_req_nomem(subreq, req)) {
1494 return tevent_req_post(req, ev);
1496 tevent_req_set_callback(subreq, cli_mkdir_done, req);
1497 return req;
1500 static void cli_mkdir_done(struct tevent_req *subreq)
1502 struct tevent_req *req = tevent_req_callback_data(
1503 subreq, struct tevent_req);
1504 NTSTATUS status;
1506 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1507 TALLOC_FREE(subreq);
1508 if (tevent_req_nterror(req, status)) {
1509 return;
1511 tevent_req_done(req);
1514 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1516 return tevent_req_simple_recv_ntstatus(req);
1519 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1521 TALLOC_CTX *frame = NULL;
1522 struct tevent_context *ev;
1523 struct tevent_req *req;
1524 NTSTATUS status = NT_STATUS_OK;
1526 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1527 return cli_smb2_mkdir(cli, dname);
1530 frame = talloc_stackframe();
1532 if (smbXcli_conn_has_async_calls(cli->conn)) {
1534 * Can't use sync call while an async call is in flight
1536 status = NT_STATUS_INVALID_PARAMETER;
1537 goto fail;
1540 ev = samba_tevent_context_init(frame);
1541 if (ev == NULL) {
1542 status = NT_STATUS_NO_MEMORY;
1543 goto fail;
1546 req = cli_mkdir_send(frame, ev, cli, dname);
1547 if (req == NULL) {
1548 status = NT_STATUS_NO_MEMORY;
1549 goto fail;
1552 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1553 goto fail;
1556 status = cli_mkdir_recv(req);
1558 fail:
1559 TALLOC_FREE(frame);
1560 return status;
1563 /****************************************************************************
1564 Remove a directory.
1565 ****************************************************************************/
1567 static void cli_rmdir_done(struct tevent_req *subreq);
1569 struct cli_rmdir_state {
1570 int dummy;
1573 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1574 struct tevent_context *ev,
1575 struct cli_state *cli,
1576 const char *dname)
1578 struct tevent_req *req = NULL, *subreq = NULL;
1579 struct cli_rmdir_state *state = NULL;
1580 uint8_t additional_flags = 0;
1581 uint16_t additional_flags2 = 0;
1582 uint8_t *bytes = NULL;
1584 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1585 if (req == NULL) {
1586 return NULL;
1589 bytes = talloc_array(state, uint8_t, 1);
1590 if (tevent_req_nomem(bytes, req)) {
1591 return tevent_req_post(req, ev);
1593 bytes[0] = 4;
1594 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1595 strlen(dname)+1, NULL);
1597 if (tevent_req_nomem(bytes, req)) {
1598 return tevent_req_post(req, ev);
1601 if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1602 additional_flags2 = FLAGS2_REPARSE_PATH;
1605 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1606 additional_flags2,
1607 0, NULL, talloc_get_size(bytes), bytes);
1608 if (tevent_req_nomem(subreq, req)) {
1609 return tevent_req_post(req, ev);
1611 tevent_req_set_callback(subreq, cli_rmdir_done, req);
1612 return req;
1615 static void cli_rmdir_done(struct tevent_req *subreq)
1617 struct tevent_req *req = tevent_req_callback_data(
1618 subreq, struct tevent_req);
1619 NTSTATUS status;
1621 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1622 TALLOC_FREE(subreq);
1623 if (tevent_req_nterror(req, status)) {
1624 return;
1626 tevent_req_done(req);
1629 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1631 return tevent_req_simple_recv_ntstatus(req);
1634 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1636 TALLOC_CTX *frame = NULL;
1637 struct tevent_context *ev;
1638 struct tevent_req *req;
1639 NTSTATUS status = NT_STATUS_OK;
1641 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1642 return cli_smb2_rmdir(cli, dname);
1645 frame = talloc_stackframe();
1647 if (smbXcli_conn_has_async_calls(cli->conn)) {
1649 * Can't use sync call while an async call is in flight
1651 status = NT_STATUS_INVALID_PARAMETER;
1652 goto fail;
1655 ev = samba_tevent_context_init(frame);
1656 if (ev == NULL) {
1657 status = NT_STATUS_NO_MEMORY;
1658 goto fail;
1661 req = cli_rmdir_send(frame, ev, cli, dname);
1662 if (req == NULL) {
1663 status = NT_STATUS_NO_MEMORY;
1664 goto fail;
1667 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1668 goto fail;
1671 status = cli_rmdir_recv(req);
1673 fail:
1674 TALLOC_FREE(frame);
1675 return status;
1678 /****************************************************************************
1679 Set or clear the delete on close flag.
1680 ****************************************************************************/
1682 struct doc_state {
1683 uint16_t setup;
1684 uint8_t param[6];
1685 uint8_t data[1];
1688 static void cli_nt_delete_on_close_done(struct tevent_req *subreq)
1690 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
1691 NULL, 0, NULL, NULL, 0, NULL);
1692 tevent_req_simple_finish_ntstatus(subreq, status);
1695 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1696 struct tevent_context *ev,
1697 struct cli_state *cli,
1698 uint16_t fnum,
1699 bool flag)
1701 struct tevent_req *req = NULL, *subreq = NULL;
1702 struct doc_state *state = NULL;
1704 req = tevent_req_create(mem_ctx, &state, struct doc_state);
1705 if (req == NULL) {
1706 return NULL;
1709 /* Setup setup word. */
1710 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1712 /* Setup param array. */
1713 SSVAL(state->param,0,fnum);
1714 SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1716 /* Setup data array. */
1717 SCVAL(&state->data[0], 0, flag ? 1 : 0);
1719 subreq = cli_trans_send(state, /* mem ctx. */
1720 ev, /* event ctx. */
1721 cli, /* cli_state. */
1722 0, /* additional_flags2 */
1723 SMBtrans2, /* cmd. */
1724 NULL, /* pipe name. */
1725 -1, /* fid. */
1726 0, /* function. */
1727 0, /* flags. */
1728 &state->setup, /* setup. */
1729 1, /* num setup uint16_t words. */
1730 0, /* max returned setup. */
1731 state->param, /* param. */
1732 6, /* num param. */
1733 2, /* max returned param. */
1734 state->data, /* data. */
1735 1, /* num data. */
1736 0); /* max returned data. */
1738 if (tevent_req_nomem(subreq, req)) {
1739 return tevent_req_post(req, ev);
1741 tevent_req_set_callback(subreq, cli_nt_delete_on_close_done, req);
1742 return req;
1745 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1747 return tevent_req_simple_recv_ntstatus(req);
1750 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1752 TALLOC_CTX *frame = talloc_stackframe();
1753 struct tevent_context *ev = NULL;
1754 struct tevent_req *req = NULL;
1755 NTSTATUS status = NT_STATUS_OK;
1757 if (smbXcli_conn_has_async_calls(cli->conn)) {
1759 * Can't use sync call while an async call is in flight
1761 status = NT_STATUS_INVALID_PARAMETER;
1762 goto fail;
1765 ev = samba_tevent_context_init(frame);
1766 if (ev == NULL) {
1767 status = NT_STATUS_NO_MEMORY;
1768 goto fail;
1771 req = cli_nt_delete_on_close_send(frame,
1773 cli,
1774 fnum,
1775 flag);
1776 if (req == NULL) {
1777 status = NT_STATUS_NO_MEMORY;
1778 goto fail;
1781 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1782 goto fail;
1785 status = cli_nt_delete_on_close_recv(req);
1787 fail:
1788 TALLOC_FREE(frame);
1789 return status;
1792 struct cli_ntcreate1_state {
1793 uint16_t vwv[24];
1794 uint16_t fnum;
1795 struct smb_create_returns cr;
1796 struct tevent_req *subreq;
1799 static void cli_ntcreate1_done(struct tevent_req *subreq);
1800 static bool cli_ntcreate1_cancel(struct tevent_req *req);
1802 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
1803 struct tevent_context *ev,
1804 struct cli_state *cli,
1805 const char *fname,
1806 uint32_t CreatFlags,
1807 uint32_t DesiredAccess,
1808 uint32_t FileAttributes,
1809 uint32_t ShareAccess,
1810 uint32_t CreateDisposition,
1811 uint32_t CreateOptions,
1812 uint8_t SecurityFlags)
1814 struct tevent_req *req, *subreq;
1815 struct cli_ntcreate1_state *state;
1816 uint16_t *vwv;
1817 uint8_t *bytes;
1818 size_t converted_len;
1819 uint16_t additional_flags2 = 0;
1821 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
1822 if (req == NULL) {
1823 return NULL;
1826 vwv = state->vwv;
1828 SCVAL(vwv+0, 0, 0xFF);
1829 SCVAL(vwv+0, 1, 0);
1830 SSVAL(vwv+1, 0, 0);
1831 SCVAL(vwv+2, 0, 0);
1833 if (cli->use_oplocks) {
1834 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1836 SIVAL(vwv+3, 1, CreatFlags);
1837 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
1838 SIVAL(vwv+7, 1, DesiredAccess);
1839 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
1840 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
1841 SIVAL(vwv+13, 1, FileAttributes);
1842 SIVAL(vwv+15, 1, ShareAccess);
1843 SIVAL(vwv+17, 1, CreateDisposition);
1844 SIVAL(vwv+19, 1, CreateOptions |
1845 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
1846 SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1847 SCVAL(vwv+23, 1, SecurityFlags);
1849 bytes = talloc_array(state, uint8_t, 0);
1850 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
1851 fname, strlen(fname)+1,
1852 &converted_len);
1854 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1855 additional_flags2 = FLAGS2_REPARSE_PATH;
1858 /* sigh. this copes with broken netapp filer behaviour */
1859 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
1861 if (tevent_req_nomem(bytes, req)) {
1862 return tevent_req_post(req, ev);
1865 SSVAL(vwv+2, 1, converted_len);
1867 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
1868 additional_flags2, 24, vwv,
1869 talloc_get_size(bytes), bytes);
1870 if (tevent_req_nomem(subreq, req)) {
1871 return tevent_req_post(req, ev);
1873 tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
1875 state->subreq = subreq;
1876 tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
1878 return req;
1881 static void cli_ntcreate1_done(struct tevent_req *subreq)
1883 struct tevent_req *req = tevent_req_callback_data(
1884 subreq, struct tevent_req);
1885 struct cli_ntcreate1_state *state = tevent_req_data(
1886 req, struct cli_ntcreate1_state);
1887 uint8_t wct;
1888 uint16_t *vwv;
1889 uint32_t num_bytes;
1890 uint8_t *bytes;
1891 NTSTATUS status;
1893 status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
1894 &num_bytes, &bytes);
1895 TALLOC_FREE(subreq);
1896 if (tevent_req_nterror(req, status)) {
1897 return;
1899 state->cr.oplock_level = CVAL(vwv+2, 0);
1900 state->fnum = SVAL(vwv+2, 1);
1901 state->cr.create_action = IVAL(vwv+3, 1);
1902 state->cr.creation_time = BVAL(vwv+5, 1);
1903 state->cr.last_access_time = BVAL(vwv+9, 1);
1904 state->cr.last_write_time = BVAL(vwv+13, 1);
1905 state->cr.change_time = BVAL(vwv+17, 1);
1906 state->cr.file_attributes = IVAL(vwv+21, 1);
1907 state->cr.allocation_size = BVAL(vwv+23, 1);
1908 state->cr.end_of_file = BVAL(vwv+27, 1);
1910 tevent_req_done(req);
1913 static bool cli_ntcreate1_cancel(struct tevent_req *req)
1915 struct cli_ntcreate1_state *state = tevent_req_data(
1916 req, struct cli_ntcreate1_state);
1917 return tevent_req_cancel(state->subreq);
1920 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
1921 uint16_t *pfnum,
1922 struct smb_create_returns *cr)
1924 struct cli_ntcreate1_state *state = tevent_req_data(
1925 req, struct cli_ntcreate1_state);
1926 NTSTATUS status;
1928 if (tevent_req_is_nterror(req, &status)) {
1929 return status;
1931 *pfnum = state->fnum;
1932 if (cr != NULL) {
1933 *cr = state->cr;
1935 return NT_STATUS_OK;
1938 struct cli_ntcreate_state {
1939 NTSTATUS (*recv)(struct tevent_req *req, uint16_t *fnum,
1940 struct smb_create_returns *cr);
1941 struct smb_create_returns cr;
1942 uint16_t fnum;
1943 struct tevent_req *subreq;
1946 static void cli_ntcreate_done(struct tevent_req *subreq);
1947 static bool cli_ntcreate_cancel(struct tevent_req *req);
1949 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
1950 struct tevent_context *ev,
1951 struct cli_state *cli,
1952 const char *fname,
1953 uint32_t create_flags,
1954 uint32_t desired_access,
1955 uint32_t file_attributes,
1956 uint32_t share_access,
1957 uint32_t create_disposition,
1958 uint32_t create_options,
1959 uint8_t security_flags)
1961 struct tevent_req *req, *subreq;
1962 struct cli_ntcreate_state *state;
1964 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
1965 if (req == NULL) {
1966 return NULL;
1969 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1970 state->recv = cli_smb2_create_fnum_recv;
1972 if (cli->use_oplocks) {
1973 create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
1976 subreq = cli_smb2_create_fnum_send(
1977 state, ev, cli, fname, create_flags, desired_access,
1978 file_attributes, share_access, create_disposition,
1979 create_options);
1980 } else {
1981 state->recv = cli_ntcreate1_recv;
1982 subreq = cli_ntcreate1_send(
1983 state, ev, cli, fname, create_flags, desired_access,
1984 file_attributes, share_access, create_disposition,
1985 create_options, security_flags);
1987 if (tevent_req_nomem(subreq, req)) {
1988 return tevent_req_post(req, ev);
1990 tevent_req_set_callback(subreq, cli_ntcreate_done, req);
1992 state->subreq = subreq;
1993 tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
1995 return req;
1998 static void cli_ntcreate_done(struct tevent_req *subreq)
2000 struct tevent_req *req = tevent_req_callback_data(
2001 subreq, struct tevent_req);
2002 struct cli_ntcreate_state *state = tevent_req_data(
2003 req, struct cli_ntcreate_state);
2004 NTSTATUS status;
2006 status = state->recv(subreq, &state->fnum, &state->cr);
2007 TALLOC_FREE(subreq);
2008 if (tevent_req_nterror(req, status)) {
2009 return;
2011 tevent_req_done(req);
2014 static bool cli_ntcreate_cancel(struct tevent_req *req)
2016 struct cli_ntcreate_state *state = tevent_req_data(
2017 req, struct cli_ntcreate_state);
2018 return tevent_req_cancel(state->subreq);
2021 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2022 struct smb_create_returns *cr)
2024 struct cli_ntcreate_state *state = tevent_req_data(
2025 req, struct cli_ntcreate_state);
2026 NTSTATUS status;
2028 if (tevent_req_is_nterror(req, &status)) {
2029 return status;
2031 if (fnum != NULL) {
2032 *fnum = state->fnum;
2034 if (cr != NULL) {
2035 *cr = state->cr;
2037 return NT_STATUS_OK;
2040 NTSTATUS cli_ntcreate(struct cli_state *cli,
2041 const char *fname,
2042 uint32_t CreatFlags,
2043 uint32_t DesiredAccess,
2044 uint32_t FileAttributes,
2045 uint32_t ShareAccess,
2046 uint32_t CreateDisposition,
2047 uint32_t CreateOptions,
2048 uint8_t SecurityFlags,
2049 uint16_t *pfid,
2050 struct smb_create_returns *cr)
2052 TALLOC_CTX *frame = talloc_stackframe();
2053 struct tevent_context *ev;
2054 struct tevent_req *req;
2055 NTSTATUS status = NT_STATUS_NO_MEMORY;
2057 if (smbXcli_conn_has_async_calls(cli->conn)) {
2059 * Can't use sync call while an async call is in flight
2061 status = NT_STATUS_INVALID_PARAMETER;
2062 goto fail;
2065 ev = samba_tevent_context_init(frame);
2066 if (ev == NULL) {
2067 goto fail;
2070 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2071 DesiredAccess, FileAttributes, ShareAccess,
2072 CreateDisposition, CreateOptions,
2073 SecurityFlags);
2074 if (req == NULL) {
2075 goto fail;
2078 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2079 goto fail;
2082 status = cli_ntcreate_recv(req, pfid, cr);
2083 fail:
2084 TALLOC_FREE(frame);
2085 return status;
2088 struct cli_nttrans_create_state {
2089 uint16_t fnum;
2090 struct smb_create_returns cr;
2093 static void cli_nttrans_create_done(struct tevent_req *subreq);
2095 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2096 struct tevent_context *ev,
2097 struct cli_state *cli,
2098 const char *fname,
2099 uint32_t CreatFlags,
2100 uint32_t DesiredAccess,
2101 uint32_t FileAttributes,
2102 uint32_t ShareAccess,
2103 uint32_t CreateDisposition,
2104 uint32_t CreateOptions,
2105 uint8_t SecurityFlags,
2106 struct security_descriptor *secdesc,
2107 struct ea_struct *eas,
2108 int num_eas)
2110 struct tevent_req *req, *subreq;
2111 struct cli_nttrans_create_state *state;
2112 uint8_t *param;
2113 uint8_t *secdesc_buf;
2114 size_t secdesc_len;
2115 NTSTATUS status;
2116 size_t converted_len;
2117 uint16_t additional_flags2 = 0;
2119 req = tevent_req_create(mem_ctx,
2120 &state, struct cli_nttrans_create_state);
2121 if (req == NULL) {
2122 return NULL;
2125 if (secdesc != NULL) {
2126 status = marshall_sec_desc(talloc_tos(), secdesc,
2127 &secdesc_buf, &secdesc_len);
2128 if (tevent_req_nterror(req, status)) {
2129 DEBUG(10, ("marshall_sec_desc failed: %s\n",
2130 nt_errstr(status)));
2131 return tevent_req_post(req, ev);
2133 } else {
2134 secdesc_buf = NULL;
2135 secdesc_len = 0;
2138 if (num_eas != 0) {
2140 * TODO ;-)
2142 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2143 return tevent_req_post(req, ev);
2146 param = talloc_array(state, uint8_t, 53);
2147 if (tevent_req_nomem(param, req)) {
2148 return tevent_req_post(req, ev);
2151 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2152 fname, strlen(fname),
2153 &converted_len);
2154 if (tevent_req_nomem(param, req)) {
2155 return tevent_req_post(req, ev);
2158 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2159 additional_flags2 = FLAGS2_REPARSE_PATH;
2162 SIVAL(param, 0, CreatFlags);
2163 SIVAL(param, 4, 0x0); /* RootDirectoryFid */
2164 SIVAL(param, 8, DesiredAccess);
2165 SIVAL(param, 12, 0x0); /* AllocationSize */
2166 SIVAL(param, 16, 0x0); /* AllocationSize */
2167 SIVAL(param, 20, FileAttributes);
2168 SIVAL(param, 24, ShareAccess);
2169 SIVAL(param, 28, CreateDisposition);
2170 SIVAL(param, 32, CreateOptions |
2171 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2172 SIVAL(param, 36, secdesc_len);
2173 SIVAL(param, 40, 0); /* EA length*/
2174 SIVAL(param, 44, converted_len);
2175 SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2176 SCVAL(param, 52, SecurityFlags);
2178 subreq = cli_trans_send(state, ev, cli,
2179 additional_flags2, /* additional_flags2 */
2180 SMBnttrans,
2181 NULL, -1, /* name, fid */
2182 NT_TRANSACT_CREATE, 0,
2183 NULL, 0, 0, /* setup */
2184 param, talloc_get_size(param), 128, /* param */
2185 secdesc_buf, secdesc_len, 0); /* data */
2186 if (tevent_req_nomem(subreq, req)) {
2187 return tevent_req_post(req, ev);
2189 tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2190 return req;
2193 static void cli_nttrans_create_done(struct tevent_req *subreq)
2195 struct tevent_req *req = tevent_req_callback_data(
2196 subreq, struct tevent_req);
2197 struct cli_nttrans_create_state *state = tevent_req_data(
2198 req, struct cli_nttrans_create_state);
2199 uint8_t *param;
2200 uint32_t num_param;
2201 NTSTATUS status;
2203 status = cli_trans_recv(subreq, talloc_tos(), NULL,
2204 NULL, 0, NULL, /* rsetup */
2205 &param, 69, &num_param,
2206 NULL, 0, NULL);
2207 if (tevent_req_nterror(req, status)) {
2208 return;
2210 state->cr.oplock_level = CVAL(param, 0);
2211 state->fnum = SVAL(param, 2);
2212 state->cr.create_action = IVAL(param, 4);
2213 state->cr.creation_time = BVAL(param, 12);
2214 state->cr.last_access_time = BVAL(param, 20);
2215 state->cr.last_write_time = BVAL(param, 28);
2216 state->cr.change_time = BVAL(param, 36);
2217 state->cr.file_attributes = IVAL(param, 44);
2218 state->cr.allocation_size = BVAL(param, 48);
2219 state->cr.end_of_file = BVAL(param, 56);
2221 TALLOC_FREE(param);
2222 tevent_req_done(req);
2225 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2226 uint16_t *fnum,
2227 struct smb_create_returns *cr)
2229 struct cli_nttrans_create_state *state = tevent_req_data(
2230 req, struct cli_nttrans_create_state);
2231 NTSTATUS status;
2233 if (tevent_req_is_nterror(req, &status)) {
2234 return status;
2236 *fnum = state->fnum;
2237 if (cr != NULL) {
2238 *cr = state->cr;
2240 return NT_STATUS_OK;
2243 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2244 const char *fname,
2245 uint32_t CreatFlags,
2246 uint32_t DesiredAccess,
2247 uint32_t FileAttributes,
2248 uint32_t ShareAccess,
2249 uint32_t CreateDisposition,
2250 uint32_t CreateOptions,
2251 uint8_t SecurityFlags,
2252 struct security_descriptor *secdesc,
2253 struct ea_struct *eas,
2254 int num_eas,
2255 uint16_t *pfid,
2256 struct smb_create_returns *cr)
2258 TALLOC_CTX *frame = talloc_stackframe();
2259 struct tevent_context *ev;
2260 struct tevent_req *req;
2261 NTSTATUS status = NT_STATUS_NO_MEMORY;
2263 if (smbXcli_conn_has_async_calls(cli->conn)) {
2265 * Can't use sync call while an async call is in flight
2267 status = NT_STATUS_INVALID_PARAMETER;
2268 goto fail;
2270 ev = samba_tevent_context_init(frame);
2271 if (ev == NULL) {
2272 goto fail;
2274 req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2275 DesiredAccess, FileAttributes,
2276 ShareAccess, CreateDisposition,
2277 CreateOptions, SecurityFlags,
2278 secdesc, eas, num_eas);
2279 if (req == NULL) {
2280 goto fail;
2282 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2283 goto fail;
2285 status = cli_nttrans_create_recv(req, pfid, cr);
2286 fail:
2287 TALLOC_FREE(frame);
2288 return status;
2291 /****************************************************************************
2292 Open a file
2293 WARNING: if you open with O_WRONLY then getattrE won't work!
2294 ****************************************************************************/
2296 struct cli_openx_state {
2297 const char *fname;
2298 uint16_t vwv[15];
2299 uint16_t fnum;
2300 struct iovec bytes;
2303 static void cli_openx_done(struct tevent_req *subreq);
2305 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2306 struct tevent_context *ev,
2307 struct cli_state *cli, const char *fname,
2308 int flags, int share_mode,
2309 struct tevent_req **psmbreq)
2311 struct tevent_req *req, *subreq;
2312 struct cli_openx_state *state;
2313 unsigned openfn;
2314 unsigned accessmode;
2315 uint8_t additional_flags;
2316 uint16_t additional_flags2 = 0;
2317 uint8_t *bytes;
2319 req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2320 if (req == NULL) {
2321 return NULL;
2324 openfn = 0;
2325 if (flags & O_CREAT) {
2326 openfn |= (1<<4);
2328 if (!(flags & O_EXCL)) {
2329 if (flags & O_TRUNC)
2330 openfn |= (1<<1);
2331 else
2332 openfn |= (1<<0);
2335 accessmode = (share_mode<<4);
2337 if ((flags & O_ACCMODE) == O_RDWR) {
2338 accessmode |= 2;
2339 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2340 accessmode |= 1;
2343 #if defined(O_SYNC)
2344 if ((flags & O_SYNC) == O_SYNC) {
2345 accessmode |= (1<<14);
2347 #endif /* O_SYNC */
2349 if (share_mode == DENY_FCB) {
2350 accessmode = 0xFF;
2353 SCVAL(state->vwv + 0, 0, 0xFF);
2354 SCVAL(state->vwv + 0, 1, 0);
2355 SSVAL(state->vwv + 1, 0, 0);
2356 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
2357 SSVAL(state->vwv + 3, 0, accessmode);
2358 SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2359 SSVAL(state->vwv + 5, 0, 0);
2360 SIVAL(state->vwv + 6, 0, 0);
2361 SSVAL(state->vwv + 8, 0, openfn);
2362 SIVAL(state->vwv + 9, 0, 0);
2363 SIVAL(state->vwv + 11, 0, 0);
2364 SIVAL(state->vwv + 13, 0, 0);
2366 additional_flags = 0;
2368 if (cli->use_oplocks) {
2369 /* if using oplocks then ask for a batch oplock via
2370 core and extended methods */
2371 additional_flags =
2372 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2373 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2376 bytes = talloc_array(state, uint8_t, 0);
2377 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2378 strlen(fname)+1, NULL);
2380 if (tevent_req_nomem(bytes, req)) {
2381 return tevent_req_post(req, ev);
2384 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2385 additional_flags2 = FLAGS2_REPARSE_PATH;
2388 state->bytes.iov_base = (void *)bytes;
2389 state->bytes.iov_len = talloc_get_size(bytes);
2391 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2392 additional_flags2, 15, state->vwv, 1, &state->bytes);
2393 if (subreq == NULL) {
2394 TALLOC_FREE(req);
2395 return NULL;
2397 tevent_req_set_callback(subreq, cli_openx_done, req);
2398 *psmbreq = subreq;
2399 return req;
2402 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2403 struct cli_state *cli, const char *fname,
2404 int flags, int share_mode)
2406 struct tevent_req *req, *subreq;
2407 NTSTATUS status;
2409 req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
2410 &subreq);
2411 if (req == NULL) {
2412 return NULL;
2415 status = smb1cli_req_chain_submit(&subreq, 1);
2416 if (tevent_req_nterror(req, status)) {
2417 return tevent_req_post(req, ev);
2419 return req;
2422 static void cli_openx_done(struct tevent_req *subreq)
2424 struct tevent_req *req = tevent_req_callback_data(
2425 subreq, struct tevent_req);
2426 struct cli_openx_state *state = tevent_req_data(
2427 req, struct cli_openx_state);
2428 uint8_t wct;
2429 uint16_t *vwv;
2430 NTSTATUS status;
2432 status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
2433 NULL);
2434 TALLOC_FREE(subreq);
2435 if (tevent_req_nterror(req, status)) {
2436 return;
2438 state->fnum = SVAL(vwv+2, 0);
2439 tevent_req_done(req);
2442 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2444 struct cli_openx_state *state = tevent_req_data(
2445 req, struct cli_openx_state);
2446 NTSTATUS status;
2448 if (tevent_req_is_nterror(req, &status)) {
2449 return status;
2451 *pfnum = state->fnum;
2452 return NT_STATUS_OK;
2455 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
2456 int share_mode, uint16_t *pfnum)
2458 TALLOC_CTX *frame = talloc_stackframe();
2459 struct tevent_context *ev;
2460 struct tevent_req *req;
2461 NTSTATUS status = NT_STATUS_NO_MEMORY;
2463 if (smbXcli_conn_has_async_calls(cli->conn)) {
2465 * Can't use sync call while an async call is in flight
2467 status = NT_STATUS_INVALID_PARAMETER;
2468 goto fail;
2471 ev = samba_tevent_context_init(frame);
2472 if (ev == NULL) {
2473 goto fail;
2476 req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
2477 if (req == NULL) {
2478 goto fail;
2481 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2482 goto fail;
2485 status = cli_openx_recv(req, pfnum);
2486 fail:
2487 TALLOC_FREE(frame);
2488 return status;
2490 /****************************************************************************
2491 Synchronous wrapper function that does an NtCreateX open by preference
2492 and falls back to openX if this fails.
2493 ****************************************************************************/
2495 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2496 int share_mode_in, uint16_t *pfnum)
2498 NTSTATUS status;
2499 unsigned int openfn = 0;
2500 unsigned int dos_deny = 0;
2501 uint32_t access_mask, share_mode, create_disposition, create_options;
2502 struct smb_create_returns cr;
2504 /* Do the initial mapping into OpenX parameters. */
2505 if (flags & O_CREAT) {
2506 openfn |= (1<<4);
2508 if (!(flags & O_EXCL)) {
2509 if (flags & O_TRUNC)
2510 openfn |= (1<<1);
2511 else
2512 openfn |= (1<<0);
2515 dos_deny = (share_mode_in<<4);
2517 if ((flags & O_ACCMODE) == O_RDWR) {
2518 dos_deny |= 2;
2519 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2520 dos_deny |= 1;
2523 #if defined(O_SYNC)
2524 if ((flags & O_SYNC) == O_SYNC) {
2525 dos_deny |= (1<<14);
2527 #endif /* O_SYNC */
2529 if (share_mode_in == DENY_FCB) {
2530 dos_deny = 0xFF;
2533 #if 0
2534 /* Hmmm. This is what I think the above code
2535 should look like if it's using the constants
2536 we #define. JRA. */
2538 if (flags & O_CREAT) {
2539 openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
2541 if (!(flags & O_EXCL)) {
2542 if (flags & O_TRUNC)
2543 openfn |= OPENX_FILE_EXISTS_TRUNCATE;
2544 else
2545 openfn |= OPENX_FILE_EXISTS_OPEN;
2548 dos_deny = SET_DENY_MODE(share_mode_in);
2550 if ((flags & O_ACCMODE) == O_RDWR) {
2551 dos_deny |= DOS_OPEN_RDWR;
2552 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2553 dos_deny |= DOS_OPEN_WRONLY;
2556 #if defined(O_SYNC)
2557 if ((flags & O_SYNC) == O_SYNC) {
2558 dos_deny |= FILE_SYNC_OPENMODE;
2560 #endif /* O_SYNC */
2562 if (share_mode_in == DENY_FCB) {
2563 dos_deny = 0xFF;
2565 #endif
2567 if (!map_open_params_to_ntcreate(fname, dos_deny,
2568 openfn, &access_mask,
2569 &share_mode, &create_disposition,
2570 &create_options, NULL)) {
2571 goto try_openx;
2574 status = cli_ntcreate(cli,
2575 fname,
2577 access_mask,
2579 share_mode,
2580 create_disposition,
2581 create_options,
2583 pfnum,
2584 &cr);
2586 /* Try and cope will all varients of "we don't do this call"
2587 and fall back to openX. */
2589 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
2590 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
2591 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
2592 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
2593 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
2594 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
2595 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
2596 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
2597 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
2598 goto try_openx;
2601 if (NT_STATUS_IS_OK(status) &&
2602 (create_options & FILE_NON_DIRECTORY_FILE) &&
2603 (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
2606 * Some (broken) servers return a valid handle
2607 * for directories even if FILE_NON_DIRECTORY_FILE
2608 * is set. Just close the handle and set the
2609 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
2611 status = cli_close(cli, *pfnum);
2612 if (!NT_STATUS_IS_OK(status)) {
2613 return status;
2615 status = NT_STATUS_FILE_IS_A_DIRECTORY;
2616 /* Set this so libsmbclient can retrieve it. */
2617 cli->raw_status = status;
2620 return status;
2622 try_openx:
2624 return cli_openx(cli, fname, flags, share_mode_in, pfnum);
2627 /****************************************************************************
2628 Close a file.
2629 ****************************************************************************/
2631 struct cli_close_state {
2632 uint16_t vwv[3];
2635 static void cli_close_done(struct tevent_req *subreq);
2637 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2638 struct tevent_context *ev,
2639 struct cli_state *cli,
2640 uint16_t fnum,
2641 struct tevent_req **psubreq)
2643 struct tevent_req *req, *subreq;
2644 struct cli_close_state *state;
2646 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2647 if (req == NULL) {
2648 return NULL;
2651 SSVAL(state->vwv+0, 0, fnum);
2652 SIVALS(state->vwv+1, 0, -1);
2654 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
2655 3, state->vwv, 0, NULL);
2656 if (subreq == NULL) {
2657 TALLOC_FREE(req);
2658 return NULL;
2660 tevent_req_set_callback(subreq, cli_close_done, req);
2661 *psubreq = subreq;
2662 return req;
2665 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2666 struct tevent_context *ev,
2667 struct cli_state *cli,
2668 uint16_t fnum)
2670 struct tevent_req *req, *subreq;
2671 NTSTATUS status;
2673 req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2674 if (req == NULL) {
2675 return NULL;
2678 status = smb1cli_req_chain_submit(&subreq, 1);
2679 if (tevent_req_nterror(req, status)) {
2680 return tevent_req_post(req, ev);
2682 return req;
2685 static void cli_close_done(struct tevent_req *subreq)
2687 struct tevent_req *req = tevent_req_callback_data(
2688 subreq, struct tevent_req);
2689 NTSTATUS status;
2691 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2692 TALLOC_FREE(subreq);
2693 if (tevent_req_nterror(req, status)) {
2694 return;
2696 tevent_req_done(req);
2699 NTSTATUS cli_close_recv(struct tevent_req *req)
2701 return tevent_req_simple_recv_ntstatus(req);
2704 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2706 TALLOC_CTX *frame = NULL;
2707 struct tevent_context *ev;
2708 struct tevent_req *req;
2709 NTSTATUS status = NT_STATUS_OK;
2711 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2712 return cli_smb2_close_fnum(cli, fnum);
2715 frame = talloc_stackframe();
2717 if (smbXcli_conn_has_async_calls(cli->conn)) {
2719 * Can't use sync call while an async call is in flight
2721 status = NT_STATUS_INVALID_PARAMETER;
2722 goto fail;
2725 ev = samba_tevent_context_init(frame);
2726 if (ev == NULL) {
2727 status = NT_STATUS_NO_MEMORY;
2728 goto fail;
2731 req = cli_close_send(frame, ev, cli, fnum);
2732 if (req == NULL) {
2733 status = NT_STATUS_NO_MEMORY;
2734 goto fail;
2737 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2738 goto fail;
2741 status = cli_close_recv(req);
2742 fail:
2743 TALLOC_FREE(frame);
2744 return status;
2747 /****************************************************************************
2748 Truncate a file to a specified size
2749 ****************************************************************************/
2751 struct ftrunc_state {
2752 uint16_t setup;
2753 uint8_t param[6];
2754 uint8_t data[8];
2757 static void cli_ftruncate_done(struct tevent_req *subreq)
2759 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2760 NULL, 0, NULL, NULL, 0, NULL);
2761 tevent_req_simple_finish_ntstatus(subreq, status);
2764 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2765 struct tevent_context *ev,
2766 struct cli_state *cli,
2767 uint16_t fnum,
2768 uint64_t size)
2770 struct tevent_req *req = NULL, *subreq = NULL;
2771 struct ftrunc_state *state = NULL;
2773 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2774 if (req == NULL) {
2775 return NULL;
2778 /* Setup setup word. */
2779 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2781 /* Setup param array. */
2782 SSVAL(state->param,0,fnum);
2783 SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2784 SSVAL(state->param,4,0);
2786 /* Setup data array. */
2787 SBVAL(state->data, 0, size);
2789 subreq = cli_trans_send(state, /* mem ctx. */
2790 ev, /* event ctx. */
2791 cli, /* cli_state. */
2792 0, /* additional_flags2 */
2793 SMBtrans2, /* cmd. */
2794 NULL, /* pipe name. */
2795 -1, /* fid. */
2796 0, /* function. */
2797 0, /* flags. */
2798 &state->setup, /* setup. */
2799 1, /* num setup uint16_t words. */
2800 0, /* max returned setup. */
2801 state->param, /* param. */
2802 6, /* num param. */
2803 2, /* max returned param. */
2804 state->data, /* data. */
2805 8, /* num data. */
2806 0); /* max returned data. */
2808 if (tevent_req_nomem(subreq, req)) {
2809 return tevent_req_post(req, ev);
2811 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2812 return req;
2815 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2817 return tevent_req_simple_recv_ntstatus(req);
2820 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2822 TALLOC_CTX *frame = talloc_stackframe();
2823 struct tevent_context *ev = NULL;
2824 struct tevent_req *req = NULL;
2825 NTSTATUS status = NT_STATUS_OK;
2827 if (smbXcli_conn_has_async_calls(cli->conn)) {
2829 * Can't use sync call while an async call is in flight
2831 status = NT_STATUS_INVALID_PARAMETER;
2832 goto fail;
2835 ev = samba_tevent_context_init(frame);
2836 if (ev == NULL) {
2837 status = NT_STATUS_NO_MEMORY;
2838 goto fail;
2841 req = cli_ftruncate_send(frame,
2843 cli,
2844 fnum,
2845 size);
2846 if (req == NULL) {
2847 status = NT_STATUS_NO_MEMORY;
2848 goto fail;
2851 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2852 goto fail;
2855 status = cli_ftruncate_recv(req);
2857 fail:
2858 TALLOC_FREE(frame);
2859 return status;
2862 /****************************************************************************
2863 send a lock with a specified locktype
2864 this is used for testing LOCKING_ANDX_CANCEL_LOCK
2865 ****************************************************************************/
2867 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2868 uint32_t offset, uint32_t len,
2869 int timeout, unsigned char locktype)
2871 uint16_t vwv[8];
2872 uint8_t bytes[10];
2873 NTSTATUS status;
2874 unsigned int set_timeout = 0;
2875 unsigned int saved_timeout = 0;
2877 SCVAL(vwv + 0, 0, 0xff);
2878 SCVAL(vwv + 0, 1, 0);
2879 SSVAL(vwv + 1, 0, 0);
2880 SSVAL(vwv + 2, 0, fnum);
2881 SCVAL(vwv + 3, 0, locktype);
2882 SCVAL(vwv + 3, 1, 0);
2883 SIVALS(vwv + 4, 0, timeout);
2884 SSVAL(vwv + 6, 0, 0);
2885 SSVAL(vwv + 7, 0, 1);
2887 SSVAL(bytes, 0, cli_getpid(cli));
2888 SIVAL(bytes, 2, offset);
2889 SIVAL(bytes, 6, len);
2891 if (timeout != 0) {
2892 if (timeout == -1) {
2893 set_timeout = 0x7FFFFFFF;
2894 } else {
2895 set_timeout = timeout + 2*1000;
2897 saved_timeout = cli_set_timeout(cli, set_timeout);
2900 status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2901 10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2903 if (saved_timeout != 0) {
2904 cli_set_timeout(cli, saved_timeout);
2907 return status;
2910 /****************************************************************************
2911 Lock a file.
2912 note that timeout is in units of 2 milliseconds
2913 ****************************************************************************/
2915 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
2916 uint32_t offset, uint32_t len, int timeout,
2917 enum brl_type lock_type)
2919 NTSTATUS status;
2921 status = cli_locktype(cli, fnum, offset, len, timeout,
2922 (lock_type == READ_LOCK? 1 : 0));
2923 return status;
2926 /****************************************************************************
2927 Unlock a file.
2928 ****************************************************************************/
2930 struct cli_unlock_state {
2931 uint16_t vwv[8];
2932 uint8_t data[10];
2935 static void cli_unlock_done(struct tevent_req *subreq);
2937 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
2938 struct tevent_context *ev,
2939 struct cli_state *cli,
2940 uint16_t fnum,
2941 uint64_t offset,
2942 uint64_t len)
2945 struct tevent_req *req = NULL, *subreq = NULL;
2946 struct cli_unlock_state *state = NULL;
2947 uint8_t additional_flags = 0;
2949 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
2950 if (req == NULL) {
2951 return NULL;
2954 SCVAL(state->vwv+0, 0, 0xFF);
2955 SSVAL(state->vwv+2, 0, fnum);
2956 SCVAL(state->vwv+3, 0, 0);
2957 SIVALS(state->vwv+4, 0, 0);
2958 SSVAL(state->vwv+6, 0, 1);
2959 SSVAL(state->vwv+7, 0, 0);
2961 SSVAL(state->data, 0, cli_getpid(cli));
2962 SIVAL(state->data, 2, offset);
2963 SIVAL(state->data, 6, len);
2965 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
2966 8, state->vwv, 10, state->data);
2967 if (tevent_req_nomem(subreq, req)) {
2968 return tevent_req_post(req, ev);
2970 tevent_req_set_callback(subreq, cli_unlock_done, req);
2971 return req;
2974 static void cli_unlock_done(struct tevent_req *subreq)
2976 struct tevent_req *req = tevent_req_callback_data(
2977 subreq, struct tevent_req);
2978 NTSTATUS status;
2980 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2981 TALLOC_FREE(subreq);
2982 if (tevent_req_nterror(req, status)) {
2983 return;
2985 tevent_req_done(req);
2988 NTSTATUS cli_unlock_recv(struct tevent_req *req)
2990 return tevent_req_simple_recv_ntstatus(req);
2993 NTSTATUS cli_unlock(struct cli_state *cli,
2994 uint16_t fnum,
2995 uint32_t offset,
2996 uint32_t len)
2998 TALLOC_CTX *frame = talloc_stackframe();
2999 struct tevent_context *ev;
3000 struct tevent_req *req;
3001 NTSTATUS status = NT_STATUS_OK;
3003 if (smbXcli_conn_has_async_calls(cli->conn)) {
3005 * Can't use sync call while an async call is in flight
3007 status = NT_STATUS_INVALID_PARAMETER;
3008 goto fail;
3011 ev = samba_tevent_context_init(frame);
3012 if (ev == NULL) {
3013 status = NT_STATUS_NO_MEMORY;
3014 goto fail;
3017 req = cli_unlock_send(frame, ev, cli,
3018 fnum, offset, len);
3019 if (req == NULL) {
3020 status = NT_STATUS_NO_MEMORY;
3021 goto fail;
3024 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3025 goto fail;
3028 status = cli_unlock_recv(req);
3030 fail:
3031 TALLOC_FREE(frame);
3032 return status;
3035 /****************************************************************************
3036 Lock a file with 64 bit offsets.
3037 ****************************************************************************/
3039 NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
3040 uint64_t offset, uint64_t len, int timeout,
3041 enum brl_type lock_type)
3043 uint16_t vwv[8];
3044 uint8_t bytes[20];
3045 unsigned int set_timeout = 0;
3046 unsigned int saved_timeout = 0;
3047 int ltype;
3048 NTSTATUS status;
3050 if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3051 return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
3054 ltype = (lock_type == READ_LOCK? 1 : 0);
3055 ltype |= LOCKING_ANDX_LARGE_FILES;
3057 SCVAL(vwv + 0, 0, 0xff);
3058 SCVAL(vwv + 0, 1, 0);
3059 SSVAL(vwv + 1, 0, 0);
3060 SSVAL(vwv + 2, 0, fnum);
3061 SCVAL(vwv + 3, 0, ltype);
3062 SCVAL(vwv + 3, 1, 0);
3063 SIVALS(vwv + 4, 0, timeout);
3064 SSVAL(vwv + 6, 0, 0);
3065 SSVAL(vwv + 7, 0, 1);
3067 SIVAL(bytes, 0, cli_getpid(cli));
3068 SOFF_T_R(bytes, 4, offset);
3069 SOFF_T_R(bytes, 12, len);
3071 if (timeout != 0) {
3072 if (timeout == -1) {
3073 set_timeout = 0x7FFFFFFF;
3074 } else {
3075 set_timeout = timeout + 2*1000;
3077 saved_timeout = cli_set_timeout(cli, set_timeout);
3080 status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3081 20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3083 if (saved_timeout != 0) {
3084 cli_set_timeout(cli, saved_timeout);
3087 return status;
3090 /****************************************************************************
3091 Unlock a file with 64 bit offsets.
3092 ****************************************************************************/
3094 struct cli_unlock64_state {
3095 uint16_t vwv[8];
3096 uint8_t data[20];
3099 static void cli_unlock64_done(struct tevent_req *subreq);
3101 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
3102 struct tevent_context *ev,
3103 struct cli_state *cli,
3104 uint16_t fnum,
3105 uint64_t offset,
3106 uint64_t len)
3109 struct tevent_req *req = NULL, *subreq = NULL;
3110 struct cli_unlock64_state *state = NULL;
3111 uint8_t additional_flags = 0;
3113 req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
3114 if (req == NULL) {
3115 return NULL;
3118 SCVAL(state->vwv+0, 0, 0xff);
3119 SSVAL(state->vwv+2, 0, fnum);
3120 SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
3121 SIVALS(state->vwv+4, 0, 0);
3122 SSVAL(state->vwv+6, 0, 1);
3123 SSVAL(state->vwv+7, 0, 0);
3125 SIVAL(state->data, 0, cli_getpid(cli));
3126 SOFF_T_R(state->data, 4, offset);
3127 SOFF_T_R(state->data, 12, len);
3129 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3130 8, state->vwv, 20, state->data);
3131 if (tevent_req_nomem(subreq, req)) {
3132 return tevent_req_post(req, ev);
3134 tevent_req_set_callback(subreq, cli_unlock64_done, req);
3135 return req;
3138 static void cli_unlock64_done(struct tevent_req *subreq)
3140 struct tevent_req *req = tevent_req_callback_data(
3141 subreq, struct tevent_req);
3142 NTSTATUS status;
3144 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3145 TALLOC_FREE(subreq);
3146 if (tevent_req_nterror(req, status)) {
3147 return;
3149 tevent_req_done(req);
3152 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
3154 return tevent_req_simple_recv_ntstatus(req);
3157 NTSTATUS cli_unlock64(struct cli_state *cli,
3158 uint16_t fnum,
3159 uint64_t offset,
3160 uint64_t len)
3162 TALLOC_CTX *frame = talloc_stackframe();
3163 struct tevent_context *ev;
3164 struct tevent_req *req;
3165 NTSTATUS status = NT_STATUS_OK;
3167 if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3168 return cli_unlock(cli, fnum, offset, len);
3171 if (smbXcli_conn_has_async_calls(cli->conn)) {
3173 * Can't use sync call while an async call is in flight
3175 status = NT_STATUS_INVALID_PARAMETER;
3176 goto fail;
3179 ev = samba_tevent_context_init(frame);
3180 if (ev == NULL) {
3181 status = NT_STATUS_NO_MEMORY;
3182 goto fail;
3185 req = cli_unlock64_send(frame, ev, cli,
3186 fnum, offset, len);
3187 if (req == NULL) {
3188 status = NT_STATUS_NO_MEMORY;
3189 goto fail;
3192 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3193 goto fail;
3196 status = cli_unlock64_recv(req);
3198 fail:
3199 TALLOC_FREE(frame);
3200 return status;
3203 /****************************************************************************
3204 Get/unlock a POSIX lock on a file - internal function.
3205 ****************************************************************************/
3207 struct posix_lock_state {
3208 uint16_t setup;
3209 uint8_t param[4];
3210 uint8_t data[POSIX_LOCK_DATA_SIZE];
3213 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3215 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3216 NULL, 0, NULL, NULL, 0, NULL);
3217 tevent_req_simple_finish_ntstatus(subreq, status);
3220 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3221 struct tevent_context *ev,
3222 struct cli_state *cli,
3223 uint16_t fnum,
3224 uint64_t offset,
3225 uint64_t len,
3226 bool wait_lock,
3227 enum brl_type lock_type)
3229 struct tevent_req *req = NULL, *subreq = NULL;
3230 struct posix_lock_state *state = NULL;
3232 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3233 if (req == NULL) {
3234 return NULL;
3237 /* Setup setup word. */
3238 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3240 /* Setup param array. */
3241 SSVAL(&state->param, 0, fnum);
3242 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3244 /* Setup data array. */
3245 switch (lock_type) {
3246 case READ_LOCK:
3247 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3248 POSIX_LOCK_TYPE_READ);
3249 break;
3250 case WRITE_LOCK:
3251 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3252 POSIX_LOCK_TYPE_WRITE);
3253 break;
3254 case UNLOCK_LOCK:
3255 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3256 POSIX_LOCK_TYPE_UNLOCK);
3257 break;
3258 default:
3259 return NULL;
3262 if (wait_lock) {
3263 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3264 POSIX_LOCK_FLAG_WAIT);
3265 } else {
3266 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3267 POSIX_LOCK_FLAG_NOWAIT);
3270 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3271 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3272 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3274 subreq = cli_trans_send(state, /* mem ctx. */
3275 ev, /* event ctx. */
3276 cli, /* cli_state. */
3277 0, /* additional_flags2 */
3278 SMBtrans2, /* cmd. */
3279 NULL, /* pipe name. */
3280 -1, /* fid. */
3281 0, /* function. */
3282 0, /* flags. */
3283 &state->setup, /* setup. */
3284 1, /* num setup uint16_t words. */
3285 0, /* max returned setup. */
3286 state->param, /* param. */
3287 4, /* num param. */
3288 2, /* max returned param. */
3289 state->data, /* data. */
3290 POSIX_LOCK_DATA_SIZE, /* num data. */
3291 0); /* max returned data. */
3293 if (tevent_req_nomem(subreq, req)) {
3294 return tevent_req_post(req, ev);
3296 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3297 return req;
3300 /****************************************************************************
3301 POSIX Lock a file.
3302 ****************************************************************************/
3304 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3305 struct tevent_context *ev,
3306 struct cli_state *cli,
3307 uint16_t fnum,
3308 uint64_t offset,
3309 uint64_t len,
3310 bool wait_lock,
3311 enum brl_type lock_type)
3313 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3314 wait_lock, lock_type);
3317 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3319 return tevent_req_simple_recv_ntstatus(req);
3322 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3323 uint64_t offset, uint64_t len,
3324 bool wait_lock, enum brl_type lock_type)
3326 TALLOC_CTX *frame = talloc_stackframe();
3327 struct tevent_context *ev = NULL;
3328 struct tevent_req *req = NULL;
3329 NTSTATUS status = NT_STATUS_OK;
3331 if (smbXcli_conn_has_async_calls(cli->conn)) {
3333 * Can't use sync call while an async call is in flight
3335 status = NT_STATUS_INVALID_PARAMETER;
3336 goto fail;
3339 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3340 status = NT_STATUS_INVALID_PARAMETER;
3341 goto fail;
3344 ev = samba_tevent_context_init(frame);
3345 if (ev == NULL) {
3346 status = NT_STATUS_NO_MEMORY;
3347 goto fail;
3350 req = cli_posix_lock_send(frame,
3352 cli,
3353 fnum,
3354 offset,
3355 len,
3356 wait_lock,
3357 lock_type);
3358 if (req == NULL) {
3359 status = NT_STATUS_NO_MEMORY;
3360 goto fail;
3363 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3364 goto fail;
3367 status = cli_posix_lock_recv(req);
3369 fail:
3370 TALLOC_FREE(frame);
3371 return status;
3374 /****************************************************************************
3375 POSIX Unlock a file.
3376 ****************************************************************************/
3378 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3379 struct tevent_context *ev,
3380 struct cli_state *cli,
3381 uint16_t fnum,
3382 uint64_t offset,
3383 uint64_t len)
3385 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3386 false, UNLOCK_LOCK);
3389 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3391 return tevent_req_simple_recv_ntstatus(req);
3394 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3396 TALLOC_CTX *frame = talloc_stackframe();
3397 struct tevent_context *ev = NULL;
3398 struct tevent_req *req = NULL;
3399 NTSTATUS status = NT_STATUS_OK;
3401 if (smbXcli_conn_has_async_calls(cli->conn)) {
3403 * Can't use sync call while an async call is in flight
3405 status = NT_STATUS_INVALID_PARAMETER;
3406 goto fail;
3409 ev = samba_tevent_context_init(frame);
3410 if (ev == NULL) {
3411 status = NT_STATUS_NO_MEMORY;
3412 goto fail;
3415 req = cli_posix_unlock_send(frame,
3417 cli,
3418 fnum,
3419 offset,
3420 len);
3421 if (req == NULL) {
3422 status = NT_STATUS_NO_MEMORY;
3423 goto fail;
3426 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3427 goto fail;
3430 status = cli_posix_unlock_recv(req);
3432 fail:
3433 TALLOC_FREE(frame);
3434 return status;
3437 /****************************************************************************
3438 Do a SMBgetattrE call.
3439 ****************************************************************************/
3441 static void cli_getattrE_done(struct tevent_req *subreq);
3443 struct cli_getattrE_state {
3444 uint16_t vwv[1];
3445 int zone_offset;
3446 uint16_t attr;
3447 off_t size;
3448 time_t change_time;
3449 time_t access_time;
3450 time_t write_time;
3453 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3454 struct tevent_context *ev,
3455 struct cli_state *cli,
3456 uint16_t fnum)
3458 struct tevent_req *req = NULL, *subreq = NULL;
3459 struct cli_getattrE_state *state = NULL;
3460 uint8_t additional_flags = 0;
3462 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3463 if (req == NULL) {
3464 return NULL;
3467 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3468 SSVAL(state->vwv+0,0,fnum);
3470 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
3471 1, state->vwv, 0, NULL);
3472 if (tevent_req_nomem(subreq, req)) {
3473 return tevent_req_post(req, ev);
3475 tevent_req_set_callback(subreq, cli_getattrE_done, req);
3476 return req;
3479 static void cli_getattrE_done(struct tevent_req *subreq)
3481 struct tevent_req *req = tevent_req_callback_data(
3482 subreq, struct tevent_req);
3483 struct cli_getattrE_state *state = tevent_req_data(
3484 req, struct cli_getattrE_state);
3485 uint8_t wct;
3486 uint16_t *vwv = NULL;
3487 NTSTATUS status;
3489 status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
3490 NULL, NULL);
3491 TALLOC_FREE(subreq);
3492 if (tevent_req_nterror(req, status)) {
3493 return;
3496 state->size = (off_t)IVAL(vwv+6,0);
3497 state->attr = SVAL(vwv+10,0);
3498 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3499 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3500 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3502 tevent_req_done(req);
3505 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3506 uint16_t *attr,
3507 off_t *size,
3508 time_t *change_time,
3509 time_t *access_time,
3510 time_t *write_time)
3512 struct cli_getattrE_state *state = tevent_req_data(
3513 req, struct cli_getattrE_state);
3514 NTSTATUS status;
3516 if (tevent_req_is_nterror(req, &status)) {
3517 return status;
3519 if (attr) {
3520 *attr = state->attr;
3522 if (size) {
3523 *size = state->size;
3525 if (change_time) {
3526 *change_time = state->change_time;
3528 if (access_time) {
3529 *access_time = state->access_time;
3531 if (write_time) {
3532 *write_time = state->write_time;
3534 return NT_STATUS_OK;
3537 NTSTATUS cli_getattrE(struct cli_state *cli,
3538 uint16_t fnum,
3539 uint16_t *attr,
3540 off_t *size,
3541 time_t *change_time,
3542 time_t *access_time,
3543 time_t *write_time)
3545 TALLOC_CTX *frame = NULL;
3546 struct tevent_context *ev = NULL;
3547 struct tevent_req *req = NULL;
3548 NTSTATUS status = NT_STATUS_OK;
3550 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3551 return cli_smb2_getattrE(cli,
3552 fnum,
3553 attr,
3554 size,
3555 change_time,
3556 access_time,
3557 write_time);
3560 frame = talloc_stackframe();
3562 if (smbXcli_conn_has_async_calls(cli->conn)) {
3564 * Can't use sync call while an async call is in flight
3566 status = NT_STATUS_INVALID_PARAMETER;
3567 goto fail;
3570 ev = samba_tevent_context_init(frame);
3571 if (ev == NULL) {
3572 status = NT_STATUS_NO_MEMORY;
3573 goto fail;
3576 req = cli_getattrE_send(frame, ev, cli, fnum);
3577 if (req == NULL) {
3578 status = NT_STATUS_NO_MEMORY;
3579 goto fail;
3582 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3583 goto fail;
3586 status = cli_getattrE_recv(req,
3587 attr,
3588 size,
3589 change_time,
3590 access_time,
3591 write_time);
3593 fail:
3594 TALLOC_FREE(frame);
3595 return status;
3598 /****************************************************************************
3599 Do a SMBgetatr call
3600 ****************************************************************************/
3602 static void cli_getatr_done(struct tevent_req *subreq);
3604 struct cli_getatr_state {
3605 int zone_offset;
3606 uint16_t attr;
3607 off_t size;
3608 time_t write_time;
3611 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3612 struct tevent_context *ev,
3613 struct cli_state *cli,
3614 const char *fname)
3616 struct tevent_req *req = NULL, *subreq = NULL;
3617 struct cli_getatr_state *state = NULL;
3618 uint8_t additional_flags = 0;
3619 uint16_t additional_flags2 = 0;
3620 uint8_t *bytes = NULL;
3622 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3623 if (req == NULL) {
3624 return NULL;
3627 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3629 bytes = talloc_array(state, uint8_t, 1);
3630 if (tevent_req_nomem(bytes, req)) {
3631 return tevent_req_post(req, ev);
3633 bytes[0] = 4;
3634 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3635 strlen(fname)+1, NULL);
3637 if (tevent_req_nomem(bytes, req)) {
3638 return tevent_req_post(req, ev);
3641 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
3642 additional_flags2 = FLAGS2_REPARSE_PATH;
3645 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3646 additional_flags2,
3647 0, NULL, talloc_get_size(bytes), bytes);
3648 if (tevent_req_nomem(subreq, req)) {
3649 return tevent_req_post(req, ev);
3651 tevent_req_set_callback(subreq, cli_getatr_done, req);
3652 return req;
3655 static void cli_getatr_done(struct tevent_req *subreq)
3657 struct tevent_req *req = tevent_req_callback_data(
3658 subreq, struct tevent_req);
3659 struct cli_getatr_state *state = tevent_req_data(
3660 req, struct cli_getatr_state);
3661 uint8_t wct;
3662 uint16_t *vwv = NULL;
3663 NTSTATUS status;
3665 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
3666 NULL);
3667 TALLOC_FREE(subreq);
3668 if (tevent_req_nterror(req, status)) {
3669 return;
3672 state->attr = SVAL(vwv+0,0);
3673 state->size = (off_t)IVAL(vwv+3,0);
3674 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3676 tevent_req_done(req);
3679 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3680 uint16_t *attr,
3681 off_t *size,
3682 time_t *write_time)
3684 struct cli_getatr_state *state = tevent_req_data(
3685 req, struct cli_getatr_state);
3686 NTSTATUS status;
3688 if (tevent_req_is_nterror(req, &status)) {
3689 return status;
3691 if (attr) {
3692 *attr = state->attr;
3694 if (size) {
3695 *size = state->size;
3697 if (write_time) {
3698 *write_time = state->write_time;
3700 return NT_STATUS_OK;
3703 NTSTATUS cli_getatr(struct cli_state *cli,
3704 const char *fname,
3705 uint16_t *attr,
3706 off_t *size,
3707 time_t *write_time)
3709 TALLOC_CTX *frame = NULL;
3710 struct tevent_context *ev = NULL;
3711 struct tevent_req *req = NULL;
3712 NTSTATUS status = NT_STATUS_OK;
3714 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3715 return cli_smb2_getatr(cli,
3716 fname,
3717 attr,
3718 size,
3719 write_time);
3722 frame = talloc_stackframe();
3724 if (smbXcli_conn_has_async_calls(cli->conn)) {
3726 * Can't use sync call while an async call is in flight
3728 status = NT_STATUS_INVALID_PARAMETER;
3729 goto fail;
3732 ev = samba_tevent_context_init(frame);
3733 if (ev == NULL) {
3734 status = NT_STATUS_NO_MEMORY;
3735 goto fail;
3738 req = cli_getatr_send(frame, ev, cli, fname);
3739 if (req == NULL) {
3740 status = NT_STATUS_NO_MEMORY;
3741 goto fail;
3744 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3745 goto fail;
3748 status = cli_getatr_recv(req,
3749 attr,
3750 size,
3751 write_time);
3753 fail:
3754 TALLOC_FREE(frame);
3755 return status;
3758 /****************************************************************************
3759 Do a SMBsetattrE call.
3760 ****************************************************************************/
3762 static void cli_setattrE_done(struct tevent_req *subreq);
3764 struct cli_setattrE_state {
3765 uint16_t vwv[7];
3768 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3769 struct tevent_context *ev,
3770 struct cli_state *cli,
3771 uint16_t fnum,
3772 time_t change_time,
3773 time_t access_time,
3774 time_t write_time)
3776 struct tevent_req *req = NULL, *subreq = NULL;
3777 struct cli_setattrE_state *state = NULL;
3778 uint8_t additional_flags = 0;
3780 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3781 if (req == NULL) {
3782 return NULL;
3785 SSVAL(state->vwv+0, 0, fnum);
3786 push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
3787 smb1cli_conn_server_time_zone(cli->conn));
3788 push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
3789 smb1cli_conn_server_time_zone(cli->conn));
3790 push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
3791 smb1cli_conn_server_time_zone(cli->conn));
3793 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
3794 7, state->vwv, 0, NULL);
3795 if (tevent_req_nomem(subreq, req)) {
3796 return tevent_req_post(req, ev);
3798 tevent_req_set_callback(subreq, cli_setattrE_done, req);
3799 return req;
3802 static void cli_setattrE_done(struct tevent_req *subreq)
3804 struct tevent_req *req = tevent_req_callback_data(
3805 subreq, struct tevent_req);
3806 NTSTATUS status;
3808 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3809 TALLOC_FREE(subreq);
3810 if (tevent_req_nterror(req, status)) {
3811 return;
3813 tevent_req_done(req);
3816 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3818 return tevent_req_simple_recv_ntstatus(req);
3821 NTSTATUS cli_setattrE(struct cli_state *cli,
3822 uint16_t fnum,
3823 time_t change_time,
3824 time_t access_time,
3825 time_t write_time)
3827 TALLOC_CTX *frame = NULL;
3828 struct tevent_context *ev = NULL;
3829 struct tevent_req *req = NULL;
3830 NTSTATUS status = NT_STATUS_OK;
3832 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3833 return cli_smb2_setattrE(cli,
3834 fnum,
3835 change_time,
3836 access_time,
3837 write_time);
3840 frame = talloc_stackframe();
3842 if (smbXcli_conn_has_async_calls(cli->conn)) {
3844 * Can't use sync call while an async call is in flight
3846 status = NT_STATUS_INVALID_PARAMETER;
3847 goto fail;
3850 ev = samba_tevent_context_init(frame);
3851 if (ev == NULL) {
3852 status = NT_STATUS_NO_MEMORY;
3853 goto fail;
3856 req = cli_setattrE_send(frame, ev,
3857 cli,
3858 fnum,
3859 change_time,
3860 access_time,
3861 write_time);
3863 if (req == NULL) {
3864 status = NT_STATUS_NO_MEMORY;
3865 goto fail;
3868 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3869 goto fail;
3872 status = cli_setattrE_recv(req);
3874 fail:
3875 TALLOC_FREE(frame);
3876 return status;
3879 /****************************************************************************
3880 Do a SMBsetatr call.
3881 ****************************************************************************/
3883 static void cli_setatr_done(struct tevent_req *subreq);
3885 struct cli_setatr_state {
3886 uint16_t vwv[8];
3889 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3890 struct tevent_context *ev,
3891 struct cli_state *cli,
3892 const char *fname,
3893 uint16_t attr,
3894 time_t mtime)
3896 struct tevent_req *req = NULL, *subreq = NULL;
3897 struct cli_setatr_state *state = NULL;
3898 uint8_t additional_flags = 0;
3899 uint16_t additional_flags2 = 0;
3900 uint8_t *bytes = NULL;
3902 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3903 if (req == NULL) {
3904 return NULL;
3907 SSVAL(state->vwv+0, 0, attr);
3908 push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
3910 bytes = talloc_array(state, uint8_t, 1);
3911 if (tevent_req_nomem(bytes, req)) {
3912 return tevent_req_post(req, ev);
3914 bytes[0] = 4;
3915 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3916 strlen(fname)+1, NULL);
3917 if (tevent_req_nomem(bytes, req)) {
3918 return tevent_req_post(req, ev);
3920 bytes = talloc_realloc(state, bytes, uint8_t,
3921 talloc_get_size(bytes)+1);
3922 if (tevent_req_nomem(bytes, req)) {
3923 return tevent_req_post(req, ev);
3926 bytes[talloc_get_size(bytes)-1] = 4;
3927 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
3928 1, NULL);
3929 if (tevent_req_nomem(bytes, req)) {
3930 return tevent_req_post(req, ev);
3933 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
3934 additional_flags2 = FLAGS2_REPARSE_PATH;
3937 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3938 additional_flags2,
3939 8, state->vwv, talloc_get_size(bytes), bytes);
3940 if (tevent_req_nomem(subreq, req)) {
3941 return tevent_req_post(req, ev);
3943 tevent_req_set_callback(subreq, cli_setatr_done, req);
3944 return req;
3947 static void cli_setatr_done(struct tevent_req *subreq)
3949 struct tevent_req *req = tevent_req_callback_data(
3950 subreq, struct tevent_req);
3951 NTSTATUS status;
3953 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3954 TALLOC_FREE(subreq);
3955 if (tevent_req_nterror(req, status)) {
3956 return;
3958 tevent_req_done(req);
3961 NTSTATUS cli_setatr_recv(struct tevent_req *req)
3963 return tevent_req_simple_recv_ntstatus(req);
3966 NTSTATUS cli_setatr(struct cli_state *cli,
3967 const char *fname,
3968 uint16_t attr,
3969 time_t mtime)
3971 TALLOC_CTX *frame = NULL;
3972 struct tevent_context *ev = NULL;
3973 struct tevent_req *req = NULL;
3974 NTSTATUS status = NT_STATUS_OK;
3976 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3977 return cli_smb2_setatr(cli,
3978 fname,
3979 attr,
3980 mtime);
3983 frame = talloc_stackframe();
3985 if (smbXcli_conn_has_async_calls(cli->conn)) {
3987 * Can't use sync call while an async call is in flight
3989 status = NT_STATUS_INVALID_PARAMETER;
3990 goto fail;
3993 ev = samba_tevent_context_init(frame);
3994 if (ev == NULL) {
3995 status = NT_STATUS_NO_MEMORY;
3996 goto fail;
3999 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
4000 if (req == NULL) {
4001 status = NT_STATUS_NO_MEMORY;
4002 goto fail;
4005 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4006 goto fail;
4009 status = cli_setatr_recv(req);
4011 fail:
4012 TALLOC_FREE(frame);
4013 return status;
4016 /****************************************************************************
4017 Check for existance of a dir.
4018 ****************************************************************************/
4020 static void cli_chkpath_done(struct tevent_req *subreq);
4022 struct cli_chkpath_state {
4023 int dummy;
4026 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
4027 struct tevent_context *ev,
4028 struct cli_state *cli,
4029 const char *fname)
4031 struct tevent_req *req = NULL, *subreq = NULL;
4032 struct cli_chkpath_state *state = NULL;
4033 uint8_t additional_flags = 0;
4034 uint16_t additional_flags2 = 0;
4035 uint8_t *bytes = NULL;
4037 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
4038 if (req == NULL) {
4039 return NULL;
4042 bytes = talloc_array(state, uint8_t, 1);
4043 if (tevent_req_nomem(bytes, req)) {
4044 return tevent_req_post(req, ev);
4046 bytes[0] = 4;
4047 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4048 strlen(fname)+1, NULL);
4050 if (tevent_req_nomem(bytes, req)) {
4051 return tevent_req_post(req, ev);
4054 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4055 additional_flags2 = FLAGS2_REPARSE_PATH;
4058 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
4059 additional_flags2,
4060 0, NULL, talloc_get_size(bytes), bytes);
4061 if (tevent_req_nomem(subreq, req)) {
4062 return tevent_req_post(req, ev);
4064 tevent_req_set_callback(subreq, cli_chkpath_done, req);
4065 return req;
4068 static void cli_chkpath_done(struct tevent_req *subreq)
4070 struct tevent_req *req = tevent_req_callback_data(
4071 subreq, struct tevent_req);
4072 NTSTATUS status;
4074 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4075 TALLOC_FREE(subreq);
4076 if (tevent_req_nterror(req, status)) {
4077 return;
4079 tevent_req_done(req);
4082 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
4084 return tevent_req_simple_recv_ntstatus(req);
4087 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
4089 TALLOC_CTX *frame = talloc_stackframe();
4090 struct tevent_context *ev = NULL;
4091 struct tevent_req *req = NULL;
4092 char *path2 = NULL;
4093 NTSTATUS status = NT_STATUS_OK;
4095 if (smbXcli_conn_has_async_calls(cli->conn)) {
4097 * Can't use sync call while an async call is in flight
4099 status = NT_STATUS_INVALID_PARAMETER;
4100 goto fail;
4103 path2 = talloc_strdup(frame, path);
4104 if (!path2) {
4105 status = NT_STATUS_NO_MEMORY;
4106 goto fail;
4108 trim_char(path2,'\0','\\');
4109 if (!*path2) {
4110 path2 = talloc_strdup(frame, "\\");
4111 if (!path2) {
4112 status = NT_STATUS_NO_MEMORY;
4113 goto fail;
4117 ev = samba_tevent_context_init(frame);
4118 if (ev == NULL) {
4119 status = NT_STATUS_NO_MEMORY;
4120 goto fail;
4123 req = cli_chkpath_send(frame, ev, cli, path2);
4124 if (req == NULL) {
4125 status = NT_STATUS_NO_MEMORY;
4126 goto fail;
4129 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4130 goto fail;
4133 status = cli_chkpath_recv(req);
4135 fail:
4136 TALLOC_FREE(frame);
4137 return status;
4140 /****************************************************************************
4141 Query disk space.
4142 ****************************************************************************/
4144 static void cli_dskattr_done(struct tevent_req *subreq);
4146 struct cli_dskattr_state {
4147 int bsize;
4148 int total;
4149 int avail;
4152 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
4153 struct tevent_context *ev,
4154 struct cli_state *cli)
4156 struct tevent_req *req = NULL, *subreq = NULL;
4157 struct cli_dskattr_state *state = NULL;
4158 uint8_t additional_flags = 0;
4160 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
4161 if (req == NULL) {
4162 return NULL;
4165 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
4166 0, NULL, 0, NULL);
4167 if (tevent_req_nomem(subreq, req)) {
4168 return tevent_req_post(req, ev);
4170 tevent_req_set_callback(subreq, cli_dskattr_done, req);
4171 return req;
4174 static void cli_dskattr_done(struct tevent_req *subreq)
4176 struct tevent_req *req = tevent_req_callback_data(
4177 subreq, struct tevent_req);
4178 struct cli_dskattr_state *state = tevent_req_data(
4179 req, struct cli_dskattr_state);
4180 uint8_t wct;
4181 uint16_t *vwv = NULL;
4182 NTSTATUS status;
4184 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4185 NULL);
4186 TALLOC_FREE(subreq);
4187 if (tevent_req_nterror(req, status)) {
4188 return;
4190 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
4191 state->total = SVAL(vwv+0, 0);
4192 state->avail = SVAL(vwv+3, 0);
4193 tevent_req_done(req);
4196 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
4198 struct cli_dskattr_state *state = tevent_req_data(
4199 req, struct cli_dskattr_state);
4200 NTSTATUS status;
4202 if (tevent_req_is_nterror(req, &status)) {
4203 return status;
4205 *bsize = state->bsize;
4206 *total = state->total;
4207 *avail = state->avail;
4208 return NT_STATUS_OK;
4211 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
4213 TALLOC_CTX *frame = NULL;
4214 struct tevent_context *ev = NULL;
4215 struct tevent_req *req = NULL;
4216 NTSTATUS status = NT_STATUS_OK;
4218 frame = talloc_stackframe();
4220 if (smbXcli_conn_has_async_calls(cli->conn)) {
4222 * Can't use sync call while an async call is in flight
4224 status = NT_STATUS_INVALID_PARAMETER;
4225 goto fail;
4228 ev = samba_tevent_context_init(frame);
4229 if (ev == NULL) {
4230 status = NT_STATUS_NO_MEMORY;
4231 goto fail;
4234 req = cli_dskattr_send(frame, ev, cli);
4235 if (req == NULL) {
4236 status = NT_STATUS_NO_MEMORY;
4237 goto fail;
4240 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4241 goto fail;
4244 status = cli_dskattr_recv(req, bsize, total, avail);
4246 fail:
4247 TALLOC_FREE(frame);
4248 return status;
4251 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
4252 uint64_t *total, uint64_t *avail)
4254 uint64_t sectors_per_block;
4255 uint64_t bytes_per_sector;
4256 int old_bsize, old_total, old_avail;
4257 NTSTATUS status;
4259 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4260 return cli_smb2_dskattr(cli, path, bsize, total, avail);
4264 * Try the trans2 disk full size info call first.
4265 * We already use this in SMBC_fstatvfs_ctx().
4266 * Ignore 'actual_available_units' as we only
4267 * care about the quota for the caller.
4270 status = cli_get_fs_full_size_info(cli,
4271 total,
4272 avail,
4273 NULL,
4274 &sectors_per_block,
4275 &bytes_per_sector);
4277 /* Try and cope will all varients of "we don't do this call"
4278 and fall back to cli_dskattr. */
4280 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
4281 NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
4282 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
4283 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
4284 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
4285 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
4286 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
4287 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
4288 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
4289 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
4290 goto try_dskattr;
4293 if (!NT_STATUS_IS_OK(status)) {
4294 return status;
4297 if (bsize) {
4298 *bsize = sectors_per_block *
4299 bytes_per_sector;
4302 return NT_STATUS_OK;
4304 try_dskattr:
4306 /* Old SMB1 core protocol fallback. */
4307 status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
4308 if (!NT_STATUS_IS_OK(status)) {
4309 return status;
4311 if (bsize) {
4312 *bsize = (uint64_t)old_bsize;
4314 if (total) {
4315 *total = (uint64_t)old_total;
4317 if (avail) {
4318 *avail = (uint64_t)old_avail;
4320 return NT_STATUS_OK;
4323 /****************************************************************************
4324 Create and open a temporary file.
4325 ****************************************************************************/
4327 static void cli_ctemp_done(struct tevent_req *subreq);
4329 struct ctemp_state {
4330 uint16_t vwv[3];
4331 char *ret_path;
4332 uint16_t fnum;
4335 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4336 struct tevent_context *ev,
4337 struct cli_state *cli,
4338 const char *path)
4340 struct tevent_req *req = NULL, *subreq = NULL;
4341 struct ctemp_state *state = NULL;
4342 uint8_t additional_flags = 0;
4343 uint16_t additional_flags2 = 0;
4344 uint8_t *bytes = NULL;
4346 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4347 if (req == NULL) {
4348 return NULL;
4351 SSVAL(state->vwv,0,0);
4352 SIVALS(state->vwv+1,0,-1);
4354 bytes = talloc_array(state, uint8_t, 1);
4355 if (tevent_req_nomem(bytes, req)) {
4356 return tevent_req_post(req, ev);
4358 bytes[0] = 4;
4359 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
4360 strlen(path)+1, NULL);
4361 if (tevent_req_nomem(bytes, req)) {
4362 return tevent_req_post(req, ev);
4365 if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
4366 additional_flags2 = FLAGS2_REPARSE_PATH;
4369 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4370 additional_flags2,
4371 3, state->vwv, talloc_get_size(bytes), bytes);
4372 if (tevent_req_nomem(subreq, req)) {
4373 return tevent_req_post(req, ev);
4375 tevent_req_set_callback(subreq, cli_ctemp_done, req);
4376 return req;
4379 static void cli_ctemp_done(struct tevent_req *subreq)
4381 struct tevent_req *req = tevent_req_callback_data(
4382 subreq, struct tevent_req);
4383 struct ctemp_state *state = tevent_req_data(
4384 req, struct ctemp_state);
4385 NTSTATUS status;
4386 uint8_t wcnt;
4387 uint16_t *vwv;
4388 uint32_t num_bytes = 0;
4389 uint8_t *bytes = NULL;
4391 status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
4392 &num_bytes, &bytes);
4393 TALLOC_FREE(subreq);
4394 if (tevent_req_nterror(req, status)) {
4395 return;
4398 state->fnum = SVAL(vwv+0, 0);
4400 /* From W2K3, the result is just the ASCII name */
4401 if (num_bytes < 2) {
4402 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
4403 return;
4406 if (pull_string_talloc(state,
4407 NULL,
4409 &state->ret_path,
4410 bytes,
4411 num_bytes,
4412 STR_ASCII) == 0) {
4413 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4414 return;
4416 tevent_req_done(req);
4419 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
4420 TALLOC_CTX *ctx,
4421 uint16_t *pfnum,
4422 char **outfile)
4424 struct ctemp_state *state = tevent_req_data(req,
4425 struct ctemp_state);
4426 NTSTATUS status;
4428 if (tevent_req_is_nterror(req, &status)) {
4429 return status;
4431 *pfnum = state->fnum;
4432 *outfile = talloc_strdup(ctx, state->ret_path);
4433 if (!*outfile) {
4434 return NT_STATUS_NO_MEMORY;
4436 return NT_STATUS_OK;
4439 NTSTATUS cli_ctemp(struct cli_state *cli,
4440 TALLOC_CTX *ctx,
4441 const char *path,
4442 uint16_t *pfnum,
4443 char **out_path)
4445 TALLOC_CTX *frame = talloc_stackframe();
4446 struct tevent_context *ev;
4447 struct tevent_req *req;
4448 NTSTATUS status = NT_STATUS_OK;
4450 if (smbXcli_conn_has_async_calls(cli->conn)) {
4452 * Can't use sync call while an async call is in flight
4454 status = NT_STATUS_INVALID_PARAMETER;
4455 goto fail;
4458 ev = samba_tevent_context_init(frame);
4459 if (ev == NULL) {
4460 status = NT_STATUS_NO_MEMORY;
4461 goto fail;
4464 req = cli_ctemp_send(frame, ev, cli, path);
4465 if (req == NULL) {
4466 status = NT_STATUS_NO_MEMORY;
4467 goto fail;
4470 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4471 goto fail;
4474 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4476 fail:
4477 TALLOC_FREE(frame);
4478 return status;
4482 send a raw ioctl - used by the torture code
4484 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4486 uint16_t vwv[3];
4487 NTSTATUS status;
4489 SSVAL(vwv+0, 0, fnum);
4490 SSVAL(vwv+1, 0, code>>16);
4491 SSVAL(vwv+2, 0, (code&0xFFFF));
4493 status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4494 NULL, 0, NULL, NULL, NULL, NULL);
4495 if (!NT_STATUS_IS_OK(status)) {
4496 return status;
4498 *blob = data_blob_null;
4499 return NT_STATUS_OK;
4502 /*********************************************************
4503 Set an extended attribute utility fn.
4504 *********************************************************/
4506 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
4507 uint8_t *param, unsigned int param_len,
4508 const char *ea_name,
4509 const char *ea_val, size_t ea_len)
4511 uint16_t setup[1];
4512 unsigned int data_len = 0;
4513 uint8_t *data = NULL;
4514 char *p;
4515 size_t ea_namelen = strlen(ea_name);
4516 NTSTATUS status;
4518 SSVAL(setup, 0, setup_val);
4520 if (ea_namelen == 0 && ea_len == 0) {
4521 data_len = 4;
4522 data = talloc_array(talloc_tos(),
4523 uint8_t,
4524 data_len);
4525 if (!data) {
4526 return NT_STATUS_NO_MEMORY;
4528 p = (char *)data;
4529 SIVAL(p,0,data_len);
4530 } else {
4531 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4532 data = talloc_array(talloc_tos(),
4533 uint8_t,
4534 data_len);
4535 if (!data) {
4536 return NT_STATUS_NO_MEMORY;
4538 p = (char *)data;
4539 SIVAL(p,0,data_len);
4540 p += 4;
4541 SCVAL(p, 0, 0); /* EA flags. */
4542 SCVAL(p, 1, ea_namelen);
4543 SSVAL(p, 2, ea_len);
4544 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4545 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4549 * FIXME - if we want to do previous version path
4550 * processing on an EA set call we need to turn this
4551 * into calls to cli_trans_send()/cli_trans_recv()
4552 * with a temporary event context, as cli_trans_send()
4553 * have access to the additional_flags2 needed to
4554 * send @GMT- paths. JRA.
4557 status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
4558 setup, 1, 0,
4559 param, param_len, 2,
4560 data, data_len, 0,
4561 NULL,
4562 NULL, 0, NULL, /* rsetup */
4563 NULL, 0, NULL, /* rparam */
4564 NULL, 0, NULL); /* rdata */
4565 talloc_free(data);
4566 return status;
4569 /*********************************************************
4570 Set an extended attribute on a pathname.
4571 *********************************************************/
4573 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
4574 const char *ea_name, const char *ea_val,
4575 size_t ea_len)
4577 unsigned int param_len = 0;
4578 uint8_t *param;
4579 NTSTATUS status;
4580 TALLOC_CTX *frame = NULL;
4582 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4583 return cli_smb2_set_ea_path(cli,
4584 path,
4585 ea_name,
4586 ea_val,
4587 ea_len);
4590 frame = talloc_stackframe();
4592 param = talloc_array(frame, uint8_t, 6);
4593 if (!param) {
4594 status = NT_STATUS_NO_MEMORY;
4595 goto fail;
4597 SSVAL(param,0,SMB_INFO_SET_EA);
4598 SSVAL(param,2,0);
4599 SSVAL(param,4,0);
4601 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
4602 path, strlen(path)+1,
4603 NULL);
4604 param_len = talloc_get_size(param);
4606 status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
4607 ea_name, ea_val, ea_len);
4609 fail:
4611 TALLOC_FREE(frame);
4612 return status;
4615 /*********************************************************
4616 Set an extended attribute on an fnum.
4617 *********************************************************/
4619 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
4620 const char *ea_name, const char *ea_val,
4621 size_t ea_len)
4623 uint8_t param[6];
4625 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4626 return cli_smb2_set_ea_fnum(cli,
4627 fnum,
4628 ea_name,
4629 ea_val,
4630 ea_len);
4633 memset(param, 0, 6);
4634 SSVAL(param,0,fnum);
4635 SSVAL(param,2,SMB_INFO_SET_EA);
4637 return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
4638 ea_name, ea_val, ea_len);
4641 /*********************************************************
4642 Get an extended attribute list utility fn.
4643 *********************************************************/
4645 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4646 size_t rdata_len,
4647 size_t *pnum_eas, struct ea_struct **pea_list)
4649 struct ea_struct *ea_list = NULL;
4650 size_t num_eas;
4651 size_t ea_size;
4652 const uint8_t *p;
4654 if (rdata_len < 4) {
4655 return false;
4658 ea_size = (size_t)IVAL(rdata,0);
4659 if (ea_size > rdata_len) {
4660 return false;
4663 if (ea_size == 0) {
4664 /* No EA's present. */
4665 *pnum_eas = 0;
4666 *pea_list = NULL;
4667 return true;
4670 p = rdata + 4;
4671 ea_size -= 4;
4673 /* Validate the EA list and count it. */
4674 for (num_eas = 0; ea_size >= 4; num_eas++) {
4675 unsigned int ea_namelen = CVAL(p,1);
4676 unsigned int ea_valuelen = SVAL(p,2);
4677 if (ea_namelen == 0) {
4678 return false;
4680 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4681 return false;
4683 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4684 p += 4 + ea_namelen + 1 + ea_valuelen;
4687 if (num_eas == 0) {
4688 *pnum_eas = 0;
4689 *pea_list = NULL;
4690 return true;
4693 *pnum_eas = num_eas;
4694 if (!pea_list) {
4695 /* Caller only wants number of EA's. */
4696 return true;
4699 ea_list = talloc_array(ctx, struct ea_struct, num_eas);
4700 if (!ea_list) {
4701 return false;
4704 ea_size = (size_t)IVAL(rdata,0);
4705 p = rdata + 4;
4707 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4708 struct ea_struct *ea = &ea_list[num_eas];
4709 fstring unix_ea_name;
4710 unsigned int ea_namelen = CVAL(p,1);
4711 unsigned int ea_valuelen = SVAL(p,2);
4713 ea->flags = CVAL(p,0);
4714 unix_ea_name[0] = '\0';
4715 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
4716 ea->name = talloc_strdup(ea_list, unix_ea_name);
4717 if (!ea->name) {
4718 goto fail;
4720 /* Ensure the value is null terminated (in case it's a string). */
4721 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4722 if (!ea->value.data) {
4723 goto fail;
4725 if (ea_valuelen) {
4726 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4728 ea->value.data[ea_valuelen] = 0;
4729 ea->value.length--;
4730 p += 4 + ea_namelen + 1 + ea_valuelen;
4733 *pea_list = ea_list;
4734 return true;
4736 fail:
4737 TALLOC_FREE(ea_list);
4738 return false;
4741 /*********************************************************
4742 Get an extended attribute list from a pathname.
4743 *********************************************************/
4745 struct cli_get_ea_list_path_state {
4746 uint32_t num_data;
4747 uint8_t *data;
4750 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4752 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4753 struct tevent_context *ev,
4754 struct cli_state *cli,
4755 const char *fname)
4757 struct tevent_req *req, *subreq;
4758 struct cli_get_ea_list_path_state *state;
4760 req = tevent_req_create(mem_ctx, &state,
4761 struct cli_get_ea_list_path_state);
4762 if (req == NULL) {
4763 return NULL;
4765 subreq = cli_qpathinfo_send(state, ev, cli, fname,
4766 SMB_INFO_QUERY_ALL_EAS, 4,
4767 CLI_BUFFER_SIZE);
4768 if (tevent_req_nomem(subreq, req)) {
4769 return tevent_req_post(req, ev);
4771 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4772 return req;
4775 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4777 struct tevent_req *req = tevent_req_callback_data(
4778 subreq, struct tevent_req);
4779 struct cli_get_ea_list_path_state *state = tevent_req_data(
4780 req, struct cli_get_ea_list_path_state);
4781 NTSTATUS status;
4783 status = cli_qpathinfo_recv(subreq, state, &state->data,
4784 &state->num_data);
4785 TALLOC_FREE(subreq);
4786 if (tevent_req_nterror(req, status)) {
4787 return;
4789 tevent_req_done(req);
4792 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4793 size_t *pnum_eas, struct ea_struct **peas)
4795 struct cli_get_ea_list_path_state *state = tevent_req_data(
4796 req, struct cli_get_ea_list_path_state);
4797 NTSTATUS status;
4799 if (tevent_req_is_nterror(req, &status)) {
4800 return status;
4802 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4803 pnum_eas, peas)) {
4804 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4806 return NT_STATUS_OK;
4809 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
4810 TALLOC_CTX *ctx,
4811 size_t *pnum_eas,
4812 struct ea_struct **pea_list)
4814 TALLOC_CTX *frame = NULL;
4815 struct tevent_context *ev = NULL;
4816 struct tevent_req *req = NULL;
4817 NTSTATUS status = NT_STATUS_NO_MEMORY;
4819 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4820 return cli_smb2_get_ea_list_path(cli,
4821 path,
4822 ctx,
4823 pnum_eas,
4824 pea_list);
4827 frame = talloc_stackframe();
4829 if (smbXcli_conn_has_async_calls(cli->conn)) {
4831 * Can't use sync call while an async call is in flight
4833 status = NT_STATUS_INVALID_PARAMETER;
4834 goto fail;
4836 ev = samba_tevent_context_init(frame);
4837 if (ev == NULL) {
4838 goto fail;
4840 req = cli_get_ea_list_path_send(frame, ev, cli, path);
4841 if (req == NULL) {
4842 goto fail;
4844 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4845 goto fail;
4847 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
4848 fail:
4849 TALLOC_FREE(frame);
4850 return status;
4853 /****************************************************************************
4854 Convert open "flags" arg to uint32_t on wire.
4855 ****************************************************************************/
4857 static uint32_t open_flags_to_wire(int flags)
4859 int open_mode = flags & O_ACCMODE;
4860 uint32_t ret = 0;
4862 switch (open_mode) {
4863 case O_WRONLY:
4864 ret |= SMB_O_WRONLY;
4865 break;
4866 case O_RDWR:
4867 ret |= SMB_O_RDWR;
4868 break;
4869 default:
4870 case O_RDONLY:
4871 ret |= SMB_O_RDONLY;
4872 break;
4875 if (flags & O_CREAT) {
4876 ret |= SMB_O_CREAT;
4878 if (flags & O_EXCL) {
4879 ret |= SMB_O_EXCL;
4881 if (flags & O_TRUNC) {
4882 ret |= SMB_O_TRUNC;
4884 #if defined(O_SYNC)
4885 if (flags & O_SYNC) {
4886 ret |= SMB_O_SYNC;
4888 #endif /* O_SYNC */
4889 if (flags & O_APPEND) {
4890 ret |= SMB_O_APPEND;
4892 #if defined(O_DIRECT)
4893 if (flags & O_DIRECT) {
4894 ret |= SMB_O_DIRECT;
4896 #endif
4897 #if defined(O_DIRECTORY)
4898 if (flags & O_DIRECTORY) {
4899 ret |= SMB_O_DIRECTORY;
4901 #endif
4902 return ret;
4905 /****************************************************************************
4906 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4907 ****************************************************************************/
4909 struct posix_open_state {
4910 uint16_t setup;
4911 uint8_t *param;
4912 uint8_t data[18];
4913 uint16_t fnum; /* Out */
4916 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4918 struct tevent_req *req = tevent_req_callback_data(
4919 subreq, struct tevent_req);
4920 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4921 NTSTATUS status;
4922 uint8_t *data;
4923 uint32_t num_data;
4925 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
4926 NULL, 0, NULL, &data, 12, &num_data);
4927 TALLOC_FREE(subreq);
4928 if (tevent_req_nterror(req, status)) {
4929 return;
4931 state->fnum = SVAL(data,2);
4932 tevent_req_done(req);
4935 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4936 struct tevent_context *ev,
4937 struct cli_state *cli,
4938 const char *fname,
4939 int flags,
4940 mode_t mode,
4941 bool is_dir)
4943 struct tevent_req *req = NULL, *subreq = NULL;
4944 struct posix_open_state *state = NULL;
4945 uint32_t wire_flags = open_flags_to_wire(flags);
4947 req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4948 if (req == NULL) {
4949 return NULL;
4952 /* Setup setup word. */
4953 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4955 /* Setup param array. */
4956 state->param = talloc_array(state, uint8_t, 6);
4957 if (tevent_req_nomem(state->param, req)) {
4958 return tevent_req_post(req, ev);
4960 memset(state->param, '\0', 6);
4961 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4963 state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn), fname,
4964 strlen(fname)+1, NULL);
4966 if (tevent_req_nomem(state->param, req)) {
4967 return tevent_req_post(req, ev);
4970 /* Setup data words. */
4971 if (is_dir) {
4972 wire_flags |= SMB_O_DIRECTORY;
4975 SIVAL(state->data,0,0); /* No oplock. */
4976 SIVAL(state->data,4,wire_flags);
4977 SIVAL(state->data,8,unix_perms_to_wire(mode));
4978 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
4979 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
4981 subreq = cli_trans_send(state, /* mem ctx. */
4982 ev, /* event ctx. */
4983 cli, /* cli_state. */
4984 0, /* additional_flags2 */
4985 SMBtrans2, /* cmd. */
4986 NULL, /* pipe name. */
4987 -1, /* fid. */
4988 0, /* function. */
4989 0, /* flags. */
4990 &state->setup, /* setup. */
4991 1, /* num setup uint16_t words. */
4992 0, /* max returned setup. */
4993 state->param, /* param. */
4994 talloc_get_size(state->param),/* num param. */
4995 2, /* max returned param. */
4996 state->data, /* data. */
4997 18, /* num data. */
4998 12); /* max returned data. */
5000 if (tevent_req_nomem(subreq, req)) {
5001 return tevent_req_post(req, ev);
5003 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
5004 return req;
5007 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
5008 struct tevent_context *ev,
5009 struct cli_state *cli,
5010 const char *fname,
5011 int flags,
5012 mode_t mode)
5014 return cli_posix_open_internal_send(mem_ctx, ev,
5015 cli, fname, flags, mode, false);
5018 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
5020 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
5021 NTSTATUS status;
5023 if (tevent_req_is_nterror(req, &status)) {
5024 return status;
5026 *pfnum = state->fnum;
5027 return NT_STATUS_OK;
5030 /****************************************************************************
5031 Open - POSIX semantics. Doesn't request oplock.
5032 ****************************************************************************/
5034 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
5035 int flags, mode_t mode, uint16_t *pfnum)
5038 TALLOC_CTX *frame = talloc_stackframe();
5039 struct tevent_context *ev = NULL;
5040 struct tevent_req *req = NULL;
5041 NTSTATUS status = NT_STATUS_OK;
5043 if (smbXcli_conn_has_async_calls(cli->conn)) {
5045 * Can't use sync call while an async call is in flight
5047 status = NT_STATUS_INVALID_PARAMETER;
5048 goto fail;
5051 ev = samba_tevent_context_init(frame);
5052 if (ev == NULL) {
5053 status = NT_STATUS_NO_MEMORY;
5054 goto fail;
5057 req = cli_posix_open_send(frame,
5059 cli,
5060 fname,
5061 flags,
5062 mode);
5063 if (req == NULL) {
5064 status = NT_STATUS_NO_MEMORY;
5065 goto fail;
5068 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5069 goto fail;
5072 status = cli_posix_open_recv(req, pfnum);
5074 fail:
5075 TALLOC_FREE(frame);
5076 return status;
5079 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
5080 struct tevent_context *ev,
5081 struct cli_state *cli,
5082 const char *fname,
5083 mode_t mode)
5085 return cli_posix_open_internal_send(mem_ctx, ev,
5086 cli, fname, O_CREAT, mode, true);
5089 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
5091 return tevent_req_simple_recv_ntstatus(req);
5094 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
5096 TALLOC_CTX *frame = talloc_stackframe();
5097 struct tevent_context *ev = NULL;
5098 struct tevent_req *req = NULL;
5099 NTSTATUS status = NT_STATUS_OK;
5101 if (smbXcli_conn_has_async_calls(cli->conn)) {
5103 * Can't use sync call while an async call is in flight
5105 status = NT_STATUS_INVALID_PARAMETER;
5106 goto fail;
5109 ev = samba_tevent_context_init(frame);
5110 if (ev == NULL) {
5111 status = NT_STATUS_NO_MEMORY;
5112 goto fail;
5115 req = cli_posix_mkdir_send(frame,
5117 cli,
5118 fname,
5119 mode);
5120 if (req == NULL) {
5121 status = NT_STATUS_NO_MEMORY;
5122 goto fail;
5125 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5126 goto fail;
5129 status = cli_posix_mkdir_recv(req);
5131 fail:
5132 TALLOC_FREE(frame);
5133 return status;
5136 /****************************************************************************
5137 unlink or rmdir - POSIX semantics.
5138 ****************************************************************************/
5140 struct cli_posix_unlink_internal_state {
5141 uint8_t data[2];
5144 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
5146 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
5147 struct tevent_context *ev,
5148 struct cli_state *cli,
5149 const char *fname,
5150 uint16_t level)
5152 struct tevent_req *req = NULL, *subreq = NULL;
5153 struct cli_posix_unlink_internal_state *state = NULL;
5155 req = tevent_req_create(mem_ctx, &state,
5156 struct cli_posix_unlink_internal_state);
5157 if (req == NULL) {
5158 return NULL;
5161 /* Setup data word. */
5162 SSVAL(state->data, 0, level);
5164 subreq = cli_setpathinfo_send(state, ev, cli,
5165 SMB_POSIX_PATH_UNLINK,
5166 fname,
5167 state->data, sizeof(state->data));
5168 if (tevent_req_nomem(subreq, req)) {
5169 return tevent_req_post(req, ev);
5171 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
5172 return req;
5175 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
5177 NTSTATUS status = cli_setpathinfo_recv(subreq);
5178 tevent_req_simple_finish_ntstatus(subreq, status);
5181 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
5182 struct tevent_context *ev,
5183 struct cli_state *cli,
5184 const char *fname)
5186 return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
5187 SMB_POSIX_UNLINK_FILE_TARGET);
5190 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
5192 return tevent_req_simple_recv_ntstatus(req);
5195 /****************************************************************************
5196 unlink - POSIX semantics.
5197 ****************************************************************************/
5199 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
5201 TALLOC_CTX *frame = talloc_stackframe();
5202 struct tevent_context *ev = NULL;
5203 struct tevent_req *req = NULL;
5204 NTSTATUS status = NT_STATUS_OK;
5206 if (smbXcli_conn_has_async_calls(cli->conn)) {
5208 * Can't use sync call while an async call is in flight
5210 status = NT_STATUS_INVALID_PARAMETER;
5211 goto fail;
5214 ev = samba_tevent_context_init(frame);
5215 if (ev == NULL) {
5216 status = NT_STATUS_NO_MEMORY;
5217 goto fail;
5220 req = cli_posix_unlink_send(frame,
5222 cli,
5223 fname);
5224 if (req == NULL) {
5225 status = NT_STATUS_NO_MEMORY;
5226 goto fail;
5229 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5230 goto fail;
5233 status = cli_posix_unlink_recv(req);
5235 fail:
5236 TALLOC_FREE(frame);
5237 return status;
5240 /****************************************************************************
5241 rmdir - POSIX semantics.
5242 ****************************************************************************/
5244 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
5245 struct tevent_context *ev,
5246 struct cli_state *cli,
5247 const char *fname)
5249 return cli_posix_unlink_internal_send(
5250 mem_ctx, ev, cli, fname,
5251 SMB_POSIX_UNLINK_DIRECTORY_TARGET);
5254 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
5256 return tevent_req_simple_recv_ntstatus(req);
5259 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
5261 TALLOC_CTX *frame = talloc_stackframe();
5262 struct tevent_context *ev = NULL;
5263 struct tevent_req *req = NULL;
5264 NTSTATUS status = NT_STATUS_OK;
5266 if (smbXcli_conn_has_async_calls(cli->conn)) {
5268 * Can't use sync call while an async call is in flight
5270 status = NT_STATUS_INVALID_PARAMETER;
5271 goto fail;
5274 ev = samba_tevent_context_init(frame);
5275 if (ev == NULL) {
5276 status = NT_STATUS_NO_MEMORY;
5277 goto fail;
5280 req = cli_posix_rmdir_send(frame,
5282 cli,
5283 fname);
5284 if (req == NULL) {
5285 status = NT_STATUS_NO_MEMORY;
5286 goto fail;
5289 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5290 goto fail;
5293 status = cli_posix_rmdir_recv(req, frame);
5295 fail:
5296 TALLOC_FREE(frame);
5297 return status;
5300 /****************************************************************************
5301 filechangenotify
5302 ****************************************************************************/
5304 struct cli_notify_state {
5305 uint8_t setup[8];
5306 uint32_t num_changes;
5307 struct notify_change *changes;
5310 static void cli_notify_done(struct tevent_req *subreq);
5312 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
5313 struct tevent_context *ev,
5314 struct cli_state *cli, uint16_t fnum,
5315 uint32_t buffer_size,
5316 uint32_t completion_filter, bool recursive)
5318 struct tevent_req *req, *subreq;
5319 struct cli_notify_state *state;
5320 unsigned old_timeout;
5322 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
5323 if (req == NULL) {
5324 return NULL;
5327 SIVAL(state->setup, 0, completion_filter);
5328 SSVAL(state->setup, 4, fnum);
5329 SSVAL(state->setup, 6, recursive);
5332 * Notifies should not time out
5334 old_timeout = cli_set_timeout(cli, 0);
5336 subreq = cli_trans_send(
5337 state, /* mem ctx. */
5338 ev, /* event ctx. */
5339 cli, /* cli_state. */
5340 0, /* additional_flags2 */
5341 SMBnttrans, /* cmd. */
5342 NULL, /* pipe name. */
5343 -1, /* fid. */
5344 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
5345 0, /* flags. */
5346 (uint16_t *)state->setup, /* setup. */
5347 4, /* num setup uint16_t words. */
5348 0, /* max returned setup. */
5349 NULL, /* param. */
5350 0, /* num param. */
5351 buffer_size, /* max returned param. */
5352 NULL, /* data. */
5353 0, /* num data. */
5354 0); /* max returned data. */
5356 cli_set_timeout(cli, old_timeout);
5358 if (tevent_req_nomem(subreq, req)) {
5359 return tevent_req_post(req, ev);
5361 tevent_req_set_callback(subreq, cli_notify_done, req);
5362 return req;
5365 static void cli_notify_done(struct tevent_req *subreq)
5367 struct tevent_req *req = tevent_req_callback_data(
5368 subreq, struct tevent_req);
5369 struct cli_notify_state *state = tevent_req_data(
5370 req, struct cli_notify_state);
5371 NTSTATUS status;
5372 uint8_t *params;
5373 uint32_t i, ofs, num_params;
5374 uint16_t flags2;
5376 status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
5377 &params, 0, &num_params, NULL, 0, NULL);
5378 TALLOC_FREE(subreq);
5379 if (tevent_req_nterror(req, status)) {
5380 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
5381 return;
5384 state->num_changes = 0;
5385 ofs = 0;
5387 while (num_params - ofs > 12) {
5388 uint32_t next = IVAL(params, ofs);
5389 state->num_changes += 1;
5391 if ((next == 0) || (ofs+next >= num_params)) {
5392 break;
5394 ofs += next;
5397 state->changes = talloc_array(state, struct notify_change,
5398 state->num_changes);
5399 if (tevent_req_nomem(state->changes, req)) {
5400 TALLOC_FREE(params);
5401 return;
5404 ofs = 0;
5406 for (i=0; i<state->num_changes; i++) {
5407 uint32_t next = IVAL(params, ofs);
5408 uint32_t len = IVAL(params, ofs+8);
5409 ssize_t ret;
5410 char *name;
5412 if (trans_oob(num_params, ofs + 12, len)) {
5413 TALLOC_FREE(params);
5414 tevent_req_nterror(
5415 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5416 return;
5419 state->changes[i].action = IVAL(params, ofs+4);
5420 ret = clistr_pull_talloc(state->changes, (char *)params, flags2,
5421 &name, params+ofs+12, len,
5422 STR_TERMINATE|STR_UNICODE);
5423 if (ret == -1) {
5424 TALLOC_FREE(params);
5425 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5426 return;
5428 state->changes[i].name = name;
5429 ofs += next;
5432 TALLOC_FREE(params);
5433 tevent_req_done(req);
5436 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5437 uint32_t *pnum_changes,
5438 struct notify_change **pchanges)
5440 struct cli_notify_state *state = tevent_req_data(
5441 req, struct cli_notify_state);
5442 NTSTATUS status;
5444 if (tevent_req_is_nterror(req, &status)) {
5445 return status;
5448 *pnum_changes = state->num_changes;
5449 *pchanges = talloc_move(mem_ctx, &state->changes);
5450 return NT_STATUS_OK;
5453 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
5454 uint32_t completion_filter, bool recursive,
5455 TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
5456 struct notify_change **pchanges)
5458 TALLOC_CTX *frame = talloc_stackframe();
5459 struct tevent_context *ev;
5460 struct tevent_req *req;
5461 NTSTATUS status = NT_STATUS_NO_MEMORY;
5463 if (smbXcli_conn_has_async_calls(cli->conn)) {
5465 * Can't use sync call while an async call is in flight
5467 status = NT_STATUS_INVALID_PARAMETER;
5468 goto fail;
5470 ev = samba_tevent_context_init(frame);
5471 if (ev == NULL) {
5472 goto fail;
5474 req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
5475 completion_filter, recursive);
5476 if (req == NULL) {
5477 goto fail;
5479 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5480 goto fail;
5482 status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
5483 fail:
5484 TALLOC_FREE(frame);
5485 return status;
5488 struct cli_qpathinfo_state {
5489 uint8_t *param;
5490 uint8_t *data;
5491 uint16_t setup[1];
5492 uint32_t min_rdata;
5493 uint8_t *rdata;
5494 uint32_t num_rdata;
5497 static void cli_qpathinfo_done(struct tevent_req *subreq);
5499 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
5500 struct tevent_context *ev,
5501 struct cli_state *cli, const char *fname,
5502 uint16_t level, uint32_t min_rdata,
5503 uint32_t max_rdata)
5505 struct tevent_req *req, *subreq;
5506 struct cli_qpathinfo_state *state;
5507 uint16_t additional_flags2 = 0;
5509 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
5510 if (req == NULL) {
5511 return NULL;
5513 state->min_rdata = min_rdata;
5514 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
5516 state->param = talloc_zero_array(state, uint8_t, 6);
5517 if (tevent_req_nomem(state->param, req)) {
5518 return tevent_req_post(req, ev);
5520 SSVAL(state->param, 0, level);
5521 state->param = trans2_bytes_push_str(
5522 state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
5523 if (tevent_req_nomem(state->param, req)) {
5524 return tevent_req_post(req, ev);
5527 if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
5528 !INFO_LEVEL_IS_UNIX(level)) {
5529 additional_flags2 = FLAGS2_REPARSE_PATH;
5532 subreq = cli_trans_send(
5533 state, /* mem ctx. */
5534 ev, /* event ctx. */
5535 cli, /* cli_state. */
5536 additional_flags2, /* additional_flags2 */
5537 SMBtrans2, /* cmd. */
5538 NULL, /* pipe name. */
5539 -1, /* fid. */
5540 0, /* function. */
5541 0, /* flags. */
5542 state->setup, /* setup. */
5543 1, /* num setup uint16_t words. */
5544 0, /* max returned setup. */
5545 state->param, /* param. */
5546 talloc_get_size(state->param), /* num param. */
5547 2, /* max returned param. */
5548 NULL, /* data. */
5549 0, /* num data. */
5550 max_rdata); /* max returned data. */
5552 if (tevent_req_nomem(subreq, req)) {
5553 return tevent_req_post(req, ev);
5555 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5556 return req;
5559 static void cli_qpathinfo_done(struct tevent_req *subreq)
5561 struct tevent_req *req = tevent_req_callback_data(
5562 subreq, struct tevent_req);
5563 struct cli_qpathinfo_state *state = tevent_req_data(
5564 req, struct cli_qpathinfo_state);
5565 NTSTATUS status;
5567 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5568 NULL, 0, NULL,
5569 &state->rdata, state->min_rdata,
5570 &state->num_rdata);
5571 if (tevent_req_nterror(req, status)) {
5572 return;
5574 tevent_req_done(req);
5577 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5578 uint8_t **rdata, uint32_t *num_rdata)
5580 struct cli_qpathinfo_state *state = tevent_req_data(
5581 req, struct cli_qpathinfo_state);
5582 NTSTATUS status;
5584 if (tevent_req_is_nterror(req, &status)) {
5585 return status;
5587 if (rdata != NULL) {
5588 *rdata = talloc_move(mem_ctx, &state->rdata);
5589 } else {
5590 TALLOC_FREE(state->rdata);
5592 if (num_rdata != NULL) {
5593 *num_rdata = state->num_rdata;
5595 return NT_STATUS_OK;
5598 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5599 const char *fname, uint16_t level, uint32_t min_rdata,
5600 uint32_t max_rdata,
5601 uint8_t **rdata, uint32_t *num_rdata)
5603 TALLOC_CTX *frame = talloc_stackframe();
5604 struct tevent_context *ev;
5605 struct tevent_req *req;
5606 NTSTATUS status = NT_STATUS_NO_MEMORY;
5608 if (smbXcli_conn_has_async_calls(cli->conn)) {
5610 * Can't use sync call while an async call is in flight
5612 status = NT_STATUS_INVALID_PARAMETER;
5613 goto fail;
5615 ev = samba_tevent_context_init(frame);
5616 if (ev == NULL) {
5617 goto fail;
5619 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5620 max_rdata);
5621 if (req == NULL) {
5622 goto fail;
5624 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5625 goto fail;
5627 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5628 fail:
5629 TALLOC_FREE(frame);
5630 return status;
5633 struct cli_qfileinfo_state {
5634 uint16_t setup[1];
5635 uint8_t param[4];
5636 uint8_t *data;
5637 uint16_t recv_flags2;
5638 uint32_t min_rdata;
5639 uint8_t *rdata;
5640 uint32_t num_rdata;
5643 static void cli_qfileinfo_done(struct tevent_req *subreq);
5645 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
5646 struct tevent_context *ev,
5647 struct cli_state *cli, uint16_t fnum,
5648 uint16_t level, uint32_t min_rdata,
5649 uint32_t max_rdata)
5651 struct tevent_req *req, *subreq;
5652 struct cli_qfileinfo_state *state;
5654 req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
5655 if (req == NULL) {
5656 return NULL;
5658 state->min_rdata = min_rdata;
5659 SSVAL(state->param, 0, fnum);
5660 SSVAL(state->param, 2, level);
5661 SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
5663 subreq = cli_trans_send(
5664 state, /* mem ctx. */
5665 ev, /* event ctx. */
5666 cli, /* cli_state. */
5667 0, /* additional_flags2 */
5668 SMBtrans2, /* cmd. */
5669 NULL, /* pipe name. */
5670 -1, /* fid. */
5671 0, /* function. */
5672 0, /* flags. */
5673 state->setup, /* setup. */
5674 1, /* num setup uint16_t words. */
5675 0, /* max returned setup. */
5676 state->param, /* param. */
5677 sizeof(state->param), /* num param. */
5678 2, /* max returned param. */
5679 NULL, /* data. */
5680 0, /* num data. */
5681 max_rdata); /* max returned data. */
5683 if (tevent_req_nomem(subreq, req)) {
5684 return tevent_req_post(req, ev);
5686 tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
5687 return req;
5690 static void cli_qfileinfo_done(struct tevent_req *subreq)
5692 struct tevent_req *req = tevent_req_callback_data(
5693 subreq, struct tevent_req);
5694 struct cli_qfileinfo_state *state = tevent_req_data(
5695 req, struct cli_qfileinfo_state);
5696 NTSTATUS status;
5698 status = cli_trans_recv(subreq, state,
5699 &state->recv_flags2,
5700 NULL, 0, NULL,
5701 NULL, 0, NULL,
5702 &state->rdata, state->min_rdata,
5703 &state->num_rdata);
5704 if (tevent_req_nterror(req, status)) {
5705 return;
5707 tevent_req_done(req);
5710 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5711 uint16_t *recv_flags2,
5712 uint8_t **rdata, uint32_t *num_rdata)
5714 struct cli_qfileinfo_state *state = tevent_req_data(
5715 req, struct cli_qfileinfo_state);
5716 NTSTATUS status;
5718 if (tevent_req_is_nterror(req, &status)) {
5719 return status;
5722 if (recv_flags2 != NULL) {
5723 *recv_flags2 = state->recv_flags2;
5725 if (rdata != NULL) {
5726 *rdata = talloc_move(mem_ctx, &state->rdata);
5727 } else {
5728 TALLOC_FREE(state->rdata);
5730 if (num_rdata != NULL) {
5731 *num_rdata = state->num_rdata;
5733 return NT_STATUS_OK;
5736 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5737 uint16_t fnum, uint16_t level, uint32_t min_rdata,
5738 uint32_t max_rdata, uint16_t *recv_flags2,
5739 uint8_t **rdata, uint32_t *num_rdata)
5741 TALLOC_CTX *frame = talloc_stackframe();
5742 struct tevent_context *ev;
5743 struct tevent_req *req;
5744 NTSTATUS status = NT_STATUS_NO_MEMORY;
5746 if (smbXcli_conn_has_async_calls(cli->conn)) {
5748 * Can't use sync call while an async call is in flight
5750 status = NT_STATUS_INVALID_PARAMETER;
5751 goto fail;
5753 ev = samba_tevent_context_init(frame);
5754 if (ev == NULL) {
5755 goto fail;
5757 req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
5758 max_rdata);
5759 if (req == NULL) {
5760 goto fail;
5762 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5763 goto fail;
5765 status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
5766 fail:
5767 TALLOC_FREE(frame);
5768 return status;
5771 struct cli_flush_state {
5772 uint16_t vwv[1];
5775 static void cli_flush_done(struct tevent_req *subreq);
5777 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
5778 struct tevent_context *ev,
5779 struct cli_state *cli,
5780 uint16_t fnum)
5782 struct tevent_req *req, *subreq;
5783 struct cli_flush_state *state;
5785 req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
5786 if (req == NULL) {
5787 return NULL;
5789 SSVAL(state->vwv + 0, 0, fnum);
5791 subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
5792 0, NULL);
5793 if (tevent_req_nomem(subreq, req)) {
5794 return tevent_req_post(req, ev);
5796 tevent_req_set_callback(subreq, cli_flush_done, req);
5797 return req;
5800 static void cli_flush_done(struct tevent_req *subreq)
5802 struct tevent_req *req = tevent_req_callback_data(
5803 subreq, struct tevent_req);
5804 NTSTATUS status;
5806 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5807 TALLOC_FREE(subreq);
5808 if (tevent_req_nterror(req, status)) {
5809 return;
5811 tevent_req_done(req);
5814 NTSTATUS cli_flush_recv(struct tevent_req *req)
5816 return tevent_req_simple_recv_ntstatus(req);
5819 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
5821 TALLOC_CTX *frame = talloc_stackframe();
5822 struct tevent_context *ev;
5823 struct tevent_req *req;
5824 NTSTATUS status = NT_STATUS_NO_MEMORY;
5826 if (smbXcli_conn_has_async_calls(cli->conn)) {
5828 * Can't use sync call while an async call is in flight
5830 status = NT_STATUS_INVALID_PARAMETER;
5831 goto fail;
5833 ev = samba_tevent_context_init(frame);
5834 if (ev == NULL) {
5835 goto fail;
5837 req = cli_flush_send(frame, ev, cli, fnum);
5838 if (req == NULL) {
5839 goto fail;
5841 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5842 goto fail;
5844 status = cli_flush_recv(req);
5845 fail:
5846 TALLOC_FREE(frame);
5847 return status;
5850 struct cli_shadow_copy_data_state {
5851 uint16_t setup[4];
5852 uint8_t *data;
5853 uint32_t num_data;
5854 bool get_names;
5857 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
5859 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
5860 struct tevent_context *ev,
5861 struct cli_state *cli,
5862 uint16_t fnum,
5863 bool get_names)
5865 struct tevent_req *req, *subreq;
5866 struct cli_shadow_copy_data_state *state;
5867 uint32_t ret_size;
5869 req = tevent_req_create(mem_ctx, &state,
5870 struct cli_shadow_copy_data_state);
5871 if (req == NULL) {
5872 return NULL;
5874 state->get_names = get_names;
5875 ret_size = get_names ? CLI_BUFFER_SIZE : 16;
5877 SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
5878 SSVAL(state->setup + 2, 0, fnum);
5879 SCVAL(state->setup + 3, 0, 1); /* isFsctl */
5880 SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
5882 subreq = cli_trans_send(
5883 state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
5884 state->setup, ARRAY_SIZE(state->setup),
5885 ARRAY_SIZE(state->setup),
5886 NULL, 0, 0,
5887 NULL, 0, ret_size);
5888 if (tevent_req_nomem(subreq, req)) {
5889 return tevent_req_post(req, ev);
5891 tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
5892 return req;
5895 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
5897 struct tevent_req *req = tevent_req_callback_data(
5898 subreq, struct tevent_req);
5899 struct cli_shadow_copy_data_state *state = tevent_req_data(
5900 req, struct cli_shadow_copy_data_state);
5901 NTSTATUS status;
5903 status = cli_trans_recv(subreq, state, NULL,
5904 NULL, 0, NULL, /* setup */
5905 NULL, 0, NULL, /* param */
5906 &state->data, 12, &state->num_data);
5907 TALLOC_FREE(subreq);
5908 if (tevent_req_nterror(req, status)) {
5909 return;
5911 tevent_req_done(req);
5914 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5915 char ***pnames, int *pnum_names)
5917 struct cli_shadow_copy_data_state *state = tevent_req_data(
5918 req, struct cli_shadow_copy_data_state);
5919 char **names = NULL;
5920 uint32_t i, num_names;
5921 uint32_t dlength;
5922 uint8_t *endp = NULL;
5923 NTSTATUS status;
5925 if (tevent_req_is_nterror(req, &status)) {
5926 return status;
5929 if (state->num_data < 16) {
5930 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5933 num_names = IVAL(state->data, 4);
5934 dlength = IVAL(state->data, 8);
5936 if (num_names > 0x7FFFFFFF) {
5937 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5940 if (!state->get_names) {
5941 *pnum_names = (int)num_names;
5942 return NT_STATUS_OK;
5945 if (dlength + 12 < 12) {
5946 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5948 if (dlength + 12 > state->num_data) {
5949 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5951 if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
5952 state->num_data) {
5953 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5956 names = talloc_array(mem_ctx, char *, num_names);
5957 if (names == NULL) {
5958 return NT_STATUS_NO_MEMORY;
5961 endp = state->data + state->num_data;
5963 for (i=0; i<num_names; i++) {
5964 bool ret;
5965 uint8_t *src;
5966 size_t converted_size;
5968 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
5970 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
5971 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5974 ret = convert_string_talloc(
5975 names, CH_UTF16LE, CH_UNIX,
5976 src, 2 * sizeof(SHADOW_COPY_LABEL),
5977 &names[i], &converted_size);
5978 if (!ret) {
5979 TALLOC_FREE(names);
5980 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5983 *pnum_names = (int)num_names;
5984 *pnames = names;
5985 return NT_STATUS_OK;
5988 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5989 uint16_t fnum, bool get_names,
5990 char ***pnames, int *pnum_names)
5992 TALLOC_CTX *frame = NULL;
5993 struct tevent_context *ev;
5994 struct tevent_req *req;
5995 NTSTATUS status = NT_STATUS_NO_MEMORY;
5997 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5998 return cli_smb2_shadow_copy_data(mem_ctx,
5999 cli,
6000 fnum,
6001 get_names,
6002 pnames,
6003 pnum_names);
6006 frame = talloc_stackframe();
6008 if (smbXcli_conn_has_async_calls(cli->conn)) {
6010 * Can't use sync call while an async call is in flight
6012 status = NT_STATUS_INVALID_PARAMETER;
6013 goto fail;
6015 ev = samba_tevent_context_init(frame);
6016 if (ev == NULL) {
6017 goto fail;
6019 req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
6020 if (req == NULL) {
6021 goto fail;
6023 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6024 goto fail;
6026 status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
6027 fail:
6028 TALLOC_FREE(frame);
6029 return status;