s3:libsmb: avoid passing a function call as function parameter
[Samba.git] / source3 / libsmb / clifile.c
blobd7fcc4b4e3c45e6e64906e674fcc408ada20601b
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"
23 /***********************************************************
24 Common function for pushing stings, used by smb_bytes_push_str()
25 and trans_bytes_push_str(). Only difference is the align_odd
26 parameter setting.
27 ***********************************************************/
29 static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
30 const char *str, size_t str_len,
31 bool align_odd,
32 size_t *pconverted_size)
34 size_t buflen;
35 char *converted;
36 size_t converted_size;
38 if (buf == NULL) {
39 return NULL;
42 buflen = talloc_get_size(buf);
44 if (align_odd && ucs2 && (buflen % 2 == 0)) {
46 * We're pushing into an SMB buffer, align odd
48 buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
49 if (buf == NULL) {
50 return NULL;
52 buf[buflen] = '\0';
53 buflen += 1;
56 if (!convert_string_talloc(talloc_tos(), CH_UNIX,
57 ucs2 ? CH_UTF16LE : CH_DOS,
58 str, str_len, &converted,
59 &converted_size, true)) {
60 return NULL;
63 buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
64 buflen + converted_size);
65 if (buf == NULL) {
66 TALLOC_FREE(converted);
67 return NULL;
70 memcpy(buf + buflen, converted, converted_size);
72 TALLOC_FREE(converted);
74 if (pconverted_size) {
75 *pconverted_size = converted_size;
78 return buf;
81 /***********************************************************
82 Push a string into an SMB buffer, with odd byte alignment
83 if it's a UCS2 string.
84 ***********************************************************/
86 uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
87 const char *str, size_t str_len,
88 size_t *pconverted_size)
90 return internal_bytes_push_str(buf, ucs2, str, str_len,
91 true, pconverted_size);
94 /***********************************************************
95 Same as smb_bytes_push_str(), but without the odd byte
96 align for ucs2 (we're pushing into a param or data block).
97 static for now, although this will probably change when
98 other modules use async trans calls.
99 ***********************************************************/
101 static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
102 const char *str, size_t str_len,
103 size_t *pconverted_size)
105 return internal_bytes_push_str(buf, ucs2, str, str_len,
106 false, pconverted_size);
109 /****************************************************************************
110 Hard/Symlink a file (UNIX extensions).
111 Creates new name (sym)linked to oldname.
112 ****************************************************************************/
114 struct link_state {
115 uint16_t setup;
116 uint8_t *param;
117 uint8_t *data;
120 static void cli_posix_link_internal_done(struct tevent_req *subreq)
122 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
123 NULL, 0, NULL, NULL, 0, NULL);
124 return tevent_req_simple_finish_ntstatus(subreq, status);
127 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
128 struct event_context *ev,
129 struct cli_state *cli,
130 const char *oldname,
131 const char *newname,
132 bool hardlink)
134 struct tevent_req *req = NULL, *subreq = NULL;
135 struct link_state *state = NULL;
137 req = tevent_req_create(mem_ctx, &state, struct link_state);
138 if (req == NULL) {
139 return NULL;
142 /* Setup setup word. */
143 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
145 /* Setup param array. */
146 state->param = talloc_array(state, uint8_t, 6);
147 if (tevent_req_nomem(state->param, req)) {
148 return tevent_req_post(req, ev);
150 memset(state->param, '\0', 6);
151 SSVAL(state->param,0,hardlink ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
153 state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), newname,
154 strlen(newname)+1, NULL);
156 if (tevent_req_nomem(state->param, req)) {
157 return tevent_req_post(req, ev);
160 /* Setup data array. */
161 state->data = talloc_array(state, uint8_t, 0);
162 if (tevent_req_nomem(state->data, req)) {
163 return tevent_req_post(req, ev);
165 state->data = trans2_bytes_push_str(state->data, cli_ucs2(cli), oldname,
166 strlen(oldname)+1, NULL);
168 subreq = cli_trans_send(state, /* mem ctx. */
169 ev, /* event ctx. */
170 cli, /* cli_state. */
171 SMBtrans2, /* cmd. */
172 NULL, /* pipe name. */
173 -1, /* fid. */
174 0, /* function. */
175 0, /* flags. */
176 &state->setup, /* setup. */
177 1, /* num setup uint16_t words. */
178 0, /* max returned setup. */
179 state->param, /* param. */
180 talloc_get_size(state->param), /* num param. */
181 2, /* max returned param. */
182 state->data, /* data. */
183 talloc_get_size(state->data), /* num data. */
184 0); /* max returned data. */
186 if (tevent_req_nomem(subreq, req)) {
187 return tevent_req_post(req, ev);
189 tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
190 return req;
193 /****************************************************************************
194 Symlink a file (UNIX extensions).
195 ****************************************************************************/
197 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
198 struct event_context *ev,
199 struct cli_state *cli,
200 const char *oldname,
201 const char *newname)
203 return cli_posix_link_internal_send(mem_ctx, ev, cli,
204 oldname, newname, false);
207 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
209 NTSTATUS status;
211 if (tevent_req_is_nterror(req, &status)) {
212 return status;
214 return NT_STATUS_OK;
217 NTSTATUS cli_posix_symlink(struct cli_state *cli,
218 const char *oldname,
219 const char *newname)
221 TALLOC_CTX *frame = talloc_stackframe();
222 struct event_context *ev = NULL;
223 struct tevent_req *req = NULL;
224 NTSTATUS status = NT_STATUS_OK;
226 if (cli_has_async_calls(cli)) {
228 * Can't use sync call while an async call is in flight
230 status = NT_STATUS_INVALID_PARAMETER;
231 goto fail;
234 ev = event_context_init(frame);
235 if (ev == NULL) {
236 status = NT_STATUS_NO_MEMORY;
237 goto fail;
240 req = cli_posix_symlink_send(frame,
242 cli,
243 oldname,
244 newname);
245 if (req == NULL) {
246 status = NT_STATUS_NO_MEMORY;
247 goto fail;
250 if (!tevent_req_poll(req, ev)) {
251 status = map_nt_error_from_unix(errno);
252 goto fail;
255 status = cli_posix_symlink_recv(req);
257 fail:
258 TALLOC_FREE(frame);
259 if (!NT_STATUS_IS_OK(status)) {
260 cli_set_error(cli, status);
262 return status;
265 /****************************************************************************
266 Read a POSIX symlink.
267 ****************************************************************************/
269 struct readlink_state {
270 uint16_t setup;
271 uint8_t *param;
272 uint8_t *data;
273 uint32_t num_data;
276 static void cli_posix_readlink_done(struct tevent_req *subreq)
278 struct tevent_req *req = tevent_req_callback_data(
279 subreq, struct tevent_req);
280 struct readlink_state *state = tevent_req_data(req, struct readlink_state);
281 NTSTATUS status;
283 status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
284 &state->data, 0, &state->num_data);
285 TALLOC_FREE(subreq);
286 if (!NT_STATUS_IS_OK(status)) {
287 tevent_req_nterror(req, status);
288 return;
290 if (state->num_data == 0) {
291 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
292 return;
294 if (state->data[state->num_data-1] != '\0') {
295 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
296 return;
298 tevent_req_done(req);
301 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
302 struct event_context *ev,
303 struct cli_state *cli,
304 const char *fname,
305 size_t len)
307 struct tevent_req *req = NULL, *subreq = NULL;
308 struct readlink_state *state = NULL;
309 uint32_t maxbytelen = (uint32_t)(cli_ucs2(cli) ? len*3 : len);
311 if (maxbytelen < len) {
312 return NULL;
315 req = tevent_req_create(mem_ctx, &state, struct readlink_state);
316 if (req == NULL) {
317 return NULL;
320 /* Setup setup word. */
321 SSVAL(&state->setup, 0, TRANSACT2_QPATHINFO);
323 /* Setup param array. */
324 state->param = talloc_array(state, uint8_t, 6);
325 if (tevent_req_nomem(state->param, req)) {
326 return tevent_req_post(req, ev);
328 memset(state->param, '\0', 6);
329 SSVAL(state->param,0,SMB_QUERY_FILE_UNIX_LINK);
331 state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
332 strlen(fname)+1, NULL);
334 if (tevent_req_nomem(state->param, req)) {
335 return tevent_req_post(req, ev);
338 subreq = cli_trans_send(state, /* mem ctx. */
339 ev, /* event ctx. */
340 cli, /* cli_state. */
341 SMBtrans2, /* cmd. */
342 NULL, /* pipe name. */
343 -1, /* fid. */
344 0, /* function. */
345 0, /* flags. */
346 &state->setup, /* setup. */
347 1, /* num setup uint16_t words. */
348 0, /* max returned setup. */
349 state->param, /* param. */
350 talloc_get_size(state->param), /* num param. */
351 2, /* max returned param. */
352 NULL, /* data. */
353 0, /* num data. */
354 maxbytelen); /* max returned data. */
356 if (tevent_req_nomem(subreq, req)) {
357 return tevent_req_post(req, ev);
359 tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
360 return req;
363 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
364 char *retpath, size_t len)
366 NTSTATUS status;
367 char *converted = NULL;
368 size_t converted_size = 0;
369 struct readlink_state *state = tevent_req_data(req, struct readlink_state);
371 if (tevent_req_is_nterror(req, &status)) {
372 return status;
374 /* The returned data is a pushed string, not raw data. */
375 if (!convert_string_talloc(state,
376 cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
377 CH_UNIX,
378 state->data,
379 state->num_data,
380 &converted,
381 &converted_size,
382 true)) {
383 return NT_STATUS_NO_MEMORY;
386 len = MIN(len,converted_size);
387 if (len == 0) {
388 return NT_STATUS_DATA_ERROR;
390 memcpy(retpath, converted, len);
391 return NT_STATUS_OK;
394 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
395 char *linkpath, size_t len)
397 TALLOC_CTX *frame = talloc_stackframe();
398 struct event_context *ev = NULL;
399 struct tevent_req *req = NULL;
400 NTSTATUS status = NT_STATUS_OK;
402 if (cli_has_async_calls(cli)) {
404 * Can't use sync call while an async call is in flight
406 status = NT_STATUS_INVALID_PARAMETER;
407 goto fail;
410 ev = event_context_init(frame);
411 if (ev == NULL) {
412 status = NT_STATUS_NO_MEMORY;
413 goto fail;
416 /* Len is in bytes, we need it in UCS2 units. */
417 if (2*len < len) {
418 status = NT_STATUS_INVALID_PARAMETER;
419 goto fail;
422 req = cli_posix_readlink_send(frame,
424 cli,
425 fname,
426 len);
427 if (req == NULL) {
428 status = NT_STATUS_NO_MEMORY;
429 goto fail;
432 if (!tevent_req_poll(req, ev)) {
433 status = map_nt_error_from_unix(errno);
434 goto fail;
437 status = cli_posix_readlink_recv(req, cli, linkpath, len);
439 fail:
440 TALLOC_FREE(frame);
441 if (!NT_STATUS_IS_OK(status)) {
442 cli_set_error(cli, status);
444 return status;
447 /****************************************************************************
448 Hard link a file (UNIX extensions).
449 ****************************************************************************/
451 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
452 struct event_context *ev,
453 struct cli_state *cli,
454 const char *oldname,
455 const char *newname)
457 return cli_posix_link_internal_send(mem_ctx, ev, cli,
458 oldname, newname, true);
461 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
463 NTSTATUS status;
465 if (tevent_req_is_nterror(req, &status)) {
466 return status;
468 return NT_STATUS_OK;
471 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
472 const char *oldname,
473 const char *newname)
475 TALLOC_CTX *frame = talloc_stackframe();
476 struct event_context *ev = NULL;
477 struct tevent_req *req = NULL;
478 NTSTATUS status = NT_STATUS_OK;
480 if (cli_has_async_calls(cli)) {
482 * Can't use sync call while an async call is in flight
484 status = NT_STATUS_INVALID_PARAMETER;
485 goto fail;
488 ev = event_context_init(frame);
489 if (ev == NULL) {
490 status = NT_STATUS_NO_MEMORY;
491 goto fail;
494 req = cli_posix_hardlink_send(frame,
496 cli,
497 oldname,
498 newname);
499 if (req == NULL) {
500 status = NT_STATUS_NO_MEMORY;
501 goto fail;
504 if (!tevent_req_poll(req, ev)) {
505 status = map_nt_error_from_unix(errno);
506 goto fail;
509 status = cli_posix_hardlink_recv(req);
511 fail:
512 TALLOC_FREE(frame);
513 if (!NT_STATUS_IS_OK(status)) {
514 cli_set_error(cli, status);
516 return status;
519 /****************************************************************************
520 Map standard UNIX permissions onto wire representations.
521 ****************************************************************************/
523 uint32_t unix_perms_to_wire(mode_t perms)
525 unsigned int ret = 0;
527 ret |= ((perms & S_IXOTH) ? UNIX_X_OTH : 0);
528 ret |= ((perms & S_IWOTH) ? UNIX_W_OTH : 0);
529 ret |= ((perms & S_IROTH) ? UNIX_R_OTH : 0);
530 ret |= ((perms & S_IXGRP) ? UNIX_X_GRP : 0);
531 ret |= ((perms & S_IWGRP) ? UNIX_W_GRP : 0);
532 ret |= ((perms & S_IRGRP) ? UNIX_R_GRP : 0);
533 ret |= ((perms & S_IXUSR) ? UNIX_X_USR : 0);
534 ret |= ((perms & S_IWUSR) ? UNIX_W_USR : 0);
535 ret |= ((perms & S_IRUSR) ? UNIX_R_USR : 0);
536 #ifdef S_ISVTX
537 ret |= ((perms & S_ISVTX) ? UNIX_STICKY : 0);
538 #endif
539 #ifdef S_ISGID
540 ret |= ((perms & S_ISGID) ? UNIX_SET_GID : 0);
541 #endif
542 #ifdef S_ISUID
543 ret |= ((perms & S_ISUID) ? UNIX_SET_UID : 0);
544 #endif
545 return ret;
548 /****************************************************************************
549 Map wire permissions to standard UNIX.
550 ****************************************************************************/
552 mode_t wire_perms_to_unix(uint32_t perms)
554 mode_t ret = (mode_t)0;
556 ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
557 ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
558 ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
559 ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
560 ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
561 ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
562 ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
563 ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
564 ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
565 #ifdef S_ISVTX
566 ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
567 #endif
568 #ifdef S_ISGID
569 ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
570 #endif
571 #ifdef S_ISUID
572 ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
573 #endif
574 return ret;
577 /****************************************************************************
578 Return the file type from the wire filetype for UNIX extensions.
579 ****************************************************************************/
581 static mode_t unix_filetype_from_wire(uint32_t wire_type)
583 switch (wire_type) {
584 case UNIX_TYPE_FILE:
585 return S_IFREG;
586 case UNIX_TYPE_DIR:
587 return S_IFDIR;
588 #ifdef S_IFLNK
589 case UNIX_TYPE_SYMLINK:
590 return S_IFLNK;
591 #endif
592 #ifdef S_IFCHR
593 case UNIX_TYPE_CHARDEV:
594 return S_IFCHR;
595 #endif
596 #ifdef S_IFBLK
597 case UNIX_TYPE_BLKDEV:
598 return S_IFBLK;
599 #endif
600 #ifdef S_IFIFO
601 case UNIX_TYPE_FIFO:
602 return S_IFIFO;
603 #endif
604 #ifdef S_IFSOCK
605 case UNIX_TYPE_SOCKET:
606 return S_IFSOCK;
607 #endif
608 default:
609 return (mode_t)0;
613 /****************************************************************************
614 Do a POSIX getfacl (UNIX extensions).
615 ****************************************************************************/
617 struct getfacl_state {
618 uint16_t setup;
619 uint8_t *param;
620 uint32_t num_data;
621 uint8_t *data;
624 static void cli_posix_getfacl_done(struct tevent_req *subreq)
626 struct tevent_req *req = tevent_req_callback_data(
627 subreq, struct tevent_req);
628 struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
629 NTSTATUS status;
631 status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
632 &state->data, 0, &state->num_data);
633 TALLOC_FREE(subreq);
634 if (!NT_STATUS_IS_OK(status)) {
635 tevent_req_nterror(req, status);
636 return;
638 tevent_req_done(req);
641 struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
642 struct event_context *ev,
643 struct cli_state *cli,
644 const char *fname)
646 struct tevent_req *req = NULL, *subreq = NULL;
647 struct link_state *state = NULL;
649 req = tevent_req_create(mem_ctx, &state, struct getfacl_state);
650 if (req == NULL) {
651 return NULL;
654 /* Setup setup word. */
655 SSVAL(&state->setup, 0, TRANSACT2_QPATHINFO);
657 /* Setup param array. */
658 state->param = talloc_array(state, uint8_t, 6);
659 if (tevent_req_nomem(state->param, req)) {
660 return tevent_req_post(req, ev);
662 memset(state->param, '\0', 6);
663 SSVAL(state->param, 0, SMB_QUERY_POSIX_ACL);
665 state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
666 strlen(fname)+1, NULL);
668 if (tevent_req_nomem(state->param, req)) {
669 return tevent_req_post(req, ev);
672 subreq = cli_trans_send(state, /* mem ctx. */
673 ev, /* event ctx. */
674 cli, /* cli_state. */
675 SMBtrans2, /* cmd. */
676 NULL, /* pipe name. */
677 -1, /* fid. */
678 0, /* function. */
679 0, /* flags. */
680 &state->setup, /* setup. */
681 1, /* num setup uint16_t words. */
682 0, /* max returned setup. */
683 state->param, /* param. */
684 talloc_get_size(state->param), /* num param. */
685 2, /* max returned param. */
686 NULL, /* data. */
687 0, /* num data. */
688 cli->max_xmit); /* max returned data. */
690 if (tevent_req_nomem(subreq, req)) {
691 return tevent_req_post(req, ev);
693 tevent_req_set_callback(subreq, cli_posix_getfacl_done, req);
694 return req;
697 NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
698 TALLOC_CTX *mem_ctx,
699 size_t *prb_size,
700 char **retbuf)
702 struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
703 NTSTATUS status;
705 if (tevent_req_is_nterror(req, &status)) {
706 return status;
708 *prb_size = (size_t)state->num_data;
709 *retbuf = (char *)talloc_move(mem_ctx, &state->data);
710 return NT_STATUS_OK;
713 NTSTATUS cli_posix_getfacl(struct cli_state *cli,
714 const char *fname,
715 TALLOC_CTX *mem_ctx,
716 size_t *prb_size,
717 char **retbuf)
719 TALLOC_CTX *frame = talloc_stackframe();
720 struct event_context *ev = NULL;
721 struct tevent_req *req = NULL;
722 NTSTATUS status = NT_STATUS_OK;
724 if (cli_has_async_calls(cli)) {
726 * Can't use sync call while an async call is in flight
728 status = NT_STATUS_INVALID_PARAMETER;
729 goto fail;
732 ev = event_context_init(frame);
733 if (ev == NULL) {
734 status = NT_STATUS_NO_MEMORY;
735 goto fail;
738 req = cli_posix_getfacl_send(frame,
740 cli,
741 fname);
742 if (req == NULL) {
743 status = NT_STATUS_NO_MEMORY;
744 goto fail;
747 if (!tevent_req_poll(req, ev)) {
748 status = map_nt_error_from_unix(errno);
749 goto fail;
752 status = cli_posix_getfacl_recv(req, mem_ctx, prb_size, retbuf);
754 fail:
755 TALLOC_FREE(frame);
756 if (!NT_STATUS_IS_OK(status)) {
757 cli_set_error(cli, status);
759 return status;
762 /****************************************************************************
763 Stat a file (UNIX extensions).
764 ****************************************************************************/
766 struct stat_state {
767 uint16_t setup;
768 uint8_t *param;
769 uint32_t num_data;
770 uint8_t *data;
773 static void cli_posix_stat_done(struct tevent_req *subreq)
775 struct tevent_req *req = tevent_req_callback_data(
776 subreq, struct tevent_req);
777 struct stat_state *state = tevent_req_data(req, struct stat_state);
778 NTSTATUS status;
780 status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
781 &state->data, 96, &state->num_data);
782 TALLOC_FREE(subreq);
783 if (!NT_STATUS_IS_OK(status)) {
784 tevent_req_nterror(req, status);
785 return;
787 tevent_req_done(req);
790 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
791 struct event_context *ev,
792 struct cli_state *cli,
793 const char *fname)
795 struct tevent_req *req = NULL, *subreq = NULL;
796 struct stat_state *state = NULL;
798 req = tevent_req_create(mem_ctx, &state, struct stat_state);
799 if (req == NULL) {
800 return NULL;
803 /* Setup setup word. */
804 SSVAL(&state->setup, 0, TRANSACT2_QPATHINFO);
806 /* Setup param array. */
807 state->param = talloc_array(state, uint8_t, 6);
808 if (tevent_req_nomem(state->param, req)) {
809 return tevent_req_post(req, ev);
811 memset(state->param, '\0', 6);
812 SSVAL(state->param, 0, SMB_QUERY_FILE_UNIX_BASIC);
814 state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
815 strlen(fname)+1, NULL);
817 if (tevent_req_nomem(state->param, req)) {
818 return tevent_req_post(req, ev);
821 subreq = cli_trans_send(state, /* mem ctx. */
822 ev, /* event ctx. */
823 cli, /* cli_state. */
824 SMBtrans2, /* cmd. */
825 NULL, /* pipe name. */
826 -1, /* fid. */
827 0, /* function. */
828 0, /* flags. */
829 &state->setup, /* setup. */
830 1, /* num setup uint16_t words. */
831 0, /* max returned setup. */
832 state->param, /* param. */
833 talloc_get_size(state->param), /* num param. */
834 2, /* max returned param. */
835 NULL, /* data. */
836 0, /* num data. */
837 96); /* max returned data. */
839 if (tevent_req_nomem(subreq, req)) {
840 return tevent_req_post(req, ev);
842 tevent_req_set_callback(subreq, cli_posix_stat_done, req);
843 return req;
846 NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
847 SMB_STRUCT_STAT *sbuf)
849 struct stat_state *state = tevent_req_data(req, struct stat_state);
850 NTSTATUS status;
852 if (tevent_req_is_nterror(req, &status)) {
853 return status;
856 if (state->num_data != 96) {
857 return NT_STATUS_DATA_ERROR;
860 sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0); /* total size, in bytes */
861 sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8); /* number of blocks allocated */
862 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
863 sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
864 #else
865 /* assume 512 byte blocks */
866 sbuf->st_ex_blocks /= 512;
867 #endif
868 sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16)); /* time of last change */
869 sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24)); /* time of last access */
870 sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32)); /* time of last modification */
872 sbuf->st_ex_uid = (uid_t) IVAL(state->data,40); /* user ID of owner */
873 sbuf->st_ex_gid = (gid_t) IVAL(state->data,48); /* group ID of owner */
874 sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
875 #if defined(HAVE_MAKEDEV)
877 uint32_t dev_major = IVAL(state->data,60);
878 uint32_t dev_minor = IVAL(state->data,68);
879 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
881 #endif
882 sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76); /* inode */
883 sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84)); /* protection */
884 sbuf->st_ex_nlink = IVAL(state->data,92); /* number of hard links */
886 return NT_STATUS_OK;
889 NTSTATUS cli_posix_stat(struct cli_state *cli,
890 const char *fname,
891 SMB_STRUCT_STAT *sbuf)
893 TALLOC_CTX *frame = talloc_stackframe();
894 struct event_context *ev = NULL;
895 struct tevent_req *req = NULL;
896 NTSTATUS status = NT_STATUS_OK;
898 if (cli_has_async_calls(cli)) {
900 * Can't use sync call while an async call is in flight
902 status = NT_STATUS_INVALID_PARAMETER;
903 goto fail;
906 ev = event_context_init(frame);
907 if (ev == NULL) {
908 status = NT_STATUS_NO_MEMORY;
909 goto fail;
912 req = cli_posix_stat_send(frame,
914 cli,
915 fname);
916 if (req == NULL) {
917 status = NT_STATUS_NO_MEMORY;
918 goto fail;
921 if (!tevent_req_poll(req, ev)) {
922 status = map_nt_error_from_unix(errno);
923 goto fail;
926 status = cli_posix_stat_recv(req, sbuf);
928 fail:
929 TALLOC_FREE(frame);
930 if (!NT_STATUS_IS_OK(status)) {
931 cli_set_error(cli, status);
933 return status;
936 /****************************************************************************
937 Chmod or chown a file internal (UNIX extensions).
938 ****************************************************************************/
940 struct ch_state {
941 uint16_t setup;
942 uint8_t *param;
943 uint8_t *data;
946 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
948 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
949 NULL, 0, NULL, NULL, 0, NULL);
950 return tevent_req_simple_finish_ntstatus(subreq, status);
953 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
954 struct event_context *ev,
955 struct cli_state *cli,
956 const char *fname,
957 uint32_t mode,
958 uint32_t uid,
959 uint32_t gid)
961 struct tevent_req *req = NULL, *subreq = NULL;
962 struct ch_state *state = NULL;
964 req = tevent_req_create(mem_ctx, &state, struct ch_state);
965 if (req == NULL) {
966 return NULL;
969 /* Setup setup word. */
970 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
972 /* Setup param array. */
973 state->param = talloc_array(state, uint8_t, 6);
974 if (tevent_req_nomem(state->param, req)) {
975 return tevent_req_post(req, ev);
977 memset(state->param, '\0', 6);
978 SSVAL(state->param,0,SMB_SET_FILE_UNIX_BASIC);
980 state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
981 strlen(fname)+1, NULL);
983 if (tevent_req_nomem(state->param, req)) {
984 return tevent_req_post(req, ev);
987 /* Setup data array. */
988 state->data = talloc_array(state, uint8_t, 100);
989 if (tevent_req_nomem(state->data, req)) {
990 return tevent_req_post(req, ev);
992 memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
993 memset(&state->data[40], '\0', 60);
994 SIVAL(state->data,40,uid);
995 SIVAL(state->data,48,gid);
996 SIVAL(state->data,84,mode);
998 subreq = cli_trans_send(state, /* mem ctx. */
999 ev, /* event ctx. */
1000 cli, /* cli_state. */
1001 SMBtrans2, /* cmd. */
1002 NULL, /* pipe name. */
1003 -1, /* fid. */
1004 0, /* function. */
1005 0, /* flags. */
1006 &state->setup, /* setup. */
1007 1, /* num setup uint16_t words. */
1008 0, /* max returned setup. */
1009 state->param, /* param. */
1010 talloc_get_size(state->param), /* num param. */
1011 2, /* max returned param. */
1012 state->data, /* data. */
1013 talloc_get_size(state->data), /* num data. */
1014 0); /* max returned data. */
1016 if (tevent_req_nomem(subreq, req)) {
1017 return tevent_req_post(req, ev);
1019 tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done, req);
1020 return req;
1023 /****************************************************************************
1024 chmod a file (UNIX extensions).
1025 ****************************************************************************/
1027 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
1028 struct event_context *ev,
1029 struct cli_state *cli,
1030 const char *fname,
1031 mode_t mode)
1033 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
1034 fname,
1035 unix_perms_to_wire(mode),
1036 SMB_UID_NO_CHANGE,
1037 SMB_GID_NO_CHANGE);
1040 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
1042 NTSTATUS status;
1044 if (tevent_req_is_nterror(req, &status)) {
1045 return status;
1047 return NT_STATUS_OK;
1050 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
1052 TALLOC_CTX *frame = talloc_stackframe();
1053 struct event_context *ev = NULL;
1054 struct tevent_req *req = NULL;
1055 NTSTATUS status = NT_STATUS_OK;
1057 if (cli_has_async_calls(cli)) {
1059 * Can't use sync call while an async call is in flight
1061 status = NT_STATUS_INVALID_PARAMETER;
1062 goto fail;
1065 ev = event_context_init(frame);
1066 if (ev == NULL) {
1067 status = NT_STATUS_NO_MEMORY;
1068 goto fail;
1071 req = cli_posix_chmod_send(frame,
1073 cli,
1074 fname,
1075 mode);
1076 if (req == NULL) {
1077 status = NT_STATUS_NO_MEMORY;
1078 goto fail;
1081 if (!tevent_req_poll(req, ev)) {
1082 status = map_nt_error_from_unix(errno);
1083 goto fail;
1086 status = cli_posix_chmod_recv(req);
1088 fail:
1089 TALLOC_FREE(frame);
1090 if (!NT_STATUS_IS_OK(status)) {
1091 cli_set_error(cli, status);
1093 return status;
1096 /****************************************************************************
1097 chown a file (UNIX extensions).
1098 ****************************************************************************/
1100 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1101 struct event_context *ev,
1102 struct cli_state *cli,
1103 const char *fname,
1104 uid_t uid,
1105 gid_t gid)
1107 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
1108 fname,
1109 SMB_MODE_NO_CHANGE,
1110 (uint32_t)uid,
1111 (uint32_t)gid);
1114 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1116 NTSTATUS status;
1118 if (tevent_req_is_nterror(req, &status)) {
1119 return status;
1121 return NT_STATUS_OK;
1124 NTSTATUS cli_posix_chown(struct cli_state *cli,
1125 const char *fname,
1126 uid_t uid,
1127 gid_t gid)
1129 TALLOC_CTX *frame = talloc_stackframe();
1130 struct event_context *ev = NULL;
1131 struct tevent_req *req = NULL;
1132 NTSTATUS status = NT_STATUS_OK;
1134 if (cli_has_async_calls(cli)) {
1136 * Can't use sync call while an async call is in flight
1138 status = NT_STATUS_INVALID_PARAMETER;
1139 goto fail;
1142 ev = event_context_init(frame);
1143 if (ev == NULL) {
1144 status = NT_STATUS_NO_MEMORY;
1145 goto fail;
1148 req = cli_posix_chown_send(frame,
1150 cli,
1151 fname,
1152 uid,
1153 gid);
1154 if (req == NULL) {
1155 status = NT_STATUS_NO_MEMORY;
1156 goto fail;
1159 if (!tevent_req_poll(req, ev)) {
1160 status = map_nt_error_from_unix(errno);
1161 goto fail;
1164 status = cli_posix_chown_recv(req);
1166 fail:
1167 TALLOC_FREE(frame);
1168 if (!NT_STATUS_IS_OK(status)) {
1169 cli_set_error(cli, status);
1171 return status;
1174 /****************************************************************************
1175 Rename a file.
1176 ****************************************************************************/
1178 static void cli_rename_done(struct tevent_req *subreq);
1180 struct cli_rename_state {
1181 uint16_t vwv[1];
1184 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1185 struct event_context *ev,
1186 struct cli_state *cli,
1187 const char *fname_src,
1188 const char *fname_dst)
1190 struct tevent_req *req = NULL, *subreq = NULL;
1191 struct cli_rename_state *state = NULL;
1192 uint8_t additional_flags = 0;
1193 uint8_t *bytes = NULL;
1195 req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1196 if (req == NULL) {
1197 return NULL;
1200 SSVAL(state->vwv+0, 0, aSYSTEM | aHIDDEN | aDIR);
1202 bytes = talloc_array(state, uint8_t, 1);
1203 if (tevent_req_nomem(bytes, req)) {
1204 return tevent_req_post(req, ev);
1206 bytes[0] = 4;
1207 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1208 strlen(fname_src)+1, NULL);
1209 if (tevent_req_nomem(bytes, req)) {
1210 return tevent_req_post(req, ev);
1213 bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1214 talloc_get_size(bytes)+1);
1215 if (tevent_req_nomem(bytes, req)) {
1216 return tevent_req_post(req, ev);
1219 bytes[talloc_get_size(bytes)-1] = 4;
1220 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1221 strlen(fname_dst)+1, NULL);
1222 if (tevent_req_nomem(bytes, req)) {
1223 return tevent_req_post(req, ev);
1226 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1227 1, state->vwv, talloc_get_size(bytes), bytes);
1228 if (tevent_req_nomem(subreq, req)) {
1229 return tevent_req_post(req, ev);
1231 tevent_req_set_callback(subreq, cli_rename_done, req);
1232 return req;
1235 static void cli_rename_done(struct tevent_req *subreq)
1237 struct tevent_req *req = tevent_req_callback_data(
1238 subreq, struct tevent_req);
1239 NTSTATUS status;
1241 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1242 TALLOC_FREE(subreq);
1243 if (!NT_STATUS_IS_OK(status)) {
1244 tevent_req_nterror(req, status);
1245 return;
1247 tevent_req_done(req);
1250 NTSTATUS cli_rename_recv(struct tevent_req *req)
1252 return tevent_req_simple_recv_ntstatus(req);
1255 NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1257 TALLOC_CTX *frame = talloc_stackframe();
1258 struct event_context *ev;
1259 struct tevent_req *req;
1260 NTSTATUS status = NT_STATUS_OK;
1262 if (cli_has_async_calls(cli)) {
1264 * Can't use sync call while an async call is in flight
1266 status = NT_STATUS_INVALID_PARAMETER;
1267 goto fail;
1270 ev = event_context_init(frame);
1271 if (ev == NULL) {
1272 status = NT_STATUS_NO_MEMORY;
1273 goto fail;
1276 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
1277 if (req == NULL) {
1278 status = NT_STATUS_NO_MEMORY;
1279 goto fail;
1282 if (!tevent_req_poll(req, ev)) {
1283 status = map_nt_error_from_unix(errno);
1284 goto fail;
1287 status = cli_rename_recv(req);
1289 fail:
1290 TALLOC_FREE(frame);
1291 if (!NT_STATUS_IS_OK(status)) {
1292 cli_set_error(cli, status);
1294 return status;
1297 /****************************************************************************
1298 NT Rename a file.
1299 ****************************************************************************/
1301 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1303 struct cli_ntrename_internal_state {
1304 uint16_t vwv[4];
1307 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1308 struct event_context *ev,
1309 struct cli_state *cli,
1310 const char *fname_src,
1311 const char *fname_dst,
1312 uint16_t rename_flag)
1314 struct tevent_req *req = NULL, *subreq = NULL;
1315 struct cli_ntrename_internal_state *state = NULL;
1316 uint8_t additional_flags = 0;
1317 uint8_t *bytes = NULL;
1319 req = tevent_req_create(mem_ctx, &state,
1320 struct cli_ntrename_internal_state);
1321 if (req == NULL) {
1322 return NULL;
1325 SSVAL(state->vwv+0, 0 ,aSYSTEM | aHIDDEN | aDIR);
1326 SSVAL(state->vwv+1, 0, rename_flag);
1328 bytes = talloc_array(state, uint8_t, 1);
1329 if (tevent_req_nomem(bytes, req)) {
1330 return tevent_req_post(req, ev);
1332 bytes[0] = 4;
1333 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1334 strlen(fname_src)+1, NULL);
1335 if (tevent_req_nomem(bytes, req)) {
1336 return tevent_req_post(req, ev);
1339 bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1340 talloc_get_size(bytes)+1);
1341 if (tevent_req_nomem(bytes, req)) {
1342 return tevent_req_post(req, ev);
1345 bytes[talloc_get_size(bytes)-1] = 4;
1346 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1347 strlen(fname_dst)+1, NULL);
1348 if (tevent_req_nomem(bytes, req)) {
1349 return tevent_req_post(req, ev);
1352 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1353 4, state->vwv, talloc_get_size(bytes), bytes);
1354 if (tevent_req_nomem(subreq, req)) {
1355 return tevent_req_post(req, ev);
1357 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1358 return req;
1361 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1363 struct tevent_req *req = tevent_req_callback_data(
1364 subreq, struct tevent_req);
1365 NTSTATUS status;
1367 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1368 TALLOC_FREE(subreq);
1369 if (!NT_STATUS_IS_OK(status)) {
1370 tevent_req_nterror(req, status);
1371 return;
1373 tevent_req_done(req);
1376 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1378 return tevent_req_simple_recv_ntstatus(req);
1381 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1382 struct event_context *ev,
1383 struct cli_state *cli,
1384 const char *fname_src,
1385 const char *fname_dst)
1387 return cli_ntrename_internal_send(mem_ctx,
1389 cli,
1390 fname_src,
1391 fname_dst,
1392 RENAME_FLAG_RENAME);
1395 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1397 return cli_ntrename_internal_recv(req);
1400 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1402 TALLOC_CTX *frame = talloc_stackframe();
1403 struct event_context *ev;
1404 struct tevent_req *req;
1405 NTSTATUS status = NT_STATUS_OK;
1407 if (cli_has_async_calls(cli)) {
1409 * Can't use sync call while an async call is in flight
1411 status = NT_STATUS_INVALID_PARAMETER;
1412 goto fail;
1415 ev = event_context_init(frame);
1416 if (ev == NULL) {
1417 status = NT_STATUS_NO_MEMORY;
1418 goto fail;
1421 req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1422 if (req == NULL) {
1423 status = NT_STATUS_NO_MEMORY;
1424 goto fail;
1427 if (!tevent_req_poll(req, ev)) {
1428 status = map_nt_error_from_unix(errno);
1429 goto fail;
1432 status = cli_ntrename_recv(req);
1434 fail:
1435 TALLOC_FREE(frame);
1436 if (!NT_STATUS_IS_OK(status)) {
1437 cli_set_error(cli, status);
1439 return status;
1442 /****************************************************************************
1443 NT hardlink a file.
1444 ****************************************************************************/
1446 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1447 struct event_context *ev,
1448 struct cli_state *cli,
1449 const char *fname_src,
1450 const char *fname_dst)
1452 return cli_ntrename_internal_send(mem_ctx,
1454 cli,
1455 fname_src,
1456 fname_dst,
1457 RENAME_FLAG_HARD_LINK);
1460 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1462 return cli_ntrename_internal_recv(req);
1465 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1467 TALLOC_CTX *frame = talloc_stackframe();
1468 struct event_context *ev;
1469 struct tevent_req *req;
1470 NTSTATUS status = NT_STATUS_OK;
1472 if (cli_has_async_calls(cli)) {
1474 * Can't use sync call while an async call is in flight
1476 status = NT_STATUS_INVALID_PARAMETER;
1477 goto fail;
1480 ev = event_context_init(frame);
1481 if (ev == NULL) {
1482 status = NT_STATUS_NO_MEMORY;
1483 goto fail;
1486 req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1487 if (req == NULL) {
1488 status = NT_STATUS_NO_MEMORY;
1489 goto fail;
1492 if (!tevent_req_poll(req, ev)) {
1493 status = map_nt_error_from_unix(errno);
1494 goto fail;
1497 status = cli_nt_hardlink_recv(req);
1499 fail:
1500 TALLOC_FREE(frame);
1501 if (!NT_STATUS_IS_OK(status)) {
1502 cli_set_error(cli, status);
1504 return status;
1507 /****************************************************************************
1508 Delete a file.
1509 ****************************************************************************/
1511 static void cli_unlink_done(struct tevent_req *subreq);
1513 struct cli_unlink_state {
1514 uint16_t vwv[1];
1517 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1518 struct event_context *ev,
1519 struct cli_state *cli,
1520 const char *fname,
1521 uint16_t mayhave_attrs)
1523 struct tevent_req *req = NULL, *subreq = NULL;
1524 struct cli_unlink_state *state = NULL;
1525 uint8_t additional_flags = 0;
1526 uint8_t *bytes = NULL;
1528 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1529 if (req == NULL) {
1530 return NULL;
1533 SSVAL(state->vwv+0, 0, mayhave_attrs);
1535 bytes = talloc_array(state, uint8_t, 1);
1536 if (tevent_req_nomem(bytes, req)) {
1537 return tevent_req_post(req, ev);
1539 bytes[0] = 4;
1540 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
1541 strlen(fname)+1, NULL);
1543 if (tevent_req_nomem(bytes, req)) {
1544 return tevent_req_post(req, ev);
1547 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1548 1, state->vwv, talloc_get_size(bytes), bytes);
1549 if (tevent_req_nomem(subreq, req)) {
1550 return tevent_req_post(req, ev);
1552 tevent_req_set_callback(subreq, cli_unlink_done, req);
1553 return req;
1556 static void cli_unlink_done(struct tevent_req *subreq)
1558 struct tevent_req *req = tevent_req_callback_data(
1559 subreq, struct tevent_req);
1560 NTSTATUS status;
1562 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1563 TALLOC_FREE(subreq);
1564 if (!NT_STATUS_IS_OK(status)) {
1565 tevent_req_nterror(req, status);
1566 return;
1568 tevent_req_done(req);
1571 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1573 return tevent_req_simple_recv_ntstatus(req);
1576 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1578 TALLOC_CTX *frame = talloc_stackframe();
1579 struct event_context *ev;
1580 struct tevent_req *req;
1581 NTSTATUS status = NT_STATUS_OK;
1583 if (cli_has_async_calls(cli)) {
1585 * Can't use sync call while an async call is in flight
1587 status = NT_STATUS_INVALID_PARAMETER;
1588 goto fail;
1591 ev = event_context_init(frame);
1592 if (ev == NULL) {
1593 status = NT_STATUS_NO_MEMORY;
1594 goto fail;
1597 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1598 if (req == NULL) {
1599 status = NT_STATUS_NO_MEMORY;
1600 goto fail;
1603 if (!tevent_req_poll(req, ev)) {
1604 status = map_nt_error_from_unix(errno);
1605 goto fail;
1608 status = cli_unlink_recv(req);
1610 fail:
1611 TALLOC_FREE(frame);
1612 if (!NT_STATUS_IS_OK(status)) {
1613 cli_set_error(cli, status);
1615 return status;
1618 /****************************************************************************
1619 Create a directory.
1620 ****************************************************************************/
1622 static void cli_mkdir_done(struct tevent_req *subreq);
1624 struct cli_mkdir_state {
1625 int dummy;
1628 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1629 struct event_context *ev,
1630 struct cli_state *cli,
1631 const char *dname)
1633 struct tevent_req *req = NULL, *subreq = NULL;
1634 struct cli_mkdir_state *state = NULL;
1635 uint8_t additional_flags = 0;
1636 uint8_t *bytes = NULL;
1638 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1639 if (req == NULL) {
1640 return NULL;
1643 bytes = talloc_array(state, uint8_t, 1);
1644 if (tevent_req_nomem(bytes, req)) {
1645 return tevent_req_post(req, ev);
1647 bytes[0] = 4;
1648 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1649 strlen(dname)+1, NULL);
1651 if (tevent_req_nomem(bytes, req)) {
1652 return tevent_req_post(req, ev);
1655 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1656 0, NULL, talloc_get_size(bytes), bytes);
1657 if (tevent_req_nomem(subreq, req)) {
1658 return tevent_req_post(req, ev);
1660 tevent_req_set_callback(subreq, cli_mkdir_done, req);
1661 return req;
1664 static void cli_mkdir_done(struct tevent_req *subreq)
1666 struct tevent_req *req = tevent_req_callback_data(
1667 subreq, struct tevent_req);
1668 NTSTATUS status;
1670 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1671 TALLOC_FREE(subreq);
1672 if (!NT_STATUS_IS_OK(status)) {
1673 tevent_req_nterror(req, status);
1674 return;
1676 tevent_req_done(req);
1679 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1681 return tevent_req_simple_recv_ntstatus(req);
1684 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1686 TALLOC_CTX *frame = talloc_stackframe();
1687 struct event_context *ev;
1688 struct tevent_req *req;
1689 NTSTATUS status = NT_STATUS_OK;
1691 if (cli_has_async_calls(cli)) {
1693 * Can't use sync call while an async call is in flight
1695 status = NT_STATUS_INVALID_PARAMETER;
1696 goto fail;
1699 ev = event_context_init(frame);
1700 if (ev == NULL) {
1701 status = NT_STATUS_NO_MEMORY;
1702 goto fail;
1705 req = cli_mkdir_send(frame, ev, cli, dname);
1706 if (req == NULL) {
1707 status = NT_STATUS_NO_MEMORY;
1708 goto fail;
1711 if (!tevent_req_poll(req, ev)) {
1712 status = map_nt_error_from_unix(errno);
1713 goto fail;
1716 status = cli_mkdir_recv(req);
1718 fail:
1719 TALLOC_FREE(frame);
1720 if (!NT_STATUS_IS_OK(status)) {
1721 cli_set_error(cli, status);
1723 return status;
1726 /****************************************************************************
1727 Remove a directory.
1728 ****************************************************************************/
1730 static void cli_rmdir_done(struct tevent_req *subreq);
1732 struct cli_rmdir_state {
1733 int dummy;
1736 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1737 struct event_context *ev,
1738 struct cli_state *cli,
1739 const char *dname)
1741 struct tevent_req *req = NULL, *subreq = NULL;
1742 struct cli_rmdir_state *state = NULL;
1743 uint8_t additional_flags = 0;
1744 uint8_t *bytes = NULL;
1746 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1747 if (req == NULL) {
1748 return NULL;
1751 bytes = talloc_array(state, uint8_t, 1);
1752 if (tevent_req_nomem(bytes, req)) {
1753 return tevent_req_post(req, ev);
1755 bytes[0] = 4;
1756 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1757 strlen(dname)+1, NULL);
1759 if (tevent_req_nomem(bytes, req)) {
1760 return tevent_req_post(req, ev);
1763 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1764 0, NULL, talloc_get_size(bytes), bytes);
1765 if (tevent_req_nomem(subreq, req)) {
1766 return tevent_req_post(req, ev);
1768 tevent_req_set_callback(subreq, cli_rmdir_done, req);
1769 return req;
1772 static void cli_rmdir_done(struct tevent_req *subreq)
1774 struct tevent_req *req = tevent_req_callback_data(
1775 subreq, struct tevent_req);
1776 NTSTATUS status;
1778 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1779 TALLOC_FREE(subreq);
1780 if (!NT_STATUS_IS_OK(status)) {
1781 tevent_req_nterror(req, status);
1782 return;
1784 tevent_req_done(req);
1787 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1789 return tevent_req_simple_recv_ntstatus(req);
1792 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1794 TALLOC_CTX *frame = talloc_stackframe();
1795 struct event_context *ev;
1796 struct tevent_req *req;
1797 NTSTATUS status = NT_STATUS_OK;
1799 if (cli_has_async_calls(cli)) {
1801 * Can't use sync call while an async call is in flight
1803 status = NT_STATUS_INVALID_PARAMETER;
1804 goto fail;
1807 ev = event_context_init(frame);
1808 if (ev == NULL) {
1809 status = NT_STATUS_NO_MEMORY;
1810 goto fail;
1813 req = cli_rmdir_send(frame, ev, cli, dname);
1814 if (req == NULL) {
1815 status = NT_STATUS_NO_MEMORY;
1816 goto fail;
1819 if (!tevent_req_poll(req, ev)) {
1820 status = map_nt_error_from_unix(errno);
1821 goto fail;
1824 status = cli_rmdir_recv(req);
1826 fail:
1827 TALLOC_FREE(frame);
1828 if (!NT_STATUS_IS_OK(status)) {
1829 cli_set_error(cli, status);
1831 return status;
1834 /****************************************************************************
1835 Set or clear the delete on close flag.
1836 ****************************************************************************/
1838 struct doc_state {
1839 uint16_t setup;
1840 uint8_t param[6];
1841 uint8_t data[1];
1844 static void cli_nt_delete_on_close_done(struct tevent_req *subreq)
1846 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
1847 NULL, 0, NULL, NULL, 0, NULL);
1848 return tevent_req_simple_finish_ntstatus(subreq, status);
1851 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1852 struct event_context *ev,
1853 struct cli_state *cli,
1854 uint16_t fnum,
1855 bool flag)
1857 struct tevent_req *req = NULL, *subreq = NULL;
1858 struct doc_state *state = NULL;
1860 req = tevent_req_create(mem_ctx, &state, struct doc_state);
1861 if (req == NULL) {
1862 return NULL;
1865 /* Setup setup word. */
1866 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1868 /* Setup param array. */
1869 SSVAL(state->param,0,fnum);
1870 SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1872 /* Setup data array. */
1873 SCVAL(&state->data[0], 0, flag ? 1 : 0);
1875 subreq = cli_trans_send(state, /* mem ctx. */
1876 ev, /* event ctx. */
1877 cli, /* cli_state. */
1878 SMBtrans2, /* cmd. */
1879 NULL, /* pipe name. */
1880 -1, /* fid. */
1881 0, /* function. */
1882 0, /* flags. */
1883 &state->setup, /* setup. */
1884 1, /* num setup uint16_t words. */
1885 0, /* max returned setup. */
1886 state->param, /* param. */
1887 6, /* num param. */
1888 2, /* max returned param. */
1889 state->data, /* data. */
1890 1, /* num data. */
1891 0); /* max returned data. */
1893 if (tevent_req_nomem(subreq, req)) {
1894 return tevent_req_post(req, ev);
1896 tevent_req_set_callback(subreq, cli_nt_delete_on_close_done, req);
1897 return req;
1900 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1902 NTSTATUS status;
1904 if (tevent_req_is_nterror(req, &status)) {
1905 return status;
1907 return NT_STATUS_OK;
1910 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1912 TALLOC_CTX *frame = talloc_stackframe();
1913 struct event_context *ev = NULL;
1914 struct tevent_req *req = NULL;
1915 NTSTATUS status = NT_STATUS_OK;
1917 if (cli_has_async_calls(cli)) {
1919 * Can't use sync call while an async call is in flight
1921 status = NT_STATUS_INVALID_PARAMETER;
1922 goto fail;
1925 ev = event_context_init(frame);
1926 if (ev == NULL) {
1927 status = NT_STATUS_NO_MEMORY;
1928 goto fail;
1931 req = cli_nt_delete_on_close_send(frame,
1933 cli,
1934 fnum,
1935 flag);
1936 if (req == NULL) {
1937 status = NT_STATUS_NO_MEMORY;
1938 goto fail;
1941 if (!tevent_req_poll(req, ev)) {
1942 status = map_nt_error_from_unix(errno);
1943 goto fail;
1946 status = cli_nt_delete_on_close_recv(req);
1948 fail:
1949 TALLOC_FREE(frame);
1950 if (!NT_STATUS_IS_OK(status)) {
1951 cli_set_error(cli, status);
1953 return status;
1956 struct cli_ntcreate_state {
1957 uint16_t vwv[24];
1958 uint16_t fnum;
1961 static void cli_ntcreate_done(struct tevent_req *subreq);
1963 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
1964 struct event_context *ev,
1965 struct cli_state *cli,
1966 const char *fname,
1967 uint32_t CreatFlags,
1968 uint32_t DesiredAccess,
1969 uint32_t FileAttributes,
1970 uint32_t ShareAccess,
1971 uint32_t CreateDisposition,
1972 uint32_t CreateOptions,
1973 uint8_t SecurityFlags)
1975 struct tevent_req *req, *subreq;
1976 struct cli_ntcreate_state *state;
1977 uint16_t *vwv;
1978 uint8_t *bytes;
1979 size_t converted_len;
1981 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
1982 if (req == NULL) {
1983 return NULL;
1986 vwv = state->vwv;
1988 SCVAL(vwv+0, 0, 0xFF);
1989 SCVAL(vwv+0, 1, 0);
1990 SSVAL(vwv+1, 0, 0);
1991 SCVAL(vwv+2, 0, 0);
1993 if (cli->use_oplocks) {
1994 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1996 SIVAL(vwv+3, 1, CreatFlags);
1997 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
1998 SIVAL(vwv+7, 1, DesiredAccess);
1999 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
2000 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
2001 SIVAL(vwv+13, 1, FileAttributes);
2002 SIVAL(vwv+15, 1, ShareAccess);
2003 SIVAL(vwv+17, 1, CreateDisposition);
2004 SIVAL(vwv+19, 1, CreateOptions);
2005 SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
2006 SCVAL(vwv+23, 1, SecurityFlags);
2008 bytes = talloc_array(state, uint8_t, 0);
2009 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
2010 fname, strlen(fname)+1,
2011 &converted_len);
2013 /* sigh. this copes with broken netapp filer behaviour */
2014 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL);
2016 if (tevent_req_nomem(bytes, req)) {
2017 return tevent_req_post(req, ev);
2020 SSVAL(vwv+2, 1, converted_len);
2022 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
2023 talloc_get_size(bytes), bytes);
2024 if (tevent_req_nomem(subreq, req)) {
2025 return tevent_req_post(req, ev);
2027 tevent_req_set_callback(subreq, cli_ntcreate_done, req);
2028 return req;
2031 static void cli_ntcreate_done(struct tevent_req *subreq)
2033 struct tevent_req *req = tevent_req_callback_data(
2034 subreq, struct tevent_req);
2035 struct cli_ntcreate_state *state = tevent_req_data(
2036 req, struct cli_ntcreate_state);
2037 uint8_t wct;
2038 uint16_t *vwv;
2039 uint32_t num_bytes;
2040 uint8_t *bytes;
2041 NTSTATUS status;
2043 status = cli_smb_recv(subreq, 3, &wct, &vwv, &num_bytes, &bytes);
2044 if (!NT_STATUS_IS_OK(status)) {
2045 TALLOC_FREE(subreq);
2046 tevent_req_nterror(req, status);
2047 return;
2049 state->fnum = SVAL(vwv+2, 1);
2050 tevent_req_done(req);
2053 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
2055 struct cli_ntcreate_state *state = tevent_req_data(
2056 req, struct cli_ntcreate_state);
2057 NTSTATUS status;
2059 if (tevent_req_is_nterror(req, &status)) {
2060 return status;
2062 *pfnum = state->fnum;
2063 return NT_STATUS_OK;
2066 NTSTATUS cli_ntcreate(struct cli_state *cli,
2067 const char *fname,
2068 uint32_t CreatFlags,
2069 uint32_t DesiredAccess,
2070 uint32_t FileAttributes,
2071 uint32_t ShareAccess,
2072 uint32_t CreateDisposition,
2073 uint32_t CreateOptions,
2074 uint8_t SecurityFlags,
2075 uint16_t *pfid)
2077 TALLOC_CTX *frame = talloc_stackframe();
2078 struct event_context *ev;
2079 struct tevent_req *req;
2080 NTSTATUS status = NT_STATUS_OK;
2082 if (cli_has_async_calls(cli)) {
2084 * Can't use sync call while an async call is in flight
2086 status = NT_STATUS_INVALID_PARAMETER;
2087 goto fail;
2090 ev = event_context_init(frame);
2091 if (ev == NULL) {
2092 status = NT_STATUS_NO_MEMORY;
2093 goto fail;
2096 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2097 DesiredAccess, FileAttributes, ShareAccess,
2098 CreateDisposition, CreateOptions,
2099 SecurityFlags);
2100 if (req == NULL) {
2101 status = NT_STATUS_NO_MEMORY;
2102 goto fail;
2105 if (!tevent_req_poll(req, ev)) {
2106 status = map_nt_error_from_unix(errno);
2107 goto fail;
2110 status = cli_ntcreate_recv(req, pfid);
2111 fail:
2112 TALLOC_FREE(frame);
2113 if (!NT_STATUS_IS_OK(status)) {
2114 cli_set_error(cli, status);
2116 return status;
2119 /****************************************************************************
2120 Open a file
2121 WARNING: if you open with O_WRONLY then getattrE won't work!
2122 ****************************************************************************/
2124 struct cli_open_state {
2125 uint16_t vwv[15];
2126 uint16_t fnum;
2127 struct iovec bytes;
2130 static void cli_open_done(struct tevent_req *subreq);
2132 struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx,
2133 struct event_context *ev,
2134 struct cli_state *cli, const char *fname,
2135 int flags, int share_mode,
2136 struct tevent_req **psmbreq)
2138 struct tevent_req *req, *subreq;
2139 struct cli_open_state *state;
2140 unsigned openfn;
2141 unsigned accessmode;
2142 uint8_t additional_flags;
2143 uint8_t *bytes;
2145 req = tevent_req_create(mem_ctx, &state, struct cli_open_state);
2146 if (req == NULL) {
2147 return NULL;
2150 openfn = 0;
2151 if (flags & O_CREAT) {
2152 openfn |= (1<<4);
2154 if (!(flags & O_EXCL)) {
2155 if (flags & O_TRUNC)
2156 openfn |= (1<<1);
2157 else
2158 openfn |= (1<<0);
2161 accessmode = (share_mode<<4);
2163 if ((flags & O_ACCMODE) == O_RDWR) {
2164 accessmode |= 2;
2165 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2166 accessmode |= 1;
2169 #if defined(O_SYNC)
2170 if ((flags & O_SYNC) == O_SYNC) {
2171 accessmode |= (1<<14);
2173 #endif /* O_SYNC */
2175 if (share_mode == DENY_FCB) {
2176 accessmode = 0xFF;
2179 SCVAL(state->vwv + 0, 0, 0xFF);
2180 SCVAL(state->vwv + 0, 1, 0);
2181 SSVAL(state->vwv + 1, 0, 0);
2182 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
2183 SSVAL(state->vwv + 3, 0, accessmode);
2184 SSVAL(state->vwv + 4, 0, aSYSTEM | aHIDDEN);
2185 SSVAL(state->vwv + 5, 0, 0);
2186 SIVAL(state->vwv + 6, 0, 0);
2187 SSVAL(state->vwv + 8, 0, openfn);
2188 SIVAL(state->vwv + 9, 0, 0);
2189 SIVAL(state->vwv + 11, 0, 0);
2190 SIVAL(state->vwv + 13, 0, 0);
2192 additional_flags = 0;
2194 if (cli->use_oplocks) {
2195 /* if using oplocks then ask for a batch oplock via
2196 core and extended methods */
2197 additional_flags =
2198 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2199 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2202 bytes = talloc_array(state, uint8_t, 0);
2203 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
2204 strlen(fname)+1, NULL);
2206 if (tevent_req_nomem(bytes, req)) {
2207 return tevent_req_post(req, ev);
2210 state->bytes.iov_base = (void *)bytes;
2211 state->bytes.iov_len = talloc_get_size(bytes);
2213 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2214 15, state->vwv, 1, &state->bytes);
2215 if (subreq == NULL) {
2216 TALLOC_FREE(req);
2217 return NULL;
2219 tevent_req_set_callback(subreq, cli_open_done, req);
2220 *psmbreq = subreq;
2221 return req;
2224 struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
2225 struct cli_state *cli, const char *fname,
2226 int flags, int share_mode)
2228 struct tevent_req *req, *subreq;
2229 NTSTATUS status;
2231 req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode,
2232 &subreq);
2233 if (req == NULL) {
2234 return NULL;
2237 status = cli_smb_req_send(subreq);
2238 if (!NT_STATUS_IS_OK(status)) {
2239 tevent_req_nterror(req, status);
2240 return tevent_req_post(req, ev);
2242 return req;
2245 static void cli_open_done(struct tevent_req *subreq)
2247 struct tevent_req *req = tevent_req_callback_data(
2248 subreq, struct tevent_req);
2249 struct cli_open_state *state = tevent_req_data(
2250 req, struct cli_open_state);
2251 uint8_t wct;
2252 uint16_t *vwv;
2253 NTSTATUS status;
2255 status = cli_smb_recv(subreq, 3, &wct, &vwv, NULL, NULL);
2256 if (!NT_STATUS_IS_OK(status)) {
2257 TALLOC_FREE(subreq);
2258 tevent_req_nterror(req, status);
2259 return;
2261 state->fnum = SVAL(vwv+2, 0);
2262 tevent_req_done(req);
2265 NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum)
2267 struct cli_open_state *state = tevent_req_data(
2268 req, struct cli_open_state);
2269 NTSTATUS status;
2271 if (tevent_req_is_nterror(req, &status)) {
2272 return status;
2274 *pfnum = state->fnum;
2275 return NT_STATUS_OK;
2278 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2279 int share_mode, uint16_t *pfnum)
2281 TALLOC_CTX *frame = talloc_stackframe();
2282 struct event_context *ev;
2283 struct tevent_req *req;
2284 NTSTATUS status = NT_STATUS_OK;
2286 if (cli_has_async_calls(cli)) {
2288 * Can't use sync call while an async call is in flight
2290 status = NT_STATUS_INVALID_PARAMETER;
2291 goto fail;
2294 ev = event_context_init(frame);
2295 if (ev == NULL) {
2296 status = NT_STATUS_NO_MEMORY;
2297 goto fail;
2300 req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
2301 if (req == NULL) {
2302 status = NT_STATUS_NO_MEMORY;
2303 goto fail;
2306 if (!tevent_req_poll(req, ev)) {
2307 status = map_nt_error_from_unix(errno);
2308 goto fail;
2311 status = cli_open_recv(req, pfnum);
2312 fail:
2313 TALLOC_FREE(frame);
2314 if (!NT_STATUS_IS_OK(status)) {
2315 cli_set_error(cli, status);
2317 return status;
2320 /****************************************************************************
2321 Close a file.
2322 ****************************************************************************/
2324 struct cli_close_state {
2325 uint16_t vwv[3];
2328 static void cli_close_done(struct tevent_req *subreq);
2330 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2331 struct event_context *ev,
2332 struct cli_state *cli,
2333 uint16_t fnum,
2334 struct tevent_req **psubreq)
2336 struct tevent_req *req, *subreq;
2337 struct cli_close_state *state;
2339 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2340 if (req == NULL) {
2341 return NULL;
2344 SSVAL(state->vwv+0, 0, fnum);
2345 SIVALS(state->vwv+1, 0, -1);
2347 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2348 0, NULL);
2349 if (subreq == NULL) {
2350 TALLOC_FREE(req);
2351 return NULL;
2353 tevent_req_set_callback(subreq, cli_close_done, req);
2354 *psubreq = subreq;
2355 return req;
2358 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2359 struct event_context *ev,
2360 struct cli_state *cli,
2361 uint16_t fnum)
2363 struct tevent_req *req, *subreq;
2364 NTSTATUS status;
2366 req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2367 if (req == NULL) {
2368 return NULL;
2371 status = cli_smb_req_send(subreq);
2372 if (!NT_STATUS_IS_OK(status)) {
2373 tevent_req_nterror(req, status);
2374 return tevent_req_post(req, ev);
2376 return req;
2379 static void cli_close_done(struct tevent_req *subreq)
2381 struct tevent_req *req = tevent_req_callback_data(
2382 subreq, struct tevent_req);
2383 NTSTATUS status;
2385 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2386 TALLOC_FREE(subreq);
2387 if (!NT_STATUS_IS_OK(status)) {
2388 tevent_req_nterror(req, status);
2389 return;
2391 tevent_req_done(req);
2394 NTSTATUS cli_close_recv(struct tevent_req *req)
2396 return tevent_req_simple_recv_ntstatus(req);
2399 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2401 TALLOC_CTX *frame = talloc_stackframe();
2402 struct event_context *ev;
2403 struct tevent_req *req;
2404 NTSTATUS status = NT_STATUS_OK;
2406 if (cli_has_async_calls(cli)) {
2408 * Can't use sync call while an async call is in flight
2410 status = NT_STATUS_INVALID_PARAMETER;
2411 goto fail;
2414 ev = event_context_init(frame);
2415 if (ev == NULL) {
2416 status = NT_STATUS_NO_MEMORY;
2417 goto fail;
2420 req = cli_close_send(frame, ev, cli, fnum);
2421 if (req == NULL) {
2422 status = NT_STATUS_NO_MEMORY;
2423 goto fail;
2426 if (!tevent_req_poll(req, ev)) {
2427 status = map_nt_error_from_unix(errno);
2428 goto fail;
2431 status = cli_close_recv(req);
2432 fail:
2433 TALLOC_FREE(frame);
2434 if (!NT_STATUS_IS_OK(status)) {
2435 cli_set_error(cli, status);
2437 return status;
2440 /****************************************************************************
2441 Truncate a file to a specified size
2442 ****************************************************************************/
2444 struct ftrunc_state {
2445 uint16_t setup;
2446 uint8_t param[6];
2447 uint8_t data[8];
2450 static void cli_ftruncate_done(struct tevent_req *subreq)
2452 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
2453 NULL, 0, NULL, NULL, 0, NULL);
2454 return tevent_req_simple_finish_ntstatus(subreq, status);
2457 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2458 struct event_context *ev,
2459 struct cli_state *cli,
2460 uint16_t fnum,
2461 uint64_t size)
2463 struct tevent_req *req = NULL, *subreq = NULL;
2464 struct ftrunc_state *state = NULL;
2466 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2467 if (req == NULL) {
2468 return NULL;
2471 /* Setup setup word. */
2472 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2474 /* Setup param array. */
2475 SSVAL(state->param,0,fnum);
2476 SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2477 SSVAL(state->param,4,0);
2479 /* Setup data array. */
2480 SBVAL(state->data, 0, size);
2482 subreq = cli_trans_send(state, /* mem ctx. */
2483 ev, /* event ctx. */
2484 cli, /* cli_state. */
2485 SMBtrans2, /* cmd. */
2486 NULL, /* pipe name. */
2487 -1, /* fid. */
2488 0, /* function. */
2489 0, /* flags. */
2490 &state->setup, /* setup. */
2491 1, /* num setup uint16_t words. */
2492 0, /* max returned setup. */
2493 state->param, /* param. */
2494 6, /* num param. */
2495 2, /* max returned param. */
2496 state->data, /* data. */
2497 8, /* num data. */
2498 0); /* max returned data. */
2500 if (tevent_req_nomem(subreq, req)) {
2501 return tevent_req_post(req, ev);
2503 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2504 return req;
2507 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2509 NTSTATUS status;
2511 if (tevent_req_is_nterror(req, &status)) {
2512 return status;
2514 return NT_STATUS_OK;
2517 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2519 TALLOC_CTX *frame = talloc_stackframe();
2520 struct event_context *ev = NULL;
2521 struct tevent_req *req = NULL;
2522 NTSTATUS status = NT_STATUS_OK;
2524 if (cli_has_async_calls(cli)) {
2526 * Can't use sync call while an async call is in flight
2528 status = NT_STATUS_INVALID_PARAMETER;
2529 goto fail;
2532 ev = event_context_init(frame);
2533 if (ev == NULL) {
2534 status = NT_STATUS_NO_MEMORY;
2535 goto fail;
2538 req = cli_ftruncate_send(frame,
2540 cli,
2541 fnum,
2542 size);
2543 if (req == NULL) {
2544 status = NT_STATUS_NO_MEMORY;
2545 goto fail;
2548 if (!tevent_req_poll(req, ev)) {
2549 status = map_nt_error_from_unix(errno);
2550 goto fail;
2553 status = cli_ftruncate_recv(req);
2555 fail:
2556 TALLOC_FREE(frame);
2557 if (!NT_STATUS_IS_OK(status)) {
2558 cli_set_error(cli, status);
2560 return status;
2563 /****************************************************************************
2564 send a lock with a specified locktype
2565 this is used for testing LOCKING_ANDX_CANCEL_LOCK
2566 ****************************************************************************/
2568 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2569 uint32_t offset, uint32_t len,
2570 int timeout, unsigned char locktype)
2572 char *p;
2573 int saved_timeout = cli->timeout;
2575 memset(cli->outbuf,'\0',smb_size);
2576 memset(cli->inbuf,'\0', smb_size);
2578 cli_set_message(cli->outbuf,8,0,True);
2580 SCVAL(cli->outbuf,smb_com,SMBlockingX);
2581 SSVAL(cli->outbuf,smb_tid,cli->cnum);
2582 cli_setup_packet(cli);
2584 SCVAL(cli->outbuf,smb_vwv0,0xFF);
2585 SSVAL(cli->outbuf,smb_vwv2,fnum);
2586 SCVAL(cli->outbuf,smb_vwv3,locktype);
2587 SIVALS(cli->outbuf, smb_vwv4, timeout);
2588 SSVAL(cli->outbuf,smb_vwv6,0);
2589 SSVAL(cli->outbuf,smb_vwv7,1);
2591 p = smb_buf(cli->outbuf);
2592 SSVAL(p, 0, cli->pid);
2593 SIVAL(p, 2, offset);
2594 SIVAL(p, 6, len);
2596 p += 10;
2598 cli_setup_bcc(cli, p);
2600 cli_send_smb(cli);
2602 if (timeout != 0) {
2603 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
2606 if (!cli_receive_smb(cli)) {
2607 cli->timeout = saved_timeout;
2608 return NT_STATUS_UNSUCCESSFUL;
2611 cli->timeout = saved_timeout;
2613 return cli_nt_error(cli);
2616 /****************************************************************************
2617 Lock a file.
2618 note that timeout is in units of 2 milliseconds
2619 ****************************************************************************/
2621 bool cli_lock(struct cli_state *cli, uint16_t fnum,
2622 uint32_t offset, uint32_t len, int timeout, enum brl_type lock_type)
2624 char *p;
2625 int saved_timeout = cli->timeout;
2627 memset(cli->outbuf,'\0',smb_size);
2628 memset(cli->inbuf,'\0', smb_size);
2630 cli_set_message(cli->outbuf,8,0,True);
2632 SCVAL(cli->outbuf,smb_com,SMBlockingX);
2633 SSVAL(cli->outbuf,smb_tid,cli->cnum);
2634 cli_setup_packet(cli);
2636 SCVAL(cli->outbuf,smb_vwv0,0xFF);
2637 SSVAL(cli->outbuf,smb_vwv2,fnum);
2638 SCVAL(cli->outbuf,smb_vwv3,(lock_type == READ_LOCK? 1 : 0));
2639 SIVALS(cli->outbuf, smb_vwv4, timeout);
2640 SSVAL(cli->outbuf,smb_vwv6,0);
2641 SSVAL(cli->outbuf,smb_vwv7,1);
2643 p = smb_buf(cli->outbuf);
2644 SSVAL(p, 0, cli->pid);
2645 SIVAL(p, 2, offset);
2646 SIVAL(p, 6, len);
2648 p += 10;
2650 cli_setup_bcc(cli, p);
2652 cli_send_smb(cli);
2654 if (timeout != 0) {
2655 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout*2 + 5*1000);
2658 if (!cli_receive_smb(cli)) {
2659 cli->timeout = saved_timeout;
2660 return False;
2663 cli->timeout = saved_timeout;
2665 if (cli_is_error(cli)) {
2666 return False;
2669 return True;
2672 /****************************************************************************
2673 Unlock a file.
2674 ****************************************************************************/
2676 struct cli_unlock_state {
2677 uint16_t vwv[8];
2678 uint8_t data[10];
2681 static void cli_unlock_done(struct tevent_req *subreq);
2683 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
2684 struct event_context *ev,
2685 struct cli_state *cli,
2686 uint16_t fnum,
2687 uint64_t offset,
2688 uint64_t len)
2691 struct tevent_req *req = NULL, *subreq = NULL;
2692 struct cli_unlock_state *state = NULL;
2693 uint8_t additional_flags = 0;
2695 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
2696 if (req == NULL) {
2697 return NULL;
2700 SCVAL(state->vwv+0, 0, 0xFF);
2701 SSVAL(state->vwv+2, 0, fnum);
2702 SCVAL(state->vwv+3, 0, 0);
2703 SIVALS(state->vwv+4, 0, 0);
2704 SSVAL(state->vwv+6, 0, 1);
2705 SSVAL(state->vwv+7, 0, 0);
2707 SSVAL(state->data, 0, cli->pid);
2708 SIVAL(state->data, 2, offset);
2709 SIVAL(state->data, 6, len);
2711 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2712 8, state->vwv, 10, state->data);
2713 if (tevent_req_nomem(subreq, req)) {
2714 return tevent_req_post(req, ev);
2716 tevent_req_set_callback(subreq, cli_unlock_done, req);
2717 return req;
2720 static void cli_unlock_done(struct tevent_req *subreq)
2722 struct tevent_req *req = tevent_req_callback_data(
2723 subreq, struct tevent_req);
2724 NTSTATUS status;
2726 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2727 TALLOC_FREE(subreq);
2728 if (!NT_STATUS_IS_OK(status)) {
2729 tevent_req_nterror(req, status);
2730 return;
2732 tevent_req_done(req);
2735 NTSTATUS cli_unlock_recv(struct tevent_req *req)
2737 return tevent_req_simple_recv_ntstatus(req);
2740 NTSTATUS cli_unlock(struct cli_state *cli,
2741 uint16_t fnum,
2742 uint32_t offset,
2743 uint32_t len)
2745 TALLOC_CTX *frame = talloc_stackframe();
2746 struct event_context *ev;
2747 struct tevent_req *req;
2748 NTSTATUS status = NT_STATUS_OK;
2750 if (cli_has_async_calls(cli)) {
2752 * Can't use sync call while an async call is in flight
2754 status = NT_STATUS_INVALID_PARAMETER;
2755 goto fail;
2758 ev = event_context_init(frame);
2759 if (ev == NULL) {
2760 status = NT_STATUS_NO_MEMORY;
2761 goto fail;
2764 req = cli_unlock_send(frame, ev, cli,
2765 fnum, offset, len);
2766 if (req == NULL) {
2767 status = NT_STATUS_NO_MEMORY;
2768 goto fail;
2771 if (!tevent_req_poll(req, ev)) {
2772 status = map_nt_error_from_unix(errno);
2773 goto fail;
2776 status = cli_unlock_recv(req);
2778 fail:
2779 TALLOC_FREE(frame);
2780 if (!NT_STATUS_IS_OK(status)) {
2781 cli_set_error(cli, status);
2783 return status;
2786 /****************************************************************************
2787 Lock a file with 64 bit offsets.
2788 ****************************************************************************/
2790 bool cli_lock64(struct cli_state *cli, uint16_t fnum,
2791 uint64_t offset, uint64_t len, int timeout, enum brl_type lock_type)
2793 char *p;
2794 int saved_timeout = cli->timeout;
2795 int ltype;
2797 if (! (cli->capabilities & CAP_LARGE_FILES)) {
2798 return cli_lock(cli, fnum, offset, len, timeout, lock_type);
2801 ltype = (lock_type == READ_LOCK? 1 : 0);
2802 ltype |= LOCKING_ANDX_LARGE_FILES;
2804 memset(cli->outbuf,'\0',smb_size);
2805 memset(cli->inbuf,'\0', smb_size);
2807 cli_set_message(cli->outbuf,8,0,True);
2809 SCVAL(cli->outbuf,smb_com,SMBlockingX);
2810 SSVAL(cli->outbuf,smb_tid,cli->cnum);
2811 cli_setup_packet(cli);
2813 SCVAL(cli->outbuf,smb_vwv0,0xFF);
2814 SSVAL(cli->outbuf,smb_vwv2,fnum);
2815 SCVAL(cli->outbuf,smb_vwv3,ltype);
2816 SIVALS(cli->outbuf, smb_vwv4, timeout);
2817 SSVAL(cli->outbuf,smb_vwv6,0);
2818 SSVAL(cli->outbuf,smb_vwv7,1);
2820 p = smb_buf(cli->outbuf);
2821 SIVAL(p, 0, cli->pid);
2822 SOFF_T_R(p, 4, offset);
2823 SOFF_T_R(p, 12, len);
2824 p += 20;
2826 cli_setup_bcc(cli, p);
2827 cli_send_smb(cli);
2829 if (timeout != 0) {
2830 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 5*1000);
2833 if (!cli_receive_smb(cli)) {
2834 cli->timeout = saved_timeout;
2835 return False;
2838 cli->timeout = saved_timeout;
2840 if (cli_is_error(cli)) {
2841 return False;
2844 return True;
2847 /****************************************************************************
2848 Unlock a file with 64 bit offsets.
2849 ****************************************************************************/
2851 struct cli_unlock64_state {
2852 uint16_t vwv[8];
2853 uint8_t data[20];
2856 static void cli_unlock64_done(struct tevent_req *subreq);
2858 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
2859 struct event_context *ev,
2860 struct cli_state *cli,
2861 uint16_t fnum,
2862 uint64_t offset,
2863 uint64_t len)
2866 struct tevent_req *req = NULL, *subreq = NULL;
2867 struct cli_unlock64_state *state = NULL;
2868 uint8_t additional_flags = 0;
2870 req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
2871 if (req == NULL) {
2872 return NULL;
2875 SCVAL(state->vwv+0, 0, 0xff);
2876 SSVAL(state->vwv+2, 0, fnum);
2877 SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
2878 SIVALS(state->vwv+4, 0, 0);
2879 SSVAL(state->vwv+6, 0, 1);
2880 SSVAL(state->vwv+7, 0, 0);
2882 SIVAL(state->data, 0, cli->pid);
2883 SOFF_T_R(state->data, 4, offset);
2884 SOFF_T_R(state->data, 12, len);
2886 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2887 8, state->vwv, 20, state->data);
2888 if (tevent_req_nomem(subreq, req)) {
2889 return tevent_req_post(req, ev);
2891 tevent_req_set_callback(subreq, cli_unlock64_done, req);
2892 return req;
2895 static void cli_unlock64_done(struct tevent_req *subreq)
2897 struct tevent_req *req = tevent_req_callback_data(
2898 subreq, struct tevent_req);
2899 NTSTATUS status;
2901 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2902 TALLOC_FREE(subreq);
2903 if (!NT_STATUS_IS_OK(status)) {
2904 tevent_req_nterror(req, status);
2905 return;
2907 tevent_req_done(req);
2910 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
2912 return tevent_req_simple_recv_ntstatus(req);
2915 NTSTATUS cli_unlock64(struct cli_state *cli,
2916 uint16_t fnum,
2917 uint64_t offset,
2918 uint64_t len)
2920 TALLOC_CTX *frame = talloc_stackframe();
2921 struct event_context *ev;
2922 struct tevent_req *req;
2923 NTSTATUS status = NT_STATUS_OK;
2925 if (! (cli->capabilities & CAP_LARGE_FILES)) {
2926 return cli_unlock(cli, fnum, offset, len);
2929 if (cli_has_async_calls(cli)) {
2931 * Can't use sync call while an async call is in flight
2933 status = NT_STATUS_INVALID_PARAMETER;
2934 goto fail;
2937 ev = event_context_init(frame);
2938 if (ev == NULL) {
2939 status = NT_STATUS_NO_MEMORY;
2940 goto fail;
2943 req = cli_unlock64_send(frame, ev, cli,
2944 fnum, offset, len);
2945 if (req == NULL) {
2946 status = NT_STATUS_NO_MEMORY;
2947 goto fail;
2950 if (!tevent_req_poll(req, ev)) {
2951 status = map_nt_error_from_unix(errno);
2952 goto fail;
2955 status = cli_unlock64_recv(req);
2957 fail:
2958 TALLOC_FREE(frame);
2959 if (!NT_STATUS_IS_OK(status)) {
2960 cli_set_error(cli, status);
2962 return status;
2965 /****************************************************************************
2966 Get/unlock a POSIX lock on a file - internal function.
2967 ****************************************************************************/
2969 struct posix_lock_state {
2970 uint16_t setup;
2971 uint8_t param[4];
2972 uint8_t data[POSIX_LOCK_DATA_SIZE];
2975 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
2977 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
2978 NULL, 0, NULL, NULL, 0, NULL);
2979 return tevent_req_simple_finish_ntstatus(subreq, status);
2982 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
2983 struct event_context *ev,
2984 struct cli_state *cli,
2985 uint16_t fnum,
2986 uint64_t offset,
2987 uint64_t len,
2988 bool wait_lock,
2989 enum brl_type lock_type)
2991 struct tevent_req *req = NULL, *subreq = NULL;
2992 struct posix_lock_state *state = NULL;
2994 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
2995 if (req == NULL) {
2996 return NULL;
2999 /* Setup setup word. */
3000 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3002 /* Setup param array. */
3003 SSVAL(&state->param, 0, fnum);
3004 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3006 /* Setup data array. */
3007 switch (lock_type) {
3008 case READ_LOCK:
3009 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3010 POSIX_LOCK_TYPE_READ);
3011 break;
3012 case WRITE_LOCK:
3013 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3014 POSIX_LOCK_TYPE_WRITE);
3015 break;
3016 case UNLOCK_LOCK:
3017 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3018 POSIX_LOCK_TYPE_UNLOCK);
3019 break;
3020 default:
3021 return NULL;
3024 if (wait_lock) {
3025 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3026 POSIX_LOCK_FLAG_WAIT);
3027 } else {
3028 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3029 POSIX_LOCK_FLAG_NOWAIT);
3032 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli->pid);
3033 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3034 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3036 subreq = cli_trans_send(state, /* mem ctx. */
3037 ev, /* event ctx. */
3038 cli, /* cli_state. */
3039 SMBtrans2, /* cmd. */
3040 NULL, /* pipe name. */
3041 -1, /* fid. */
3042 0, /* function. */
3043 0, /* flags. */
3044 &state->setup, /* setup. */
3045 1, /* num setup uint16_t words. */
3046 0, /* max returned setup. */
3047 state->param, /* param. */
3048 4, /* num param. */
3049 2, /* max returned param. */
3050 state->data, /* data. */
3051 POSIX_LOCK_DATA_SIZE, /* num data. */
3052 0); /* max returned data. */
3054 if (tevent_req_nomem(subreq, req)) {
3055 return tevent_req_post(req, ev);
3057 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3058 return req;
3061 /****************************************************************************
3062 POSIX Lock a file.
3063 ****************************************************************************/
3065 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3066 struct event_context *ev,
3067 struct cli_state *cli,
3068 uint16_t fnum,
3069 uint64_t offset,
3070 uint64_t len,
3071 bool wait_lock,
3072 enum brl_type lock_type)
3074 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3075 wait_lock, lock_type);
3078 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3080 NTSTATUS status;
3082 if (tevent_req_is_nterror(req, &status)) {
3083 return status;
3085 return NT_STATUS_OK;
3088 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3089 uint64_t offset, uint64_t len,
3090 bool wait_lock, enum brl_type lock_type)
3092 TALLOC_CTX *frame = talloc_stackframe();
3093 struct event_context *ev = NULL;
3094 struct tevent_req *req = NULL;
3095 NTSTATUS status = NT_STATUS_OK;
3097 if (cli_has_async_calls(cli)) {
3099 * Can't use sync call while an async call is in flight
3101 status = NT_STATUS_INVALID_PARAMETER;
3102 goto fail;
3105 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3106 status = NT_STATUS_INVALID_PARAMETER;
3107 goto fail;
3110 ev = event_context_init(frame);
3111 if (ev == NULL) {
3112 status = NT_STATUS_NO_MEMORY;
3113 goto fail;
3116 req = cli_posix_lock_send(frame,
3118 cli,
3119 fnum,
3120 offset,
3121 len,
3122 wait_lock,
3123 lock_type);
3124 if (req == NULL) {
3125 status = NT_STATUS_NO_MEMORY;
3126 goto fail;
3129 if (!tevent_req_poll(req, ev)) {
3130 status = map_nt_error_from_unix(errno);
3131 goto fail;
3134 status = cli_posix_lock_recv(req);
3136 fail:
3137 TALLOC_FREE(frame);
3138 if (!NT_STATUS_IS_OK(status)) {
3139 cli_set_error(cli, status);
3141 return status;
3144 /****************************************************************************
3145 POSIX Unlock a file.
3146 ****************************************************************************/
3148 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3149 struct event_context *ev,
3150 struct cli_state *cli,
3151 uint16_t fnum,
3152 uint64_t offset,
3153 uint64_t len)
3155 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3156 false, UNLOCK_LOCK);
3159 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3161 NTSTATUS status;
3163 if (tevent_req_is_nterror(req, &status)) {
3164 return status;
3166 return NT_STATUS_OK;
3169 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3171 TALLOC_CTX *frame = talloc_stackframe();
3172 struct event_context *ev = NULL;
3173 struct tevent_req *req = NULL;
3174 NTSTATUS status = NT_STATUS_OK;
3176 if (cli_has_async_calls(cli)) {
3178 * Can't use sync call while an async call is in flight
3180 status = NT_STATUS_INVALID_PARAMETER;
3181 goto fail;
3184 ev = event_context_init(frame);
3185 if (ev == NULL) {
3186 status = NT_STATUS_NO_MEMORY;
3187 goto fail;
3190 req = cli_posix_unlock_send(frame,
3192 cli,
3193 fnum,
3194 offset,
3195 len);
3196 if (req == NULL) {
3197 status = NT_STATUS_NO_MEMORY;
3198 goto fail;
3201 if (!tevent_req_poll(req, ev)) {
3202 status = map_nt_error_from_unix(errno);
3203 goto fail;
3206 status = cli_posix_unlock_recv(req);
3208 fail:
3209 TALLOC_FREE(frame);
3210 if (!NT_STATUS_IS_OK(status)) {
3211 cli_set_error(cli, status);
3213 return status;
3216 /****************************************************************************
3217 Do a SMBgetattrE call.
3218 ****************************************************************************/
3220 static void cli_getattrE_done(struct tevent_req *subreq);
3222 struct cli_getattrE_state {
3223 uint16_t vwv[1];
3224 int zone_offset;
3225 uint16_t attr;
3226 SMB_OFF_T size;
3227 time_t change_time;
3228 time_t access_time;
3229 time_t write_time;
3232 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3233 struct event_context *ev,
3234 struct cli_state *cli,
3235 uint16_t fnum)
3237 struct tevent_req *req = NULL, *subreq = NULL;
3238 struct cli_getattrE_state *state = NULL;
3239 uint8_t additional_flags = 0;
3241 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3242 if (req == NULL) {
3243 return NULL;
3246 state->zone_offset = cli->serverzone;
3247 SSVAL(state->vwv+0,0,fnum);
3249 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
3250 1, state->vwv, 0, NULL);
3251 if (tevent_req_nomem(subreq, req)) {
3252 return tevent_req_post(req, ev);
3254 tevent_req_set_callback(subreq, cli_getattrE_done, req);
3255 return req;
3258 static void cli_getattrE_done(struct tevent_req *subreq)
3260 struct tevent_req *req = tevent_req_callback_data(
3261 subreq, struct tevent_req);
3262 struct cli_getattrE_state *state = tevent_req_data(
3263 req, struct cli_getattrE_state);
3264 uint8_t wct;
3265 uint16_t *vwv = NULL;
3266 NTSTATUS status;
3268 status = cli_smb_recv(subreq, 11, &wct, &vwv, NULL, NULL);
3269 if (!NT_STATUS_IS_OK(status)) {
3270 tevent_req_nterror(req, status);
3271 return;
3274 state->size = (SMB_OFF_T)IVAL(vwv+6,0);
3275 state->attr = SVAL(vwv+10,0);
3276 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3277 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3278 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3280 TALLOC_FREE(subreq);
3281 tevent_req_done(req);
3284 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3285 uint16_t *attr,
3286 SMB_OFF_T *size,
3287 time_t *change_time,
3288 time_t *access_time,
3289 time_t *write_time)
3291 struct cli_getattrE_state *state = tevent_req_data(
3292 req, struct cli_getattrE_state);
3293 NTSTATUS status;
3295 if (tevent_req_is_nterror(req, &status)) {
3296 return status;
3298 if (attr) {
3299 *attr = state->attr;
3301 if (size) {
3302 *size = state->size;
3304 if (change_time) {
3305 *change_time = state->change_time;
3307 if (access_time) {
3308 *access_time = state->access_time;
3310 if (write_time) {
3311 *write_time = state->write_time;
3313 return NT_STATUS_OK;
3316 NTSTATUS cli_getattrE(struct cli_state *cli,
3317 uint16_t fnum,
3318 uint16_t *attr,
3319 SMB_OFF_T *size,
3320 time_t *change_time,
3321 time_t *access_time,
3322 time_t *write_time)
3324 TALLOC_CTX *frame = talloc_stackframe();
3325 struct event_context *ev = NULL;
3326 struct tevent_req *req = NULL;
3327 NTSTATUS status = NT_STATUS_OK;
3329 if (cli_has_async_calls(cli)) {
3331 * Can't use sync call while an async call is in flight
3333 status = NT_STATUS_INVALID_PARAMETER;
3334 goto fail;
3337 ev = event_context_init(frame);
3338 if (ev == NULL) {
3339 status = NT_STATUS_NO_MEMORY;
3340 goto fail;
3343 req = cli_getattrE_send(frame, ev, cli, fnum);
3344 if (req == NULL) {
3345 status = NT_STATUS_NO_MEMORY;
3346 goto fail;
3349 if (!tevent_req_poll(req, ev)) {
3350 status = map_nt_error_from_unix(errno);
3351 goto fail;
3354 status = cli_getattrE_recv(req,
3355 attr,
3356 size,
3357 change_time,
3358 access_time,
3359 write_time);
3361 fail:
3362 TALLOC_FREE(frame);
3363 if (!NT_STATUS_IS_OK(status)) {
3364 cli_set_error(cli, status);
3366 return status;
3369 /****************************************************************************
3370 Do a SMBgetatr call
3371 ****************************************************************************/
3373 static void cli_getatr_done(struct tevent_req *subreq);
3375 struct cli_getatr_state {
3376 int zone_offset;
3377 uint16_t attr;
3378 SMB_OFF_T size;
3379 time_t write_time;
3382 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3383 struct event_context *ev,
3384 struct cli_state *cli,
3385 const char *fname)
3387 struct tevent_req *req = NULL, *subreq = NULL;
3388 struct cli_getatr_state *state = NULL;
3389 uint8_t additional_flags = 0;
3390 uint8_t *bytes = NULL;
3392 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3393 if (req == NULL) {
3394 return NULL;
3397 state->zone_offset = cli->serverzone;
3399 bytes = talloc_array(state, uint8_t, 1);
3400 if (tevent_req_nomem(bytes, req)) {
3401 return tevent_req_post(req, ev);
3403 bytes[0] = 4;
3404 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3405 strlen(fname)+1, NULL);
3407 if (tevent_req_nomem(bytes, req)) {
3408 return tevent_req_post(req, ev);
3411 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3412 0, NULL, talloc_get_size(bytes), bytes);
3413 if (tevent_req_nomem(subreq, req)) {
3414 return tevent_req_post(req, ev);
3416 tevent_req_set_callback(subreq, cli_getatr_done, req);
3417 return req;
3420 static void cli_getatr_done(struct tevent_req *subreq)
3422 struct tevent_req *req = tevent_req_callback_data(
3423 subreq, struct tevent_req);
3424 struct cli_getatr_state *state = tevent_req_data(
3425 req, struct cli_getatr_state);
3426 uint8_t wct;
3427 uint16_t *vwv = NULL;
3428 NTSTATUS status;
3430 status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL);
3431 if (!NT_STATUS_IS_OK(status)) {
3432 tevent_req_nterror(req, status);
3433 return;
3436 state->attr = SVAL(vwv+0,0);
3437 state->size = (SMB_OFF_T)IVAL(vwv+3,0);
3438 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3440 TALLOC_FREE(subreq);
3441 tevent_req_done(req);
3444 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3445 uint16_t *attr,
3446 SMB_OFF_T *size,
3447 time_t *write_time)
3449 struct cli_getatr_state *state = tevent_req_data(
3450 req, struct cli_getatr_state);
3451 NTSTATUS status;
3453 if (tevent_req_is_nterror(req, &status)) {
3454 return status;
3456 if (attr) {
3457 *attr = state->attr;
3459 if (size) {
3460 *size = state->size;
3462 if (write_time) {
3463 *write_time = state->write_time;
3465 return NT_STATUS_OK;
3468 NTSTATUS cli_getatr(struct cli_state *cli,
3469 const char *fname,
3470 uint16_t *attr,
3471 SMB_OFF_T *size,
3472 time_t *write_time)
3474 TALLOC_CTX *frame = talloc_stackframe();
3475 struct event_context *ev = NULL;
3476 struct tevent_req *req = NULL;
3477 NTSTATUS status = NT_STATUS_OK;
3479 if (cli_has_async_calls(cli)) {
3481 * Can't use sync call while an async call is in flight
3483 status = NT_STATUS_INVALID_PARAMETER;
3484 goto fail;
3487 ev = event_context_init(frame);
3488 if (ev == NULL) {
3489 status = NT_STATUS_NO_MEMORY;
3490 goto fail;
3493 req = cli_getatr_send(frame, ev, cli, fname);
3494 if (req == NULL) {
3495 status = NT_STATUS_NO_MEMORY;
3496 goto fail;
3499 if (!tevent_req_poll(req, ev)) {
3500 status = map_nt_error_from_unix(errno);
3501 goto fail;
3504 status = cli_getatr_recv(req,
3505 attr,
3506 size,
3507 write_time);
3509 fail:
3510 TALLOC_FREE(frame);
3511 if (!NT_STATUS_IS_OK(status)) {
3512 cli_set_error(cli, status);
3514 return status;
3517 /****************************************************************************
3518 Do a SMBsetattrE call.
3519 ****************************************************************************/
3521 static void cli_setattrE_done(struct tevent_req *subreq);
3523 struct cli_setattrE_state {
3524 uint16_t vwv[7];
3527 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3528 struct event_context *ev,
3529 struct cli_state *cli,
3530 uint16_t fnum,
3531 time_t change_time,
3532 time_t access_time,
3533 time_t write_time)
3535 struct tevent_req *req = NULL, *subreq = NULL;
3536 struct cli_setattrE_state *state = NULL;
3537 uint8_t additional_flags = 0;
3539 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3540 if (req == NULL) {
3541 return NULL;
3544 SSVAL(state->vwv+0, 0, fnum);
3545 cli_put_dos_date2(cli, (char *)&state->vwv[1], 0, change_time);
3546 cli_put_dos_date2(cli, (char *)&state->vwv[3], 0, access_time);
3547 cli_put_dos_date2(cli, (char *)&state->vwv[5], 0, write_time);
3549 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3550 7, state->vwv, 0, NULL);
3551 if (tevent_req_nomem(subreq, req)) {
3552 return tevent_req_post(req, ev);
3554 tevent_req_set_callback(subreq, cli_setattrE_done, req);
3555 return req;
3558 static void cli_setattrE_done(struct tevent_req *subreq)
3560 struct tevent_req *req = tevent_req_callback_data(
3561 subreq, struct tevent_req);
3562 NTSTATUS status;
3564 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
3565 TALLOC_FREE(subreq);
3566 if (!NT_STATUS_IS_OK(status)) {
3567 tevent_req_nterror(req, status);
3568 return;
3570 tevent_req_done(req);
3573 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3575 return tevent_req_simple_recv_ntstatus(req);
3578 NTSTATUS cli_setattrE(struct cli_state *cli,
3579 uint16_t fnum,
3580 time_t change_time,
3581 time_t access_time,
3582 time_t write_time)
3584 TALLOC_CTX *frame = talloc_stackframe();
3585 struct event_context *ev = NULL;
3586 struct tevent_req *req = NULL;
3587 NTSTATUS status = NT_STATUS_OK;
3589 if (cli_has_async_calls(cli)) {
3591 * Can't use sync call while an async call is in flight
3593 status = NT_STATUS_INVALID_PARAMETER;
3594 goto fail;
3597 ev = event_context_init(frame);
3598 if (ev == NULL) {
3599 status = NT_STATUS_NO_MEMORY;
3600 goto fail;
3603 req = cli_setattrE_send(frame, ev,
3604 cli,
3605 fnum,
3606 change_time,
3607 access_time,
3608 write_time);
3610 if (req == NULL) {
3611 status = NT_STATUS_NO_MEMORY;
3612 goto fail;
3615 if (!tevent_req_poll(req, ev)) {
3616 status = map_nt_error_from_unix(errno);
3617 goto fail;
3620 status = cli_setattrE_recv(req);
3622 fail:
3623 TALLOC_FREE(frame);
3624 if (!NT_STATUS_IS_OK(status)) {
3625 cli_set_error(cli, status);
3627 return status;
3630 /****************************************************************************
3631 Do a SMBsetatr call.
3632 ****************************************************************************/
3634 static void cli_setatr_done(struct tevent_req *subreq);
3636 struct cli_setatr_state {
3637 uint16_t vwv[8];
3640 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3641 struct event_context *ev,
3642 struct cli_state *cli,
3643 const char *fname,
3644 uint16_t attr,
3645 time_t mtime)
3647 struct tevent_req *req = NULL, *subreq = NULL;
3648 struct cli_setatr_state *state = NULL;
3649 uint8_t additional_flags = 0;
3650 uint8_t *bytes = NULL;
3652 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3653 if (req == NULL) {
3654 return NULL;
3657 SSVAL(state->vwv+0, 0, attr);
3658 cli_put_dos_date3(cli, (char *)&state->vwv[1], 0, mtime);
3660 bytes = talloc_array(state, uint8_t, 1);
3661 if (tevent_req_nomem(bytes, req)) {
3662 return tevent_req_post(req, ev);
3664 bytes[0] = 4;
3665 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3666 strlen(fname)+1, NULL);
3667 if (tevent_req_nomem(bytes, req)) {
3668 return tevent_req_post(req, ev);
3670 bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
3671 talloc_get_size(bytes)+1);
3672 if (tevent_req_nomem(bytes, req)) {
3673 return tevent_req_post(req, ev);
3676 bytes[talloc_get_size(bytes)-1] = 4;
3677 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",
3678 1, NULL);
3679 if (tevent_req_nomem(bytes, req)) {
3680 return tevent_req_post(req, ev);
3683 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3684 8, state->vwv, talloc_get_size(bytes), bytes);
3685 if (tevent_req_nomem(subreq, req)) {
3686 return tevent_req_post(req, ev);
3688 tevent_req_set_callback(subreq, cli_setatr_done, req);
3689 return req;
3692 static void cli_setatr_done(struct tevent_req *subreq)
3694 struct tevent_req *req = tevent_req_callback_data(
3695 subreq, struct tevent_req);
3696 NTSTATUS status;
3698 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
3699 TALLOC_FREE(subreq);
3700 if (!NT_STATUS_IS_OK(status)) {
3701 tevent_req_nterror(req, status);
3702 return;
3704 tevent_req_done(req);
3707 NTSTATUS cli_setatr_recv(struct tevent_req *req)
3709 return tevent_req_simple_recv_ntstatus(req);
3712 NTSTATUS cli_setatr(struct cli_state *cli,
3713 const char *fname,
3714 uint16_t attr,
3715 time_t mtime)
3717 TALLOC_CTX *frame = talloc_stackframe();
3718 struct event_context *ev = NULL;
3719 struct tevent_req *req = NULL;
3720 NTSTATUS status = NT_STATUS_OK;
3722 if (cli_has_async_calls(cli)) {
3724 * Can't use sync call while an async call is in flight
3726 status = NT_STATUS_INVALID_PARAMETER;
3727 goto fail;
3730 ev = event_context_init(frame);
3731 if (ev == NULL) {
3732 status = NT_STATUS_NO_MEMORY;
3733 goto fail;
3736 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
3737 if (req == NULL) {
3738 status = NT_STATUS_NO_MEMORY;
3739 goto fail;
3742 if (!tevent_req_poll(req, ev)) {
3743 status = map_nt_error_from_unix(errno);
3744 goto fail;
3747 status = cli_setatr_recv(req);
3749 fail:
3750 TALLOC_FREE(frame);
3751 if (!NT_STATUS_IS_OK(status)) {
3752 cli_set_error(cli, status);
3754 return status;
3757 /****************************************************************************
3758 Check for existance of a dir.
3759 ****************************************************************************/
3761 static void cli_chkpath_done(struct tevent_req *subreq);
3763 struct cli_chkpath_state {
3764 int dummy;
3767 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
3768 struct event_context *ev,
3769 struct cli_state *cli,
3770 const char *fname)
3772 struct tevent_req *req = NULL, *subreq = NULL;
3773 struct cli_chkpath_state *state = NULL;
3774 uint8_t additional_flags = 0;
3775 uint8_t *bytes = NULL;
3777 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
3778 if (req == NULL) {
3779 return NULL;
3782 bytes = talloc_array(state, uint8_t, 1);
3783 if (tevent_req_nomem(bytes, req)) {
3784 return tevent_req_post(req, ev);
3786 bytes[0] = 4;
3787 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3788 strlen(fname)+1, NULL);
3790 if (tevent_req_nomem(bytes, req)) {
3791 return tevent_req_post(req, ev);
3794 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
3795 0, NULL, talloc_get_size(bytes), bytes);
3796 if (tevent_req_nomem(subreq, req)) {
3797 return tevent_req_post(req, ev);
3799 tevent_req_set_callback(subreq, cli_chkpath_done, req);
3800 return req;
3803 static void cli_chkpath_done(struct tevent_req *subreq)
3805 struct tevent_req *req = tevent_req_callback_data(
3806 subreq, struct tevent_req);
3807 NTSTATUS status;
3809 status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
3810 TALLOC_FREE(subreq);
3811 if (!NT_STATUS_IS_OK(status)) {
3812 tevent_req_nterror(req, status);
3813 return;
3815 tevent_req_done(req);
3818 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
3820 return tevent_req_simple_recv_ntstatus(req);
3823 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
3825 TALLOC_CTX *frame = talloc_stackframe();
3826 struct event_context *ev = NULL;
3827 struct tevent_req *req = NULL;
3828 char *path2 = 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 path2 = talloc_strdup(frame, path);
3840 if (!path2) {
3841 status = NT_STATUS_NO_MEMORY;
3842 goto fail;
3844 trim_char(path2,'\0','\\');
3845 if (!*path2) {
3846 path2 = talloc_strdup(frame, "\\");
3847 if (!path2) {
3848 status = NT_STATUS_NO_MEMORY;
3849 goto fail;
3853 ev = event_context_init(frame);
3854 if (ev == NULL) {
3855 status = NT_STATUS_NO_MEMORY;
3856 goto fail;
3859 req = cli_chkpath_send(frame, ev, cli, path2);
3860 if (req == NULL) {
3861 status = NT_STATUS_NO_MEMORY;
3862 goto fail;
3865 if (!tevent_req_poll(req, ev)) {
3866 status = map_nt_error_from_unix(errno);
3867 goto fail;
3870 status = cli_chkpath_recv(req);
3872 fail:
3873 TALLOC_FREE(frame);
3874 if (!NT_STATUS_IS_OK(status)) {
3875 cli_set_error(cli, status);
3877 return status;
3880 /****************************************************************************
3881 Query disk space.
3882 ****************************************************************************/
3884 static void cli_dskattr_done(struct tevent_req *subreq);
3886 struct cli_dskattr_state {
3887 int bsize;
3888 int total;
3889 int avail;
3892 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
3893 struct event_context *ev,
3894 struct cli_state *cli)
3896 struct tevent_req *req = NULL, *subreq = NULL;
3897 struct cli_dskattr_state *state = NULL;
3898 uint8_t additional_flags = 0;
3900 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
3901 if (req == NULL) {
3902 return NULL;
3905 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
3906 0, NULL, 0, NULL);
3907 if (tevent_req_nomem(subreq, req)) {
3908 return tevent_req_post(req, ev);
3910 tevent_req_set_callback(subreq, cli_dskattr_done, req);
3911 return req;
3914 static void cli_dskattr_done(struct tevent_req *subreq)
3916 struct tevent_req *req = tevent_req_callback_data(
3917 subreq, struct tevent_req);
3918 struct cli_dskattr_state *state = tevent_req_data(
3919 req, struct cli_dskattr_state);
3920 uint8_t wct;
3921 uint16_t *vwv = NULL;
3922 NTSTATUS status;
3924 status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL);
3925 if (!NT_STATUS_IS_OK(status)) {
3926 tevent_req_nterror(req, status);
3927 return;
3929 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
3930 state->total = SVAL(vwv+0, 0);
3931 state->avail = SVAL(vwv+3, 0);
3932 TALLOC_FREE(subreq);
3933 tevent_req_done(req);
3936 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
3938 struct cli_dskattr_state *state = tevent_req_data(
3939 req, struct cli_dskattr_state);
3940 NTSTATUS status;
3942 if (tevent_req_is_nterror(req, &status)) {
3943 return status;
3945 *bsize = state->bsize;
3946 *total = state->total;
3947 *avail = state->avail;
3948 return NT_STATUS_OK;
3951 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3953 TALLOC_CTX *frame = talloc_stackframe();
3954 struct event_context *ev = NULL;
3955 struct tevent_req *req = NULL;
3956 NTSTATUS status = NT_STATUS_OK;
3958 if (cli_has_async_calls(cli)) {
3960 * Can't use sync call while an async call is in flight
3962 status = NT_STATUS_INVALID_PARAMETER;
3963 goto fail;
3966 ev = event_context_init(frame);
3967 if (ev == NULL) {
3968 status = NT_STATUS_NO_MEMORY;
3969 goto fail;
3972 req = cli_dskattr_send(frame, ev, cli);
3973 if (req == NULL) {
3974 status = NT_STATUS_NO_MEMORY;
3975 goto fail;
3978 if (!tevent_req_poll(req, ev)) {
3979 status = map_nt_error_from_unix(errno);
3980 goto fail;
3983 status = cli_dskattr_recv(req, bsize, total, avail);
3985 fail:
3986 TALLOC_FREE(frame);
3987 if (!NT_STATUS_IS_OK(status)) {
3988 cli_set_error(cli, status);
3990 return status;
3993 /****************************************************************************
3994 Create and open a temporary file.
3995 ****************************************************************************/
3997 static void cli_ctemp_done(struct tevent_req *subreq);
3999 struct ctemp_state {
4000 uint16_t vwv[3];
4001 char *ret_path;
4002 uint16_t fnum;
4005 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4006 struct event_context *ev,
4007 struct cli_state *cli,
4008 const char *path)
4010 struct tevent_req *req = NULL, *subreq = NULL;
4011 struct ctemp_state *state = NULL;
4012 uint8_t additional_flags = 0;
4013 uint8_t *bytes = NULL;
4015 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4016 if (req == NULL) {
4017 return NULL;
4020 SSVAL(state->vwv,0,0);
4021 SIVALS(state->vwv+1,0,-1);
4023 bytes = talloc_array(state, uint8_t, 1);
4024 if (tevent_req_nomem(bytes, req)) {
4025 return tevent_req_post(req, ev);
4027 bytes[0] = 4;
4028 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), path,
4029 strlen(path)+1, NULL);
4030 if (tevent_req_nomem(bytes, req)) {
4031 return tevent_req_post(req, ev);
4034 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4035 3, state->vwv, talloc_get_size(bytes), bytes);
4036 if (tevent_req_nomem(subreq, req)) {
4037 return tevent_req_post(req, ev);
4039 tevent_req_set_callback(subreq, cli_ctemp_done, req);
4040 return req;
4043 static void cli_ctemp_done(struct tevent_req *subreq)
4045 struct tevent_req *req = tevent_req_callback_data(
4046 subreq, struct tevent_req);
4047 struct ctemp_state *state = tevent_req_data(
4048 req, struct ctemp_state);
4049 NTSTATUS status;
4050 uint8_t wcnt;
4051 uint16_t *vwv;
4052 uint32_t num_bytes = 0;
4053 uint8_t *bytes = NULL;
4055 status = cli_smb_recv(subreq, 1, &wcnt, &vwv, &num_bytes, &bytes);
4056 if (!NT_STATUS_IS_OK(status)) {
4057 TALLOC_FREE(subreq);
4058 tevent_req_nterror(req, status);
4059 return;
4062 state->fnum = SVAL(vwv+0, 0);
4064 TALLOC_FREE(subreq);
4066 /* From W2K3, the result is just the ASCII name */
4067 if (num_bytes < 2) {
4068 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
4069 return;
4072 if (pull_string_talloc(state,
4073 NULL,
4075 &state->ret_path,
4076 bytes,
4077 num_bytes,
4078 STR_ASCII) == 0) {
4079 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4080 return;
4082 tevent_req_done(req);
4085 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
4086 TALLOC_CTX *ctx,
4087 uint16_t *pfnum,
4088 char **outfile)
4090 struct ctemp_state *state = tevent_req_data(req,
4091 struct ctemp_state);
4092 NTSTATUS status;
4094 if (tevent_req_is_nterror(req, &status)) {
4095 return status;
4097 *pfnum = state->fnum;
4098 *outfile = talloc_strdup(ctx, state->ret_path);
4099 if (!*outfile) {
4100 return NT_STATUS_NO_MEMORY;
4102 return NT_STATUS_OK;
4105 NTSTATUS cli_ctemp(struct cli_state *cli,
4106 TALLOC_CTX *ctx,
4107 const char *path,
4108 uint16_t *pfnum,
4109 char **out_path)
4111 TALLOC_CTX *frame = talloc_stackframe();
4112 struct event_context *ev;
4113 struct tevent_req *req;
4114 NTSTATUS status = NT_STATUS_OK;
4116 if (cli_has_async_calls(cli)) {
4118 * Can't use sync call while an async call is in flight
4120 status = NT_STATUS_INVALID_PARAMETER;
4121 goto fail;
4124 ev = event_context_init(frame);
4125 if (ev == NULL) {
4126 status = NT_STATUS_NO_MEMORY;
4127 goto fail;
4130 req = cli_ctemp_send(frame, ev, cli, path);
4131 if (req == NULL) {
4132 status = NT_STATUS_NO_MEMORY;
4133 goto fail;
4136 if (!tevent_req_poll(req, ev)) {
4137 status = map_nt_error_from_unix(errno);
4138 goto fail;
4141 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4143 fail:
4144 TALLOC_FREE(frame);
4145 if (!NT_STATUS_IS_OK(status)) {
4146 cli_set_error(cli, status);
4148 return status;
4152 send a raw ioctl - used by the torture code
4154 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4156 memset(cli->outbuf,'\0',smb_size);
4157 memset(cli->inbuf,'\0',smb_size);
4159 cli_set_message(cli->outbuf, 3, 0, True);
4160 SCVAL(cli->outbuf,smb_com,SMBioctl);
4161 cli_setup_packet(cli);
4163 SSVAL(cli->outbuf, smb_vwv0, fnum);
4164 SSVAL(cli->outbuf, smb_vwv1, code>>16);
4165 SSVAL(cli->outbuf, smb_vwv2, (code&0xFFFF));
4167 cli_send_smb(cli);
4168 if (!cli_receive_smb(cli)) {
4169 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
4172 if (cli_is_error(cli)) {
4173 return cli_nt_error(cli);
4176 *blob = data_blob_null;
4178 return NT_STATUS_OK;
4181 /*********************************************************
4182 Set an extended attribute utility fn.
4183 *********************************************************/
4185 static bool cli_set_ea(struct cli_state *cli, uint16_t setup, char *param, unsigned int param_len,
4186 const char *ea_name, const char *ea_val, size_t ea_len)
4188 unsigned int data_len = 0;
4189 char *data = NULL;
4190 char *rparam=NULL, *rdata=NULL;
4191 char *p;
4192 size_t ea_namelen = strlen(ea_name);
4194 if (ea_namelen == 0 && ea_len == 0) {
4195 data_len = 4;
4196 data = (char *)SMB_MALLOC(data_len);
4197 if (!data) {
4198 return False;
4200 p = data;
4201 SIVAL(p,0,data_len);
4202 } else {
4203 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4204 data = (char *)SMB_MALLOC(data_len);
4205 if (!data) {
4206 return False;
4208 p = data;
4209 SIVAL(p,0,data_len);
4210 p += 4;
4211 SCVAL(p, 0, 0); /* EA flags. */
4212 SCVAL(p, 1, ea_namelen);
4213 SSVAL(p, 2, ea_len);
4214 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4215 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4218 if (!cli_send_trans(cli, SMBtrans2,
4219 NULL, /* name */
4220 -1, 0, /* fid, flags */
4221 &setup, 1, 0, /* setup, length, max */
4222 param, param_len, 2, /* param, length, max */
4223 data, data_len, cli->max_xmit /* data, length, max */
4224 )) {
4225 SAFE_FREE(data);
4226 return False;
4229 if (!cli_receive_trans(cli, SMBtrans2,
4230 &rparam, &param_len,
4231 &rdata, &data_len)) {
4232 SAFE_FREE(data);
4233 return false;
4236 SAFE_FREE(data);
4237 SAFE_FREE(rdata);
4238 SAFE_FREE(rparam);
4240 return True;
4243 /*********************************************************
4244 Set an extended attribute on a pathname.
4245 *********************************************************/
4247 bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len)
4249 uint16_t setup = TRANSACT2_SETPATHINFO;
4250 unsigned int param_len = 0;
4251 char *param;
4252 size_t srclen = 2*(strlen(path)+1);
4253 char *p;
4254 bool ret;
4256 param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
4257 if (!param) {
4258 return false;
4260 memset(param, '\0', 6);
4261 SSVAL(param,0,SMB_INFO_SET_EA);
4262 p = &param[6];
4264 p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
4265 param_len = PTR_DIFF(p, param);
4267 ret = cli_set_ea(cli, setup, param, param_len, ea_name, ea_val, ea_len);
4268 SAFE_FREE(param);
4269 return ret;
4272 /*********************************************************
4273 Set an extended attribute on an fnum.
4274 *********************************************************/
4276 bool cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum, const char *ea_name, const char *ea_val, size_t ea_len)
4278 char param[6];
4279 uint16_t setup = TRANSACT2_SETFILEINFO;
4281 memset(param, 0, 6);
4282 SSVAL(param,0,fnum);
4283 SSVAL(param,2,SMB_INFO_SET_EA);
4285 return cli_set_ea(cli, setup, param, 6, ea_name, ea_val, ea_len);
4288 /*********************************************************
4289 Get an extended attribute list utility fn.
4290 *********************************************************/
4292 static bool cli_get_ea_list(struct cli_state *cli,
4293 uint16_t setup, char *param, unsigned int param_len,
4294 TALLOC_CTX *ctx,
4295 size_t *pnum_eas,
4296 struct ea_struct **pea_list)
4298 unsigned int data_len = 0;
4299 unsigned int rparam_len, rdata_len;
4300 char *rparam=NULL, *rdata=NULL;
4301 char *p;
4302 size_t ea_size;
4303 size_t num_eas;
4304 bool ret = False;
4305 struct ea_struct *ea_list;
4307 *pnum_eas = 0;
4308 if (pea_list) {
4309 *pea_list = NULL;
4312 if (!cli_send_trans(cli, SMBtrans2,
4313 NULL, /* Name */
4314 -1, 0, /* fid, flags */
4315 &setup, 1, 0, /* setup, length, max */
4316 param, param_len, 10, /* param, length, max */
4317 NULL, data_len, cli->max_xmit /* data, length, max */
4318 )) {
4319 return False;
4322 if (!cli_receive_trans(cli, SMBtrans2,
4323 &rparam, &rparam_len,
4324 &rdata, &rdata_len)) {
4325 return False;
4328 if (!rdata || rdata_len < 4) {
4329 goto out;
4332 ea_size = (size_t)IVAL(rdata,0);
4333 if (ea_size > rdata_len) {
4334 goto out;
4337 if (ea_size == 0) {
4338 /* No EA's present. */
4339 ret = True;
4340 goto out;
4343 p = rdata + 4;
4344 ea_size -= 4;
4346 /* Validate the EA list and count it. */
4347 for (num_eas = 0; ea_size >= 4; num_eas++) {
4348 unsigned int ea_namelen = CVAL(p,1);
4349 unsigned int ea_valuelen = SVAL(p,2);
4350 if (ea_namelen == 0) {
4351 goto out;
4353 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4354 goto out;
4356 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4357 p += 4 + ea_namelen + 1 + ea_valuelen;
4360 if (num_eas == 0) {
4361 ret = True;
4362 goto out;
4365 *pnum_eas = num_eas;
4366 if (!pea_list) {
4367 /* Caller only wants number of EA's. */
4368 ret = True;
4369 goto out;
4372 ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
4373 if (!ea_list) {
4374 goto out;
4377 ea_size = (size_t)IVAL(rdata,0);
4378 p = rdata + 4;
4380 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4381 struct ea_struct *ea = &ea_list[num_eas];
4382 fstring unix_ea_name;
4383 unsigned int ea_namelen = CVAL(p,1);
4384 unsigned int ea_valuelen = SVAL(p,2);
4386 ea->flags = CVAL(p,0);
4387 unix_ea_name[0] = '\0';
4388 pull_ascii_fstring(unix_ea_name, p + 4);
4389 ea->name = talloc_strdup(ctx, unix_ea_name);
4390 /* Ensure the value is null terminated (in case it's a string). */
4391 ea->value = data_blob_talloc(ctx, NULL, ea_valuelen + 1);
4392 if (!ea->value.data) {
4393 goto out;
4395 if (ea_valuelen) {
4396 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4398 ea->value.data[ea_valuelen] = 0;
4399 ea->value.length--;
4400 p += 4 + ea_namelen + 1 + ea_valuelen;
4403 *pea_list = ea_list;
4404 ret = True;
4406 out :
4408 SAFE_FREE(rdata);
4409 SAFE_FREE(rparam);
4410 return ret;
4413 /*********************************************************
4414 Get an extended attribute list from a pathname.
4415 *********************************************************/
4417 bool cli_get_ea_list_path(struct cli_state *cli, const char *path,
4418 TALLOC_CTX *ctx,
4419 size_t *pnum_eas,
4420 struct ea_struct **pea_list)
4422 uint16_t setup = TRANSACT2_QPATHINFO;
4423 unsigned int param_len = 0;
4424 char *param;
4425 char *p;
4426 size_t srclen = 2*(strlen(path)+1);
4427 bool ret;
4429 param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
4430 if (!param) {
4431 return false;
4433 p = param;
4434 memset(p, 0, 6);
4435 SSVAL(p, 0, SMB_INFO_QUERY_ALL_EAS);
4436 p += 6;
4437 p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
4438 param_len = PTR_DIFF(p, param);
4440 ret = cli_get_ea_list(cli, setup, param, param_len, ctx, pnum_eas, pea_list);
4441 SAFE_FREE(param);
4442 return ret;
4445 /*********************************************************
4446 Get an extended attribute list from an fnum.
4447 *********************************************************/
4449 bool cli_get_ea_list_fnum(struct cli_state *cli, uint16_t fnum,
4450 TALLOC_CTX *ctx,
4451 size_t *pnum_eas,
4452 struct ea_struct **pea_list)
4454 uint16_t setup = TRANSACT2_QFILEINFO;
4455 char param[6];
4457 memset(param, 0, 6);
4458 SSVAL(param,0,fnum);
4459 SSVAL(param,2,SMB_INFO_SET_EA);
4461 return cli_get_ea_list(cli, setup, param, 6, ctx, pnum_eas, pea_list);
4464 /****************************************************************************
4465 Convert open "flags" arg to uint32_t on wire.
4466 ****************************************************************************/
4468 static uint32_t open_flags_to_wire(int flags)
4470 int open_mode = flags & O_ACCMODE;
4471 uint32_t ret = 0;
4473 switch (open_mode) {
4474 case O_WRONLY:
4475 ret |= SMB_O_WRONLY;
4476 break;
4477 case O_RDWR:
4478 ret |= SMB_O_RDWR;
4479 break;
4480 default:
4481 case O_RDONLY:
4482 ret |= SMB_O_RDONLY;
4483 break;
4486 if (flags & O_CREAT) {
4487 ret |= SMB_O_CREAT;
4489 if (flags & O_EXCL) {
4490 ret |= SMB_O_EXCL;
4492 if (flags & O_TRUNC) {
4493 ret |= SMB_O_TRUNC;
4495 #if defined(O_SYNC)
4496 if (flags & O_SYNC) {
4497 ret |= SMB_O_SYNC;
4499 #endif /* O_SYNC */
4500 if (flags & O_APPEND) {
4501 ret |= SMB_O_APPEND;
4503 #if defined(O_DIRECT)
4504 if (flags & O_DIRECT) {
4505 ret |= SMB_O_DIRECT;
4507 #endif
4508 #if defined(O_DIRECTORY)
4509 if (flags & O_DIRECTORY) {
4510 ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4511 ret |= SMB_O_DIRECTORY;
4513 #endif
4514 return ret;
4517 /****************************************************************************
4518 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4519 ****************************************************************************/
4521 struct posix_open_state {
4522 uint16_t setup;
4523 uint8_t *param;
4524 uint8_t data[18];
4525 uint16_t fnum; /* Out */
4528 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4530 struct tevent_req *req = tevent_req_callback_data(
4531 subreq, struct tevent_req);
4532 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4533 NTSTATUS status;
4534 uint8_t *data;
4535 uint32_t num_data;
4537 status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
4538 &data, 12, &num_data);
4539 TALLOC_FREE(subreq);
4540 if (!NT_STATUS_IS_OK(status)) {
4541 tevent_req_nterror(req, status);
4542 return;
4544 state->fnum = SVAL(data,2);
4545 tevent_req_done(req);
4548 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4549 struct event_context *ev,
4550 struct cli_state *cli,
4551 const char *fname,
4552 int flags,
4553 mode_t mode,
4554 bool is_dir)
4556 struct tevent_req *req = NULL, *subreq = NULL;
4557 struct posix_open_state *state = NULL;
4558 uint32_t wire_flags = open_flags_to_wire(flags);
4560 req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4561 if (req == NULL) {
4562 return NULL;
4565 /* Setup setup word. */
4566 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4568 /* Setup param array. */
4569 state->param = talloc_array(state, uint8_t, 6);
4570 if (tevent_req_nomem(state->param, req)) {
4571 return tevent_req_post(req, ev);
4573 memset(state->param, '\0', 6);
4574 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4576 state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
4577 strlen(fname)+1, NULL);
4579 if (tevent_req_nomem(state->param, req)) {
4580 return tevent_req_post(req, ev);
4583 /* Setup data words. */
4584 if (is_dir) {
4585 wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4586 wire_flags |= SMB_O_DIRECTORY;
4589 SIVAL(state->data,0,0); /* No oplock. */
4590 SIVAL(state->data,4,wire_flags);
4591 SIVAL(state->data,8,unix_perms_to_wire(mode));
4592 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
4593 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
4595 subreq = cli_trans_send(state, /* mem ctx. */
4596 ev, /* event ctx. */
4597 cli, /* cli_state. */
4598 SMBtrans2, /* cmd. */
4599 NULL, /* pipe name. */
4600 -1, /* fid. */
4601 0, /* function. */
4602 0, /* flags. */
4603 &state->setup, /* setup. */
4604 1, /* num setup uint16_t words. */
4605 0, /* max returned setup. */
4606 state->param, /* param. */
4607 talloc_get_size(state->param),/* num param. */
4608 2, /* max returned param. */
4609 state->data, /* data. */
4610 18, /* num data. */
4611 12); /* max returned data. */
4613 if (tevent_req_nomem(subreq, req)) {
4614 return tevent_req_post(req, ev);
4616 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
4617 return req;
4620 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
4621 struct event_context *ev,
4622 struct cli_state *cli,
4623 const char *fname,
4624 int flags,
4625 mode_t mode)
4627 return cli_posix_open_internal_send(mem_ctx, ev,
4628 cli, fname, flags, mode, false);
4631 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
4633 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4634 NTSTATUS status;
4636 if (tevent_req_is_nterror(req, &status)) {
4637 return status;
4639 *pfnum = state->fnum;
4640 return NT_STATUS_OK;
4643 /****************************************************************************
4644 Open - POSIX semantics. Doesn't request oplock.
4645 ****************************************************************************/
4647 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
4648 int flags, mode_t mode, uint16_t *pfnum)
4651 TALLOC_CTX *frame = talloc_stackframe();
4652 struct event_context *ev = NULL;
4653 struct tevent_req *req = NULL;
4654 NTSTATUS status = NT_STATUS_OK;
4656 if (cli_has_async_calls(cli)) {
4658 * Can't use sync call while an async call is in flight
4660 status = NT_STATUS_INVALID_PARAMETER;
4661 goto fail;
4664 ev = event_context_init(frame);
4665 if (ev == NULL) {
4666 status = NT_STATUS_NO_MEMORY;
4667 goto fail;
4670 req = cli_posix_open_send(frame,
4672 cli,
4673 fname,
4674 flags,
4675 mode);
4676 if (req == NULL) {
4677 status = NT_STATUS_NO_MEMORY;
4678 goto fail;
4681 if (!tevent_req_poll(req, ev)) {
4682 status = map_nt_error_from_unix(errno);
4683 goto fail;
4686 status = cli_posix_open_recv(req, pfnum);
4688 fail:
4689 TALLOC_FREE(frame);
4690 if (!NT_STATUS_IS_OK(status)) {
4691 cli_set_error(cli, status);
4693 return status;
4696 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
4697 struct event_context *ev,
4698 struct cli_state *cli,
4699 const char *fname,
4700 mode_t mode)
4702 return cli_posix_open_internal_send(mem_ctx, ev,
4703 cli, fname, O_CREAT, mode, true);
4706 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
4708 NTSTATUS status;
4710 if (tevent_req_is_nterror(req, &status)) {
4711 return status;
4713 return NT_STATUS_OK;
4716 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
4718 TALLOC_CTX *frame = talloc_stackframe();
4719 struct event_context *ev = NULL;
4720 struct tevent_req *req = NULL;
4721 NTSTATUS status = NT_STATUS_OK;
4723 if (cli_has_async_calls(cli)) {
4725 * Can't use sync call while an async call is in flight
4727 status = NT_STATUS_INVALID_PARAMETER;
4728 goto fail;
4731 ev = event_context_init(frame);
4732 if (ev == NULL) {
4733 status = NT_STATUS_NO_MEMORY;
4734 goto fail;
4737 req = cli_posix_mkdir_send(frame,
4739 cli,
4740 fname,
4741 mode);
4742 if (req == NULL) {
4743 status = NT_STATUS_NO_MEMORY;
4744 goto fail;
4747 if (!tevent_req_poll(req, ev)) {
4748 status = map_nt_error_from_unix(errno);
4749 goto fail;
4752 status = cli_posix_mkdir_recv(req);
4754 fail:
4755 TALLOC_FREE(frame);
4756 if (!NT_STATUS_IS_OK(status)) {
4757 cli_set_error(cli, status);
4759 return status;
4762 /****************************************************************************
4763 unlink or rmdir - POSIX semantics.
4764 ****************************************************************************/
4766 struct unlink_state {
4767 uint16_t setup;
4768 uint8_t data[2];
4771 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
4773 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
4774 NULL, 0, NULL, NULL, 0, NULL);
4775 return tevent_req_simple_finish_ntstatus(subreq, status);
4778 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
4779 struct event_context *ev,
4780 struct cli_state *cli,
4781 const char *fname,
4782 bool is_dir)
4784 struct tevent_req *req = NULL, *subreq = NULL;
4785 struct unlink_state *state = NULL;
4786 uint8_t *param = NULL;
4788 req = tevent_req_create(mem_ctx, &state, struct unlink_state);
4789 if (req == NULL) {
4790 return NULL;
4793 /* Setup setup word. */
4794 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4796 /* Setup param array. */
4797 param = talloc_array(state, uint8_t, 6);
4798 if (tevent_req_nomem(param, req)) {
4799 return tevent_req_post(req, ev);
4801 memset(param, '\0', 6);
4802 SSVAL(param, 0, SMB_POSIX_PATH_UNLINK);
4804 param = trans2_bytes_push_str(param, cli_ucs2(cli), fname,
4805 strlen(fname)+1, NULL);
4807 if (tevent_req_nomem(param, req)) {
4808 return tevent_req_post(req, ev);
4811 /* Setup data word. */
4812 SSVAL(state->data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET :
4813 SMB_POSIX_UNLINK_FILE_TARGET);
4815 subreq = cli_trans_send(state, /* mem ctx. */
4816 ev, /* event ctx. */
4817 cli, /* cli_state. */
4818 SMBtrans2, /* cmd. */
4819 NULL, /* pipe name. */
4820 -1, /* fid. */
4821 0, /* function. */
4822 0, /* flags. */
4823 &state->setup, /* setup. */
4824 1, /* num setup uint16_t words. */
4825 0, /* max returned setup. */
4826 param, /* param. */
4827 talloc_get_size(param), /* num param. */
4828 2, /* max returned param. */
4829 state->data, /* data. */
4830 2, /* num data. */
4831 0); /* max returned data. */
4833 if (tevent_req_nomem(subreq, req)) {
4834 return tevent_req_post(req, ev);
4836 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
4837 return req;
4840 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
4841 struct event_context *ev,
4842 struct cli_state *cli,
4843 const char *fname)
4845 return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, false);
4848 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
4850 NTSTATUS status;
4852 if (tevent_req_is_nterror(req, &status)) {
4853 return status;
4855 return NT_STATUS_OK;
4858 /****************************************************************************
4859 unlink - POSIX semantics.
4860 ****************************************************************************/
4862 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
4864 TALLOC_CTX *frame = talloc_stackframe();
4865 struct event_context *ev = NULL;
4866 struct tevent_req *req = NULL;
4867 NTSTATUS status = NT_STATUS_OK;
4869 if (cli_has_async_calls(cli)) {
4871 * Can't use sync call while an async call is in flight
4873 status = NT_STATUS_INVALID_PARAMETER;
4874 goto fail;
4877 ev = event_context_init(frame);
4878 if (ev == NULL) {
4879 status = NT_STATUS_NO_MEMORY;
4880 goto fail;
4883 req = cli_posix_unlink_send(frame,
4885 cli,
4886 fname);
4887 if (req == NULL) {
4888 status = NT_STATUS_NO_MEMORY;
4889 goto fail;
4892 if (!tevent_req_poll(req, ev)) {
4893 status = map_nt_error_from_unix(errno);
4894 goto fail;
4897 status = cli_posix_unlink_recv(req);
4899 fail:
4900 TALLOC_FREE(frame);
4901 if (!NT_STATUS_IS_OK(status)) {
4902 cli_set_error(cli, status);
4904 return status;
4907 /****************************************************************************
4908 rmdir - POSIX semantics.
4909 ****************************************************************************/
4911 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
4912 struct event_context *ev,
4913 struct cli_state *cli,
4914 const char *fname)
4916 return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, true);
4919 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
4921 NTSTATUS status;
4923 if (tevent_req_is_nterror(req, &status)) {
4924 return status;
4926 return NT_STATUS_OK;
4929 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
4931 TALLOC_CTX *frame = talloc_stackframe();
4932 struct event_context *ev = NULL;
4933 struct tevent_req *req = NULL;
4934 NTSTATUS status = NT_STATUS_OK;
4936 if (cli_has_async_calls(cli)) {
4938 * Can't use sync call while an async call is in flight
4940 status = NT_STATUS_INVALID_PARAMETER;
4941 goto fail;
4944 ev = event_context_init(frame);
4945 if (ev == NULL) {
4946 status = NT_STATUS_NO_MEMORY;
4947 goto fail;
4950 req = cli_posix_rmdir_send(frame,
4952 cli,
4953 fname);
4954 if (req == NULL) {
4955 status = NT_STATUS_NO_MEMORY;
4956 goto fail;
4959 if (!tevent_req_poll(req, ev)) {
4960 status = map_nt_error_from_unix(errno);
4961 goto fail;
4964 status = cli_posix_rmdir_recv(req, frame);
4966 fail:
4967 TALLOC_FREE(frame);
4968 if (!NT_STATUS_IS_OK(status)) {
4969 cli_set_error(cli, status);
4971 return status;
4974 /****************************************************************************
4975 filechangenotify
4976 ****************************************************************************/
4978 struct cli_notify_state {
4979 uint8_t setup[8];
4980 uint32_t num_changes;
4981 struct notify_change *changes;
4984 static void cli_notify_done(struct tevent_req *subreq);
4986 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
4987 struct tevent_context *ev,
4988 struct cli_state *cli, uint16_t fnum,
4989 uint32_t buffer_size,
4990 uint32_t completion_filter, bool recursive)
4992 struct tevent_req *req, *subreq;
4993 struct cli_notify_state *state;
4995 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
4996 if (req == NULL) {
4997 return NULL;
5000 SIVAL(state->setup, 0, completion_filter);
5001 SSVAL(state->setup, 4, fnum);
5002 SSVAL(state->setup, 6, recursive);
5004 subreq = cli_trans_send(
5005 state, /* mem ctx. */
5006 ev, /* event ctx. */
5007 cli, /* cli_state. */
5008 SMBnttrans, /* cmd. */
5009 NULL, /* pipe name. */
5010 -1, /* fid. */
5011 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
5012 0, /* flags. */
5013 (uint16_t *)state->setup, /* setup. */
5014 4, /* num setup uint16_t words. */
5015 0, /* max returned setup. */
5016 NULL, /* param. */
5017 0, /* num param. */
5018 buffer_size, /* max returned param. */
5019 NULL, /* data. */
5020 0, /* num data. */
5021 0); /* max returned data. */
5023 if (tevent_req_nomem(subreq, req)) {
5024 return tevent_req_post(req, ev);
5026 tevent_req_set_callback(subreq, cli_notify_done, req);
5027 return req;
5030 static void cli_notify_done(struct tevent_req *subreq)
5032 struct tevent_req *req = tevent_req_callback_data(
5033 subreq, struct tevent_req);
5034 struct cli_notify_state *state = tevent_req_data(
5035 req, struct cli_notify_state);
5036 NTSTATUS status;
5037 uint8_t *params;
5038 uint32_t i, ofs, num_params;
5040 status = cli_trans_recv(subreq, talloc_tos(), NULL, 0, NULL,
5041 &params, 0, &num_params, NULL, 0, NULL);
5042 TALLOC_FREE(subreq);
5043 if (!NT_STATUS_IS_OK(status)) {
5044 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
5045 tevent_req_nterror(req, status);
5046 return;
5049 state->num_changes = 0;
5050 ofs = 0;
5052 while (num_params - ofs > 12) {
5053 uint32_t len = IVAL(params, ofs);
5054 state->num_changes += 1;
5056 if ((len == 0) || (ofs+len >= num_params)) {
5057 break;
5059 ofs += len;
5062 state->changes = talloc_array(state, struct notify_change,
5063 state->num_changes);
5064 if (tevent_req_nomem(state->changes, req)) {
5065 TALLOC_FREE(params);
5066 return;
5069 ofs = 0;
5071 for (i=0; i<state->num_changes; i++) {
5072 uint32_t next = IVAL(params, ofs);
5073 uint32_t len = IVAL(params, ofs+8);
5074 ssize_t ret;
5075 char *name;
5077 if ((next != 0) && (len+12 != next)) {
5078 TALLOC_FREE(params);
5079 tevent_req_nterror(
5080 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5081 return;
5084 state->changes[i].action = IVAL(params, ofs+4);
5085 ret = clistr_pull_talloc(params, (char *)params, &name,
5086 params+ofs+12, len,
5087 STR_TERMINATE|STR_UNICODE);
5088 if (ret == -1) {
5089 TALLOC_FREE(params);
5090 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5091 return;
5093 state->changes[i].name = name;
5094 ofs += next;
5097 TALLOC_FREE(params);
5098 tevent_req_done(req);
5101 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5102 uint32_t *pnum_changes,
5103 struct notify_change **pchanges)
5105 struct cli_notify_state *state = tevent_req_data(
5106 req, struct cli_notify_state);
5107 NTSTATUS status;
5109 if (tevent_req_is_nterror(req, &status)) {
5110 return status;
5113 *pnum_changes = state->num_changes;
5114 *pchanges = talloc_move(mem_ctx, &state->changes);
5115 return NT_STATUS_OK;