libsmb: Use tevent_req_simple_finish_ntstatus
[samba.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "libsmb/libsmb.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "async_smb.h"
26 #include "libsmb/clirap.h"
27 #include "trans2.h"
28 #include "ntioctl.h"
29 #include "libcli/security/secdesc.h"
30 #include "../libcli/smb/smbXcli_base.h"
31
32 struct cli_setpathinfo_state {
33         uint16_t setup;
34         uint8_t *param;
35 };
36
37 static void cli_setpathinfo_done(struct tevent_req *subreq);
38
39 struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
40                                         struct tevent_context *ev,
41                                         struct cli_state *cli,
42                                         uint16_t level,
43                                         const char *path,
44                                         uint8_t *data,
45                                         size_t data_len)
46 {
47         struct tevent_req *req, *subreq;
48         struct cli_setpathinfo_state *state;
49         uint16_t additional_flags2 = 0;
50
51         req = tevent_req_create(mem_ctx, &state,
52                                 struct cli_setpathinfo_state);
53         if (req == NULL) {
54                 return NULL;
55         }
56
57         /* Setup setup word. */
58         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
59
60         /* Setup param array. */
61         state->param = talloc_zero_array(state, uint8_t, 6);
62         if (tevent_req_nomem(state->param, req)) {
63                 return tevent_req_post(req, ev);
64         }
65         SSVAL(state->param, 0, level);
66
67         state->param = trans2_bytes_push_str(
68                 state->param, smbXcli_conn_use_unicode(cli->conn), path, strlen(path)+1, NULL);
69         if (tevent_req_nomem(state->param, req)) {
70                 return tevent_req_post(req, ev);
71         }
72
73         if (clistr_is_previous_version_path(path, NULL, NULL, NULL) &&
74                         !INFO_LEVEL_IS_UNIX(level)) {
75                 additional_flags2 = FLAGS2_REPARSE_PATH;
76         }
77
78         subreq = cli_trans_send(
79                 state,                  /* mem ctx. */
80                 ev,                     /* event ctx. */
81                 cli,                    /* cli_state. */
82                 additional_flags2,      /* additional_flags2 */
83                 SMBtrans2,              /* cmd. */
84                 NULL,                   /* pipe name. */
85                 -1,                     /* fid. */
86                 0,                      /* function. */
87                 0,                      /* flags. */
88                 &state->setup,          /* setup. */
89                 1,                      /* num setup uint16_t words. */
90                 0,                      /* max returned setup. */
91                 state->param,           /* param. */
92                 talloc_get_size(state->param),  /* num param. */
93                 2,                      /* max returned param. */
94                 data,                   /* data. */
95                 data_len,               /* num data. */
96                 0);                     /* max returned data. */
97
98         if (tevent_req_nomem(subreq, req)) {
99                 return tevent_req_post(req, ev);
100         }
101         tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
102         return req;
103 }
104
105 static void cli_setpathinfo_done(struct tevent_req *subreq)
106 {
107         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
108                                          NULL, 0, NULL, NULL, 0, NULL);
109         tevent_req_simple_finish_ntstatus(subreq, status);
110 }
111
112 NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
113 {
114         return tevent_req_simple_recv_ntstatus(req);
115 }
116
117 NTSTATUS cli_setpathinfo(struct cli_state *cli,
118                          uint16_t level,
119                          const char *path,
120                          uint8_t *data,
121                          size_t data_len)
122 {
123         TALLOC_CTX *frame = talloc_stackframe();
124         struct tevent_context *ev;
125         struct tevent_req *req;
126         NTSTATUS status = NT_STATUS_NO_MEMORY;
127
128         if (smbXcli_conn_has_async_calls(cli->conn)) {
129                 /*
130                  * Can't use sync call while an async call is in flight
131                  */
132                 status = NT_STATUS_INVALID_PARAMETER;
133                 goto fail;
134         }
135         ev = samba_tevent_context_init(frame);
136         if (ev == NULL) {
137                 goto fail;
138         }
139         req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
140         if (req == NULL) {
141                 goto fail;
142         }
143         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
144                 goto fail;
145         }
146         status = cli_setpathinfo_recv(req);
147  fail:
148         TALLOC_FREE(frame);
149         return status;
150 }
151
152 /****************************************************************************
153  Hard/Symlink a file (UNIX extensions).
154  Creates new name (sym)linked to link_target.
155 ****************************************************************************/
156
157 struct cli_posix_link_internal_state {
158         uint8_t *data;
159 };
160
161 static void cli_posix_link_internal_done(struct tevent_req *subreq);
162
163 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
164                                         struct tevent_context *ev,
165                                         struct cli_state *cli,
166                                         uint16_t level,
167                                         const char *link_target,
168                                         const char *newname)
169 {
170         struct tevent_req *req = NULL, *subreq = NULL;
171         struct cli_posix_link_internal_state *state = NULL;
172
173         req = tevent_req_create(mem_ctx, &state,
174                                 struct cli_posix_link_internal_state);
175         if (req == NULL) {
176                 return NULL;
177         }
178
179         /* Setup data array. */
180         state->data = talloc_array(state, uint8_t, 0);
181         if (tevent_req_nomem(state->data, req)) {
182                 return tevent_req_post(req, ev);
183         }
184         state->data = trans2_bytes_push_str(
185                 state->data, smbXcli_conn_use_unicode(cli->conn),
186                 link_target, strlen(link_target)+1, NULL);
187
188         subreq = cli_setpathinfo_send(
189                 state, ev, cli, level, newname,
190                 state->data, talloc_get_size(state->data));
191         if (tevent_req_nomem(subreq, req)) {
192                 return tevent_req_post(req, ev);
193         }
194         tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
195         return req;
196 }
197
198 static void cli_posix_link_internal_done(struct tevent_req *subreq)
199 {
200         NTSTATUS status = cli_setpathinfo_recv(subreq);
201         tevent_req_simple_finish_ntstatus(subreq, status);
202 }
203
204 /****************************************************************************
205  Symlink a file (UNIX extensions).
206 ****************************************************************************/
207
208 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
209                                         struct tevent_context *ev,
210                                         struct cli_state *cli,
211                                         const char *link_target,
212                                         const char *newname)
213 {
214         return cli_posix_link_internal_send(
215                 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, link_target, newname);
216 }
217
218 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
219 {
220         return tevent_req_simple_recv_ntstatus(req);
221 }
222
223 NTSTATUS cli_posix_symlink(struct cli_state *cli,
224                         const char *link_target,
225                         const char *newname)
226 {
227         TALLOC_CTX *frame = talloc_stackframe();
228         struct tevent_context *ev = NULL;
229         struct tevent_req *req = NULL;
230         NTSTATUS status = NT_STATUS_OK;
231
232         if (smbXcli_conn_has_async_calls(cli->conn)) {
233                 /*
234                  * Can't use sync call while an async call is in flight
235                  */
236                 status = NT_STATUS_INVALID_PARAMETER;
237                 goto fail;
238         }
239
240         ev = samba_tevent_context_init(frame);
241         if (ev == NULL) {
242                 status = NT_STATUS_NO_MEMORY;
243                 goto fail;
244         }
245
246         req = cli_posix_symlink_send(frame,
247                                 ev,
248                                 cli,
249                                 link_target,
250                                 newname);
251         if (req == NULL) {
252                 status = NT_STATUS_NO_MEMORY;
253                 goto fail;
254         }
255
256         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
257                 goto fail;
258         }
259
260         status = cli_posix_symlink_recv(req);
261
262  fail:
263         TALLOC_FREE(frame);
264         return status;
265 }
266
267 /****************************************************************************
268  Read a POSIX symlink.
269 ****************************************************************************/
270
271 struct readlink_state {
272         uint8_t *data;
273         uint32_t num_data;
274 };
275
276 static void cli_posix_readlink_done(struct tevent_req *subreq);
277
278 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
279                                         struct tevent_context *ev,
280                                         struct cli_state *cli,
281                                         const char *fname,
282                                         size_t len)
283 {
284         struct tevent_req *req = NULL, *subreq = NULL;
285         struct readlink_state *state = NULL;
286         uint32_t maxbytelen = (uint32_t)(smbXcli_conn_use_unicode(cli->conn) ? len*3 : len);
287
288         req = tevent_req_create(mem_ctx, &state, struct readlink_state);
289         if (req == NULL) {
290                 return NULL;
291         }
292
293         /*
294          * Len is in bytes, we need it in UCS2 units.
295          */
296         if ((2*len < len) || (maxbytelen < len)) {
297                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
298                 return tevent_req_post(req, ev);
299         }
300
301         subreq = cli_qpathinfo_send(state, ev, cli, fname,
302                                     SMB_QUERY_FILE_UNIX_LINK, 1, maxbytelen);
303         if (tevent_req_nomem(subreq, req)) {
304                 return tevent_req_post(req, ev);
305         }
306         tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
307         return req;
308 }
309
310 static void cli_posix_readlink_done(struct tevent_req *subreq)
311 {
312         struct tevent_req *req = tevent_req_callback_data(
313                 subreq, struct tevent_req);
314         struct readlink_state *state = tevent_req_data(
315                 req, struct readlink_state);
316         NTSTATUS status;
317
318         status = cli_qpathinfo_recv(subreq, state, &state->data,
319                                     &state->num_data);
320         TALLOC_FREE(subreq);
321         if (tevent_req_nterror(req, status)) {
322                 return;
323         }
324         /*
325          * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
326          */
327         if (state->data[state->num_data-1] != '\0') {
328                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
329                 return;
330         }
331         tevent_req_done(req);
332 }
333
334 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
335                                 char *retpath, size_t len)
336 {
337         NTSTATUS status;
338         char *converted = NULL;
339         size_t converted_size = 0;
340         struct readlink_state *state = tevent_req_data(req, struct readlink_state);
341
342         if (tevent_req_is_nterror(req, &status)) {
343                 return status;
344         }
345         /* The returned data is a pushed string, not raw data. */
346         if (!convert_string_talloc(state,
347                                 smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS, 
348                                 CH_UNIX,
349                                 state->data,
350                                 state->num_data,
351                                 &converted,
352                                 &converted_size)) {
353                 return NT_STATUS_NO_MEMORY;
354         }
355
356         len = MIN(len,converted_size);
357         if (len == 0) {
358                 return NT_STATUS_DATA_ERROR;
359         }
360         memcpy(retpath, converted, len);
361         return NT_STATUS_OK;
362 }
363
364 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
365                                 char *linkpath, size_t len)
366 {
367         TALLOC_CTX *frame = talloc_stackframe();
368         struct tevent_context *ev = NULL;
369         struct tevent_req *req = NULL;
370         NTSTATUS status = NT_STATUS_OK;
371
372         if (smbXcli_conn_has_async_calls(cli->conn)) {
373                 /*
374                  * Can't use sync call while an async call is in flight
375                  */
376                 status = NT_STATUS_INVALID_PARAMETER;
377                 goto fail;
378         }
379
380         ev = samba_tevent_context_init(frame);
381         if (ev == NULL) {
382                 status = NT_STATUS_NO_MEMORY;
383                 goto fail;
384         }
385
386         req = cli_posix_readlink_send(frame,
387                                 ev,
388                                 cli,
389                                 fname,
390                                 len);
391         if (req == NULL) {
392                 status = NT_STATUS_NO_MEMORY;
393                 goto fail;
394         }
395
396         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
397                 goto fail;
398         }
399
400         status = cli_posix_readlink_recv(req, cli, linkpath, len);
401
402  fail:
403         TALLOC_FREE(frame);
404         return status;
405 }
406
407 /****************************************************************************
408  Hard link a file (UNIX extensions).
409 ****************************************************************************/
410
411 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
412                                         struct tevent_context *ev,
413                                         struct cli_state *cli,
414                                         const char *oldname,
415                                         const char *newname)
416 {
417         return cli_posix_link_internal_send(
418                 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
419 }
420
421 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
422 {
423         return tevent_req_simple_recv_ntstatus(req);
424 }
425
426 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
427                         const char *oldname,
428                         const char *newname)
429 {
430         TALLOC_CTX *frame = talloc_stackframe();
431         struct tevent_context *ev = NULL;
432         struct tevent_req *req = NULL;
433         NTSTATUS status = NT_STATUS_OK;
434
435         if (smbXcli_conn_has_async_calls(cli->conn)) {
436                 /*
437                  * Can't use sync call while an async call is in flight
438                  */
439                 status = NT_STATUS_INVALID_PARAMETER;
440                 goto fail;
441         }
442
443         ev = samba_tevent_context_init(frame);
444         if (ev == NULL) {
445                 status = NT_STATUS_NO_MEMORY;
446                 goto fail;
447         }
448
449         req = cli_posix_hardlink_send(frame,
450                                 ev,
451                                 cli,
452                                 oldname,
453                                 newname);
454         if (req == NULL) {
455                 status = NT_STATUS_NO_MEMORY;
456                 goto fail;
457         }
458
459         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
460                 goto fail;
461         }
462
463         status = cli_posix_hardlink_recv(req);
464
465  fail:
466         TALLOC_FREE(frame);
467         return status;
468 }
469
470 /****************************************************************************
471  Do a POSIX getacl - pathname based ACL get (UNIX extensions).
472 ****************************************************************************/
473
474 struct getacl_state {
475         uint32_t num_data;
476         uint8_t *data;
477 };
478
479 static void cli_posix_getacl_done(struct tevent_req *subreq);
480
481 struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
482                                         struct tevent_context *ev,
483                                         struct cli_state *cli,
484                                         const char *fname)
485 {
486         struct tevent_req *req = NULL, *subreq = NULL;
487         struct getacl_state *state = NULL;
488
489         req = tevent_req_create(mem_ctx, &state, struct getacl_state);
490         if (req == NULL) {
491                 return NULL;
492         }
493         subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
494                                     0, CLI_BUFFER_SIZE);
495         if (tevent_req_nomem(subreq, req)) {
496                 return tevent_req_post(req, ev);
497         }
498         tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
499         return req;
500 }
501
502 static void cli_posix_getacl_done(struct tevent_req *subreq)
503 {
504         struct tevent_req *req = tevent_req_callback_data(
505                 subreq, struct tevent_req);
506         struct getacl_state *state = tevent_req_data(
507                 req, struct getacl_state);
508         NTSTATUS status;
509
510         status = cli_qpathinfo_recv(subreq, state, &state->data,
511                                     &state->num_data);
512         TALLOC_FREE(subreq);
513         if (tevent_req_nterror(req, status)) {
514                 return;
515         }
516         tevent_req_done(req);
517 }
518
519 NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
520                                 TALLOC_CTX *mem_ctx,
521                                 size_t *prb_size,
522                                 char **retbuf)
523 {
524         struct getacl_state *state = tevent_req_data(req, struct getacl_state);
525         NTSTATUS status;
526
527         if (tevent_req_is_nterror(req, &status)) {
528                 return status;
529         }
530         *prb_size = (size_t)state->num_data;
531         *retbuf = (char *)talloc_move(mem_ctx, &state->data);
532         return NT_STATUS_OK;
533 }
534
535 NTSTATUS cli_posix_getacl(struct cli_state *cli,
536                         const char *fname,
537                         TALLOC_CTX *mem_ctx,
538                         size_t *prb_size,
539                         char **retbuf)
540 {
541         TALLOC_CTX *frame = talloc_stackframe();
542         struct tevent_context *ev = NULL;
543         struct tevent_req *req = NULL;
544         NTSTATUS status = NT_STATUS_OK;
545
546         if (smbXcli_conn_has_async_calls(cli->conn)) {
547                 /*
548                  * Can't use sync call while an async call is in flight
549                  */
550                 status = NT_STATUS_INVALID_PARAMETER;
551                 goto fail;
552         }
553
554         ev = samba_tevent_context_init(frame);
555         if (ev == NULL) {
556                 status = NT_STATUS_NO_MEMORY;
557                 goto fail;
558         }
559
560         req = cli_posix_getacl_send(frame,
561                                 ev,
562                                 cli,
563                                 fname);
564         if (req == NULL) {
565                 status = NT_STATUS_NO_MEMORY;
566                 goto fail;
567         }
568
569         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
570                 goto fail;
571         }
572
573         status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
574
575  fail:
576         TALLOC_FREE(frame);
577         return status;
578 }
579
580 /****************************************************************************
581  Do a POSIX setacl - pathname based ACL set (UNIX extensions).
582 ****************************************************************************/
583
584 struct setacl_state {
585         uint8_t *data;
586 };
587
588 static void cli_posix_setacl_done(struct tevent_req *subreq);
589
590 struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
591                                         struct tevent_context *ev,
592                                         struct cli_state *cli,
593                                         const char *fname,
594                                         const void *data,
595                                         size_t num_data)
596 {
597         struct tevent_req *req = NULL, *subreq = NULL;
598         struct setacl_state *state = NULL;
599
600         req = tevent_req_create(mem_ctx, &state, struct setacl_state);
601         if (req == NULL) {
602                 return NULL;
603         }
604         state->data = talloc_memdup(state, data, num_data);
605         if (tevent_req_nomem(state->data, req)) {
606                 return tevent_req_post(req, ev);
607         }
608
609         subreq = cli_setpathinfo_send(state,
610                                 ev,
611                                 cli,
612                                 SMB_SET_POSIX_ACL,
613                                 fname,
614                                 state->data,
615                                 num_data);
616         if (tevent_req_nomem(subreq, req)) {
617                 return tevent_req_post(req, ev);
618         }
619         tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
620         return req;
621 }
622
623 static void cli_posix_setacl_done(struct tevent_req *subreq)
624 {
625         NTSTATUS status = cli_setpathinfo_recv(subreq);
626         tevent_req_simple_finish_ntstatus(subreq, status);
627 }
628
629 NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
630 {
631         return tevent_req_simple_recv_ntstatus(req);
632 }
633
634 NTSTATUS cli_posix_setacl(struct cli_state *cli,
635                         const char *fname,
636                         const void *acl_buf,
637                         size_t acl_buf_size)
638 {
639         TALLOC_CTX *frame = talloc_stackframe();
640         struct tevent_context *ev = NULL;
641         struct tevent_req *req = NULL;
642         NTSTATUS status = NT_STATUS_OK;
643
644         if (smbXcli_conn_has_async_calls(cli->conn)) {
645                 /*
646                  * Can't use sync call while an async call is in flight
647                  */
648                 status = NT_STATUS_INVALID_PARAMETER;
649                 goto fail;
650         }
651
652         ev = samba_tevent_context_init(frame);
653         if (ev == NULL) {
654                 status = NT_STATUS_NO_MEMORY;
655                 goto fail;
656         }
657
658         req = cli_posix_setacl_send(frame,
659                                 ev,
660                                 cli,
661                                 fname,
662                                 acl_buf,
663                                 acl_buf_size);
664         if (req == NULL) {
665                 status = NT_STATUS_NO_MEMORY;
666                 goto fail;
667         }
668
669         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
670                 goto fail;
671         }
672
673         status = cli_posix_setacl_recv(req);
674
675  fail:
676         TALLOC_FREE(frame);
677         return status;
678 }
679
680 /****************************************************************************
681  Stat a file (UNIX extensions).
682 ****************************************************************************/
683
684 struct stat_state {
685         uint32_t num_data;
686         uint8_t *data;
687 };
688
689 static void cli_posix_stat_done(struct tevent_req *subreq);
690
691 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
692                                         struct tevent_context *ev,
693                                         struct cli_state *cli,
694                                         const char *fname)
695 {
696         struct tevent_req *req = NULL, *subreq = NULL;
697         struct stat_state *state = NULL;
698
699         req = tevent_req_create(mem_ctx, &state, struct stat_state);
700         if (req == NULL) {
701                 return NULL;
702         }
703         subreq = cli_qpathinfo_send(state, ev, cli, fname,
704                                     SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
705         if (tevent_req_nomem(subreq, req)) {
706                 return tevent_req_post(req, ev);
707         }
708         tevent_req_set_callback(subreq, cli_posix_stat_done, req);
709         return req;
710 }
711
712 static void cli_posix_stat_done(struct tevent_req *subreq)
713 {
714         struct tevent_req *req = tevent_req_callback_data(
715                                 subreq, struct tevent_req);
716         struct stat_state *state = tevent_req_data(req, struct stat_state);
717         NTSTATUS status;
718
719         status = cli_qpathinfo_recv(subreq, state, &state->data,
720                                     &state->num_data);
721         TALLOC_FREE(subreq);
722         if (tevent_req_nterror(req, status)) {
723                 return;
724         }
725         tevent_req_done(req);
726 }
727
728 NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
729                                 SMB_STRUCT_STAT *sbuf)
730 {
731         struct stat_state *state = tevent_req_data(req, struct stat_state);
732         NTSTATUS status;
733
734         if (tevent_req_is_nterror(req, &status)) {
735                 return status;
736         }
737
738         sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0);     /* total size, in bytes */
739         sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8);   /* number of blocks allocated */
740 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
741         sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
742 #else
743         /* assume 512 byte blocks */
744         sbuf->st_ex_blocks /= 512;
745 #endif
746         sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16));    /* time of last change */
747         sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24));    /* time of last access */
748         sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32));    /* time of last modification */
749
750         sbuf->st_ex_uid = (uid_t) IVAL(state->data,40);      /* user ID of owner */
751         sbuf->st_ex_gid = (gid_t) IVAL(state->data,48);      /* group ID of owner */
752         sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
753 #if defined(HAVE_MAKEDEV)
754         {
755                 uint32_t dev_major = IVAL(state->data,60);
756                 uint32_t dev_minor = IVAL(state->data,68);
757                 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
758         }
759 #endif
760         sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76);      /* inode */
761         sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84));     /* protection */
762         sbuf->st_ex_nlink = BIG_UINT(state->data,92); /* number of hard links */
763
764         return NT_STATUS_OK;
765 }
766
767 NTSTATUS cli_posix_stat(struct cli_state *cli,
768                         const char *fname,
769                         SMB_STRUCT_STAT *sbuf)
770 {
771         TALLOC_CTX *frame = talloc_stackframe();
772         struct tevent_context *ev = NULL;
773         struct tevent_req *req = NULL;
774         NTSTATUS status = NT_STATUS_OK;
775
776         if (smbXcli_conn_has_async_calls(cli->conn)) {
777                 /*
778                  * Can't use sync call while an async call is in flight
779                  */
780                 status = NT_STATUS_INVALID_PARAMETER;
781                 goto fail;
782         }
783
784         ev = samba_tevent_context_init(frame);
785         if (ev == NULL) {
786                 status = NT_STATUS_NO_MEMORY;
787                 goto fail;
788         }
789
790         req = cli_posix_stat_send(frame,
791                                 ev,
792                                 cli,
793                                 fname);
794         if (req == NULL) {
795                 status = NT_STATUS_NO_MEMORY;
796                 goto fail;
797         }
798
799         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
800                 goto fail;
801         }
802
803         status = cli_posix_stat_recv(req, sbuf);
804
805  fail:
806         TALLOC_FREE(frame);
807         return status;
808 }
809
810 /****************************************************************************
811  Chmod or chown a file internal (UNIX extensions).
812 ****************************************************************************/
813
814 struct cli_posix_chown_chmod_internal_state {
815         uint8_t data[100];
816 };
817
818 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
819
820 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
821                                         struct tevent_context *ev,
822                                         struct cli_state *cli,
823                                         const char *fname,
824                                         uint32_t mode,
825                                         uint32_t uid,
826                                         uint32_t gid)
827 {
828         struct tevent_req *req = NULL, *subreq = NULL;
829         struct cli_posix_chown_chmod_internal_state *state = NULL;
830
831         req = tevent_req_create(mem_ctx, &state,
832                                 struct cli_posix_chown_chmod_internal_state);
833         if (req == NULL) {
834                 return NULL;
835         }
836
837         memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
838         memset(&state->data[40], '\0', 60);
839         SIVAL(state->data,40,uid);
840         SIVAL(state->data,48,gid);
841         SIVAL(state->data,84,mode);
842
843         subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
844                                       fname, state->data, sizeof(state->data));
845         if (tevent_req_nomem(subreq, req)) {
846                 return tevent_req_post(req, ev);
847         }
848         tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
849                                 req);
850         return req;
851 }
852
853 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
854 {
855         NTSTATUS status = cli_setpathinfo_recv(subreq);
856         tevent_req_simple_finish_ntstatus(subreq, status);
857 }
858
859 /****************************************************************************
860  chmod a file (UNIX extensions).
861 ****************************************************************************/
862
863 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
864                                         struct tevent_context *ev,
865                                         struct cli_state *cli,
866                                         const char *fname,
867                                         mode_t mode)
868 {
869         return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
870                         fname,
871                         unix_perms_to_wire(mode),
872                         SMB_UID_NO_CHANGE,
873                         SMB_GID_NO_CHANGE);
874 }
875
876 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
877 {
878         return tevent_req_simple_recv_ntstatus(req);
879 }
880
881 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
882 {
883         TALLOC_CTX *frame = talloc_stackframe();
884         struct tevent_context *ev = NULL;
885         struct tevent_req *req = NULL;
886         NTSTATUS status = NT_STATUS_OK;
887
888         if (smbXcli_conn_has_async_calls(cli->conn)) {
889                 /*
890                  * Can't use sync call while an async call is in flight
891                  */
892                 status = NT_STATUS_INVALID_PARAMETER;
893                 goto fail;
894         }
895
896         ev = samba_tevent_context_init(frame);
897         if (ev == NULL) {
898                 status = NT_STATUS_NO_MEMORY;
899                 goto fail;
900         }
901
902         req = cli_posix_chmod_send(frame,
903                                 ev,
904                                 cli,
905                                 fname,
906                                 mode);
907         if (req == NULL) {
908                 status = NT_STATUS_NO_MEMORY;
909                 goto fail;
910         }
911
912         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
913                 goto fail;
914         }
915
916         status = cli_posix_chmod_recv(req);
917
918  fail:
919         TALLOC_FREE(frame);
920         return status;
921 }
922
923 /****************************************************************************
924  chown a file (UNIX extensions).
925 ****************************************************************************/
926
927 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
928                                         struct tevent_context *ev,
929                                         struct cli_state *cli,
930                                         const char *fname,
931                                         uid_t uid,
932                                         gid_t gid)
933 {
934         return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
935                         fname,
936                         SMB_MODE_NO_CHANGE,
937                         (uint32_t)uid,
938                         (uint32_t)gid);
939 }
940
941 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
942 {
943         return tevent_req_simple_recv_ntstatus(req);
944 }
945
946 NTSTATUS cli_posix_chown(struct cli_state *cli,
947                         const char *fname,
948                         uid_t uid,
949                         gid_t gid)
950 {
951         TALLOC_CTX *frame = talloc_stackframe();
952         struct tevent_context *ev = NULL;
953         struct tevent_req *req = NULL;
954         NTSTATUS status = NT_STATUS_OK;
955
956         if (smbXcli_conn_has_async_calls(cli->conn)) {
957                 /*
958                  * Can't use sync call while an async call is in flight
959                  */
960                 status = NT_STATUS_INVALID_PARAMETER;
961                 goto fail;
962         }
963
964         ev = samba_tevent_context_init(frame);
965         if (ev == NULL) {
966                 status = NT_STATUS_NO_MEMORY;
967                 goto fail;
968         }
969
970         req = cli_posix_chown_send(frame,
971                                 ev,
972                                 cli,
973                                 fname,
974                                 uid,
975                                 gid);
976         if (req == NULL) {
977                 status = NT_STATUS_NO_MEMORY;
978                 goto fail;
979         }
980
981         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
982                 goto fail;
983         }
984
985         status = cli_posix_chown_recv(req);
986
987  fail:
988         TALLOC_FREE(frame);
989         return status;
990 }
991
992 /****************************************************************************
993  Rename a file.
994 ****************************************************************************/
995
996 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
997                                                struct tevent_context *ev,
998                                                struct cli_state *cli,
999                                                const char *fname_src,
1000                                                const char *fname_dst,
1001                                                bool replace);
1002
1003 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1004                                                struct tevent_context *ev,
1005                                                struct cli_state *cli,
1006                                                const char *fname_src,
1007                                                const char *fname_dst,
1008                                                bool replace);
1009
1010 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1011                                    struct tevent_context *ev,
1012                                    struct cli_state *cli,
1013                                    const char *fname_src,
1014                                    const char *fname_dst,
1015                                    bool replace)
1016 {
1017         if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
1018                 return cli_smb1_rename_send(mem_ctx, ev, cli, fname_src,
1019                                             fname_dst, replace);
1020         } else {
1021                 return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src,
1022                                             fname_dst, replace);
1023         }
1024 }
1025
1026 struct cli_smb1_rename_state {
1027         uint8_t *data;
1028 };
1029
1030 static void cli_smb1_rename_done(struct tevent_req *subreq);
1031
1032 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1033                                                struct tevent_context *ev,
1034                                                struct cli_state *cli,
1035                                                const char *fname_src,
1036                                                const char *fname_dst,
1037                                                bool replace)
1038 {
1039         NTSTATUS status;
1040         struct tevent_req *req = NULL, *subreq = NULL;
1041         struct cli_smb1_rename_state *state = NULL;
1042         smb_ucs2_t *converted_str = NULL;
1043         size_t converted_size_bytes = 0;
1044
1045         req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
1046         if (req == NULL) {
1047                 return NULL;
1048         }
1049
1050         if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
1051                               &converted_size_bytes)) {
1052                 status = NT_STATUS_INVALID_PARAMETER;
1053                 goto fail;
1054         }
1055
1056         /* W2K8 insists the dest name is not null
1057            terminated. Remove the last 2 zero bytes
1058            and reduce the name length. */
1059
1060         if (converted_size_bytes < 2) {
1061                 status = NT_STATUS_INVALID_PARAMETER;
1062                 goto fail;
1063         }
1064         converted_size_bytes -= 2;
1065
1066         state->data =
1067             talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
1068         if (state->data == NULL) {
1069                 status = NT_STATUS_NO_MEMORY;
1070                 goto fail;
1071         }
1072
1073         if (replace) {
1074                 SCVAL(state->data, 0, 1);
1075         }
1076
1077         SIVAL(state->data, 8, converted_size_bytes);
1078         memcpy(state->data + 12, converted_str, converted_size_bytes);
1079
1080         TALLOC_FREE(converted_str);
1081
1082         subreq = cli_setpathinfo_send(
1083             state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
1084             talloc_get_size(state->data));
1085         if (tevent_req_nomem(subreq, req)) {
1086                 status = NT_STATUS_NO_MEMORY;
1087                 goto fail;
1088         }
1089         tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
1090         return req;
1091
1092 fail:
1093         TALLOC_FREE(converted_str);
1094         tevent_req_nterror(req, status);
1095         return tevent_req_post(req, ev);
1096 }
1097
1098 static void cli_smb1_rename_done(struct tevent_req *subreq)
1099 {
1100         NTSTATUS status = cli_setpathinfo_recv(subreq);
1101         tevent_req_simple_finish_ntstatus(subreq, status);
1102 }
1103
1104 static void cli_cifs_rename_done(struct tevent_req *subreq);
1105
1106 struct cli_cifs_rename_state {
1107         uint16_t vwv[1];
1108 };
1109
1110 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1111                                                struct tevent_context *ev,
1112                                                struct cli_state *cli,
1113                                                const char *fname_src,
1114                                                const char *fname_dst,
1115                                                bool replace)
1116 {
1117         struct tevent_req *req = NULL, *subreq = NULL;
1118         struct cli_cifs_rename_state *state = NULL;
1119         uint8_t additional_flags = 0;
1120         uint16_t additional_flags2 = 0;
1121         uint8_t *bytes = NULL;
1122
1123         req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
1124         if (req == NULL) {
1125                 return NULL;
1126         }
1127
1128         if (replace) {
1129                 /*
1130                  * CIFS doesn't support replace
1131                  */
1132                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1133                 return tevent_req_post(req, ev);
1134         }
1135
1136         SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1137
1138         bytes = talloc_array(state, uint8_t, 1);
1139         if (tevent_req_nomem(bytes, req)) {
1140                 return tevent_req_post(req, ev);
1141         }
1142         bytes[0] = 4;
1143         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1144                                    strlen(fname_src)+1, NULL);
1145         if (tevent_req_nomem(bytes, req)) {
1146                 return tevent_req_post(req, ev);
1147         }
1148
1149         if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1150                 additional_flags2 = FLAGS2_REPARSE_PATH;
1151         }
1152
1153         bytes = talloc_realloc(state, bytes, uint8_t,
1154                         talloc_get_size(bytes)+1);
1155         if (tevent_req_nomem(bytes, req)) {
1156                 return tevent_req_post(req, ev);
1157         }
1158
1159         bytes[talloc_get_size(bytes)-1] = 4;
1160         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1161                                    strlen(fname_dst)+1, NULL);
1162         if (tevent_req_nomem(bytes, req)) {
1163                 return tevent_req_post(req, ev);
1164         }
1165
1166         subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1167                         additional_flags2,
1168                         1, state->vwv, talloc_get_size(bytes), bytes);
1169         if (tevent_req_nomem(subreq, req)) {
1170                 return tevent_req_post(req, ev);
1171         }
1172         tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
1173         return req;
1174 }
1175
1176 static void cli_cifs_rename_done(struct tevent_req *subreq)
1177 {
1178         struct tevent_req *req = tevent_req_callback_data(
1179                                 subreq, struct tevent_req);
1180         NTSTATUS status;
1181
1182         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1183         TALLOC_FREE(subreq);
1184         if (tevent_req_nterror(req, status)) {
1185                 return;
1186         }
1187         tevent_req_done(req);
1188 }
1189
1190 NTSTATUS cli_rename_recv(struct tevent_req *req)
1191 {
1192         return tevent_req_simple_recv_ntstatus(req);
1193 }
1194
1195 NTSTATUS cli_rename(struct cli_state *cli,
1196                     const char *fname_src,
1197                     const char *fname_dst,
1198                     bool replace)
1199 {
1200         TALLOC_CTX *frame = NULL;
1201         struct tevent_context *ev;
1202         struct tevent_req *req;
1203         NTSTATUS status = NT_STATUS_OK;
1204
1205         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1206                 return cli_smb2_rename(cli, fname_src, fname_dst, replace);
1207         }
1208
1209         frame = talloc_stackframe();
1210
1211         if (smbXcli_conn_has_async_calls(cli->conn)) {
1212                 /*
1213                  * Can't use sync call while an async call is in flight
1214                  */
1215                 status = NT_STATUS_INVALID_PARAMETER;
1216                 goto fail;
1217         }
1218
1219         ev = samba_tevent_context_init(frame);
1220         if (ev == NULL) {
1221                 status = NT_STATUS_NO_MEMORY;
1222                 goto fail;
1223         }
1224
1225         req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
1226         if (req == NULL) {
1227                 status = NT_STATUS_NO_MEMORY;
1228                 goto fail;
1229         }
1230
1231         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1232                 goto fail;
1233         }
1234
1235         status = cli_rename_recv(req);
1236
1237  fail:
1238         TALLOC_FREE(frame);
1239         return status;
1240 }
1241
1242 /****************************************************************************
1243  NT Rename a file.
1244 ****************************************************************************/
1245
1246 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1247
1248 struct cli_ntrename_internal_state {
1249         uint16_t vwv[4];
1250 };
1251
1252 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1253                                 struct tevent_context *ev,
1254                                 struct cli_state *cli,
1255                                 const char *fname_src,
1256                                 const char *fname_dst,
1257                                 uint16_t rename_flag)
1258 {
1259         struct tevent_req *req = NULL, *subreq = NULL;
1260         struct cli_ntrename_internal_state *state = NULL;
1261         uint8_t additional_flags = 0;
1262         uint16_t additional_flags2 = 0;
1263         uint8_t *bytes = NULL;
1264
1265         req = tevent_req_create(mem_ctx, &state,
1266                                 struct cli_ntrename_internal_state);
1267         if (req == NULL) {
1268                 return NULL;
1269         }
1270
1271         SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1272         SSVAL(state->vwv+1, 0, rename_flag);
1273
1274         bytes = talloc_array(state, uint8_t, 1);
1275         if (tevent_req_nomem(bytes, req)) {
1276                 return tevent_req_post(req, ev);
1277         }
1278         bytes[0] = 4;
1279         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1280                                    strlen(fname_src)+1, NULL);
1281         if (tevent_req_nomem(bytes, req)) {
1282                 return tevent_req_post(req, ev);
1283         }
1284
1285         if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1286                 additional_flags2 = FLAGS2_REPARSE_PATH;
1287         }
1288
1289         bytes = talloc_realloc(state, bytes, uint8_t,
1290                         talloc_get_size(bytes)+1);
1291         if (tevent_req_nomem(bytes, req)) {
1292                 return tevent_req_post(req, ev);
1293         }
1294
1295         bytes[talloc_get_size(bytes)-1] = 4;
1296         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1297                                    strlen(fname_dst)+1, NULL);
1298         if (tevent_req_nomem(bytes, req)) {
1299                 return tevent_req_post(req, ev);
1300         }
1301
1302         subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1303                         additional_flags2,
1304                         4, state->vwv, talloc_get_size(bytes), bytes);
1305         if (tevent_req_nomem(subreq, req)) {
1306                 return tevent_req_post(req, ev);
1307         }
1308         tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1309         return req;
1310 }
1311
1312 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1313 {
1314         NTSTATUS status = cli_smb_recv(
1315                 subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1316         tevent_req_simple_finish_ntstatus(subreq, status);
1317 }
1318
1319 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1320 {
1321         return tevent_req_simple_recv_ntstatus(req);
1322 }
1323
1324 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1325                                 struct tevent_context *ev,
1326                                 struct cli_state *cli,
1327                                 const char *fname_src,
1328                                 const char *fname_dst)
1329 {
1330         return cli_ntrename_internal_send(mem_ctx,
1331                                           ev,
1332                                           cli,
1333                                           fname_src,
1334                                           fname_dst,
1335                                           RENAME_FLAG_RENAME);
1336 }
1337
1338 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1339 {
1340         return cli_ntrename_internal_recv(req);
1341 }
1342
1343 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1344 {
1345         TALLOC_CTX *frame = talloc_stackframe();
1346         struct tevent_context *ev;
1347         struct tevent_req *req;
1348         NTSTATUS status = NT_STATUS_OK;
1349
1350         if (smbXcli_conn_has_async_calls(cli->conn)) {
1351                 /*
1352                  * Can't use sync call while an async call is in flight
1353                  */
1354                 status = NT_STATUS_INVALID_PARAMETER;
1355                 goto fail;
1356         }
1357
1358         ev = samba_tevent_context_init(frame);
1359         if (ev == NULL) {
1360                 status = NT_STATUS_NO_MEMORY;
1361                 goto fail;
1362         }
1363
1364         req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1365         if (req == NULL) {
1366                 status = NT_STATUS_NO_MEMORY;
1367                 goto fail;
1368         }
1369
1370         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1371                 goto fail;
1372         }
1373
1374         status = cli_ntrename_recv(req);
1375
1376  fail:
1377         TALLOC_FREE(frame);
1378         return status;
1379 }
1380
1381 /****************************************************************************
1382  NT hardlink a file.
1383 ****************************************************************************/
1384
1385 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1386                                 struct tevent_context *ev,
1387                                 struct cli_state *cli,
1388                                 const char *fname_src,
1389                                 const char *fname_dst)
1390 {
1391         return cli_ntrename_internal_send(mem_ctx,
1392                                           ev,
1393                                           cli,
1394                                           fname_src,
1395                                           fname_dst,
1396                                           RENAME_FLAG_HARD_LINK);
1397 }
1398
1399 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1400 {
1401         return cli_ntrename_internal_recv(req);
1402 }
1403
1404 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1405 {
1406         TALLOC_CTX *frame = talloc_stackframe();
1407         struct tevent_context *ev;
1408         struct tevent_req *req;
1409         NTSTATUS status = NT_STATUS_OK;
1410
1411         if (smbXcli_conn_has_async_calls(cli->conn)) {
1412                 /*
1413                  * Can't use sync call while an async call is in flight
1414                  */
1415                 status = NT_STATUS_INVALID_PARAMETER;
1416                 goto fail;
1417         }
1418
1419         ev = samba_tevent_context_init(frame);
1420         if (ev == NULL) {
1421                 status = NT_STATUS_NO_MEMORY;
1422                 goto fail;
1423         }
1424
1425         req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1426         if (req == NULL) {
1427                 status = NT_STATUS_NO_MEMORY;
1428                 goto fail;
1429         }
1430
1431         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1432                 goto fail;
1433         }
1434
1435         status = cli_nt_hardlink_recv(req);
1436
1437  fail:
1438         TALLOC_FREE(frame);
1439         return status;
1440 }
1441
1442 /****************************************************************************
1443  Delete a file.
1444 ****************************************************************************/
1445
1446 static void cli_unlink_done(struct tevent_req *subreq);
1447
1448 struct cli_unlink_state {
1449         uint16_t vwv[1];
1450 };
1451
1452 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1453                                 struct tevent_context *ev,
1454                                 struct cli_state *cli,
1455                                 const char *fname,
1456                                 uint16_t mayhave_attrs)
1457 {
1458         struct tevent_req *req = NULL, *subreq = NULL;
1459         struct cli_unlink_state *state = NULL;
1460         uint8_t additional_flags = 0;
1461         uint16_t additional_flags2 = 0;
1462         uint8_t *bytes = NULL;
1463
1464         req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1465         if (req == NULL) {
1466                 return NULL;
1467         }
1468
1469         SSVAL(state->vwv+0, 0, mayhave_attrs);
1470
1471         bytes = talloc_array(state, uint8_t, 1);
1472         if (tevent_req_nomem(bytes, req)) {
1473                 return tevent_req_post(req, ev);
1474         }
1475         bytes[0] = 4;
1476         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
1477                                    strlen(fname)+1, NULL);
1478
1479         if (tevent_req_nomem(bytes, req)) {
1480                 return tevent_req_post(req, ev);
1481         }
1482
1483         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1484                 additional_flags2 = FLAGS2_REPARSE_PATH;
1485         }
1486
1487         subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1488                                 additional_flags2,
1489                                 1, state->vwv, talloc_get_size(bytes), bytes);
1490         if (tevent_req_nomem(subreq, req)) {
1491                 return tevent_req_post(req, ev);
1492         }
1493         tevent_req_set_callback(subreq, cli_unlink_done, req);
1494         return req;
1495 }
1496
1497 static void cli_unlink_done(struct tevent_req *subreq)
1498 {
1499         struct tevent_req *req = tevent_req_callback_data(
1500                 subreq, struct tevent_req);
1501         NTSTATUS status;
1502
1503         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1504         TALLOC_FREE(subreq);
1505         if (tevent_req_nterror(req, status)) {
1506                 return;
1507         }
1508         tevent_req_done(req);
1509 }
1510
1511 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1512 {
1513         return tevent_req_simple_recv_ntstatus(req);
1514 }
1515
1516 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1517 {
1518         TALLOC_CTX *frame = NULL;
1519         struct tevent_context *ev;
1520         struct tevent_req *req;
1521         NTSTATUS status = NT_STATUS_OK;
1522
1523         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1524                 return cli_smb2_unlink(cli, fname, NULL);
1525         }
1526
1527         frame = talloc_stackframe();
1528
1529         if (smbXcli_conn_has_async_calls(cli->conn)) {
1530                 /*
1531                  * Can't use sync call while an async call is in flight
1532                  */
1533                 status = NT_STATUS_INVALID_PARAMETER;
1534                 goto fail;
1535         }
1536
1537         ev = samba_tevent_context_init(frame);
1538         if (ev == NULL) {
1539                 status = NT_STATUS_NO_MEMORY;
1540                 goto fail;
1541         }
1542
1543         req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1544         if (req == NULL) {
1545                 status = NT_STATUS_NO_MEMORY;
1546                 goto fail;
1547         }
1548
1549         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1550                 goto fail;
1551         }
1552
1553         status = cli_unlink_recv(req);
1554
1555  fail:
1556         TALLOC_FREE(frame);
1557         return status;
1558 }
1559
1560 /****************************************************************************
1561  Create a directory.
1562 ****************************************************************************/
1563
1564 static void cli_mkdir_done(struct tevent_req *subreq);
1565
1566 struct cli_mkdir_state {
1567         int dummy;
1568 };
1569
1570 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1571                                   struct tevent_context *ev,
1572                                   struct cli_state *cli,
1573                                   const char *dname)
1574 {
1575         struct tevent_req *req = NULL, *subreq = NULL;
1576         struct cli_mkdir_state *state = NULL;
1577         uint8_t additional_flags = 0;
1578         uint16_t additional_flags2 = 0;
1579         uint8_t *bytes = NULL;
1580
1581         req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1582         if (req == NULL) {
1583                 return NULL;
1584         }
1585
1586         bytes = talloc_array(state, uint8_t, 1);
1587         if (tevent_req_nomem(bytes, req)) {
1588                 return tevent_req_post(req, ev);
1589         }
1590         bytes[0] = 4;
1591         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1592                                    strlen(dname)+1, NULL);
1593
1594         if (tevent_req_nomem(bytes, req)) {
1595                 return tevent_req_post(req, ev);
1596         }
1597
1598         if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1599                 additional_flags2 = FLAGS2_REPARSE_PATH;
1600         }
1601
1602         subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1603                         additional_flags2,
1604                         0, NULL, talloc_get_size(bytes), bytes);
1605         if (tevent_req_nomem(subreq, req)) {
1606                 return tevent_req_post(req, ev);
1607         }
1608         tevent_req_set_callback(subreq, cli_mkdir_done, req);
1609         return req;
1610 }
1611
1612 static void cli_mkdir_done(struct tevent_req *subreq)
1613 {
1614         struct tevent_req *req = tevent_req_callback_data(
1615                 subreq, struct tevent_req);
1616         NTSTATUS status;
1617
1618         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1619         TALLOC_FREE(subreq);
1620         if (tevent_req_nterror(req, status)) {
1621                 return;
1622         }
1623         tevent_req_done(req);
1624 }
1625
1626 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1627 {
1628         return tevent_req_simple_recv_ntstatus(req);
1629 }
1630
1631 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1632 {
1633         TALLOC_CTX *frame = NULL;
1634         struct tevent_context *ev;
1635         struct tevent_req *req;
1636         NTSTATUS status = NT_STATUS_OK;
1637
1638         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1639                 return cli_smb2_mkdir(cli, dname);
1640         }
1641
1642         frame = talloc_stackframe();
1643
1644         if (smbXcli_conn_has_async_calls(cli->conn)) {
1645                 /*
1646                  * Can't use sync call while an async call is in flight
1647                  */
1648                 status = NT_STATUS_INVALID_PARAMETER;
1649                 goto fail;
1650         }
1651
1652         ev = samba_tevent_context_init(frame);
1653         if (ev == NULL) {
1654                 status = NT_STATUS_NO_MEMORY;
1655                 goto fail;
1656         }
1657
1658         req = cli_mkdir_send(frame, ev, cli, dname);
1659         if (req == NULL) {
1660                 status = NT_STATUS_NO_MEMORY;
1661                 goto fail;
1662         }
1663
1664         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1665                 goto fail;
1666         }
1667
1668         status = cli_mkdir_recv(req);
1669
1670  fail:
1671         TALLOC_FREE(frame);
1672         return status;
1673 }
1674
1675 /****************************************************************************
1676  Remove a directory.
1677 ****************************************************************************/
1678
1679 static void cli_rmdir_done(struct tevent_req *subreq);
1680
1681 struct cli_rmdir_state {
1682         int dummy;
1683 };
1684
1685 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1686                                   struct tevent_context *ev,
1687                                   struct cli_state *cli,
1688                                   const char *dname)
1689 {
1690         struct tevent_req *req = NULL, *subreq = NULL;
1691         struct cli_rmdir_state *state = NULL;
1692         uint8_t additional_flags = 0;
1693         uint16_t additional_flags2 = 0;
1694         uint8_t *bytes = NULL;
1695
1696         req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1697         if (req == NULL) {
1698                 return NULL;
1699         }
1700
1701         bytes = talloc_array(state, uint8_t, 1);
1702         if (tevent_req_nomem(bytes, req)) {
1703                 return tevent_req_post(req, ev);
1704         }
1705         bytes[0] = 4;
1706         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1707                                    strlen(dname)+1, NULL);
1708
1709         if (tevent_req_nomem(bytes, req)) {
1710                 return tevent_req_post(req, ev);
1711         }
1712
1713         if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1714                 additional_flags2 = FLAGS2_REPARSE_PATH;
1715         }
1716
1717         subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1718                         additional_flags2,
1719                         0, NULL, talloc_get_size(bytes), bytes);
1720         if (tevent_req_nomem(subreq, req)) {
1721                 return tevent_req_post(req, ev);
1722         }
1723         tevent_req_set_callback(subreq, cli_rmdir_done, req);
1724         return req;
1725 }
1726
1727 static void cli_rmdir_done(struct tevent_req *subreq)
1728 {
1729         struct tevent_req *req = tevent_req_callback_data(
1730                 subreq, struct tevent_req);
1731         NTSTATUS status;
1732
1733         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1734         TALLOC_FREE(subreq);
1735         if (tevent_req_nterror(req, status)) {
1736                 return;
1737         }
1738         tevent_req_done(req);
1739 }
1740
1741 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1742 {
1743         return tevent_req_simple_recv_ntstatus(req);
1744 }
1745
1746 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1747 {
1748         TALLOC_CTX *frame = NULL;
1749         struct tevent_context *ev;
1750         struct tevent_req *req;
1751         NTSTATUS status = NT_STATUS_OK;
1752
1753         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1754                 return cli_smb2_rmdir(cli, dname, NULL);
1755         }
1756
1757         frame = talloc_stackframe();
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_rmdir_send(frame, ev, cli, dname);
1774         if (req == NULL) {
1775                 status = NT_STATUS_NO_MEMORY;
1776                 goto fail;
1777         }
1778
1779         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1780                 goto fail;
1781         }
1782
1783         status = cli_rmdir_recv(req);
1784
1785  fail:
1786         TALLOC_FREE(frame);
1787         return status;
1788 }
1789
1790 /****************************************************************************
1791  Set or clear the delete on close flag.
1792 ****************************************************************************/
1793
1794 struct doc_state {
1795         uint16_t setup;
1796         uint8_t param[6];
1797         uint8_t data[1];
1798 };
1799
1800 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
1801 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
1802
1803 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1804                                         struct tevent_context *ev,
1805                                         struct cli_state *cli,
1806                                         uint16_t fnum,
1807                                         bool flag)
1808 {
1809         struct tevent_req *req = NULL, *subreq = NULL;
1810         struct doc_state *state = NULL;
1811
1812         req = tevent_req_create(mem_ctx, &state, struct doc_state);
1813         if (req == NULL) {
1814                 return NULL;
1815         }
1816
1817         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1818                 subreq = cli_smb2_delete_on_close_send(state, ev, cli,
1819                                                        fnum, flag);
1820                 if (tevent_req_nomem(subreq, req)) {
1821                         return tevent_req_post(req, ev);
1822                 }
1823                 tevent_req_set_callback(subreq,
1824                                         cli_nt_delete_on_close_smb2_done,
1825                                         req);
1826                 return req;
1827         }
1828
1829         /* Setup setup word. */
1830         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1831
1832         /* Setup param array. */
1833         SSVAL(state->param,0,fnum);
1834         SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1835
1836         /* Setup data array. */
1837         SCVAL(&state->data[0], 0, flag ? 1 : 0);
1838
1839         subreq = cli_trans_send(state,                  /* mem ctx. */
1840                                 ev,                     /* event ctx. */
1841                                 cli,                    /* cli_state. */
1842                                 0,                      /* additional_flags2 */
1843                                 SMBtrans2,              /* cmd. */
1844                                 NULL,                   /* pipe name. */
1845                                 -1,                     /* fid. */
1846                                 0,                      /* function. */
1847                                 0,                      /* flags. */
1848                                 &state->setup,          /* setup. */
1849                                 1,                      /* num setup uint16_t words. */
1850                                 0,                      /* max returned setup. */
1851                                 state->param,           /* param. */
1852                                 6,                      /* num param. */
1853                                 2,                      /* max returned param. */
1854                                 state->data,            /* data. */
1855                                 1,                      /* num data. */
1856                                 0);                     /* max returned data. */
1857
1858         if (tevent_req_nomem(subreq, req)) {
1859                 return tevent_req_post(req, ev);
1860         }
1861         tevent_req_set_callback(subreq,
1862                                 cli_nt_delete_on_close_smb1_done,
1863                                 req);
1864         return req;
1865 }
1866
1867 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
1868 {
1869         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
1870                                          NULL, 0, NULL, NULL, 0, NULL);
1871         tevent_req_simple_finish_ntstatus(subreq, status);
1872 }
1873
1874 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
1875 {
1876         NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
1877         tevent_req_simple_finish_ntstatus(subreq, status);
1878 }
1879
1880 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1881 {
1882         return tevent_req_simple_recv_ntstatus(req);
1883 }
1884
1885 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1886 {
1887         TALLOC_CTX *frame = talloc_stackframe();
1888         struct tevent_context *ev = NULL;
1889         struct tevent_req *req = NULL;
1890         NTSTATUS status = NT_STATUS_OK;
1891
1892         if (smbXcli_conn_has_async_calls(cli->conn)) {
1893                 /*
1894                  * Can't use sync call while an async call is in flight
1895                  */
1896                 status = NT_STATUS_INVALID_PARAMETER;
1897                 goto fail;
1898         }
1899
1900         ev = samba_tevent_context_init(frame);
1901         if (ev == NULL) {
1902                 status = NT_STATUS_NO_MEMORY;
1903                 goto fail;
1904         }
1905
1906         req = cli_nt_delete_on_close_send(frame,
1907                                 ev,
1908                                 cli,
1909                                 fnum,
1910                                 flag);
1911         if (req == NULL) {
1912                 status = NT_STATUS_NO_MEMORY;
1913                 goto fail;
1914         }
1915
1916         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1917                 goto fail;
1918         }
1919
1920         status = cli_nt_delete_on_close_recv(req);
1921
1922  fail:
1923         TALLOC_FREE(frame);
1924         return status;
1925 }
1926
1927 struct cli_ntcreate1_state {
1928         uint16_t vwv[24];
1929         uint16_t fnum;
1930         struct smb_create_returns cr;
1931         struct tevent_req *subreq;
1932 };
1933
1934 static void cli_ntcreate1_done(struct tevent_req *subreq);
1935 static bool cli_ntcreate1_cancel(struct tevent_req *req);
1936
1937 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
1938                                              struct tevent_context *ev,
1939                                              struct cli_state *cli,
1940                                              const char *fname,
1941                                              uint32_t CreatFlags,
1942                                              uint32_t DesiredAccess,
1943                                              uint32_t FileAttributes,
1944                                              uint32_t ShareAccess,
1945                                              uint32_t CreateDisposition,
1946                                              uint32_t CreateOptions,
1947                                              uint32_t ImpersonationLevel,
1948                                              uint8_t SecurityFlags)
1949 {
1950         struct tevent_req *req, *subreq;
1951         struct cli_ntcreate1_state *state;
1952         uint16_t *vwv;
1953         uint8_t *bytes;
1954         size_t converted_len;
1955         uint16_t additional_flags2 = 0;
1956
1957         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
1958         if (req == NULL) {
1959                 return NULL;
1960         }
1961
1962         vwv = state->vwv;
1963
1964         SCVAL(vwv+0, 0, 0xFF);
1965         SCVAL(vwv+0, 1, 0);
1966         SSVAL(vwv+1, 0, 0);
1967         SCVAL(vwv+2, 0, 0);
1968
1969         if (cli->use_oplocks) {
1970                 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1971         }
1972         SIVAL(vwv+3, 1, CreatFlags);
1973         SIVAL(vwv+5, 1, 0x0);   /* RootDirectoryFid */
1974         SIVAL(vwv+7, 1, DesiredAccess);
1975         SIVAL(vwv+9, 1, 0x0);   /* AllocationSize */
1976         SIVAL(vwv+11, 1, 0x0);  /* AllocationSize */
1977         SIVAL(vwv+13, 1, FileAttributes);
1978         SIVAL(vwv+15, 1, ShareAccess);
1979         SIVAL(vwv+17, 1, CreateDisposition);
1980         SIVAL(vwv+19, 1, CreateOptions |
1981                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
1982         SIVAL(vwv+21, 1, ImpersonationLevel);
1983         SCVAL(vwv+23, 1, SecurityFlags);
1984
1985         bytes = talloc_array(state, uint8_t, 0);
1986         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
1987                                    fname, strlen(fname)+1,
1988                                    &converted_len);
1989
1990         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1991                 additional_flags2 = FLAGS2_REPARSE_PATH;
1992         }
1993
1994         /* sigh. this copes with broken netapp filer behaviour */
1995         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
1996
1997         if (tevent_req_nomem(bytes, req)) {
1998                 return tevent_req_post(req, ev);
1999         }
2000
2001         SSVAL(vwv+2, 1, converted_len);
2002
2003         subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2004                         additional_flags2, 24, vwv,
2005                         talloc_get_size(bytes), bytes);
2006         if (tevent_req_nomem(subreq, req)) {
2007                 return tevent_req_post(req, ev);
2008         }
2009         tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2010
2011         state->subreq = subreq;
2012         tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2013
2014         return req;
2015 }
2016
2017 static void cli_ntcreate1_done(struct tevent_req *subreq)
2018 {
2019         struct tevent_req *req = tevent_req_callback_data(
2020                 subreq, struct tevent_req);
2021         struct cli_ntcreate1_state *state = tevent_req_data(
2022                 req, struct cli_ntcreate1_state);
2023         uint8_t wct;
2024         uint16_t *vwv;
2025         uint32_t num_bytes;
2026         uint8_t *bytes;
2027         NTSTATUS status;
2028
2029         status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2030                               &num_bytes, &bytes);
2031         TALLOC_FREE(subreq);
2032         if (tevent_req_nterror(req, status)) {
2033                 return;
2034         }
2035         state->cr.oplock_level = CVAL(vwv+2, 0);
2036         state->fnum = SVAL(vwv+2, 1);
2037         state->cr.create_action = IVAL(vwv+3, 1);
2038         state->cr.creation_time = BVAL(vwv+5, 1);
2039         state->cr.last_access_time = BVAL(vwv+9, 1);
2040         state->cr.last_write_time = BVAL(vwv+13, 1);
2041         state->cr.change_time   = BVAL(vwv+17, 1);
2042         state->cr.file_attributes = IVAL(vwv+21, 1);
2043         state->cr.allocation_size = BVAL(vwv+23, 1);
2044         state->cr.end_of_file   = BVAL(vwv+27, 1);
2045
2046         tevent_req_done(req);
2047 }
2048
2049 static bool cli_ntcreate1_cancel(struct tevent_req *req)
2050 {
2051         struct cli_ntcreate1_state *state = tevent_req_data(
2052                 req, struct cli_ntcreate1_state);
2053         return tevent_req_cancel(state->subreq);
2054 }
2055
2056 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2057                                    uint16_t *pfnum,
2058                                    struct smb_create_returns *cr)
2059 {
2060         struct cli_ntcreate1_state *state = tevent_req_data(
2061                 req, struct cli_ntcreate1_state);
2062         NTSTATUS status;
2063
2064         if (tevent_req_is_nterror(req, &status)) {
2065                 return status;
2066         }
2067         *pfnum = state->fnum;
2068         if (cr != NULL) {
2069                 *cr = state->cr;
2070         }
2071         return NT_STATUS_OK;
2072 }
2073
2074 struct cli_ntcreate_state {
2075         struct smb_create_returns cr;
2076         uint16_t fnum;
2077         struct tevent_req *subreq;
2078 };
2079
2080 static void cli_ntcreate_done_nt1(struct tevent_req *subreq);
2081 static void cli_ntcreate_done_smb2(struct tevent_req *subreq);
2082 static bool cli_ntcreate_cancel(struct tevent_req *req);
2083
2084 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
2085                                      struct tevent_context *ev,
2086                                      struct cli_state *cli,
2087                                      const char *fname,
2088                                      uint32_t create_flags,
2089                                      uint32_t desired_access,
2090                                      uint32_t file_attributes,
2091                                      uint32_t share_access,
2092                                      uint32_t create_disposition,
2093                                      uint32_t create_options,
2094                                      uint32_t impersonation_level,
2095                                      uint8_t security_flags)
2096 {
2097         struct tevent_req *req, *subreq;
2098         struct cli_ntcreate_state *state;
2099
2100         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2101         if (req == NULL) {
2102                 return NULL;
2103         }
2104
2105         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2106                 if (cli->use_oplocks) {
2107                         create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2108                 }
2109
2110                 subreq = cli_smb2_create_fnum_send(
2111                         state,
2112                         ev,
2113                         cli,
2114                         fname,
2115                         create_flags,
2116                         impersonation_level,
2117                         desired_access,
2118                         file_attributes,
2119                         share_access,
2120                         create_disposition,
2121                         create_options,
2122                         NULL);
2123                 if (tevent_req_nomem(subreq, req)) {
2124                         return tevent_req_post(req, ev);
2125                 }
2126                 tevent_req_set_callback(subreq, cli_ntcreate_done_smb2, req);
2127         } else {
2128                 subreq = cli_ntcreate1_send(
2129                         state, ev, cli, fname, create_flags, desired_access,
2130                         file_attributes, share_access, create_disposition,
2131                         create_options, impersonation_level, security_flags);
2132                 if (tevent_req_nomem(subreq, req)) {
2133                         return tevent_req_post(req, ev);
2134                 }
2135                 tevent_req_set_callback(subreq, cli_ntcreate_done_nt1, req);
2136         }
2137
2138         state->subreq = subreq;
2139         tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2140
2141         return req;
2142 }
2143
2144 static void cli_ntcreate_done_nt1(struct tevent_req *subreq)
2145 {
2146         struct tevent_req *req = tevent_req_callback_data(
2147                 subreq, struct tevent_req);
2148         struct cli_ntcreate_state *state = tevent_req_data(
2149                 req, struct cli_ntcreate_state);
2150         NTSTATUS status;
2151
2152         status = cli_ntcreate1_recv(subreq, &state->fnum, &state->cr);
2153         TALLOC_FREE(subreq);
2154         if (tevent_req_nterror(req, status)) {
2155                 return;
2156         }
2157         tevent_req_done(req);
2158 }
2159
2160 static void cli_ntcreate_done_smb2(struct tevent_req *subreq)
2161 {
2162         struct tevent_req *req = tevent_req_callback_data(
2163                 subreq, struct tevent_req);
2164         struct cli_ntcreate_state *state = tevent_req_data(
2165                 req, struct cli_ntcreate_state);
2166         NTSTATUS status;
2167
2168         status = cli_smb2_create_fnum_recv(
2169                 subreq,
2170                 &state->fnum,
2171                 &state->cr,
2172                 NULL,
2173                 NULL);
2174         TALLOC_FREE(subreq);
2175         if (tevent_req_nterror(req, status)) {
2176                 return;
2177         }
2178         tevent_req_done(req);
2179 }
2180
2181 static bool cli_ntcreate_cancel(struct tevent_req *req)
2182 {
2183         struct cli_ntcreate_state *state = tevent_req_data(
2184                 req, struct cli_ntcreate_state);
2185         return tevent_req_cancel(state->subreq);
2186 }
2187
2188 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2189                            struct smb_create_returns *cr)
2190 {
2191         struct cli_ntcreate_state *state = tevent_req_data(
2192                 req, struct cli_ntcreate_state);
2193         NTSTATUS status;
2194
2195         if (tevent_req_is_nterror(req, &status)) {
2196                 return status;
2197         }
2198         if (fnum != NULL) {
2199                 *fnum = state->fnum;
2200         }
2201         if (cr != NULL) {
2202                 *cr = state->cr;
2203         }
2204         return NT_STATUS_OK;
2205 }
2206
2207 NTSTATUS cli_ntcreate(struct cli_state *cli,
2208                       const char *fname,
2209                       uint32_t CreatFlags,
2210                       uint32_t DesiredAccess,
2211                       uint32_t FileAttributes,
2212                       uint32_t ShareAccess,
2213                       uint32_t CreateDisposition,
2214                       uint32_t CreateOptions,
2215                       uint8_t SecurityFlags,
2216                       uint16_t *pfid,
2217                       struct smb_create_returns *cr)
2218 {
2219         TALLOC_CTX *frame = talloc_stackframe();
2220         struct tevent_context *ev;
2221         struct tevent_req *req;
2222         uint32_t ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
2223         NTSTATUS status = NT_STATUS_NO_MEMORY;
2224
2225         if (smbXcli_conn_has_async_calls(cli->conn)) {
2226                 /*
2227                  * Can't use sync call while an async call is in flight
2228                  */
2229                 status = NT_STATUS_INVALID_PARAMETER;
2230                 goto fail;
2231         }
2232
2233         ev = samba_tevent_context_init(frame);
2234         if (ev == NULL) {
2235                 goto fail;
2236         }
2237
2238         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2239                                 DesiredAccess, FileAttributes, ShareAccess,
2240                                 CreateDisposition, CreateOptions,
2241                                 ImpersonationLevel, SecurityFlags);
2242         if (req == NULL) {
2243                 goto fail;
2244         }
2245
2246         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2247                 goto fail;
2248         }
2249
2250         status = cli_ntcreate_recv(req, pfid, cr);
2251  fail:
2252         TALLOC_FREE(frame);
2253         return status;
2254 }
2255
2256 struct cli_nttrans_create_state {
2257         uint16_t fnum;
2258         struct smb_create_returns cr;
2259 };
2260
2261 static void cli_nttrans_create_done(struct tevent_req *subreq);
2262
2263 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2264                                            struct tevent_context *ev,
2265                                            struct cli_state *cli,
2266                                            const char *fname,
2267                                            uint32_t CreatFlags,
2268                                            uint32_t DesiredAccess,
2269                                            uint32_t FileAttributes,
2270                                            uint32_t ShareAccess,
2271                                            uint32_t CreateDisposition,
2272                                            uint32_t CreateOptions,
2273                                            uint8_t SecurityFlags,
2274                                            struct security_descriptor *secdesc,
2275                                            struct ea_struct *eas,
2276                                            int num_eas)
2277 {
2278         struct tevent_req *req, *subreq;
2279         struct cli_nttrans_create_state *state;
2280         uint8_t *param;
2281         uint8_t *secdesc_buf;
2282         size_t secdesc_len;
2283         NTSTATUS status;
2284         size_t converted_len;
2285         uint16_t additional_flags2 = 0;
2286
2287         req = tevent_req_create(mem_ctx,
2288                                 &state, struct cli_nttrans_create_state);
2289         if (req == NULL) {
2290                 return NULL;
2291         }
2292
2293         if (secdesc != NULL) {
2294                 status = marshall_sec_desc(talloc_tos(), secdesc,
2295                                            &secdesc_buf, &secdesc_len);
2296                 if (tevent_req_nterror(req, status)) {
2297                         DEBUG(10, ("marshall_sec_desc failed: %s\n",
2298                                    nt_errstr(status)));
2299                         return tevent_req_post(req, ev);
2300                 }
2301         } else {
2302                 secdesc_buf = NULL;
2303                 secdesc_len = 0;
2304         }
2305
2306         if (num_eas != 0) {
2307                 /*
2308                  * TODO ;-)
2309                  */
2310                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2311                 return tevent_req_post(req, ev);
2312         }
2313
2314         param = talloc_array(state, uint8_t, 53);
2315         if (tevent_req_nomem(param, req)) {
2316                 return tevent_req_post(req, ev);
2317         }
2318
2319         param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2320                                       fname, strlen(fname),
2321                                       &converted_len);
2322         if (tevent_req_nomem(param, req)) {
2323                 return tevent_req_post(req, ev);
2324         }
2325
2326         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2327                 additional_flags2 = FLAGS2_REPARSE_PATH;
2328         }
2329
2330         SIVAL(param, 0, CreatFlags);
2331         SIVAL(param, 4, 0x0);   /* RootDirectoryFid */
2332         SIVAL(param, 8, DesiredAccess);
2333         SIVAL(param, 12, 0x0);  /* AllocationSize */
2334         SIVAL(param, 16, 0x0);  /* AllocationSize */
2335         SIVAL(param, 20, FileAttributes);
2336         SIVAL(param, 24, ShareAccess);
2337         SIVAL(param, 28, CreateDisposition);
2338         SIVAL(param, 32, CreateOptions |
2339                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2340         SIVAL(param, 36, secdesc_len);
2341         SIVAL(param, 40, 0);     /* EA length*/
2342         SIVAL(param, 44, converted_len);
2343         SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2344         SCVAL(param, 52, SecurityFlags);
2345
2346         subreq = cli_trans_send(state, ev, cli,
2347                                 additional_flags2, /* additional_flags2 */
2348                                 SMBnttrans,
2349                                 NULL, -1, /* name, fid */
2350                                 NT_TRANSACT_CREATE, 0,
2351                                 NULL, 0, 0, /* setup */
2352                                 param, talloc_get_size(param), 128, /* param */
2353                                 secdesc_buf, secdesc_len, 0); /* data */
2354         if (tevent_req_nomem(subreq, req)) {
2355                 return tevent_req_post(req, ev);
2356         }
2357         tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2358         return req;
2359 }
2360
2361 static void cli_nttrans_create_done(struct tevent_req *subreq)
2362 {
2363         struct tevent_req *req = tevent_req_callback_data(
2364                 subreq, struct tevent_req);
2365         struct cli_nttrans_create_state *state = tevent_req_data(
2366                 req, struct cli_nttrans_create_state);
2367         uint8_t *param;
2368         uint32_t num_param;
2369         NTSTATUS status;
2370
2371         status = cli_trans_recv(subreq, talloc_tos(), NULL,
2372                                 NULL, 0, NULL, /* rsetup */
2373                                 &param, 69, &num_param,
2374                                 NULL, 0, NULL);
2375         if (tevent_req_nterror(req, status)) {
2376                 return;
2377         }
2378         state->cr.oplock_level = CVAL(param, 0);
2379         state->fnum = SVAL(param, 2);
2380         state->cr.create_action = IVAL(param, 4);
2381         state->cr.creation_time = BVAL(param, 12);
2382         state->cr.last_access_time = BVAL(param, 20);
2383         state->cr.last_write_time = BVAL(param, 28);
2384         state->cr.change_time   = BVAL(param, 36);
2385         state->cr.file_attributes = IVAL(param, 44);
2386         state->cr.allocation_size = BVAL(param, 48);
2387         state->cr.end_of_file   = BVAL(param, 56);
2388
2389         TALLOC_FREE(param);
2390         tevent_req_done(req);
2391 }
2392
2393 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2394                         uint16_t *fnum,
2395                         struct smb_create_returns *cr)
2396 {
2397         struct cli_nttrans_create_state *state = tevent_req_data(
2398                 req, struct cli_nttrans_create_state);
2399         NTSTATUS status;
2400
2401         if (tevent_req_is_nterror(req, &status)) {
2402                 return status;
2403         }
2404         *fnum = state->fnum;
2405         if (cr != NULL) {
2406                 *cr = state->cr;
2407         }
2408         return NT_STATUS_OK;
2409 }
2410
2411 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2412                             const char *fname,
2413                             uint32_t CreatFlags,
2414                             uint32_t DesiredAccess,
2415                             uint32_t FileAttributes,
2416                             uint32_t ShareAccess,
2417                             uint32_t CreateDisposition,
2418                             uint32_t CreateOptions,
2419                             uint8_t SecurityFlags,
2420                             struct security_descriptor *secdesc,
2421                             struct ea_struct *eas,
2422                             int num_eas,
2423                             uint16_t *pfid,
2424                             struct smb_create_returns *cr)
2425 {
2426         TALLOC_CTX *frame = talloc_stackframe();
2427         struct tevent_context *ev;
2428         struct tevent_req *req;
2429         NTSTATUS status = NT_STATUS_NO_MEMORY;
2430
2431         if (smbXcli_conn_has_async_calls(cli->conn)) {
2432                 /*
2433                  * Can't use sync call while an async call is in flight
2434                  */
2435                 status = NT_STATUS_INVALID_PARAMETER;
2436                 goto fail;
2437         }
2438         ev = samba_tevent_context_init(frame);
2439         if (ev == NULL) {
2440                 goto fail;
2441         }
2442         req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2443                                       DesiredAccess, FileAttributes,
2444                                       ShareAccess, CreateDisposition,
2445                                       CreateOptions, SecurityFlags,
2446                                       secdesc, eas, num_eas);
2447         if (req == NULL) {
2448                 goto fail;
2449         }
2450         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2451                 goto fail;
2452         }
2453         status = cli_nttrans_create_recv(req, pfid, cr);
2454  fail:
2455         TALLOC_FREE(frame);
2456         return status;
2457 }
2458
2459 /****************************************************************************
2460  Open a file
2461  WARNING: if you open with O_WRONLY then getattrE won't work!
2462 ****************************************************************************/
2463
2464 struct cli_openx_state {
2465         const char *fname;
2466         uint16_t vwv[15];
2467         uint16_t fnum;
2468         struct iovec bytes;
2469 };
2470
2471 static void cli_openx_done(struct tevent_req *subreq);
2472
2473 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2474                                    struct tevent_context *ev,
2475                                    struct cli_state *cli, const char *fname,
2476                                    int flags, int share_mode,
2477                                    struct tevent_req **psmbreq)
2478 {
2479         struct tevent_req *req, *subreq;
2480         struct cli_openx_state *state;
2481         unsigned openfn;
2482         unsigned accessmode;
2483         uint8_t additional_flags;
2484         uint16_t additional_flags2 = 0;
2485         uint8_t *bytes;
2486
2487         req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2488         if (req == NULL) {
2489                 return NULL;
2490         }
2491
2492         openfn = 0;
2493         if (flags & O_CREAT) {
2494                 openfn |= (1<<4);
2495         }
2496         if (!(flags & O_EXCL)) {
2497                 if (flags & O_TRUNC)
2498                         openfn |= (1<<1);
2499                 else
2500                         openfn |= (1<<0);
2501         }
2502
2503         accessmode = (share_mode<<4);
2504
2505         if ((flags & O_ACCMODE) == O_RDWR) {
2506                 accessmode |= 2;
2507         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2508                 accessmode |= 1;
2509         }
2510
2511 #if defined(O_SYNC)
2512         if ((flags & O_SYNC) == O_SYNC) {
2513                 accessmode |= (1<<14);
2514         }
2515 #endif /* O_SYNC */
2516
2517         if (share_mode == DENY_FCB) {
2518                 accessmode = 0xFF;
2519         }
2520
2521         SCVAL(state->vwv + 0, 0, 0xFF);
2522         SCVAL(state->vwv + 0, 1, 0);
2523         SSVAL(state->vwv + 1, 0, 0);
2524         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
2525         SSVAL(state->vwv + 3, 0, accessmode);
2526         SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2527         SSVAL(state->vwv + 5, 0, 0);
2528         SIVAL(state->vwv + 6, 0, 0);
2529         SSVAL(state->vwv + 8, 0, openfn);
2530         SIVAL(state->vwv + 9, 0, 0);
2531         SIVAL(state->vwv + 11, 0, 0);
2532         SIVAL(state->vwv + 13, 0, 0);
2533
2534         additional_flags = 0;
2535
2536         if (cli->use_oplocks) {
2537                 /* if using oplocks then ask for a batch oplock via
2538                    core and extended methods */
2539                 additional_flags =
2540                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2541                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2542         }
2543
2544         bytes = talloc_array(state, uint8_t, 0);
2545         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2546                                    strlen(fname)+1, NULL);
2547
2548         if (tevent_req_nomem(bytes, req)) {
2549                 return tevent_req_post(req, ev);
2550         }
2551
2552         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2553                 additional_flags2 = FLAGS2_REPARSE_PATH;
2554         }
2555
2556         state->bytes.iov_base = (void *)bytes;
2557         state->bytes.iov_len = talloc_get_size(bytes);
2558
2559         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2560                         additional_flags2, 15, state->vwv, 1, &state->bytes);
2561         if (subreq == NULL) {
2562                 TALLOC_FREE(req);
2563                 return NULL;
2564         }
2565         tevent_req_set_callback(subreq, cli_openx_done, req);
2566         *psmbreq = subreq;
2567         return req;
2568 }
2569
2570 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2571                                  struct cli_state *cli, const char *fname,
2572                                  int flags, int share_mode)
2573 {
2574         struct tevent_req *req, *subreq;
2575         NTSTATUS status;
2576
2577         req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
2578                               &subreq);
2579         if (req == NULL) {
2580                 return NULL;
2581         }
2582
2583         status = smb1cli_req_chain_submit(&subreq, 1);
2584         if (tevent_req_nterror(req, status)) {
2585                 return tevent_req_post(req, ev);
2586         }
2587         return req;
2588 }
2589
2590 static void cli_openx_done(struct tevent_req *subreq)
2591 {
2592         struct tevent_req *req = tevent_req_callback_data(
2593                 subreq, struct tevent_req);
2594         struct cli_openx_state *state = tevent_req_data(
2595                 req, struct cli_openx_state);
2596         uint8_t wct;
2597         uint16_t *vwv;
2598         NTSTATUS status;
2599
2600         status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
2601                               NULL);
2602         TALLOC_FREE(subreq);
2603         if (tevent_req_nterror(req, status)) {
2604                 return;
2605         }
2606         state->fnum = SVAL(vwv+2, 0);
2607         tevent_req_done(req);
2608 }
2609
2610 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2611 {
2612         struct cli_openx_state *state = tevent_req_data(
2613                 req, struct cli_openx_state);
2614         NTSTATUS status;
2615
2616         if (tevent_req_is_nterror(req, &status)) {
2617                 return status;
2618         }
2619         *pfnum = state->fnum;
2620         return NT_STATUS_OK;
2621 }
2622
2623 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
2624              int share_mode, uint16_t *pfnum)
2625 {
2626         TALLOC_CTX *frame = talloc_stackframe();
2627         struct tevent_context *ev;
2628         struct tevent_req *req;
2629         NTSTATUS status = NT_STATUS_NO_MEMORY;
2630
2631         if (smbXcli_conn_has_async_calls(cli->conn)) {
2632                 /*
2633                  * Can't use sync call while an async call is in flight
2634                  */
2635                 status = NT_STATUS_INVALID_PARAMETER;
2636                 goto fail;
2637         }
2638
2639         ev = samba_tevent_context_init(frame);
2640         if (ev == NULL) {
2641                 goto fail;
2642         }
2643
2644         req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
2645         if (req == NULL) {
2646                 goto fail;
2647         }
2648
2649         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2650                 goto fail;
2651         }
2652
2653         status = cli_openx_recv(req, pfnum);
2654  fail:
2655         TALLOC_FREE(frame);
2656         return status;
2657 }
2658 /****************************************************************************
2659  Synchronous wrapper function that does an NtCreateX open by preference
2660  and falls back to openX if this fails.
2661 ****************************************************************************/
2662
2663 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2664                         int share_mode_in, uint16_t *pfnum)
2665 {
2666         NTSTATUS status;
2667         unsigned int openfn = 0;
2668         unsigned int dos_deny = 0;
2669         uint32_t access_mask, share_mode, create_disposition, create_options;
2670         struct smb_create_returns cr;
2671
2672         /* Do the initial mapping into OpenX parameters. */
2673         if (flags & O_CREAT) {
2674                 openfn |= (1<<4);
2675         }
2676         if (!(flags & O_EXCL)) {
2677                 if (flags & O_TRUNC)
2678                         openfn |= (1<<1);
2679                 else
2680                         openfn |= (1<<0);
2681         }
2682
2683         dos_deny = (share_mode_in<<4);
2684
2685         if ((flags & O_ACCMODE) == O_RDWR) {
2686                 dos_deny |= 2;
2687         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2688                 dos_deny |= 1;
2689         }
2690
2691 #if defined(O_SYNC)
2692         if ((flags & O_SYNC) == O_SYNC) {
2693                 dos_deny |= (1<<14);
2694         }
2695 #endif /* O_SYNC */
2696
2697         if (share_mode_in == DENY_FCB) {
2698                 dos_deny = 0xFF;
2699         }
2700
2701 #if 0
2702         /* Hmmm. This is what I think the above code
2703            should look like if it's using the constants
2704            we #define. JRA. */
2705
2706         if (flags & O_CREAT) {
2707                 openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
2708         }
2709         if (!(flags & O_EXCL)) {
2710                 if (flags & O_TRUNC)
2711                         openfn |= OPENX_FILE_EXISTS_TRUNCATE;
2712                 else
2713                         openfn |= OPENX_FILE_EXISTS_OPEN;
2714         }
2715
2716         dos_deny = SET_DENY_MODE(share_mode_in);
2717
2718         if ((flags & O_ACCMODE) == O_RDWR) {
2719                 dos_deny |= DOS_OPEN_RDWR;
2720         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2721                 dos_deny |= DOS_OPEN_WRONLY;
2722         }
2723
2724 #if defined(O_SYNC)
2725         if ((flags & O_SYNC) == O_SYNC) {
2726                 dos_deny |= FILE_SYNC_OPENMODE;
2727         }
2728 #endif /* O_SYNC */
2729
2730         if (share_mode_in == DENY_FCB) {
2731                 dos_deny = 0xFF;
2732         }
2733 #endif
2734
2735         if (!map_open_params_to_ntcreate(fname, dos_deny,
2736                                         openfn, &access_mask,
2737                                         &share_mode, &create_disposition,
2738                                         &create_options, NULL)) {
2739                 goto try_openx;
2740         }
2741
2742         status = cli_ntcreate(cli,
2743                                 fname,
2744                                 0,
2745                                 access_mask,
2746                                 0,
2747                                 share_mode,
2748                                 create_disposition,
2749                                 create_options,
2750                                 0,
2751                                 pfnum,
2752                                 &cr);
2753
2754         /* Try and cope will all varients of "we don't do this call"
2755            and fall back to openX. */
2756
2757         if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
2758                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
2759                         NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
2760                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
2761                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
2762                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
2763                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
2764                         NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
2765                         NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
2766                 goto try_openx;
2767         }
2768
2769         if (NT_STATUS_IS_OK(status) &&
2770             (create_options & FILE_NON_DIRECTORY_FILE) &&
2771             (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
2772         {
2773                 /*
2774                  * Some (broken) servers return a valid handle
2775                  * for directories even if FILE_NON_DIRECTORY_FILE
2776                  * is set. Just close the handle and set the
2777                  * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
2778                  */
2779                 status = cli_close(cli, *pfnum);
2780                 if (!NT_STATUS_IS_OK(status)) {
2781                         return status;
2782                 }
2783                 status = NT_STATUS_FILE_IS_A_DIRECTORY;
2784                 /* Set this so libsmbclient can retrieve it. */
2785                 cli->raw_status = status;
2786         }
2787
2788         return status;
2789
2790   try_openx:
2791
2792         return cli_openx(cli, fname, flags, share_mode_in, pfnum);
2793 }
2794
2795 /****************************************************************************
2796  Close a file.
2797 ****************************************************************************/
2798
2799 struct cli_smb1_close_state {
2800         uint16_t vwv[3];
2801 };
2802
2803 static void cli_smb1_close_done(struct tevent_req *subreq);
2804
2805 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
2806                                 struct tevent_context *ev,
2807                                 struct cli_state *cli,
2808                                 uint16_t fnum,
2809                                 struct tevent_req **psubreq)
2810 {
2811         struct tevent_req *req, *subreq;
2812         struct cli_smb1_close_state *state;
2813
2814         req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
2815         if (req == NULL) {
2816                 return NULL;
2817         }
2818
2819         SSVAL(state->vwv+0, 0, fnum);
2820         SIVALS(state->vwv+1, 0, -1);
2821
2822         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
2823                                 3, state->vwv, 0, NULL);
2824         if (subreq == NULL) {
2825                 TALLOC_FREE(req);
2826                 return NULL;
2827         }
2828         tevent_req_set_callback(subreq, cli_smb1_close_done, req);
2829         *psubreq = subreq;
2830         return req;
2831 }
2832
2833 static void cli_smb1_close_done(struct tevent_req *subreq)
2834 {
2835         struct tevent_req *req = tevent_req_callback_data(
2836                 subreq, struct tevent_req);
2837         NTSTATUS status;
2838
2839         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2840         TALLOC_FREE(subreq);
2841         if (tevent_req_nterror(req, status)) {
2842                 return;
2843         }
2844         tevent_req_done(req);
2845 }
2846
2847 struct cli_close_state {
2848         int dummy;
2849 };
2850
2851 static void cli_close_done(struct tevent_req *subreq);
2852
2853 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2854                                 struct tevent_context *ev,
2855                                 struct cli_state *cli,
2856                                 uint16_t fnum)
2857 {
2858         struct tevent_req *req, *subreq;
2859         struct cli_close_state *state;
2860         NTSTATUS status;
2861
2862         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2863         if (req == NULL) {
2864                 return NULL;
2865         }
2866
2867         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2868                 subreq = cli_smb2_close_fnum_send(state,
2869                                                 ev,
2870                                                 cli,
2871                                                 fnum);
2872                 if (tevent_req_nomem(subreq, req)) {
2873                         return tevent_req_post(req, ev);
2874                 }
2875         } else {
2876                 struct tevent_req *ch_req = NULL;
2877                 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
2878                 if (tevent_req_nomem(subreq, req)) {
2879                         return tevent_req_post(req, ev);
2880                 }
2881                 status = smb1cli_req_chain_submit(&ch_req, 1);
2882                 if (tevent_req_nterror(req, status)) {
2883                         return tevent_req_post(req, ev);
2884                 }
2885         }
2886
2887         tevent_req_set_callback(subreq, cli_close_done, req);
2888         return req;
2889 }
2890
2891 static void cli_close_done(struct tevent_req *subreq)
2892 {
2893         struct tevent_req *req = tevent_req_callback_data(
2894                 subreq, struct tevent_req);
2895         NTSTATUS status = NT_STATUS_OK;
2896         bool err = tevent_req_is_nterror(subreq, &status);
2897
2898         TALLOC_FREE(subreq);
2899         if (err) {
2900                 tevent_req_nterror(req, status);
2901                 return;
2902         }
2903         tevent_req_done(req);
2904 }
2905
2906 NTSTATUS cli_close_recv(struct tevent_req *req)
2907 {
2908         return tevent_req_simple_recv_ntstatus(req);
2909 }
2910
2911 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2912 {
2913         TALLOC_CTX *frame = NULL;
2914         struct tevent_context *ev;
2915         struct tevent_req *req;
2916         NTSTATUS status = NT_STATUS_OK;
2917
2918         frame = talloc_stackframe();
2919
2920         if (smbXcli_conn_has_async_calls(cli->conn)) {
2921                 /*
2922                  * Can't use sync call while an async call is in flight
2923                  */
2924                 status = NT_STATUS_INVALID_PARAMETER;
2925                 goto fail;
2926         }
2927
2928         ev = samba_tevent_context_init(frame);
2929         if (ev == NULL) {
2930                 status = NT_STATUS_NO_MEMORY;
2931                 goto fail;
2932         }
2933
2934         req = cli_close_send(frame, ev, cli, fnum);
2935         if (req == NULL) {
2936                 status = NT_STATUS_NO_MEMORY;
2937                 goto fail;
2938         }
2939
2940         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2941                 goto fail;
2942         }
2943
2944         status = cli_close_recv(req);
2945  fail:
2946         TALLOC_FREE(frame);
2947         return status;
2948 }
2949
2950 /****************************************************************************
2951  Truncate a file to a specified size
2952 ****************************************************************************/
2953
2954 struct ftrunc_state {
2955         uint16_t setup;
2956         uint8_t param[6];
2957         uint8_t data[8];
2958 };
2959
2960 static void cli_ftruncate_done(struct tevent_req *subreq)
2961 {
2962         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2963                                          NULL, 0, NULL, NULL, 0, NULL);
2964         tevent_req_simple_finish_ntstatus(subreq, status);
2965 }
2966
2967 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2968                                         struct tevent_context *ev,
2969                                         struct cli_state *cli,
2970                                         uint16_t fnum,
2971                                         uint64_t size)
2972 {
2973         struct tevent_req *req = NULL, *subreq = NULL;
2974         struct ftrunc_state *state = NULL;
2975
2976         req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2977         if (req == NULL) {
2978                 return NULL;
2979         }
2980
2981         /* Setup setup word. */
2982         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2983
2984         /* Setup param array. */
2985         SSVAL(state->param,0,fnum);
2986         SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2987         SSVAL(state->param,4,0);
2988
2989         /* Setup data array. */
2990         SBVAL(state->data, 0, size);
2991
2992         subreq = cli_trans_send(state,                  /* mem ctx. */
2993                                 ev,                     /* event ctx. */
2994                                 cli,                    /* cli_state. */
2995                                 0,                      /* additional_flags2 */
2996                                 SMBtrans2,              /* cmd. */
2997                                 NULL,                   /* pipe name. */
2998                                 -1,                     /* fid. */
2999                                 0,                      /* function. */
3000                                 0,                      /* flags. */
3001                                 &state->setup,          /* setup. */
3002                                 1,                      /* num setup uint16_t words. */
3003                                 0,                      /* max returned setup. */
3004                                 state->param,           /* param. */
3005                                 6,                      /* num param. */
3006                                 2,                      /* max returned param. */
3007                                 state->data,            /* data. */
3008                                 8,                      /* num data. */
3009                                 0);                     /* max returned data. */
3010
3011         if (tevent_req_nomem(subreq, req)) {
3012                 return tevent_req_post(req, ev);
3013         }
3014         tevent_req_set_callback(subreq, cli_ftruncate_done, req);
3015         return req;
3016 }
3017
3018 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
3019 {
3020         return tevent_req_simple_recv_ntstatus(req);
3021 }
3022
3023 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3024 {
3025         TALLOC_CTX *frame = NULL;
3026         struct tevent_context *ev = NULL;
3027         struct tevent_req *req = NULL;
3028         NTSTATUS status = NT_STATUS_OK;
3029
3030         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3031                 return cli_smb2_ftruncate(cli, fnum, size);
3032         }
3033
3034         frame = talloc_stackframe();
3035
3036         if (smbXcli_conn_has_async_calls(cli->conn)) {
3037                 /*
3038                  * Can't use sync call while an async call is in flight
3039                  */
3040                 status = NT_STATUS_INVALID_PARAMETER;
3041                 goto fail;
3042         }
3043
3044         ev = samba_tevent_context_init(frame);
3045         if (ev == NULL) {
3046                 status = NT_STATUS_NO_MEMORY;
3047                 goto fail;
3048         }
3049
3050         req = cli_ftruncate_send(frame,
3051                                 ev,
3052                                 cli,
3053                                 fnum,
3054                                 size);
3055         if (req == NULL) {
3056                 status = NT_STATUS_NO_MEMORY;
3057                 goto fail;
3058         }
3059
3060         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3061                 goto fail;
3062         }
3063
3064         status = cli_ftruncate_recv(req);
3065
3066  fail:
3067         TALLOC_FREE(frame);
3068         return status;
3069 }
3070
3071 /****************************************************************************
3072  send a lock with a specified locktype
3073  this is used for testing LOCKING_ANDX_CANCEL_LOCK
3074 ****************************************************************************/
3075
3076 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
3077                       uint32_t offset, uint32_t len,
3078                       int timeout, unsigned char locktype)
3079 {
3080         uint16_t vwv[8];
3081         uint8_t bytes[10];
3082         NTSTATUS status;
3083         unsigned int set_timeout = 0;
3084         unsigned int saved_timeout = 0;
3085
3086         SCVAL(vwv + 0, 0, 0xff);
3087         SCVAL(vwv + 0, 1, 0);
3088         SSVAL(vwv + 1, 0, 0);
3089         SSVAL(vwv + 2, 0, fnum);
3090         SCVAL(vwv + 3, 0, locktype);
3091         SCVAL(vwv + 3, 1, 0);
3092         SIVALS(vwv + 4, 0, timeout);
3093         SSVAL(vwv + 6, 0, 0);
3094         SSVAL(vwv + 7, 0, 1);
3095
3096         SSVAL(bytes, 0, cli_getpid(cli));
3097         SIVAL(bytes, 2, offset);
3098         SIVAL(bytes, 6, len);
3099
3100         if (timeout != 0) {
3101                 if (timeout == -1) {
3102                         set_timeout = 0x7FFFFFFF;
3103                 } else {
3104                         set_timeout = timeout + 2*1000;
3105                 }
3106                 saved_timeout = cli_set_timeout(cli, set_timeout);
3107         }
3108
3109         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3110                          10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3111
3112         if (saved_timeout != 0) {
3113                 cli_set_timeout(cli, saved_timeout);
3114         }
3115
3116         return status;
3117 }
3118
3119 /****************************************************************************
3120  Lock a file.
3121  note that timeout is in units of 2 milliseconds
3122 ****************************************************************************/
3123
3124 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
3125                   uint32_t offset, uint32_t len, int timeout,
3126                   enum brl_type lock_type)
3127 {
3128         NTSTATUS status;
3129
3130         status = cli_locktype(cli, fnum, offset, len, timeout,
3131                               (lock_type == READ_LOCK? 1 : 0));
3132         return status;
3133 }
3134
3135 /****************************************************************************
3136  Unlock a file.
3137 ****************************************************************************/
3138
3139 struct cli_unlock_state {
3140         uint16_t vwv[8];
3141         uint8_t data[10];
3142 };
3143
3144 static void cli_unlock_done(struct tevent_req *subreq);
3145
3146 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3147                                 struct tevent_context *ev,
3148                                 struct cli_state *cli,
3149                                 uint16_t fnum,
3150                                 uint64_t offset,
3151                                 uint64_t len)
3152
3153 {
3154         struct tevent_req *req = NULL, *subreq = NULL;
3155         struct cli_unlock_state *state = NULL;
3156         uint8_t additional_flags = 0;
3157
3158         req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3159         if (req == NULL) {
3160                 return NULL;
3161         }
3162
3163         SCVAL(state->vwv+0, 0, 0xFF);
3164         SSVAL(state->vwv+2, 0, fnum);
3165         SCVAL(state->vwv+3, 0, 0);
3166         SIVALS(state->vwv+4, 0, 0);
3167         SSVAL(state->vwv+6, 0, 1);
3168         SSVAL(state->vwv+7, 0, 0);
3169
3170         SSVAL(state->data, 0, cli_getpid(cli));
3171         SIVAL(state->data, 2, offset);
3172         SIVAL(state->data, 6, len);
3173
3174         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3175                                 8, state->vwv, 10, state->data);
3176         if (tevent_req_nomem(subreq, req)) {
3177                 return tevent_req_post(req, ev);
3178         }
3179         tevent_req_set_callback(subreq, cli_unlock_done, req);
3180         return req;
3181 }
3182
3183 static void cli_unlock_done(struct tevent_req *subreq)
3184 {
3185         struct tevent_req *req = tevent_req_callback_data(
3186                                 subreq, struct tevent_req);
3187         NTSTATUS status;
3188
3189         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3190         TALLOC_FREE(subreq);
3191         if (tevent_req_nterror(req, status)) {
3192                 return;
3193         }
3194         tevent_req_done(req);
3195 }
3196
3197 NTSTATUS cli_unlock_recv(struct tevent_req *req)
3198 {
3199         return tevent_req_simple_recv_ntstatus(req);
3200 }
3201
3202 NTSTATUS cli_unlock(struct cli_state *cli,
3203                         uint16_t fnum,
3204                         uint32_t offset,
3205                         uint32_t len)
3206 {
3207         TALLOC_CTX *frame = talloc_stackframe();
3208         struct tevent_context *ev;
3209         struct tevent_req *req;
3210         NTSTATUS status = NT_STATUS_OK;
3211
3212         if (smbXcli_conn_has_async_calls(cli->conn)) {
3213                 /*
3214                  * Can't use sync call while an async call is in flight
3215                  */
3216                 status = NT_STATUS_INVALID_PARAMETER;
3217                 goto fail;
3218         }
3219
3220         ev = samba_tevent_context_init(frame);
3221         if (ev == NULL) {
3222                 status = NT_STATUS_NO_MEMORY;
3223                 goto fail;
3224         }
3225
3226         req = cli_unlock_send(frame, ev, cli,
3227                         fnum, offset, len);
3228         if (req == NULL) {
3229                 status = NT_STATUS_NO_MEMORY;
3230                 goto fail;
3231         }
3232
3233         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3234                 goto fail;
3235         }
3236
3237         status = cli_unlock_recv(req);
3238
3239  fail:
3240         TALLOC_FREE(frame);
3241         return status;
3242 }
3243
3244 /****************************************************************************
3245  Lock a file with 64 bit offsets.
3246 ****************************************************************************/
3247
3248 NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
3249                     uint64_t offset, uint64_t len, int timeout,
3250                     enum brl_type lock_type)
3251 {
3252         uint16_t vwv[8];
3253         uint8_t bytes[20];
3254         unsigned int set_timeout = 0;
3255         unsigned int saved_timeout = 0;
3256         int ltype;
3257         NTSTATUS status;
3258
3259         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3260                 return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
3261         }
3262
3263         ltype = (lock_type == READ_LOCK? 1 : 0);
3264         ltype |= LOCKING_ANDX_LARGE_FILES;
3265
3266         SCVAL(vwv + 0, 0, 0xff);
3267         SCVAL(vwv + 0, 1, 0);
3268         SSVAL(vwv + 1, 0, 0);
3269         SSVAL(vwv + 2, 0, fnum);
3270         SCVAL(vwv + 3, 0, ltype);
3271         SCVAL(vwv + 3, 1, 0);
3272         SIVALS(vwv + 4, 0, timeout);
3273         SSVAL(vwv + 6, 0, 0);
3274         SSVAL(vwv + 7, 0, 1);
3275
3276         SIVAL(bytes, 0, cli_getpid(cli));
3277         SOFF_T_R(bytes, 4, offset);
3278         SOFF_T_R(bytes, 12, len);
3279
3280         if (timeout != 0) {
3281                 if (timeout == -1) {
3282                         set_timeout = 0x7FFFFFFF;
3283                 } else {
3284                         set_timeout = timeout + 2*1000;
3285                 }
3286                 saved_timeout = cli_set_timeout(cli, set_timeout);
3287         }
3288
3289         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3290                          20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3291
3292         if (saved_timeout != 0) {
3293                 cli_set_timeout(cli, saved_timeout);
3294         }
3295
3296         return status;
3297 }
3298
3299 /****************************************************************************
3300  Unlock a file with 64 bit offsets.
3301 ****************************************************************************/
3302
3303 struct cli_unlock64_state {
3304         uint16_t vwv[8];
3305         uint8_t data[20];
3306 };
3307
3308 static void cli_unlock64_done(struct tevent_req *subreq);
3309
3310 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
3311                                 struct tevent_context *ev,
3312                                 struct cli_state *cli,
3313                                 uint16_t fnum,
3314                                 uint64_t offset,
3315                                 uint64_t len)
3316
3317 {
3318         struct tevent_req *req = NULL, *subreq = NULL;
3319         struct cli_unlock64_state *state = NULL;
3320         uint8_t additional_flags = 0;
3321
3322         req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
3323         if (req == NULL) {
3324                 return NULL;
3325         }
3326
3327         SCVAL(state->vwv+0, 0, 0xff);
3328         SSVAL(state->vwv+2, 0, fnum);
3329         SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
3330         SIVALS(state->vwv+4, 0, 0);
3331         SSVAL(state->vwv+6, 0, 1);
3332         SSVAL(state->vwv+7, 0, 0);
3333
3334         SIVAL(state->data, 0, cli_getpid(cli));
3335         SOFF_T_R(state->data, 4, offset);
3336         SOFF_T_R(state->data, 12, len);
3337
3338         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3339                                 8, state->vwv, 20, state->data);
3340         if (tevent_req_nomem(subreq, req)) {
3341                 return tevent_req_post(req, ev);
3342         }
3343         tevent_req_set_callback(subreq, cli_unlock64_done, req);
3344         return req;
3345 }
3346
3347 static void cli_unlock64_done(struct tevent_req *subreq)
3348 {
3349         struct tevent_req *req = tevent_req_callback_data(
3350                                 subreq, struct tevent_req);
3351         NTSTATUS status;
3352
3353         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3354         TALLOC_FREE(subreq);
3355         if (tevent_req_nterror(req, status)) {
3356                 return;
3357         }
3358         tevent_req_done(req);
3359 }
3360
3361 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
3362 {
3363         return tevent_req_simple_recv_ntstatus(req);
3364 }
3365
3366 NTSTATUS cli_unlock64(struct cli_state *cli,
3367                                 uint16_t fnum,
3368                                 uint64_t offset,
3369                                 uint64_t len)
3370 {
3371         TALLOC_CTX *frame = talloc_stackframe();
3372         struct tevent_context *ev;
3373         struct tevent_req *req;
3374         NTSTATUS status = NT_STATUS_OK;
3375
3376         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3377                 return cli_unlock(cli, fnum, offset, len);
3378         }
3379
3380         if (smbXcli_conn_has_async_calls(cli->conn)) {
3381                 /*
3382                  * Can't use sync call while an async call is in flight
3383                  */
3384                 status = NT_STATUS_INVALID_PARAMETER;
3385                 goto fail;
3386         }
3387
3388         ev = samba_tevent_context_init(frame);
3389         if (ev == NULL) {
3390                 status = NT_STATUS_NO_MEMORY;
3391                 goto fail;
3392         }
3393
3394         req = cli_unlock64_send(frame, ev, cli,
3395                         fnum, offset, len);
3396         if (req == NULL) {
3397                 status = NT_STATUS_NO_MEMORY;
3398                 goto fail;
3399         }
3400
3401         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3402                 goto fail;
3403         }
3404
3405         status = cli_unlock64_recv(req);
3406
3407  fail:
3408         TALLOC_FREE(frame);
3409         return status;
3410 }
3411
3412 /****************************************************************************
3413  Get/unlock a POSIX lock on a file - internal function.
3414 ****************************************************************************/
3415
3416 struct posix_lock_state {
3417         uint16_t setup;
3418         uint8_t param[4];
3419         uint8_t data[POSIX_LOCK_DATA_SIZE];
3420 };
3421
3422 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3423 {
3424         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3425                                          NULL, 0, NULL, NULL, 0, NULL);
3426         tevent_req_simple_finish_ntstatus(subreq, status);
3427 }
3428
3429 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3430                                         struct tevent_context *ev,
3431                                         struct cli_state *cli,
3432                                         uint16_t fnum,
3433                   &n