ee37808a225d166272b0884c671298855e893e57
[mat/samba.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "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_BUFFER_SIZE);
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                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
1818         SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1819         SCVAL(vwv+23, 1, SecurityFlags);
1820
1821         bytes = talloc_array(state, uint8_t, 0);
1822         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
1823                                    fname, strlen(fname)+1,
1824                                    &converted_len);
1825
1826         /* sigh. this copes with broken netapp filer behaviour */
1827         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL);
1828
1829         if (tevent_req_nomem(bytes, req)) {
1830                 return tevent_req_post(req, ev);
1831         }
1832
1833         SSVAL(vwv+2, 1, converted_len);
1834
1835         subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
1836                               talloc_get_size(bytes), bytes);
1837         if (tevent_req_nomem(subreq, req)) {
1838                 return tevent_req_post(req, ev);
1839         }
1840         tevent_req_set_callback(subreq, cli_ntcreate_done, req);
1841         return req;
1842 }
1843
1844 static void cli_ntcreate_done(struct tevent_req *subreq)
1845 {
1846         struct tevent_req *req = tevent_req_callback_data(
1847                 subreq, struct tevent_req);
1848         struct cli_ntcreate_state *state = tevent_req_data(
1849                 req, struct cli_ntcreate_state);
1850         uint8_t wct;
1851         uint16_t *vwv;
1852         uint32_t num_bytes;
1853         uint8_t *bytes;
1854         uint8_t *inbuf;
1855         NTSTATUS status;
1856
1857         status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv,
1858                               &num_bytes, &bytes);
1859         TALLOC_FREE(subreq);
1860         if (tevent_req_nterror(req, status)) {
1861                 return;
1862         }
1863         state->fnum = SVAL(vwv+2, 1);
1864         tevent_req_done(req);
1865 }
1866
1867 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
1868 {
1869         struct cli_ntcreate_state *state = tevent_req_data(
1870                 req, struct cli_ntcreate_state);
1871         NTSTATUS status;
1872
1873         if (tevent_req_is_nterror(req, &status)) {
1874                 return status;
1875         }
1876         *pfnum = state->fnum;
1877         return NT_STATUS_OK;
1878 }
1879
1880 NTSTATUS cli_ntcreate(struct cli_state *cli,
1881                       const char *fname,
1882                       uint32_t CreatFlags,
1883                       uint32_t DesiredAccess,
1884                       uint32_t FileAttributes,
1885                       uint32_t ShareAccess,
1886                       uint32_t CreateDisposition,
1887                       uint32_t CreateOptions,
1888                       uint8_t SecurityFlags,
1889                       uint16_t *pfid)
1890 {
1891         TALLOC_CTX *frame = talloc_stackframe();
1892         struct event_context *ev;
1893         struct tevent_req *req;
1894         NTSTATUS status = NT_STATUS_OK;
1895
1896         if (cli_has_async_calls(cli)) {
1897                 /*
1898                  * Can't use sync call while an async call is in flight
1899                  */
1900                 status = NT_STATUS_INVALID_PARAMETER;
1901                 goto fail;
1902         }
1903
1904         ev = event_context_init(frame);
1905         if (ev == NULL) {
1906                 status = NT_STATUS_NO_MEMORY;
1907                 goto fail;
1908         }
1909
1910         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
1911                                 DesiredAccess, FileAttributes, ShareAccess,
1912                                 CreateDisposition, CreateOptions,
1913                                 SecurityFlags);
1914         if (req == NULL) {
1915                 status = NT_STATUS_NO_MEMORY;
1916                 goto fail;
1917         }
1918
1919         if (!tevent_req_poll(req, ev)) {
1920                 status = map_nt_error_from_unix(errno);
1921                 goto fail;
1922         }
1923
1924         status = cli_ntcreate_recv(req, pfid);
1925  fail:
1926         TALLOC_FREE(frame);
1927         return status;
1928 }
1929
1930 struct cli_nttrans_create_state {
1931         uint16_t fnum;
1932 };
1933
1934 static void cli_nttrans_create_done(struct tevent_req *subreq);
1935
1936 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
1937                                            struct event_context *ev,
1938                                            struct cli_state *cli,
1939                                            const char *fname,
1940                                            uint32_t CreatFlags,
1941                                            uint32_t DesiredAccess,
1942                                            uint32_t FileAttributes,
1943                                            uint32_t ShareAccess,
1944                                            uint32_t CreateDisposition,
1945                                            uint32_t CreateOptions,
1946                                            uint8_t SecurityFlags,
1947                                            struct security_descriptor *secdesc,
1948                                            struct ea_struct *eas,
1949                                            int num_eas)
1950 {
1951         struct tevent_req *req, *subreq;
1952         struct cli_nttrans_create_state *state;
1953         uint8_t *param;
1954         uint8_t *secdesc_buf;
1955         size_t secdesc_len;
1956         NTSTATUS status;
1957         size_t converted_len;
1958
1959         req = tevent_req_create(mem_ctx,
1960                                 &state, struct cli_nttrans_create_state);
1961         if (req == NULL) {
1962                 return NULL;
1963         }
1964
1965         if (secdesc != NULL) {
1966                 status = marshall_sec_desc(talloc_tos(), secdesc,
1967                                            &secdesc_buf, &secdesc_len);
1968                 if (tevent_req_nterror(req, status)) {
1969                         DEBUG(10, ("marshall_sec_desc failed: %s\n",
1970                                    nt_errstr(status)));
1971                         return tevent_req_post(req, ev);
1972                 }
1973         } else {
1974                 secdesc_buf = NULL;
1975                 secdesc_len = 0;
1976         }
1977
1978         if (num_eas != 0) {
1979                 /*
1980                  * TODO ;-)
1981                  */
1982                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1983                 return tevent_req_post(req, ev);
1984         }
1985
1986         param = talloc_array(state, uint8_t, 53);
1987         if (tevent_req_nomem(param, req)) {
1988                 return tevent_req_post(req, ev);
1989         }
1990
1991         param = trans2_bytes_push_str(param, cli_ucs2(cli),
1992                                       fname, strlen(fname),
1993                                       &converted_len);
1994         if (tevent_req_nomem(param, req)) {
1995                 return tevent_req_post(req, ev);
1996         }
1997
1998         SIVAL(param, 0, CreatFlags);
1999         SIVAL(param, 4, 0x0);   /* RootDirectoryFid */
2000         SIVAL(param, 8, DesiredAccess);
2001         SIVAL(param, 12, 0x0);  /* AllocationSize */
2002         SIVAL(param, 16, 0x0);  /* AllocationSize */
2003         SIVAL(param, 20, FileAttributes);
2004         SIVAL(param, 24, ShareAccess);
2005         SIVAL(param, 28, CreateDisposition);
2006         SIVAL(param, 32, CreateOptions |
2007                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2008         SIVAL(param, 36, secdesc_len);
2009         SIVAL(param, 40, 0);     /* EA length*/
2010         SIVAL(param, 44, converted_len);
2011         SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2012         SCVAL(param, 52, SecurityFlags);
2013
2014         subreq = cli_trans_send(state, ev, cli, SMBnttrans,
2015                                 NULL, -1, /* name, fid */
2016                                 NT_TRANSACT_CREATE, 0,
2017                                 NULL, 0, 0, /* setup */
2018                                 param, talloc_get_size(param), 128, /* param */
2019                                 secdesc_buf, secdesc_len, 0); /* data */
2020         if (tevent_req_nomem(subreq, req)) {
2021                 return tevent_req_post(req, ev);
2022         }
2023         tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2024         return req;
2025 }
2026
2027 static void cli_nttrans_create_done(struct tevent_req *subreq)
2028 {
2029         struct tevent_req *req = tevent_req_callback_data(
2030                 subreq, struct tevent_req);
2031         struct cli_nttrans_create_state *state = tevent_req_data(
2032                 req, struct cli_nttrans_create_state);
2033         uint8_t *param;
2034         uint32_t num_param;
2035         NTSTATUS status;
2036
2037         status = cli_trans_recv(subreq, talloc_tos(), NULL,
2038                                 NULL, 0, NULL, /* rsetup */
2039                                 &param, 69, &num_param,
2040                                 NULL, 0, NULL);
2041         if (tevent_req_nterror(req, status)) {
2042                 return;
2043         }
2044         state->fnum = SVAL(param, 2);
2045         TALLOC_FREE(param);
2046         tevent_req_done(req);
2047 }
2048
2049 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req, uint16_t *fnum)
2050 {
2051         struct cli_nttrans_create_state *state = tevent_req_data(
2052                 req, struct cli_nttrans_create_state);
2053         NTSTATUS status;
2054
2055         if (tevent_req_is_nterror(req, &status)) {
2056                 return status;
2057         }
2058         *fnum = state->fnum;
2059         return NT_STATUS_OK;
2060 }
2061
2062 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2063                             const char *fname,
2064                             uint32_t CreatFlags,
2065                             uint32_t DesiredAccess,
2066                             uint32_t FileAttributes,
2067                             uint32_t ShareAccess,
2068                             uint32_t CreateDisposition,
2069                             uint32_t CreateOptions,
2070                             uint8_t SecurityFlags,
2071                             struct security_descriptor *secdesc,
2072                             struct ea_struct *eas,
2073                             int num_eas,
2074                             uint16_t *pfid)
2075 {
2076         TALLOC_CTX *frame = talloc_stackframe();
2077         struct event_context *ev;
2078         struct tevent_req *req;
2079         NTSTATUS status = NT_STATUS_NO_MEMORY;
2080
2081         if (cli_has_async_calls(cli)) {
2082                 /*
2083                  * Can't use sync call while an async call is in flight
2084                  */
2085                 status = NT_STATUS_INVALID_PARAMETER;
2086                 goto fail;
2087         }
2088         ev = event_context_init(frame);
2089         if (ev == NULL) {
2090                 goto fail;
2091         }
2092         req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2093                                       DesiredAccess, FileAttributes,
2094                                       ShareAccess, CreateDisposition,
2095                                       CreateOptions, SecurityFlags,
2096                                       secdesc, eas, num_eas);
2097         if (req == NULL) {
2098                 goto fail;
2099         }
2100         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2101                 goto fail;
2102         }
2103         status = cli_nttrans_create_recv(req, pfid);
2104  fail:
2105         TALLOC_FREE(frame);
2106         return status;
2107 }
2108
2109 /****************************************************************************
2110  Open a file
2111  WARNING: if you open with O_WRONLY then getattrE won't work!
2112 ****************************************************************************/
2113
2114 struct cli_openx_state {
2115         struct tevent_context *ev;
2116         struct cli_state *cli;
2117         const char *fname;
2118         uint16_t vwv[15];
2119         uint16_t fnum;
2120         unsigned openfn;
2121         unsigned dos_deny;
2122         uint8_t additional_flags;
2123         struct iovec bytes;
2124 };
2125
2126 static void cli_openx_done(struct tevent_req *subreq);
2127 static void cli_open_ntcreate_done(struct tevent_req *subreq);
2128
2129 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2130                                    struct event_context *ev,
2131                                    struct cli_state *cli, const char *fname,
2132                                    int flags, int share_mode,
2133                                    struct tevent_req **psmbreq)
2134 {
2135         struct tevent_req *req, *subreq;
2136         struct cli_openx_state *state;
2137         uint8_t *bytes;
2138
2139         req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2140         if (req == NULL) {
2141                 return NULL;
2142         }
2143         state->ev = ev;
2144         state->cli = cli;
2145         state->fname = fname;
2146
2147         if (flags & O_CREAT) {
2148                 state->openfn |= (1<<4);
2149         }
2150         if (!(flags & O_EXCL)) {
2151                 if (flags & O_TRUNC)
2152                         state->openfn |= (1<<1);
2153                 else
2154                         state->openfn |= (1<<0);
2155         }
2156
2157         state->dos_deny = (share_mode<<4);
2158
2159         if ((flags & O_ACCMODE) == O_RDWR) {
2160                 state->dos_deny |= 2;
2161         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2162                 state->dos_deny |= 1;
2163         }
2164
2165 #if defined(O_SYNC)
2166         if ((flags & O_SYNC) == O_SYNC) {
2167                 state->dos_deny |= (1<<14);
2168         }
2169 #endif /* O_SYNC */
2170
2171         if (share_mode == DENY_FCB) {
2172                 state->dos_deny = 0xFF;
2173         }
2174
2175         SCVAL(state->vwv + 0, 0, 0xFF);
2176         SCVAL(state->vwv + 0, 1, 0);
2177         SSVAL(state->vwv + 1, 0, 0);
2178         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
2179         SSVAL(state->vwv + 3, 0, state->dos_deny);
2180         SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2181         SSVAL(state->vwv + 5, 0, 0);
2182         SIVAL(state->vwv + 6, 0, 0);
2183         SSVAL(state->vwv + 8, 0, state->openfn);
2184         SIVAL(state->vwv + 9, 0, 0);
2185         SIVAL(state->vwv + 11, 0, 0);
2186         SIVAL(state->vwv + 13, 0, 0);
2187
2188         if (cli->use_oplocks) {
2189                 /* if using oplocks then ask for a batch oplock via
2190                    core and extended methods */
2191                 state->additional_flags =
2192                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2193                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2194         }
2195
2196         bytes = talloc_array(state, uint8_t, 0);
2197         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
2198                                    strlen(fname)+1, NULL);
2199
2200         if (tevent_req_nomem(bytes, req)) {
2201                 return tevent_req_post(req, ev);
2202         }
2203
2204         state->bytes.iov_base = (void *)bytes;
2205         state->bytes.iov_len = talloc_get_size(bytes);
2206
2207         subreq = cli_smb_req_create(state, ev, cli, SMBopenX,
2208                                     state->additional_flags,
2209                                     15, state->vwv, 1, &state->bytes);
2210         if (subreq == NULL) {
2211                 TALLOC_FREE(req);
2212                 return NULL;
2213         }
2214         tevent_req_set_callback(subreq, cli_openx_done, req);
2215         *psmbreq = subreq;
2216         return req;
2217 }
2218
2219 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
2220                                  struct cli_state *cli, const char *fname,
2221                                  int flags, int share_mode)
2222 {
2223         struct tevent_req *req, *subreq;
2224         NTSTATUS status;
2225
2226         req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
2227                               &subreq);
2228         if (req == NULL) {
2229                 return NULL;
2230         }
2231
2232         status = cli_smb_req_send(subreq);
2233         if (tevent_req_nterror(req, status)) {
2234                 return tevent_req_post(req, ev);
2235         }
2236         return req;
2237 }
2238
2239 static void cli_openx_done(struct tevent_req *subreq)
2240 {
2241         struct tevent_req *req = tevent_req_callback_data(
2242                 subreq, struct tevent_req);
2243         struct cli_openx_state *state = tevent_req_data(
2244                 req, struct cli_openx_state);
2245         uint8_t wct;
2246         uint16_t *vwv;
2247         uint8_t *inbuf;
2248         NTSTATUS status;
2249         uint32_t access_mask, share_mode, create_disposition, create_options;
2250
2251         status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv, NULL,
2252                               NULL);
2253         TALLOC_FREE(subreq);
2254
2255         if (NT_STATUS_IS_OK(status)) {
2256                 state->fnum = SVAL(vwv+2, 0);
2257                 tevent_req_done(req);
2258                 return;
2259         }
2260
2261         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
2262                 tevent_req_nterror(req, status);
2263                 return;
2264         }
2265
2266         /*
2267          * For the new shiny OS/X Lion SMB server, try a ntcreate
2268          * fallback.
2269          */
2270
2271         if (!map_open_params_to_ntcreate(state->fname, state->dos_deny,
2272                                          state->openfn, &access_mask,
2273                                          &share_mode, &create_disposition,
2274                                          &create_options, NULL)) {
2275                 tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
2276                 return;
2277         }
2278
2279         subreq = cli_ntcreate_send(state, state->ev, state->cli,
2280                                    state->fname, 0, access_mask,
2281                                    0, share_mode, create_disposition,
2282                                    create_options, 0);
2283         if (tevent_req_nomem(subreq, req)) {
2284                 return;
2285         }
2286         tevent_req_set_callback(subreq, cli_open_ntcreate_done, req);
2287 }
2288
2289 static void cli_open_ntcreate_done(struct tevent_req *subreq)
2290 {
2291         struct tevent_req *req = tevent_req_callback_data(
2292                 subreq, struct tevent_req);
2293         struct cli_openx_state *state = tevent_req_data(
2294                 req, struct cli_openx_state);
2295         NTSTATUS status;
2296
2297         status = cli_ntcreate_recv(subreq, &state->fnum);
2298         TALLOC_FREE(subreq);
2299         if (tevent_req_nterror(req, status)) {
2300                 return;
2301         }
2302         tevent_req_done(req);
2303 }
2304
2305 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2306 {
2307         struct cli_openx_state *state = tevent_req_data(
2308                 req, struct cli_openx_state);
2309         NTSTATUS status;
2310
2311         if (tevent_req_is_nterror(req, &status)) {
2312                 return status;
2313         }
2314         *pfnum = state->fnum;
2315         return NT_STATUS_OK;
2316 }
2317
2318 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
2319              int share_mode, uint16_t *pfnum)
2320 {
2321         TALLOC_CTX *frame = talloc_stackframe();
2322         struct event_context *ev;
2323         struct tevent_req *req;
2324         NTSTATUS status = NT_STATUS_OK;
2325
2326         if (cli_has_async_calls(cli)) {
2327                 /*
2328                  * Can't use sync call while an async call is in flight
2329                  */
2330                 status = NT_STATUS_INVALID_PARAMETER;
2331                 goto fail;
2332         }
2333
2334         ev = event_context_init(frame);
2335         if (ev == NULL) {
2336                 status = NT_STATUS_NO_MEMORY;
2337                 goto fail;
2338         }
2339
2340         req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
2341         if (req == NULL) {
2342                 status = NT_STATUS_NO_MEMORY;
2343                 goto fail;
2344         }
2345
2346         if (!tevent_req_poll(req, ev)) {
2347                 status = map_nt_error_from_unix(errno);
2348                 goto fail;
2349         }
2350
2351         status = cli_openx_recv(req, pfnum);
2352  fail:
2353         TALLOC_FREE(frame);
2354         return status;
2355 }
2356 /****************************************************************************
2357  Synchronous wrapper function that does an NtCreateX open by preference
2358  and falls back to openX if this fails.
2359 ****************************************************************************/
2360
2361 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2362                         int share_mode_in, uint16_t *pfnum)
2363 {
2364         NTSTATUS status;
2365         unsigned int openfn = 0;
2366         unsigned int dos_deny = 0;
2367         uint32_t access_mask, share_mode, create_disposition, create_options;
2368
2369         /* Do the initial mapping into OpenX parameters. */
2370         if (flags & O_CREAT) {
2371                 openfn |= (1<<4);
2372         }
2373         if (!(flags & O_EXCL)) {
2374                 if (flags & O_TRUNC)
2375                         openfn |= (1<<1);
2376                 else
2377                         openfn |= (1<<0);
2378         }
2379
2380         dos_deny = (share_mode_in<<4);
2381
2382         if ((flags & O_ACCMODE) == O_RDWR) {
2383                 dos_deny |= 2;
2384         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2385                 dos_deny |= 1;
2386         }
2387
2388 #if defined(O_SYNC)
2389         if ((flags & O_SYNC) == O_SYNC) {
2390                 dos_deny |= (1<<14);
2391         }
2392 #endif /* O_SYNC */
2393
2394         if (share_mode_in == DENY_FCB) {
2395                 dos_deny = 0xFF;
2396         }
2397
2398 #if 0
2399         /* Hmmm. This is what I think the above code
2400            should look like if it's using the constants
2401            we #define. JRA. */
2402
2403         if (flags & O_CREAT) {
2404                 openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
2405         }
2406         if (!(flags & O_EXCL)) {
2407                 if (flags & O_TRUNC)
2408                         openfn |= OPENX_FILE_EXISTS_TRUNCATE;
2409                 else
2410                         openfn |= OPENX_FILE_EXISTS_OPEN;
2411         }
2412
2413         dos_deny = SET_DENY_MODE(share_mode_in);
2414
2415         if ((flags & O_ACCMODE) == O_RDWR) {
2416                 dos_deny |= DOS_OPEN_RDWR;
2417         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2418                 dos_deny |= DOS_OPEN_WRONLY;
2419         }
2420
2421 #if defined(O_SYNC)
2422         if ((flags & O_SYNC) == O_SYNC) {
2423                 dos_deny |= FILE_SYNC_OPENMODE;
2424         }
2425 #endif /* O_SYNC */
2426
2427         if (share_mode_in == DENY_FCB) {
2428                 dos_deny = 0xFF;
2429         }
2430 #endif
2431
2432         if (!map_open_params_to_ntcreate(fname, dos_deny,
2433                                         openfn, &access_mask,
2434                                         &share_mode, &create_disposition,
2435                                         &create_options, NULL)) {
2436                 goto try_openx;
2437         }
2438
2439         status = cli_ntcreate(cli,
2440                                 fname,
2441                                 0,
2442                                 access_mask,
2443                                 0,
2444                                 share_mode,
2445                                 create_disposition,
2446                                 create_options,
2447                                 0,
2448                                 pfnum);
2449
2450         /* Try and cope will all varients of "we don't do this call"
2451            and fall back to openX. */
2452
2453         if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
2454                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
2455                         NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
2456                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
2457                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
2458                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
2459                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
2460                         NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
2461                         NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
2462                 goto try_openx;
2463         }
2464
2465         return status;
2466
2467   try_openx:
2468
2469         return cli_openx(cli, fname, flags, share_mode_in, pfnum);
2470 }
2471
2472 /****************************************************************************
2473  Close a file.
2474 ****************************************************************************/
2475
2476 struct cli_close_state {
2477         uint16_t vwv[3];
2478 };
2479
2480 static void cli_close_done(struct tevent_req *subreq);
2481
2482 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2483                                 struct event_context *ev,
2484                                 struct cli_state *cli,
2485                                 uint16_t fnum,
2486                                 struct tevent_req **psubreq)
2487 {
2488         struct tevent_req *req, *subreq;
2489         struct cli_close_state *state;
2490
2491         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2492         if (req == NULL) {
2493                 return NULL;
2494         }
2495
2496         SSVAL(state->vwv+0, 0, fnum);
2497         SIVALS(state->vwv+1, 0, -1);
2498
2499         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2500                                     0, NULL);
2501         if (subreq == NULL) {
2502                 TALLOC_FREE(req);
2503                 return NULL;
2504         }
2505         tevent_req_set_callback(subreq, cli_close_done, req);
2506         *psubreq = subreq;
2507         return req;
2508 }
2509
2510 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2511                                 struct event_context *ev,
2512                                 struct cli_state *cli,
2513                                 uint16_t fnum)
2514 {
2515         struct tevent_req *req, *subreq;
2516         NTSTATUS status;
2517
2518         req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2519         if (req == NULL) {
2520                 return NULL;
2521         }
2522
2523         status = cli_smb_req_send(subreq);
2524         if (tevent_req_nterror(req, status)) {
2525                 return tevent_req_post(req, ev);
2526         }
2527         return req;
2528 }
2529
2530 static void cli_close_done(struct tevent_req *subreq)
2531 {
2532         struct tevent_req *req = tevent_req_callback_data(
2533                 subreq, struct tevent_req);
2534         NTSTATUS status;
2535
2536         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2537         TALLOC_FREE(subreq);
2538         if (tevent_req_nterror(req, status)) {
2539                 return;
2540         }
2541         tevent_req_done(req);
2542 }
2543
2544 NTSTATUS cli_close_recv(struct tevent_req *req)
2545 {
2546         return tevent_req_simple_recv_ntstatus(req);
2547 }
2548
2549 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2550 {
2551         TALLOC_CTX *frame = talloc_stackframe();
2552         struct event_context *ev;
2553         struct tevent_req *req;
2554         NTSTATUS status = NT_STATUS_OK;
2555
2556         if (cli_has_async_calls(cli)) {
2557                 /*
2558                  * Can't use sync call while an async call is in flight
2559                  */
2560                 status = NT_STATUS_INVALID_PARAMETER;
2561                 goto fail;
2562         }
2563
2564         ev = event_context_init(frame);
2565         if (ev == NULL) {
2566                 status = NT_STATUS_NO_MEMORY;
2567                 goto fail;
2568         }
2569
2570         req = cli_close_send(frame, ev, cli, fnum);
2571         if (req == NULL) {
2572                 status = NT_STATUS_NO_MEMORY;
2573                 goto fail;
2574         }
2575
2576         if (!tevent_req_poll(req, ev)) {
2577                 status = map_nt_error_from_unix(errno);
2578                 goto fail;
2579         }
2580
2581         status = cli_close_recv(req);
2582  fail:
2583         TALLOC_FREE(frame);
2584         return status;
2585 }
2586
2587 /****************************************************************************
2588  Truncate a file to a specified size
2589 ****************************************************************************/
2590
2591 struct ftrunc_state {
2592         uint16_t setup;
2593         uint8_t param[6];
2594         uint8_t data[8];
2595 };
2596
2597 static void cli_ftruncate_done(struct tevent_req *subreq)
2598 {
2599         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2600                                          NULL, 0, NULL, NULL, 0, NULL);
2601         tevent_req_simple_finish_ntstatus(subreq, status);
2602 }
2603
2604 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2605                                         struct event_context *ev,
2606                                         struct cli_state *cli,
2607                                         uint16_t fnum,
2608                                         uint64_t size)
2609 {
2610         struct tevent_req *req = NULL, *subreq = NULL;
2611         struct ftrunc_state *state = NULL;
2612
2613         req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2614         if (req == NULL) {
2615                 return NULL;
2616         }
2617
2618         /* Setup setup word. */
2619         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2620
2621         /* Setup param array. */
2622         SSVAL(state->param,0,fnum);
2623         SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2624         SSVAL(state->param,4,0);
2625
2626         /* Setup data array. */
2627         SBVAL(state->data, 0, size);
2628
2629         subreq = cli_trans_send(state,                  /* mem ctx. */
2630                                 ev,                     /* event ctx. */
2631                                 cli,                    /* cli_state. */
2632                                 SMBtrans2,              /* cmd. */
2633                                 NULL,                   /* pipe name. */
2634                                 -1,                     /* fid. */
2635                                 0,                      /* function. */
2636                                 0,                      /* flags. */
2637                                 &state->setup,          /* setup. */
2638                                 1,                      /* num setup uint16_t words. */
2639                                 0,                      /* max returned setup. */
2640                                 state->param,           /* param. */
2641                                 6,                      /* num param. */
2642                                 2,                      /* max returned param. */
2643                                 state->data,            /* data. */
2644                                 8,                      /* num data. */
2645                                 0);                     /* max returned data. */
2646
2647         if (tevent_req_nomem(subreq, req)) {
2648                 return tevent_req_post(req, ev);
2649         }
2650         tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2651         return req;
2652 }
2653
2654 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2655 {
2656         return tevent_req_simple_recv_ntstatus(req);
2657 }
2658
2659 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2660 {
2661         TALLOC_CTX *frame = talloc_stackframe();
2662         struct event_context *ev = NULL;
2663         struct tevent_req *req = NULL;
2664         NTSTATUS status = NT_STATUS_OK;
2665
2666         if (cli_has_async_calls(cli)) {
2667                 /*
2668                  * Can't use sync call while an async call is in flight
2669                  */
2670                 status = NT_STATUS_INVALID_PARAMETER;
2671                 goto fail;
2672         }
2673
2674         ev = event_context_init(frame);
2675         if (ev == NULL) {
2676                 status = NT_STATUS_NO_MEMORY;
2677                 goto fail;
2678         }
2679
2680         req = cli_ftruncate_send(frame,
2681                                 ev,
2682                                 cli,
2683                                 fnum,
2684                                 size);
2685         if (req == NULL) {
2686                 status = NT_STATUS_NO_MEMORY;
2687                 goto fail;
2688         }
2689
2690         if (!tevent_req_poll(req, ev)) {
2691                 status = map_nt_error_from_unix(errno);
2692                 goto fail;
2693         }
2694
2695         status = cli_ftruncate_recv(req);
2696
2697  fail:
2698         TALLOC_FREE(frame);
2699         return status;
2700 }
2701
2702 /****************************************************************************
2703  send a lock with a specified locktype
2704  this is used for testing LOCKING_ANDX_CANCEL_LOCK
2705 ****************************************************************************/
2706
2707 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2708                       uint32_t offset, uint32_t len,
2709                       int timeout, unsigned char locktype)
2710 {
2711         uint16_t vwv[8];
2712         uint8_t bytes[10];
2713         NTSTATUS status;
2714         unsigned int set_timeout = 0;
2715         unsigned int saved_timeout = 0;
2716
2717         SCVAL(vwv + 0, 0, 0xff);
2718         SCVAL(vwv + 0, 1, 0);
2719         SSVAL(vwv + 1, 0, 0);
2720         SSVAL(vwv + 2, 0, fnum);
2721         SCVAL(vwv + 3, 0, locktype);
2722         SCVAL(vwv + 3, 1, 0);
2723         SIVALS(vwv + 4, 0, timeout);
2724         SSVAL(vwv + 6, 0, 0);
2725         SSVAL(vwv + 7, 0, 1);
2726
2727         SSVAL(bytes, 0, cli_getpid(cli));
2728         SIVAL(bytes, 2, offset);
2729         SIVAL(bytes, 6, len);
2730
2731         if (timeout != 0) {
2732                 if (timeout == -1) {
2733                         set_timeout = 0x7FFFFFFF;
2734                 } else {
2735                         set_timeout = timeout + 2*1000;
2736                 }
2737                 saved_timeout = cli_set_timeout(cli, set_timeout);
2738         }
2739
2740         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2741                          10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2742
2743         if (saved_timeout != 0) {
2744                 cli_set_timeout(cli, saved_timeout);
2745         }
2746
2747         return status;
2748 }
2749
2750 /****************************************************************************
2751  Lock a file.
2752  note that timeout is in units of 2 milliseconds
2753 ****************************************************************************/
2754
2755 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
2756                   uint32_t offset, uint32_t len, int timeout,
2757                   enum brl_type lock_type)
2758 {
2759         NTSTATUS status;
2760
2761         status = cli_locktype(cli, fnum, offset, len, timeout,
2762                               (lock_type == READ_LOCK? 1 : 0));
2763         return status;
2764 }
2765
2766 /****************************************************************************
2767  Unlock a file.
2768 ****************************************************************************/
2769
2770 struct cli_unlock_state {
2771         uint16_t vwv[8];
2772         uint8_t data[10];
2773 };
2774
2775 static void cli_unlock_done(struct tevent_req *subreq);
2776
2777 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
2778                                 struct event_context *ev,
2779                                 struct cli_state *cli,
2780                                 uint16_t fnum,
2781                                 uint64_t offset,
2782                                 uint64_t len)
2783
2784 {
2785         struct tevent_req *req = NULL, *subreq = NULL;
2786         struct cli_unlock_state *state = NULL;
2787         uint8_t additional_flags = 0;
2788
2789         req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
2790         if (req == NULL) {
2791                 return NULL;
2792         }
2793
2794         SCVAL(state->vwv+0, 0, 0xFF);
2795         SSVAL(state->vwv+2, 0, fnum);
2796         SCVAL(state->vwv+3, 0, 0);
2797         SIVALS(state->vwv+4, 0, 0);
2798         SSVAL(state->vwv+6, 0, 1);
2799         SSVAL(state->vwv+7, 0, 0);
2800
2801         SSVAL(state->data, 0, cli_getpid(cli));
2802         SIVAL(state->data, 2, offset);
2803         SIVAL(state->data, 6, len);
2804
2805         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2806                                 8, state->vwv, 10, state->data);
2807         if (tevent_req_nomem(subreq, req)) {
2808                 return tevent_req_post(req, ev);
2809         }
2810         tevent_req_set_callback(subreq, cli_unlock_done, req);
2811         return req;
2812 }
2813
2814 static void cli_unlock_done(struct tevent_req *subreq)
2815 {
2816         struct tevent_req *req = tevent_req_callback_data(
2817                                 subreq, struct tevent_req);
2818         NTSTATUS status;
2819
2820         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2821         TALLOC_FREE(subreq);
2822         if (tevent_req_nterror(req, status)) {
2823                 return;
2824         }
2825         tevent_req_done(req);
2826 }
2827
2828 NTSTATUS cli_unlock_recv(struct tevent_req *req)
2829 {
2830         return tevent_req_simple_recv_ntstatus(req);
2831 }
2832
2833 NTSTATUS cli_unlock(struct cli_state *cli,
2834                         uint16_t fnum,
2835                         uint32_t offset,
2836                         uint32_t len)
2837 {
2838         TALLOC_CTX *frame = talloc_stackframe();
2839         struct event_context *ev;
2840         struct tevent_req *req;
2841         NTSTATUS status = NT_STATUS_OK;
2842
2843         if (cli_has_async_calls(cli)) {
2844                 /*
2845                  * Can't use sync call while an async call is in flight
2846                  */
2847                 status = NT_STATUS_INVALID_PARAMETER;
2848                 goto fail;
2849         }
2850
2851         ev = event_context_init(frame);
2852         if (ev == NULL) {
2853                 status = NT_STATUS_NO_MEMORY;
2854                 goto fail;
2855         }
2856
2857         req = cli_unlock_send(frame, ev, cli,
2858                         fnum, offset, len);
2859         if (req == NULL) {
2860                 status = NT_STATUS_NO_MEMORY;
2861                 goto fail;
2862         }
2863
2864         if (!tevent_req_poll(req, ev)) {
2865                 status = map_nt_error_from_unix(errno);
2866                 goto fail;
2867         }
2868
2869         status = cli_unlock_recv(req);
2870
2871  fail:
2872         TALLOC_FREE(frame);
2873         return status;
2874 }
2875
2876 /****************************************************************************
2877  Lock a file with 64 bit offsets.
2878 ****************************************************************************/
2879
2880 NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
2881                     uint64_t offset, uint64_t len, int timeout,
2882                     enum brl_type lock_type)
2883 {
2884         uint16_t vwv[8];
2885         uint8_t bytes[20];
2886         unsigned int set_timeout = 0;
2887         unsigned int saved_timeout = 0;
2888         int ltype;
2889         NTSTATUS status;
2890
2891         if (! (cli_state_capabilities(cli) & CAP_LARGE_FILES)) {
2892                 return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
2893         }
2894
2895         ltype = (lock_type == READ_LOCK? 1 : 0);
2896         ltype |= LOCKING_ANDX_LARGE_FILES;
2897
2898         SCVAL(vwv + 0, 0, 0xff);
2899         SCVAL(vwv + 0, 1, 0);
2900         SSVAL(vwv + 1, 0, 0);
2901         SSVAL(vwv + 2, 0, fnum);
2902         SCVAL(vwv + 3, 0, ltype);
2903         SCVAL(vwv + 3, 1, 0);
2904         SIVALS(vwv + 4, 0, timeout);
2905         SSVAL(vwv + 6, 0, 0);
2906         SSVAL(vwv + 7, 0, 1);
2907
2908         SIVAL(bytes, 0, cli_getpid(cli));
2909         SOFF_T_R(bytes, 4, offset);
2910         SOFF_T_R(bytes, 12, len);
2911
2912         if (timeout != 0) {
2913                 if (timeout == -1) {
2914                         set_timeout = 0x7FFFFFFF;
2915                 } else {
2916                         set_timeout = timeout + 2*1000;
2917                 }
2918                 saved_timeout = cli_set_timeout(cli, set_timeout);
2919         }
2920
2921         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2922                          20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2923
2924         if (saved_timeout != 0) {
2925                 cli_set_timeout(cli, saved_timeout);
2926         }
2927
2928         return status;
2929 }
2930
2931 /****************************************************************************
2932  Unlock a file with 64 bit offsets.
2933 ****************************************************************************/
2934
2935 struct cli_unlock64_state {
2936         uint16_t vwv[8];
2937         uint8_t data[20];
2938 };
2939
2940 static void cli_unlock64_done(struct tevent_req *subreq);
2941
2942 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
2943                                 struct event_context *ev,
2944                                 struct cli_state *cli,
2945                                 uint16_t fnum,
2946                                 uint64_t offset,
2947                                 uint64_t len)
2948
2949 {
2950         struct tevent_req *req = NULL, *subreq = NULL;
2951         struct cli_unlock64_state *state = NULL;
2952         uint8_t additional_flags = 0;
2953
2954         req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
2955         if (req == NULL) {
2956                 return NULL;
2957         }
2958
2959         SCVAL(state->vwv+0, 0, 0xff);
2960         SSVAL(state->vwv+2, 0, fnum);
2961         SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
2962         SIVALS(state->vwv+4, 0, 0);
2963         SSVAL(state->vwv+6, 0, 1);
2964         SSVAL(state->vwv+7, 0, 0);
2965
2966         SIVAL(state->data, 0, cli_getpid(cli));
2967         SOFF_T_R(state->data, 4, offset);
2968         SOFF_T_R(state->data, 12, len);
2969
2970         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2971                                 8, state->vwv, 20, state->data);
2972         if (tevent_req_nomem(subreq, req)) {
2973                 return tevent_req_post(req, ev);
2974         }
2975         tevent_req_set_callback(subreq, cli_unlock64_done, req);
2976         return req;
2977 }
2978
2979 static void cli_unlock64_done(struct tevent_req *subreq)
2980 {
2981         struct tevent_req *req = tevent_req_callback_data(
2982                                 subreq, struct tevent_req);
2983         NTSTATUS status;
2984
2985         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2986         TALLOC_FREE(subreq);
2987         if (tevent_req_nterror(req, status)) {
2988                 return;
2989         }
2990         tevent_req_done(req);
2991 }
2992
2993 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
2994 {
2995         return tevent_req_simple_recv_ntstatus(req);
2996 }
2997
2998 NTSTATUS cli_unlock64(struct cli_state *cli,
2999                                 uint16_t fnum,
3000                                 uint64_t offset,
3001                                 uint64_t len)
3002 {
3003         TALLOC_CTX *frame = talloc_stackframe();
3004         struct event_context *ev;
3005         struct tevent_req *req;
3006         NTSTATUS status = NT_STATUS_OK;
3007
3008         if (! (cli_state_capabilities(cli) & CAP_LARGE_FILES)) {
3009                 return cli_unlock(cli, fnum, offset, len);
3010         }
3011
3012         if (cli_has_async_calls(cli)) {
3013                 /*
3014                  * Can't use sync call while an async call is in flight
3015                  */
3016                 status = NT_STATUS_INVALID_PARAMETER;
3017                 goto fail;
3018         }
3019
3020         ev = event_context_init(frame);
3021         if (ev == NULL) {
3022                 status = NT_STATUS_NO_MEMORY;
3023                 goto fail;
3024         }
3025
3026         req = cli_unlock64_send(frame, ev, cli,
3027                         fnum, offset, len);
3028         if (req == NULL) {
3029                 status = NT_STATUS_NO_MEMORY;
3030                 goto fail;
3031         }
3032
3033         if (!tevent_req_poll(req, ev)) {
3034                 status = map_nt_error_from_unix(errno);
3035                 goto fail;
3036         }
3037
3038         status = cli_unlock64_recv(req);
3039
3040  fail:
3041         TALLOC_FREE(frame);
3042         return status;
3043 }
3044
3045 /****************************************************************************
3046  Get/unlock a POSIX lock on a file - internal function.
3047 ****************************************************************************/
3048
3049 struct posix_lock_state {
3050         uint16_t setup;
3051         uint8_t param[4];
3052         uint8_t data[POSIX_LOCK_DATA_SIZE];
3053 };
3054
3055 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3056 {
3057         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3058                                          NULL, 0, NULL, NULL, 0, NULL);
3059         tevent_req_simple_finish_ntstatus(subreq, status);
3060 }
3061
3062 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3063                                         struct event_context *ev,
3064                                         struct cli_state *cli,
3065                                         uint16_t fnum,
3066                                         uint64_t offset,
3067                                         uint64_t len,
3068                                         bool wait_lock,
3069                                         enum brl_type lock_type)
3070 {
3071         struct tevent_req *req = NULL, *subreq = NULL;
3072         struct posix_lock_state *state = NULL;
3073
3074         req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3075         if (req == NULL) {
3076                 return NULL;
3077         }
3078
3079         /* Setup setup word. */
3080         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3081
3082         /* Setup param array. */
3083         SSVAL(&state->param, 0, fnum);
3084         SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3085
3086         /* Setup data array. */
3087         switch (lock_type) {
3088                 case READ_LOCK:
3089                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3090                                 POSIX_LOCK_TYPE_READ);
3091                         break;
3092                 case WRITE_LOCK:
3093                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3094                                 POSIX_LOCK_TYPE_WRITE);
3095                         break;
3096                 case UNLOCK_LOCK:
3097                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3098                                 POSIX_LOCK_TYPE_UNLOCK);
3099                         break;
3100                 default:
3101                         return NULL;
3102         }
3103
3104         if (wait_lock) {
3105                 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3106                                 POSIX_LOCK_FLAG_WAIT);
3107         } else {
3108                 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3109                                 POSIX_LOCK_FLAG_NOWAIT);
3110         }
3111
3112         SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3113         SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3114         SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3115
3116         subreq = cli_trans_send(state,                  /* mem ctx. */
3117                                 ev,                     /* event ctx. */
3118                                 cli,                    /* cli_state. */
3119                                 SMBtrans2,              /* cmd. */
3120                                 NULL,                   /* pipe name. */
3121                                 -1,                     /* fid. */
3122                                 0,                      /* function. */
3123                                 0,                      /* flags. */
3124                                 &state->setup,          /* setup. */
3125                                 1,                      /* num setup uint16_t words. */
3126                                 0,                      /* max returned setup. */
3127                                 state->param,           /* param. */
3128                                 4,                      /* num param. */
3129                                 2,                      /* max returned param. */
3130                                 state->data,            /* data. */
3131                                 POSIX_LOCK_DATA_SIZE,   /* num data. */
3132                                 0);                     /* max returned data. */
3133
3134         if (tevent_req_nomem(subreq, req)) {
3135                 return tevent_req_post(req, ev);
3136         }
3137         tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3138         return req;
3139 }
3140
3141 /****************************************************************************
3142  POSIX Lock a file.
3143 ****************************************************************************/
3144
3145 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3146                                         struct event_context *ev,
3147                                         struct cli_state *cli,
3148                                         uint16_t fnum,
3149                                         uint64_t offset,
3150                                         uint64_t len,
3151                                         bool wait_lock,
3152                                         enum brl_type lock_type)
3153 {
3154         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3155                                         wait_lock, lock_type);
3156 }
3157
3158 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3159 {
3160         return tevent_req_simple_recv_ntstatus(req);
3161 }
3162
3163 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3164                         uint64_t offset, uint64_t len,
3165                         bool wait_lock, enum brl_type lock_type)
3166 {
3167         TALLOC_CTX *frame = talloc_stackframe();
3168         struct event_context *ev = NULL;
3169         struct tevent_req *req = NULL;
3170         NTSTATUS status = NT_STATUS_OK;
3171
3172         if (cli_has_async_calls(cli)) {
3173                 /*
3174                  * Can't use sync call while an async call is in flight
3175                  */
3176                 status = NT_STATUS_INVALID_PARAMETER;
3177                 goto fail;
3178         }
3179
3180         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3181                 status = NT_STATUS_INVALID_PARAMETER;
3182                 goto fail;
3183         }
3184
3185         ev = event_context_init(frame);
3186         if (ev == NULL) {
3187                 status = NT_STATUS_NO_MEMORY;
3188                 goto fail;
3189         }
3190
3191         req = cli_posix_lock_send(frame,
3192                                 ev,
3193                                 cli,
3194                                 fnum,
3195                                 offset,
3196                                 len,
3197                                 wait_lock,
3198                                 lock_type);
3199         if (req == NULL) {
3200                 status = NT_STATUS_NO_MEMORY;
3201                 goto fail;
3202         }
3203
3204         if (!tevent_req_poll(req, ev)) {
3205                 status = map_nt_error_from_unix(errno);
3206                 goto fail;
3207         }
3208
3209         status = cli_posix_lock_recv(req);
3210
3211  fail:
3212         TALLOC_FREE(frame);
3213         return status;
3214 }
3215
3216 /****************************************************************************
3217  POSIX Unlock a file.
3218 ****************************************************************************/
3219
3220 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3221                                         struct event_context *ev,
3222                                         struct cli_state *cli,
3223                                         uint16_t fnum,
3224                                         uint64_t offset,
3225                                         uint64_t len)
3226 {
3227         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3228                                         false, UNLOCK_LOCK);
3229 }
3230
3231 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3232 {
3233         return tevent_req_simple_recv_ntstatus(req);
3234 }
3235
3236 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3237 {
3238         TALLOC_CTX *frame = talloc_stackframe();
3239         struct event_context *ev = NULL;
3240         struct tevent_req *req = NULL;
3241         NTSTATUS status = NT_STATUS_OK;
3242
3243         if (cli_has_async_calls(cli)) {
3244                 /*
3245                  * Can't use sync call while an async call is in flight
3246                  */
3247                 status = NT_STATUS_INVALID_PARAMETER;
3248                 goto fail;
3249         }
3250
3251         ev = event_context_init(frame);
3252         if (ev == NULL) {
3253                 status = NT_STATUS_NO_MEMORY;
3254                 goto fail;
3255         }
3256
3257         req = cli_posix_unlock_send(frame,
3258                                 ev,
3259                                 cli,
3260                                 fnum,
3261                                 offset,
3262                                 len);
3263         if (req == NULL) {
3264                 status = NT_STATUS_NO_MEMORY;
3265                 goto fail;
3266         }
3267
3268         if (!tevent_req_poll(req, ev)) {
3269                 status = map_nt_error_from_unix(errno);
3270                 goto fail;
3271         }
3272
3273         status = cli_posix_unlock_recv(req);
3274
3275  fail:
3276         TALLOC_FREE(frame);
3277         return status;
3278 }
3279
3280 /****************************************************************************
3281  Do a SMBgetattrE call.
3282 ****************************************************************************/
3283
3284 static void cli_getattrE_done(struct tevent_req *subreq);
3285
3286 struct cli_getattrE_state {
3287         uint16_t vwv[1];
3288         int zone_offset;
3289         uint16_t attr;
3290         SMB_OFF_T size;
3291         time_t change_time;
3292         time_t access_time;
3293         time_t write_time;
3294 };
3295
3296 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3297                                 struct event_context *ev,
3298                                 struct cli_state *cli,
3299                                 uint16_t fnum)
3300 {
3301         struct tevent_req *req = NULL, *subreq = NULL;
3302         struct cli_getattrE_state *state = NULL;
3303         uint8_t additional_flags = 0;
3304
3305         req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3306         if (req == NULL) {
3307                 return NULL;
3308         }
3309
3310         state->zone_offset = cli_state_server_time_zone(cli);
3311         SSVAL(state->vwv+0,0,fnum);
3312
3313         subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
3314                               1, state->vwv, 0, NULL);
3315         if (tevent_req_nomem(subreq, req)) {
3316                 return tevent_req_post(req, ev);
3317         }
3318         tevent_req_set_callback(subreq, cli_getattrE_done, req);
3319         return req;
3320 }
3321
3322 static void cli_getattrE_done(struct tevent_req *subreq)
3323 {
3324         struct tevent_req *req = tevent_req_callback_data(
3325                 subreq, struct tevent_req);
3326         struct cli_getattrE_state *state = tevent_req_data(
3327                 req, struct cli_getattrE_state);
3328         uint8_t wct;
3329         uint16_t *vwv = NULL;
3330         uint8_t *inbuf;
3331         NTSTATUS status;
3332
3333         status = cli_smb_recv(subreq, state, &inbuf, 11, &wct, &vwv,
3334                               NULL, NULL);
3335         TALLOC_FREE(subreq);
3336         if (tevent_req_nterror(req, status)) {
3337                 return;
3338         }
3339
3340         state->size = (SMB_OFF_T)IVAL(vwv+6,0);
3341         state->attr = SVAL(vwv+10,0);
3342         state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3343         state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3344         state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3345
3346         tevent_req_done(req);
3347 }
3348
3349 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3350                         uint16_t *attr,
3351                         SMB_OFF_T *size,
3352                         time_t *change_time,
3353                         time_t *access_time,
3354                         time_t *write_time)
3355 {
3356         struct cli_getattrE_state *state = tevent_req_data(
3357                                 req, struct cli_getattrE_state);
3358         NTSTATUS status;
3359
3360         if (tevent_req_is_nterror(req, &status)) {
3361                 return status;
3362         }
3363         if (attr) {
3364                 *attr = state->attr;
3365         }
3366         if (size) {
3367                 *size = state->size;
3368         }
3369         if (change_time) {
3370                 *change_time = state->change_time;
3371         }
3372         if (access_time) {
3373                 *access_time = state->access_time;
3374         }
3375         if (write_time) {
3376                 *write_time = state->write_time;
3377         }
3378         return NT_STATUS_OK;
3379 }
3380
3381 NTSTATUS cli_getattrE(struct cli_state *cli,
3382                         uint16_t fnum,
3383                         uint16_t *attr,
3384                         SMB_OFF_T *size,
3385                         time_t *change_time,
3386                         time_t *access_time,
3387                         time_t *write_time)
3388 {
3389         TALLOC_CTX *frame = talloc_stackframe();
3390         struct event_context *ev = NULL;
3391         struct tevent_req *req = NULL;
3392         NTSTATUS status = NT_STATUS_OK;
3393
3394         if (cli_has_async_calls(cli)) {
3395                 /*
3396                  * Can't use sync call while an async call is in flight
3397                  */
3398                 status = NT_STATUS_INVALID_PARAMETER;
3399                 goto fail;
3400         }
3401
3402         ev = event_context_init(frame);
3403         if (ev == NULL) {
3404                 status = NT_STATUS_NO_MEMORY;
3405                 goto fail;
3406         }
3407
3408         req = cli_getattrE_send(frame, ev, cli, fnum);
3409         if (req == NULL) {
3410                 status = NT_STATUS_NO_MEMORY;
3411                 goto fail;
3412         }
3413
3414         if (!tevent_req_poll(req, ev)) {
3415                 status = map_nt_error_from_unix(errno);
3416                 goto fail;
3417         }
3418
3419         status = cli_getattrE_recv(req,
3420                                         attr,
3421                                         size,
3422                                         change_time,
3423                                         access_time,
3424                                         write_time);
3425
3426  fail:
3427         TALLOC_FREE(frame);
3428         return status;
3429 }
3430
3431 /****************************************************************************
3432  Do a SMBgetatr call
3433 ****************************************************************************/
3434
3435 static void cli_getatr_done(struct tevent_req *subreq);
3436
3437 struct cli_getatr_state {
3438         int zone_offset;
3439         uint16_t attr;
3440         SMB_OFF_T size;
3441         time_t write_time;
3442 };
3443
3444 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3445                                 struct event_context *ev,
3446                                 struct cli_state *cli,
3447                                 const char *fname)
3448 {
3449         struct tevent_req *req = NULL, *subreq = NULL;
3450         struct cli_getatr_state *state = NULL;
3451         uint8_t additional_flags = 0;
3452         uint8_t *bytes = NULL;
3453
3454         req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3455         if (req == NULL) {
3456                 return NULL;
3457         }
3458
3459         state->zone_offset = cli_state_server_time_zone(cli);
3460
3461         bytes = talloc_array(state, uint8_t, 1);
3462         if (tevent_req_nomem(bytes, req)) {
3463                 return tevent_req_post(req, ev);
3464         }
3465         bytes[0] = 4;
3466         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3467                                    strlen(fname)+1, NULL);
3468
3469         if (tevent_req_nomem(bytes, req)) {
3470                 return tevent_req_post(req, ev);
3471         }
3472
3473         subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3474                               0, NULL, talloc_get_size(bytes), bytes);
3475         if (tevent_req_nomem(subreq, req)) {
3476                 return tevent_req_post(req, ev);
3477         }
3478         tevent_req_set_callback(subreq, cli_getatr_done, req);
3479         return req;
3480 }
3481
3482 static void cli_getatr_done(struct tevent_req *subreq)
3483 {
3484         struct tevent_req *req = tevent_req_callback_data(
3485                 subreq, struct tevent_req);
3486         struct cli_getatr_state *state = tevent_req_data(
3487                 req, struct cli_getatr_state);
3488         uint8_t wct;
3489         uint16_t *vwv = NULL;
3490         uint8_t *inbuf;
3491         NTSTATUS status;
3492
3493         status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3494                               NULL);
3495         TALLOC_FREE(subreq);
3496         if (tevent_req_nterror(req, status)) {
3497                 return;
3498         }
3499
3500         state->attr = SVAL(vwv+0,0);
3501         state->size = (SMB_OFF_T)IVAL(vwv+3,0);
3502         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3503
3504         tevent_req_done(req);
3505 }
3506
3507 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3508                         uint16_t *attr,
3509                         SMB_OFF_T *size,
3510                         time_t *write_time)
3511 {
3512         struct cli_getatr_state *state = tevent_req_data(
3513                                 req, struct cli_getatr_state);
3514         NTSTATUS status;
3515
3516         if (tevent_req_is_nterror(req, &status)) {
3517                 return status;
3518         }
3519         if (attr) {
3520                 *attr = state->attr;
3521         }
3522         if (size) {
3523                 *size = state->size;
3524         }
3525         if (write_time) {
3526                 *write_time = state->write_time;
3527         }
3528         return NT_STATUS_OK;
3529 }
3530
3531 NTSTATUS cli_getatr(struct cli_state *cli,
3532                         const char *fname,
3533                         uint16_t *attr,
3534                         SMB_OFF_T *size,
3535                         time_t *write_time)
3536 {
3537         TALLOC_CTX *frame = talloc_stackframe();
3538         struct event_context *ev = NULL;
3539         struct tevent_req *req = NULL;
3540         NTSTATUS status = NT_STATUS_OK;
3541
3542         if (cli_has_async_calls(cli)) {
3543                 /*
3544                  * Can't use sync call while an async call is in flight
3545                  */
3546                 status = NT_STATUS_INVALID_PARAMETER;
3547                 goto fail;
3548         }
3549
3550         ev = event_context_init(frame);
3551         if (ev == NULL) {
3552                 status = NT_STATUS_NO_MEMORY;
3553                 goto fail;
3554         }
3555
3556         req = cli_getatr_send(frame, ev, cli, fname);
3557         if (req == NULL) {
3558                 status = NT_STATUS_NO_MEMORY;
3559                 goto fail;
3560         }
3561
3562         if (!tevent_req_poll(req, ev)) {
3563                 status = map_nt_error_from_unix(errno);
3564                 goto fail;
3565         }
3566
3567         status = cli_getatr_recv(req,
3568                                 attr,
3569                                 size,
3570                                 write_time);
3571
3572  fail:
3573         TALLOC_FREE(frame);
3574         return status;
3575 }
3576
3577 /****************************************************************************
3578  Do a SMBsetattrE call.
3579 ****************************************************************************/
3580
3581 static void cli_setattrE_done(struct tevent_req *subreq);
3582
3583 struct cli_setattrE_state {
3584         uint16_t vwv[7];
3585 };
3586
3587 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3588                                 struct event_context *ev,
3589                                 struct cli_state *cli,
3590                                 uint16_t fnum,
3591                                 time_t change_time,
3592                                 time_t access_time,
3593                                 time_t write_time)
3594 {
3595         struct tevent_req *req = NULL, *subreq = NULL;
3596         struct cli_setattrE_state *state = NULL;
3597         uint8_t additional_flags = 0;
3598
3599         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3600         if (req == NULL) {
3601                 return NULL;
3602         }
3603
3604         SSVAL(state->vwv+0, 0, fnum);
3605         push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
3606                        cli_state_server_time_zone(cli));
3607         push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
3608                        cli_state_server_time_zone(cli));
3609         push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
3610                        cli_state_server_time_zone(cli));
3611
3612         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3613                               7, state->vwv, 0, NULL);
3614         if (tevent_req_nomem(subreq, req)) {
3615                 return tevent_req_post(req, ev);
3616         }
3617         tevent_req_set_callback(subreq, cli_setattrE_done, req);
3618         return req;
3619 }
3620
3621 static void cli_setattrE_done(struct tevent_req *subreq)
3622 {
3623         struct tevent_req *req = tevent_req_callback_data(
3624                 subreq, struct tevent_req);
3625         NTSTATUS status;
3626
3627         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3628         TALLOC_FREE(subreq);
3629         if (tevent_req_nterror(req, status)) {
3630                 return;
3631         }
3632         tevent_req_done(req);
3633 }
3634
3635 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3636 {
3637         return tevent_req_simple_recv_ntstatus(req);
3638 }
3639
3640 NTSTATUS cli_setattrE(struct cli_state *cli,
3641                         uint16_t fnum,
3642                         time_t change_time,
3643                         time_t access_time,
3644                         time_t write_time)
3645 {
3646         TALLOC_CTX *frame = talloc_stackframe();
3647         struct event_context *ev = NULL;
3648         struct tevent_req *req = NULL;
3649         NTSTATUS status = NT_STATUS_OK;
3650
3651         if (cli_has_async_calls(cli)) {
3652                 /*
3653                  * Can't use sync call while an async call is in flight
3654                  */
3655                 status = NT_STATUS_INVALID_PARAMETER;
3656                 goto fail;
3657         }
3658
3659         ev = event_context_init(frame);
3660         if (ev == NULL) {
3661                 status = NT_STATUS_NO_MEMORY;
3662                 goto fail;
3663         }
3664
3665         req = cli_setattrE_send(frame, ev,
3666                         cli,
3667                         fnum,
3668                         change_time,
3669                         access_time,
3670                         write_time);
3671
3672         if (req == NULL) {
3673                 status = NT_STATUS_NO_MEMORY;
3674                 goto fail;
3675         }
3676
3677         if (!tevent_req_poll(req, ev)) {
3678                 status = map_nt_error_from_unix(errno);
3679                 goto fail;
3680         }
3681
3682         status = cli_setattrE_recv(req);
3683
3684  fail:
3685         TALLOC_FREE(frame);
3686         return status;
3687 }
3688
3689 /****************************************************************************
3690  Do a SMBsetatr call.
3691 ****************************************************************************/
3692
3693 static void cli_setatr_done(struct tevent_req *subreq);
3694
3695 struct cli_setatr_state {
3696         uint16_t vwv[8];
3697 };
3698
3699 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3700                                 struct event_context *ev,
3701                                 struct cli_state *cli,
3702                                 const char *fname,
3703                                 uint16_t attr,
3704                                 time_t mtime)
3705 {
3706         struct tevent_req *req = NULL, *subreq = NULL;
3707         struct cli_setatr_state *state = NULL;
3708         uint8_t additional_flags = 0;
3709         uint8_t *bytes = NULL;
3710
3711         req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3712         if (req == NULL) {
3713                 return NULL;
3714         }
3715
3716         SSVAL(state->vwv+0, 0, attr);
3717         push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, cli_state_server_time_zone(cli));
3718
3719         bytes = talloc_array(state, uint8_t, 1);
3720         if (tevent_req_nomem(bytes, req)) {
3721                 return tevent_req_post(req, ev);
3722         }
3723         bytes[0] = 4;
3724         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3725                                    strlen(fname)+1, NULL);
3726         if (tevent_req_nomem(bytes, req)) {
3727                 return tevent_req_post(req, ev);
3728         }
3729         bytes = talloc_realloc(state, bytes, uint8_t,
3730                         talloc_get_size(bytes)+1);
3731         if (tevent_req_nomem(bytes, req)) {
3732                 return tevent_req_post(req, ev);
3733         }
3734
3735         bytes[talloc_get_size(bytes)-1] = 4;
3736         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",
3737                                    1, NULL);
3738         if (tevent_req_nomem(bytes, req)) {
3739                 return tevent_req_post(req, ev);
3740         }
3741
3742         subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3743                               8, state->vwv, talloc_get_size(bytes), bytes);
3744         if (tevent_req_nomem(subreq, req)) {
3745                 return tevent_req_post(req, ev);
3746         }
3747         tevent_req_set_callback(subreq, cli_setatr_done, req);
3748         return req;
3749 }
3750
3751 static void cli_setatr_done(struct tevent_req *subreq)
3752 {
3753         struct tevent_req *req = tevent_req_callback_data(
3754                 subreq, struct tevent_req);
3755         NTSTATUS status;
3756
3757         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3758         TALLOC_FREE(subreq);
3759         if (tevent_req_nterror(req, status)) {
3760                 return;
3761         }
3762         tevent_req_done(req);
3763 }
3764
3765 NTSTATUS cli_setatr_recv(struct tevent_req *req)
3766 {
3767         return tevent_req_simple_recv_ntstatus(req);
3768 }
3769
3770 NTSTATUS cli_setatr(struct cli_state *cli,
3771                 const char *fname,
3772                 uint16_t attr,
3773                 time_t mtime)
3774 {
3775         TALLOC_CTX *frame = talloc_stackframe();
3776         struct event_context *ev = NULL;
3777         struct tevent_req *req = NULL;
3778         NTSTATUS status = NT_STATUS_OK;
3779
3780         if (cli_has_async_calls(cli)) {
3781                 /*
3782                  * Can't use sync call while an async call is in flight
3783                  */
3784                 status = NT_STATUS_INVALID_PARAMETER;
3785                 goto fail;
3786         }
3787
3788         ev = event_context_init(frame);
3789         if (ev == NULL) {
3790                 status = NT_STATUS_NO_MEMORY;
3791                 goto fail;
3792         }
3793
3794         req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
3795         if (req == NULL) {
3796                 status = NT_STATUS_NO_MEMORY;
3797                 goto fail;
3798         }
3799
3800         if (!tevent_req_poll(req, ev)) {
3801                 status = map_nt_error_from_unix(errno);
3802                 goto fail;
3803         }
3804
3805         status = cli_setatr_recv(req);
3806
3807  fail:
3808         TALLOC_FREE(frame);
3809         return status;
3810 }
3811
3812 /****************************************************************************
3813  Check for existance of a dir.
3814 ****************************************************************************/
3815
3816 static void cli_chkpath_done(struct tevent_req *subreq);
3817
3818 struct cli_chkpath_state {
3819         int dummy;
3820 };
3821
3822 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
3823                                   struct event_context *ev,
3824                                   struct cli_state *cli,
3825                                   const char *fname)
3826 {
3827         struct tevent_req *req = NULL, *subreq = NULL;
3828         struct cli_chkpath_state *state = NULL;
3829         uint8_t additional_flags = 0;
3830         uint8_t *bytes = NULL;
3831
3832         req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
3833         if (req == NULL) {
3834                 return NULL;
3835         }
3836
3837         bytes = talloc_array(state, uint8_t, 1);
3838         if (tevent_req_nomem(bytes, req)) {
3839                 return tevent_req_post(req, ev);
3840         }
3841         bytes[0] = 4;
3842         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3843                                    strlen(fname)+1, NULL);
3844
3845         if (tevent_req_nomem(bytes, req)) {
3846                 return tevent_req_post(req, ev);
3847         }
3848
3849         subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
3850                               0, NULL, talloc_get_size(bytes), bytes);
3851         if (tevent_req_nomem(subreq, req)) {
3852                 return tevent_req_post(req, ev);
3853         }
3854         tevent_req_set_callback(subreq, cli_chkpath_done, req);
3855         return req;
3856 }
3857
3858 static void cli_chkpath_done(struct tevent_req *subreq)
3859 {
3860         struct tevent_req *req = tevent_req_callback_data(
3861                 subreq, struct tevent_req);
3862         NTSTATUS status;
3863
3864         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3865         TALLOC_FREE(subreq);
3866         if (tevent_req_nterror(req, status)) {
3867                 return;
3868         }
3869         tevent_req_done(req);
3870 }
3871
3872 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
3873 {
3874         return tevent_req_simple_recv_ntstatus(req);
3875 }
3876
3877 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
3878 {
3879         TALLOC_CTX *frame = talloc_stackframe();
3880         struct event_context *ev = NULL;
3881         struct tevent_req *req = NULL;
3882         char *path2 = NULL;
3883         NTSTATUS status = NT_STATUS_OK;
3884
3885         if (cli_has_async_calls(cli)) {
3886                 /*
3887                  * Can't use sync call while an async call is in flight
3888                  */
3889                 status = NT_STATUS_INVALID_PARAMETER;
3890                 goto fail;
3891         }
3892
3893         path2 = talloc_strdup(frame, path);
3894         if (!path2) {
3895                 status = NT_STATUS_NO_MEMORY;
3896                 goto fail;
3897         }
3898         trim_char(path2,'\0','\\');
3899         if (!*path2) {
3900                 path2 = talloc_strdup(frame, "\\");
3901                 if (!path2) {
3902                         status = NT_STATUS_NO_MEMORY;
3903                         goto fail;
3904                 }
3905         }
3906
3907         ev = event_context_init(frame);
3908         if (ev == NULL) {
3909                 status = NT_STATUS_NO_MEMORY;
3910                 goto fail;
3911         }
3912
3913         req = cli_chkpath_send(frame, ev, cli, path2);
3914         if (req == NULL) {
3915                 status = NT_STATUS_NO_MEMORY;
3916                 goto fail;
3917         }
3918
3919         if (!tevent_req_poll(req, ev)) {
3920                 status = map_nt_error_from_unix(errno);
3921                 goto fail;
3922         }
3923
3924         status = cli_chkpath_recv(req);
3925
3926  fail:
3927         TALLOC_FREE(frame);
3928         return status;
3929 }
3930
3931 /****************************************************************************
3932  Query disk space.
3933 ****************************************************************************/
3934
3935 static void cli_dskattr_done(struct tevent_req *subreq);
3936
3937 struct cli_dskattr_state {
3938         int bsize;
3939         int total;
3940         int avail;
3941 };
3942
3943 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
3944                                   struct event_context *ev,
3945                                   struct cli_state *cli)
3946 {
3947         struct tevent_req *req = NULL, *subreq = NULL;
3948         struct cli_dskattr_state *state = NULL;
3949         uint8_t additional_flags = 0;
3950
3951         req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
3952         if (req == NULL) {
3953                 return NULL;
3954         }
3955
3956         subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
3957                               0, NULL, 0, NULL);
3958         if (tevent_req_nomem(subreq, req)) {
3959                 return tevent_req_post(req, ev);
3960         }
3961         tevent_req_set_callback(subreq, cli_dskattr_done, req);
3962         return req;
3963 }
3964
3965 static void cli_dskattr_done(struct tevent_req *subreq)
3966 {
3967         struct tevent_req *req = tevent_req_callback_data(
3968                 subreq, struct tevent_req);
3969         struct cli_dskattr_state *state = tevent_req_data(
3970                 req, struct cli_dskattr_state);
3971         uint8_t wct;
3972         uint16_t *vwv = NULL;
3973         uint8_t *inbuf;
3974         NTSTATUS status;
3975
3976         status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3977                               NULL);
3978         TALLOC_FREE(subreq);
3979         if (tevent_req_nterror(req, status)) {
3980                 return;
3981         }
3982         state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
3983         state->total = SVAL(vwv+0, 0);
3984         state->avail = SVAL(vwv+3, 0);
3985         tevent_req_done(req);
3986 }
3987
3988 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
3989 {
3990         struct cli_dskattr_state *state = tevent_req_data(
3991                                 req, struct cli_dskattr_state);
3992         NTSTATUS status;
3993
3994         if (tevent_req_is_nterror(req, &status)) {
3995                 return status;
3996         }
3997         *bsize = state->bsize;
3998         *total = state->total;
3999         *avail = state->avail;
4000         return NT_STATUS_OK;
4001 }
4002
4003 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
4004 {
4005         TALLOC_CTX *frame = talloc_stackframe();
4006         struct event_context *ev = NULL;
4007         struct tevent_req *req = NULL;
4008         NTSTATUS status = NT_STATUS_OK;
4009
4010         if (cli_has_async_calls(cli)) {
4011                 /*
4012                  * Can't use sync call while an async call is in flight
4013                  */
4014                 status = NT_STATUS_INVALID_PARAMETER;
4015                 goto fail;
4016         }
4017
4018         ev = event_context_init(frame);
4019         if (ev == NULL) {
4020                 status = NT_STATUS_NO_MEMORY;
4021                 goto fail;
4022         }
4023
4024         req = cli_dskattr_send(frame, ev, cli);
4025         if (req == NULL) {
4026                 status = NT_STATUS_NO_MEMORY;
4027                 goto fail;
4028         }
4029
4030         if (!tevent_req_poll(req, ev)) {
4031                 status = map_nt_error_from_unix(errno);
4032                 goto fail;
4033         }
4034
4035         status = cli_dskattr_recv(req, bsize, total, avail);
4036
4037  fail:
4038         TALLOC_FREE(frame);
4039         return status;
4040 }
4041
4042 /****************************************************************************
4043  Create and open a temporary file.
4044 ****************************************************************************/
4045
4046 static void cli_ctemp_done(struct tevent_req *subreq);
4047
4048 struct ctemp_state {
4049         uint16_t vwv[3];
4050         char *ret_path;
4051         uint16_t fnum;
4052 };
4053
4054 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4055                                 struct event_context *ev,
4056                                 struct cli_state *cli,
4057                                 const char *path)
4058 {
4059         struct tevent_req *req = NULL, *subreq = NULL;
4060         struct ctemp_state *state = NULL;
4061         uint8_t additional_flags = 0;
4062         uint8_t *bytes = NULL;
4063
4064         req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4065         if (req == NULL) {
4066                 return NULL;
4067         }
4068
4069         SSVAL(state->vwv,0,0);
4070         SIVALS(state->vwv+1,0,-1);
4071
4072         bytes = talloc_array(state, uint8_t, 1);
4073         if (tevent_req_nomem(bytes, req)) {
4074                 return tevent_req_post(req, ev);
4075         }
4076         bytes[0] = 4;
4077         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), path,
4078                                    strlen(path)+1, NULL);
4079         if (tevent_req_nomem(bytes, req)) {
4080                 return tevent_req_post(req, ev);
4081         }
4082
4083         subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4084                               3, state->vwv, talloc_get_size(bytes), bytes);
4085         if (tevent_req_nomem(subreq, req)) {
4086                 return tevent_req_post(req, ev);
4087         }
4088         tevent_req_set_callback(subreq, cli_ctemp_done, req);
4089         return req;
4090 }
4091
4092 static void cli_ctemp_done(struct tevent_req *subreq)
4093 {
4094         struct tevent_req *req = tevent_req_callback_data(
4095                                 subreq, struct tevent_req);
4096         struct ctemp_state *state = tevent_req_data(
4097                                 req, struct ctemp_state);
4098         NTSTATUS status;
4099         uint8_t wcnt;
4100         uint16_t *vwv;
4101         uint32_t num_bytes = 0;
4102         uint8_t *bytes = NULL;
4103         uint8_t *inbuf;
4104
4105         status = cli_smb_recv(subreq, state, &inbuf, 1, &wcnt, &vwv,
4106                               &num_bytes, &bytes);
4107         TALLOC_FREE(subreq);
4108         if (tevent_req_nterror(req, status)) {
4109                 return;
4110         }
4111
4112         state->fnum = SVAL(vwv+0, 0);
4113
4114         /* From W2K3, the result is just the ASCII name */
4115         if (num_bytes < 2) {
4116                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
4117                 return;
4118         }
4119
4120         if (pull_string_talloc(state,
4121                         NULL,
4122                         0,
4123                         &state->ret_path,
4124                         bytes,
4125                         num_bytes,
4126                         STR_ASCII) == 0) {
4127                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4128                 return;
4129         }
4130         tevent_req_done(req);
4131 }
4132
4133 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
4134                         TALLOC_CTX *ctx,
4135                         uint16_t *pfnum,
4136                         char **outfile)
4137 {
4138         struct ctemp_state *state = tevent_req_data(req,
4139                         struct ctemp_state);
4140         NTSTATUS status;
4141
4142         if (tevent_req_is_nterror(req, &status)) {
4143                 return status;
4144         }
4145         *pfnum = state->fnum;
4146         *outfile = talloc_strdup(ctx, state->ret_path);
4147         if (!*outfile) {
4148                 return NT_STATUS_NO_MEMORY;
4149         }
4150         return NT_STATUS_OK;
4151 }
4152
4153 NTSTATUS cli_ctemp(struct cli_state *cli,
4154                         TALLOC_CTX *ctx,
4155                         const char *path,
4156                         uint16_t *pfnum,
4157                         char **out_path)
4158 {
4159         TALLOC_CTX *frame = talloc_stackframe();
4160         struct event_context *ev;
4161         struct tevent_req *req;
4162         NTSTATUS status = NT_STATUS_OK;
4163
4164         if (cli_has_async_calls(cli)) {
4165                 /*
4166                  * Can't use sync call while an async call is in flight
4167                  */
4168                 status = NT_STATUS_INVALID_PARAMETER;
4169                 goto fail;
4170         }
4171
4172         ev = event_context_init(frame);
4173         if (ev == NULL) {
4174                 status = NT_STATUS_NO_MEMORY;
4175                 goto fail;
4176         }
4177
4178         req = cli_ctemp_send(frame, ev, cli, path);
4179         if (req == NULL) {
4180                 status = NT_STATUS_NO_MEMORY;
4181                 goto fail;
4182         }
4183
4184         if (!tevent_req_poll(req, ev)) {
4185                 status = map_nt_error_from_unix(errno);
4186                 goto fail;
4187         }
4188
4189         status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4190
4191  fail:
4192         TALLOC_FREE(frame);
4193         return status;
4194 }
4195
4196 /*
4197    send a raw ioctl - used by the torture code
4198 */
4199 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4200 {
4201         uint16_t vwv[3];
4202         NTSTATUS status;
4203
4204         SSVAL(vwv+0, 0, fnum);
4205         SSVAL(vwv+1, 0, code>>16);
4206         SSVAL(vwv+2, 0, (code&0xFFFF));
4207
4208         status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4209                          NULL, 0, NULL, NULL, NULL, NULL);
4210         if (!NT_STATUS_IS_OK(status)) {
4211                 return status;
4212         }
4213         *blob = data_blob_null;
4214         return NT_STATUS_OK;
4215 }
4216
4217 /*********************************************************
4218  Set an extended attribute utility fn.
4219 *********************************************************/
4220
4221 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
4222                            uint8_t *param, unsigned int param_len,
4223                            const char *ea_name,
4224                            const char *ea_val, size_t ea_len)
4225 {
4226         uint16_t setup[1];
4227         unsigned int data_len = 0;
4228         uint8_t *data = NULL;
4229         char *p;
4230         size_t ea_namelen = strlen(ea_name);
4231         NTSTATUS status;
4232
4233         SSVAL(setup, 0, setup_val);
4234
4235         if (ea_namelen == 0 && ea_len == 0) {
4236                 data_len = 4;
4237                 data = (uint8_t *)SMB_MALLOC(data_len);
4238                 if (!data) {
4239                         return NT_STATUS_NO_MEMORY;
4240                 }
4241                 p = (char *)data;
4242                 SIVAL(p,0,data_len);
4243         } else {
4244                 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4245                 data = (uint8_t *)SMB_MALLOC(data_len);
4246                 if (!data) {
4247                         return NT_STATUS_NO_MEMORY;
4248                 }
4249                 p = (char *)data;
4250                 SIVAL(p,0,data_len);
4251                 p += 4;
4252                 SCVAL(p, 0, 0); /* EA flags. */
4253                 SCVAL(p, 1, ea_namelen);
4254                 SSVAL(p, 2, ea_len);
4255                 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4256                 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4257         }
4258
4259         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
4260                            setup, 1, 0,
4261                            param, param_len, 2,
4262                            data,  data_len, CLI_BUFFER_SIZE,
4263                            NULL,
4264                            NULL, 0, NULL, /* rsetup */
4265                            NULL, 0, NULL, /* rparam */
4266                            NULL, 0, NULL); /* rdata */
4267         SAFE_FREE(data);
4268         return status;
4269 }
4270
4271 /*********************************************************
4272  Set an extended attribute on a pathname.
4273 *********************************************************/
4274
4275 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
4276                          const char *ea_name, const char *ea_val,
4277                          size_t ea_len)
4278 {
4279         unsigned int param_len = 0;
4280         uint8_t *param;
4281         NTSTATUS status;
4282         TALLOC_CTX *frame = talloc_stackframe();
4283
4284         param = talloc_array(talloc_tos(), uint8_t, 6);
4285         if (!param) {
4286                 return NT_STATUS_NO_MEMORY;
4287         }
4288         SSVAL(param,0,SMB_INFO_SET_EA);
4289         SSVAL(param,2,0);
4290         SSVAL(param,4,0);
4291
4292         param = trans2_bytes_push_str(param, cli_ucs2(cli),
4293                                       path, strlen(path)+1,
4294                                       NULL);
4295         param_len = talloc_get_size(param);
4296
4297         status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
4298                             ea_name, ea_val, ea_len);
4299         SAFE_FREE(frame);
4300         return status;
4301 }
4302
4303 /*********************************************************
4304  Set an extended attribute on an fnum.
4305 *********************************************************/
4306
4307 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
4308                          const char *ea_name, const char *ea_val,
4309                          size_t ea_len)
4310 {
4311         uint8_t param[6];
4312
4313         memset(param, 0, 6);
4314         SSVAL(param,0,fnum);
4315         SSVAL(param,2,SMB_INFO_SET_EA);
4316
4317         return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
4318                           ea_name, ea_val, ea_len);
4319 }
4320
4321 /*********************************************************
4322  Get an extended attribute list utility fn.
4323 *********************************************************/
4324
4325 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4326                           size_t rdata_len,
4327                           size_t *pnum_eas, struct ea_struct **pea_list)
4328 {
4329         struct ea_struct *ea_list = NULL;
4330         size_t num_eas;
4331         size_t ea_size;
4332         const uint8_t *p;
4333
4334         if (rdata_len < 4) {
4335                 return false;
4336         }
4337
4338         ea_size = (size_t)IVAL(rdata,0);
4339         if (ea_size > rdata_len) {
4340                 return false;
4341         }
4342
4343         if (ea_size == 0) {
4344                 /* No EA's present. */
4345                 *pnum_eas = 0;
4346                 *pea_list = NULL;
4347                 return true;
4348         }
4349
4350         p = rdata + 4;
4351         ea_size -= 4;
4352
4353         /* Validate the EA list and count it. */
4354         for (num_eas = 0; ea_size >= 4; num_eas++) {
4355                 unsigned int ea_namelen = CVAL(p,1);
4356                 unsigned int ea_valuelen = SVAL(p,2);
4357                 if (ea_namelen == 0) {
4358                         return false;
4359                 }
4360                 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4361                         return false;
4362                 }
4363                 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4364                 p += 4 + ea_namelen + 1 + ea_valuelen;
4365         }
4366
4367         if (num_eas == 0) {
4368                 *pnum_eas = 0;
4369                 *pea_list = NULL;
4370                 return true;
4371         }
4372
4373         *pnum_eas = num_eas;
4374         if (!pea_list) {
4375                 /* Caller only wants number of EA's. */
4376                 return true;
4377         }
4378
4379         ea_list = talloc_array(ctx, struct ea_struct, num_eas);
4380         if (!ea_list) {
4381                 return false;
4382         }
4383
4384         ea_size = (size_t)IVAL(rdata,0);
4385         p = rdata + 4;
4386
4387         for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4388                 struct ea_struct *ea = &ea_list[num_eas];
4389                 fstring unix_ea_name;
4390                 unsigned int ea_namelen = CVAL(p,1);
4391                 unsigned int ea_valuelen = SVAL(p,2);
4392
4393                 ea->flags = CVAL(p,0);
4394                 unix_ea_name[0] = '\0';
4395                 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
4396                 ea->name = talloc_strdup(ea_list, unix_ea_name);
4397                 if (!ea->name) {
4398                         goto fail;
4399                 }
4400                 /* Ensure the value is null terminated (in case it's a string). */
4401                 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4402                 if (!ea->value.data) {
4403                         goto fail;
4404                 }
4405                 if (ea_valuelen) {
4406                         memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4407                 }
4408                 ea->value.data[ea_valuelen] = 0;
4409                 ea->value.length--;
4410                 p += 4 + ea_namelen + 1 + ea_valuelen;
4411         }
4412
4413         *pea_list = ea_list;
4414         return true;
4415
4416 fail:
4417         TALLOC_FREE(ea_list);
4418         return false;
4419 }
4420
4421 /*********************************************************
4422  Get an extended attribute list from a pathname.
4423 *********************************************************/
4424
4425 struct cli_get_ea_list_path_state {
4426         uint32_t num_data;
4427         uint8_t *data;
4428 };
4429
4430 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4431
4432 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4433                                              struct tevent_context *ev,
4434                                              struct cli_state *cli,
4435                                              const char *fname)
4436 {
4437         struct tevent_req *req, *subreq;
4438         struct cli_get_ea_list_path_state *state;
4439
4440         req = tevent_req_create(mem_ctx, &state,
4441                                 struct cli_get_ea_list_path_state);
4442         if (req == NULL) {
4443                 return NULL;
4444         }
4445         subreq = cli_qpathinfo_send(state, ev, cli, fname,
4446                                     SMB_INFO_QUERY_ALL_EAS, 4,
4447                                     CLI_BUFFER_SIZE);
4448         if (tevent_req_nomem(subreq, req)) {
4449                 return tevent_req_post(req, ev);
4450         }
4451         tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4452         return req;
4453 }
4454
4455 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4456 {
4457         struct tevent_req *req = tevent_req_callback_data(
4458                                 subreq, struct tevent_req);
4459         struct cli_get_ea_list_path_state *state = tevent_req_data(
4460                 req, struct cli_get_ea_list_path_state);
4461         NTSTATUS status;
4462
4463         status = cli_qpathinfo_recv(subreq, state, &state->data,
4464                                     &state->num_data);
4465         TALLOC_FREE(subreq);
4466         if (tevent_req_nterror(req, status)) {
4467                 return;
4468         }
4469         tevent_req_done(req);
4470 }
4471
4472 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4473                                    size_t *pnum_eas, struct ea_struct **peas)
4474 {
4475         struct cli_get_ea_list_path_state *state = tevent_req_data(
4476                 req, struct cli_get_ea_list_path_state);
4477         NTSTATUS status;
4478
4479         if (tevent_req_is_nterror(req, &status)) {
4480                 return status;
4481         }
4482         if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4483                            pnum_eas, peas)) {
4484                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4485         }
4486         return NT_STATUS_OK;
4487 }
4488
4489 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
4490                 TALLOC_CTX *ctx,
4491                 size_t *pnum_eas,
4492                 struct ea_struct **pea_list)
4493 {
4494         TALLOC_CTX *frame = talloc_stackframe();
4495         struct event_context *ev = NULL;
4496         struct tevent_req *req = NULL;
4497         NTSTATUS status = NT_STATUS_NO_MEMORY;
4498
4499         if (cli_has_async_calls(cli)) {
4500                 /*
4501                  * Can't use sync call while an async call is in flight
4502                  */
4503                 status = NT_STATUS_INVALID_PARAMETER;
4504                 goto fail;
4505         }
4506         ev = event_context_init(frame);
4507         if (ev == NULL) {
4508                 goto fail;
4509         }
4510         req = cli_get_ea_list_path_send(frame, ev, cli, path);
4511         if (req == NULL) {
4512                 goto fail;
4513         }
4514         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4515                 goto fail;
4516         }
4517         status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
4518  fail:
4519         TALLOC_FREE(frame);
4520         return status;
4521 }
4522
4523 /****************************************************************************
4524  Convert open "flags" arg to uint32_t on wire.
4525 ****************************************************************************/
4526
4527 static uint32_t open_flags_to_wire(int flags)
4528 {
4529         int open_mode = flags & O_ACCMODE;
4530         uint32_t ret = 0;
4531
4532         switch (open_mode) {
4533                 case O_WRONLY:
4534                         ret |= SMB_O_WRONLY;
4535                         break;
4536                 case O_RDWR:
4537                         ret |= SMB_O_RDWR;
4538                         break;
4539                 default:
4540                 case O_RDONLY:
4541                         ret |= SMB_O_RDONLY;
4542                         break;
4543         }
4544
4545         if (flags & O_CREAT) {
4546                 ret |= SMB_O_CREAT;
4547         }
4548         if (flags & O_EXCL) {
4549                 ret |= SMB_O_EXCL;
4550         }
4551         if (flags & O_TRUNC) {
4552                 ret |= SMB_O_TRUNC;
4553         }
4554 #if defined(O_SYNC)
4555         if (flags & O_SYNC) {
4556                 ret |= SMB_O_SYNC;
4557         }
4558 #endif /* O_SYNC */
4559         if (flags & O_APPEND) {
4560                 ret |= SMB_O_APPEND;
4561         }
4562 #if defined(O_DIRECT)
4563         if (flags & O_DIRECT) {
4564                 ret |= SMB_O_DIRECT;
4565         }
4566 #endif
4567 #if defined(O_DIRECTORY)
4568         if (flags & O_DIRECTORY) {
4569                 ret |= SMB_O_DIRECTORY;
4570         }
4571 #endif
4572         return ret;
4573 }
4574
4575 /****************************************************************************
4576  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4577 ****************************************************************************/
4578
4579 struct posix_open_state {
4580         uint16_t setup;
4581         uint8_t *param;
4582         uint8_t data[18];
4583         uint16_t fnum; /* Out */
4584 };
4585
4586 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4587 {
4588         struct tevent_req *req = tevent_req_callback_data(
4589                                 subreq, struct tevent_req);
4590         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4591         NTSTATUS status;
4592         uint8_t *data;
4593         uint32_t num_data;
4594
4595         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
4596                                 NULL, 0, NULL, &data, 12, &num_data);
4597         TALLOC_FREE(subreq);
4598         if (tevent_req_nterror(req, status)) {
4599                 return;
4600         }
4601         state->fnum = SVAL(data,2);
4602         tevent_req_done(req);
4603 }
4604
4605 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4606                                         struct event_context *ev,
4607                                         struct cli_state *cli,
4608                                         const char *fname,
4609                                         int flags,
4610                                         mode_t mode,
4611                                         bool is_dir)
4612 {
4613         struct tevent_req *req = NULL, *subreq = NULL;
4614         struct posix_open_state *state = NULL;
4615         uint32_t wire_flags = open_flags_to_wire(flags);
4616
4617         req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4618         if (req == NULL) {
4619                 return NULL;
4620         }
4621
4622         /* Setup setup word. */
4623         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4624
4625         /* Setup param array. */
4626         state->param = talloc_array(state, uint8_t, 6);
4627         if (tevent_req_nomem(state->param, req)) {
4628                 return tevent_req_post(req, ev);
4629         }
4630         memset(state->param, '\0', 6);
4631         SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4632
4633         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
4634                                    strlen(fname)+1, NULL);
4635
4636         if (tevent_req_nomem(state->param, req)) {
4637                 return tevent_req_post(req, ev);
4638         }
4639
4640         /* Setup data words. */
4641         if (is_dir) {
4642                 wire_flags |= SMB_O_DIRECTORY;
4643         }
4644
4645         SIVAL(state->data,0,0); /* No oplock. */
4646         SIVAL(state->data,4,wire_flags);
4647         SIVAL(state->data,8,unix_perms_to_wire(mode));
4648         SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
4649         SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
4650
4651         subreq = cli_trans_send(state,                  /* mem ctx. */
4652                                 ev,                     /* event ctx. */
4653                                 cli,                    /* cli_state. */
4654                                 SMBtrans2,              /* cmd. */
4655                                 NULL,                   /* pipe name. */
4656                                 -1,                     /* fid. */
4657                                 0,                      /* function. */
4658                                 0,                      /* flags. */
4659                                 &state->setup,          /* setup. */
4660                                 1,                      /* num setup uint16_t words. */
4661                                 0,                      /* max returned setup. */
4662                                 state->param,           /* param. */
4663                                 talloc_get_size(state->param),/* num param. */
4664                                 2,                      /* max returned param. */
4665                                 state->data,            /* data. */
4666                                 18,                     /* num data. */
4667                                 12);                    /* max returned data. */
4668
4669         if (tevent_req_nomem(subreq, req)) {
4670                 return tevent_req_post(req, ev);
4671         }
4672         tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
4673         return req;
4674 }
4675
4676 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
4677                                         struct event_context *ev,
4678                                         struct cli_state *cli,
4679                                         const char *fname,
4680                                         int flags,
4681                                         mode_t mode)
4682 {
4683         return cli_posix_open_internal_send(mem_ctx, ev,
4684                                 cli, fname, flags, mode, false);
4685 }
4686
4687 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
4688 {
4689         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4690         NTSTATUS status;
4691
4692         if (tevent_req_is_nterror(req, &status)) {
4693                 return status;
4694         }
4695         *pfnum = state->fnum;
4696         return NT_STATUS_OK;
4697 }
4698
4699 /****************************************************************************
4700  Open - POSIX semantics. Doesn't request oplock.
4701 ****************************************************************************/
4702
4703 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
4704                         int flags, mode_t mode, uint16_t *pfnum)
4705 {
4706
4707         TALLOC_CTX *frame = talloc_stackframe();
4708         struct event_context *ev = NULL;
4709         struct tevent_req *req = NULL;
4710         NTSTATUS status = NT_STATUS_OK;
4711
4712         if (cli_has_async_calls(cli)) {
4713                 /*
4714                  * Can't use sync call while an async call is in flight
4715                  */
4716                 status = NT_STATUS_INVALID_PARAMETER;
4717                 goto fail;
4718         }
4719
4720         ev = event_context_init(frame);
4721         if (ev == NULL) {
4722                 status = NT_STATUS_NO_MEMORY;
4723                 goto fail;
4724         }
4725
4726         req = cli_posix_open_send(frame,
4727                                 ev,
4728                                 cli,
4729                                 fname,
4730                                 flags,
4731                                 mode);
4732         if (req == NULL) {
4733                 status = NT_STATUS_NO_MEMORY;
4734                 goto fail;
4735         }
4736
4737         if (!tevent_req_poll(req, ev)) {
4738                 status = map_nt_error_from_unix(errno);
4739                 goto fail;
4740         }
4741
4742         status = cli_posix_open_recv(req, pfnum);
4743
4744  fail:
4745         TALLOC_FREE(frame);
4746         return status;
4747 }
4748
4749 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
4750                                         struct event_context *ev,
4751                                         struct cli_state *cli,
4752                                         const char *fname,
4753                                         mode_t mode)
4754 {
4755         return cli_posix_open_internal_send(mem_ctx, ev,
4756                                 cli, fname, O_CREAT, mode, true);
4757 }
4758
4759 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
4760 {
4761         return tevent_req_simple_recv_ntstatus(req);
4762 }
4763
4764 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
4765 {
4766         TALLOC_CTX *frame = talloc_stackframe();
4767         struct event_context *ev = NULL;
4768         struct tevent_req *req = NULL;
4769         NTSTATUS status = NT_STATUS_OK;
4770
4771         if (cli_has_async_calls(cli)) {
4772                 /*
4773                  * Can't use sync call while an async call is in flight
4774                  */
4775                 status = NT_STATUS_INVALID_PARAMETER;
4776                 goto fail;
4777         }
4778
4779         ev = event_context_init(frame);
4780         if (ev == NULL) {
4781                 status = NT_STATUS_NO_MEMORY;
4782                 goto fail;
4783         }
4784
4785         req = cli_posix_mkdir_send(frame,
4786                                 ev,
4787                                 cli,
4788                                 fname,
4789                                 mode);
4790         if (req == NULL) {
4791                 status = NT_STATUS_NO_MEMORY;
4792                 goto fail;
4793         }
4794
4795         if (!tevent_req_poll(req, ev)) {
4796                 status = map_nt_error_from_unix(errno);
4797                 goto fail;
4798         }
4799
4800         status = cli_posix_mkdir_recv(req);
4801
4802  fail:
4803         TALLOC_FREE(frame);
4804         return status;
4805 }
4806
4807 /****************************************************************************
4808  unlink or rmdir - POSIX semantics.
4809 ****************************************************************************/
4810
4811 struct cli_posix_unlink_internal_state {
4812         uint8_t data[2];
4813 };
4814
4815 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
4816
4817 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
4818                                         struct event_context *ev,
4819                                         struct cli_state *cli,
4820                                         const char *fname,
4821                                         uint16_t level)
4822 {
4823         struct tevent_req *req = NULL, *subreq = NULL;
4824         struct cli_posix_unlink_internal_state *state = NULL;
4825
4826         req = tevent_req_create(mem_ctx, &state,
4827                                 struct cli_posix_unlink_internal_state);
4828         if (req == NULL) {
4829                 return NULL;
4830         }
4831
4832         /* Setup data word. */
4833         SSVAL(state->data, 0, level);
4834
4835         subreq = cli_setpathinfo_send(state, ev, cli,
4836                                       SMB_POSIX_PATH_UNLINK,
4837                                       fname,
4838                                       state->data, sizeof(state->data));
4839         if (tevent_req_nomem(subreq, req)) {
4840                 return tevent_req_post(req, ev);
4841         }
4842         tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
4843         return req;
4844 }
4845
4846 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
4847 {
4848         NTSTATUS status = cli_setpathinfo_recv(subreq);
4849         tevent_req_simple_finish_ntstatus(subreq, status);
4850 }
4851
4852 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
4853                                         struct event_context *ev,
4854                                         struct cli_state *cli,
4855                                         const char *fname)
4856 {
4857         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
4858                                               SMB_POSIX_UNLINK_FILE_TARGET);
4859 }
4860
4861 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
4862 {
4863         return tevent_req_simple_recv_ntstatus(req);
4864 }
4865
4866 /****************************************************************************
4867  unlink - POSIX semantics.
4868 ****************************************************************************/
4869
4870 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
4871 {
4872         TALLOC_CTX *frame = talloc_stackframe();
4873         struct event_context *ev = NULL;
4874         struct tevent_req *req = NULL;
4875         NTSTATUS status = NT_STATUS_OK;
4876
4877         if (cli_has_async_calls(cli)) {
4878                 /*
4879                  * Can't use sync call while an async call is in flight
4880                  */
4881                 status = NT_STATUS_INVALID_PARAMETER;
4882                 goto fail;
4883         }
4884
4885         ev = event_context_init(frame);
4886         if (ev == NULL) {
4887                 status = NT_STATUS_NO_MEMORY;
4888                 goto fail;
4889         }
4890
4891         req = cli_posix_unlink_send(frame,
4892                                 ev,
4893                                 cli,
4894                                 fname);
4895         if (req == NULL) {
4896                 status = NT_STATUS_NO_MEMORY;
4897                 goto fail;
4898         }
4899
4900         if (!tevent_req_poll(req, ev)) {
4901                 status = map_nt_error_from_unix(errno);
4902                 goto fail;
4903         }
4904
4905         status = cli_posix_unlink_recv(req);
4906
4907  fail:
4908         TALLOC_FREE(frame);
4909         return status;
4910 }
4911
4912 /****************************************************************************
4913  rmdir - POSIX semantics.
4914 ****************************************************************************/
4915
4916 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
4917                                         struct event_context *ev,
4918                                         struct cli_state *cli,
4919                                         const char *fname)
4920 {
4921         return cli_posix_unlink_internal_send(
4922                 mem_ctx, ev, cli, fname,
4923                 SMB_POSIX_UNLINK_DIRECTORY_TARGET);
4924 }
4925
4926 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
4927 {
4928         return tevent_req_simple_recv_ntstatus(req);
4929 }
4930
4931 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
4932 {
4933         TALLOC_CTX *frame = talloc_stackframe();
4934         struct event_context *ev = NULL;
4935         struct tevent_req *req = NULL;
4936         NTSTATUS status = NT_STATUS_OK;
4937
4938         if (cli_has_async_calls(cli)) {
4939                 /*
4940                  * Can't use sync call while an async call is in flight
4941                  */
4942                 status = NT_STATUS_INVALID_PARAMETER;
4943                 goto fail;
4944         }
4945
4946         ev = event_context_init(frame);
4947         if (ev == NULL) {
4948                 status = NT_STATUS_NO_MEMORY;
4949                 goto fail;
4950         }
4951
4952         req = cli_posix_rmdir_send(frame,
4953                                 ev,
4954                                 cli,
4955                                 fname);
4956         if (req == NULL) {
4957                 status = NT_STATUS_NO_MEMORY;
4958                 goto fail;
4959         }
4960
4961         if (!tevent_req_poll(req, ev)) {
4962                 status = map_nt_error_from_unix(errno);
4963                 goto fail;
4964         }
4965
4966         status = cli_posix_rmdir_recv(req, frame);
4967
4968  fail:
4969         TALLOC_FREE(frame);
4970         return status;
4971 }
4972
4973 /****************************************************************************
4974  filechangenotify
4975 ****************************************************************************/
4976
4977 struct cli_notify_state {
4978         uint8_t setup[8];
4979         uint32_t num_changes;
4980         struct notify_change *changes;
4981 };
4982
4983 static void cli_notify_done(struct tevent_req *subreq);
4984
4985 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
4986                                    struct tevent_context *ev,
4987                                    struct cli_state *cli, uint16_t fnum,
4988                                    uint32_t buffer_size,
4989                                    uint32_t completion_filter, bool recursive)
4990 {
4991         struct tevent_req *req, *subreq;
4992         struct cli_notify_state *state;
4993
4994         req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
4995         if (req == NULL) {
4996                 return NULL;
4997         }
4998
4999         SIVAL(state->setup, 0, completion_filter);
5000         SSVAL(state->setup, 4, fnum);
5001         SSVAL(state->setup, 6, recursive);
5002
5003         subreq = cli_trans_send(
5004                 state,                  /* mem ctx. */
5005                 ev,                     /* event ctx. */
5006                 cli,                    /* cli_state. */
5007                 SMBnttrans,             /* cmd. */
5008                 NULL,                   /* pipe name. */
5009                 -1,                     /* fid. */
5010                 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
5011                 0,                      /* flags. */
5012                 (uint16_t *)state->setup, /* setup. */
5013                 4,                      /* num setup uint16_t words. */
5014                 0,                      /* max returned setup. */
5015                 NULL,                   /* param. */
5016                 0,                      /* num param. */
5017                 buffer_size,            /* max returned param. */
5018                 NULL,                   /* data. */
5019                 0,                      /* num data. */
5020                 0);                     /* max returned data. */
5021
5022         if (tevent_req_nomem(subreq, req)) {
5023                 return tevent_req_post(req, ev);
5024         }
5025         tevent_req_set_callback(subreq, cli_notify_done, req);
5026         return req;
5027 }
5028
5029 static void cli_notify_done(struct tevent_req *subreq)
5030 {
5031         struct tevent_req *req = tevent_req_callback_data(
5032                 subreq, struct tevent_req);
5033         struct cli_notify_state *state = tevent_req_data(
5034                 req, struct cli_notify_state);
5035         NTSTATUS status;
5036         uint8_t *params;
5037         uint32_t i, ofs, num_params;
5038         uint16_t flags2;
5039
5040         status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
5041                                 &params, 0, &num_params, NULL, 0, NULL);
5042         TALLOC_FREE(subreq);
5043         if (tevent_req_nterror(req, status)) {
5044                 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
5045                 return;
5046         }
5047
5048         state->num_changes = 0;
5049         ofs = 0;
5050
5051         while (num_params - ofs > 12) {
5052                 uint32_t len = IVAL(params, ofs);
5053                 state->num_changes += 1;
5054
5055                 if ((len == 0) || (ofs+len >= num_params)) {
5056                         break;
5057                 }
5058                 ofs += len;
5059         }
5060
5061         state->changes = talloc_array(state, struct notify_change,
5062                                       state->num_changes);
5063         if (tevent_req_nomem(state->changes, req)) {
5064                 TALLOC_FREE(params);
5065                 return;
5066         }
5067
5068         ofs = 0;
5069
5070         for (i=0; i<state->num_changes; i++) {
5071                 uint32_t next = IVAL(params, ofs);
5072                 uint32_t len = IVAL(params, ofs+8);
5073                 ssize_t ret;
5074                 char *name;
5075
5076                 if ((next != 0) && (len+12 != next)) {
5077                         TALLOC_FREE(params);
5078                         tevent_req_nterror(
5079                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5080                         return;
5081                 }
5082
5083                 state->changes[i].action = IVAL(params, ofs+4);
5084                 ret = clistr_pull_talloc(params, (char *)params, flags2,
5085                                          &name, params+ofs+12, len,
5086                                          STR_TERMINATE|STR_UNICODE);
5087                 if (ret == -1) {
5088                         TALLOC_FREE(params);
5089                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5090                         return;
5091                 }
5092                 state->changes[i].name = name;
5093                 ofs += next;
5094         }
5095
5096         TALLOC_FREE(params);
5097         tevent_req_done(req);
5098 }
5099
5100 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5101                          uint32_t *pnum_changes,
5102                          struct notify_change **pchanges)
5103 {
5104         struct cli_notify_state *state = tevent_req_data(
5105                 req, struct cli_notify_state);
5106         NTSTATUS status;
5107
5108         if (tevent_req_is_nterror(req, &status)) {
5109                 return status;
5110         }
5111
5112         *pnum_changes = state->num_changes;
5113         *pchanges = talloc_move(mem_ctx, &state->changes);
5114         return NT_STATUS_OK;
5115 }
5116
5117 struct cli_qpathinfo_state {
5118         uint8_t *param;
5119         uint8_t *data;
5120         uint16_t setup[1];
5121         uint32_t min_rdata;
5122         uint8_t *rdata;
5123         uint32_t num_rdata;
5124 };
5125
5126 static void cli_qpathinfo_done(struct tevent_req *subreq);
5127
5128 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
5129                                       struct tevent_context *ev,
5130                                       struct cli_state *cli, const char *fname,
5131                                       uint16_t level, uint32_t min_rdata,
5132                                       uint32_t max_rdata)
5133 {
5134         struct tevent_req *req, *subreq;
5135         struct cli_qpathinfo_state *state;
5136
5137         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
5138         if (req == NULL) {
5139                 return NULL;
5140         }
5141         state->min_rdata = min_rdata;
5142         SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
5143
5144         state->param = talloc_zero_array(state, uint8_t, 6);
5145         if (tevent_req_nomem(state->param, req)) {
5146                 return tevent_req_post(req, ev);
5147         }
5148         SSVAL(state->param, 0, level);
5149         state->param = trans2_bytes_push_str(
5150                 state->param, cli_ucs2(cli), fname, strlen(fname)+1, NULL);
5151         if (tevent_req_nomem(state->param, req)) {
5152                 return tevent_req_post(req, ev);
5153         }
5154
5155         subreq = cli_trans_send(
5156                 state,                  /* mem ctx. */
5157                 ev,                     /* event ctx. */
5158                 cli,                    /* cli_state. */
5159                 SMBtrans2,              /* cmd. */
5160                 NULL,                   /* pipe name. */
5161                 -1,                     /* fid. */
5162                 0,                      /* function. */
5163                 0,                      /* flags. */
5164                 state->setup,           /* setup. */
5165                 1,                      /* num setup uint16_t words. */
5166                 0,                      /* max returned setup. */
5167                 state->param,           /* param. */
5168                 talloc_get_size(state->param),  /* num param. */
5169                 2,                      /* max returned param. */
5170                 NULL,                   /* data. */
5171                 0,                      /* num data. */
5172                 max_rdata);             /* max returned data. */
5173
5174         if (tevent_req_nomem(subreq, req)) {
5175                 return tevent_req_post(req, ev);
5176         }
5177         tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5178         return req;
5179 }
5180
5181 static void cli_qpathinfo_done(struct tevent_req *subreq)
5182 {
5183         struct tevent_req *req = tevent_req_callback_data(
5184                 subreq, struct tevent_req);
5185         struct cli_qpathinfo_state *state = tevent_req_data(
5186                 req, struct cli_qpathinfo_state);
5187         NTSTATUS status;
5188
5189         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5190                                 NULL, 0, NULL,
5191                                 &state->rdata, state->min_rdata,
5192                                 &state->num_rdata);
5193         if (tevent_req_nterror(req, status)) {
5194                 return;
5195         }
5196         tevent_req_done(req);
5197 }
5198
5199 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5200                             uint8_t **rdata, uint32_t *num_rdata)
5201 {
5202         struct cli_qpathinfo_state *state = tevent_req_data(
5203                 req, struct cli_qpathinfo_state);
5204         NTSTATUS status;
5205
5206         if (tevent_req_is_nterror(req, &status)) {
5207                 return status;
5208         }
5209         if (rdata != NULL) {
5210                 *rdata = talloc_move(mem_ctx, &state->rdata);
5211         } else {
5212                 TALLOC_FREE(state->rdata);
5213         }
5214         if (num_rdata != NULL) {
5215                 *num_rdata = state->num_rdata;
5216         }
5217         return NT_STATUS_OK;
5218 }
5219
5220 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5221                        const char *fname, uint16_t level, uint32_t min_rdata,
5222                        uint32_t max_rdata,
5223                        uint8_t **rdata, uint32_t *num_rdata)
5224 {
5225         TALLOC_CTX *frame = talloc_stackframe();
5226         struct event_context *ev;
5227         struct tevent_req *req;
5228         NTSTATUS status = NT_STATUS_NO_MEMORY;
5229
5230         if (cli_has_async_calls(cli)) {
5231                 /*
5232                  * Can't use sync call while an async call is in flight
5233                  */
5234                 status = NT_STATUS_INVALID_PARAMETER;
5235                 goto fail;
5236         }
5237         ev = event_context_init(frame);
5238         if (ev == NULL) {
5239                 goto fail;
5240         }
5241         req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5242                                  max_rdata);
5243         if (req == NULL) {
5244                 goto fail;
5245         }
5246         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5247                 goto fail;
5248         }
5249         status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5250  fail:
5251         TALLOC_FREE(frame);
5252         return status;
5253 }
5254
5255 struct cli_qfileinfo_state {
5256         uint16_t setup[1];
5257         uint8_t param[4];
5258         uint8_t *data;
5259         uint16_t recv_flags2;
5260         uint32_t min_rdata;
5261         uint8_t *rdata;
5262         uint32_t num_rdata;
5263 };
5264
5265 static void cli_qfileinfo_done(struct tevent_req *subreq);
5266
5267 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
5268                                       struct tevent_context *ev,
5269                                       struct cli_state *cli, uint16_t fnum,
5270                                       uint16_t level, uint32_t min_rdata,
5271                                       uint32_t max_rdata)
5272 {
5273         struct tevent_req *req, *subreq;
5274         struct cli_qfileinfo_state *state;
5275
5276         req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
5277         if (req == NULL) {
5278                 return NULL;
5279         }
5280         state->min_rdata = min_rdata;
5281         SSVAL(state->param, 0, fnum);
5282         SSVAL(state->param, 2, level);
5283         SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
5284
5285         subreq = cli_trans_send(
5286                 state,                  /* mem ctx. */
5287                 ev,                     /* event ctx. */
5288                 cli,                    /* cli_state. */
5289                 SMBtrans2,              /* cmd. */
5290                 NULL,                   /* pipe name. */
5291                 -1,                     /* fid. */
5292                 0,                      /* function. */
5293                 0,                      /* flags. */
5294                 state->setup,           /* setup. */
5295                 1,                      /* num setup uint16_t words. */
5296                 0,                      /* max returned setup. */
5297                 state->param,           /* param. */
5298                 sizeof(state->param),   /* num param. */
5299                 2,                      /* max returned param. */
5300                 NULL,                   /* data. */
5301                 0,                      /* num data. */
5302                 max_rdata);             /* max returned data. */
5303
5304         if (tevent_req_nomem(subreq, req)) {
5305                 return tevent_req_post(req, ev);
5306         }
5307         tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
5308         return req;
5309 }
5310
5311 static void cli_qfileinfo_done(struct tevent_req *subreq)
5312 {
5313         struct tevent_req *req = tevent_req_callback_data(
5314                 subreq, struct tevent_req);
5315         struct cli_qfileinfo_state *state = tevent_req_data(
5316                 req, struct cli_qfileinfo_state);
5317         NTSTATUS status;
5318
5319         status = cli_trans_recv(subreq, state,
5320                                 &state->recv_flags2,
5321                                 NULL, 0, NULL,
5322                                 NULL, 0, NULL,
5323                                 &state->rdata, state->min_rdata,
5324                                 &state->num_rdata);
5325         if (tevent_req_nterror(req, status)) {
5326                 return;
5327         }
5328         tevent_req_done(req);
5329 }
5330
5331 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5332                             uint16_t *recv_flags2,
5333                             uint8_t **rdata, uint32_t *num_rdata)
5334 {
5335         struct cli_qfileinfo_state *state = tevent_req_data(
5336                 req, struct cli_qfileinfo_state);
5337         NTSTATUS status;
5338
5339         if (tevent_req_is_nterror(req, &status)) {
5340                 return status;
5341         }
5342
5343         if (recv_flags2 != NULL) {
5344                 *recv_flags2 = state->recv_flags2;
5345         }
5346         if (rdata != NULL) {
5347                 *rdata = talloc_move(mem_ctx, &state->rdata);
5348         } else {
5349                 TALLOC_FREE(state->rdata);
5350         }
5351         if (num_rdata != NULL) {
5352                 *num_rdata = state->num_rdata;
5353         }
5354         return NT_STATUS_OK;
5355 }
5356
5357 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5358                        uint16_t fnum, uint16_t level, uint32_t min_rdata,
5359                        uint32_t max_rdata, uint16_t *recv_flags2,
5360                        uint8_t **rdata, uint32_t *num_rdata)
5361 {
5362         TALLOC_CTX *frame = talloc_stackframe();
5363         struct event_context *ev;
5364         struct tevent_req *req;
5365         NTSTATUS status = NT_STATUS_NO_MEMORY;
5366
5367         if (cli_has_async_calls(cli)) {
5368                 /*
5369                  * Can't use sync call while an async call is in flight
5370                  */
5371                 status = NT_STATUS_INVALID_PARAMETER;
5372                 goto fail;
5373         }
5374         ev = event_context_init(frame);
5375         if (ev == NULL) {
5376                 goto fail;
5377         }
5378         req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
5379                                  max_rdata);
5380         if (req == NULL) {
5381                 goto fail;
5382         }
5383         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5384                 goto fail;
5385         }
5386         status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
5387  fail:
5388         TALLOC_FREE(frame);
5389         return status;
5390 }
5391
5392 struct cli_flush_state {
5393         uint16_t vwv[1];
5394 };
5395
5396 static void cli_flush_done(struct tevent_req *subreq);
5397
5398 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
5399                                   struct event_context *ev,
5400                                   struct cli_state *cli,
5401                                   uint16_t fnum)
5402 {
5403         struct tevent_req *req, *subreq;
5404         struct cli_flush_state *state;
5405
5406         req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
5407         if (req == NULL) {
5408                 return NULL;
5409         }
5410         SSVAL(state->vwv + 0, 0, fnum);
5411
5412         subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 1, state->vwv,
5413                               0, NULL);
5414         if (tevent_req_nomem(subreq, req)) {
5415                 return tevent_req_post(req, ev);
5416         }
5417         tevent_req_set_callback(subreq, cli_flush_done, req);
5418         return req;
5419 }
5420
5421 static void cli_flush_done(struct tevent_req *subreq)
5422 {
5423         struct tevent_req *req = tevent_req_callback_data(
5424                 subreq, struct tevent_req);
5425         NTSTATUS status;
5426
5427         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5428         TALLOC_FREE(subreq);
5429         if (tevent_req_nterror(req, status)) {
5430                 return;
5431         }
5432         tevent_req_done(req);
5433 }
5434
5435 NTSTATUS cli_flush_recv(struct tevent_req *req)
5436 {
5437         return tevent_req_simple_recv_ntstatus(req);
5438 }
5439
5440 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
5441 {
5442         TALLOC_CTX *frame = talloc_stackframe();
5443         struct event_context *ev;
5444         struct tevent_req *req;
5445         NTSTATUS status = NT_STATUS_NO_MEMORY;
5446
5447         if (cli_has_async_calls(cli)) {
5448                 /*
5449                  * Can't use sync call while an async call is in flight
5450                  */
5451                 status = NT_STATUS_INVALID_PARAMETER;
5452                 goto fail;
5453         }
5454         ev = event_context_init(frame);
5455         if (ev == NULL) {
5456                 goto fail;
5457         }
5458         req = cli_flush_send(frame, ev, cli, fnum);
5459         if (req == NULL) {
5460                 goto fail;
5461         }
5462         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5463                 goto fail;
5464         }
5465         status = cli_flush_recv(req);
5466  fail:
5467         TALLOC_FREE(frame);
5468         return status;
5469 }
5470
5471 struct cli_shadow_copy_data_state {
5472         uint16_t setup[4];
5473         uint8_t *data;
5474         uint32_t num_data;
5475         bool get_names;
5476 };
5477
5478 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
5479
5480 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
5481                                              struct tevent_context *ev,
5482                                              struct cli_state *cli,
5483                                              uint16_t fnum,
5484                                              bool get_names)
5485 {
5486         struct tevent_req *req, *subreq;
5487         struct cli_shadow_copy_data_state *state;
5488         uint32_t ret_size;
5489
5490         req = tevent_req_create(mem_ctx, &state,
5491                                 struct cli_shadow_copy_data_state);
5492         if (req == NULL) {
5493                 return NULL;
5494         }
5495         state->get_names = get_names;
5496         ret_size = get_names ? CLI_BUFFER_SIZE : 16;
5497
5498         SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
5499         SSVAL(state->setup + 2, 0, fnum);
5500         SCVAL(state->setup + 3, 0, 0); /* isFsctl */
5501         SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
5502
5503         subreq = cli_trans_send(
5504                 state, ev, cli, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
5505                 state->setup, ARRAY_SIZE(state->setup), 0,
5506                 NULL, 0, 0,
5507                 NULL, 0, ret_size);
5508         if (tevent_req_nomem(subreq, req)) {
5509                 return tevent_req_post(req, ev);
5510         }
5511         tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
5512         return req;
5513 }
5514
5515 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
5516 {
5517         struct tevent_req *req = tevent_req_callback_data(
5518                 subreq, struct tevent_req);
5519         struct cli_shadow_copy_data_state *state = tevent_req_data(
5520                 req, struct cli_shadow_copy_data_state);
5521         NTSTATUS status;
5522
5523         status = cli_trans_recv(subreq, state, NULL,
5524                                 NULL, 0, NULL, /* setup */
5525                                 NULL, 0, NULL, /* param */
5526                                 &state->data, 12, &state->num_data);
5527         TALLOC_FREE(subreq);
5528         if (tevent_req_nterror(req, status)) {
5529                 return;
5530         }
5531         tevent_req_done(req);
5532 }
5533
5534 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5535                                    char ***pnames, int *pnum_names)
5536 {
5537         struct cli_shadow_copy_data_state *state = tevent_req_data(
5538                 req, struct cli_shadow_copy_data_state);
5539         char **names;
5540         int i, num_names;
5541         uint32_t dlength;
5542         NTSTATUS status;
5543
5544         if (tevent_req_is_nterror(req, &status)) {
5545                 return status;
5546         }
5547         num_names = IVAL(state->data, 4);
5548         dlength = IVAL(state->data, 8);
5549
5550         if (!state->get_names) {
5551                 *pnum_names = num_names;
5552                 return NT_STATUS_OK;
5553         }
5554
5555         if (dlength+12 > state->num_data) {
5556                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5557         }
5558         names = talloc_array(mem_ctx, char *, num_names);
5559         if (names == NULL) {
5560                 return NT_STATUS_NO_MEMORY;
5561         }
5562
5563         for (i=0; i<num_names; i++) {
5564                 bool ret;
5565                 uint8_t *src;
5566                 size_t converted_size;
5567
5568                 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
5569                 ret = convert_string_talloc(
5570                         names, CH_UTF16LE, CH_UNIX,
5571                         src, 2 * sizeof(SHADOW_COPY_LABEL),
5572                         &names[i], &converted_size);
5573                 if (!ret) {
5574                         TALLOC_FREE(names);
5575                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
5576                 }
5577         }
5578         *pnum_names = num_names;
5579         *pnames = names;
5580         return NT_STATUS_OK;
5581 }
5582
5583 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5584                               uint16_t fnum, bool get_names,
5585                               char ***pnames, int *pnum_names)
5586 {
5587         TALLOC_CTX *frame = talloc_stackframe();
5588         struct event_context *ev;
5589         struct tevent_req *req;
5590         NTSTATUS status = NT_STATUS_NO_MEMORY;
5591
5592         if (cli_has_async_calls(cli)) {
5593                 /*
5594                  * Can't use sync call while an async call is in flight
5595                  */
5596                 status = NT_STATUS_INVALID_PARAMETER;
5597                 goto fail;
5598         }
5599         ev = event_context_init(frame);
5600         if (ev == NULL) {
5601                 goto fail;
5602         }
5603         req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
5604         if (req == NULL) {
5605                 goto fail;
5606         }
5607         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5608                 goto fail;
5609         }
5610         status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
5611  fail:
5612         TALLOC_FREE(frame);
5613         return status;
5614 }