ctdb-scripts: Quote some variable expansions
[Samba.git] / source3 / libsmb / clifile.c
blob684f26386b6d109e541f8b96e36a52b390b728ff
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 /***********************************************************
33 Common function for pushing stings, used by smb_bytes_push_str()
34 and trans_bytes_push_str(). Only difference is the align_odd
35 parameter setting.
36 ***********************************************************/
38 static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
39 const char *str, size_t str_len,
40 bool align_odd,
41 size_t *pconverted_size)
43 size_t buflen;
44 char *converted;
45 size_t converted_size;
47 if (buf == NULL) {
48 return NULL;
51 buflen = talloc_get_size(buf);
53 if (ucs2 &&
54 ((align_odd && (buflen % 2 == 0)) ||
55 (!align_odd && (buflen % 2 == 1)))) {
57 * We're pushing into an SMB buffer, align odd
59 buf = talloc_realloc(NULL, buf, uint8_t, buflen + 1);
60 if (buf == NULL) {
61 return NULL;
63 buf[buflen] = '\0';
64 buflen += 1;
67 if (!convert_string_talloc(talloc_tos(), CH_UNIX,
68 ucs2 ? CH_UTF16LE : CH_DOS,
69 str, str_len, &converted,
70 &converted_size)) {
71 return NULL;
74 buf = talloc_realloc(NULL, buf, uint8_t,
75 buflen + converted_size);
76 if (buf == NULL) {
77 TALLOC_FREE(converted);
78 return NULL;
81 memcpy(buf + buflen, converted, converted_size);
83 TALLOC_FREE(converted);
85 if (pconverted_size) {
86 *pconverted_size = converted_size;
89 return buf;
92 /***********************************************************
93 Push a string into an SMB buffer, with odd byte alignment
94 if it's a UCS2 string.
95 ***********************************************************/
97 uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
98 const char *str, size_t str_len,
99 size_t *pconverted_size)
101 return internal_bytes_push_str(buf, ucs2, str, str_len,
102 true, pconverted_size);
105 uint8_t *smb_bytes_push_bytes(uint8_t *buf, uint8_t prefix,
106 const uint8_t *bytes, size_t num_bytes)
108 size_t buflen;
110 if (buf == NULL) {
111 return NULL;
113 buflen = talloc_get_size(buf);
115 buf = talloc_realloc(NULL, buf, uint8_t,
116 buflen + 1 + num_bytes);
117 if (buf == NULL) {
118 return NULL;
120 buf[buflen] = prefix;
121 memcpy(&buf[buflen+1], bytes, num_bytes);
122 return buf;
125 /***********************************************************
126 Same as smb_bytes_push_str(), but without the odd byte
127 align for ucs2 (we're pushing into a param or data block).
128 static for now, although this will probably change when
129 other modules use async trans calls.
130 ***********************************************************/
132 uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
133 const char *str, size_t str_len,
134 size_t *pconverted_size)
136 return internal_bytes_push_str(buf, ucs2, str, str_len,
137 false, pconverted_size);
140 uint8_t *trans2_bytes_push_bytes(uint8_t *buf,
141 const uint8_t *bytes, size_t num_bytes)
143 size_t buflen;
145 if (buf == NULL) {
146 return NULL;
148 buflen = talloc_get_size(buf);
150 buf = talloc_realloc(NULL, buf, uint8_t,
151 buflen + num_bytes);
152 if (buf == NULL) {
153 return NULL;
155 memcpy(&buf[buflen], bytes, num_bytes);
156 return buf;
159 struct cli_setpathinfo_state {
160 uint16_t setup;
161 uint8_t *param;
164 static void cli_setpathinfo_done(struct tevent_req *subreq);
166 struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
167 struct tevent_context *ev,
168 struct cli_state *cli,
169 uint16_t level,
170 const char *path,
171 uint8_t *data,
172 size_t data_len)
174 struct tevent_req *req, *subreq;
175 struct cli_setpathinfo_state *state;
177 req = tevent_req_create(mem_ctx, &state,
178 struct cli_setpathinfo_state);
179 if (req == NULL) {
180 return NULL;
183 /* Setup setup word. */
184 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
186 /* Setup param array. */
187 state->param = talloc_zero_array(state, uint8_t, 6);
188 if (tevent_req_nomem(state->param, req)) {
189 return tevent_req_post(req, ev);
191 SSVAL(state->param, 0, level);
193 state->param = trans2_bytes_push_str(
194 state->param, smbXcli_conn_use_unicode(cli->conn), path, strlen(path)+1, NULL);
195 if (tevent_req_nomem(state->param, req)) {
196 return tevent_req_post(req, ev);
199 subreq = cli_trans_send(
200 state, /* mem ctx. */
201 ev, /* event ctx. */
202 cli, /* cli_state. */
203 SMBtrans2, /* cmd. */
204 NULL, /* pipe name. */
205 -1, /* fid. */
206 0, /* function. */
207 0, /* flags. */
208 &state->setup, /* setup. */
209 1, /* num setup uint16_t words. */
210 0, /* max returned setup. */
211 state->param, /* param. */
212 talloc_get_size(state->param), /* num param. */
213 2, /* max returned param. */
214 data, /* data. */
215 data_len, /* num data. */
216 0); /* max returned data. */
218 if (tevent_req_nomem(subreq, req)) {
219 return tevent_req_post(req, ev);
221 tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
222 return req;
225 static void cli_setpathinfo_done(struct tevent_req *subreq)
227 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
228 NULL, 0, NULL, NULL, 0, NULL);
229 tevent_req_simple_finish_ntstatus(subreq, status);
232 NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
234 return tevent_req_simple_recv_ntstatus(req);
237 NTSTATUS cli_setpathinfo(struct cli_state *cli,
238 uint16_t level,
239 const char *path,
240 uint8_t *data,
241 size_t data_len)
243 TALLOC_CTX *frame = talloc_stackframe();
244 struct tevent_context *ev;
245 struct tevent_req *req;
246 NTSTATUS status = NT_STATUS_NO_MEMORY;
248 if (smbXcli_conn_has_async_calls(cli->conn)) {
250 * Can't use sync call while an async call is in flight
252 status = NT_STATUS_INVALID_PARAMETER;
253 goto fail;
255 ev = samba_tevent_context_init(frame);
256 if (ev == NULL) {
257 goto fail;
259 req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
260 if (req == NULL) {
261 goto fail;
263 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
264 goto fail;
266 status = cli_setpathinfo_recv(req);
267 fail:
268 TALLOC_FREE(frame);
269 return status;
272 /****************************************************************************
273 Hard/Symlink a file (UNIX extensions).
274 Creates new name (sym)linked to oldname.
275 ****************************************************************************/
277 struct cli_posix_link_internal_state {
278 uint8_t *data;
281 static void cli_posix_link_internal_done(struct tevent_req *subreq);
283 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
284 struct tevent_context *ev,
285 struct cli_state *cli,
286 uint16_t level,
287 const char *oldname,
288 const char *newname)
290 struct tevent_req *req = NULL, *subreq = NULL;
291 struct cli_posix_link_internal_state *state = NULL;
293 req = tevent_req_create(mem_ctx, &state,
294 struct cli_posix_link_internal_state);
295 if (req == NULL) {
296 return NULL;
299 /* Setup data array. */
300 state->data = talloc_array(state, uint8_t, 0);
301 if (tevent_req_nomem(state->data, req)) {
302 return tevent_req_post(req, ev);
304 state->data = trans2_bytes_push_str(
305 state->data, smbXcli_conn_use_unicode(cli->conn), oldname, strlen(oldname)+1, NULL);
307 subreq = cli_setpathinfo_send(
308 state, ev, cli, level, newname,
309 state->data, talloc_get_size(state->data));
310 if (tevent_req_nomem(subreq, req)) {
311 return tevent_req_post(req, ev);
313 tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
314 return req;
317 static void cli_posix_link_internal_done(struct tevent_req *subreq)
319 NTSTATUS status = cli_setpathinfo_recv(subreq);
320 tevent_req_simple_finish_ntstatus(subreq, status);
323 /****************************************************************************
324 Symlink a file (UNIX extensions).
325 ****************************************************************************/
327 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
328 struct tevent_context *ev,
329 struct cli_state *cli,
330 const char *oldname,
331 const char *newname)
333 return cli_posix_link_internal_send(
334 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, oldname, newname);
337 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
339 return tevent_req_simple_recv_ntstatus(req);
342 NTSTATUS cli_posix_symlink(struct cli_state *cli,
343 const char *oldname,
344 const char *newname)
346 TALLOC_CTX *frame = talloc_stackframe();
347 struct tevent_context *ev = NULL;
348 struct tevent_req *req = NULL;
349 NTSTATUS status = NT_STATUS_OK;
351 if (smbXcli_conn_has_async_calls(cli->conn)) {
353 * Can't use sync call while an async call is in flight
355 status = NT_STATUS_INVALID_PARAMETER;
356 goto fail;
359 ev = samba_tevent_context_init(frame);
360 if (ev == NULL) {
361 status = NT_STATUS_NO_MEMORY;
362 goto fail;
365 req = cli_posix_symlink_send(frame,
367 cli,
368 oldname,
369 newname);
370 if (req == NULL) {
371 status = NT_STATUS_NO_MEMORY;
372 goto fail;
375 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
376 goto fail;
379 status = cli_posix_symlink_recv(req);
381 fail:
382 TALLOC_FREE(frame);
383 return status;
386 /****************************************************************************
387 Read a POSIX symlink.
388 ****************************************************************************/
390 struct readlink_state {
391 uint8_t *data;
392 uint32_t num_data;
395 static void cli_posix_readlink_done(struct tevent_req *subreq);
397 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
398 struct tevent_context *ev,
399 struct cli_state *cli,
400 const char *fname,
401 size_t len)
403 struct tevent_req *req = NULL, *subreq = NULL;
404 struct readlink_state *state = NULL;
405 uint32_t maxbytelen = (uint32_t)(smbXcli_conn_use_unicode(cli->conn) ? len*3 : len);
407 req = tevent_req_create(mem_ctx, &state, struct readlink_state);
408 if (req == NULL) {
409 return NULL;
413 * Len is in bytes, we need it in UCS2 units.
415 if ((2*len < len) || (maxbytelen < len)) {
416 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
417 return tevent_req_post(req, ev);
420 subreq = cli_qpathinfo_send(state, ev, cli, fname,
421 SMB_QUERY_FILE_UNIX_LINK, 1, maxbytelen);
422 if (tevent_req_nomem(subreq, req)) {
423 return tevent_req_post(req, ev);
425 tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
426 return req;
429 static void cli_posix_readlink_done(struct tevent_req *subreq)
431 struct tevent_req *req = tevent_req_callback_data(
432 subreq, struct tevent_req);
433 struct readlink_state *state = tevent_req_data(
434 req, struct readlink_state);
435 NTSTATUS status;
437 status = cli_qpathinfo_recv(subreq, state, &state->data,
438 &state->num_data);
439 TALLOC_FREE(subreq);
440 if (tevent_req_nterror(req, status)) {
441 return;
444 * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
446 if (state->data[state->num_data-1] != '\0') {
447 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
448 return;
450 tevent_req_done(req);
453 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
454 char *retpath, size_t len)
456 NTSTATUS status;
457 char *converted = NULL;
458 size_t converted_size = 0;
459 struct readlink_state *state = tevent_req_data(req, struct readlink_state);
461 if (tevent_req_is_nterror(req, &status)) {
462 return status;
464 /* The returned data is a pushed string, not raw data. */
465 if (!convert_string_talloc(state,
466 smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
467 CH_UNIX,
468 state->data,
469 state->num_data,
470 &converted,
471 &converted_size)) {
472 return NT_STATUS_NO_MEMORY;
475 len = MIN(len,converted_size);
476 if (len == 0) {
477 return NT_STATUS_DATA_ERROR;
479 memcpy(retpath, converted, len);
480 return NT_STATUS_OK;
483 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
484 char *linkpath, size_t len)
486 TALLOC_CTX *frame = talloc_stackframe();
487 struct tevent_context *ev = NULL;
488 struct tevent_req *req = NULL;
489 NTSTATUS status = NT_STATUS_OK;
491 if (smbXcli_conn_has_async_calls(cli->conn)) {
493 * Can't use sync call while an async call is in flight
495 status = NT_STATUS_INVALID_PARAMETER;
496 goto fail;
499 ev = samba_tevent_context_init(frame);
500 if (ev == NULL) {
501 status = NT_STATUS_NO_MEMORY;
502 goto fail;
505 req = cli_posix_readlink_send(frame,
507 cli,
508 fname,
509 len);
510 if (req == NULL) {
511 status = NT_STATUS_NO_MEMORY;
512 goto fail;
515 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
516 goto fail;
519 status = cli_posix_readlink_recv(req, cli, linkpath, len);
521 fail:
522 TALLOC_FREE(frame);
523 return status;
526 /****************************************************************************
527 Hard link a file (UNIX extensions).
528 ****************************************************************************/
530 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
531 struct tevent_context *ev,
532 struct cli_state *cli,
533 const char *oldname,
534 const char *newname)
536 return cli_posix_link_internal_send(
537 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
540 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
542 return tevent_req_simple_recv_ntstatus(req);
545 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
546 const char *oldname,
547 const char *newname)
549 TALLOC_CTX *frame = talloc_stackframe();
550 struct tevent_context *ev = NULL;
551 struct tevent_req *req = NULL;
552 NTSTATUS status = NT_STATUS_OK;
554 if (smbXcli_conn_has_async_calls(cli->conn)) {
556 * Can't use sync call while an async call is in flight
558 status = NT_STATUS_INVALID_PARAMETER;
559 goto fail;
562 ev = samba_tevent_context_init(frame);
563 if (ev == NULL) {
564 status = NT_STATUS_NO_MEMORY;
565 goto fail;
568 req = cli_posix_hardlink_send(frame,
570 cli,
571 oldname,
572 newname);
573 if (req == NULL) {
574 status = NT_STATUS_NO_MEMORY;
575 goto fail;
578 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
579 goto fail;
582 status = cli_posix_hardlink_recv(req);
584 fail:
585 TALLOC_FREE(frame);
586 return status;
589 /****************************************************************************
590 Do a POSIX getacl - pathname based ACL get (UNIX extensions).
591 ****************************************************************************/
593 struct getacl_state {
594 uint32_t num_data;
595 uint8_t *data;
598 static void cli_posix_getacl_done(struct tevent_req *subreq);
600 struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
601 struct tevent_context *ev,
602 struct cli_state *cli,
603 const char *fname)
605 struct tevent_req *req = NULL, *subreq = NULL;
606 struct getacl_state *state = NULL;
608 req = tevent_req_create(mem_ctx, &state, struct getacl_state);
609 if (req == NULL) {
610 return NULL;
612 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
613 0, CLI_BUFFER_SIZE);
614 if (tevent_req_nomem(subreq, req)) {
615 return tevent_req_post(req, ev);
617 tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
618 return req;
621 static void cli_posix_getacl_done(struct tevent_req *subreq)
623 struct tevent_req *req = tevent_req_callback_data(
624 subreq, struct tevent_req);
625 struct getacl_state *state = tevent_req_data(
626 req, struct getacl_state);
627 NTSTATUS status;
629 status = cli_qpathinfo_recv(subreq, state, &state->data,
630 &state->num_data);
631 TALLOC_FREE(subreq);
632 if (tevent_req_nterror(req, status)) {
633 return;
635 tevent_req_done(req);
638 NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
639 TALLOC_CTX *mem_ctx,
640 size_t *prb_size,
641 char **retbuf)
643 struct getacl_state *state = tevent_req_data(req, struct getacl_state);
644 NTSTATUS status;
646 if (tevent_req_is_nterror(req, &status)) {
647 return status;
649 *prb_size = (size_t)state->num_data;
650 *retbuf = (char *)talloc_move(mem_ctx, &state->data);
651 return NT_STATUS_OK;
654 NTSTATUS cli_posix_getacl(struct cli_state *cli,
655 const char *fname,
656 TALLOC_CTX *mem_ctx,
657 size_t *prb_size,
658 char **retbuf)
660 TALLOC_CTX *frame = talloc_stackframe();
661 struct tevent_context *ev = NULL;
662 struct tevent_req *req = NULL;
663 NTSTATUS status = NT_STATUS_OK;
665 if (smbXcli_conn_has_async_calls(cli->conn)) {
667 * Can't use sync call while an async call is in flight
669 status = NT_STATUS_INVALID_PARAMETER;
670 goto fail;
673 ev = samba_tevent_context_init(frame);
674 if (ev == NULL) {
675 status = NT_STATUS_NO_MEMORY;
676 goto fail;
679 req = cli_posix_getacl_send(frame,
681 cli,
682 fname);
683 if (req == NULL) {
684 status = NT_STATUS_NO_MEMORY;
685 goto fail;
688 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
689 goto fail;
692 status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
694 fail:
695 TALLOC_FREE(frame);
696 return status;
699 /****************************************************************************
700 Do a POSIX setacl - pathname based ACL set (UNIX extensions).
701 ****************************************************************************/
703 struct setacl_state {
704 uint8_t *data;
707 static void cli_posix_setacl_done(struct tevent_req *subreq);
709 struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
710 struct tevent_context *ev,
711 struct cli_state *cli,
712 const char *fname,
713 const void *data,
714 size_t num_data)
716 struct tevent_req *req = NULL, *subreq = NULL;
717 struct setacl_state *state = NULL;
719 req = tevent_req_create(mem_ctx, &state, struct setacl_state);
720 if (req == NULL) {
721 return NULL;
723 state->data = talloc_memdup(state, data, num_data);
724 if (tevent_req_nomem(state->data, req)) {
725 return tevent_req_post(req, ev);
728 subreq = cli_setpathinfo_send(state,
730 cli,
731 SMB_SET_POSIX_ACL,
732 fname,
733 state->data,
734 num_data);
735 if (tevent_req_nomem(subreq, req)) {
736 return tevent_req_post(req, ev);
738 tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
739 return req;
742 static void cli_posix_setacl_done(struct tevent_req *subreq)
744 NTSTATUS status = cli_setpathinfo_recv(subreq);
745 tevent_req_simple_finish_ntstatus(subreq, status);
748 NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
750 return tevent_req_simple_recv_ntstatus(req);
753 NTSTATUS cli_posix_setacl(struct cli_state *cli,
754 const char *fname,
755 const void *acl_buf,
756 size_t acl_buf_size)
758 TALLOC_CTX *frame = talloc_stackframe();
759 struct tevent_context *ev = NULL;
760 struct tevent_req *req = NULL;
761 NTSTATUS status = NT_STATUS_OK;
763 if (smbXcli_conn_has_async_calls(cli->conn)) {
765 * Can't use sync call while an async call is in flight
767 status = NT_STATUS_INVALID_PARAMETER;
768 goto fail;
771 ev = samba_tevent_context_init(frame);
772 if (ev == NULL) {
773 status = NT_STATUS_NO_MEMORY;
774 goto fail;
777 req = cli_posix_setacl_send(frame,
779 cli,
780 fname,
781 acl_buf,
782 acl_buf_size);
783 if (req == NULL) {
784 status = NT_STATUS_NO_MEMORY;
785 goto fail;
788 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
789 goto fail;
792 status = cli_posix_setacl_recv(req);
794 fail:
795 TALLOC_FREE(frame);
796 return status;
799 /****************************************************************************
800 Stat a file (UNIX extensions).
801 ****************************************************************************/
803 struct stat_state {
804 uint32_t num_data;
805 uint8_t *data;
808 static void cli_posix_stat_done(struct tevent_req *subreq);
810 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
811 struct tevent_context *ev,
812 struct cli_state *cli,
813 const char *fname)
815 struct tevent_req *req = NULL, *subreq = NULL;
816 struct stat_state *state = NULL;
818 req = tevent_req_create(mem_ctx, &state, struct stat_state);
819 if (req == NULL) {
820 return NULL;
822 subreq = cli_qpathinfo_send(state, ev, cli, fname,
823 SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
824 if (tevent_req_nomem(subreq, req)) {
825 return tevent_req_post(req, ev);
827 tevent_req_set_callback(subreq, cli_posix_stat_done, req);
828 return req;
831 static void cli_posix_stat_done(struct tevent_req *subreq)
833 struct tevent_req *req = tevent_req_callback_data(
834 subreq, struct tevent_req);
835 struct stat_state *state = tevent_req_data(req, struct stat_state);
836 NTSTATUS status;
838 status = cli_qpathinfo_recv(subreq, state, &state->data,
839 &state->num_data);
840 TALLOC_FREE(subreq);
841 if (tevent_req_nterror(req, status)) {
842 return;
844 tevent_req_done(req);
847 NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
848 SMB_STRUCT_STAT *sbuf)
850 struct stat_state *state = tevent_req_data(req, struct stat_state);
851 NTSTATUS status;
853 if (tevent_req_is_nterror(req, &status)) {
854 return status;
857 sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0); /* total size, in bytes */
858 sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8); /* number of blocks allocated */
859 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
860 sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
861 #else
862 /* assume 512 byte blocks */
863 sbuf->st_ex_blocks /= 512;
864 #endif
865 sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16)); /* time of last change */
866 sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24)); /* time of last access */
867 sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32)); /* time of last modification */
869 sbuf->st_ex_uid = (uid_t) IVAL(state->data,40); /* user ID of owner */
870 sbuf->st_ex_gid = (gid_t) IVAL(state->data,48); /* group ID of owner */
871 sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
872 #if defined(HAVE_MAKEDEV)
874 uint32_t dev_major = IVAL(state->data,60);
875 uint32_t dev_minor = IVAL(state->data,68);
876 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
878 #endif
879 sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76); /* inode */
880 sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84)); /* protection */
881 sbuf->st_ex_nlink = BIG_UINT(state->data,92); /* number of hard links */
883 return NT_STATUS_OK;
886 NTSTATUS cli_posix_stat(struct cli_state *cli,
887 const char *fname,
888 SMB_STRUCT_STAT *sbuf)
890 TALLOC_CTX *frame = talloc_stackframe();
891 struct tevent_context *ev = NULL;
892 struct tevent_req *req = NULL;
893 NTSTATUS status = NT_STATUS_OK;
895 if (smbXcli_conn_has_async_calls(cli->conn)) {
897 * Can't use sync call while an async call is in flight
899 status = NT_STATUS_INVALID_PARAMETER;
900 goto fail;
903 ev = samba_tevent_context_init(frame);
904 if (ev == NULL) {
905 status = NT_STATUS_NO_MEMORY;
906 goto fail;
909 req = cli_posix_stat_send(frame,
911 cli,
912 fname);
913 if (req == NULL) {
914 status = NT_STATUS_NO_MEMORY;
915 goto fail;
918 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
919 goto fail;
922 status = cli_posix_stat_recv(req, sbuf);
924 fail:
925 TALLOC_FREE(frame);
926 return status;
929 /****************************************************************************
930 Chmod or chown a file internal (UNIX extensions).
931 ****************************************************************************/
933 struct cli_posix_chown_chmod_internal_state {
934 uint8_t data[100];
937 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
939 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
940 struct tevent_context *ev,
941 struct cli_state *cli,
942 const char *fname,
943 uint32_t mode,
944 uint32_t uid,
945 uint32_t gid)
947 struct tevent_req *req = NULL, *subreq = NULL;
948 struct cli_posix_chown_chmod_internal_state *state = NULL;
950 req = tevent_req_create(mem_ctx, &state,
951 struct cli_posix_chown_chmod_internal_state);
952 if (req == NULL) {
953 return NULL;
956 memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
957 memset(&state->data[40], '\0', 60);
958 SIVAL(state->data,40,uid);
959 SIVAL(state->data,48,gid);
960 SIVAL(state->data,84,mode);
962 subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
963 fname, state->data, sizeof(state->data));
964 if (tevent_req_nomem(subreq, req)) {
965 return tevent_req_post(req, ev);
967 tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
968 req);
969 return req;
972 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
974 NTSTATUS status = cli_setpathinfo_recv(subreq);
975 tevent_req_simple_finish_ntstatus(subreq, status);
978 /****************************************************************************
979 chmod a file (UNIX extensions).
980 ****************************************************************************/
982 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
983 struct tevent_context *ev,
984 struct cli_state *cli,
985 const char *fname,
986 mode_t mode)
988 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
989 fname,
990 unix_perms_to_wire(mode),
991 SMB_UID_NO_CHANGE,
992 SMB_GID_NO_CHANGE);
995 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
997 return tevent_req_simple_recv_ntstatus(req);
1000 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
1002 TALLOC_CTX *frame = talloc_stackframe();
1003 struct tevent_context *ev = NULL;
1004 struct tevent_req *req = NULL;
1005 NTSTATUS status = NT_STATUS_OK;
1007 if (smbXcli_conn_has_async_calls(cli->conn)) {
1009 * Can't use sync call while an async call is in flight
1011 status = NT_STATUS_INVALID_PARAMETER;
1012 goto fail;
1015 ev = samba_tevent_context_init(frame);
1016 if (ev == NULL) {
1017 status = NT_STATUS_NO_MEMORY;
1018 goto fail;
1021 req = cli_posix_chmod_send(frame,
1023 cli,
1024 fname,
1025 mode);
1026 if (req == NULL) {
1027 status = NT_STATUS_NO_MEMORY;
1028 goto fail;
1031 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1032 goto fail;
1035 status = cli_posix_chmod_recv(req);
1037 fail:
1038 TALLOC_FREE(frame);
1039 return status;
1042 /****************************************************************************
1043 chown a file (UNIX extensions).
1044 ****************************************************************************/
1046 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1047 struct tevent_context *ev,
1048 struct cli_state *cli,
1049 const char *fname,
1050 uid_t uid,
1051 gid_t gid)
1053 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
1054 fname,
1055 SMB_MODE_NO_CHANGE,
1056 (uint32_t)uid,
1057 (uint32_t)gid);
1060 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1062 return tevent_req_simple_recv_ntstatus(req);
1065 NTSTATUS cli_posix_chown(struct cli_state *cli,
1066 const char *fname,
1067 uid_t uid,
1068 gid_t gid)
1070 TALLOC_CTX *frame = talloc_stackframe();
1071 struct tevent_context *ev = NULL;
1072 struct tevent_req *req = NULL;
1073 NTSTATUS status = NT_STATUS_OK;
1075 if (smbXcli_conn_has_async_calls(cli->conn)) {
1077 * Can't use sync call while an async call is in flight
1079 status = NT_STATUS_INVALID_PARAMETER;
1080 goto fail;
1083 ev = samba_tevent_context_init(frame);
1084 if (ev == NULL) {
1085 status = NT_STATUS_NO_MEMORY;
1086 goto fail;
1089 req = cli_posix_chown_send(frame,
1091 cli,
1092 fname,
1093 uid,
1094 gid);
1095 if (req == NULL) {
1096 status = NT_STATUS_NO_MEMORY;
1097 goto fail;
1100 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1101 goto fail;
1104 status = cli_posix_chown_recv(req);
1106 fail:
1107 TALLOC_FREE(frame);
1108 return status;
1111 /****************************************************************************
1112 Rename a file.
1113 ****************************************************************************/
1115 static void cli_rename_done(struct tevent_req *subreq);
1117 struct cli_rename_state {
1118 uint16_t vwv[1];
1121 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1122 struct tevent_context *ev,
1123 struct cli_state *cli,
1124 const char *fname_src,
1125 const char *fname_dst)
1127 struct tevent_req *req = NULL, *subreq = NULL;
1128 struct cli_rename_state *state = NULL;
1129 uint8_t additional_flags = 0;
1130 uint8_t *bytes = NULL;
1132 req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1133 if (req == NULL) {
1134 return NULL;
1137 SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1139 bytes = talloc_array(state, uint8_t, 1);
1140 if (tevent_req_nomem(bytes, req)) {
1141 return tevent_req_post(req, ev);
1143 bytes[0] = 4;
1144 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1145 strlen(fname_src)+1, NULL);
1146 if (tevent_req_nomem(bytes, req)) {
1147 return tevent_req_post(req, ev);
1150 bytes = talloc_realloc(state, bytes, uint8_t,
1151 talloc_get_size(bytes)+1);
1152 if (tevent_req_nomem(bytes, req)) {
1153 return tevent_req_post(req, ev);
1156 bytes[talloc_get_size(bytes)-1] = 4;
1157 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1158 strlen(fname_dst)+1, NULL);
1159 if (tevent_req_nomem(bytes, req)) {
1160 return tevent_req_post(req, ev);
1163 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1164 1, state->vwv, talloc_get_size(bytes), bytes);
1165 if (tevent_req_nomem(subreq, req)) {
1166 return tevent_req_post(req, ev);
1168 tevent_req_set_callback(subreq, cli_rename_done, req);
1169 return req;
1172 static void cli_rename_done(struct tevent_req *subreq)
1174 struct tevent_req *req = tevent_req_callback_data(
1175 subreq, struct tevent_req);
1176 NTSTATUS status;
1178 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1179 TALLOC_FREE(subreq);
1180 if (tevent_req_nterror(req, status)) {
1181 return;
1183 tevent_req_done(req);
1186 NTSTATUS cli_rename_recv(struct tevent_req *req)
1188 return tevent_req_simple_recv_ntstatus(req);
1191 NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1193 TALLOC_CTX *frame = NULL;
1194 struct tevent_context *ev;
1195 struct tevent_req *req;
1196 NTSTATUS status = NT_STATUS_OK;
1198 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1199 return cli_smb2_rename(cli,
1200 fname_src,
1201 fname_dst);
1204 frame = talloc_stackframe();
1206 if (smbXcli_conn_has_async_calls(cli->conn)) {
1208 * Can't use sync call while an async call is in flight
1210 status = NT_STATUS_INVALID_PARAMETER;
1211 goto fail;
1214 ev = samba_tevent_context_init(frame);
1215 if (ev == NULL) {
1216 status = NT_STATUS_NO_MEMORY;
1217 goto fail;
1220 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
1221 if (req == NULL) {
1222 status = NT_STATUS_NO_MEMORY;
1223 goto fail;
1226 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1227 goto fail;
1230 status = cli_rename_recv(req);
1232 fail:
1233 TALLOC_FREE(frame);
1234 return status;
1237 /****************************************************************************
1238 NT Rename a file.
1239 ****************************************************************************/
1241 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1243 struct cli_ntrename_internal_state {
1244 uint16_t vwv[4];
1247 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1248 struct tevent_context *ev,
1249 struct cli_state *cli,
1250 const char *fname_src,
1251 const char *fname_dst,
1252 uint16_t rename_flag)
1254 struct tevent_req *req = NULL, *subreq = NULL;
1255 struct cli_ntrename_internal_state *state = NULL;
1256 uint8_t additional_flags = 0;
1257 uint8_t *bytes = NULL;
1259 req = tevent_req_create(mem_ctx, &state,
1260 struct cli_ntrename_internal_state);
1261 if (req == NULL) {
1262 return NULL;
1265 SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1266 SSVAL(state->vwv+1, 0, rename_flag);
1268 bytes = talloc_array(state, uint8_t, 1);
1269 if (tevent_req_nomem(bytes, req)) {
1270 return tevent_req_post(req, ev);
1272 bytes[0] = 4;
1273 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1274 strlen(fname_src)+1, NULL);
1275 if (tevent_req_nomem(bytes, req)) {
1276 return tevent_req_post(req, ev);
1279 bytes = talloc_realloc(state, bytes, uint8_t,
1280 talloc_get_size(bytes)+1);
1281 if (tevent_req_nomem(bytes, req)) {
1282 return tevent_req_post(req, ev);
1285 bytes[talloc_get_size(bytes)-1] = 4;
1286 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1287 strlen(fname_dst)+1, NULL);
1288 if (tevent_req_nomem(bytes, req)) {
1289 return tevent_req_post(req, ev);
1292 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1293 4, state->vwv, talloc_get_size(bytes), bytes);
1294 if (tevent_req_nomem(subreq, req)) {
1295 return tevent_req_post(req, ev);
1297 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1298 return req;
1301 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1303 struct tevent_req *req = tevent_req_callback_data(
1304 subreq, struct tevent_req);
1305 NTSTATUS status;
1307 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1308 TALLOC_FREE(subreq);
1309 if (tevent_req_nterror(req, status)) {
1310 return;
1312 tevent_req_done(req);
1315 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1317 return tevent_req_simple_recv_ntstatus(req);
1320 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1321 struct tevent_context *ev,
1322 struct cli_state *cli,
1323 const char *fname_src,
1324 const char *fname_dst)
1326 return cli_ntrename_internal_send(mem_ctx,
1328 cli,
1329 fname_src,
1330 fname_dst,
1331 RENAME_FLAG_RENAME);
1334 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1336 return cli_ntrename_internal_recv(req);
1339 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1341 TALLOC_CTX *frame = talloc_stackframe();
1342 struct tevent_context *ev;
1343 struct tevent_req *req;
1344 NTSTATUS status = NT_STATUS_OK;
1346 if (smbXcli_conn_has_async_calls(cli->conn)) {
1348 * Can't use sync call while an async call is in flight
1350 status = NT_STATUS_INVALID_PARAMETER;
1351 goto fail;
1354 ev = samba_tevent_context_init(frame);
1355 if (ev == NULL) {
1356 status = NT_STATUS_NO_MEMORY;
1357 goto fail;
1360 req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1361 if (req == NULL) {
1362 status = NT_STATUS_NO_MEMORY;
1363 goto fail;
1366 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1367 goto fail;
1370 status = cli_ntrename_recv(req);
1372 fail:
1373 TALLOC_FREE(frame);
1374 return status;
1377 /****************************************************************************
1378 NT hardlink a file.
1379 ****************************************************************************/
1381 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1382 struct tevent_context *ev,
1383 struct cli_state *cli,
1384 const char *fname_src,
1385 const char *fname_dst)
1387 return cli_ntrename_internal_send(mem_ctx,
1389 cli,
1390 fname_src,
1391 fname_dst,
1392 RENAME_FLAG_HARD_LINK);
1395 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1397 return cli_ntrename_internal_recv(req);
1400 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1402 TALLOC_CTX *frame = talloc_stackframe();
1403 struct tevent_context *ev;
1404 struct tevent_req *req;
1405 NTSTATUS status = NT_STATUS_OK;
1407 if (smbXcli_conn_has_async_calls(cli->conn)) {
1409 * Can't use sync call while an async call is in flight
1411 status = NT_STATUS_INVALID_PARAMETER;
1412 goto fail;
1415 ev = samba_tevent_context_init(frame);
1416 if (ev == NULL) {
1417 status = NT_STATUS_NO_MEMORY;
1418 goto fail;
1421 req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1422 if (req == NULL) {
1423 status = NT_STATUS_NO_MEMORY;
1424 goto fail;
1427 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1428 goto fail;
1431 status = cli_nt_hardlink_recv(req);
1433 fail:
1434 TALLOC_FREE(frame);
1435 return status;
1438 /****************************************************************************
1439 Delete a file.
1440 ****************************************************************************/
1442 static void cli_unlink_done(struct tevent_req *subreq);
1444 struct cli_unlink_state {
1445 uint16_t vwv[1];
1448 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1449 struct tevent_context *ev,
1450 struct cli_state *cli,
1451 const char *fname,
1452 uint16_t mayhave_attrs)
1454 struct tevent_req *req = NULL, *subreq = NULL;
1455 struct cli_unlink_state *state = NULL;
1456 uint8_t additional_flags = 0;
1457 uint8_t *bytes = NULL;
1459 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1460 if (req == NULL) {
1461 return NULL;
1464 SSVAL(state->vwv+0, 0, mayhave_attrs);
1466 bytes = talloc_array(state, uint8_t, 1);
1467 if (tevent_req_nomem(bytes, req)) {
1468 return tevent_req_post(req, ev);
1470 bytes[0] = 4;
1471 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
1472 strlen(fname)+1, NULL);
1474 if (tevent_req_nomem(bytes, req)) {
1475 return tevent_req_post(req, ev);
1478 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1479 1, state->vwv, talloc_get_size(bytes), bytes);
1480 if (tevent_req_nomem(subreq, req)) {
1481 return tevent_req_post(req, ev);
1483 tevent_req_set_callback(subreq, cli_unlink_done, req);
1484 return req;
1487 static void cli_unlink_done(struct tevent_req *subreq)
1489 struct tevent_req *req = tevent_req_callback_data(
1490 subreq, struct tevent_req);
1491 NTSTATUS status;
1493 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1494 TALLOC_FREE(subreq);
1495 if (tevent_req_nterror(req, status)) {
1496 return;
1498 tevent_req_done(req);
1501 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1503 return tevent_req_simple_recv_ntstatus(req);
1506 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1508 TALLOC_CTX *frame = NULL;
1509 struct tevent_context *ev;
1510 struct tevent_req *req;
1511 NTSTATUS status = NT_STATUS_OK;
1513 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1514 return cli_smb2_unlink(cli, fname);
1517 frame = talloc_stackframe();
1519 if (smbXcli_conn_has_async_calls(cli->conn)) {
1521 * Can't use sync call while an async call is in flight
1523 status = NT_STATUS_INVALID_PARAMETER;
1524 goto fail;
1527 ev = samba_tevent_context_init(frame);
1528 if (ev == NULL) {
1529 status = NT_STATUS_NO_MEMORY;
1530 goto fail;
1533 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1534 if (req == NULL) {
1535 status = NT_STATUS_NO_MEMORY;
1536 goto fail;
1539 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1540 goto fail;
1543 status = cli_unlink_recv(req);
1545 fail:
1546 TALLOC_FREE(frame);
1547 return status;
1550 /****************************************************************************
1551 Create a directory.
1552 ****************************************************************************/
1554 static void cli_mkdir_done(struct tevent_req *subreq);
1556 struct cli_mkdir_state {
1557 int dummy;
1560 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1561 struct tevent_context *ev,
1562 struct cli_state *cli,
1563 const char *dname)
1565 struct tevent_req *req = NULL, *subreq = NULL;
1566 struct cli_mkdir_state *state = NULL;
1567 uint8_t additional_flags = 0;
1568 uint8_t *bytes = NULL;
1570 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1571 if (req == NULL) {
1572 return NULL;
1575 bytes = talloc_array(state, uint8_t, 1);
1576 if (tevent_req_nomem(bytes, req)) {
1577 return tevent_req_post(req, ev);
1579 bytes[0] = 4;
1580 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1581 strlen(dname)+1, NULL);
1583 if (tevent_req_nomem(bytes, req)) {
1584 return tevent_req_post(req, ev);
1587 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1588 0, NULL, talloc_get_size(bytes), bytes);
1589 if (tevent_req_nomem(subreq, req)) {
1590 return tevent_req_post(req, ev);
1592 tevent_req_set_callback(subreq, cli_mkdir_done, req);
1593 return req;
1596 static void cli_mkdir_done(struct tevent_req *subreq)
1598 struct tevent_req *req = tevent_req_callback_data(
1599 subreq, struct tevent_req);
1600 NTSTATUS status;
1602 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1603 TALLOC_FREE(subreq);
1604 if (tevent_req_nterror(req, status)) {
1605 return;
1607 tevent_req_done(req);
1610 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1612 return tevent_req_simple_recv_ntstatus(req);
1615 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1617 TALLOC_CTX *frame = NULL;
1618 struct tevent_context *ev;
1619 struct tevent_req *req;
1620 NTSTATUS status = NT_STATUS_OK;
1622 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1623 return cli_smb2_mkdir(cli, dname);
1626 frame = talloc_stackframe();
1628 if (smbXcli_conn_has_async_calls(cli->conn)) {
1630 * Can't use sync call while an async call is in flight
1632 status = NT_STATUS_INVALID_PARAMETER;
1633 goto fail;
1636 ev = samba_tevent_context_init(frame);
1637 if (ev == NULL) {
1638 status = NT_STATUS_NO_MEMORY;
1639 goto fail;
1642 req = cli_mkdir_send(frame, ev, cli, dname);
1643 if (req == NULL) {
1644 status = NT_STATUS_NO_MEMORY;
1645 goto fail;
1648 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1649 goto fail;
1652 status = cli_mkdir_recv(req);
1654 fail:
1655 TALLOC_FREE(frame);
1656 return status;
1659 /****************************************************************************
1660 Remove a directory.
1661 ****************************************************************************/
1663 static void cli_rmdir_done(struct tevent_req *subreq);
1665 struct cli_rmdir_state {
1666 int dummy;
1669 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1670 struct tevent_context *ev,
1671 struct cli_state *cli,
1672 const char *dname)
1674 struct tevent_req *req = NULL, *subreq = NULL;
1675 struct cli_rmdir_state *state = NULL;
1676 uint8_t additional_flags = 0;
1677 uint8_t *bytes = NULL;
1679 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1680 if (req == NULL) {
1681 return NULL;
1684 bytes = talloc_array(state, uint8_t, 1);
1685 if (tevent_req_nomem(bytes, req)) {
1686 return tevent_req_post(req, ev);
1688 bytes[0] = 4;
1689 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1690 strlen(dname)+1, NULL);
1692 if (tevent_req_nomem(bytes, req)) {
1693 return tevent_req_post(req, ev);
1696 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1697 0, NULL, talloc_get_size(bytes), bytes);
1698 if (tevent_req_nomem(subreq, req)) {
1699 return tevent_req_post(req, ev);
1701 tevent_req_set_callback(subreq, cli_rmdir_done, req);
1702 return req;
1705 static void cli_rmdir_done(struct tevent_req *subreq)
1707 struct tevent_req *req = tevent_req_callback_data(
1708 subreq, struct tevent_req);
1709 NTSTATUS status;
1711 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1712 TALLOC_FREE(subreq);
1713 if (tevent_req_nterror(req, status)) {
1714 return;
1716 tevent_req_done(req);
1719 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1721 return tevent_req_simple_recv_ntstatus(req);
1724 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1726 TALLOC_CTX *frame = NULL;
1727 struct tevent_context *ev;
1728 struct tevent_req *req;
1729 NTSTATUS status = NT_STATUS_OK;
1731 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1732 return cli_smb2_rmdir(cli, dname);
1735 frame = talloc_stackframe();
1737 if (smbXcli_conn_has_async_calls(cli->conn)) {
1739 * Can't use sync call while an async call is in flight
1741 status = NT_STATUS_INVALID_PARAMETER;
1742 goto fail;
1745 ev = samba_tevent_context_init(frame);
1746 if (ev == NULL) {
1747 status = NT_STATUS_NO_MEMORY;
1748 goto fail;
1751 req = cli_rmdir_send(frame, ev, cli, dname);
1752 if (req == NULL) {
1753 status = NT_STATUS_NO_MEMORY;
1754 goto fail;
1757 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1758 goto fail;
1761 status = cli_rmdir_recv(req);
1763 fail:
1764 TALLOC_FREE(frame);
1765 return status;
1768 /****************************************************************************
1769 Set or clear the delete on close flag.
1770 ****************************************************************************/
1772 struct doc_state {
1773 uint16_t setup;
1774 uint8_t param[6];
1775 uint8_t data[1];
1778 static void cli_nt_delete_on_close_done(struct tevent_req *subreq)
1780 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
1781 NULL, 0, NULL, NULL, 0, NULL);
1782 tevent_req_simple_finish_ntstatus(subreq, status);
1785 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1786 struct tevent_context *ev,
1787 struct cli_state *cli,
1788 uint16_t fnum,
1789 bool flag)
1791 struct tevent_req *req = NULL, *subreq = NULL;
1792 struct doc_state *state = NULL;
1794 req = tevent_req_create(mem_ctx, &state, struct doc_state);
1795 if (req == NULL) {
1796 return NULL;
1799 /* Setup setup word. */
1800 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1802 /* Setup param array. */
1803 SSVAL(state->param,0,fnum);
1804 SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1806 /* Setup data array. */
1807 SCVAL(&state->data[0], 0, flag ? 1 : 0);
1809 subreq = cli_trans_send(state, /* mem ctx. */
1810 ev, /* event ctx. */
1811 cli, /* cli_state. */
1812 SMBtrans2, /* cmd. */
1813 NULL, /* pipe name. */
1814 -1, /* fid. */
1815 0, /* function. */
1816 0, /* flags. */
1817 &state->setup, /* setup. */
1818 1, /* num setup uint16_t words. */
1819 0, /* max returned setup. */
1820 state->param, /* param. */
1821 6, /* num param. */
1822 2, /* max returned param. */
1823 state->data, /* data. */
1824 1, /* num data. */
1825 0); /* max returned data. */
1827 if (tevent_req_nomem(subreq, req)) {
1828 return tevent_req_post(req, ev);
1830 tevent_req_set_callback(subreq, cli_nt_delete_on_close_done, req);
1831 return req;
1834 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1836 return tevent_req_simple_recv_ntstatus(req);
1839 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1841 TALLOC_CTX *frame = talloc_stackframe();
1842 struct tevent_context *ev = NULL;
1843 struct tevent_req *req = NULL;
1844 NTSTATUS status = NT_STATUS_OK;
1846 if (smbXcli_conn_has_async_calls(cli->conn)) {
1848 * Can't use sync call while an async call is in flight
1850 status = NT_STATUS_INVALID_PARAMETER;
1851 goto fail;
1854 ev = samba_tevent_context_init(frame);
1855 if (ev == NULL) {
1856 status = NT_STATUS_NO_MEMORY;
1857 goto fail;
1860 req = cli_nt_delete_on_close_send(frame,
1862 cli,
1863 fnum,
1864 flag);
1865 if (req == NULL) {
1866 status = NT_STATUS_NO_MEMORY;
1867 goto fail;
1870 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1871 goto fail;
1874 status = cli_nt_delete_on_close_recv(req);
1876 fail:
1877 TALLOC_FREE(frame);
1878 return status;
1881 struct cli_ntcreate1_state {
1882 uint16_t vwv[24];
1883 uint16_t fnum;
1884 struct smb_create_returns cr;
1885 struct tevent_req *subreq;
1888 static void cli_ntcreate1_done(struct tevent_req *subreq);
1889 static bool cli_ntcreate1_cancel(struct tevent_req *req);
1891 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
1892 struct tevent_context *ev,
1893 struct cli_state *cli,
1894 const char *fname,
1895 uint32_t CreatFlags,
1896 uint32_t DesiredAccess,
1897 uint32_t FileAttributes,
1898 uint32_t ShareAccess,
1899 uint32_t CreateDisposition,
1900 uint32_t CreateOptions,
1901 uint8_t SecurityFlags)
1903 struct tevent_req *req, *subreq;
1904 struct cli_ntcreate1_state *state;
1905 uint16_t *vwv;
1906 uint8_t *bytes;
1907 size_t converted_len;
1909 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
1910 if (req == NULL) {
1911 return NULL;
1914 vwv = state->vwv;
1916 SCVAL(vwv+0, 0, 0xFF);
1917 SCVAL(vwv+0, 1, 0);
1918 SSVAL(vwv+1, 0, 0);
1919 SCVAL(vwv+2, 0, 0);
1921 if (cli->use_oplocks) {
1922 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1924 SIVAL(vwv+3, 1, CreatFlags);
1925 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
1926 SIVAL(vwv+7, 1, DesiredAccess);
1927 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
1928 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
1929 SIVAL(vwv+13, 1, FileAttributes);
1930 SIVAL(vwv+15, 1, ShareAccess);
1931 SIVAL(vwv+17, 1, CreateDisposition);
1932 SIVAL(vwv+19, 1, CreateOptions |
1933 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
1934 SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1935 SCVAL(vwv+23, 1, SecurityFlags);
1937 bytes = talloc_array(state, uint8_t, 0);
1938 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
1939 fname, strlen(fname)+1,
1940 &converted_len);
1942 /* sigh. this copes with broken netapp filer behaviour */
1943 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
1945 if (tevent_req_nomem(bytes, req)) {
1946 return tevent_req_post(req, ev);
1949 SSVAL(vwv+2, 1, converted_len);
1951 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
1952 talloc_get_size(bytes), bytes);
1953 if (tevent_req_nomem(subreq, req)) {
1954 return tevent_req_post(req, ev);
1956 tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
1958 state->subreq = subreq;
1959 tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
1961 return req;
1964 static void cli_ntcreate1_done(struct tevent_req *subreq)
1966 struct tevent_req *req = tevent_req_callback_data(
1967 subreq, struct tevent_req);
1968 struct cli_ntcreate1_state *state = tevent_req_data(
1969 req, struct cli_ntcreate1_state);
1970 uint8_t wct;
1971 uint16_t *vwv;
1972 uint32_t num_bytes;
1973 uint8_t *bytes;
1974 NTSTATUS status;
1976 status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
1977 &num_bytes, &bytes);
1978 TALLOC_FREE(subreq);
1979 if (tevent_req_nterror(req, status)) {
1980 return;
1982 state->cr.oplock_level = CVAL(vwv+2, 0);
1983 state->fnum = SVAL(vwv+2, 1);
1984 state->cr.create_action = IVAL(vwv+3, 1);
1985 state->cr.creation_time = BVAL(vwv+5, 1);
1986 state->cr.last_access_time = BVAL(vwv+9, 1);
1987 state->cr.last_write_time = BVAL(vwv+13, 1);
1988 state->cr.change_time = BVAL(vwv+17, 1);
1989 state->cr.file_attributes = IVAL(vwv+21, 1);
1990 state->cr.allocation_size = BVAL(vwv+23, 1);
1991 state->cr.end_of_file = BVAL(vwv+27, 1);
1993 tevent_req_done(req);
1996 static bool cli_ntcreate1_cancel(struct tevent_req *req)
1998 struct cli_ntcreate1_state *state = tevent_req_data(
1999 req, struct cli_ntcreate1_state);
2000 return tevent_req_cancel(state->subreq);
2003 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2004 uint16_t *pfnum,
2005 struct smb_create_returns *cr)
2007 struct cli_ntcreate1_state *state = tevent_req_data(
2008 req, struct cli_ntcreate1_state);
2009 NTSTATUS status;
2011 if (tevent_req_is_nterror(req, &status)) {
2012 return status;
2014 *pfnum = state->fnum;
2015 if (cr != NULL) {
2016 *cr = state->cr;
2018 return NT_STATUS_OK;
2021 struct cli_ntcreate_state {
2022 NTSTATUS (*recv)(struct tevent_req *req, uint16_t *fnum,
2023 struct smb_create_returns *cr);
2024 struct smb_create_returns cr;
2025 uint16_t fnum;
2026 struct tevent_req *subreq;
2029 static void cli_ntcreate_done(struct tevent_req *subreq);
2030 static bool cli_ntcreate_cancel(struct tevent_req *req);
2032 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
2033 struct tevent_context *ev,
2034 struct cli_state *cli,
2035 const char *fname,
2036 uint32_t create_flags,
2037 uint32_t desired_access,
2038 uint32_t file_attributes,
2039 uint32_t share_access,
2040 uint32_t create_disposition,
2041 uint32_t create_options,
2042 uint8_t security_flags)
2044 struct tevent_req *req, *subreq;
2045 struct cli_ntcreate_state *state;
2047 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2048 if (req == NULL) {
2049 return NULL;
2052 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2053 state->recv = cli_smb2_create_fnum_recv;
2055 if (cli->use_oplocks) {
2056 create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2059 subreq = cli_smb2_create_fnum_send(
2060 state, ev, cli, fname, create_flags, desired_access,
2061 file_attributes, share_access, create_disposition,
2062 create_options);
2063 } else {
2064 state->recv = cli_ntcreate1_recv;
2065 subreq = cli_ntcreate1_send(
2066 state, ev, cli, fname, create_flags, desired_access,
2067 file_attributes, share_access, create_disposition,
2068 create_options, security_flags);
2070 if (tevent_req_nomem(subreq, req)) {
2071 return tevent_req_post(req, ev);
2073 tevent_req_set_callback(subreq, cli_ntcreate_done, req);
2075 state->subreq = subreq;
2076 tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2078 return req;
2081 static void cli_ntcreate_done(struct tevent_req *subreq)
2083 struct tevent_req *req = tevent_req_callback_data(
2084 subreq, struct tevent_req);
2085 struct cli_ntcreate_state *state = tevent_req_data(
2086 req, struct cli_ntcreate_state);
2087 NTSTATUS status;
2089 status = state->recv(subreq, &state->fnum, &state->cr);
2090 TALLOC_FREE(subreq);
2091 if (tevent_req_nterror(req, status)) {
2092 return;
2094 tevent_req_done(req);
2097 static bool cli_ntcreate_cancel(struct tevent_req *req)
2099 struct cli_ntcreate_state *state = tevent_req_data(
2100 req, struct cli_ntcreate_state);
2101 return tevent_req_cancel(state->subreq);
2104 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2105 struct smb_create_returns *cr)
2107 struct cli_ntcreate_state *state = tevent_req_data(
2108 req, struct cli_ntcreate_state);
2109 NTSTATUS status;
2111 if (tevent_req_is_nterror(req, &status)) {
2112 return status;
2114 if (fnum != NULL) {
2115 *fnum = state->fnum;
2117 if (cr != NULL) {
2118 *cr = state->cr;
2120 return NT_STATUS_OK;
2123 NTSTATUS cli_ntcreate(struct cli_state *cli,
2124 const char *fname,
2125 uint32_t CreatFlags,
2126 uint32_t DesiredAccess,
2127 uint32_t FileAttributes,
2128 uint32_t ShareAccess,
2129 uint32_t CreateDisposition,
2130 uint32_t CreateOptions,
2131 uint8_t SecurityFlags,
2132 uint16_t *pfid,
2133 struct smb_create_returns *cr)
2135 TALLOC_CTX *frame = talloc_stackframe();
2136 struct tevent_context *ev;
2137 struct tevent_req *req;
2138 NTSTATUS status = NT_STATUS_NO_MEMORY;
2140 if (smbXcli_conn_has_async_calls(cli->conn)) {
2142 * Can't use sync call while an async call is in flight
2144 status = NT_STATUS_INVALID_PARAMETER;
2145 goto fail;
2148 ev = samba_tevent_context_init(frame);
2149 if (ev == NULL) {
2150 goto fail;
2153 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2154 DesiredAccess, FileAttributes, ShareAccess,
2155 CreateDisposition, CreateOptions,
2156 SecurityFlags);
2157 if (req == NULL) {
2158 goto fail;
2161 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2162 goto fail;
2165 status = cli_ntcreate_recv(req, pfid, cr);
2166 fail:
2167 TALLOC_FREE(frame);
2168 return status;
2171 struct cli_nttrans_create_state {
2172 uint16_t fnum;
2173 struct smb_create_returns cr;
2176 static void cli_nttrans_create_done(struct tevent_req *subreq);
2178 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2179 struct tevent_context *ev,
2180 struct cli_state *cli,
2181 const char *fname,
2182 uint32_t CreatFlags,
2183 uint32_t DesiredAccess,
2184 uint32_t FileAttributes,
2185 uint32_t ShareAccess,
2186 uint32_t CreateDisposition,
2187 uint32_t CreateOptions,
2188 uint8_t SecurityFlags,
2189 struct security_descriptor *secdesc,
2190 struct ea_struct *eas,
2191 int num_eas)
2193 struct tevent_req *req, *subreq;
2194 struct cli_nttrans_create_state *state;
2195 uint8_t *param;
2196 uint8_t *secdesc_buf;
2197 size_t secdesc_len;
2198 NTSTATUS status;
2199 size_t converted_len;
2201 req = tevent_req_create(mem_ctx,
2202 &state, struct cli_nttrans_create_state);
2203 if (req == NULL) {
2204 return NULL;
2207 if (secdesc != NULL) {
2208 status = marshall_sec_desc(talloc_tos(), secdesc,
2209 &secdesc_buf, &secdesc_len);
2210 if (tevent_req_nterror(req, status)) {
2211 DEBUG(10, ("marshall_sec_desc failed: %s\n",
2212 nt_errstr(status)));
2213 return tevent_req_post(req, ev);
2215 } else {
2216 secdesc_buf = NULL;
2217 secdesc_len = 0;
2220 if (num_eas != 0) {
2222 * TODO ;-)
2224 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2225 return tevent_req_post(req, ev);
2228 param = talloc_array(state, uint8_t, 53);
2229 if (tevent_req_nomem(param, req)) {
2230 return tevent_req_post(req, ev);
2233 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2234 fname, strlen(fname),
2235 &converted_len);
2236 if (tevent_req_nomem(param, req)) {
2237 return tevent_req_post(req, ev);
2240 SIVAL(param, 0, CreatFlags);
2241 SIVAL(param, 4, 0x0); /* RootDirectoryFid */
2242 SIVAL(param, 8, DesiredAccess);
2243 SIVAL(param, 12, 0x0); /* AllocationSize */
2244 SIVAL(param, 16, 0x0); /* AllocationSize */
2245 SIVAL(param, 20, FileAttributes);
2246 SIVAL(param, 24, ShareAccess);
2247 SIVAL(param, 28, CreateDisposition);
2248 SIVAL(param, 32, CreateOptions |
2249 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2250 SIVAL(param, 36, secdesc_len);
2251 SIVAL(param, 40, 0); /* EA length*/
2252 SIVAL(param, 44, converted_len);
2253 SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2254 SCVAL(param, 52, SecurityFlags);
2256 subreq = cli_trans_send(state, ev, cli, SMBnttrans,
2257 NULL, -1, /* name, fid */
2258 NT_TRANSACT_CREATE, 0,
2259 NULL, 0, 0, /* setup */
2260 param, talloc_get_size(param), 128, /* param */
2261 secdesc_buf, secdesc_len, 0); /* data */
2262 if (tevent_req_nomem(subreq, req)) {
2263 return tevent_req_post(req, ev);
2265 tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2266 return req;
2269 static void cli_nttrans_create_done(struct tevent_req *subreq)
2271 struct tevent_req *req = tevent_req_callback_data(
2272 subreq, struct tevent_req);
2273 struct cli_nttrans_create_state *state = tevent_req_data(
2274 req, struct cli_nttrans_create_state);
2275 uint8_t *param;
2276 uint32_t num_param;
2277 NTSTATUS status;
2279 status = cli_trans_recv(subreq, talloc_tos(), NULL,
2280 NULL, 0, NULL, /* rsetup */
2281 &param, 69, &num_param,
2282 NULL, 0, NULL);
2283 if (tevent_req_nterror(req, status)) {
2284 return;
2286 state->cr.oplock_level = CVAL(param, 0);
2287 state->fnum = SVAL(param, 2);
2288 state->cr.create_action = IVAL(param, 4);
2289 state->cr.creation_time = BVAL(param, 12);
2290 state->cr.last_access_time = BVAL(param, 20);
2291 state->cr.last_write_time = BVAL(param, 28);
2292 state->cr.change_time = BVAL(param, 36);
2293 state->cr.file_attributes = IVAL(param, 44);
2294 state->cr.allocation_size = BVAL(param, 48);
2295 state->cr.end_of_file = BVAL(param, 56);
2297 TALLOC_FREE(param);
2298 tevent_req_done(req);
2301 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2302 uint16_t *fnum,
2303 struct smb_create_returns *cr)
2305 struct cli_nttrans_create_state *state = tevent_req_data(
2306 req, struct cli_nttrans_create_state);
2307 NTSTATUS status;
2309 if (tevent_req_is_nterror(req, &status)) {
2310 return status;
2312 *fnum = state->fnum;
2313 if (cr != NULL) {
2314 *cr = state->cr;
2316 return NT_STATUS_OK;
2319 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2320 const char *fname,
2321 uint32_t CreatFlags,
2322 uint32_t DesiredAccess,
2323 uint32_t FileAttributes,
2324 uint32_t ShareAccess,
2325 uint32_t CreateDisposition,
2326 uint32_t CreateOptions,
2327 uint8_t SecurityFlags,
2328 struct security_descriptor *secdesc,
2329 struct ea_struct *eas,
2330 int num_eas,
2331 uint16_t *pfid,
2332 struct smb_create_returns *cr)
2334 TALLOC_CTX *frame = talloc_stackframe();
2335 struct tevent_context *ev;
2336 struct tevent_req *req;
2337 NTSTATUS status = NT_STATUS_NO_MEMORY;
2339 if (smbXcli_conn_has_async_calls(cli->conn)) {
2341 * Can't use sync call while an async call is in flight
2343 status = NT_STATUS_INVALID_PARAMETER;
2344 goto fail;
2346 ev = samba_tevent_context_init(frame);
2347 if (ev == NULL) {
2348 goto fail;
2350 req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2351 DesiredAccess, FileAttributes,
2352 ShareAccess, CreateDisposition,
2353 CreateOptions, SecurityFlags,
2354 secdesc, eas, num_eas);
2355 if (req == NULL) {
2356 goto fail;
2358 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2359 goto fail;
2361 status = cli_nttrans_create_recv(req, pfid, cr);
2362 fail:
2363 TALLOC_FREE(frame);
2364 return status;
2367 /****************************************************************************
2368 Open a file
2369 WARNING: if you open with O_WRONLY then getattrE won't work!
2370 ****************************************************************************/
2372 struct cli_openx_state {
2373 const char *fname;
2374 uint16_t vwv[15];
2375 uint16_t fnum;
2376 struct iovec bytes;
2379 static void cli_openx_done(struct tevent_req *subreq);
2381 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2382 struct tevent_context *ev,
2383 struct cli_state *cli, const char *fname,
2384 int flags, int share_mode,
2385 struct tevent_req **psmbreq)
2387 struct tevent_req *req, *subreq;
2388 struct cli_openx_state *state;
2389 unsigned openfn;
2390 unsigned accessmode;
2391 uint8_t additional_flags;
2392 uint8_t *bytes;
2394 req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2395 if (req == NULL) {
2396 return NULL;
2399 openfn = 0;
2400 if (flags & O_CREAT) {
2401 openfn |= (1<<4);
2403 if (!(flags & O_EXCL)) {
2404 if (flags & O_TRUNC)
2405 openfn |= (1<<1);
2406 else
2407 openfn |= (1<<0);
2410 accessmode = (share_mode<<4);
2412 if ((flags & O_ACCMODE) == O_RDWR) {
2413 accessmode |= 2;
2414 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2415 accessmode |= 1;
2418 #if defined(O_SYNC)
2419 if ((flags & O_SYNC) == O_SYNC) {
2420 accessmode |= (1<<14);
2422 #endif /* O_SYNC */
2424 if (share_mode == DENY_FCB) {
2425 accessmode = 0xFF;
2428 SCVAL(state->vwv + 0, 0, 0xFF);
2429 SCVAL(state->vwv + 0, 1, 0);
2430 SSVAL(state->vwv + 1, 0, 0);
2431 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
2432 SSVAL(state->vwv + 3, 0, accessmode);
2433 SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2434 SSVAL(state->vwv + 5, 0, 0);
2435 SIVAL(state->vwv + 6, 0, 0);
2436 SSVAL(state->vwv + 8, 0, openfn);
2437 SIVAL(state->vwv + 9, 0, 0);
2438 SIVAL(state->vwv + 11, 0, 0);
2439 SIVAL(state->vwv + 13, 0, 0);
2441 additional_flags = 0;
2443 if (cli->use_oplocks) {
2444 /* if using oplocks then ask for a batch oplock via
2445 core and extended methods */
2446 additional_flags =
2447 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2448 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2451 bytes = talloc_array(state, uint8_t, 0);
2452 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2453 strlen(fname)+1, NULL);
2455 if (tevent_req_nomem(bytes, req)) {
2456 return tevent_req_post(req, ev);
2459 state->bytes.iov_base = (void *)bytes;
2460 state->bytes.iov_len = talloc_get_size(bytes);
2462 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2463 15, state->vwv, 1, &state->bytes);
2464 if (subreq == NULL) {
2465 TALLOC_FREE(req);
2466 return NULL;
2468 tevent_req_set_callback(subreq, cli_openx_done, req);
2469 *psmbreq = subreq;
2470 return req;
2473 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2474 struct cli_state *cli, const char *fname,
2475 int flags, int share_mode)
2477 struct tevent_req *req, *subreq;
2478 NTSTATUS status;
2480 req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
2481 &subreq);
2482 if (req == NULL) {
2483 return NULL;
2486 status = smb1cli_req_chain_submit(&subreq, 1);
2487 if (tevent_req_nterror(req, status)) {
2488 return tevent_req_post(req, ev);
2490 return req;
2493 static void cli_openx_done(struct tevent_req *subreq)
2495 struct tevent_req *req = tevent_req_callback_data(
2496 subreq, struct tevent_req);
2497 struct cli_openx_state *state = tevent_req_data(
2498 req, struct cli_openx_state);
2499 uint8_t wct;
2500 uint16_t *vwv;
2501 NTSTATUS status;
2503 status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
2504 NULL);
2505 TALLOC_FREE(subreq);
2506 if (tevent_req_nterror(req, status)) {
2507 return;
2509 state->fnum = SVAL(vwv+2, 0);
2510 tevent_req_done(req);
2513 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2515 struct cli_openx_state *state = tevent_req_data(
2516 req, struct cli_openx_state);
2517 NTSTATUS status;
2519 if (tevent_req_is_nterror(req, &status)) {
2520 return status;
2522 *pfnum = state->fnum;
2523 return NT_STATUS_OK;
2526 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
2527 int share_mode, uint16_t *pfnum)
2529 TALLOC_CTX *frame = talloc_stackframe();
2530 struct tevent_context *ev;
2531 struct tevent_req *req;
2532 NTSTATUS status = NT_STATUS_NO_MEMORY;
2534 if (smbXcli_conn_has_async_calls(cli->conn)) {
2536 * Can't use sync call while an async call is in flight
2538 status = NT_STATUS_INVALID_PARAMETER;
2539 goto fail;
2542 ev = samba_tevent_context_init(frame);
2543 if (ev == NULL) {
2544 goto fail;
2547 req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
2548 if (req == NULL) {
2549 goto fail;
2552 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2553 goto fail;
2556 status = cli_openx_recv(req, pfnum);
2557 fail:
2558 TALLOC_FREE(frame);
2559 return status;
2561 /****************************************************************************
2562 Synchronous wrapper function that does an NtCreateX open by preference
2563 and falls back to openX if this fails.
2564 ****************************************************************************/
2566 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2567 int share_mode_in, uint16_t *pfnum)
2569 NTSTATUS status;
2570 unsigned int openfn = 0;
2571 unsigned int dos_deny = 0;
2572 uint32_t access_mask, share_mode, create_disposition, create_options;
2573 struct smb_create_returns cr;
2575 /* Do the initial mapping into OpenX parameters. */
2576 if (flags & O_CREAT) {
2577 openfn |= (1<<4);
2579 if (!(flags & O_EXCL)) {
2580 if (flags & O_TRUNC)
2581 openfn |= (1<<1);
2582 else
2583 openfn |= (1<<0);
2586 dos_deny = (share_mode_in<<4);
2588 if ((flags & O_ACCMODE) == O_RDWR) {
2589 dos_deny |= 2;
2590 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2591 dos_deny |= 1;
2594 #if defined(O_SYNC)
2595 if ((flags & O_SYNC) == O_SYNC) {
2596 dos_deny |= (1<<14);
2598 #endif /* O_SYNC */
2600 if (share_mode_in == DENY_FCB) {
2601 dos_deny = 0xFF;
2604 #if 0
2605 /* Hmmm. This is what I think the above code
2606 should look like if it's using the constants
2607 we #define. JRA. */
2609 if (flags & O_CREAT) {
2610 openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
2612 if (!(flags & O_EXCL)) {
2613 if (flags & O_TRUNC)
2614 openfn |= OPENX_FILE_EXISTS_TRUNCATE;
2615 else
2616 openfn |= OPENX_FILE_EXISTS_OPEN;
2619 dos_deny = SET_DENY_MODE(share_mode_in);
2621 if ((flags & O_ACCMODE) == O_RDWR) {
2622 dos_deny |= DOS_OPEN_RDWR;
2623 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2624 dos_deny |= DOS_OPEN_WRONLY;
2627 #if defined(O_SYNC)
2628 if ((flags & O_SYNC) == O_SYNC) {
2629 dos_deny |= FILE_SYNC_OPENMODE;
2631 #endif /* O_SYNC */
2633 if (share_mode_in == DENY_FCB) {
2634 dos_deny = 0xFF;
2636 #endif
2638 if (!map_open_params_to_ntcreate(fname, dos_deny,
2639 openfn, &access_mask,
2640 &share_mode, &create_disposition,
2641 &create_options, NULL)) {
2642 goto try_openx;
2645 status = cli_ntcreate(cli,
2646 fname,
2648 access_mask,
2650 share_mode,
2651 create_disposition,
2652 create_options,
2654 pfnum,
2655 &cr);
2657 /* Try and cope will all varients of "we don't do this call"
2658 and fall back to openX. */
2660 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
2661 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
2662 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
2663 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
2664 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
2665 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
2666 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
2667 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
2668 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
2669 goto try_openx;
2672 if (NT_STATUS_IS_OK(status) &&
2673 (create_options & FILE_NON_DIRECTORY_FILE) &&
2674 (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
2677 * Some (broken) servers return a valid handle
2678 * for directories even if FILE_NON_DIRECTORY_FILE
2679 * is set. Just close the handle and set the
2680 * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
2682 status = cli_close(cli, *pfnum);
2683 if (!NT_STATUS_IS_OK(status)) {
2684 return status;
2686 status = NT_STATUS_FILE_IS_A_DIRECTORY;
2687 /* Set this so libsmbclient can retrieve it. */
2688 cli->raw_status = status;
2691 return status;
2693 try_openx:
2695 return cli_openx(cli, fname, flags, share_mode_in, pfnum);
2698 /****************************************************************************
2699 Close a file.
2700 ****************************************************************************/
2702 struct cli_close_state {
2703 uint16_t vwv[3];
2706 static void cli_close_done(struct tevent_req *subreq);
2708 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2709 struct tevent_context *ev,
2710 struct cli_state *cli,
2711 uint16_t fnum,
2712 struct tevent_req **psubreq)
2714 struct tevent_req *req, *subreq;
2715 struct cli_close_state *state;
2717 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2718 if (req == NULL) {
2719 return NULL;
2722 SSVAL(state->vwv+0, 0, fnum);
2723 SIVALS(state->vwv+1, 0, -1);
2725 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2726 0, NULL);
2727 if (subreq == NULL) {
2728 TALLOC_FREE(req);
2729 return NULL;
2731 tevent_req_set_callback(subreq, cli_close_done, req);
2732 *psubreq = subreq;
2733 return req;
2736 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2737 struct tevent_context *ev,
2738 struct cli_state *cli,
2739 uint16_t fnum)
2741 struct tevent_req *req, *subreq;
2742 NTSTATUS status;
2744 req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2745 if (req == NULL) {
2746 return NULL;
2749 status = smb1cli_req_chain_submit(&subreq, 1);
2750 if (tevent_req_nterror(req, status)) {
2751 return tevent_req_post(req, ev);
2753 return req;
2756 static void cli_close_done(struct tevent_req *subreq)
2758 struct tevent_req *req = tevent_req_callback_data(
2759 subreq, struct tevent_req);
2760 NTSTATUS status;
2762 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2763 TALLOC_FREE(subreq);
2764 if (tevent_req_nterror(req, status)) {
2765 return;
2767 tevent_req_done(req);
2770 NTSTATUS cli_close_recv(struct tevent_req *req)
2772 return tevent_req_simple_recv_ntstatus(req);
2775 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2777 TALLOC_CTX *frame = NULL;
2778 struct tevent_context *ev;
2779 struct tevent_req *req;
2780 NTSTATUS status = NT_STATUS_OK;
2782 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2783 return cli_smb2_close_fnum(cli, fnum);
2786 frame = talloc_stackframe();
2788 if (smbXcli_conn_has_async_calls(cli->conn)) {
2790 * Can't use sync call while an async call is in flight
2792 status = NT_STATUS_INVALID_PARAMETER;
2793 goto fail;
2796 ev = samba_tevent_context_init(frame);
2797 if (ev == NULL) {
2798 status = NT_STATUS_NO_MEMORY;
2799 goto fail;
2802 req = cli_close_send(frame, ev, cli, fnum);
2803 if (req == NULL) {
2804 status = NT_STATUS_NO_MEMORY;
2805 goto fail;
2808 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2809 goto fail;
2812 status = cli_close_recv(req);
2813 fail:
2814 TALLOC_FREE(frame);
2815 return status;
2818 /****************************************************************************
2819 Truncate a file to a specified size
2820 ****************************************************************************/
2822 struct ftrunc_state {
2823 uint16_t setup;
2824 uint8_t param[6];
2825 uint8_t data[8];
2828 static void cli_ftruncate_done(struct tevent_req *subreq)
2830 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2831 NULL, 0, NULL, NULL, 0, NULL);
2832 tevent_req_simple_finish_ntstatus(subreq, status);
2835 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2836 struct tevent_context *ev,
2837 struct cli_state *cli,
2838 uint16_t fnum,
2839 uint64_t size)
2841 struct tevent_req *req = NULL, *subreq = NULL;
2842 struct ftrunc_state *state = NULL;
2844 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2845 if (req == NULL) {
2846 return NULL;
2849 /* Setup setup word. */
2850 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2852 /* Setup param array. */
2853 SSVAL(state->param,0,fnum);
2854 SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2855 SSVAL(state->param,4,0);
2857 /* Setup data array. */
2858 SBVAL(state->data, 0, size);
2860 subreq = cli_trans_send(state, /* mem ctx. */
2861 ev, /* event ctx. */
2862 cli, /* cli_state. */
2863 SMBtrans2, /* cmd. */
2864 NULL, /* pipe name. */
2865 -1, /* fid. */
2866 0, /* function. */
2867 0, /* flags. */
2868 &state->setup, /* setup. */
2869 1, /* num setup uint16_t words. */
2870 0, /* max returned setup. */
2871 state->param, /* param. */
2872 6, /* num param. */
2873 2, /* max returned param. */
2874 state->data, /* data. */
2875 8, /* num data. */
2876 0); /* max returned data. */
2878 if (tevent_req_nomem(subreq, req)) {
2879 return tevent_req_post(req, ev);
2881 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2882 return req;
2885 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2887 return tevent_req_simple_recv_ntstatus(req);
2890 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2892 TALLOC_CTX *frame = talloc_stackframe();
2893 struct tevent_context *ev = NULL;
2894 struct tevent_req *req = NULL;
2895 NTSTATUS status = NT_STATUS_OK;
2897 if (smbXcli_conn_has_async_calls(cli->conn)) {
2899 * Can't use sync call while an async call is in flight
2901 status = NT_STATUS_INVALID_PARAMETER;
2902 goto fail;
2905 ev = samba_tevent_context_init(frame);
2906 if (ev == NULL) {
2907 status = NT_STATUS_NO_MEMORY;
2908 goto fail;
2911 req = cli_ftruncate_send(frame,
2913 cli,
2914 fnum,
2915 size);
2916 if (req == NULL) {
2917 status = NT_STATUS_NO_MEMORY;
2918 goto fail;
2921 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2922 goto fail;
2925 status = cli_ftruncate_recv(req);
2927 fail:
2928 TALLOC_FREE(frame);
2929 return status;
2932 /****************************************************************************
2933 send a lock with a specified locktype
2934 this is used for testing LOCKING_ANDX_CANCEL_LOCK
2935 ****************************************************************************/
2937 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2938 uint32_t offset, uint32_t len,
2939 int timeout, unsigned char locktype)
2941 uint16_t vwv[8];
2942 uint8_t bytes[10];
2943 NTSTATUS status;
2944 unsigned int set_timeout = 0;
2945 unsigned int saved_timeout = 0;
2947 SCVAL(vwv + 0, 0, 0xff);
2948 SCVAL(vwv + 0, 1, 0);
2949 SSVAL(vwv + 1, 0, 0);
2950 SSVAL(vwv + 2, 0, fnum);
2951 SCVAL(vwv + 3, 0, locktype);
2952 SCVAL(vwv + 3, 1, 0);
2953 SIVALS(vwv + 4, 0, timeout);
2954 SSVAL(vwv + 6, 0, 0);
2955 SSVAL(vwv + 7, 0, 1);
2957 SSVAL(bytes, 0, cli_getpid(cli));
2958 SIVAL(bytes, 2, offset);
2959 SIVAL(bytes, 6, len);
2961 if (timeout != 0) {
2962 if (timeout == -1) {
2963 set_timeout = 0x7FFFFFFF;
2964 } else {
2965 set_timeout = timeout + 2*1000;
2967 saved_timeout = cli_set_timeout(cli, set_timeout);
2970 status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2971 10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2973 if (saved_timeout != 0) {
2974 cli_set_timeout(cli, saved_timeout);
2977 return status;
2980 /****************************************************************************
2981 Lock a file.
2982 note that timeout is in units of 2 milliseconds
2983 ****************************************************************************/
2985 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
2986 uint32_t offset, uint32_t len, int timeout,
2987 enum brl_type lock_type)
2989 NTSTATUS status;
2991 status = cli_locktype(cli, fnum, offset, len, timeout,
2992 (lock_type == READ_LOCK? 1 : 0));
2993 return status;
2996 /****************************************************************************
2997 Unlock a file.
2998 ****************************************************************************/
3000 struct cli_unlock_state {
3001 uint16_t vwv[8];
3002 uint8_t data[10];
3005 static void cli_unlock_done(struct tevent_req *subreq);
3007 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3008 struct tevent_context *ev,
3009 struct cli_state *cli,
3010 uint16_t fnum,
3011 uint64_t offset,
3012 uint64_t len)
3015 struct tevent_req *req = NULL, *subreq = NULL;
3016 struct cli_unlock_state *state = NULL;
3017 uint8_t additional_flags = 0;
3019 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3020 if (req == NULL) {
3021 return NULL;
3024 SCVAL(state->vwv+0, 0, 0xFF);
3025 SSVAL(state->vwv+2, 0, fnum);
3026 SCVAL(state->vwv+3, 0, 0);
3027 SIVALS(state->vwv+4, 0, 0);
3028 SSVAL(state->vwv+6, 0, 1);
3029 SSVAL(state->vwv+7, 0, 0);
3031 SSVAL(state->data, 0, cli_getpid(cli));
3032 SIVAL(state->data, 2, offset);
3033 SIVAL(state->data, 6, len);
3035 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
3036 8, state->vwv, 10, state->data);
3037 if (tevent_req_nomem(subreq, req)) {
3038 return tevent_req_post(req, ev);
3040 tevent_req_set_callback(subreq, cli_unlock_done, req);
3041 return req;
3044 static void cli_unlock_done(struct tevent_req *subreq)
3046 struct tevent_req *req = tevent_req_callback_data(
3047 subreq, struct tevent_req);
3048 NTSTATUS status;
3050 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3051 TALLOC_FREE(subreq);
3052 if (tevent_req_nterror(req, status)) {
3053 return;
3055 tevent_req_done(req);
3058 NTSTATUS cli_unlock_recv(struct tevent_req *req)
3060 return tevent_req_simple_recv_ntstatus(req);
3063 NTSTATUS cli_unlock(struct cli_state *cli,
3064 uint16_t fnum,
3065 uint32_t offset,
3066 uint32_t len)
3068 TALLOC_CTX *frame = talloc_stackframe();
3069 struct tevent_context *ev;
3070 struct tevent_req *req;
3071 NTSTATUS status = NT_STATUS_OK;
3073 if (smbXcli_conn_has_async_calls(cli->conn)) {
3075 * Can't use sync call while an async call is in flight
3077 status = NT_STATUS_INVALID_PARAMETER;
3078 goto fail;
3081 ev = samba_tevent_context_init(frame);
3082 if (ev == NULL) {
3083 status = NT_STATUS_NO_MEMORY;
3084 goto fail;
3087 req = cli_unlock_send(frame, ev, cli,
3088 fnum, offset, len);
3089 if (req == NULL) {
3090 status = NT_STATUS_NO_MEMORY;
3091 goto fail;
3094 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3095 goto fail;
3098 status = cli_unlock_recv(req);
3100 fail:
3101 TALLOC_FREE(frame);
3102 return status;
3105 /****************************************************************************
3106 Lock a file with 64 bit offsets.
3107 ****************************************************************************/
3109 NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
3110 uint64_t offset, uint64_t len, int timeout,
3111 enum brl_type lock_type)
3113 uint16_t vwv[8];
3114 uint8_t bytes[20];
3115 unsigned int set_timeout = 0;
3116 unsigned int saved_timeout = 0;
3117 int ltype;
3118 NTSTATUS status;
3120 if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3121 return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
3124 ltype = (lock_type == READ_LOCK? 1 : 0);
3125 ltype |= LOCKING_ANDX_LARGE_FILES;
3127 SCVAL(vwv + 0, 0, 0xff);
3128 SCVAL(vwv + 0, 1, 0);
3129 SSVAL(vwv + 1, 0, 0);
3130 SSVAL(vwv + 2, 0, fnum);
3131 SCVAL(vwv + 3, 0, ltype);
3132 SCVAL(vwv + 3, 1, 0);
3133 SIVALS(vwv + 4, 0, timeout);
3134 SSVAL(vwv + 6, 0, 0);
3135 SSVAL(vwv + 7, 0, 1);
3137 SIVAL(bytes, 0, cli_getpid(cli));
3138 SOFF_T_R(bytes, 4, offset);
3139 SOFF_T_R(bytes, 12, len);
3141 if (timeout != 0) {
3142 if (timeout == -1) {
3143 set_timeout = 0x7FFFFFFF;
3144 } else {
3145 set_timeout = timeout + 2*1000;
3147 saved_timeout = cli_set_timeout(cli, set_timeout);
3150 status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3151 20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3153 if (saved_timeout != 0) {
3154 cli_set_timeout(cli, saved_timeout);
3157 return status;
3160 /****************************************************************************
3161 Unlock a file with 64 bit offsets.
3162 ****************************************************************************/
3164 struct cli_unlock64_state {
3165 uint16_t vwv[8];
3166 uint8_t data[20];
3169 static void cli_unlock64_done(struct tevent_req *subreq);
3171 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
3172 struct tevent_context *ev,
3173 struct cli_state *cli,
3174 uint16_t fnum,
3175 uint64_t offset,
3176 uint64_t len)
3179 struct tevent_req *req = NULL, *subreq = NULL;
3180 struct cli_unlock64_state *state = NULL;
3181 uint8_t additional_flags = 0;
3183 req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
3184 if (req == NULL) {
3185 return NULL;
3188 SCVAL(state->vwv+0, 0, 0xff);
3189 SSVAL(state->vwv+2, 0, fnum);
3190 SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
3191 SIVALS(state->vwv+4, 0, 0);
3192 SSVAL(state->vwv+6, 0, 1);
3193 SSVAL(state->vwv+7, 0, 0);
3195 SIVAL(state->data, 0, cli_getpid(cli));
3196 SOFF_T_R(state->data, 4, offset);
3197 SOFF_T_R(state->data, 12, len);
3199 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
3200 8, state->vwv, 20, state->data);
3201 if (tevent_req_nomem(subreq, req)) {
3202 return tevent_req_post(req, ev);
3204 tevent_req_set_callback(subreq, cli_unlock64_done, req);
3205 return req;
3208 static void cli_unlock64_done(struct tevent_req *subreq)
3210 struct tevent_req *req = tevent_req_callback_data(
3211 subreq, struct tevent_req);
3212 NTSTATUS status;
3214 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3215 TALLOC_FREE(subreq);
3216 if (tevent_req_nterror(req, status)) {
3217 return;
3219 tevent_req_done(req);
3222 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
3224 return tevent_req_simple_recv_ntstatus(req);
3227 NTSTATUS cli_unlock64(struct cli_state *cli,
3228 uint16_t fnum,
3229 uint64_t offset,
3230 uint64_t len)
3232 TALLOC_CTX *frame = talloc_stackframe();
3233 struct tevent_context *ev;
3234 struct tevent_req *req;
3235 NTSTATUS status = NT_STATUS_OK;
3237 if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3238 return cli_unlock(cli, fnum, offset, len);
3241 if (smbXcli_conn_has_async_calls(cli->conn)) {
3243 * Can't use sync call while an async call is in flight
3245 status = NT_STATUS_INVALID_PARAMETER;
3246 goto fail;
3249 ev = samba_tevent_context_init(frame);
3250 if (ev == NULL) {
3251 status = NT_STATUS_NO_MEMORY;
3252 goto fail;
3255 req = cli_unlock64_send(frame, ev, cli,
3256 fnum, offset, len);
3257 if (req == NULL) {
3258 status = NT_STATUS_NO_MEMORY;
3259 goto fail;
3262 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3263 goto fail;
3266 status = cli_unlock64_recv(req);
3268 fail:
3269 TALLOC_FREE(frame);
3270 return status;
3273 /****************************************************************************
3274 Get/unlock a POSIX lock on a file - internal function.
3275 ****************************************************************************/
3277 struct posix_lock_state {
3278 uint16_t setup;
3279 uint8_t param[4];
3280 uint8_t data[POSIX_LOCK_DATA_SIZE];
3283 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3285 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3286 NULL, 0, NULL, NULL, 0, NULL);
3287 tevent_req_simple_finish_ntstatus(subreq, status);
3290 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3291 struct tevent_context *ev,
3292 struct cli_state *cli,
3293 uint16_t fnum,
3294 uint64_t offset,
3295 uint64_t len,
3296 bool wait_lock,
3297 enum brl_type lock_type)
3299 struct tevent_req *req = NULL, *subreq = NULL;
3300 struct posix_lock_state *state = NULL;
3302 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3303 if (req == NULL) {
3304 return NULL;
3307 /* Setup setup word. */
3308 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3310 /* Setup param array. */
3311 SSVAL(&state->param, 0, fnum);
3312 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3314 /* Setup data array. */
3315 switch (lock_type) {
3316 case READ_LOCK:
3317 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3318 POSIX_LOCK_TYPE_READ);
3319 break;
3320 case WRITE_LOCK:
3321 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3322 POSIX_LOCK_TYPE_WRITE);
3323 break;
3324 case UNLOCK_LOCK:
3325 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3326 POSIX_LOCK_TYPE_UNLOCK);
3327 break;
3328 default:
3329 return NULL;
3332 if (wait_lock) {
3333 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3334 POSIX_LOCK_FLAG_WAIT);
3335 } else {
3336 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3337 POSIX_LOCK_FLAG_NOWAIT);
3340 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3341 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3342 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3344 subreq = cli_trans_send(state, /* mem ctx. */
3345 ev, /* event ctx. */
3346 cli, /* cli_state. */
3347 SMBtrans2, /* cmd. */
3348 NULL, /* pipe name. */
3349 -1, /* fid. */
3350 0, /* function. */
3351 0, /* flags. */
3352 &state->setup, /* setup. */
3353 1, /* num setup uint16_t words. */
3354 0, /* max returned setup. */
3355 state->param, /* param. */
3356 4, /* num param. */
3357 2, /* max returned param. */
3358 state->data, /* data. */
3359 POSIX_LOCK_DATA_SIZE, /* num data. */
3360 0); /* max returned data. */
3362 if (tevent_req_nomem(subreq, req)) {
3363 return tevent_req_post(req, ev);
3365 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3366 return req;
3369 /****************************************************************************
3370 POSIX Lock a file.
3371 ****************************************************************************/
3373 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3374 struct tevent_context *ev,
3375 struct cli_state *cli,
3376 uint16_t fnum,
3377 uint64_t offset,
3378 uint64_t len,
3379 bool wait_lock,
3380 enum brl_type lock_type)
3382 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3383 wait_lock, lock_type);
3386 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3388 return tevent_req_simple_recv_ntstatus(req);
3391 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3392 uint64_t offset, uint64_t len,
3393 bool wait_lock, enum brl_type lock_type)
3395 TALLOC_CTX *frame = talloc_stackframe();
3396 struct tevent_context *ev = NULL;
3397 struct tevent_req *req = NULL;
3398 NTSTATUS status = NT_STATUS_OK;
3400 if (smbXcli_conn_has_async_calls(cli->conn)) {
3402 * Can't use sync call while an async call is in flight
3404 status = NT_STATUS_INVALID_PARAMETER;
3405 goto fail;
3408 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3409 status = NT_STATUS_INVALID_PARAMETER;
3410 goto fail;
3413 ev = samba_tevent_context_init(frame);
3414 if (ev == NULL) {
3415 status = NT_STATUS_NO_MEMORY;
3416 goto fail;
3419 req = cli_posix_lock_send(frame,
3421 cli,
3422 fnum,
3423 offset,
3424 len,
3425 wait_lock,
3426 lock_type);
3427 if (req == NULL) {
3428 status = NT_STATUS_NO_MEMORY;
3429 goto fail;
3432 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3433 goto fail;
3436 status = cli_posix_lock_recv(req);
3438 fail:
3439 TALLOC_FREE(frame);
3440 return status;
3443 /****************************************************************************
3444 POSIX Unlock a file.
3445 ****************************************************************************/
3447 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3448 struct tevent_context *ev,
3449 struct cli_state *cli,
3450 uint16_t fnum,
3451 uint64_t offset,
3452 uint64_t len)
3454 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3455 false, UNLOCK_LOCK);
3458 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3460 return tevent_req_simple_recv_ntstatus(req);
3463 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3465 TALLOC_CTX *frame = talloc_stackframe();
3466 struct tevent_context *ev = NULL;
3467 struct tevent_req *req = NULL;
3468 NTSTATUS status = NT_STATUS_OK;
3470 if (smbXcli_conn_has_async_calls(cli->conn)) {
3472 * Can't use sync call while an async call is in flight
3474 status = NT_STATUS_INVALID_PARAMETER;
3475 goto fail;
3478 ev = samba_tevent_context_init(frame);
3479 if (ev == NULL) {
3480 status = NT_STATUS_NO_MEMORY;
3481 goto fail;
3484 req = cli_posix_unlock_send(frame,
3486 cli,
3487 fnum,
3488 offset,
3489 len);
3490 if (req == NULL) {
3491 status = NT_STATUS_NO_MEMORY;
3492 goto fail;
3495 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3496 goto fail;
3499 status = cli_posix_unlock_recv(req);
3501 fail:
3502 TALLOC_FREE(frame);
3503 return status;
3506 /****************************************************************************
3507 Do a SMBgetattrE call.
3508 ****************************************************************************/
3510 static void cli_getattrE_done(struct tevent_req *subreq);
3512 struct cli_getattrE_state {
3513 uint16_t vwv[1];
3514 int zone_offset;
3515 uint16_t attr;
3516 off_t size;
3517 time_t change_time;
3518 time_t access_time;
3519 time_t write_time;
3522 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3523 struct tevent_context *ev,
3524 struct cli_state *cli,
3525 uint16_t fnum)
3527 struct tevent_req *req = NULL, *subreq = NULL;
3528 struct cli_getattrE_state *state = NULL;
3529 uint8_t additional_flags = 0;
3531 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3532 if (req == NULL) {
3533 return NULL;
3536 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3537 SSVAL(state->vwv+0,0,fnum);
3539 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
3540 1, state->vwv, 0, NULL);
3541 if (tevent_req_nomem(subreq, req)) {
3542 return tevent_req_post(req, ev);
3544 tevent_req_set_callback(subreq, cli_getattrE_done, req);
3545 return req;
3548 static void cli_getattrE_done(struct tevent_req *subreq)
3550 struct tevent_req *req = tevent_req_callback_data(
3551 subreq, struct tevent_req);
3552 struct cli_getattrE_state *state = tevent_req_data(
3553 req, struct cli_getattrE_state);
3554 uint8_t wct;
3555 uint16_t *vwv = NULL;
3556 NTSTATUS status;
3558 status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
3559 NULL, NULL);
3560 TALLOC_FREE(subreq);
3561 if (tevent_req_nterror(req, status)) {
3562 return;
3565 state->size = (off_t)IVAL(vwv+6,0);
3566 state->attr = SVAL(vwv+10,0);
3567 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3568 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3569 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3571 tevent_req_done(req);
3574 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3575 uint16_t *attr,
3576 off_t *size,
3577 time_t *change_time,
3578 time_t *access_time,
3579 time_t *write_time)
3581 struct cli_getattrE_state *state = tevent_req_data(
3582 req, struct cli_getattrE_state);
3583 NTSTATUS status;
3585 if (tevent_req_is_nterror(req, &status)) {
3586 return status;
3588 if (attr) {
3589 *attr = state->attr;
3591 if (size) {
3592 *size = state->size;
3594 if (change_time) {
3595 *change_time = state->change_time;
3597 if (access_time) {
3598 *access_time = state->access_time;
3600 if (write_time) {
3601 *write_time = state->write_time;
3603 return NT_STATUS_OK;
3606 NTSTATUS cli_getattrE(struct cli_state *cli,
3607 uint16_t fnum,
3608 uint16_t *attr,
3609 off_t *size,
3610 time_t *change_time,
3611 time_t *access_time,
3612 time_t *write_time)
3614 TALLOC_CTX *frame = NULL;
3615 struct tevent_context *ev = NULL;
3616 struct tevent_req *req = NULL;
3617 NTSTATUS status = NT_STATUS_OK;
3619 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3620 return cli_smb2_getattrE(cli,
3621 fnum,
3622 attr,
3623 size,
3624 change_time,
3625 access_time,
3626 write_time);
3629 frame = talloc_stackframe();
3631 if (smbXcli_conn_has_async_calls(cli->conn)) {
3633 * Can't use sync call while an async call is in flight
3635 status = NT_STATUS_INVALID_PARAMETER;
3636 goto fail;
3639 ev = samba_tevent_context_init(frame);
3640 if (ev == NULL) {
3641 status = NT_STATUS_NO_MEMORY;
3642 goto fail;
3645 req = cli_getattrE_send(frame, ev, cli, fnum);
3646 if (req == NULL) {
3647 status = NT_STATUS_NO_MEMORY;
3648 goto fail;
3651 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3652 goto fail;
3655 status = cli_getattrE_recv(req,
3656 attr,
3657 size,
3658 change_time,
3659 access_time,
3660 write_time);
3662 fail:
3663 TALLOC_FREE(frame);
3664 return status;
3667 /****************************************************************************
3668 Do a SMBgetatr call
3669 ****************************************************************************/
3671 static void cli_getatr_done(struct tevent_req *subreq);
3673 struct cli_getatr_state {
3674 int zone_offset;
3675 uint16_t attr;
3676 off_t size;
3677 time_t write_time;
3680 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3681 struct tevent_context *ev,
3682 struct cli_state *cli,
3683 const char *fname)
3685 struct tevent_req *req = NULL, *subreq = NULL;
3686 struct cli_getatr_state *state = NULL;
3687 uint8_t additional_flags = 0;
3688 uint8_t *bytes = NULL;
3690 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3691 if (req == NULL) {
3692 return NULL;
3695 state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3697 bytes = talloc_array(state, uint8_t, 1);
3698 if (tevent_req_nomem(bytes, req)) {
3699 return tevent_req_post(req, ev);
3701 bytes[0] = 4;
3702 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3703 strlen(fname)+1, NULL);
3705 if (tevent_req_nomem(bytes, req)) {
3706 return tevent_req_post(req, ev);
3709 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3710 0, NULL, talloc_get_size(bytes), bytes);
3711 if (tevent_req_nomem(subreq, req)) {
3712 return tevent_req_post(req, ev);
3714 tevent_req_set_callback(subreq, cli_getatr_done, req);
3715 return req;
3718 static void cli_getatr_done(struct tevent_req *subreq)
3720 struct tevent_req *req = tevent_req_callback_data(
3721 subreq, struct tevent_req);
3722 struct cli_getatr_state *state = tevent_req_data(
3723 req, struct cli_getatr_state);
3724 uint8_t wct;
3725 uint16_t *vwv = NULL;
3726 NTSTATUS status;
3728 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
3729 NULL);
3730 TALLOC_FREE(subreq);
3731 if (tevent_req_nterror(req, status)) {
3732 return;
3735 state->attr = SVAL(vwv+0,0);
3736 state->size = (off_t)IVAL(vwv+3,0);
3737 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3739 tevent_req_done(req);
3742 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3743 uint16_t *attr,
3744 off_t *size,
3745 time_t *write_time)
3747 struct cli_getatr_state *state = tevent_req_data(
3748 req, struct cli_getatr_state);
3749 NTSTATUS status;
3751 if (tevent_req_is_nterror(req, &status)) {
3752 return status;
3754 if (attr) {
3755 *attr = state->attr;
3757 if (size) {
3758 *size = state->size;
3760 if (write_time) {
3761 *write_time = state->write_time;
3763 return NT_STATUS_OK;
3766 NTSTATUS cli_getatr(struct cli_state *cli,
3767 const char *fname,
3768 uint16_t *attr,
3769 off_t *size,
3770 time_t *write_time)
3772 TALLOC_CTX *frame = NULL;
3773 struct tevent_context *ev = NULL;
3774 struct tevent_req *req = NULL;
3775 NTSTATUS status = NT_STATUS_OK;
3777 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3778 return cli_smb2_getatr(cli,
3779 fname,
3780 attr,
3781 size,
3782 write_time);
3785 frame = talloc_stackframe();
3787 if (smbXcli_conn_has_async_calls(cli->conn)) {
3789 * Can't use sync call while an async call is in flight
3791 status = NT_STATUS_INVALID_PARAMETER;
3792 goto fail;
3795 ev = samba_tevent_context_init(frame);
3796 if (ev == NULL) {
3797 status = NT_STATUS_NO_MEMORY;
3798 goto fail;
3801 req = cli_getatr_send(frame, ev, cli, fname);
3802 if (req == NULL) {
3803 status = NT_STATUS_NO_MEMORY;
3804 goto fail;
3807 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3808 goto fail;
3811 status = cli_getatr_recv(req,
3812 attr,
3813 size,
3814 write_time);
3816 fail:
3817 TALLOC_FREE(frame);
3818 return status;
3821 /****************************************************************************
3822 Do a SMBsetattrE call.
3823 ****************************************************************************/
3825 static void cli_setattrE_done(struct tevent_req *subreq);
3827 struct cli_setattrE_state {
3828 uint16_t vwv[7];
3831 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3832 struct tevent_context *ev,
3833 struct cli_state *cli,
3834 uint16_t fnum,
3835 time_t change_time,
3836 time_t access_time,
3837 time_t write_time)
3839 struct tevent_req *req = NULL, *subreq = NULL;
3840 struct cli_setattrE_state *state = NULL;
3841 uint8_t additional_flags = 0;
3843 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3844 if (req == NULL) {
3845 return NULL;
3848 SSVAL(state->vwv+0, 0, fnum);
3849 push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
3850 smb1cli_conn_server_time_zone(cli->conn));
3851 push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
3852 smb1cli_conn_server_time_zone(cli->conn));
3853 push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
3854 smb1cli_conn_server_time_zone(cli->conn));
3856 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3857 7, state->vwv, 0, NULL);
3858 if (tevent_req_nomem(subreq, req)) {
3859 return tevent_req_post(req, ev);
3861 tevent_req_set_callback(subreq, cli_setattrE_done, req);
3862 return req;
3865 static void cli_setattrE_done(struct tevent_req *subreq)
3867 struct tevent_req *req = tevent_req_callback_data(
3868 subreq, struct tevent_req);
3869 NTSTATUS status;
3871 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3872 TALLOC_FREE(subreq);
3873 if (tevent_req_nterror(req, status)) {
3874 return;
3876 tevent_req_done(req);
3879 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3881 return tevent_req_simple_recv_ntstatus(req);
3884 NTSTATUS cli_setattrE(struct cli_state *cli,
3885 uint16_t fnum,
3886 time_t change_time,
3887 time_t access_time,
3888 time_t write_time)
3890 TALLOC_CTX *frame = NULL;
3891 struct tevent_context *ev = NULL;
3892 struct tevent_req *req = NULL;
3893 NTSTATUS status = NT_STATUS_OK;
3895 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3896 return cli_smb2_setattrE(cli,
3897 fnum,
3898 change_time,
3899 access_time,
3900 write_time);
3903 frame = talloc_stackframe();
3905 if (smbXcli_conn_has_async_calls(cli->conn)) {
3907 * Can't use sync call while an async call is in flight
3909 status = NT_STATUS_INVALID_PARAMETER;
3910 goto fail;
3913 ev = samba_tevent_context_init(frame);
3914 if (ev == NULL) {
3915 status = NT_STATUS_NO_MEMORY;
3916 goto fail;
3919 req = cli_setattrE_send(frame, ev,
3920 cli,
3921 fnum,
3922 change_time,
3923 access_time,
3924 write_time);
3926 if (req == NULL) {
3927 status = NT_STATUS_NO_MEMORY;
3928 goto fail;
3931 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3932 goto fail;
3935 status = cli_setattrE_recv(req);
3937 fail:
3938 TALLOC_FREE(frame);
3939 return status;
3942 /****************************************************************************
3943 Do a SMBsetatr call.
3944 ****************************************************************************/
3946 static void cli_setatr_done(struct tevent_req *subreq);
3948 struct cli_setatr_state {
3949 uint16_t vwv[8];
3952 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3953 struct tevent_context *ev,
3954 struct cli_state *cli,
3955 const char *fname,
3956 uint16_t attr,
3957 time_t mtime)
3959 struct tevent_req *req = NULL, *subreq = NULL;
3960 struct cli_setatr_state *state = NULL;
3961 uint8_t additional_flags = 0;
3962 uint8_t *bytes = NULL;
3964 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3965 if (req == NULL) {
3966 return NULL;
3969 SSVAL(state->vwv+0, 0, attr);
3970 push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
3972 bytes = talloc_array(state, uint8_t, 1);
3973 if (tevent_req_nomem(bytes, req)) {
3974 return tevent_req_post(req, ev);
3976 bytes[0] = 4;
3977 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3978 strlen(fname)+1, NULL);
3979 if (tevent_req_nomem(bytes, req)) {
3980 return tevent_req_post(req, ev);
3982 bytes = talloc_realloc(state, bytes, uint8_t,
3983 talloc_get_size(bytes)+1);
3984 if (tevent_req_nomem(bytes, req)) {
3985 return tevent_req_post(req, ev);
3988 bytes[talloc_get_size(bytes)-1] = 4;
3989 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
3990 1, NULL);
3991 if (tevent_req_nomem(bytes, req)) {
3992 return tevent_req_post(req, ev);
3995 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3996 8, state->vwv, talloc_get_size(bytes), bytes);
3997 if (tevent_req_nomem(subreq, req)) {
3998 return tevent_req_post(req, ev);
4000 tevent_req_set_callback(subreq, cli_setatr_done, req);
4001 return req;
4004 static void cli_setatr_done(struct tevent_req *subreq)
4006 struct tevent_req *req = tevent_req_callback_data(
4007 subreq, struct tevent_req);
4008 NTSTATUS status;
4010 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4011 TALLOC_FREE(subreq);
4012 if (tevent_req_nterror(req, status)) {
4013 return;
4015 tevent_req_done(req);
4018 NTSTATUS cli_setatr_recv(struct tevent_req *req)
4020 return tevent_req_simple_recv_ntstatus(req);
4023 NTSTATUS cli_setatr(struct cli_state *cli,
4024 const char *fname,
4025 uint16_t attr,
4026 time_t mtime)
4028 TALLOC_CTX *frame = NULL;
4029 struct tevent_context *ev = NULL;
4030 struct tevent_req *req = NULL;
4031 NTSTATUS status = NT_STATUS_OK;
4033 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4034 return cli_smb2_setatr(cli,
4035 fname,
4036 attr,
4037 mtime);
4040 frame = talloc_stackframe();
4042 if (smbXcli_conn_has_async_calls(cli->conn)) {
4044 * Can't use sync call while an async call is in flight
4046 status = NT_STATUS_INVALID_PARAMETER;
4047 goto fail;
4050 ev = samba_tevent_context_init(frame);
4051 if (ev == NULL) {
4052 status = NT_STATUS_NO_MEMORY;
4053 goto fail;
4056 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
4057 if (req == NULL) {
4058 status = NT_STATUS_NO_MEMORY;
4059 goto fail;
4062 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4063 goto fail;
4066 status = cli_setatr_recv(req);
4068 fail:
4069 TALLOC_FREE(frame);
4070 return status;
4073 /****************************************************************************
4074 Check for existance of a dir.
4075 ****************************************************************************/
4077 static void cli_chkpath_done(struct tevent_req *subreq);
4079 struct cli_chkpath_state {
4080 int dummy;
4083 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
4084 struct tevent_context *ev,
4085 struct cli_state *cli,
4086 const char *fname)
4088 struct tevent_req *req = NULL, *subreq = NULL;
4089 struct cli_chkpath_state *state = NULL;
4090 uint8_t additional_flags = 0;
4091 uint8_t *bytes = NULL;
4093 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
4094 if (req == NULL) {
4095 return NULL;
4098 bytes = talloc_array(state, uint8_t, 1);
4099 if (tevent_req_nomem(bytes, req)) {
4100 return tevent_req_post(req, ev);
4102 bytes[0] = 4;
4103 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4104 strlen(fname)+1, NULL);
4106 if (tevent_req_nomem(bytes, req)) {
4107 return tevent_req_post(req, ev);
4110 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
4111 0, NULL, talloc_get_size(bytes), bytes);
4112 if (tevent_req_nomem(subreq, req)) {
4113 return tevent_req_post(req, ev);
4115 tevent_req_set_callback(subreq, cli_chkpath_done, req);
4116 return req;
4119 static void cli_chkpath_done(struct tevent_req *subreq)
4121 struct tevent_req *req = tevent_req_callback_data(
4122 subreq, struct tevent_req);
4123 NTSTATUS status;
4125 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4126 TALLOC_FREE(subreq);
4127 if (tevent_req_nterror(req, status)) {
4128 return;
4130 tevent_req_done(req);
4133 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
4135 return tevent_req_simple_recv_ntstatus(req);
4138 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
4140 TALLOC_CTX *frame = talloc_stackframe();
4141 struct tevent_context *ev = NULL;
4142 struct tevent_req *req = NULL;
4143 char *path2 = NULL;
4144 NTSTATUS status = NT_STATUS_OK;
4146 if (smbXcli_conn_has_async_calls(cli->conn)) {
4148 * Can't use sync call while an async call is in flight
4150 status = NT_STATUS_INVALID_PARAMETER;
4151 goto fail;
4154 path2 = talloc_strdup(frame, path);
4155 if (!path2) {
4156 status = NT_STATUS_NO_MEMORY;
4157 goto fail;
4159 trim_char(path2,'\0','\\');
4160 if (!*path2) {
4161 path2 = talloc_strdup(frame, "\\");
4162 if (!path2) {
4163 status = NT_STATUS_NO_MEMORY;
4164 goto fail;
4168 ev = samba_tevent_context_init(frame);
4169 if (ev == NULL) {
4170 status = NT_STATUS_NO_MEMORY;
4171 goto fail;
4174 req = cli_chkpath_send(frame, ev, cli, path2);
4175 if (req == NULL) {
4176 status = NT_STATUS_NO_MEMORY;
4177 goto fail;
4180 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4181 goto fail;
4184 status = cli_chkpath_recv(req);
4186 fail:
4187 TALLOC_FREE(frame);
4188 return status;
4191 /****************************************************************************
4192 Query disk space.
4193 ****************************************************************************/
4195 static void cli_dskattr_done(struct tevent_req *subreq);
4197 struct cli_dskattr_state {
4198 int bsize;
4199 int total;
4200 int avail;
4203 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
4204 struct tevent_context *ev,
4205 struct cli_state *cli)
4207 struct tevent_req *req = NULL, *subreq = NULL;
4208 struct cli_dskattr_state *state = NULL;
4209 uint8_t additional_flags = 0;
4211 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
4212 if (req == NULL) {
4213 return NULL;
4216 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
4217 0, NULL, 0, NULL);
4218 if (tevent_req_nomem(subreq, req)) {
4219 return tevent_req_post(req, ev);
4221 tevent_req_set_callback(subreq, cli_dskattr_done, req);
4222 return req;
4225 static void cli_dskattr_done(struct tevent_req *subreq)
4227 struct tevent_req *req = tevent_req_callback_data(
4228 subreq, struct tevent_req);
4229 struct cli_dskattr_state *state = tevent_req_data(
4230 req, struct cli_dskattr_state);
4231 uint8_t wct;
4232 uint16_t *vwv = NULL;
4233 NTSTATUS status;
4235 status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4236 NULL);
4237 TALLOC_FREE(subreq);
4238 if (tevent_req_nterror(req, status)) {
4239 return;
4241 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
4242 state->total = SVAL(vwv+0, 0);
4243 state->avail = SVAL(vwv+3, 0);
4244 tevent_req_done(req);
4247 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
4249 struct cli_dskattr_state *state = tevent_req_data(
4250 req, struct cli_dskattr_state);
4251 NTSTATUS status;
4253 if (tevent_req_is_nterror(req, &status)) {
4254 return status;
4256 *bsize = state->bsize;
4257 *total = state->total;
4258 *avail = state->avail;
4259 return NT_STATUS_OK;
4262 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
4264 TALLOC_CTX *frame = NULL;
4265 struct tevent_context *ev = NULL;
4266 struct tevent_req *req = NULL;
4267 NTSTATUS status = NT_STATUS_OK;
4269 frame = talloc_stackframe();
4271 if (smbXcli_conn_has_async_calls(cli->conn)) {
4273 * Can't use sync call while an async call is in flight
4275 status = NT_STATUS_INVALID_PARAMETER;
4276 goto fail;
4279 ev = samba_tevent_context_init(frame);
4280 if (ev == NULL) {
4281 status = NT_STATUS_NO_MEMORY;
4282 goto fail;
4285 req = cli_dskattr_send(frame, ev, cli);
4286 if (req == NULL) {
4287 status = NT_STATUS_NO_MEMORY;
4288 goto fail;
4291 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4292 goto fail;
4295 status = cli_dskattr_recv(req, bsize, total, avail);
4297 fail:
4298 TALLOC_FREE(frame);
4299 return status;
4302 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
4303 uint64_t *total, uint64_t *avail)
4305 uint64_t sectors_per_block;
4306 uint64_t bytes_per_sector;
4307 int old_bsize, old_total, old_avail;
4308 NTSTATUS status;
4310 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4311 return cli_smb2_dskattr(cli, path, bsize, total, avail);
4315 * Try the trans2 disk full size info call first.
4316 * We already use this in SMBC_fstatvfs_ctx().
4317 * Ignore 'actual_available_units' as we only
4318 * care about the quota for the caller.
4321 status = cli_get_fs_full_size_info(cli,
4322 total,
4323 avail,
4324 NULL,
4325 &sectors_per_block,
4326 &bytes_per_sector);
4328 /* Try and cope will all varients of "we don't do this call"
4329 and fall back to cli_dskattr. */
4331 if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
4332 NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
4333 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
4334 NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
4335 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
4336 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
4337 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
4338 NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
4339 NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
4340 NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
4341 goto try_dskattr;
4344 if (!NT_STATUS_IS_OK(status)) {
4345 return status;
4348 if (bsize) {
4349 *bsize = sectors_per_block *
4350 bytes_per_sector;
4353 return NT_STATUS_OK;
4355 try_dskattr:
4357 /* Old SMB1 core protocol fallback. */
4358 status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
4359 if (!NT_STATUS_IS_OK(status)) {
4360 return status;
4362 if (bsize) {
4363 *bsize = (uint64_t)old_bsize;
4365 if (total) {
4366 *total = (uint64_t)old_total;
4368 if (avail) {
4369 *avail = (uint64_t)old_avail;
4371 return NT_STATUS_OK;
4374 /****************************************************************************
4375 Create and open a temporary file.
4376 ****************************************************************************/
4378 static void cli_ctemp_done(struct tevent_req *subreq);
4380 struct ctemp_state {
4381 uint16_t vwv[3];
4382 char *ret_path;
4383 uint16_t fnum;
4386 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4387 struct tevent_context *ev,
4388 struct cli_state *cli,
4389 const char *path)
4391 struct tevent_req *req = NULL, *subreq = NULL;
4392 struct ctemp_state *state = NULL;
4393 uint8_t additional_flags = 0;
4394 uint8_t *bytes = NULL;
4396 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4397 if (req == NULL) {
4398 return NULL;
4401 SSVAL(state->vwv,0,0);
4402 SIVALS(state->vwv+1,0,-1);
4404 bytes = talloc_array(state, uint8_t, 1);
4405 if (tevent_req_nomem(bytes, req)) {
4406 return tevent_req_post(req, ev);
4408 bytes[0] = 4;
4409 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
4410 strlen(path)+1, NULL);
4411 if (tevent_req_nomem(bytes, req)) {
4412 return tevent_req_post(req, ev);
4415 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4416 3, state->vwv, talloc_get_size(bytes), bytes);
4417 if (tevent_req_nomem(subreq, req)) {
4418 return tevent_req_post(req, ev);
4420 tevent_req_set_callback(subreq, cli_ctemp_done, req);
4421 return req;
4424 static void cli_ctemp_done(struct tevent_req *subreq)
4426 struct tevent_req *req = tevent_req_callback_data(
4427 subreq, struct tevent_req);
4428 struct ctemp_state *state = tevent_req_data(
4429 req, struct ctemp_state);
4430 NTSTATUS status;
4431 uint8_t wcnt;
4432 uint16_t *vwv;
4433 uint32_t num_bytes = 0;
4434 uint8_t *bytes = NULL;
4436 status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
4437 &num_bytes, &bytes);
4438 TALLOC_FREE(subreq);
4439 if (tevent_req_nterror(req, status)) {
4440 return;
4443 state->fnum = SVAL(vwv+0, 0);
4445 /* From W2K3, the result is just the ASCII name */
4446 if (num_bytes < 2) {
4447 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
4448 return;
4451 if (pull_string_talloc(state,
4452 NULL,
4454 &state->ret_path,
4455 bytes,
4456 num_bytes,
4457 STR_ASCII) == 0) {
4458 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4459 return;
4461 tevent_req_done(req);
4464 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
4465 TALLOC_CTX *ctx,
4466 uint16_t *pfnum,
4467 char **outfile)
4469 struct ctemp_state *state = tevent_req_data(req,
4470 struct ctemp_state);
4471 NTSTATUS status;
4473 if (tevent_req_is_nterror(req, &status)) {
4474 return status;
4476 *pfnum = state->fnum;
4477 *outfile = talloc_strdup(ctx, state->ret_path);
4478 if (!*outfile) {
4479 return NT_STATUS_NO_MEMORY;
4481 return NT_STATUS_OK;
4484 NTSTATUS cli_ctemp(struct cli_state *cli,
4485 TALLOC_CTX *ctx,
4486 const char *path,
4487 uint16_t *pfnum,
4488 char **out_path)
4490 TALLOC_CTX *frame = talloc_stackframe();
4491 struct tevent_context *ev;
4492 struct tevent_req *req;
4493 NTSTATUS status = NT_STATUS_OK;
4495 if (smbXcli_conn_has_async_calls(cli->conn)) {
4497 * Can't use sync call while an async call is in flight
4499 status = NT_STATUS_INVALID_PARAMETER;
4500 goto fail;
4503 ev = samba_tevent_context_init(frame);
4504 if (ev == NULL) {
4505 status = NT_STATUS_NO_MEMORY;
4506 goto fail;
4509 req = cli_ctemp_send(frame, ev, cli, path);
4510 if (req == NULL) {
4511 status = NT_STATUS_NO_MEMORY;
4512 goto fail;
4515 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4516 goto fail;
4519 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4521 fail:
4522 TALLOC_FREE(frame);
4523 return status;
4527 send a raw ioctl - used by the torture code
4529 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4531 uint16_t vwv[3];
4532 NTSTATUS status;
4534 SSVAL(vwv+0, 0, fnum);
4535 SSVAL(vwv+1, 0, code>>16);
4536 SSVAL(vwv+2, 0, (code&0xFFFF));
4538 status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4539 NULL, 0, NULL, NULL, NULL, NULL);
4540 if (!NT_STATUS_IS_OK(status)) {
4541 return status;
4543 *blob = data_blob_null;
4544 return NT_STATUS_OK;
4547 /*********************************************************
4548 Set an extended attribute utility fn.
4549 *********************************************************/
4551 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
4552 uint8_t *param, unsigned int param_len,
4553 const char *ea_name,
4554 const char *ea_val, size_t ea_len)
4556 uint16_t setup[1];
4557 unsigned int data_len = 0;
4558 uint8_t *data = NULL;
4559 char *p;
4560 size_t ea_namelen = strlen(ea_name);
4561 NTSTATUS status;
4563 SSVAL(setup, 0, setup_val);
4565 if (ea_namelen == 0 && ea_len == 0) {
4566 data_len = 4;
4567 data = talloc_array(talloc_tos(),
4568 uint8_t,
4569 data_len);
4570 if (!data) {
4571 return NT_STATUS_NO_MEMORY;
4573 p = (char *)data;
4574 SIVAL(p,0,data_len);
4575 } else {
4576 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4577 data = talloc_array(talloc_tos(),
4578 uint8_t,
4579 data_len);
4580 if (!data) {
4581 return NT_STATUS_NO_MEMORY;
4583 p = (char *)data;
4584 SIVAL(p,0,data_len);
4585 p += 4;
4586 SCVAL(p, 0, 0); /* EA flags. */
4587 SCVAL(p, 1, ea_namelen);
4588 SSVAL(p, 2, ea_len);
4589 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4590 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4593 status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
4594 setup, 1, 0,
4595 param, param_len, 2,
4596 data, data_len, 0,
4597 NULL,
4598 NULL, 0, NULL, /* rsetup */
4599 NULL, 0, NULL, /* rparam */
4600 NULL, 0, NULL); /* rdata */
4601 talloc_free(data);
4602 return status;
4605 /*********************************************************
4606 Set an extended attribute on a pathname.
4607 *********************************************************/
4609 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
4610 const char *ea_name, const char *ea_val,
4611 size_t ea_len)
4613 unsigned int param_len = 0;
4614 uint8_t *param;
4615 NTSTATUS status;
4616 TALLOC_CTX *frame = NULL;
4618 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4619 return cli_smb2_set_ea_path(cli,
4620 path,
4621 ea_name,
4622 ea_val,
4623 ea_len);
4626 frame = talloc_stackframe();
4628 param = talloc_array(frame, uint8_t, 6);
4629 if (!param) {
4630 status = NT_STATUS_NO_MEMORY;
4631 goto fail;
4633 SSVAL(param,0,SMB_INFO_SET_EA);
4634 SSVAL(param,2,0);
4635 SSVAL(param,4,0);
4637 param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
4638 path, strlen(path)+1,
4639 NULL);
4640 param_len = talloc_get_size(param);
4642 status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
4643 ea_name, ea_val, ea_len);
4645 fail:
4647 TALLOC_FREE(frame);
4648 return status;
4651 /*********************************************************
4652 Set an extended attribute on an fnum.
4653 *********************************************************/
4655 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
4656 const char *ea_name, const char *ea_val,
4657 size_t ea_len)
4659 uint8_t param[6];
4661 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4662 return cli_smb2_set_ea_fnum(cli,
4663 fnum,
4664 ea_name,
4665 ea_val,
4666 ea_len);
4669 memset(param, 0, 6);
4670 SSVAL(param,0,fnum);
4671 SSVAL(param,2,SMB_INFO_SET_EA);
4673 return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
4674 ea_name, ea_val, ea_len);
4677 /*********************************************************
4678 Get an extended attribute list utility fn.
4679 *********************************************************/
4681 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4682 size_t rdata_len,
4683 size_t *pnum_eas, struct ea_struct **pea_list)
4685 struct ea_struct *ea_list = NULL;
4686 size_t num_eas;
4687 size_t ea_size;
4688 const uint8_t *p;
4690 if (rdata_len < 4) {
4691 return false;
4694 ea_size = (size_t)IVAL(rdata,0);
4695 if (ea_size > rdata_len) {
4696 return false;
4699 if (ea_size == 0) {
4700 /* No EA's present. */
4701 *pnum_eas = 0;
4702 *pea_list = NULL;
4703 return true;
4706 p = rdata + 4;
4707 ea_size -= 4;
4709 /* Validate the EA list and count it. */
4710 for (num_eas = 0; ea_size >= 4; num_eas++) {
4711 unsigned int ea_namelen = CVAL(p,1);
4712 unsigned int ea_valuelen = SVAL(p,2);
4713 if (ea_namelen == 0) {
4714 return false;
4716 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4717 return false;
4719 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4720 p += 4 + ea_namelen + 1 + ea_valuelen;
4723 if (num_eas == 0) {
4724 *pnum_eas = 0;
4725 *pea_list = NULL;
4726 return true;
4729 *pnum_eas = num_eas;
4730 if (!pea_list) {
4731 /* Caller only wants number of EA's. */
4732 return true;
4735 ea_list = talloc_array(ctx, struct ea_struct, num_eas);
4736 if (!ea_list) {
4737 return false;
4740 ea_size = (size_t)IVAL(rdata,0);
4741 p = rdata + 4;
4743 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4744 struct ea_struct *ea = &ea_list[num_eas];
4745 fstring unix_ea_name;
4746 unsigned int ea_namelen = CVAL(p,1);
4747 unsigned int ea_valuelen = SVAL(p,2);
4749 ea->flags = CVAL(p,0);
4750 unix_ea_name[0] = '\0';
4751 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
4752 ea->name = talloc_strdup(ea_list, unix_ea_name);
4753 if (!ea->name) {
4754 goto fail;
4756 /* Ensure the value is null terminated (in case it's a string). */
4757 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4758 if (!ea->value.data) {
4759 goto fail;
4761 if (ea_valuelen) {
4762 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4764 ea->value.data[ea_valuelen] = 0;
4765 ea->value.length--;
4766 p += 4 + ea_namelen + 1 + ea_valuelen;
4769 *pea_list = ea_list;
4770 return true;
4772 fail:
4773 TALLOC_FREE(ea_list);
4774 return false;
4777 /*********************************************************
4778 Get an extended attribute list from a pathname.
4779 *********************************************************/
4781 struct cli_get_ea_list_path_state {
4782 uint32_t num_data;
4783 uint8_t *data;
4786 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4788 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4789 struct tevent_context *ev,
4790 struct cli_state *cli,
4791 const char *fname)
4793 struct tevent_req *req, *subreq;
4794 struct cli_get_ea_list_path_state *state;
4796 req = tevent_req_create(mem_ctx, &state,
4797 struct cli_get_ea_list_path_state);
4798 if (req == NULL) {
4799 return NULL;
4801 subreq = cli_qpathinfo_send(state, ev, cli, fname,
4802 SMB_INFO_QUERY_ALL_EAS, 4,
4803 CLI_BUFFER_SIZE);
4804 if (tevent_req_nomem(subreq, req)) {
4805 return tevent_req_post(req, ev);
4807 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4808 return req;
4811 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4813 struct tevent_req *req = tevent_req_callback_data(
4814 subreq, struct tevent_req);
4815 struct cli_get_ea_list_path_state *state = tevent_req_data(
4816 req, struct cli_get_ea_list_path_state);
4817 NTSTATUS status;
4819 status = cli_qpathinfo_recv(subreq, state, &state->data,
4820 &state->num_data);
4821 TALLOC_FREE(subreq);
4822 if (tevent_req_nterror(req, status)) {
4823 return;
4825 tevent_req_done(req);
4828 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4829 size_t *pnum_eas, struct ea_struct **peas)
4831 struct cli_get_ea_list_path_state *state = tevent_req_data(
4832 req, struct cli_get_ea_list_path_state);
4833 NTSTATUS status;
4835 if (tevent_req_is_nterror(req, &status)) {
4836 return status;
4838 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4839 pnum_eas, peas)) {
4840 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4842 return NT_STATUS_OK;
4845 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
4846 TALLOC_CTX *ctx,
4847 size_t *pnum_eas,
4848 struct ea_struct **pea_list)
4850 TALLOC_CTX *frame = NULL;
4851 struct tevent_context *ev = NULL;
4852 struct tevent_req *req = NULL;
4853 NTSTATUS status = NT_STATUS_NO_MEMORY;
4855 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4856 return cli_smb2_get_ea_list_path(cli,
4857 path,
4858 ctx,
4859 pnum_eas,
4860 pea_list);
4863 frame = talloc_stackframe();
4865 if (smbXcli_conn_has_async_calls(cli->conn)) {
4867 * Can't use sync call while an async call is in flight
4869 status = NT_STATUS_INVALID_PARAMETER;
4870 goto fail;
4872 ev = samba_tevent_context_init(frame);
4873 if (ev == NULL) {
4874 goto fail;
4876 req = cli_get_ea_list_path_send(frame, ev, cli, path);
4877 if (req == NULL) {
4878 goto fail;
4880 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4881 goto fail;
4883 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
4884 fail:
4885 TALLOC_FREE(frame);
4886 return status;
4889 /****************************************************************************
4890 Convert open "flags" arg to uint32_t on wire.
4891 ****************************************************************************/
4893 static uint32_t open_flags_to_wire(int flags)
4895 int open_mode = flags & O_ACCMODE;
4896 uint32_t ret = 0;
4898 switch (open_mode) {
4899 case O_WRONLY:
4900 ret |= SMB_O_WRONLY;
4901 break;
4902 case O_RDWR:
4903 ret |= SMB_O_RDWR;
4904 break;
4905 default:
4906 case O_RDONLY:
4907 ret |= SMB_O_RDONLY;
4908 break;
4911 if (flags & O_CREAT) {
4912 ret |= SMB_O_CREAT;
4914 if (flags & O_EXCL) {
4915 ret |= SMB_O_EXCL;
4917 if (flags & O_TRUNC) {
4918 ret |= SMB_O_TRUNC;
4920 #if defined(O_SYNC)
4921 if (flags & O_SYNC) {
4922 ret |= SMB_O_SYNC;
4924 #endif /* O_SYNC */
4925 if (flags & O_APPEND) {
4926 ret |= SMB_O_APPEND;
4928 #if defined(O_DIRECT)
4929 if (flags & O_DIRECT) {
4930 ret |= SMB_O_DIRECT;
4932 #endif
4933 #if defined(O_DIRECTORY)
4934 if (flags & O_DIRECTORY) {
4935 ret |= SMB_O_DIRECTORY;
4937 #endif
4938 return ret;
4941 /****************************************************************************
4942 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4943 ****************************************************************************/
4945 struct posix_open_state {
4946 uint16_t setup;
4947 uint8_t *param;
4948 uint8_t data[18];
4949 uint16_t fnum; /* Out */
4952 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4954 struct tevent_req *req = tevent_req_callback_data(
4955 subreq, struct tevent_req);
4956 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4957 NTSTATUS status;
4958 uint8_t *data;
4959 uint32_t num_data;
4961 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
4962 NULL, 0, NULL, &data, 12, &num_data);
4963 TALLOC_FREE(subreq);
4964 if (tevent_req_nterror(req, status)) {
4965 return;
4967 state->fnum = SVAL(data,2);
4968 tevent_req_done(req);
4971 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4972 struct tevent_context *ev,
4973 struct cli_state *cli,
4974 const char *fname,
4975 int flags,
4976 mode_t mode,
4977 bool is_dir)
4979 struct tevent_req *req = NULL, *subreq = NULL;
4980 struct posix_open_state *state = NULL;
4981 uint32_t wire_flags = open_flags_to_wire(flags);
4983 req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4984 if (req == NULL) {
4985 return NULL;
4988 /* Setup setup word. */
4989 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4991 /* Setup param array. */
4992 state->param = talloc_array(state, uint8_t, 6);
4993 if (tevent_req_nomem(state->param, req)) {
4994 return tevent_req_post(req, ev);
4996 memset(state->param, '\0', 6);
4997 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4999 state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn), fname,
5000 strlen(fname)+1, NULL);
5002 if (tevent_req_nomem(state->param, req)) {
5003 return tevent_req_post(req, ev);
5006 /* Setup data words. */
5007 if (is_dir) {
5008 wire_flags |= SMB_O_DIRECTORY;
5011 SIVAL(state->data,0,0); /* No oplock. */
5012 SIVAL(state->data,4,wire_flags);
5013 SIVAL(state->data,8,unix_perms_to_wire(mode));
5014 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
5015 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
5017 subreq = cli_trans_send(state, /* mem ctx. */
5018 ev, /* event ctx. */
5019 cli, /* cli_state. */
5020 SMBtrans2, /* cmd. */
5021 NULL, /* pipe name. */
5022 -1, /* fid. */
5023 0, /* function. */
5024 0, /* flags. */
5025 &state->setup, /* setup. */
5026 1, /* num setup uint16_t words. */
5027 0, /* max returned setup. */
5028 state->param, /* param. */
5029 talloc_get_size(state->param),/* num param. */
5030 2, /* max returned param. */
5031 state->data, /* data. */
5032 18, /* num data. */
5033 12); /* max returned data. */
5035 if (tevent_req_nomem(subreq, req)) {
5036 return tevent_req_post(req, ev);
5038 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
5039 return req;
5042 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
5043 struct tevent_context *ev,
5044 struct cli_state *cli,
5045 const char *fname,
5046 int flags,
5047 mode_t mode)
5049 return cli_posix_open_internal_send(mem_ctx, ev,
5050 cli, fname, flags, mode, false);
5053 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
5055 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
5056 NTSTATUS status;
5058 if (tevent_req_is_nterror(req, &status)) {
5059 return status;
5061 *pfnum = state->fnum;
5062 return NT_STATUS_OK;
5065 /****************************************************************************
5066 Open - POSIX semantics. Doesn't request oplock.
5067 ****************************************************************************/
5069 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
5070 int flags, mode_t mode, uint16_t *pfnum)
5073 TALLOC_CTX *frame = talloc_stackframe();
5074 struct tevent_context *ev = NULL;
5075 struct tevent_req *req = NULL;
5076 NTSTATUS status = NT_STATUS_OK;
5078 if (smbXcli_conn_has_async_calls(cli->conn)) {
5080 * Can't use sync call while an async call is in flight
5082 status = NT_STATUS_INVALID_PARAMETER;
5083 goto fail;
5086 ev = samba_tevent_context_init(frame);
5087 if (ev == NULL) {
5088 status = NT_STATUS_NO_MEMORY;
5089 goto fail;
5092 req = cli_posix_open_send(frame,
5094 cli,
5095 fname,
5096 flags,
5097 mode);
5098 if (req == NULL) {
5099 status = NT_STATUS_NO_MEMORY;
5100 goto fail;
5103 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5104 goto fail;
5107 status = cli_posix_open_recv(req, pfnum);
5109 fail:
5110 TALLOC_FREE(frame);
5111 return status;
5114 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
5115 struct tevent_context *ev,
5116 struct cli_state *cli,
5117 const char *fname,
5118 mode_t mode)
5120 return cli_posix_open_internal_send(mem_ctx, ev,
5121 cli, fname, O_CREAT, mode, true);
5124 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
5126 return tevent_req_simple_recv_ntstatus(req);
5129 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
5131 TALLOC_CTX *frame = talloc_stackframe();
5132 struct tevent_context *ev = NULL;
5133 struct tevent_req *req = NULL;
5134 NTSTATUS status = NT_STATUS_OK;
5136 if (smbXcli_conn_has_async_calls(cli->conn)) {
5138 * Can't use sync call while an async call is in flight
5140 status = NT_STATUS_INVALID_PARAMETER;
5141 goto fail;
5144 ev = samba_tevent_context_init(frame);
5145 if (ev == NULL) {
5146 status = NT_STATUS_NO_MEMORY;
5147 goto fail;
5150 req = cli_posix_mkdir_send(frame,
5152 cli,
5153 fname,
5154 mode);
5155 if (req == NULL) {
5156 status = NT_STATUS_NO_MEMORY;
5157 goto fail;
5160 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5161 goto fail;
5164 status = cli_posix_mkdir_recv(req);
5166 fail:
5167 TALLOC_FREE(frame);
5168 return status;
5171 /****************************************************************************
5172 unlink or rmdir - POSIX semantics.
5173 ****************************************************************************/
5175 struct cli_posix_unlink_internal_state {
5176 uint8_t data[2];
5179 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
5181 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
5182 struct tevent_context *ev,
5183 struct cli_state *cli,
5184 const char *fname,
5185 uint16_t level)
5187 struct tevent_req *req = NULL, *subreq = NULL;
5188 struct cli_posix_unlink_internal_state *state = NULL;
5190 req = tevent_req_create(mem_ctx, &state,
5191 struct cli_posix_unlink_internal_state);
5192 if (req == NULL) {
5193 return NULL;
5196 /* Setup data word. */
5197 SSVAL(state->data, 0, level);
5199 subreq = cli_setpathinfo_send(state, ev, cli,
5200 SMB_POSIX_PATH_UNLINK,
5201 fname,
5202 state->data, sizeof(state->data));
5203 if (tevent_req_nomem(subreq, req)) {
5204 return tevent_req_post(req, ev);
5206 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
5207 return req;
5210 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
5212 NTSTATUS status = cli_setpathinfo_recv(subreq);
5213 tevent_req_simple_finish_ntstatus(subreq, status);
5216 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
5217 struct tevent_context *ev,
5218 struct cli_state *cli,
5219 const char *fname)
5221 return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
5222 SMB_POSIX_UNLINK_FILE_TARGET);
5225 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
5227 return tevent_req_simple_recv_ntstatus(req);
5230 /****************************************************************************
5231 unlink - POSIX semantics.
5232 ****************************************************************************/
5234 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
5236 TALLOC_CTX *frame = talloc_stackframe();
5237 struct tevent_context *ev = NULL;
5238 struct tevent_req *req = NULL;
5239 NTSTATUS status = NT_STATUS_OK;
5241 if (smbXcli_conn_has_async_calls(cli->conn)) {
5243 * Can't use sync call while an async call is in flight
5245 status = NT_STATUS_INVALID_PARAMETER;
5246 goto fail;
5249 ev = samba_tevent_context_init(frame);
5250 if (ev == NULL) {
5251 status = NT_STATUS_NO_MEMORY;
5252 goto fail;
5255 req = cli_posix_unlink_send(frame,
5257 cli,
5258 fname);
5259 if (req == NULL) {
5260 status = NT_STATUS_NO_MEMORY;
5261 goto fail;
5264 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5265 goto fail;
5268 status = cli_posix_unlink_recv(req);
5270 fail:
5271 TALLOC_FREE(frame);
5272 return status;
5275 /****************************************************************************
5276 rmdir - POSIX semantics.
5277 ****************************************************************************/
5279 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
5280 struct tevent_context *ev,
5281 struct cli_state *cli,
5282 const char *fname)
5284 return cli_posix_unlink_internal_send(
5285 mem_ctx, ev, cli, fname,
5286 SMB_POSIX_UNLINK_DIRECTORY_TARGET);
5289 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
5291 return tevent_req_simple_recv_ntstatus(req);
5294 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
5296 TALLOC_CTX *frame = talloc_stackframe();
5297 struct tevent_context *ev = NULL;
5298 struct tevent_req *req = NULL;
5299 NTSTATUS status = NT_STATUS_OK;
5301 if (smbXcli_conn_has_async_calls(cli->conn)) {
5303 * Can't use sync call while an async call is in flight
5305 status = NT_STATUS_INVALID_PARAMETER;
5306 goto fail;
5309 ev = samba_tevent_context_init(frame);
5310 if (ev == NULL) {
5311 status = NT_STATUS_NO_MEMORY;
5312 goto fail;
5315 req = cli_posix_rmdir_send(frame,
5317 cli,
5318 fname);
5319 if (req == NULL) {
5320 status = NT_STATUS_NO_MEMORY;
5321 goto fail;
5324 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5325 goto fail;
5328 status = cli_posix_rmdir_recv(req, frame);
5330 fail:
5331 TALLOC_FREE(frame);
5332 return status;
5335 /****************************************************************************
5336 filechangenotify
5337 ****************************************************************************/
5339 struct cli_notify_state {
5340 uint8_t setup[8];
5341 uint32_t num_changes;
5342 struct notify_change *changes;
5345 static void cli_notify_done(struct tevent_req *subreq);
5347 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
5348 struct tevent_context *ev,
5349 struct cli_state *cli, uint16_t fnum,
5350 uint32_t buffer_size,
5351 uint32_t completion_filter, bool recursive)
5353 struct tevent_req *req, *subreq;
5354 struct cli_notify_state *state;
5355 unsigned old_timeout;
5357 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
5358 if (req == NULL) {
5359 return NULL;
5362 SIVAL(state->setup, 0, completion_filter);
5363 SSVAL(state->setup, 4, fnum);
5364 SSVAL(state->setup, 6, recursive);
5367 * Notifies should not time out
5369 old_timeout = cli_set_timeout(cli, 0);
5371 subreq = cli_trans_send(
5372 state, /* mem ctx. */
5373 ev, /* event ctx. */
5374 cli, /* cli_state. */
5375 SMBnttrans, /* cmd. */
5376 NULL, /* pipe name. */
5377 -1, /* fid. */
5378 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
5379 0, /* flags. */
5380 (uint16_t *)state->setup, /* setup. */
5381 4, /* num setup uint16_t words. */
5382 0, /* max returned setup. */
5383 NULL, /* param. */
5384 0, /* num param. */
5385 buffer_size, /* max returned param. */
5386 NULL, /* data. */
5387 0, /* num data. */
5388 0); /* max returned data. */
5390 cli_set_timeout(cli, old_timeout);
5392 if (tevent_req_nomem(subreq, req)) {
5393 return tevent_req_post(req, ev);
5395 tevent_req_set_callback(subreq, cli_notify_done, req);
5396 return req;
5399 static void cli_notify_done(struct tevent_req *subreq)
5401 struct tevent_req *req = tevent_req_callback_data(
5402 subreq, struct tevent_req);
5403 struct cli_notify_state *state = tevent_req_data(
5404 req, struct cli_notify_state);
5405 NTSTATUS status;
5406 uint8_t *params;
5407 uint32_t i, ofs, num_params;
5408 uint16_t flags2;
5410 status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
5411 &params, 0, &num_params, NULL, 0, NULL);
5412 TALLOC_FREE(subreq);
5413 if (tevent_req_nterror(req, status)) {
5414 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
5415 return;
5418 state->num_changes = 0;
5419 ofs = 0;
5421 while (num_params - ofs > 12) {
5422 uint32_t next = IVAL(params, ofs);
5423 state->num_changes += 1;
5425 if ((next == 0) || (ofs+next >= num_params)) {
5426 break;
5428 ofs += next;
5431 state->changes = talloc_array(state, struct notify_change,
5432 state->num_changes);
5433 if (tevent_req_nomem(state->changes, req)) {
5434 TALLOC_FREE(params);
5435 return;
5438 ofs = 0;
5440 for (i=0; i<state->num_changes; i++) {
5441 uint32_t next = IVAL(params, ofs);
5442 uint32_t len = IVAL(params, ofs+8);
5443 ssize_t ret;
5444 char *name;
5446 if (trans_oob(num_params, ofs + 12, len)) {
5447 TALLOC_FREE(params);
5448 tevent_req_nterror(
5449 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5450 return;
5453 state->changes[i].action = IVAL(params, ofs+4);
5454 ret = clistr_pull_talloc(state->changes, (char *)params, flags2,
5455 &name, params+ofs+12, len,
5456 STR_TERMINATE|STR_UNICODE);
5457 if (ret == -1) {
5458 TALLOC_FREE(params);
5459 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5460 return;
5462 state->changes[i].name = name;
5463 ofs += next;
5466 TALLOC_FREE(params);
5467 tevent_req_done(req);
5470 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5471 uint32_t *pnum_changes,
5472 struct notify_change **pchanges)
5474 struct cli_notify_state *state = tevent_req_data(
5475 req, struct cli_notify_state);
5476 NTSTATUS status;
5478 if (tevent_req_is_nterror(req, &status)) {
5479 return status;
5482 *pnum_changes = state->num_changes;
5483 *pchanges = talloc_move(mem_ctx, &state->changes);
5484 return NT_STATUS_OK;
5487 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
5488 uint32_t completion_filter, bool recursive,
5489 TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
5490 struct notify_change **pchanges)
5492 TALLOC_CTX *frame = talloc_stackframe();
5493 struct tevent_context *ev;
5494 struct tevent_req *req;
5495 NTSTATUS status = NT_STATUS_NO_MEMORY;
5497 if (smbXcli_conn_has_async_calls(cli->conn)) {
5499 * Can't use sync call while an async call is in flight
5501 status = NT_STATUS_INVALID_PARAMETER;
5502 goto fail;
5504 ev = samba_tevent_context_init(frame);
5505 if (ev == NULL) {
5506 goto fail;
5508 req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
5509 completion_filter, recursive);
5510 if (req == NULL) {
5511 goto fail;
5513 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5514 goto fail;
5516 status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
5517 fail:
5518 TALLOC_FREE(frame);
5519 return status;
5522 struct cli_qpathinfo_state {
5523 uint8_t *param;
5524 uint8_t *data;
5525 uint16_t setup[1];
5526 uint32_t min_rdata;
5527 uint8_t *rdata;
5528 uint32_t num_rdata;
5531 static void cli_qpathinfo_done(struct tevent_req *subreq);
5533 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
5534 struct tevent_context *ev,
5535 struct cli_state *cli, const char *fname,
5536 uint16_t level, uint32_t min_rdata,
5537 uint32_t max_rdata)
5539 struct tevent_req *req, *subreq;
5540 struct cli_qpathinfo_state *state;
5542 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
5543 if (req == NULL) {
5544 return NULL;
5546 state->min_rdata = min_rdata;
5547 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
5549 state->param = talloc_zero_array(state, uint8_t, 6);
5550 if (tevent_req_nomem(state->param, req)) {
5551 return tevent_req_post(req, ev);
5553 SSVAL(state->param, 0, level);
5554 state->param = trans2_bytes_push_str(
5555 state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
5556 if (tevent_req_nomem(state->param, req)) {
5557 return tevent_req_post(req, ev);
5560 subreq = cli_trans_send(
5561 state, /* mem ctx. */
5562 ev, /* event ctx. */
5563 cli, /* cli_state. */
5564 SMBtrans2, /* cmd. */
5565 NULL, /* pipe name. */
5566 -1, /* fid. */
5567 0, /* function. */
5568 0, /* flags. */
5569 state->setup, /* setup. */
5570 1, /* num setup uint16_t words. */
5571 0, /* max returned setup. */
5572 state->param, /* param. */
5573 talloc_get_size(state->param), /* num param. */
5574 2, /* max returned param. */
5575 NULL, /* data. */
5576 0, /* num data. */
5577 max_rdata); /* max returned data. */
5579 if (tevent_req_nomem(subreq, req)) {
5580 return tevent_req_post(req, ev);
5582 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5583 return req;
5586 static void cli_qpathinfo_done(struct tevent_req *subreq)
5588 struct tevent_req *req = tevent_req_callback_data(
5589 subreq, struct tevent_req);
5590 struct cli_qpathinfo_state *state = tevent_req_data(
5591 req, struct cli_qpathinfo_state);
5592 NTSTATUS status;
5594 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5595 NULL, 0, NULL,
5596 &state->rdata, state->min_rdata,
5597 &state->num_rdata);
5598 if (tevent_req_nterror(req, status)) {
5599 return;
5601 tevent_req_done(req);
5604 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5605 uint8_t **rdata, uint32_t *num_rdata)
5607 struct cli_qpathinfo_state *state = tevent_req_data(
5608 req, struct cli_qpathinfo_state);
5609 NTSTATUS status;
5611 if (tevent_req_is_nterror(req, &status)) {
5612 return status;
5614 if (rdata != NULL) {
5615 *rdata = talloc_move(mem_ctx, &state->rdata);
5616 } else {
5617 TALLOC_FREE(state->rdata);
5619 if (num_rdata != NULL) {
5620 *num_rdata = state->num_rdata;
5622 return NT_STATUS_OK;
5625 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5626 const char *fname, uint16_t level, uint32_t min_rdata,
5627 uint32_t max_rdata,
5628 uint8_t **rdata, uint32_t *num_rdata)
5630 TALLOC_CTX *frame = talloc_stackframe();
5631 struct tevent_context *ev;
5632 struct tevent_req *req;
5633 NTSTATUS status = NT_STATUS_NO_MEMORY;
5635 if (smbXcli_conn_has_async_calls(cli->conn)) {
5637 * Can't use sync call while an async call is in flight
5639 status = NT_STATUS_INVALID_PARAMETER;
5640 goto fail;
5642 ev = samba_tevent_context_init(frame);
5643 if (ev == NULL) {
5644 goto fail;
5646 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5647 max_rdata);
5648 if (req == NULL) {
5649 goto fail;
5651 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5652 goto fail;
5654 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5655 fail:
5656 TALLOC_FREE(frame);
5657 return status;
5660 struct cli_qfileinfo_state {
5661 uint16_t setup[1];
5662 uint8_t param[4];
5663 uint8_t *data;
5664 uint16_t recv_flags2;
5665 uint32_t min_rdata;
5666 uint8_t *rdata;
5667 uint32_t num_rdata;
5670 static void cli_qfileinfo_done(struct tevent_req *subreq);
5672 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
5673 struct tevent_context *ev,
5674 struct cli_state *cli, uint16_t fnum,
5675 uint16_t level, uint32_t min_rdata,
5676 uint32_t max_rdata)
5678 struct tevent_req *req, *subreq;
5679 struct cli_qfileinfo_state *state;
5681 req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
5682 if (req == NULL) {
5683 return NULL;
5685 state->min_rdata = min_rdata;
5686 SSVAL(state->param, 0, fnum);
5687 SSVAL(state->param, 2, level);
5688 SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
5690 subreq = cli_trans_send(
5691 state, /* mem ctx. */
5692 ev, /* event ctx. */
5693 cli, /* cli_state. */
5694 SMBtrans2, /* cmd. */
5695 NULL, /* pipe name. */
5696 -1, /* fid. */
5697 0, /* function. */
5698 0, /* flags. */
5699 state->setup, /* setup. */
5700 1, /* num setup uint16_t words. */
5701 0, /* max returned setup. */
5702 state->param, /* param. */
5703 sizeof(state->param), /* num param. */
5704 2, /* max returned param. */
5705 NULL, /* data. */
5706 0, /* num data. */
5707 max_rdata); /* max returned data. */
5709 if (tevent_req_nomem(subreq, req)) {
5710 return tevent_req_post(req, ev);
5712 tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
5713 return req;
5716 static void cli_qfileinfo_done(struct tevent_req *subreq)
5718 struct tevent_req *req = tevent_req_callback_data(
5719 subreq, struct tevent_req);
5720 struct cli_qfileinfo_state *state = tevent_req_data(
5721 req, struct cli_qfileinfo_state);
5722 NTSTATUS status;
5724 status = cli_trans_recv(subreq, state,
5725 &state->recv_flags2,
5726 NULL, 0, NULL,
5727 NULL, 0, NULL,
5728 &state->rdata, state->min_rdata,
5729 &state->num_rdata);
5730 if (tevent_req_nterror(req, status)) {
5731 return;
5733 tevent_req_done(req);
5736 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5737 uint16_t *recv_flags2,
5738 uint8_t **rdata, uint32_t *num_rdata)
5740 struct cli_qfileinfo_state *state = tevent_req_data(
5741 req, struct cli_qfileinfo_state);
5742 NTSTATUS status;
5744 if (tevent_req_is_nterror(req, &status)) {
5745 return status;
5748 if (recv_flags2 != NULL) {
5749 *recv_flags2 = state->recv_flags2;
5751 if (rdata != NULL) {
5752 *rdata = talloc_move(mem_ctx, &state->rdata);
5753 } else {
5754 TALLOC_FREE(state->rdata);
5756 if (num_rdata != NULL) {
5757 *num_rdata = state->num_rdata;
5759 return NT_STATUS_OK;
5762 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5763 uint16_t fnum, uint16_t level, uint32_t min_rdata,
5764 uint32_t max_rdata, uint16_t *recv_flags2,
5765 uint8_t **rdata, uint32_t *num_rdata)
5767 TALLOC_CTX *frame = talloc_stackframe();
5768 struct tevent_context *ev;
5769 struct tevent_req *req;
5770 NTSTATUS status = NT_STATUS_NO_MEMORY;
5772 if (smbXcli_conn_has_async_calls(cli->conn)) {
5774 * Can't use sync call while an async call is in flight
5776 status = NT_STATUS_INVALID_PARAMETER;
5777 goto fail;
5779 ev = samba_tevent_context_init(frame);
5780 if (ev == NULL) {
5781 goto fail;
5783 req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
5784 max_rdata);
5785 if (req == NULL) {
5786 goto fail;
5788 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5789 goto fail;
5791 status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
5792 fail:
5793 TALLOC_FREE(frame);
5794 return status;
5797 struct cli_flush_state {
5798 uint16_t vwv[1];
5801 static void cli_flush_done(struct tevent_req *subreq);
5803 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
5804 struct tevent_context *ev,
5805 struct cli_state *cli,
5806 uint16_t fnum)
5808 struct tevent_req *req, *subreq;
5809 struct cli_flush_state *state;
5811 req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
5812 if (req == NULL) {
5813 return NULL;
5815 SSVAL(state->vwv + 0, 0, fnum);
5817 subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 1, state->vwv,
5818 0, NULL);
5819 if (tevent_req_nomem(subreq, req)) {
5820 return tevent_req_post(req, ev);
5822 tevent_req_set_callback(subreq, cli_flush_done, req);
5823 return req;
5826 static void cli_flush_done(struct tevent_req *subreq)
5828 struct tevent_req *req = tevent_req_callback_data(
5829 subreq, struct tevent_req);
5830 NTSTATUS status;
5832 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5833 TALLOC_FREE(subreq);
5834 if (tevent_req_nterror(req, status)) {
5835 return;
5837 tevent_req_done(req);
5840 NTSTATUS cli_flush_recv(struct tevent_req *req)
5842 return tevent_req_simple_recv_ntstatus(req);
5845 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
5847 TALLOC_CTX *frame = talloc_stackframe();
5848 struct tevent_context *ev;
5849 struct tevent_req *req;
5850 NTSTATUS status = NT_STATUS_NO_MEMORY;
5852 if (smbXcli_conn_has_async_calls(cli->conn)) {
5854 * Can't use sync call while an async call is in flight
5856 status = NT_STATUS_INVALID_PARAMETER;
5857 goto fail;
5859 ev = samba_tevent_context_init(frame);
5860 if (ev == NULL) {
5861 goto fail;
5863 req = cli_flush_send(frame, ev, cli, fnum);
5864 if (req == NULL) {
5865 goto fail;
5867 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5868 goto fail;
5870 status = cli_flush_recv(req);
5871 fail:
5872 TALLOC_FREE(frame);
5873 return status;
5876 struct cli_shadow_copy_data_state {
5877 uint16_t setup[4];
5878 uint8_t *data;
5879 uint32_t num_data;
5880 bool get_names;
5883 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
5885 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
5886 struct tevent_context *ev,
5887 struct cli_state *cli,
5888 uint16_t fnum,
5889 bool get_names)
5891 struct tevent_req *req, *subreq;
5892 struct cli_shadow_copy_data_state *state;
5893 uint32_t ret_size;
5895 req = tevent_req_create(mem_ctx, &state,
5896 struct cli_shadow_copy_data_state);
5897 if (req == NULL) {
5898 return NULL;
5900 state->get_names = get_names;
5901 ret_size = get_names ? CLI_BUFFER_SIZE : 16;
5903 SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
5904 SSVAL(state->setup + 2, 0, fnum);
5905 SCVAL(state->setup + 3, 0, 1); /* isFsctl */
5906 SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
5908 subreq = cli_trans_send(
5909 state, ev, cli, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
5910 state->setup, ARRAY_SIZE(state->setup), 0,
5911 NULL, 0, 0,
5912 NULL, 0, ret_size);
5913 if (tevent_req_nomem(subreq, req)) {
5914 return tevent_req_post(req, ev);
5916 tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
5917 return req;
5920 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
5922 struct tevent_req *req = tevent_req_callback_data(
5923 subreq, struct tevent_req);
5924 struct cli_shadow_copy_data_state *state = tevent_req_data(
5925 req, struct cli_shadow_copy_data_state);
5926 NTSTATUS status;
5928 status = cli_trans_recv(subreq, state, NULL,
5929 NULL, 0, NULL, /* setup */
5930 NULL, 0, NULL, /* param */
5931 &state->data, 12, &state->num_data);
5932 TALLOC_FREE(subreq);
5933 if (tevent_req_nterror(req, status)) {
5934 return;
5936 tevent_req_done(req);
5939 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5940 char ***pnames, int *pnum_names)
5942 struct cli_shadow_copy_data_state *state = tevent_req_data(
5943 req, struct cli_shadow_copy_data_state);
5944 char **names;
5945 int i, num_names;
5946 uint32_t dlength;
5947 NTSTATUS status;
5949 if (tevent_req_is_nterror(req, &status)) {
5950 return status;
5952 num_names = IVAL(state->data, 4);
5953 dlength = IVAL(state->data, 8);
5955 if (!state->get_names) {
5956 *pnum_names = num_names;
5957 return NT_STATUS_OK;
5960 if (dlength+12 > state->num_data) {
5961 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5963 names = talloc_array(mem_ctx, char *, num_names);
5964 if (names == NULL) {
5965 return NT_STATUS_NO_MEMORY;
5968 for (i=0; i<num_names; i++) {
5969 bool ret;
5970 uint8_t *src;
5971 size_t converted_size;
5973 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
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 = 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 = talloc_stackframe();
5993 struct tevent_context *ev;
5994 struct tevent_req *req;
5995 NTSTATUS status = NT_STATUS_NO_MEMORY;
5997 if (smbXcli_conn_has_async_calls(cli->conn)) {
5999 * Can't use sync call while an async call is in flight
6001 status = NT_STATUS_INVALID_PARAMETER;
6002 goto fail;
6004 ev = samba_tevent_context_init(frame);
6005 if (ev == NULL) {
6006 goto fail;
6008 req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
6009 if (req == NULL) {
6010 goto fail;
6012 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6013 goto fail;
6015 status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
6016 fail:
6017 TALLOC_FREE(frame);
6018 return status;