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