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