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