WHATSNEW: Update changes.
[Samba.git] / source3 / libsmb / clifile.c
blob6b8230b67410aa2c0bcee126d33b92cb73ed0e67
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 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 uint8_t *data;
271 uint32_t num_data;
274 static void cli_posix_readlink_done(struct tevent_req *subreq);
276 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
277 struct event_context *ev,
278 struct cli_state *cli,
279 const char *fname,
280 size_t len)
282 struct tevent_req *req = NULL, *subreq = NULL;
283 struct readlink_state *state = NULL;
284 uint32_t maxbytelen = (uint32_t)(cli_ucs2(cli) ? len*3 : len);
286 req = tevent_req_create(mem_ctx, &state, struct readlink_state);
287 if (req == NULL) {
288 return NULL;
292 * Len is in bytes, we need it in UCS2 units.
294 if ((2*len < len) || (maxbytelen < len)) {
295 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
296 return tevent_req_post(req, ev);
299 subreq = cli_qpathinfo_send(state, ev, cli, fname,
300 SMB_QUERY_FILE_UNIX_LINK, 1, maxbytelen);
301 if (tevent_req_nomem(subreq, req)) {
302 return tevent_req_post(req, ev);
304 tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
305 return req;
308 static void cli_posix_readlink_done(struct tevent_req *subreq)
310 struct tevent_req *req = tevent_req_callback_data(
311 subreq, struct tevent_req);
312 struct readlink_state *state = tevent_req_data(
313 req, struct readlink_state);
314 NTSTATUS status;
316 status = cli_qpathinfo_recv(subreq, state, &state->data,
317 &state->num_data);
318 TALLOC_FREE(subreq);
319 if (!NT_STATUS_IS_OK(status)) {
320 tevent_req_nterror(req, status);
321 return;
324 * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
326 if (state->data[state->num_data-1] != '\0') {
327 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
328 return;
330 tevent_req_done(req);
333 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
334 char *retpath, size_t len)
336 NTSTATUS status;
337 char *converted = NULL;
338 size_t converted_size = 0;
339 struct readlink_state *state = tevent_req_data(req, struct readlink_state);
341 if (tevent_req_is_nterror(req, &status)) {
342 return status;
344 /* The returned data is a pushed string, not raw data. */
345 if (!convert_string_talloc(state,
346 cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
347 CH_UNIX,
348 state->data,
349 state->num_data,
350 &converted,
351 &converted_size,
352 true)) {
353 return NT_STATUS_NO_MEMORY;
356 len = MIN(len,converted_size);
357 if (len == 0) {
358 return NT_STATUS_DATA_ERROR;
360 memcpy(retpath, converted, len);
361 return NT_STATUS_OK;
364 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
365 char *linkpath, size_t len)
367 TALLOC_CTX *frame = talloc_stackframe();
368 struct event_context *ev = NULL;
369 struct tevent_req *req = NULL;
370 NTSTATUS status = NT_STATUS_OK;
372 if (cli_has_async_calls(cli)) {
374 * Can't use sync call while an async call is in flight
376 status = NT_STATUS_INVALID_PARAMETER;
377 goto fail;
380 ev = event_context_init(frame);
381 if (ev == NULL) {
382 status = NT_STATUS_NO_MEMORY;
383 goto fail;
386 req = cli_posix_readlink_send(frame,
388 cli,
389 fname,
390 len);
391 if (req == NULL) {
392 status = NT_STATUS_NO_MEMORY;
393 goto fail;
396 if (!tevent_req_poll(req, ev)) {
397 status = map_nt_error_from_unix(errno);
398 goto fail;
401 status = cli_posix_readlink_recv(req, cli, linkpath, len);
403 fail:
404 TALLOC_FREE(frame);
405 if (!NT_STATUS_IS_OK(status)) {
406 cli_set_error(cli, status);
408 return status;
411 /****************************************************************************
412 Hard link a file (UNIX extensions).
413 ****************************************************************************/
415 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
416 struct event_context *ev,
417 struct cli_state *cli,
418 const char *oldname,
419 const char *newname)
421 return cli_posix_link_internal_send(mem_ctx, ev, cli,
422 oldname, newname, true);
425 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
427 NTSTATUS status;
429 if (tevent_req_is_nterror(req, &status)) {
430 return status;
432 return NT_STATUS_OK;
435 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
436 const char *oldname,
437 const char *newname)
439 TALLOC_CTX *frame = talloc_stackframe();
440 struct event_context *ev = NULL;
441 struct tevent_req *req = NULL;
442 NTSTATUS status = NT_STATUS_OK;
444 if (cli_has_async_calls(cli)) {
446 * Can't use sync call while an async call is in flight
448 status = NT_STATUS_INVALID_PARAMETER;
449 goto fail;
452 ev = event_context_init(frame);
453 if (ev == NULL) {
454 status = NT_STATUS_NO_MEMORY;
455 goto fail;
458 req = cli_posix_hardlink_send(frame,
460 cli,
461 oldname,
462 newname);
463 if (req == NULL) {
464 status = NT_STATUS_NO_MEMORY;
465 goto fail;
468 if (!tevent_req_poll(req, ev)) {
469 status = map_nt_error_from_unix(errno);
470 goto fail;
473 status = cli_posix_hardlink_recv(req);
475 fail:
476 TALLOC_FREE(frame);
477 if (!NT_STATUS_IS_OK(status)) {
478 cli_set_error(cli, status);
480 return status;
483 /****************************************************************************
484 Map standard UNIX permissions onto wire representations.
485 ****************************************************************************/
487 uint32_t unix_perms_to_wire(mode_t perms)
489 unsigned int ret = 0;
491 ret |= ((perms & S_IXOTH) ? UNIX_X_OTH : 0);
492 ret |= ((perms & S_IWOTH) ? UNIX_W_OTH : 0);
493 ret |= ((perms & S_IROTH) ? UNIX_R_OTH : 0);
494 ret |= ((perms & S_IXGRP) ? UNIX_X_GRP : 0);
495 ret |= ((perms & S_IWGRP) ? UNIX_W_GRP : 0);
496 ret |= ((perms & S_IRGRP) ? UNIX_R_GRP : 0);
497 ret |= ((perms & S_IXUSR) ? UNIX_X_USR : 0);
498 ret |= ((perms & S_IWUSR) ? UNIX_W_USR : 0);
499 ret |= ((perms & S_IRUSR) ? UNIX_R_USR : 0);
500 #ifdef S_ISVTX
501 ret |= ((perms & S_ISVTX) ? UNIX_STICKY : 0);
502 #endif
503 #ifdef S_ISGID
504 ret |= ((perms & S_ISGID) ? UNIX_SET_GID : 0);
505 #endif
506 #ifdef S_ISUID
507 ret |= ((perms & S_ISUID) ? UNIX_SET_UID : 0);
508 #endif
509 return ret;
512 /****************************************************************************
513 Map wire permissions to standard UNIX.
514 ****************************************************************************/
516 mode_t wire_perms_to_unix(uint32_t perms)
518 mode_t ret = (mode_t)0;
520 ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
521 ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
522 ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
523 ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
524 ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
525 ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
526 ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
527 ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
528 ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
529 #ifdef S_ISVTX
530 ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
531 #endif
532 #ifdef S_ISGID
533 ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
534 #endif
535 #ifdef S_ISUID
536 ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
537 #endif
538 return ret;
541 /****************************************************************************
542 Return the file type from the wire filetype for UNIX extensions.
543 ****************************************************************************/
545 static mode_t unix_filetype_from_wire(uint32_t wire_type)
547 switch (wire_type) {
548 case UNIX_TYPE_FILE:
549 return S_IFREG;
550 case UNIX_TYPE_DIR:
551 return S_IFDIR;
552 #ifdef S_IFLNK
553 case UNIX_TYPE_SYMLINK:
554 return S_IFLNK;
555 #endif
556 #ifdef S_IFCHR
557 case UNIX_TYPE_CHARDEV:
558 return S_IFCHR;
559 #endif
560 #ifdef S_IFBLK
561 case UNIX_TYPE_BLKDEV:
562 return S_IFBLK;
563 #endif
564 #ifdef S_IFIFO
565 case UNIX_TYPE_FIFO:
566 return S_IFIFO;
567 #endif
568 #ifdef S_IFSOCK
569 case UNIX_TYPE_SOCKET:
570 return S_IFSOCK;
571 #endif
572 default:
573 return (mode_t)0;
577 /****************************************************************************
578 Do a POSIX getfacl (UNIX extensions).
579 ****************************************************************************/
581 struct getfacl_state {
582 uint32_t num_data;
583 uint8_t *data;
586 static void cli_posix_getfacl_done(struct tevent_req *subreq);
588 struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
589 struct event_context *ev,
590 struct cli_state *cli,
591 const char *fname)
593 struct tevent_req *req = NULL, *subreq = NULL;
594 struct getfacl_state *state = NULL;
596 req = tevent_req_create(mem_ctx, &state, struct getfacl_state);
597 if (req == NULL) {
598 return NULL;
600 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
601 0, cli->max_xmit);
602 if (tevent_req_nomem(subreq, req)) {
603 return tevent_req_post(req, ev);
605 tevent_req_set_callback(subreq, cli_posix_getfacl_done, req);
606 return req;
609 static void cli_posix_getfacl_done(struct tevent_req *subreq)
611 struct tevent_req *req = tevent_req_callback_data(
612 subreq, struct tevent_req);
613 struct getfacl_state *state = tevent_req_data(
614 req, struct getfacl_state);
615 NTSTATUS status;
617 status = cli_qpathinfo_recv(subreq, state, &state->data,
618 &state->num_data);
619 TALLOC_FREE(subreq);
620 if (!NT_STATUS_IS_OK(status)) {
621 tevent_req_nterror(req, status);
622 return;
624 tevent_req_done(req);
627 NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
628 TALLOC_CTX *mem_ctx,
629 size_t *prb_size,
630 char **retbuf)
632 struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
633 NTSTATUS status;
635 if (tevent_req_is_nterror(req, &status)) {
636 return status;
638 *prb_size = (size_t)state->num_data;
639 *retbuf = (char *)talloc_move(mem_ctx, &state->data);
640 return NT_STATUS_OK;
643 NTSTATUS cli_posix_getfacl(struct cli_state *cli,
644 const char *fname,
645 TALLOC_CTX *mem_ctx,
646 size_t *prb_size,
647 char **retbuf)
649 TALLOC_CTX *frame = talloc_stackframe();
650 struct event_context *ev = NULL;
651 struct tevent_req *req = NULL;
652 NTSTATUS status = NT_STATUS_OK;
654 if (cli_has_async_calls(cli)) {
656 * Can't use sync call while an async call is in flight
658 status = NT_STATUS_INVALID_PARAMETER;
659 goto fail;
662 ev = event_context_init(frame);
663 if (ev == NULL) {
664 status = NT_STATUS_NO_MEMORY;
665 goto fail;
668 req = cli_posix_getfacl_send(frame,
670 cli,
671 fname);
672 if (req == NULL) {
673 status = NT_STATUS_NO_MEMORY;
674 goto fail;
677 if (!tevent_req_poll(req, ev)) {
678 status = map_nt_error_from_unix(errno);
679 goto fail;
682 status = cli_posix_getfacl_recv(req, mem_ctx, prb_size, retbuf);
684 fail:
685 TALLOC_FREE(frame);
686 if (!NT_STATUS_IS_OK(status)) {
687 cli_set_error(cli, status);
689 return status;
692 /****************************************************************************
693 Stat a file (UNIX extensions).
694 ****************************************************************************/
696 struct stat_state {
697 uint32_t num_data;
698 uint8_t *data;
701 static void cli_posix_stat_done(struct tevent_req *subreq);
703 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
704 struct event_context *ev,
705 struct cli_state *cli,
706 const char *fname)
708 struct tevent_req *req = NULL, *subreq = NULL;
709 struct stat_state *state = NULL;
711 req = tevent_req_create(mem_ctx, &state, struct stat_state);
712 if (req == NULL) {
713 return NULL;
715 subreq = cli_qpathinfo_send(state, ev, cli, fname,
716 SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
717 if (tevent_req_nomem(subreq, req)) {
718 return tevent_req_post(req, ev);
720 tevent_req_set_callback(subreq, cli_posix_stat_done, req);
721 return req;
724 static void cli_posix_stat_done(struct tevent_req *subreq)
726 struct tevent_req *req = tevent_req_callback_data(
727 subreq, struct tevent_req);
728 struct stat_state *state = tevent_req_data(req, struct stat_state);
729 NTSTATUS status;
731 status = cli_qpathinfo_recv(subreq, state, &state->data,
732 &state->num_data);
733 TALLOC_FREE(subreq);
734 if (!NT_STATUS_IS_OK(status)) {
735 tevent_req_nterror(req, status);
736 return;
738 tevent_req_done(req);
741 NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
742 SMB_STRUCT_STAT *sbuf)
744 struct stat_state *state = tevent_req_data(req, struct stat_state);
745 NTSTATUS status;
747 if (tevent_req_is_nterror(req, &status)) {
748 return status;
751 sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0); /* total size, in bytes */
752 sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8); /* number of blocks allocated */
753 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
754 sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
755 #else
756 /* assume 512 byte blocks */
757 sbuf->st_ex_blocks /= 512;
758 #endif
759 sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16)); /* time of last change */
760 sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24)); /* time of last access */
761 sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32)); /* time of last modification */
763 sbuf->st_ex_uid = (uid_t) IVAL(state->data,40); /* user ID of owner */
764 sbuf->st_ex_gid = (gid_t) IVAL(state->data,48); /* group ID of owner */
765 sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
766 #if defined(HAVE_MAKEDEV)
768 uint32_t dev_major = IVAL(state->data,60);
769 uint32_t dev_minor = IVAL(state->data,68);
770 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
772 #endif
773 sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76); /* inode */
774 sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84)); /* protection */
775 sbuf->st_ex_nlink = BIG_UINT(state->data,92); /* number of hard links */
777 return NT_STATUS_OK;
780 NTSTATUS cli_posix_stat(struct cli_state *cli,
781 const char *fname,
782 SMB_STRUCT_STAT *sbuf)
784 TALLOC_CTX *frame = talloc_stackframe();
785 struct event_context *ev = NULL;
786 struct tevent_req *req = NULL;
787 NTSTATUS status = NT_STATUS_OK;
789 if (cli_has_async_calls(cli)) {
791 * Can't use sync call while an async call is in flight
793 status = NT_STATUS_INVALID_PARAMETER;
794 goto fail;
797 ev = event_context_init(frame);
798 if (ev == NULL) {
799 status = NT_STATUS_NO_MEMORY;
800 goto fail;
803 req = cli_posix_stat_send(frame,
805 cli,
806 fname);
807 if (req == NULL) {
808 status = NT_STATUS_NO_MEMORY;
809 goto fail;
812 if (!tevent_req_poll(req, ev)) {
813 status = map_nt_error_from_unix(errno);
814 goto fail;
817 status = cli_posix_stat_recv(req, sbuf);
819 fail:
820 TALLOC_FREE(frame);
821 if (!NT_STATUS_IS_OK(status)) {
822 cli_set_error(cli, status);
824 return status;
827 /****************************************************************************
828 Chmod or chown a file internal (UNIX extensions).
829 ****************************************************************************/
831 struct ch_state {
832 uint16_t setup;
833 uint8_t *param;
834 uint8_t *data;
837 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
839 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
840 NULL, 0, NULL, NULL, 0, NULL);
841 tevent_req_simple_finish_ntstatus(subreq, status);
844 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
845 struct event_context *ev,
846 struct cli_state *cli,
847 const char *fname,
848 uint32_t mode,
849 uint32_t uid,
850 uint32_t gid)
852 struct tevent_req *req = NULL, *subreq = NULL;
853 struct ch_state *state = NULL;
855 req = tevent_req_create(mem_ctx, &state, struct ch_state);
856 if (req == NULL) {
857 return NULL;
860 /* Setup setup word. */
861 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
863 /* Setup param array. */
864 state->param = talloc_array(state, uint8_t, 6);
865 if (tevent_req_nomem(state->param, req)) {
866 return tevent_req_post(req, ev);
868 memset(state->param, '\0', 6);
869 SSVAL(state->param,0,SMB_SET_FILE_UNIX_BASIC);
871 state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
872 strlen(fname)+1, NULL);
874 if (tevent_req_nomem(state->param, req)) {
875 return tevent_req_post(req, ev);
878 /* Setup data array. */
879 state->data = talloc_array(state, uint8_t, 100);
880 if (tevent_req_nomem(state->data, req)) {
881 return tevent_req_post(req, ev);
883 memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
884 memset(&state->data[40], '\0', 60);
885 SIVAL(state->data,40,uid);
886 SIVAL(state->data,48,gid);
887 SIVAL(state->data,84,mode);
889 subreq = cli_trans_send(state, /* mem ctx. */
890 ev, /* event ctx. */
891 cli, /* cli_state. */
892 SMBtrans2, /* cmd. */
893 NULL, /* pipe name. */
894 -1, /* fid. */
895 0, /* function. */
896 0, /* flags. */
897 &state->setup, /* setup. */
898 1, /* num setup uint16_t words. */
899 0, /* max returned setup. */
900 state->param, /* param. */
901 talloc_get_size(state->param), /* num param. */
902 2, /* max returned param. */
903 state->data, /* data. */
904 talloc_get_size(state->data), /* num data. */
905 0); /* max returned data. */
907 if (tevent_req_nomem(subreq, req)) {
908 return tevent_req_post(req, ev);
910 tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done, req);
911 return req;
914 /****************************************************************************
915 chmod a file (UNIX extensions).
916 ****************************************************************************/
918 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
919 struct event_context *ev,
920 struct cli_state *cli,
921 const char *fname,
922 mode_t mode)
924 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
925 fname,
926 unix_perms_to_wire(mode),
927 SMB_UID_NO_CHANGE,
928 SMB_GID_NO_CHANGE);
931 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
933 NTSTATUS status;
935 if (tevent_req_is_nterror(req, &status)) {
936 return status;
938 return NT_STATUS_OK;
941 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
943 TALLOC_CTX *frame = talloc_stackframe();
944 struct event_context *ev = NULL;
945 struct tevent_req *req = NULL;
946 NTSTATUS status = NT_STATUS_OK;
948 if (cli_has_async_calls(cli)) {
950 * Can't use sync call while an async call is in flight
952 status = NT_STATUS_INVALID_PARAMETER;
953 goto fail;
956 ev = event_context_init(frame);
957 if (ev == NULL) {
958 status = NT_STATUS_NO_MEMORY;
959 goto fail;
962 req = cli_posix_chmod_send(frame,
964 cli,
965 fname,
966 mode);
967 if (req == NULL) {
968 status = NT_STATUS_NO_MEMORY;
969 goto fail;
972 if (!tevent_req_poll(req, ev)) {
973 status = map_nt_error_from_unix(errno);
974 goto fail;
977 status = cli_posix_chmod_recv(req);
979 fail:
980 TALLOC_FREE(frame);
981 if (!NT_STATUS_IS_OK(status)) {
982 cli_set_error(cli, status);
984 return status;
987 /****************************************************************************
988 chown a file (UNIX extensions).
989 ****************************************************************************/
991 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
992 struct event_context *ev,
993 struct cli_state *cli,
994 const char *fname,
995 uid_t uid,
996 gid_t gid)
998 return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
999 fname,
1000 SMB_MODE_NO_CHANGE,
1001 (uint32_t)uid,
1002 (uint32_t)gid);
1005 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1007 NTSTATUS status;
1009 if (tevent_req_is_nterror(req, &status)) {
1010 return status;
1012 return NT_STATUS_OK;
1015 NTSTATUS cli_posix_chown(struct cli_state *cli,
1016 const char *fname,
1017 uid_t uid,
1018 gid_t gid)
1020 TALLOC_CTX *frame = talloc_stackframe();
1021 struct event_context *ev = NULL;
1022 struct tevent_req *req = NULL;
1023 NTSTATUS status = NT_STATUS_OK;
1025 if (cli_has_async_calls(cli)) {
1027 * Can't use sync call while an async call is in flight
1029 status = NT_STATUS_INVALID_PARAMETER;
1030 goto fail;
1033 ev = event_context_init(frame);
1034 if (ev == NULL) {
1035 status = NT_STATUS_NO_MEMORY;
1036 goto fail;
1039 req = cli_posix_chown_send(frame,
1041 cli,
1042 fname,
1043 uid,
1044 gid);
1045 if (req == NULL) {
1046 status = NT_STATUS_NO_MEMORY;
1047 goto fail;
1050 if (!tevent_req_poll(req, ev)) {
1051 status = map_nt_error_from_unix(errno);
1052 goto fail;
1055 status = cli_posix_chown_recv(req);
1057 fail:
1058 TALLOC_FREE(frame);
1059 if (!NT_STATUS_IS_OK(status)) {
1060 cli_set_error(cli, status);
1062 return status;
1065 /****************************************************************************
1066 Rename a file.
1067 ****************************************************************************/
1069 static void cli_rename_done(struct tevent_req *subreq);
1071 struct cli_rename_state {
1072 uint16_t vwv[1];
1075 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1076 struct event_context *ev,
1077 struct cli_state *cli,
1078 const char *fname_src,
1079 const char *fname_dst)
1081 struct tevent_req *req = NULL, *subreq = NULL;
1082 struct cli_rename_state *state = NULL;
1083 uint8_t additional_flags = 0;
1084 uint8_t *bytes = NULL;
1086 req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1087 if (req == NULL) {
1088 return NULL;
1091 SSVAL(state->vwv+0, 0, aSYSTEM | aHIDDEN | aDIR);
1093 bytes = talloc_array(state, uint8_t, 1);
1094 if (tevent_req_nomem(bytes, req)) {
1095 return tevent_req_post(req, ev);
1097 bytes[0] = 4;
1098 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1099 strlen(fname_src)+1, NULL);
1100 if (tevent_req_nomem(bytes, req)) {
1101 return tevent_req_post(req, ev);
1104 bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1105 talloc_get_size(bytes)+1);
1106 if (tevent_req_nomem(bytes, req)) {
1107 return tevent_req_post(req, ev);
1110 bytes[talloc_get_size(bytes)-1] = 4;
1111 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1112 strlen(fname_dst)+1, NULL);
1113 if (tevent_req_nomem(bytes, req)) {
1114 return tevent_req_post(req, ev);
1117 subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1118 1, state->vwv, talloc_get_size(bytes), bytes);
1119 if (tevent_req_nomem(subreq, req)) {
1120 return tevent_req_post(req, ev);
1122 tevent_req_set_callback(subreq, cli_rename_done, req);
1123 return req;
1126 static void cli_rename_done(struct tevent_req *subreq)
1128 struct tevent_req *req = tevent_req_callback_data(
1129 subreq, struct tevent_req);
1130 NTSTATUS status;
1132 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1133 TALLOC_FREE(subreq);
1134 if (!NT_STATUS_IS_OK(status)) {
1135 tevent_req_nterror(req, status);
1136 return;
1138 tevent_req_done(req);
1141 NTSTATUS cli_rename_recv(struct tevent_req *req)
1143 return tevent_req_simple_recv_ntstatus(req);
1146 NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1148 TALLOC_CTX *frame = talloc_stackframe();
1149 struct event_context *ev;
1150 struct tevent_req *req;
1151 NTSTATUS status = NT_STATUS_OK;
1153 if (cli_has_async_calls(cli)) {
1155 * Can't use sync call while an async call is in flight
1157 status = NT_STATUS_INVALID_PARAMETER;
1158 goto fail;
1161 ev = event_context_init(frame);
1162 if (ev == NULL) {
1163 status = NT_STATUS_NO_MEMORY;
1164 goto fail;
1167 req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
1168 if (req == NULL) {
1169 status = NT_STATUS_NO_MEMORY;
1170 goto fail;
1173 if (!tevent_req_poll(req, ev)) {
1174 status = map_nt_error_from_unix(errno);
1175 goto fail;
1178 status = cli_rename_recv(req);
1180 fail:
1181 TALLOC_FREE(frame);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 cli_set_error(cli, status);
1185 return status;
1188 /****************************************************************************
1189 NT Rename a file.
1190 ****************************************************************************/
1192 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1194 struct cli_ntrename_internal_state {
1195 uint16_t vwv[4];
1198 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1199 struct event_context *ev,
1200 struct cli_state *cli,
1201 const char *fname_src,
1202 const char *fname_dst,
1203 uint16_t rename_flag)
1205 struct tevent_req *req = NULL, *subreq = NULL;
1206 struct cli_ntrename_internal_state *state = NULL;
1207 uint8_t additional_flags = 0;
1208 uint8_t *bytes = NULL;
1210 req = tevent_req_create(mem_ctx, &state,
1211 struct cli_ntrename_internal_state);
1212 if (req == NULL) {
1213 return NULL;
1216 SSVAL(state->vwv+0, 0 ,aSYSTEM | aHIDDEN | aDIR);
1217 SSVAL(state->vwv+1, 0, rename_flag);
1219 bytes = talloc_array(state, uint8_t, 1);
1220 if (tevent_req_nomem(bytes, req)) {
1221 return tevent_req_post(req, ev);
1223 bytes[0] = 4;
1224 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1225 strlen(fname_src)+1, NULL);
1226 if (tevent_req_nomem(bytes, req)) {
1227 return tevent_req_post(req, ev);
1230 bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1231 talloc_get_size(bytes)+1);
1232 if (tevent_req_nomem(bytes, req)) {
1233 return tevent_req_post(req, ev);
1236 bytes[talloc_get_size(bytes)-1] = 4;
1237 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1238 strlen(fname_dst)+1, NULL);
1239 if (tevent_req_nomem(bytes, req)) {
1240 return tevent_req_post(req, ev);
1243 subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1244 4, state->vwv, talloc_get_size(bytes), bytes);
1245 if (tevent_req_nomem(subreq, req)) {
1246 return tevent_req_post(req, ev);
1248 tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1249 return req;
1252 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1254 struct tevent_req *req = tevent_req_callback_data(
1255 subreq, struct tevent_req);
1256 NTSTATUS status;
1258 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1259 TALLOC_FREE(subreq);
1260 if (!NT_STATUS_IS_OK(status)) {
1261 tevent_req_nterror(req, status);
1262 return;
1264 tevent_req_done(req);
1267 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1269 return tevent_req_simple_recv_ntstatus(req);
1272 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1273 struct event_context *ev,
1274 struct cli_state *cli,
1275 const char *fname_src,
1276 const char *fname_dst)
1278 return cli_ntrename_internal_send(mem_ctx,
1280 cli,
1281 fname_src,
1282 fname_dst,
1283 RENAME_FLAG_RENAME);
1286 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1288 return cli_ntrename_internal_recv(req);
1291 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1293 TALLOC_CTX *frame = talloc_stackframe();
1294 struct event_context *ev;
1295 struct tevent_req *req;
1296 NTSTATUS status = NT_STATUS_OK;
1298 if (cli_has_async_calls(cli)) {
1300 * Can't use sync call while an async call is in flight
1302 status = NT_STATUS_INVALID_PARAMETER;
1303 goto fail;
1306 ev = event_context_init(frame);
1307 if (ev == NULL) {
1308 status = NT_STATUS_NO_MEMORY;
1309 goto fail;
1312 req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1313 if (req == NULL) {
1314 status = NT_STATUS_NO_MEMORY;
1315 goto fail;
1318 if (!tevent_req_poll(req, ev)) {
1319 status = map_nt_error_from_unix(errno);
1320 goto fail;
1323 status = cli_ntrename_recv(req);
1325 fail:
1326 TALLOC_FREE(frame);
1327 if (!NT_STATUS_IS_OK(status)) {
1328 cli_set_error(cli, status);
1330 return status;
1333 /****************************************************************************
1334 NT hardlink a file.
1335 ****************************************************************************/
1337 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1338 struct event_context *ev,
1339 struct cli_state *cli,
1340 const char *fname_src,
1341 const char *fname_dst)
1343 return cli_ntrename_internal_send(mem_ctx,
1345 cli,
1346 fname_src,
1347 fname_dst,
1348 RENAME_FLAG_HARD_LINK);
1351 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1353 return cli_ntrename_internal_recv(req);
1356 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1358 TALLOC_CTX *frame = talloc_stackframe();
1359 struct event_context *ev;
1360 struct tevent_req *req;
1361 NTSTATUS status = NT_STATUS_OK;
1363 if (cli_has_async_calls(cli)) {
1365 * Can't use sync call while an async call is in flight
1367 status = NT_STATUS_INVALID_PARAMETER;
1368 goto fail;
1371 ev = event_context_init(frame);
1372 if (ev == NULL) {
1373 status = NT_STATUS_NO_MEMORY;
1374 goto fail;
1377 req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1378 if (req == NULL) {
1379 status = NT_STATUS_NO_MEMORY;
1380 goto fail;
1383 if (!tevent_req_poll(req, ev)) {
1384 status = map_nt_error_from_unix(errno);
1385 goto fail;
1388 status = cli_nt_hardlink_recv(req);
1390 fail:
1391 TALLOC_FREE(frame);
1392 if (!NT_STATUS_IS_OK(status)) {
1393 cli_set_error(cli, status);
1395 return status;
1398 /****************************************************************************
1399 Delete a file.
1400 ****************************************************************************/
1402 static void cli_unlink_done(struct tevent_req *subreq);
1404 struct cli_unlink_state {
1405 uint16_t vwv[1];
1408 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1409 struct event_context *ev,
1410 struct cli_state *cli,
1411 const char *fname,
1412 uint16_t mayhave_attrs)
1414 struct tevent_req *req = NULL, *subreq = NULL;
1415 struct cli_unlink_state *state = NULL;
1416 uint8_t additional_flags = 0;
1417 uint8_t *bytes = NULL;
1419 req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1420 if (req == NULL) {
1421 return NULL;
1424 SSVAL(state->vwv+0, 0, mayhave_attrs);
1426 bytes = talloc_array(state, uint8_t, 1);
1427 if (tevent_req_nomem(bytes, req)) {
1428 return tevent_req_post(req, ev);
1430 bytes[0] = 4;
1431 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
1432 strlen(fname)+1, NULL);
1434 if (tevent_req_nomem(bytes, req)) {
1435 return tevent_req_post(req, ev);
1438 subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1439 1, state->vwv, talloc_get_size(bytes), bytes);
1440 if (tevent_req_nomem(subreq, req)) {
1441 return tevent_req_post(req, ev);
1443 tevent_req_set_callback(subreq, cli_unlink_done, req);
1444 return req;
1447 static void cli_unlink_done(struct tevent_req *subreq)
1449 struct tevent_req *req = tevent_req_callback_data(
1450 subreq, struct tevent_req);
1451 NTSTATUS status;
1453 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1454 TALLOC_FREE(subreq);
1455 if (!NT_STATUS_IS_OK(status)) {
1456 tevent_req_nterror(req, status);
1457 return;
1459 tevent_req_done(req);
1462 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1464 return tevent_req_simple_recv_ntstatus(req);
1467 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1469 TALLOC_CTX *frame = talloc_stackframe();
1470 struct event_context *ev;
1471 struct tevent_req *req;
1472 NTSTATUS status = NT_STATUS_OK;
1474 if (cli_has_async_calls(cli)) {
1476 * Can't use sync call while an async call is in flight
1478 status = NT_STATUS_INVALID_PARAMETER;
1479 goto fail;
1482 ev = event_context_init(frame);
1483 if (ev == NULL) {
1484 status = NT_STATUS_NO_MEMORY;
1485 goto fail;
1488 req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1489 if (req == NULL) {
1490 status = NT_STATUS_NO_MEMORY;
1491 goto fail;
1494 if (!tevent_req_poll(req, ev)) {
1495 status = map_nt_error_from_unix(errno);
1496 goto fail;
1499 status = cli_unlink_recv(req);
1501 fail:
1502 TALLOC_FREE(frame);
1503 if (!NT_STATUS_IS_OK(status)) {
1504 cli_set_error(cli, status);
1506 return status;
1509 /****************************************************************************
1510 Create a directory.
1511 ****************************************************************************/
1513 static void cli_mkdir_done(struct tevent_req *subreq);
1515 struct cli_mkdir_state {
1516 int dummy;
1519 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1520 struct event_context *ev,
1521 struct cli_state *cli,
1522 const char *dname)
1524 struct tevent_req *req = NULL, *subreq = NULL;
1525 struct cli_mkdir_state *state = NULL;
1526 uint8_t additional_flags = 0;
1527 uint8_t *bytes = NULL;
1529 req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1530 if (req == NULL) {
1531 return NULL;
1534 bytes = talloc_array(state, uint8_t, 1);
1535 if (tevent_req_nomem(bytes, req)) {
1536 return tevent_req_post(req, ev);
1538 bytes[0] = 4;
1539 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1540 strlen(dname)+1, NULL);
1542 if (tevent_req_nomem(bytes, req)) {
1543 return tevent_req_post(req, ev);
1546 subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1547 0, NULL, talloc_get_size(bytes), bytes);
1548 if (tevent_req_nomem(subreq, req)) {
1549 return tevent_req_post(req, ev);
1551 tevent_req_set_callback(subreq, cli_mkdir_done, req);
1552 return req;
1555 static void cli_mkdir_done(struct tevent_req *subreq)
1557 struct tevent_req *req = tevent_req_callback_data(
1558 subreq, struct tevent_req);
1559 NTSTATUS status;
1561 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1562 TALLOC_FREE(subreq);
1563 if (!NT_STATUS_IS_OK(status)) {
1564 tevent_req_nterror(req, status);
1565 return;
1567 tevent_req_done(req);
1570 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1572 return tevent_req_simple_recv_ntstatus(req);
1575 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1577 TALLOC_CTX *frame = talloc_stackframe();
1578 struct event_context *ev;
1579 struct tevent_req *req;
1580 NTSTATUS status = NT_STATUS_OK;
1582 if (cli_has_async_calls(cli)) {
1584 * Can't use sync call while an async call is in flight
1586 status = NT_STATUS_INVALID_PARAMETER;
1587 goto fail;
1590 ev = event_context_init(frame);
1591 if (ev == NULL) {
1592 status = NT_STATUS_NO_MEMORY;
1593 goto fail;
1596 req = cli_mkdir_send(frame, ev, cli, dname);
1597 if (req == NULL) {
1598 status = NT_STATUS_NO_MEMORY;
1599 goto fail;
1602 if (!tevent_req_poll(req, ev)) {
1603 status = map_nt_error_from_unix(errno);
1604 goto fail;
1607 status = cli_mkdir_recv(req);
1609 fail:
1610 TALLOC_FREE(frame);
1611 if (!NT_STATUS_IS_OK(status)) {
1612 cli_set_error(cli, status);
1614 return status;
1617 /****************************************************************************
1618 Remove a directory.
1619 ****************************************************************************/
1621 static void cli_rmdir_done(struct tevent_req *subreq);
1623 struct cli_rmdir_state {
1624 int dummy;
1627 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1628 struct event_context *ev,
1629 struct cli_state *cli,
1630 const char *dname)
1632 struct tevent_req *req = NULL, *subreq = NULL;
1633 struct cli_rmdir_state *state = NULL;
1634 uint8_t additional_flags = 0;
1635 uint8_t *bytes = NULL;
1637 req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1638 if (req == NULL) {
1639 return NULL;
1642 bytes = talloc_array(state, uint8_t, 1);
1643 if (tevent_req_nomem(bytes, req)) {
1644 return tevent_req_post(req, ev);
1646 bytes[0] = 4;
1647 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1648 strlen(dname)+1, NULL);
1650 if (tevent_req_nomem(bytes, req)) {
1651 return tevent_req_post(req, ev);
1654 subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1655 0, NULL, talloc_get_size(bytes), bytes);
1656 if (tevent_req_nomem(subreq, req)) {
1657 return tevent_req_post(req, ev);
1659 tevent_req_set_callback(subreq, cli_rmdir_done, req);
1660 return req;
1663 static void cli_rmdir_done(struct tevent_req *subreq)
1665 struct tevent_req *req = tevent_req_callback_data(
1666 subreq, struct tevent_req);
1667 NTSTATUS status;
1669 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1670 TALLOC_FREE(subreq);
1671 if (!NT_STATUS_IS_OK(status)) {
1672 tevent_req_nterror(req, status);
1673 return;
1675 tevent_req_done(req);
1678 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1680 return tevent_req_simple_recv_ntstatus(req);
1683 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1685 TALLOC_CTX *frame = talloc_stackframe();
1686 struct event_context *ev;
1687 struct tevent_req *req;
1688 NTSTATUS status = NT_STATUS_OK;
1690 if (cli_has_async_calls(cli)) {
1692 * Can't use sync call while an async call is in flight
1694 status = NT_STATUS_INVALID_PARAMETER;
1695 goto fail;
1698 ev = event_context_init(frame);
1699 if (ev == NULL) {
1700 status = NT_STATUS_NO_MEMORY;
1701 goto fail;
1704 req = cli_rmdir_send(frame, ev, cli, dname);
1705 if (req == NULL) {
1706 status = NT_STATUS_NO_MEMORY;
1707 goto fail;
1710 if (!tevent_req_poll(req, ev)) {
1711 status = map_nt_error_from_unix(errno);
1712 goto fail;
1715 status = cli_rmdir_recv(req);
1717 fail:
1718 TALLOC_FREE(frame);
1719 if (!NT_STATUS_IS_OK(status)) {
1720 cli_set_error(cli, status);
1722 return status;
1725 /****************************************************************************
1726 Set or clear the delete on close flag.
1727 ****************************************************************************/
1729 struct doc_state {
1730 uint16_t setup;
1731 uint8_t param[6];
1732 uint8_t data[1];
1735 static void cli_nt_delete_on_close_done(struct tevent_req *subreq)
1737 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
1738 NULL, 0, NULL, NULL, 0, NULL);
1739 tevent_req_simple_finish_ntstatus(subreq, status);
1742 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1743 struct event_context *ev,
1744 struct cli_state *cli,
1745 uint16_t fnum,
1746 bool flag)
1748 struct tevent_req *req = NULL, *subreq = NULL;
1749 struct doc_state *state = NULL;
1751 req = tevent_req_create(mem_ctx, &state, struct doc_state);
1752 if (req == NULL) {
1753 return NULL;
1756 /* Setup setup word. */
1757 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1759 /* Setup param array. */
1760 SSVAL(state->param,0,fnum);
1761 SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1763 /* Setup data array. */
1764 SCVAL(&state->data[0], 0, flag ? 1 : 0);
1766 subreq = cli_trans_send(state, /* mem ctx. */
1767 ev, /* event ctx. */
1768 cli, /* cli_state. */
1769 SMBtrans2, /* cmd. */
1770 NULL, /* pipe name. */
1771 -1, /* fid. */
1772 0, /* function. */
1773 0, /* flags. */
1774 &state->setup, /* setup. */
1775 1, /* num setup uint16_t words. */
1776 0, /* max returned setup. */
1777 state->param, /* param. */
1778 6, /* num param. */
1779 2, /* max returned param. */
1780 state->data, /* data. */
1781 1, /* num data. */
1782 0); /* max returned data. */
1784 if (tevent_req_nomem(subreq, req)) {
1785 return tevent_req_post(req, ev);
1787 tevent_req_set_callback(subreq, cli_nt_delete_on_close_done, req);
1788 return req;
1791 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1793 NTSTATUS status;
1795 if (tevent_req_is_nterror(req, &status)) {
1796 return status;
1798 return NT_STATUS_OK;
1801 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1803 TALLOC_CTX *frame = talloc_stackframe();
1804 struct event_context *ev = NULL;
1805 struct tevent_req *req = NULL;
1806 NTSTATUS status = NT_STATUS_OK;
1808 if (cli_has_async_calls(cli)) {
1810 * Can't use sync call while an async call is in flight
1812 status = NT_STATUS_INVALID_PARAMETER;
1813 goto fail;
1816 ev = event_context_init(frame);
1817 if (ev == NULL) {
1818 status = NT_STATUS_NO_MEMORY;
1819 goto fail;
1822 req = cli_nt_delete_on_close_send(frame,
1824 cli,
1825 fnum,
1826 flag);
1827 if (req == NULL) {
1828 status = NT_STATUS_NO_MEMORY;
1829 goto fail;
1832 if (!tevent_req_poll(req, ev)) {
1833 status = map_nt_error_from_unix(errno);
1834 goto fail;
1837 status = cli_nt_delete_on_close_recv(req);
1839 fail:
1840 TALLOC_FREE(frame);
1841 if (!NT_STATUS_IS_OK(status)) {
1842 cli_set_error(cli, status);
1844 return status;
1847 struct cli_ntcreate_state {
1848 uint16_t vwv[24];
1849 uint16_t fnum;
1852 static void cli_ntcreate_done(struct tevent_req *subreq);
1854 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
1855 struct event_context *ev,
1856 struct cli_state *cli,
1857 const char *fname,
1858 uint32_t CreatFlags,
1859 uint32_t DesiredAccess,
1860 uint32_t FileAttributes,
1861 uint32_t ShareAccess,
1862 uint32_t CreateDisposition,
1863 uint32_t CreateOptions,
1864 uint8_t SecurityFlags)
1866 struct tevent_req *req, *subreq;
1867 struct cli_ntcreate_state *state;
1868 uint16_t *vwv;
1869 uint8_t *bytes;
1870 size_t converted_len;
1872 req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
1873 if (req == NULL) {
1874 return NULL;
1877 vwv = state->vwv;
1879 SCVAL(vwv+0, 0, 0xFF);
1880 SCVAL(vwv+0, 1, 0);
1881 SSVAL(vwv+1, 0, 0);
1882 SCVAL(vwv+2, 0, 0);
1884 if (cli->use_oplocks) {
1885 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1887 SIVAL(vwv+3, 1, CreatFlags);
1888 SIVAL(vwv+5, 1, 0x0); /* RootDirectoryFid */
1889 SIVAL(vwv+7, 1, DesiredAccess);
1890 SIVAL(vwv+9, 1, 0x0); /* AllocationSize */
1891 SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
1892 SIVAL(vwv+13, 1, FileAttributes);
1893 SIVAL(vwv+15, 1, ShareAccess);
1894 SIVAL(vwv+17, 1, CreateDisposition);
1895 SIVAL(vwv+19, 1, CreateOptions);
1896 SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1897 SCVAL(vwv+23, 1, SecurityFlags);
1899 bytes = talloc_array(state, uint8_t, 0);
1900 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
1901 fname, strlen(fname)+1,
1902 &converted_len);
1904 /* sigh. this copes with broken netapp filer behaviour */
1905 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL);
1907 if (tevent_req_nomem(bytes, req)) {
1908 return tevent_req_post(req, ev);
1911 SSVAL(vwv+2, 1, converted_len);
1913 subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
1914 talloc_get_size(bytes), bytes);
1915 if (tevent_req_nomem(subreq, req)) {
1916 return tevent_req_post(req, ev);
1918 tevent_req_set_callback(subreq, cli_ntcreate_done, req);
1919 return req;
1922 static void cli_ntcreate_done(struct tevent_req *subreq)
1924 struct tevent_req *req = tevent_req_callback_data(
1925 subreq, struct tevent_req);
1926 struct cli_ntcreate_state *state = tevent_req_data(
1927 req, struct cli_ntcreate_state);
1928 uint8_t wct;
1929 uint16_t *vwv;
1930 uint32_t num_bytes;
1931 uint8_t *bytes;
1932 uint8_t *inbuf;
1933 NTSTATUS status;
1935 status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv,
1936 &num_bytes, &bytes);
1937 TALLOC_FREE(subreq);
1938 if (!NT_STATUS_IS_OK(status)) {
1939 tevent_req_nterror(req, status);
1940 return;
1942 state->fnum = SVAL(vwv+2, 1);
1943 tevent_req_done(req);
1946 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
1948 struct cli_ntcreate_state *state = tevent_req_data(
1949 req, struct cli_ntcreate_state);
1950 NTSTATUS status;
1952 if (tevent_req_is_nterror(req, &status)) {
1953 return status;
1955 *pfnum = state->fnum;
1956 return NT_STATUS_OK;
1959 NTSTATUS cli_ntcreate(struct cli_state *cli,
1960 const char *fname,
1961 uint32_t CreatFlags,
1962 uint32_t DesiredAccess,
1963 uint32_t FileAttributes,
1964 uint32_t ShareAccess,
1965 uint32_t CreateDisposition,
1966 uint32_t CreateOptions,
1967 uint8_t SecurityFlags,
1968 uint16_t *pfid)
1970 TALLOC_CTX *frame = talloc_stackframe();
1971 struct event_context *ev;
1972 struct tevent_req *req;
1973 NTSTATUS status = NT_STATUS_OK;
1975 if (cli_has_async_calls(cli)) {
1977 * Can't use sync call while an async call is in flight
1979 status = NT_STATUS_INVALID_PARAMETER;
1980 goto fail;
1983 ev = event_context_init(frame);
1984 if (ev == NULL) {
1985 status = NT_STATUS_NO_MEMORY;
1986 goto fail;
1989 req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
1990 DesiredAccess, FileAttributes, ShareAccess,
1991 CreateDisposition, CreateOptions,
1992 SecurityFlags);
1993 if (req == NULL) {
1994 status = NT_STATUS_NO_MEMORY;
1995 goto fail;
1998 if (!tevent_req_poll(req, ev)) {
1999 status = map_nt_error_from_unix(errno);
2000 goto fail;
2003 status = cli_ntcreate_recv(req, pfid);
2004 fail:
2005 TALLOC_FREE(frame);
2006 if (!NT_STATUS_IS_OK(status)) {
2007 cli_set_error(cli, status);
2009 return status;
2012 /****************************************************************************
2013 Open a file
2014 WARNING: if you open with O_WRONLY then getattrE won't work!
2015 ****************************************************************************/
2017 struct cli_open_state {
2018 uint16_t vwv[15];
2019 uint16_t fnum;
2020 struct iovec bytes;
2023 static void cli_open_done(struct tevent_req *subreq);
2025 struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx,
2026 struct event_context *ev,
2027 struct cli_state *cli, const char *fname,
2028 int flags, int share_mode,
2029 struct tevent_req **psmbreq)
2031 struct tevent_req *req, *subreq;
2032 struct cli_open_state *state;
2033 unsigned openfn;
2034 unsigned accessmode;
2035 uint8_t additional_flags;
2036 uint8_t *bytes;
2038 req = tevent_req_create(mem_ctx, &state, struct cli_open_state);
2039 if (req == NULL) {
2040 return NULL;
2043 openfn = 0;
2044 if (flags & O_CREAT) {
2045 openfn |= (1<<4);
2047 if (!(flags & O_EXCL)) {
2048 if (flags & O_TRUNC)
2049 openfn |= (1<<1);
2050 else
2051 openfn |= (1<<0);
2054 accessmode = (share_mode<<4);
2056 if ((flags & O_ACCMODE) == O_RDWR) {
2057 accessmode |= 2;
2058 } else if ((flags & O_ACCMODE) == O_WRONLY) {
2059 accessmode |= 1;
2062 #if defined(O_SYNC)
2063 if ((flags & O_SYNC) == O_SYNC) {
2064 accessmode |= (1<<14);
2066 #endif /* O_SYNC */
2068 if (share_mode == DENY_FCB) {
2069 accessmode = 0xFF;
2072 SCVAL(state->vwv + 0, 0, 0xFF);
2073 SCVAL(state->vwv + 0, 1, 0);
2074 SSVAL(state->vwv + 1, 0, 0);
2075 SSVAL(state->vwv + 2, 0, 0); /* no additional info */
2076 SSVAL(state->vwv + 3, 0, accessmode);
2077 SSVAL(state->vwv + 4, 0, aSYSTEM | aHIDDEN);
2078 SSVAL(state->vwv + 5, 0, 0);
2079 SIVAL(state->vwv + 6, 0, 0);
2080 SSVAL(state->vwv + 8, 0, openfn);
2081 SIVAL(state->vwv + 9, 0, 0);
2082 SIVAL(state->vwv + 11, 0, 0);
2083 SIVAL(state->vwv + 13, 0, 0);
2085 additional_flags = 0;
2087 if (cli->use_oplocks) {
2088 /* if using oplocks then ask for a batch oplock via
2089 core and extended methods */
2090 additional_flags =
2091 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2092 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2095 bytes = talloc_array(state, uint8_t, 0);
2096 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
2097 strlen(fname)+1, NULL);
2099 if (tevent_req_nomem(bytes, req)) {
2100 return tevent_req_post(req, ev);
2103 state->bytes.iov_base = (void *)bytes;
2104 state->bytes.iov_len = talloc_get_size(bytes);
2106 subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2107 15, state->vwv, 1, &state->bytes);
2108 if (subreq == NULL) {
2109 TALLOC_FREE(req);
2110 return NULL;
2112 tevent_req_set_callback(subreq, cli_open_done, req);
2113 *psmbreq = subreq;
2114 return req;
2117 struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
2118 struct cli_state *cli, const char *fname,
2119 int flags, int share_mode)
2121 struct tevent_req *req, *subreq;
2122 NTSTATUS status;
2124 req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode,
2125 &subreq);
2126 if (req == NULL) {
2127 return NULL;
2130 status = cli_smb_req_send(subreq);
2131 if (!NT_STATUS_IS_OK(status)) {
2132 tevent_req_nterror(req, status);
2133 return tevent_req_post(req, ev);
2135 return req;
2138 static void cli_open_done(struct tevent_req *subreq)
2140 struct tevent_req *req = tevent_req_callback_data(
2141 subreq, struct tevent_req);
2142 struct cli_open_state *state = tevent_req_data(
2143 req, struct cli_open_state);
2144 uint8_t wct;
2145 uint16_t *vwv;
2146 uint8_t *inbuf;
2147 NTSTATUS status;
2149 status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv, NULL,
2150 NULL);
2151 TALLOC_FREE(subreq);
2152 if (!NT_STATUS_IS_OK(status)) {
2153 tevent_req_nterror(req, status);
2154 return;
2156 state->fnum = SVAL(vwv+2, 0);
2157 tevent_req_done(req);
2160 NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum)
2162 struct cli_open_state *state = tevent_req_data(
2163 req, struct cli_open_state);
2164 NTSTATUS status;
2166 if (tevent_req_is_nterror(req, &status)) {
2167 return status;
2169 *pfnum = state->fnum;
2170 return NT_STATUS_OK;
2173 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2174 int share_mode, uint16_t *pfnum)
2176 TALLOC_CTX *frame = talloc_stackframe();
2177 struct event_context *ev;
2178 struct tevent_req *req;
2179 NTSTATUS status = NT_STATUS_OK;
2181 if (cli_has_async_calls(cli)) {
2183 * Can't use sync call while an async call is in flight
2185 status = NT_STATUS_INVALID_PARAMETER;
2186 goto fail;
2189 ev = event_context_init(frame);
2190 if (ev == NULL) {
2191 status = NT_STATUS_NO_MEMORY;
2192 goto fail;
2195 req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
2196 if (req == NULL) {
2197 status = NT_STATUS_NO_MEMORY;
2198 goto fail;
2201 if (!tevent_req_poll(req, ev)) {
2202 status = map_nt_error_from_unix(errno);
2203 goto fail;
2206 status = cli_open_recv(req, pfnum);
2207 fail:
2208 TALLOC_FREE(frame);
2209 if (!NT_STATUS_IS_OK(status)) {
2210 cli_set_error(cli, status);
2212 return status;
2215 /****************************************************************************
2216 Close a file.
2217 ****************************************************************************/
2219 struct cli_close_state {
2220 uint16_t vwv[3];
2223 static void cli_close_done(struct tevent_req *subreq);
2225 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2226 struct event_context *ev,
2227 struct cli_state *cli,
2228 uint16_t fnum,
2229 struct tevent_req **psubreq)
2231 struct tevent_req *req, *subreq;
2232 struct cli_close_state *state;
2234 req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2235 if (req == NULL) {
2236 return NULL;
2239 SSVAL(state->vwv+0, 0, fnum);
2240 SIVALS(state->vwv+1, 0, -1);
2242 subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2243 0, NULL);
2244 if (subreq == NULL) {
2245 TALLOC_FREE(req);
2246 return NULL;
2248 tevent_req_set_callback(subreq, cli_close_done, req);
2249 *psubreq = subreq;
2250 return req;
2253 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2254 struct event_context *ev,
2255 struct cli_state *cli,
2256 uint16_t fnum)
2258 struct tevent_req *req, *subreq;
2259 NTSTATUS status;
2261 req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2262 if (req == NULL) {
2263 return NULL;
2266 status = cli_smb_req_send(subreq);
2267 if (!NT_STATUS_IS_OK(status)) {
2268 tevent_req_nterror(req, status);
2269 return tevent_req_post(req, ev);
2271 return req;
2274 static void cli_close_done(struct tevent_req *subreq)
2276 struct tevent_req *req = tevent_req_callback_data(
2277 subreq, struct tevent_req);
2278 NTSTATUS status;
2280 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2281 TALLOC_FREE(subreq);
2282 if (!NT_STATUS_IS_OK(status)) {
2283 tevent_req_nterror(req, status);
2284 return;
2286 tevent_req_done(req);
2289 NTSTATUS cli_close_recv(struct tevent_req *req)
2291 return tevent_req_simple_recv_ntstatus(req);
2294 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2296 TALLOC_CTX *frame = talloc_stackframe();
2297 struct event_context *ev;
2298 struct tevent_req *req;
2299 NTSTATUS status = NT_STATUS_OK;
2301 if (cli_has_async_calls(cli)) {
2303 * Can't use sync call while an async call is in flight
2305 status = NT_STATUS_INVALID_PARAMETER;
2306 goto fail;
2309 ev = event_context_init(frame);
2310 if (ev == NULL) {
2311 status = NT_STATUS_NO_MEMORY;
2312 goto fail;
2315 req = cli_close_send(frame, ev, cli, fnum);
2316 if (req == NULL) {
2317 status = NT_STATUS_NO_MEMORY;
2318 goto fail;
2321 if (!tevent_req_poll(req, ev)) {
2322 status = map_nt_error_from_unix(errno);
2323 goto fail;
2326 status = cli_close_recv(req);
2327 fail:
2328 TALLOC_FREE(frame);
2329 if (!NT_STATUS_IS_OK(status)) {
2330 cli_set_error(cli, status);
2332 return status;
2335 /****************************************************************************
2336 Truncate a file to a specified size
2337 ****************************************************************************/
2339 struct ftrunc_state {
2340 uint16_t setup;
2341 uint8_t param[6];
2342 uint8_t data[8];
2345 static void cli_ftruncate_done(struct tevent_req *subreq)
2347 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
2348 NULL, 0, NULL, NULL, 0, NULL);
2349 tevent_req_simple_finish_ntstatus(subreq, status);
2352 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2353 struct event_context *ev,
2354 struct cli_state *cli,
2355 uint16_t fnum,
2356 uint64_t size)
2358 struct tevent_req *req = NULL, *subreq = NULL;
2359 struct ftrunc_state *state = NULL;
2361 req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2362 if (req == NULL) {
2363 return NULL;
2366 /* Setup setup word. */
2367 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2369 /* Setup param array. */
2370 SSVAL(state->param,0,fnum);
2371 SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2372 SSVAL(state->param,4,0);
2374 /* Setup data array. */
2375 SBVAL(state->data, 0, size);
2377 subreq = cli_trans_send(state, /* mem ctx. */
2378 ev, /* event ctx. */
2379 cli, /* cli_state. */
2380 SMBtrans2, /* cmd. */
2381 NULL, /* pipe name. */
2382 -1, /* fid. */
2383 0, /* function. */
2384 0, /* flags. */
2385 &state->setup, /* setup. */
2386 1, /* num setup uint16_t words. */
2387 0, /* max returned setup. */
2388 state->param, /* param. */
2389 6, /* num param. */
2390 2, /* max returned param. */
2391 state->data, /* data. */
2392 8, /* num data. */
2393 0); /* max returned data. */
2395 if (tevent_req_nomem(subreq, req)) {
2396 return tevent_req_post(req, ev);
2398 tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2399 return req;
2402 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2404 NTSTATUS status;
2406 if (tevent_req_is_nterror(req, &status)) {
2407 return status;
2409 return NT_STATUS_OK;
2412 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2414 TALLOC_CTX *frame = talloc_stackframe();
2415 struct event_context *ev = NULL;
2416 struct tevent_req *req = NULL;
2417 NTSTATUS status = NT_STATUS_OK;
2419 if (cli_has_async_calls(cli)) {
2421 * Can't use sync call while an async call is in flight
2423 status = NT_STATUS_INVALID_PARAMETER;
2424 goto fail;
2427 ev = event_context_init(frame);
2428 if (ev == NULL) {
2429 status = NT_STATUS_NO_MEMORY;
2430 goto fail;
2433 req = cli_ftruncate_send(frame,
2435 cli,
2436 fnum,
2437 size);
2438 if (req == NULL) {
2439 status = NT_STATUS_NO_MEMORY;
2440 goto fail;
2443 if (!tevent_req_poll(req, ev)) {
2444 status = map_nt_error_from_unix(errno);
2445 goto fail;
2448 status = cli_ftruncate_recv(req);
2450 fail:
2451 TALLOC_FREE(frame);
2452 if (!NT_STATUS_IS_OK(status)) {
2453 cli_set_error(cli, status);
2455 return status;
2458 /****************************************************************************
2459 send a lock with a specified locktype
2460 this is used for testing LOCKING_ANDX_CANCEL_LOCK
2461 ****************************************************************************/
2463 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2464 uint32_t offset, uint32_t len,
2465 int timeout, unsigned char locktype)
2467 char *p;
2468 int saved_timeout = cli->timeout;
2470 memset(cli->outbuf,'\0',smb_size);
2471 memset(cli->inbuf,'\0', smb_size);
2473 cli_set_message(cli->outbuf,8,0,True);
2475 SCVAL(cli->outbuf,smb_com,SMBlockingX);
2476 SSVAL(cli->outbuf,smb_tid,cli->cnum);
2477 cli_setup_packet(cli);
2479 SCVAL(cli->outbuf,smb_vwv0,0xFF);
2480 SSVAL(cli->outbuf,smb_vwv2,fnum);
2481 SCVAL(cli->outbuf,smb_vwv3,locktype);
2482 SIVALS(cli->outbuf, smb_vwv4, timeout);
2483 SSVAL(cli->outbuf,smb_vwv6,0);
2484 SSVAL(cli->outbuf,smb_vwv7,1);
2486 p = smb_buf(cli->outbuf);
2487 SSVAL(p, 0, cli->pid);
2488 SIVAL(p, 2, offset);
2489 SIVAL(p, 6, len);
2491 p += 10;
2493 cli_setup_bcc(cli, p);
2495 cli_send_smb(cli);
2497 if (timeout != 0) {
2498 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
2501 if (!cli_receive_smb(cli)) {
2502 cli->timeout = saved_timeout;
2503 return NT_STATUS_UNSUCCESSFUL;
2506 cli->timeout = saved_timeout;
2508 return cli_nt_error(cli);
2511 /****************************************************************************
2512 Lock a file.
2513 note that timeout is in units of 2 milliseconds
2514 ****************************************************************************/
2516 bool cli_lock(struct cli_state *cli, uint16_t fnum,
2517 uint32_t offset, uint32_t len, int timeout, enum brl_type lock_type)
2519 char *p;
2520 int saved_timeout = cli->timeout;
2522 memset(cli->outbuf,'\0',smb_size);
2523 memset(cli->inbuf,'\0', smb_size);
2525 cli_set_message(cli->outbuf,8,0,True);
2527 SCVAL(cli->outbuf,smb_com,SMBlockingX);
2528 SSVAL(cli->outbuf,smb_tid,cli->cnum);
2529 cli_setup_packet(cli);
2531 SCVAL(cli->outbuf,smb_vwv0,0xFF);
2532 SSVAL(cli->outbuf,smb_vwv2,fnum);
2533 SCVAL(cli->outbuf,smb_vwv3,(lock_type == READ_LOCK? 1 : 0));
2534 SIVALS(cli->outbuf, smb_vwv4, timeout);
2535 SSVAL(cli->outbuf,smb_vwv6,0);
2536 SSVAL(cli->outbuf,smb_vwv7,1);
2538 p = smb_buf(cli->outbuf);
2539 SSVAL(p, 0, cli->pid);
2540 SIVAL(p, 2, offset);
2541 SIVAL(p, 6, len);
2543 p += 10;
2545 cli_setup_bcc(cli, p);
2547 cli_send_smb(cli);
2549 if (timeout != 0) {
2550 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout*2 + 5*1000);
2553 if (!cli_receive_smb(cli)) {
2554 cli->timeout = saved_timeout;
2555 return False;
2558 cli->timeout = saved_timeout;
2560 if (cli_is_error(cli)) {
2561 return False;
2564 return True;
2567 /****************************************************************************
2568 Unlock a file.
2569 ****************************************************************************/
2571 struct cli_unlock_state {
2572 uint16_t vwv[8];
2573 uint8_t data[10];
2576 static void cli_unlock_done(struct tevent_req *subreq);
2578 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
2579 struct event_context *ev,
2580 struct cli_state *cli,
2581 uint16_t fnum,
2582 uint64_t offset,
2583 uint64_t len)
2586 struct tevent_req *req = NULL, *subreq = NULL;
2587 struct cli_unlock_state *state = NULL;
2588 uint8_t additional_flags = 0;
2590 req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
2591 if (req == NULL) {
2592 return NULL;
2595 SCVAL(state->vwv+0, 0, 0xFF);
2596 SSVAL(state->vwv+2, 0, fnum);
2597 SCVAL(state->vwv+3, 0, 0);
2598 SIVALS(state->vwv+4, 0, 0);
2599 SSVAL(state->vwv+6, 0, 1);
2600 SSVAL(state->vwv+7, 0, 0);
2602 SSVAL(state->data, 0, cli->pid);
2603 SIVAL(state->data, 2, offset);
2604 SIVAL(state->data, 6, len);
2606 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2607 8, state->vwv, 10, state->data);
2608 if (tevent_req_nomem(subreq, req)) {
2609 return tevent_req_post(req, ev);
2611 tevent_req_set_callback(subreq, cli_unlock_done, req);
2612 return req;
2615 static void cli_unlock_done(struct tevent_req *subreq)
2617 struct tevent_req *req = tevent_req_callback_data(
2618 subreq, struct tevent_req);
2619 NTSTATUS status;
2621 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2622 TALLOC_FREE(subreq);
2623 if (!NT_STATUS_IS_OK(status)) {
2624 tevent_req_nterror(req, status);
2625 return;
2627 tevent_req_done(req);
2630 NTSTATUS cli_unlock_recv(struct tevent_req *req)
2632 return tevent_req_simple_recv_ntstatus(req);
2635 NTSTATUS cli_unlock(struct cli_state *cli,
2636 uint16_t fnum,
2637 uint32_t offset,
2638 uint32_t len)
2640 TALLOC_CTX *frame = talloc_stackframe();
2641 struct event_context *ev;
2642 struct tevent_req *req;
2643 NTSTATUS status = NT_STATUS_OK;
2645 if (cli_has_async_calls(cli)) {
2647 * Can't use sync call while an async call is in flight
2649 status = NT_STATUS_INVALID_PARAMETER;
2650 goto fail;
2653 ev = event_context_init(frame);
2654 if (ev == NULL) {
2655 status = NT_STATUS_NO_MEMORY;
2656 goto fail;
2659 req = cli_unlock_send(frame, ev, cli,
2660 fnum, offset, len);
2661 if (req == NULL) {
2662 status = NT_STATUS_NO_MEMORY;
2663 goto fail;
2666 if (!tevent_req_poll(req, ev)) {
2667 status = map_nt_error_from_unix(errno);
2668 goto fail;
2671 status = cli_unlock_recv(req);
2673 fail:
2674 TALLOC_FREE(frame);
2675 if (!NT_STATUS_IS_OK(status)) {
2676 cli_set_error(cli, status);
2678 return status;
2681 /****************************************************************************
2682 Lock a file with 64 bit offsets.
2683 ****************************************************************************/
2685 bool cli_lock64(struct cli_state *cli, uint16_t fnum,
2686 uint64_t offset, uint64_t len, int timeout, enum brl_type lock_type)
2688 char *p;
2689 int saved_timeout = cli->timeout;
2690 int ltype;
2692 if (! (cli->capabilities & CAP_LARGE_FILES)) {
2693 return cli_lock(cli, fnum, offset, len, timeout, lock_type);
2696 ltype = (lock_type == READ_LOCK? 1 : 0);
2697 ltype |= LOCKING_ANDX_LARGE_FILES;
2699 memset(cli->outbuf,'\0',smb_size);
2700 memset(cli->inbuf,'\0', smb_size);
2702 cli_set_message(cli->outbuf,8,0,True);
2704 SCVAL(cli->outbuf,smb_com,SMBlockingX);
2705 SSVAL(cli->outbuf,smb_tid,cli->cnum);
2706 cli_setup_packet(cli);
2708 SCVAL(cli->outbuf,smb_vwv0,0xFF);
2709 SSVAL(cli->outbuf,smb_vwv2,fnum);
2710 SCVAL(cli->outbuf,smb_vwv3,ltype);
2711 SIVALS(cli->outbuf, smb_vwv4, timeout);
2712 SSVAL(cli->outbuf,smb_vwv6,0);
2713 SSVAL(cli->outbuf,smb_vwv7,1);
2715 p = smb_buf(cli->outbuf);
2716 SIVAL(p, 0, cli->pid);
2717 SOFF_T_R(p, 4, offset);
2718 SOFF_T_R(p, 12, len);
2719 p += 20;
2721 cli_setup_bcc(cli, p);
2722 cli_send_smb(cli);
2724 if (timeout != 0) {
2725 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 5*1000);
2728 if (!cli_receive_smb(cli)) {
2729 cli->timeout = saved_timeout;
2730 return False;
2733 cli->timeout = saved_timeout;
2735 if (cli_is_error(cli)) {
2736 return False;
2739 return True;
2742 /****************************************************************************
2743 Unlock a file with 64 bit offsets.
2744 ****************************************************************************/
2746 struct cli_unlock64_state {
2747 uint16_t vwv[8];
2748 uint8_t data[20];
2751 static void cli_unlock64_done(struct tevent_req *subreq);
2753 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
2754 struct event_context *ev,
2755 struct cli_state *cli,
2756 uint16_t fnum,
2757 uint64_t offset,
2758 uint64_t len)
2761 struct tevent_req *req = NULL, *subreq = NULL;
2762 struct cli_unlock64_state *state = NULL;
2763 uint8_t additional_flags = 0;
2765 req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
2766 if (req == NULL) {
2767 return NULL;
2770 SCVAL(state->vwv+0, 0, 0xff);
2771 SSVAL(state->vwv+2, 0, fnum);
2772 SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
2773 SIVALS(state->vwv+4, 0, 0);
2774 SSVAL(state->vwv+6, 0, 1);
2775 SSVAL(state->vwv+7, 0, 0);
2777 SIVAL(state->data, 0, cli->pid);
2778 SOFF_T_R(state->data, 4, offset);
2779 SOFF_T_R(state->data, 12, len);
2781 subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2782 8, state->vwv, 20, state->data);
2783 if (tevent_req_nomem(subreq, req)) {
2784 return tevent_req_post(req, ev);
2786 tevent_req_set_callback(subreq, cli_unlock64_done, req);
2787 return req;
2790 static void cli_unlock64_done(struct tevent_req *subreq)
2792 struct tevent_req *req = tevent_req_callback_data(
2793 subreq, struct tevent_req);
2794 NTSTATUS status;
2796 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2797 TALLOC_FREE(subreq);
2798 if (!NT_STATUS_IS_OK(status)) {
2799 tevent_req_nterror(req, status);
2800 return;
2802 tevent_req_done(req);
2805 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
2807 return tevent_req_simple_recv_ntstatus(req);
2810 NTSTATUS cli_unlock64(struct cli_state *cli,
2811 uint16_t fnum,
2812 uint64_t offset,
2813 uint64_t len)
2815 TALLOC_CTX *frame = talloc_stackframe();
2816 struct event_context *ev;
2817 struct tevent_req *req;
2818 NTSTATUS status = NT_STATUS_OK;
2820 if (! (cli->capabilities & CAP_LARGE_FILES)) {
2821 return cli_unlock(cli, fnum, offset, len);
2824 if (cli_has_async_calls(cli)) {
2826 * Can't use sync call while an async call is in flight
2828 status = NT_STATUS_INVALID_PARAMETER;
2829 goto fail;
2832 ev = event_context_init(frame);
2833 if (ev == NULL) {
2834 status = NT_STATUS_NO_MEMORY;
2835 goto fail;
2838 req = cli_unlock64_send(frame, ev, cli,
2839 fnum, offset, len);
2840 if (req == NULL) {
2841 status = NT_STATUS_NO_MEMORY;
2842 goto fail;
2845 if (!tevent_req_poll(req, ev)) {
2846 status = map_nt_error_from_unix(errno);
2847 goto fail;
2850 status = cli_unlock64_recv(req);
2852 fail:
2853 TALLOC_FREE(frame);
2854 if (!NT_STATUS_IS_OK(status)) {
2855 cli_set_error(cli, status);
2857 return status;
2860 /****************************************************************************
2861 Get/unlock a POSIX lock on a file - internal function.
2862 ****************************************************************************/
2864 struct posix_lock_state {
2865 uint16_t setup;
2866 uint8_t param[4];
2867 uint8_t data[POSIX_LOCK_DATA_SIZE];
2870 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
2872 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
2873 NULL, 0, NULL, NULL, 0, NULL);
2874 tevent_req_simple_finish_ntstatus(subreq, status);
2877 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
2878 struct event_context *ev,
2879 struct cli_state *cli,
2880 uint16_t fnum,
2881 uint64_t offset,
2882 uint64_t len,
2883 bool wait_lock,
2884 enum brl_type lock_type)
2886 struct tevent_req *req = NULL, *subreq = NULL;
2887 struct posix_lock_state *state = NULL;
2889 req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
2890 if (req == NULL) {
2891 return NULL;
2894 /* Setup setup word. */
2895 SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2897 /* Setup param array. */
2898 SSVAL(&state->param, 0, fnum);
2899 SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
2901 /* Setup data array. */
2902 switch (lock_type) {
2903 case READ_LOCK:
2904 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2905 POSIX_LOCK_TYPE_READ);
2906 break;
2907 case WRITE_LOCK:
2908 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2909 POSIX_LOCK_TYPE_WRITE);
2910 break;
2911 case UNLOCK_LOCK:
2912 SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2913 POSIX_LOCK_TYPE_UNLOCK);
2914 break;
2915 default:
2916 return NULL;
2919 if (wait_lock) {
2920 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
2921 POSIX_LOCK_FLAG_WAIT);
2922 } else {
2923 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
2924 POSIX_LOCK_FLAG_NOWAIT);
2927 SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli->pid);
2928 SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
2929 SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
2931 subreq = cli_trans_send(state, /* mem ctx. */
2932 ev, /* event ctx. */
2933 cli, /* cli_state. */
2934 SMBtrans2, /* cmd. */
2935 NULL, /* pipe name. */
2936 -1, /* fid. */
2937 0, /* function. */
2938 0, /* flags. */
2939 &state->setup, /* setup. */
2940 1, /* num setup uint16_t words. */
2941 0, /* max returned setup. */
2942 state->param, /* param. */
2943 4, /* num param. */
2944 2, /* max returned param. */
2945 state->data, /* data. */
2946 POSIX_LOCK_DATA_SIZE, /* num data. */
2947 0); /* max returned data. */
2949 if (tevent_req_nomem(subreq, req)) {
2950 return tevent_req_post(req, ev);
2952 tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
2953 return req;
2956 /****************************************************************************
2957 POSIX Lock a file.
2958 ****************************************************************************/
2960 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
2961 struct event_context *ev,
2962 struct cli_state *cli,
2963 uint16_t fnum,
2964 uint64_t offset,
2965 uint64_t len,
2966 bool wait_lock,
2967 enum brl_type lock_type)
2969 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
2970 wait_lock, lock_type);
2973 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
2975 NTSTATUS status;
2977 if (tevent_req_is_nterror(req, &status)) {
2978 return status;
2980 return NT_STATUS_OK;
2983 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
2984 uint64_t offset, uint64_t len,
2985 bool wait_lock, enum brl_type lock_type)
2987 TALLOC_CTX *frame = talloc_stackframe();
2988 struct event_context *ev = NULL;
2989 struct tevent_req *req = NULL;
2990 NTSTATUS status = NT_STATUS_OK;
2992 if (cli_has_async_calls(cli)) {
2994 * Can't use sync call while an async call is in flight
2996 status = NT_STATUS_INVALID_PARAMETER;
2997 goto fail;
3000 if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3001 status = NT_STATUS_INVALID_PARAMETER;
3002 goto fail;
3005 ev = event_context_init(frame);
3006 if (ev == NULL) {
3007 status = NT_STATUS_NO_MEMORY;
3008 goto fail;
3011 req = cli_posix_lock_send(frame,
3013 cli,
3014 fnum,
3015 offset,
3016 len,
3017 wait_lock,
3018 lock_type);
3019 if (req == NULL) {
3020 status = NT_STATUS_NO_MEMORY;
3021 goto fail;
3024 if (!tevent_req_poll(req, ev)) {
3025 status = map_nt_error_from_unix(errno);
3026 goto fail;
3029 status = cli_posix_lock_recv(req);
3031 fail:
3032 TALLOC_FREE(frame);
3033 if (!NT_STATUS_IS_OK(status)) {
3034 cli_set_error(cli, status);
3036 return status;
3039 /****************************************************************************
3040 POSIX Unlock a file.
3041 ****************************************************************************/
3043 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3044 struct event_context *ev,
3045 struct cli_state *cli,
3046 uint16_t fnum,
3047 uint64_t offset,
3048 uint64_t len)
3050 return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3051 false, UNLOCK_LOCK);
3054 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3056 NTSTATUS status;
3058 if (tevent_req_is_nterror(req, &status)) {
3059 return status;
3061 return NT_STATUS_OK;
3064 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3066 TALLOC_CTX *frame = talloc_stackframe();
3067 struct event_context *ev = NULL;
3068 struct tevent_req *req = NULL;
3069 NTSTATUS status = NT_STATUS_OK;
3071 if (cli_has_async_calls(cli)) {
3073 * Can't use sync call while an async call is in flight
3075 status = NT_STATUS_INVALID_PARAMETER;
3076 goto fail;
3079 ev = event_context_init(frame);
3080 if (ev == NULL) {
3081 status = NT_STATUS_NO_MEMORY;
3082 goto fail;
3085 req = cli_posix_unlock_send(frame,
3087 cli,
3088 fnum,
3089 offset,
3090 len);
3091 if (req == NULL) {
3092 status = NT_STATUS_NO_MEMORY;
3093 goto fail;
3096 if (!tevent_req_poll(req, ev)) {
3097 status = map_nt_error_from_unix(errno);
3098 goto fail;
3101 status = cli_posix_unlock_recv(req);
3103 fail:
3104 TALLOC_FREE(frame);
3105 if (!NT_STATUS_IS_OK(status)) {
3106 cli_set_error(cli, status);
3108 return status;
3111 /****************************************************************************
3112 Do a SMBgetattrE call.
3113 ****************************************************************************/
3115 static void cli_getattrE_done(struct tevent_req *subreq);
3117 struct cli_getattrE_state {
3118 uint16_t vwv[1];
3119 int zone_offset;
3120 uint16_t attr;
3121 SMB_OFF_T size;
3122 time_t change_time;
3123 time_t access_time;
3124 time_t write_time;
3127 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3128 struct event_context *ev,
3129 struct cli_state *cli,
3130 uint16_t fnum)
3132 struct tevent_req *req = NULL, *subreq = NULL;
3133 struct cli_getattrE_state *state = NULL;
3134 uint8_t additional_flags = 0;
3136 req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3137 if (req == NULL) {
3138 return NULL;
3141 state->zone_offset = cli->serverzone;
3142 SSVAL(state->vwv+0,0,fnum);
3144 subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
3145 1, state->vwv, 0, NULL);
3146 if (tevent_req_nomem(subreq, req)) {
3147 return tevent_req_post(req, ev);
3149 tevent_req_set_callback(subreq, cli_getattrE_done, req);
3150 return req;
3153 static void cli_getattrE_done(struct tevent_req *subreq)
3155 struct tevent_req *req = tevent_req_callback_data(
3156 subreq, struct tevent_req);
3157 struct cli_getattrE_state *state = tevent_req_data(
3158 req, struct cli_getattrE_state);
3159 uint8_t wct;
3160 uint16_t *vwv = NULL;
3161 uint8_t *inbuf;
3162 NTSTATUS status;
3164 status = cli_smb_recv(subreq, state, &inbuf, 11, &wct, &vwv,
3165 NULL, NULL);
3166 TALLOC_FREE(subreq);
3167 if (!NT_STATUS_IS_OK(status)) {
3168 tevent_req_nterror(req, status);
3169 return;
3172 state->size = (SMB_OFF_T)IVAL(vwv+6,0);
3173 state->attr = SVAL(vwv+10,0);
3174 state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3175 state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3176 state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3178 tevent_req_done(req);
3181 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3182 uint16_t *attr,
3183 SMB_OFF_T *size,
3184 time_t *change_time,
3185 time_t *access_time,
3186 time_t *write_time)
3188 struct cli_getattrE_state *state = tevent_req_data(
3189 req, struct cli_getattrE_state);
3190 NTSTATUS status;
3192 if (tevent_req_is_nterror(req, &status)) {
3193 return status;
3195 if (attr) {
3196 *attr = state->attr;
3198 if (size) {
3199 *size = state->size;
3201 if (change_time) {
3202 *change_time = state->change_time;
3204 if (access_time) {
3205 *access_time = state->access_time;
3207 if (write_time) {
3208 *write_time = state->write_time;
3210 return NT_STATUS_OK;
3213 NTSTATUS cli_getattrE(struct cli_state *cli,
3214 uint16_t fnum,
3215 uint16_t *attr,
3216 SMB_OFF_T *size,
3217 time_t *change_time,
3218 time_t *access_time,
3219 time_t *write_time)
3221 TALLOC_CTX *frame = talloc_stackframe();
3222 struct event_context *ev = NULL;
3223 struct tevent_req *req = NULL;
3224 NTSTATUS status = NT_STATUS_OK;
3226 if (cli_has_async_calls(cli)) {
3228 * Can't use sync call while an async call is in flight
3230 status = NT_STATUS_INVALID_PARAMETER;
3231 goto fail;
3234 ev = event_context_init(frame);
3235 if (ev == NULL) {
3236 status = NT_STATUS_NO_MEMORY;
3237 goto fail;
3240 req = cli_getattrE_send(frame, ev, cli, fnum);
3241 if (req == NULL) {
3242 status = NT_STATUS_NO_MEMORY;
3243 goto fail;
3246 if (!tevent_req_poll(req, ev)) {
3247 status = map_nt_error_from_unix(errno);
3248 goto fail;
3251 status = cli_getattrE_recv(req,
3252 attr,
3253 size,
3254 change_time,
3255 access_time,
3256 write_time);
3258 fail:
3259 TALLOC_FREE(frame);
3260 if (!NT_STATUS_IS_OK(status)) {
3261 cli_set_error(cli, status);
3263 return status;
3266 /****************************************************************************
3267 Do a SMBgetatr call
3268 ****************************************************************************/
3270 static void cli_getatr_done(struct tevent_req *subreq);
3272 struct cli_getatr_state {
3273 int zone_offset;
3274 uint16_t attr;
3275 SMB_OFF_T size;
3276 time_t write_time;
3279 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3280 struct event_context *ev,
3281 struct cli_state *cli,
3282 const char *fname)
3284 struct tevent_req *req = NULL, *subreq = NULL;
3285 struct cli_getatr_state *state = NULL;
3286 uint8_t additional_flags = 0;
3287 uint8_t *bytes = NULL;
3289 req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3290 if (req == NULL) {
3291 return NULL;
3294 state->zone_offset = cli->serverzone;
3296 bytes = talloc_array(state, uint8_t, 1);
3297 if (tevent_req_nomem(bytes, req)) {
3298 return tevent_req_post(req, ev);
3300 bytes[0] = 4;
3301 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3302 strlen(fname)+1, NULL);
3304 if (tevent_req_nomem(bytes, req)) {
3305 return tevent_req_post(req, ev);
3308 subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3309 0, NULL, talloc_get_size(bytes), bytes);
3310 if (tevent_req_nomem(subreq, req)) {
3311 return tevent_req_post(req, ev);
3313 tevent_req_set_callback(subreq, cli_getatr_done, req);
3314 return req;
3317 static void cli_getatr_done(struct tevent_req *subreq)
3319 struct tevent_req *req = tevent_req_callback_data(
3320 subreq, struct tevent_req);
3321 struct cli_getatr_state *state = tevent_req_data(
3322 req, struct cli_getatr_state);
3323 uint8_t wct;
3324 uint16_t *vwv = NULL;
3325 uint8_t *inbuf;
3326 NTSTATUS status;
3328 status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3329 NULL);
3330 TALLOC_FREE(subreq);
3331 if (!NT_STATUS_IS_OK(status)) {
3332 tevent_req_nterror(req, status);
3333 return;
3336 state->attr = SVAL(vwv+0,0);
3337 state->size = (SMB_OFF_T)IVAL(vwv+3,0);
3338 state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3340 tevent_req_done(req);
3343 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3344 uint16_t *attr,
3345 SMB_OFF_T *size,
3346 time_t *write_time)
3348 struct cli_getatr_state *state = tevent_req_data(
3349 req, struct cli_getatr_state);
3350 NTSTATUS status;
3352 if (tevent_req_is_nterror(req, &status)) {
3353 return status;
3355 if (attr) {
3356 *attr = state->attr;
3358 if (size) {
3359 *size = state->size;
3361 if (write_time) {
3362 *write_time = state->write_time;
3364 return NT_STATUS_OK;
3367 NTSTATUS cli_getatr(struct cli_state *cli,
3368 const char *fname,
3369 uint16_t *attr,
3370 SMB_OFF_T *size,
3371 time_t *write_time)
3373 TALLOC_CTX *frame = talloc_stackframe();
3374 struct event_context *ev = NULL;
3375 struct tevent_req *req = NULL;
3376 NTSTATUS status = NT_STATUS_OK;
3378 if (cli_has_async_calls(cli)) {
3380 * Can't use sync call while an async call is in flight
3382 status = NT_STATUS_INVALID_PARAMETER;
3383 goto fail;
3386 ev = event_context_init(frame);
3387 if (ev == NULL) {
3388 status = NT_STATUS_NO_MEMORY;
3389 goto fail;
3392 req = cli_getatr_send(frame, ev, cli, fname);
3393 if (req == NULL) {
3394 status = NT_STATUS_NO_MEMORY;
3395 goto fail;
3398 if (!tevent_req_poll(req, ev)) {
3399 status = map_nt_error_from_unix(errno);
3400 goto fail;
3403 status = cli_getatr_recv(req,
3404 attr,
3405 size,
3406 write_time);
3408 fail:
3409 TALLOC_FREE(frame);
3410 if (!NT_STATUS_IS_OK(status)) {
3411 cli_set_error(cli, status);
3413 return status;
3416 /****************************************************************************
3417 Do a SMBsetattrE call.
3418 ****************************************************************************/
3420 static void cli_setattrE_done(struct tevent_req *subreq);
3422 struct cli_setattrE_state {
3423 uint16_t vwv[7];
3426 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3427 struct event_context *ev,
3428 struct cli_state *cli,
3429 uint16_t fnum,
3430 time_t change_time,
3431 time_t access_time,
3432 time_t write_time)
3434 struct tevent_req *req = NULL, *subreq = NULL;
3435 struct cli_setattrE_state *state = NULL;
3436 uint8_t additional_flags = 0;
3438 req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3439 if (req == NULL) {
3440 return NULL;
3443 SSVAL(state->vwv+0, 0, fnum);
3444 cli_put_dos_date2(cli, (char *)&state->vwv[1], 0, change_time);
3445 cli_put_dos_date2(cli, (char *)&state->vwv[3], 0, access_time);
3446 cli_put_dos_date2(cli, (char *)&state->vwv[5], 0, write_time);
3448 subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3449 7, state->vwv, 0, NULL);
3450 if (tevent_req_nomem(subreq, req)) {
3451 return tevent_req_post(req, ev);
3453 tevent_req_set_callback(subreq, cli_setattrE_done, req);
3454 return req;
3457 static void cli_setattrE_done(struct tevent_req *subreq)
3459 struct tevent_req *req = tevent_req_callback_data(
3460 subreq, struct tevent_req);
3461 NTSTATUS status;
3463 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3464 TALLOC_FREE(subreq);
3465 if (!NT_STATUS_IS_OK(status)) {
3466 tevent_req_nterror(req, status);
3467 return;
3469 tevent_req_done(req);
3472 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3474 return tevent_req_simple_recv_ntstatus(req);
3477 NTSTATUS cli_setattrE(struct cli_state *cli,
3478 uint16_t fnum,
3479 time_t change_time,
3480 time_t access_time,
3481 time_t write_time)
3483 TALLOC_CTX *frame = talloc_stackframe();
3484 struct event_context *ev = NULL;
3485 struct tevent_req *req = NULL;
3486 NTSTATUS status = NT_STATUS_OK;
3488 if (cli_has_async_calls(cli)) {
3490 * Can't use sync call while an async call is in flight
3492 status = NT_STATUS_INVALID_PARAMETER;
3493 goto fail;
3496 ev = event_context_init(frame);
3497 if (ev == NULL) {
3498 status = NT_STATUS_NO_MEMORY;
3499 goto fail;
3502 req = cli_setattrE_send(frame, ev,
3503 cli,
3504 fnum,
3505 change_time,
3506 access_time,
3507 write_time);
3509 if (req == NULL) {
3510 status = NT_STATUS_NO_MEMORY;
3511 goto fail;
3514 if (!tevent_req_poll(req, ev)) {
3515 status = map_nt_error_from_unix(errno);
3516 goto fail;
3519 status = cli_setattrE_recv(req);
3521 fail:
3522 TALLOC_FREE(frame);
3523 if (!NT_STATUS_IS_OK(status)) {
3524 cli_set_error(cli, status);
3526 return status;
3529 /****************************************************************************
3530 Do a SMBsetatr call.
3531 ****************************************************************************/
3533 static void cli_setatr_done(struct tevent_req *subreq);
3535 struct cli_setatr_state {
3536 uint16_t vwv[8];
3539 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3540 struct event_context *ev,
3541 struct cli_state *cli,
3542 const char *fname,
3543 uint16_t attr,
3544 time_t mtime)
3546 struct tevent_req *req = NULL, *subreq = NULL;
3547 struct cli_setatr_state *state = NULL;
3548 uint8_t additional_flags = 0;
3549 uint8_t *bytes = NULL;
3551 req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3552 if (req == NULL) {
3553 return NULL;
3556 SSVAL(state->vwv+0, 0, attr);
3557 cli_put_dos_date3(cli, (char *)&state->vwv[1], 0, mtime);
3559 bytes = talloc_array(state, uint8_t, 1);
3560 if (tevent_req_nomem(bytes, req)) {
3561 return tevent_req_post(req, ev);
3563 bytes[0] = 4;
3564 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3565 strlen(fname)+1, NULL);
3566 if (tevent_req_nomem(bytes, req)) {
3567 return tevent_req_post(req, ev);
3569 bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
3570 talloc_get_size(bytes)+1);
3571 if (tevent_req_nomem(bytes, req)) {
3572 return tevent_req_post(req, ev);
3575 bytes[talloc_get_size(bytes)-1] = 4;
3576 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",
3577 1, NULL);
3578 if (tevent_req_nomem(bytes, req)) {
3579 return tevent_req_post(req, ev);
3582 subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3583 8, state->vwv, talloc_get_size(bytes), bytes);
3584 if (tevent_req_nomem(subreq, req)) {
3585 return tevent_req_post(req, ev);
3587 tevent_req_set_callback(subreq, cli_setatr_done, req);
3588 return req;
3591 static void cli_setatr_done(struct tevent_req *subreq)
3593 struct tevent_req *req = tevent_req_callback_data(
3594 subreq, struct tevent_req);
3595 NTSTATUS status;
3597 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3598 TALLOC_FREE(subreq);
3599 if (!NT_STATUS_IS_OK(status)) {
3600 tevent_req_nterror(req, status);
3601 return;
3603 tevent_req_done(req);
3606 NTSTATUS cli_setatr_recv(struct tevent_req *req)
3608 return tevent_req_simple_recv_ntstatus(req);
3611 NTSTATUS cli_setatr(struct cli_state *cli,
3612 const char *fname,
3613 uint16_t attr,
3614 time_t mtime)
3616 TALLOC_CTX *frame = talloc_stackframe();
3617 struct event_context *ev = NULL;
3618 struct tevent_req *req = NULL;
3619 NTSTATUS status = NT_STATUS_OK;
3621 if (cli_has_async_calls(cli)) {
3623 * Can't use sync call while an async call is in flight
3625 status = NT_STATUS_INVALID_PARAMETER;
3626 goto fail;
3629 ev = event_context_init(frame);
3630 if (ev == NULL) {
3631 status = NT_STATUS_NO_MEMORY;
3632 goto fail;
3635 req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
3636 if (req == NULL) {
3637 status = NT_STATUS_NO_MEMORY;
3638 goto fail;
3641 if (!tevent_req_poll(req, ev)) {
3642 status = map_nt_error_from_unix(errno);
3643 goto fail;
3646 status = cli_setatr_recv(req);
3648 fail:
3649 TALLOC_FREE(frame);
3650 if (!NT_STATUS_IS_OK(status)) {
3651 cli_set_error(cli, status);
3653 return status;
3656 /****************************************************************************
3657 Check for existance of a dir.
3658 ****************************************************************************/
3660 static void cli_chkpath_done(struct tevent_req *subreq);
3662 struct cli_chkpath_state {
3663 int dummy;
3666 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
3667 struct event_context *ev,
3668 struct cli_state *cli,
3669 const char *fname)
3671 struct tevent_req *req = NULL, *subreq = NULL;
3672 struct cli_chkpath_state *state = NULL;
3673 uint8_t additional_flags = 0;
3674 uint8_t *bytes = NULL;
3676 req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
3677 if (req == NULL) {
3678 return NULL;
3681 bytes = talloc_array(state, uint8_t, 1);
3682 if (tevent_req_nomem(bytes, req)) {
3683 return tevent_req_post(req, ev);
3685 bytes[0] = 4;
3686 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3687 strlen(fname)+1, NULL);
3689 if (tevent_req_nomem(bytes, req)) {
3690 return tevent_req_post(req, ev);
3693 subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
3694 0, NULL, talloc_get_size(bytes), bytes);
3695 if (tevent_req_nomem(subreq, req)) {
3696 return tevent_req_post(req, ev);
3698 tevent_req_set_callback(subreq, cli_chkpath_done, req);
3699 return req;
3702 static void cli_chkpath_done(struct tevent_req *subreq)
3704 struct tevent_req *req = tevent_req_callback_data(
3705 subreq, struct tevent_req);
3706 NTSTATUS status;
3708 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3709 TALLOC_FREE(subreq);
3710 if (!NT_STATUS_IS_OK(status)) {
3711 tevent_req_nterror(req, status);
3712 return;
3714 tevent_req_done(req);
3717 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
3719 return tevent_req_simple_recv_ntstatus(req);
3722 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
3724 TALLOC_CTX *frame = talloc_stackframe();
3725 struct event_context *ev = NULL;
3726 struct tevent_req *req = NULL;
3727 char *path2 = NULL;
3728 NTSTATUS status = NT_STATUS_OK;
3730 if (cli_has_async_calls(cli)) {
3732 * Can't use sync call while an async call is in flight
3734 status = NT_STATUS_INVALID_PARAMETER;
3735 goto fail;
3738 path2 = talloc_strdup(frame, path);
3739 if (!path2) {
3740 status = NT_STATUS_NO_MEMORY;
3741 goto fail;
3743 trim_char(path2,'\0','\\');
3744 if (!*path2) {
3745 path2 = talloc_strdup(frame, "\\");
3746 if (!path2) {
3747 status = NT_STATUS_NO_MEMORY;
3748 goto fail;
3752 ev = event_context_init(frame);
3753 if (ev == NULL) {
3754 status = NT_STATUS_NO_MEMORY;
3755 goto fail;
3758 req = cli_chkpath_send(frame, ev, cli, path2);
3759 if (req == NULL) {
3760 status = NT_STATUS_NO_MEMORY;
3761 goto fail;
3764 if (!tevent_req_poll(req, ev)) {
3765 status = map_nt_error_from_unix(errno);
3766 goto fail;
3769 status = cli_chkpath_recv(req);
3771 fail:
3772 TALLOC_FREE(frame);
3773 if (!NT_STATUS_IS_OK(status)) {
3774 cli_set_error(cli, status);
3776 return status;
3779 /****************************************************************************
3780 Query disk space.
3781 ****************************************************************************/
3783 static void cli_dskattr_done(struct tevent_req *subreq);
3785 struct cli_dskattr_state {
3786 int bsize;
3787 int total;
3788 int avail;
3791 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
3792 struct event_context *ev,
3793 struct cli_state *cli)
3795 struct tevent_req *req = NULL, *subreq = NULL;
3796 struct cli_dskattr_state *state = NULL;
3797 uint8_t additional_flags = 0;
3799 req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
3800 if (req == NULL) {
3801 return NULL;
3804 subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
3805 0, NULL, 0, NULL);
3806 if (tevent_req_nomem(subreq, req)) {
3807 return tevent_req_post(req, ev);
3809 tevent_req_set_callback(subreq, cli_dskattr_done, req);
3810 return req;
3813 static void cli_dskattr_done(struct tevent_req *subreq)
3815 struct tevent_req *req = tevent_req_callback_data(
3816 subreq, struct tevent_req);
3817 struct cli_dskattr_state *state = tevent_req_data(
3818 req, struct cli_dskattr_state);
3819 uint8_t wct;
3820 uint16_t *vwv = NULL;
3821 uint8_t *inbuf;
3822 NTSTATUS status;
3824 status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3825 NULL);
3826 TALLOC_FREE(subreq);
3827 if (!NT_STATUS_IS_OK(status)) {
3828 tevent_req_nterror(req, status);
3829 return;
3831 state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
3832 state->total = SVAL(vwv+0, 0);
3833 state->avail = SVAL(vwv+3, 0);
3834 tevent_req_done(req);
3837 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
3839 struct cli_dskattr_state *state = tevent_req_data(
3840 req, struct cli_dskattr_state);
3841 NTSTATUS status;
3843 if (tevent_req_is_nterror(req, &status)) {
3844 return status;
3846 *bsize = state->bsize;
3847 *total = state->total;
3848 *avail = state->avail;
3849 return NT_STATUS_OK;
3852 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3854 TALLOC_CTX *frame = talloc_stackframe();
3855 struct event_context *ev = NULL;
3856 struct tevent_req *req = NULL;
3857 NTSTATUS status = NT_STATUS_OK;
3859 if (cli_has_async_calls(cli)) {
3861 * Can't use sync call while an async call is in flight
3863 status = NT_STATUS_INVALID_PARAMETER;
3864 goto fail;
3867 ev = event_context_init(frame);
3868 if (ev == NULL) {
3869 status = NT_STATUS_NO_MEMORY;
3870 goto fail;
3873 req = cli_dskattr_send(frame, ev, cli);
3874 if (req == NULL) {
3875 status = NT_STATUS_NO_MEMORY;
3876 goto fail;
3879 if (!tevent_req_poll(req, ev)) {
3880 status = map_nt_error_from_unix(errno);
3881 goto fail;
3884 status = cli_dskattr_recv(req, bsize, total, avail);
3886 fail:
3887 TALLOC_FREE(frame);
3888 if (!NT_STATUS_IS_OK(status)) {
3889 cli_set_error(cli, status);
3891 return status;
3894 /****************************************************************************
3895 Create and open a temporary file.
3896 ****************************************************************************/
3898 static void cli_ctemp_done(struct tevent_req *subreq);
3900 struct ctemp_state {
3901 uint16_t vwv[3];
3902 char *ret_path;
3903 uint16_t fnum;
3906 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
3907 struct event_context *ev,
3908 struct cli_state *cli,
3909 const char *path)
3911 struct tevent_req *req = NULL, *subreq = NULL;
3912 struct ctemp_state *state = NULL;
3913 uint8_t additional_flags = 0;
3914 uint8_t *bytes = NULL;
3916 req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
3917 if (req == NULL) {
3918 return NULL;
3921 SSVAL(state->vwv,0,0);
3922 SIVALS(state->vwv+1,0,-1);
3924 bytes = talloc_array(state, uint8_t, 1);
3925 if (tevent_req_nomem(bytes, req)) {
3926 return tevent_req_post(req, ev);
3928 bytes[0] = 4;
3929 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), path,
3930 strlen(path)+1, NULL);
3931 if (tevent_req_nomem(bytes, req)) {
3932 return tevent_req_post(req, ev);
3935 subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
3936 3, state->vwv, talloc_get_size(bytes), bytes);
3937 if (tevent_req_nomem(subreq, req)) {
3938 return tevent_req_post(req, ev);
3940 tevent_req_set_callback(subreq, cli_ctemp_done, req);
3941 return req;
3944 static void cli_ctemp_done(struct tevent_req *subreq)
3946 struct tevent_req *req = tevent_req_callback_data(
3947 subreq, struct tevent_req);
3948 struct ctemp_state *state = tevent_req_data(
3949 req, struct ctemp_state);
3950 NTSTATUS status;
3951 uint8_t wcnt;
3952 uint16_t *vwv;
3953 uint32_t num_bytes = 0;
3954 uint8_t *bytes = NULL;
3955 uint8_t *inbuf;
3957 status = cli_smb_recv(subreq, state, &inbuf, 1, &wcnt, &vwv,
3958 &num_bytes, &bytes);
3959 TALLOC_FREE(subreq);
3960 if (!NT_STATUS_IS_OK(status)) {
3961 tevent_req_nterror(req, status);
3962 return;
3965 state->fnum = SVAL(vwv+0, 0);
3967 /* From W2K3, the result is just the ASCII name */
3968 if (num_bytes < 2) {
3969 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
3970 return;
3973 if (pull_string_talloc(state,
3974 NULL,
3976 &state->ret_path,
3977 bytes,
3978 num_bytes,
3979 STR_ASCII) == 0) {
3980 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
3981 return;
3983 tevent_req_done(req);
3986 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
3987 TALLOC_CTX *ctx,
3988 uint16_t *pfnum,
3989 char **outfile)
3991 struct ctemp_state *state = tevent_req_data(req,
3992 struct ctemp_state);
3993 NTSTATUS status;
3995 if (tevent_req_is_nterror(req, &status)) {
3996 return status;
3998 *pfnum = state->fnum;
3999 *outfile = talloc_strdup(ctx, state->ret_path);
4000 if (!*outfile) {
4001 return NT_STATUS_NO_MEMORY;
4003 return NT_STATUS_OK;
4006 NTSTATUS cli_ctemp(struct cli_state *cli,
4007 TALLOC_CTX *ctx,
4008 const char *path,
4009 uint16_t *pfnum,
4010 char **out_path)
4012 TALLOC_CTX *frame = talloc_stackframe();
4013 struct event_context *ev;
4014 struct tevent_req *req;
4015 NTSTATUS status = NT_STATUS_OK;
4017 if (cli_has_async_calls(cli)) {
4019 * Can't use sync call while an async call is in flight
4021 status = NT_STATUS_INVALID_PARAMETER;
4022 goto fail;
4025 ev = event_context_init(frame);
4026 if (ev == NULL) {
4027 status = NT_STATUS_NO_MEMORY;
4028 goto fail;
4031 req = cli_ctemp_send(frame, ev, cli, path);
4032 if (req == NULL) {
4033 status = NT_STATUS_NO_MEMORY;
4034 goto fail;
4037 if (!tevent_req_poll(req, ev)) {
4038 status = map_nt_error_from_unix(errno);
4039 goto fail;
4042 status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4044 fail:
4045 TALLOC_FREE(frame);
4046 if (!NT_STATUS_IS_OK(status)) {
4047 cli_set_error(cli, status);
4049 return status;
4053 send a raw ioctl - used by the torture code
4055 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4057 uint16_t vwv[3];
4058 NTSTATUS status;
4059 struct tevent_req *result_parent;
4061 SSVAL(vwv+0, 0, fnum);
4062 SSVAL(vwv+1, 0, code>>16);
4063 SSVAL(vwv+2, 0, (code&0xFFFF));
4065 status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4066 &result_parent, 0, NULL, NULL, NULL, NULL);
4067 if (!NT_STATUS_IS_OK(status)) {
4068 return status;
4070 *blob = data_blob_null;
4071 return NT_STATUS_OK;
4074 /*********************************************************
4075 Set an extended attribute utility fn.
4076 *********************************************************/
4078 static bool cli_set_ea(struct cli_state *cli, uint16_t setup, char *param, unsigned int param_len,
4079 const char *ea_name, const char *ea_val, size_t ea_len)
4081 unsigned int data_len = 0;
4082 char *data = NULL;
4083 char *rparam=NULL, *rdata=NULL;
4084 char *p;
4085 size_t ea_namelen = strlen(ea_name);
4087 if (ea_namelen == 0 && ea_len == 0) {
4088 data_len = 4;
4089 data = (char *)SMB_MALLOC(data_len);
4090 if (!data) {
4091 return False;
4093 p = data;
4094 SIVAL(p,0,data_len);
4095 } else {
4096 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4097 data = (char *)SMB_MALLOC(data_len);
4098 if (!data) {
4099 return False;
4101 p = data;
4102 SIVAL(p,0,data_len);
4103 p += 4;
4104 SCVAL(p, 0, 0); /* EA flags. */
4105 SCVAL(p, 1, ea_namelen);
4106 SSVAL(p, 2, ea_len);
4107 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4108 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4111 if (!cli_send_trans(cli, SMBtrans2,
4112 NULL, /* name */
4113 -1, 0, /* fid, flags */
4114 &setup, 1, 0, /* setup, length, max */
4115 param, param_len, 2, /* param, length, max */
4116 data, data_len, cli->max_xmit /* data, length, max */
4117 )) {
4118 SAFE_FREE(data);
4119 return False;
4122 if (!cli_receive_trans(cli, SMBtrans2,
4123 &rparam, &param_len,
4124 &rdata, &data_len)) {
4125 SAFE_FREE(data);
4126 return false;
4129 SAFE_FREE(data);
4130 SAFE_FREE(rdata);
4131 SAFE_FREE(rparam);
4133 return True;
4136 /*********************************************************
4137 Set an extended attribute on a pathname.
4138 *********************************************************/
4140 bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len)
4142 uint16_t setup = TRANSACT2_SETPATHINFO;
4143 unsigned int param_len = 0;
4144 char *param;
4145 size_t srclen = 2*(strlen(path)+1);
4146 char *p;
4147 bool ret;
4149 param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
4150 if (!param) {
4151 return false;
4153 memset(param, '\0', 6);
4154 SSVAL(param,0,SMB_INFO_SET_EA);
4155 p = &param[6];
4157 p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
4158 param_len = PTR_DIFF(p, param);
4160 ret = cli_set_ea(cli, setup, param, param_len, ea_name, ea_val, ea_len);
4161 SAFE_FREE(param);
4162 return ret;
4165 /*********************************************************
4166 Set an extended attribute on an fnum.
4167 *********************************************************/
4169 bool cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum, const char *ea_name, const char *ea_val, size_t ea_len)
4171 char param[6];
4172 uint16_t setup = TRANSACT2_SETFILEINFO;
4174 memset(param, 0, 6);
4175 SSVAL(param,0,fnum);
4176 SSVAL(param,2,SMB_INFO_SET_EA);
4178 return cli_set_ea(cli, setup, param, 6, ea_name, ea_val, ea_len);
4181 /*********************************************************
4182 Get an extended attribute list utility fn.
4183 *********************************************************/
4185 static bool parse_ea_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
4186 size_t rdata_len,
4187 size_t *pnum_eas, struct ea_struct **pea_list);
4189 static bool cli_get_ea_list(struct cli_state *cli,
4190 uint16_t setup, char *param, unsigned int param_len,
4191 TALLOC_CTX *ctx,
4192 size_t *pnum_eas,
4193 struct ea_struct **pea_list)
4195 unsigned int data_len = 0;
4196 unsigned int rparam_len, rdata_len;
4197 char *rparam=NULL, *rdata=NULL;
4198 bool ret = False;
4200 *pnum_eas = 0;
4201 if (pea_list) {
4202 *pea_list = NULL;
4205 if (!cli_send_trans(cli, SMBtrans2,
4206 NULL, /* Name */
4207 -1, 0, /* fid, flags */
4208 &setup, 1, 0, /* setup, length, max */
4209 param, param_len, 10, /* param, length, max */
4210 NULL, data_len, cli->max_xmit /* data, length, max */
4211 )) {
4212 return False;
4215 if (!cli_receive_trans(cli, SMBtrans2,
4216 &rparam, &rparam_len,
4217 &rdata, &rdata_len)) {
4218 return False;
4221 ret = parse_ea_blob(ctx, (uint8_t *)rdata, rdata_len, pnum_eas,
4222 pea_list);
4223 SAFE_FREE(rparam);
4224 SAFE_FREE(rdata);
4225 return ret;
4228 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4229 size_t rdata_len,
4230 size_t *pnum_eas, struct ea_struct **pea_list)
4232 struct ea_struct *ea_list = NULL;
4233 size_t num_eas;
4234 size_t ea_size;
4235 const uint8_t *p;
4237 if (rdata_len < 4) {
4238 return false;
4241 ea_size = (size_t)IVAL(rdata,0);
4242 if (ea_size > rdata_len) {
4243 return false;
4246 if (ea_size == 0) {
4247 /* No EA's present. */
4248 *pnum_eas = 0;
4249 return true;
4252 p = rdata + 4;
4253 ea_size -= 4;
4255 /* Validate the EA list and count it. */
4256 for (num_eas = 0; ea_size >= 4; num_eas++) {
4257 unsigned int ea_namelen = CVAL(p,1);
4258 unsigned int ea_valuelen = SVAL(p,2);
4259 if (ea_namelen == 0) {
4260 return false;
4262 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4263 return false;
4265 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4266 p += 4 + ea_namelen + 1 + ea_valuelen;
4269 if (num_eas == 0) {
4270 *pnum_eas = 0;
4271 return true;
4274 *pnum_eas = num_eas;
4275 if (!pea_list) {
4276 /* Caller only wants number of EA's. */
4277 return true;
4280 ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
4281 if (!ea_list) {
4282 return false;
4285 ea_size = (size_t)IVAL(rdata,0);
4286 p = rdata + 4;
4288 for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4289 struct ea_struct *ea = &ea_list[num_eas];
4290 fstring unix_ea_name;
4291 unsigned int ea_namelen = CVAL(p,1);
4292 unsigned int ea_valuelen = SVAL(p,2);
4294 ea->flags = CVAL(p,0);
4295 unix_ea_name[0] = '\0';
4296 pull_ascii_fstring(unix_ea_name, p + 4);
4297 ea->name = talloc_strdup(ea_list, unix_ea_name);
4298 if (!ea->name) {
4299 goto fail;
4301 /* Ensure the value is null terminated (in case it's a string). */
4302 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4303 if (!ea->value.data) {
4304 goto fail;
4306 if (ea_valuelen) {
4307 memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4309 ea->value.data[ea_valuelen] = 0;
4310 ea->value.length--;
4311 p += 4 + ea_namelen + 1 + ea_valuelen;
4314 *pea_list = ea_list;
4315 return true;
4317 fail:
4318 TALLOC_FREE(ea_list);
4319 return false;
4322 /*********************************************************
4323 Get an extended attribute list from a pathname.
4324 *********************************************************/
4326 struct cli_get_ea_list_path_state {
4327 uint32_t num_data;
4328 uint8_t *data;
4331 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4333 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4334 struct tevent_context *ev,
4335 struct cli_state *cli,
4336 const char *fname)
4338 struct tevent_req *req, *subreq;
4339 struct cli_get_ea_list_path_state *state;
4341 req = tevent_req_create(mem_ctx, &state,
4342 struct cli_get_ea_list_path_state);
4343 if (req == NULL) {
4344 return NULL;
4346 subreq = cli_qpathinfo_send(state, ev, cli, fname,
4347 SMB_INFO_QUERY_ALL_EAS, 4,
4348 cli->max_xmit);
4349 if (tevent_req_nomem(subreq, req)) {
4350 return tevent_req_post(req, ev);
4352 tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4353 return req;
4356 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4358 struct tevent_req *req = tevent_req_callback_data(
4359 subreq, struct tevent_req);
4360 struct cli_get_ea_list_path_state *state = tevent_req_data(
4361 req, struct cli_get_ea_list_path_state);
4362 NTSTATUS status;
4364 status = cli_qpathinfo_recv(subreq, state, &state->data,
4365 &state->num_data);
4366 TALLOC_FREE(subreq);
4367 if (!NT_STATUS_IS_OK(status)) {
4368 tevent_req_nterror(req, status);
4369 return;
4371 tevent_req_done(req);
4374 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4375 size_t *pnum_eas, struct ea_struct **peas)
4377 struct cli_get_ea_list_path_state *state = tevent_req_data(
4378 req, struct cli_get_ea_list_path_state);
4379 NTSTATUS status;
4381 if (tevent_req_is_nterror(req, &status)) {
4382 return status;
4384 if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4385 pnum_eas, peas)) {
4386 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4388 return NT_STATUS_OK;
4391 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
4392 TALLOC_CTX *ctx,
4393 size_t *pnum_eas,
4394 struct ea_struct **pea_list)
4396 TALLOC_CTX *frame = talloc_stackframe();
4397 struct event_context *ev = NULL;
4398 struct tevent_req *req = NULL;
4399 NTSTATUS status = NT_STATUS_NO_MEMORY;
4401 if (cli_has_async_calls(cli)) {
4403 * Can't use sync call while an async call is in flight
4405 status = NT_STATUS_INVALID_PARAMETER;
4406 goto fail;
4408 ev = event_context_init(frame);
4409 if (ev == NULL) {
4410 goto fail;
4412 req = cli_get_ea_list_path_send(frame, ev, cli, path);
4413 if (req == NULL) {
4414 goto fail;
4416 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4417 goto fail;
4419 status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
4420 fail:
4421 TALLOC_FREE(frame);
4422 if (!NT_STATUS_IS_OK(status)) {
4423 cli_set_error(cli, status);
4425 return status;
4428 /*********************************************************
4429 Get an extended attribute list from an fnum.
4430 *********************************************************/
4432 bool cli_get_ea_list_fnum(struct cli_state *cli, uint16_t fnum,
4433 TALLOC_CTX *ctx,
4434 size_t *pnum_eas,
4435 struct ea_struct **pea_list)
4437 uint16_t setup = TRANSACT2_QFILEINFO;
4438 char param[6];
4440 memset(param, 0, 6);
4441 SSVAL(param,0,fnum);
4442 SSVAL(param,2,SMB_INFO_SET_EA);
4444 return cli_get_ea_list(cli, setup, param, 6, ctx, pnum_eas, pea_list);
4447 /****************************************************************************
4448 Convert open "flags" arg to uint32_t on wire.
4449 ****************************************************************************/
4451 static uint32_t open_flags_to_wire(int flags)
4453 int open_mode = flags & O_ACCMODE;
4454 uint32_t ret = 0;
4456 switch (open_mode) {
4457 case O_WRONLY:
4458 ret |= SMB_O_WRONLY;
4459 break;
4460 case O_RDWR:
4461 ret |= SMB_O_RDWR;
4462 break;
4463 default:
4464 case O_RDONLY:
4465 ret |= SMB_O_RDONLY;
4466 break;
4469 if (flags & O_CREAT) {
4470 ret |= SMB_O_CREAT;
4472 if (flags & O_EXCL) {
4473 ret |= SMB_O_EXCL;
4475 if (flags & O_TRUNC) {
4476 ret |= SMB_O_TRUNC;
4478 #if defined(O_SYNC)
4479 if (flags & O_SYNC) {
4480 ret |= SMB_O_SYNC;
4482 #endif /* O_SYNC */
4483 if (flags & O_APPEND) {
4484 ret |= SMB_O_APPEND;
4486 #if defined(O_DIRECT)
4487 if (flags & O_DIRECT) {
4488 ret |= SMB_O_DIRECT;
4490 #endif
4491 #if defined(O_DIRECTORY)
4492 if (flags & O_DIRECTORY) {
4493 ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4494 ret |= SMB_O_DIRECTORY;
4496 #endif
4497 return ret;
4500 /****************************************************************************
4501 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4502 ****************************************************************************/
4504 struct posix_open_state {
4505 uint16_t setup;
4506 uint8_t *param;
4507 uint8_t data[18];
4508 uint16_t fnum; /* Out */
4511 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4513 struct tevent_req *req = tevent_req_callback_data(
4514 subreq, struct tevent_req);
4515 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4516 NTSTATUS status;
4517 uint8_t *data;
4518 uint32_t num_data;
4520 status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
4521 &data, 12, &num_data);
4522 TALLOC_FREE(subreq);
4523 if (!NT_STATUS_IS_OK(status)) {
4524 tevent_req_nterror(req, status);
4525 return;
4527 state->fnum = SVAL(data,2);
4528 tevent_req_done(req);
4531 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4532 struct event_context *ev,
4533 struct cli_state *cli,
4534 const char *fname,
4535 int flags,
4536 mode_t mode,
4537 bool is_dir)
4539 struct tevent_req *req = NULL, *subreq = NULL;
4540 struct posix_open_state *state = NULL;
4541 uint32_t wire_flags = open_flags_to_wire(flags);
4543 req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4544 if (req == NULL) {
4545 return NULL;
4548 /* Setup setup word. */
4549 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4551 /* Setup param array. */
4552 state->param = talloc_array(state, uint8_t, 6);
4553 if (tevent_req_nomem(state->param, req)) {
4554 return tevent_req_post(req, ev);
4556 memset(state->param, '\0', 6);
4557 SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4559 state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
4560 strlen(fname)+1, NULL);
4562 if (tevent_req_nomem(state->param, req)) {
4563 return tevent_req_post(req, ev);
4566 /* Setup data words. */
4567 if (is_dir) {
4568 wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4569 wire_flags |= SMB_O_DIRECTORY;
4572 SIVAL(state->data,0,0); /* No oplock. */
4573 SIVAL(state->data,4,wire_flags);
4574 SIVAL(state->data,8,unix_perms_to_wire(mode));
4575 SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
4576 SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
4578 subreq = cli_trans_send(state, /* mem ctx. */
4579 ev, /* event ctx. */
4580 cli, /* cli_state. */
4581 SMBtrans2, /* cmd. */
4582 NULL, /* pipe name. */
4583 -1, /* fid. */
4584 0, /* function. */
4585 0, /* flags. */
4586 &state->setup, /* setup. */
4587 1, /* num setup uint16_t words. */
4588 0, /* max returned setup. */
4589 state->param, /* param. */
4590 talloc_get_size(state->param),/* num param. */
4591 2, /* max returned param. */
4592 state->data, /* data. */
4593 18, /* num data. */
4594 12); /* max returned data. */
4596 if (tevent_req_nomem(subreq, req)) {
4597 return tevent_req_post(req, ev);
4599 tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
4600 return req;
4603 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
4604 struct event_context *ev,
4605 struct cli_state *cli,
4606 const char *fname,
4607 int flags,
4608 mode_t mode)
4610 return cli_posix_open_internal_send(mem_ctx, ev,
4611 cli, fname, flags, mode, false);
4614 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
4616 struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4617 NTSTATUS status;
4619 if (tevent_req_is_nterror(req, &status)) {
4620 return status;
4622 *pfnum = state->fnum;
4623 return NT_STATUS_OK;
4626 /****************************************************************************
4627 Open - POSIX semantics. Doesn't request oplock.
4628 ****************************************************************************/
4630 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
4631 int flags, mode_t mode, uint16_t *pfnum)
4634 TALLOC_CTX *frame = talloc_stackframe();
4635 struct event_context *ev = NULL;
4636 struct tevent_req *req = NULL;
4637 NTSTATUS status = NT_STATUS_OK;
4639 if (cli_has_async_calls(cli)) {
4641 * Can't use sync call while an async call is in flight
4643 status = NT_STATUS_INVALID_PARAMETER;
4644 goto fail;
4647 ev = event_context_init(frame);
4648 if (ev == NULL) {
4649 status = NT_STATUS_NO_MEMORY;
4650 goto fail;
4653 req = cli_posix_open_send(frame,
4655 cli,
4656 fname,
4657 flags,
4658 mode);
4659 if (req == NULL) {
4660 status = NT_STATUS_NO_MEMORY;
4661 goto fail;
4664 if (!tevent_req_poll(req, ev)) {
4665 status = map_nt_error_from_unix(errno);
4666 goto fail;
4669 status = cli_posix_open_recv(req, pfnum);
4671 fail:
4672 TALLOC_FREE(frame);
4673 if (!NT_STATUS_IS_OK(status)) {
4674 cli_set_error(cli, status);
4676 return status;
4679 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
4680 struct event_context *ev,
4681 struct cli_state *cli,
4682 const char *fname,
4683 mode_t mode)
4685 return cli_posix_open_internal_send(mem_ctx, ev,
4686 cli, fname, O_CREAT, mode, true);
4689 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
4691 NTSTATUS status;
4693 if (tevent_req_is_nterror(req, &status)) {
4694 return status;
4696 return NT_STATUS_OK;
4699 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
4701 TALLOC_CTX *frame = talloc_stackframe();
4702 struct event_context *ev = NULL;
4703 struct tevent_req *req = NULL;
4704 NTSTATUS status = NT_STATUS_OK;
4706 if (cli_has_async_calls(cli)) {
4708 * Can't use sync call while an async call is in flight
4710 status = NT_STATUS_INVALID_PARAMETER;
4711 goto fail;
4714 ev = event_context_init(frame);
4715 if (ev == NULL) {
4716 status = NT_STATUS_NO_MEMORY;
4717 goto fail;
4720 req = cli_posix_mkdir_send(frame,
4722 cli,
4723 fname,
4724 mode);
4725 if (req == NULL) {
4726 status = NT_STATUS_NO_MEMORY;
4727 goto fail;
4730 if (!tevent_req_poll(req, ev)) {
4731 status = map_nt_error_from_unix(errno);
4732 goto fail;
4735 status = cli_posix_mkdir_recv(req);
4737 fail:
4738 TALLOC_FREE(frame);
4739 if (!NT_STATUS_IS_OK(status)) {
4740 cli_set_error(cli, status);
4742 return status;
4745 /****************************************************************************
4746 unlink or rmdir - POSIX semantics.
4747 ****************************************************************************/
4749 struct unlink_state {
4750 uint16_t setup;
4751 uint8_t data[2];
4754 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
4756 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
4757 NULL, 0, NULL, NULL, 0, NULL);
4758 tevent_req_simple_finish_ntstatus(subreq, status);
4761 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
4762 struct event_context *ev,
4763 struct cli_state *cli,
4764 const char *fname,
4765 bool is_dir)
4767 struct tevent_req *req = NULL, *subreq = NULL;
4768 struct unlink_state *state = NULL;
4769 uint8_t *param = NULL;
4771 req = tevent_req_create(mem_ctx, &state, struct unlink_state);
4772 if (req == NULL) {
4773 return NULL;
4776 /* Setup setup word. */
4777 SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4779 /* Setup param array. */
4780 param = talloc_array(state, uint8_t, 6);
4781 if (tevent_req_nomem(param, req)) {
4782 return tevent_req_post(req, ev);
4784 memset(param, '\0', 6);
4785 SSVAL(param, 0, SMB_POSIX_PATH_UNLINK);
4787 param = trans2_bytes_push_str(param, cli_ucs2(cli), fname,
4788 strlen(fname)+1, NULL);
4790 if (tevent_req_nomem(param, req)) {
4791 return tevent_req_post(req, ev);
4794 /* Setup data word. */
4795 SSVAL(state->data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET :
4796 SMB_POSIX_UNLINK_FILE_TARGET);
4798 subreq = cli_trans_send(state, /* mem ctx. */
4799 ev, /* event ctx. */
4800 cli, /* cli_state. */
4801 SMBtrans2, /* cmd. */
4802 NULL, /* pipe name. */
4803 -1, /* fid. */
4804 0, /* function. */
4805 0, /* flags. */
4806 &state->setup, /* setup. */
4807 1, /* num setup uint16_t words. */
4808 0, /* max returned setup. */
4809 param, /* param. */
4810 talloc_get_size(param), /* num param. */
4811 2, /* max returned param. */
4812 state->data, /* data. */
4813 2, /* num data. */
4814 0); /* max returned data. */
4816 if (tevent_req_nomem(subreq, req)) {
4817 return tevent_req_post(req, ev);
4819 tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
4820 return req;
4823 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
4824 struct event_context *ev,
4825 struct cli_state *cli,
4826 const char *fname)
4828 return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, false);
4831 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
4833 NTSTATUS status;
4835 if (tevent_req_is_nterror(req, &status)) {
4836 return status;
4838 return NT_STATUS_OK;
4841 /****************************************************************************
4842 unlink - POSIX semantics.
4843 ****************************************************************************/
4845 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
4847 TALLOC_CTX *frame = talloc_stackframe();
4848 struct event_context *ev = NULL;
4849 struct tevent_req *req = NULL;
4850 NTSTATUS status = NT_STATUS_OK;
4852 if (cli_has_async_calls(cli)) {
4854 * Can't use sync call while an async call is in flight
4856 status = NT_STATUS_INVALID_PARAMETER;
4857 goto fail;
4860 ev = event_context_init(frame);
4861 if (ev == NULL) {
4862 status = NT_STATUS_NO_MEMORY;
4863 goto fail;
4866 req = cli_posix_unlink_send(frame,
4868 cli,
4869 fname);
4870 if (req == NULL) {
4871 status = NT_STATUS_NO_MEMORY;
4872 goto fail;
4875 if (!tevent_req_poll(req, ev)) {
4876 status = map_nt_error_from_unix(errno);
4877 goto fail;
4880 status = cli_posix_unlink_recv(req);
4882 fail:
4883 TALLOC_FREE(frame);
4884 if (!NT_STATUS_IS_OK(status)) {
4885 cli_set_error(cli, status);
4887 return status;
4890 /****************************************************************************
4891 rmdir - POSIX semantics.
4892 ****************************************************************************/
4894 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
4895 struct event_context *ev,
4896 struct cli_state *cli,
4897 const char *fname)
4899 return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, true);
4902 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
4904 NTSTATUS status;
4906 if (tevent_req_is_nterror(req, &status)) {
4907 return status;
4909 return NT_STATUS_OK;
4912 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
4914 TALLOC_CTX *frame = talloc_stackframe();
4915 struct event_context *ev = NULL;
4916 struct tevent_req *req = NULL;
4917 NTSTATUS status = NT_STATUS_OK;
4919 if (cli_has_async_calls(cli)) {
4921 * Can't use sync call while an async call is in flight
4923 status = NT_STATUS_INVALID_PARAMETER;
4924 goto fail;
4927 ev = event_context_init(frame);
4928 if (ev == NULL) {
4929 status = NT_STATUS_NO_MEMORY;
4930 goto fail;
4933 req = cli_posix_rmdir_send(frame,
4935 cli,
4936 fname);
4937 if (req == NULL) {
4938 status = NT_STATUS_NO_MEMORY;
4939 goto fail;
4942 if (!tevent_req_poll(req, ev)) {
4943 status = map_nt_error_from_unix(errno);
4944 goto fail;
4947 status = cli_posix_rmdir_recv(req, frame);
4949 fail:
4950 TALLOC_FREE(frame);
4951 if (!NT_STATUS_IS_OK(status)) {
4952 cli_set_error(cli, status);
4954 return status;
4957 /****************************************************************************
4958 filechangenotify
4959 ****************************************************************************/
4961 struct cli_notify_state {
4962 uint8_t setup[8];
4963 uint32_t num_changes;
4964 struct notify_change *changes;
4967 static void cli_notify_done(struct tevent_req *subreq);
4969 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
4970 struct tevent_context *ev,
4971 struct cli_state *cli, uint16_t fnum,
4972 uint32_t buffer_size,
4973 uint32_t completion_filter, bool recursive)
4975 struct tevent_req *req, *subreq;
4976 struct cli_notify_state *state;
4978 req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
4979 if (req == NULL) {
4980 return NULL;
4983 SIVAL(state->setup, 0, completion_filter);
4984 SSVAL(state->setup, 4, fnum);
4985 SSVAL(state->setup, 6, recursive);
4987 subreq = cli_trans_send(
4988 state, /* mem ctx. */
4989 ev, /* event ctx. */
4990 cli, /* cli_state. */
4991 SMBnttrans, /* cmd. */
4992 NULL, /* pipe name. */
4993 -1, /* fid. */
4994 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
4995 0, /* flags. */
4996 (uint16_t *)state->setup, /* setup. */
4997 4, /* num setup uint16_t words. */
4998 0, /* max returned setup. */
4999 NULL, /* param. */
5000 0, /* num param. */
5001 buffer_size, /* max returned param. */
5002 NULL, /* data. */
5003 0, /* num data. */
5004 0); /* max returned data. */
5006 if (tevent_req_nomem(subreq, req)) {
5007 return tevent_req_post(req, ev);
5009 tevent_req_set_callback(subreq, cli_notify_done, req);
5010 return req;
5013 static void cli_notify_done(struct tevent_req *subreq)
5015 struct tevent_req *req = tevent_req_callback_data(
5016 subreq, struct tevent_req);
5017 struct cli_notify_state *state = tevent_req_data(
5018 req, struct cli_notify_state);
5019 NTSTATUS status;
5020 uint8_t *params;
5021 uint32_t i, ofs, num_params;
5023 status = cli_trans_recv(subreq, talloc_tos(), NULL, 0, NULL,
5024 &params, 0, &num_params, NULL, 0, NULL);
5025 TALLOC_FREE(subreq);
5026 if (!NT_STATUS_IS_OK(status)) {
5027 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
5028 tevent_req_nterror(req, status);
5029 return;
5032 state->num_changes = 0;
5033 ofs = 0;
5035 while (num_params - ofs > 12) {
5036 uint32_t len = IVAL(params, ofs);
5037 state->num_changes += 1;
5039 if ((len == 0) || (ofs+len >= num_params)) {
5040 break;
5042 ofs += len;
5045 state->changes = talloc_array(state, struct notify_change,
5046 state->num_changes);
5047 if (tevent_req_nomem(state->changes, req)) {
5048 TALLOC_FREE(params);
5049 return;
5052 ofs = 0;
5054 for (i=0; i<state->num_changes; i++) {
5055 uint32_t next = IVAL(params, ofs);
5056 uint32_t len = IVAL(params, ofs+8);
5057 ssize_t ret;
5058 char *name;
5060 if ((next != 0) && (len+12 != next)) {
5061 TALLOC_FREE(params);
5062 tevent_req_nterror(
5063 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5064 return;
5067 state->changes[i].action = IVAL(params, ofs+4);
5068 ret = clistr_pull_talloc(params, (char *)params, &name,
5069 params+ofs+12, len,
5070 STR_TERMINATE|STR_UNICODE);
5071 if (ret == -1) {
5072 TALLOC_FREE(params);
5073 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5074 return;
5076 state->changes[i].name = name;
5077 ofs += next;
5080 TALLOC_FREE(params);
5081 tevent_req_done(req);
5084 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5085 uint32_t *pnum_changes,
5086 struct notify_change **pchanges)
5088 struct cli_notify_state *state = tevent_req_data(
5089 req, struct cli_notify_state);
5090 NTSTATUS status;
5092 if (tevent_req_is_nterror(req, &status)) {
5093 return status;
5096 *pnum_changes = state->num_changes;
5097 *pchanges = talloc_move(mem_ctx, &state->changes);
5098 return NT_STATUS_OK;
5101 struct cli_qpathinfo_state {
5102 uint8_t *param;
5103 uint8_t *data;
5104 uint16_t setup[1];
5105 uint32_t min_rdata;
5106 uint8_t *rdata;
5107 uint32_t num_rdata;
5110 static void cli_qpathinfo_done(struct tevent_req *subreq);
5112 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
5113 struct tevent_context *ev,
5114 struct cli_state *cli, const char *fname,
5115 uint16_t level, uint32_t min_rdata,
5116 uint32_t max_rdata)
5118 struct tevent_req *req, *subreq;
5119 struct cli_qpathinfo_state *state;
5121 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
5122 if (req == NULL) {
5123 return NULL;
5125 state->min_rdata = min_rdata;
5126 SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
5128 state->param = talloc_zero_array(state, uint8_t, 6);
5129 if (tevent_req_nomem(state->param, req)) {
5130 return tevent_req_post(req, ev);
5132 SSVAL(state->param, 0, level);
5133 state->param = trans2_bytes_push_str(
5134 state->param, cli_ucs2(cli), fname, strlen(fname)+1, NULL);
5135 if (tevent_req_nomem(state->param, req)) {
5136 return tevent_req_post(req, ev);
5139 subreq = cli_trans_send(
5140 state, /* mem ctx. */
5141 ev, /* event ctx. */
5142 cli, /* cli_state. */
5143 SMBtrans2, /* cmd. */
5144 NULL, /* pipe name. */
5145 -1, /* fid. */
5146 0, /* function. */
5147 0, /* flags. */
5148 state->setup, /* setup. */
5149 1, /* num setup uint16_t words. */
5150 0, /* max returned setup. */
5151 state->param, /* param. */
5152 talloc_get_size(state->param), /* num param. */
5153 2, /* max returned param. */
5154 NULL, /* data. */
5155 0, /* num data. */
5156 max_rdata); /* max returned data. */
5158 if (tevent_req_nomem(subreq, req)) {
5159 return tevent_req_post(req, ev);
5161 tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5162 return req;
5165 static void cli_qpathinfo_done(struct tevent_req *subreq)
5167 struct tevent_req *req = tevent_req_callback_data(
5168 subreq, struct tevent_req);
5169 struct cli_qpathinfo_state *state = tevent_req_data(
5170 req, struct cli_qpathinfo_state);
5171 NTSTATUS status;
5173 status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
5174 &state->rdata, state->min_rdata,
5175 &state->num_rdata);
5176 if (!NT_STATUS_IS_OK(status)) {
5177 tevent_req_nterror(req, status);
5178 return;
5180 tevent_req_done(req);
5183 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5184 uint8_t **rdata, uint32_t *num_rdata)
5186 struct cli_qpathinfo_state *state = tevent_req_data(
5187 req, struct cli_qpathinfo_state);
5188 NTSTATUS status;
5190 if (tevent_req_is_nterror(req, &status)) {
5191 return status;
5193 if (rdata != NULL) {
5194 *rdata = talloc_move(mem_ctx, &state->rdata);
5195 } else {
5196 TALLOC_FREE(state->rdata);
5198 if (num_rdata != NULL) {
5199 *num_rdata = state->num_rdata;
5201 return NT_STATUS_OK;
5204 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5205 const char *fname, uint16_t level, uint32_t min_rdata,
5206 uint32_t max_rdata,
5207 uint8_t **rdata, uint32_t *num_rdata)
5209 TALLOC_CTX *frame = talloc_stackframe();
5210 struct event_context *ev;
5211 struct tevent_req *req;
5212 NTSTATUS status = NT_STATUS_NO_MEMORY;
5214 if (cli_has_async_calls(cli)) {
5216 * Can't use sync call while an async call is in flight
5218 status = NT_STATUS_INVALID_PARAMETER;
5219 goto fail;
5221 ev = event_context_init(frame);
5222 if (ev == NULL) {
5223 goto fail;
5225 req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5226 max_rdata);
5227 if (req == NULL) {
5228 goto fail;
5230 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5231 goto fail;
5233 status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5234 fail:
5235 TALLOC_FREE(frame);
5236 if (!NT_STATUS_IS_OK(status)) {
5237 cli_set_error(cli, status);
5239 return status;