s4:libcli/util/nterr: NO_S4U_PROT_SUPPORT and CROSSREALM_DELEGATION_FAILURE
[Samba.git] / source3 / libsmb / clifile.c
blob7b39f5076a102ff879f065e336b49c1045f79305
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 "../lib/util/tevent_ntstatus.h"
24 #include "async_smb.h"
25 #include "libsmb/clirap.h"
26 #include "trans2.h"
27 #include "ntioctl.h"
29 /***********************************************************
30 Common function for pushing stings, used by smb_bytes_push_str()
31 and trans_bytes_push_str(). Only difference is the align_odd
32 parameter setting.
33 ***********************************************************/
35 static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
36 const char *str, size_t str_len,
37 bool align_odd,
38 size_t *pconverted_size)
40 size_t buflen;
41 char *converted;
42 size_t converted_size;
44 if (buf == NULL) {
45 return NULL;
48 buflen = talloc_get_size(buf);
50 if (align_odd && ucs2 && (buflen % 2 == 0)) {
52 * We're pushing into an SMB buffer, align odd
54 buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
55 if (buf == NULL) {
56 return NULL;
58 buf[buflen] = '\0';
59 buflen += 1;
62 if (!convert_string_talloc(talloc_tos(), CH_UNIX,
63 ucs2 ? CH_UTF16LE : CH_DOS,
64 str, str_len, &converted,
65 &converted_size, true)) {
66 return NULL;
69 buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
70 buflen + converted_size);
71 if (buf == NULL) {
72 TALLOC_FREE(converted);
73 return NULL;
76 memcpy(buf + buflen, converted, converted_size);
78 TALLOC_FREE(converted);
80 if (pconverted_size) {
81 *pconverted_size = converted_size;
84 return buf;
87 /***********************************************************
88 Push a string into an SMB buffer, with odd byte alignment
89 if it's a UCS2 string.
90 ***********************************************************/
92 uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
93 const char *str, size_t str_len,
94 size_t *pconverted_size)
96 return internal_bytes_push_str(buf, ucs2, str, str_len,
97 true, pconverted_size);
100 uint8_t *smb_bytes_push_bytes(uint8_t *buf, uint8_t prefix,
101 const uint8_t *bytes, size_t num_bytes)
103 size_t buflen;
105 if (buf == NULL) {
106 return NULL;
108 buflen = talloc_get_size(buf);
110 buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
111 buflen + 1 + num_bytes);
112 if (buf == NULL) {
113 return NULL;
115 buf[buflen] = prefix;
116 memcpy(&buf[buflen+1], bytes, num_bytes);
117 return buf;
120 /***********************************************************
121 Same as smb_bytes_push_str(), but without the odd byte
122 align for ucs2 (we're pushing into a param or data block).
123 static for now, although this will probably change when
124 other modules use async trans calls.
125 ***********************************************************/
127 static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
128 const char *str, size_t str_len,
129 size_t *pconverted_size)
131 return internal_bytes_push_str(buf, ucs2, str, str_len,
132 false, pconverted_size);
135 struct cli_setpathinfo_state {
136 uint16_t setup;
137 uint8_t *param;
140 static void cli_setpathinfo_done(struct tevent_req *subreq);
142 struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
143 struct tevent_context *ev,
144 struct cli_state *cli,
145 uint16_t level,
146 const char *path,
147 uint8_t *data,
148 size_t data_len)
150 struct tevent_req *req, *subreq;
151 struct cli_setpathinfo_state *state;
153 req = tevent_req_create(mem_ctx, &state,
154 struct cli_setpathinfo_state);
155 if (req == NULL) {
156 return NULL;
159 /* Setup setup word. */
160 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
162 /* Setup param array. */
163 state->param = TALLOC_ZERO_ARRAY(state, uint8_t, 6);
164 if (tevent_req_nomem(state->param, req)) {
165 return tevent_req_post(req, ev);
167 SSVAL(state->param, 0, level);
169 state->param = trans2_bytes_push_str(
170 state->param, cli_ucs2(cli), path, strlen(path)+1, NULL);
171 if (tevent_req_nomem(state->param, req)) {
172 return tevent_req_post(req, ev);
175 subreq = cli_trans_send(
176 state, /* mem ctx. */
177 ev, /* event ctx. */
178 cli, /* cli_state. */
179 SMBtrans2, /* cmd. */
180 NULL, /* pipe name. */
181 -1, /* fid. */
182 0, /* function. */
183 0, /* flags. */
184 &state->setup, /* setup. */
185 1, /* num setup uint16_t words. */
186 0, /* max returned setup. */
187 state->param, /* param. */
188 talloc_get_size(state->param), /* num param. */
189 2, /* max returned param. */
190 data, /* data. */
191 data_len, /* num data. */
192 0); /* max returned data. */
194 if (tevent_req_nomem(subreq, req)) {
195 return tevent_req_post(req, ev);
197 tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
198 return req;
201 static void cli_setpathinfo_done(struct tevent_req *subreq)
203 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
204 NULL, 0, NULL, NULL, 0, NULL);
205 tevent_req_simple_finish_ntstatus(subreq, status);
208 NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
210 return tevent_req_simple_recv_ntstatus(req);
213 NTSTATUS cli_setpathinfo(struct cli_state *cli,
214 uint16_t level,
215 const char *path,
216 uint8_t *data,
217 size_t data_len)
219 TALLOC_CTX *frame = talloc_stackframe();
220 struct tevent_context *ev;
221 struct tevent_req *req;
222 NTSTATUS status = NT_STATUS_NO_MEMORY;
224 if (cli_has_async_calls(cli)) {
226 * Can't use sync call while an async call is in flight
228 status = NT_STATUS_INVALID_PARAMETER;
229 goto fail;
231 ev = tevent_context_init(frame);
232 if (ev == NULL) {
233 goto fail;
235 req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
236 if (req == NULL) {
237 goto fail;
239 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
240 goto fail;
242 status = cli_setpathinfo_recv(req);
243 fail:
244 TALLOC_FREE(frame);
245 return status;
248 /****************************************************************************
249 Hard/Symlink a file (UNIX extensions).
250 Creates new name (sym)linked to oldname.
251 ****************************************************************************/
253 struct cli_posix_link_internal_state {
254 uint8_t *data;
257 static void cli_posix_link_internal_done(struct tevent_req *subreq);
259 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
260 struct event_context *ev,
261 struct cli_state *cli,
262 uint16_t level,
263 const char *oldname,
264 const char *newname)
266 struct tevent_req *req = NULL, *subreq = NULL;
267 struct cli_posix_link_internal_state *state = NULL;
269 req = tevent_req_create(mem_ctx, &state,
270 struct cli_posix_link_internal_state);
271 if (req == NULL) {
272 return NULL;
275 /* Setup data array. */
276 state->data = talloc_array(state, uint8_t, 0);
277 if (tevent_req_nomem(state->data, req)) {
278 return tevent_req_post(req, ev);
280 state->data = trans2_bytes_push_str(
281 state->data, cli_ucs2(cli), oldname, strlen(oldname)+1, NULL);
283 subreq = cli_setpathinfo_send(
284 state, ev, cli, level, newname,
285 state->data, talloc_get_size(state->data));
286 if (tevent_req_nomem(subreq, req)) {
287 return tevent_req_post(req, ev);
289 tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
290 return req;
293 static void cli_posix_link_internal_done(struct tevent_req *subreq)
295 NTSTATUS status = cli_setpathinfo_recv(subreq);
296 tevent_req_simple_finish_ntstatus(subreq, status);
299 /****************************************************************************
300 Symlink a file (UNIX extensions).
301 ****************************************************************************/
303 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
304 struct event_context *ev,
305 struct cli_state *cli,
306 const char *oldname,
307 const char *newname)
309 return cli_posix_link_internal_send(
310 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, oldname, newname);
313 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
315 return tevent_req_simple_recv_ntstatus(req);
318 NTSTATUS cli_posix_symlink(struct cli_state *cli,
319 const char *oldname,
320 const char *newname)
322 TALLOC_CTX *frame = talloc_stackframe();
323 struct event_context *ev = NULL;
324 struct tevent_req *req = NULL;
325 NTSTATUS status = NT_STATUS_OK;
327 if (cli_has_async_calls(cli)) {
329 * Can't use sync call while an async call is in flight
331 status = NT_STATUS_INVALID_PARAMETER;
332 goto fail;
335 ev = event_context_init(frame);
336 if (ev == NULL) {
337 status = NT_STATUS_NO_MEMORY;
338 goto fail;
341 req = cli_posix_symlink_send(frame,
343 cli,
344 oldname,
345 newname);
346 if (req == NULL) {
347 status = NT_STATUS_NO_MEMORY;
348 goto fail;
351 if (!tevent_req_poll(req, ev)) {
352 status = map_nt_error_from_unix(errno);
353 goto fail;
356 status = cli_posix_symlink_recv(req);
358 fail:
359 TALLOC_FREE(frame);
360 if (!NT_STATUS_IS_OK(status)) {
361 cli_set_error(cli, status);
363 return status;
366 /****************************************************************************
367 Read a POSIX symlink.
368 ****************************************************************************/
370 struct readlink_state {
371 uint8_t *data;
372 uint32_t num_data;
375 static void cli_posix_readlink_done(struct tevent_req *subreq);
377 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
378 struct event_context *ev,
379 struct cli_state *cli,
380 const char *fname,
381 size_t len)
383 struct tevent_req *req = NULL, *subreq = NULL;
384 struct readlink_state *state = NULL;
385 uint32_t maxbytelen = (uint32_t)(cli_ucs2(cli) ? len*3 : len);
387 req = tevent_req_create(mem_ctx, &state, struct readlink_state);
388 if (req == NULL) {
389 return NULL;
393 * Len is in bytes, we need it in UCS2 units.
395 if ((2*len < len) || (maxbytelen < len)) {
396 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
397 return tevent_req_post(req, ev);
400 subreq = cli_qpathinfo_send(state, ev, cli, fname,
401 SMB_QUERY_FILE_UNIX_LINK, 1, maxbytelen);
402 if (tevent_req_nomem(subreq, req)) {
403 return tevent_req_post(req, ev);
405 tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
406 return req;
409 static void cli_posix_readlink_done(struct tevent_req *subreq)
411 struct tevent_req *req = tevent_req_callback_data(
412 subreq, struct tevent_req);
413 struct readlink_state *state = tevent_req_data(
414 req, struct readlink_state);
415 NTSTATUS status;
417 status = cli_qpathinfo_recv(subreq, state, &state->data,
418 &state->num_data);
419 TALLOC_FREE(subreq);
420 if (!NT_STATUS_IS_OK(status)) {
421 tevent_req_nterror(req, status);
422 return;
425 * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
427 if (state->data[state->num_data-1] != '\0') {
428 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
429 return;
431 tevent_req_done(req);
434 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
435 char *retpath, size_t len)
437 NTSTATUS status;
438 char *converted = NULL;
439 size_t converted_size = 0;
440 struct readlink_state *state = tevent_req_data(req, struct readlink_state);
442 if (tevent_req_is_nterror(req, &status)) {
443 return status;
445 /* The returned data is a pushed string, not raw data. */
446 if (!convert_string_talloc(state,
447 cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
448 CH_UNIX,
449 state->data,
450 state->num_data,
451 &converted,
452 &converted_size,
453 true)) {
454 return NT_STATUS_NO_MEMORY;
457 len = MIN(len,converted_size);
458 if (len == 0) {
459 return NT_STATUS_DATA_ERROR;
461 memcpy(retpath, converted, len);
462 return NT_STATUS_OK;
465 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
466 char *linkpath, size_t len)
468 TALLOC_CTX *frame = talloc_stackframe();
469 struct event_context *ev = NULL;
470 struct tevent_req *req = NULL;
471 NTSTATUS status = NT_STATUS_OK;
473 if (cli_has_async_calls(cli)) {
475 * Can't use sync call while an async call is in flight
477 status = NT_STATUS_INVALID_PARAMETER;
478 goto fail;
481 ev = event_context_init(frame);
482 if (ev == NULL) {
483 status = NT_STATUS_NO_MEMORY;
484 goto fail;
487 req = cli_posix_readlink_send(frame,
489 cli,
490 fname,
491 len);
492 if (req == NULL) {
493 status = NT_STATUS_NO_MEMORY;
494 goto fail;
497 if (!tevent_req_poll(req, ev)) {
498 status = map_nt_error_from_unix(errno);
499 goto fail;
502 status = cli_posix_readlink_recv(req, cli, linkpath, len);
504 fail:
505 TALLOC_FREE(frame);
506 if (!NT_STATUS_IS_OK(status)) {
507 cli_set_error(cli, status);
509 return status;
512 /****************************************************************************
513 Hard link a file (UNIX extensions).
514 ****************************************************************************/
516 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
517 struct event_context *ev,
518 struct cli_state *cli,
519 const char *oldname,
520 const char *newname)
522 return cli_posix_link_internal_send(
523 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
526 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
528 return tevent_req_simple_recv_ntstatus(req);
531 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
532 const char *oldname,
533 const char *newname)
535 TALLOC_CTX *frame = talloc_stackframe();
536 struct event_context *ev = NULL;
537 struct tevent_req *req = NULL;
538 NTSTATUS status = NT_STATUS_OK;
540 if (cli_has_async_calls(cli)) {
542 * Can't use sync call while an async call is in flight
544 status = NT_STATUS_INVALID_PARAMETER;
545 goto fail;
548 ev = event_context_init(frame);
549 if (ev == NULL) {
550 status = NT_STATUS_NO_MEMORY;
551 goto fail;
554 req = cli_posix_hardlink_send(frame,
556 cli,
557 oldname,
558 newname);
559 if (req == NULL) {
560 status = NT_STATUS_NO_MEMORY;
561 goto fail;
564 if (!tevent_req_poll(req, ev)) {
565 status = map_nt_error_from_unix(errno);
566 goto fail;
569 status = cli_posix_hardlink_recv(req);
571 fail:
572 TALLOC_FREE(frame);
573 if (!NT_STATUS_IS_OK(status)) {
574 cli_set_error(cli, status);
576 return status;
579 /****************************************************************************
580 Map standard UNIX permissions onto wire representations.
581 ****************************************************************************/
583 uint32_t unix_perms_to_wire(mode_t perms)
585 unsigned int ret = 0;
587 ret |= ((perms & S_IXOTH) ? UNIX_X_OTH : 0);
588 ret |= ((perms & S_IWOTH) ? UNIX_W_OTH : 0);
589 ret |= ((perms & S_IROTH) ? UNIX_R_OTH : 0);
590 ret |= ((perms & S_IXGRP) ? UNIX_X_GRP : 0);
591 ret |= ((perms & S_IWGRP) ? UNIX_W_GRP : 0);
592 ret |= ((perms & S_IRGRP) ? UNIX_R_GRP : 0);
593 ret |= ((perms & S_IXUSR) ? UNIX_X_USR : 0);
594 ret |= ((perms & S_IWUSR) ? UNIX_W_USR : 0);
595 ret |= ((perms & S_IRUSR) ? UNIX_R_USR : 0);
596 #ifdef S_ISVTX
597 ret |= ((perms & S_ISVTX) ? UNIX_STICKY : 0);
598 #endif
599 #ifdef S_ISGID
600 ret |= ((perms & S_ISGID) ? UNIX_SET_GID : 0);
601 #endif
602 #ifdef S_ISUID
603 ret |= ((perms & S_ISUID) ? UNIX_SET_UID : 0);
604 #endif
605 return ret;
608 /****************************************************************************
609 Map wire permissions to standard UNIX.
610 ****************************************************************************/
612 mode_t wire_perms_to_unix(uint32_t perms)
614 mode_t ret = (mode_t)0;
616 ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
617 ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
618 ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
619 ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
620 ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
621 ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
622 ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
623 ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
624 ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
625 #ifdef S_ISVTX
626 ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
627 #endif
628 #ifdef S_ISGID
629 ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
630 #endif
631 #ifdef S_ISUID
632 ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
633 #endif
634 return ret;
637 /****************************************************************************
638 Return the file type from the wire filetype for UNIX extensions.
639 ****************************************************************************/
641 static mode_t unix_filetype_from_wire(uint32_t wire_type)
643 switch (wire_type) {
644 case UNIX_TYPE_FILE:
645 return S_IFREG;
646 case UNIX_TYPE_DIR:
647 return S_IFDIR;
648 #ifdef S_IFLNK
649 case UNIX_TYPE_SYMLINK:
650 return S_IFLNK;
651 #endif
652 #ifdef S_IFCHR
653 case UNIX_TYPE_CHARDEV:
654 return S_IFCHR;
655 #endif
656 #ifdef S_IFBLK
657 case UNIX_TYPE_BLKDEV:
658 return S_IFBLK;
659 #endif
660 #ifdef S_IFIFO
661 case UNIX_TYPE_FIFO:
662 return S_IFIFO;
663 #endif
664 #ifdef S_IFSOCK
665 case UNIX_TYPE_SOCKET:
666 return S_IFSOCK;
667 #endif
668 default:
669 return (mode_t)0;
673 /****************************************************************************
674 Do a POSIX getfacl (UNIX extensions).
675 ****************************************************************************/
677 struct getfacl_state {
678 uint32_t num_data;
679 uint8_t *data;
682 static void cli_posix_getfacl_done(struct tevent_req *subreq);
684 struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
685 struct event_context *ev,
686 struct cli_state *cli,
687 const char *fname)
689 struct tevent_req *req = NULL, *subreq = NULL;
690 struct getfacl_state *state = NULL;
692 req = tevent_req_create(mem_ctx, &state, struct getfacl_state);
693 if (req == NULL) {
694 return NULL;
696 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
697 0, cli->max_xmit);
698 if (tevent_req_nomem(subreq, req)) {
699 return tevent_req_post(req, ev);
701 tevent_req_set_callback(subreq, cli_posix_getfacl_done, req);
702 return req;
705 static void cli_posix_getfacl_done(struct tevent_req *subreq)
707 struct tevent_req *req = tevent_req_callback_data(
708 subreq, struct tevent_req);
709 struct getfacl_state *state = tevent_req_data(
710 req, struct getfacl_state);
711 NTSTATUS status;
713 status = cli_qpathinfo_recv(subreq, state, &state->data,
714 &state->num_data);
715 TALLOC_FREE(subreq);
716 if (!NT_STATUS_IS_OK(status)) {
717 tevent_req_nterror(req, status);
718 return;
720 tevent_req_done(req);
723 NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
724 TALLOC_CTX *mem_ctx,
725 size_t *prb_size,
726 char **retbuf)
728 struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
729 NTSTATUS status;
731 if (tevent_req_is_nterror(req, &status)) {
732 return status;
734 *prb_size = (size_t)state->num_data;
735 *retbuf = (char *)talloc_move(mem_ctx, &state->data);
736 return NT_STATUS_OK;
739 NTSTATUS cli_posix_getfacl(struct cli_state *cli,
740 const char *fname,
741 TALLOC_CTX *mem_ctx,
742 size_t *prb_size,
743 char **retbuf)
745 TALLOC_CTX *frame = talloc_stackframe();
746 struct event_context *ev = NULL;
747 struct tevent_req *req = NULL;
748 NTSTATUS status = NT_STATUS_OK;
750 if (cli_has_async_calls(cli)) {
752 * Can't use sync call while an async call is in flight
754 status = NT_STATUS_INVALID_PARAMETER;
755 goto fail;
758 ev = event_context_init(frame);
759 if (ev == NULL) {
760 status = NT_STATUS_NO_MEMORY;
761 goto fail;
764 req = cli_posix_getfacl_send(frame,
766 cli,
767 fname);
768 if (req == NULL) {
769 status = NT_STATUS_NO_MEMORY;
770 goto fail;
773 if (!tevent_req_poll(req, ev)) {
774 status = map_nt_error_from_unix(errno);
775 goto fail;
778 status = cli_posix_getfacl_recv(req, mem_ctx, prb_size, retbuf);
780 fail:
781 TALLOC_FREE(frame);
782 if (!NT_STATUS_IS_OK(status)) {
783 cli_set_error(cli, status);
785 return status;
788 /****************************************************************************
789 Stat a file (UNIX extensions).
790 ****************************************************************************/
792 struct stat_state {
793 uint32_t num_data;
794 uint8_t *data;
797 static void cli_posix_stat_done(struct tevent_req *subreq);
799 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
800 struct event_context *ev,
801 struct cli_state *cli,
802 const char *fname)
804 struct tevent_req *req = NULL, *subreq = NULL;
805 struct stat_state *state = NULL;
807 req = tevent_req_create(mem_ctx, &state, struct stat_state);
808 if (req == NULL) {
809 return NULL;
811 subreq = cli_qpathinfo_send(state, ev, cli, fname,
812 SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
813 if (tevent_req_nomem(subreq, req)) {
814 return tevent_req_post(req, ev);
816 tevent_req_set_callback(subreq, cli_posix_stat_done, req);
817 return req;
820 static void cli_posix_stat_done(struct tevent_req *subreq)
822 struct tevent_req *req = tevent_req_callback_data(
823 subreq, struct tevent_req);
824 struct stat_state *state = tevent_req_data(req, struct stat_state);
825 NTSTATUS status;
827 status = cli_qpathinfo_recv(subreq, state, &state->data,
828 &state->num_data);
829 TALLOC_FREE(subreq);
830 if (!NT_STATUS_IS_OK(status)) {
831 tevent_req_nterror(req, status);
832 return;
834 tevent_req_done(req);
837 NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
838 SMB_STRUCT_STAT *sbuf)
840 struct stat_state *state = tevent_req_data(req, struct stat_state);
841 NTSTATUS status;
843 if (tevent_req_is_nterror(req, &status)) {
844 return status;
847 sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0); /* total size, in bytes */
848 sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8); /* number of blocks allocated */
849 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
850 sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
851 #else
852 /* assume 512 byte blocks */
853 sbuf->st_ex_blocks /= 512;
854 #endif
855 sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16)); /* time of last change */
856 sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24)); /* time of last access */
857 sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32)); /* time of last modification */
859 sbuf->st_ex_uid = (uid_t) IVAL(state->data,40); /* user ID of owner */
860 sbuf->st_ex_gid = (gid_t) IVAL(state->data,48); /* group ID of owner */
861 sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
862 #if defined(HAVE_MAKEDEV)
864 uint32_t dev_major = IVAL(state->data,60);
865 uint32_t dev_minor = IVAL(state->data,68);
866 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
868 #endif
869 sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76); /* inode */
870 sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84)); /* protection */
871 sbuf->st_ex_nlink = BIG_UINT(state->data,92); /* number of hard links */
873 return NT_STATUS_OK;
876 NTSTATUS cli_posix_stat(struct cli_state *cli,
877 const char *fname,
878 SMB_STRUCT_STAT *sbuf)
880 TALLOC_CTX *frame = talloc_stackframe();
881 struct event_context *ev = NULL;
882 struct tevent_req *req = NULL;
883 NTSTATUS status = NT_STATUS_OK;
885 if (cli_has_async_calls(cli)) {
887 * Can't use sync call while an async call is in flight
889 status = NT_STATUS_INVALID_PARAMETER;
890 goto fail;
893 ev = event_context_init(frame);
894 if (ev == NULL) {
895 status = NT_STATUS_NO_MEMORY;
896 goto fail;
899 req = cli_posix_stat_send(frame,
901 cli,
902 fname);
903 if (req == NULL) {
904 status = NT_STATUS_NO_MEMORY;
905 goto fail;
908 if (!tevent_req_poll(req, ev)) {
909 status = map_nt_error_from_unix(errno);
910 goto fail;
913 status = cli_posix_stat_recv(req, sbuf);
915 fail:
916 TALLOC_FREE(frame);
917 if (!NT_STATUS_IS_OK(status)) {
918 cli_set_error(cli, status);
920 return status;
923 /****************************************************************************
924 Chmod or chown a file internal (UNIX extensions).
925 ****************************************************************************/
927 struct cli_posix_chown_chmod_internal_state {
928 uint8_t data[100];
931 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
933 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
934 struct event_context *ev,
935 struct cli_state *cli,
936 const char *fname,
937 uint32_t mode,
938 uint32_t uid,
939 uint32_t gid)
941 struct tevent_req *req = NULL, *subreq = NULL;
942 struct cli_posix_chown_chmod_internal_state *state = NULL;
944 req = tevent_req_create(mem_ctx, &state,
945 struct cli_posix_chown_chmod_internal_state);
946 if (req == NULL) {
947 return NULL;
950 memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
951 memset(&state->data[40], '\0', 60);
952 SIVAL(state->data,40,uid);
953 SIVAL(state->data,48,gid);
954 SIVAL(state->data,84,mode);
956 subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
957 fname, state->data, sizeof(state->data));
958 if (tevent_req_nomem(subreq, req)) {
959 return tevent_req_post(req, ev);
961 tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
962 req);
963 return req;
966 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
968 NTSTATUS status = cli_setpathinfo_recv(subreq);
969 tevent_req_simple_finish_ntstatus(subreq, status);
972 /****************************************************************************
973 chmod a file (UNIX extensions).
974 ****************************************************************************/
976 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
977 struct event_context *ev,
978 struct cli_state *cli,
979 const char *fname,
980 mode_t mode)
982 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
983 fname,
984 unix_perms_to_wire(mode),
985 SMB_UID_NO_CHANGE,
986 SMB_GID_NO_CHANGE);
989 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
991 return tevent_req_simple_recv_ntstatus(req);
994 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
996 TALLOC_CTX *frame = talloc_stackframe();
997 struct event_context *ev = NULL;
998 struct tevent_req *req = NULL;
999 NTSTATUS status = NT_STATUS_OK;
1001 if (cli_has_async_calls(cli)) {
1003 * Can't use sync call while an async call is in flight
1005 status = NT_STATUS_INVALID_PARAMETER;
1006 goto fail;
1009 ev = event_context_init(frame);
1010 if (ev == NULL) {
1011 status = NT_STATUS_NO_MEMORY;
1012 goto fail;
1015 req = cli_posix_chmod_send(frame,
1017 cli,
1018 fname,
1019 mode);
1020 if (req == NULL) {
1021 status = NT_STATUS_NO_MEMORY;
1022 goto fail;
1025 if (!tevent_req_poll(req, ev)) {
1026 status = map_nt_error_from_unix(errno);
1027 goto fail;
1030 status = cli_posix_chmod_recv(req);
1032 fail:
1033 TALLOC_FREE(frame);
1034 if (!NT_STATUS_IS_OK(status)) {
1035 cli_set_error(cli, status);
1037 return status;
1040 /****************************************************************************
1041 chown a file (UNIX extensions).
1042 ****************************************************************************/
1044 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1045 struct event_context *ev,
1046 struct cli_state *cli,
1047 const char *fname,
1048 uid_t uid,
1049 gid_t gid)
1051 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
1052 fname,
1053 SMB_MODE_NO_CHANGE,
1054 (uint32_t)uid,
1055 (uint32_t)gid);
1058 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1060 return tevent_req_simple_recv_ntstatus(req);
1063 NTSTATUS cli_posix_chown(struct cli_state *cli,
1064 const char *fname,
1065 uid_t uid,
1066 gid_t gid)
1068 TALLOC_CTX *frame = talloc_stackframe();
1069 struct event_context *ev = NULL;
1070 struct tevent_req *req = NULL;
1071 NTSTATUS status = NT_STATUS_OK;
1073 if (cli_has_async_calls(cli)) {
1075 * Can't use sync call while an async call is in flight
1077 status = NT_STATUS_INVALID_PARAMETER;
1078 goto fail;
1081 ev = event_context_init(frame);
1082 if (ev == NULL) {
1083 status = NT_STATUS_NO_MEMORY;
1084 goto fail;
1087 req = cli_posix_chown_send(frame,
1089 cli,
1090 fname,
1091 uid,
1092 gid);
1093 if (req == NULL) {
1094 status = NT_STATUS_NO_MEMORY;
1095 goto fail;
1098 if (!tevent_req_poll(req, ev)) {
1099 status = map_nt_error_from_unix(errno);
1100 goto fail;
1103 status = cli_posix_chown_recv(req);
1105 fail:
1106 TALLOC_FREE(frame);
1107 if (!NT_STATUS_IS_OK(status)) {
1108 cli_set_error(cli, status);
1110 return status;
1113 /****************************************************************************
1114 Rename a file.
1115 ****************************************************************************/
1117 static void cli_rename_done(struct tevent_req *subreq);
1119 struct cli_rename_state {
1120 uint16_t vwv[1];
1123 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1124 struct event_context *ev,
1125 struct cli_state *cli,
1126 const char *fname_src,
1127 const char *fname_dst)
1129 struct tevent_req *req = NULL, *subreq = NULL;
1130 struct cli_rename_state *state = NULL;
1131 uint8_t additional_flags = 0;
1132 uint8_t *bytes = NULL;
1134 req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1135 if (req == NULL) {
1136 return NULL;
1139 SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1141 bytes = talloc_array(state, uint8_t, 1);
1142 if (tevent_req_nomem(bytes, req)) {
1143 return tevent_req_post(req, ev);
1145 bytes[0] = 4;
1146 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1147 strlen(fname_src)+1, NULL);
1148 if (tevent_req_nomem(bytes, req)) {
1149 return tevent_req_post(req, ev);
1152 bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1153 talloc_get_size(bytes)+1);
1154 if (tevent_req_nomem(bytes, req)) {
1155 return tevent_req_post(req, ev);
1158 bytes[talloc_get_size(bytes)-1] = 4;
1159 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1160 strlen(fname_dst)+1, NULL);
1161 if (tevent_req_nomem(bytes, req)) {
1162 return tevent_req_post(req, ev);
1165 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1166 1, state->vwv, talloc_get_size(bytes), bytes);
1167 if (tevent_req_nomem(subreq, req)) {
1168 return tevent_req_post(req, ev);
1170 tevent_req_set_callback(subreq, cli_rename_done, req);
1171 return req;
1174 static void cli_rename_done(struct tevent_req *subreq)
1176 struct tevent_req *req = tevent_req_callback_data(
1177 subreq, struct tevent_req);
1178 NTSTATUS status;
1180 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1181 TALLOC_FREE(subreq);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 tevent_req_nterror(req, status);
1184 return;
1186 tevent_req_done(req);
1189 NTSTATUS cli_rename_recv(struct tevent_req *req)
1191 return tevent_req_simple_recv_ntstatus(req);
1194 NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1196 TALLOC_CTX *frame = talloc_stackframe();
1197 struct event_context *ev;
1198 struct tevent_req *req;
1199 NTSTATUS status = NT_STATUS_OK;
1201 if (cli_has_async_calls(cli)) {
1203 * Can't use sync call while an async call is in flight
1205 status = NT_STATUS_INVALID_PARAMETER;
1206 goto fail;
1209 ev = event_context_init(frame);
1210 if (ev == NULL) {
1211 status = NT_STATUS_NO_MEMORY;
1212 goto fail;
1215 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
1216 if (req == NULL) {
1217 status = NT_STATUS_NO_MEMORY;
1218 goto fail;
1221 if (!tevent_req_poll(req, ev)) {
1222 status = map_nt_error_from_unix(errno);
1223 goto fail;
1226 status = cli_rename_recv(req);
1228 fail:
1229 TALLOC_FREE(frame);
1230 if (!NT_STATUS_IS_OK(status)) {
1231 cli_set_error(cli, status);
1233 return status;
1236 /****************************************************************************
1237 NT Rename a file.
1238 ****************************************************************************/
1240 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1242 struct cli_ntrename_internal_state {
1243 uint16_t vwv[4];
1246 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1247 struct event_context *ev,
1248 struct cli_state *cli,
1249 const char *fname_src,
1250 const char *fname_dst,
1251 uint16_t rename_flag)
1253 struct tevent_req *req = NULL, *subreq = NULL;
1254 struct cli_ntrename_internal_state *state = NULL;
1255 uint8_t additional_flags = 0;
1256 uint8_t *bytes = NULL;
1258 req = tevent_req_create(mem_ctx, &state,
1259 struct cli_ntrename_internal_state);
1260 if (req == NULL) {
1261 return NULL;
1264 SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1265 SSVAL(state->vwv+1, 0, rename_flag);
1267 bytes = talloc_array(state, uint8_t, 1);
1268 if (tevent_req_nomem(bytes, req)) {
1269 return tevent_req_post(req, ev);
1271 bytes[0] = 4;
1272 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1273 strlen(fname_src)+1, NULL);
1274 if (tevent_req_nomem(bytes, req)) {
1275 return tevent_req_post(req, ev);
1278 bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1279 talloc_get_size(bytes)+1);
1280 if (tevent_req_nomem(bytes, req)) {
1281 return tevent_req_post(req, ev);
1284 bytes[talloc_get_size(bytes)-1] = 4;
1285 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1286 strlen(fname_dst)+1, NULL);
1287 if (tevent_req_nomem(bytes, req)) {
1288 return tevent_req_post(req, ev);
1291 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1292 4, state->vwv, talloc_get_size(bytes), bytes);
1293 if (tevent_req_nomem(subreq, req)) {
1294 return tevent_req_post(req, ev);
1296 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1297 return req;
1300 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1302 struct tevent_req *req = tevent_req_callback_data(
1303 subreq, struct tevent_req);
1304 NTSTATUS status;
1306 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1307 TALLOC_FREE(subreq);
1308 if (!NT_STATUS_IS_OK(status)) {
1309 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 event_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 event_context *ev;
1343 struct tevent_req *req;
1344 NTSTATUS status = NT_STATUS_OK;
1346 if (cli_has_async_calls(cli)) {
1348 * Can't use sync call while an async call is in flight
1350 status = NT_STATUS_INVALID_PARAMETER;
1351 goto fail;
1354 ev = event_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(req, ev)) {
1367 status = map_nt_error_from_unix(errno);
1368 goto fail;
1371 status = cli_ntrename_recv(req);
1373 fail:
1374 TALLOC_FREE(frame);
1375 if (!NT_STATUS_IS_OK(status)) {
1376 cli_set_error(cli, status);
1378 return status;
1381 /****************************************************************************
1382 NT hardlink a file.
1383 ****************************************************************************/
1385 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1386 struct event_context *ev,
1387 struct cli_state *cli,
1388 const char *fname_src,
1389 const char *fname_dst)
1391 return cli_ntrename_internal_send(mem_ctx,
1393 cli,
1394 fname_src,
1395 fname_dst,
1396 RENAME_FLAG_HARD_LINK);
1399 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1401 return cli_ntrename_internal_recv(req);
1404 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1406 TALLOC_CTX *frame = talloc_stackframe();
1407 struct event_context *ev;
1408 struct tevent_req *req;
1409 NTSTATUS status = NT_STATUS_OK;
1411 if (cli_has_async_calls(cli)) {
1413 * Can't use sync call while an async call is in flight
1415 status = NT_STATUS_INVALID_PARAMETER;
1416 goto fail;
1419 ev = event_context_init(frame);
1420 if (ev == NULL) {
1421 status = NT_STATUS_NO_MEMORY;
1422 goto fail;
1425 req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1426 if (req == NULL) {
1427 status = NT_STATUS_NO_MEMORY;
1428 goto fail;
1431 if (!tevent_req_poll(req, ev)) {
1432 status = map_nt_error_from_unix(errno);
1433 goto fail;
1436 status = cli_nt_hardlink_recv(req);
1438 fail:
1439 TALLOC_FREE(frame);
1440 if (!NT_STATUS_IS_OK(status)) {
1441 cli_set_error(cli, status);
1443 return status;
1446 /****************************************************************************
1447 Delete a file.
1448 ****************************************************************************/
1450 static void cli_unlink_done(struct tevent_req *subreq);
1452 struct cli_unlink_state {
1453 uint16_t vwv[1];
1456 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1457 struct event_context *ev,
1458 struct cli_state *cli,
1459 const char *fname,
1460 uint16_t mayhave_attrs)
1462 struct tevent_req *req = NULL, *subreq = NULL;
1463 struct cli_unlink_state *state = NULL;
1464 uint8_t additional_flags = 0;
1465 uint8_t *bytes = NULL;
1467 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1468 if (req == NULL) {
1469 return NULL;
1472 SSVAL(state->vwv+0, 0, mayhave_attrs);
1474 bytes = talloc_array(state, uint8_t, 1);
1475 if (tevent_req_nomem(bytes, req)) {
1476 return tevent_req_post(req, ev);
1478 bytes[0] = 4;
1479 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
1480 strlen(fname)+1, NULL);
1482 if (tevent_req_nomem(bytes, req)) {
1483 return tevent_req_post(req, ev);
1486 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1487 1, state->vwv, talloc_get_size(bytes), bytes);
1488 if (tevent_req_nomem(subreq, req)) {
1489 return tevent_req_post(req, ev);
1491 tevent_req_set_callback(subreq, cli_unlink_done, req);
1492 return req;
1495 static void cli_unlink_done(struct tevent_req *subreq)
1497 struct tevent_req *req = tevent_req_callback_data(
1498 subreq, struct tevent_req);
1499 NTSTATUS status;
1501 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1502 TALLOC_FREE(subreq);
1503 if (!NT_STATUS_IS_OK(status)) {
1504 tevent_req_nterror(req, status);
1505 return;
1507 tevent_req_done(req);
1510 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1512 return tevent_req_simple_recv_ntstatus(req);
1515 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1517 TALLOC_CTX *frame = talloc_stackframe();
1518 struct event_context *ev;
1519 struct tevent_req *req;
1520 NTSTATUS status = NT_STATUS_OK;
1522 if (cli_has_async_calls(cli)) {
1524 * Can't use sync call while an async call is in flight
1526 status = NT_STATUS_INVALID_PARAMETER;
1527 goto fail;
1530 ev = event_context_init(frame);
1531 if (ev == NULL) {
1532 status = NT_STATUS_NO_MEMORY;
1533 goto fail;
1536 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1537 if (req == NULL) {
1538 status = NT_STATUS_NO_MEMORY;
1539 goto fail;
1542 if (!tevent_req_poll(req, ev)) {
1543 status = map_nt_error_from_unix(errno);
1544 goto fail;
1547 status = cli_unlink_recv(req);
1549 fail:
1550 TALLOC_FREE(frame);
1551 if (!NT_STATUS_IS_OK(status)) {
1552 cli_set_error(cli, status);
1554 return status;
1557 /****************************************************************************
1558 Create a directory.
1559 ****************************************************************************/
1561 static void cli_mkdir_done(struct tevent_req *subreq);
1563 struct cli_mkdir_state {
1564 int dummy;
1567 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1568 struct event_context *ev,
1569 struct cli_state *cli,
1570 const char *dname)
1572 struct tevent_req *req = NULL, *subreq = NULL;
1573 struct cli_mkdir_state *state = NULL;
1574 uint8_t additional_flags = 0;
1575 uint8_t *bytes = NULL;
1577 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1578 if (req == NULL) {
1579 return NULL;
1582 bytes = talloc_array(state, uint8_t, 1);
1583 if (tevent_req_nomem(bytes, req)) {
1584 return tevent_req_post(req, ev);
1586 bytes[0] = 4;
1587 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1588 strlen(dname)+1, NULL);
1590 if (tevent_req_nomem(bytes, req)) {
1591 return tevent_req_post(req, ev);
1594 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1595 0, NULL, talloc_get_size(bytes), bytes);
1596 if (tevent_req_nomem(subreq, req)) {
1597 return tevent_req_post(req, ev);
1599 tevent_req_set_callback(subreq, cli_mkdir_done, req);
1600 return req;
1603 static void cli_mkdir_done(struct tevent_req *subreq)
1605 struct tevent_req *req = tevent_req_callback_data(
1606 subreq, struct tevent_req);
1607 NTSTATUS status;
1609 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1610 TALLOC_FREE(subreq);
1611 if (!NT_STATUS_IS_OK(status)) {
1612 tevent_req_nterror(req, status);
1613 return;
1615 tevent_req_done(req);
1618 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1620 return tevent_req_simple_recv_ntstatus(req);
1623 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1625 TALLOC_CTX *frame = talloc_stackframe();
1626 struct event_context *ev;
1627 struct tevent_req *req;
1628 NTSTATUS status = NT_STATUS_OK;
1630 if (cli_has_async_calls(cli)) {
1632 * Can't use sync call while an async call is in flight
1634 status = NT_STATUS_INVALID_PARAMETER;
1635 goto fail;
1638 ev = event_context_init(frame);
1639 if (ev == NULL) {
1640 status = NT_STATUS_NO_MEMORY;
1641 goto fail;
1644 req = cli_mkdir_send(frame, ev, cli, dname);
1645 if (req == NULL) {
1646 status = NT_STATUS_NO_MEMORY;
1647 goto fail;
1650 if (!tevent_req_poll(req, ev)) {
1651 status = map_nt_error_from_unix(errno);
1652 goto fail;
1655 status = cli_mkdir_recv(req);
1657 fail:
1658 TALLOC_FREE(frame);
1659 if (!NT_STATUS_IS_OK(status)) {
1660 cli_set_error(cli, status);
1662 return status;
1665 /****************************************************************************
1666 Remove a directory.
1667 ****************************************************************************/
1669 static void cli_rmdir_done(struct tevent_req *subreq);
1671 struct cli_rmdir_state {
1672 int dummy;
1675 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1676 struct event_context *ev,
1677 struct cli_state *cli,
1678 const char *dname)
1680 struct tevent_req *req = NULL, *subreq = NULL;
1681 struct cli_rmdir_state *state = NULL;
1682 uint8_t additional_flags = 0;
1683 uint8_t *bytes = NULL;
1685 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1686 if (req == NULL) {
1687 return NULL;
1690 bytes = talloc_array(state, uint8_t, 1);
1691 if (tevent_req_nomem(bytes, req)) {
1692 return tevent_req_post(req, ev);
1694 bytes[0] = 4;
1695 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1696 strlen(dname)+1, NULL);
1698 if (tevent_req_nomem(bytes, req)) {
1699 return tevent_req_post(req, ev);
1702 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1703 0, NULL, talloc_get_size(bytes), bytes);
1704 if (tevent_req_nomem(subreq, req)) {
1705 return tevent_req_post(req, ev);
1707 tevent_req_set_callback(subreq, cli_rmdir_done, req);
1708 return req;
1711 static void cli_rmdir_done(struct tevent_req *subreq)
1713 struct tevent_req *req = tevent_req_callback_data(
1714 subreq, struct tevent_req);
1715 NTSTATUS status;
1717 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1718 TALLOC_FREE(subreq);
1719 if (!NT_STATUS_IS_OK(status)) {
1720 tevent_req_nterror(req, status);
1721 return;
1723 tevent_req_done(req);
1726 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1728 return tevent_req_simple_recv_ntstatus(req);
1731 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1733 TALLOC_CTX *frame = talloc_stackframe();
1734 struct event_context *ev;
1735 struct tevent_req *req;
1736 NTSTATUS status = NT_STATUS_OK;
1738 if (cli_has_async_calls(cli)) {
1740 * Can't use sync call while an async call is in flight
1742 status = NT_STATUS_INVALID_PARAMETER;
1743 goto fail;
1746 ev = event_context_init(frame);
1747 if (ev == NULL) {
1748 status = NT_STATUS_NO_MEMORY;
1749 goto fail;
1752 req = cli_rmdir_send(frame, ev, cli, dname);
1753 if (req == NULL) {
1754 status = NT_STATUS_NO_MEMORY;
1755 goto fail;
1758 if (!tevent_req_poll(req, ev)) {
1759 status = map_nt_error_from_unix(errno);
1760 goto fail;
1763 status = cli_rmdir_recv(req);
1765 fail:
1766 TALLOC_FREE(frame);
1767 if (!NT_STATUS_IS_OK(status)) {
1768 cli_set_error(cli, status);
1770 return status;
1773 /****************************************************************************
1774 Set or clear the delete on close flag.
1775 ****************************************************************************/
1777 struct doc_state {
1778 uint16_t setup;
1779 uint8_t param[6];
1780 uint8_t data[1];
1783 static void cli_nt_delete_on_close_done(struct tevent_req *subreq)
1785 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
1786 NULL, 0, NULL, NULL, 0, NULL);
1787 tevent_req_simple_finish_ntstatus(subreq, status);
1790 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1791 struct event_context *ev,
1792 struct cli_state *cli,
1793 uint16_t fnum,
1794 bool flag)
1796 struct tevent_req *req = NULL, *subreq = NULL;
1797 struct doc_state *state = NULL;
1799 req = tevent_req_create(mem_ctx, &state, struct doc_state);
1800 if (req == NULL) {
1801 return NULL;
1804 /* Setup setup word. */
1805 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1807 /* Setup param array. */
1808 SSVAL(state->param,0,fnum);
1809 SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1811 /* Setup data array. */
1812 SCVAL(&state->data[0], 0, flag ? 1 : 0);
1814 subreq = cli_trans_send(state, /* mem ctx. */
1815 ev, /* event ctx. */
1816 cli, /* cli_state. */
1817 SMBtrans2, /* cmd. */
1818 NULL, /* pipe name. */
1819 -1, /* fid. */
1820 0, /* function. */
1821 0, /* flags. */
1822 &state->setup, /* setup. */
1823 1, /* num setup uint16_t words. */
1824 0, /* max returned setup. */
1825 state->param, /* param. */
1826 6, /* num param. */
1827 2, /* max returned param. */
1828 state->data, /* data. */
1829 1, /* num data. */
1830 0); /* max returned data. */
1832 if (tevent_req_nomem(subreq, req)) {
1833 return tevent_req_post(req, ev);
1835 tevent_req_set_callback(subreq, cli_nt_delete_on_close_done, req);
1836 return req;
1839 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1841 return tevent_req_simple_recv_ntstatus(req);
1844 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1846 TALLOC_CTX *frame = talloc_stackframe();
1847 struct event_context *ev = NULL;
1848 struct tevent_req *req = NULL;
1849 NTSTATUS status = NT_STATUS_OK;
1851 if (cli_has_async_calls(cli)) {
1853 * Can't use sync call while an async call is in flight
1855 status = NT_STATUS_INVALID_PARAMETER;
1856 goto fail;
1859 ev = event_context_init(frame);
1860 if (ev == NULL) {
1861 status = NT_STATUS_NO_MEMORY;
1862 goto fail;
1865 req = cli_nt_delete_on_close_send(frame,
1867 cli,
1868 fnum,
1869 flag);
1870 if (req == NULL) {
1871 status = NT_STATUS_NO_MEMORY;
1872 goto fail;
1875 if (!tevent_req_poll(req, ev)) {
1876 status = map_nt_error_from_unix(errno);
1877 goto fail;
1880 status = cli_nt_delete_on_close_recv(req);
1882 fail:
1883 TALLOC_FREE(frame);
1884 if (!NT_STATUS_IS_OK(status)) {
1885 cli_set_error(cli, status);
1887 return status;
1890 struct cli_ntcreate_state {
1891 uint16_t vwv[24];
1892 uint16_t fnum;
1895 static void cli_ntcreate_done(struct tevent_req *subreq);
1897 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
1898 struct event_context *ev,
1899 struct cli_state *cli,
1900 const char *fname,
1901 uint32_t CreatFlags,
1902 uint32_t DesiredAccess,
1903 uint32_t FileAttributes,
1904 uint32_t ShareAccess,
1905 uint32_t CreateDisposition,
1906 uint32_t CreateOptions,
1907 uint8_t SecurityFlags)
1909 struct tevent_req *req, *subreq;
1910 struct cli_ntcreate_state *state;
1911 uint16_t *vwv;
1912 uint8_t *bytes;
1913 size_t converted_len;
1915 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
1916 if (req == NULL) {
1917 return NULL;
1920 vwv = state->vwv;
1922 SCVAL(vwv+0, 0, 0xFF);
1923 SCVAL(vwv+0, 1, 0);
1924 SSVAL(vwv+1, 0, 0);
1925 SCVAL(vwv+2, 0, 0);
1927 if (cli->use_oplocks) {
1928 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1930 SIVAL(vwv+3, 1, CreatFlags);
1931 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
1932 SIVAL(vwv+7, 1, DesiredAccess);
1933 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
1934 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
1935 SIVAL(vwv+13, 1, FileAttributes);
1936 SIVAL(vwv+15, 1, ShareAccess);
1937 SIVAL(vwv+17, 1, CreateDisposition);
1938 SIVAL(vwv+19, 1, CreateOptions);
1939 SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1940 SCVAL(vwv+23, 1, SecurityFlags);
1942 bytes = talloc_array(state, uint8_t, 0);
1943 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
1944 fname, strlen(fname)+1,
1945 &converted_len);
1947 /* sigh. this copes with broken netapp filer behaviour */
1948 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL);
1950 if (tevent_req_nomem(bytes, req)) {
1951 return tevent_req_post(req, ev);
1954 SSVAL(vwv+2, 1, converted_len);
1956 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
1957 talloc_get_size(bytes), bytes);
1958 if (tevent_req_nomem(subreq, req)) {
1959 return tevent_req_post(req, ev);
1961 tevent_req_set_callback(subreq, cli_ntcreate_done, req);
1962 return req;
1965 static void cli_ntcreate_done(struct tevent_req *subreq)
1967 struct tevent_req *req = tevent_req_callback_data(
1968 subreq, struct tevent_req);
1969 struct cli_ntcreate_state *state = tevent_req_data(
1970 req, struct cli_ntcreate_state);
1971 uint8_t wct;
1972 uint16_t *vwv;
1973 uint32_t num_bytes;
1974 uint8_t *bytes;
1975 uint8_t *inbuf;
1976 NTSTATUS status;
1978 status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv,
1979 &num_bytes, &bytes);
1980 TALLOC_FREE(subreq);
1981 if (!NT_STATUS_IS_OK(status)) {
1982 tevent_req_nterror(req, status);
1983 return;
1985 state->fnum = SVAL(vwv+2, 1);
1986 tevent_req_done(req);
1989 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
1991 struct cli_ntcreate_state *state = tevent_req_data(
1992 req, struct cli_ntcreate_state);
1993 NTSTATUS status;
1995 if (tevent_req_is_nterror(req, &status)) {
1996 return status;
1998 *pfnum = state->fnum;
1999 return NT_STATUS_OK;
2002 NTSTATUS cli_ntcreate(struct cli_state *cli,
2003 const char *fname,
2004 uint32_t CreatFlags,
2005 uint32_t DesiredAccess,
2006 uint32_t FileAttributes,
2007 uint32_t ShareAccess,
2008 uint32_t CreateDisposition,
2009 uint32_t CreateOptions,
2010 uint8_t SecurityFlags,
2011 uint16_t *pfid)
2013 TALLOC_CTX *frame = talloc_stackframe();
2014 struct event_context *ev;
2015 struct tevent_req *req;
2016 NTSTATUS status = NT_STATUS_OK;
2018 if (cli_has_async_calls(cli)) {
2020 * Can't use sync call while an async call is in flight
2022 status = NT_STATUS_INVALID_PARAMETER;
2023 goto fail;
2026 ev = event_context_init(frame);
2027 if (ev == NULL) {
2028 status = NT_STATUS_NO_MEMORY;
2029 goto fail;
2032 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2033 DesiredAccess, FileAttributes, ShareAccess,
2034 CreateDisposition, CreateOptions,
2035 SecurityFlags);
2036 if (req == NULL) {
2037 status = NT_STATUS_NO_MEMORY;
2038 goto fail;
2041 if (!tevent_req_poll(req, ev)) {
2042 status = map_nt_error_from_unix(errno);
2043 goto fail;
2046 status = cli_ntcreate_recv(req, pfid);
2047 fail:
2048 TALLOC_FREE(frame);
2049 if (!NT_STATUS_IS_OK(status)) {
2050 cli_set_error(cli, status);
2052 return status;
2055 /****************************************************************************
2056 Open a file
2057 WARNING: if you open with O_WRONLY then getattrE won't work!
2058 ****************************************************************************/
2060 struct cli_open_state {
2061 uint16_t vwv[15];
2062 uint16_t fnum;
2063 struct iovec bytes;
2066 static void cli_open_done(struct tevent_req *subreq);
2068 struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx,
2069 struct event_context *ev,
2070 struct cli_state *cli, const char *fname,
2071 int flags, int share_mode,
2072 struct tevent_req **psmbreq)
2074 struct tevent_req *req, *subreq;
2075 struct cli_open_state *state;
2076 unsigned openfn;
2077 unsigned accessmode;
2078 uint8_t additional_flags;
2079 uint8_t *bytes;
2081 req = tevent_req_create(mem_ctx, &state, struct cli_open_state);
2082 if (req == NULL) {
2083 return NULL;
2086 openfn = 0;
2087 if (flags & O_CREAT) {
2088 openfn |= (1<<4);
2090 if (!(flags & O_EXCL)) {
2091 if (flags & O_TRUNC)
2092 openfn |= (1<<1);
2093 else
2094 openfn |= (1<<0);
2097 accessmode = (share_mode<<4);
2099 if ((flags & O_ACCMODE) == O_RDWR) {
2100 accessmode |= 2;
2101 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2102 accessmode |= 1;
2105 #if defined(O_SYNC)
2106 if ((flags & O_SYNC) == O_SYNC) {
2107 accessmode |= (1<<14);
2109 #endif /* O_SYNC */
2111 if (share_mode == DENY_FCB) {
2112 accessmode = 0xFF;
2115 SCVAL(state->vwv + 0, 0, 0xFF);
2116 SCVAL(state->vwv + 0, 1, 0);
2117 SSVAL(state->vwv + 1, 0, 0);
2118 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
2119 SSVAL(state->vwv + 3, 0, accessmode);
2120 SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2121 SSVAL(state->vwv + 5, 0, 0);
2122 SIVAL(state->vwv + 6, 0, 0);
2123 SSVAL(state->vwv + 8, 0, openfn);
2124 SIVAL(state->vwv + 9, 0, 0);
2125 SIVAL(state->vwv + 11, 0, 0);
2126 SIVAL(state->vwv + 13, 0, 0);
2128 additional_flags = 0;
2130 if (cli->use_oplocks) {
2131 /* if using oplocks then ask for a batch oplock via
2132 core and extended methods */
2133 additional_flags =
2134 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2135 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2138 bytes = talloc_array(state, uint8_t, 0);
2139 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
2140 strlen(fname)+1, NULL);
2142 if (tevent_req_nomem(bytes, req)) {
2143 return tevent_req_post(req, ev);
2146 state->bytes.iov_base = (void *)bytes;
2147 state->bytes.iov_len = talloc_get_size(bytes);
2149 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2150 15, state->vwv, 1, &state->bytes);
2151 if (subreq == NULL) {
2152 TALLOC_FREE(req);
2153 return NULL;
2155 tevent_req_set_callback(subreq, cli_open_done, req);
2156 *psmbreq = subreq;
2157 return req;
2160 struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
2161 struct cli_state *cli, const char *fname,
2162 int flags, int share_mode)
2164 struct tevent_req *req, *subreq;
2165 NTSTATUS status;
2167 req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode,
2168 &subreq);
2169 if (req == NULL) {
2170 return NULL;
2173 status = cli_smb_req_send(subreq);
2174 if (!NT_STATUS_IS_OK(status)) {
2175 tevent_req_nterror(req, status);
2176 return tevent_req_post(req, ev);
2178 return req;
2181 static void cli_open_done(struct tevent_req *subreq)
2183 struct tevent_req *req = tevent_req_callback_data(
2184 subreq, struct tevent_req);
2185 struct cli_open_state *state = tevent_req_data(
2186 req, struct cli_open_state);
2187 uint8_t wct;
2188 uint16_t *vwv;
2189 uint8_t *inbuf;
2190 NTSTATUS status;
2192 status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv, NULL,
2193 NULL);
2194 TALLOC_FREE(subreq);
2195 if (!NT_STATUS_IS_OK(status)) {
2196 tevent_req_nterror(req, status);
2197 return;
2199 state->fnum = SVAL(vwv+2, 0);
2200 tevent_req_done(req);
2203 NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum)
2205 struct cli_open_state *state = tevent_req_data(
2206 req, struct cli_open_state);
2207 NTSTATUS status;
2209 if (tevent_req_is_nterror(req, &status)) {
2210 return status;
2212 *pfnum = state->fnum;
2213 return NT_STATUS_OK;
2216 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2217 int share_mode, uint16_t *pfnum)
2219 TALLOC_CTX *frame = talloc_stackframe();
2220 struct event_context *ev;
2221 struct tevent_req *req;
2222 NTSTATUS status = NT_STATUS_OK;
2224 if (cli_has_async_calls(cli)) {
2226 * Can't use sync call while an async call is in flight
2228 status = NT_STATUS_INVALID_PARAMETER;
2229 goto fail;
2232 ev = event_context_init(frame);
2233 if (ev == NULL) {
2234 status = NT_STATUS_NO_MEMORY;
2235 goto fail;
2238 req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
2239 if (req == NULL) {
2240 status = NT_STATUS_NO_MEMORY;
2241 goto fail;
2244 if (!tevent_req_poll(req, ev)) {
2245 status = map_nt_error_from_unix(errno);
2246 goto fail;
2249 status = cli_open_recv(req, pfnum);
2250 fail:
2251 TALLOC_FREE(frame);
2252 if (!NT_STATUS_IS_OK(status)) {
2253 cli_set_error(cli, status);
2255 return status;
2258 /****************************************************************************
2259 Close a file.
2260 ****************************************************************************/
2262 struct cli_close_state {
2263 uint16_t vwv[3];
2266 static void cli_close_done(struct tevent_req *subreq);
2268 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2269 struct event_context *ev,
2270 struct cli_state *cli,
2271 uint16_t fnum,
2272 struct tevent_req **psubreq)
2274 struct tevent_req *req, *subreq;
2275 struct cli_close_state *state;
2277 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2278 if (req == NULL) {
2279 return NULL;
2282 SSVAL(state->vwv+0, 0, fnum);
2283 SIVALS(state->vwv+1, 0, -1);
2285 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2286 0, NULL);
2287 if (subreq == NULL) {
2288 TALLOC_FREE(req);
2289 return NULL;
2291 tevent_req_set_callback(subreq, cli_close_done, req);
2292 *psubreq = subreq;
2293 return req;
2296 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2297 struct event_context *ev,
2298 struct cli_state *cli,
2299 uint16_t fnum)
2301 struct tevent_req *req, *subreq;
2302 NTSTATUS status;
2304 req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2305 if (req == NULL) {
2306 return NULL;
2309 status = cli_smb_req_send(subreq);
2310 if (!NT_STATUS_IS_OK(status)) {
2311 tevent_req_nterror(req, status);
2312 return tevent_req_post(req, ev);
2314 return req;
2317 static void cli_close_done(struct tevent_req *subreq)
2319 struct tevent_req *req = tevent_req_callback_data(
2320 subreq, struct tevent_req);
2321 NTSTATUS status;
2323 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2324 TALLOC_FREE(subreq);
2325 if (!NT_STATUS_IS_OK(status)) {
2326 tevent_req_nterror(req, status);
2327 return;
2329 tevent_req_done(req);
2332 NTSTATUS cli_close_recv(struct tevent_req *req)
2334 return tevent_req_simple_recv_ntstatus(req);
2337 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2339 TALLOC_CTX *frame = talloc_stackframe();
2340 struct event_context *ev;
2341 struct tevent_req *req;
2342 NTSTATUS status = NT_STATUS_OK;
2344 if (cli_has_async_calls(cli)) {
2346 * Can't use sync call while an async call is in flight
2348 status = NT_STATUS_INVALID_PARAMETER;
2349 goto fail;
2352 ev = event_context_init(frame);
2353 if (ev == NULL) {
2354 status = NT_STATUS_NO_MEMORY;
2355 goto fail;
2358 req = cli_close_send(frame, ev, cli, fnum);
2359 if (req == NULL) {
2360 status = NT_STATUS_NO_MEMORY;
2361 goto fail;
2364 if (!tevent_req_poll(req, ev)) {
2365 status = map_nt_error_from_unix(errno);
2366 goto fail;
2369 status = cli_close_recv(req);
2370 fail:
2371 TALLOC_FREE(frame);
2372 if (!NT_STATUS_IS_OK(status)) {
2373 cli_set_error(cli, status);
2375 return status;
2378 /****************************************************************************
2379 Truncate a file to a specified size
2380 ****************************************************************************/
2382 struct ftrunc_state {
2383 uint16_t setup;
2384 uint8_t param[6];
2385 uint8_t data[8];
2388 static void cli_ftruncate_done(struct tevent_req *subreq)
2390 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2391 NULL, 0, NULL, NULL, 0, NULL);
2392 tevent_req_simple_finish_ntstatus(subreq, status);
2395 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2396 struct event_context *ev,
2397 struct cli_state *cli,
2398 uint16_t fnum,
2399 uint64_t size)
2401 struct tevent_req *req = NULL, *subreq = NULL;
2402 struct ftrunc_state *state = NULL;
2404 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2405 if (req == NULL) {
2406 return NULL;
2409 /* Setup setup word. */
2410 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2412 /* Setup param array. */
2413 SSVAL(state->param,0,fnum);
2414 SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2415 SSVAL(state->param,4,0);
2417 /* Setup data array. */
2418 SBVAL(state->data, 0, size);
2420 subreq = cli_trans_send(state, /* mem ctx. */
2421 ev, /* event ctx. */
2422 cli, /* cli_state. */
2423 SMBtrans2, /* cmd. */
2424 NULL, /* pipe name. */
2425 -1, /* fid. */
2426 0, /* function. */
2427 0, /* flags. */
2428 &state->setup, /* setup. */
2429 1, /* num setup uint16_t words. */
2430 0, /* max returned setup. */
2431 state->param, /* param. */
2432 6, /* num param. */
2433 2, /* max returned param. */
2434 state->data, /* data. */
2435 8, /* num data. */
2436 0); /* max returned data. */
2438 if (tevent_req_nomem(subreq, req)) {
2439 return tevent_req_post(req, ev);
2441 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2442 return req;
2445 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2447 return tevent_req_simple_recv_ntstatus(req);
2450 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2452 TALLOC_CTX *frame = talloc_stackframe();
2453 struct event_context *ev = NULL;
2454 struct tevent_req *req = NULL;
2455 NTSTATUS status = NT_STATUS_OK;
2457 if (cli_has_async_calls(cli)) {
2459 * Can't use sync call while an async call is in flight
2461 status = NT_STATUS_INVALID_PARAMETER;
2462 goto fail;
2465 ev = event_context_init(frame);
2466 if (ev == NULL) {
2467 status = NT_STATUS_NO_MEMORY;
2468 goto fail;
2471 req = cli_ftruncate_send(frame,
2473 cli,
2474 fnum,
2475 size);
2476 if (req == NULL) {
2477 status = NT_STATUS_NO_MEMORY;
2478 goto fail;
2481 if (!tevent_req_poll(req, ev)) {
2482 status = map_nt_error_from_unix(errno);
2483 goto fail;
2486 status = cli_ftruncate_recv(req);
2488 fail:
2489 TALLOC_FREE(frame);
2490 if (!NT_STATUS_IS_OK(status)) {
2491 cli_set_error(cli, status);
2493 return status;
2496 /****************************************************************************
2497 send a lock with a specified locktype
2498 this is used for testing LOCKING_ANDX_CANCEL_LOCK
2499 ****************************************************************************/
2501 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2502 uint32_t offset, uint32_t len,
2503 int timeout, unsigned char locktype)
2505 uint16_t vwv[8];
2506 uint8_t bytes[10];
2507 NTSTATUS status;
2508 int saved_timeout;
2510 SCVAL(vwv + 0, 0, 0xff);
2511 SCVAL(vwv + 0, 1, 0);
2512 SSVAL(vwv + 1, 0, 0);
2513 SSVAL(vwv + 2, 0, fnum);
2514 SCVAL(vwv + 3, 0, locktype);
2515 SCVAL(vwv + 3, 1, 0);
2516 SIVALS(vwv + 4, 0, timeout);
2517 SSVAL(vwv + 6, 0, 0);
2518 SSVAL(vwv + 7, 0, 1);
2520 SSVAL(bytes, 0, cli->pid);
2521 SIVAL(bytes, 2, offset);
2522 SIVAL(bytes, 6, len);
2524 saved_timeout = cli->timeout;
2526 if (timeout != 0) {
2527 cli->timeout = (timeout == -1)
2528 ? 0x7FFFFFFF : (timeout + 2*1000);
2531 status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2532 10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2534 cli->timeout = saved_timeout;
2536 return status;
2539 /****************************************************************************
2540 Lock a file.
2541 note that timeout is in units of 2 milliseconds
2542 ****************************************************************************/
2544 bool cli_lock(struct cli_state *cli, uint16_t fnum,
2545 uint32_t offset, uint32_t len, int timeout,
2546 enum brl_type lock_type)
2548 NTSTATUS status;
2550 status = cli_locktype(cli, fnum, offset, len, timeout,
2551 (lock_type == READ_LOCK? 1 : 0));
2552 cli_set_error(cli, status);
2553 return NT_STATUS_IS_OK(status);
2556 /****************************************************************************
2557 Unlock a file.
2558 ****************************************************************************/
2560 struct cli_unlock_state {
2561 uint16_t vwv[8];
2562 uint8_t data[10];
2565 static void cli_unlock_done(struct tevent_req *subreq);
2567 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
2568 struct event_context *ev,
2569 struct cli_state *cli,
2570 uint16_t fnum,
2571 uint64_t offset,
2572 uint64_t len)
2575 struct tevent_req *req = NULL, *subreq = NULL;
2576 struct cli_unlock_state *state = NULL;
2577 uint8_t additional_flags = 0;
2579 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
2580 if (req == NULL) {
2581 return NULL;
2584 SCVAL(state->vwv+0, 0, 0xFF);
2585 SSVAL(state->vwv+2, 0, fnum);
2586 SCVAL(state->vwv+3, 0, 0);
2587 SIVALS(state->vwv+4, 0, 0);
2588 SSVAL(state->vwv+6, 0, 1);
2589 SSVAL(state->vwv+7, 0, 0);
2591 SSVAL(state->data, 0, cli->pid);
2592 SIVAL(state->data, 2, offset);
2593 SIVAL(state->data, 6, len);
2595 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2596 8, state->vwv, 10, state->data);
2597 if (tevent_req_nomem(subreq, req)) {
2598 return tevent_req_post(req, ev);
2600 tevent_req_set_callback(subreq, cli_unlock_done, req);
2601 return req;
2604 static void cli_unlock_done(struct tevent_req *subreq)
2606 struct tevent_req *req = tevent_req_callback_data(
2607 subreq, struct tevent_req);
2608 NTSTATUS status;
2610 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2611 TALLOC_FREE(subreq);
2612 if (!NT_STATUS_IS_OK(status)) {
2613 tevent_req_nterror(req, status);
2614 return;
2616 tevent_req_done(req);
2619 NTSTATUS cli_unlock_recv(struct tevent_req *req)
2621 return tevent_req_simple_recv_ntstatus(req);
2624 NTSTATUS cli_unlock(struct cli_state *cli,
2625 uint16_t fnum,
2626 uint32_t offset,
2627 uint32_t len)
2629 TALLOC_CTX *frame = talloc_stackframe();
2630 struct event_context *ev;
2631 struct tevent_req *req;
2632 NTSTATUS status = NT_STATUS_OK;
2634 if (cli_has_async_calls(cli)) {
2636 * Can't use sync call while an async call is in flight
2638 status = NT_STATUS_INVALID_PARAMETER;
2639 goto fail;
2642 ev = event_context_init(frame);
2643 if (ev == NULL) {
2644 status = NT_STATUS_NO_MEMORY;
2645 goto fail;
2648 req = cli_unlock_send(frame, ev, cli,
2649 fnum, offset, len);
2650 if (req == NULL) {
2651 status = NT_STATUS_NO_MEMORY;
2652 goto fail;
2655 if (!tevent_req_poll(req, ev)) {
2656 status = map_nt_error_from_unix(errno);
2657 goto fail;
2660 status = cli_unlock_recv(req);
2662 fail:
2663 TALLOC_FREE(frame);
2664 if (!NT_STATUS_IS_OK(status)) {
2665 cli_set_error(cli, status);
2667 return status;
2670 /****************************************************************************
2671 Lock a file with 64 bit offsets.
2672 ****************************************************************************/
2674 bool cli_lock64(struct cli_state *cli, uint16_t fnum,
2675 uint64_t offset, uint64_t len, int timeout,
2676 enum brl_type lock_type)
2678 uint16_t vwv[8];
2679 uint8_t bytes[20];
2680 int saved_timeout = cli->timeout;
2681 int ltype;
2682 NTSTATUS status;
2684 if (! (cli->capabilities & CAP_LARGE_FILES)) {
2685 return cli_lock(cli, fnum, offset, len, timeout, lock_type);
2688 ltype = (lock_type == READ_LOCK? 1 : 0);
2689 ltype |= LOCKING_ANDX_LARGE_FILES;
2691 SCVAL(vwv + 0, 0, 0xff);
2692 SCVAL(vwv + 0, 1, 0);
2693 SSVAL(vwv + 1, 0, 0);
2694 SSVAL(vwv + 2, 0, fnum);
2695 SCVAL(vwv + 3, 0, ltype);
2696 SCVAL(vwv + 3, 1, 0);
2697 SIVALS(vwv + 4, 0, timeout);
2698 SSVAL(vwv + 6, 0, 0);
2699 SSVAL(vwv + 7, 0, 1);
2701 SIVAL(bytes, 0, cli->pid);
2702 SOFF_T_R(bytes, 4, offset);
2703 SOFF_T_R(bytes, 12, len);
2705 saved_timeout = cli->timeout;
2707 if (timeout != 0) {
2708 cli->timeout = (timeout == -1)
2709 ? 0x7FFFFFFF : (timeout + 2*1000);
2712 status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2713 20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2715 cli->timeout = saved_timeout;
2717 cli_set_error(cli, status);
2718 return NT_STATUS_IS_OK(status);
2721 /****************************************************************************
2722 Unlock a file with 64 bit offsets.
2723 ****************************************************************************/
2725 struct cli_unlock64_state {
2726 uint16_t vwv[8];
2727 uint8_t data[20];
2730 static void cli_unlock64_done(struct tevent_req *subreq);
2732 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
2733 struct event_context *ev,
2734 struct cli_state *cli,
2735 uint16_t fnum,
2736 uint64_t offset,
2737 uint64_t len)
2740 struct tevent_req *req = NULL, *subreq = NULL;
2741 struct cli_unlock64_state *state = NULL;
2742 uint8_t additional_flags = 0;
2744 req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
2745 if (req == NULL) {
2746 return NULL;
2749 SCVAL(state->vwv+0, 0, 0xff);
2750 SSVAL(state->vwv+2, 0, fnum);
2751 SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
2752 SIVALS(state->vwv+4, 0, 0);
2753 SSVAL(state->vwv+6, 0, 1);
2754 SSVAL(state->vwv+7, 0, 0);
2756 SIVAL(state->data, 0, cli->pid);
2757 SOFF_T_R(state->data, 4, offset);
2758 SOFF_T_R(state->data, 12, len);
2760 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2761 8, state->vwv, 20, state->data);
2762 if (tevent_req_nomem(subreq, req)) {
2763 return tevent_req_post(req, ev);
2765 tevent_req_set_callback(subreq, cli_unlock64_done, req);
2766 return req;
2769 static void cli_unlock64_done(struct tevent_req *subreq)
2771 struct tevent_req *req = tevent_req_callback_data(
2772 subreq, struct tevent_req);
2773 NTSTATUS status;
2775 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2776 TALLOC_FREE(subreq);
2777 if (!NT_STATUS_IS_OK(status)) {
2778 tevent_req_nterror(req, status);
2779 return;
2781 tevent_req_done(req);
2784 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
2786 return tevent_req_simple_recv_ntstatus(req);
2789 NTSTATUS cli_unlock64(struct cli_state *cli,
2790 uint16_t fnum,
2791 uint64_t offset,
2792 uint64_t len)
2794 TALLOC_CTX *frame = talloc_stackframe();
2795 struct event_context *ev;
2796 struct tevent_req *req;
2797 NTSTATUS status = NT_STATUS_OK;
2799 if (! (cli->capabilities & CAP_LARGE_FILES)) {
2800 return cli_unlock(cli, fnum, offset, len);
2803 if (cli_has_async_calls(cli)) {
2805 * Can't use sync call while an async call is in flight
2807 status = NT_STATUS_INVALID_PARAMETER;
2808 goto fail;
2811 ev = event_context_init(frame);
2812 if (ev == NULL) {
2813 status = NT_STATUS_NO_MEMORY;
2814 goto fail;
2817 req = cli_unlock64_send(frame, ev, cli,
2818 fnum, offset, len);
2819 if (req == NULL) {
2820 status = NT_STATUS_NO_MEMORY;
2821 goto fail;
2824 if (!tevent_req_poll(req, ev)) {
2825 status = map_nt_error_from_unix(errno);
2826 goto fail;
2829 status = cli_unlock64_recv(req);
2831 fail:
2832 TALLOC_FREE(frame);
2833 if (!NT_STATUS_IS_OK(status)) {
2834 cli_set_error(cli, status);
2836 return status;
2839 /****************************************************************************
2840 Get/unlock a POSIX lock on a file - internal function.
2841 ****************************************************************************/
2843 struct posix_lock_state {
2844 uint16_t setup;
2845 uint8_t param[4];
2846 uint8_t data[POSIX_LOCK_DATA_SIZE];
2849 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
2851 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2852 NULL, 0, NULL, NULL, 0, NULL);
2853 tevent_req_simple_finish_ntstatus(subreq, status);
2856 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
2857 struct event_context *ev,
2858 struct cli_state *cli,
2859 uint16_t fnum,
2860 uint64_t offset,
2861 uint64_t len,
2862 bool wait_lock,
2863 enum brl_type lock_type)
2865 struct tevent_req *req = NULL, *subreq = NULL;
2866 struct posix_lock_state *state = NULL;
2868 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
2869 if (req == NULL) {
2870 return NULL;
2873 /* Setup setup word. */
2874 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2876 /* Setup param array. */
2877 SSVAL(&state->param, 0, fnum);
2878 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
2880 /* Setup data array. */
2881 switch (lock_type) {
2882 case READ_LOCK:
2883 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2884 POSIX_LOCK_TYPE_READ);
2885 break;
2886 case WRITE_LOCK:
2887 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2888 POSIX_LOCK_TYPE_WRITE);
2889 break;
2890 case UNLOCK_LOCK:
2891 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2892 POSIX_LOCK_TYPE_UNLOCK);
2893 break;
2894 default:
2895 return NULL;
2898 if (wait_lock) {
2899 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
2900 POSIX_LOCK_FLAG_WAIT);
2901 } else {
2902 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
2903 POSIX_LOCK_FLAG_NOWAIT);
2906 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli->pid);
2907 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
2908 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
2910 subreq = cli_trans_send(state, /* mem ctx. */
2911 ev, /* event ctx. */
2912 cli, /* cli_state. */
2913 SMBtrans2, /* cmd. */
2914 NULL, /* pipe name. */
2915 -1, /* fid. */
2916 0, /* function. */
2917 0, /* flags. */
2918 &state->setup, /* setup. */
2919 1, /* num setup uint16_t words. */
2920 0, /* max returned setup. */
2921 state->param, /* param. */
2922 4, /* num param. */
2923 2, /* max returned param. */
2924 state->data, /* data. */
2925 POSIX_LOCK_DATA_SIZE, /* num data. */
2926 0); /* max returned data. */
2928 if (tevent_req_nomem(subreq, req)) {
2929 return tevent_req_post(req, ev);
2931 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
2932 return req;
2935 /****************************************************************************
2936 POSIX Lock a file.
2937 ****************************************************************************/
2939 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
2940 struct event_context *ev,
2941 struct cli_state *cli,
2942 uint16_t fnum,
2943 uint64_t offset,
2944 uint64_t len,
2945 bool wait_lock,
2946 enum brl_type lock_type)
2948 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
2949 wait_lock, lock_type);
2952 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
2954 return tevent_req_simple_recv_ntstatus(req);
2957 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
2958 uint64_t offset, uint64_t len,
2959 bool wait_lock, enum brl_type lock_type)
2961 TALLOC_CTX *frame = talloc_stackframe();
2962 struct event_context *ev = NULL;
2963 struct tevent_req *req = NULL;
2964 NTSTATUS status = NT_STATUS_OK;
2966 if (cli_has_async_calls(cli)) {
2968 * Can't use sync call while an async call is in flight
2970 status = NT_STATUS_INVALID_PARAMETER;
2971 goto fail;
2974 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
2975 status = NT_STATUS_INVALID_PARAMETER;
2976 goto fail;
2979 ev = event_context_init(frame);
2980 if (ev == NULL) {
2981 status = NT_STATUS_NO_MEMORY;
2982 goto fail;
2985 req = cli_posix_lock_send(frame,
2987 cli,
2988 fnum,
2989 offset,
2990 len,
2991 wait_lock,
2992 lock_type);
2993 if (req == NULL) {
2994 status = NT_STATUS_NO_MEMORY;
2995 goto fail;
2998 if (!tevent_req_poll(req, ev)) {
2999 status = map_nt_error_from_unix(errno);
3000 goto fail;
3003 status = cli_posix_lock_recv(req);
3005 fail:
3006 TALLOC_FREE(frame);
3007 if (!NT_STATUS_IS_OK(status)) {
3008 cli_set_error(cli, status);
3010 return status;
3013 /****************************************************************************
3014 POSIX Unlock a file.
3015 ****************************************************************************/
3017 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3018 struct event_context *ev,
3019 struct cli_state *cli,
3020 uint16_t fnum,
3021 uint64_t offset,
3022 uint64_t len)
3024 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3025 false, UNLOCK_LOCK);
3028 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3030 return tevent_req_simple_recv_ntstatus(req);
3033 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3035 TALLOC_CTX *frame = talloc_stackframe();
3036 struct event_context *ev = NULL;
3037 struct tevent_req *req = NULL;
3038 NTSTATUS status = NT_STATUS_OK;
3040 if (cli_has_async_calls(cli)) {
3042 * Can't use sync call while an async call is in flight
3044 status = NT_STATUS_INVALID_PARAMETER;
3045 goto fail;
3048 ev = event_context_init(frame);
3049 if (ev == NULL) {
3050 status = NT_STATUS_NO_MEMORY;
3051 goto fail;
3054 req = cli_posix_unlock_send(frame,
3056 cli,
3057 fnum,
3058 offset,
3059 len);
3060 if (req == NULL) {
3061 status = NT_STATUS_NO_MEMORY;
3062 goto fail;
3065 if (!tevent_req_poll(req, ev)) {
3066 status = map_nt_error_from_unix(errno);
3067 goto fail;
3070 status = cli_posix_unlock_recv(req);
3072 fail:
3073 TALLOC_FREE(frame);
3074 if (!NT_STATUS_IS_OK(status)) {
3075 cli_set_error(cli, status);
3077 return status;
3080 /****************************************************************************
3081 Do a SMBgetattrE call.
3082 ****************************************************************************/
3084 static void cli_getattrE_done(struct tevent_req *subreq);
3086 struct cli_getattrE_state {
3087 uint16_t vwv[1];
3088 int zone_offset;
3089 uint16_t attr;
3090 SMB_OFF_T size;
3091 time_t change_time;
3092 time_t access_time;
3093 time_t write_time;
3096 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3097 struct event_context *ev,
3098 struct cli_state *cli,
3099 uint16_t fnum)
3101 struct tevent_req *req = NULL, *subreq = NULL;
3102 struct cli_getattrE_state *state = NULL;
3103 uint8_t additional_flags = 0;
3105 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3106 if (req == NULL) {
3107 return NULL;
3110 state->zone_offset = cli->serverzone;
3111 SSVAL(state->vwv+0,0,fnum);
3113 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
3114 1, state->vwv, 0, NULL);
3115 if (tevent_req_nomem(subreq, req)) {
3116 return tevent_req_post(req, ev);
3118 tevent_req_set_callback(subreq, cli_getattrE_done, req);
3119 return req;
3122 static void cli_getattrE_done(struct tevent_req *subreq)
3124 struct tevent_req *req = tevent_req_callback_data(
3125 subreq, struct tevent_req);
3126 struct cli_getattrE_state *state = tevent_req_data(
3127 req, struct cli_getattrE_state);
3128 uint8_t wct;
3129 uint16_t *vwv = NULL;
3130 uint8_t *inbuf;
3131 NTSTATUS status;
3133 status = cli_smb_recv(subreq, state, &inbuf, 11, &wct, &vwv,
3134 NULL, NULL);
3135 TALLOC_FREE(subreq);
3136 if (!NT_STATUS_IS_OK(status)) {
3137 tevent_req_nterror(req, status);
3138 return;
3141 state->size = (SMB_OFF_T)IVAL(vwv+6,0);
3142 state->attr = SVAL(vwv+10,0);
3143 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3144 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3145 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3147 tevent_req_done(req);
3150 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3151 uint16_t *attr,
3152 SMB_OFF_T *size,
3153 time_t *change_time,
3154 time_t *access_time,
3155 time_t *write_time)
3157 struct cli_getattrE_state *state = tevent_req_data(
3158 req, struct cli_getattrE_state);
3159 NTSTATUS status;
3161 if (tevent_req_is_nterror(req, &status)) {
3162 return status;
3164 if (attr) {
3165 *attr = state->attr;
3167 if (size) {
3168 *size = state->size;
3170 if (change_time) {
3171 *change_time = state->change_time;
3173 if (access_time) {
3174 *access_time = state->access_time;
3176 if (write_time) {
3177 *write_time = state->write_time;
3179 return NT_STATUS_OK;
3182 NTSTATUS cli_getattrE(struct cli_state *cli,
3183 uint16_t fnum,
3184 uint16_t *attr,
3185 SMB_OFF_T *size,
3186 time_t *change_time,
3187 time_t *access_time,
3188 time_t *write_time)
3190 TALLOC_CTX *frame = talloc_stackframe();
3191 struct event_context *ev = NULL;
3192 struct tevent_req *req = NULL;
3193 NTSTATUS status = NT_STATUS_OK;
3195 if (cli_has_async_calls(cli)) {
3197 * Can't use sync call while an async call is in flight
3199 status = NT_STATUS_INVALID_PARAMETER;
3200 goto fail;
3203 ev = event_context_init(frame);
3204 if (ev == NULL) {
3205 status = NT_STATUS_NO_MEMORY;
3206 goto fail;
3209 req = cli_getattrE_send(frame, ev, cli, fnum);
3210 if (req == NULL) {
3211 status = NT_STATUS_NO_MEMORY;
3212 goto fail;
3215 if (!tevent_req_poll(req, ev)) {
3216 status = map_nt_error_from_unix(errno);
3217 goto fail;
3220 status = cli_getattrE_recv(req,
3221 attr,
3222 size,
3223 change_time,
3224 access_time,
3225 write_time);
3227 fail:
3228 TALLOC_FREE(frame);
3229 if (!NT_STATUS_IS_OK(status)) {
3230 cli_set_error(cli, status);
3232 return status;
3235 /****************************************************************************
3236 Do a SMBgetatr call
3237 ****************************************************************************/
3239 static void cli_getatr_done(struct tevent_req *subreq);
3241 struct cli_getatr_state {
3242 int zone_offset;
3243 uint16_t attr;
3244 SMB_OFF_T size;
3245 time_t write_time;
3248 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3249 struct event_context *ev,
3250 struct cli_state *cli,
3251 const char *fname)
3253 struct tevent_req *req = NULL, *subreq = NULL;
3254 struct cli_getatr_state *state = NULL;
3255 uint8_t additional_flags = 0;
3256 uint8_t *bytes = NULL;
3258 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3259 if (req == NULL) {
3260 return NULL;
3263 state->zone_offset = cli->serverzone;
3265 bytes = talloc_array(state, uint8_t, 1);
3266 if (tevent_req_nomem(bytes, req)) {
3267 return tevent_req_post(req, ev);
3269 bytes[0] = 4;
3270 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3271 strlen(fname)+1, NULL);
3273 if (tevent_req_nomem(bytes, req)) {
3274 return tevent_req_post(req, ev);
3277 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3278 0, NULL, talloc_get_size(bytes), bytes);
3279 if (tevent_req_nomem(subreq, req)) {
3280 return tevent_req_post(req, ev);
3282 tevent_req_set_callback(subreq, cli_getatr_done, req);
3283 return req;
3286 static void cli_getatr_done(struct tevent_req *subreq)
3288 struct tevent_req *req = tevent_req_callback_data(
3289 subreq, struct tevent_req);
3290 struct cli_getatr_state *state = tevent_req_data(
3291 req, struct cli_getatr_state);
3292 uint8_t wct;
3293 uint16_t *vwv = NULL;
3294 uint8_t *inbuf;
3295 NTSTATUS status;
3297 status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3298 NULL);
3299 TALLOC_FREE(subreq);
3300 if (!NT_STATUS_IS_OK(status)) {
3301 tevent_req_nterror(req, status);
3302 return;
3305 state->attr = SVAL(vwv+0,0);
3306 state->size = (SMB_OFF_T)IVAL(vwv+3,0);
3307 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3309 tevent_req_done(req);
3312 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3313 uint16_t *attr,
3314 SMB_OFF_T *size,
3315 time_t *write_time)
3317 struct cli_getatr_state *state = tevent_req_data(
3318 req, struct cli_getatr_state);
3319 NTSTATUS status;
3321 if (tevent_req_is_nterror(req, &status)) {
3322 return status;
3324 if (attr) {
3325 *attr = state->attr;
3327 if (size) {
3328 *size = state->size;
3330 if (write_time) {
3331 *write_time = state->write_time;
3333 return NT_STATUS_OK;
3336 NTSTATUS cli_getatr(struct cli_state *cli,
3337 const char *fname,
3338 uint16_t *attr,
3339 SMB_OFF_T *size,
3340 time_t *write_time)
3342 TALLOC_CTX *frame = talloc_stackframe();
3343 struct event_context *ev = NULL;
3344 struct tevent_req *req = NULL;
3345 NTSTATUS status = NT_STATUS_OK;
3347 if (cli_has_async_calls(cli)) {
3349 * Can't use sync call while an async call is in flight
3351 status = NT_STATUS_INVALID_PARAMETER;
3352 goto fail;
3355 ev = event_context_init(frame);
3356 if (ev == NULL) {
3357 status = NT_STATUS_NO_MEMORY;
3358 goto fail;
3361 req = cli_getatr_send(frame, ev, cli, fname);
3362 if (req == NULL) {
3363 status = NT_STATUS_NO_MEMORY;
3364 goto fail;
3367 if (!tevent_req_poll(req, ev)) {
3368 status = map_nt_error_from_unix(errno);
3369 goto fail;
3372 status = cli_getatr_recv(req,
3373 attr,
3374 size,
3375 write_time);
3377 fail:
3378 TALLOC_FREE(frame);
3379 if (!NT_STATUS_IS_OK(status)) {
3380 cli_set_error(cli, status);
3382 return status;
3385 /****************************************************************************
3386 Do a SMBsetattrE call.
3387 ****************************************************************************/
3389 static void cli_setattrE_done(struct tevent_req *subreq);
3391 struct cli_setattrE_state {
3392 uint16_t vwv[7];
3395 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3396 struct event_context *ev,
3397 struct cli_state *cli,
3398 uint16_t fnum,
3399 time_t change_time,
3400 time_t access_time,
3401 time_t write_time)
3403 struct tevent_req *req = NULL, *subreq = NULL;
3404 struct cli_setattrE_state *state = NULL;
3405 uint8_t additional_flags = 0;
3407 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3408 if (req == NULL) {
3409 return NULL;
3412 SSVAL(state->vwv+0, 0, fnum);
3413 push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
3414 cli->serverzone);
3415 push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
3416 cli->serverzone);
3417 push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
3418 cli->serverzone);
3420 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3421 7, state->vwv, 0, NULL);
3422 if (tevent_req_nomem(subreq, req)) {
3423 return tevent_req_post(req, ev);
3425 tevent_req_set_callback(subreq, cli_setattrE_done, req);
3426 return req;
3429 static void cli_setattrE_done(struct tevent_req *subreq)
3431 struct tevent_req *req = tevent_req_callback_data(
3432 subreq, struct tevent_req);
3433 NTSTATUS status;
3435 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3436 TALLOC_FREE(subreq);
3437 if (!NT_STATUS_IS_OK(status)) {
3438 tevent_req_nterror(req, status);
3439 return;
3441 tevent_req_done(req);
3444 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3446 return tevent_req_simple_recv_ntstatus(req);
3449 NTSTATUS cli_setattrE(struct cli_state *cli,
3450 uint16_t fnum,
3451 time_t change_time,
3452 time_t access_time,
3453 time_t write_time)
3455 TALLOC_CTX *frame = talloc_stackframe();
3456 struct event_context *ev = NULL;
3457 struct tevent_req *req = NULL;
3458 NTSTATUS status = NT_STATUS_OK;
3460 if (cli_has_async_calls(cli)) {
3462 * Can't use sync call while an async call is in flight
3464 status = NT_STATUS_INVALID_PARAMETER;
3465 goto fail;
3468 ev = event_context_init(frame);
3469 if (ev == NULL) {
3470 status = NT_STATUS_NO_MEMORY;
3471 goto fail;
3474 req = cli_setattrE_send(frame, ev,
3475 cli,
3476 fnum,
3477 change_time,
3478 access_time,
3479 write_time);
3481 if (req == NULL) {
3482 status = NT_STATUS_NO_MEMORY;
3483 goto fail;
3486 if (!tevent_req_poll(req, ev)) {
3487 status = map_nt_error_from_unix(errno);
3488 goto fail;
3491 status = cli_setattrE_recv(req);
3493 fail:
3494 TALLOC_FREE(frame);
3495 if (!NT_STATUS_IS_OK(status)) {
3496 cli_set_error(cli, status);
3498 return status;
3501 /****************************************************************************
3502 Do a SMBsetatr call.
3503 ****************************************************************************/
3505 static void cli_setatr_done(struct tevent_req *subreq);
3507 struct cli_setatr_state {
3508 uint16_t vwv[8];
3511 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3512 struct event_context *ev,
3513 struct cli_state *cli,
3514 const char *fname,
3515 uint16_t attr,
3516 time_t mtime)
3518 struct tevent_req *req = NULL, *subreq = NULL;
3519 struct cli_setatr_state *state = NULL;
3520 uint8_t additional_flags = 0;
3521 uint8_t *bytes = NULL;
3523 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3524 if (req == NULL) {
3525 return NULL;
3528 SSVAL(state->vwv+0, 0, attr);
3529 push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, cli->serverzone);
3531 bytes = talloc_array(state, uint8_t, 1);
3532 if (tevent_req_nomem(bytes, req)) {
3533 return tevent_req_post(req, ev);
3535 bytes[0] = 4;
3536 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3537 strlen(fname)+1, NULL);
3538 if (tevent_req_nomem(bytes, req)) {
3539 return tevent_req_post(req, ev);
3541 bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
3542 talloc_get_size(bytes)+1);
3543 if (tevent_req_nomem(bytes, req)) {
3544 return tevent_req_post(req, ev);
3547 bytes[talloc_get_size(bytes)-1] = 4;
3548 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",
3549 1, NULL);
3550 if (tevent_req_nomem(bytes, req)) {
3551 return tevent_req_post(req, ev);
3554 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3555 8, state->vwv, talloc_get_size(bytes), bytes);
3556 if (tevent_req_nomem(subreq, req)) {
3557 return tevent_req_post(req, ev);
3559 tevent_req_set_callback(subreq, cli_setatr_done, req);
3560 return req;
3563 static void cli_setatr_done(struct tevent_req *subreq)
3565 struct tevent_req *req = tevent_req_callback_data(
3566 subreq, struct tevent_req);
3567 NTSTATUS status;
3569 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3570 TALLOC_FREE(subreq);
3571 if (!NT_STATUS_IS_OK(status)) {
3572 tevent_req_nterror(req, status);
3573 return;
3575 tevent_req_done(req);
3578 NTSTATUS cli_setatr_recv(struct tevent_req *req)
3580 return tevent_req_simple_recv_ntstatus(req);
3583 NTSTATUS cli_setatr(struct cli_state *cli,
3584 const char *fname,
3585 uint16_t attr,
3586 time_t mtime)
3588 TALLOC_CTX *frame = talloc_stackframe();
3589 struct event_context *ev = NULL;
3590 struct tevent_req *req = NULL;
3591 NTSTATUS status = NT_STATUS_OK;
3593 if (cli_has_async_calls(cli)) {
3595 * Can't use sync call while an async call is in flight
3597 status = NT_STATUS_INVALID_PARAMETER;
3598 goto fail;
3601 ev = event_context_init(frame);
3602 if (ev == NULL) {
3603 status = NT_STATUS_NO_MEMORY;
3604 goto fail;
3607 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
3608 if (req == NULL) {
3609 status = NT_STATUS_NO_MEMORY;
3610 goto fail;
3613 if (!tevent_req_poll(req, ev)) {
3614 status = map_nt_error_from_unix(errno);
3615 goto fail;
3618 status = cli_setatr_recv(req);
3620 fail:
3621 TALLOC_FREE(frame);
3622 if (!NT_STATUS_IS_OK(status)) {
3623 cli_set_error(cli, status);
3625 return status;
3628 /****************************************************************************
3629 Check for existance of a dir.
3630 ****************************************************************************/
3632 static void cli_chkpath_done(struct tevent_req *subreq);
3634 struct cli_chkpath_state {
3635 int dummy;
3638 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
3639 struct event_context *ev,
3640 struct cli_state *cli,
3641 const char *fname)
3643 struct tevent_req *req = NULL, *subreq = NULL;
3644 struct cli_chkpath_state *state = NULL;
3645 uint8_t additional_flags = 0;
3646 uint8_t *bytes = NULL;
3648 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
3649 if (req == NULL) {
3650 return NULL;
3653 bytes = talloc_array(state, uint8_t, 1);
3654 if (tevent_req_nomem(bytes, req)) {
3655 return tevent_req_post(req, ev);
3657 bytes[0] = 4;
3658 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3659 strlen(fname)+1, NULL);
3661 if (tevent_req_nomem(bytes, req)) {
3662 return tevent_req_post(req, ev);
3665 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
3666 0, NULL, talloc_get_size(bytes), bytes);
3667 if (tevent_req_nomem(subreq, req)) {
3668 return tevent_req_post(req, ev);
3670 tevent_req_set_callback(subreq, cli_chkpath_done, req);
3671 return req;
3674 static void cli_chkpath_done(struct tevent_req *subreq)
3676 struct tevent_req *req = tevent_req_callback_data(
3677 subreq, struct tevent_req);
3678 NTSTATUS status;
3680 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3681 TALLOC_FREE(subreq);
3682 if (!NT_STATUS_IS_OK(status)) {
3683 tevent_req_nterror(req, status);
3684 return;
3686 tevent_req_done(req);
3689 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
3691 return tevent_req_simple_recv_ntstatus(req);
3694 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
3696 TALLOC_CTX *frame = talloc_stackframe();
3697 struct event_context *ev = NULL;
3698 struct tevent_req *req = NULL;
3699 char *path2 = NULL;
3700 NTSTATUS status = NT_STATUS_OK;
3702 if (cli_has_async_calls(cli)) {
3704 * Can't use sync call while an async call is in flight
3706 status = NT_STATUS_INVALID_PARAMETER;
3707 goto fail;
3710 path2 = talloc_strdup(frame, path);
3711 if (!path2) {
3712 status = NT_STATUS_NO_MEMORY;
3713 goto fail;
3715 trim_char(path2,'\0','\\');
3716 if (!*path2) {
3717 path2 = talloc_strdup(frame, "\\");
3718 if (!path2) {
3719 status = NT_STATUS_NO_MEMORY;
3720 goto fail;
3724 ev = event_context_init(frame);
3725 if (ev == NULL) {
3726 status = NT_STATUS_NO_MEMORY;
3727 goto fail;
3730 req = cli_chkpath_send(frame, ev, cli, path2);
3731 if (req == NULL) {
3732 status = NT_STATUS_NO_MEMORY;
3733 goto fail;
3736 if (!tevent_req_poll(req, ev)) {
3737 status = map_nt_error_from_unix(errno);
3738 goto fail;
3741 status = cli_chkpath_recv(req);
3743 fail:
3744 TALLOC_FREE(frame);
3745 if (!NT_STATUS_IS_OK(status)) {
3746 cli_set_error(cli, status);
3748 return status;
3751 /****************************************************************************
3752 Query disk space.
3753 ****************************************************************************/
3755 static void cli_dskattr_done(struct tevent_req *subreq);
3757 struct cli_dskattr_state {
3758 int bsize;
3759 int total;
3760 int avail;
3763 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
3764 struct event_context *ev,
3765 struct cli_state *cli)
3767 struct tevent_req *req = NULL, *subreq = NULL;
3768 struct cli_dskattr_state *state = NULL;
3769 uint8_t additional_flags = 0;
3771 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
3772 if (req == NULL) {
3773 return NULL;
3776 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
3777 0, NULL, 0, NULL);
3778 if (tevent_req_nomem(subreq, req)) {
3779 return tevent_req_post(req, ev);
3781 tevent_req_set_callback(subreq, cli_dskattr_done, req);
3782 return req;
3785 static void cli_dskattr_done(struct tevent_req *subreq)
3787 struct tevent_req *req = tevent_req_callback_data(
3788 subreq, struct tevent_req);
3789 struct cli_dskattr_state *state = tevent_req_data(
3790 req, struct cli_dskattr_state);
3791 uint8_t wct;
3792 uint16_t *vwv = NULL;
3793 uint8_t *inbuf;
3794 NTSTATUS status;
3796 status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3797 NULL);
3798 TALLOC_FREE(subreq);
3799 if (!NT_STATUS_IS_OK(status)) {
3800 tevent_req_nterror(req, status);
3801 return;
3803 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
3804 state->total = SVAL(vwv+0, 0);
3805 state->avail = SVAL(vwv+3, 0);
3806 tevent_req_done(req);
3809 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
3811 struct cli_dskattr_state *state = tevent_req_data(
3812 req, struct cli_dskattr_state);
3813 NTSTATUS status;
3815 if (tevent_req_is_nterror(req, &status)) {
3816 return status;
3818 *bsize = state->bsize;
3819 *total = state->total;
3820 *avail = state->avail;
3821 return NT_STATUS_OK;
3824 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3826 TALLOC_CTX *frame = talloc_stackframe();
3827 struct event_context *ev = NULL;
3828 struct tevent_req *req = NULL;
3829 NTSTATUS status = NT_STATUS_OK;
3831 if (cli_has_async_calls(cli)) {
3833 * Can't use sync call while an async call is in flight
3835 status = NT_STATUS_INVALID_PARAMETER;
3836 goto fail;
3839 ev = event_context_init(frame);
3840 if (ev == NULL) {
3841 status = NT_STATUS_NO_MEMORY;
3842 goto fail;
3845 req = cli_dskattr_send(frame, ev, cli);
3846 if (req == NULL) {
3847 status = NT_STATUS_NO_MEMORY;
3848 goto fail;
3851 if (!tevent_req_poll(req, ev)) {
3852 status = map_nt_error_from_unix(errno);
3853 goto fail;
3856 status = cli_dskattr_recv(req, bsize, total, avail);
3858 fail:
3859 TALLOC_FREE(frame);
3860 if (!NT_STATUS_IS_OK(status)) {
3861 cli_set_error(cli, status);
3863 return status;
3866 /****************************************************************************
3867 Create and open a temporary file.
3868 ****************************************************************************/
3870 static void cli_ctemp_done(struct tevent_req *subreq);
3872 struct ctemp_state {
3873 uint16_t vwv[3];
3874 char *ret_path;
3875 uint16_t fnum;
3878 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
3879 struct event_context *ev,
3880 struct cli_state *cli,
3881 const char *path)
3883 struct tevent_req *req = NULL, *subreq = NULL;
3884 struct ctemp_state *state = NULL;
3885 uint8_t additional_flags = 0;
3886 uint8_t *bytes = NULL;
3888 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
3889 if (req == NULL) {
3890 return NULL;
3893 SSVAL(state->vwv,0,0);
3894 SIVALS(state->vwv+1,0,-1);
3896 bytes = talloc_array(state, uint8_t, 1);
3897 if (tevent_req_nomem(bytes, req)) {
3898 return tevent_req_post(req, ev);
3900 bytes[0] = 4;
3901 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), path,
3902 strlen(path)+1, NULL);
3903 if (tevent_req_nomem(bytes, req)) {
3904 return tevent_req_post(req, ev);
3907 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
3908 3, state->vwv, talloc_get_size(bytes), bytes);
3909 if (tevent_req_nomem(subreq, req)) {
3910 return tevent_req_post(req, ev);
3912 tevent_req_set_callback(subreq, cli_ctemp_done, req);
3913 return req;
3916 static void cli_ctemp_done(struct tevent_req *subreq)
3918 struct tevent_req *req = tevent_req_callback_data(
3919 subreq, struct tevent_req);
3920 struct ctemp_state *state = tevent_req_data(
3921 req, struct ctemp_state);
3922 NTSTATUS status;
3923 uint8_t wcnt;
3924 uint16_t *vwv;
3925 uint32_t num_bytes = 0;
3926 uint8_t *bytes = NULL;
3927 uint8_t *inbuf;
3929 status = cli_smb_recv(subreq, state, &inbuf, 1, &wcnt, &vwv,
3930 &num_bytes, &bytes);
3931 TALLOC_FREE(subreq);
3932 if (!NT_STATUS_IS_OK(status)) {
3933 tevent_req_nterror(req, status);
3934 return;
3937 state->fnum = SVAL(vwv+0, 0);
3939 /* From W2K3, the result is just the ASCII name */
3940 if (num_bytes < 2) {
3941 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
3942 return;
3945 if (pull_string_talloc(state,
3946 NULL,
3948 &state->ret_path,
3949 bytes,
3950 num_bytes,
3951 STR_ASCII) == 0) {
3952 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
3953 return;
3955 tevent_req_done(req);
3958 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
3959 TALLOC_CTX *ctx,
3960 uint16_t *pfnum,
3961 char **outfile)
3963 struct ctemp_state *state = tevent_req_data(req,
3964 struct ctemp_state);
3965 NTSTATUS status;
3967 if (tevent_req_is_nterror(req, &status)) {
3968 return status;
3970 *pfnum = state->fnum;
3971 *outfile = talloc_strdup(ctx, state->ret_path);
3972 if (!*outfile) {
3973 return NT_STATUS_NO_MEMORY;
3975 return NT_STATUS_OK;
3978 NTSTATUS cli_ctemp(struct cli_state *cli,
3979 TALLOC_CTX *ctx,
3980 const char *path,
3981 uint16_t *pfnum,
3982 char **out_path)
3984 TALLOC_CTX *frame = talloc_stackframe();
3985 struct event_context *ev;
3986 struct tevent_req *req;
3987 NTSTATUS status = NT_STATUS_OK;
3989 if (cli_has_async_calls(cli)) {
3991 * Can't use sync call while an async call is in flight
3993 status = NT_STATUS_INVALID_PARAMETER;
3994 goto fail;
3997 ev = event_context_init(frame);
3998 if (ev == NULL) {
3999 status = NT_STATUS_NO_MEMORY;
4000 goto fail;
4003 req = cli_ctemp_send(frame, ev, cli, path);
4004 if (req == NULL) {
4005 status = NT_STATUS_NO_MEMORY;
4006 goto fail;
4009 if (!tevent_req_poll(req, ev)) {
4010 status = map_nt_error_from_unix(errno);
4011 goto fail;
4014 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4016 fail:
4017 TALLOC_FREE(frame);
4018 if (!NT_STATUS_IS_OK(status)) {
4019 cli_set_error(cli, status);
4021 return status;
4025 send a raw ioctl - used by the torture code
4027 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4029 uint16_t vwv[3];
4030 NTSTATUS status;
4032 SSVAL(vwv+0, 0, fnum);
4033 SSVAL(vwv+1, 0, code>>16);
4034 SSVAL(vwv+2, 0, (code&0xFFFF));
4036 status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4037 NULL, 0, NULL, NULL, NULL, NULL);
4038 if (!NT_STATUS_IS_OK(status)) {
4039 return status;
4041 *blob = data_blob_null;
4042 return NT_STATUS_OK;
4045 /*********************************************************
4046 Set an extended attribute utility fn.
4047 *********************************************************/
4049 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
4050 uint8_t *param, unsigned int param_len,
4051 const char *ea_name,
4052 const char *ea_val, size_t ea_len)
4054 uint16_t setup[1];
4055 unsigned int data_len = 0;
4056 uint8_t *data = NULL;
4057 char *p;
4058 size_t ea_namelen = strlen(ea_name);
4059 NTSTATUS status;
4061 SSVAL(setup, 0, setup_val);
4063 if (ea_namelen == 0 && ea_len == 0) {
4064 data_len = 4;
4065 data = (uint8_t *)SMB_MALLOC(data_len);
4066 if (!data) {
4067 return NT_STATUS_NO_MEMORY;
4069 p = (char *)data;
4070 SIVAL(p,0,data_len);
4071 } else {
4072 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4073 data = (uint8_t *)SMB_MALLOC(data_len);
4074 if (!data) {
4075 return NT_STATUS_NO_MEMORY;
4077 p = (char *)data;
4078 SIVAL(p,0,data_len);
4079 p += 4;
4080 SCVAL(p, 0, 0); /* EA flags. */
4081 SCVAL(p, 1, ea_namelen);
4082 SSVAL(p, 2, ea_len);
4083 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4084 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4087 status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
4088 setup, 1, 0,
4089 param, param_len, 2,
4090 data, data_len, cli->max_xmit,
4091 NULL,
4092 NULL, 0, NULL, /* rsetup */
4093 NULL, 0, NULL, /* rparam */
4094 NULL, 0, NULL); /* rdata */
4095 SAFE_FREE(data);
4096 return status;
4099 /*********************************************************
4100 Set an extended attribute on a pathname.
4101 *********************************************************/
4103 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
4104 const char *ea_name, const char *ea_val,
4105 size_t ea_len)
4107 unsigned int param_len = 0;
4108 uint8_t *param;
4109 size_t srclen = 2*(strlen(path)+1);
4110 char *p;
4111 NTSTATUS status;
4113 param = SMB_MALLOC_ARRAY(uint8_t, 6+srclen+2);
4114 if (!param) {
4115 return NT_STATUS_NO_MEMORY;
4117 memset(param, '\0', 6);
4118 SSVAL(param,0,SMB_INFO_SET_EA);
4119 p = (char *)(&param[6]);
4121 p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
4122 param_len = PTR_DIFF(p, param);
4124 status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
4125 ea_name, ea_val, ea_len);
4126 SAFE_FREE(param);
4127 return status;
4130 /*********************************************************
4131 Set an extended attribute on an fnum.
4132 *********************************************************/
4134 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
4135 const char *ea_name, const char *ea_val,
4136 size_t ea_len)
4138 uint8_t param[6];
4140 memset(param, 0, 6);
4141 SSVAL(param,0,fnum);
4142 SSVAL(param,2,SMB_INFO_SET_EA);
4144 return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
4145 ea_name, ea_val, ea_len);
4148 /*********************************************************
4149 Get an extended attribute list utility fn.
4150 *********************************************************/
4152 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4153 size_t rdata_len,
4154 size_t *pnum_eas, struct ea_struct **pea_list)
4156 struct ea_struct *ea_list = NULL;
4157 size_t num_eas;
4158 size_t ea_size;
4159 const uint8_t *p;
4161 if (rdata_len < 4) {
4162 return false;
4165 ea_size = (size_t)IVAL(rdata,0);
4166 if (ea_size > rdata_len) {
4167 return false;
4170 if (ea_size == 0) {
4171 /* No EA's present. */
4172 *pnum_eas = 0;
4173 *pea_list = NULL;
4174 return true;
4177 p = rdata + 4;
4178 ea_size -= 4;
4180 /* Validate the EA list and count it. */
4181 for (num_eas = 0; ea_size >= 4; num_eas++) {
4182 unsigned int ea_namelen = CVAL(p,1);
4183 unsigned int ea_valuelen = SVAL(p,2);
4184 if (ea_namelen == 0) {
4185 return false;
4187 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4188 return false;
4190 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4191 p += 4 + ea_namelen + 1 + ea_valuelen;
4194 if (num_eas == 0) {
4195 *pnum_eas = 0;
4196 *pea_list = NULL;
4197 return true;
4200 *pnum_eas = num_eas;
4201 if (!pea_list) {
4202 /* Caller only wants number of EA's. */
4203 return true;
4206 ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
4207 if (!ea_list) {
4208 return false;
4211 ea_size = (size_t)IVAL(rdata,0);
4212 p = rdata + 4;
4214 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4215 struct ea_struct *ea = &ea_list[num_eas];
4216 fstring unix_ea_name;
4217 unsigned int ea_namelen = CVAL(p,1);
4218 unsigned int ea_valuelen = SVAL(p,2);
4220 ea->flags = CVAL(p,0);
4221 unix_ea_name[0] = '\0';
4222 pull_ascii_fstring(unix_ea_name, p + 4);
4223 ea->name = talloc_strdup(ea_list, unix_ea_name);
4224 if (!ea->name) {
4225 goto fail;
4227 /* Ensure the value is null terminated (in case it's a string). */
4228 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4229 if (!ea->value.data) {
4230 goto fail;
4232 if (ea_valuelen) {
4233 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4235 ea->value.data[ea_valuelen] = 0;
4236 ea->value.length--;
4237 p += 4 + ea_namelen + 1 + ea_valuelen;
4240 *pea_list = ea_list;
4241 return true;
4243 fail:
4244 TALLOC_FREE(ea_list);
4245 return false;
4248 /*********************************************************
4249 Get an extended attribute list from a pathname.
4250 *********************************************************/
4252 struct cli_get_ea_list_path_state {
4253 uint32_t num_data;
4254 uint8_t *data;
4257 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4259 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4260 struct tevent_context *ev,
4261 struct cli_state *cli,
4262 const char *fname)
4264 struct tevent_req *req, *subreq;
4265 struct cli_get_ea_list_path_state *state;
4267 req = tevent_req_create(mem_ctx, &state,
4268 struct cli_get_ea_list_path_state);
4269 if (req == NULL) {
4270 return NULL;
4272 subreq = cli_qpathinfo_send(state, ev, cli, fname,
4273 SMB_INFO_QUERY_ALL_EAS, 4,
4274 cli->max_xmit);
4275 if (tevent_req_nomem(subreq, req)) {
4276 return tevent_req_post(req, ev);
4278 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4279 return req;
4282 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4284 struct tevent_req *req = tevent_req_callback_data(
4285 subreq, struct tevent_req);
4286 struct cli_get_ea_list_path_state *state = tevent_req_data(
4287 req, struct cli_get_ea_list_path_state);
4288 NTSTATUS status;
4290 status = cli_qpathinfo_recv(subreq, state, &state->data,
4291 &state->num_data);
4292 TALLOC_FREE(subreq);
4293 if (!NT_STATUS_IS_OK(status)) {
4294 tevent_req_nterror(req, status);
4295 return;
4297 tevent_req_done(req);
4300 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4301 size_t *pnum_eas, struct ea_struct **peas)
4303 struct cli_get_ea_list_path_state *state = tevent_req_data(
4304 req, struct cli_get_ea_list_path_state);
4305 NTSTATUS status;
4307 if (tevent_req_is_nterror(req, &status)) {
4308 return status;
4310 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4311 pnum_eas, peas)) {
4312 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4314 return NT_STATUS_OK;
4317 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
4318 TALLOC_CTX *ctx,
4319 size_t *pnum_eas,
4320 struct ea_struct **pea_list)
4322 TALLOC_CTX *frame = talloc_stackframe();
4323 struct event_context *ev = NULL;
4324 struct tevent_req *req = NULL;
4325 NTSTATUS status = NT_STATUS_NO_MEMORY;
4327 if (cli_has_async_calls(cli)) {
4329 * Can't use sync call while an async call is in flight
4331 status = NT_STATUS_INVALID_PARAMETER;
4332 goto fail;
4334 ev = event_context_init(frame);
4335 if (ev == NULL) {
4336 goto fail;
4338 req = cli_get_ea_list_path_send(frame, ev, cli, path);
4339 if (req == NULL) {
4340 goto fail;
4342 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4343 goto fail;
4345 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
4346 fail:
4347 TALLOC_FREE(frame);
4348 if (!NT_STATUS_IS_OK(status)) {
4349 cli_set_error(cli, status);
4351 return status;
4354 /****************************************************************************
4355 Convert open "flags" arg to uint32_t on wire.
4356 ****************************************************************************/
4358 static uint32_t open_flags_to_wire(int flags)
4360 int open_mode = flags & O_ACCMODE;
4361 uint32_t ret = 0;
4363 switch (open_mode) {
4364 case O_WRONLY:
4365 ret |= SMB_O_WRONLY;
4366 break;
4367 case O_RDWR:
4368 ret |= SMB_O_RDWR;
4369 break;
4370 default:
4371 case O_RDONLY:
4372 ret |= SMB_O_RDONLY;
4373 break;
4376 if (flags & O_CREAT) {
4377 ret |= SMB_O_CREAT;
4379 if (flags & O_EXCL) {
4380 ret |= SMB_O_EXCL;
4382 if (flags & O_TRUNC) {
4383 ret |= SMB_O_TRUNC;
4385 #if defined(O_SYNC)
4386 if (flags & O_SYNC) {
4387 ret |= SMB_O_SYNC;
4389 #endif /* O_SYNC */
4390 if (flags & O_APPEND) {
4391 ret |= SMB_O_APPEND;
4393 #if defined(O_DIRECT)
4394 if (flags & O_DIRECT) {
4395 ret |= SMB_O_DIRECT;
4397 #endif
4398 #if defined(O_DIRECTORY)
4399 if (flags & O_DIRECTORY) {
4400 ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4401 ret |= SMB_O_DIRECTORY;
4403 #endif
4404 return ret;
4407 /****************************************************************************
4408 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4409 ****************************************************************************/
4411 struct posix_open_state {
4412 uint16_t setup;
4413 uint8_t *param;
4414 uint8_t data[18];
4415 uint16_t fnum; /* Out */
4418 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4420 struct tevent_req *req = tevent_req_callback_data(
4421 subreq, struct tevent_req);
4422 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4423 NTSTATUS status;
4424 uint8_t *data;
4425 uint32_t num_data;
4427 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
4428 NULL, 0, NULL, &data, 12, &num_data);
4429 TALLOC_FREE(subreq);
4430 if (!NT_STATUS_IS_OK(status)) {
4431 tevent_req_nterror(req, status);
4432 return;
4434 state->fnum = SVAL(data,2);
4435 tevent_req_done(req);
4438 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4439 struct event_context *ev,
4440 struct cli_state *cli,
4441 const char *fname,
4442 int flags,
4443 mode_t mode,
4444 bool is_dir)
4446 struct tevent_req *req = NULL, *subreq = NULL;
4447 struct posix_open_state *state = NULL;
4448 uint32_t wire_flags = open_flags_to_wire(flags);
4450 req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4451 if (req == NULL) {
4452 return NULL;
4455 /* Setup setup word. */
4456 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4458 /* Setup param array. */
4459 state->param = talloc_array(state, uint8_t, 6);
4460 if (tevent_req_nomem(state->param, req)) {
4461 return tevent_req_post(req, ev);
4463 memset(state->param, '\0', 6);
4464 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4466 state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
4467 strlen(fname)+1, NULL);
4469 if (tevent_req_nomem(state->param, req)) {
4470 return tevent_req_post(req, ev);
4473 /* Setup data words. */
4474 if (is_dir) {
4475 wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4476 wire_flags |= SMB_O_DIRECTORY;
4479 SIVAL(state->data,0,0); /* No oplock. */
4480 SIVAL(state->data,4,wire_flags);
4481 SIVAL(state->data,8,unix_perms_to_wire(mode));
4482 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
4483 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
4485 subreq = cli_trans_send(state, /* mem ctx. */
4486 ev, /* event ctx. */
4487 cli, /* cli_state. */
4488 SMBtrans2, /* cmd. */
4489 NULL, /* pipe name. */
4490 -1, /* fid. */
4491 0, /* function. */
4492 0, /* flags. */
4493 &state->setup, /* setup. */
4494 1, /* num setup uint16_t words. */
4495 0, /* max returned setup. */
4496 state->param, /* param. */
4497 talloc_get_size(state->param),/* num param. */
4498 2, /* max returned param. */
4499 state->data, /* data. */
4500 18, /* num data. */
4501 12); /* max returned data. */
4503 if (tevent_req_nomem(subreq, req)) {
4504 return tevent_req_post(req, ev);
4506 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
4507 return req;
4510 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
4511 struct event_context *ev,
4512 struct cli_state *cli,
4513 const char *fname,
4514 int flags,
4515 mode_t mode)
4517 return cli_posix_open_internal_send(mem_ctx, ev,
4518 cli, fname, flags, mode, false);
4521 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
4523 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4524 NTSTATUS status;
4526 if (tevent_req_is_nterror(req, &status)) {
4527 return status;
4529 *pfnum = state->fnum;
4530 return NT_STATUS_OK;
4533 /****************************************************************************
4534 Open - POSIX semantics. Doesn't request oplock.
4535 ****************************************************************************/
4537 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
4538 int flags, mode_t mode, uint16_t *pfnum)
4541 TALLOC_CTX *frame = talloc_stackframe();
4542 struct event_context *ev = NULL;
4543 struct tevent_req *req = NULL;
4544 NTSTATUS status = NT_STATUS_OK;
4546 if (cli_has_async_calls(cli)) {
4548 * Can't use sync call while an async call is in flight
4550 status = NT_STATUS_INVALID_PARAMETER;
4551 goto fail;
4554 ev = event_context_init(frame);
4555 if (ev == NULL) {
4556 status = NT_STATUS_NO_MEMORY;
4557 goto fail;
4560 req = cli_posix_open_send(frame,
4562 cli,
4563 fname,
4564 flags,
4565 mode);
4566 if (req == NULL) {
4567 status = NT_STATUS_NO_MEMORY;
4568 goto fail;
4571 if (!tevent_req_poll(req, ev)) {
4572 status = map_nt_error_from_unix(errno);
4573 goto fail;
4576 status = cli_posix_open_recv(req, pfnum);
4578 fail:
4579 TALLOC_FREE(frame);
4580 if (!NT_STATUS_IS_OK(status)) {
4581 cli_set_error(cli, status);
4583 return status;
4586 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
4587 struct event_context *ev,
4588 struct cli_state *cli,
4589 const char *fname,
4590 mode_t mode)
4592 return cli_posix_open_internal_send(mem_ctx, ev,
4593 cli, fname, O_CREAT, mode, true);
4596 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
4598 return tevent_req_simple_recv_ntstatus(req);
4601 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
4603 TALLOC_CTX *frame = talloc_stackframe();
4604 struct event_context *ev = NULL;
4605 struct tevent_req *req = NULL;
4606 NTSTATUS status = NT_STATUS_OK;
4608 if (cli_has_async_calls(cli)) {
4610 * Can't use sync call while an async call is in flight
4612 status = NT_STATUS_INVALID_PARAMETER;
4613 goto fail;
4616 ev = event_context_init(frame);
4617 if (ev == NULL) {
4618 status = NT_STATUS_NO_MEMORY;
4619 goto fail;
4622 req = cli_posix_mkdir_send(frame,
4624 cli,
4625 fname,
4626 mode);
4627 if (req == NULL) {
4628 status = NT_STATUS_NO_MEMORY;
4629 goto fail;
4632 if (!tevent_req_poll(req, ev)) {
4633 status = map_nt_error_from_unix(errno);
4634 goto fail;
4637 status = cli_posix_mkdir_recv(req);
4639 fail:
4640 TALLOC_FREE(frame);
4641 if (!NT_STATUS_IS_OK(status)) {
4642 cli_set_error(cli, status);
4644 return status;
4647 /****************************************************************************
4648 unlink or rmdir - POSIX semantics.
4649 ****************************************************************************/
4651 struct cli_posix_unlink_internal_state {
4652 uint8_t data[2];
4655 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
4657 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
4658 struct event_context *ev,
4659 struct cli_state *cli,
4660 const char *fname,
4661 uint16_t level)
4663 struct tevent_req *req = NULL, *subreq = NULL;
4664 struct cli_posix_unlink_internal_state *state = NULL;
4666 req = tevent_req_create(mem_ctx, &state,
4667 struct cli_posix_unlink_internal_state);
4668 if (req == NULL) {
4669 return NULL;
4672 /* Setup data word. */
4673 SSVAL(state->data, 0, level);
4675 subreq = cli_setpathinfo_send(state, ev, cli,
4676 SMB_POSIX_PATH_UNLINK,
4677 fname,
4678 state->data, sizeof(state->data));
4679 if (tevent_req_nomem(subreq, req)) {
4680 return tevent_req_post(req, ev);
4682 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
4683 return req;
4686 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
4688 NTSTATUS status = cli_setpathinfo_recv(subreq);
4689 tevent_req_simple_finish_ntstatus(subreq, status);
4692 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
4693 struct event_context *ev,
4694 struct cli_state *cli,
4695 const char *fname)
4697 return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
4698 SMB_POSIX_UNLINK_FILE_TARGET);
4701 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
4703 return tevent_req_simple_recv_ntstatus(req);
4706 /****************************************************************************
4707 unlink - POSIX semantics.
4708 ****************************************************************************/
4710 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
4712 TALLOC_CTX *frame = talloc_stackframe();
4713 struct event_context *ev = NULL;
4714 struct tevent_req *req = NULL;
4715 NTSTATUS status = NT_STATUS_OK;
4717 if (cli_has_async_calls(cli)) {
4719 * Can't use sync call while an async call is in flight
4721 status = NT_STATUS_INVALID_PARAMETER;
4722 goto fail;
4725 ev = event_context_init(frame);
4726 if (ev == NULL) {
4727 status = NT_STATUS_NO_MEMORY;
4728 goto fail;
4731 req = cli_posix_unlink_send(frame,
4733 cli,
4734 fname);
4735 if (req == NULL) {
4736 status = NT_STATUS_NO_MEMORY;
4737 goto fail;
4740 if (!tevent_req_poll(req, ev)) {
4741 status = map_nt_error_from_unix(errno);
4742 goto fail;
4745 status = cli_posix_unlink_recv(req);
4747 fail:
4748 TALLOC_FREE(frame);
4749 if (!NT_STATUS_IS_OK(status)) {
4750 cli_set_error(cli, status);
4752 return status;
4755 /****************************************************************************
4756 rmdir - POSIX semantics.
4757 ****************************************************************************/
4759 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
4760 struct event_context *ev,
4761 struct cli_state *cli,
4762 const char *fname)
4764 return cli_posix_unlink_internal_send(
4765 mem_ctx, ev, cli, fname,
4766 SMB_POSIX_UNLINK_DIRECTORY_TARGET);
4769 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
4771 return tevent_req_simple_recv_ntstatus(req);
4774 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
4776 TALLOC_CTX *frame = talloc_stackframe();
4777 struct event_context *ev = NULL;
4778 struct tevent_req *req = NULL;
4779 NTSTATUS status = NT_STATUS_OK;
4781 if (cli_has_async_calls(cli)) {
4783 * Can't use sync call while an async call is in flight
4785 status = NT_STATUS_INVALID_PARAMETER;
4786 goto fail;
4789 ev = event_context_init(frame);
4790 if (ev == NULL) {
4791 status = NT_STATUS_NO_MEMORY;
4792 goto fail;
4795 req = cli_posix_rmdir_send(frame,
4797 cli,
4798 fname);
4799 if (req == NULL) {
4800 status = NT_STATUS_NO_MEMORY;
4801 goto fail;
4804 if (!tevent_req_poll(req, ev)) {
4805 status = map_nt_error_from_unix(errno);
4806 goto fail;
4809 status = cli_posix_rmdir_recv(req, frame);
4811 fail:
4812 TALLOC_FREE(frame);
4813 if (!NT_STATUS_IS_OK(status)) {
4814 cli_set_error(cli, status);
4816 return status;
4819 /****************************************************************************
4820 filechangenotify
4821 ****************************************************************************/
4823 struct cli_notify_state {
4824 uint8_t setup[8];
4825 uint32_t num_changes;
4826 struct notify_change *changes;
4829 static void cli_notify_done(struct tevent_req *subreq);
4831 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
4832 struct tevent_context *ev,
4833 struct cli_state *cli, uint16_t fnum,
4834 uint32_t buffer_size,
4835 uint32_t completion_filter, bool recursive)
4837 struct tevent_req *req, *subreq;
4838 struct cli_notify_state *state;
4840 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
4841 if (req == NULL) {
4842 return NULL;
4845 SIVAL(state->setup, 0, completion_filter);
4846 SSVAL(state->setup, 4, fnum);
4847 SSVAL(state->setup, 6, recursive);
4849 subreq = cli_trans_send(
4850 state, /* mem ctx. */
4851 ev, /* event ctx. */
4852 cli, /* cli_state. */
4853 SMBnttrans, /* cmd. */
4854 NULL, /* pipe name. */
4855 -1, /* fid. */
4856 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
4857 0, /* flags. */
4858 (uint16_t *)state->setup, /* setup. */
4859 4, /* num setup uint16_t words. */
4860 0, /* max returned setup. */
4861 NULL, /* param. */
4862 0, /* num param. */
4863 buffer_size, /* max returned param. */
4864 NULL, /* data. */
4865 0, /* num data. */
4866 0); /* max returned data. */
4868 if (tevent_req_nomem(subreq, req)) {
4869 return tevent_req_post(req, ev);
4871 tevent_req_set_callback(subreq, cli_notify_done, req);
4872 return req;
4875 static void cli_notify_done(struct tevent_req *subreq)
4877 struct tevent_req *req = tevent_req_callback_data(
4878 subreq, struct tevent_req);
4879 struct cli_notify_state *state = tevent_req_data(
4880 req, struct cli_notify_state);
4881 NTSTATUS status;
4882 uint8_t *params;
4883 uint32_t i, ofs, num_params;
4884 uint16_t flags2;
4886 status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
4887 &params, 0, &num_params, NULL, 0, NULL);
4888 TALLOC_FREE(subreq);
4889 if (!NT_STATUS_IS_OK(status)) {
4890 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
4891 tevent_req_nterror(req, status);
4892 return;
4895 state->num_changes = 0;
4896 ofs = 0;
4898 while (num_params - ofs > 12) {
4899 uint32_t len = IVAL(params, ofs);
4900 state->num_changes += 1;
4902 if ((len == 0) || (ofs+len >= num_params)) {
4903 break;
4905 ofs += len;
4908 state->changes = talloc_array(state, struct notify_change,
4909 state->num_changes);
4910 if (tevent_req_nomem(state->changes, req)) {
4911 TALLOC_FREE(params);
4912 return;
4915 ofs = 0;
4917 for (i=0; i<state->num_changes; i++) {
4918 uint32_t next = IVAL(params, ofs);
4919 uint32_t len = IVAL(params, ofs+8);
4920 ssize_t ret;
4921 char *name;
4923 if ((next != 0) && (len+12 != next)) {
4924 TALLOC_FREE(params);
4925 tevent_req_nterror(
4926 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4927 return;
4930 state->changes[i].action = IVAL(params, ofs+4);
4931 ret = clistr_pull_talloc(params, (char *)params, flags2,
4932 &name, params+ofs+12, len,
4933 STR_TERMINATE|STR_UNICODE);
4934 if (ret == -1) {
4935 TALLOC_FREE(params);
4936 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4937 return;
4939 state->changes[i].name = name;
4940 ofs += next;
4943 TALLOC_FREE(params);
4944 tevent_req_done(req);
4947 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4948 uint32_t *pnum_changes,
4949 struct notify_change **pchanges)
4951 struct cli_notify_state *state = tevent_req_data(
4952 req, struct cli_notify_state);
4953 NTSTATUS status;
4955 if (tevent_req_is_nterror(req, &status)) {
4956 return status;
4959 *pnum_changes = state->num_changes;
4960 *pchanges = talloc_move(mem_ctx, &state->changes);
4961 return NT_STATUS_OK;
4964 struct cli_qpathinfo_state {
4965 uint8_t *param;
4966 uint8_t *data;
4967 uint16_t setup[1];
4968 uint32_t min_rdata;
4969 uint8_t *rdata;
4970 uint32_t num_rdata;
4973 static void cli_qpathinfo_done(struct tevent_req *subreq);
4975 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
4976 struct tevent_context *ev,
4977 struct cli_state *cli, const char *fname,
4978 uint16_t level, uint32_t min_rdata,
4979 uint32_t max_rdata)
4981 struct tevent_req *req, *subreq;
4982 struct cli_qpathinfo_state *state;
4984 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
4985 if (req == NULL) {
4986 return NULL;
4988 state->min_rdata = min_rdata;
4989 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
4991 state->param = talloc_zero_array(state, uint8_t, 6);
4992 if (tevent_req_nomem(state->param, req)) {
4993 return tevent_req_post(req, ev);
4995 SSVAL(state->param, 0, level);
4996 state->param = trans2_bytes_push_str(
4997 state->param, cli_ucs2(cli), fname, strlen(fname)+1, NULL);
4998 if (tevent_req_nomem(state->param, req)) {
4999 return tevent_req_post(req, ev);
5002 subreq = cli_trans_send(
5003 state, /* mem ctx. */
5004 ev, /* event ctx. */
5005 cli, /* cli_state. */
5006 SMBtrans2, /* cmd. */
5007 NULL, /* pipe name. */
5008 -1, /* fid. */
5009 0, /* function. */
5010 0, /* flags. */
5011 state->setup, /* setup. */
5012 1, /* num setup uint16_t words. */
5013 0, /* max returned setup. */
5014 state->param, /* param. */
5015 talloc_get_size(state->param), /* num param. */
5016 2, /* max returned param. */
5017 NULL, /* data. */
5018 0, /* num data. */
5019 max_rdata); /* max returned data. */
5021 if (tevent_req_nomem(subreq, req)) {
5022 return tevent_req_post(req, ev);
5024 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5025 return req;
5028 static void cli_qpathinfo_done(struct tevent_req *subreq)
5030 struct tevent_req *req = tevent_req_callback_data(
5031 subreq, struct tevent_req);
5032 struct cli_qpathinfo_state *state = tevent_req_data(
5033 req, struct cli_qpathinfo_state);
5034 NTSTATUS status;
5036 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5037 NULL, 0, NULL,
5038 &state->rdata, state->min_rdata,
5039 &state->num_rdata);
5040 if (!NT_STATUS_IS_OK(status)) {
5041 tevent_req_nterror(req, status);
5042 return;
5044 tevent_req_done(req);
5047 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5048 uint8_t **rdata, uint32_t *num_rdata)
5050 struct cli_qpathinfo_state *state = tevent_req_data(
5051 req, struct cli_qpathinfo_state);
5052 NTSTATUS status;
5054 if (tevent_req_is_nterror(req, &status)) {
5055 return status;
5057 if (rdata != NULL) {
5058 *rdata = talloc_move(mem_ctx, &state->rdata);
5059 } else {
5060 TALLOC_FREE(state->rdata);
5062 if (num_rdata != NULL) {
5063 *num_rdata = state->num_rdata;
5065 return NT_STATUS_OK;
5068 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5069 const char *fname, uint16_t level, uint32_t min_rdata,
5070 uint32_t max_rdata,
5071 uint8_t **rdata, uint32_t *num_rdata)
5073 TALLOC_CTX *frame = talloc_stackframe();
5074 struct event_context *ev;
5075 struct tevent_req *req;
5076 NTSTATUS status = NT_STATUS_NO_MEMORY;
5078 if (cli_has_async_calls(cli)) {
5080 * Can't use sync call while an async call is in flight
5082 status = NT_STATUS_INVALID_PARAMETER;
5083 goto fail;
5085 ev = event_context_init(frame);
5086 if (ev == NULL) {
5087 goto fail;
5089 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5090 max_rdata);
5091 if (req == NULL) {
5092 goto fail;
5094 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5095 goto fail;
5097 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5098 fail:
5099 TALLOC_FREE(frame);
5100 if (!NT_STATUS_IS_OK(status)) {
5101 cli_set_error(cli, status);
5103 return status;
5106 struct cli_qfileinfo_state {
5107 uint16_t setup[1];
5108 uint8_t param[4];
5109 uint8_t *data;
5110 uint32_t min_rdata;
5111 uint8_t *rdata;
5112 uint32_t num_rdata;
5115 static void cli_qfileinfo_done(struct tevent_req *subreq);
5117 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
5118 struct tevent_context *ev,
5119 struct cli_state *cli, uint16_t fnum,
5120 uint16_t level, uint32_t min_rdata,
5121 uint32_t max_rdata)
5123 struct tevent_req *req, *subreq;
5124 struct cli_qfileinfo_state *state;
5126 req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
5127 if (req == NULL) {
5128 return NULL;
5130 state->min_rdata = min_rdata;
5131 SSVAL(state->param, 0, fnum);
5132 SSVAL(state->param, 2, level);
5133 SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
5135 subreq = cli_trans_send(
5136 state, /* mem ctx. */
5137 ev, /* event ctx. */
5138 cli, /* cli_state. */
5139 SMBtrans2, /* cmd. */
5140 NULL, /* pipe name. */
5141 -1, /* fid. */
5142 0, /* function. */
5143 0, /* flags. */
5144 state->setup, /* setup. */
5145 1, /* num setup uint16_t words. */
5146 0, /* max returned setup. */
5147 state->param, /* param. */
5148 sizeof(state->param), /* num param. */
5149 2, /* max returned param. */
5150 NULL, /* data. */
5151 0, /* num data. */
5152 max_rdata); /* max returned data. */
5154 if (tevent_req_nomem(subreq, req)) {
5155 return tevent_req_post(req, ev);
5157 tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
5158 return req;
5161 static void cli_qfileinfo_done(struct tevent_req *subreq)
5163 struct tevent_req *req = tevent_req_callback_data(
5164 subreq, struct tevent_req);
5165 struct cli_qfileinfo_state *state = tevent_req_data(
5166 req, struct cli_qfileinfo_state);
5167 NTSTATUS status;
5169 status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5170 NULL, 0, NULL,
5171 &state->rdata, state->min_rdata,
5172 &state->num_rdata);
5173 if (!NT_STATUS_IS_OK(status)) {
5174 tevent_req_nterror(req, status);
5175 return;
5177 tevent_req_done(req);
5180 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5181 uint8_t **rdata, uint32_t *num_rdata)
5183 struct cli_qfileinfo_state *state = tevent_req_data(
5184 req, struct cli_qfileinfo_state);
5185 NTSTATUS status;
5187 if (tevent_req_is_nterror(req, &status)) {
5188 return status;
5190 if (rdata != NULL) {
5191 *rdata = talloc_move(mem_ctx, &state->rdata);
5192 } else {
5193 TALLOC_FREE(state->rdata);
5195 if (num_rdata != NULL) {
5196 *num_rdata = state->num_rdata;
5198 return NT_STATUS_OK;
5201 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5202 uint16_t fnum, uint16_t level, uint32_t min_rdata,
5203 uint32_t max_rdata,
5204 uint8_t **rdata, uint32_t *num_rdata)
5206 TALLOC_CTX *frame = talloc_stackframe();
5207 struct event_context *ev;
5208 struct tevent_req *req;
5209 NTSTATUS status = NT_STATUS_NO_MEMORY;
5211 if (cli_has_async_calls(cli)) {
5213 * Can't use sync call while an async call is in flight
5215 status = NT_STATUS_INVALID_PARAMETER;
5216 goto fail;
5218 ev = event_context_init(frame);
5219 if (ev == NULL) {
5220 goto fail;
5222 req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
5223 max_rdata);
5224 if (req == NULL) {
5225 goto fail;
5227 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5228 goto fail;
5230 status = cli_qfileinfo_recv(req, mem_ctx, rdata, num_rdata);
5231 fail:
5232 TALLOC_FREE(frame);
5233 if (!NT_STATUS_IS_OK(status)) {
5234 cli_set_error(cli, status);
5236 return status;
5239 struct cli_flush_state {
5240 uint16_t vwv[1];
5243 static void cli_flush_done(struct tevent_req *subreq);
5245 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
5246 struct event_context *ev,
5247 struct cli_state *cli,
5248 uint16_t fnum)
5250 struct tevent_req *req, *subreq;
5251 struct cli_flush_state *state;
5253 req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
5254 if (req == NULL) {
5255 return NULL;
5257 SSVAL(state->vwv + 0, 0, fnum);
5259 subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 1, state->vwv,
5260 0, NULL);
5261 if (tevent_req_nomem(subreq, req)) {
5262 return tevent_req_post(req, ev);
5264 tevent_req_set_callback(subreq, cli_flush_done, req);
5265 return req;
5268 static void cli_flush_done(struct tevent_req *subreq)
5270 struct tevent_req *req = tevent_req_callback_data(
5271 subreq, struct tevent_req);
5272 NTSTATUS status;
5274 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5275 TALLOC_FREE(subreq);
5276 if (!NT_STATUS_IS_OK(status)) {
5277 tevent_req_nterror(req, status);
5278 return;
5280 tevent_req_done(req);
5283 NTSTATUS cli_flush_recv(struct tevent_req *req)
5285 return tevent_req_simple_recv_ntstatus(req);
5288 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
5290 TALLOC_CTX *frame = talloc_stackframe();
5291 struct event_context *ev;
5292 struct tevent_req *req;
5293 NTSTATUS status = NT_STATUS_NO_MEMORY;
5295 if (cli_has_async_calls(cli)) {
5297 * Can't use sync call while an async call is in flight
5299 status = NT_STATUS_INVALID_PARAMETER;
5300 goto fail;
5302 ev = event_context_init(frame);
5303 if (ev == NULL) {
5304 goto fail;
5306 req = cli_flush_send(frame, ev, cli, fnum);
5307 if (req == NULL) {
5308 goto fail;
5310 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5311 goto fail;
5313 status = cli_flush_recv(req);
5314 fail:
5315 TALLOC_FREE(frame);
5316 if (!NT_STATUS_IS_OK(status)) {
5317 cli_set_error(cli, status);
5319 return status;
5322 struct cli_shadow_copy_data_state {
5323 uint16_t setup[4];
5324 uint8_t *data;
5325 uint32_t num_data;
5326 bool get_names;
5329 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
5331 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
5332 struct tevent_context *ev,
5333 struct cli_state *cli,
5334 uint16_t fnum,
5335 bool get_names)
5337 struct tevent_req *req, *subreq;
5338 struct cli_shadow_copy_data_state *state;
5339 uint32_t ret_size;
5341 req = tevent_req_create(mem_ctx, &state,
5342 struct cli_shadow_copy_data_state);
5343 if (req == NULL) {
5344 return NULL;
5346 state->get_names = get_names;
5347 ret_size = get_names ? cli->max_xmit : 16;
5349 SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
5350 SSVAL(state->setup + 2, 0, fnum);
5351 SCVAL(state->setup + 3, 0, 0); /* isFsctl */
5352 SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
5354 subreq = cli_trans_send(
5355 state, ev, cli, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
5356 state->setup, ARRAY_SIZE(state->setup), 0,
5357 NULL, 0, 0,
5358 NULL, 0, ret_size);
5359 if (tevent_req_nomem(subreq, req)) {
5360 return tevent_req_post(req, ev);
5362 tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
5363 return req;
5366 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
5368 struct tevent_req *req = tevent_req_callback_data(
5369 subreq, struct tevent_req);
5370 struct cli_shadow_copy_data_state *state = tevent_req_data(
5371 req, struct cli_shadow_copy_data_state);
5372 NTSTATUS status;
5374 status = cli_trans_recv(subreq, state, NULL,
5375 NULL, 0, NULL, /* setup */
5376 NULL, 0, NULL, /* param */
5377 &state->data, 12, &state->num_data);
5378 TALLOC_FREE(subreq);
5379 if (!NT_STATUS_IS_OK(status)) {
5380 tevent_req_nterror(req, status);
5381 return;
5383 tevent_req_done(req);
5386 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5387 char ***pnames, int *pnum_names)
5389 struct cli_shadow_copy_data_state *state = tevent_req_data(
5390 req, struct cli_shadow_copy_data_state);
5391 char **names;
5392 int i, num_names;
5393 uint32_t dlength;
5394 NTSTATUS status;
5396 if (tevent_req_is_nterror(req, &status)) {
5397 return status;
5399 num_names = IVAL(state->data, 4);
5400 dlength = IVAL(state->data, 8);
5402 if (!state->get_names) {
5403 *pnum_names = num_names;
5404 return NT_STATUS_OK;
5407 if (dlength+12 > state->num_data) {
5408 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5410 names = talloc_array(mem_ctx, char *, num_names);
5411 if (names == NULL) {
5412 return NT_STATUS_NO_MEMORY;
5415 for (i=0; i<num_names; i++) {
5416 bool ret;
5417 uint8_t *src;
5418 size_t converted_size;
5420 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
5421 ret = convert_string_talloc(
5422 names, CH_UTF16LE, CH_UNIX,
5423 src, 2 * sizeof(SHADOW_COPY_LABEL),
5424 &names[i], &converted_size, True);
5425 if (!ret) {
5426 TALLOC_FREE(names);
5427 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5430 *pnum_names = num_names;
5431 *pnames = names;
5432 return NT_STATUS_OK;
5435 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5436 uint16_t fnum, bool get_names,
5437 char ***pnames, int *pnum_names)
5439 TALLOC_CTX *frame = talloc_stackframe();
5440 struct event_context *ev;
5441 struct tevent_req *req;
5442 NTSTATUS status = NT_STATUS_NO_MEMORY;
5444 if (cli_has_async_calls(cli)) {
5446 * Can't use sync call while an async call is in flight
5448 status = NT_STATUS_INVALID_PARAMETER;
5449 goto fail;
5451 ev = event_context_init(frame);
5452 if (ev == NULL) {
5453 goto fail;
5455 req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
5456 if (req == NULL) {
5457 goto fail;
5459 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5460 goto fail;
5462 status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
5463 fail:
5464 TALLOC_FREE(frame);
5465 if (!NT_STATUS_IS_OK(status)) {
5466 cli_set_error(cli, status);
5468 return status;