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