b50926307a5049131883591655b846e660f76a2f
[garming/samba-autobuild/.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "libsmb/libsmb.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "async_smb.h"
26 #include "libsmb/clirap.h"
27 #include "trans2.h"
28 #include "ntioctl.h"
29 #include "libcli/security/secdesc.h"
30 #include "../libcli/smb/smbXcli_base.h"
31
32 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         struct tevent_req *req = tevent_req_callback_data(
1315                                 subreq, struct tevent_req);
1316         NTSTATUS status;
1317
1318         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1319         TALLOC_FREE(subreq);
1320         if (tevent_req_nterror(req, status)) {
1321                 return;
1322         }
1323         tevent_req_done(req);
1324 }
1325
1326 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1327 {
1328         return tevent_req_simple_recv_ntstatus(req);
1329 }
1330
1331 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1332                                 struct tevent_context *ev,
1333                                 struct cli_state *cli,
1334                                 const char *fname_src,
1335                                 const char *fname_dst)
1336 {
1337         return cli_ntrename_internal_send(mem_ctx,
1338                                           ev,
1339                                           cli,
1340                                           fname_src,
1341                                           fname_dst,
1342                                           RENAME_FLAG_RENAME);
1343 }
1344
1345 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1346 {
1347         return cli_ntrename_internal_recv(req);
1348 }
1349
1350 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1351 {
1352         TALLOC_CTX *frame = talloc_stackframe();
1353         struct tevent_context *ev;
1354         struct tevent_req *req;
1355         NTSTATUS status = NT_STATUS_OK;
1356
1357         if (smbXcli_conn_has_async_calls(cli->conn)) {
1358                 /*
1359                  * Can't use sync call while an async call is in flight
1360                  */
1361                 status = NT_STATUS_INVALID_PARAMETER;
1362                 goto fail;
1363         }
1364
1365         ev = samba_tevent_context_init(frame);
1366         if (ev == NULL) {
1367                 status = NT_STATUS_NO_MEMORY;
1368                 goto fail;
1369         }
1370
1371         req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1372         if (req == NULL) {
1373                 status = NT_STATUS_NO_MEMORY;
1374                 goto fail;
1375         }
1376
1377         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1378                 goto fail;
1379         }
1380
1381         status = cli_ntrename_recv(req);
1382
1383  fail:
1384         TALLOC_FREE(frame);
1385         return status;
1386 }
1387
1388 /****************************************************************************
1389  NT hardlink a file.
1390 ****************************************************************************/
1391
1392 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1393                                 struct tevent_context *ev,
1394                                 struct cli_state *cli,
1395                                 const char *fname_src,
1396                                 const char *fname_dst)
1397 {
1398         return cli_ntrename_internal_send(mem_ctx,
1399                                           ev,
1400                                           cli,
1401                                           fname_src,
1402                                           fname_dst,
1403                                           RENAME_FLAG_HARD_LINK);
1404 }
1405
1406 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1407 {
1408         return cli_ntrename_internal_recv(req);
1409 }
1410
1411 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1412 {
1413         TALLOC_CTX *frame = talloc_stackframe();
1414         struct tevent_context *ev;
1415         struct tevent_req *req;
1416         NTSTATUS status = NT_STATUS_OK;
1417
1418         if (smbXcli_conn_has_async_calls(cli->conn)) {
1419                 /*
1420                  * Can't use sync call while an async call is in flight
1421                  */
1422                 status = NT_STATUS_INVALID_PARAMETER;
1423                 goto fail;
1424         }
1425
1426         ev = samba_tevent_context_init(frame);
1427         if (ev == NULL) {
1428                 status = NT_STATUS_NO_MEMORY;
1429                 goto fail;
1430         }
1431
1432         req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1433         if (req == NULL) {
1434                 status = NT_STATUS_NO_MEMORY;
1435                 goto fail;
1436         }
1437
1438         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1439                 goto fail;
1440         }
1441
1442         status = cli_nt_hardlink_recv(req);
1443
1444  fail:
1445         TALLOC_FREE(frame);
1446         return status;
1447 }
1448
1449 /****************************************************************************
1450  Delete a file.
1451 ****************************************************************************/
1452
1453 static void cli_unlink_done(struct tevent_req *subreq);
1454
1455 struct cli_unlink_state {
1456         uint16_t vwv[1];
1457 };
1458
1459 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1460                                 struct tevent_context *ev,
1461                                 struct cli_state *cli,
1462                                 const char *fname,
1463                                 uint16_t mayhave_attrs)
1464 {
1465         struct tevent_req *req = NULL, *subreq = NULL;
1466         struct cli_unlink_state *state = NULL;
1467         uint8_t additional_flags = 0;
1468         uint16_t additional_flags2 = 0;
1469         uint8_t *bytes = NULL;
1470
1471         req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1472         if (req == NULL) {
1473                 return NULL;
1474         }
1475
1476         SSVAL(state->vwv+0, 0, mayhave_attrs);
1477
1478         bytes = talloc_array(state, uint8_t, 1);
1479         if (tevent_req_nomem(bytes, req)) {
1480                 return tevent_req_post(req, ev);
1481         }
1482         bytes[0] = 4;
1483         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
1484                                    strlen(fname)+1, NULL);
1485
1486         if (tevent_req_nomem(bytes, req)) {
1487                 return tevent_req_post(req, ev);
1488         }
1489
1490         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1491                 additional_flags2 = FLAGS2_REPARSE_PATH;
1492         }
1493
1494         subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1495                                 additional_flags2,
1496                                 1, state->vwv, talloc_get_size(bytes), bytes);
1497         if (tevent_req_nomem(subreq, req)) {
1498                 return tevent_req_post(req, ev);
1499         }
1500         tevent_req_set_callback(subreq, cli_unlink_done, req);
1501         return req;
1502 }
1503
1504 static void cli_unlink_done(struct tevent_req *subreq)
1505 {
1506         struct tevent_req *req = tevent_req_callback_data(
1507                 subreq, struct tevent_req);
1508         NTSTATUS status;
1509
1510         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1511         TALLOC_FREE(subreq);
1512         if (tevent_req_nterror(req, status)) {
1513                 return;
1514         }
1515         tevent_req_done(req);
1516 }
1517
1518 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1519 {
1520         return tevent_req_simple_recv_ntstatus(req);
1521 }
1522
1523 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1524 {
1525         TALLOC_CTX *frame = NULL;
1526         struct tevent_context *ev;
1527         struct tevent_req *req;
1528         NTSTATUS status = NT_STATUS_OK;
1529
1530         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1531                 return cli_smb2_unlink(cli, fname);
1532         }
1533
1534         frame = talloc_stackframe();
1535
1536         if (smbXcli_conn_has_async_calls(cli->conn)) {
1537                 /*
1538                  * Can't use sync call while an async call is in flight
1539                  */
1540                 status = NT_STATUS_INVALID_PARAMETER;
1541                 goto fail;
1542         }
1543
1544         ev = samba_tevent_context_init(frame);
1545         if (ev == NULL) {
1546                 status = NT_STATUS_NO_MEMORY;
1547                 goto fail;
1548         }
1549
1550         req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1551         if (req == NULL) {
1552                 status = NT_STATUS_NO_MEMORY;
1553                 goto fail;
1554         }
1555
1556         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1557                 goto fail;
1558         }
1559
1560         status = cli_unlink_recv(req);
1561
1562  fail:
1563         TALLOC_FREE(frame);
1564         return status;
1565 }
1566
1567 /****************************************************************************
1568  Create a directory.
1569 ****************************************************************************/
1570
1571 static void cli_mkdir_done(struct tevent_req *subreq);
1572
1573 struct cli_mkdir_state {
1574         int dummy;
1575 };
1576
1577 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1578                                   struct tevent_context *ev,
1579                                   struct cli_state *cli,
1580                                   const char *dname)
1581 {
1582         struct tevent_req *req = NULL, *subreq = NULL;
1583         struct cli_mkdir_state *state = NULL;
1584         uint8_t additional_flags = 0;
1585         uint16_t additional_flags2 = 0;
1586         uint8_t *bytes = NULL;
1587
1588         req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1589         if (req == NULL) {
1590                 return NULL;
1591         }
1592
1593         bytes = talloc_array(state, uint8_t, 1);
1594         if (tevent_req_nomem(bytes, req)) {
1595                 return tevent_req_post(req, ev);
1596         }
1597         bytes[0] = 4;
1598         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1599                                    strlen(dname)+1, NULL);
1600
1601         if (tevent_req_nomem(bytes, req)) {
1602                 return tevent_req_post(req, ev);
1603         }
1604
1605         if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1606                 additional_flags2 = FLAGS2_REPARSE_PATH;
1607         }
1608
1609         subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1610                         additional_flags2,
1611                         0, NULL, talloc_get_size(bytes), bytes);
1612         if (tevent_req_nomem(subreq, req)) {
1613                 return tevent_req_post(req, ev);
1614         }
1615         tevent_req_set_callback(subreq, cli_mkdir_done, req);
1616         return req;
1617 }
1618
1619 static void cli_mkdir_done(struct tevent_req *subreq)
1620 {
1621         struct tevent_req *req = tevent_req_callback_data(
1622                 subreq, struct tevent_req);
1623         NTSTATUS status;
1624
1625         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1626         TALLOC_FREE(subreq);
1627         if (tevent_req_nterror(req, status)) {
1628                 return;
1629         }
1630         tevent_req_done(req);
1631 }
1632
1633 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1634 {
1635         return tevent_req_simple_recv_ntstatus(req);
1636 }
1637
1638 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1639 {
1640         TALLOC_CTX *frame = NULL;
1641         struct tevent_context *ev;
1642         struct tevent_req *req;
1643         NTSTATUS status = NT_STATUS_OK;
1644
1645         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1646                 return cli_smb2_mkdir(cli, dname);
1647         }
1648
1649         frame = talloc_stackframe();
1650
1651         if (smbXcli_conn_has_async_calls(cli->conn)) {
1652                 /*
1653                  * Can't use sync call while an async call is in flight
1654                  */
1655                 status = NT_STATUS_INVALID_PARAMETER;
1656                 goto fail;
1657         }
1658
1659         ev = samba_tevent_context_init(frame);
1660         if (ev == NULL) {
1661                 status = NT_STATUS_NO_MEMORY;
1662                 goto fail;
1663         }
1664
1665         req = cli_mkdir_send(frame, ev, cli, dname);
1666         if (req == NULL) {
1667                 status = NT_STATUS_NO_MEMORY;
1668                 goto fail;
1669         }
1670
1671         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1672                 goto fail;
1673         }
1674
1675         status = cli_mkdir_recv(req);
1676
1677  fail:
1678         TALLOC_FREE(frame);
1679         return status;
1680 }
1681
1682 /****************************************************************************
1683  Remove a directory.
1684 ****************************************************************************/
1685
1686 static void cli_rmdir_done(struct tevent_req *subreq);
1687
1688 struct cli_rmdir_state {
1689         int dummy;
1690 };
1691
1692 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1693                                   struct tevent_context *ev,
1694                                   struct cli_state *cli,
1695                                   const char *dname)
1696 {
1697         struct tevent_req *req = NULL, *subreq = NULL;
1698         struct cli_rmdir_state *state = NULL;
1699         uint8_t additional_flags = 0;
1700         uint16_t additional_flags2 = 0;
1701         uint8_t *bytes = NULL;
1702
1703         req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1704         if (req == NULL) {
1705                 return NULL;
1706         }
1707
1708         bytes = talloc_array(state, uint8_t, 1);
1709         if (tevent_req_nomem(bytes, req)) {
1710                 return tevent_req_post(req, ev);
1711         }
1712         bytes[0] = 4;
1713         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1714                                    strlen(dname)+1, NULL);
1715
1716         if (tevent_req_nomem(bytes, req)) {
1717                 return tevent_req_post(req, ev);
1718         }
1719
1720         if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1721                 additional_flags2 = FLAGS2_REPARSE_PATH;
1722         }
1723
1724         subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1725                         additional_flags2,
1726                         0, NULL, talloc_get_size(bytes), bytes);
1727         if (tevent_req_nomem(subreq, req)) {
1728                 return tevent_req_post(req, ev);
1729         }
1730         tevent_req_set_callback(subreq, cli_rmdir_done, req);
1731         return req;
1732 }
1733
1734 static void cli_rmdir_done(struct tevent_req *subreq)
1735 {
1736         struct tevent_req *req = tevent_req_callback_data(
1737                 subreq, struct tevent_req);
1738         NTSTATUS status;
1739
1740         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1741         TALLOC_FREE(subreq);
1742         if (tevent_req_nterror(req, status)) {
1743                 return;
1744         }
1745         tevent_req_done(req);
1746 }
1747
1748 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1749 {
1750         return tevent_req_simple_recv_ntstatus(req);
1751 }
1752
1753 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1754 {
1755         TALLOC_CTX *frame = NULL;
1756         struct tevent_context *ev;
1757         struct tevent_req *req;
1758         NTSTATUS status = NT_STATUS_OK;
1759
1760         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1761                 return cli_smb2_rmdir(cli, dname);
1762         }
1763
1764         frame = talloc_stackframe();
1765
1766         if (smbXcli_conn_has_async_calls(cli->conn)) {
1767                 /*
1768                  * Can't use sync call while an async call is in flight
1769                  */
1770                 status = NT_STATUS_INVALID_PARAMETER;
1771                 goto fail;
1772         }
1773
1774         ev = samba_tevent_context_init(frame);
1775         if (ev == NULL) {
1776                 status = NT_STATUS_NO_MEMORY;
1777                 goto fail;
1778         }
1779
1780         req = cli_rmdir_send(frame, ev, cli, dname);
1781         if (req == NULL) {
1782                 status = NT_STATUS_NO_MEMORY;
1783                 goto fail;
1784         }
1785
1786         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1787                 goto fail;
1788         }
1789
1790         status = cli_rmdir_recv(req);
1791
1792  fail:
1793         TALLOC_FREE(frame);
1794         return status;
1795 }
1796
1797 /****************************************************************************
1798  Set or clear the delete on close flag.
1799 ****************************************************************************/
1800
1801 struct doc_state {
1802         uint16_t setup;
1803         uint8_t param[6];
1804         uint8_t data[1];
1805 };
1806
1807 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
1808 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
1809
1810 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1811                                         struct tevent_context *ev,
1812                                         struct cli_state *cli,
1813                                         uint16_t fnum,
1814                                         bool flag)
1815 {
1816         struct tevent_req *req = NULL, *subreq = NULL;
1817         struct doc_state *state = NULL;
1818
1819         req = tevent_req_create(mem_ctx, &state, struct doc_state);
1820         if (req == NULL) {
1821                 return NULL;
1822         }
1823
1824         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1825                 subreq = cli_smb2_delete_on_close_send(state, ev, cli,
1826                                                        fnum, flag);
1827                 if (tevent_req_nomem(subreq, req)) {
1828                         return tevent_req_post(req, ev);
1829                 }
1830                 tevent_req_set_callback(subreq,
1831                                         cli_nt_delete_on_close_smb2_done,
1832                                         req);
1833                 return req;
1834         }
1835
1836         /* Setup setup word. */
1837         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1838
1839         /* Setup param array. */
1840         SSVAL(state->param,0,fnum);
1841         SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1842
1843         /* Setup data array. */
1844         SCVAL(&state->data[0], 0, flag ? 1 : 0);
1845
1846         subreq = cli_trans_send(state,                  /* mem ctx. */
1847                                 ev,                     /* event ctx. */
1848                                 cli,                    /* cli_state. */
1849                                 0,                      /* additional_flags2 */
1850                                 SMBtrans2,              /* cmd. */
1851                                 NULL,                   /* pipe name. */
1852                                 -1,                     /* fid. */
1853                                 0,                      /* function. */
1854                                 0,                      /* flags. */
1855                                 &state->setup,          /* setup. */
1856                                 1,                      /* num setup uint16_t words. */
1857                                 0,                      /* max returned setup. */
1858                                 state->param,           /* param. */
1859                                 6,                      /* num param. */
1860                                 2,                      /* max returned param. */
1861                                 state->data,            /* data. */
1862                                 1,                      /* num data. */
1863                                 0);                     /* max returned data. */
1864
1865         if (tevent_req_nomem(subreq, req)) {
1866                 return tevent_req_post(req, ev);
1867         }
1868         tevent_req_set_callback(subreq,
1869                                 cli_nt_delete_on_close_smb1_done,
1870                                 req);
1871         return req;
1872 }
1873
1874 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
1875 {
1876         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
1877                                          NULL, 0, NULL, NULL, 0, NULL);
1878         tevent_req_simple_finish_ntstatus(subreq, status);
1879 }
1880
1881 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
1882 {
1883         NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
1884         tevent_req_simple_finish_ntstatus(subreq, status);
1885 }
1886
1887 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1888 {
1889         return tevent_req_simple_recv_ntstatus(req);
1890 }
1891
1892 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1893 {
1894         TALLOC_CTX *frame = talloc_stackframe();
1895         struct tevent_context *ev = NULL;
1896         struct tevent_req *req = NULL;
1897         NTSTATUS status = NT_STATUS_OK;
1898
1899         if (smbXcli_conn_has_async_calls(cli->conn)) {
1900                 /*
1901                  * Can't use sync call while an async call is in flight
1902                  */
1903                 status = NT_STATUS_INVALID_PARAMETER;
1904                 goto fail;
1905         }
1906
1907         ev = samba_tevent_context_init(frame);
1908         if (ev == NULL) {
1909                 status = NT_STATUS_NO_MEMORY;
1910                 goto fail;
1911         }
1912
1913         req = cli_nt_delete_on_close_send(frame,
1914                                 ev,
1915                                 cli,
1916                                 fnum,
1917                                 flag);
1918         if (req == NULL) {
1919                 status = NT_STATUS_NO_MEMORY;
1920                 goto fail;
1921         }
1922
1923         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1924                 goto fail;
1925         }
1926
1927         status = cli_nt_delete_on_close_recv(req);
1928
1929  fail:
1930         TALLOC_FREE(frame);
1931         return status;
1932 }
1933
1934 struct cli_ntcreate1_state {
1935         uint16_t vwv[24];
1936         uint16_t fnum;
1937         struct smb_create_returns cr;
1938         struct tevent_req *subreq;
1939 };
1940
1941 static void cli_ntcreate1_done(struct tevent_req *subreq);
1942 static bool cli_ntcreate1_cancel(struct tevent_req *req);
1943
1944 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
1945                                              struct tevent_context *ev,
1946                                              struct cli_state *cli,
1947                                              const char *fname,
1948                                              uint32_t CreatFlags,
1949                                              uint32_t DesiredAccess,
1950                                              uint32_t FileAttributes,
1951                                              uint32_t ShareAccess,
1952                                              uint32_t CreateDisposition,
1953                                              uint32_t CreateOptions,
1954                                              uint8_t SecurityFlags)
1955 {
1956         struct tevent_req *req, *subreq;
1957         struct cli_ntcreate1_state *state;
1958         uint16_t *vwv;
1959         uint8_t *bytes;
1960         size_t converted_len;
1961         uint16_t additional_flags2 = 0;
1962
1963         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
1964         if (req == NULL) {
1965                 return NULL;
1966         }
1967
1968         vwv = state->vwv;
1969
1970         SCVAL(vwv+0, 0, 0xFF);
1971         SCVAL(vwv+0, 1, 0);
1972         SSVAL(vwv+1, 0, 0);
1973         SCVAL(vwv+2, 0, 0);
1974
1975         if (cli->use_oplocks) {
1976                 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1977         }
1978         SIVAL(vwv+3, 1, CreatFlags);
1979         SIVAL(vwv+5, 1, 0x0);   /* RootDirectoryFid */
1980         SIVAL(vwv+7, 1, DesiredAccess);
1981         SIVAL(vwv+9, 1, 0x0);   /* AllocationSize */
1982         SIVAL(vwv+11, 1, 0x0);  /* AllocationSize */
1983         SIVAL(vwv+13, 1, FileAttributes);
1984         SIVAL(vwv+15, 1, ShareAccess);
1985         SIVAL(vwv+17, 1, CreateDisposition);
1986         SIVAL(vwv+19, 1, CreateOptions |
1987                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
1988         SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1989         SCVAL(vwv+23, 1, SecurityFlags);
1990
1991         bytes = talloc_array(state, uint8_t, 0);
1992         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
1993                                    fname, strlen(fname)+1,
1994                                    &converted_len);
1995
1996         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1997                 additional_flags2 = FLAGS2_REPARSE_PATH;
1998         }
1999
2000         /* sigh. this copes with broken netapp filer behaviour */
2001         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2002
2003         if (tevent_req_nomem(bytes, req)) {
2004                 return tevent_req_post(req, ev);
2005         }
2006
2007         SSVAL(vwv+2, 1, converted_len);
2008
2009         subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2010                         additional_flags2, 24, vwv,
2011                         talloc_get_size(bytes), bytes);
2012         if (tevent_req_nomem(subreq, req)) {
2013                 return tevent_req_post(req, ev);
2014         }
2015         tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2016
2017         state->subreq = subreq;
2018         tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2019
2020         return req;
2021 }
2022
2023 static void cli_ntcreate1_done(struct tevent_req *subreq)
2024 {
2025         struct tevent_req *req = tevent_req_callback_data(
2026                 subreq, struct tevent_req);
2027         struct cli_ntcreate1_state *state = tevent_req_data(
2028                 req, struct cli_ntcreate1_state);
2029         uint8_t wct;
2030         uint16_t *vwv;
2031         uint32_t num_bytes;
2032         uint8_t *bytes;
2033         NTSTATUS status;
2034
2035         status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2036                               &num_bytes, &bytes);
2037         TALLOC_FREE(subreq);
2038         if (tevent_req_nterror(req, status)) {
2039                 return;
2040         }
2041         state->cr.oplock_level = CVAL(vwv+2, 0);
2042         state->fnum = SVAL(vwv+2, 1);
2043         state->cr.create_action = IVAL(vwv+3, 1);
2044         state->cr.creation_time = BVAL(vwv+5, 1);
2045         state->cr.last_access_time = BVAL(vwv+9, 1);
2046         state->cr.last_write_time = BVAL(vwv+13, 1);
2047         state->cr.change_time   = BVAL(vwv+17, 1);
2048         state->cr.file_attributes = IVAL(vwv+21, 1);
2049         state->cr.allocation_size = BVAL(vwv+23, 1);
2050         state->cr.end_of_file   = BVAL(vwv+27, 1);
2051
2052         tevent_req_done(req);
2053 }
2054
2055 static bool cli_ntcreate1_cancel(struct tevent_req *req)
2056 {
2057         struct cli_ntcreate1_state *state = tevent_req_data(
2058                 req, struct cli_ntcreate1_state);
2059         return tevent_req_cancel(state->subreq);
2060 }
2061
2062 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2063                                    uint16_t *pfnum,
2064                                    struct smb_create_returns *cr)
2065 {
2066         struct cli_ntcreate1_state *state = tevent_req_data(
2067                 req, struct cli_ntcreate1_state);
2068         NTSTATUS status;
2069
2070         if (tevent_req_is_nterror(req, &status)) {
2071                 return status;
2072         }
2073         *pfnum = state->fnum;
2074         if (cr != NULL) {
2075                 *cr = state->cr;
2076         }
2077         return NT_STATUS_OK;
2078 }
2079
2080 struct cli_ntcreate_state {
2081         NTSTATUS (*recv)(struct tevent_req *req, uint16_t *fnum,
2082                          struct smb_create_returns *cr);
2083         struct smb_create_returns cr;
2084         uint16_t fnum;
2085         struct tevent_req *subreq;
2086 };
2087
2088 static void cli_ntcreate_done(struct tevent_req *subreq);
2089 static bool cli_ntcreate_cancel(struct tevent_req *req);
2090
2091 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
2092                                      struct tevent_context *ev,
2093                                      struct cli_state *cli,
2094                                      const char *fname,
2095                                      uint32_t create_flags,
2096                                      uint32_t desired_access,
2097                                      uint32_t file_attributes,
2098                                      uint32_t share_access,
2099                                      uint32_t create_disposition,
2100                                      uint32_t create_options,
2101                                      uint8_t security_flags)
2102 {
2103         struct tevent_req *req, *subreq;
2104         struct cli_ntcreate_state *state;
2105
2106         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2107         if (req == NULL) {
2108                 return NULL;
2109         }
2110
2111         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2112                 state->recv = cli_smb2_create_fnum_recv;
2113
2114                 if (cli->use_oplocks) {
2115                         create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2116                 }
2117
2118                 subreq = cli_smb2_create_fnum_send(
2119                         state, ev, cli, fname, create_flags, desired_access,
2120                         file_attributes, share_access, create_disposition,
2121                         create_options);
2122         } else {
2123                 state->recv = cli_ntcreate1_recv;
2124                 subreq = cli_ntcreate1_send(
2125                         state, ev, cli, fname, create_flags, desired_access,
2126                         file_attributes, share_access, create_disposition,
2127                         create_options, security_flags);
2128         }
2129         if (tevent_req_nomem(subreq, req)) {
2130                 return tevent_req_post(req, ev);
2131         }
2132         tevent_req_set_callback(subreq, cli_ntcreate_done, req);
2133
2134         state->subreq = subreq;
2135         tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2136
2137         return req;
2138 }
2139
2140 static void cli_ntcreate_done(struct tevent_req *subreq)
2141 {
2142         struct tevent_req *req = tevent_req_callback_data(
2143                 subreq, struct tevent_req);
2144         struct cli_ntcreate_state *state = tevent_req_data(
2145                 req, struct cli_ntcreate_state);
2146         NTSTATUS status;
2147
2148         status = state->recv(subreq, &state->fnum, &state->cr);
2149         TALLOC_FREE(subreq);
2150         if (tevent_req_nterror(req, status)) {
2151                 return;
2152         }
2153         tevent_req_done(req);
2154 }
2155
2156 static bool cli_ntcreate_cancel(struct tevent_req *req)
2157 {
2158         struct cli_ntcreate_state *state = tevent_req_data(
2159                 req, struct cli_ntcreate_state);
2160         return tevent_req_cancel(state->subreq);
2161 }
2162
2163 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2164                            struct smb_create_returns *cr)
2165 {
2166         struct cli_ntcreate_state *state = tevent_req_data(
2167                 req, struct cli_ntcreate_state);
2168         NTSTATUS status;
2169
2170         if (tevent_req_is_nterror(req, &status)) {
2171                 return status;
2172         }
2173         if (fnum != NULL) {
2174                 *fnum = state->fnum;
2175         }
2176         if (cr != NULL) {
2177                 *cr = state->cr;
2178         }
2179         return NT_STATUS_OK;
2180 }
2181
2182 NTSTATUS cli_ntcreate(struct cli_state *cli,
2183                       const char *fname,
2184                       uint32_t CreatFlags,
2185                       uint32_t DesiredAccess,
2186                       uint32_t FileAttributes,
2187                       uint32_t ShareAccess,
2188                       uint32_t CreateDisposition,
2189                       uint32_t CreateOptions,
2190                       uint8_t SecurityFlags,
2191                       uint16_t *pfid,
2192                       struct smb_create_returns *cr)
2193 {
2194         TALLOC_CTX *frame = talloc_stackframe();
2195         struct tevent_context *ev;
2196         struct tevent_req *req;
2197         NTSTATUS status = NT_STATUS_NO_MEMORY;
2198
2199         if (smbXcli_conn_has_async_calls(cli->conn)) {
2200                 /*
2201                  * Can't use sync call while an async call is in flight
2202                  */
2203                 status = NT_STATUS_INVALID_PARAMETER;
2204                 goto fail;
2205         }
2206
2207         ev = samba_tevent_context_init(frame);
2208         if (ev == NULL) {
2209                 goto fail;
2210         }
2211
2212         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2213                                 DesiredAccess, FileAttributes, ShareAccess,
2214                                 CreateDisposition, CreateOptions,
2215                                 SecurityFlags);
2216         if (req == NULL) {
2217                 goto fail;
2218         }
2219
2220         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2221                 goto fail;
2222         }
2223
2224         status = cli_ntcreate_recv(req, pfid, cr);
2225  fail:
2226         TALLOC_FREE(frame);
2227         return status;
2228 }
2229
2230 struct cli_nttrans_create_state {
2231         uint16_t fnum;
2232         struct smb_create_returns cr;
2233 };
2234
2235 static void cli_nttrans_create_done(struct tevent_req *subreq);
2236
2237 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2238                                            struct tevent_context *ev,
2239                                            struct cli_state *cli,
2240                                            const char *fname,
2241                                            uint32_t CreatFlags,
2242                                            uint32_t DesiredAccess,
2243                                            uint32_t FileAttributes,
2244                                            uint32_t ShareAccess,
2245                                            uint32_t CreateDisposition,
2246                                            uint32_t CreateOptions,
2247                                            uint8_t SecurityFlags,
2248                                            struct security_descriptor *secdesc,
2249                                            struct ea_struct *eas,
2250                                            int num_eas)
2251 {
2252         struct tevent_req *req, *subreq;
2253         struct cli_nttrans_create_state *state;
2254         uint8_t *param;
2255         uint8_t *secdesc_buf;
2256         size_t secdesc_len;
2257         NTSTATUS status;
2258         size_t converted_len;
2259         uint16_t additional_flags2 = 0;
2260
2261         req = tevent_req_create(mem_ctx,
2262                                 &state, struct cli_nttrans_create_state);
2263         if (req == NULL) {
2264                 return NULL;
2265         }
2266
2267         if (secdesc != NULL) {
2268                 status = marshall_sec_desc(talloc_tos(), secdesc,
2269                                            &secdesc_buf, &secdesc_len);
2270                 if (tevent_req_nterror(req, status)) {
2271                         DEBUG(10, ("marshall_sec_desc failed: %s\n",
2272                                    nt_errstr(status)));
2273                         return tevent_req_post(req, ev);
2274                 }
2275         } else {
2276                 secdesc_buf = NULL;
2277                 secdesc_len = 0;
2278         }
2279
2280         if (num_eas != 0) {
2281                 /*
2282                  * TODO ;-)
2283                  */
2284                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2285                 return tevent_req_post(req, ev);
2286         }
2287
2288         param = talloc_array(state, uint8_t, 53);
2289         if (tevent_req_nomem(param, req)) {
2290                 return tevent_req_post(req, ev);
2291         }
2292
2293         param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2294                                       fname, strlen(fname),
2295                                       &converted_len);
2296         if (tevent_req_nomem(param, req)) {
2297                 return tevent_req_post(req, ev);
2298         }
2299
2300         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2301                 additional_flags2 = FLAGS2_REPARSE_PATH;
2302         }
2303
2304         SIVAL(param, 0, CreatFlags);
2305         SIVAL(param, 4, 0x0);   /* RootDirectoryFid */
2306         SIVAL(param, 8, DesiredAccess);
2307         SIVAL(param, 12, 0x0);  /* AllocationSize */
2308         SIVAL(param, 16, 0x0);  /* AllocationSize */
2309         SIVAL(param, 20, FileAttributes);
2310         SIVAL(param, 24, ShareAccess);
2311         SIVAL(param, 28, CreateDisposition);
2312         SIVAL(param, 32, CreateOptions |
2313                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2314         SIVAL(param, 36, secdesc_len);
2315         SIVAL(param, 40, 0);     /* EA length*/
2316         SIVAL(param, 44, converted_len);
2317         SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2318         SCVAL(param, 52, SecurityFlags);
2319
2320         subreq = cli_trans_send(state, ev, cli,
2321                                 additional_flags2, /* additional_flags2 */
2322                                 SMBnttrans,
2323                                 NULL, -1, /* name, fid */
2324                                 NT_TRANSACT_CREATE, 0,
2325                                 NULL, 0, 0, /* setup */
2326                                 param, talloc_get_size(param), 128, /* param */
2327                                 secdesc_buf, secdesc_len, 0); /* data */
2328         if (tevent_req_nomem(subreq, req)) {
2329                 return tevent_req_post(req, ev);
2330         }
2331         tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2332         return req;
2333 }
2334
2335 static void cli_nttrans_create_done(struct tevent_req *subreq)
2336 {
2337         struct tevent_req *req = tevent_req_callback_data(
2338                 subreq, struct tevent_req);
2339         struct cli_nttrans_create_state *state = tevent_req_data(
2340                 req, struct cli_nttrans_create_state);
2341         uint8_t *param;
2342         uint32_t num_param;
2343         NTSTATUS status;
2344
2345         status = cli_trans_recv(subreq, talloc_tos(), NULL,
2346                                 NULL, 0, NULL, /* rsetup */
2347                                 &param, 69, &num_param,
2348                                 NULL, 0, NULL);
2349         if (tevent_req_nterror(req, status)) {
2350                 return;
2351         }
2352         state->cr.oplock_level = CVAL(param, 0);
2353         state->fnum = SVAL(param, 2);
2354         state->cr.create_action = IVAL(param, 4);
2355         state->cr.creation_time = BVAL(param, 12);
2356         state->cr.last_access_time = BVAL(param, 20);
2357         state->cr.last_write_time = BVAL(param, 28);
2358         state->cr.change_time   = BVAL(param, 36);
2359         state->cr.file_attributes = IVAL(param, 44);
2360         state->cr.allocation_size = BVAL(param, 48);
2361         state->cr.end_of_file   = BVAL(param, 56);
2362
2363         TALLOC_FREE(param);
2364         tevent_req_done(req);
2365 }
2366
2367 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2368                         uint16_t *fnum,
2369                         struct smb_create_returns *cr)
2370 {
2371         struct cli_nttrans_create_state *state = tevent_req_data(
2372                 req, struct cli_nttrans_create_state);
2373         NTSTATUS status;
2374
2375         if (tevent_req_is_nterror(req, &status)) {
2376                 return status;
2377         }
2378         *fnum = state->fnum;
2379         if (cr != NULL) {
2380                 *cr = state->cr;
2381         }
2382         return NT_STATUS_OK;
2383 }
2384
2385 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2386                             const char *fname,
2387                             uint32_t CreatFlags,
2388                             uint32_t DesiredAccess,
2389                             uint32_t FileAttributes,
2390                             uint32_t ShareAccess,
2391                             uint32_t CreateDisposition,
2392                             uint32_t CreateOptions,
2393                             uint8_t SecurityFlags,
2394                             struct security_descriptor *secdesc,
2395                             struct ea_struct *eas,
2396                             int num_eas,
2397                             uint16_t *pfid,
2398                             struct smb_create_returns *cr)
2399 {
2400         TALLOC_CTX *frame = talloc_stackframe();
2401         struct tevent_context *ev;
2402         struct tevent_req *req;
2403         NTSTATUS status = NT_STATUS_NO_MEMORY;
2404
2405         if (smbXcli_conn_has_async_calls(cli->conn)) {
2406                 /*
2407                  * Can't use sync call while an async call is in flight
2408                  */
2409                 status = NT_STATUS_INVALID_PARAMETER;
2410                 goto fail;
2411         }
2412         ev = samba_tevent_context_init(frame);
2413         if (ev == NULL) {
2414                 goto fail;
2415         }
2416         req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2417                                       DesiredAccess, FileAttributes,
2418                                       ShareAccess, CreateDisposition,
2419                                       CreateOptions, SecurityFlags,
2420                                       secdesc, eas, num_eas);
2421         if (req == NULL) {
2422                 goto fail;
2423         }
2424         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2425                 goto fail;
2426         }
2427         status = cli_nttrans_create_recv(req, pfid, cr);
2428  fail:
2429         TALLOC_FREE(frame);
2430         return status;
2431 }
2432
2433 /****************************************************************************
2434  Open a file
2435  WARNING: if you open with O_WRONLY then getattrE won't work!
2436 ****************************************************************************/
2437
2438 struct cli_openx_state {
2439         const char *fname;
2440         uint16_t vwv[15];
2441         uint16_t fnum;
2442         struct iovec bytes;
2443 };
2444
2445 static void cli_openx_done(struct tevent_req *subreq);
2446
2447 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2448                                    struct tevent_context *ev,
2449                                    struct cli_state *cli, const char *fname,
2450                                    int flags, int share_mode,
2451                                    struct tevent_req **psmbreq)
2452 {
2453         struct tevent_req *req, *subreq;
2454         struct cli_openx_state *state;
2455         unsigned openfn;
2456         unsigned accessmode;
2457         uint8_t additional_flags;
2458         uint16_t additional_flags2 = 0;
2459         uint8_t *bytes;
2460
2461         req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2462         if (req == NULL) {
2463                 return NULL;
2464         }
2465
2466         openfn = 0;
2467         if (flags & O_CREAT) {
2468                 openfn |= (1<<4);
2469         }
2470         if (!(flags & O_EXCL)) {
2471                 if (flags & O_TRUNC)
2472                         openfn |= (1<<1);
2473                 else
2474                         openfn |= (1<<0);
2475         }
2476
2477         accessmode = (share_mode<<4);
2478
2479         if ((flags & O_ACCMODE) == O_RDWR) {
2480                 accessmode |= 2;
2481         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2482                 accessmode |= 1;
2483         }
2484
2485 #if defined(O_SYNC)
2486         if ((flags & O_SYNC) == O_SYNC) {
2487                 accessmode |= (1<<14);
2488         }
2489 #endif /* O_SYNC */
2490
2491         if (share_mode == DENY_FCB) {
2492                 accessmode = 0xFF;
2493         }
2494
2495         SCVAL(state->vwv + 0, 0, 0xFF);
2496         SCVAL(state->vwv + 0, 1, 0);
2497         SSVAL(state->vwv + 1, 0, 0);
2498         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
2499         SSVAL(state->vwv + 3, 0, accessmode);
2500         SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2501         SSVAL(state->vwv + 5, 0, 0);
2502         SIVAL(state->vwv + 6, 0, 0);
2503         SSVAL(state->vwv + 8, 0, openfn);
2504         SIVAL(state->vwv + 9, 0, 0);
2505         SIVAL(state->vwv + 11, 0, 0);
2506         SIVAL(state->vwv + 13, 0, 0);
2507
2508         additional_flags = 0;
2509
2510         if (cli->use_oplocks) {
2511                 /* if using oplocks then ask for a batch oplock via
2512                    core and extended methods */
2513                 additional_flags =
2514                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2515                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2516         }
2517
2518         bytes = talloc_array(state, uint8_t, 0);
2519         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2520                                    strlen(fname)+1, NULL);
2521
2522         if (tevent_req_nomem(bytes, req)) {
2523                 return tevent_req_post(req, ev);
2524         }
2525
2526         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2527                 additional_flags2 = FLAGS2_REPARSE_PATH;
2528         }
2529
2530         state->bytes.iov_base = (void *)bytes;
2531         state->bytes.iov_len = talloc_get_size(bytes);
2532
2533         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2534                         additional_flags2, 15, state->vwv, 1, &state->bytes);
2535         if (subreq == NULL) {
2536                 TALLOC_FREE(req);
2537                 return NULL;
2538         }
2539         tevent_req_set_callback(subreq, cli_openx_done, req);
2540         *psmbreq = subreq;
2541         return req;
2542 }
2543
2544 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2545                                  struct cli_state *cli, const char *fname,
2546                                  int flags, int share_mode)
2547 {
2548         struct tevent_req *req, *subreq;
2549         NTSTATUS status;
2550
2551         req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
2552                               &subreq);
2553         if (req == NULL) {
2554                 return NULL;
2555         }
2556
2557         status = smb1cli_req_chain_submit(&subreq, 1);
2558         if (tevent_req_nterror(req, status)) {
2559                 return tevent_req_post(req, ev);
2560         }
2561         return req;
2562 }
2563
2564 static void cli_openx_done(struct tevent_req *subreq)
2565 {
2566         struct tevent_req *req = tevent_req_callback_data(
2567                 subreq, struct tevent_req);
2568         struct cli_openx_state *state = tevent_req_data(
2569                 req, struct cli_openx_state);
2570         uint8_t wct;
2571         uint16_t *vwv;
2572         NTSTATUS status;
2573
2574         status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
2575                               NULL);
2576         TALLOC_FREE(subreq);
2577         if (tevent_req_nterror(req, status)) {
2578                 return;
2579         }
2580         state->fnum = SVAL(vwv+2, 0);
2581         tevent_req_done(req);
2582 }
2583
2584 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2585 {
2586         struct cli_openx_state *state = tevent_req_data(
2587                 req, struct cli_openx_state);
2588         NTSTATUS status;
2589
2590         if (tevent_req_is_nterror(req, &status)) {
2591                 return status;
2592         }
2593         *pfnum = state->fnum;
2594         return NT_STATUS_OK;
2595 }
2596
2597 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
2598              int share_mode, uint16_t *pfnum)
2599 {
2600         TALLOC_CTX *frame = talloc_stackframe();
2601         struct tevent_context *ev;
2602         struct tevent_req *req;
2603         NTSTATUS status = NT_STATUS_NO_MEMORY;
2604
2605         if (smbXcli_conn_has_async_calls(cli->conn)) {
2606                 /*
2607                  * Can't use sync call while an async call is in flight
2608                  */
2609                 status = NT_STATUS_INVALID_PARAMETER;
2610                 goto fail;
2611         }
2612
2613         ev = samba_tevent_context_init(frame);
2614         if (ev == NULL) {
2615                 goto fail;
2616         }
2617
2618         req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
2619         if (req == NULL) {
2620                 goto fail;
2621         }
2622
2623         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2624                 goto fail;
2625         }
2626
2627         status = cli_openx_recv(req, pfnum);
2628  fail:
2629         TALLOC_FREE(frame);
2630         return status;
2631 }
2632 /****************************************************************************
2633  Synchronous wrapper function that does an NtCreateX open by preference
2634  and falls back to openX if this fails.
2635 ****************************************************************************/
2636
2637 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2638                         int share_mode_in, uint16_t *pfnum)
2639 {
2640         NTSTATUS status;
2641         unsigned int openfn = 0;
2642         unsigned int dos_deny = 0;
2643         uint32_t access_mask, share_mode, create_disposition, create_options;
2644         struct smb_create_returns cr;
2645
2646         /* Do the initial mapping into OpenX parameters. */
2647         if (flags & O_CREAT) {
2648                 openfn |= (1<<4);
2649         }
2650         if (!(flags & O_EXCL)) {
2651                 if (flags & O_TRUNC)
2652                         openfn |= (1<<1);
2653                 else
2654                         openfn |= (1<<0);
2655         }
2656
2657         dos_deny = (share_mode_in<<4);
2658
2659         if ((flags & O_ACCMODE) == O_RDWR) {
2660                 dos_deny |= 2;
2661         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2662                 dos_deny |= 1;
2663         }
2664
2665 #if defined(O_SYNC)
2666         if ((flags & O_SYNC) == O_SYNC) {
2667                 dos_deny |= (1<<14);
2668         }
2669 #endif /* O_SYNC */
2670
2671         if (share_mode_in == DENY_FCB) {
2672                 dos_deny = 0xFF;
2673         }
2674
2675 #if 0
2676         /* Hmmm. This is what I think the above code
2677            should look like if it's using the constants
2678            we #define. JRA. */
2679
2680         if (flags & O_CREAT) {
2681                 openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
2682         }
2683         if (!(flags & O_EXCL)) {
2684                 if (flags & O_TRUNC)
2685                         openfn |= OPENX_FILE_EXISTS_TRUNCATE;
2686                 else
2687                         openfn |= OPENX_FILE_EXISTS_OPEN;
2688         }
2689
2690         dos_deny = SET_DENY_MODE(share_mode_in);
2691
2692         if ((flags & O_ACCMODE) == O_RDWR) {
2693                 dos_deny |= DOS_OPEN_RDWR;
2694         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2695                 dos_deny |= DOS_OPEN_WRONLY;
2696         }
2697
2698 #if defined(O_SYNC)
2699         if ((flags & O_SYNC) == O_SYNC) {
2700                 dos_deny |= FILE_SYNC_OPENMODE;
2701         }
2702 #endif /* O_SYNC */
2703
2704         if (share_mode_in == DENY_FCB) {
2705                 dos_deny = 0xFF;
2706         }
2707 #endif
2708
2709         if (!map_open_params_to_ntcreate(fname, dos_deny,
2710                                         openfn, &access_mask,
2711                                         &share_mode, &create_disposition,
2712                                         &create_options, NULL)) {
2713                 goto try_openx;
2714         }
2715
2716         status = cli_ntcreate(cli,
2717                                 fname,
2718                                 0,
2719                                 access_mask,
2720                                 0,
2721                                 share_mode,
2722                                 create_disposition,
2723                                 create_options,
2724                                 0,
2725                                 pfnum,
2726                                 &cr);
2727
2728         /* Try and cope will all varients of "we don't do this call"
2729            and fall back to openX. */
2730
2731         if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
2732                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
2733                         NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
2734                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
2735                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
2736                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
2737                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
2738                         NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
2739                         NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
2740                 goto try_openx;
2741         }
2742
2743         if (NT_STATUS_IS_OK(status) &&
2744             (create_options & FILE_NON_DIRECTORY_FILE) &&
2745             (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
2746         {
2747                 /*
2748                  * Some (broken) servers return a valid handle
2749                  * for directories even if FILE_NON_DIRECTORY_FILE
2750                  * is set. Just close the handle and set the
2751                  * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
2752                  */
2753                 status = cli_close(cli, *pfnum);
2754                 if (!NT_STATUS_IS_OK(status)) {
2755                         return status;
2756                 }
2757                 status = NT_STATUS_FILE_IS_A_DIRECTORY;
2758                 /* Set this so libsmbclient can retrieve it. */
2759                 cli->raw_status = status;
2760         }
2761
2762         return status;
2763
2764   try_openx:
2765
2766         return cli_openx(cli, fname, flags, share_mode_in, pfnum);
2767 }
2768
2769 /****************************************************************************
2770  Close a file.
2771 ****************************************************************************/
2772
2773 struct cli_smb1_close_state {
2774         uint16_t vwv[3];
2775 };
2776
2777 static void cli_smb1_close_done(struct tevent_req *subreq);
2778
2779 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
2780                                 struct tevent_context *ev,
2781                                 struct cli_state *cli,
2782                                 uint16_t fnum,
2783                                 struct tevent_req **psubreq)
2784 {
2785         struct tevent_req *req, *subreq;
2786         struct cli_smb1_close_state *state;
2787
2788         req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
2789         if (req == NULL) {
2790                 return NULL;
2791         }
2792
2793         SSVAL(state->vwv+0, 0, fnum);
2794         SIVALS(state->vwv+1, 0, -1);
2795
2796         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
2797                                 3, state->vwv, 0, NULL);
2798         if (subreq == NULL) {
2799                 TALLOC_FREE(req);
2800                 return NULL;
2801         }
2802         tevent_req_set_callback(subreq, cli_smb1_close_done, req);
2803         *psubreq = subreq;
2804         return req;
2805 }
2806
2807 static void cli_smb1_close_done(struct tevent_req *subreq)
2808 {
2809         struct tevent_req *req = tevent_req_callback_data(
2810                 subreq, struct tevent_req);
2811         NTSTATUS status;
2812
2813         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2814         TALLOC_FREE(subreq);
2815         if (tevent_req_nterror(req, status)) {
2816                 return;
2817         }
2818         tevent_req_done(req);
2819 }
2820
2821 struct cli_close_state {
2822         int dummy;
2823 };
2824
2825 static void cli_close_done(struct tevent_req *subreq);
2826
2827 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2828                                 struct tevent_context *ev,
2829                                 struct cli_state *cli,
2830                                 uint16_t fnum)
2831 {
2832         struct tevent_req *req, *subreq;
2833         struct cli_close_state *state;
2834         NTSTATUS status;
2835
2836         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2837         if (req == NULL) {
2838                 return NULL;
2839         }
2840
2841         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2842                 subreq = cli_smb2_close_fnum_send(state,
2843                                                 ev,
2844                                                 cli,
2845                                                 fnum);
2846                 if (tevent_req_nomem(subreq, req)) {
2847                         return tevent_req_post(req, ev);
2848                 }
2849         } else {
2850                 struct tevent_req *ch_req = NULL;
2851                 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
2852                 if (tevent_req_nomem(subreq, req)) {
2853                         return tevent_req_post(req, ev);
2854                 }
2855                 status = smb1cli_req_chain_submit(&ch_req, 1);
2856                 if (tevent_req_nterror(req, status)) {
2857                         return tevent_req_post(req, ev);
2858                 }
2859         }
2860
2861         tevent_req_set_callback(subreq, cli_close_done, req);
2862         return req;
2863 }
2864
2865 static void cli_close_done(struct tevent_req *subreq)
2866 {
2867         struct tevent_req *req = tevent_req_callback_data(
2868                 subreq, struct tevent_req);
2869         NTSTATUS status = NT_STATUS_OK;
2870         bool err = tevent_req_is_nterror(subreq, &status);
2871
2872         TALLOC_FREE(subreq);
2873         if (err) {
2874                 tevent_req_nterror(req, status);
2875                 return;
2876         }
2877         tevent_req_done(req);
2878 }
2879
2880 NTSTATUS cli_close_recv(struct tevent_req *req)
2881 {
2882         return tevent_req_simple_recv_ntstatus(req);
2883 }
2884
2885 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2886 {
2887         TALLOC_CTX *frame = NULL;
2888         struct tevent_context *ev;
2889         struct tevent_req *req;
2890         NTSTATUS status = NT_STATUS_OK;
2891
2892         frame = talloc_stackframe();
2893
2894         if (smbXcli_conn_has_async_calls(cli->conn)) {
2895                 /*
2896                  * Can't use sync call while an async call is in flight
2897                  */
2898                 status = NT_STATUS_INVALID_PARAMETER;
2899                 goto fail;
2900         }
2901
2902         ev = samba_tevent_context_init(frame);
2903         if (ev == NULL) {
2904                 status = NT_STATUS_NO_MEMORY;
2905                 goto fail;
2906         }
2907
2908         req = cli_close_send(frame, ev, cli, fnum);
2909         if (req == NULL) {
2910                 status = NT_STATUS_NO_MEMORY;
2911                 goto fail;
2912         }
2913
2914         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2915                 goto fail;
2916         }
2917
2918         status = cli_close_recv(req);
2919  fail:
2920         TALLOC_FREE(frame);
2921         return status;
2922 }
2923
2924 /****************************************************************************
2925  Truncate a file to a specified size
2926 ****************************************************************************/
2927
2928 struct ftrunc_state {
2929         uint16_t setup;
2930         uint8_t param[6];
2931         uint8_t data[8];
2932 };
2933
2934 static void cli_ftruncate_done(struct tevent_req *subreq)
2935 {
2936         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2937                                          NULL, 0, NULL, NULL, 0, NULL);
2938         tevent_req_simple_finish_ntstatus(subreq, status);
2939 }
2940
2941 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2942                                         struct tevent_context *ev,
2943                                         struct cli_state *cli,
2944                                         uint16_t fnum,
2945                                         uint64_t size)
2946 {
2947         struct tevent_req *req = NULL, *subreq = NULL;
2948         struct ftrunc_state *state = NULL;
2949
2950         req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2951         if (req == NULL) {
2952                 return NULL;
2953         }
2954
2955         /* Setup setup word. */
2956         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2957
2958         /* Setup param array. */
2959         SSVAL(state->param,0,fnum);
2960         SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2961         SSVAL(state->param,4,0);
2962
2963         /* Setup data array. */
2964         SBVAL(state->data, 0, size);
2965
2966         subreq = cli_trans_send(state,                  /* mem ctx. */
2967                                 ev,                     /* event ctx. */
2968                                 cli,                    /* cli_state. */
2969                                 0,                      /* additional_flags2 */
2970                                 SMBtrans2,              /* cmd. */
2971                                 NULL,                   /* pipe name. */
2972                                 -1,                     /* fid. */
2973                                 0,                      /* function. */
2974                                 0,                      /* flags. */
2975                                 &state->setup,          /* setup. */
2976                                 1,                      /* num setup uint16_t words. */
2977                                 0,                      /* max returned setup. */
2978                                 state->param,           /* param. */
2979                                 6,                      /* num param. */
2980                                 2,                      /* max returned param. */
2981                                 state->data,            /* data. */
2982                                 8,                      /* num data. */
2983                                 0);                     /* max returned data. */
2984
2985         if (tevent_req_nomem(subreq, req)) {
2986                 return tevent_req_post(req, ev);
2987         }
2988         tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2989         return req;
2990 }
2991
2992 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2993 {
2994         return tevent_req_simple_recv_ntstatus(req);
2995 }
2996
2997 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2998 {
2999         TALLOC_CTX *frame = NULL;
3000         struct tevent_context *ev = NULL;
3001         struct tevent_req *req = NULL;
3002         NTSTATUS status = NT_STATUS_OK;
3003
3004         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3005                 return cli_smb2_ftruncate(cli, fnum, size);
3006         }
3007
3008         frame = talloc_stackframe();
3009
3010         if (smbXcli_conn_has_async_calls(cli->conn)) {
3011                 /*
3012                  * Can't use sync call while an async call is in flight
3013                  */
3014                 status = NT_STATUS_INVALID_PARAMETER;
3015                 goto fail;
3016         }
3017
3018         ev = samba_tevent_context_init(frame);
3019         if (ev == NULL) {
3020                 status = NT_STATUS_NO_MEMORY;
3021                 goto fail;
3022         }
3023
3024         req = cli_ftruncate_send(frame,
3025                                 ev,
3026                                 cli,
3027                                 fnum,
3028                                 size);
3029         if (req == NULL) {
3030                 status = NT_STATUS_NO_MEMORY;
3031                 goto fail;
3032         }
3033
3034         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3035                 goto fail;
3036         }
3037
3038         status = cli_ftruncate_recv(req);
3039
3040  fail:
3041         TALLOC_FREE(frame);
3042         return status;
3043 }
3044
3045 /****************************************************************************
3046  send a lock with a specified locktype
3047  this is used for testing LOCKING_ANDX_CANCEL_LOCK
3048 ****************************************************************************/
3049
3050 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
3051                       uint32_t offset, uint32_t len,
3052                       int timeout, unsigned char locktype)
3053 {
3054         uint16_t vwv[8];
3055         uint8_t bytes[10];
3056         NTSTATUS status;
3057         unsigned int set_timeout = 0;
3058         unsigned int saved_timeout = 0;
3059
3060         SCVAL(vwv + 0, 0, 0xff);
3061         SCVAL(vwv + 0, 1, 0);
3062         SSVAL(vwv + 1, 0, 0);
3063         SSVAL(vwv + 2, 0, fnum);
3064         SCVAL(vwv + 3, 0, locktype);
3065         SCVAL(vwv + 3, 1, 0);
3066         SIVALS(vwv + 4, 0, timeout);
3067         SSVAL(vwv + 6, 0, 0);
3068         SSVAL(vwv + 7, 0, 1);
3069
3070         SSVAL(bytes, 0, cli_getpid(cli));
3071         SIVAL(bytes, 2, offset);
3072         SIVAL(bytes, 6, len);
3073
3074         if (timeout != 0) {
3075                 if (timeout == -1) {
3076                         set_timeout = 0x7FFFFFFF;
3077                 } else {
3078                         set_timeout = timeout + 2*1000;
3079                 }
3080                 saved_timeout = cli_set_timeout(cli, set_timeout);
3081         }
3082
3083         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3084                          10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3085
3086         if (saved_timeout != 0) {
3087                 cli_set_timeout(cli, saved_timeout);
3088         }
3089
3090         return status;
3091 }
3092
3093 /****************************************************************************
3094  Lock a file.
3095  note that timeout is in units of 2 milliseconds
3096 ****************************************************************************/
3097
3098 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
3099                   uint32_t offset, uint32_t len, int timeout,
3100                   enum brl_type lock_type)
3101 {
3102         NTSTATUS status;
3103
3104         status = cli_locktype(cli, fnum, offset, len, timeout,
3105                               (lock_type == READ_LOCK? 1 : 0));
3106         return status;
3107 }
3108
3109 /****************************************************************************
3110  Unlock a file.
3111 ****************************************************************************/
3112
3113 struct cli_unlock_state {
3114         uint16_t vwv[8];
3115         uint8_t data[10];
3116 };
3117
3118 static void cli_unlock_done(struct tevent_req *subreq);
3119
3120 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3121                                 struct tevent_context *ev,
3122                                 struct cli_state *cli,
3123                                 uint16_t fnum,
3124                                 uint64_t offset,
3125                                 uint64_t len)
3126
3127 {
3128         struct tevent_req *req = NULL, *subreq = NULL;
3129         struct cli_unlock_state *state = NULL;
3130         uint8_t additional_flags = 0;
3131
3132         req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3133         if (req == NULL) {
3134                 return NULL;
3135         }
3136
3137         SCVAL(state->vwv+0, 0, 0xFF);
3138         SSVAL(state->vwv+2, 0, fnum);
3139         SCVAL(state->vwv+3, 0, 0);
3140         SIVALS(state->vwv+4, 0, 0);
3141         SSVAL(state->vwv+6, 0, 1);
3142         SSVAL(state->vwv+7, 0, 0);
3143
3144         SSVAL(state->data, 0, cli_getpid(cli));
3145         SIVAL(state->data, 2, offset);
3146         SIVAL(state->data, 6, len);
3147
3148         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3149                                 8, state->vwv, 10, state->data);
3150         if (tevent_req_nomem(subreq, req)) {
3151                 return tevent_req_post(req, ev);
3152         }
3153         tevent_req_set_callback(subreq, cli_unlock_done, req);
3154         return req;
3155 }
3156
3157 static void cli_unlock_done(struct tevent_req *subreq)
3158 {
3159         struct tevent_req *req = tevent_req_callback_data(
3160                                 subreq, struct tevent_req);
3161         NTSTATUS status;
3162
3163         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3164         TALLOC_FREE(subreq);
3165         if (tevent_req_nterror(req, status)) {
3166                 return;
3167         }
3168         tevent_req_done(req);
3169 }
3170
3171 NTSTATUS cli_unlock_recv(struct tevent_req *req)
3172 {
3173         return tevent_req_simple_recv_ntstatus(req);
3174 }
3175
3176 NTSTATUS cli_unlock(struct cli_state *cli,
3177                         uint16_t fnum,
3178                         uint32_t offset,
3179                         uint32_t len)
3180 {
3181         TALLOC_CTX *frame = talloc_stackframe();
3182         struct tevent_context *ev;
3183         struct tevent_req *req;
3184         NTSTATUS status = NT_STATUS_OK;
3185
3186         if (smbXcli_conn_has_async_calls(cli->conn)) {
3187                 /*
3188                  * Can't use sync call while an async call is in flight
3189                  */
3190                 status = NT_STATUS_INVALID_PARAMETER;
3191                 goto fail;
3192         }
3193
3194         ev = samba_tevent_context_init(frame);
3195         if (ev == NULL) {
3196                 status = NT_STATUS_NO_MEMORY;
3197                 goto fail;
3198         }
3199
3200         req = cli_unlock_send(frame, ev, cli,
3201                         fnum, offset, len);
3202         if (req == NULL) {
3203                 status = NT_STATUS_NO_MEMORY;
3204                 goto fail;
3205         }
3206
3207         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3208                 goto fail;
3209         }
3210
3211         status = cli_unlock_recv(req);
3212
3213  fail:
3214         TALLOC_FREE(frame);
3215         return status;
3216 }
3217
3218 /****************************************************************************
3219  Lock a file with 64 bit offsets.
3220 ****************************************************************************/
3221
3222 NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
3223                     uint64_t offset, uint64_t len, int timeout,
3224                     enum brl_type lock_type)
3225 {
3226         uint16_t vwv[8];
3227         uint8_t bytes[20];
3228         unsigned int set_timeout = 0;
3229         unsigned int saved_timeout = 0;
3230         int ltype;
3231         NTSTATUS status;
3232
3233         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3234                 return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
3235         }
3236
3237         ltype = (lock_type == READ_LOCK? 1 : 0);
3238         ltype |= LOCKING_ANDX_LARGE_FILES;
3239
3240         SCVAL(vwv + 0, 0, 0xff);
3241         SCVAL(vwv + 0, 1, 0);
3242         SSVAL(vwv + 1, 0, 0);
3243         SSVAL(vwv + 2, 0, fnum);
3244         SCVAL(vwv + 3, 0, ltype);
3245         SCVAL(vwv + 3, 1, 0);
3246         SIVALS(vwv + 4, 0, timeout);
3247         SSVAL(vwv + 6, 0, 0);
3248         SSVAL(vwv + 7, 0, 1);
3249
3250         SIVAL(bytes, 0, cli_getpid(cli));
3251         SOFF_T_R(bytes, 4, offset);
3252         SOFF_T_R(bytes, 12, len);
3253
3254         if (timeout != 0) {
3255                 if (timeout == -1) {
3256                         set_timeout = 0x7FFFFFFF;
3257                 } else {
3258                         set_timeout = timeout + 2*1000;
3259                 }
3260                 saved_timeout = cli_set_timeout(cli, set_timeout);
3261         }
3262
3263         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3264                          20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3265
3266         if (saved_timeout != 0) {
3267                 cli_set_timeout(cli, saved_timeout);
3268         }
3269
3270         return status;
3271 }
3272
3273 /****************************************************************************
3274  Unlock a file with 64 bit offsets.
3275 ****************************************************************************/
3276
3277 struct cli_unlock64_state {
3278         uint16_t vwv[8];
3279         uint8_t data[20];
3280 };
3281
3282 static void cli_unlock64_done(struct tevent_req *subreq);
3283
3284 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
3285                                 struct tevent_context *ev,
3286                                 struct cli_state *cli,
3287                                 uint16_t fnum,
3288                                 uint64_t offset,
3289                                 uint64_t len)
3290
3291 {
3292         struct tevent_req *req = NULL, *subreq = NULL;
3293         struct cli_unlock64_state *state = NULL;
3294         uint8_t additional_flags = 0;
3295
3296         req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
3297         if (req == NULL) {
3298                 return NULL;
3299         }
3300
3301         SCVAL(state->vwv+0, 0, 0xff);
3302         SSVAL(state->vwv+2, 0, fnum);
3303         SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
3304         SIVALS(state->vwv+4, 0, 0);
3305         SSVAL(state->vwv+6, 0, 1);
3306         SSVAL(state->vwv+7, 0, 0);
3307
3308         SIVAL(state->data, 0, cli_getpid(cli));
3309         SOFF_T_R(state->data, 4, offset);
3310         SOFF_T_R(state->data, 12, len);
3311
3312         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3313                                 8, state->vwv, 20, state->data);
3314         if (tevent_req_nomem(subreq, req)) {
3315                 return tevent_req_post(req, ev);
3316         }
3317         tevent_req_set_callback(subreq, cli_unlock64_done, req);
3318         return req;
3319 }
3320
3321 static void cli_unlock64_done(struct tevent_req *subreq)
3322 {
3323         struct tevent_req *req = tevent_req_callback_data(
3324                                 subreq, struct tevent_req);
3325         NTSTATUS status;
3326
3327         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3328         TALLOC_FREE(subreq);
3329         if (tevent_req_nterror(req, status)) {
3330                 return;
3331         }
3332         tevent_req_done(req);
3333 }
3334
3335 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
3336 {
3337         return tevent_req_simple_recv_ntstatus(req);
3338 }
3339
3340 NTSTATUS cli_unlock64(struct cli_state *cli,
3341                                 uint16_t fnum,
3342                                 uint64_t offset,
3343                                 uint64_t len)
3344 {
3345         TALLOC_CTX *frame = talloc_stackframe();
3346         struct tevent_context *ev;
3347         struct tevent_req *req;
3348         NTSTATUS status = NT_STATUS_OK;
3349
3350         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3351                 return cli_unlock(cli, fnum, offset, len);
3352         }
3353
3354         if (smbXcli_conn_has_async_calls(cli->conn)) {
3355                 /*
3356                  * Can't use sync call while an async call is in flight
3357                  */
3358                 status = NT_STATUS_INVALID_PARAMETER;
3359                 goto fail;
3360         }
3361
3362         ev = samba_tevent_context_init(frame);
3363         if (ev == NULL) {
3364                 status = NT_STATUS_NO_MEMORY;
3365                 goto fail;
3366         }
3367
3368         req = cli_unlock64_send(frame, ev, cli,
3369                         fnum, offset, len);
3370         if (req == NULL) {
3371                 status = NT_STATUS_NO_MEMORY;
3372                 goto fail;
3373         }
3374
3375         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3376                 goto fail;
3377         }
3378
3379         status = cli_unlock64_recv(req);
3380
3381  fail:
3382         TALLOC_FREE(frame);
3383         return status;
3384 }
3385
3386 /****************************************************************************
3387  Get/unlock a POSIX lock on a file - internal function.
3388 ****************************************************************************/
3389
3390 struct posix_lock_state {
3391         uint16_t setup;
3392         uint8_t param[4];
3393         uint8_t data[POSIX_LOCK_DATA_SIZE];
3394 };
3395
3396 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3397 {
3398         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3399                                          NULL, 0, NULL, NULL, 0, NULL);
3400         tevent_req_simple_finish_ntstatus(subreq, status);
3401 }
3402
3403 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3404                                         struct tevent_context *ev,
3405                                         struct cli_state *cli,
3406                                         uint16_t fnum,
3407                                         uint64_t offset,
3408                                         uint64_t len,
3409                                         bool wait_lock,
3410                                         enum brl_type lock_type)
3411 {
3412         struct tevent_req *req = NULL, *subreq = NULL;
3413         struct posix_lock_state *state = NULL;
3414
3415         req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3416         if (req == NULL) {
3417                 return NULL;
3418         }
3419
3420         /* Setup setup word. */
3421         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3422
3423         /* Setup param array. */
3424         SSVAL(&state->param, 0, fnum);
3425         SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3426
3427         /* Setup data array. */
3428         switch (lock_type) {
3429                 case READ_LOCK:
3430                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3431                                 POSIX_LOCK_TYPE_READ);
3432                         break;
3433                 case WRITE_LOCK:
3434                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3435                                 POSIX_LOCK_TYPE_WRITE);
3436                         break;
3437                 case UNLOCK_LOCK:
3438                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3439                                 POSIX_LOCK_TYPE_UNLOCK);
3440                         break;
3441                 default:
3442                         return NULL;
3443         }
3444
3445         if (wait_lock) {
3446                 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3447                                 POSIX_LOCK_FLAG_WAIT);
3448         } else {
3449                 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3450                                 POSIX_LOCK_FLAG_NOWAIT);
3451         }
3452
3453         SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3454         SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3455         SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3456
3457         subreq = cli_trans_send(state,                  /* mem ctx. */
3458                                 ev,                     /* event ctx. */
3459                                 cli,                    /* cli_state. */
3460                                 0,                      /* additional_flags2 */
3461                                 SMBtrans2,              /* cmd. */
3462                                 NULL,                   /* pipe name. */
3463                                 -1,                     /* fid. */
3464                                 0,                      /* function. */
3465                                 0,                      /* flags. */
3466                                 &state->setup,          /* setup. */
3467                                 1,                      /* num setup uint16_t words. */
3468                                 0,                      /* max returned setup. */
3469                                 state->param,           /* param. */
3470                                 4,                      /* num param. */
3471                                 2,                      /* max returned param. */
3472                                 state->data,            /* data. */
3473                                 POSIX_LOCK_DATA_SIZE,   /* num data. */
3474                                 0);                     /* max returned data. */
3475
3476         if (tevent_req_nomem(subreq, req)) {
3477                 return tevent_req_post(req, ev);
3478         }
3479         tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3480         return req;
3481 }
3482
3483 /****************************************************************************
3484  POSIX Lock a file.
3485 ****************************************************************************/
3486
3487 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3488                                         struct tevent_context *ev,
3489                                         struct cli_state *cli,
3490                                         uint16_t fnum,
3491                                         uint64_t offset,
3492                                         uint64_t len,
3493                                         bool wait_lock,
3494                                         enum brl_type lock_type)
3495 {
3496         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3497                                         wait_lock, lock_type);
3498 }
3499
3500 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3501 {
3502         return tevent_req_simple_recv_ntstatus(req);
3503 }
3504
3505 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3506                         uint64_t offset, uint64_t len,
3507                         bool wait_lock, enum brl_type lock_type)
3508 {
3509         TALLOC_CTX *frame = talloc_stackframe();
3510         struct tevent_context *ev = NULL;
3511         struct tevent_req *req = NULL;
3512         NTSTATUS status = NT_STATUS_OK;
3513
3514         if (smbXcli_conn_has_async_calls(cli->conn)) {
3515                 /*
3516                  * Can't use sync call while an async call is in flight
3517                  */
3518                 status = NT_STATUS_INVALID_PARAMETER;
3519                 goto fail;
3520         }
3521
3522         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3523                 status = NT_STATUS_INVALID_PARAMETER;
3524                 goto fail;
3525         }
3526
3527         ev = samba_tevent_context_init(frame);
3528         if (ev == NULL) {
3529                 status = NT_STATUS_NO_MEMORY;
3530                 goto fail;
3531         }
3532
3533         req = cli_posix_lock_send(frame,
3534                                 ev,
3535                                 cli,
3536                                 fnum,
3537                                 offset,
3538                                 len,
3539                                 wait_lock,
3540                                 lock_type);
3541         if (req == NULL) {
3542                 status = NT_STATUS_NO_MEMORY;
3543                 goto fail;
3544         }
3545
3546         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3547                 goto fail;
3548         }
3549
3550         status = cli_posix_lock_recv(req);
3551
3552  fail:
3553         TALLOC_FREE(frame);
3554         return status;
3555 }
3556
3557 /****************************************************************************
3558  POSIX Unlock a file.
3559 ****************************************************************************/
3560
3561 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3562                                         struct tevent_context *ev,
3563                                         struct cli_state *cli,
3564                                         uint16_t fnum,
3565                                         uint64_t offset,
3566                                         uint64_t len)
3567 {
3568         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3569                                         false, UNLOCK_LOCK);
3570 }
3571
3572 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3573 {
3574         return tevent_req_simple_recv_ntstatus(req);
3575 }
3576
3577 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3578 {
3579         TALLOC_CTX *frame = talloc_stackframe();
3580         struct tevent_context *ev = NULL;
3581         struct tevent_req *req = NULL;
3582         NTSTATUS status = NT_STATUS_OK;
3583
3584         if (smbXcli_conn_has_async_calls(cli->conn)) {
3585                 /*
3586                  * Can't use sync call while an async call is in flight
3587                  */
3588                 status = NT_STATUS_INVALID_PARAMETER;
3589                 goto fail;
3590         }
3591
3592         ev = samba_tevent_context_init(frame);
3593         if (ev == NULL) {
3594                 status = NT_STATUS_NO_MEMORY;