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