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