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