dc3751aa821351e0d9d9df8a6af3aa9da9e6ce41
[vlendec/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         uint32_t impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
2106
2107         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2108         if (req == NULL) {
2109                 return NULL;
2110         }
2111
2112         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2113                 state->recv = cli_smb2_create_fnum_recv;
2114
2115                 if (cli->use_oplocks) {
2116                         create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2117                 }
2118
2119                 subreq = cli_smb2_create_fnum_send(
2120                         state, ev, cli, fname, create_flags,
2121                         impersonation_level, desired_access,
2122                         file_attributes, share_access, create_disposition,
2123                         create_options);
2124         } else {
2125                 state->recv = cli_ntcreate1_recv;
2126                 subreq = cli_ntcreate1_send(
2127                         state, ev, cli, fname, create_flags, desired_access,
2128                         file_attributes, share_access, create_disposition,
2129                         create_options, security_flags);
2130         }
2131         if (tevent_req_nomem(subreq, req)) {
2132                 return tevent_req_post(req, ev);
2133         }
2134         tevent_req_set_callback(subreq, cli_ntcreate_done, req);
2135
2136         state->subreq = subreq;
2137         tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2138
2139         return req;
2140 }
2141
2142 static void cli_ntcreate_done(struct tevent_req *subreq)
2143 {
2144         struct tevent_req *req = tevent_req_callback_data(
2145                 subreq, struct tevent_req);
2146         struct cli_ntcreate_state *state = tevent_req_data(
2147                 req, struct cli_ntcreate_state);
2148         NTSTATUS status;
2149
2150         status = state->recv(subreq, &state->fnum, &state->cr);
2151         TALLOC_FREE(subreq);
2152         if (tevent_req_nterror(req, status)) {
2153                 return;
2154         }
2155         tevent_req_done(req);
2156 }
2157
2158 static bool cli_ntcreate_cancel(struct tevent_req *req)
2159 {
2160         struct cli_ntcreate_state *state = tevent_req_data(
2161                 req, struct cli_ntcreate_state);
2162         return tevent_req_cancel(state->subreq);
2163 }
2164
2165 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2166                            struct smb_create_returns *cr)
2167 {
2168         struct cli_ntcreate_state *state = tevent_req_data(
2169                 req, struct cli_ntcreate_state);
2170         NTSTATUS status;
2171
2172         if (tevent_req_is_nterror(req, &status)) {
2173                 return status;
2174         }
2175         if (fnum != NULL) {
2176                 *fnum = state->fnum;
2177         }
2178         if (cr != NULL) {
2179                 *cr = state->cr;
2180         }
2181         return NT_STATUS_OK;
2182 }
2183
2184 NTSTATUS cli_ntcreate(struct cli_state *cli,
2185                       const char *fname,
2186                       uint32_t CreatFlags,
2187                       uint32_t DesiredAccess,
2188                       uint32_t FileAttributes,
2189                       uint32_t ShareAccess,
2190                       uint32_t CreateDisposition,
2191                       uint32_t CreateOptions,
2192                       uint8_t SecurityFlags,
2193                       uint16_t *pfid,
2194                       struct smb_create_returns *cr)
2195 {
2196         TALLOC_CTX *frame = talloc_stackframe();
2197         struct tevent_context *ev;
2198         struct tevent_req *req;
2199         NTSTATUS status = NT_STATUS_NO_MEMORY;
2200
2201         if (smbXcli_conn_has_async_calls(cli->conn)) {
2202                 /*
2203                  * Can't use sync call while an async call is in flight
2204                  */
2205                 status = NT_STATUS_INVALID_PARAMETER;
2206                 goto fail;
2207         }
2208
2209         ev = samba_tevent_context_init(frame);
2210         if (ev == NULL) {
2211                 goto fail;
2212         }
2213
2214         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2215                                 DesiredAccess, FileAttributes, ShareAccess,
2216                                 CreateDisposition, CreateOptions,
2217                                 SecurityFlags);
2218         if (req == NULL) {
2219                 goto fail;
2220         }
2221
2222         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2223                 goto fail;
2224         }
2225
2226         status = cli_ntcreate_recv(req, pfid, cr);
2227  fail:
2228         TALLOC_FREE(frame);
2229         return status;
2230 }
2231
2232 struct cli_nttrans_create_state {
2233         uint16_t fnum;
2234         struct smb_create_returns cr;
2235 };
2236
2237 static void cli_nttrans_create_done(struct tevent_req *subreq);
2238
2239 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2240                                            struct tevent_context *ev,
2241                                            struct cli_state *cli,
2242                                            const char *fname,
2243                                            uint32_t CreatFlags,
2244                                            uint32_t DesiredAccess,
2245                                            uint32_t FileAttributes,
2246                                            uint32_t ShareAccess,
2247                                            uint32_t CreateDisposition,
2248                                            uint32_t CreateOptions,
2249                                            uint8_t SecurityFlags,
2250                                            struct security_descriptor *secdesc,
2251                                            struct ea_struct *eas,
2252                                            int num_eas)
2253 {
2254         struct tevent_req *req, *subreq;
2255         struct cli_nttrans_create_state *state;
2256         uint8_t *param;
2257         uint8_t *secdesc_buf;
2258         size_t secdesc_len;
2259         NTSTATUS status;
2260         size_t converted_len;
2261         uint16_t additional_flags2 = 0;
2262
2263         req = tevent_req_create(mem_ctx,
2264                                 &state, struct cli_nttrans_create_state);
2265         if (req == NULL) {
2266                 return NULL;
2267         }
2268
2269         if (secdesc != NULL) {
2270                 status = marshall_sec_desc(talloc_tos(), secdesc,
2271                                            &secdesc_buf, &secdesc_len);
2272                 if (tevent_req_nterror(req, status)) {
2273                         DEBUG(10, ("marshall_sec_desc failed: %s\n",
2274                                    nt_errstr(status)));
2275                         return tevent_req_post(req, ev);
2276                 }
2277         } else {
2278                 secdesc_buf = NULL;
2279                 secdesc_len = 0;
2280         }
2281
2282         if (num_eas != 0) {
2283                 /*
2284                  * TODO ;-)
2285                  */
2286                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2287                 return tevent_req_post(req, ev);
2288         }
2289
2290         param = talloc_array(state, uint8_t, 53);
2291         if (tevent_req_nomem(param, req)) {
2292                 return tevent_req_post(req, ev);
2293         }
2294
2295         param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2296                                       fname, strlen(fname),
2297                                       &converted_len);
2298         if (tevent_req_nomem(param, req)) {
2299                 return tevent_req_post(req, ev);
2300         }
2301
2302         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2303                 additional_flags2 = FLAGS2_REPARSE_PATH;
2304         }
2305
2306         SIVAL(param, 0, CreatFlags);
2307         SIVAL(param, 4, 0x0);   /* RootDirectoryFid */
2308         SIVAL(param, 8, DesiredAccess);
2309         SIVAL(param, 12, 0x0);  /* AllocationSize */
2310         SIVAL(param, 16, 0x0);  /* AllocationSize */
2311         SIVAL(param, 20, FileAttributes);
2312         SIVAL(param, 24, ShareAccess);
2313         SIVAL(param, 28, CreateDisposition);
2314         SIVAL(param, 32, CreateOptions |
2315                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2316         SIVAL(param, 36, secdesc_len);
2317         SIVAL(param, 40, 0);     /* EA length*/
2318         SIVAL(param, 44, converted_len);
2319         SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2320         SCVAL(param, 52, SecurityFlags);
2321
2322         subreq = cli_trans_send(state, ev, cli,
2323                                 additional_flags2, /* additional_flags2 */
2324                                 SMBnttrans,
2325                                 NULL, -1, /* name, fid */
2326                                 NT_TRANSACT_CREATE, 0,
2327                                 NULL, 0, 0, /* setup */
2328                                 param, talloc_get_size(param), 128, /* param */
2329                                 secdesc_buf, secdesc_len, 0); /* data */
2330         if (tevent_req_nomem(subreq, req)) {
2331                 return tevent_req_post(req, ev);
2332         }
2333         tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2334         return req;
2335 }
2336
2337 static void cli_nttrans_create_done(struct tevent_req *subreq)
2338 {
2339         struct tevent_req *req = tevent_req_callback_data(
2340                 subreq, struct tevent_req);
2341         struct cli_nttrans_create_state *state = tevent_req_data(
2342                 req, struct cli_nttrans_create_state);
2343         uint8_t *param;
2344         uint32_t num_param;
2345         NTSTATUS status;
2346
2347         status = cli_trans_recv(subreq, talloc_tos(), NULL,
2348                                 NULL, 0, NULL, /* rsetup */
2349                                 &param, 69, &num_param,
2350                                 NULL, 0, NULL);
2351         if (tevent_req_nterror(req, status)) {
2352                 return;
2353         }
2354         state->cr.oplock_level = CVAL(param, 0);
2355         state->fnum = SVAL(param, 2);
2356         state->cr.create_action = IVAL(param, 4);
2357         state->cr.creation_time = BVAL(param, 12);
2358         state->cr.last_access_time = BVAL(param, 20);
2359         state->cr.last_write_time = BVAL(param, 28);
2360         state->cr.change_time   = BVAL(param, 36);
2361         state->cr.file_attributes = IVAL(param, 44);
2362         state->cr.allocation_size = BVAL(param, 48);
2363         state->cr.end_of_file   = BVAL(param, 56);
2364
2365         TALLOC_FREE(param);
2366         tevent_req_done(req);
2367 }
2368
2369 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2370                         uint16_t *fnum,
2371                         struct smb_create_returns *cr)
2372 {
2373         struct cli_nttrans_create_state *state = tevent_req_data(
2374                 req, struct cli_nttrans_create_state);
2375         NTSTATUS status;
2376
2377         if (tevent_req_is_nterror(req, &status)) {
2378                 return status;
2379         }
2380         *fnum = state->fnum;
2381         if (cr != NULL) {
2382                 *cr = state->cr;
2383         }
2384         return NT_STATUS_OK;
2385 }
2386
2387 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2388                             const char *fname,
2389                             uint32_t CreatFlags,
2390                             uint32_t DesiredAccess,
2391                             uint32_t FileAttributes,
2392                             uint32_t ShareAccess,
2393                             uint32_t CreateDisposition,
2394                             uint32_t CreateOptions,
2395                             uint8_t SecurityFlags,
2396                             struct security_descriptor *secdesc,
2397                             struct ea_struct *eas,
2398                             int num_eas,
2399                             uint16_t *pfid,
2400                             struct smb_create_returns *cr)
2401 {
2402         TALLOC_CTX *frame = talloc_stackframe();
2403         struct tevent_context *ev;
2404         struct tevent_req *req;
2405         NTSTATUS status = NT_STATUS_NO_MEMORY;
2406
2407         if (smbXcli_conn_has_async_calls(cli->conn)) {
2408                 /*
2409                  * Can't use sync call while an async call is in flight
2410                  */
2411                 status = NT_STATUS_INVALID_PARAMETER;
2412                 goto fail;
2413         }
2414         ev = samba_tevent_context_init(frame);
2415         if (ev == NULL) {
2416                 goto fail;
2417         }
2418         req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2419                                       DesiredAccess, FileAttributes,
2420                                       ShareAccess, CreateDisposition,
2421                                       CreateOptions, SecurityFlags,
2422                                       secdesc, eas, num_eas);
2423         if (req == NULL) {
2424                 goto fail;
2425         }
2426         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2427                 goto fail;
2428         }
2429         status = cli_nttrans_create_recv(req, pfid, cr);
2430  fail:
2431         TALLOC_FREE(frame);
2432         return status;
2433 }
2434
2435 /****************************************************************************
2436  Open a file
2437  WARNING: if you open with O_WRONLY then getattrE won't work!
2438 ****************************************************************************/
2439
2440 struct cli_openx_state {
2441         const char *fname;
2442         uint16_t vwv[15];
2443         uint16_t fnum;
2444         struct iovec bytes;
2445 };
2446
2447 static void cli_openx_done(struct tevent_req *subreq);
2448
2449 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2450                                    struct tevent_context *ev,
2451                                    struct cli_state *cli, const char *fname,
2452                                    int flags, int share_mode,
2453                                    struct tevent_req **psmbreq)
2454 {
2455         struct tevent_req *req, *subreq;
2456         struct cli_openx_state *state;
2457         unsigned openfn;
2458         unsigned accessmode;
2459         uint8_t additional_flags;
2460         uint16_t additional_flags2 = 0;
2461         uint8_t *bytes;
2462
2463         req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2464         if (req == NULL) {
2465                 return NULL;
2466         }
2467
2468         openfn = 0;
2469         if (flags & O_CREAT) {
2470                 openfn |= (1<<4);
2471         }
2472         if (!(flags & O_EXCL)) {
2473                 if (flags & O_TRUNC)
2474                         openfn |= (1<<1);
2475                 else
2476                         openfn |= (1<<0);
2477         }
2478
2479         accessmode = (share_mode<<4);
2480
2481         if ((flags & O_ACCMODE) == O_RDWR) {
2482                 accessmode |= 2;
2483         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2484                 accessmode |= 1;
2485         }
2486
2487 #if defined(O_SYNC)
2488         if ((flags & O_SYNC) == O_SYNC) {
2489                 accessmode |= (1<<14);
2490         }
2491 #endif /* O_SYNC */
2492
2493         if (share_mode == DENY_FCB) {
2494                 accessmode = 0xFF;
2495         }
2496
2497         SCVAL(state->vwv + 0, 0, 0xFF);
2498         SCVAL(state->vwv + 0, 1, 0);
2499         SSVAL(state->vwv + 1, 0, 0);
2500         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
2501         SSVAL(state->vwv + 3, 0, accessmode);
2502         SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2503         SSVAL(state->vwv + 5, 0, 0);
2504         SIVAL(state->vwv + 6, 0, 0);
2505         SSVAL(state->vwv + 8, 0, openfn);
2506         SIVAL(state->vwv + 9, 0, 0);
2507         SIVAL(state->vwv + 11, 0, 0);
2508         SIVAL(state->vwv + 13, 0, 0);
2509
2510         additional_flags = 0;
2511
2512         if (cli->use_oplocks) {
2513                 /* if using oplocks then ask for a batch oplock via
2514                    core and extended methods */
2515                 additional_flags =
2516                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2517                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2518         }
2519
2520         bytes = talloc_array(state, uint8_t, 0);
2521         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2522                                    strlen(fname)+1, NULL);
2523
2524         if (tevent_req_nomem(bytes, req)) {
2525                 return tevent_req_post(req, ev);
2526         }
2527
2528         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2529                 additional_flags2 = FLAGS2_REPARSE_PATH;
2530         }
2531
2532         state->bytes.iov_base = (void *)bytes;
2533         state->bytes.iov_len = talloc_get_size(bytes);
2534
2535         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2536                         additional_flags2, 15, state->vwv, 1, &state->bytes);
2537         if (subreq == NULL) {
2538                 TALLOC_FREE(req);
2539                 return NULL;
2540         }
2541         tevent_req_set_callback(subreq, cli_openx_done, req);
2542         *psmbreq = subreq;
2543         return req;
2544 }
2545
2546 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2547                                  struct cli_state *cli, const char *fname,
2548                                  int flags, int share_mode)
2549 {
2550         struct tevent_req *req, *subreq;
2551         NTSTATUS status;
2552
2553         req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
2554                               &subreq);
2555         if (req == NULL) {
2556                 return NULL;
2557         }
2558
2559         status = smb1cli_req_chain_submit(&subreq, 1);
2560         if (tevent_req_nterror(req, status)) {
2561                 return tevent_req_post(req, ev);
2562         }
2563         return req;
2564 }
2565
2566 static void cli_openx_done(struct tevent_req *subreq)
2567 {
2568         struct tevent_req *req = tevent_req_callback_data(
2569                 subreq, struct tevent_req);
2570         struct cli_openx_state *state = tevent_req_data(
2571                 req, struct cli_openx_state);
2572         uint8_t wct;
2573         uint16_t *vwv;
2574         NTSTATUS status;
2575
2576         status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
2577                               NULL);
2578         TALLOC_FREE(subreq);
2579         if (tevent_req_nterror(req, status)) {
2580                 return;
2581         }
2582         state->fnum = SVAL(vwv+2, 0);
2583         tevent_req_done(req);
2584 }
2585
2586 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2587 {
2588         struct cli_openx_state *state = tevent_req_data(
2589                 req, struct cli_openx_state);
2590         NTSTATUS status;
2591
2592         if (tevent_req_is_nterror(req, &status)) {
2593                 return status;
2594         }
2595         *pfnum = state->fnum;
2596         return NT_STATUS_OK;
2597 }
2598
2599 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
2600              int share_mode, uint16_t *pfnum)
2601 {
2602         TALLOC_CTX *frame = talloc_stackframe();
2603         struct tevent_context *ev;
2604         struct tevent_req *req;
2605         NTSTATUS status = NT_STATUS_NO_MEMORY;
2606
2607         if (smbXcli_conn_has_async_calls(cli->conn)) {
2608                 /*
2609                  * Can't use sync call while an async call is in flight
2610                  */
2611                 status = NT_STATUS_INVALID_PARAMETER;
2612                 goto fail;
2613         }
2614
2615         ev = samba_tevent_context_init(frame);
2616         if (ev == NULL) {
2617                 goto fail;
2618         }
2619
2620         req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
2621         if (req == NULL) {
2622                 goto fail;
2623         }
2624
2625         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2626                 goto fail;
2627         }
2628
2629         status = cli_openx_recv(req, pfnum);
2630  fail:
2631         TALLOC_FREE(frame);
2632         return status;
2633 }
2634 /****************************************************************************
2635  Synchronous wrapper function that does an NtCreateX open by preference
2636  and falls back to openX if this fails.
2637 ****************************************************************************/
2638
2639 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2640                         int share_mode_in, uint16_t *pfnum)
2641 {
2642         NTSTATUS status;
2643         unsigned int openfn = 0;
2644         unsigned int dos_deny = 0;
2645         uint32_t access_mask, share_mode, create_disposition, create_options;
2646         struct smb_create_returns cr;
2647
2648         /* Do the initial mapping into OpenX parameters. */
2649         if (flags & O_CREAT) {
2650                 openfn |= (1<<4);
2651         }
2652         if (!(flags & O_EXCL)) {
2653                 if (flags & O_TRUNC)
2654                         openfn |= (1<<1);
2655                 else
2656                         openfn |= (1<<0);
2657         }
2658
2659         dos_deny = (share_mode_in<<4);
2660
2661         if ((flags & O_ACCMODE) == O_RDWR) {
2662                 dos_deny |= 2;
2663         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2664                 dos_deny |= 1;
2665         }
2666
2667 #if defined(O_SYNC)
2668         if ((flags & O_SYNC) == O_SYNC) {
2669                 dos_deny |= (1<<14);
2670         }
2671 #endif /* O_SYNC */
2672
2673         if (share_mode_in == DENY_FCB) {
2674                 dos_deny = 0xFF;
2675         }
2676
2677 #if 0
2678         /* Hmmm. This is what I think the above code
2679            should look like if it's using the constants
2680            we #define. JRA. */
2681
2682         if (flags & O_CREAT) {
2683                 openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
2684         }
2685         if (!(flags & O_EXCL)) {
2686                 if (flags & O_TRUNC)
2687                         openfn |= OPENX_FILE_EXISTS_TRUNCATE;
2688                 else
2689                         openfn |= OPENX_FILE_EXISTS_OPEN;
2690         }
2691
2692         dos_deny = SET_DENY_MODE(share_mode_in);
2693
2694         if ((flags & O_ACCMODE) == O_RDWR) {
2695                 dos_deny |= DOS_OPEN_RDWR;
2696         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2697                 dos_deny |= DOS_OPEN_WRONLY;
2698         }
2699
2700 #if defined(O_SYNC)
2701         if ((flags & O_SYNC) == O_SYNC) {
2702                 dos_deny |= FILE_SYNC_OPENMODE;
2703         }
2704 #endif /* O_SYNC */
2705
2706         if (share_mode_in == DENY_FCB) {
2707                 dos_deny = 0xFF;
2708         }
2709 #endif
2710
2711         if (!map_open_params_to_ntcreate(fname, dos_deny,
2712                                         openfn, &access_mask,
2713                                         &share_mode, &create_disposition,
2714                                         &create_options, NULL)) {
2715                 goto try_openx;
2716         }
2717
2718         status = cli_ntcreate(cli,
2719                                 fname,
2720                                 0,
2721                                 access_mask,
2722                                 0,
2723                                 share_mode,
2724                                 create_disposition,
2725                                 create_options,
2726                                 0,
2727                                 pfnum,
2728                                 &cr);
2729
2730         /* Try and cope will all varients of "we don't do this call"
2731            and fall back to openX. */
2732
2733         if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
2734                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
2735                         NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
2736                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
2737                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
2738                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
2739                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
2740                         NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
2741                         NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
2742                 goto try_openx;
2743         }
2744
2745         if (NT_STATUS_IS_OK(status) &&
2746             (create_options & FILE_NON_DIRECTORY_FILE) &&
2747             (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
2748         {
2749                 /*
2750                  * Some (broken) servers return a valid handle
2751                  * for directories even if FILE_NON_DIRECTORY_FILE
2752                  * is set. Just close the handle and set the
2753                  * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
2754                  */
2755                 status = cli_close(cli, *pfnum);
2756                 if (!NT_STATUS_IS_OK(status)) {
2757                         return status;
2758                 }
2759                 status = NT_STATUS_FILE_IS_A_DIRECTORY;
2760                 /* Set this so libsmbclient can retrieve it. */
2761                 cli->raw_status = status;
2762         }
2763
2764         return status;
2765
2766   try_openx:
2767
2768         return cli_openx(cli, fname, flags, share_mode_in, pfnum);
2769 }
2770
2771 /****************************************************************************
2772  Close a file.
2773 ****************************************************************************/
2774
2775 struct cli_smb1_close_state {
2776         uint16_t vwv[3];
2777 };
2778
2779 static void cli_smb1_close_done(struct tevent_req *subreq);
2780
2781 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
2782                                 struct tevent_context *ev,
2783                                 struct cli_state *cli,
2784                                 uint16_t fnum,
2785                                 struct tevent_req **psubreq)
2786 {
2787         struct tevent_req *req, *subreq;
2788         struct cli_smb1_close_state *state;
2789
2790         req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
2791         if (req == NULL) {
2792                 return NULL;
2793         }
2794
2795         SSVAL(state->vwv+0, 0, fnum);
2796         SIVALS(state->vwv+1, 0, -1);
2797
2798         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
2799                                 3, state->vwv, 0, NULL);
2800         if (subreq == NULL) {
2801                 TALLOC_FREE(req);
2802                 return NULL;
2803         }
2804         tevent_req_set_callback(subreq, cli_smb1_close_done, req);
2805         *psubreq = subreq;
2806         return req;
2807 }
2808
2809 static void cli_smb1_close_done(struct tevent_req *subreq)
2810 {
2811         struct tevent_req *req = tevent_req_callback_data(
2812                 subreq, struct tevent_req);
2813         NTSTATUS status;
2814
2815         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2816         TALLOC_FREE(subreq);
2817         if (tevent_req_nterror(req, status)) {
2818                 return;
2819         }
2820         tevent_req_done(req);
2821 }
2822
2823 struct cli_close_state {
2824         int dummy;
2825 };
2826
2827 static void cli_close_done(struct tevent_req *subreq);
2828
2829 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2830                                 struct tevent_context *ev,
2831                                 struct cli_state *cli,
2832                                 uint16_t fnum)
2833 {
2834         struct tevent_req *req, *subreq;
2835         struct cli_close_state *state;
2836         NTSTATUS status;
2837
2838         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2839         if (req == NULL) {
2840                 return NULL;
2841         }
2842
2843         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2844                 subreq = cli_smb2_close_fnum_send(state,
2845                                                 ev,
2846                                                 cli,
2847                                                 fnum);
2848                 if (tevent_req_nomem(subreq, req)) {
2849                         return tevent_req_post(req, ev);
2850                 }
2851         } else {
2852                 struct tevent_req *ch_req = NULL;
2853                 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
2854                 if (tevent_req_nomem(subreq, req)) {
2855                         return tevent_req_post(req, ev);
2856                 }
2857                 status = smb1cli_req_chain_submit(&ch_req, 1);
2858                 if (tevent_req_nterror(req, status)) {
2859                         return tevent_req_post(req, ev);
2860                 }
2861         }
2862
2863         tevent_req_set_callback(subreq, cli_close_done, req);
2864         return req;
2865 }
2866
2867 static void cli_close_done(struct tevent_req *subreq)
2868 {
2869         struct tevent_req *req = tevent_req_callback_data(
2870                 subreq, struct tevent_req);
2871         NTSTATUS status = NT_STATUS_OK;
2872         bool err = tevent_req_is_nterror(subreq, &status);
2873
2874         TALLOC_FREE(subreq);
2875         if (err) {
2876                 tevent_req_nterror(req, status);
2877                 return;
2878         }
2879         tevent_req_done(req);
2880 }
2881
2882 NTSTATUS cli_close_recv(struct tevent_req *req)
2883 {
2884         return tevent_req_simple_recv_ntstatus(req);
2885 }
2886
2887 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2888 {
2889         TALLOC_CTX *frame = NULL;
2890         struct tevent_context *ev;
2891         struct tevent_req *req;
2892         NTSTATUS status = NT_STATUS_OK;
2893
2894         frame = talloc_stackframe();
2895
2896         if (smbXcli_conn_has_async_calls(cli->conn)) {
2897                 /*
2898                  * Can't use sync call while an async call is in flight
2899                  */
2900                 status = NT_STATUS_INVALID_PARAMETER;
2901                 goto fail;
2902         }
2903
2904         ev = samba_tevent_context_init(frame);
2905         if (ev == NULL) {
2906                 status = NT_STATUS_NO_MEMORY;
2907                 goto fail;
2908         }
2909
2910         req = cli_close_send(frame, ev, cli, fnum);
2911         if (req == NULL) {
2912                 status = NT_STATUS_NO_MEMORY;
2913                 goto fail;
2914         }
2915
2916         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2917                 goto fail;
2918         }
2919
2920         status = cli_close_recv(req);
2921  fail:
2922         TALLOC_FREE(frame);
2923         return status;
2924 }
2925
2926 /****************************************************************************
2927  Truncate a file to a specified size
2928 ****************************************************************************/
2929
2930 struct ftrunc_state {
2931         uint16_t setup;
2932         uint8_t param[6];
2933         uint8_t data[8];
2934 };
2935
2936 static void cli_ftruncate_done(struct tevent_req *subreq)
2937 {
2938         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2939                                          NULL, 0, NULL, NULL, 0, NULL);
2940         tevent_req_simple_finish_ntstatus(subreq, status);
2941 }
2942
2943 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2944                                         struct tevent_context *ev,
2945                                         struct cli_state *cli,
2946                                         uint16_t fnum,
2947                                         uint64_t size)
2948 {
2949         struct tevent_req *req = NULL, *subreq = NULL;
2950         struct ftrunc_state *state = NULL;
2951
2952         req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2953         if (req == NULL) {
2954                 return NULL;
2955         }
2956
2957         /* Setup setup word. */
2958         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2959
2960         /* Setup param array. */
2961         SSVAL(state->param,0,fnum);
2962         SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2963         SSVAL(state->param,4,0);
2964
2965         /* Setup data array. */
2966         SBVAL(state->data, 0, size);
2967
2968         subreq = cli_trans_send(state,                  /* mem ctx. */
2969                                 ev,                     /* event ctx. */
2970                                 cli,                    /* cli_state. */
2971                                 0,                      /* additional_flags2 */
2972                                 SMBtrans2,              /* cmd. */
2973                                 NULL,                   /* pipe name. */
2974                                 -1,                     /* fid. */
2975                                 0,                      /* function. */
2976                                 0,                      /* flags. */
2977                                 &state->setup,          /* setup. */
2978                                 1,                      /* num setup uint16_t words. */
2979                                 0,                      /* max returned setup. */
2980                                 state->param,           /* param. */
2981                                 6,                      /* num param. */
2982                                 2,                      /* max returned param. */
2983                                 state->data,            /* data. */
2984                                 8,                      /* num data. */
2985                                 0);                     /* max returned data. */
2986
2987         if (tevent_req_nomem(subreq, req)) {
2988                 return tevent_req_post(req, ev);
2989         }
2990         tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2991         return req;
2992 }
2993
2994 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2995 {
2996         return tevent_req_simple_recv_ntstatus(req);
2997 }
2998
2999 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3000 {
3001         TALLOC_CTX *frame = NULL;
3002         struct tevent_context *ev = NULL;
3003         struct tevent_req *req = NULL;
3004         NTSTATUS status = NT_STATUS_OK;
3005
3006         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3007                 return cli_smb2_ftruncate(cli, fnum, size);
3008         }
3009
3010         frame = talloc_stackframe();
3011
3012         if (smbXcli_conn_has_async_calls(cli->conn)) {
3013                 /*
3014                  * Can't use sync call while an async call is in flight
3015                  */
3016                 status = NT_STATUS_INVALID_PARAMETER;
3017                 goto fail;
3018         }
3019
3020         ev = samba_tevent_context_init(frame);
3021         if (ev == NULL) {
3022                 status = NT_STATUS_NO_MEMORY;
3023                 goto fail;
3024         }
3025
3026         req = cli_ftruncate_send(frame,
3027                                 ev,
3028                                 cli,
3029                                 fnum,
3030                                 size);
3031         if (req == NULL) {
3032                 status = NT_STATUS_NO_MEMORY;
3033                 goto fail;
3034         }
3035
3036         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3037                 goto fail;
3038         }
3039
3040         status = cli_ftruncate_recv(req);
3041
3042  fail:
3043         TALLOC_FREE(frame);
3044         return status;
3045 }
3046
3047 /****************************************************************************
3048  send a lock with a specified locktype
3049  this is used for testing LOCKING_ANDX_CANCEL_LOCK
3050 ****************************************************************************/
3051
3052 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
3053                       uint32_t offset, uint32_t len,
3054                       int timeout, unsigned char locktype)
3055 {
3056         uint16_t vwv[8];
3057         uint8_t bytes[10];
3058         NTSTATUS status;
3059         unsigned int set_timeout = 0;
3060         unsigned int saved_timeout = 0;
3061
3062         SCVAL(vwv + 0, 0, 0xff);
3063         SCVAL(vwv + 0, 1, 0);
3064         SSVAL(vwv + 1, 0, 0);
3065         SSVAL(vwv + 2, 0, fnum);
3066         SCVAL(vwv + 3, 0, locktype);
3067         SCVAL(vwv + 3, 1, 0);
3068         SIVALS(vwv + 4, 0, timeout);
3069         SSVAL(vwv + 6, 0, 0);
3070         SSVAL(vwv + 7, 0, 1);
3071
3072         SSVAL(bytes, 0, cli_getpid(cli));
3073         SIVAL(bytes, 2, offset);
3074         SIVAL(bytes, 6, len);
3075
3076         if (timeout != 0) {
3077                 if (timeout == -1) {
3078                         set_timeout = 0x7FFFFFFF;
3079                 } else {
3080                         set_timeout = timeout + 2*1000;
3081                 }
3082                 saved_timeout = cli_set_timeout(cli, set_timeout);
3083         }
3084
3085         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3086                          10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3087
3088         if (saved_timeout != 0) {
3089                 cli_set_timeout(cli, saved_timeout);
3090         }
3091
3092         return status;
3093 }
3094
3095 /****************************************************************************
3096  Lock a file.
3097  note that timeout is in units of 2 milliseconds
3098 ****************************************************************************/
3099
3100 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
3101                   uint32_t offset, uint32_t len, int timeout,
3102                   enum brl_type lock_type)
3103 {
3104         NTSTATUS status;
3105
3106         status = cli_locktype(cli, fnum, offset, len, timeout,
3107                               (lock_type == READ_LOCK? 1 : 0));
3108         return status;
3109 }
3110
3111 /****************************************************************************
3112  Unlock a file.
3113 ****************************************************************************/
3114
3115 struct cli_unlock_state {
3116         uint16_t vwv[8];
3117         uint8_t data[10];
3118 };
3119
3120 static void cli_unlock_done(struct tevent_req *subreq);
3121
3122 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3123                                 struct tevent_context *ev,
3124                                 struct cli_state *cli,
3125                                 uint16_t fnum,
3126                                 uint64_t offset,
3127                                 uint64_t len)
3128
3129 {
3130         struct tevent_req *req = NULL, *subreq = NULL;
3131         struct cli_unlock_state *state = NULL;
3132         uint8_t additional_flags = 0;
3133
3134         req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3135         if (req == NULL) {
3136                 return NULL;
3137         }
3138
3139         SCVAL(state->vwv+0, 0, 0xFF);
3140         SSVAL(state->vwv+2, 0, fnum);
3141         SCVAL(state->vwv+3, 0, 0);
3142         SIVALS(state->vwv+4, 0, 0);
3143         SSVAL(state->vwv+6, 0, 1);
3144         SSVAL(state->vwv+7, 0, 0);
3145
3146         SSVAL(state->data, 0, cli_getpid(cli));
3147         SIVAL(state->data, 2, offset);
3148         SIVAL(state->data, 6, len);
3149
3150         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3151                                 8, state->vwv, 10, state->data);
3152         if (tevent_req_nomem(subreq, req)) {
3153                 return tevent_req_post(req, ev);
3154         }
3155         tevent_req_set_callback(subreq, cli_unlock_done, req);
3156         return req;
3157 }
3158
3159 static void cli_unlock_done(struct tevent_req *subreq)
3160 {
3161         struct tevent_req *req = tevent_req_callback_data(
3162                                 subreq, struct tevent_req);
3163         NTSTATUS status;
3164
3165         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3166         TALLOC_FREE(subreq);
3167         if (tevent_req_nterror(req, status)) {
3168                 return;
3169         }
3170         tevent_req_done(req);
3171 }
3172
3173 NTSTATUS cli_unlock_recv(struct tevent_req *req)
3174 {
3175         return tevent_req_simple_recv_ntstatus(req);
3176 }
3177
3178 NTSTATUS cli_unlock(struct cli_state *cli,
3179                         uint16_t fnum,
3180                         uint32_t offset,
3181                         uint32_t len)
3182 {
3183         TALLOC_CTX *frame = talloc_stackframe();
3184         struct tevent_context *ev;
3185         struct tevent_req *req;
3186         NTSTATUS status = NT_STATUS_OK;
3187
3188         if (smbXcli_conn_has_async_calls(cli->conn)) {
3189                 /*
3190                  * Can't use sync call while an async call is in flight
3191                  */
3192                 status = NT_STATUS_INVALID_PARAMETER;
3193                 goto fail;
3194         }
3195
3196         ev = samba_tevent_context_init(frame);
3197         if (ev == NULL) {
3198                 status = NT_STATUS_NO_MEMORY;
3199                 goto fail;
3200         }
3201
3202         req = cli_unlock_send(frame, ev, cli,
3203                         fnum, offset, len);
3204         if (req == NULL) {
3205                 status = NT_STATUS_NO_MEMORY;
3206                 goto fail;
3207         }
3208
3209         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3210                 goto fail;
3211         }
3212
3213         status = cli_unlock_recv(req);
3214
3215  fail:
3216         TALLOC_FREE(frame);
3217         return status;
3218 }
3219
3220 /****************************************************************************
3221  Lock a file with 64 bit offsets.
3222 ****************************************************************************/
3223
3224 NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
3225                     uint64_t offset, uint64_t len, int timeout,
3226                     enum brl_type lock_type)
3227 {
3228         uint16_t vwv[8];
3229         uint8_t bytes[20];
3230         unsigned int set_timeout = 0;
3231         unsigned int saved_timeout = 0;
3232         int ltype;
3233         NTSTATUS status;
3234
3235         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3236                 return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
3237         }
3238
3239         ltype = (lock_type == READ_LOCK? 1 : 0);
3240         ltype |= LOCKING_ANDX_LARGE_FILES;
3241
3242         SCVAL(vwv + 0, 0, 0xff);
3243         SCVAL(vwv + 0, 1, 0);
3244         SSVAL(vwv + 1, 0, 0);
3245         SSVAL(vwv + 2, 0, fnum);
3246         SCVAL(vwv + 3, 0, ltype);
3247         SCVAL(vwv + 3, 1, 0);
3248         SIVALS(vwv + 4, 0, timeout);
3249         SSVAL(vwv + 6, 0, 0);
3250         SSVAL(vwv + 7, 0, 1);
3251
3252         SIVAL(bytes, 0, cli_getpid(cli));
3253         SOFF_T_R(bytes, 4, offset);
3254         SOFF_T_R(bytes, 12, len);
3255
3256         if (timeout != 0) {
3257                 if (timeout == -1) {
3258                         set_timeout = 0x7FFFFFFF;
3259                 } else {
3260                         set_timeout = timeout + 2*1000;
3261                 }
3262                 saved_timeout = cli_set_timeout(cli, set_timeout);
3263         }
3264
3265         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3266                          20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3267
3268         if (saved_timeout != 0) {
3269                 cli_set_timeout(cli, saved_timeout);
3270         }
3271
3272         return status;
3273 }
3274
3275 /****************************************************************************
3276  Unlock a file with 64 bit offsets.
3277 ****************************************************************************/
3278
3279 struct cli_unlock64_state {
3280         uint16_t vwv[8];
3281         uint8_t data[20];
3282 };
3283
3284 static void cli_unlock64_done(struct tevent_req *subreq);
3285
3286 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
3287                                 struct tevent_context *ev,
3288                                 struct cli_state *cli,
3289                                 uint16_t fnum,
3290                                 uint64_t offset,
3291                                 uint64_t len)
3292
3293 {
3294         struct tevent_req *req = NULL, *subreq = NULL;
3295         struct cli_unlock64_state *state = NULL;
3296         uint8_t additional_flags = 0;
3297
3298         req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
3299         if (req == NULL) {
3300                 return NULL;
3301         }
3302
3303         SCVAL(state->vwv+0, 0, 0xff);
3304         SSVAL(state->vwv+2, 0, fnum);
3305         SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
3306         SIVALS(state->vwv+4, 0, 0);
3307         SSVAL(state->vwv+6, 0, 1);
3308         SSVAL(state->vwv+7, 0, 0);
3309
3310         SIVAL(state->data, 0, cli_getpid(cli));
3311         SOFF_T_R(state->data, 4, offset);
3312         SOFF_T_R(state->data, 12, len);
3313
3314         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3315                                 8, state->vwv, 20, state->data);
3316         if (tevent_req_nomem(subreq, req)) {
3317                 return tevent_req_post(req, ev);
3318         }
3319         tevent_req_set_callback(subreq, cli_unlock64_done, req);
3320         return req;
3321 }
3322
3323 static void cli_unlock64_done(struct tevent_req *subreq)
3324 {
3325         struct tevent_req *req = tevent_req_callback_data(
3326                                 subreq, struct tevent_req);
3327         NTSTATUS status;
3328
3329         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3330         TALLOC_FREE(subreq);
3331         if (tevent_req_nterror(req, status)) {
3332                 return;
3333         }
3334         tevent_req_done(req);
3335 }
3336
3337 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
3338 {
3339         return tevent_req_simple_recv_ntstatus(req);
3340 }
3341
3342 NTSTATUS cli_unlock64(struct cli_state *cli,
3343                                 uint16_t fnum,
3344                                 uint64_t offset,
3345                                 uint64_t len)
3346 {
3347         TALLOC_CTX *frame = talloc_stackframe();
3348         struct tevent_context *ev;
3349         struct tevent_req *req;
3350         NTSTATUS status = NT_STATUS_OK;
3351
3352         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3353                 return cli_unlock(cli, fnum, offset, len);
3354         }
3355
3356         if (smbXcli_conn_has_async_calls(cli->conn)) {
3357                 /*
3358                  * Can't use sync call while an async call is in flight
3359                  */
3360                 status = NT_STATUS_INVALID_PARAMETER;
3361                 goto fail;
3362         }
3363
3364         ev = samba_tevent_context_init(frame);
3365         if (ev == NULL) {
3366                 status = NT_STATUS_NO_MEMORY;
3367                 goto fail;
3368         }
3369
3370         req = cli_unlock64_send(frame, ev, cli,
3371                         fnum, offset, len);
3372         if (req == NULL) {
3373                 status = NT_STATUS_NO_MEMORY;
3374                 goto fail;
3375         }
3376
3377         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3378                 goto fail;
3379         }
3380
3381         status = cli_unlock64_recv(req);
3382
3383  fail:
3384         TALLOC_FREE(frame);
3385         return status;
3386 }
3387
3388 /****************************************************************************
3389  Get/unlock a POSIX lock on a file - internal function.
3390 ****************************************************************************/
3391
3392 struct posix_lock_state {
3393         uint16_t setup;
3394         uint8_t param[4];
3395         uint8_t data[POSIX_LOCK_DATA_SIZE];
3396 };
3397
3398 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3399 {
3400         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3401                                          NULL, 0, NULL, NULL, 0, NULL);
3402         tevent_req_simple_finish_ntstatus(subreq, status);
3403 }
3404
3405 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3406                                         struct tevent_context *ev,
3407                                         struct cli_state *cli,
3408                                         uint16_t fnum,
3409                                         uint64_t offset,
3410                                         uint64_t len,
3411                                         bool wait_lock,
3412                                         enum brl_type lock_type)
3413 {
3414         struct tevent_req *req = NULL, *subreq = NULL;
3415         struct posix_lock_state *state = NULL;
3416
3417         req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3418         if (req == NULL) {
3419                 return NULL;
3420         }
3421
3422         /* Setup setup word. */
3423         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3424
3425         /* Setup param array. */
3426         SSVAL(&state->param, 0, fnum);
3427         SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3428
3429         /* Setup data array. */
3430         switch (lock_type) {
3431                 case READ_LOCK:
3432                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3433                                 POSIX_LOCK_TYPE_READ);
3434                         break;
3435                 case WRITE_LOCK:
3436                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3437                                 POSIX_LOCK_TYPE_WRITE);
3438                         break;
3439                 case UNLOCK_LOCK:
3440                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3441                                 POSIX_LOCK_TYPE_UNLOCK);
3442                         break;
3443                 default:
3444                         return NULL;
3445         }
3446
3447         if (wait_lock) {
3448                 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3449                                 POSIX_LOCK_FLAG_WAIT);
3450         } else {
3451                 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3452                                 POSIX_LOCK_FLAG_NOWAIT);
3453         }
3454
3455         SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3456         SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3457         SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3458
3459         subreq = cli_trans_send(state,                  /* mem ctx. */
3460                                 ev,                     /* event ctx. */
3461                                 cli,                    /* cli_state. */
3462                                 0,                      /* additional_flags2 */
3463                                 SMBtrans2,              /* cmd. */
3464                                 NULL,                   /* pipe name. */
3465                                 -1,                     /* fid. */
3466                                 0,                      /* function. */
3467                                 0,                      /* flags. */
3468                                 &state->setup,          /* setup. */
3469                                 1,                      /* num setup uint16_t words. */
3470                                 0,                      /* max returned setup. */
3471                                 state->param,           /* param. */
3472                                 4,                      /* num param. */
3473                                 2,                      /* max returned param. */
3474                                 state->data,            /* data. */
3475                                 POSIX_LOCK_DATA_SIZE,   /* num data. */
3476                                 0);                     /* max returned data. */
3477
3478         if (tevent_req_nomem(subreq, req)) {
3479                 return tevent_req_post(req, ev);
3480         }
3481         tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3482         return req;
3483 }
3484
3485 /****************************************************************************
3486  POSIX Lock a file.
3487 ****************************************************************************/
3488
3489 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3490                                         struct tevent_context *ev,
3491                                         struct cli_state *cli,
3492                                         uint16_t fnum,
3493                                         uint64_t offset,
3494                                         uint64_t len,
3495                                         bool wait_lock,
3496                                         enum brl_type lock_type)
3497 {
3498         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3499                                         wait_lock, lock_type);
3500 }
3501
3502 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3503 {
3504         return tevent_req_simple_recv_ntstatus(req);
3505 }
3506
3507 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3508                         uint64_t offset, uint64_t len,
3509                         bool wait_lock, enum brl_type lock_type)
3510 {
3511         TALLOC_CTX *frame = talloc_stackframe();
3512         struct tevent_context *ev = NULL;
3513         struct tevent_req *req = NULL;
3514         NTSTATUS status = NT_STATUS_OK;
3515
3516         if (smbXcli_conn_has_async_calls(cli->conn)) {
3517                 /*
3518                  * Can't use sync call while an async call is in flight
3519                  */
3520                 status = NT_STATUS_INVALID_PARAMETER;
3521                 goto fail;
3522         }
3523
3524         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3525                 status = NT_STATUS_INVALID_PARAMETER;
3526                 goto fail;
3527         }
3528
3529         ev = samba_tevent_context_init(frame);
3530         if (ev == NULL) {
3531                 status = NT_STATUS_NO_MEMORY;
3532                 goto fail;
3533         }
3534
3535         req = cli_posix_lock_send(frame,
3536                                 ev,
3537                                 cli,
3538                                 fnum,
3539                                 offset,
3540                                 len,
3541                                 wait_lock,
3542                                 lock_type);
3543         if (req == NULL) {
3544                 status = NT_STATUS_NO_MEMORY;
3545                 goto fail;
3546         }
3547
3548         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3549                 goto fail;
3550         }
3551
3552         status = cli_posix_lock_recv(req);
3553
3554  fail:
3555         TALLOC_FREE(frame);
3556         return status;
3557 }
3558
3559 /****************************************************************************
3560  POSIX Unlock a file.
3561 ****************************************************************************/
3562
3563 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3564                                         struct tevent_context *ev,
3565                                         struct cli_state *cli,
3566                                         uint16_t fnum,
3567                                         uint64_t offset,
3568                                         uint64_t len)
3569 {
3570         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3571                                         false, UNLOCK_LOCK);
3572 }
3573
3574 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3575 {
3576         return tevent_req_simple_recv_ntstatus(req);
3577 }
3578
3579 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3580 {
3581         TALLOC_CTX *frame = talloc_stackframe();
3582         struct tevent_context *ev = NULL;
3583         struct tevent_req *req = NULL;
3584         NTSTATUS status = NT_STATUS_OK;
3585
3586         if (smbXcli_conn_has_async_calls(cli->conn)) {
3587                 /*
3588                  * Can't use sync call while an async call is in flight
3589                  */
3590                 status = NT_STATUS_INVALID_PARAMETER;
3591                 goto fail;
3592         }
3593
3594         ev = samba_tevent_context_init(frame);
3595         if (ev == NULL) {
3596                 status = NT_STATUS_NO_MEMORY;
3597                 goto fail;
3598         }
3599
3600         req = cli_posix_unlock_send(frame,
3601                                 ev,
3602                                 cli,
3603                                 fnum,
3604                                 offset,
3605                                 len);
3606         if (req == NULL) {
3607                 status = NT_STATUS_NO_MEMORY;
3608                 goto fail;
3609         }
3610
3611         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3612                 goto fail;
3613         }
3614
3615         status = cli_posix_unlock_recv(req);
3616
3617  fail:
3618         TALLOC_FREE(frame);
3619         return status;
3620 }
3621
3622 /****************************************************************************
3623  Do a SMBgetattrE call.
3624 ****************************************************************************/
3625
3626 static void cli_getattrE_done(struct tevent_req *subreq);
3627
3628 struct cli_getattrE_state {
3629         uint16_t vwv[1];
3630         int zone_offset;
3631         uint16_t attr;
3632         off_t size;
3633         time_t change_time;
3634         time_t access_time;
3635         time_t write_time;
3636 };
3637
3638 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3639                                 struct tevent_context *ev,
3640                                 struct cli_state *cli,
3641                                 uint16_t fnum)
3642 {
3643         struct tevent_req *req = NULL, *subreq = NULL;
3644         struct cli_getattrE_state *state = NULL;
3645         uint8_t additional_flags = 0;
3646
3647         req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3648         if (req == NULL) {
3649                 return NULL;
3650         }
3651
3652         state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3653         SSVAL(state->vwv+0,0,fnum);
3654
3655         subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
3656                               1, state->vwv, 0, NULL);
3657         if (tevent_req_nomem(subreq, req)) {
3658                 return tevent_req_post(req, ev);
3659         }
3660         tevent_req_set_callback(subreq, cli_getattrE_done, req);
3661         return req;
3662 }
3663
3664 static void cli_getattrE_done(struct tevent_req *subreq)
3665 {
3666         struct tevent_req *req = tevent_req_callback_data(
3667                 subreq, struct tevent_req);
3668         struct cli_getattrE_state *state = tevent_req_data(
3669                 req, struct cli_getattrE_state);
3670         uint8_t wct;
3671         uint16_t *vwv = NULL;
3672         NTSTATUS status;
3673
3674         status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
3675                               NULL, NULL);
3676         TALLOC_FREE(subreq);
3677         if (tevent_req_nterror(req, status)) {
3678                 return;
3679         }
3680
3681         state->size = (off_t)IVAL(vwv+6,0);
3682         state->attr = SVAL(vwv+10,0);
3683         state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3684         state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3685         state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3686
3687         tevent_req_done(req);
3688 }
3689
3690 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3691                         uint16_t *attr,
3692                         off_t *size,
3693                         time_t *change_time,
3694                         time_t *access_time,
3695                         time_t *write_time)
3696 {
3697         struct cli_getattrE_state *state = tevent_req_data(
3698                                 req, struct cli_getattrE_state);
3699         NTSTATUS status;
3700
3701         if (tevent_req_is_nterror(req, &status)) {
3702                 return status;
3703         }
3704         if (attr) {
3705                 *attr = state->attr;
3706         }
3707         if (size) {
3708                 *size = state->size;
3709         }
3710         if (change_time) {
3711                 *change_time = state->change_time;
3712         }
3713         if (access_time) {
3714                 *access_time = state->access_time;
3715         }
3716         if (write_time) {
3717                 *write_time = state->write_time;
3718         }
3719         return NT_STATUS_OK;
3720 }
3721
3722 NTSTATUS cli_getattrE(struct cli_state *cli,
3723                         uint16_t fnum,
3724                         uint16_t *attr,
3725                         off_t *size,
3726                         time_t *change_time,
3727                         time_t *access_time,
3728                         time_t *write_time)
3729 {
3730         TALLOC_CTX *frame = NULL;
3731         struct tevent_context *ev = NULL;
3732         struct tevent_req *req = NULL;
3733         NTSTATUS status = NT_STATUS_OK;
3734
3735         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3736                 return cli_smb2_getattrE(cli,
3737                                         fnum,
3738                                         attr,
3739                                         size,
3740                                         change_time,
3741                                         access_time,
3742                                         write_time);
3743         }
3744
3745         frame = talloc_stackframe();
3746
3747         if (smbXcli_conn_has_async_calls(cli->conn)) {
3748                 /*
3749                  * Can't use sync call while an async call is in flight
3750                  */
3751                 status = NT_STATUS_INVALID_PARAMETER;
3752                 goto fail;
3753         }
3754
3755         ev = samba_tevent_context_init(frame);
3756         if (ev == NULL) {
3757                 status = NT_STATUS_NO_MEMORY;
3758                 goto fail;
3759         }
3760
3761         req = cli_getattrE_send(frame, ev, cli, fnum);
3762         if (req == NULL) {
3763                 status = NT_STATUS_NO_MEMORY;
3764                 goto fail;
3765         }
3766
3767         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3768                 goto fail;
3769         }
3770
3771         status = cli_getattrE_recv(req,
3772                                         attr,
3773                                         size,
3774                                         change_time,
3775                                         access_time,
3776                                         write_time);
3777
3778  fail:
3779         TALLOC_FREE(frame);
3780         return status;
3781 }
3782
3783 /****************************************************************************
3784  Do a SMBgetatr call
3785 ****************************************************************************/
3786
3787 static void cli_getatr_done(struct tevent_req *subreq);
3788
3789 struct cli_getatr_state {
3790         int zone_offset;
3791         uint16_t attr;
3792         off_t size;
3793         time_t write_time;
3794 };
3795
3796 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3797                                 struct tevent_context *ev,
3798                                 struct cli_state *cli,
3799                                 const char *fname)
3800 {
3801         struct tevent_req *req = NULL, *subreq = NULL;
3802         struct cli_getatr_state *state = NULL;
3803         uint8_t additional_flags = 0;
3804         uint16_t additional_flags2 = 0;
3805         uint8_t *bytes = NULL;
3806
3807         req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3808         if (req == NULL) {
3809                 return NULL;
3810         }
3811
3812         state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3813
3814         bytes = talloc_array(state, uint8_t, 1);
3815         if (tevent_req_nomem(bytes, req)) {
3816                 return tevent_req_post(req, ev);
3817         }
3818         bytes[0] = 4;
3819         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3820                                    strlen(fname)+1, NULL);
3821
3822         if (tevent_req_nomem(bytes, req)) {
3823                 return tevent_req_post(req, ev);
3824         }
3825
3826         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
3827                 additional_flags2 = FLAGS2_REPARSE_PATH;
3828         }
3829
3830         subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3831                         additional_flags2,
3832                         0, NULL, talloc_get_size(bytes), bytes);
3833         if (tevent_req_nomem(subreq, req)) {
3834                 return tevent_req_post(req, ev);
3835         }
3836         tevent_req_set_callback(subreq, cli_getatr_done, req);
3837         return req;
3838 }
3839
3840 static void cli_getatr_done(struct tevent_req *subreq)
3841 {
3842         struct tevent_req *req = tevent_req_callback_data(
3843                 subreq, struct tevent_req);
3844         struct cli_getatr_state *state = tevent_req_data(
3845                 req, struct cli_getatr_state);
3846         uint8_t wct;
3847         uint16_t *vwv = NULL;
3848         NTSTATUS status;
3849
3850         status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
3851                               NULL);
3852         TALLOC_FREE(subreq);
3853         if (tevent_req_nterror(req, status)) {
3854                 return;
3855         }
3856
3857         state->attr = SVAL(vwv+0,0);
3858         state->size = (off_t)IVAL(vwv+3,0);
3859         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3860
3861         tevent_req_done(req);
3862 }
3863
3864 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3865                         uint16_t *attr,
3866                         off_t *size,
3867                         time_t *write_time)
3868 {
3869         struct cli_getatr_state *state = tevent_req_data(
3870                                 req, struct cli_getatr_state);
3871         NTSTATUS status;
3872
3873         if (tevent_req_is_nterror(req, &status)) {
3874                 return status;
3875         }
3876         if (attr) {
3877                 *attr = state->attr;
3878         }
3879         if (size) {
3880                 *size = state->size;
3881         }
3882         if (write_time) {
3883                 *write_time = state->write_time;
3884         }
3885         return NT_STATUS_OK;
3886 }
3887
3888 NTSTATUS cli_getatr(struct cli_state *cli,
3889                         const char *fname,
3890                         uint16_t *attr,
3891                         off_t *size,
3892                         time_t *write_time)
3893 {
3894         TALLOC_CTX *frame = NULL;
3895         struct tevent_context *ev = NULL;
3896         struct tevent_req *req = NULL;
3897         NTSTATUS status = NT_STATUS_OK;
3898
3899         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3900                 return cli_smb2_getatr(cli,
3901                                         fname,
3902                                         attr,
3903                                         size,
3904                                         write_time);
3905         }
3906
3907         frame = talloc_stackframe();
3908
3909         if (smbXcli_conn_has_async_calls(cli->conn)) {
3910                 /*
3911                  * Can't use sync call while an async call is in flight
3912                  */
3913                 status = NT_STATUS_INVALID_PARAMETER;
3914                 goto fail;
3915         }
3916
3917         ev = samba_tevent_context_init(frame);
3918         if (ev == NULL) {
3919                 status = NT_STATUS_NO_MEMORY;
3920                 goto fail;
3921         }
3922
3923         req = cli_getatr_send(frame, ev, cli, fname);
3924         if (req == NULL) {
3925                 status = NT_STATUS_NO_MEMORY;
3926                 goto fail;
3927         }
3928
3929         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3930                 goto fail;
3931         }
3932
3933         status = cli_getatr_recv(req,
3934                                 attr,
3935                                 size,
3936                                 write_time);
3937
3938  fail:
3939         TALLOC_FREE(frame);
3940         return status;
3941 }
3942
3943 /****************************************************************************
3944  Do a SMBsetattrE call.
3945 ****************************************************************************/
3946
3947 static void cli_setattrE_done(struct tevent_req *subreq);
3948
3949 struct cli_setattrE_state {
3950         uint16_t vwv[7];
3951 };
3952
3953 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3954                                 struct tevent_context *ev,
3955                                 struct cli_state *cli,
3956                                 uint16_t fnum,
3957                                 time_t change_time,
3958                                 time_t access_time,
3959                                 time_t write_time)
3960 {
3961         struct tevent_req *req = NULL, *subreq = NULL;
3962         struct cli_setattrE_state *state = NULL;
3963         uint8_t additional_flags = 0;
3964
3965         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3966         if (req == NULL) {
3967                 return NULL;
3968         }
3969
3970         SSVAL(state->vwv+0, 0, fnum);
3971         push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
3972                        smb1cli_conn_server_time_zone(cli->conn));
3973         push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
3974                        smb1cli_conn_server_time_zone(cli->conn));
3975         push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
3976                        smb1cli_conn_server_time_zone(cli->conn));
3977
3978         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
3979                               7, state->vwv, 0, NULL);
3980         if (tevent_req_nomem(subreq, req)) {
3981                 return tevent_req_post(req, ev);
3982         }
3983         tevent_req_set_callback(subreq, cli_setattrE_done, req);
3984         return req;
3985 }
3986
3987 static void cli_setattrE_done(struct tevent_req *subreq)
3988 {
3989         struct tevent_req *req = tevent_req_callback_data(
3990                 subreq, struct tevent_req);
3991         NTSTATUS status;
3992
3993         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3994         TALLOC_FREE(subreq);
3995         if (tevent_req_nterror(req, status)) {
3996                 return;
3997         }
3998         tevent_req_done(req);
3999 }
4000
4001 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4002 {
4003         return tevent_req_simple_recv_ntstatus(req);
4004 }
4005
4006 NTSTATUS cli_setattrE(struct cli_state *cli,
4007                         uint16_t fnum,
4008                         time_t change_time,
4009                         time_t access_time,
4010                         time_t write_time)
4011 {
4012         TALLOC_CTX *frame = NULL;
4013         struct tevent_context *ev = NULL;
4014         struct tevent_req *req = NULL;
4015         NTSTATUS status = NT_STATUS_OK;
4016
4017         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4018                 return cli_smb2_setattrE(cli,
4019                                         fnum,
4020                                         change_time,
4021                                         access_time,
4022                                         write_time);
4023         }
4024
4025         frame = talloc_stackframe();
4026
4027         if (smbXcli_conn_has_async_calls(cli->conn)) {
4028                 /*
4029                  * Can't use sync call while an async call is in flight
4030                  */
4031                 status = NT_STATUS_INVALID_PARAMETER;
4032                 goto fail;
4033         }
4034
4035         ev = samba_tevent_context_init(frame);
4036         if (ev == NULL) {
4037                 status = NT_STATUS_NO_MEMORY;
4038                 goto fail;
4039         }
4040
4041         req = cli_setattrE_send(frame, ev,
4042                         cli,
4043                         fnum,
4044                         change_time,
4045                         access_time,
4046                         write_time);
4047
4048         if (req == NULL) {
4049                 status = NT_STATUS_NO_MEMORY;
4050                 goto fail;
4051         }
4052
4053         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4054                 goto fail;
4055         }
4056
4057         status = cli_setattrE_recv(req);
4058
4059  fail:
4060         TALLOC_FREE(frame);
4061         return status;
4062 }
4063
4064 /****************************************************************************
4065  Do a SMBsetatr call.
4066 ****************************************************************************/
4067
4068 static void cli_setatr_done(struct tevent_req *subreq);
4069
4070 struct cli_setatr_state {
4071         uint16_t vwv[8];
4072 };
4073
4074 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
4075                                 struct tevent_context *ev,
4076                                 struct cli_state *cli,
4077                                 const char *fname,
4078                                 uint16_t attr,
4079                                 time_t mtime)
4080 {
4081         struct tevent_req *req = NULL, *subreq = NULL;
4082         struct cli_setatr_state *state = NULL;
4083         uint8_t additional_flags = 0;
4084         uint16_t additional_flags2 = 0;
4085         uint8_t *bytes = NULL;
4086
4087         req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
4088         if (req == NULL) {
4089                 return NULL;
4090         }
4091
4092         SSVAL(state->vwv+0, 0, attr);
4093         push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
4094
4095         bytes = talloc_array(state, uint8_t, 1);
4096         if (tevent_req_nomem(bytes, req)) {
4097                 return tevent_req_post(req, ev);
4098         }
4099         bytes[0] = 4;
4100         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4101                                    strlen(fname)+1, NULL);
4102         if (tevent_req_nomem(bytes, req)) {
4103                 return tevent_req_post(req, ev);
4104         }
4105         bytes = talloc_realloc(state, bytes, uint8_t,
4106                         talloc_get_size(bytes)+1);
4107         if (tevent_req_nomem(bytes, req)) {
4108                 return tevent_req_post(req, ev);
4109         }
4110
4111         bytes[talloc_get_size(bytes)-1] = 4;
4112         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
4113                                    1, NULL);
4114         if (tevent_req_nomem(bytes, req)) {
4115                 return tevent_req_post(req, ev);
4116         }
4117
4118         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4119                 additional_flags2 = FLAGS2_REPARSE_PATH;
4120         }
4121
4122         subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
4123                         additional_flags2,
4124                         8, state->vwv, talloc_get_size(bytes), bytes);
4125         if (tevent_req_nomem(subreq, req)) {
4126                 return tevent_req_post(req, ev);
4127         }
4128         tevent_req_set_callback(subreq, cli_setatr_done, req);
4129         return req;
4130 }
4131
4132 static void cli_setatr_done(struct tevent_req *subreq)
4133 {
4134         struct tevent_req *req = tevent_req_callback_data(
4135                 subreq, struct tevent_req);
4136         NTSTATUS status;
4137
4138         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4139         TALLOC_FREE(subreq);
4140         if (tevent_req_nterror(req, status)) {
4141                 return;
4142         }
4143         tevent_req_done(req);
4144 }
4145
4146 NTSTATUS cli_setatr_recv(struct tevent_req *req)
4147 {
4148         return tevent_req_simple_recv_ntstatus(req);
4149 }
4150
4151 NTSTATUS cli_setatr(struct cli_state *cli,
4152                 const char *fname,
4153                 uint16_t attr,
4154                 time_t mtime)
4155 {
4156         TALLOC_CTX *frame = NULL;
4157         struct tevent_context *ev = NULL;
4158         struct tevent_req *req = NULL;
4159         NTSTATUS status = NT_STATUS_OK;
4160
4161         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4162                 return cli_smb2_setatr(cli,
4163                                         fname,
4164                                         attr,
4165                                         mtime);
4166         }
4167
4168         frame = talloc_stackframe();
4169
4170         if (smbXcli_conn_has_async_calls(cli->conn)) {
4171                 /*
4172                  * Can't use sync call while an async call is in flight
4173                  */
4174                 status = NT_STATUS_INVALID_PARAMETER;
4175                 goto fail;
4176         }
4177
4178         ev = samba_tevent_context_init(frame);
4179         if (ev == NULL) {
4180                 status = NT_STATUS_NO_MEMORY;
4181                 goto fail;
4182         }
4183
4184         req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
4185         if (req == NULL) {
4186                 status = NT_STATUS_NO_MEMORY;
4187                 goto fail;
4188         }
4189
4190         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4191                 goto fail;
4192         }
4193
4194         status = cli_setatr_recv(req);
4195
4196  fail:
4197         TALLOC_FREE(frame);
4198         return status;
4199 }
4200
4201 /****************************************************************************
4202  Check for existence of a dir.
4203 ****************************************************************************/
4204
4205 static void cli_chkpath_done(struct tevent_req *subreq);
4206
4207 struct cli_chkpath_state {
4208         int dummy;
4209 };
4210
4211 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
4212                                   struct tevent_context *ev,
4213                                   struct cli_state *cli,
4214                                   const char *fname)
4215 {
4216         struct tevent_req *req = NULL, *subreq = NULL;
4217         struct cli_chkpath_state *state = NULL;
4218         uint8_t additional_flags = 0;
4219         uint16_t additional_flags2 = 0;
4220         uint8_t *bytes = NULL;
4221
4222         req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
4223         if (req == NULL) {
4224                 return NULL;
4225         }
4226
4227         bytes = talloc_array(state, uint8_t, 1);
4228         if (tevent_req_nomem(bytes, req)) {
4229                 return tevent_req_post(req, ev);
4230         }
4231         bytes[0] = 4;
4232         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4233                                    strlen(fname)+1, NULL);
4234
4235         if (tevent_req_nomem(bytes, req)) {
4236                 return tevent_req_post(req, ev);
4237         }
4238
4239         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4240                 additional_flags2 = FLAGS2_REPARSE_PATH;
4241         }
4242
4243         subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
4244                         additional_flags2,
4245                         0, NULL, talloc_get_size(bytes), bytes);
4246         if (tevent_req_nomem(subreq, req)) {
4247                 return tevent_req_post(req, ev);
4248         }
4249         tevent_req_set_callback(subreq, cli_chkpath_done, req);
4250         return req;
4251 }
4252
4253 static void cli_chkpath_done(struct tevent_req *subreq)
4254 {
4255         struct tevent_req *req = tevent_req_callback_data(
4256                 subreq, struct tevent_req);
4257         NTSTATUS status;
4258
4259         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4260         TALLOC_FREE(subreq);
4261         if (tevent_req_nterror(req, status)) {
4262                 return;
4263         }
4264         tevent_req_done(req);
4265 }
4266
4267 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
4268 {
4269         return tevent_req_simple_recv_ntstatus(req);
4270 }
4271
4272 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
4273 {
4274         TALLOC_CTX *frame = NULL;
4275         struct tevent_context *ev = NULL;
4276         struct tevent_req *req = NULL;
4277         char *path2 = NULL;
4278         NTSTATUS status = NT_STATUS_OK;
4279
4280         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4281                 return cli_smb2_chkpath(cli, path);
4282         }
4283
4284         frame = talloc_stackframe();
4285
4286         if (smbXcli_conn_has_async_calls(cli->conn)) {
4287                 /*
4288                  * Can't use sync call while an async call is in flight
4289                  */
4290                 status = NT_STATUS_INVALID_PARAMETER;
4291                 goto fail;
4292         }
4293
4294         path2 = talloc_strdup(frame, path);
4295         if (!path2) {
4296                 status = NT_STATUS_NO_MEMORY;
4297                 goto fail;
4298         }
4299         trim_char(path2,'\0','\\');
4300         if (!*path2) {
4301                 path2 = talloc_strdup(frame, "\\");
4302                 if (!path2) {
4303                         status = NT_STATUS_NO_MEMORY;
4304                         goto fail;
4305                 }
4306         }
4307
4308         ev = samba_tevent_context_init(frame);
4309         if (ev == NULL) {
4310                 status = NT_STATUS_NO_MEMORY;
4311                 goto fail;
4312         }
4313
4314         req = cli_chkpath_send(frame, ev, cli, path2);
4315         if (req == NULL) {
4316                 status = NT_STATUS_NO_MEMORY;
4317                 goto fail;
4318         }
4319
4320         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4321                 goto fail;
4322         }
4323
4324         status = cli_chkpath_recv(req);
4325
4326  fail:
4327         TALLOC_FREE(frame);
4328         return status;
4329 }
4330
4331 /****************************************************************************
4332  Query disk space.
4333 ****************************************************************************/
4334
4335 static void cli_dskattr_done(struct tevent_req *subreq);
4336
4337 struct cli_dskattr_state {
4338         int bsize;
4339         int total;
4340         int avail;
4341 };
4342
4343 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
4344                                   struct tevent_context *ev,
4345                                   struct cli_state *cli)
4346 {
4347         struct tevent_req *req = NULL, *subreq = NULL;
4348         struct cli_dskattr_state *state = NULL;
4349         uint8_t additional_flags = 0;
4350
4351         req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
4352         if (req == NULL) {
4353                 return NULL;
4354         }
4355
4356         subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
4357                               0, NULL, 0, NULL);
4358         if (tevent_req_nomem(subreq, req)) {
4359                 return tevent_req_post(req, ev);
4360         }
4361         tevent_req_set_callback(subreq, cli_dskattr_done, req);
4362         return req;
4363 }
4364
4365 static void cli_dskattr_done(struct tevent_req *subreq)
4366 {
4367         struct tevent_req *req = tevent_req_callback_data(
4368                 subreq, struct tevent_req);
4369         struct cli_dskattr_state *state = tevent_req_data(
4370                 req, struct cli_dskattr_state);
4371         uint8_t wct;
4372         uint16_t *vwv = NULL;
4373         NTSTATUS status;
4374
4375         status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4376                               NULL);
4377         TALLOC_FREE(subreq);
4378         if (tevent_req_nterror(req, status)) {
4379                 return;
4380         }
4381         state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
4382         state->total = SVAL(vwv+0, 0);
4383         state->avail = SVAL(vwv+3, 0);
4384         tevent_req_done(req);
4385 }
4386
4387 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
4388 {
4389         struct cli_dskattr_state *state = tevent_req_data(
4390                                 req, struct cli_dskattr_state);
4391         NTSTATUS status;
4392
4393         if (tevent_req_is_nterror(req, &status)) {
4394                 return status;
4395         }
4396         *bsize = state->bsize;
4397         *total = state->total;
4398         *avail = state->avail;
4399         return NT_STATUS_OK;
4400 }
4401
4402 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
4403 {
4404         TALLOC_CTX *frame = NULL;
4405         struct tevent_context *ev = NULL;
4406         struct tevent_req *req = NULL;
4407         NTSTATUS status = NT_STATUS_OK;
4408
4409         frame = talloc_stackframe();
4410
4411         if (smbXcli_conn_has_async_calls(cli->conn)) {
4412                 /*
4413                  * Can't use sync call while an async call is in flight
4414                  */
4415                 status = NT_STATUS_INVALID_PARAMETER;
4416                 goto fail;
4417         }
4418
4419         ev = samba_tevent_context_init(frame);
4420         if (ev == NULL) {
4421                 status = NT_STATUS_NO_MEMORY;
4422                 goto fail;
4423         }
4424
4425         req = cli_dskattr_send(frame, ev, cli);
4426         if (req == NULL) {
4427                 status = NT_STATUS_NO_MEMORY;
4428                 goto fail;
4429         }
4430
4431         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4432                 goto fail;
4433         }
4434
4435         status = cli_dskattr_recv(req, bsize, total, avail);
4436
4437  fail:
4438         TALLOC_FREE(frame);
4439         return status;
4440 }
4441
4442 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
4443                        uint64_t *total, uint64_t *avail)
4444 {
4445         uint64_t sectors_per_block;
4446         uint64_t bytes_per_sector;
4447         int old_bsize, old_total, old_avail;
4448         NTSTATUS status;
4449
4450         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4451                 return cli_smb2_dskattr(cli, path, bsize, total, avail);
4452         }
4453
4454         /*
4455          * Try the trans2 disk full size info call first.
4456          * We already use this in SMBC_fstatvfs_ctx().
4457          * Ignore 'actual_available_units' as we only
4458          * care about the quota for the caller.
4459          */
4460
4461         status = cli_get_fs_full_size_info(cli,
4462                         total,
4463                         avail,
4464                         NULL,
4465                         &sectors_per_block,
4466                         &bytes_per_sector);
4467
4468         /* Try and cope will all varients of "we don't do this call"
4469            and fall back to cli_dskattr. */
4470
4471         if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
4472                         NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
4473                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
4474                         NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
4475                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
4476                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
4477                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
4478                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
4479                         NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
4480                         NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
4481                 goto try_dskattr;
4482         }
4483
4484         if (!NT_STATUS_IS_OK(status)) {
4485                 return status;
4486         }
4487
4488         if (bsize) {
4489                 *bsize = sectors_per_block *
4490                          bytes_per_sector;
4491         }
4492
4493         return NT_STATUS_OK;
4494
4495   try_dskattr:
4496
4497         /* Old SMB1 core protocol fallback. */
4498         status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
4499         if (!NT_STATUS_IS_OK(status)) {
4500                 return status;
4501         }
4502         if (bsize) {
4503                 *bsize = (uint64_t)old_bsize;
4504         }
4505         if (total) {
4506                 *total = (uint64_t)old_total;
4507         }
4508         if (avail) {
4509                 *avail = (uint64_t)old_avail;
4510         }
4511         return NT_STATUS_OK;
4512 }
4513
4514 /****************************************************************************
4515  Create and open a temporary file.
4516 ****************************************************************************/
4517
4518 static void cli_ctemp_done(struct tevent_req *subreq);
4519
4520 struct ctemp_state {
4521         uint16_t vwv[3];
4522         char *ret_path;
4523         uint16_t fnum;
4524 };
4525
4526 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4527                                 struct tevent_context *ev,
4528                                 struct cli_state *cli,
4529                                 const char *path)
4530 {
4531         struct tevent_req *req = NULL, *subreq = NULL;
4532         struct ctemp_state *state = NULL;
4533         uint8_t additional_flags = 0;
4534         uint16_t additional_flags2 = 0;
4535         uint8_t *bytes = NULL;
4536
4537         req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4538         if (req == NULL) {
4539                 return NULL;
4540         }
4541
4542         SSVAL(state->vwv,0,0);
4543         SIVALS(state->vwv+1,0,-1);
4544
4545         bytes = talloc_array(state, uint8_t, 1);
4546         if (tevent_req_nomem(bytes, req)) {
4547                 return tevent_req_post(req, ev);
4548         }
4549         bytes[0] = 4;
4550         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
4551                                    strlen(path)+1, NULL);
4552         if (tevent_req_nomem(bytes, req)) {
4553                 return tevent_req_post(req, ev);
4554         }
4555
4556         if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
4557                 additional_flags2 = FLAGS2_REPARSE_PATH;
4558         }
4559
4560         subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4561                         additional_flags2,
4562                         3, state->vwv, talloc_get_size(bytes), bytes);
4563         if (tevent_req_nomem(subreq, req)) {
4564                 return tevent_req_post(req, ev);
4565         }
4566         tevent_req_set_callback(subreq, cli_ctemp_done, req);
4567         return req;
4568 }
4569
4570 static void cli_ctemp_done(struct tevent_req *subreq)
4571 {
4572         struct tevent_req *req = tevent_req_callback_data(
4573                                 subreq, struct tevent_req);
4574         struct ctemp_state *state = tevent_req_data(
4575                                 req, struct ctemp_state);
4576         NTSTATUS status;
4577         uint8_t wcnt;
4578         uint16_t *vwv;
4579         uint32_t num_bytes = 0;
4580         uint8_t *bytes = NULL;
4581
4582         status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
4583                               &num_bytes, &bytes);
4584         TALLOC_FREE(subreq);
4585         if (tevent_req_nterror(req, status)) {
4586                 return;
4587         }
4588
4589         state->fnum = SVAL(vwv+0, 0);
4590
4591         /* From W2K3, the result is just the ASCII name */
4592         if (num_bytes < 2) {
4593                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
4594                 return;
4595         }
4596
4597         if (pull_string_talloc(state,
4598                         NULL,
4599                         0,
4600                         &state->ret_path,
4601                         bytes,
4602                         num_bytes,
4603                         STR_ASCII) == 0) {
4604                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4605                 return;
4606         }
4607         tevent_req_done(req);
4608 }
4609
4610 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
4611                         TALLOC_CTX *ctx,
4612                         uint16_t *pfnum,
4613                         char **outfile)
4614 {
4615         struct ctemp_state *state = tevent_req_data(req,
4616                         struct ctemp_state);
4617         NTSTATUS status;
4618
4619         if (tevent_req_is_nterror(req, &status)) {
4620                 return status;
4621         }
4622         *pfnum = state->fnum;
4623         *outfile = talloc_strdup(ctx, state->ret_path);
4624         if (!*outfile) {
4625                 return NT_STATUS_NO_MEMORY;
4626         }
4627         return NT_STATUS_OK;
4628 }
4629
4630 NTSTATUS cli_ctemp(struct cli_state *cli,
4631                         TALLOC_CTX *ctx,
4632                         const char *path,
4633                         uint16_t *pfnum,
4634                         char **out_path)
4635 {
4636         TALLOC_CTX *frame = talloc_stackframe();
4637         struct tevent_context *ev;
4638         struct tevent_req *req;
4639         NTSTATUS status = NT_STATUS_OK;
4640
4641         if (smbXcli_conn_has_async_calls(cli->conn)) {
4642                 /*
4643                  * Can't use sync call while an async call is in flight
4644                  */
4645                 status = NT_STATUS_INVALID_PARAMETER;
4646                 goto fail;
4647         }
4648
4649         ev = samba_tevent_context_init(frame);
4650         if (ev == NULL) {
4651                 status = NT_STATUS_NO_MEMORY;
4652                 goto fail;
4653         }
4654
4655         req = cli_ctemp_send(frame, ev, cli, path);
4656         if (req == NULL) {
4657                 status = NT_STATUS_NO_MEMORY;
4658                 goto fail;
4659         }
4660
4661         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4662                 goto fail;
4663         }
4664
4665         status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4666
4667  fail:
4668         TALLOC_FREE(frame);
4669         return status;
4670 }
4671
4672 /*
4673    send a raw ioctl - used by the torture code
4674 */
4675 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4676 {
4677         uint16_t vwv[3];
4678         NTSTATUS status;
4679
4680         SSVAL(vwv+0, 0, fnum);
4681         SSVAL(vwv+1, 0, code>>16);
4682         SSVAL(vwv+2, 0, (code&0xFFFF));
4683
4684         status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4685                          NULL, 0, NULL, NULL, NULL, NULL);
4686         if (!NT_STATUS_IS_OK(status)) {
4687                 return status;
4688         }
4689         *blob = data_blob_null;
4690         return NT_STATUS_OK;
4691 }
4692
4693 /*********************************************************
4694  Set an extended attribute utility fn.
4695 *********************************************************/
4696
4697 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
4698                            uint8_t *param, unsigned int param_len,
4699                            const char *ea_name,
4700                            const char *ea_val, size_t ea_len)
4701 {
4702         uint16_t setup[1];
4703         unsigned int data_len = 0;
4704         uint8_t *data = NULL;
4705         char *p;
4706         size_t ea_namelen = strlen(ea_name);
4707         NTSTATUS status;
4708
4709         SSVAL(setup, 0, setup_val);
4710
4711         if (ea_namelen == 0 && ea_len == 0) {
4712                 data_len = 4;
4713                 data = talloc_array(talloc_tos(),
4714                                 uint8_t,
4715                                 data_len);
4716                 if (!data) {
4717                         return NT_STATUS_NO_MEMORY;
4718                 }
4719                 p = (char *)data;
4720                 SIVAL(p,0,data_len);
4721         } else {
4722                 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4723                 data = talloc_array(talloc_tos(),
4724                                 uint8_t,
4725                                 data_len);
4726                 if (!data) {
4727                         return NT_STATUS_NO_MEMORY;
4728                 }
4729                 p = (char *)data;
4730                 SIVAL(p,0,data_len);
4731                 p += 4;
4732                 SCVAL(p, 0, 0); /* EA flags. */
4733                 SCVAL(p, 1, ea_namelen);
4734                 SSVAL(p, 2, ea_len);
4735                 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4736                 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4737         }
4738
4739         /*
4740          * FIXME - if we want to do previous version path
4741          * processing on an EA set call we need to turn this
4742          * into calls to cli_trans_send()/cli_trans_recv()
4743          * with a temporary event context, as cli_trans_send()
4744          * have access to the additional_flags2 needed to
4745          * send @GMT- paths. JRA.
4746          */
4747
4748         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
4749                            setup, 1, 0,
4750                            param, param_len, 2,
4751                            data,  data_len, 0,
4752                            NULL,
4753                            NULL, 0, NULL, /* rsetup */
4754                            NULL, 0, NULL, /* rparam */
4755                            NULL, 0, NULL); /* rdata */
4756         talloc_free(data);
4757         return status;
4758 }
4759
4760 /*********************************************************
4761  Set an extended attribute on a pathname.
4762 *********************************************************/
4763
4764 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
4765                          const char *ea_name, const char *ea_val,
4766                          size_t ea_len)
4767 {
4768         unsigned int param_len = 0;
4769         uint8_t *param;
4770         NTSTATUS status;
4771         TALLOC_CTX *frame = NULL;
4772
4773         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4774                 return cli_smb2_set_ea_path(cli,
4775                                         path,
4776                                         ea_name,
4777                                         ea_val,
4778                                         ea_len);
4779         }
4780
4781         frame = talloc_stackframe();
4782
4783         param = talloc_array(frame, uint8_t, 6);
4784         if (!param) {
4785                 status = NT_STATUS_NO_MEMORY;
4786                 goto fail;
4787         }
4788         SSVAL(param,0,SMB_INFO_SET_EA);
4789         SSVAL(param,2,0);
4790         SSVAL(param,4,0);
4791
4792         param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
4793                                       path, strlen(path)+1,
4794                                       NULL);
4795         param_len = talloc_get_size(param);
4796
4797         status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
4798                             ea_name, ea_val, ea_len);
4799
4800   fail:
4801
4802         TALLOC_FREE(frame);
4803         return status;
4804 }
4805
4806 /*********************************************************
4807  Set an extended attribute on an fnum.
4808 *********************************************************/
4809
4810 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
4811                          const char *ea_name, const char *ea_val,
4812                          size_t ea_len)
4813 {
4814         uint8_t param[6];
4815
4816         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4817                 return cli_smb2_set_ea_fnum(cli,
4818                                         fnum,
4819                                         ea_name,
4820                                         ea_val,
4821                                         ea_len);
4822         }
4823
4824         memset(param, 0, 6);
4825         SSVAL(param,0,fnum);
4826         SSVAL(param,2,SMB_INFO_SET_EA);
4827
4828         return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
4829                           ea_name, ea_val, ea_len);
4830 }
4831
4832 /*********************************************************
4833  Get an extended attribute list utility fn.
4834 *********************************************************/
4835
4836 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4837                           size_t rdata_len,
4838                           size_t *pnum_eas, struct ea_struct **pea_list)
4839 {
4840         struct ea_struct *ea_list = NULL;
4841         size_t num_eas;
4842         size_t ea_size;
4843         const uint8_t *p;
4844
4845         if (rdata_len < 4) {
4846                 return false;
4847         }
4848
4849         ea_size = (size_t)IVAL(rdata,0);
4850         if (ea_size > rdata_len) {
4851                 return false;
4852         }
4853
4854         if (ea_size == 0) {
4855                 /* No EA's present. */
4856                 *pnum_eas = 0;
4857                 *pea_list = NULL;
4858                 return true;
4859         }
4860
4861         p = rdata + 4;
4862         ea_size -= 4;
4863
4864         /* Validate the EA list and count it. */
4865         for (num_eas = 0; ea_size >= 4; num_eas++) {
4866                 unsigned int ea_namelen = CVAL(p,1);
4867                 unsigned int ea_valuelen = SVAL(p,2);
4868                 if (ea_namelen == 0) {
4869                         return false;
4870                 }
4871                 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4872                         return false;
4873                 }
4874                 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4875                 p += 4 + ea_namelen + 1 + ea_valuelen;
4876         }
4877
4878         if (num_eas == 0) {
4879                 *pnum_eas = 0;
4880                 *pea_list = NULL;
4881                 return true;
4882         }
4883
4884         *pnum_eas = num_eas;
4885         if (!pea_list) {
4886                 /* Caller only wants number of EA's. */
4887                 return true;
4888         }
4889
4890         ea_list = talloc_array(ctx, struct ea_struct, num_eas);
4891         if (!ea_list) {
4892                 return false;
4893         }
4894
4895         ea_size = (size_t)IVAL(rdata,0);
4896         p = rdata + 4;
4897
4898         for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4899                 struct ea_struct *ea = &ea_list[num_eas];
4900                 fstring unix_ea_name;
4901                 unsigned int ea_namelen = CVAL(p,1);
4902                 unsigned int ea_valuelen = SVAL(p,2);
4903
4904                 ea->flags = CVAL(p,0);
4905                 unix_ea_name[0] = '\0';
4906                 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
4907                 ea->name = talloc_strdup(ea_list, unix_ea_name);
4908                 if (!ea->name) {
4909                         goto fail;
4910                 }
4911                 /* Ensure the value is null terminated (in case it's a string). */
4912                 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4913                 if (!ea->value.data) {
4914                         goto fail;
4915                 }
4916                 if (ea_valuelen) {
4917                         memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4918                 }
4919                 ea->value.data[ea_valuelen] = 0;
4920                 ea->value.length--;
4921                 p += 4 + ea_namelen + 1 + ea_valuelen;
4922         }
4923
4924         *pea_list = ea_list;
4925         return true;
4926
4927 fail:
4928         TALLOC_FREE(ea_list);
4929         return false;
4930 }
4931
4932 /*********************************************************
4933  Get an extended attribute list from a pathname.
4934 *********************************************************/
4935
4936 struct cli_get_ea_list_path_state {
4937         uint32_t num_data;
4938         uint8_t *data;
4939 };
4940
4941 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4942
4943 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4944                                              struct tevent_context *ev,
4945                                              struct cli_state *cli,
4946                                              const char *fname)
4947 {
4948         struct tevent_req *req, *subreq;
4949         struct cli_get_ea_list_path_state *state;
4950
4951         req = tevent_req_create(mem_ctx, &state,
4952                                 struct cli_get_ea_list_path_state);
4953         if (req == NULL) {
4954                 return NULL;
4955         }
4956         subreq = cli_qpathinfo_send(state, ev, cli, fname,
4957                                     SMB_INFO_QUERY_ALL_EAS, 4,
4958                                     CLI_BUFFER_SIZE);
4959         if (tevent_req_nomem(subreq, req)) {
4960                 return tevent_req_post(req, ev);
4961         }
4962         tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4963         return req;
4964 }
4965
4966 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4967 {
4968         struct tevent_req *req = tevent_req_callback_data(
4969                                 subreq, struct tevent_req);
4970         struct cli_get_ea_list_path_state *state = tevent_req_data(
4971                 req, struct cli_get_ea_list_path_state);
4972         NTSTATUS status;
4973
4974         status = cli_qpathinfo_recv(subreq, state, &state->data,
4975                                     &state->num_data);
4976         TALLOC_FREE(subreq);
4977         if (tevent_req_nterror(req, status)) {
4978                 return;
4979         }
4980         tevent_req_done(req);
4981 }
4982
4983 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4984                                    size_t *pnum_eas, struct ea_struct **peas)
4985 {
4986         struct cli_get_ea_list_path_state *state = tevent_req_data(
4987                 req, struct cli_get_ea_list_path_state);
4988         NTSTATUS status;
4989
4990         if (tevent_req_is_nterror(req, &status)) {
4991                 return status;
4992         }
4993         if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4994                            pnum_eas, peas)) {
4995                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4996         }
4997         return NT_STATUS_OK;
4998 }
4999
5000 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
5001                 TALLOC_CTX *ctx,
5002                 size_t *pnum_eas,
5003                 struct ea_struct **pea_list)
5004 {
5005         TALLOC_CTX *frame = NULL;
5006         struct tevent_context *ev = NULL;
5007         struct tevent_req *req = NULL;
5008         NTSTATUS status = NT_STATUS_NO_MEMORY;
5009
5010         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5011                 return cli_smb2_get_ea_list_path(cli,
5012                                         path,
5013                                         ctx,
5014                                         pnum_eas,
5015                                         pea_list);
5016         }
5017
5018         frame = talloc_stackframe();
5019
5020         if (smbXcli_conn_has_async_calls(cli->conn)) {
5021                 /*
5022                  * Can't use sync call while an async call is in flight
5023                  */
5024                 status = NT_STATUS_INVALID_PARAMETER;
5025                 goto fail;
5026         }
5027         ev = samba_tevent_context_init(frame);
5028         if (ev == NULL) {
5029                 goto fail;
5030         }
5031         req = cli_get_ea_list_path_send(frame, ev, cli, path);
5032         if (req == NULL) {
5033                 goto fail;
5034         }
5035         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5036                 goto fail;
5037         }
5038         status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
5039  fail:
5040         TALLOC_FREE(frame);
5041         return status;
5042 }
5043
5044 /****************************************************************************
5045  Convert open "flags" arg to uint32_t on wire.
5046 ****************************************************************************/
5047
5048 static uint32_t open_flags_to_wire(int flags)
5049 {
5050         int open_mode = flags & O_ACCMODE;
5051         uint32_t ret = 0;
5052
5053         switch (open_mode) {
5054                 case O_WRONLY:
5055                         ret |= SMB_O_WRONLY;
5056                         break;
5057                 case O_RDWR:
5058                         ret |= SMB_O_RDWR;
5059                         break;
5060                 default:
5061                 case O_RDONLY:
5062                         ret |= SMB_O_RDONLY;
5063                         break;
5064         }
5065
5066         if (flags & O_CREAT) {
5067                 ret |= SMB_O_CREAT;
5068         }
5069         if (flags & O_EXCL) {
5070                 ret |= SMB_O_EXCL;
5071         }
5072         if (flags & O_TRUNC) {
5073                 ret |= SMB_O_TRUNC;
5074         }
5075 #if defined(O_SYNC)
5076         if (flags & O_SYNC) {
5077                 ret |= SMB_O_SYNC;
5078         }
5079 #endif /* O_SYNC */
5080         if (flags & O_APPEND) {
5081                 ret |= SMB_O_APPEND;
5082         }
5083 #if defined(O_DIRECT)
5084         if (flags & O_DIRECT) {
5085                 ret |= SMB_O_DIRECT;
5086         }
5087 #endif
5088 #if defined(O_DIRECTORY)
5089         if (flags & O_DIRECTORY) {
5090                 ret |= SMB_O_DIRECTORY;
5091         }
5092 #endif
5093         return ret;
5094 }
5095
5096 /****************************************************************************
5097  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
5098 ****************************************************************************/
5099
5100 struct posix_open_state {
5101         uint16_t setup;
5102         uint8_t *param;
5103         uint8_t data[18];
5104         uint16_t fnum; /* Out */
5105 };
5106
5107 static void cli_posix_open_internal_done(struct tevent_req *subreq)
5108 {
5109         struct tevent_req *req = tevent_req_callback_data(
5110                                 subreq, struct tevent_req);
5111         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
5112         NTSTATUS status;
5113         uint8_t *data;
5114         uint32_t num_data;
5115
5116         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5117                                 NULL, 0, NULL, &data, 12, &num_data);
5118         TALLOC_FREE(subreq);
5119         if (tevent_req_nterror(req, status)) {
5120                 return;
5121         }
5122         state->fnum = SVAL(data,2);
5123         tevent_req_done(req);
5124 }
5125
5126 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
5127                                         struct tevent_context *ev,
5128                                         struct cli_state *cli,
5129                                         const char *fname,
5130                                         int flags,
5131                                         mode_t mode,
5132                                         bool is_dir)
5133 {
5134         struct tevent_req *req = NULL, *subreq = NULL;
5135         struct posix_open_state *state = NULL;
5136         uint32_t wire_flags = open_flags_to_wire(flags);
5137
5138         req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
5139         if (req == NULL) {
5140                 return NULL;
5141         }
5142
5143         /* Setup setup word. */
5144         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
5145
5146         /* Setup param array. */
5147         state->param = talloc_array(state, uint8_t, 6);
5148         if (tevent_req_nomem(state->param, req)) {
5149                 return tevent_req_post(req, ev);
5150         }
5151         memset(state->param, '\0', 6);
5152         SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
5153
5154         state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn), fname,
5155                                    strlen(fname)+1, NULL);
5156
5157         if (tevent_req_nomem(state->param, req)) {
5158                 return tevent_req_post(req, ev);
5159         }
5160
5161         /* Setup data words. */
5162         if (is_dir) {
5163                 wire_flags |= SMB_O_DIRECTORY;
5164         }
5165
5166         SIVAL(state->data,0,0); /* No oplock. */
5167         SIVAL(state->data,4,wire_flags);
5168         SIVAL(state->data,8,unix_perms_to_wire(mode));
5169         SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
5170         SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
5171
5172         subreq = cli_trans_send(state,                  /* mem ctx. */
5173                                 ev,                     /* event ctx. */
5174                                 cli,                    /* cli_state. */
5175                                 0,                      /* additional_flags2 */
5176                                 SMBtrans2,              /* cmd. */
5177                                 NULL,                   /* pipe name. */
5178                                 -1,                     /* fid. */
5179                                 0,                      /* function. */
5180                                 0,                      /* flags. */
5181                                 &state->setup,          /* setup. */
5182                                 1,                      /* num setup uint16_t words. */
5183                                 0,                      /* max returned setup. */
5184                                 state->param,           /* param. */
5185                                 talloc_get_size(state->param),/* num param. */
5186                                 2,                      /* max returned param. */
5187                                 state->data,            /* data. */
5188                                 18,                     /* num data. */
5189                                 12);                    /* max returned data. */
5190
5191         if (tevent_req_nomem(subreq, req)) {
5192                 return tevent_req_post(req, ev);
5193         }
5194         tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
5195         return req;
5196 }
5197
5198 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
5199                                         struct tevent_context *ev,
5200                                         struct cli_state *cli,
5201                                         const char *fname,
5202                                         int flags,
5203                                         mode_t mode)
5204 {
5205         return cli_posix_open_internal_send(mem_ctx, ev,
5206                                 cli, fname, flags, mode, false);
5207 }
5208
5209 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
5210 {
5211         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
5212         NTSTATUS status;
5213
5214         if (tevent_req_is_nterror(req, &status)) {
5215                 return status;
5216         }
5217         *pfnum = state->fnum;
5218         return NT_STATUS_OK;
5219 }
5220
5221 /****************************************************************************
5222  Open - POSIX semantics. Doesn't request oplock.
5223 ****************************************************************************/
5224
5225 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
5226                         int flags, mode_t mode, uint16_t *pfnum)
5227 {
5228
5229         TALLOC_CTX *frame = talloc_stackframe();
5230         struct tevent_context *ev = NULL;
5231         struct tevent_req *req = NULL;
5232         NTSTATUS status = NT_STATUS_OK;
5233
5234         if (smbXcli_conn_has_async_calls(cli->conn)) {
5235                 /*
5236                  * Can't use sync call while an async call is in flight
5237                  */
5238                 status = NT_STATUS_INVALID_PARAMETER;
5239                 goto fail;
5240         }
5241
5242         ev = samba_tevent_context_init(frame);
5243         if (ev == NULL) {
5244                 status = NT_STATUS_NO_MEMORY;
5245                 goto fail;
5246         }
5247
5248         req = cli_posix_open_send(frame,
5249                                 ev,
5250                                 cli,
5251                                 fname,
5252                                 flags,
5253                                 mode);
5254         if (req == NULL) {
5255                 status = NT_STATUS_NO_MEMORY;
5256                 goto fail;
5257         }
5258
5259         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5260                 goto fail;
5261         }
5262
5263         status = cli_posix_open_recv(req, pfnum);
5264
5265  fail:
5266         TALLOC_FREE(frame);
5267         return status;
5268 }
5269
5270 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
5271                                         struct tevent_context *ev,
5272                                         struct cli_state *cli,
5273                                         const char *fname,
5274                                         mode_t mode)
5275 {
5276         return cli_posix_open_internal_send(mem_ctx, ev,
5277                                 cli, fname, O_CREAT, mode, true);
5278 }
5279
5280 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
5281 {
5282         return tevent_req_simple_recv_ntstatus(req);
5283 }
5284
5285 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
5286 {
5287         TALLOC_CTX *frame = talloc_stackframe();
5288         struct tevent_context *ev = NULL;
5289         struct tevent_req *req = NULL;
5290         NTSTATUS status = NT_STATUS_OK;
5291
5292         if (smbXcli_conn_has_async_calls(cli->conn)) {
5293                 /*
5294                  * Can't use sync call while an async call is in flight
5295                  */
5296                 status = NT_STATUS_INVALID_PARAMETER;
5297                 goto fail;
5298         }
5299
5300         ev = samba_tevent_context_init(frame);
5301         if (ev == NULL) {
5302                 status = NT_STATUS_NO_MEMORY;
5303                 goto fail;
5304         }
5305
5306         req = cli_posix_mkdir_send(frame,
5307                                 ev,
5308                                 cli,
5309                                 fname,
5310                                 mode);
5311         if (req == NULL) {
5312                 status = NT_STATUS_NO_MEMORY;
5313                 goto fail;
5314         }
5315
5316         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5317                 goto fail;
5318         }
5319
5320         status = cli_posix_mkdir_recv(req);
5321
5322  fail:
5323         TALLOC_FREE(frame);
5324         return status;
5325 }
5326
5327 /****************************************************************************
5328  unlink or rmdir - POSIX semantics.
5329 ****************************************************************************/
5330
5331 struct cli_posix_unlink_internal_state {
5332         uint8_t data[2];
5333 };
5334
5335 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
5336
5337 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
5338                                         struct tevent_context *ev,
5339                                         struct cli_state *cli,
5340                                         const char *fname,
5341                                         uint16_t level)
5342 {
5343         struct tevent_req *req = NULL, *subreq = NULL;
5344         struct cli_posix_unlink_internal_state *state = NULL;
5345
5346         req = tevent_req_create(mem_ctx, &state,
5347                                 struct cli_posix_unlink_internal_state);
5348         if (req == NULL) {
5349                 return NULL;
5350         }
5351
5352         /* Setup data word. */
5353         SSVAL(state->data, 0, level);
5354
5355         subreq = cli_setpathinfo_send(state, ev, cli,
5356                                       SMB_POSIX_PATH_UNLINK,
5357                                       fname,
5358                                       state->data, sizeof(state->data));
5359         if (tevent_req_nomem(subreq, req)) {
5360                 return tevent_req_post(req, ev);
5361         }
5362         tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
5363         return req;
5364 }
5365
5366 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
5367 {
5368         NTSTATUS status = cli_setpathinfo_recv(subreq);
5369         tevent_req_simple_finish_ntstatus(subreq, status);
5370 }
5371
5372 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
5373                                         struct tevent_context *ev,
5374                                         struct cli_state *cli,
5375                                         const char *fname)
5376 {
5377         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
5378                                               SMB_POSIX_UNLINK_FILE_TARGET);
5379 }
5380
5381 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
5382 {
5383         return tevent_req_simple_recv_ntstatus(req);
5384 }
5385
5386 /****************************************************************************
5387  unlink - POSIX semantics.
5388 ****************************************************************************/
5389
5390 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
5391 {
5392         TALLOC_CTX *frame = talloc_stackframe();
5393         struct tevent_context *ev = NULL;
5394         struct tevent_req *req = NULL;
5395         NTSTATUS status = NT_STATUS_OK;
5396
5397         if (smbXcli_conn_has_async_calls(cli->conn)) {
5398                 /*
5399                  * Can't use sync call while an async call is in flight
5400                  */
5401                 status = NT_STATUS_INVALID_PARAMETER;
5402                 goto fail;
5403         }
5404
5405         ev = samba_tevent_context_init(frame);
5406         if (ev == NULL) {
5407                 status = NT_STATUS_NO_MEMORY;
5408                 goto fail;
5409         }
5410
5411         req = cli_posix_unlink_send(frame,
5412                                 ev,
5413                                 cli,
5414                                 fname);
5415         if (req == NULL) {
5416                 status = NT_STATUS_NO_MEMORY;
5417                 goto fail;
5418         }
5419
5420         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5421                 goto fail;
5422         }
5423
5424         status = cli_posix_unlink_recv(req);
5425
5426  fail:
5427         TALLOC_FREE(frame);
5428         return status;
5429 }
5430
5431 /****************************************************************************
5432  rmdir - POSIX semantics.
5433 ****************************************************************************/
5434
5435 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
5436                                         struct tevent_context *ev,
5437                                         struct cli_state *cli,
5438                                         const char *fname)
5439 {
5440         return cli_posix_unlink_internal_send(
5441                 mem_ctx, ev, cli, fname,
5442                 SMB_POSIX_UNLINK_DIRECTORY_TARGET);
5443 }
5444
5445 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
5446 {
5447         return tevent_req_simple_recv_ntstatus(req);
5448 }
5449
5450 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
5451 {
5452         TALLOC_CTX *frame = talloc_stackframe();
5453         struct tevent_context *ev = NULL;
5454         struct tevent_req *req = NULL;
5455         NTSTATUS status = NT_STATUS_OK;
5456
5457         if (smbXcli_conn_has_async_calls(cli->conn)) {
5458                 /*
5459                  * Can't use sync call while an async call is in flight
5460                  */
5461                 status = NT_STATUS_INVALID_PARAMETER;
5462                 goto fail;
5463         }
5464
5465         ev = samba_tevent_context_init(frame);
5466         if (ev == NULL) {
5467                 status = NT_STATUS_NO_MEMORY;
5468                 goto fail;
5469         }
5470
5471         req = cli_posix_rmdir_send(frame,
5472                                 ev,
5473                                 cli,
5474                                 fname);
5475         if (req == NULL) {
5476                 status = NT_STATUS_NO_MEMORY;
5477                 goto fail;
5478         }
5479
5480         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5481                 goto fail;
5482         }
5483
5484         status = cli_posix_rmdir_recv(req, frame);
5485
5486  fail:
5487         TALLOC_FREE(frame);
5488         return status;
5489 }
5490
5491 /****************************************************************************
5492  filechangenotify
5493 ****************************************************************************/
5494
5495 struct cli_notify_state {
5496         struct tevent_req *subreq;
5497         uint8_t setup[8];
5498         uint32_t num_changes;
5499         struct notify_change *changes;
5500 };
5501
5502 static void cli_notify_done(struct tevent_req *subreq);
5503 static void cli_notify_done_smb2(struct tevent_req *subreq);
5504 static bool cli_notify_cancel(struct tevent_req *req);
5505
5506 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
5507                                    struct tevent_context *ev,
5508                                    struct cli_state *cli, uint16_t fnum,
5509                                    uint32_t buffer_size,
5510                                    uint32_t completion_filter, bool recursive)
5511 {
5512         struct tevent_req *req;
5513         struct cli_notify_state *state;
5514         unsigned old_timeout;
5515
5516         req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
5517         if (req == NULL) {
5518                 return NULL;
5519         }
5520
5521         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5522                 /*
5523                  * Notifies should not time out
5524                  */
5525                 old_timeout = cli_set_timeout(cli, 0);
5526
5527                 state->subreq = cli_smb2_notify_send(
5528                         state,
5529                         ev,
5530                         cli,
5531                         fnum,
5532                         buffer_size,
5533                         completion_filter,
5534                         recursive);
5535
5536                 cli_set_timeout(cli, old_timeout);
5537
5538                 if (tevent_req_nomem(state->subreq, req)) {
5539                         return tevent_req_post(req, ev);
5540                 }
5541                 tevent_req_set_callback(
5542                         state->subreq, cli_notify_done_smb2, req);
5543                 goto done;
5544         }
5545
5546         SIVAL(state->setup, 0, completion_filter);
5547         SSVAL(state->setup, 4, fnum);
5548         SSVAL(state->setup, 6, recursive);
5549
5550         /*
5551          * Notifies should not time out
5552          */
5553         old_timeout = cli_set_timeout(cli, 0);
5554
5555         state->subreq = cli_trans_send(
5556                 state,                  /* mem ctx. */
5557                 ev,                     /* event ctx. */
5558                 cli,                    /* cli_state. */
5559                 0,                      /* additional_flags2 */
5560                 SMBnttrans,             /* cmd. */
5561                 NULL,                   /* pipe name. */
5562                 -1,                     /* fid. */
5563                 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
5564                 0,                      /* flags. */
5565                 (uint16_t *)state->setup, /* setup. */
5566                 4,                      /* num setup uint16_t words. */
5567                 0,                      /* max returned setup. */
5568                 NULL,                   /* param. */
5569                 0,                      /* num param. */
5570                 buffer_size,            /* max returned param. */
5571                 NULL,                   /* data. */
5572                 0,                      /* num data. */
5573                 0);                     /* max returned data. */
5574
5575         cli_set_timeout(cli, old_timeout);
5576
5577         if (tevent_req_nomem(state->subreq, req)) {
5578                 return tevent_req_post(req, ev);
5579         }
5580         tevent_req_set_callback(state->subreq, cli_notify_done, req);
5581 done:
5582         tevent_req_set_cancel_fn(req, cli_notify_cancel);
5583         return req;
5584 }
5585
5586 static bool cli_notify_cancel(struct tevent_req *req)
5587 {
5588         struct cli_notify_state *state = tevent_req_data(
5589                 req, struct cli_notify_state);
5590         bool ok;
5591
5592         ok = tevent_req_cancel(state->subreq);
5593         return ok;
5594 }
5595
5596 static void cli_notify_done(struct tevent_req *subreq)
5597 {
5598         struct tevent_req *req = tevent_req_callback_data(
5599                 subreq, struct tevent_req);
5600         struct cli_notify_state *state = tevent_req_data(
5601                 req, struct cli_notify_state);
5602         NTSTATUS status;
5603         uint8_t *params;
5604         uint32_t i, ofs, num_params;
5605         uint16_t flags2;
5606
5607         status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
5608                                 &params, 0, &num_params, NULL, 0, NULL);
5609         TALLOC_FREE(subreq);
5610         state->subreq = NULL;
5611         if (tevent_req_nterror(req, status)) {
5612                 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
5613                 return;
5614         }
5615
5616         state->num_changes = 0;
5617         ofs = 0;
5618
5619         while (num_params - ofs > 12) {
5620                 uint32_t next = IVAL(params, ofs);
5621                 state->num_changes += 1;
5622
5623                 if ((next == 0) || (ofs+next >= num_params)) {
5624                         break;
5625                 }
5626                 ofs += next;
5627         }
5628
5629         state->changes = talloc_array(state, struct notify_change,
5630                                       state->num_changes);
5631         if (tevent_req_nomem(state->changes, req)) {
5632                 TALLOC_FREE(params);
5633                 return;
5634         }
5635
5636         ofs = 0;
5637
5638         for (i=0; i<state->num_changes; i++) {
5639                 uint32_t next = IVAL(params, ofs);
5640                 uint32_t len = IVAL(params, ofs+8);
5641                 ssize_t ret;
5642                 char *name;
5643
5644                 if (trans_oob(num_params, ofs + 12, len)) {
5645                         TALLOC_FREE(params);
5646                         tevent_req_nterror(
5647                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5648                         return;
5649                 }
5650
5651                 state->changes[i].action = IVAL(params, ofs+4);
5652                 ret = clistr_pull_talloc(state->changes, (char *)params, flags2,
5653                                          &name, params+ofs+12, len,
5654                                          STR_TERMINATE|STR_UNICODE);
5655                 if (ret == -1) {
5656                         TALLOC_FREE(params);
5657                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5658                         return;
5659                 }
5660                 state->changes[i].name = name;
5661                 ofs += next;
5662         }
5663
5664         TALLOC_FREE(params);
5665         tevent_req_done(req);
5666 }
5667
5668 static void cli_notify_done_smb2(struct tevent_req *subreq)
5669 {
5670         struct tevent_req *req = tevent_req_callback_data(
5671                 subreq, struct tevent_req);
5672         struct cli_notify_state *state = tevent_req_data(
5673                 req, struct cli_notify_state);
5674         NTSTATUS status;
5675
5676         status = cli_smb2_notify_recv(
5677                 subreq,
5678                 state,
5679                 &state->changes,
5680                 &state->num_changes);
5681         TALLOC_FREE(subreq);
5682         if (tevent_req_nterror(req, status)) {
5683                 return;
5684         }
5685         tevent_req_done(req);
5686 }
5687
5688 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5689                          uint32_t *pnum_changes,
5690                          struct notify_change **pchanges)
5691 {
5692         struct cli_notify_state *state = tevent_req_data(
5693                 req, struct cli_notify_state);
5694         NTSTATUS status;
5695
5696         if (tevent_req_is_nterror(req, &status)) {
5697                 return status;
5698         }
5699
5700         *pnum_changes = state->num_changes;
5701         *pchanges = talloc_move(mem_ctx, &state->changes);
5702         return NT_STATUS_OK;
5703 }
5704
5705 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
5706                     uint32_t completion_filter, bool recursive,
5707                     TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
5708                     struct notify_change **pchanges)
5709 {
5710         TALLOC_CTX *frame;
5711         struct tevent_context *ev;
5712         struct tevent_req *req;
5713         NTSTATUS status = NT_STATUS_NO_MEMORY;
5714
5715         frame = talloc_stackframe();
5716
5717         if (smbXcli_conn_has_async_calls(cli->conn)) {
5718                 /*
5719                  * Can't use sync call while an async call is in flight
5720                  */
5721                 status = NT_STATUS_INVALID_PARAMETER;
5722                 goto fail;
5723         }
5724         ev = samba_tevent_context_init(frame);
5725         if (ev == NULL) {
5726                 goto fail;
5727         }
5728         req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
5729                               completion_filter, recursive);
5730         if (req == NULL) {
5731                 goto fail;
5732         }
5733         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5734                 goto fail;
5735         }
5736         status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
5737  fail:
5738         TALLOC_FREE(frame);
5739         return status;
5740 }
5741
5742 struct cli_qpathinfo_state {
5743         uint8_t *param;
5744         uint8_t *data;
5745         uint16_t setup[1];
5746         uint32_t min_rdata;
5747         uint8_t *rdata;
5748         uint32_t num_rdata;
5749 };
5750
5751 static void cli_qpathinfo_done(struct tevent_req *subreq);
5752
5753 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
5754                                       struct tevent_context *ev,
5755                                       struct cli_state *cli, const char *fname,
5756                                       uint16_t level, uint32_t min_rdata,
5757                                       uint32_t max_rdata)
5758 {
5759         struct tevent_req *req, *subreq;
5760         struct cli_qpathinfo_state *state;
5761         uint16_t additional_flags2 = 0;
5762
5763         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
5764         if (req == NULL) {
5765                 return NULL;
5766         }
5767         state->min_rdata = min_rdata;
5768         SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
5769
5770         state->param = talloc_zero_array(state, uint8_t, 6);
5771         if (tevent_req_nomem(state->param, req)) {
5772                 return tevent_req_post(req, ev);
5773         }
5774         SSVAL(state->param, 0, level);
5775         state->param = trans2_bytes_push_str(
5776                 state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
5777         if (tevent_req_nomem(state->param, req)) {
5778                 return tevent_req_post(req, ev);
5779         }
5780
5781         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
5782                         !INFO_LEVEL_IS_UNIX(level)) {
5783                 additional_flags2 = FLAGS2_REPARSE_PATH;
5784         }
5785
5786         subreq = cli_trans_send(
5787                 state,                  /* mem ctx. */
5788                 ev,                     /* event ctx. */
5789                 cli,                    /* cli_state. */
5790                 additional_flags2,      /* additional_flags2 */
5791                 SMBtrans2,              /* cmd. */
5792                 NULL,                   /* pipe name. */
5793                 -1,                     /* fid. */
5794                 0,                      /* function. */
5795                 0,                      /* flags. */
5796                 state->setup,           /* setup. */
5797                 1,                      /* num setup uint16_t words. */
5798                 0,                      /* max returned setup. */
5799                 state->param,           /* param. */
5800                 talloc_get_size(state->param),  /* num param. */
5801                 2,                      /* max returned param. */
5802                 NULL,                   /* data. */
5803                 0,                      /* num data. */
5804                 max_rdata);             /* max returned data. */
5805
5806         if (tevent_req_nomem(subreq, req)) {
5807                 return tevent_req_post(req, ev);
5808         }
5809         tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5810         return req;
5811 }
5812
5813 static void cli_qpathinfo_done(struct tevent_req *subreq)
5814 {
5815         struct tevent_req *req = tevent_req_callback_data(
5816                 subreq, struct tevent_req);
5817         struct cli_qpathinfo_state *state = tevent_req_data(
5818                 req, struct cli_qpathinfo_state);
5819         NTSTATUS status;
5820
5821         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5822                                 NULL, 0, NULL,
5823                                 &state->rdata, state->min_rdata,
5824                                 &state->num_rdata);
5825         if (tevent_req_nterror(req, status)) {
5826                 return;
5827         }
5828         tevent_req_done(req);
5829 }
5830
5831 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5832                             uint8_t **rdata, uint32_t *num_rdata)
5833 {
5834         struct cli_qpathinfo_state *state = tevent_req_data(
5835                 req, struct cli_qpathinfo_state);
5836         NTSTATUS status;
5837
5838         if (tevent_req_is_nterror(req, &status)) {
5839                 return status;
5840         }
5841         if (rdata != NULL) {
5842                 *rdata = talloc_move(mem_ctx, &state->rdata);
5843         } else {
5844                 TALLOC_FREE(state->rdata);
5845         }
5846         if (num_rdata != NULL) {
5847                 *num_rdata = state->num_rdata;
5848         }
5849         return NT_STATUS_OK;
5850 }
5851
5852 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5853                        const char *fname, uint16_t level, uint32_t min_rdata,
5854                        uint32_t max_rdata,
5855                        uint8_t **rdata, uint32_t *num_rdata)
5856 {
5857         TALLOC_CTX *frame = talloc_stackframe();
5858         struct tevent_context *ev;
5859         struct tevent_req *req;
5860         NTSTATUS status = NT_STATUS_NO_MEMORY;
5861
5862         if (smbXcli_conn_has_async_calls(cli->conn)) {
5863                 /*
5864                  * Can't use sync call while an async call is in flight
5865                  */
5866                 status = NT_STATUS_INVALID_PARAMETER;
5867                 goto fail;
5868         }
5869         ev = samba_tevent_context_init(frame);
5870         if (ev == NULL) {
5871                 goto fail;
5872         }
5873         req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5874                                  max_rdata);
5875         if (req == NULL) {
5876                 goto fail;
5877         }
5878         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5879                 goto fail;
5880         }
5881         status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5882  fail:
5883         TALLOC_FREE(frame);
5884         return status;
5885 }
5886
5887 struct cli_qfileinfo_state {
5888         uint16_t setup[1];
5889         uint8_t param[4];
5890         uint8_t *data;
5891         uint16_t recv_flags2;
5892         uint32_t min_rdata;
5893         uint8_t *rdata;
5894         uint32_t num_rdata;
5895 };
5896
5897 static void cli_qfileinfo_done(struct tevent_req *subreq);
5898
5899 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
5900                                       struct tevent_context *ev,
5901                                       struct cli_state *cli, uint16_t fnum,
5902                                       uint16_t level, uint32_t min_rdata,
5903                                       uint32_t max_rdata)
5904 {
5905         struct tevent_req *req, *subreq;
5906         struct cli_qfileinfo_state *state;
5907
5908         req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
5909         if (req == NULL) {
5910                 return NULL;
5911         }
5912         state->min_rdata = min_rdata;
5913         SSVAL(state->param, 0, fnum);
5914         SSVAL(state->param, 2, level);
5915         SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
5916
5917         subreq = cli_trans_send(
5918                 state,                  /* mem ctx. */
5919                 ev,                     /* event ctx. */
5920                 cli,                    /* cli_state. */
5921                 0,                      /* additional_flags2 */
5922                 SMBtrans2,              /* cmd. */
5923                 NULL,                   /* pipe name. */
5924                 -1,                     /* fid. */
5925                 0,                      /* function. */
5926                 0,                      /* flags. */
5927                 state->setup,           /* setup. */
5928                 1,                      /* num setup uint16_t words. */
5929                 0,                      /* max returned setup. */
5930                 state->param,           /* param. */
5931                 sizeof(state->param),   /* num param. */
5932                 2,                      /* max returned param. */
5933                 NULL,                   /* data. */
5934                 0,                      /* num data. */
5935                 max_rdata);             /* max returned data. */
5936
5937         if (tevent_req_nomem(subreq, req)) {
5938                 return tevent_req_post(req, ev);
5939         }
5940         tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
5941         return req;
5942 }
5943
5944 static void cli_qfileinfo_done(struct tevent_req *subreq)
5945 {
5946         struct tevent_req *req = tevent_req_callback_data(
5947                 subreq, struct tevent_req);
5948         struct cli_qfileinfo_state *state = tevent_req_data(
5949                 req, struct cli_qfileinfo_state);
5950         NTSTATUS status;
5951
5952         status = cli_trans_recv(subreq, state,
5953                                 &state->recv_flags2,
5954                                 NULL, 0, NULL,
5955                                 NULL, 0, NULL,
5956                                 &state->rdata, state->min_rdata,
5957                                 &state->num_rdata);
5958         if (tevent_req_nterror(req, status)) {
5959                 return;
5960         }
5961         tevent_req_done(req);
5962 }
5963
5964 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5965                             uint16_t *recv_flags2,
5966                             uint8_t **rdata, uint32_t *num_rdata)
5967 {
5968         struct cli_qfileinfo_state *state = tevent_req_data(
5969                 req, struct cli_qfileinfo_state);
5970         NTSTATUS status;
5971
5972         if (tevent_req_is_nterror(req, &status)) {
5973                 return status;
5974         }
5975
5976         if (recv_flags2 != NULL) {
5977                 *recv_flags2 = state->recv_flags2;
5978         }
5979         if (rdata != NULL) {
5980                 *rdata = talloc_move(mem_ctx, &state->rdata);
5981         } else {
5982                 TALLOC_FREE(state->rdata);
5983         }
5984         if (num_rdata != NULL) {
5985                 *num_rdata = state->num_rdata;
5986         }
5987         return NT_STATUS_OK;
5988 }
5989
5990 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5991                        uint16_t fnum, uint16_t level, uint32_t min_rdata,
5992                        uint32_t max_rdata, uint16_t *recv_flags2,
5993                        uint8_t **rdata, uint32_t *num_rdata)
5994 {
5995         TALLOC_CTX *frame = talloc_stackframe();
5996         struct tevent_context *ev;
5997         struct tevent_req *req;
5998         NTSTATUS status = NT_STATUS_NO_MEMORY;
5999
6000         if (smbXcli_conn_has_async_calls(cli->conn)) {
6001                 /*
6002                  * Can't use sync call while an async call is in flight
6003                  */
6004                 status = NT_STATUS_INVALID_PARAMETER;
6005                 goto fail;
6006         }
6007         ev = samba_tevent_context_init(frame);
6008         if (ev == NULL) {
6009                 goto fail;
6010         }
6011         req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
6012                                  max_rdata);
6013         if (req == NULL) {
6014                 goto fail;
6015         }
6016         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6017                 goto fail;
6018         }
6019         status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
6020  fail:
6021         TALLOC_FREE(frame);
6022         return status;
6023 }
6024
6025 struct cli_flush_state {
6026         uint16_t vwv[1];
6027 };
6028
6029 static void cli_flush_done(struct tevent_req *subreq);
6030
6031 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
6032                                   struct tevent_context *ev,
6033                                   struct cli_state *cli,
6034                                   uint16_t fnum)
6035 {
6036         struct tevent_req *req, *subreq;
6037         struct cli_flush_state *state;
6038
6039         req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
6040         if (req == NULL) {
6041                 return NULL;
6042         }
6043         SSVAL(state->vwv + 0, 0, fnum);
6044
6045         subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
6046                               0, NULL);
6047         if (tevent_req_nomem(subreq, req)) {
6048                 return tevent_req_post(req, ev);
6049         }
6050         tevent_req_set_callback(subreq, cli_flush_done, req);
6051         return req;
6052 }
6053
6054 static void cli_flush_done(struct tevent_req *subreq)
6055 {
6056         struct tevent_req *req = tevent_req_callback_data(
6057                 subreq, struct tevent_req);
6058         NTSTATUS status;
6059
6060         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
6061         TALLOC_FREE(subreq);
6062         if (tevent_req_nterror(req, status)) {
6063                 return;
6064         }
6065         tevent_req_done(req);
6066 }
6067
6068 NTSTATUS cli_flush_recv(struct tevent_req *req)
6069 {
6070         return tevent_req_simple_recv_ntstatus(req);
6071 }
6072
6073 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
6074 {
6075         TALLOC_CTX *frame = talloc_stackframe();
6076         struct tevent_context *ev;
6077         struct tevent_req *req;
6078         NTSTATUS status = NT_STATUS_NO_MEMORY;
6079
6080         if (smbXcli_conn_has_async_calls(cli->conn)) {
6081                 /*
6082                  * Can't use sync call while an async call is in flight
6083                  */
6084                 status = NT_STATUS_INVALID_PARAMETER;
6085                 goto fail;
6086         }
6087         ev = samba_tevent_context_init(frame);
6088         if (ev == NULL) {
6089                 goto fail;
6090         }
6091         req = cli_flush_send(frame, ev, cli, fnum);
6092         if (req == NULL) {
6093                 goto fail;
6094         }
6095         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6096                 goto fail;
6097         }
6098         status = cli_flush_recv(req);
6099  fail:
6100         TALLOC_FREE(frame);
6101         return status;
6102 }
6103
6104 struct cli_shadow_copy_data_state {
6105         uint16_t setup[4];
6106         uint8_t *data;
6107         uint32_t num_data;
6108         bool get_names;
6109 };
6110
6111 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
6112
6113 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
6114                                              struct tevent_context *ev,
6115                                              struct cli_state *cli,
6116                                              uint16_t fnum,
6117                                              bool get_names)
6118 {
6119         struct tevent_req *req, *subreq;
6120         struct cli_shadow_copy_data_state *state;
6121         uint32_t ret_size;
6122
6123         req = tevent_req_create(mem_ctx, &state,
6124                                 struct cli_shadow_copy_data_state);
6125         if (req == NULL) {
6126                 return NULL;
6127         }
6128         state->get_names = get_names;
6129         ret_size = get_names ? CLI_BUFFER_SIZE : 16;
6130
6131         SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
6132         SSVAL(state->setup + 2, 0, fnum);
6133         SCVAL(state->setup + 3, 0, 1); /* isFsctl */
6134         SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
6135
6136         subreq = cli_trans_send(
6137                 state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
6138                 state->setup, ARRAY_SIZE(state->setup),
6139                 ARRAY_SIZE(state->setup),
6140                 NULL, 0, 0,
6141                 NULL, 0, ret_size);
6142         if (tevent_req_nomem(subreq, req)) {
6143                 return tevent_req_post(req, ev);
6144         }
6145         tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
6146         return req;
6147 }
6148
6149 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
6150 {
6151         struct tevent_req *req = tevent_req_callback_data(
6152                 subreq, struct tevent_req);
6153         struct cli_shadow_copy_data_state *state = tevent_req_data(
6154                 req, struct cli_shadow_copy_data_state);
6155         NTSTATUS status;
6156
6157         status = cli_trans_recv(subreq, state, NULL,
6158                                 NULL, 0, NULL, /* setup */
6159                                 NULL, 0, NULL, /* param */
6160                                 &state->data, 12, &state->num_data);
6161         TALLOC_FREE(subreq);
6162         if (tevent_req_nterror(req, status)) {
6163                 return;
6164         }
6165         tevent_req_done(req);
6166 }
6167
6168 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6169                                    char ***pnames, int *pnum_names)
6170 {
6171         struct cli_shadow_copy_data_state *state = tevent_req_data(
6172                 req, struct cli_shadow_copy_data_state);
6173         char **names = NULL;
6174         uint32_t i, num_names;
6175         uint32_t dlength;
6176         uint8_t *endp = NULL;
6177         NTSTATUS status;
6178
6179         if (tevent_req_is_nterror(req, &status)) {
6180                 return status;
6181         }
6182
6183         if (state->num_data < 16) {
6184                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6185         }
6186
6187         num_names = IVAL(state->data, 4);
6188         dlength = IVAL(state->data, 8);
6189
6190         if (num_names > 0x7FFFFFFF) {
6191                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6192         }
6193
6194         if (!state->get_names) {
6195                 *pnum_names = (int)num_names;
6196                 return NT_STATUS_OK;
6197         }
6198
6199         if (dlength + 12 < 12) {
6200                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6201         }
6202         if (dlength + 12 > state->num_data) {
6203                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6204         }
6205         if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
6206                         state->num_data) {
6207                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6208         }
6209
6210         names = talloc_array(mem_ctx, char *, num_names);
6211         if (names == NULL) {
6212                 return NT_STATUS_NO_MEMORY;
6213         }
6214
6215         endp = state->data + state->num_data;
6216
6217         for (i=0; i<num_names; i++) {
6218                 bool ret;
6219                 uint8_t *src;
6220                 size_t converted_size;
6221
6222                 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
6223
6224                 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
6225                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
6226                 }
6227
6228                 ret = convert_string_talloc(
6229                         names, CH_UTF16LE, CH_UNIX,
6230                         src, 2 * sizeof(SHADOW_COPY_LABEL),
6231                         &names[i], &converted_size);
6232                 if (!ret) {
6233                         TALLOC_FREE(names);
6234                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
6235                 }
6236         }
6237         *pnum_names = (int)num_names;
6238         *pnames = names;
6239         return NT_STATUS_OK;
6240 }
6241
6242 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6243                               uint16_t fnum, bool get_names,
6244                               char ***pnames, int *pnum_names)
6245 {
6246         TALLOC_CTX *frame = NULL;
6247         struct tevent_context *ev;
6248         struct tevent_req *req;
6249         NTSTATUS status = NT_STATUS_NO_MEMORY;
6250
6251         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6252                 return cli_smb2_shadow_copy_data(mem_ctx,
6253                                         cli,
6254                                         fnum,
6255                                         get_names,
6256                                         pnames,
6257                                         pnum_names);
6258         }
6259
6260         frame = talloc_stackframe();
6261
6262         if (smbXcli_conn_has_async_calls(cli->conn)) {
6263                 /*
6264                  * Can't use sync call while an async call is in flight
6265                  */
6266                 status = NT_STATUS_INVALID_PARAMETER;
6267                 goto fail;
6268         }
6269         ev = samba_tevent_context_init(frame);
6270         if (ev == NULL) {
6271                 goto fail;
6272         }
6273         req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
6274         if (req == NULL) {
6275                 goto fail;
6276         }
6277         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6278                 goto fail;
6279         }
6280         status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
6281  fail:
6282         TALLOC_FREE(frame);
6283         return status;
6284 }