s3-tevent: only include ../lib/util/tevent wrappers where needed.
[kai/samba.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6
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.
11
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.
16
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/>.
19 */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "../lib/util/tevent_ntstatus.h"
24 #include "async_smb.h"
25 #include "libsmb/clirap.h"
26 #include "trans2.h"
27 #include "ntioctl.h"
28
29 /***********************************************************
30  Common function for pushing stings, used by smb_bytes_push_str()
31  and trans_bytes_push_str(). Only difference is the align_odd
32  parameter setting.
33 ***********************************************************/
34
35 static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
36                                 const char *str, size_t str_len,
37                                 bool align_odd,
38                                 size_t *pconverted_size)
39 {
40         size_t buflen;
41         char *converted;
42         size_t converted_size;
43
44         if (buf == NULL) {
45                 return NULL;
46         }
47
48         buflen = talloc_get_size(buf);
49
50         if (align_odd && ucs2 && (buflen % 2 == 0)) {
51                 /*
52                  * We're pushing into an SMB buffer, align odd
53                  */
54                 buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
55                 if (buf == NULL) {
56                         return NULL;
57                 }
58                 buf[buflen] = '\0';
59                 buflen += 1;
60         }
61
62         if (!convert_string_talloc(talloc_tos(), CH_UNIX,
63                                    ucs2 ? CH_UTF16LE : CH_DOS,
64                                    str, str_len, &converted,
65                                    &converted_size)) {
66                 return NULL;
67         }
68
69         buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
70                                    buflen + converted_size);
71         if (buf == NULL) {
72                 TALLOC_FREE(converted);
73                 return NULL;
74         }
75
76         memcpy(buf + buflen, converted, converted_size);
77
78         TALLOC_FREE(converted);
79
80         if (pconverted_size) {
81                 *pconverted_size = converted_size;
82         }
83
84         return buf;
85 }
86
87 /***********************************************************
88  Push a string into an SMB buffer, with odd byte alignment
89  if it's a UCS2 string.
90 ***********************************************************/
91
92 uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
93                             const char *str, size_t str_len,
94                             size_t *pconverted_size)
95 {
96         return internal_bytes_push_str(buf, ucs2, str, str_len,
97                         true, pconverted_size);
98 }
99
100 uint8_t *smb_bytes_push_bytes(uint8_t *buf, uint8_t prefix,
101                               const uint8_t *bytes, size_t num_bytes)
102 {
103         size_t buflen;
104
105         if (buf == NULL) {
106                 return NULL;
107         }
108         buflen = talloc_get_size(buf);
109
110         buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
111                                    buflen + 1 + num_bytes);
112         if (buf == NULL) {
113                 return NULL;
114         }
115         buf[buflen] = prefix;
116         memcpy(&buf[buflen+1], bytes, num_bytes);
117         return buf;
118 }
119
120 /***********************************************************
121  Same as smb_bytes_push_str(), but without the odd byte
122  align for ucs2 (we're pushing into a param or data block).
123  static for now, although this will probably change when
124  other modules use async trans calls.
125 ***********************************************************/
126
127 static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
128                             const char *str, size_t str_len,
129                             size_t *pconverted_size)
130 {
131         return internal_bytes_push_str(buf, ucs2, str, str_len,
132                         false, pconverted_size);
133 }
134
135 struct cli_setpathinfo_state {
136         uint16_t setup;
137         uint8_t *param;
138 };
139
140 static void cli_setpathinfo_done(struct tevent_req *subreq);
141
142 struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
143                                         struct tevent_context *ev,
144                                         struct cli_state *cli,
145                                         uint16_t level,
146                                         const char *path,
147                                         uint8_t *data,
148                                         size_t data_len)
149 {
150         struct tevent_req *req, *subreq;
151         struct cli_setpathinfo_state *state;
152
153         req = tevent_req_create(mem_ctx, &state,
154                                 struct cli_setpathinfo_state);
155         if (req == NULL) {
156                 return NULL;
157         }
158
159         /* Setup setup word. */
160         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
161
162         /* Setup param array. */
163         state->param = TALLOC_ZERO_ARRAY(state, uint8_t, 6);
164         if (tevent_req_nomem(state->param, req)) {
165                 return tevent_req_post(req, ev);
166         }
167         SSVAL(state->param, 0, level);
168
169         state->param = trans2_bytes_push_str(
170                 state->param, cli_ucs2(cli), path, strlen(path)+1, NULL);
171         if (tevent_req_nomem(state->param, req)) {
172                 return tevent_req_post(req, ev);
173         }
174
175         subreq = cli_trans_send(
176                 state,                  /* mem ctx. */
177                 ev,                     /* event ctx. */
178                 cli,                    /* cli_state. */
179                 SMBtrans2,              /* cmd. */
180                 NULL,                   /* pipe name. */
181                 -1,                     /* fid. */
182                 0,                      /* function. */
183                 0,                      /* flags. */
184                 &state->setup,          /* setup. */
185                 1,                      /* num setup uint16_t words. */
186                 0,                      /* max returned setup. */
187                 state->param,           /* param. */
188                 talloc_get_size(state->param),  /* num param. */
189                 2,                      /* max returned param. */
190                 data,                   /* data. */
191                 data_len,               /* num data. */
192                 0);                     /* max returned data. */
193
194         if (tevent_req_nomem(subreq, req)) {
195                 return tevent_req_post(req, ev);
196         }
197         tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
198         return req;
199 }
200
201 static void cli_setpathinfo_done(struct tevent_req *subreq)
202 {
203         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
204                                          NULL, 0, NULL, NULL, 0, NULL);
205         tevent_req_simple_finish_ntstatus(subreq, status);
206 }
207
208 NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
209 {
210         return tevent_req_simple_recv_ntstatus(req);
211 }
212
213 NTSTATUS cli_setpathinfo(struct cli_state *cli,
214                          uint16_t level,
215                          const char *path,
216                          uint8_t *data,
217                          size_t data_len)
218 {
219         TALLOC_CTX *frame = talloc_stackframe();
220         struct tevent_context *ev;
221         struct tevent_req *req;
222         NTSTATUS status = NT_STATUS_NO_MEMORY;
223
224         if (cli_has_async_calls(cli)) {
225                 /*
226                  * Can't use sync call while an async call is in flight
227                  */
228                 status = NT_STATUS_INVALID_PARAMETER;
229                 goto fail;
230         }
231         ev = tevent_context_init(frame);
232         if (ev == NULL) {
233                 goto fail;
234         }
235         req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
236         if (req == NULL) {
237                 goto fail;
238         }
239         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
240                 goto fail;
241         }
242         status = cli_setpathinfo_recv(req);
243  fail:
244         TALLOC_FREE(frame);
245         return status;
246 }
247
248 /****************************************************************************
249  Hard/Symlink a file (UNIX extensions).
250  Creates new name (sym)linked to oldname.
251 ****************************************************************************/
252
253 struct cli_posix_link_internal_state {
254         uint8_t *data;
255 };
256
257 static void cli_posix_link_internal_done(struct tevent_req *subreq);
258
259 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
260                                         struct event_context *ev,
261                                         struct cli_state *cli,
262                                         uint16_t level,
263                                         const char *oldname,
264                                         const char *newname)
265 {
266         struct tevent_req *req = NULL, *subreq = NULL;
267         struct cli_posix_link_internal_state *state = NULL;
268
269         req = tevent_req_create(mem_ctx, &state,
270                                 struct cli_posix_link_internal_state);
271         if (req == NULL) {
272                 return NULL;
273         }
274
275         /* Setup data array. */
276         state->data = talloc_array(state, uint8_t, 0);
277         if (tevent_req_nomem(state->data, req)) {
278                 return tevent_req_post(req, ev);
279         }
280         state->data = trans2_bytes_push_str(
281                 state->data, cli_ucs2(cli), oldname, strlen(oldname)+1, NULL);
282
283         subreq = cli_setpathinfo_send(
284                 state, ev, cli, level, newname,
285                 state->data, talloc_get_size(state->data));
286         if (tevent_req_nomem(subreq, req)) {
287                 return tevent_req_post(req, ev);
288         }
289         tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
290         return req;
291 }
292
293 static void cli_posix_link_internal_done(struct tevent_req *subreq)
294 {
295         NTSTATUS status = cli_setpathinfo_recv(subreq);
296         tevent_req_simple_finish_ntstatus(subreq, status);
297 }
298
299 /****************************************************************************
300  Symlink a file (UNIX extensions).
301 ****************************************************************************/
302
303 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
304                                         struct event_context *ev,
305                                         struct cli_state *cli,
306                                         const char *oldname,
307                                         const char *newname)
308 {
309         return cli_posix_link_internal_send(
310                 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, oldname, newname);
311 }
312
313 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
314 {
315         return tevent_req_simple_recv_ntstatus(req);
316 }
317
318 NTSTATUS cli_posix_symlink(struct cli_state *cli,
319                         const char *oldname,
320                         const char *newname)
321 {
322         TALLOC_CTX *frame = talloc_stackframe();
323         struct event_context *ev = NULL;
324         struct tevent_req *req = NULL;
325         NTSTATUS status = NT_STATUS_OK;
326
327         if (cli_has_async_calls(cli)) {
328                 /*
329                  * Can't use sync call while an async call is in flight
330                  */
331                 status = NT_STATUS_INVALID_PARAMETER;
332                 goto fail;
333         }
334
335         ev = event_context_init(frame);
336         if (ev == NULL) {
337                 status = NT_STATUS_NO_MEMORY;
338                 goto fail;
339         }
340
341         req = cli_posix_symlink_send(frame,
342                                 ev,
343                                 cli,
344                                 oldname,
345                                 newname);
346         if (req == NULL) {
347                 status = NT_STATUS_NO_MEMORY;
348                 goto fail;
349         }
350
351         if (!tevent_req_poll(req, ev)) {
352                 status = map_nt_error_from_unix(errno);
353                 goto fail;
354         }
355
356         status = cli_posix_symlink_recv(req);
357
358  fail:
359         TALLOC_FREE(frame);
360         if (!NT_STATUS_IS_OK(status)) {
361                 cli_set_error(cli, status);
362         }
363         return status;
364 }
365
366 /****************************************************************************
367  Read a POSIX symlink.
368 ****************************************************************************/
369
370 struct readlink_state {
371         uint8_t *data;
372         uint32_t num_data;
373 };
374
375 static void cli_posix_readlink_done(struct tevent_req *subreq);
376
377 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
378                                         struct event_context *ev,
379                                         struct cli_state *cli,
380                                         const char *fname,
381                                         size_t len)
382 {
383         struct tevent_req *req = NULL, *subreq = NULL;
384         struct readlink_state *state = NULL;
385         uint32_t maxbytelen = (uint32_t)(cli_ucs2(cli) ? len*3 : len);
386
387         req = tevent_req_create(mem_ctx, &state, struct readlink_state);
388         if (req == NULL) {
389                 return NULL;
390         }
391
392         /*
393          * Len is in bytes, we need it in UCS2 units.
394          */
395         if ((2*len < len) || (maxbytelen < len)) {
396                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
397                 return tevent_req_post(req, ev);
398         }
399
400         subreq = cli_qpathinfo_send(state, ev, cli, fname,
401                                     SMB_QUERY_FILE_UNIX_LINK, 1, maxbytelen);
402         if (tevent_req_nomem(subreq, req)) {
403                 return tevent_req_post(req, ev);
404         }
405         tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
406         return req;
407 }
408
409 static void cli_posix_readlink_done(struct tevent_req *subreq)
410 {
411         struct tevent_req *req = tevent_req_callback_data(
412                 subreq, struct tevent_req);
413         struct readlink_state *state = tevent_req_data(
414                 req, struct readlink_state);
415         NTSTATUS status;
416
417         status = cli_qpathinfo_recv(subreq, state, &state->data,
418                                     &state->num_data);
419         TALLOC_FREE(subreq);
420         if (!NT_STATUS_IS_OK(status)) {
421                 tevent_req_nterror(req, status);
422                 return;
423         }
424         /*
425          * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
426          */
427         if (state->data[state->num_data-1] != '\0') {
428                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
429                 return;
430         }
431         tevent_req_done(req);
432 }
433
434 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
435                                 char *retpath, size_t len)
436 {
437         NTSTATUS status;
438         char *converted = NULL;
439         size_t converted_size = 0;
440         struct readlink_state *state = tevent_req_data(req, struct readlink_state);
441
442         if (tevent_req_is_nterror(req, &status)) {
443                 return status;
444         }
445         /* The returned data is a pushed string, not raw data. */
446         if (!convert_string_talloc(state,
447                                 cli_ucs2(cli) ? CH_UTF16LE : CH_DOS, 
448                                 CH_UNIX,
449                                 state->data,
450                                 state->num_data,
451                                 &converted,
452                                 &converted_size)) {
453                 return NT_STATUS_NO_MEMORY;
454         }
455
456         len = MIN(len,converted_size);
457         if (len == 0) {
458                 return NT_STATUS_DATA_ERROR;
459         }
460         memcpy(retpath, converted, len);
461         return NT_STATUS_OK;
462 }
463
464 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
465                                 char *linkpath, size_t len)
466 {
467         TALLOC_CTX *frame = talloc_stackframe();
468         struct event_context *ev = NULL;
469         struct tevent_req *req = NULL;
470         NTSTATUS status = NT_STATUS_OK;
471
472         if (cli_has_async_calls(cli)) {
473                 /*
474                  * Can't use sync call while an async call is in flight
475                  */
476                 status = NT_STATUS_INVALID_PARAMETER;
477                 goto fail;
478         }
479
480         ev = event_context_init(frame);
481         if (ev == NULL) {
482                 status = NT_STATUS_NO_MEMORY;
483                 goto fail;
484         }
485
486         req = cli_posix_readlink_send(frame,
487                                 ev,
488                                 cli,
489                                 fname,
490                                 len);
491         if (req == NULL) {
492                 status = NT_STATUS_NO_MEMORY;
493                 goto fail;
494         }
495
496         if (!tevent_req_poll(req, ev)) {
497                 status = map_nt_error_from_unix(errno);
498                 goto fail;
499         }
500
501         status = cli_posix_readlink_recv(req, cli, linkpath, len);
502
503  fail:
504         TALLOC_FREE(frame);
505         if (!NT_STATUS_IS_OK(status)) {
506                 cli_set_error(cli, status);
507         }
508         return status;
509 }
510
511 /****************************************************************************
512  Hard link a file (UNIX extensions).
513 ****************************************************************************/
514
515 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
516                                         struct event_context *ev,
517                                         struct cli_state *cli,
518                                         const char *oldname,
519                                         const char *newname)
520 {
521         return cli_posix_link_internal_send(
522                 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
523 }
524
525 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
526 {
527         return tevent_req_simple_recv_ntstatus(req);
528 }
529
530 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
531                         const char *oldname,
532                         const char *newname)
533 {
534         TALLOC_CTX *frame = talloc_stackframe();
535         struct event_context *ev = NULL;
536         struct tevent_req *req = NULL;
537         NTSTATUS status = NT_STATUS_OK;
538
539         if (cli_has_async_calls(cli)) {
540                 /*
541                  * Can't use sync call while an async call is in flight
542                  */
543                 status = NT_STATUS_INVALID_PARAMETER;
544                 goto fail;
545         }
546
547         ev = event_context_init(frame);
548         if (ev == NULL) {
549                 status = NT_STATUS_NO_MEMORY;
550                 goto fail;
551         }
552
553         req = cli_posix_hardlink_send(frame,
554                                 ev,
555                                 cli,
556                                 oldname,
557                                 newname);
558         if (req == NULL) {
559                 status = NT_STATUS_NO_MEMORY;
560                 goto fail;
561         }
562
563         if (!tevent_req_poll(req, ev)) {
564                 status = map_nt_error_from_unix(errno);
565                 goto fail;
566         }
567
568         status = cli_posix_hardlink_recv(req);
569
570  fail:
571         TALLOC_FREE(frame);
572         if (!NT_STATUS_IS_OK(status)) {
573                 cli_set_error(cli, status);
574         }
575         return status;
576 }
577
578 /****************************************************************************
579  Map standard UNIX permissions onto wire representations.
580 ****************************************************************************/
581
582 uint32_t unix_perms_to_wire(mode_t perms)
583 {
584         unsigned int ret = 0;
585
586         ret |= ((perms & S_IXOTH) ?  UNIX_X_OTH : 0);
587         ret |= ((perms & S_IWOTH) ?  UNIX_W_OTH : 0);
588         ret |= ((perms & S_IROTH) ?  UNIX_R_OTH : 0);
589         ret |= ((perms & S_IXGRP) ?  UNIX_X_GRP : 0);
590         ret |= ((perms & S_IWGRP) ?  UNIX_W_GRP : 0);
591         ret |= ((perms & S_IRGRP) ?  UNIX_R_GRP : 0);
592         ret |= ((perms & S_IXUSR) ?  UNIX_X_USR : 0);
593         ret |= ((perms & S_IWUSR) ?  UNIX_W_USR : 0);
594         ret |= ((perms & S_IRUSR) ?  UNIX_R_USR : 0);
595 #ifdef S_ISVTX
596         ret |= ((perms & S_ISVTX) ?  UNIX_STICKY : 0);
597 #endif
598 #ifdef S_ISGID
599         ret |= ((perms & S_ISGID) ?  UNIX_SET_GID : 0);
600 #endif
601 #ifdef S_ISUID
602         ret |= ((perms & S_ISUID) ?  UNIX_SET_UID : 0);
603 #endif
604         return ret;
605 }
606
607 /****************************************************************************
608  Map wire permissions to standard UNIX.
609 ****************************************************************************/
610
611 mode_t wire_perms_to_unix(uint32_t perms)
612 {
613         mode_t ret = (mode_t)0;
614
615         ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
616         ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
617         ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
618         ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
619         ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
620         ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
621         ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
622         ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
623         ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
624 #ifdef S_ISVTX
625         ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
626 #endif
627 #ifdef S_ISGID
628         ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
629 #endif
630 #ifdef S_ISUID
631         ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
632 #endif
633         return ret;
634 }
635
636 /****************************************************************************
637  Return the file type from the wire filetype for UNIX extensions.
638 ****************************************************************************/
639
640 static mode_t unix_filetype_from_wire(uint32_t wire_type)
641 {
642         switch (wire_type) {
643                 case UNIX_TYPE_FILE:
644                         return S_IFREG;
645                 case UNIX_TYPE_DIR:
646                         return S_IFDIR;
647 #ifdef S_IFLNK
648                 case UNIX_TYPE_SYMLINK:
649                         return S_IFLNK;
650 #endif
651 #ifdef S_IFCHR
652                 case UNIX_TYPE_CHARDEV:
653                         return S_IFCHR;
654 #endif
655 #ifdef S_IFBLK
656                 case UNIX_TYPE_BLKDEV:
657                         return S_IFBLK;
658 #endif
659 #ifdef S_IFIFO
660                 case UNIX_TYPE_FIFO:
661                         return S_IFIFO;
662 #endif
663 #ifdef S_IFSOCK
664                 case UNIX_TYPE_SOCKET:
665                         return S_IFSOCK;
666 #endif
667                 default:
668                         return (mode_t)0;
669         }
670 }
671
672 /****************************************************************************
673  Do a POSIX getfacl (UNIX extensions).
674 ****************************************************************************/
675
676 struct getfacl_state {
677         uint32_t num_data;
678         uint8_t *data;
679 };
680
681 static void cli_posix_getfacl_done(struct tevent_req *subreq);
682
683 struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
684                                         struct event_context *ev,
685                                         struct cli_state *cli,
686                                         const char *fname)
687 {
688         struct tevent_req *req = NULL, *subreq = NULL;
689         struct getfacl_state *state = NULL;
690
691         req = tevent_req_create(mem_ctx, &state, struct getfacl_state);
692         if (req == NULL) {
693                 return NULL;
694         }
695         subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
696                                     0, cli->max_xmit);
697         if (tevent_req_nomem(subreq, req)) {
698                 return tevent_req_post(req, ev);
699         }
700         tevent_req_set_callback(subreq, cli_posix_getfacl_done, req);
701         return req;
702 }
703
704 static void cli_posix_getfacl_done(struct tevent_req *subreq)
705 {
706         struct tevent_req *req = tevent_req_callback_data(
707                 subreq, struct tevent_req);
708         struct getfacl_state *state = tevent_req_data(
709                 req, struct getfacl_state);
710         NTSTATUS status;
711
712         status = cli_qpathinfo_recv(subreq, state, &state->data,
713                                     &state->num_data);
714         TALLOC_FREE(subreq);
715         if (!NT_STATUS_IS_OK(status)) {
716                 tevent_req_nterror(req, status);
717                 return;
718         }
719         tevent_req_done(req);
720 }
721
722 NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
723                                 TALLOC_CTX *mem_ctx,
724                                 size_t *prb_size,
725                                 char **retbuf)
726 {
727         struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
728         NTSTATUS status;
729
730         if (tevent_req_is_nterror(req, &status)) {
731                 return status;
732         }
733         *prb_size = (size_t)state->num_data;
734         *retbuf = (char *)talloc_move(mem_ctx, &state->data);
735         return NT_STATUS_OK;
736 }
737
738 NTSTATUS cli_posix_getfacl(struct cli_state *cli,
739                         const char *fname,
740                         TALLOC_CTX *mem_ctx,
741                         size_t *prb_size,
742                         char **retbuf)
743 {
744         TALLOC_CTX *frame = talloc_stackframe();
745         struct event_context *ev = NULL;
746         struct tevent_req *req = NULL;
747         NTSTATUS status = NT_STATUS_OK;
748
749         if (cli_has_async_calls(cli)) {
750                 /*
751                  * Can't use sync call while an async call is in flight
752                  */
753                 status = NT_STATUS_INVALID_PARAMETER;
754                 goto fail;
755         }
756
757         ev = event_context_init(frame);
758         if (ev == NULL) {
759                 status = NT_STATUS_NO_MEMORY;
760                 goto fail;
761         }
762
763         req = cli_posix_getfacl_send(frame,
764                                 ev,
765                                 cli,
766                                 fname);
767         if (req == NULL) {
768                 status = NT_STATUS_NO_MEMORY;
769                 goto fail;
770         }
771
772         if (!tevent_req_poll(req, ev)) {
773                 status = map_nt_error_from_unix(errno);
774                 goto fail;
775         }
776
777         status = cli_posix_getfacl_recv(req, mem_ctx, prb_size, retbuf);
778
779  fail:
780         TALLOC_FREE(frame);
781         if (!NT_STATUS_IS_OK(status)) {
782                 cli_set_error(cli, status);
783         }
784         return status;
785 }
786
787 /****************************************************************************
788  Stat a file (UNIX extensions).
789 ****************************************************************************/
790
791 struct stat_state {
792         uint32_t num_data;
793         uint8_t *data;
794 };
795
796 static void cli_posix_stat_done(struct tevent_req *subreq);
797
798 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
799                                         struct event_context *ev,
800                                         struct cli_state *cli,
801                                         const char *fname)
802 {
803         struct tevent_req *req = NULL, *subreq = NULL;
804         struct stat_state *state = NULL;
805
806         req = tevent_req_create(mem_ctx, &state, struct stat_state);
807         if (req == NULL) {
808                 return NULL;
809         }
810         subreq = cli_qpathinfo_send(state, ev, cli, fname,
811                                     SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
812         if (tevent_req_nomem(subreq, req)) {
813                 return tevent_req_post(req, ev);
814         }
815         tevent_req_set_callback(subreq, cli_posix_stat_done, req);
816         return req;
817 }
818
819 static void cli_posix_stat_done(struct tevent_req *subreq)
820 {
821         struct tevent_req *req = tevent_req_callback_data(
822                                 subreq, struct tevent_req);
823         struct stat_state *state = tevent_req_data(req, struct stat_state);
824         NTSTATUS status;
825
826         status = cli_qpathinfo_recv(subreq, state, &state->data,
827                                     &state->num_data);
828         TALLOC_FREE(subreq);
829         if (!NT_STATUS_IS_OK(status)) {
830                 tevent_req_nterror(req, status);
831                 return;
832         }
833         tevent_req_done(req);
834 }
835
836 NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
837                                 SMB_STRUCT_STAT *sbuf)
838 {
839         struct stat_state *state = tevent_req_data(req, struct stat_state);
840         NTSTATUS status;
841
842         if (tevent_req_is_nterror(req, &status)) {
843                 return status;
844         }
845
846         sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0);     /* total size, in bytes */
847         sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8);   /* number of blocks allocated */
848 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
849         sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
850 #else
851         /* assume 512 byte blocks */
852         sbuf->st_ex_blocks /= 512;
853 #endif
854         sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16));    /* time of last change */
855         sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24));    /* time of last access */
856         sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32));    /* time of last modification */
857
858         sbuf->st_ex_uid = (uid_t) IVAL(state->data,40);      /* user ID of owner */
859         sbuf->st_ex_gid = (gid_t) IVAL(state->data,48);      /* group ID of owner */
860         sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
861 #if defined(HAVE_MAKEDEV)
862         {
863                 uint32_t dev_major = IVAL(state->data,60);
864                 uint32_t dev_minor = IVAL(state->data,68);
865                 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
866         }
867 #endif
868         sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76);      /* inode */
869         sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84));     /* protection */
870         sbuf->st_ex_nlink = BIG_UINT(state->data,92); /* number of hard links */
871
872         return NT_STATUS_OK;
873 }
874
875 NTSTATUS cli_posix_stat(struct cli_state *cli,
876                         const char *fname,
877                         SMB_STRUCT_STAT *sbuf)
878 {
879         TALLOC_CTX *frame = talloc_stackframe();
880         struct event_context *ev = NULL;
881         struct tevent_req *req = NULL;
882         NTSTATUS status = NT_STATUS_OK;
883
884         if (cli_has_async_calls(cli)) {
885                 /*
886                  * Can't use sync call while an async call is in flight
887                  */
888                 status = NT_STATUS_INVALID_PARAMETER;
889                 goto fail;
890         }
891
892         ev = event_context_init(frame);
893         if (ev == NULL) {
894                 status = NT_STATUS_NO_MEMORY;
895                 goto fail;
896         }
897
898         req = cli_posix_stat_send(frame,
899                                 ev,
900                                 cli,
901                                 fname);
902         if (req == NULL) {
903                 status = NT_STATUS_NO_MEMORY;
904                 goto fail;
905         }
906
907         if (!tevent_req_poll(req, ev)) {
908                 status = map_nt_error_from_unix(errno);
909                 goto fail;
910         }
911
912         status = cli_posix_stat_recv(req, sbuf);
913
914  fail:
915         TALLOC_FREE(frame);
916         if (!NT_STATUS_IS_OK(status)) {
917                 cli_set_error(cli, status);
918         }
919         return status;
920 }
921
922 /****************************************************************************
923  Chmod or chown a file internal (UNIX extensions).
924 ****************************************************************************/
925
926 struct cli_posix_chown_chmod_internal_state {
927         uint8_t data[100];
928 };
929
930 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
931
932 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
933                                         struct event_context *ev,
934                                         struct cli_state *cli,
935                                         const char *fname,
936                                         uint32_t mode,
937                                         uint32_t uid,
938                                         uint32_t gid)
939 {
940         struct tevent_req *req = NULL, *subreq = NULL;
941         struct cli_posix_chown_chmod_internal_state *state = NULL;
942
943         req = tevent_req_create(mem_ctx, &state,
944                                 struct cli_posix_chown_chmod_internal_state);
945         if (req == NULL) {
946                 return NULL;
947         }
948
949         memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
950         memset(&state->data[40], '\0', 60);
951         SIVAL(state->data,40,uid);
952         SIVAL(state->data,48,gid);
953         SIVAL(state->data,84,mode);
954
955         subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
956                                       fname, state->data, sizeof(state->data));
957         if (tevent_req_nomem(subreq, req)) {
958                 return tevent_req_post(req, ev);
959         }
960         tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
961                                 req);
962         return req;
963 }
964
965 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
966 {
967         NTSTATUS status = cli_setpathinfo_recv(subreq);
968         tevent_req_simple_finish_ntstatus(subreq, status);
969 }
970
971 /****************************************************************************
972  chmod a file (UNIX extensions).
973 ****************************************************************************/
974
975 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
976                                         struct event_context *ev,
977                                         struct cli_state *cli,
978                                         const char *fname,
979                                         mode_t mode)
980 {
981         return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
982                         fname,
983                         unix_perms_to_wire(mode),
984                         SMB_UID_NO_CHANGE,
985                         SMB_GID_NO_CHANGE);
986 }
987
988 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
989 {
990         return tevent_req_simple_recv_ntstatus(req);
991 }
992
993 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
994 {
995         TALLOC_CTX *frame = talloc_stackframe();
996         struct event_context *ev = NULL;
997         struct tevent_req *req = NULL;
998         NTSTATUS status = NT_STATUS_OK;
999
1000         if (cli_has_async_calls(cli)) {
1001                 /*
1002                  * Can't use sync call while an async call is in flight
1003                  */
1004                 status = NT_STATUS_INVALID_PARAMETER;
1005                 goto fail;
1006         }
1007
1008         ev = event_context_init(frame);
1009         if (ev == NULL) {
1010                 status = NT_STATUS_NO_MEMORY;
1011                 goto fail;
1012         }
1013
1014         req = cli_posix_chmod_send(frame,
1015                                 ev,
1016                                 cli,
1017                                 fname,
1018                                 mode);
1019         if (req == NULL) {
1020                 status = NT_STATUS_NO_MEMORY;
1021                 goto fail;
1022         }
1023
1024         if (!tevent_req_poll(req, ev)) {
1025                 status = map_nt_error_from_unix(errno);
1026                 goto fail;
1027         }
1028
1029         status = cli_posix_chmod_recv(req);
1030
1031  fail:
1032         TALLOC_FREE(frame);
1033         if (!NT_STATUS_IS_OK(status)) {
1034                 cli_set_error(cli, status);
1035         }
1036         return status;
1037 }
1038
1039 /****************************************************************************
1040  chown a file (UNIX extensions).
1041 ****************************************************************************/
1042
1043 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1044                                         struct event_context *ev,
1045                                         struct cli_state *cli,
1046                                         const char *fname,
1047                                         uid_t uid,
1048                                         gid_t gid)
1049 {
1050         return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
1051                         fname,
1052                         SMB_MODE_NO_CHANGE,
1053                         (uint32_t)uid,
1054                         (uint32_t)gid);
1055 }
1056
1057 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1058 {
1059         return tevent_req_simple_recv_ntstatus(req);
1060 }
1061
1062 NTSTATUS cli_posix_chown(struct cli_state *cli,
1063                         const char *fname,
1064                         uid_t uid,
1065                         gid_t gid)
1066 {
1067         TALLOC_CTX *frame = talloc_stackframe();
1068         struct event_context *ev = NULL;
1069         struct tevent_req *req = NULL;
1070         NTSTATUS status = NT_STATUS_OK;
1071
1072         if (cli_has_async_calls(cli)) {
1073                 /*
1074                  * Can't use sync call while an async call is in flight
1075                  */
1076                 status = NT_STATUS_INVALID_PARAMETER;
1077                 goto fail;
1078         }
1079
1080         ev = event_context_init(frame);
1081         if (ev == NULL) {
1082                 status = NT_STATUS_NO_MEMORY;
1083                 goto fail;
1084         }
1085
1086         req = cli_posix_chown_send(frame,
1087                                 ev,
1088                                 cli,
1089                                 fname,
1090                                 uid,
1091                                 gid);
1092         if (req == NULL) {
1093                 status = NT_STATUS_NO_MEMORY;
1094                 goto fail;
1095         }
1096
1097         if (!tevent_req_poll(req, ev)) {
1098                 status = map_nt_error_from_unix(errno);
1099                 goto fail;
1100         }
1101
1102         status = cli_posix_chown_recv(req);
1103
1104  fail:
1105         TALLOC_FREE(frame);
1106         if (!NT_STATUS_IS_OK(status)) {
1107                 cli_set_error(cli, status);
1108         }
1109         return status;
1110 }
1111
1112 /****************************************************************************
1113  Rename a file.
1114 ****************************************************************************/
1115
1116 static void cli_rename_done(struct tevent_req *subreq);
1117
1118 struct cli_rename_state {
1119         uint16_t vwv[1];
1120 };
1121
1122 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1123                                 struct event_context *ev,
1124                                 struct cli_state *cli,
1125                                 const char *fname_src,
1126                                 const char *fname_dst)
1127 {
1128         struct tevent_req *req = NULL, *subreq = NULL;
1129         struct cli_rename_state *state = NULL;
1130         uint8_t additional_flags = 0;
1131         uint8_t *bytes = NULL;
1132
1133         req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1134         if (req == NULL) {
1135                 return NULL;
1136         }
1137
1138         SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1139
1140         bytes = talloc_array(state, uint8_t, 1);
1141         if (tevent_req_nomem(bytes, req)) {
1142                 return tevent_req_post(req, ev);
1143         }
1144         bytes[0] = 4;
1145         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1146                                    strlen(fname_src)+1, NULL);
1147         if (tevent_req_nomem(bytes, req)) {
1148                 return tevent_req_post(req, ev);
1149         }
1150
1151         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1152                         talloc_get_size(bytes)+1);
1153         if (tevent_req_nomem(bytes, req)) {
1154                 return tevent_req_post(req, ev);
1155         }
1156
1157         bytes[talloc_get_size(bytes)-1] = 4;
1158         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1159                                    strlen(fname_dst)+1, NULL);
1160         if (tevent_req_nomem(bytes, req)) {
1161                 return tevent_req_post(req, ev);
1162         }
1163
1164         subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1165                               1, state->vwv, talloc_get_size(bytes), bytes);
1166         if (tevent_req_nomem(subreq, req)) {
1167                 return tevent_req_post(req, ev);
1168         }
1169         tevent_req_set_callback(subreq, cli_rename_done, req);
1170         return req;
1171 }
1172
1173 static void cli_rename_done(struct tevent_req *subreq)
1174 {
1175         struct tevent_req *req = tevent_req_callback_data(
1176                                 subreq, struct tevent_req);
1177         NTSTATUS status;
1178
1179         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1180         TALLOC_FREE(subreq);
1181         if (!NT_STATUS_IS_OK(status)) {
1182                 tevent_req_nterror(req, status);
1183                 return;
1184         }
1185         tevent_req_done(req);
1186 }
1187
1188 NTSTATUS cli_rename_recv(struct tevent_req *req)
1189 {
1190         return tevent_req_simple_recv_ntstatus(req);
1191 }
1192
1193 NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1194 {
1195         TALLOC_CTX *frame = talloc_stackframe();
1196         struct event_context *ev;
1197         struct tevent_req *req;
1198         NTSTATUS status = NT_STATUS_OK;
1199
1200         if (cli_has_async_calls(cli)) {
1201                 /*
1202                  * Can't use sync call while an async call is in flight
1203                  */
1204                 status = NT_STATUS_INVALID_PARAMETER;
1205                 goto fail;
1206         }
1207
1208         ev = event_context_init(frame);
1209         if (ev == NULL) {
1210                 status = NT_STATUS_NO_MEMORY;
1211                 goto fail;
1212         }
1213
1214         req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
1215         if (req == NULL) {
1216                 status = NT_STATUS_NO_MEMORY;
1217                 goto fail;
1218         }
1219
1220         if (!tevent_req_poll(req, ev)) {
1221                 status = map_nt_error_from_unix(errno);
1222                 goto fail;
1223         }
1224
1225         status = cli_rename_recv(req);
1226
1227  fail:
1228         TALLOC_FREE(frame);
1229         if (!NT_STATUS_IS_OK(status)) {
1230                 cli_set_error(cli, status);
1231         }
1232         return status;
1233 }
1234
1235 /****************************************************************************
1236  NT Rename a file.
1237 ****************************************************************************/
1238
1239 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1240
1241 struct cli_ntrename_internal_state {
1242         uint16_t vwv[4];
1243 };
1244
1245 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1246                                 struct event_context *ev,
1247                                 struct cli_state *cli,
1248                                 const char *fname_src,
1249                                 const char *fname_dst,
1250                                 uint16_t rename_flag)
1251 {
1252         struct tevent_req *req = NULL, *subreq = NULL;
1253         struct cli_ntrename_internal_state *state = NULL;
1254         uint8_t additional_flags = 0;
1255         uint8_t *bytes = NULL;
1256
1257         req = tevent_req_create(mem_ctx, &state,
1258                                 struct cli_ntrename_internal_state);
1259         if (req == NULL) {
1260                 return NULL;
1261         }
1262
1263         SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1264         SSVAL(state->vwv+1, 0, rename_flag);
1265
1266         bytes = talloc_array(state, uint8_t, 1);
1267         if (tevent_req_nomem(bytes, req)) {
1268                 return tevent_req_post(req, ev);
1269         }
1270         bytes[0] = 4;
1271         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1272                                    strlen(fname_src)+1, NULL);
1273         if (tevent_req_nomem(bytes, req)) {
1274                 return tevent_req_post(req, ev);
1275         }
1276
1277         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1278                         talloc_get_size(bytes)+1);
1279         if (tevent_req_nomem(bytes, req)) {
1280                 return tevent_req_post(req, ev);
1281         }
1282
1283         bytes[talloc_get_size(bytes)-1] = 4;
1284         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1285                                    strlen(fname_dst)+1, NULL);
1286         if (tevent_req_nomem(bytes, req)) {
1287                 return tevent_req_post(req, ev);
1288         }
1289
1290         subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1291                               4, state->vwv, talloc_get_size(bytes), bytes);
1292         if (tevent_req_nomem(subreq, req)) {
1293                 return tevent_req_post(req, ev);
1294         }
1295         tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1296         return req;
1297 }
1298
1299 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1300 {
1301         struct tevent_req *req = tevent_req_callback_data(
1302                                 subreq, struct tevent_req);
1303         NTSTATUS status;
1304
1305         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1306         TALLOC_FREE(subreq);
1307         if (!NT_STATUS_IS_OK(status)) {
1308                 tevent_req_nterror(req, status);
1309                 return;
1310         }
1311         tevent_req_done(req);
1312 }
1313
1314 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1315 {
1316         return tevent_req_simple_recv_ntstatus(req);
1317 }
1318
1319 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1320                                 struct event_context *ev,
1321                                 struct cli_state *cli,
1322                                 const char *fname_src,
1323                                 const char *fname_dst)
1324 {
1325         return cli_ntrename_internal_send(mem_ctx,
1326                                           ev,
1327                                           cli,
1328                                           fname_src,
1329                                           fname_dst,
1330                                           RENAME_FLAG_RENAME);
1331 }
1332
1333 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1334 {
1335         return cli_ntrename_internal_recv(req);
1336 }
1337
1338 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1339 {
1340         TALLOC_CTX *frame = talloc_stackframe();
1341         struct event_context *ev;
1342         struct tevent_req *req;
1343         NTSTATUS status = NT_STATUS_OK;
1344
1345         if (cli_has_async_calls(cli)) {
1346                 /*
1347                  * Can't use sync call while an async call is in flight
1348                  */
1349                 status = NT_STATUS_INVALID_PARAMETER;
1350                 goto fail;
1351         }
1352
1353         ev = event_context_init(frame);
1354         if (ev == NULL) {
1355                 status = NT_STATUS_NO_MEMORY;
1356                 goto fail;
1357         }
1358
1359         req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1360         if (req == NULL) {
1361                 status = NT_STATUS_NO_MEMORY;
1362                 goto fail;
1363         }
1364
1365         if (!tevent_req_poll(req, ev)) {
1366                 status = map_nt_error_from_unix(errno);
1367                 goto fail;
1368         }
1369
1370         status = cli_ntrename_recv(req);
1371
1372  fail:
1373         TALLOC_FREE(frame);
1374         if (!NT_STATUS_IS_OK(status)) {
1375                 cli_set_error(cli, status);
1376         }
1377         return status;
1378 }
1379
1380 /****************************************************************************
1381  NT hardlink a file.
1382 ****************************************************************************/
1383
1384 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1385                                 struct event_context *ev,
1386                                 struct cli_state *cli,
1387                                 const char *fname_src,
1388                                 const char *fname_dst)
1389 {
1390         return cli_ntrename_internal_send(mem_ctx,
1391                                           ev,
1392                                           cli,
1393                                           fname_src,
1394                                           fname_dst,
1395                                           RENAME_FLAG_HARD_LINK);
1396 }
1397
1398 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1399 {
1400         return cli_ntrename_internal_recv(req);
1401 }
1402
1403 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1404 {
1405         TALLOC_CTX *frame = talloc_stackframe();
1406         struct event_context *ev;
1407         struct tevent_req *req;
1408         NTSTATUS status = NT_STATUS_OK;
1409
1410         if (cli_has_async_calls(cli)) {
1411                 /*
1412                  * Can't use sync call while an async call is in flight
1413                  */
1414                 status = NT_STATUS_INVALID_PARAMETER;
1415                 goto fail;
1416         }
1417
1418         ev = event_context_init(frame);
1419         if (ev == NULL) {
1420                 status = NT_STATUS_NO_MEMORY;
1421                 goto fail;
1422         }
1423
1424         req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1425         if (req == NULL) {
1426                 status = NT_STATUS_NO_MEMORY;
1427                 goto fail;
1428         }
1429
1430         if (!tevent_req_poll(req, ev)) {
1431                 status = map_nt_error_from_unix(errno);
1432                 goto fail;
1433         }
1434
1435         status = cli_nt_hardlink_recv(req);
1436
1437  fail:
1438         TALLOC_FREE(frame);
1439         if (!NT_STATUS_IS_OK(status)) {
1440                 cli_set_error(cli, status);
1441         }
1442         return status;
1443 }
1444
1445 /****************************************************************************
1446  Delete a file.
1447 ****************************************************************************/
1448
1449 static void cli_unlink_done(struct tevent_req *subreq);
1450
1451 struct cli_unlink_state {
1452         uint16_t vwv[1];
1453 };
1454
1455 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1456                                 struct event_context *ev,
1457                                 struct cli_state *cli,
1458                                 const char *fname,
1459                                 uint16_t mayhave_attrs)
1460 {
1461         struct tevent_req *req = NULL, *subreq = NULL;
1462         struct cli_unlink_state *state = NULL;
1463         uint8_t additional_flags = 0;
1464         uint8_t *bytes = NULL;
1465
1466         req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1467         if (req == NULL) {
1468                 return NULL;
1469         }
1470
1471         SSVAL(state->vwv+0, 0, mayhave_attrs);
1472
1473         bytes = talloc_array(state, uint8_t, 1);
1474         if (tevent_req_nomem(bytes, req)) {
1475                 return tevent_req_post(req, ev);
1476         }
1477         bytes[0] = 4;
1478         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
1479                                    strlen(fname)+1, NULL);
1480
1481         if (tevent_req_nomem(bytes, req)) {
1482                 return tevent_req_post(req, ev);
1483         }
1484
1485         subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1486                                 1, state->vwv, talloc_get_size(bytes), bytes);
1487         if (tevent_req_nomem(subreq, req)) {
1488                 return tevent_req_post(req, ev);
1489         }
1490         tevent_req_set_callback(subreq, cli_unlink_done, req);
1491         return req;
1492 }
1493
1494 static void cli_unlink_done(struct tevent_req *subreq)
1495 {
1496         struct tevent_req *req = tevent_req_callback_data(
1497                 subreq, struct tevent_req);
1498         NTSTATUS status;
1499
1500         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1501         TALLOC_FREE(subreq);
1502         if (!NT_STATUS_IS_OK(status)) {
1503                 tevent_req_nterror(req, status);
1504                 return;
1505         }
1506         tevent_req_done(req);
1507 }
1508
1509 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1510 {
1511         return tevent_req_simple_recv_ntstatus(req);
1512 }
1513
1514 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1515 {
1516         TALLOC_CTX *frame = talloc_stackframe();
1517         struct event_context *ev;
1518         struct tevent_req *req;
1519         NTSTATUS status = NT_STATUS_OK;
1520
1521         if (cli_has_async_calls(cli)) {
1522                 /*
1523                  * Can't use sync call while an async call is in flight
1524                  */
1525                 status = NT_STATUS_INVALID_PARAMETER;
1526                 goto fail;
1527         }
1528
1529         ev = event_context_init(frame);
1530         if (ev == NULL) {
1531                 status = NT_STATUS_NO_MEMORY;
1532                 goto fail;
1533         }
1534
1535         req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1536         if (req == NULL) {
1537                 status = NT_STATUS_NO_MEMORY;
1538                 goto fail;
1539         }
1540
1541         if (!tevent_req_poll(req, ev)) {
1542                 status = map_nt_error_from_unix(errno);
1543                 goto fail;
1544         }
1545
1546         status = cli_unlink_recv(req);
1547
1548  fail:
1549         TALLOC_FREE(frame);
1550         if (!NT_STATUS_IS_OK(status)) {
1551                 cli_set_error(cli, status);
1552         }
1553         return status;
1554 }
1555
1556 /****************************************************************************
1557  Create a directory.
1558 ****************************************************************************/
1559
1560 static void cli_mkdir_done(struct tevent_req *subreq);
1561
1562 struct cli_mkdir_state {
1563         int dummy;
1564 };
1565
1566 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1567                                   struct event_context *ev,
1568                                   struct cli_state *cli,
1569                                   const char *dname)
1570 {
1571         struct tevent_req *req = NULL, *subreq = NULL;
1572         struct cli_mkdir_state *state = NULL;
1573         uint8_t additional_flags = 0;
1574         uint8_t *bytes = NULL;
1575
1576         req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1577         if (req == NULL) {
1578                 return NULL;
1579         }
1580
1581         bytes = talloc_array(state, uint8_t, 1);
1582         if (tevent_req_nomem(bytes, req)) {
1583                 return tevent_req_post(req, ev);
1584         }
1585         bytes[0] = 4;
1586         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1587                                    strlen(dname)+1, NULL);
1588
1589         if (tevent_req_nomem(bytes, req)) {
1590                 return tevent_req_post(req, ev);
1591         }
1592
1593         subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1594                               0, NULL, talloc_get_size(bytes), bytes);
1595         if (tevent_req_nomem(subreq, req)) {
1596                 return tevent_req_post(req, ev);
1597         }
1598         tevent_req_set_callback(subreq, cli_mkdir_done, req);
1599         return req;
1600 }
1601
1602 static void cli_mkdir_done(struct tevent_req *subreq)
1603 {
1604         struct tevent_req *req = tevent_req_callback_data(
1605                 subreq, struct tevent_req);
1606         NTSTATUS status;
1607
1608         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1609         TALLOC_FREE(subreq);
1610         if (!NT_STATUS_IS_OK(status)) {
1611                 tevent_req_nterror(req, status);
1612                 return;
1613         }
1614         tevent_req_done(req);
1615 }
1616
1617 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1618 {
1619         return tevent_req_simple_recv_ntstatus(req);
1620 }
1621
1622 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1623 {
1624         TALLOC_CTX *frame = talloc_stackframe();
1625         struct event_context *ev;
1626         struct tevent_req *req;
1627         NTSTATUS status = NT_STATUS_OK;
1628
1629         if (cli_has_async_calls(cli)) {
1630                 /*
1631                  * Can't use sync call while an async call is in flight
1632                  */
1633                 status = NT_STATUS_INVALID_PARAMETER;
1634                 goto fail;
1635         }
1636
1637         ev = event_context_init(frame);
1638         if (ev == NULL) {
1639                 status = NT_STATUS_NO_MEMORY;
1640                 goto fail;
1641         }
1642
1643         req = cli_mkdir_send(frame, ev, cli, dname);
1644         if (req == NULL) {
1645                 status = NT_STATUS_NO_MEMORY;
1646                 goto fail;
1647         }
1648
1649         if (!tevent_req_poll(req, ev)) {
1650                 status = map_nt_error_from_unix(errno);
1651                 goto fail;
1652         }
1653
1654         status = cli_mkdir_recv(req);
1655
1656  fail:
1657         TALLOC_FREE(frame);
1658         if (!NT_STATUS_IS_OK(status)) {
1659                 cli_set_error(cli, status);
1660         }
1661         return status;
1662 }
1663
1664 /****************************************************************************
1665  Remove a directory.
1666 ****************************************************************************/
1667
1668 static void cli_rmdir_done(struct tevent_req *subreq);
1669
1670 struct cli_rmdir_state {
1671         int dummy;
1672 };
1673
1674 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1675                                   struct event_context *ev,
1676                                   struct cli_state *cli,
1677                                   const char *dname)
1678 {
1679         struct tevent_req *req = NULL, *subreq = NULL;
1680         struct cli_rmdir_state *state = NULL;
1681         uint8_t additional_flags = 0;
1682         uint8_t *bytes = NULL;
1683
1684         req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1685         if (req == NULL) {
1686                 return NULL;
1687         }
1688
1689         bytes = talloc_array(state, uint8_t, 1);
1690         if (tevent_req_nomem(bytes, req)) {
1691                 return tevent_req_post(req, ev);
1692         }
1693         bytes[0] = 4;
1694         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1695                                    strlen(dname)+1, NULL);
1696
1697         if (tevent_req_nomem(bytes, req)) {
1698                 return tevent_req_post(req, ev);
1699         }
1700
1701         subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1702                               0, NULL, talloc_get_size(bytes), bytes);
1703         if (tevent_req_nomem(subreq, req)) {
1704                 return tevent_req_post(req, ev);
1705         }
1706         tevent_req_set_callback(subreq, cli_rmdir_done, req);
1707         return req;
1708 }
1709
1710 static void cli_rmdir_done(struct tevent_req *subreq)
1711 {
1712         struct tevent_req *req = tevent_req_callback_data(
1713                 subreq, struct tevent_req);
1714         NTSTATUS status;
1715
1716         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1717         TALLOC_FREE(subreq);
1718         if (!NT_STATUS_IS_OK(status)) {
1719                 tevent_req_nterror(req, status);
1720                 return;
1721         }
1722         tevent_req_done(req);
1723 }
1724
1725 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1726 {
1727         return tevent_req_simple_recv_ntstatus(req);
1728 }
1729
1730 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1731 {
1732         TALLOC_CTX *frame = talloc_stackframe();
1733         struct event_context *ev;
1734         struct tevent_req *req;
1735         NTSTATUS status = NT_STATUS_OK;
1736
1737         if (cli_has_async_calls(cli)) {
1738                 /*
1739                  * Can't use sync call while an async call is in flight
1740                  */
1741                 status = NT_STATUS_INVALID_PARAMETER;
1742                 goto fail;
1743         }
1744
1745         ev = event_context_init(frame);
1746         if (ev == NULL) {
1747                 status = NT_STATUS_NO_MEMORY;
1748                 goto fail;
1749         }
1750
1751         req = cli_rmdir_send(frame, ev, cli, dname);
1752         if (req == NULL) {
1753                 status = NT_STATUS_NO_MEMORY;
1754                 goto fail;
1755         }
1756
1757         if (!tevent_req_poll(req, ev)) {
1758                 status = map_nt_error_from_unix(errno);
1759                 goto fail;
1760         }
1761
1762         status = cli_rmdir_recv(req);
1763
1764  fail:
1765         TALLOC_FREE(frame);
1766         if (!NT_STATUS_IS_OK(status)) {
1767                 cli_set_error(cli, status);
1768         }
1769         return status;
1770 }
1771
1772 /****************************************************************************
1773  Set or clear the delete on close flag.
1774 ****************************************************************************/
1775
1776 struct doc_state {
1777         uint16_t setup;
1778         uint8_t param[6];
1779         uint8_t data[1];
1780 };
1781
1782 static void cli_nt_delete_on_close_done(struct tevent_req *subreq)
1783 {
1784         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
1785                                          NULL, 0, NULL, NULL, 0, NULL);
1786         tevent_req_simple_finish_ntstatus(subreq, status);
1787 }
1788
1789 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1790                                         struct event_context *ev,
1791                                         struct cli_state *cli,
1792                                         uint16_t fnum,
1793                                         bool flag)
1794 {
1795         struct tevent_req *req = NULL, *subreq = NULL;
1796         struct doc_state *state = NULL;
1797
1798         req = tevent_req_create(mem_ctx, &state, struct doc_state);
1799         if (req == NULL) {
1800                 return NULL;
1801         }
1802
1803         /* Setup setup word. */
1804         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1805
1806         /* Setup param array. */
1807         SSVAL(state->param,0,fnum);
1808         SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1809
1810         /* Setup data array. */
1811         SCVAL(&state->data[0], 0, flag ? 1 : 0);
1812
1813         subreq = cli_trans_send(state,                  /* mem ctx. */
1814                                 ev,                     /* event ctx. */
1815                                 cli,                    /* cli_state. */
1816                                 SMBtrans2,              /* cmd. */
1817                                 NULL,                   /* pipe name. */
1818                                 -1,                     /* fid. */
1819                                 0,                      /* function. */
1820                                 0,                      /* flags. */
1821                                 &state->setup,          /* setup. */
1822                                 1,                      /* num setup uint16_t words. */
1823                                 0,                      /* max returned setup. */
1824                                 state->param,           /* param. */
1825                                 6,                      /* num param. */
1826                                 2,                      /* max returned param. */
1827                                 state->data,            /* data. */
1828                                 1,                      /* num data. */
1829                                 0);                     /* max returned data. */
1830
1831         if (tevent_req_nomem(subreq, req)) {
1832                 return tevent_req_post(req, ev);
1833         }
1834         tevent_req_set_callback(subreq, cli_nt_delete_on_close_done, req);
1835         return req;
1836 }
1837
1838 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1839 {
1840         return tevent_req_simple_recv_ntstatus(req);
1841 }
1842
1843 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1844 {
1845         TALLOC_CTX *frame = talloc_stackframe();
1846         struct event_context *ev = NULL;
1847         struct tevent_req *req = NULL;
1848         NTSTATUS status = NT_STATUS_OK;
1849
1850         if (cli_has_async_calls(cli)) {
1851                 /*
1852                  * Can't use sync call while an async call is in flight
1853                  */
1854                 status = NT_STATUS_INVALID_PARAMETER;
1855                 goto fail;
1856         }
1857
1858         ev = event_context_init(frame);
1859         if (ev == NULL) {
1860                 status = NT_STATUS_NO_MEMORY;
1861                 goto fail;
1862         }
1863
1864         req = cli_nt_delete_on_close_send(frame,
1865                                 ev,
1866                                 cli,
1867                                 fnum,
1868                                 flag);
1869         if (req == NULL) {
1870                 status = NT_STATUS_NO_MEMORY;
1871                 goto fail;
1872         }
1873
1874         if (!tevent_req_poll(req, ev)) {
1875                 status = map_nt_error_from_unix(errno);
1876                 goto fail;
1877         }
1878
1879         status = cli_nt_delete_on_close_recv(req);
1880
1881  fail:
1882         TALLOC_FREE(frame);
1883         if (!NT_STATUS_IS_OK(status)) {
1884                 cli_set_error(cli, status);
1885         }
1886         return status;
1887 }
1888
1889 struct cli_ntcreate_state {
1890         uint16_t vwv[24];
1891         uint16_t fnum;
1892 };
1893
1894 static void cli_ntcreate_done(struct tevent_req *subreq);
1895
1896 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
1897                                      struct event_context *ev,
1898                                      struct cli_state *cli,
1899                                      const char *fname,
1900                                      uint32_t CreatFlags,
1901                                      uint32_t DesiredAccess,
1902                                      uint32_t FileAttributes,
1903                                      uint32_t ShareAccess,
1904                                      uint32_t CreateDisposition,
1905                                      uint32_t CreateOptions,
1906                                      uint8_t SecurityFlags)
1907 {
1908         struct tevent_req *req, *subreq;
1909         struct cli_ntcreate_state *state;
1910         uint16_t *vwv;
1911         uint8_t *bytes;
1912         size_t converted_len;
1913
1914         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
1915         if (req == NULL) {
1916                 return NULL;
1917         }
1918
1919         vwv = state->vwv;
1920
1921         SCVAL(vwv+0, 0, 0xFF);
1922         SCVAL(vwv+0, 1, 0);
1923         SSVAL(vwv+1, 0, 0);
1924         SCVAL(vwv+2, 0, 0);
1925
1926         if (cli->use_oplocks) {
1927                 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1928         }
1929         SIVAL(vwv+3, 1, CreatFlags);
1930         SIVAL(vwv+5, 1, 0x0);   /* RootDirectoryFid */
1931         SIVAL(vwv+7, 1, DesiredAccess);
1932         SIVAL(vwv+9, 1, 0x0);   /* AllocationSize */
1933         SIVAL(vwv+11, 1, 0x0);  /* AllocationSize */
1934         SIVAL(vwv+13, 1, FileAttributes);
1935         SIVAL(vwv+15, 1, ShareAccess);
1936         SIVAL(vwv+17, 1, CreateDisposition);
1937         SIVAL(vwv+19, 1, CreateOptions);
1938         SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1939         SCVAL(vwv+23, 1, SecurityFlags);
1940
1941         bytes = talloc_array(state, uint8_t, 0);
1942         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
1943                                    fname, strlen(fname)+1,
1944                                    &converted_len);
1945
1946         /* sigh. this copes with broken netapp filer behaviour */
1947         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL);
1948
1949         if (tevent_req_nomem(bytes, req)) {
1950                 return tevent_req_post(req, ev);
1951         }
1952
1953         SSVAL(vwv+2, 1, converted_len);
1954
1955         subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
1956                               talloc_get_size(bytes), bytes);
1957         if (tevent_req_nomem(subreq, req)) {
1958                 return tevent_req_post(req, ev);
1959         }
1960         tevent_req_set_callback(subreq, cli_ntcreate_done, req);
1961         return req;
1962 }
1963
1964 static void cli_ntcreate_done(struct tevent_req *subreq)
1965 {
1966         struct tevent_req *req = tevent_req_callback_data(
1967                 subreq, struct tevent_req);
1968         struct cli_ntcreate_state *state = tevent_req_data(
1969                 req, struct cli_ntcreate_state);
1970         uint8_t wct;
1971         uint16_t *vwv;
1972         uint32_t num_bytes;
1973         uint8_t *bytes;
1974         uint8_t *inbuf;
1975         NTSTATUS status;
1976
1977         status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv,
1978                               &num_bytes, &bytes);
1979         TALLOC_FREE(subreq);
1980         if (!NT_STATUS_IS_OK(status)) {
1981                 tevent_req_nterror(req, status);
1982                 return;
1983         }
1984         state->fnum = SVAL(vwv+2, 1);
1985         tevent_req_done(req);
1986 }
1987
1988 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
1989 {
1990         struct cli_ntcreate_state *state = tevent_req_data(
1991                 req, struct cli_ntcreate_state);
1992         NTSTATUS status;
1993
1994         if (tevent_req_is_nterror(req, &status)) {
1995                 return status;
1996         }
1997         *pfnum = state->fnum;
1998         return NT_STATUS_OK;
1999 }
2000
2001 NTSTATUS cli_ntcreate(struct cli_state *cli,
2002                       const char *fname,
2003                       uint32_t CreatFlags,
2004                       uint32_t DesiredAccess,
2005                       uint32_t FileAttributes,
2006                       uint32_t ShareAccess,
2007                       uint32_t CreateDisposition,
2008                       uint32_t CreateOptions,
2009                       uint8_t SecurityFlags,
2010                       uint16_t *pfid)
2011 {
2012         TALLOC_CTX *frame = talloc_stackframe();
2013         struct event_context *ev;
2014         struct tevent_req *req;
2015         NTSTATUS status = NT_STATUS_OK;
2016
2017         if (cli_has_async_calls(cli)) {
2018                 /*
2019                  * Can't use sync call while an async call is in flight
2020                  */
2021                 status = NT_STATUS_INVALID_PARAMETER;
2022                 goto fail;
2023         }
2024
2025         ev = event_context_init(frame);
2026         if (ev == NULL) {
2027                 status = NT_STATUS_NO_MEMORY;
2028                 goto fail;
2029         }
2030
2031         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2032                                 DesiredAccess, FileAttributes, ShareAccess,
2033                                 CreateDisposition, CreateOptions,
2034                                 SecurityFlags);
2035         if (req == NULL) {
2036                 status = NT_STATUS_NO_MEMORY;
2037                 goto fail;
2038         }
2039
2040         if (!tevent_req_poll(req, ev)) {
2041                 status = map_nt_error_from_unix(errno);
2042                 goto fail;
2043         }
2044
2045         status = cli_ntcreate_recv(req, pfid);
2046  fail:
2047         TALLOC_FREE(frame);
2048         if (!NT_STATUS_IS_OK(status)) {
2049                 cli_set_error(cli, status);
2050         }
2051         return status;
2052 }
2053
2054 /****************************************************************************
2055  Open a file
2056  WARNING: if you open with O_WRONLY then getattrE won't work!
2057 ****************************************************************************/
2058
2059 struct cli_open_state {
2060         uint16_t vwv[15];
2061         uint16_t fnum;
2062         struct iovec bytes;
2063 };
2064
2065 static void cli_open_done(struct tevent_req *subreq);
2066
2067 struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx,
2068                                    struct event_context *ev,
2069                                    struct cli_state *cli, const char *fname,
2070                                    int flags, int share_mode,
2071                                    struct tevent_req **psmbreq)
2072 {
2073         struct tevent_req *req, *subreq;
2074         struct cli_open_state *state;
2075         unsigned openfn;
2076         unsigned accessmode;
2077         uint8_t additional_flags;
2078         uint8_t *bytes;
2079
2080         req = tevent_req_create(mem_ctx, &state, struct cli_open_state);
2081         if (req == NULL) {
2082                 return NULL;
2083         }
2084
2085         openfn = 0;
2086         if (flags & O_CREAT) {
2087                 openfn |= (1<<4);
2088         }
2089         if (!(flags & O_EXCL)) {
2090                 if (flags & O_TRUNC)
2091                         openfn |= (1<<1);
2092                 else
2093                         openfn |= (1<<0);
2094         }
2095
2096         accessmode = (share_mode<<4);
2097
2098         if ((flags & O_ACCMODE) == O_RDWR) {
2099                 accessmode |= 2;
2100         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2101                 accessmode |= 1;
2102         }
2103
2104 #if defined(O_SYNC)
2105         if ((flags & O_SYNC) == O_SYNC) {
2106                 accessmode |= (1<<14);
2107         }
2108 #endif /* O_SYNC */
2109
2110         if (share_mode == DENY_FCB) {
2111                 accessmode = 0xFF;
2112         }
2113
2114         SCVAL(state->vwv + 0, 0, 0xFF);
2115         SCVAL(state->vwv + 0, 1, 0);
2116         SSVAL(state->vwv + 1, 0, 0);
2117         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
2118         SSVAL(state->vwv + 3, 0, accessmode);
2119         SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2120         SSVAL(state->vwv + 5, 0, 0);
2121         SIVAL(state->vwv + 6, 0, 0);
2122         SSVAL(state->vwv + 8, 0, openfn);
2123         SIVAL(state->vwv + 9, 0, 0);
2124         SIVAL(state->vwv + 11, 0, 0);
2125         SIVAL(state->vwv + 13, 0, 0);
2126
2127         additional_flags = 0;
2128
2129         if (cli->use_oplocks) {
2130                 /* if using oplocks then ask for a batch oplock via
2131                    core and extended methods */
2132                 additional_flags =
2133                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2134                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2135         }
2136
2137         bytes = talloc_array(state, uint8_t, 0);
2138         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
2139                                    strlen(fname)+1, NULL);
2140
2141         if (tevent_req_nomem(bytes, req)) {
2142                 return tevent_req_post(req, ev);
2143         }
2144
2145         state->bytes.iov_base = (void *)bytes;
2146         state->bytes.iov_len = talloc_get_size(bytes);
2147
2148         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2149                                     15, state->vwv, 1, &state->bytes);
2150         if (subreq == NULL) {
2151                 TALLOC_FREE(req);
2152                 return NULL;
2153         }
2154         tevent_req_set_callback(subreq, cli_open_done, req);
2155         *psmbreq = subreq;
2156         return req;
2157 }
2158
2159 struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
2160                                  struct cli_state *cli, const char *fname,
2161                                  int flags, int share_mode)
2162 {
2163         struct tevent_req *req, *subreq;
2164         NTSTATUS status;
2165
2166         req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode,
2167                               &subreq);
2168         if (req == NULL) {
2169                 return NULL;
2170         }
2171
2172         status = cli_smb_req_send(subreq);
2173         if (!NT_STATUS_IS_OK(status)) {
2174                 tevent_req_nterror(req, status);
2175                 return tevent_req_post(req, ev);
2176         }
2177         return req;
2178 }
2179
2180 static void cli_open_done(struct tevent_req *subreq)
2181 {
2182         struct tevent_req *req = tevent_req_callback_data(
2183                 subreq, struct tevent_req);
2184         struct cli_open_state *state = tevent_req_data(
2185                 req, struct cli_open_state);
2186         uint8_t wct;
2187         uint16_t *vwv;
2188         uint8_t *inbuf;
2189         NTSTATUS status;
2190
2191         status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv, NULL,
2192                               NULL);
2193         TALLOC_FREE(subreq);
2194         if (!NT_STATUS_IS_OK(status)) {
2195                 tevent_req_nterror(req, status);
2196                 return;
2197         }
2198         state->fnum = SVAL(vwv+2, 0);
2199         tevent_req_done(req);
2200 }
2201
2202 NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum)
2203 {
2204         struct cli_open_state *state = tevent_req_data(
2205                 req, struct cli_open_state);
2206         NTSTATUS status;
2207
2208         if (tevent_req_is_nterror(req, &status)) {
2209                 return status;
2210         }
2211         *pfnum = state->fnum;
2212         return NT_STATUS_OK;
2213 }
2214
2215 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2216              int share_mode, uint16_t *pfnum)
2217 {
2218         TALLOC_CTX *frame = talloc_stackframe();
2219         struct event_context *ev;
2220         struct tevent_req *req;
2221         NTSTATUS status = NT_STATUS_OK;
2222
2223         if (cli_has_async_calls(cli)) {
2224                 /*
2225                  * Can't use sync call while an async call is in flight
2226                  */
2227                 status = NT_STATUS_INVALID_PARAMETER;
2228                 goto fail;
2229         }
2230
2231         ev = event_context_init(frame);
2232         if (ev == NULL) {
2233                 status = NT_STATUS_NO_MEMORY;
2234                 goto fail;
2235         }
2236
2237         req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
2238         if (req == NULL) {
2239                 status = NT_STATUS_NO_MEMORY;
2240                 goto fail;
2241         }
2242
2243         if (!tevent_req_poll(req, ev)) {
2244                 status = map_nt_error_from_unix(errno);
2245                 goto fail;
2246         }
2247
2248         status = cli_open_recv(req, pfnum);
2249  fail:
2250         TALLOC_FREE(frame);
2251         if (!NT_STATUS_IS_OK(status)) {
2252                 cli_set_error(cli, status);
2253         }
2254         return status;
2255 }
2256
2257 /****************************************************************************
2258  Close a file.
2259 ****************************************************************************/
2260
2261 struct cli_close_state {
2262         uint16_t vwv[3];
2263 };
2264
2265 static void cli_close_done(struct tevent_req *subreq);
2266
2267 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2268                                 struct event_context *ev,
2269                                 struct cli_state *cli,
2270                                 uint16_t fnum,
2271                                 struct tevent_req **psubreq)
2272 {
2273         struct tevent_req *req, *subreq;
2274         struct cli_close_state *state;
2275
2276         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2277         if (req == NULL) {
2278                 return NULL;
2279         }
2280
2281         SSVAL(state->vwv+0, 0, fnum);
2282         SIVALS(state->vwv+1, 0, -1);
2283
2284         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2285                                     0, NULL);
2286         if (subreq == NULL) {
2287                 TALLOC_FREE(req);
2288                 return NULL;
2289         }
2290         tevent_req_set_callback(subreq, cli_close_done, req);
2291         *psubreq = subreq;
2292         return req;
2293 }
2294
2295 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2296                                 struct event_context *ev,
2297                                 struct cli_state *cli,
2298                                 uint16_t fnum)
2299 {
2300         struct tevent_req *req, *subreq;
2301         NTSTATUS status;
2302
2303         req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2304         if (req == NULL) {
2305                 return NULL;
2306         }
2307
2308         status = cli_smb_req_send(subreq);
2309         if (!NT_STATUS_IS_OK(status)) {
2310                 tevent_req_nterror(req, status);
2311                 return tevent_req_post(req, ev);
2312         }
2313         return req;
2314 }
2315
2316 static void cli_close_done(struct tevent_req *subreq)
2317 {
2318         struct tevent_req *req = tevent_req_callback_data(
2319                 subreq, struct tevent_req);
2320         NTSTATUS status;
2321
2322         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2323         TALLOC_FREE(subreq);
2324         if (!NT_STATUS_IS_OK(status)) {
2325                 tevent_req_nterror(req, status);
2326                 return;
2327         }
2328         tevent_req_done(req);
2329 }
2330
2331 NTSTATUS cli_close_recv(struct tevent_req *req)
2332 {
2333         return tevent_req_simple_recv_ntstatus(req);
2334 }
2335
2336 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2337 {
2338         TALLOC_CTX *frame = talloc_stackframe();
2339         struct event_context *ev;
2340         struct tevent_req *req;
2341         NTSTATUS status = NT_STATUS_OK;
2342
2343         if (cli_has_async_calls(cli)) {
2344                 /*
2345                  * Can't use sync call while an async call is in flight
2346                  */
2347                 status = NT_STATUS_INVALID_PARAMETER;
2348                 goto fail;
2349         }
2350
2351         ev = event_context_init(frame);
2352         if (ev == NULL) {
2353                 status = NT_STATUS_NO_MEMORY;
2354                 goto fail;
2355         }
2356
2357         req = cli_close_send(frame, ev, cli, fnum);
2358         if (req == NULL) {
2359                 status = NT_STATUS_NO_MEMORY;
2360                 goto fail;
2361         }
2362
2363         if (!tevent_req_poll(req, ev)) {
2364                 status = map_nt_error_from_unix(errno);
2365                 goto fail;
2366         }
2367
2368         status = cli_close_recv(req);
2369  fail:
2370         TALLOC_FREE(frame);
2371         if (!NT_STATUS_IS_OK(status)) {
2372                 cli_set_error(cli, status);
2373         }
2374         return status;
2375 }
2376
2377 /****************************************************************************
2378  Truncate a file to a specified size
2379 ****************************************************************************/
2380
2381 struct ftrunc_state {
2382         uint16_t setup;
2383         uint8_t param[6];
2384         uint8_t data[8];
2385 };
2386
2387 static void cli_ftruncate_done(struct tevent_req *subreq)
2388 {
2389         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2390                                          NULL, 0, NULL, NULL, 0, NULL);
2391         tevent_req_simple_finish_ntstatus(subreq, status);
2392 }
2393
2394 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2395                                         struct event_context *ev,
2396                                         struct cli_state *cli,
2397                                         uint16_t fnum,
2398                                         uint64_t size)
2399 {
2400         struct tevent_req *req = NULL, *subreq = NULL;
2401         struct ftrunc_state *state = NULL;
2402
2403         req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2404         if (req == NULL) {
2405                 return NULL;
2406         }
2407
2408         /* Setup setup word. */
2409         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2410
2411         /* Setup param array. */
2412         SSVAL(state->param,0,fnum);
2413         SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2414         SSVAL(state->param,4,0);
2415
2416         /* Setup data array. */
2417         SBVAL(state->data, 0, size);
2418
2419         subreq = cli_trans_send(state,                  /* mem ctx. */
2420                                 ev,                     /* event ctx. */
2421                                 cli,                    /* cli_state. */
2422                                 SMBtrans2,              /* cmd. */
2423                                 NULL,                   /* pipe name. */
2424                                 -1,                     /* fid. */
2425                                 0,                      /* function. */
2426                                 0,                      /* flags. */
2427                                 &state->setup,          /* setup. */
2428                                 1,                      /* num setup uint16_t words. */
2429                                 0,                      /* max returned setup. */
2430                                 state->param,           /* param. */
2431                                 6,                      /* num param. */
2432                                 2,                      /* max returned param. */
2433                                 state->data,            /* data. */
2434                                 8,                      /* num data. */
2435                                 0);                     /* max returned data. */
2436
2437         if (tevent_req_nomem(subreq, req)) {
2438                 return tevent_req_post(req, ev);
2439         }
2440         tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2441         return req;
2442 }
2443
2444 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2445 {
2446         return tevent_req_simple_recv_ntstatus(req);
2447 }
2448
2449 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2450 {
2451         TALLOC_CTX *frame = talloc_stackframe();
2452         struct event_context *ev = NULL;
2453         struct tevent_req *req = NULL;
2454         NTSTATUS status = NT_STATUS_OK;
2455
2456         if (cli_has_async_calls(cli)) {
2457                 /*
2458                  * Can't use sync call while an async call is in flight
2459                  */
2460                 status = NT_STATUS_INVALID_PARAMETER;
2461                 goto fail;
2462         }
2463
2464         ev = event_context_init(frame);
2465         if (ev == NULL) {
2466                 status = NT_STATUS_NO_MEMORY;
2467                 goto fail;
2468         }
2469
2470         req = cli_ftruncate_send(frame,
2471                                 ev,
2472                                 cli,
2473                                 fnum,
2474                                 size);
2475         if (req == NULL) {
2476                 status = NT_STATUS_NO_MEMORY;
2477                 goto fail;
2478         }
2479
2480         if (!tevent_req_poll(req, ev)) {
2481                 status = map_nt_error_from_unix(errno);
2482                 goto fail;
2483         }
2484
2485         status = cli_ftruncate_recv(req);
2486
2487  fail:
2488         TALLOC_FREE(frame);
2489         if (!NT_STATUS_IS_OK(status)) {
2490                 cli_set_error(cli, status);
2491         }
2492         return status;
2493 }
2494
2495 /****************************************************************************
2496  send a lock with a specified locktype
2497  this is used for testing LOCKING_ANDX_CANCEL_LOCK
2498 ****************************************************************************/
2499
2500 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2501                       uint32_t offset, uint32_t len,
2502                       int timeout, unsigned char locktype)
2503 {
2504         uint16_t vwv[8];
2505         uint8_t bytes[10];
2506         NTSTATUS status;
2507         int saved_timeout;
2508
2509         SCVAL(vwv + 0, 0, 0xff);
2510         SCVAL(vwv + 0, 1, 0);
2511         SSVAL(vwv + 1, 0, 0);
2512         SSVAL(vwv + 2, 0, fnum);
2513         SCVAL(vwv + 3, 0, locktype);
2514         SCVAL(vwv + 3, 1, 0);
2515         SIVALS(vwv + 4, 0, timeout);
2516         SSVAL(vwv + 6, 0, 0);
2517         SSVAL(vwv + 7, 0, 1);
2518
2519         SSVAL(bytes, 0, cli->pid);
2520         SIVAL(bytes, 2, offset);
2521         SIVAL(bytes, 6, len);
2522
2523         saved_timeout = cli->timeout;
2524
2525         if (timeout != 0) {
2526                 cli->timeout = (timeout == -1)
2527                         ? 0x7FFFFFFF : (timeout + 2*1000);
2528         }
2529
2530         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2531                          10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2532
2533         cli->timeout = saved_timeout;
2534
2535         return status;
2536 }
2537
2538 /****************************************************************************
2539  Lock a file.
2540  note that timeout is in units of 2 milliseconds
2541 ****************************************************************************/
2542
2543 bool cli_lock(struct cli_state *cli, uint16_t fnum,
2544                   uint32_t offset, uint32_t len, int timeout,
2545                   enum brl_type lock_type)
2546 {
2547         NTSTATUS status;
2548
2549         status = cli_locktype(cli, fnum, offset, len, timeout,
2550                               (lock_type == READ_LOCK? 1 : 0));
2551         cli_set_error(cli, status);
2552         return NT_STATUS_IS_OK(status);
2553 }
2554
2555 /****************************************************************************
2556  Unlock a file.
2557 ****************************************************************************/
2558
2559 struct cli_unlock_state {
2560         uint16_t vwv[8];
2561         uint8_t data[10];
2562 };
2563
2564 static void cli_unlock_done(struct tevent_req *subreq);
2565
2566 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
2567                                 struct event_context *ev,
2568                                 struct cli_state *cli,
2569                                 uint16_t fnum,
2570                                 uint64_t offset,
2571                                 uint64_t len)
2572
2573 {
2574         struct tevent_req *req = NULL, *subreq = NULL;
2575         struct cli_unlock_state *state = NULL;
2576         uint8_t additional_flags = 0;
2577
2578         req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
2579         if (req == NULL) {
2580                 return NULL;
2581         }
2582
2583         SCVAL(state->vwv+0, 0, 0xFF);
2584         SSVAL(state->vwv+2, 0, fnum);
2585         SCVAL(state->vwv+3, 0, 0);
2586         SIVALS(state->vwv+4, 0, 0);
2587         SSVAL(state->vwv+6, 0, 1);
2588         SSVAL(state->vwv+7, 0, 0);
2589
2590         SSVAL(state->data, 0, cli->pid);
2591         SIVAL(state->data, 2, offset);
2592         SIVAL(state->data, 6, len);
2593
2594         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2595                                 8, state->vwv, 10, state->data);
2596         if (tevent_req_nomem(subreq, req)) {
2597                 return tevent_req_post(req, ev);
2598         }
2599         tevent_req_set_callback(subreq, cli_unlock_done, req);
2600         return req;
2601 }
2602
2603 static void cli_unlock_done(struct tevent_req *subreq)
2604 {
2605         struct tevent_req *req = tevent_req_callback_data(
2606                                 subreq, struct tevent_req);
2607         NTSTATUS status;
2608
2609         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2610         TALLOC_FREE(subreq);
2611         if (!NT_STATUS_IS_OK(status)) {
2612                 tevent_req_nterror(req, status);
2613                 return;
2614         }
2615         tevent_req_done(req);
2616 }
2617
2618 NTSTATUS cli_unlock_recv(struct tevent_req *req)
2619 {
2620         return tevent_req_simple_recv_ntstatus(req);
2621 }
2622
2623 NTSTATUS cli_unlock(struct cli_state *cli,
2624                         uint16_t fnum,
2625                         uint32_t offset,
2626                         uint32_t len)
2627 {
2628         TALLOC_CTX *frame = talloc_stackframe();
2629         struct event_context *ev;
2630         struct tevent_req *req;
2631         NTSTATUS status = NT_STATUS_OK;
2632
2633         if (cli_has_async_calls(cli)) {
2634                 /*
2635                  * Can't use sync call while an async call is in flight
2636                  */
2637                 status = NT_STATUS_INVALID_PARAMETER;
2638                 goto fail;
2639         }
2640
2641         ev = event_context_init(frame);
2642         if (ev == NULL) {
2643                 status = NT_STATUS_NO_MEMORY;
2644                 goto fail;
2645         }
2646
2647         req = cli_unlock_send(frame, ev, cli,
2648                         fnum, offset, len);
2649         if (req == NULL) {
2650                 status = NT_STATUS_NO_MEMORY;
2651                 goto fail;
2652         }
2653
2654         if (!tevent_req_poll(req, ev)) {
2655                 status = map_nt_error_from_unix(errno);
2656                 goto fail;
2657         }
2658
2659         status = cli_unlock_recv(req);
2660
2661  fail:
2662         TALLOC_FREE(frame);
2663         if (!NT_STATUS_IS_OK(status)) {
2664                 cli_set_error(cli, status);
2665         }
2666         return status;
2667 }
2668
2669 /****************************************************************************
2670  Lock a file with 64 bit offsets.
2671 ****************************************************************************/
2672
2673 bool cli_lock64(struct cli_state *cli, uint16_t fnum,
2674                 uint64_t offset, uint64_t len, int timeout,
2675                 enum brl_type lock_type)
2676 {
2677         uint16_t vwv[8];
2678         uint8_t bytes[20];
2679         int saved_timeout = cli->timeout;
2680         int ltype;
2681         NTSTATUS status;
2682
2683         if (! (cli->capabilities & CAP_LARGE_FILES)) {
2684                 return cli_lock(cli, fnum, offset, len, timeout, lock_type);
2685         }
2686
2687         ltype = (lock_type == READ_LOCK? 1 : 0);
2688         ltype |= LOCKING_ANDX_LARGE_FILES;
2689
2690         SCVAL(vwv + 0, 0, 0xff);
2691         SCVAL(vwv + 0, 1, 0);
2692         SSVAL(vwv + 1, 0, 0);
2693         SSVAL(vwv + 2, 0, fnum);
2694         SCVAL(vwv + 3, 0, ltype);
2695         SCVAL(vwv + 3, 1, 0);
2696         SIVALS(vwv + 4, 0, timeout);
2697         SSVAL(vwv + 6, 0, 0);
2698         SSVAL(vwv + 7, 0, 1);
2699
2700         SIVAL(bytes, 0, cli->pid);
2701         SOFF_T_R(bytes, 4, offset);
2702         SOFF_T_R(bytes, 12, len);
2703
2704         saved_timeout = cli->timeout;
2705
2706         if (timeout != 0) {
2707                 cli->timeout = (timeout == -1)
2708                         ? 0x7FFFFFFF : (timeout + 2*1000);
2709         }
2710
2711         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2712                          20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2713
2714         cli->timeout = saved_timeout;
2715
2716         cli_set_error(cli, status);
2717         return NT_STATUS_IS_OK(status);
2718 }
2719
2720 /****************************************************************************
2721  Unlock a file with 64 bit offsets.
2722 ****************************************************************************/
2723
2724 struct cli_unlock64_state {
2725         uint16_t vwv[8];
2726         uint8_t data[20];
2727 };
2728
2729 static void cli_unlock64_done(struct tevent_req *subreq);
2730
2731 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
2732                                 struct event_context *ev,
2733                                 struct cli_state *cli,
2734                                 uint16_t fnum,
2735                                 uint64_t offset,
2736                                 uint64_t len)
2737
2738 {
2739         struct tevent_req *req = NULL, *subreq = NULL;
2740         struct cli_unlock64_state *state = NULL;
2741         uint8_t additional_flags = 0;
2742
2743         req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
2744         if (req == NULL) {
2745                 return NULL;
2746         }
2747
2748         SCVAL(state->vwv+0, 0, 0xff);
2749         SSVAL(state->vwv+2, 0, fnum);
2750         SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
2751         SIVALS(state->vwv+4, 0, 0);
2752         SSVAL(state->vwv+6, 0, 1);
2753         SSVAL(state->vwv+7, 0, 0);
2754
2755         SIVAL(state->data, 0, cli->pid);
2756         SOFF_T_R(state->data, 4, offset);
2757         SOFF_T_R(state->data, 12, len);
2758
2759         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2760                                 8, state->vwv, 20, state->data);
2761         if (tevent_req_nomem(subreq, req)) {
2762                 return tevent_req_post(req, ev);
2763         }
2764         tevent_req_set_callback(subreq, cli_unlock64_done, req);
2765         return req;
2766 }
2767
2768 static void cli_unlock64_done(struct tevent_req *subreq)
2769 {
2770         struct tevent_req *req = tevent_req_callback_data(
2771                                 subreq, struct tevent_req);
2772         NTSTATUS status;
2773
2774         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2775         TALLOC_FREE(subreq);
2776         if (!NT_STATUS_IS_OK(status)) {
2777                 tevent_req_nterror(req, status);
2778                 return;
2779         }
2780         tevent_req_done(req);
2781 }
2782
2783 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
2784 {
2785         return tevent_req_simple_recv_ntstatus(req);
2786 }
2787
2788 NTSTATUS cli_unlock64(struct cli_state *cli,
2789                                 uint16_t fnum,
2790                                 uint64_t offset,
2791                                 uint64_t len)
2792 {
2793         TALLOC_CTX *frame = talloc_stackframe();
2794         struct event_context *ev;
2795         struct tevent_req *req;
2796         NTSTATUS status = NT_STATUS_OK;
2797
2798         if (! (cli->capabilities & CAP_LARGE_FILES)) {
2799                 return cli_unlock(cli, fnum, offset, len);
2800         }
2801
2802         if (cli_has_async_calls(cli)) {
2803                 /*
2804                  * Can't use sync call while an async call is in flight
2805                  */
2806                 status = NT_STATUS_INVALID_PARAMETER;
2807                 goto fail;
2808         }
2809
2810         ev = event_context_init(frame);
2811         if (ev == NULL) {
2812                 status = NT_STATUS_NO_MEMORY;
2813                 goto fail;
2814         }
2815
2816         req = cli_unlock64_send(frame, ev, cli,
2817                         fnum, offset, len);
2818         if (req == NULL) {
2819                 status = NT_STATUS_NO_MEMORY;
2820                 goto fail;
2821         }
2822
2823         if (!tevent_req_poll(req, ev)) {
2824                 status = map_nt_error_from_unix(errno);
2825                 goto fail;
2826         }
2827
2828         status = cli_unlock64_recv(req);
2829
2830  fail:
2831         TALLOC_FREE(frame);
2832         if (!NT_STATUS_IS_OK(status)) {
2833                 cli_set_error(cli, status);
2834         }
2835         return status;
2836 }
2837
2838 /****************************************************************************
2839  Get/unlock a POSIX lock on a file - internal function.
2840 ****************************************************************************/
2841
2842 struct posix_lock_state {
2843         uint16_t setup;
2844         uint8_t param[4];
2845         uint8_t data[POSIX_LOCK_DATA_SIZE];
2846 };
2847
2848 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
2849 {
2850         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2851                                          NULL, 0, NULL, NULL, 0, NULL);
2852         tevent_req_simple_finish_ntstatus(subreq, status);
2853 }
2854
2855 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
2856                                         struct event_context *ev,
2857                                         struct cli_state *cli,
2858                                         uint16_t fnum,
2859                                         uint64_t offset,
2860                                         uint64_t len,
2861                                         bool wait_lock,
2862                                         enum brl_type lock_type)
2863 {
2864         struct tevent_req *req = NULL, *subreq = NULL;
2865         struct posix_lock_state *state = NULL;
2866
2867         req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
2868         if (req == NULL) {
2869                 return NULL;
2870         }
2871
2872         /* Setup setup word. */
2873         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2874
2875         /* Setup param array. */
2876         SSVAL(&state->param, 0, fnum);
2877         SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
2878
2879         /* Setup data array. */
2880         switch (lock_type) {
2881                 case READ_LOCK:
2882                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2883                                 POSIX_LOCK_TYPE_READ);
2884                         break;
2885                 case WRITE_LOCK:
2886                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2887                                 POSIX_LOCK_TYPE_WRITE);
2888                         break;
2889                 case UNLOCK_LOCK:
2890                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2891                                 POSIX_LOCK_TYPE_UNLOCK);
2892                         break;
2893                 default:
2894                         return NULL;
2895         }
2896
2897         if (wait_lock) {
2898                 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
2899                                 POSIX_LOCK_FLAG_WAIT);
2900         } else {
2901                 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
2902                                 POSIX_LOCK_FLAG_NOWAIT);
2903         }
2904
2905         SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli->pid);
2906         SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
2907         SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
2908
2909         subreq = cli_trans_send(state,                  /* mem ctx. */
2910                                 ev,                     /* event ctx. */
2911                                 cli,                    /* cli_state. */
2912                                 SMBtrans2,              /* cmd. */
2913                                 NULL,                   /* pipe name. */
2914                                 -1,                     /* fid. */
2915                                 0,                      /* function. */
2916                                 0,                      /* flags. */
2917                                 &state->setup,          /* setup. */
2918                                 1,                      /* num setup uint16_t words. */
2919                                 0,                      /* max returned setup. */
2920                                 state->param,           /* param. */
2921                                 4,                      /* num param. */
2922                                 2,                      /* max returned param. */
2923                                 state->data,            /* data. */
2924                                 POSIX_LOCK_DATA_SIZE,   /* num data. */
2925                                 0);                     /* max returned data. */
2926
2927         if (tevent_req_nomem(subreq, req)) {
2928                 return tevent_req_post(req, ev);
2929         }
2930         tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
2931         return req;
2932 }
2933
2934 /****************************************************************************
2935  POSIX Lock a file.
2936 ****************************************************************************/
2937
2938 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
2939                                         struct event_context *ev,
2940                                         struct cli_state *cli,
2941                                         uint16_t fnum,
2942                                         uint64_t offset,
2943                                         uint64_t len,
2944                                         bool wait_lock,
2945                                         enum brl_type lock_type)
2946 {
2947         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
2948                                         wait_lock, lock_type);
2949 }
2950
2951 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
2952 {
2953         return tevent_req_simple_recv_ntstatus(req);
2954 }
2955
2956 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
2957                         uint64_t offset, uint64_t len,
2958                         bool wait_lock, enum brl_type lock_type)
2959 {
2960         TALLOC_CTX *frame = talloc_stackframe();
2961         struct event_context *ev = NULL;
2962         struct tevent_req *req = NULL;
2963         NTSTATUS status = NT_STATUS_OK;
2964
2965         if (cli_has_async_calls(cli)) {
2966                 /*
2967                  * Can't use sync call while an async call is in flight
2968                  */
2969                 status = NT_STATUS_INVALID_PARAMETER;
2970                 goto fail;
2971         }
2972
2973         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
2974                 status = NT_STATUS_INVALID_PARAMETER;
2975                 goto fail;
2976         }
2977
2978         ev = event_context_init(frame);
2979         if (ev == NULL) {
2980                 status = NT_STATUS_NO_MEMORY;
2981                 goto fail;
2982         }
2983
2984         req = cli_posix_lock_send(frame,
2985                                 ev,
2986                                 cli,
2987                                 fnum,
2988                                 offset,
2989                                 len,
2990                                 wait_lock,
2991                                 lock_type);
2992         if (req == NULL) {
2993                 status = NT_STATUS_NO_MEMORY;
2994                 goto fail;
2995         }
2996
2997         if (!tevent_req_poll(req, ev)) {
2998                 status = map_nt_error_from_unix(errno);
2999                 goto fail;
3000         }
3001
3002         status = cli_posix_lock_recv(req);
3003
3004  fail:
3005         TALLOC_FREE(frame);
3006         if (!NT_STATUS_IS_OK(status)) {
3007                 cli_set_error(cli, status);
3008         }
3009         return status;
3010 }
3011
3012 /****************************************************************************
3013  POSIX Unlock a file.
3014 ****************************************************************************/
3015
3016 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3017                                         struct event_context *ev,
3018                                         struct cli_state *cli,
3019                                         uint16_t fnum,
3020                                         uint64_t offset,
3021                                         uint64_t len)
3022 {
3023         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3024                                         false, UNLOCK_LOCK);
3025 }
3026
3027 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3028 {
3029         return tevent_req_simple_recv_ntstatus(req);
3030 }
3031
3032 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3033 {
3034         TALLOC_CTX *frame = talloc_stackframe();
3035         struct event_context *ev = NULL;
3036         struct tevent_req *req = NULL;
3037         NTSTATUS status = NT_STATUS_OK;
3038
3039         if (cli_has_async_calls(cli)) {
3040                 /*
3041                  * Can't use sync call while an async call is in flight
3042                  */
3043                 status = NT_STATUS_INVALID_PARAMETER;
3044                 goto fail;
3045         }
3046
3047         ev = event_context_init(frame);
3048         if (ev == NULL) {
3049                 status = NT_STATUS_NO_MEMORY;
3050                 goto fail;
3051         }
3052
3053         req = cli_posix_unlock_send(frame,
3054                                 ev,
3055                                 cli,
3056                                 fnum,
3057                                 offset,
3058                                 len);
3059         if (req == NULL) {
3060                 status = NT_STATUS_NO_MEMORY;
3061                 goto fail;
3062         }
3063
3064         if (!tevent_req_poll(req, ev)) {
3065                 status = map_nt_error_from_unix(errno);
3066                 goto fail;
3067         }
3068
3069         status = cli_posix_unlock_recv(req);
3070
3071  fail:
3072         TALLOC_FREE(frame);
3073         if (!NT_STATUS_IS_OK(status)) {
3074                 cli_set_error(cli, status);
3075         }
3076         return status;
3077 }
3078
3079 /****************************************************************************
3080  Do a SMBgetattrE call.
3081 ****************************************************************************/
3082
3083 static void cli_getattrE_done(struct tevent_req *subreq);
3084
3085 struct cli_getattrE_state {
3086         uint16_t vwv[1];
3087         int zone_offset;
3088         uint16_t attr;
3089         SMB_OFF_T size;
3090         time_t change_time;
3091         time_t access_time;
3092         time_t write_time;
3093 };
3094
3095 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3096                                 struct event_context *ev,
3097                                 struct cli_state *cli,
3098                                 uint16_t fnum)
3099 {
3100         struct tevent_req *req = NULL, *subreq = NULL;
3101         struct cli_getattrE_state *state = NULL;
3102         uint8_t additional_flags = 0;
3103
3104         req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3105         if (req == NULL) {
3106                 return NULL;
3107         }
3108
3109         state->zone_offset = cli->serverzone;
3110         SSVAL(state->vwv+0,0,fnum);
3111
3112         subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
3113                               1, state->vwv, 0, NULL);
3114         if (tevent_req_nomem(subreq, req)) {
3115                 return tevent_req_post(req, ev);
3116         }
3117         tevent_req_set_callback(subreq, cli_getattrE_done, req);
3118         return req;
3119 }
3120
3121 static void cli_getattrE_done(struct tevent_req *subreq)
3122 {
3123         struct tevent_req *req = tevent_req_callback_data(
3124                 subreq, struct tevent_req);
3125         struct cli_getattrE_state *state = tevent_req_data(
3126                 req, struct cli_getattrE_state);
3127         uint8_t wct;
3128         uint16_t *vwv = NULL;
3129         uint8_t *inbuf;
3130         NTSTATUS status;
3131
3132         status = cli_smb_recv(subreq, state, &inbuf, 11, &wct, &vwv,
3133                               NULL, NULL);
3134         TALLOC_FREE(subreq);
3135         if (!NT_STATUS_IS_OK(status)) {
3136                 tevent_req_nterror(req, status);
3137                 return;
3138         }
3139
3140         state->size = (SMB_OFF_T)IVAL(vwv+6,0);
3141         state->attr = SVAL(vwv+10,0);
3142         state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3143         state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3144         state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3145
3146         tevent_req_done(req);
3147 }
3148
3149 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3150                         uint16_t *attr,
3151                         SMB_OFF_T *size,
3152                         time_t *change_time,
3153                         time_t *access_time,
3154                         time_t *write_time)
3155 {
3156         struct cli_getattrE_state *state = tevent_req_data(
3157                                 req, struct cli_getattrE_state);
3158         NTSTATUS status;
3159
3160         if (tevent_req_is_nterror(req, &status)) {
3161                 return status;
3162         }
3163         if (attr) {
3164                 *attr = state->attr;
3165         }
3166         if (size) {
3167                 *size = state->size;
3168         }
3169         if (change_time) {
3170                 *change_time = state->change_time;
3171         }
3172         if (access_time) {
3173                 *access_time = state->access_time;
3174         }
3175         if (write_time) {
3176                 *write_time = state->write_time;
3177         }
3178         return NT_STATUS_OK;
3179 }
3180
3181 NTSTATUS cli_getattrE(struct cli_state *cli,
3182                         uint16_t fnum,
3183                         uint16_t *attr,
3184                         SMB_OFF_T *size,
3185                         time_t *change_time,
3186                         time_t *access_time,
3187                         time_t *write_time)
3188 {
3189         TALLOC_CTX *frame = talloc_stackframe();
3190         struct event_context *ev = NULL;
3191         struct tevent_req *req = NULL;
3192         NTSTATUS status = NT_STATUS_OK;
3193
3194         if (cli_has_async_calls(cli)) {
3195                 /*
3196                  * Can't use sync call while an async call is in flight
3197                  */
3198                 status = NT_STATUS_INVALID_PARAMETER;
3199                 goto fail;
3200         }
3201
3202         ev = event_context_init(frame);
3203         if (ev == NULL) {
3204                 status = NT_STATUS_NO_MEMORY;
3205                 goto fail;
3206         }
3207
3208         req = cli_getattrE_send(frame, ev, cli, fnum);
3209         if (req == NULL) {
3210                 status = NT_STATUS_NO_MEMORY;
3211                 goto fail;
3212         }
3213
3214         if (!tevent_req_poll(req, ev)) {
3215                 status = map_nt_error_from_unix(errno);
3216                 goto fail;
3217         }
3218
3219         status = cli_getattrE_recv(req,
3220                                         attr,
3221                                         size,
3222                                         change_time,
3223                                         access_time,
3224                                         write_time);
3225
3226  fail:
3227         TALLOC_FREE(frame);
3228         if (!NT_STATUS_IS_OK(status)) {
3229                 cli_set_error(cli, status);
3230         }
3231         return status;
3232 }
3233
3234 /****************************************************************************
3235  Do a SMBgetatr call
3236 ****************************************************************************/
3237
3238 static void cli_getatr_done(struct tevent_req *subreq);
3239
3240 struct cli_getatr_state {
3241         int zone_offset;
3242         uint16_t attr;
3243         SMB_OFF_T size;
3244         time_t write_time;
3245 };
3246
3247 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3248                                 struct event_context *ev,
3249                                 struct cli_state *cli,
3250                                 const char *fname)
3251 {
3252         struct tevent_req *req = NULL, *subreq = NULL;
3253         struct cli_getatr_state *state = NULL;
3254         uint8_t additional_flags = 0;
3255         uint8_t *bytes = NULL;
3256
3257         req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3258         if (req == NULL) {
3259                 return NULL;
3260         }
3261
3262         state->zone_offset = cli->serverzone;
3263
3264         bytes = talloc_array(state, uint8_t, 1);
3265         if (tevent_req_nomem(bytes, req)) {
3266                 return tevent_req_post(req, ev);
3267         }
3268         bytes[0] = 4;
3269         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3270                                    strlen(fname)+1, NULL);
3271
3272         if (tevent_req_nomem(bytes, req)) {
3273                 return tevent_req_post(req, ev);
3274         }
3275
3276         subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3277                               0, NULL, talloc_get_size(bytes), bytes);
3278         if (tevent_req_nomem(subreq, req)) {
3279                 return tevent_req_post(req, ev);
3280         }
3281         tevent_req_set_callback(subreq, cli_getatr_done, req);
3282         return req;
3283 }
3284
3285 static void cli_getatr_done(struct tevent_req *subreq)
3286 {
3287         struct tevent_req *req = tevent_req_callback_data(
3288                 subreq, struct tevent_req);
3289         struct cli_getatr_state *state = tevent_req_data(
3290                 req, struct cli_getatr_state);
3291         uint8_t wct;
3292         uint16_t *vwv = NULL;
3293         uint8_t *inbuf;
3294         NTSTATUS status;
3295
3296         status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3297                               NULL);
3298         TALLOC_FREE(subreq);
3299         if (!NT_STATUS_IS_OK(status)) {
3300                 tevent_req_nterror(req, status);
3301                 return;
3302         }
3303
3304         state->attr = SVAL(vwv+0,0);
3305         state->size = (SMB_OFF_T)IVAL(vwv+3,0);
3306         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3307
3308         tevent_req_done(req);
3309 }
3310
3311 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3312                         uint16_t *attr,
3313                         SMB_OFF_T *size,
3314                         time_t *write_time)
3315 {
3316         struct cli_getatr_state *state = tevent_req_data(
3317                                 req, struct cli_getatr_state);
3318         NTSTATUS status;
3319
3320         if (tevent_req_is_nterror(req, &status)) {
3321                 return status;
3322         }
3323         if (attr) {
3324                 *attr = state->attr;
3325         }
3326         if (size) {
3327                 *size = state->size;
3328         }
3329         if (write_time) {
3330                 *write_time = state->write_time;
3331         }
3332         return NT_STATUS_OK;
3333 }
3334
3335 NTSTATUS cli_getatr(struct cli_state *cli,
3336                         const char *fname,
3337                         uint16_t *attr,
3338                         SMB_OFF_T *size,
3339                         time_t *write_time)
3340 {
3341         TALLOC_CTX *frame = talloc_stackframe();
3342         struct event_context *ev = NULL;
3343         struct tevent_req *req = NULL;
3344         NTSTATUS status = NT_STATUS_OK;
3345
3346         if (cli_has_async_calls(cli)) {
3347                 /*
3348                  * Can't use sync call while an async call is in flight
3349                  */
3350                 status = NT_STATUS_INVALID_PARAMETER;
3351                 goto fail;
3352         }
3353
3354         ev = event_context_init(frame);
3355         if (ev == NULL) {
3356                 status = NT_STATUS_NO_MEMORY;
3357                 goto fail;
3358         }
3359
3360         req = cli_getatr_send(frame, ev, cli, fname);
3361         if (req == NULL) {
3362                 status = NT_STATUS_NO_MEMORY;
3363                 goto fail;
3364         }
3365
3366         if (!tevent_req_poll(req, ev)) {
3367                 status = map_nt_error_from_unix(errno);
3368                 goto fail;
3369         }
3370
3371         status = cli_getatr_recv(req,
3372                                 attr,
3373                                 size,
3374                                 write_time);
3375
3376  fail:
3377         TALLOC_FREE(frame);
3378         if (!NT_STATUS_IS_OK(status)) {
3379                 cli_set_error(cli, status);
3380         }
3381         return status;
3382 }
3383
3384 /****************************************************************************
3385  Do a SMBsetattrE call.
3386 ****************************************************************************/
3387
3388 static void cli_setattrE_done(struct tevent_req *subreq);
3389
3390 struct cli_setattrE_state {
3391         uint16_t vwv[7];
3392 };
3393
3394 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3395                                 struct event_context *ev,
3396                                 struct cli_state *cli,
3397                                 uint16_t fnum,
3398                                 time_t change_time,
3399                                 time_t access_time,
3400                                 time_t write_time)
3401 {
3402         struct tevent_req *req = NULL, *subreq = NULL;
3403         struct cli_setattrE_state *state = NULL;
3404         uint8_t additional_flags = 0;
3405
3406         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3407         if (req == NULL) {
3408                 return NULL;
3409         }
3410
3411         SSVAL(state->vwv+0, 0, fnum);
3412         push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
3413                        cli->serverzone);
3414         push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
3415                        cli->serverzone);
3416         push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
3417                        cli->serverzone);
3418
3419         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3420                               7, state->vwv, 0, NULL);
3421         if (tevent_req_nomem(subreq, req)) {
3422                 return tevent_req_post(req, ev);
3423         }
3424         tevent_req_set_callback(subreq, cli_setattrE_done, req);
3425         return req;
3426 }
3427
3428 static void cli_setattrE_done(struct tevent_req *subreq)
3429 {
3430         struct tevent_req *req = tevent_req_callback_data(
3431                 subreq, struct tevent_req);
3432         NTSTATUS status;
3433
3434         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3435         TALLOC_FREE(subreq);
3436         if (!NT_STATUS_IS_OK(status)) {
3437                 tevent_req_nterror(req, status);
3438                 return;
3439         }
3440         tevent_req_done(req);
3441 }
3442
3443 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3444 {
3445         return tevent_req_simple_recv_ntstatus(req);
3446 }
3447
3448 NTSTATUS cli_setattrE(struct cli_state *cli,
3449                         uint16_t fnum,
3450                         time_t change_time,
3451                         time_t access_time,
3452                         time_t write_time)
3453 {
3454         TALLOC_CTX *frame = talloc_stackframe();
3455         struct event_context *ev = NULL;
3456         struct tevent_req *req = NULL;
3457         NTSTATUS status = NT_STATUS_OK;
3458
3459         if (cli_has_async_calls(cli)) {
3460                 /*
3461                  * Can't use sync call while an async call is in flight
3462                  */
3463                 status = NT_STATUS_INVALID_PARAMETER;
3464                 goto fail;
3465         }
3466
3467         ev = event_context_init(frame);
3468         if (ev == NULL) {
3469                 status = NT_STATUS_NO_MEMORY;
3470                 goto fail;
3471         }
3472
3473         req = cli_setattrE_send(frame, ev,
3474                         cli,
3475                         fnum,
3476                         change_time,
3477                         access_time,
3478                         write_time);
3479
3480         if (req == NULL) {
3481                 status = NT_STATUS_NO_MEMORY;
3482                 goto fail;
3483         }
3484
3485         if (!tevent_req_poll(req, ev)) {
3486                 status = map_nt_error_from_unix(errno);
3487                 goto fail;
3488         }
3489
3490         status = cli_setattrE_recv(req);
3491
3492  fail:
3493         TALLOC_FREE(frame);
3494         if (!NT_STATUS_IS_OK(status)) {
3495                 cli_set_error(cli, status);
3496         }
3497         return status;
3498 }
3499
3500 /****************************************************************************
3501  Do a SMBsetatr call.
3502 ****************************************************************************/
3503
3504 static void cli_setatr_done(struct tevent_req *subreq);
3505
3506 struct cli_setatr_state {
3507         uint16_t vwv[8];
3508 };
3509
3510 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3511                                 struct event_context *ev,
3512                                 struct cli_state *cli,
3513                                 const char *fname,
3514                                 uint16_t attr,
3515                                 time_t mtime)
3516 {
3517         struct tevent_req *req = NULL, *subreq = NULL;
3518         struct cli_setatr_state *state = NULL;
3519         uint8_t additional_flags = 0;
3520         uint8_t *bytes = NULL;
3521
3522         req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3523         if (req == NULL) {
3524                 return NULL;
3525         }
3526
3527         SSVAL(state->vwv+0, 0, attr);
3528         push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, cli->serverzone);
3529
3530         bytes = talloc_array(state, uint8_t, 1);
3531         if (tevent_req_nomem(bytes, req)) {
3532                 return tevent_req_post(req, ev);
3533         }
3534         bytes[0] = 4;
3535         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3536                                    strlen(fname)+1, NULL);
3537         if (tevent_req_nomem(bytes, req)) {
3538                 return tevent_req_post(req, ev);
3539         }
3540         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
3541                         talloc_get_size(bytes)+1);
3542         if (tevent_req_nomem(bytes, req)) {
3543                 return tevent_req_post(req, ev);
3544         }
3545
3546         bytes[talloc_get_size(bytes)-1] = 4;
3547         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",
3548                                    1, NULL);
3549         if (tevent_req_nomem(bytes, req)) {
3550                 return tevent_req_post(req, ev);
3551         }
3552
3553         subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3554                               8, state->vwv, talloc_get_size(bytes), bytes);
3555         if (tevent_req_nomem(subreq, req)) {
3556                 return tevent_req_post(req, ev);
3557         }
3558         tevent_req_set_callback(subreq, cli_setatr_done, req);
3559         return req;
3560 }
3561
3562 static void cli_setatr_done(struct tevent_req *subreq)
3563 {
3564         struct tevent_req *req = tevent_req_callback_data(
3565                 subreq, struct tevent_req);
3566         NTSTATUS status;
3567
3568         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3569         TALLOC_FREE(subreq);
3570         if (!NT_STATUS_IS_OK(status)) {
3571                 tevent_req_nterror(req, status);
3572                 return;
3573         }
3574         tevent_req_done(req);
3575 }
3576
3577 NTSTATUS cli_setatr_recv(struct tevent_req *req)
3578 {
3579         return tevent_req_simple_recv_ntstatus(req);
3580 }
3581
3582 NTSTATUS cli_setatr(struct cli_state *cli,
3583                 const char *fname,
3584                 uint16_t attr,
3585                 time_t mtime)
3586 {
3587         TALLOC_CTX *frame = talloc_stackframe();
3588         struct event_context *ev = NULL;
3589         struct tevent_req *req = NULL;
3590         NTSTATUS status = NT_STATUS_OK;
3591
3592         if (cli_has_async_calls(cli)) {
3593                 /*
3594                  * Can't use sync call while an async call is in flight
3595                  */
3596                 status = NT_STATUS_INVALID_PARAMETER;
3597                 goto fail;
3598         }
3599
3600         ev = event_context_init(frame);
3601         if (ev == NULL) {
3602                 status = NT_STATUS_NO_MEMORY;
3603                 goto fail;
3604         }
3605
3606         req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
3607         if (req == NULL) {
3608                 status = NT_STATUS_NO_MEMORY;
3609                 goto fail;
3610         }
3611
3612         if (!tevent_req_poll(req, ev)) {
3613                 status = map_nt_error_from_unix(errno);
3614                 goto fail;
3615         }
3616
3617         status = cli_setatr_recv(req);
3618
3619  fail:
3620         TALLOC_FREE(frame);
3621         if (!NT_STATUS_IS_OK(status)) {
3622                 cli_set_error(cli, status);
3623         }
3624         return status;
3625 }
3626
3627 /****************************************************************************
3628  Check for existance of a dir.
3629 ****************************************************************************/
3630
3631 static void cli_chkpath_done(struct tevent_req *subreq);
3632
3633 struct cli_chkpath_state {
3634         int dummy;
3635 };
3636
3637 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
3638                                   struct event_context *ev,
3639                                   struct cli_state *cli,
3640                                   const char *fname)
3641 {
3642         struct tevent_req *req = NULL, *subreq = NULL;
3643         struct cli_chkpath_state *state = NULL;
3644         uint8_t additional_flags = 0;
3645         uint8_t *bytes = NULL;
3646
3647         req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
3648         if (req == NULL) {
3649                 return NULL;
3650         }
3651
3652         bytes = talloc_array(state, uint8_t, 1);
3653         if (tevent_req_nomem(bytes, req)) {
3654                 return tevent_req_post(req, ev);
3655         }
3656         bytes[0] = 4;
3657         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3658                                    strlen(fname)+1, NULL);
3659
3660         if (tevent_req_nomem(bytes, req)) {
3661                 return tevent_req_post(req, ev);
3662         }
3663
3664         subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
3665                               0, NULL, talloc_get_size(bytes), bytes);
3666         if (tevent_req_nomem(subreq, req)) {
3667                 return tevent_req_post(req, ev);
3668         }
3669         tevent_req_set_callback(subreq, cli_chkpath_done, req);
3670         return req;
3671 }
3672
3673 static void cli_chkpath_done(struct tevent_req *subreq)
3674 {
3675         struct tevent_req *req = tevent_req_callback_data(
3676                 subreq, struct tevent_req);
3677         NTSTATUS status;
3678
3679         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3680         TALLOC_FREE(subreq);
3681         if (!NT_STATUS_IS_OK(status)) {
3682                 tevent_req_nterror(req, status);
3683                 return;
3684         }
3685         tevent_req_done(req);
3686 }
3687
3688 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
3689 {
3690         return tevent_req_simple_recv_ntstatus(req);
3691 }
3692
3693 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
3694 {
3695         TALLOC_CTX *frame = talloc_stackframe();
3696         struct event_context *ev = NULL;
3697         struct tevent_req *req = NULL;
3698         char *path2 = NULL;
3699         NTSTATUS status = NT_STATUS_OK;
3700
3701         if (cli_has_async_calls(cli)) {
3702                 /*
3703                  * Can't use sync call while an async call is in flight
3704                  */
3705                 status = NT_STATUS_INVALID_PARAMETER;
3706                 goto fail;
3707         }
3708
3709         path2 = talloc_strdup(frame, path);
3710         if (!path2) {
3711                 status = NT_STATUS_NO_MEMORY;
3712                 goto fail;
3713         }
3714         trim_char(path2,'\0','\\');
3715         if (!*path2) {
3716                 path2 = talloc_strdup(frame, "\\");
3717                 if (!path2) {
3718                         status = NT_STATUS_NO_MEMORY;
3719                         goto fail;
3720                 }
3721         }
3722
3723         ev = event_context_init(frame);
3724         if (ev == NULL) {
3725                 status = NT_STATUS_NO_MEMORY;
3726                 goto fail;
3727         }
3728
3729         req = cli_chkpath_send(frame, ev, cli, path2);
3730         if (req == NULL) {
3731                 status = NT_STATUS_NO_MEMORY;
3732                 goto fail;
3733         }
3734
3735         if (!tevent_req_poll(req, ev)) {
3736                 status = map_nt_error_from_unix(errno);
3737                 goto fail;
3738         }
3739
3740         status = cli_chkpath_recv(req);
3741
3742  fail:
3743         TALLOC_FREE(frame);
3744         if (!NT_STATUS_IS_OK(status)) {
3745                 cli_set_error(cli, status);
3746         }
3747         return status;
3748 }
3749
3750 /****************************************************************************
3751  Query disk space.
3752 ****************************************************************************/
3753
3754 static void cli_dskattr_done(struct tevent_req *subreq);
3755
3756 struct cli_dskattr_state {
3757         int bsize;
3758         int total;
3759         int avail;
3760 };
3761
3762 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
3763                                   struct event_context *ev,
3764                                   struct cli_state *cli)
3765 {
3766         struct tevent_req *req = NULL, *subreq = NULL;
3767         struct cli_dskattr_state *state = NULL;
3768         uint8_t additional_flags = 0;
3769
3770         req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
3771         if (req == NULL) {
3772                 return NULL;
3773         }
3774
3775         subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
3776                               0, NULL, 0, NULL);
3777         if (tevent_req_nomem(subreq, req)) {
3778                 return tevent_req_post(req, ev);
3779         }
3780         tevent_req_set_callback(subreq, cli_dskattr_done, req);
3781         return req;
3782 }
3783
3784 static void cli_dskattr_done(struct tevent_req *subreq)
3785 {
3786         struct tevent_req *req = tevent_req_callback_data(
3787                 subreq, struct tevent_req);
3788         struct cli_dskattr_state *state = tevent_req_data(
3789                 req, struct cli_dskattr_state);
3790         uint8_t wct;
3791         uint16_t *vwv = NULL;
3792         uint8_t *inbuf;
3793         NTSTATUS status;
3794
3795         status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3796                               NULL);
3797         TALLOC_FREE(subreq);
3798         if (!NT_STATUS_IS_OK(status)) {
3799                 tevent_req_nterror(req, status);
3800                 return;
3801         }
3802         state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
3803         state->total = SVAL(vwv+0, 0);
3804         state->avail = SVAL(vwv+3, 0);
3805         tevent_req_done(req);
3806 }
3807
3808 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
3809 {
3810         struct cli_dskattr_state *state = tevent_req_data(
3811                                 req, struct cli_dskattr_state);
3812         NTSTATUS status;
3813
3814         if (tevent_req_is_nterror(req, &status)) {
3815                 return status;
3816         }
3817         *bsize = state->bsize;
3818         *total = state->total;
3819         *avail = state->avail;
3820         return NT_STATUS_OK;
3821 }
3822
3823 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3824 {
3825         TALLOC_CTX *frame = talloc_stackframe();
3826         struct event_context *ev = NULL;
3827         struct tevent_req *req = NULL;
3828         NTSTATUS status = NT_STATUS_OK;
3829
3830         if (cli_has_async_calls(cli)) {
3831                 /*
3832                  * Can't use sync call while an async call is in flight
3833                  */
3834                 status = NT_STATUS_INVALID_PARAMETER;
3835                 goto fail;
3836         }
3837
3838         ev = event_context_init(frame);
3839         if (ev == NULL) {
3840                 status = NT_STATUS_NO_MEMORY;
3841                 goto fail;
3842         }
3843
3844         req = cli_dskattr_send(frame, ev, cli);
3845         if (req == NULL) {
3846                 status = NT_STATUS_NO_MEMORY;
3847                 goto fail;
3848         }
3849
3850         if (!tevent_req_poll(req, ev)) {
3851                 status = map_nt_error_from_unix(errno);
3852                 goto fail;
3853         }
3854
3855         status = cli_dskattr_recv(req, bsize, total, avail);
3856
3857  fail:
3858         TALLOC_FREE(frame);
3859         if (!NT_STATUS_IS_OK(status)) {
3860                 cli_set_error(cli, status);
3861         }
3862         return status;
3863 }
3864
3865 /****************************************************************************
3866  Create and open a temporary file.
3867 ****************************************************************************/
3868
3869 static void cli_ctemp_done(struct tevent_req *subreq);
3870
3871 struct ctemp_state {
3872         uint16_t vwv[3];
3873         char *ret_path;
3874         uint16_t fnum;
3875 };
3876
3877 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
3878                                 struct event_context *ev,
3879                                 struct cli_state *cli,
3880                                 const char *path)
3881 {
3882         struct tevent_req *req = NULL, *subreq = NULL;
3883         struct ctemp_state *state = NULL;
3884         uint8_t additional_flags = 0;
3885         uint8_t *bytes = NULL;
3886
3887         req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
3888         if (req == NULL) {
3889                 return NULL;
3890         }
3891
3892         SSVAL(state->vwv,0,0);
3893         SIVALS(state->vwv+1,0,-1);
3894
3895         bytes = talloc_array(state, uint8_t, 1);
3896         if (tevent_req_nomem(bytes, req)) {
3897                 return tevent_req_post(req, ev);
3898         }
3899         bytes[0] = 4;
3900         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), path,
3901                                    strlen(path)+1, NULL);
3902         if (tevent_req_nomem(bytes, req)) {
3903                 return tevent_req_post(req, ev);
3904         }
3905
3906         subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
3907                               3, state->vwv, talloc_get_size(bytes), bytes);
3908         if (tevent_req_nomem(subreq, req)) {
3909                 return tevent_req_post(req, ev);
3910         }
3911         tevent_req_set_callback(subreq, cli_ctemp_done, req);
3912         return req;
3913 }
3914
3915 static void cli_ctemp_done(struct tevent_req *subreq)
3916 {
3917         struct tevent_req *req = tevent_req_callback_data(
3918                                 subreq, struct tevent_req);
3919         struct ctemp_state *state = tevent_req_data(
3920                                 req, struct ctemp_state);
3921         NTSTATUS status;
3922         uint8_t wcnt;
3923         uint16_t *vwv;
3924         uint32_t num_bytes = 0;
3925         uint8_t *bytes = NULL;
3926         uint8_t *inbuf;
3927
3928         status = cli_smb_recv(subreq, state, &inbuf, 1, &wcnt, &vwv,
3929                               &num_bytes, &bytes);
3930         TALLOC_FREE(subreq);
3931         if (!NT_STATUS_IS_OK(status)) {
3932                 tevent_req_nterror(req, status);
3933                 return;
3934         }
3935
3936         state->fnum = SVAL(vwv+0, 0);
3937
3938         /* From W2K3, the result is just the ASCII name */
3939         if (num_bytes < 2) {
3940                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
3941                 return;
3942         }
3943
3944         if (pull_string_talloc(state,
3945                         NULL,
3946                         0,
3947                         &state->ret_path,
3948                         bytes,
3949                         num_bytes,
3950                         STR_ASCII) == 0) {
3951                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
3952                 return;
3953         }
3954         tevent_req_done(req);
3955 }
3956
3957 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
3958                         TALLOC_CTX *ctx,
3959                         uint16_t *pfnum,
3960                         char **outfile)
3961 {
3962         struct ctemp_state *state = tevent_req_data(req,
3963                         struct ctemp_state);
3964         NTSTATUS status;
3965
3966         if (tevent_req_is_nterror(req, &status)) {
3967                 return status;
3968         }
3969         *pfnum = state->fnum;
3970         *outfile = talloc_strdup(ctx, state->ret_path);
3971         if (!*outfile) {
3972                 return NT_STATUS_NO_MEMORY;
3973         }
3974         return NT_STATUS_OK;
3975 }
3976
3977 NTSTATUS cli_ctemp(struct cli_state *cli,
3978                         TALLOC_CTX *ctx,
3979                         const char *path,
3980                         uint16_t *pfnum,
3981                         char **out_path)
3982 {
3983         TALLOC_CTX *frame = talloc_stackframe();
3984         struct event_context *ev;
3985         struct tevent_req *req;
3986         NTSTATUS status = NT_STATUS_OK;
3987
3988         if (cli_has_async_calls(cli)) {
3989                 /*
3990                  * Can't use sync call while an async call is in flight
3991                  */
3992                 status = NT_STATUS_INVALID_PARAMETER;
3993                 goto fail;
3994         }
3995
3996         ev = event_context_init(frame);
3997         if (ev == NULL) {
3998                 status = NT_STATUS_NO_MEMORY;
3999                 goto fail;
4000         }
4001
4002         req = cli_ctemp_send(frame, ev, cli, path);
4003         if (req == NULL) {
4004                 status = NT_STATUS_NO_MEMORY;
4005                 goto fail;
4006         }
4007
4008         if (!tevent_req_poll(req, ev)) {
4009                 status = map_nt_error_from_unix(errno);
4010                 goto fail;
4011         }
4012
4013         status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4014
4015  fail:
4016         TALLOC_FREE(frame);
4017         if (!NT_STATUS_IS_OK(status)) {
4018                 cli_set_error(cli, status);
4019         }
4020         return status;
4021 }
4022
4023 /*
4024    send a raw ioctl - used by the torture code
4025 */
4026 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4027 {
4028         uint16_t vwv[3];
4029         NTSTATUS status;
4030
4031         SSVAL(vwv+0, 0, fnum);
4032         SSVAL(vwv+1, 0, code>>16);
4033         SSVAL(vwv+2, 0, (code&0xFFFF));
4034
4035         status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4036                          NULL, 0, NULL, NULL, NULL, NULL);
4037         if (!NT_STATUS_IS_OK(status)) {
4038                 return status;
4039         }
4040         *blob = data_blob_null;
4041         return NT_STATUS_OK;
4042 }
4043
4044 /*********************************************************
4045  Set an extended attribute utility fn.
4046 *********************************************************/
4047
4048 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
4049                            uint8_t *param, unsigned int param_len,
4050                            const char *ea_name,
4051                            const char *ea_val, size_t ea_len)
4052 {
4053         uint16_t setup[1];
4054         unsigned int data_len = 0;
4055         uint8_t *data = NULL;
4056         char *p;
4057         size_t ea_namelen = strlen(ea_name);
4058         NTSTATUS status;
4059
4060         SSVAL(setup, 0, setup_val);
4061
4062         if (ea_namelen == 0 && ea_len == 0) {
4063                 data_len = 4;
4064                 data = (uint8_t *)SMB_MALLOC(data_len);
4065                 if (!data) {
4066                         return NT_STATUS_NO_MEMORY;
4067                 }
4068                 p = (char *)data;
4069                 SIVAL(p,0,data_len);
4070         } else {
4071                 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4072                 data = (uint8_t *)SMB_MALLOC(data_len);
4073                 if (!data) {
4074                         return NT_STATUS_NO_MEMORY;
4075                 }
4076                 p = (char *)data;
4077                 SIVAL(p,0,data_len);
4078                 p += 4;
4079                 SCVAL(p, 0, 0); /* EA flags. */
4080                 SCVAL(p, 1, ea_namelen);
4081                 SSVAL(p, 2, ea_len);
4082                 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4083                 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4084         }
4085
4086         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
4087                            setup, 1, 0,
4088                            param, param_len, 2,
4089                            data,  data_len, cli->max_xmit,
4090                            NULL,
4091                            NULL, 0, NULL, /* rsetup */
4092                            NULL, 0, NULL, /* rparam */
4093                            NULL, 0, NULL); /* rdata */
4094         SAFE_FREE(data);
4095         return status;
4096 }
4097
4098 /*********************************************************
4099  Set an extended attribute on a pathname.
4100 *********************************************************/
4101
4102 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
4103                          const char *ea_name, const char *ea_val,
4104                          size_t ea_len)
4105 {
4106         unsigned int param_len = 0;
4107         uint8_t *param;
4108         size_t srclen = 2*(strlen(path)+1);
4109         char *p;
4110         NTSTATUS status;
4111
4112         param = SMB_MALLOC_ARRAY(uint8_t, 6+srclen+2);
4113         if (!param) {
4114                 return NT_STATUS_NO_MEMORY;
4115         }
4116         memset(param, '\0', 6);
4117         SSVAL(param,0,SMB_INFO_SET_EA);
4118         p = (char *)(&param[6]);
4119
4120         p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
4121         param_len = PTR_DIFF(p, param);
4122
4123         status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
4124                             ea_name, ea_val, ea_len);
4125         SAFE_FREE(param);
4126         return status;
4127 }
4128
4129 /*********************************************************
4130  Set an extended attribute on an fnum.
4131 *********************************************************/
4132
4133 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
4134                          const char *ea_name, const char *ea_val,
4135                          size_t ea_len)
4136 {
4137         uint8_t param[6];
4138
4139         memset(param, 0, 6);
4140         SSVAL(param,0,fnum);
4141         SSVAL(param,2,SMB_INFO_SET_EA);
4142
4143         return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
4144                           ea_name, ea_val, ea_len);
4145 }
4146
4147 /*********************************************************
4148  Get an extended attribute list utility fn.
4149 *********************************************************/
4150
4151 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4152                           size_t rdata_len,
4153                           size_t *pnum_eas, struct ea_struct **pea_list)
4154 {
4155         struct ea_struct *ea_list = NULL;
4156         size_t num_eas;
4157         size_t ea_size;
4158         const uint8_t *p;
4159
4160         if (rdata_len < 4) {
4161                 return false;
4162         }
4163
4164         ea_size = (size_t)IVAL(rdata,0);
4165         if (ea_size > rdata_len) {
4166                 return false;
4167         }
4168
4169         if (ea_size == 0) {
4170                 /* No EA's present. */
4171                 *pnum_eas = 0;
4172                 *pea_list = NULL;
4173                 return true;
4174         }
4175
4176         p = rdata + 4;
4177         ea_size -= 4;
4178
4179         /* Validate the EA list and count it. */
4180         for (num_eas = 0; ea_size >= 4; num_eas++) {
4181                 unsigned int ea_namelen = CVAL(p,1);
4182                 unsigned int ea_valuelen = SVAL(p,2);
4183                 if (ea_namelen == 0) {
4184                         return false;
4185                 }
4186                 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4187                         return false;
4188                 }
4189                 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4190                 p += 4 + ea_namelen + 1 + ea_valuelen;
4191         }
4192
4193         if (num_eas == 0) {
4194                 *pnum_eas = 0;
4195                 *pea_list = NULL;
4196                 return true;
4197         }
4198
4199         *pnum_eas = num_eas;
4200         if (!pea_list) {
4201                 /* Caller only wants number of EA's. */
4202                 return true;
4203         }
4204
4205         ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
4206         if (!ea_list) {
4207                 return false;
4208         }
4209
4210         ea_size = (size_t)IVAL(rdata,0);
4211         p = rdata + 4;
4212
4213         for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4214                 struct ea_struct *ea = &ea_list[num_eas];
4215                 fstring unix_ea_name;
4216                 unsigned int ea_namelen = CVAL(p,1);
4217                 unsigned int ea_valuelen = SVAL(p,2);
4218
4219                 ea->flags = CVAL(p,0);
4220                 unix_ea_name[0] = '\0';
4221                 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
4222                 ea->name = talloc_strdup(ea_list, unix_ea_name);
4223                 if (!ea->name) {
4224                         goto fail;
4225                 }
4226                 /* Ensure the value is null terminated (in case it's a string). */
4227                 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4228                 if (!ea->value.data) {
4229                         goto fail;
4230                 }
4231                 if (ea_valuelen) {
4232                         memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4233                 }
4234                 ea->value.data[ea_valuelen] = 0;
4235                 ea->value.length--;
4236                 p += 4 + ea_namelen + 1 + ea_valuelen;
4237         }
4238
4239         *pea_list = ea_list;
4240         return true;
4241
4242 fail:
4243         TALLOC_FREE(ea_list);
4244         return false;
4245 }
4246
4247 /*********************************************************
4248  Get an extended attribute list from a pathname.
4249 *********************************************************/
4250
4251 struct cli_get_ea_list_path_state {
4252         uint32_t num_data;
4253         uint8_t *data;
4254 };
4255
4256 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4257
4258 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4259                                              struct tevent_context *ev,
4260                                              struct cli_state *cli,
4261                                              const char *fname)
4262 {
4263         struct tevent_req *req, *subreq;
4264         struct cli_get_ea_list_path_state *state;
4265
4266         req = tevent_req_create(mem_ctx, &state,
4267                                 struct cli_get_ea_list_path_state);
4268         if (req == NULL) {
4269                 return NULL;
4270         }
4271         subreq = cli_qpathinfo_send(state, ev, cli, fname,
4272                                     SMB_INFO_QUERY_ALL_EAS, 4,
4273                                     cli->max_xmit);
4274         if (tevent_req_nomem(subreq, req)) {
4275                 return tevent_req_post(req, ev);
4276         }
4277         tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4278         return req;
4279 }
4280
4281 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4282 {
4283         struct tevent_req *req = tevent_req_callback_data(
4284                                 subreq, struct tevent_req);
4285         struct cli_get_ea_list_path_state *state = tevent_req_data(
4286                 req, struct cli_get_ea_list_path_state);
4287         NTSTATUS status;
4288
4289         status = cli_qpathinfo_recv(subreq, state, &state->data,
4290                                     &state->num_data);
4291         TALLOC_FREE(subreq);
4292         if (!NT_STATUS_IS_OK(status)) {
4293                 tevent_req_nterror(req, status);
4294                 return;
4295         }
4296         tevent_req_done(req);
4297 }
4298
4299 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4300                                    size_t *pnum_eas, struct ea_struct **peas)
4301 {
4302         struct cli_get_ea_list_path_state *state = tevent_req_data(
4303                 req, struct cli_get_ea_list_path_state);
4304         NTSTATUS status;
4305
4306         if (tevent_req_is_nterror(req, &status)) {
4307                 return status;
4308         }
4309         if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4310                            pnum_eas, peas)) {
4311                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4312         }
4313         return NT_STATUS_OK;
4314 }
4315
4316 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
4317                 TALLOC_CTX *ctx,
4318                 size_t *pnum_eas,
4319                 struct ea_struct **pea_list)
4320 {
4321         TALLOC_CTX *frame = talloc_stackframe();
4322         struct event_context *ev = NULL;
4323         struct tevent_req *req = NULL;
4324         NTSTATUS status = NT_STATUS_NO_MEMORY;
4325
4326         if (cli_has_async_calls(cli)) {
4327                 /*
4328                  * Can't use sync call while an async call is in flight
4329                  */
4330                 status = NT_STATUS_INVALID_PARAMETER;
4331                 goto fail;
4332         }
4333         ev = event_context_init(frame);
4334         if (ev == NULL) {
4335                 goto fail;
4336         }
4337         req = cli_get_ea_list_path_send(frame, ev, cli, path);
4338         if (req == NULL) {
4339                 goto fail;
4340         }
4341         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4342                 goto fail;
4343         }
4344         status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
4345  fail:
4346         TALLOC_FREE(frame);
4347         if (!NT_STATUS_IS_OK(status)) {
4348                 cli_set_error(cli, status);
4349         }
4350         return status;
4351 }
4352
4353 /****************************************************************************
4354  Convert open "flags" arg to uint32_t on wire.
4355 ****************************************************************************/
4356
4357 static uint32_t open_flags_to_wire(int flags)
4358 {
4359         int open_mode = flags & O_ACCMODE;
4360         uint32_t ret = 0;
4361
4362         switch (open_mode) {
4363                 case O_WRONLY:
4364                         ret |= SMB_O_WRONLY;
4365                         break;
4366                 case O_RDWR:
4367                         ret |= SMB_O_RDWR;
4368                         break;
4369                 default:
4370                 case O_RDONLY:
4371                         ret |= SMB_O_RDONLY;
4372                         break;
4373         }
4374
4375         if (flags & O_CREAT) {
4376                 ret |= SMB_O_CREAT;
4377         }
4378         if (flags & O_EXCL) {
4379                 ret |= SMB_O_EXCL;
4380         }
4381         if (flags & O_TRUNC) {
4382                 ret |= SMB_O_TRUNC;
4383         }
4384 #if defined(O_SYNC)
4385         if (flags & O_SYNC) {
4386                 ret |= SMB_O_SYNC;
4387         }
4388 #endif /* O_SYNC */
4389         if (flags & O_APPEND) {
4390                 ret |= SMB_O_APPEND;
4391         }
4392 #if defined(O_DIRECT)
4393         if (flags & O_DIRECT) {
4394                 ret |= SMB_O_DIRECT;
4395         }
4396 #endif
4397 #if defined(O_DIRECTORY)
4398         if (flags & O_DIRECTORY) {
4399                 ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4400                 ret |= SMB_O_DIRECTORY;
4401         }
4402 #endif
4403         return ret;
4404 }
4405
4406 /****************************************************************************
4407  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4408 ****************************************************************************/
4409
4410 struct posix_open_state {
4411         uint16_t setup;
4412         uint8_t *param;
4413         uint8_t data[18];
4414         uint16_t fnum; /* Out */
4415 };
4416
4417 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4418 {
4419         struct tevent_req *req = tevent_req_callback_data(
4420                                 subreq, struct tevent_req);
4421         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4422         NTSTATUS status;
4423         uint8_t *data;
4424         uint32_t num_data;
4425
4426         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
4427                                 NULL, 0, NULL, &data, 12, &num_data);
4428         TALLOC_FREE(subreq);
4429         if (!NT_STATUS_IS_OK(status)) {
4430                 tevent_req_nterror(req, status);
4431                 return;
4432         }
4433         state->fnum = SVAL(data,2);
4434         tevent_req_done(req);
4435 }
4436
4437 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4438                                         struct event_context *ev,
4439                                         struct cli_state *cli,
4440                                         const char *fname,
4441                                         int flags,
4442                                         mode_t mode,
4443                                         bool is_dir)
4444 {
4445         struct tevent_req *req = NULL, *subreq = NULL;
4446         struct posix_open_state *state = NULL;
4447         uint32_t wire_flags = open_flags_to_wire(flags);
4448
4449         req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4450         if (req == NULL) {
4451                 return NULL;
4452         }
4453
4454         /* Setup setup word. */
4455         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4456
4457         /* Setup param array. */
4458         state->param = talloc_array(state, uint8_t, 6);
4459         if (tevent_req_nomem(state->param, req)) {
4460                 return tevent_req_post(req, ev);
4461         }
4462         memset(state->param, '\0', 6);
4463         SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4464
4465         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
4466                                    strlen(fname)+1, NULL);
4467
4468         if (tevent_req_nomem(state->param, req)) {
4469                 return tevent_req_post(req, ev);
4470         }
4471
4472         /* Setup data words. */
4473         if (is_dir) {
4474                 wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4475                 wire_flags |= SMB_O_DIRECTORY;
4476         }
4477
4478         SIVAL(state->data,0,0); /* No oplock. */
4479         SIVAL(state->data,4,wire_flags);
4480         SIVAL(state->data,8,unix_perms_to_wire(mode));
4481         SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
4482         SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
4483
4484         subreq = cli_trans_send(state,                  /* mem ctx. */
4485                                 ev,                     /* event ctx. */
4486                                 cli,                    /* cli_state. */
4487                                 SMBtrans2,              /* cmd. */
4488                                 NULL,                   /* pipe name. */
4489                                 -1,                     /* fid. */
4490                                 0,                      /* function. */
4491                                 0,                      /* flags. */
4492                                 &state->setup,          /* setup. */
4493                                 1,                      /* num setup uint16_t words. */
4494                                 0,                      /* max returned setup. */
4495                                 state->param,           /* param. */
4496                                 talloc_get_size(state->param),/* num param. */
4497                                 2,                      /* max returned param. */
4498                                 state->data,            /* data. */
4499                                 18,                     /* num data. */
4500                                 12);                    /* max returned data. */
4501
4502         if (tevent_req_nomem(subreq, req)) {
4503                 return tevent_req_post(req, ev);
4504         }
4505         tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
4506         return req;
4507 }
4508
4509 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
4510                                         struct event_context *ev,
4511                                         struct cli_state *cli,
4512                                         const char *fname,
4513                                         int flags,
4514                                         mode_t mode)
4515 {
4516         return cli_posix_open_internal_send(mem_ctx, ev,
4517                                 cli, fname, flags, mode, false);
4518 }
4519
4520 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
4521 {
4522         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4523         NTSTATUS status;
4524
4525         if (tevent_req_is_nterror(req, &status)) {
4526                 return status;
4527         }
4528         *pfnum = state->fnum;
4529         return NT_STATUS_OK;
4530 }
4531
4532 /****************************************************************************
4533  Open - POSIX semantics. Doesn't request oplock.
4534 ****************************************************************************/
4535
4536 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
4537                         int flags, mode_t mode, uint16_t *pfnum)
4538 {
4539
4540         TALLOC_CTX *frame = talloc_stackframe();
4541         struct event_context *ev = NULL;
4542         struct tevent_req *req = NULL;
4543         NTSTATUS status = NT_STATUS_OK;
4544
4545         if (cli_has_async_calls(cli)) {
4546                 /*
4547                  * Can't use sync call while an async call is in flight
4548                  */
4549                 status = NT_STATUS_INVALID_PARAMETER;
4550                 goto fail;
4551         }
4552
4553         ev = event_context_init(frame);
4554         if (ev == NULL) {
4555                 status = NT_STATUS_NO_MEMORY;
4556                 goto fail;
4557         }
4558
4559         req = cli_posix_open_send(frame,
4560                                 ev,
4561                                 cli,
4562                                 fname,
4563                                 flags,
4564                                 mode);
4565         if (req == NULL) {
4566                 status = NT_STATUS_NO_MEMORY;
4567                 goto fail;
4568         }
4569
4570         if (!tevent_req_poll(req, ev)) {
4571                 status = map_nt_error_from_unix(errno);
4572                 goto fail;
4573         }
4574
4575         status = cli_posix_open_recv(req, pfnum);
4576
4577  fail:
4578         TALLOC_FREE(frame);
4579         if (!NT_STATUS_IS_OK(status)) {
4580                 cli_set_error(cli, status);
4581         }
4582         return status;
4583 }
4584
4585 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
4586                                         struct event_context *ev,
4587                                         struct cli_state *cli,
4588                                         const char *fname,
4589                                         mode_t mode)
4590 {
4591         return cli_posix_open_internal_send(mem_ctx, ev,
4592                                 cli, fname, O_CREAT, mode, true);
4593 }
4594
4595 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
4596 {
4597         return tevent_req_simple_recv_ntstatus(req);
4598 }
4599
4600 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
4601 {
4602         TALLOC_CTX *frame = talloc_stackframe();
4603         struct event_context *ev = NULL;
4604         struct tevent_req *req = NULL;
4605         NTSTATUS status = NT_STATUS_OK;
4606
4607         if (cli_has_async_calls(cli)) {
4608                 /*
4609                  * Can't use sync call while an async call is in flight
4610                  */
4611                 status = NT_STATUS_INVALID_PARAMETER;
4612                 goto fail;
4613         }
4614
4615         ev = event_context_init(frame);
4616         if (ev == NULL) {
4617                 status = NT_STATUS_NO_MEMORY;
4618                 goto fail;
4619         }
4620
4621         req = cli_posix_mkdir_send(frame,
4622                                 ev,
4623                                 cli,
4624                                 fname,
4625                                 mode);
4626         if (req == NULL) {
4627                 status = NT_STATUS_NO_MEMORY;
4628                 goto fail;
4629         }
4630
4631         if (!tevent_req_poll(req, ev)) {
4632                 status = map_nt_error_from_unix(errno);
4633                 goto fail;
4634         }
4635
4636         status = cli_posix_mkdir_recv(req);
4637
4638  fail:
4639         TALLOC_FREE(frame);
4640         if (!NT_STATUS_IS_OK(status)) {
4641                 cli_set_error(cli, status);
4642         }
4643         return status;
4644 }
4645
4646 /****************************************************************************
4647  unlink or rmdir - POSIX semantics.
4648 ****************************************************************************/
4649
4650 struct cli_posix_unlink_internal_state {
4651         uint8_t data[2];
4652 };
4653
4654 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
4655
4656 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
4657                                         struct event_context *ev,
4658                                         struct cli_state *cli,
4659                                         const char *fname,
4660                                         uint16_t level)
4661 {
4662         struct tevent_req *req = NULL, *subreq = NULL;
4663         struct cli_posix_unlink_internal_state *state = NULL;
4664
4665         req = tevent_req_create(mem_ctx, &state,
4666                                 struct cli_posix_unlink_internal_state);
4667         if (req == NULL) {
4668                 return NULL;
4669         }
4670
4671         /* Setup data word. */
4672         SSVAL(state->data, 0, level);
4673
4674         subreq = cli_setpathinfo_send(state, ev, cli,
4675                                       SMB_POSIX_PATH_UNLINK,
4676                                       fname,
4677                                       state->data, sizeof(state->data));
4678         if (tevent_req_nomem(subreq, req)) {
4679                 return tevent_req_post(req, ev);
4680         }
4681         tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
4682         return req;
4683 }
4684
4685 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
4686 {
4687         NTSTATUS status = cli_setpathinfo_recv(subreq);
4688         tevent_req_simple_finish_ntstatus(subreq, status);
4689 }
4690
4691 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
4692                                         struct event_context *ev,
4693                                         struct cli_state *cli,
4694                                         const char *fname)
4695 {
4696         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
4697                                               SMB_POSIX_UNLINK_FILE_TARGET);
4698 }
4699
4700 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
4701 {
4702         return tevent_req_simple_recv_ntstatus(req);
4703 }
4704
4705 /****************************************************************************
4706  unlink - POSIX semantics.
4707 ****************************************************************************/
4708
4709 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
4710 {
4711         TALLOC_CTX *frame = talloc_stackframe();
4712         struct event_context *ev = NULL;
4713         struct tevent_req *req = NULL;
4714         NTSTATUS status = NT_STATUS_OK;
4715
4716         if (cli_has_async_calls(cli)) {
4717                 /*
4718                  * Can't use sync call while an async call is in flight
4719                  */
4720                 status = NT_STATUS_INVALID_PARAMETER;
4721                 goto fail;
4722         }
4723
4724         ev = event_context_init(frame);
4725         if (ev == NULL) {
4726                 status = NT_STATUS_NO_MEMORY;
4727                 goto fail;
4728         }
4729
4730         req = cli_posix_unlink_send(frame,
4731                                 ev,
4732                                 cli,
4733                                 fname);
4734         if (req == NULL) {
4735                 status = NT_STATUS_NO_MEMORY;
4736                 goto fail;
4737         }
4738
4739         if (!tevent_req_poll(req, ev)) {
4740                 status = map_nt_error_from_unix(errno);
4741                 goto fail;
4742         }
4743
4744         status = cli_posix_unlink_recv(req);
4745
4746  fail:
4747         TALLOC_FREE(frame);
4748         if (!NT_STATUS_IS_OK(status)) {
4749                 cli_set_error(cli, status);
4750         }
4751         return status;
4752 }
4753
4754 /****************************************************************************
4755  rmdir - POSIX semantics.
4756 ****************************************************************************/
4757
4758 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
4759                                         struct event_context *ev,
4760                                         struct cli_state *cli,
4761                                         const char *fname)
4762 {
4763         return cli_posix_unlink_internal_send(
4764                 mem_ctx, ev, cli, fname,
4765                 SMB_POSIX_UNLINK_DIRECTORY_TARGET);
4766 }
4767
4768 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
4769 {
4770         return tevent_req_simple_recv_ntstatus(req);
4771 }
4772
4773 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
4774 {
4775         TALLOC_CTX *frame = talloc_stackframe();
4776         struct event_context *ev = NULL;
4777         struct tevent_req *req = NULL;
4778         NTSTATUS status = NT_STATUS_OK;
4779
4780         if (cli_has_async_calls(cli)) {
4781                 /*
4782                  * Can't use sync call while an async call is in flight
4783                  */
4784                 status = NT_STATUS_INVALID_PARAMETER;
4785                 goto fail;
4786         }
4787
4788         ev = event_context_init(frame);
4789         if (ev == NULL) {
4790                 status = NT_STATUS_NO_MEMORY;
4791                 goto fail;
4792         }
4793
4794         req = cli_posix_rmdir_send(frame,
4795                                 ev,
4796                                 cli,
4797                                 fname);
4798         if (req == NULL) {
4799                 status = NT_STATUS_NO_MEMORY;
4800                 goto fail;
4801         }
4802
4803         if (!tevent_req_poll(req, ev)) {
4804                 status = map_nt_error_from_unix(errno);
4805                 goto fail;
4806         }
4807
4808         status = cli_posix_rmdir_recv(req, frame);
4809
4810  fail:
4811         TALLOC_FREE(frame);
4812         if (!NT_STATUS_IS_OK(status)) {
4813                 cli_set_error(cli, status);
4814         }
4815         return status;
4816 }
4817
4818 /****************************************************************************
4819  filechangenotify
4820 ****************************************************************************/
4821
4822 struct cli_notify_state {
4823         uint8_t setup[8];
4824         uint32_t num_changes;
4825         struct notify_change *changes;
4826 };
4827
4828 static void cli_notify_done(struct tevent_req *subreq);
4829
4830 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
4831                                    struct tevent_context *ev,
4832                                    struct cli_state *cli, uint16_t fnum,
4833                                    uint32_t buffer_size,
4834                                    uint32_t completion_filter, bool recursive)
4835 {
4836         struct tevent_req *req, *subreq;
4837         struct cli_notify_state *state;
4838
4839         req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
4840         if (req == NULL) {
4841                 return NULL;
4842         }
4843
4844         SIVAL(state->setup, 0, completion_filter);
4845         SSVAL(state->setup, 4, fnum);
4846         SSVAL(state->setup, 6, recursive);
4847
4848         subreq = cli_trans_send(
4849                 state,                  /* mem ctx. */
4850                 ev,                     /* event ctx. */
4851                 cli,                    /* cli_state. */
4852                 SMBnttrans,             /* cmd. */
4853                 NULL,                   /* pipe name. */
4854                 -1,                     /* fid. */
4855                 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
4856                 0,                      /* flags. */
4857                 (uint16_t *)state->setup, /* setup. */
4858                 4,                      /* num setup uint16_t words. */
4859                 0,                      /* max returned setup. */
4860                 NULL,                   /* param. */
4861                 0,                      /* num param. */
4862                 buffer_size,            /* max returned param. */
4863                 NULL,                   /* data. */
4864                 0,                      /* num data. */
4865                 0);                     /* max returned data. */
4866
4867         if (tevent_req_nomem(subreq, req)) {
4868                 return tevent_req_post(req, ev);
4869         }
4870         tevent_req_set_callback(subreq, cli_notify_done, req);
4871         return req;
4872 }
4873
4874 static void cli_notify_done(struct tevent_req *subreq)
4875 {
4876         struct tevent_req *req = tevent_req_callback_data(
4877                 subreq, struct tevent_req);
4878         struct cli_notify_state *state = tevent_req_data(
4879                 req, struct cli_notify_state);
4880         NTSTATUS status;
4881         uint8_t *params;
4882         uint32_t i, ofs, num_params;
4883         uint16_t flags2;
4884
4885         status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
4886                                 &params, 0, &num_params, NULL, 0, NULL);
4887         TALLOC_FREE(subreq);
4888         if (!NT_STATUS_IS_OK(status)) {
4889                 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
4890                 tevent_req_nterror(req, status);
4891                 return;
4892         }
4893
4894         state->num_changes = 0;
4895         ofs = 0;
4896
4897         while (num_params - ofs > 12) {
4898                 uint32_t len = IVAL(params, ofs);
4899                 state->num_changes += 1;
4900
4901                 if ((len == 0) || (ofs+len >= num_params)) {
4902                         break;
4903                 }
4904                 ofs += len;
4905         }
4906
4907         state->changes = talloc_array(state, struct notify_change,
4908                                       state->num_changes);
4909         if (tevent_req_nomem(state->changes, req)) {
4910                 TALLOC_FREE(params);
4911                 return;
4912         }
4913
4914         ofs = 0;
4915
4916         for (i=0; i<state->num_changes; i++) {
4917                 uint32_t next = IVAL(params, ofs);
4918                 uint32_t len = IVAL(params, ofs+8);
4919                 ssize_t ret;
4920                 char *name;
4921
4922                 if ((next != 0) && (len+12 != next)) {
4923                         TALLOC_FREE(params);
4924                         tevent_req_nterror(
4925                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4926                         return;
4927                 }
4928
4929                 state->changes[i].action = IVAL(params, ofs+4);
4930                 ret = clistr_pull_talloc(params, (char *)params, flags2,
4931                                          &name, params+ofs+12, len,
4932                                          STR_TERMINATE|STR_UNICODE);
4933                 if (ret == -1) {
4934                         TALLOC_FREE(params);
4935                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4936                         return;
4937                 }
4938                 state->changes[i].name = name;
4939                 ofs += next;
4940         }
4941
4942         TALLOC_FREE(params);
4943         tevent_req_done(req);
4944 }
4945
4946 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4947                          uint32_t *pnum_changes,
4948                          struct notify_change **pchanges)
4949 {
4950         struct cli_notify_state *state = tevent_req_data(
4951                 req, struct cli_notify_state);
4952         NTSTATUS status;
4953
4954         if (tevent_req_is_nterror(req, &status)) {
4955                 return status;
4956         }
4957
4958         *pnum_changes = state->num_changes;
4959         *pchanges = talloc_move(mem_ctx, &state->changes);
4960         return NT_STATUS_OK;
4961 }
4962
4963 struct cli_qpathinfo_state {
4964         uint8_t *param;
4965         uint8_t *data;
4966         uint16_t setup[1];
4967         uint32_t min_rdata;
4968         uint8_t *rdata;
4969         uint32_t num_rdata;
4970 };
4971
4972 static void cli_qpathinfo_done(struct tevent_req *subreq);
4973
4974 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
4975                                       struct tevent_context *ev,
4976                                       struct cli_state *cli, const char *fname,
4977                                       uint16_t level, uint32_t min_rdata,
4978                                       uint32_t max_rdata)
4979 {
4980         struct tevent_req *req, *subreq;
4981         struct cli_qpathinfo_state *state;
4982
4983         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
4984         if (req == NULL) {
4985                 return NULL;
4986         }
4987         state->min_rdata = min_rdata;
4988         SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
4989
4990         state->param = talloc_zero_array(state, uint8_t, 6);
4991         if (tevent_req_nomem(state->param, req)) {
4992                 return tevent_req_post(req, ev);
4993         }
4994         SSVAL(state->param, 0, level);
4995         state->param = trans2_bytes_push_str(
4996                 state->param, cli_ucs2(cli), fname, strlen(fname)+1, NULL);
4997         if (tevent_req_nomem(state->param, req)) {
4998                 return tevent_req_post(req, ev);
4999         }
5000
5001         subreq = cli_trans_send(
5002                 state,                  /* mem ctx. */
5003                 ev,                     /* event ctx. */
5004                 cli,                    /* cli_state. */
5005                 SMBtrans2,              /* cmd. */
5006                 NULL,                   /* pipe name. */
5007                 -1,                     /* fid. */
5008                 0,                      /* function. */
5009                 0,                      /* flags. */
5010                 state->setup,           /* setup. */
5011                 1,                      /* num setup uint16_t words. */
5012                 0,                      /* max returned setup. */
5013                 state->param,           /* param. */
5014                 talloc_get_size(state->param),  /* num param. */
5015                 2,                      /* max returned param. */
5016                 NULL,                   /* data. */
5017                 0,                      /* num data. */
5018                 max_rdata);             /* max returned data. */
5019
5020         if (tevent_req_nomem(subreq, req)) {
5021                 return tevent_req_post(req, ev);
5022         }
5023         tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5024         return req;
5025 }
5026
5027 static void cli_qpathinfo_done(struct tevent_req *subreq)
5028 {
5029         struct tevent_req *req = tevent_req_callback_data(
5030                 subreq, struct tevent_req);
5031         struct cli_qpathinfo_state *state = tevent_req_data(
5032                 req, struct cli_qpathinfo_state);
5033         NTSTATUS status;
5034
5035         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5036                                 NULL, 0, NULL,
5037                                 &state->rdata, state->min_rdata,
5038                                 &state->num_rdata);
5039         if (!NT_STATUS_IS_OK(status)) {
5040                 tevent_req_nterror(req, status);
5041                 return;
5042         }
5043         tevent_req_done(req);
5044 }
5045
5046 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5047                             uint8_t **rdata, uint32_t *num_rdata)
5048 {
5049         struct cli_qpathinfo_state *state = tevent_req_data(
5050                 req, struct cli_qpathinfo_state);
5051         NTSTATUS status;
5052
5053         if (tevent_req_is_nterror(req, &status)) {
5054                 return status;
5055         }
5056         if (rdata != NULL) {
5057                 *rdata = talloc_move(mem_ctx, &state->rdata);
5058         } else {
5059                 TALLOC_FREE(state->rdata);
5060         }
5061         if (num_rdata != NULL) {
5062                 *num_rdata = state->num_rdata;
5063         }
5064         return NT_STATUS_OK;
5065 }
5066
5067 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5068                        const char *fname, uint16_t level, uint32_t min_rdata,
5069                        uint32_t max_rdata,
5070                        uint8_t **rdata, uint32_t *num_rdata)
5071 {
5072         TALLOC_CTX *frame = talloc_stackframe();
5073         struct event_context *ev;
5074         struct tevent_req *req;
5075         NTSTATUS status = NT_STATUS_NO_MEMORY;
5076
5077         if (cli_has_async_calls(cli)) {
5078                 /*
5079                  * Can't use sync call while an async call is in flight
5080                  */
5081                 status = NT_STATUS_INVALID_PARAMETER;
5082                 goto fail;
5083         }
5084         ev = event_context_init(frame);
5085         if (ev == NULL) {
5086                 goto fail;
5087         }
5088         req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5089                                  max_rdata);
5090         if (req == NULL) {
5091                 goto fail;
5092         }
5093         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5094                 goto fail;
5095         }
5096         status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5097  fail:
5098         TALLOC_FREE(frame);
5099         if (!NT_STATUS_IS_OK(status)) {
5100                 cli_set_error(cli, status);
5101         }
5102         return status;
5103 }
5104
5105 struct cli_qfileinfo_state {
5106         uint16_t setup[1];
5107         uint8_t param[4];
5108         uint8_t *data;
5109         uint32_t min_rdata;
5110         uint8_t *rdata;
5111         uint32_t num_rdata;
5112 };
5113
5114 static void cli_qfileinfo_done(struct tevent_req *subreq);
5115
5116 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
5117                                       struct tevent_context *ev,
5118                                       struct cli_state *cli, uint16_t fnum,
5119                                       uint16_t level, uint32_t min_rdata,
5120                                       uint32_t max_rdata)
5121 {
5122         struct tevent_req *req, *subreq;
5123         struct cli_qfileinfo_state *state;
5124
5125         req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
5126         if (req == NULL) {
5127                 return NULL;
5128         }
5129         state->min_rdata = min_rdata;
5130         SSVAL(state->param, 0, fnum);
5131         SSVAL(state->param, 2, level);
5132         SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
5133
5134         subreq = cli_trans_send(
5135                 state,                  /* mem ctx. */
5136                 ev,                     /* event ctx. */
5137                 cli,                    /* cli_state. */
5138                 SMBtrans2,              /* cmd. */
5139                 NULL,                   /* pipe name. */
5140                 -1,                     /* fid. */
5141                 0,                      /* function. */
5142                 0,                      /* flags. */
5143                 state->setup,           /* setup. */
5144                 1,                      /* num setup uint16_t words. */
5145                 0,                      /* max returned setup. */
5146                 state->param,           /* param. */
5147                 sizeof(state->param),   /* num param. */
5148                 2,                      /* max returned param. */
5149                 NULL,                   /* data. */
5150                 0,                      /* num data. */
5151                 max_rdata);             /* max returned data. */
5152
5153         if (tevent_req_nomem(subreq, req)) {
5154                 return tevent_req_post(req, ev);
5155         }
5156         tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
5157         return req;
5158 }
5159
5160 static void cli_qfileinfo_done(struct tevent_req *subreq)
5161 {
5162         struct tevent_req *req = tevent_req_callback_data(
5163                 subreq, struct tevent_req);
5164         struct cli_qfileinfo_state *state = tevent_req_data(
5165                 req, struct cli_qfileinfo_state);
5166         NTSTATUS status;
5167
5168         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5169                                 NULL, 0, NULL,
5170                                 &state->rdata, state->min_rdata,
5171                                 &state->num_rdata);
5172         if (!NT_STATUS_IS_OK(status)) {
5173                 tevent_req_nterror(req, status);
5174                 return;
5175         }
5176         tevent_req_done(req);
5177 }
5178
5179 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5180                             uint8_t **rdata, uint32_t *num_rdata)
5181 {
5182         struct cli_qfileinfo_state *state = tevent_req_data(
5183                 req, struct cli_qfileinfo_state);
5184         NTSTATUS status;
5185
5186         if (tevent_req_is_nterror(req, &status)) {
5187                 return status;
5188         }
5189         if (rdata != NULL) {
5190                 *rdata = talloc_move(mem_ctx, &state->rdata);
5191         } else {
5192                 TALLOC_FREE(state->rdata);
5193         }
5194         if (num_rdata != NULL) {
5195                 *num_rdata = state->num_rdata;
5196         }
5197         return NT_STATUS_OK;
5198 }
5199
5200 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5201                        uint16_t fnum, uint16_t level, uint32_t min_rdata,
5202                        uint32_t max_rdata,
5203                        uint8_t **rdata, uint32_t *num_rdata)
5204 {
5205         TALLOC_CTX *frame = talloc_stackframe();
5206         struct event_context *ev;
5207         struct tevent_req *req;
5208         NTSTATUS status = NT_STATUS_NO_MEMORY;
5209
5210         if (cli_has_async_calls(cli)) {
5211                 /*
5212                  * Can't use sync call while an async call is in flight
5213                  */
5214                 status = NT_STATUS_INVALID_PARAMETER;
5215                 goto fail;
5216         }
5217         ev = event_context_init(frame);
5218         if (ev == NULL) {
5219                 goto fail;
5220         }
5221         req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
5222                                  max_rdata);
5223         if (req == NULL) {
5224                 goto fail;
5225         }
5226         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5227                 goto fail;
5228         }
5229         status = cli_qfileinfo_recv(req, mem_ctx, rdata, num_rdata);
5230  fail:
5231         TALLOC_FREE(frame);
5232         if (!NT_STATUS_IS_OK(status)) {
5233                 cli_set_error(cli, status);
5234         }
5235         return status;
5236 }
5237
5238 struct cli_flush_state {
5239         uint16_t vwv[1];
5240 };
5241
5242 static void cli_flush_done(struct tevent_req *subreq);
5243
5244 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
5245                                   struct event_context *ev,
5246                                   struct cli_state *cli,
5247                                   uint16_t fnum)
5248 {
5249         struct tevent_req *req, *subreq;
5250         struct cli_flush_state *state;
5251
5252         req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
5253         if (req == NULL) {
5254                 return NULL;
5255         }
5256         SSVAL(state->vwv + 0, 0, fnum);
5257
5258         subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 1, state->vwv,
5259                               0, NULL);
5260         if (tevent_req_nomem(subreq, req)) {
5261                 return tevent_req_post(req, ev);
5262         }
5263         tevent_req_set_callback(subreq, cli_flush_done, req);
5264         return req;
5265 }
5266
5267 static void cli_flush_done(struct tevent_req *subreq)
5268 {
5269         struct tevent_req *req = tevent_req_callback_data(
5270                 subreq, struct tevent_req);
5271         NTSTATUS status;
5272
5273         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5274         TALLOC_FREE(subreq);
5275         if (!NT_STATUS_IS_OK(status)) {
5276                 tevent_req_nterror(req, status);
5277                 return;
5278         }
5279         tevent_req_done(req);
5280 }
5281
5282 NTSTATUS cli_flush_recv(struct tevent_req *req)
5283 {
5284         return tevent_req_simple_recv_ntstatus(req);
5285 }
5286
5287 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
5288 {
5289         TALLOC_CTX *frame = talloc_stackframe();
5290         struct event_context *ev;
5291         struct tevent_req *req;
5292         NTSTATUS status = NT_STATUS_NO_MEMORY;
5293
5294         if (cli_has_async_calls(cli)) {
5295                 /*
5296                  * Can't use sync call while an async call is in flight
5297                  */
5298                 status = NT_STATUS_INVALID_PARAMETER;
5299                 goto fail;
5300         }
5301         ev = event_context_init(frame);
5302         if (ev == NULL) {
5303                 goto fail;
5304         }
5305         req = cli_flush_send(frame, ev, cli, fnum);
5306         if (req == NULL) {
5307                 goto fail;
5308         }
5309         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5310                 goto fail;
5311         }
5312         status = cli_flush_recv(req);
5313  fail:
5314         TALLOC_FREE(frame);
5315         if (!NT_STATUS_IS_OK(status)) {
5316                 cli_set_error(cli, status);
5317         }
5318         return status;
5319 }
5320
5321 struct cli_shadow_copy_data_state {
5322         uint16_t setup[4];
5323         uint8_t *data;
5324         uint32_t num_data;
5325         bool get_names;
5326 };
5327
5328 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
5329
5330 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
5331                                              struct tevent_context *ev,
5332                                              struct cli_state *cli,
5333                                              uint16_t fnum,
5334                                              bool get_names)
5335 {
5336         struct tevent_req *req, *subreq;
5337         struct cli_shadow_copy_data_state *state;
5338         uint32_t ret_size;
5339
5340         req = tevent_req_create(mem_ctx, &state,
5341                                 struct cli_shadow_copy_data_state);
5342         if (req == NULL) {
5343                 return NULL;
5344         }
5345         state->get_names = get_names;
5346         ret_size = get_names ? cli->max_xmit : 16;
5347
5348         SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
5349         SSVAL(state->setup + 2, 0, fnum);
5350         SCVAL(state->setup + 3, 0, 0); /* isFsctl */
5351         SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
5352
5353         subreq = cli_trans_send(
5354                 state, ev, cli, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
5355                 state->setup, ARRAY_SIZE(state->setup), 0,
5356                 NULL, 0, 0,
5357                 NULL, 0, ret_size);
5358         if (tevent_req_nomem(subreq, req)) {
5359                 return tevent_req_post(req, ev);
5360         }
5361         tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
5362         return req;
5363 }
5364
5365 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
5366 {
5367         struct tevent_req *req = tevent_req_callback_data(
5368                 subreq, struct tevent_req);
5369         struct cli_shadow_copy_data_state *state = tevent_req_data(
5370                 req, struct cli_shadow_copy_data_state);
5371         NTSTATUS status;
5372
5373         status = cli_trans_recv(subreq, state, NULL,
5374                                 NULL, 0, NULL, /* setup */
5375                                 NULL, 0, NULL, /* param */
5376                                 &state->data, 12, &state->num_data);
5377         TALLOC_FREE(subreq);
5378         if (!NT_STATUS_IS_OK(status)) {
5379                 tevent_req_nterror(req, status);
5380                 return;
5381         }
5382         tevent_req_done(req);
5383 }
5384
5385 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5386                                    char ***pnames, int *pnum_names)
5387 {
5388         struct cli_shadow_copy_data_state *state = tevent_req_data(
5389                 req, struct cli_shadow_copy_data_state);
5390         char **names;
5391         int i, num_names;
5392         uint32_t dlength;
5393         NTSTATUS status;
5394
5395         if (tevent_req_is_nterror(req, &status)) {
5396                 return status;
5397         }
5398         num_names = IVAL(state->data, 4);
5399         dlength = IVAL(state->data, 8);
5400
5401         if (!state->get_names) {
5402                 *pnum_names = num_names;
5403                 return NT_STATUS_OK;
5404         }
5405
5406         if (dlength+12 > state->num_data) {
5407                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5408         }
5409         names = talloc_array(mem_ctx, char *, num_names);
5410         if (names == NULL) {
5411                 return NT_STATUS_NO_MEMORY;
5412         }
5413
5414         for (i=0; i<num_names; i++) {
5415                 bool ret;
5416                 uint8_t *src;
5417                 size_t converted_size;
5418
5419                 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
5420                 ret = convert_string_talloc(
5421                         names, CH_UTF16LE, CH_UNIX,
5422                         src, 2 * sizeof(SHADOW_COPY_LABEL),
5423                         &names[i], &converted_size);
5424                 if (!ret) {
5425                         TALLOC_FREE(names);
5426                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
5427                 }
5428         }
5429         *pnum_names = num_names;
5430         *pnames = names;
5431         return NT_STATUS_OK;
5432 }
5433
5434 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5435                               uint16_t fnum, bool get_names,
5436                               char ***pnames, int *pnum_names)
5437 {
5438         TALLOC_CTX *frame = talloc_stackframe();
5439         struct event_context *ev;
5440         struct tevent_req *req;
5441         NTSTATUS status = NT_STATUS_NO_MEMORY;
5442
5443         if (cli_has_async_calls(cli)) {
5444                 /*
5445                  * Can't use sync call while an async call is in flight
5446                  */
5447                 status = NT_STATUS_INVALID_PARAMETER;
5448                 goto fail;
5449         }
5450         ev = event_context_init(frame);
5451         if (ev == NULL) {
5452                 goto fail;
5453         }
5454         req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
5455         if (req == NULL) {
5456                 goto fail;
5457         }
5458         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5459                 goto fail;
5460         }
5461         status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
5462  fail:
5463         TALLOC_FREE(frame);
5464         if (!NT_STATUS_IS_OK(status)) {
5465                 cli_set_error(cli, status);
5466         }
5467         return status;
5468 }