s3:libsmb: pass ImpersonationLevel to cli_ntcreate1_send()
[martins/samba.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "libsmb/libsmb.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "async_smb.h"
26 #include "libsmb/clirap.h"
27 #include "trans2.h"
28 #include "ntioctl.h"
29 #include "libcli/security/secdesc.h"
30 #include "../libcli/smb/smbXcli_base.h"
31
32 struct cli_setpathinfo_state {
33         uint16_t setup;
34         uint8_t *param;
35 };
36
37 static void cli_setpathinfo_done(struct tevent_req *subreq);
38
39 struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
40                                         struct tevent_context *ev,
41                                         struct cli_state *cli,
42                                         uint16_t level,
43                                         const char *path,
44                                         uint8_t *data,
45                                         size_t data_len)
46 {
47         struct tevent_req *req, *subreq;
48         struct cli_setpathinfo_state *state;
49         uint16_t additional_flags2 = 0;
50
51         req = tevent_req_create(mem_ctx, &state,
52                                 struct cli_setpathinfo_state);
53         if (req == NULL) {
54                 return NULL;
55         }
56
57         /* Setup setup word. */
58         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
59
60         /* Setup param array. */
61         state->param = talloc_zero_array(state, uint8_t, 6);
62         if (tevent_req_nomem(state->param, req)) {
63                 return tevent_req_post(req, ev);
64         }
65         SSVAL(state->param, 0, level);
66
67         state->param = trans2_bytes_push_str(
68                 state->param, smbXcli_conn_use_unicode(cli->conn), path, strlen(path)+1, NULL);
69         if (tevent_req_nomem(state->param, req)) {
70                 return tevent_req_post(req, ev);
71         }
72
73         if (clistr_is_previous_version_path(path, NULL, NULL, NULL) &&
74                         !INFO_LEVEL_IS_UNIX(level)) {
75                 additional_flags2 = FLAGS2_REPARSE_PATH;
76         }
77
78         subreq = cli_trans_send(
79                 state,                  /* mem ctx. */
80                 ev,                     /* event ctx. */
81                 cli,                    /* cli_state. */
82                 additional_flags2,      /* additional_flags2 */
83                 SMBtrans2,              /* cmd. */
84                 NULL,                   /* pipe name. */
85                 -1,                     /* fid. */
86                 0,                      /* function. */
87                 0,                      /* flags. */
88                 &state->setup,          /* setup. */
89                 1,                      /* num setup uint16_t words. */
90                 0,                      /* max returned setup. */
91                 state->param,           /* param. */
92                 talloc_get_size(state->param),  /* num param. */
93                 2,                      /* max returned param. */
94                 data,                   /* data. */
95                 data_len,               /* num data. */
96                 0);                     /* max returned data. */
97
98         if (tevent_req_nomem(subreq, req)) {
99                 return tevent_req_post(req, ev);
100         }
101         tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
102         return req;
103 }
104
105 static void cli_setpathinfo_done(struct tevent_req *subreq)
106 {
107         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
108                                          NULL, 0, NULL, NULL, 0, NULL);
109         tevent_req_simple_finish_ntstatus(subreq, status);
110 }
111
112 NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
113 {
114         return tevent_req_simple_recv_ntstatus(req);
115 }
116
117 NTSTATUS cli_setpathinfo(struct cli_state *cli,
118                          uint16_t level,
119                          const char *path,
120                          uint8_t *data,
121                          size_t data_len)
122 {
123         TALLOC_CTX *frame = talloc_stackframe();
124         struct tevent_context *ev;
125         struct tevent_req *req;
126         NTSTATUS status = NT_STATUS_NO_MEMORY;
127
128         if (smbXcli_conn_has_async_calls(cli->conn)) {
129                 /*
130                  * Can't use sync call while an async call is in flight
131                  */
132                 status = NT_STATUS_INVALID_PARAMETER;
133                 goto fail;
134         }
135         ev = samba_tevent_context_init(frame);
136         if (ev == NULL) {
137                 goto fail;
138         }
139         req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
140         if (req == NULL) {
141                 goto fail;
142         }
143         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
144                 goto fail;
145         }
146         status = cli_setpathinfo_recv(req);
147  fail:
148         TALLOC_FREE(frame);
149         return status;
150 }
151
152 /****************************************************************************
153  Hard/Symlink a file (UNIX extensions).
154  Creates new name (sym)linked to link_target.
155 ****************************************************************************/
156
157 struct cli_posix_link_internal_state {
158         uint8_t *data;
159 };
160
161 static void cli_posix_link_internal_done(struct tevent_req *subreq);
162
163 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
164                                         struct tevent_context *ev,
165                                         struct cli_state *cli,
166                                         uint16_t level,
167                                         const char *link_target,
168                                         const char *newname)
169 {
170         struct tevent_req *req = NULL, *subreq = NULL;
171         struct cli_posix_link_internal_state *state = NULL;
172
173         req = tevent_req_create(mem_ctx, &state,
174                                 struct cli_posix_link_internal_state);
175         if (req == NULL) {
176                 return NULL;
177         }
178
179         /* Setup data array. */
180         state->data = talloc_array(state, uint8_t, 0);
181         if (tevent_req_nomem(state->data, req)) {
182                 return tevent_req_post(req, ev);
183         }
184         state->data = trans2_bytes_push_str(
185                 state->data, smbXcli_conn_use_unicode(cli->conn),
186                 link_target, strlen(link_target)+1, NULL);
187
188         subreq = cli_setpathinfo_send(
189                 state, ev, cli, level, newname,
190                 state->data, talloc_get_size(state->data));
191         if (tevent_req_nomem(subreq, req)) {
192                 return tevent_req_post(req, ev);
193         }
194         tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
195         return req;
196 }
197
198 static void cli_posix_link_internal_done(struct tevent_req *subreq)
199 {
200         NTSTATUS status = cli_setpathinfo_recv(subreq);
201         tevent_req_simple_finish_ntstatus(subreq, status);
202 }
203
204 /****************************************************************************
205  Symlink a file (UNIX extensions).
206 ****************************************************************************/
207
208 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
209                                         struct tevent_context *ev,
210                                         struct cli_state *cli,
211                                         const char *link_target,
212                                         const char *newname)
213 {
214         return cli_posix_link_internal_send(
215                 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, link_target, newname);
216 }
217
218 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
219 {
220         return tevent_req_simple_recv_ntstatus(req);
221 }
222
223 NTSTATUS cli_posix_symlink(struct cli_state *cli,
224                         const char *link_target,
225                         const char *newname)
226 {
227         TALLOC_CTX *frame = talloc_stackframe();
228         struct tevent_context *ev = NULL;
229         struct tevent_req *req = NULL;
230         NTSTATUS status = NT_STATUS_OK;
231
232         if (smbXcli_conn_has_async_calls(cli->conn)) {
233                 /*
234                  * Can't use sync call while an async call is in flight
235                  */
236                 status = NT_STATUS_INVALID_PARAMETER;
237                 goto fail;
238         }
239
240         ev = samba_tevent_context_init(frame);
241         if (ev == NULL) {
242                 status = NT_STATUS_NO_MEMORY;
243                 goto fail;
244         }
245
246         req = cli_posix_symlink_send(frame,
247                                 ev,
248                                 cli,
249                                 link_target,
250                                 newname);
251         if (req == NULL) {
252                 status = NT_STATUS_NO_MEMORY;
253                 goto fail;
254         }
255
256         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
257                 goto fail;
258         }
259
260         status = cli_posix_symlink_recv(req);
261
262  fail:
263         TALLOC_FREE(frame);
264         return status;
265 }
266
267 /****************************************************************************
268  Read a POSIX symlink.
269 ****************************************************************************/
270
271 struct readlink_state {
272         uint8_t *data;
273         uint32_t num_data;
274 };
275
276 static void cli_posix_readlink_done(struct tevent_req *subreq);
277
278 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
279                                         struct tevent_context *ev,
280                                         struct cli_state *cli,
281                                         const char *fname,
282                                         size_t len)
283 {
284         struct tevent_req *req = NULL, *subreq = NULL;
285         struct readlink_state *state = NULL;
286         uint32_t maxbytelen = (uint32_t)(smbXcli_conn_use_unicode(cli->conn) ? len*3 : len);
287
288         req = tevent_req_create(mem_ctx, &state, struct readlink_state);
289         if (req == NULL) {
290                 return NULL;
291         }
292
293         /*
294          * Len is in bytes, we need it in UCS2 units.
295          */
296         if ((2*len < len) || (maxbytelen < len)) {
297                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
298                 return tevent_req_post(req, ev);
299         }
300
301         subreq = cli_qpathinfo_send(state, ev, cli, fname,
302                                     SMB_QUERY_FILE_UNIX_LINK, 1, maxbytelen);
303         if (tevent_req_nomem(subreq, req)) {
304                 return tevent_req_post(req, ev);
305         }
306         tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
307         return req;
308 }
309
310 static void cli_posix_readlink_done(struct tevent_req *subreq)
311 {
312         struct tevent_req *req = tevent_req_callback_data(
313                 subreq, struct tevent_req);
314         struct readlink_state *state = tevent_req_data(
315                 req, struct readlink_state);
316         NTSTATUS status;
317
318         status = cli_qpathinfo_recv(subreq, state, &state->data,
319                                     &state->num_data);
320         TALLOC_FREE(subreq);
321         if (tevent_req_nterror(req, status)) {
322                 return;
323         }
324         /*
325          * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
326          */
327         if (state->data[state->num_data-1] != '\0') {
328                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
329                 return;
330         }
331         tevent_req_done(req);
332 }
333
334 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
335                                 char *retpath, size_t len)
336 {
337         NTSTATUS status;
338         char *converted = NULL;
339         size_t converted_size = 0;
340         struct readlink_state *state = tevent_req_data(req, struct readlink_state);
341
342         if (tevent_req_is_nterror(req, &status)) {
343                 return status;
344         }
345         /* The returned data is a pushed string, not raw data. */
346         if (!convert_string_talloc(state,
347                                 smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS, 
348                                 CH_UNIX,
349                                 state->data,
350                                 state->num_data,
351                                 &converted,
352                                 &converted_size)) {
353                 return NT_STATUS_NO_MEMORY;
354         }
355
356         len = MIN(len,converted_size);
357         if (len == 0) {
358                 return NT_STATUS_DATA_ERROR;
359         }
360         memcpy(retpath, converted, len);
361         return NT_STATUS_OK;
362 }
363
364 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
365                                 char *linkpath, size_t len)
366 {
367         TALLOC_CTX *frame = talloc_stackframe();
368         struct tevent_context *ev = NULL;
369         struct tevent_req *req = NULL;
370         NTSTATUS status = NT_STATUS_OK;
371
372         if (smbXcli_conn_has_async_calls(cli->conn)) {
373                 /*
374                  * Can't use sync call while an async call is in flight
375                  */
376                 status = NT_STATUS_INVALID_PARAMETER;
377                 goto fail;
378         }
379
380         ev = samba_tevent_context_init(frame);
381         if (ev == NULL) {
382                 status = NT_STATUS_NO_MEMORY;
383                 goto fail;
384         }
385
386         req = cli_posix_readlink_send(frame,
387                                 ev,
388                                 cli,
389                                 fname,
390                                 len);
391         if (req == NULL) {
392                 status = NT_STATUS_NO_MEMORY;
393                 goto fail;
394         }
395
396         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
397                 goto fail;
398         }
399
400         status = cli_posix_readlink_recv(req, cli, linkpath, len);
401
402  fail:
403         TALLOC_FREE(frame);
404         return status;
405 }
406
407 /****************************************************************************
408  Hard link a file (UNIX extensions).
409 ****************************************************************************/
410
411 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
412                                         struct tevent_context *ev,
413                                         struct cli_state *cli,
414                                         const char *oldname,
415                                         const char *newname)
416 {
417         return cli_posix_link_internal_send(
418                 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
419 }
420
421 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
422 {
423         return tevent_req_simple_recv_ntstatus(req);
424 }
425
426 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
427                         const char *oldname,
428                         const char *newname)
429 {
430         TALLOC_CTX *frame = talloc_stackframe();
431         struct tevent_context *ev = NULL;
432         struct tevent_req *req = NULL;
433         NTSTATUS status = NT_STATUS_OK;
434
435         if (smbXcli_conn_has_async_calls(cli->conn)) {
436                 /*
437                  * Can't use sync call while an async call is in flight
438                  */
439                 status = NT_STATUS_INVALID_PARAMETER;
440                 goto fail;
441         }
442
443         ev = samba_tevent_context_init(frame);
444         if (ev == NULL) {
445                 status = NT_STATUS_NO_MEMORY;
446                 goto fail;
447         }
448
449         req = cli_posix_hardlink_send(frame,
450                                 ev,
451                                 cli,
452                                 oldname,
453                                 newname);
454         if (req == NULL) {
455                 status = NT_STATUS_NO_MEMORY;
456                 goto fail;
457         }
458
459         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
460                 goto fail;
461         }
462
463         status = cli_posix_hardlink_recv(req);
464
465  fail:
466         TALLOC_FREE(frame);
467         return status;
468 }
469
470 /****************************************************************************
471  Do a POSIX getacl - pathname based ACL get (UNIX extensions).
472 ****************************************************************************/
473
474 struct getacl_state {
475         uint32_t num_data;
476         uint8_t *data;
477 };
478
479 static void cli_posix_getacl_done(struct tevent_req *subreq);
480
481 struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
482                                         struct tevent_context *ev,
483                                         struct cli_state *cli,
484                                         const char *fname)
485 {
486         struct tevent_req *req = NULL, *subreq = NULL;
487         struct getacl_state *state = NULL;
488
489         req = tevent_req_create(mem_ctx, &state, struct getacl_state);
490         if (req == NULL) {
491                 return NULL;
492         }
493         subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
494                                     0, CLI_BUFFER_SIZE);
495         if (tevent_req_nomem(subreq, req)) {
496                 return tevent_req_post(req, ev);
497         }
498         tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
499         return req;
500 }
501
502 static void cli_posix_getacl_done(struct tevent_req *subreq)
503 {
504         struct tevent_req *req = tevent_req_callback_data(
505                 subreq, struct tevent_req);
506         struct getacl_state *state = tevent_req_data(
507                 req, struct getacl_state);
508         NTSTATUS status;
509
510         status = cli_qpathinfo_recv(subreq, state, &state->data,
511                                     &state->num_data);
512         TALLOC_FREE(subreq);
513         if (tevent_req_nterror(req, status)) {
514                 return;
515         }
516         tevent_req_done(req);
517 }
518
519 NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
520                                 TALLOC_CTX *mem_ctx,
521                                 size_t *prb_size,
522                                 char **retbuf)
523 {
524         struct getacl_state *state = tevent_req_data(req, struct getacl_state);
525         NTSTATUS status;
526
527         if (tevent_req_is_nterror(req, &status)) {
528                 return status;
529         }
530         *prb_size = (size_t)state->num_data;
531         *retbuf = (char *)talloc_move(mem_ctx, &state->data);
532         return NT_STATUS_OK;
533 }
534
535 NTSTATUS cli_posix_getacl(struct cli_state *cli,
536                         const char *fname,
537                         TALLOC_CTX *mem_ctx,
538                         size_t *prb_size,
539                         char **retbuf)
540 {
541         TALLOC_CTX *frame = talloc_stackframe();
542         struct tevent_context *ev = NULL;
543         struct tevent_req *req = NULL;
544         NTSTATUS status = NT_STATUS_OK;
545
546         if (smbXcli_conn_has_async_calls(cli->conn)) {
547                 /*
548                  * Can't use sync call while an async call is in flight
549                  */
550                 status = NT_STATUS_INVALID_PARAMETER;
551                 goto fail;
552         }
553
554         ev = samba_tevent_context_init(frame);
555         if (ev == NULL) {
556                 status = NT_STATUS_NO_MEMORY;
557                 goto fail;
558         }
559
560         req = cli_posix_getacl_send(frame,
561                                 ev,
562                                 cli,
563                                 fname);
564         if (req == NULL) {
565                 status = NT_STATUS_NO_MEMORY;
566                 goto fail;
567         }
568
569         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
570                 goto fail;
571         }
572
573         status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
574
575  fail:
576         TALLOC_FREE(frame);
577         return status;
578 }
579
580 /****************************************************************************
581  Do a POSIX setacl - pathname based ACL set (UNIX extensions).
582 ****************************************************************************/
583
584 struct setacl_state {
585         uint8_t *data;
586 };
587
588 static void cli_posix_setacl_done(struct tevent_req *subreq);
589
590 struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
591                                         struct tevent_context *ev,
592                                         struct cli_state *cli,
593                                         const char *fname,
594                                         const void *data,
595                                         size_t num_data)
596 {
597         struct tevent_req *req = NULL, *subreq = NULL;
598         struct setacl_state *state = NULL;
599
600         req = tevent_req_create(mem_ctx, &state, struct setacl_state);
601         if (req == NULL) {
602                 return NULL;
603         }
604         state->data = talloc_memdup(state, data, num_data);
605         if (tevent_req_nomem(state->data, req)) {
606                 return tevent_req_post(req, ev);
607         }
608
609         subreq = cli_setpathinfo_send(state,
610                                 ev,
611                                 cli,
612                                 SMB_SET_POSIX_ACL,
613                                 fname,
614                                 state->data,
615                                 num_data);
616         if (tevent_req_nomem(subreq, req)) {
617                 return tevent_req_post(req, ev);
618         }
619         tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
620         return req;
621 }
622
623 static void cli_posix_setacl_done(struct tevent_req *subreq)
624 {
625         NTSTATUS status = cli_setpathinfo_recv(subreq);
626         tevent_req_simple_finish_ntstatus(subreq, status);
627 }
628
629 NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
630 {
631         return tevent_req_simple_recv_ntstatus(req);
632 }
633
634 NTSTATUS cli_posix_setacl(struct cli_state *cli,
635                         const char *fname,
636                         const void *acl_buf,
637                         size_t acl_buf_size)
638 {
639         TALLOC_CTX *frame = talloc_stackframe();
640         struct tevent_context *ev = NULL;
641         struct tevent_req *req = NULL;
642         NTSTATUS status = NT_STATUS_OK;
643
644         if (smbXcli_conn_has_async_calls(cli->conn)) {
645                 /*
646                  * Can't use sync call while an async call is in flight
647                  */
648                 status = NT_STATUS_INVALID_PARAMETER;
649                 goto fail;
650         }
651
652         ev = samba_tevent_context_init(frame);
653         if (ev == NULL) {
654                 status = NT_STATUS_NO_MEMORY;
655                 goto fail;
656         }
657
658         req = cli_posix_setacl_send(frame,
659                                 ev,
660                                 cli,
661                                 fname,
662                                 acl_buf,
663                                 acl_buf_size);
664         if (req == NULL) {
665                 status = NT_STATUS_NO_MEMORY;
666                 goto fail;
667         }
668
669         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
670                 goto fail;
671         }
672
673         status = cli_posix_setacl_recv(req);
674
675  fail:
676         TALLOC_FREE(frame);
677         return status;
678 }
679
680 /****************************************************************************
681  Stat a file (UNIX extensions).
682 ****************************************************************************/
683
684 struct stat_state {
685         uint32_t num_data;
686         uint8_t *data;
687 };
688
689 static void cli_posix_stat_done(struct tevent_req *subreq);
690
691 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
692                                         struct tevent_context *ev,
693                                         struct cli_state *cli,
694                                         const char *fname)
695 {
696         struct tevent_req *req = NULL, *subreq = NULL;
697         struct stat_state *state = NULL;
698
699         req = tevent_req_create(mem_ctx, &state, struct stat_state);
700         if (req == NULL) {
701                 return NULL;
702         }
703         subreq = cli_qpathinfo_send(state, ev, cli, fname,
704                                     SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
705         if (tevent_req_nomem(subreq, req)) {
706                 return tevent_req_post(req, ev);
707         }
708         tevent_req_set_callback(subreq, cli_posix_stat_done, req);
709         return req;
710 }
711
712 static void cli_posix_stat_done(struct tevent_req *subreq)
713 {
714         struct tevent_req *req = tevent_req_callback_data(
715                                 subreq, struct tevent_req);
716         struct stat_state *state = tevent_req_data(req, struct stat_state);
717         NTSTATUS status;
718
719         status = cli_qpathinfo_recv(subreq, state, &state->data,
720                                     &state->num_data);
721         TALLOC_FREE(subreq);
722         if (tevent_req_nterror(req, status)) {
723                 return;
724         }
725         tevent_req_done(req);
726 }
727
728 NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
729                                 SMB_STRUCT_STAT *sbuf)
730 {
731         struct stat_state *state = tevent_req_data(req, struct stat_state);
732         NTSTATUS status;
733
734         if (tevent_req_is_nterror(req, &status)) {
735                 return status;
736         }
737
738         sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0);     /* total size, in bytes */
739         sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8);   /* number of blocks allocated */
740 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
741         sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
742 #else
743         /* assume 512 byte blocks */
744         sbuf->st_ex_blocks /= 512;
745 #endif
746         sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16));    /* time of last change */
747         sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24));    /* time of last access */
748         sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32));    /* time of last modification */
749
750         sbuf->st_ex_uid = (uid_t) IVAL(state->data,40);      /* user ID of owner */
751         sbuf->st_ex_gid = (gid_t) IVAL(state->data,48);      /* group ID of owner */
752         sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
753 #if defined(HAVE_MAKEDEV)
754         {
755                 uint32_t dev_major = IVAL(state->data,60);
756                 uint32_t dev_minor = IVAL(state->data,68);
757                 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
758         }
759 #endif
760         sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76);      /* inode */
761         sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84));     /* protection */
762         sbuf->st_ex_nlink = BIG_UINT(state->data,92); /* number of hard links */
763
764         return NT_STATUS_OK;
765 }
766
767 NTSTATUS cli_posix_stat(struct cli_state *cli,
768                         const char *fname,
769                         SMB_STRUCT_STAT *sbuf)
770 {
771         TALLOC_CTX *frame = talloc_stackframe();
772         struct tevent_context *ev = NULL;
773         struct tevent_req *req = NULL;
774         NTSTATUS status = NT_STATUS_OK;
775
776         if (smbXcli_conn_has_async_calls(cli->conn)) {
777                 /*
778                  * Can't use sync call while an async call is in flight
779                  */
780                 status = NT_STATUS_INVALID_PARAMETER;
781                 goto fail;
782         }
783
784         ev = samba_tevent_context_init(frame);
785         if (ev == NULL) {
786                 status = NT_STATUS_NO_MEMORY;
787                 goto fail;
788         }
789
790         req = cli_posix_stat_send(frame,
791                                 ev,
792                                 cli,
793                                 fname);
794         if (req == NULL) {
795                 status = NT_STATUS_NO_MEMORY;
796                 goto fail;
797         }
798
799         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
800                 goto fail;
801         }
802
803         status = cli_posix_stat_recv(req, sbuf);
804
805  fail:
806         TALLOC_FREE(frame);
807         return status;
808 }
809
810 /****************************************************************************
811  Chmod or chown a file internal (UNIX extensions).
812 ****************************************************************************/
813
814 struct cli_posix_chown_chmod_internal_state {
815         uint8_t data[100];
816 };
817
818 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
819
820 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
821                                         struct tevent_context *ev,
822                                         struct cli_state *cli,
823                                         const char *fname,
824                                         uint32_t mode,
825                                         uint32_t uid,
826                                         uint32_t gid)
827 {
828         struct tevent_req *req = NULL, *subreq = NULL;
829         struct cli_posix_chown_chmod_internal_state *state = NULL;
830
831         req = tevent_req_create(mem_ctx, &state,
832                                 struct cli_posix_chown_chmod_internal_state);
833         if (req == NULL) {
834                 return NULL;
835         }
836
837         memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
838         memset(&state->data[40], '\0', 60);
839         SIVAL(state->data,40,uid);
840         SIVAL(state->data,48,gid);
841         SIVAL(state->data,84,mode);
842
843         subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
844                                       fname, state->data, sizeof(state->data));
845         if (tevent_req_nomem(subreq, req)) {
846                 return tevent_req_post(req, ev);
847         }
848         tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
849                                 req);
850         return req;
851 }
852
853 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
854 {
855         NTSTATUS status = cli_setpathinfo_recv(subreq);
856         tevent_req_simple_finish_ntstatus(subreq, status);
857 }
858
859 /****************************************************************************
860  chmod a file (UNIX extensions).
861 ****************************************************************************/
862
863 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
864                                         struct tevent_context *ev,
865                                         struct cli_state *cli,
866                                         const char *fname,
867                                         mode_t mode)
868 {
869         return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
870                         fname,
871                         unix_perms_to_wire(mode),
872                         SMB_UID_NO_CHANGE,
873                         SMB_GID_NO_CHANGE);
874 }
875
876 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
877 {
878         return tevent_req_simple_recv_ntstatus(req);
879 }
880
881 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
882 {
883         TALLOC_CTX *frame = talloc_stackframe();
884         struct tevent_context *ev = NULL;
885         struct tevent_req *req = NULL;
886         NTSTATUS status = NT_STATUS_OK;
887
888         if (smbXcli_conn_has_async_calls(cli->conn)) {
889                 /*
890                  * Can't use sync call while an async call is in flight
891                  */
892                 status = NT_STATUS_INVALID_PARAMETER;
893                 goto fail;
894         }
895
896         ev = samba_tevent_context_init(frame);
897         if (ev == NULL) {
898                 status = NT_STATUS_NO_MEMORY;
899                 goto fail;
900         }
901
902         req = cli_posix_chmod_send(frame,
903                                 ev,
904                                 cli,
905                                 fname,
906                                 mode);
907         if (req == NULL) {
908                 status = NT_STATUS_NO_MEMORY;
909                 goto fail;
910         }
911
912         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
913                 goto fail;
914         }
915
916         status = cli_posix_chmod_recv(req);
917
918  fail:
919         TALLOC_FREE(frame);
920         return status;
921 }
922
923 /****************************************************************************
924  chown a file (UNIX extensions).
925 ****************************************************************************/
926
927 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
928                                         struct tevent_context *ev,
929                                         struct cli_state *cli,
930                                         const char *fname,
931                                         uid_t uid,
932                                         gid_t gid)
933 {
934         return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
935                         fname,
936                         SMB_MODE_NO_CHANGE,
937                         (uint32_t)uid,
938                         (uint32_t)gid);
939 }
940
941 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
942 {
943         return tevent_req_simple_recv_ntstatus(req);
944 }
945
946 NTSTATUS cli_posix_chown(struct cli_state *cli,
947                         const char *fname,
948                         uid_t uid,
949                         gid_t gid)
950 {
951         TALLOC_CTX *frame = talloc_stackframe();
952         struct tevent_context *ev = NULL;
953         struct tevent_req *req = NULL;
954         NTSTATUS status = NT_STATUS_OK;
955
956         if (smbXcli_conn_has_async_calls(cli->conn)) {
957                 /*
958                  * Can't use sync call while an async call is in flight
959                  */
960                 status = NT_STATUS_INVALID_PARAMETER;
961                 goto fail;
962         }
963
964         ev = samba_tevent_context_init(frame);
965         if (ev == NULL) {
966                 status = NT_STATUS_NO_MEMORY;
967                 goto fail;
968         }
969
970         req = cli_posix_chown_send(frame,
971                                 ev,
972                                 cli,
973                                 fname,
974                                 uid,
975                                 gid);
976         if (req == NULL) {
977                 status = NT_STATUS_NO_MEMORY;
978                 goto fail;
979         }
980
981         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
982                 goto fail;
983         }
984
985         status = cli_posix_chown_recv(req);
986
987  fail:
988         TALLOC_FREE(frame);
989         return status;
990 }
991
992 /****************************************************************************
993  Rename a file.
994 ****************************************************************************/
995
996 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
997                                                struct tevent_context *ev,
998                                                struct cli_state *cli,
999                                                const char *fname_src,
1000                                                const char *fname_dst,
1001                                                bool replace);
1002
1003 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1004                                                struct tevent_context *ev,
1005                                                struct cli_state *cli,
1006                                                const char *fname_src,
1007                                                const char *fname_dst,
1008                                                bool replace);
1009
1010 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1011                                    struct tevent_context *ev,
1012                                    struct cli_state *cli,
1013                                    const char *fname_src,
1014                                    const char *fname_dst,
1015                                    bool replace)
1016 {
1017         if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
1018                 return cli_smb1_rename_send(mem_ctx, ev, cli, fname_src,
1019                                             fname_dst, replace);
1020         } else {
1021                 return cli_cifs_rename_send(mem_ctx, ev, cli, fname_src,
1022                                             fname_dst, replace);
1023         }
1024 }
1025
1026 struct cli_smb1_rename_state {
1027         uint8_t *data;
1028 };
1029
1030 static void cli_smb1_rename_done(struct tevent_req *subreq);
1031
1032 static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1033                                                struct tevent_context *ev,
1034                                                struct cli_state *cli,
1035                                                const char *fname_src,
1036                                                const char *fname_dst,
1037                                                bool replace)
1038 {
1039         NTSTATUS status;
1040         struct tevent_req *req = NULL, *subreq = NULL;
1041         struct cli_smb1_rename_state *state = NULL;
1042         smb_ucs2_t *converted_str = NULL;
1043         size_t converted_size_bytes = 0;
1044
1045         req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
1046         if (req == NULL) {
1047                 return NULL;
1048         }
1049
1050         if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
1051                               &converted_size_bytes)) {
1052                 status = NT_STATUS_INVALID_PARAMETER;
1053                 goto fail;
1054         }
1055
1056         /* W2K8 insists the dest name is not null
1057            terminated. Remove the last 2 zero bytes
1058            and reduce the name length. */
1059
1060         if (converted_size_bytes < 2) {
1061                 status = NT_STATUS_INVALID_PARAMETER;
1062                 goto fail;
1063         }
1064         converted_size_bytes -= 2;
1065
1066         state->data =
1067             talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
1068         if (state->data == NULL) {
1069                 status = NT_STATUS_NO_MEMORY;
1070                 goto fail;
1071         }
1072
1073         if (replace) {
1074                 SCVAL(state->data, 0, 1);
1075         }
1076
1077         SIVAL(state->data, 8, converted_size_bytes);
1078         memcpy(state->data + 12, converted_str, converted_size_bytes);
1079
1080         TALLOC_FREE(converted_str);
1081
1082         subreq = cli_setpathinfo_send(
1083             state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
1084             talloc_get_size(state->data));
1085         if (tevent_req_nomem(subreq, req)) {
1086                 status = NT_STATUS_NO_MEMORY;
1087                 goto fail;
1088         }
1089         tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
1090         return req;
1091
1092 fail:
1093         TALLOC_FREE(converted_str);
1094         tevent_req_nterror(req, status);
1095         return tevent_req_post(req, ev);
1096 }
1097
1098 static void cli_smb1_rename_done(struct tevent_req *subreq)
1099 {
1100         NTSTATUS status = cli_setpathinfo_recv(subreq);
1101         tevent_req_simple_finish_ntstatus(subreq, status);
1102 }
1103
1104 static void cli_cifs_rename_done(struct tevent_req *subreq);
1105
1106 struct cli_cifs_rename_state {
1107         uint16_t vwv[1];
1108 };
1109
1110 static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1111                                                struct tevent_context *ev,
1112                                                struct cli_state *cli,
1113                                                const char *fname_src,
1114                                                const char *fname_dst,
1115                                                bool replace)
1116 {
1117         struct tevent_req *req = NULL, *subreq = NULL;
1118         struct cli_cifs_rename_state *state = NULL;
1119         uint8_t additional_flags = 0;
1120         uint16_t additional_flags2 = 0;
1121         uint8_t *bytes = NULL;
1122
1123         req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
1124         if (req == NULL) {
1125                 return NULL;
1126         }
1127
1128         if (replace) {
1129                 /*
1130                  * CIFS doesn't support replace
1131                  */
1132                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1133                 return tevent_req_post(req, ev);
1134         }
1135
1136         SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1137
1138         bytes = talloc_array(state, uint8_t, 1);
1139         if (tevent_req_nomem(bytes, req)) {
1140                 return tevent_req_post(req, ev);
1141         }
1142         bytes[0] = 4;
1143         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1144                                    strlen(fname_src)+1, NULL);
1145         if (tevent_req_nomem(bytes, req)) {
1146                 return tevent_req_post(req, ev);
1147         }
1148
1149         if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1150                 additional_flags2 = FLAGS2_REPARSE_PATH;
1151         }
1152
1153         bytes = talloc_realloc(state, bytes, uint8_t,
1154                         talloc_get_size(bytes)+1);
1155         if (tevent_req_nomem(bytes, req)) {
1156                 return tevent_req_post(req, ev);
1157         }
1158
1159         bytes[talloc_get_size(bytes)-1] = 4;
1160         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1161                                    strlen(fname_dst)+1, NULL);
1162         if (tevent_req_nomem(bytes, req)) {
1163                 return tevent_req_post(req, ev);
1164         }
1165
1166         subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1167                         additional_flags2,
1168                         1, state->vwv, talloc_get_size(bytes), bytes);
1169         if (tevent_req_nomem(subreq, req)) {
1170                 return tevent_req_post(req, ev);
1171         }
1172         tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
1173         return req;
1174 }
1175
1176 static void cli_cifs_rename_done(struct tevent_req *subreq)
1177 {
1178         struct tevent_req *req = tevent_req_callback_data(
1179                                 subreq, struct tevent_req);
1180         NTSTATUS status;
1181
1182         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1183         TALLOC_FREE(subreq);
1184         if (tevent_req_nterror(req, status)) {
1185                 return;
1186         }
1187         tevent_req_done(req);
1188 }
1189
1190 NTSTATUS cli_rename_recv(struct tevent_req *req)
1191 {
1192         return tevent_req_simple_recv_ntstatus(req);
1193 }
1194
1195 NTSTATUS cli_rename(struct cli_state *cli,
1196                     const char *fname_src,
1197                     const char *fname_dst,
1198                     bool replace)
1199 {
1200         TALLOC_CTX *frame = NULL;
1201         struct tevent_context *ev;
1202         struct tevent_req *req;
1203         NTSTATUS status = NT_STATUS_OK;
1204
1205         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1206                 return cli_smb2_rename(cli, fname_src, fname_dst, replace);
1207         }
1208
1209         frame = talloc_stackframe();
1210
1211         if (smbXcli_conn_has_async_calls(cli->conn)) {
1212                 /*
1213                  * Can't use sync call while an async call is in flight
1214                  */
1215                 status = NT_STATUS_INVALID_PARAMETER;
1216                 goto fail;
1217         }
1218
1219         ev = samba_tevent_context_init(frame);
1220         if (ev == NULL) {
1221                 status = NT_STATUS_NO_MEMORY;
1222                 goto fail;
1223         }
1224
1225         req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
1226         if (req == NULL) {
1227                 status = NT_STATUS_NO_MEMORY;
1228                 goto fail;
1229         }
1230
1231         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1232                 goto fail;
1233         }
1234
1235         status = cli_rename_recv(req);
1236
1237  fail:
1238         TALLOC_FREE(frame);
1239         return status;
1240 }
1241
1242 /****************************************************************************
1243  NT Rename a file.
1244 ****************************************************************************/
1245
1246 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1247
1248 struct cli_ntrename_internal_state {
1249         uint16_t vwv[4];
1250 };
1251
1252 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1253                                 struct tevent_context *ev,
1254                                 struct cli_state *cli,
1255                                 const char *fname_src,
1256                                 const char *fname_dst,
1257                                 uint16_t rename_flag)
1258 {
1259         struct tevent_req *req = NULL, *subreq = NULL;
1260         struct cli_ntrename_internal_state *state = NULL;
1261         uint8_t additional_flags = 0;
1262         uint16_t additional_flags2 = 0;
1263         uint8_t *bytes = NULL;
1264
1265         req = tevent_req_create(mem_ctx, &state,
1266                                 struct cli_ntrename_internal_state);
1267         if (req == NULL) {
1268                 return NULL;
1269         }
1270
1271         SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1272         SSVAL(state->vwv+1, 0, rename_flag);
1273
1274         bytes = talloc_array(state, uint8_t, 1);
1275         if (tevent_req_nomem(bytes, req)) {
1276                 return tevent_req_post(req, ev);
1277         }
1278         bytes[0] = 4;
1279         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1280                                    strlen(fname_src)+1, NULL);
1281         if (tevent_req_nomem(bytes, req)) {
1282                 return tevent_req_post(req, ev);
1283         }
1284
1285         if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
1286                 additional_flags2 = FLAGS2_REPARSE_PATH;
1287         }
1288
1289         bytes = talloc_realloc(state, bytes, uint8_t,
1290                         talloc_get_size(bytes)+1);
1291         if (tevent_req_nomem(bytes, req)) {
1292                 return tevent_req_post(req, ev);
1293         }
1294
1295         bytes[talloc_get_size(bytes)-1] = 4;
1296         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1297                                    strlen(fname_dst)+1, NULL);
1298         if (tevent_req_nomem(bytes, req)) {
1299                 return tevent_req_post(req, ev);
1300         }
1301
1302         subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1303                         additional_flags2,
1304                         4, state->vwv, talloc_get_size(bytes), bytes);
1305         if (tevent_req_nomem(subreq, req)) {
1306                 return tevent_req_post(req, ev);
1307         }
1308         tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1309         return req;
1310 }
1311
1312 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1313 {
1314         struct tevent_req *req = tevent_req_callback_data(
1315                                 subreq, struct tevent_req);
1316         NTSTATUS status;
1317
1318         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1319         TALLOC_FREE(subreq);
1320         if (tevent_req_nterror(req, status)) {
1321                 return;
1322         }
1323         tevent_req_done(req);
1324 }
1325
1326 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1327 {
1328         return tevent_req_simple_recv_ntstatus(req);
1329 }
1330
1331 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1332                                 struct tevent_context *ev,
1333                                 struct cli_state *cli,
1334                                 const char *fname_src,
1335                                 const char *fname_dst)
1336 {
1337         return cli_ntrename_internal_send(mem_ctx,
1338                                           ev,
1339                                           cli,
1340                                           fname_src,
1341                                           fname_dst,
1342                                           RENAME_FLAG_RENAME);
1343 }
1344
1345 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1346 {
1347         return cli_ntrename_internal_recv(req);
1348 }
1349
1350 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1351 {
1352         TALLOC_CTX *frame = talloc_stackframe();
1353         struct tevent_context *ev;
1354         struct tevent_req *req;
1355         NTSTATUS status = NT_STATUS_OK;
1356
1357         if (smbXcli_conn_has_async_calls(cli->conn)) {
1358                 /*
1359                  * Can't use sync call while an async call is in flight
1360                  */
1361                 status = NT_STATUS_INVALID_PARAMETER;
1362                 goto fail;
1363         }
1364
1365         ev = samba_tevent_context_init(frame);
1366         if (ev == NULL) {
1367                 status = NT_STATUS_NO_MEMORY;
1368                 goto fail;
1369         }
1370
1371         req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1372         if (req == NULL) {
1373                 status = NT_STATUS_NO_MEMORY;
1374                 goto fail;
1375         }
1376
1377         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1378                 goto fail;
1379         }
1380
1381         status = cli_ntrename_recv(req);
1382
1383  fail:
1384         TALLOC_FREE(frame);
1385         return status;
1386 }
1387
1388 /****************************************************************************
1389  NT hardlink a file.
1390 ****************************************************************************/
1391
1392 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1393                                 struct tevent_context *ev,
1394                                 struct cli_state *cli,
1395                                 const char *fname_src,
1396                                 const char *fname_dst)
1397 {
1398         return cli_ntrename_internal_send(mem_ctx,
1399                                           ev,
1400                                           cli,
1401                                           fname_src,
1402                                           fname_dst,
1403                                           RENAME_FLAG_HARD_LINK);
1404 }
1405
1406 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1407 {
1408         return cli_ntrename_internal_recv(req);
1409 }
1410
1411 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1412 {
1413         TALLOC_CTX *frame = talloc_stackframe();
1414         struct tevent_context *ev;
1415         struct tevent_req *req;
1416         NTSTATUS status = NT_STATUS_OK;
1417
1418         if (smbXcli_conn_has_async_calls(cli->conn)) {
1419                 /*
1420                  * Can't use sync call while an async call is in flight
1421                  */
1422                 status = NT_STATUS_INVALID_PARAMETER;
1423                 goto fail;
1424         }
1425
1426         ev = samba_tevent_context_init(frame);
1427         if (ev == NULL) {
1428                 status = NT_STATUS_NO_MEMORY;
1429                 goto fail;
1430         }
1431
1432         req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1433         if (req == NULL) {
1434                 status = NT_STATUS_NO_MEMORY;
1435                 goto fail;
1436         }
1437
1438         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1439                 goto fail;
1440         }
1441
1442         status = cli_nt_hardlink_recv(req);
1443
1444  fail:
1445         TALLOC_FREE(frame);
1446         return status;
1447 }
1448
1449 /****************************************************************************
1450  Delete a file.
1451 ****************************************************************************/
1452
1453 static void cli_unlink_done(struct tevent_req *subreq);
1454
1455 struct cli_unlink_state {
1456         uint16_t vwv[1];
1457 };
1458
1459 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1460                                 struct tevent_context *ev,
1461                                 struct cli_state *cli,
1462                                 const char *fname,
1463                                 uint16_t mayhave_attrs)
1464 {
1465         struct tevent_req *req = NULL, *subreq = NULL;
1466         struct cli_unlink_state *state = NULL;
1467         uint8_t additional_flags = 0;
1468         uint16_t additional_flags2 = 0;
1469         uint8_t *bytes = NULL;
1470
1471         req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1472         if (req == NULL) {
1473                 return NULL;
1474         }
1475
1476         SSVAL(state->vwv+0, 0, mayhave_attrs);
1477
1478         bytes = talloc_array(state, uint8_t, 1);
1479         if (tevent_req_nomem(bytes, req)) {
1480                 return tevent_req_post(req, ev);
1481         }
1482         bytes[0] = 4;
1483         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
1484                                    strlen(fname)+1, NULL);
1485
1486         if (tevent_req_nomem(bytes, req)) {
1487                 return tevent_req_post(req, ev);
1488         }
1489
1490         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1491                 additional_flags2 = FLAGS2_REPARSE_PATH;
1492         }
1493
1494         subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1495                                 additional_flags2,
1496                                 1, state->vwv, talloc_get_size(bytes), bytes);
1497         if (tevent_req_nomem(subreq, req)) {
1498                 return tevent_req_post(req, ev);
1499         }
1500         tevent_req_set_callback(subreq, cli_unlink_done, req);
1501         return req;
1502 }
1503
1504 static void cli_unlink_done(struct tevent_req *subreq)
1505 {
1506         struct tevent_req *req = tevent_req_callback_data(
1507                 subreq, struct tevent_req);
1508         NTSTATUS status;
1509
1510         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1511         TALLOC_FREE(subreq);
1512         if (tevent_req_nterror(req, status)) {
1513                 return;
1514         }
1515         tevent_req_done(req);
1516 }
1517
1518 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1519 {
1520         return tevent_req_simple_recv_ntstatus(req);
1521 }
1522
1523 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1524 {
1525         TALLOC_CTX *frame = NULL;
1526         struct tevent_context *ev;
1527         struct tevent_req *req;
1528         NTSTATUS status = NT_STATUS_OK;
1529
1530         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1531                 return cli_smb2_unlink(cli, fname);
1532         }
1533
1534         frame = talloc_stackframe();
1535
1536         if (smbXcli_conn_has_async_calls(cli->conn)) {
1537                 /*
1538                  * Can't use sync call while an async call is in flight
1539                  */
1540                 status = NT_STATUS_INVALID_PARAMETER;
1541                 goto fail;
1542         }
1543
1544         ev = samba_tevent_context_init(frame);
1545         if (ev == NULL) {
1546                 status = NT_STATUS_NO_MEMORY;
1547                 goto fail;
1548         }
1549
1550         req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1551         if (req == NULL) {
1552                 status = NT_STATUS_NO_MEMORY;
1553                 goto fail;
1554         }
1555
1556         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1557                 goto fail;
1558         }
1559
1560         status = cli_unlink_recv(req);
1561
1562  fail:
1563         TALLOC_FREE(frame);
1564         return status;
1565 }
1566
1567 /****************************************************************************
1568  Create a directory.
1569 ****************************************************************************/
1570
1571 static void cli_mkdir_done(struct tevent_req *subreq);
1572
1573 struct cli_mkdir_state {
1574         int dummy;
1575 };
1576
1577 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1578                                   struct tevent_context *ev,
1579                                   struct cli_state *cli,
1580                                   const char *dname)
1581 {
1582         struct tevent_req *req = NULL, *subreq = NULL;
1583         struct cli_mkdir_state *state = NULL;
1584         uint8_t additional_flags = 0;
1585         uint16_t additional_flags2 = 0;
1586         uint8_t *bytes = NULL;
1587
1588         req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1589         if (req == NULL) {
1590                 return NULL;
1591         }
1592
1593         bytes = talloc_array(state, uint8_t, 1);
1594         if (tevent_req_nomem(bytes, req)) {
1595                 return tevent_req_post(req, ev);
1596         }
1597         bytes[0] = 4;
1598         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1599                                    strlen(dname)+1, NULL);
1600
1601         if (tevent_req_nomem(bytes, req)) {
1602                 return tevent_req_post(req, ev);
1603         }
1604
1605         if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1606                 additional_flags2 = FLAGS2_REPARSE_PATH;
1607         }
1608
1609         subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1610                         additional_flags2,
1611                         0, NULL, talloc_get_size(bytes), bytes);
1612         if (tevent_req_nomem(subreq, req)) {
1613                 return tevent_req_post(req, ev);
1614         }
1615         tevent_req_set_callback(subreq, cli_mkdir_done, req);
1616         return req;
1617 }
1618
1619 static void cli_mkdir_done(struct tevent_req *subreq)
1620 {
1621         struct tevent_req *req = tevent_req_callback_data(
1622                 subreq, struct tevent_req);
1623         NTSTATUS status;
1624
1625         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1626         TALLOC_FREE(subreq);
1627         if (tevent_req_nterror(req, status)) {
1628                 return;
1629         }
1630         tevent_req_done(req);
1631 }
1632
1633 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1634 {
1635         return tevent_req_simple_recv_ntstatus(req);
1636 }
1637
1638 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1639 {
1640         TALLOC_CTX *frame = NULL;
1641         struct tevent_context *ev;
1642         struct tevent_req *req;
1643         NTSTATUS status = NT_STATUS_OK;
1644
1645         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1646                 return cli_smb2_mkdir(cli, dname);
1647         }
1648
1649         frame = talloc_stackframe();
1650
1651         if (smbXcli_conn_has_async_calls(cli->conn)) {
1652                 /*
1653                  * Can't use sync call while an async call is in flight
1654                  */
1655                 status = NT_STATUS_INVALID_PARAMETER;
1656                 goto fail;
1657         }
1658
1659         ev = samba_tevent_context_init(frame);
1660         if (ev == NULL) {
1661                 status = NT_STATUS_NO_MEMORY;
1662                 goto fail;
1663         }
1664
1665         req = cli_mkdir_send(frame, ev, cli, dname);
1666         if (req == NULL) {
1667                 status = NT_STATUS_NO_MEMORY;
1668                 goto fail;
1669         }
1670
1671         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1672                 goto fail;
1673         }
1674
1675         status = cli_mkdir_recv(req);
1676
1677  fail:
1678         TALLOC_FREE(frame);
1679         return status;
1680 }
1681
1682 /****************************************************************************
1683  Remove a directory.
1684 ****************************************************************************/
1685
1686 static void cli_rmdir_done(struct tevent_req *subreq);
1687
1688 struct cli_rmdir_state {
1689         int dummy;
1690 };
1691
1692 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1693                                   struct tevent_context *ev,
1694                                   struct cli_state *cli,
1695                                   const char *dname)
1696 {
1697         struct tevent_req *req = NULL, *subreq = NULL;
1698         struct cli_rmdir_state *state = NULL;
1699         uint8_t additional_flags = 0;
1700         uint16_t additional_flags2 = 0;
1701         uint8_t *bytes = NULL;
1702
1703         req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1704         if (req == NULL) {
1705                 return NULL;
1706         }
1707
1708         bytes = talloc_array(state, uint8_t, 1);
1709         if (tevent_req_nomem(bytes, req)) {
1710                 return tevent_req_post(req, ev);
1711         }
1712         bytes[0] = 4;
1713         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1714                                    strlen(dname)+1, NULL);
1715
1716         if (tevent_req_nomem(bytes, req)) {
1717                 return tevent_req_post(req, ev);
1718         }
1719
1720         if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
1721                 additional_flags2 = FLAGS2_REPARSE_PATH;
1722         }
1723
1724         subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1725                         additional_flags2,
1726                         0, NULL, talloc_get_size(bytes), bytes);
1727         if (tevent_req_nomem(subreq, req)) {
1728                 return tevent_req_post(req, ev);
1729         }
1730         tevent_req_set_callback(subreq, cli_rmdir_done, req);
1731         return req;
1732 }
1733
1734 static void cli_rmdir_done(struct tevent_req *subreq)
1735 {
1736         struct tevent_req *req = tevent_req_callback_data(
1737                 subreq, struct tevent_req);
1738         NTSTATUS status;
1739
1740         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1741         TALLOC_FREE(subreq);
1742         if (tevent_req_nterror(req, status)) {
1743                 return;
1744         }
1745         tevent_req_done(req);
1746 }
1747
1748 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1749 {
1750         return tevent_req_simple_recv_ntstatus(req);
1751 }
1752
1753 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1754 {
1755         TALLOC_CTX *frame = NULL;
1756         struct tevent_context *ev;
1757         struct tevent_req *req;
1758         NTSTATUS status = NT_STATUS_OK;
1759
1760         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1761                 return cli_smb2_rmdir(cli, dname);
1762         }
1763
1764         frame = talloc_stackframe();
1765
1766         if (smbXcli_conn_has_async_calls(cli->conn)) {
1767                 /*
1768                  * Can't use sync call while an async call is in flight
1769                  */
1770                 status = NT_STATUS_INVALID_PARAMETER;
1771                 goto fail;
1772         }
1773
1774         ev = samba_tevent_context_init(frame);
1775         if (ev == NULL) {
1776                 status = NT_STATUS_NO_MEMORY;
1777                 goto fail;
1778         }
1779
1780         req = cli_rmdir_send(frame, ev, cli, dname);
1781         if (req == NULL) {
1782                 status = NT_STATUS_NO_MEMORY;
1783                 goto fail;
1784         }
1785
1786         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1787                 goto fail;
1788         }
1789
1790         status = cli_rmdir_recv(req);
1791
1792  fail:
1793         TALLOC_FREE(frame);
1794         return status;
1795 }
1796
1797 /****************************************************************************
1798  Set or clear the delete on close flag.
1799 ****************************************************************************/
1800
1801 struct doc_state {
1802         uint16_t setup;
1803         uint8_t param[6];
1804         uint8_t data[1];
1805 };
1806
1807 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
1808 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
1809
1810 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1811                                         struct tevent_context *ev,
1812                                         struct cli_state *cli,
1813                                         uint16_t fnum,
1814                                         bool flag)
1815 {
1816         struct tevent_req *req = NULL, *subreq = NULL;
1817         struct doc_state *state = NULL;
1818
1819         req = tevent_req_create(mem_ctx, &state, struct doc_state);
1820         if (req == NULL) {
1821                 return NULL;
1822         }
1823
1824         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1825                 subreq = cli_smb2_delete_on_close_send(state, ev, cli,
1826                                                        fnum, flag);
1827                 if (tevent_req_nomem(subreq, req)) {
1828                         return tevent_req_post(req, ev);
1829                 }
1830                 tevent_req_set_callback(subreq,
1831                                         cli_nt_delete_on_close_smb2_done,
1832                                         req);
1833                 return req;
1834         }
1835
1836         /* Setup setup word. */
1837         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1838
1839         /* Setup param array. */
1840         SSVAL(state->param,0,fnum);
1841         SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1842
1843         /* Setup data array. */
1844         SCVAL(&state->data[0], 0, flag ? 1 : 0);
1845
1846         subreq = cli_trans_send(state,                  /* mem ctx. */
1847                                 ev,                     /* event ctx. */
1848                                 cli,                    /* cli_state. */
1849                                 0,                      /* additional_flags2 */
1850                                 SMBtrans2,              /* cmd. */
1851                                 NULL,                   /* pipe name. */
1852                                 -1,                     /* fid. */
1853                                 0,                      /* function. */
1854                                 0,                      /* flags. */
1855                                 &state->setup,          /* setup. */
1856                                 1,                      /* num setup uint16_t words. */
1857                                 0,                      /* max returned setup. */
1858                                 state->param,           /* param. */
1859                                 6,                      /* num param. */
1860                                 2,                      /* max returned param. */
1861                                 state->data,            /* data. */
1862                                 1,                      /* num data. */
1863                                 0);                     /* max returned data. */
1864
1865         if (tevent_req_nomem(subreq, req)) {
1866                 return tevent_req_post(req, ev);
1867         }
1868         tevent_req_set_callback(subreq,
1869                                 cli_nt_delete_on_close_smb1_done,
1870                                 req);
1871         return req;
1872 }
1873
1874 static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
1875 {
1876         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
1877                                          NULL, 0, NULL, NULL, 0, NULL);
1878         tevent_req_simple_finish_ntstatus(subreq, status);
1879 }
1880
1881 static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
1882 {
1883         NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
1884         tevent_req_simple_finish_ntstatus(subreq, status);
1885 }
1886
1887 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1888 {
1889         return tevent_req_simple_recv_ntstatus(req);
1890 }
1891
1892 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1893 {
1894         TALLOC_CTX *frame = talloc_stackframe();
1895         struct tevent_context *ev = NULL;
1896         struct tevent_req *req = NULL;
1897         NTSTATUS status = NT_STATUS_OK;
1898
1899         if (smbXcli_conn_has_async_calls(cli->conn)) {
1900                 /*
1901                  * Can't use sync call while an async call is in flight
1902                  */
1903                 status = NT_STATUS_INVALID_PARAMETER;
1904                 goto fail;
1905         }
1906
1907         ev = samba_tevent_context_init(frame);
1908         if (ev == NULL) {
1909                 status = NT_STATUS_NO_MEMORY;
1910                 goto fail;
1911         }
1912
1913         req = cli_nt_delete_on_close_send(frame,
1914                                 ev,
1915                                 cli,
1916                                 fnum,
1917                                 flag);
1918         if (req == NULL) {
1919                 status = NT_STATUS_NO_MEMORY;
1920                 goto fail;
1921         }
1922
1923         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1924                 goto fail;
1925         }
1926
1927         status = cli_nt_delete_on_close_recv(req);
1928
1929  fail:
1930         TALLOC_FREE(frame);
1931         return status;
1932 }
1933
1934 struct cli_ntcreate1_state {
1935         uint16_t vwv[24];
1936         uint16_t fnum;
1937         struct smb_create_returns cr;
1938         struct tevent_req *subreq;
1939 };
1940
1941 static void cli_ntcreate1_done(struct tevent_req *subreq);
1942 static bool cli_ntcreate1_cancel(struct tevent_req *req);
1943
1944 static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
1945                                              struct tevent_context *ev,
1946                                              struct cli_state *cli,
1947                                              const char *fname,
1948                                              uint32_t CreatFlags,
1949                                              uint32_t DesiredAccess,
1950                                              uint32_t FileAttributes,
1951                                              uint32_t ShareAccess,
1952                                              uint32_t CreateDisposition,
1953                                              uint32_t CreateOptions,
1954                                              uint32_t ImpersonationLevel,
1955                                              uint8_t SecurityFlags)
1956 {
1957         struct tevent_req *req, *subreq;
1958         struct cli_ntcreate1_state *state;
1959         uint16_t *vwv;
1960         uint8_t *bytes;
1961         size_t converted_len;
1962         uint16_t additional_flags2 = 0;
1963
1964         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
1965         if (req == NULL) {
1966                 return NULL;
1967         }
1968
1969         vwv = state->vwv;
1970
1971         SCVAL(vwv+0, 0, 0xFF);
1972         SCVAL(vwv+0, 1, 0);
1973         SSVAL(vwv+1, 0, 0);
1974         SCVAL(vwv+2, 0, 0);
1975
1976         if (cli->use_oplocks) {
1977                 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1978         }
1979         SIVAL(vwv+3, 1, CreatFlags);
1980         SIVAL(vwv+5, 1, 0x0);   /* RootDirectoryFid */
1981         SIVAL(vwv+7, 1, DesiredAccess);
1982         SIVAL(vwv+9, 1, 0x0);   /* AllocationSize */
1983         SIVAL(vwv+11, 1, 0x0);  /* AllocationSize */
1984         SIVAL(vwv+13, 1, FileAttributes);
1985         SIVAL(vwv+15, 1, ShareAccess);
1986         SIVAL(vwv+17, 1, CreateDisposition);
1987         SIVAL(vwv+19, 1, CreateOptions |
1988                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
1989         SIVAL(vwv+21, 1, ImpersonationLevel);
1990         SCVAL(vwv+23, 1, SecurityFlags);
1991
1992         bytes = talloc_array(state, uint8_t, 0);
1993         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
1994                                    fname, strlen(fname)+1,
1995                                    &converted_len);
1996
1997         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
1998                 additional_flags2 = FLAGS2_REPARSE_PATH;
1999         }
2000
2001         /* sigh. this copes with broken netapp filer behaviour */
2002         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2003
2004         if (tevent_req_nomem(bytes, req)) {
2005                 return tevent_req_post(req, ev);
2006         }
2007
2008         SSVAL(vwv+2, 1, converted_len);
2009
2010         subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2011                         additional_flags2, 24, vwv,
2012                         talloc_get_size(bytes), bytes);
2013         if (tevent_req_nomem(subreq, req)) {
2014                 return tevent_req_post(req, ev);
2015         }
2016         tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2017
2018         state->subreq = subreq;
2019         tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2020
2021         return req;
2022 }
2023
2024 static void cli_ntcreate1_done(struct tevent_req *subreq)
2025 {
2026         struct tevent_req *req = tevent_req_callback_data(
2027                 subreq, struct tevent_req);
2028         struct cli_ntcreate1_state *state = tevent_req_data(
2029                 req, struct cli_ntcreate1_state);
2030         uint8_t wct;
2031         uint16_t *vwv;
2032         uint32_t num_bytes;
2033         uint8_t *bytes;
2034         NTSTATUS status;
2035
2036         status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2037                               &num_bytes, &bytes);
2038         TALLOC_FREE(subreq);
2039         if (tevent_req_nterror(req, status)) {
2040                 return;
2041         }
2042         state->cr.oplock_level = CVAL(vwv+2, 0);
2043         state->fnum = SVAL(vwv+2, 1);
2044         state->cr.create_action = IVAL(vwv+3, 1);
2045         state->cr.creation_time = BVAL(vwv+5, 1);
2046         state->cr.last_access_time = BVAL(vwv+9, 1);
2047         state->cr.last_write_time = BVAL(vwv+13, 1);
2048         state->cr.change_time   = BVAL(vwv+17, 1);
2049         state->cr.file_attributes = IVAL(vwv+21, 1);
2050         state->cr.allocation_size = BVAL(vwv+23, 1);
2051         state->cr.end_of_file   = BVAL(vwv+27, 1);
2052
2053         tevent_req_done(req);
2054 }
2055
2056 static bool cli_ntcreate1_cancel(struct tevent_req *req)
2057 {
2058         struct cli_ntcreate1_state *state = tevent_req_data(
2059                 req, struct cli_ntcreate1_state);
2060         return tevent_req_cancel(state->subreq);
2061 }
2062
2063 static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2064                                    uint16_t *pfnum,
2065                                    struct smb_create_returns *cr)
2066 {
2067         struct cli_ntcreate1_state *state = tevent_req_data(
2068                 req, struct cli_ntcreate1_state);
2069         NTSTATUS status;
2070
2071         if (tevent_req_is_nterror(req, &status)) {
2072                 return status;
2073         }
2074         *pfnum = state->fnum;
2075         if (cr != NULL) {
2076                 *cr = state->cr;
2077         }
2078         return NT_STATUS_OK;
2079 }
2080
2081 struct cli_ntcreate_state {
2082         NTSTATUS (*recv)(struct tevent_req *req, uint16_t *fnum,
2083                          struct smb_create_returns *cr);
2084         struct smb_create_returns cr;
2085         uint16_t fnum;
2086         struct tevent_req *subreq;
2087 };
2088
2089 static void cli_ntcreate_done(struct tevent_req *subreq);
2090 static bool cli_ntcreate_cancel(struct tevent_req *req);
2091
2092 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
2093                                      struct tevent_context *ev,
2094                                      struct cli_state *cli,
2095                                      const char *fname,
2096                                      uint32_t create_flags,
2097                                      uint32_t desired_access,
2098                                      uint32_t file_attributes,
2099                                      uint32_t share_access,
2100                                      uint32_t create_disposition,
2101                                      uint32_t create_options,
2102                                      uint8_t security_flags)
2103 {
2104         struct tevent_req *req, *subreq;
2105         struct cli_ntcreate_state *state;
2106         uint32_t impersonation_level = SMB2_IMPERSONATION_IMPERSONATION;
2107
2108         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2109         if (req == NULL) {
2110                 return NULL;
2111         }
2112
2113         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2114                 state->recv = cli_smb2_create_fnum_recv;
2115
2116                 if (cli->use_oplocks) {
2117                         create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
2118                 }
2119
2120                 subreq = cli_smb2_create_fnum_send(
2121                         state, ev, cli, fname, create_flags,
2122                         impersonation_level, desired_access,
2123                         file_attributes, share_access, create_disposition,
2124                         create_options);
2125         } else {
2126                 state->recv = cli_ntcreate1_recv;
2127                 subreq = cli_ntcreate1_send(
2128                         state, ev, cli, fname, create_flags, desired_access,
2129                         file_attributes, share_access, create_disposition,
2130                         create_options, impersonation_level, security_flags);
2131         }
2132         if (tevent_req_nomem(subreq, req)) {
2133                 return tevent_req_post(req, ev);
2134         }
2135         tevent_req_set_callback(subreq, cli_ntcreate_done, req);
2136
2137         state->subreq = subreq;
2138         tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
2139
2140         return req;
2141 }
2142
2143 static void cli_ntcreate_done(struct tevent_req *subreq)
2144 {
2145         struct tevent_req *req = tevent_req_callback_data(
2146                 subreq, struct tevent_req);
2147         struct cli_ntcreate_state *state = tevent_req_data(
2148                 req, struct cli_ntcreate_state);
2149         NTSTATUS status;
2150
2151         status = state->recv(subreq, &state->fnum, &state->cr);
2152         TALLOC_FREE(subreq);
2153         if (tevent_req_nterror(req, status)) {
2154                 return;
2155         }
2156         tevent_req_done(req);
2157 }
2158
2159 static bool cli_ntcreate_cancel(struct tevent_req *req)
2160 {
2161         struct cli_ntcreate_state *state = tevent_req_data(
2162                 req, struct cli_ntcreate_state);
2163         return tevent_req_cancel(state->subreq);
2164 }
2165
2166 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
2167                            struct smb_create_returns *cr)
2168 {
2169         struct cli_ntcreate_state *state = tevent_req_data(
2170                 req, struct cli_ntcreate_state);
2171         NTSTATUS status;
2172
2173         if (tevent_req_is_nterror(req, &status)) {
2174                 return status;
2175         }
2176         if (fnum != NULL) {
2177                 *fnum = state->fnum;
2178         }
2179         if (cr != NULL) {
2180                 *cr = state->cr;
2181         }
2182         return NT_STATUS_OK;
2183 }
2184
2185 NTSTATUS cli_ntcreate(struct cli_state *cli,
2186                       const char *fname,
2187                       uint32_t CreatFlags,
2188                       uint32_t DesiredAccess,
2189                       uint32_t FileAttributes,
2190                       uint32_t ShareAccess,
2191                       uint32_t CreateDisposition,
2192                       uint32_t CreateOptions,
2193                       uint8_t SecurityFlags,
2194                       uint16_t *pfid,
2195                       struct smb_create_returns *cr)
2196 {
2197         TALLOC_CTX *frame = talloc_stackframe();
2198         struct tevent_context *ev;
2199         struct tevent_req *req;
2200         NTSTATUS status = NT_STATUS_NO_MEMORY;
2201
2202         if (smbXcli_conn_has_async_calls(cli->conn)) {
2203                 /*
2204                  * Can't use sync call while an async call is in flight
2205                  */
2206                 status = NT_STATUS_INVALID_PARAMETER;
2207                 goto fail;
2208         }
2209
2210         ev = samba_tevent_context_init(frame);
2211         if (ev == NULL) {
2212                 goto fail;
2213         }
2214
2215         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2216                                 DesiredAccess, FileAttributes, ShareAccess,
2217                                 CreateDisposition, CreateOptions,
2218                                 SecurityFlags);
2219         if (req == NULL) {
2220                 goto fail;
2221         }
2222
2223         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2224                 goto fail;
2225         }
2226
2227         status = cli_ntcreate_recv(req, pfid, cr);
2228  fail:
2229         TALLOC_FREE(frame);
2230         return status;
2231 }
2232
2233 struct cli_nttrans_create_state {
2234         uint16_t fnum;
2235         struct smb_create_returns cr;
2236 };
2237
2238 static void cli_nttrans_create_done(struct tevent_req *subreq);
2239
2240 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
2241                                            struct tevent_context *ev,
2242                                            struct cli_state *cli,
2243                                            const char *fname,
2244                                            uint32_t CreatFlags,
2245                                            uint32_t DesiredAccess,
2246                                            uint32_t FileAttributes,
2247                                            uint32_t ShareAccess,
2248                                            uint32_t CreateDisposition,
2249                                            uint32_t CreateOptions,
2250                                            uint8_t SecurityFlags,
2251                                            struct security_descriptor *secdesc,
2252                                            struct ea_struct *eas,
2253                                            int num_eas)
2254 {
2255         struct tevent_req *req, *subreq;
2256         struct cli_nttrans_create_state *state;
2257         uint8_t *param;
2258         uint8_t *secdesc_buf;
2259         size_t secdesc_len;
2260         NTSTATUS status;
2261         size_t converted_len;
2262         uint16_t additional_flags2 = 0;
2263
2264         req = tevent_req_create(mem_ctx,
2265                                 &state, struct cli_nttrans_create_state);
2266         if (req == NULL) {
2267                 return NULL;
2268         }
2269
2270         if (secdesc != NULL) {
2271                 status = marshall_sec_desc(talloc_tos(), secdesc,
2272                                            &secdesc_buf, &secdesc_len);
2273                 if (tevent_req_nterror(req, status)) {
2274                         DEBUG(10, ("marshall_sec_desc failed: %s\n",
2275                                    nt_errstr(status)));
2276                         return tevent_req_post(req, ev);
2277                 }
2278         } else {
2279                 secdesc_buf = NULL;
2280                 secdesc_len = 0;
2281         }
2282
2283         if (num_eas != 0) {
2284                 /*
2285                  * TODO ;-)
2286                  */
2287                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
2288                 return tevent_req_post(req, ev);
2289         }
2290
2291         param = talloc_array(state, uint8_t, 53);
2292         if (tevent_req_nomem(param, req)) {
2293                 return tevent_req_post(req, ev);
2294         }
2295
2296         param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
2297                                       fname, strlen(fname),
2298                                       &converted_len);
2299         if (tevent_req_nomem(param, req)) {
2300                 return tevent_req_post(req, ev);
2301         }
2302
2303         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2304                 additional_flags2 = FLAGS2_REPARSE_PATH;
2305         }
2306
2307         SIVAL(param, 0, CreatFlags);
2308         SIVAL(param, 4, 0x0);   /* RootDirectoryFid */
2309         SIVAL(param, 8, DesiredAccess);
2310         SIVAL(param, 12, 0x0);  /* AllocationSize */
2311         SIVAL(param, 16, 0x0);  /* AllocationSize */
2312         SIVAL(param, 20, FileAttributes);
2313         SIVAL(param, 24, ShareAccess);
2314         SIVAL(param, 28, CreateDisposition);
2315         SIVAL(param, 32, CreateOptions |
2316                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2317         SIVAL(param, 36, secdesc_len);
2318         SIVAL(param, 40, 0);     /* EA length*/
2319         SIVAL(param, 44, converted_len);
2320         SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2321         SCVAL(param, 52, SecurityFlags);
2322
2323         subreq = cli_trans_send(state, ev, cli,
2324                                 additional_flags2, /* additional_flags2 */
2325                                 SMBnttrans,
2326                                 NULL, -1, /* name, fid */
2327                                 NT_TRANSACT_CREATE, 0,
2328                                 NULL, 0, 0, /* setup */
2329                                 param, talloc_get_size(param), 128, /* param */
2330                                 secdesc_buf, secdesc_len, 0); /* data */
2331         if (tevent_req_nomem(subreq, req)) {
2332                 return tevent_req_post(req, ev);
2333         }
2334         tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2335         return req;
2336 }
2337
2338 static void cli_nttrans_create_done(struct tevent_req *subreq)
2339 {
2340         struct tevent_req *req = tevent_req_callback_data(
2341                 subreq, struct tevent_req);
2342         struct cli_nttrans_create_state *state = tevent_req_data(
2343                 req, struct cli_nttrans_create_state);
2344         uint8_t *param;
2345         uint32_t num_param;
2346         NTSTATUS status;
2347
2348         status = cli_trans_recv(subreq, talloc_tos(), NULL,
2349                                 NULL, 0, NULL, /* rsetup */
2350                                 &param, 69, &num_param,
2351                                 NULL, 0, NULL);
2352         if (tevent_req_nterror(req, status)) {
2353                 return;
2354         }
2355         state->cr.oplock_level = CVAL(param, 0);
2356         state->fnum = SVAL(param, 2);
2357         state->cr.create_action = IVAL(param, 4);
2358         state->cr.creation_time = BVAL(param, 12);
2359         state->cr.last_access_time = BVAL(param, 20);
2360         state->cr.last_write_time = BVAL(param, 28);
2361         state->cr.change_time   = BVAL(param, 36);
2362         state->cr.file_attributes = IVAL(param, 44);
2363         state->cr.allocation_size = BVAL(param, 48);
2364         state->cr.end_of_file   = BVAL(param, 56);
2365
2366         TALLOC_FREE(param);
2367         tevent_req_done(req);
2368 }
2369
2370 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
2371                         uint16_t *fnum,
2372                         struct smb_create_returns *cr)
2373 {
2374         struct cli_nttrans_create_state *state = tevent_req_data(
2375                 req, struct cli_nttrans_create_state);
2376         NTSTATUS status;
2377
2378         if (tevent_req_is_nterror(req, &status)) {
2379                 return status;
2380         }
2381         *fnum = state->fnum;
2382         if (cr != NULL) {
2383                 *cr = state->cr;
2384         }
2385         return NT_STATUS_OK;
2386 }
2387
2388 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2389                             const char *fname,
2390                             uint32_t CreatFlags,
2391                             uint32_t DesiredAccess,
2392                             uint32_t FileAttributes,
2393                             uint32_t ShareAccess,
2394                             uint32_t CreateDisposition,
2395                             uint32_t CreateOptions,
2396                             uint8_t SecurityFlags,
2397                             struct security_descriptor *secdesc,
2398                             struct ea_struct *eas,
2399                             int num_eas,
2400                             uint16_t *pfid,
2401                             struct smb_create_returns *cr)
2402 {
2403         TALLOC_CTX *frame = talloc_stackframe();
2404         struct tevent_context *ev;
2405         struct tevent_req *req;
2406         NTSTATUS status = NT_STATUS_NO_MEMORY;
2407
2408         if (smbXcli_conn_has_async_calls(cli->conn)) {
2409                 /*
2410                  * Can't use sync call while an async call is in flight
2411                  */
2412                 status = NT_STATUS_INVALID_PARAMETER;
2413                 goto fail;
2414         }
2415         ev = samba_tevent_context_init(frame);
2416         if (ev == NULL) {
2417                 goto fail;
2418         }
2419         req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2420                                       DesiredAccess, FileAttributes,
2421                                       ShareAccess, CreateDisposition,
2422                                       CreateOptions, SecurityFlags,
2423                                       secdesc, eas, num_eas);
2424         if (req == NULL) {
2425                 goto fail;
2426         }
2427         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2428                 goto fail;
2429         }
2430         status = cli_nttrans_create_recv(req, pfid, cr);
2431  fail:
2432         TALLOC_FREE(frame);
2433         return status;
2434 }
2435
2436 /****************************************************************************
2437  Open a file
2438  WARNING: if you open with O_WRONLY then getattrE won't work!
2439 ****************************************************************************/
2440
2441 struct cli_openx_state {
2442         const char *fname;
2443         uint16_t vwv[15];
2444         uint16_t fnum;
2445         struct iovec bytes;
2446 };
2447
2448 static void cli_openx_done(struct tevent_req *subreq);
2449
2450 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2451                                    struct tevent_context *ev,
2452                                    struct cli_state *cli, const char *fname,
2453                                    int flags, int share_mode,
2454                                    struct tevent_req **psmbreq)
2455 {
2456         struct tevent_req *req, *subreq;
2457         struct cli_openx_state *state;
2458         unsigned openfn;
2459         unsigned accessmode;
2460         uint8_t additional_flags;
2461         uint16_t additional_flags2 = 0;
2462         uint8_t *bytes;
2463
2464         req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2465         if (req == NULL) {
2466                 return NULL;
2467         }
2468
2469         openfn = 0;
2470         if (flags & O_CREAT) {
2471                 openfn |= (1<<4);
2472         }
2473         if (!(flags & O_EXCL)) {
2474                 if (flags & O_TRUNC)
2475                         openfn |= (1<<1);
2476                 else
2477                         openfn |= (1<<0);
2478         }
2479
2480         accessmode = (share_mode<<4);
2481
2482         if ((flags & O_ACCMODE) == O_RDWR) {
2483                 accessmode |= 2;
2484         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2485                 accessmode |= 1;
2486         }
2487
2488 #if defined(O_SYNC)
2489         if ((flags & O_SYNC) == O_SYNC) {
2490                 accessmode |= (1<<14);
2491         }
2492 #endif /* O_SYNC */
2493
2494         if (share_mode == DENY_FCB) {
2495                 accessmode = 0xFF;
2496         }
2497
2498         SCVAL(state->vwv + 0, 0, 0xFF);
2499         SCVAL(state->vwv + 0, 1, 0);
2500         SSVAL(state->vwv + 1, 0, 0);
2501         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
2502         SSVAL(state->vwv + 3, 0, accessmode);
2503         SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2504         SSVAL(state->vwv + 5, 0, 0);
2505         SIVAL(state->vwv + 6, 0, 0);
2506         SSVAL(state->vwv + 8, 0, openfn);
2507         SIVAL(state->vwv + 9, 0, 0);
2508         SIVAL(state->vwv + 11, 0, 0);
2509         SIVAL(state->vwv + 13, 0, 0);
2510
2511         additional_flags = 0;
2512
2513         if (cli->use_oplocks) {
2514                 /* if using oplocks then ask for a batch oplock via
2515                    core and extended methods */
2516                 additional_flags =
2517                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2518                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2519         }
2520
2521         bytes = talloc_array(state, uint8_t, 0);
2522         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2523                                    strlen(fname)+1, NULL);
2524
2525         if (tevent_req_nomem(bytes, req)) {
2526                 return tevent_req_post(req, ev);
2527         }
2528
2529         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
2530                 additional_flags2 = FLAGS2_REPARSE_PATH;
2531         }
2532
2533         state->bytes.iov_base = (void *)bytes;
2534         state->bytes.iov_len = talloc_get_size(bytes);
2535
2536         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2537                         additional_flags2, 15, state->vwv, 1, &state->bytes);
2538         if (subreq == NULL) {
2539                 TALLOC_FREE(req);
2540                 return NULL;
2541         }
2542         tevent_req_set_callback(subreq, cli_openx_done, req);
2543         *psmbreq = subreq;
2544         return req;
2545 }
2546
2547 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2548                                  struct cli_state *cli, const char *fname,
2549                                  int flags, int share_mode)
2550 {
2551         struct tevent_req *req, *subreq;
2552         NTSTATUS status;
2553
2554         req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
2555                               &subreq);
2556         if (req == NULL) {
2557                 return NULL;
2558         }
2559
2560         status = smb1cli_req_chain_submit(&subreq, 1);
2561         if (tevent_req_nterror(req, status)) {
2562                 return tevent_req_post(req, ev);
2563         }
2564         return req;
2565 }
2566
2567 static void cli_openx_done(struct tevent_req *subreq)
2568 {
2569         struct tevent_req *req = tevent_req_callback_data(
2570                 subreq, struct tevent_req);
2571         struct cli_openx_state *state = tevent_req_data(
2572                 req, struct cli_openx_state);
2573         uint8_t wct;
2574         uint16_t *vwv;
2575         NTSTATUS status;
2576
2577         status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
2578                               NULL);
2579         TALLOC_FREE(subreq);
2580         if (tevent_req_nterror(req, status)) {
2581                 return;
2582         }
2583         state->fnum = SVAL(vwv+2, 0);
2584         tevent_req_done(req);
2585 }
2586
2587 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2588 {
2589         struct cli_openx_state *state = tevent_req_data(
2590                 req, struct cli_openx_state);
2591         NTSTATUS status;
2592
2593         if (tevent_req_is_nterror(req, &status)) {
2594                 return status;
2595         }
2596         *pfnum = state->fnum;
2597         return NT_STATUS_OK;
2598 }
2599
2600 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
2601              int share_mode, uint16_t *pfnum)
2602 {
2603         TALLOC_CTX *frame = talloc_stackframe();
2604         struct tevent_context *ev;
2605         struct tevent_req *req;
2606         NTSTATUS status = NT_STATUS_NO_MEMORY;
2607
2608         if (smbXcli_conn_has_async_calls(cli->conn)) {
2609                 /*
2610                  * Can't use sync call while an async call is in flight
2611                  */
2612                 status = NT_STATUS_INVALID_PARAMETER;
2613                 goto fail;
2614         }
2615
2616         ev = samba_tevent_context_init(frame);
2617         if (ev == NULL) {
2618                 goto fail;
2619         }
2620
2621         req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
2622         if (req == NULL) {
2623                 goto fail;
2624         }
2625
2626         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2627                 goto fail;
2628         }
2629
2630         status = cli_openx_recv(req, pfnum);
2631  fail:
2632         TALLOC_FREE(frame);
2633         return status;
2634 }
2635 /****************************************************************************
2636  Synchronous wrapper function that does an NtCreateX open by preference
2637  and falls back to openX if this fails.
2638 ****************************************************************************/
2639
2640 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2641                         int share_mode_in, uint16_t *pfnum)
2642 {
2643         NTSTATUS status;
2644         unsigned int openfn = 0;
2645         unsigned int dos_deny = 0;
2646         uint32_t access_mask, share_mode, create_disposition, create_options;
2647         struct smb_create_returns cr;
2648
2649         /* Do the initial mapping into OpenX parameters. */
2650         if (flags & O_CREAT) {
2651                 openfn |= (1<<4);
2652         }
2653         if (!(flags & O_EXCL)) {
2654                 if (flags & O_TRUNC)
2655                         openfn |= (1<<1);
2656                 else
2657                         openfn |= (1<<0);
2658         }
2659
2660         dos_deny = (share_mode_in<<4);
2661
2662         if ((flags & O_ACCMODE) == O_RDWR) {
2663                 dos_deny |= 2;
2664         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2665                 dos_deny |= 1;
2666         }
2667
2668 #if defined(O_SYNC)
2669         if ((flags & O_SYNC) == O_SYNC) {
2670                 dos_deny |= (1<<14);
2671         }
2672 #endif /* O_SYNC */
2673
2674         if (share_mode_in == DENY_FCB) {
2675                 dos_deny = 0xFF;
2676         }
2677
2678 #if 0
2679         /* Hmmm. This is what I think the above code
2680            should look like if it's using the constants
2681            we #define. JRA. */
2682
2683         if (flags & O_CREAT) {
2684                 openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
2685         }
2686         if (!(flags & O_EXCL)) {
2687                 if (flags & O_TRUNC)
2688                         openfn |= OPENX_FILE_EXISTS_TRUNCATE;
2689                 else
2690                         openfn |= OPENX_FILE_EXISTS_OPEN;
2691         }
2692
2693         dos_deny = SET_DENY_MODE(share_mode_in);
2694
2695         if ((flags & O_ACCMODE) == O_RDWR) {
2696                 dos_deny |= DOS_OPEN_RDWR;
2697         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2698                 dos_deny |= DOS_OPEN_WRONLY;
2699         }
2700
2701 #if defined(O_SYNC)
2702         if ((flags & O_SYNC) == O_SYNC) {
2703                 dos_deny |= FILE_SYNC_OPENMODE;
2704         }
2705 #endif /* O_SYNC */
2706
2707         if (share_mode_in == DENY_FCB) {
2708                 dos_deny = 0xFF;
2709         }
2710 #endif
2711
2712         if (!map_open_params_to_ntcreate(fname, dos_deny,
2713                                         openfn, &access_mask,
2714                                         &share_mode, &create_disposition,
2715                                         &create_options, NULL)) {
2716                 goto try_openx;
2717         }
2718
2719         status = cli_ntcreate(cli,
2720                                 fname,
2721                                 0,
2722                                 access_mask,
2723                                 0,
2724                                 share_mode,
2725                                 create_disposition,
2726                                 create_options,
2727                                 0,
2728                                 pfnum,
2729                                 &cr);
2730
2731         /* Try and cope will all varients of "we don't do this call"
2732            and fall back to openX. */
2733
2734         if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
2735                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
2736                         NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
2737                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
2738                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
2739                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
2740                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
2741                         NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
2742                         NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
2743                 goto try_openx;
2744         }
2745
2746         if (NT_STATUS_IS_OK(status) &&
2747             (create_options & FILE_NON_DIRECTORY_FILE) &&
2748             (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
2749         {
2750                 /*
2751                  * Some (broken) servers return a valid handle
2752                  * for directories even if FILE_NON_DIRECTORY_FILE
2753                  * is set. Just close the handle and set the
2754                  * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
2755                  */
2756                 status = cli_close(cli, *pfnum);
2757                 if (!NT_STATUS_IS_OK(status)) {
2758                         return status;
2759                 }
2760                 status = NT_STATUS_FILE_IS_A_DIRECTORY;
2761                 /* Set this so libsmbclient can retrieve it. */
2762                 cli->raw_status = status;
2763         }
2764
2765         return status;
2766
2767   try_openx:
2768
2769         return cli_openx(cli, fname, flags, share_mode_in, pfnum);
2770 }
2771
2772 /****************************************************************************
2773  Close a file.
2774 ****************************************************************************/
2775
2776 struct cli_smb1_close_state {
2777         uint16_t vwv[3];
2778 };
2779
2780 static void cli_smb1_close_done(struct tevent_req *subreq);
2781
2782 struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
2783                                 struct tevent_context *ev,
2784                                 struct cli_state *cli,
2785                                 uint16_t fnum,
2786                                 struct tevent_req **psubreq)
2787 {
2788         struct tevent_req *req, *subreq;
2789         struct cli_smb1_close_state *state;
2790
2791         req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
2792         if (req == NULL) {
2793                 return NULL;
2794         }
2795
2796         SSVAL(state->vwv+0, 0, fnum);
2797         SIVALS(state->vwv+1, 0, -1);
2798
2799         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
2800                                 3, state->vwv, 0, NULL);
2801         if (subreq == NULL) {
2802                 TALLOC_FREE(req);
2803                 return NULL;
2804         }
2805         tevent_req_set_callback(subreq, cli_smb1_close_done, req);
2806         *psubreq = subreq;
2807         return req;
2808 }
2809
2810 static void cli_smb1_close_done(struct tevent_req *subreq)
2811 {
2812         struct tevent_req *req = tevent_req_callback_data(
2813                 subreq, struct tevent_req);
2814         NTSTATUS status;
2815
2816         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2817         TALLOC_FREE(subreq);
2818         if (tevent_req_nterror(req, status)) {
2819                 return;
2820         }
2821         tevent_req_done(req);
2822 }
2823
2824 struct cli_close_state {
2825         int dummy;
2826 };
2827
2828 static void cli_close_done(struct tevent_req *subreq);
2829
2830 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2831                                 struct tevent_context *ev,
2832                                 struct cli_state *cli,
2833                                 uint16_t fnum)
2834 {
2835         struct tevent_req *req, *subreq;
2836         struct cli_close_state *state;
2837         NTSTATUS status;
2838
2839         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2840         if (req == NULL) {
2841                 return NULL;
2842         }
2843
2844         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2845                 subreq = cli_smb2_close_fnum_send(state,
2846                                                 ev,
2847                                                 cli,
2848                                                 fnum);
2849                 if (tevent_req_nomem(subreq, req)) {
2850                         return tevent_req_post(req, ev);
2851                 }
2852         } else {
2853                 struct tevent_req *ch_req = NULL;
2854                 subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
2855                 if (tevent_req_nomem(subreq, req)) {
2856                         return tevent_req_post(req, ev);
2857                 }
2858                 status = smb1cli_req_chain_submit(&ch_req, 1);
2859                 if (tevent_req_nterror(req, status)) {
2860                         return tevent_req_post(req, ev);
2861                 }
2862         }
2863
2864         tevent_req_set_callback(subreq, cli_close_done, req);
2865         return req;
2866 }
2867
2868 static void cli_close_done(struct tevent_req *subreq)
2869 {
2870         struct tevent_req *req = tevent_req_callback_data(
2871                 subreq, struct tevent_req);
2872         NTSTATUS status = NT_STATUS_OK;
2873         bool err = tevent_req_is_nterror(subreq, &status);
2874
2875         TALLOC_FREE(subreq);
2876         if (err) {
2877                 tevent_req_nterror(req, status);
2878                 return;
2879         }
2880         tevent_req_done(req);
2881 }
2882
2883 NTSTATUS cli_close_recv(struct tevent_req *req)
2884 {
2885         return tevent_req_simple_recv_ntstatus(req);
2886 }
2887
2888 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2889 {
2890         TALLOC_CTX *frame = NULL;
2891         struct tevent_context *ev;
2892         struct tevent_req *req;
2893         NTSTATUS status = NT_STATUS_OK;
2894
2895         frame = talloc_stackframe();
2896
2897         if (smbXcli_conn_has_async_calls(cli->conn)) {
2898                 /*
2899                  * Can't use sync call while an async call is in flight
2900                  */
2901                 status = NT_STATUS_INVALID_PARAMETER;
2902                 goto fail;
2903         }
2904
2905         ev = samba_tevent_context_init(frame);
2906         if (ev == NULL) {
2907                 status = NT_STATUS_NO_MEMORY;
2908                 goto fail;
2909         }
2910
2911         req = cli_close_send(frame, ev, cli, fnum);
2912         if (req == NULL) {
2913                 status = NT_STATUS_NO_MEMORY;
2914                 goto fail;
2915         }
2916
2917         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2918                 goto fail;
2919         }
2920
2921         status = cli_close_recv(req);
2922  fail:
2923         TALLOC_FREE(frame);
2924         return status;
2925 }
2926
2927 /****************************************************************************
2928  Truncate a file to a specified size
2929 ****************************************************************************/
2930
2931 struct ftrunc_state {
2932         uint16_t setup;
2933         uint8_t param[6];
2934         uint8_t data[8];
2935 };
2936
2937 static void cli_ftruncate_done(struct tevent_req *subreq)
2938 {
2939         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2940                                          NULL, 0, NULL, NULL, 0, NULL);
2941         tevent_req_simple_finish_ntstatus(subreq, status);
2942 }
2943
2944 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2945                                         struct tevent_context *ev,
2946                                         struct cli_state *cli,
2947                                         uint16_t fnum,
2948                                         uint64_t size)
2949 {
2950         struct tevent_req *req = NULL, *subreq = NULL;
2951         struct ftrunc_state *state = NULL;
2952
2953         req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2954         if (req == NULL) {
2955                 return NULL;
2956         }
2957
2958         /* Setup setup word. */
2959         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2960
2961         /* Setup param array. */
2962         SSVAL(state->param,0,fnum);
2963         SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2964         SSVAL(state->param,4,0);
2965
2966         /* Setup data array. */
2967         SBVAL(state->data, 0, size);
2968
2969         subreq = cli_trans_send(state,                  /* mem ctx. */
2970                                 ev,                     /* event ctx. */
2971                                 cli,                    /* cli_state. */
2972                                 0,                      /* additional_flags2 */
2973                                 SMBtrans2,              /* cmd. */
2974                                 NULL,                   /* pipe name. */
2975                                 -1,                     /* fid. */
2976                                 0,                      /* function. */
2977                                 0,                      /* flags. */
2978                                 &state->setup,          /* setup. */
2979                                 1,                      /* num setup uint16_t words. */
2980                                 0,                      /* max returned setup. */
2981                                 state->param,           /* param. */
2982                                 6,                      /* num param. */
2983                                 2,                      /* max returned param. */
2984                                 state->data,            /* data. */
2985                                 8,                      /* num data. */
2986                                 0);                     /* max returned data. */
2987
2988         if (tevent_req_nomem(subreq, req)) {
2989                 return tevent_req_post(req, ev);
2990         }
2991         tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2992         return req;
2993 }
2994
2995 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2996 {
2997         return tevent_req_simple_recv_ntstatus(req);
2998 }
2999
3000 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3001 {
3002         TALLOC_CTX *frame = NULL;
3003         struct tevent_context *ev = NULL;
3004         struct tevent_req *req = NULL;
3005         NTSTATUS status = NT_STATUS_OK;
3006
3007         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3008                 return cli_smb2_ftruncate(cli, fnum, size);
3009         }
3010
3011         frame = talloc_stackframe();
3012
3013         if (smbXcli_conn_has_async_calls(cli->conn)) {
3014                 /*
3015                  * Can't use sync call while an async call is in flight
3016                  */
3017                 status = NT_STATUS_INVALID_PARAMETER;
3018                 goto fail;
3019         }
3020
3021         ev = samba_tevent_context_init(frame);
3022         if (ev == NULL) {
3023                 status = NT_STATUS_NO_MEMORY;
3024                 goto fail;
3025         }
3026
3027         req = cli_ftruncate_send(frame,
3028                                 ev,
3029                                 cli,
3030                                 fnum,
3031                                 size);
3032         if (req == NULL) {
3033                 status = NT_STATUS_NO_MEMORY;
3034                 goto fail;
3035         }
3036
3037         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3038                 goto fail;
3039         }
3040
3041         status = cli_ftruncate_recv(req);
3042
3043  fail:
3044         TALLOC_FREE(frame);
3045         return status;
3046 }
3047
3048 /****************************************************************************
3049  send a lock with a specified locktype
3050  this is used for testing LOCKING_ANDX_CANCEL_LOCK
3051 ****************************************************************************/
3052
3053 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
3054                       uint32_t offset, uint32_t len,
3055                       int timeout, unsigned char locktype)
3056 {
3057         uint16_t vwv[8];
3058         uint8_t bytes[10];
3059         NTSTATUS status;
3060         unsigned int set_timeout = 0;
3061         unsigned int saved_timeout = 0;
3062
3063         SCVAL(vwv + 0, 0, 0xff);
3064         SCVAL(vwv + 0, 1, 0);
3065         SSVAL(vwv + 1, 0, 0);
3066         SSVAL(vwv + 2, 0, fnum);
3067         SCVAL(vwv + 3, 0, locktype);
3068         SCVAL(vwv + 3, 1, 0);
3069         SIVALS(vwv + 4, 0, timeout);
3070         SSVAL(vwv + 6, 0, 0);
3071         SSVAL(vwv + 7, 0, 1);
3072
3073         SSVAL(bytes, 0, cli_getpid(cli));
3074         SIVAL(bytes, 2, offset);
3075         SIVAL(bytes, 6, len);
3076
3077         if (timeout != 0) {
3078                 if (timeout == -1) {
3079                         set_timeout = 0x7FFFFFFF;
3080                 } else {
3081                         set_timeout = timeout + 2*1000;
3082                 }
3083                 saved_timeout = cli_set_timeout(cli, set_timeout);
3084         }
3085
3086         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3087                          10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3088
3089         if (saved_timeout != 0) {
3090                 cli_set_timeout(cli, saved_timeout);
3091         }
3092
3093         return status;
3094 }
3095
3096 /****************************************************************************
3097  Lock a file.
3098  note that timeout is in units of 2 milliseconds
3099 ****************************************************************************/
3100
3101 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
3102                   uint32_t offset, uint32_t len, int timeout,
3103                   enum brl_type lock_type)
3104 {
3105         NTSTATUS status;
3106
3107         status = cli_locktype(cli, fnum, offset, len, timeout,
3108                               (lock_type == READ_LOCK? 1 : 0));
3109         return status;
3110 }
3111
3112 /****************************************************************************
3113  Unlock a file.
3114 ****************************************************************************/
3115
3116 struct cli_unlock_state {
3117         uint16_t vwv[8];
3118         uint8_t data[10];
3119 };
3120
3121 static void cli_unlock_done(struct tevent_req *subreq);
3122
3123 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
3124                                 struct tevent_context *ev,
3125                                 struct cli_state *cli,
3126                                 uint16_t fnum,
3127                                 uint64_t offset,
3128                                 uint64_t len)
3129
3130 {
3131         struct tevent_req *req = NULL, *subreq = NULL;
3132         struct cli_unlock_state *state = NULL;
3133         uint8_t additional_flags = 0;
3134
3135         req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
3136         if (req == NULL) {
3137                 return NULL;
3138         }
3139
3140         SCVAL(state->vwv+0, 0, 0xFF);
3141         SSVAL(state->vwv+2, 0, fnum);
3142         SCVAL(state->vwv+3, 0, 0);
3143         SIVALS(state->vwv+4, 0, 0);
3144         SSVAL(state->vwv+6, 0, 1);
3145         SSVAL(state->vwv+7, 0, 0);
3146
3147         SSVAL(state->data, 0, cli_getpid(cli));
3148         SIVAL(state->data, 2, offset);
3149         SIVAL(state->data, 6, len);
3150
3151         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3152                                 8, state->vwv, 10, state->data);
3153         if (tevent_req_nomem(subreq, req)) {
3154                 return tevent_req_post(req, ev);
3155         }
3156         tevent_req_set_callback(subreq, cli_unlock_done, req);
3157         return req;
3158 }
3159
3160 static void cli_unlock_done(struct tevent_req *subreq)
3161 {
3162         struct tevent_req *req = tevent_req_callback_data(
3163                                 subreq, struct tevent_req);
3164         NTSTATUS status;
3165
3166         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3167         TALLOC_FREE(subreq);
3168         if (tevent_req_nterror(req, status)) {
3169                 return;
3170         }
3171         tevent_req_done(req);
3172 }
3173
3174 NTSTATUS cli_unlock_recv(struct tevent_req *req)
3175 {
3176         return tevent_req_simple_recv_ntstatus(req);
3177 }
3178
3179 NTSTATUS cli_unlock(struct cli_state *cli,
3180                         uint16_t fnum,
3181                         uint32_t offset,
3182                         uint32_t len)
3183 {
3184         TALLOC_CTX *frame = talloc_stackframe();
3185         struct tevent_context *ev;
3186         struct tevent_req *req;
3187         NTSTATUS status = NT_STATUS_OK;
3188
3189         if (smbXcli_conn_has_async_calls(cli->conn)) {
3190                 /*
3191                  * Can't use sync call while an async call is in flight
3192                  */
3193                 status = NT_STATUS_INVALID_PARAMETER;
3194                 goto fail;
3195         }
3196
3197         ev = samba_tevent_context_init(frame);
3198         if (ev == NULL) {
3199                 status = NT_STATUS_NO_MEMORY;
3200                 goto fail;
3201         }
3202
3203         req = cli_unlock_send(frame, ev, cli,
3204                         fnum, offset, len);
3205         if (req == NULL) {
3206                 status = NT_STATUS_NO_MEMORY;
3207                 goto fail;
3208         }
3209
3210         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3211                 goto fail;
3212         }
3213
3214         status = cli_unlock_recv(req);
3215
3216  fail:
3217         TALLOC_FREE(frame);
3218         return status;
3219 }
3220
3221 /****************************************************************************
3222  Lock a file with 64 bit offsets.
3223 ****************************************************************************/
3224
3225 NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
3226                     uint64_t offset, uint64_t len, int timeout,
3227                     enum brl_type lock_type)
3228 {
3229         uint16_t vwv[8];
3230         uint8_t bytes[20];
3231         unsigned int set_timeout = 0;
3232         unsigned int saved_timeout = 0;
3233         int ltype;
3234         NTSTATUS status;
3235
3236         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3237                 return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
3238         }
3239
3240         ltype = (lock_type == READ_LOCK? 1 : 0);
3241         ltype |= LOCKING_ANDX_LARGE_FILES;
3242
3243         SCVAL(vwv + 0, 0, 0xff);
3244         SCVAL(vwv + 0, 1, 0);
3245         SSVAL(vwv + 1, 0, 0);
3246         SSVAL(vwv + 2, 0, fnum);
3247         SCVAL(vwv + 3, 0, ltype);
3248         SCVAL(vwv + 3, 1, 0);
3249         SIVALS(vwv + 4, 0, timeout);
3250         SSVAL(vwv + 6, 0, 0);
3251         SSVAL(vwv + 7, 0, 1);
3252
3253         SIVAL(bytes, 0, cli_getpid(cli));
3254         SOFF_T_R(bytes, 4, offset);
3255         SOFF_T_R(bytes, 12, len);
3256
3257         if (timeout != 0) {
3258                 if (timeout == -1) {
3259                         set_timeout = 0x7FFFFFFF;
3260                 } else {
3261                         set_timeout = timeout + 2*1000;
3262                 }
3263                 saved_timeout = cli_set_timeout(cli, set_timeout);
3264         }
3265
3266         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
3267                          20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
3268
3269         if (saved_timeout != 0) {
3270                 cli_set_timeout(cli, saved_timeout);
3271         }
3272
3273         return status;
3274 }
3275
3276 /****************************************************************************
3277  Unlock a file with 64 bit offsets.
3278 ****************************************************************************/
3279
3280 struct cli_unlock64_state {
3281         uint16_t vwv[8];
3282         uint8_t data[20];
3283 };
3284
3285 static void cli_unlock64_done(struct tevent_req *subreq);
3286
3287 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
3288                                 struct tevent_context *ev,
3289                                 struct cli_state *cli,
3290                                 uint16_t fnum,
3291                                 uint64_t offset,
3292                                 uint64_t len)
3293
3294 {
3295         struct tevent_req *req = NULL, *subreq = NULL;
3296         struct cli_unlock64_state *state = NULL;
3297         uint8_t additional_flags = 0;
3298
3299         req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
3300         if (req == NULL) {
3301                 return NULL;
3302         }
3303
3304         SCVAL(state->vwv+0, 0, 0xff);
3305         SSVAL(state->vwv+2, 0, fnum);
3306         SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
3307         SIVALS(state->vwv+4, 0, 0);
3308         SSVAL(state->vwv+6, 0, 1);
3309         SSVAL(state->vwv+7, 0, 0);
3310
3311         SIVAL(state->data, 0, cli_getpid(cli));
3312         SOFF_T_R(state->data, 4, offset);
3313         SOFF_T_R(state->data, 12, len);
3314
3315         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags, 0,
3316                                 8, state->vwv, 20, state->data);
3317         if (tevent_req_nomem(subreq, req)) {
3318                 return tevent_req_post(req, ev);
3319         }
3320         tevent_req_set_callback(subreq, cli_unlock64_done, req);
3321         return req;
3322 }
3323
3324 static void cli_unlock64_done(struct tevent_req *subreq)
3325 {
3326         struct tevent_req *req = tevent_req_callback_data(
3327                                 subreq, struct tevent_req);
3328         NTSTATUS status;
3329
3330         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3331         TALLOC_FREE(subreq);
3332         if (tevent_req_nterror(req, status)) {
3333                 return;
3334         }
3335         tevent_req_done(req);
3336 }
3337
3338 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
3339 {
3340         return tevent_req_simple_recv_ntstatus(req);
3341 }
3342
3343 NTSTATUS cli_unlock64(struct cli_state *cli,
3344                                 uint16_t fnum,
3345                                 uint64_t offset,
3346                                 uint64_t len)
3347 {
3348         TALLOC_CTX *frame = talloc_stackframe();
3349         struct tevent_context *ev;
3350         struct tevent_req *req;
3351         NTSTATUS status = NT_STATUS_OK;
3352
3353         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
3354                 return cli_unlock(cli, fnum, offset, len);
3355         }
3356
3357         if (smbXcli_conn_has_async_calls(cli->conn)) {
3358                 /*
3359                  * Can't use sync call while an async call is in flight
3360                  */
3361                 status = NT_STATUS_INVALID_PARAMETER;
3362                 goto fail;
3363         }
3364
3365         ev = samba_tevent_context_init(frame);
3366         if (ev == NULL) {
3367                 status = NT_STATUS_NO_MEMORY;
3368                 goto fail;
3369         }
3370
3371         req = cli_unlock64_send(frame, ev, cli,
3372                         fnum, offset, len);
3373         if (req == NULL) {
3374                 status = NT_STATUS_NO_MEMORY;
3375                 goto fail;
3376         }
3377
3378         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3379                 goto fail;
3380         }
3381
3382         status = cli_unlock64_recv(req);
3383
3384  fail:
3385         TALLOC_FREE(frame);
3386         return status;
3387 }
3388
3389 /****************************************************************************
3390  Get/unlock a POSIX lock on a file - internal function.
3391 ****************************************************************************/
3392
3393 struct posix_lock_state {
3394         uint16_t setup;
3395         uint8_t param[4];
3396         uint8_t data[POSIX_LOCK_DATA_SIZE];
3397 };
3398
3399 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3400 {
3401         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3402                                          NULL, 0, NULL, NULL, 0, NULL);
3403         tevent_req_simple_finish_ntstatus(subreq, status);
3404 }
3405
3406 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3407                                         struct tevent_context *ev,
3408                                         struct cli_state *cli,
3409                                         uint16_t fnum,
3410                                         uint64_t offset,
3411                                         uint64_t len,
3412                                         bool wait_lock,
3413                                         enum brl_type lock_type)
3414 {
3415         struct tevent_req *req = NULL, *subreq = NULL;
3416         struct posix_lock_state *state = NULL;
3417
3418         req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3419         if (req == NULL) {
3420                 return NULL;
3421         }
3422
3423         /* Setup setup word. */
3424         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3425
3426         /* Setup param array. */
3427         SSVAL(&state->param, 0, fnum);
3428         SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3429
3430         /* Setup data array. */
3431         switch (lock_type) {
3432                 case READ_LOCK:
3433                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3434                                 POSIX_LOCK_TYPE_READ);
3435                         break;
3436                 case WRITE_LOCK:
3437                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3438                                 POSIX_LOCK_TYPE_WRITE);
3439                         break;
3440                 case UNLOCK_LOCK:
3441                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3442                                 POSIX_LOCK_TYPE_UNLOCK);
3443                         break;
3444                 default:
3445                         return NULL;
3446         }
3447
3448         if (wait_lock) {
3449                 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3450                                 POSIX_LOCK_FLAG_WAIT);
3451         } else {
3452                 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3453                                 POSIX_LOCK_FLAG_NOWAIT);
3454         }
3455
3456         SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3457         SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3458         SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3459
3460         subreq = cli_trans_send(state,                  /* mem ctx. */
3461                                 ev,                     /* event ctx. */
3462                                 cli,                    /* cli_state. */
3463                                 0,                      /* additional_flags2 */
3464                                 SMBtrans2,              /* cmd. */
3465                                 NULL,                   /* pipe name. */
3466                                 -1,                     /* fid. */
3467                                 0,                      /* function. */
3468                                 0,                      /* flags. */
3469                                 &state->setup,          /* setup. */
3470                                 1,                      /* num setup uint16_t words. */
3471                                 0,                      /* max returned setup. */
3472                                 state->param,           /* param. */
3473                                 4,                      /* num param. */
3474                                 2,                      /* max returned param. */
3475                                 state->data,            /* data. */
3476                                 POSIX_LOCK_DATA_SIZE,   /* num data. */
3477                                 0);                     /* max returned data. */
3478
3479         if (tevent_req_nomem(subreq, req)) {
3480                 return tevent_req_post(req, ev);
3481         }
3482         tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3483         return req;
3484 }
3485
3486 /****************************************************************************
3487  POSIX Lock a file.
3488 ****************************************************************************/
3489
3490 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3491                                         struct tevent_context *ev,
3492                                         struct cli_state *cli,
3493                                         uint16_t fnum,
3494                                         uint64_t offset,
3495                                         uint64_t len,
3496                                         bool wait_lock,
3497                                         enum brl_type lock_type)
3498 {
3499         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3500                                         wait_lock, lock_type);
3501 }
3502
3503 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3504 {
3505         return tevent_req_simple_recv_ntstatus(req);
3506 }
3507
3508 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3509                         uint64_t offset, uint64_t len,
3510                         bool wait_lock, enum brl_type lock_type)
3511 {
3512         TALLOC_CTX *frame = talloc_stackframe();
3513         struct tevent_context *ev = NULL;
3514         struct tevent_req *req = NULL;
3515         NTSTATUS status = NT_STATUS_OK;
3516
3517         if (smbXcli_conn_has_async_calls(cli->conn)) {
3518                 /*
3519                  * Can't use sync call while an async call is in flight
3520                  */
3521                 status = NT_STATUS_INVALID_PARAMETER;
3522                 goto fail;
3523         }
3524
3525         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3526                 status = NT_STATUS_INVALID_PARAMETER;
3527                 goto fail;
3528         }
3529
3530         ev = samba_tevent_context_init(frame);
3531         if (ev == NULL) {
3532                 status = NT_STATUS_NO_MEMORY;
3533                 goto fail;
3534         }
3535
3536         req = cli_posix_lock_send(frame,
3537                                 ev,
3538                                 cli,
3539                                 fnum,
3540                                 offset,
3541                                 len,
3542                                 wait_lock,
3543                                 lock_type);
3544         if (req == NULL) {
3545                 status = NT_STATUS_NO_MEMORY;
3546                 goto fail;
3547         }
3548
3549         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3550                 goto fail;
3551         }
3552
3553         status = cli_posix_lock_recv(req);
3554
3555  fail:
3556         TALLOC_FREE(frame);
3557         return status;
3558 }
3559
3560 /****************************************************************************
3561  POSIX Unlock a file.
3562 ****************************************************************************/
3563
3564 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3565                                         struct tevent_context *ev,
3566                                         struct cli_state *cli,
3567                                         uint16_t fnum,
3568                                         uint64_t offset,
3569                                         uint64_t len)
3570 {
3571         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3572                                         false, UNLOCK_LOCK);
3573 }
3574
3575 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3576 {
3577         return tevent_req_simple_recv_ntstatus(req);
3578 }
3579
3580 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3581 {
3582         TALLOC_CTX *frame = talloc_stackframe();
3583         struct tevent_context *ev = NULL;
3584         struct tevent_req *req = NULL;
3585         NTSTATUS status = NT_STATUS_OK;
3586
3587         if (smbXcli_conn_has_async_calls(cli->conn)) {
3588                 /*
3589                  * Can't use sync call while an async call is in flight
3590                  */
3591                 status = NT_STATUS_INVALID_PARAMETER;
3592                 goto fail;
3593         }
3594
3595         ev = samba_tevent_context_init(frame);
3596         if (ev == NULL) {
3597                 status = NT_STATUS_NO_MEMORY;
3598                 goto fail;
3599         }
3600
3601         req = cli_posix_unlock_send(frame,
3602                                 ev,
3603                                 cli,
3604                                 fnum,
3605                                 offset,
3606                                 len);
3607         if (req == NULL) {
3608                 status = NT_STATUS_NO_MEMORY;
3609                 goto fail;
3610         }
3611
3612         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3613                 goto fail;
3614         }
3615
3616         status = cli_posix_unlock_recv(req);
3617
3618  fail:
3619         TALLOC_FREE(frame);
3620         return status;
3621 }
3622
3623 /****************************************************************************
3624  Do a SMBgetattrE call.
3625 ****************************************************************************/
3626
3627 static void cli_getattrE_done(struct tevent_req *subreq);
3628
3629 struct cli_getattrE_state {
3630         uint16_t vwv[1];
3631         int zone_offset;
3632         uint16_t attr;
3633         off_t size;
3634         time_t change_time;
3635         time_t access_time;
3636         time_t write_time;
3637 };
3638
3639 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3640                                 struct tevent_context *ev,
3641                                 struct cli_state *cli,
3642                                 uint16_t fnum)
3643 {
3644         struct tevent_req *req = NULL, *subreq = NULL;
3645         struct cli_getattrE_state *state = NULL;
3646         uint8_t additional_flags = 0;
3647
3648         req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3649         if (req == NULL) {
3650                 return NULL;
3651         }
3652
3653         state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3654         SSVAL(state->vwv+0,0,fnum);
3655
3656         subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
3657                               1, state->vwv, 0, NULL);
3658         if (tevent_req_nomem(subreq, req)) {
3659                 return tevent_req_post(req, ev);
3660         }
3661         tevent_req_set_callback(subreq, cli_getattrE_done, req);
3662         return req;
3663 }
3664
3665 static void cli_getattrE_done(struct tevent_req *subreq)
3666 {
3667         struct tevent_req *req = tevent_req_callback_data(
3668                 subreq, struct tevent_req);
3669         struct cli_getattrE_state *state = tevent_req_data(
3670                 req, struct cli_getattrE_state);
3671         uint8_t wct;
3672         uint16_t *vwv = NULL;
3673         NTSTATUS status;
3674
3675         status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
3676                               NULL, NULL);
3677         TALLOC_FREE(subreq);
3678         if (tevent_req_nterror(req, status)) {
3679                 return;
3680         }
3681
3682         state->size = (off_t)IVAL(vwv+6,0);
3683         state->attr = SVAL(vwv+10,0);
3684         state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3685         state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3686         state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3687
3688         tevent_req_done(req);
3689 }
3690
3691 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3692                         uint16_t *attr,
3693                         off_t *size,
3694                         time_t *change_time,
3695                         time_t *access_time,
3696                         time_t *write_time)
3697 {
3698         struct cli_getattrE_state *state = tevent_req_data(
3699                                 req, struct cli_getattrE_state);
3700         NTSTATUS status;
3701
3702         if (tevent_req_is_nterror(req, &status)) {
3703                 return status;
3704         }
3705         if (attr) {
3706                 *attr = state->attr;
3707         }
3708         if (size) {
3709                 *size = state->size;
3710         }
3711         if (change_time) {
3712                 *change_time = state->change_time;
3713         }
3714         if (access_time) {
3715                 *access_time = state->access_time;
3716         }
3717         if (write_time) {
3718                 *write_time = state->write_time;
3719         }
3720         return NT_STATUS_OK;
3721 }
3722
3723 NTSTATUS cli_getattrE(struct cli_state *cli,
3724                         uint16_t fnum,
3725                         uint16_t *attr,
3726                         off_t *size,
3727                         time_t *change_time,
3728                         time_t *access_time,
3729                         time_t *write_time)
3730 {
3731         TALLOC_CTX *frame = NULL;
3732         struct tevent_context *ev = NULL;
3733         struct tevent_req *req = NULL;
3734         NTSTATUS status = NT_STATUS_OK;
3735
3736         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3737                 return cli_smb2_getattrE(cli,
3738                                         fnum,
3739                                         attr,
3740                                         size,
3741                                         change_time,
3742                                         access_time,
3743                                         write_time);
3744         }
3745
3746         frame = talloc_stackframe();
3747
3748         if (smbXcli_conn_has_async_calls(cli->conn)) {
3749                 /*
3750                  * Can't use sync call while an async call is in flight
3751                  */
3752                 status = NT_STATUS_INVALID_PARAMETER;
3753                 goto fail;
3754         }
3755
3756         ev = samba_tevent_context_init(frame);
3757         if (ev == NULL) {
3758                 status = NT_STATUS_NO_MEMORY;
3759                 goto fail;
3760         }
3761
3762         req = cli_getattrE_send(frame, ev, cli, fnum);
3763         if (req == NULL) {
3764                 status = NT_STATUS_NO_MEMORY;
3765                 goto fail;
3766         }
3767
3768         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3769                 goto fail;
3770         }
3771
3772         status = cli_getattrE_recv(req,
3773                                         attr,
3774                                         size,
3775                                         change_time,
3776                                         access_time,
3777                                         write_time);
3778
3779  fail:
3780         TALLOC_FREE(frame);
3781         return status;
3782 }
3783
3784 /****************************************************************************
3785  Do a SMBgetatr call
3786 ****************************************************************************/
3787
3788 static void cli_getatr_done(struct tevent_req *subreq);
3789
3790 struct cli_getatr_state {
3791         int zone_offset;
3792         uint16_t attr;
3793         off_t size;
3794         time_t write_time;
3795 };
3796
3797 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3798                                 struct tevent_context *ev,
3799                                 struct cli_state *cli,
3800                                 const char *fname)
3801 {
3802         struct tevent_req *req = NULL, *subreq = NULL;
3803         struct cli_getatr_state *state = NULL;
3804         uint8_t additional_flags = 0;
3805         uint16_t additional_flags2 = 0;
3806         uint8_t *bytes = NULL;
3807
3808         req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3809         if (req == NULL) {
3810                 return NULL;
3811         }
3812
3813         state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3814
3815         bytes = talloc_array(state, uint8_t, 1);
3816         if (tevent_req_nomem(bytes, req)) {
3817                 return tevent_req_post(req, ev);
3818         }
3819         bytes[0] = 4;
3820         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3821                                    strlen(fname)+1, NULL);
3822
3823         if (tevent_req_nomem(bytes, req)) {
3824                 return tevent_req_post(req, ev);
3825         }
3826
3827         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
3828                 additional_flags2 = FLAGS2_REPARSE_PATH;
3829         }
3830
3831         subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3832                         additional_flags2,
3833                         0, NULL, talloc_get_size(bytes), bytes);
3834         if (tevent_req_nomem(subreq, req)) {
3835                 return tevent_req_post(req, ev);
3836         }
3837         tevent_req_set_callback(subreq, cli_getatr_done, req);
3838         return req;
3839 }
3840
3841 static void cli_getatr_done(struct tevent_req *subreq)
3842 {
3843         struct tevent_req *req = tevent_req_callback_data(
3844                 subreq, struct tevent_req);
3845         struct cli_getatr_state *state = tevent_req_data(
3846                 req, struct cli_getatr_state);
3847         uint8_t wct;
3848         uint16_t *vwv = NULL;
3849         NTSTATUS status;
3850
3851         status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
3852                               NULL);
3853         TALLOC_FREE(subreq);
3854         if (tevent_req_nterror(req, status)) {
3855                 return;
3856         }
3857
3858         state->attr = SVAL(vwv+0,0);
3859         state->size = (off_t)IVAL(vwv+3,0);
3860         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3861
3862         tevent_req_done(req);
3863 }
3864
3865 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3866                         uint16_t *attr,
3867                         off_t *size,
3868                         time_t *write_time)
3869 {
3870         struct cli_getatr_state *state = tevent_req_data(
3871                                 req, struct cli_getatr_state);
3872         NTSTATUS status;
3873
3874         if (tevent_req_is_nterror(req, &status)) {
3875                 return status;
3876         }
3877         if (attr) {
3878                 *attr = state->attr;
3879         }
3880         if (size) {
3881                 *size = state->size;
3882         }
3883         if (write_time) {
3884                 *write_time = state->write_time;
3885         }
3886         return NT_STATUS_OK;
3887 }
3888
3889 NTSTATUS cli_getatr(struct cli_state *cli,
3890                         const char *fname,
3891                         uint16_t *attr,
3892                         off_t *size,
3893                         time_t *write_time)
3894 {
3895         TALLOC_CTX *frame = NULL;
3896         struct tevent_context *ev = NULL;
3897         struct tevent_req *req = NULL;
3898         NTSTATUS status = NT_STATUS_OK;
3899
3900         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3901                 return cli_smb2_getatr(cli,
3902                                         fname,
3903                                         attr,
3904                                         size,
3905                                         write_time);
3906         }
3907
3908         frame = talloc_stackframe();
3909
3910         if (smbXcli_conn_has_async_calls(cli->conn)) {
3911                 /*
3912                  * Can't use sync call while an async call is in flight
3913                  */
3914                 status = NT_STATUS_INVALID_PARAMETER;
3915                 goto fail;
3916         }
3917
3918         ev = samba_tevent_context_init(frame);
3919         if (ev == NULL) {
3920                 status = NT_STATUS_NO_MEMORY;
3921                 goto fail;
3922         }
3923
3924         req = cli_getatr_send(frame, ev, cli, fname);
3925         if (req == NULL) {
3926                 status = NT_STATUS_NO_MEMORY;
3927                 goto fail;
3928         }
3929
3930         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3931                 goto fail;
3932         }
3933
3934         status = cli_getatr_recv(req,
3935                                 attr,
3936                                 size,
3937                                 write_time);
3938
3939  fail:
3940         TALLOC_FREE(frame);
3941         return status;
3942 }
3943
3944 /****************************************************************************
3945  Do a SMBsetattrE call.
3946 ****************************************************************************/
3947
3948 static void cli_setattrE_done(struct tevent_req *subreq);
3949
3950 struct cli_setattrE_state {
3951         uint16_t vwv[7];
3952 };
3953
3954 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3955                                 struct tevent_context *ev,
3956                                 struct cli_state *cli,
3957                                 uint16_t fnum,
3958                                 time_t change_time,
3959                                 time_t access_time,
3960                                 time_t write_time)
3961 {
3962         struct tevent_req *req = NULL, *subreq = NULL;
3963         struct cli_setattrE_state *state = NULL;
3964         uint8_t additional_flags = 0;
3965
3966         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3967         if (req == NULL) {
3968                 return NULL;
3969         }
3970
3971         SSVAL(state->vwv+0, 0, fnum);
3972         push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
3973                        smb1cli_conn_server_time_zone(cli->conn));
3974         push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
3975                        smb1cli_conn_server_time_zone(cli->conn));
3976         push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
3977                        smb1cli_conn_server_time_zone(cli->conn));
3978
3979         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
3980                               7, state->vwv, 0, NULL);
3981         if (tevent_req_nomem(subreq, req)) {
3982                 return tevent_req_post(req, ev);
3983         }
3984         tevent_req_set_callback(subreq, cli_setattrE_done, req);
3985         return req;
3986 }
3987
3988 static void cli_setattrE_done(struct tevent_req *subreq)
3989 {
3990         struct tevent_req *req = tevent_req_callback_data(
3991                 subreq, struct tevent_req);
3992         NTSTATUS status;
3993
3994         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3995         TALLOC_FREE(subreq);
3996         if (tevent_req_nterror(req, status)) {
3997                 return;
3998         }
3999         tevent_req_done(req);
4000 }
4001
4002 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4003 {
4004         return tevent_req_simple_recv_ntstatus(req);
4005 }
4006
4007 NTSTATUS cli_setattrE(struct cli_state *cli,
4008                         uint16_t fnum,
4009                         time_t change_time,
4010                         time_t access_time,
4011                         time_t write_time)
4012 {
4013         TALLOC_CTX *frame = NULL;
4014         struct tevent_context *ev = NULL;
4015         struct tevent_req *req = NULL;
4016         NTSTATUS status = NT_STATUS_OK;
4017
4018         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4019                 return cli_smb2_setattrE(cli,
4020                                         fnum,
4021                                         change_time,
4022                                         access_time,
4023                                         write_time);
4024         }
4025
4026         frame = talloc_stackframe();
4027
4028         if (smbXcli_conn_has_async_calls(cli->conn)) {
4029                 /*
4030                  * Can't use sync call while an async call is in flight
4031                  */
4032                 status = NT_STATUS_INVALID_PARAMETER;
4033                 goto fail;
4034         }
4035
4036         ev = samba_tevent_context_init(frame);
4037         if (ev == NULL) {
4038                 status = NT_STATUS_NO_MEMORY;
4039                 goto fail;
4040         }
4041
4042         req = cli_setattrE_send(frame, ev,
4043                         cli,
4044                         fnum,
4045                         change_time,
4046                         access_time,
4047                         write_time);
4048
4049         if (req == NULL) {
4050                 status = NT_STATUS_NO_MEMORY;
4051                 goto fail;
4052         }
4053
4054         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4055                 goto fail;
4056         }
4057
4058         status = cli_setattrE_recv(req);
4059
4060  fail:
4061         TALLOC_FREE(frame);
4062         return status;
4063 }
4064
4065 /****************************************************************************
4066  Do a SMBsetatr call.
4067 ****************************************************************************/
4068
4069 static void cli_setatr_done(struct tevent_req *subreq);
4070
4071 struct cli_setatr_state {
4072         uint16_t vwv[8];
4073 };
4074
4075 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
4076                                 struct tevent_context *ev,
4077                                 struct cli_state *cli,
4078                                 const char *fname,
4079                                 uint16_t attr,
4080                                 time_t mtime)
4081 {
4082         struct tevent_req *req = NULL, *subreq = NULL;
4083         struct cli_setatr_state *state = NULL;
4084         uint8_t additional_flags = 0;
4085         uint16_t additional_flags2 = 0;
4086         uint8_t *bytes = NULL;
4087
4088         req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
4089         if (req == NULL) {
4090                 return NULL;
4091         }
4092
4093         SSVAL(state->vwv+0, 0, attr);
4094         push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
4095
4096         bytes = talloc_array(state, uint8_t, 1);
4097         if (tevent_req_nomem(bytes, req)) {
4098                 return tevent_req_post(req, ev);
4099         }
4100         bytes[0] = 4;
4101         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4102                                    strlen(fname)+1, NULL);
4103         if (tevent_req_nomem(bytes, req)) {
4104                 return tevent_req_post(req, ev);
4105         }
4106         bytes = talloc_realloc(state, bytes, uint8_t,
4107                         talloc_get_size(bytes)+1);
4108         if (tevent_req_nomem(bytes, req)) {
4109                 return tevent_req_post(req, ev);
4110         }
4111
4112         bytes[talloc_get_size(bytes)-1] = 4;
4113         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
4114                                    1, NULL);
4115         if (tevent_req_nomem(bytes, req)) {
4116                 return tevent_req_post(req, ev);
4117         }
4118
4119         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4120                 additional_flags2 = FLAGS2_REPARSE_PATH;
4121         }
4122
4123         subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
4124                         additional_flags2,
4125                         8, state->vwv, talloc_get_size(bytes), bytes);
4126         if (tevent_req_nomem(subreq, req)) {
4127                 return tevent_req_post(req, ev);
4128         }
4129         tevent_req_set_callback(subreq, cli_setatr_done, req);
4130         return req;
4131 }
4132
4133 static void cli_setatr_done(struct tevent_req *subreq)
4134 {
4135         struct tevent_req *req = tevent_req_callback_data(
4136                 subreq, struct tevent_req);
4137         NTSTATUS status;
4138
4139         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4140         TALLOC_FREE(subreq);
4141         if (tevent_req_nterror(req, status)) {
4142                 return;
4143         }
4144         tevent_req_done(req);
4145 }
4146
4147 NTSTATUS cli_setatr_recv(struct tevent_req *req)
4148 {
4149         return tevent_req_simple_recv_ntstatus(req);
4150 }
4151
4152 NTSTATUS cli_setatr(struct cli_state *cli,
4153                 const char *fname,
4154                 uint16_t attr,
4155                 time_t mtime)
4156 {
4157         TALLOC_CTX *frame = NULL;
4158         struct tevent_context *ev = NULL;
4159         struct tevent_req *req = NULL;
4160         NTSTATUS status = NT_STATUS_OK;
4161
4162         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4163                 return cli_smb2_setatr(cli,
4164                                         fname,
4165                                         attr,
4166                                         mtime);
4167         }
4168
4169         frame = talloc_stackframe();
4170
4171         if (smbXcli_conn_has_async_calls(cli->conn)) {
4172                 /*
4173                  * Can't use sync call while an async call is in flight
4174                  */
4175                 status = NT_STATUS_INVALID_PARAMETER;
4176                 goto fail;
4177         }
4178
4179         ev = samba_tevent_context_init(frame);
4180         if (ev == NULL) {
4181                 status = NT_STATUS_NO_MEMORY;
4182                 goto fail;
4183         }
4184
4185         req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
4186         if (req == NULL) {
4187                 status = NT_STATUS_NO_MEMORY;
4188                 goto fail;
4189         }
4190
4191         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4192                 goto fail;
4193         }
4194
4195         status = cli_setatr_recv(req);
4196
4197  fail:
4198         TALLOC_FREE(frame);
4199         return status;
4200 }
4201
4202 /****************************************************************************
4203  Check for existence of a dir.
4204 ****************************************************************************/
4205
4206 static void cli_chkpath_done(struct tevent_req *subreq);
4207
4208 struct cli_chkpath_state {
4209         int dummy;
4210 };
4211
4212 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
4213                                   struct tevent_context *ev,
4214                                   struct cli_state *cli,
4215                                   const char *fname)
4216 {
4217         struct tevent_req *req = NULL, *subreq = NULL;
4218         struct cli_chkpath_state *state = NULL;
4219         uint8_t additional_flags = 0;
4220         uint16_t additional_flags2 = 0;
4221         uint8_t *bytes = NULL;
4222
4223         req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
4224         if (req == NULL) {
4225                 return NULL;
4226         }
4227
4228         bytes = talloc_array(state, uint8_t, 1);
4229         if (tevent_req_nomem(bytes, req)) {
4230                 return tevent_req_post(req, ev);
4231         }
4232         bytes[0] = 4;
4233         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
4234                                    strlen(fname)+1, NULL);
4235
4236         if (tevent_req_nomem(bytes, req)) {
4237                 return tevent_req_post(req, ev);
4238         }
4239
4240         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
4241                 additional_flags2 = FLAGS2_REPARSE_PATH;
4242         }
4243
4244         subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
4245                         additional_flags2,
4246                         0, NULL, talloc_get_size(bytes), bytes);
4247         if (tevent_req_nomem(subreq, req)) {
4248                 return tevent_req_post(req, ev);
4249         }
4250         tevent_req_set_callback(subreq, cli_chkpath_done, req);
4251         return req;
4252 }
4253
4254 static void cli_chkpath_done(struct tevent_req *subreq)
4255 {
4256         struct tevent_req *req = tevent_req_callback_data(
4257                 subreq, struct tevent_req);
4258         NTSTATUS status;
4259
4260         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4261         TALLOC_FREE(subreq);
4262         if (tevent_req_nterror(req, status)) {
4263                 return;
4264         }
4265         tevent_req_done(req);
4266 }
4267
4268 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
4269 {
4270         return tevent_req_simple_recv_ntstatus(req);
4271 }
4272
4273 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
4274 {
4275         TALLOC_CTX *frame = NULL;
4276         struct tevent_context *ev = NULL;
4277         struct tevent_req *req = NULL;
4278         char *path2 = NULL;
4279         NTSTATUS status = NT_STATUS_OK;
4280
4281         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4282                 return cli_smb2_chkpath(cli, path);
4283         }
4284
4285         frame = talloc_stackframe();
4286
4287         if (smbXcli_conn_has_async_calls(cli->conn)) {
4288                 /*
4289                  * Can't use sync call while an async call is in flight
4290                  */
4291                 status = NT_STATUS_INVALID_PARAMETER;
4292                 goto fail;
4293         }
4294
4295         path2 = talloc_strdup(frame, path);
4296         if (!path2) {
4297                 status = NT_STATUS_NO_MEMORY;
4298                 goto fail;
4299         }
4300         trim_char(path2,'\0','\\');
4301         if (!*path2) {
4302                 path2 = talloc_strdup(frame, "\\");
4303                 if (!path2) {
4304                         status = NT_STATUS_NO_MEMORY;
4305                         goto fail;
4306                 }
4307         }
4308
4309         ev = samba_tevent_context_init(frame);
4310         if (ev == NULL) {
4311                 status = NT_STATUS_NO_MEMORY;
4312                 goto fail;
4313         }
4314
4315         req = cli_chkpath_send(frame, ev, cli, path2);
4316         if (req == NULL) {
4317                 status = NT_STATUS_NO_MEMORY;
4318                 goto fail;
4319         }
4320
4321         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4322                 goto fail;
4323         }
4324
4325         status = cli_chkpath_recv(req);
4326
4327  fail:
4328         TALLOC_FREE(frame);
4329         return status;
4330 }
4331
4332 /****************************************************************************
4333  Query disk space.
4334 ****************************************************************************/
4335
4336 static void cli_dskattr_done(struct tevent_req *subreq);
4337
4338 struct cli_dskattr_state {
4339         int bsize;
4340         int total;
4341         int avail;
4342 };
4343
4344 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
4345                                   struct tevent_context *ev,
4346                                   struct cli_state *cli)
4347 {
4348         struct tevent_req *req = NULL, *subreq = NULL;
4349         struct cli_dskattr_state *state = NULL;
4350         uint8_t additional_flags = 0;
4351
4352         req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
4353         if (req == NULL) {
4354                 return NULL;
4355         }
4356
4357         subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
4358                               0, NULL, 0, NULL);
4359         if (tevent_req_nomem(subreq, req)) {
4360                 return tevent_req_post(req, ev);
4361         }
4362         tevent_req_set_callback(subreq, cli_dskattr_done, req);
4363         return req;
4364 }
4365
4366 static void cli_dskattr_done(struct tevent_req *subreq)
4367 {
4368         struct tevent_req *req = tevent_req_callback_data(
4369                 subreq, struct tevent_req);
4370         struct cli_dskattr_state *state = tevent_req_data(
4371                 req, struct cli_dskattr_state);
4372         uint8_t wct;
4373         uint16_t *vwv = NULL;
4374         NTSTATUS status;
4375
4376         status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4377                               NULL);
4378         TALLOC_FREE(subreq);
4379         if (tevent_req_nterror(req, status)) {
4380                 return;
4381         }
4382         state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
4383         state->total = SVAL(vwv+0, 0);
4384         state->avail = SVAL(vwv+3, 0);
4385         tevent_req_done(req);
4386 }
4387
4388 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
4389 {
4390         struct cli_dskattr_state *state = tevent_req_data(
4391                                 req, struct cli_dskattr_state);
4392         NTSTATUS status;
4393
4394         if (tevent_req_is_nterror(req, &status)) {
4395                 return status;
4396         }
4397         *bsize = state->bsize;
4398         *total = state->total;
4399         *avail = state->avail;
4400         return NT_STATUS_OK;
4401 }
4402
4403 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
4404 {
4405         TALLOC_CTX *frame = NULL;
4406         struct tevent_context *ev = NULL;
4407         struct tevent_req *req = NULL;
4408         NTSTATUS status = NT_STATUS_OK;
4409
4410         frame = talloc_stackframe();
4411
4412         if (smbXcli_conn_has_async_calls(cli->conn)) {
4413                 /*
4414                  * Can't use sync call while an async call is in flight
4415                  */
4416                 status = NT_STATUS_INVALID_PARAMETER;
4417                 goto fail;
4418         }
4419
4420         ev = samba_tevent_context_init(frame);
4421         if (ev == NULL) {
4422                 status = NT_STATUS_NO_MEMORY;
4423                 goto fail;
4424         }
4425
4426         req = cli_dskattr_send(frame, ev, cli);
4427         if (req == NULL) {
4428                 status = NT_STATUS_NO_MEMORY;
4429                 goto fail;
4430         }
4431
4432         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4433                 goto fail;
4434         }
4435
4436         status = cli_dskattr_recv(req, bsize, total, avail);
4437
4438  fail:
4439         TALLOC_FREE(frame);
4440         return status;
4441 }
4442
4443 NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
4444                        uint64_t *total, uint64_t *avail)
4445 {
4446         uint64_t sectors_per_block;
4447         uint64_t bytes_per_sector;
4448         int old_bsize, old_total, old_avail;
4449         NTSTATUS status;
4450
4451         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4452                 return cli_smb2_dskattr(cli, path, bsize, total, avail);
4453         }
4454
4455         /*
4456          * Try the trans2 disk full size info call first.
4457          * We already use this in SMBC_fstatvfs_ctx().
4458          * Ignore 'actual_available_units' as we only
4459          * care about the quota for the caller.
4460          */
4461
4462         status = cli_get_fs_full_size_info(cli,
4463                         total,
4464                         avail,
4465                         NULL,
4466                         &sectors_per_block,
4467                         &bytes_per_sector);
4468
4469         /* Try and cope will all varients of "we don't do this call"
4470            and fall back to cli_dskattr. */
4471
4472         if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
4473                         NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
4474                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
4475                         NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
4476                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
4477                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
4478                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
4479                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
4480                         NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
4481                         NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
4482                 goto try_dskattr;
4483         }
4484
4485         if (!NT_STATUS_IS_OK(status)) {
4486                 return status;
4487         }
4488
4489         if (bsize) {
4490                 *bsize = sectors_per_block *
4491                          bytes_per_sector;
4492         }
4493
4494         return NT_STATUS_OK;
4495
4496   try_dskattr:
4497
4498         /* Old SMB1 core protocol fallback. */
4499         status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
4500         if (!NT_STATUS_IS_OK(status)) {
4501                 return status;
4502         }
4503         if (bsize) {
4504                 *bsize = (uint64_t)old_bsize;
4505         }
4506         if (total) {
4507                 *total = (uint64_t)old_total;
4508         }
4509         if (avail) {
4510                 *avail = (uint64_t)old_avail;
4511         }
4512         return NT_STATUS_OK;
4513 }
4514
4515 /****************************************************************************
4516  Create and open a temporary file.
4517 ****************************************************************************/
4518
4519 static void cli_ctemp_done(struct tevent_req *subreq);
4520
4521 struct ctemp_state {
4522         uint16_t vwv[3];
4523         char *ret_path;
4524         uint16_t fnum;
4525 };
4526
4527 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4528                                 struct tevent_context *ev,
4529                                 struct cli_state *cli,
4530                                 const char *path)
4531 {
4532         struct tevent_req *req = NULL, *subreq = NULL;
4533         struct ctemp_state *state = NULL;
4534         uint8_t additional_flags = 0;
4535         uint16_t additional_flags2 = 0;
4536         uint8_t *bytes = NULL;
4537
4538         req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4539         if (req == NULL) {
4540                 return NULL;
4541         }
4542
4543         SSVAL(state->vwv,0,0);
4544         SIVALS(state->vwv+1,0,-1);
4545
4546         bytes = talloc_array(state, uint8_t, 1);
4547         if (tevent_req_nomem(bytes, req)) {
4548                 return tevent_req_post(req, ev);
4549         }
4550         bytes[0] = 4;
4551         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
4552                                    strlen(path)+1, NULL);
4553         if (tevent_req_nomem(bytes, req)) {
4554                 return tevent_req_post(req, ev);
4555         }
4556
4557         if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
4558                 additional_flags2 = FLAGS2_REPARSE_PATH;
4559         }
4560
4561         subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4562                         additional_flags2,
4563                         3, state->vwv, talloc_get_size(bytes), bytes);
4564         if (tevent_req_nomem(subreq, req)) {
4565                 return tevent_req_post(req, ev);
4566         }
4567         tevent_req_set_callback(subreq, cli_ctemp_done, req);
4568         return req;
4569 }
4570
4571 static void cli_ctemp_done(struct tevent_req *subreq)
4572 {
4573         struct tevent_req *req = tevent_req_callback_data(
4574                                 subreq, struct tevent_req);
4575         struct ctemp_state *state = tevent_req_data(
4576                                 req, struct ctemp_state);
4577         NTSTATUS status;
4578         uint8_t wcnt;
4579         uint16_t *vwv;
4580         uint32_t num_bytes = 0;
4581         uint8_t *bytes = NULL;
4582
4583         status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
4584                               &num_bytes, &bytes);
4585         TALLOC_FREE(subreq);
4586         if (tevent_req_nterror(req, status)) {
4587                 return;
4588         }
4589
4590         state->fnum = SVAL(vwv+0, 0);
4591
4592         /* From W2K3, the result is just the ASCII name */
4593         if (num_bytes < 2) {
4594                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
4595                 return;
4596         }
4597
4598         if (pull_string_talloc(state,
4599                         NULL,
4600                         0,
4601                         &state->ret_path,
4602                         bytes,
4603                         num_bytes,
4604                         STR_ASCII) == 0) {
4605                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4606                 return;
4607         }
4608         tevent_req_done(req);
4609 }
4610
4611 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
4612                         TALLOC_CTX *ctx,
4613                         uint16_t *pfnum,
4614                         char **outfile)
4615 {
4616         struct ctemp_state *state = tevent_req_data(req,
4617                         struct ctemp_state);
4618         NTSTATUS status;
4619
4620         if (tevent_req_is_nterror(req, &status)) {
4621                 return status;
4622         }
4623         *pfnum = state->fnum;
4624         *outfile = talloc_strdup(ctx, state->ret_path);
4625         if (!*outfile) {
4626                 return NT_STATUS_NO_MEMORY;
4627         }
4628         return NT_STATUS_OK;
4629 }
4630
4631 NTSTATUS cli_ctemp(struct cli_state *cli,
4632                         TALLOC_CTX *ctx,
4633                         const char *path,
4634                         uint16_t *pfnum,
4635                         char **out_path)
4636 {
4637         TALLOC_CTX *frame = talloc_stackframe();
4638         struct tevent_context *ev;
4639         struct tevent_req *req;
4640         NTSTATUS status = NT_STATUS_OK;
4641
4642         if (smbXcli_conn_has_async_calls(cli->conn)) {
4643                 /*
4644                  * Can't use sync call while an async call is in flight
4645                  */
4646                 status = NT_STATUS_INVALID_PARAMETER;
4647                 goto fail;
4648         }
4649
4650         ev = samba_tevent_context_init(frame);
4651         if (ev == NULL) {
4652                 status = NT_STATUS_NO_MEMORY;
4653                 goto fail;
4654         }
4655
4656         req = cli_ctemp_send(frame, ev, cli, path);
4657         if (req == NULL) {
4658                 status = NT_STATUS_NO_MEMORY;
4659                 goto fail;
4660         }
4661
4662         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4663                 goto fail;
4664         }
4665
4666         status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4667
4668  fail:
4669         TALLOC_FREE(frame);
4670         return status;
4671 }
4672
4673 /*
4674    send a raw ioctl - used by the torture code
4675 */
4676 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4677 {
4678         uint16_t vwv[3];
4679         NTSTATUS status;
4680
4681         SSVAL(vwv+0, 0, fnum);
4682         SSVAL(vwv+1, 0, code>>16);
4683         SSVAL(vwv+2, 0, (code&0xFFFF));
4684
4685         status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4686                          NULL, 0, NULL, NULL, NULL, NULL);
4687         if (!NT_STATUS_IS_OK(status)) {
4688                 return status;
4689         }
4690         *blob = data_blob_null;
4691         return NT_STATUS_OK;
4692 }
4693
4694 /*********************************************************
4695  Set an extended attribute utility fn.
4696 *********************************************************/
4697
4698 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
4699                            uint8_t *param, unsigned int param_len,
4700                            const char *ea_name,
4701                            const char *ea_val, size_t ea_len)
4702 {
4703         uint16_t setup[1];
4704         unsigned int data_len = 0;
4705         uint8_t *data = NULL;
4706         char *p;
4707         size_t ea_namelen = strlen(ea_name);
4708         NTSTATUS status;
4709
4710         SSVAL(setup, 0, setup_val);
4711
4712         if (ea_namelen == 0 && ea_len == 0) {
4713                 data_len = 4;
4714                 data = talloc_array(talloc_tos(),
4715                                 uint8_t,
4716                                 data_len);
4717                 if (!data) {
4718                         return NT_STATUS_NO_MEMORY;
4719                 }
4720                 p = (char *)data;
4721                 SIVAL(p,0,data_len);
4722         } else {
4723                 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4724                 data = talloc_array(talloc_tos(),
4725                                 uint8_t,
4726                                 data_len);
4727                 if (!data) {
4728                         return NT_STATUS_NO_MEMORY;
4729                 }
4730                 p = (char *)data;
4731                 SIVAL(p,0,data_len);
4732                 p += 4;
4733                 SCVAL(p, 0, 0); /* EA flags. */
4734                 SCVAL(p, 1, ea_namelen);
4735                 SSVAL(p, 2, ea_len);
4736                 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4737                 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4738         }
4739
4740         /*
4741          * FIXME - if we want to do previous version path
4742          * processing on an EA set call we need to turn this
4743          * into calls to cli_trans_send()/cli_trans_recv()
4744          * with a temporary event context, as cli_trans_send()
4745          * have access to the additional_flags2 needed to
4746          * send @GMT- paths. JRA.
4747          */
4748
4749         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
4750                            setup, 1, 0,
4751                            param, param_len, 2,
4752                            data,  data_len, 0,
4753                            NULL,
4754                            NULL, 0, NULL, /* rsetup */
4755                            NULL, 0, NULL, /* rparam */
4756                            NULL, 0, NULL); /* rdata */
4757         talloc_free(data);
4758         return status;
4759 }
4760
4761 /*********************************************************
4762  Set an extended attribute on a pathname.
4763 *********************************************************/
4764
4765 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
4766                          const char *ea_name, const char *ea_val,
4767                          size_t ea_len)
4768 {
4769         unsigned int param_len = 0;
4770         uint8_t *param;
4771         NTSTATUS status;
4772         TALLOC_CTX *frame = NULL;
4773
4774         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4775                 return cli_smb2_set_ea_path(cli,
4776                                         path,
4777                                         ea_name,
4778                                         ea_val,
4779                                         ea_len);
4780         }
4781
4782         frame = talloc_stackframe();
4783
4784         param = talloc_array(frame, uint8_t, 6);
4785         if (!param) {
4786                 status = NT_STATUS_NO_MEMORY;
4787                 goto fail;
4788         }
4789         SSVAL(param,0,SMB_INFO_SET_EA);
4790         SSVAL(param,2,0);
4791         SSVAL(param,4,0);
4792
4793         param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
4794                                       path, strlen(path)+1,
4795                                       NULL);
4796         param_len = talloc_get_size(param);
4797
4798         status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
4799                             ea_name, ea_val, ea_len);
4800
4801   fail:
4802
4803         TALLOC_FREE(frame);
4804         return status;
4805 }
4806
4807 /*********************************************************
4808  Set an extended attribute on an fnum.
4809 *********************************************************/
4810
4811 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
4812                          const char *ea_name, const char *ea_val,
4813                          size_t ea_len)
4814 {
4815         uint8_t param[6];
4816
4817         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4818                 return cli_smb2_set_ea_fnum(cli,
4819                                         fnum,
4820                                         ea_name,
4821                                         ea_val,
4822                                         ea_len);
4823         }
4824
4825         memset(param, 0, 6);
4826         SSVAL(param,0,fnum);
4827         SSVAL(param,2,SMB_INFO_SET_EA);
4828
4829         return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
4830                           ea_name, ea_val, ea_len);
4831 }
4832
4833 /*********************************************************
4834  Get an extended attribute list utility fn.
4835 *********************************************************/
4836
4837 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4838                           size_t rdata_len,
4839                           size_t *pnum_eas, struct ea_struct **pea_list)
4840 {
4841         struct ea_struct *ea_list = NULL;
4842         size_t num_eas;
4843         size_t ea_size;
4844         const uint8_t *p;
4845
4846         if (rdata_len < 4) {
4847                 return false;
4848         }
4849
4850         ea_size = (size_t)IVAL(rdata,0);
4851         if (ea_size > rdata_len) {
4852                 return false;
4853         }
4854
4855         if (ea_size == 0) {
4856                 /* No EA's present. */
4857                 *pnum_eas = 0;
4858                 *pea_list = NULL;
4859                 return true;
4860         }
4861
4862         p = rdata + 4;
4863         ea_size -= 4;
4864
4865         /* Validate the EA list and count it. */
4866         for (num_eas = 0; ea_size >= 4; num_eas++) {
4867                 unsigned int ea_namelen = CVAL(p,1);
4868                 unsigned int ea_valuelen = SVAL(p,2);
4869                 if (ea_namelen == 0) {
4870                         return false;
4871                 }
4872                 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4873                         return false;
4874                 }
4875                 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4876                 p += 4 + ea_namelen + 1 + ea_valuelen;
4877         }
4878
4879         if (num_eas == 0) {
4880                 *pnum_eas = 0;
4881                 *pea_list = NULL;
4882                 return true;
4883         }
4884
4885         *pnum_eas = num_eas;
4886         if (!pea_list) {
4887                 /* Caller only wants number of EA's. */
4888                 return true;
4889         }
4890
4891         ea_list = talloc_array(ctx, struct ea_struct, num_eas);
4892         if (!ea_list) {
4893                 return false;
4894         }
4895
4896         ea_size = (size_t)IVAL(rdata,0);
4897         p = rdata + 4;
4898
4899         for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4900                 struct ea_struct *ea = &ea_list[num_eas];
4901                 fstring unix_ea_name;
4902                 unsigned int ea_namelen = CVAL(p,1);
4903                 unsigned int ea_valuelen = SVAL(p,2);
4904
4905                 ea->flags = CVAL(p,0);
4906                 unix_ea_name[0] = '\0';
4907                 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
4908                 ea->name = talloc_strdup(ea_list, unix_ea_name);
4909                 if (!ea->name) {
4910                         goto fail;
4911                 }
4912                 /* Ensure the value is null terminated (in case it's a string). */
4913                 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4914                 if (!ea->value.data) {
4915                         goto fail;
4916                 }
4917                 if (ea_valuelen) {
4918                         memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4919                 }
4920                 ea->value.data[ea_valuelen] = 0;
4921                 ea->value.length--;
4922                 p += 4 + ea_namelen + 1 + ea_valuelen;
4923         }
4924
4925         *pea_list = ea_list;
4926         return true;
4927
4928 fail:
4929         TALLOC_FREE(ea_list);
4930         return false;
4931 }
4932
4933 /*********************************************************
4934  Get an extended attribute list from a pathname.
4935 *********************************************************/
4936
4937 struct cli_get_ea_list_path_state {
4938         uint32_t num_data;
4939         uint8_t *data;
4940 };
4941
4942 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4943
4944 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4945                                              struct tevent_context *ev,
4946                                              struct cli_state *cli,
4947                                              const char *fname)
4948 {
4949         struct tevent_req *req, *subreq;
4950         struct cli_get_ea_list_path_state *state;
4951
4952         req = tevent_req_create(mem_ctx, &state,
4953                                 struct cli_get_ea_list_path_state);
4954         if (req == NULL) {
4955                 return NULL;
4956         }
4957         subreq = cli_qpathinfo_send(state, ev, cli, fname,
4958                                     SMB_INFO_QUERY_ALL_EAS, 4,
4959                                     CLI_BUFFER_SIZE);
4960         if (tevent_req_nomem(subreq, req)) {
4961                 return tevent_req_post(req, ev);
4962         }
4963         tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4964         return req;
4965 }
4966
4967 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4968 {
4969         struct tevent_req *req = tevent_req_callback_data(
4970                                 subreq, struct tevent_req);
4971         struct cli_get_ea_list_path_state *state = tevent_req_data(
4972                 req, struct cli_get_ea_list_path_state);
4973         NTSTATUS status;
4974
4975         status = cli_qpathinfo_recv(subreq, state, &state->data,
4976                                     &state->num_data);
4977         TALLOC_FREE(subreq);
4978         if (tevent_req_nterror(req, status)) {
4979                 return;
4980         }
4981         tevent_req_done(req);
4982 }
4983
4984 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4985                                    size_t *pnum_eas, struct ea_struct **peas)
4986 {
4987         struct cli_get_ea_list_path_state *state = tevent_req_data(
4988                 req, struct cli_get_ea_list_path_state);
4989         NTSTATUS status;
4990
4991         if (tevent_req_is_nterror(req, &status)) {
4992                 return status;
4993         }
4994         if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4995                            pnum_eas, peas)) {
4996                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4997         }
4998         return NT_STATUS_OK;
4999 }
5000
5001 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
5002                 TALLOC_CTX *ctx,
5003                 size_t *pnum_eas,
5004                 struct ea_struct **pea_list)
5005 {
5006         TALLOC_CTX *frame = NULL;
5007         struct tevent_context *ev = NULL;
5008         struct tevent_req *req = NULL;
5009         NTSTATUS status = NT_STATUS_NO_MEMORY;
5010
5011         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5012                 return cli_smb2_get_ea_list_path(cli,
5013                                         path,
5014                                         ctx,
5015                                         pnum_eas,
5016                                         pea_list);
5017         }
5018
5019         frame = talloc_stackframe();
5020
5021         if (smbXcli_conn_has_async_calls(cli->conn)) {
5022                 /*
5023                  * Can't use sync call while an async call is in flight
5024                  */
5025                 status = NT_STATUS_INVALID_PARAMETER;
5026                 goto fail;
5027         }
5028         ev = samba_tevent_context_init(frame);
5029         if (ev == NULL) {
5030                 goto fail;
5031         }
5032         req = cli_get_ea_list_path_send(frame, ev, cli, path);
5033         if (req == NULL) {
5034                 goto fail;
5035         }
5036         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5037                 goto fail;
5038         }
5039         status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
5040  fail:
5041         TALLOC_FREE(frame);
5042         return status;
5043 }
5044
5045 /****************************************************************************
5046  Convert open "flags" arg to uint32_t on wire.
5047 ****************************************************************************/
5048
5049 static uint32_t open_flags_to_wire(int flags)
5050 {
5051         int open_mode = flags & O_ACCMODE;
5052         uint32_t ret = 0;
5053
5054         switch (open_mode) {
5055                 case O_WRONLY:
5056                         ret |= SMB_O_WRONLY;
5057                         break;
5058                 case O_RDWR:
5059                         ret |= SMB_O_RDWR;
5060                         break;
5061                 default:
5062                 case O_RDONLY:
5063                         ret |= SMB_O_RDONLY;
5064                         break;
5065         }
5066
5067         if (flags & O_CREAT) {
5068                 ret |= SMB_O_CREAT;
5069         }
5070         if (flags & O_EXCL) {
5071                 ret |= SMB_O_EXCL;
5072         }
5073         if (flags & O_TRUNC) {
5074                 ret |= SMB_O_TRUNC;
5075         }
5076 #if defined(O_SYNC)
5077         if (flags & O_SYNC) {
5078                 ret |= SMB_O_SYNC;
5079         }
5080 #endif /* O_SYNC */
5081         if (flags & O_APPEND) {
5082                 ret |= SMB_O_APPEND;
5083         }
5084 #if defined(O_DIRECT)
5085         if (flags & O_DIRECT) {
5086                 ret |= SMB_O_DIRECT;
5087         }
5088 #endif
5089 #if defined(O_DIRECTORY)
5090         if (flags & O_DIRECTORY) {
5091                 ret |= SMB_O_DIRECTORY;
5092         }
5093 #endif
5094         return ret;
5095 }
5096
5097 /****************************************************************************
5098  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
5099 ****************************************************************************/
5100
5101 struct posix_open_state {
5102         uint16_t setup;
5103         uint8_t *param;
5104         uint8_t data[18];
5105         uint16_t fnum; /* Out */
5106 };
5107
5108 static void cli_posix_open_internal_done(struct tevent_req *subreq)
5109 {
5110         struct tevent_req *req = tevent_req_callback_data(
5111                                 subreq, struct tevent_req);
5112         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
5113         NTSTATUS status;
5114         uint8_t *data;
5115         uint32_t num_data;
5116
5117         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5118                                 NULL, 0, NULL, &data, 12, &num_data);
5119         TALLOC_FREE(subreq);
5120         if (tevent_req_nterror(req, status)) {
5121                 return;
5122         }
5123         state->fnum = SVAL(data,2);
5124         tevent_req_done(req);
5125 }
5126
5127 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
5128                                         struct tevent_context *ev,
5129                                         struct cli_state *cli,
5130                                         const char *fname,
5131                                         int flags,
5132                                         mode_t mode,
5133                                         bool is_dir)
5134 {
5135         struct tevent_req *req = NULL, *subreq = NULL;
5136         struct posix_open_state *state = NULL;
5137         uint32_t wire_flags = open_flags_to_wire(flags);
5138
5139         req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
5140         if (req == NULL) {
5141                 return NULL;
5142         }
5143
5144         /* Setup setup word. */
5145         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
5146
5147         /* Setup param array. */
5148         state->param = talloc_array(state, uint8_t, 6);
5149         if (tevent_req_nomem(state->param, req)) {
5150                 return tevent_req_post(req, ev);
5151         }
5152         memset(state->param, '\0', 6);
5153         SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
5154
5155         state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn), fname,
5156                                    strlen(fname)+1, NULL);
5157
5158         if (tevent_req_nomem(state->param, req)) {
5159                 return tevent_req_post(req, ev);
5160         }
5161
5162         /* Setup data words. */
5163         if (is_dir) {
5164                 wire_flags |= SMB_O_DIRECTORY;
5165         }
5166
5167         SIVAL(state->data,0,0); /* No oplock. */
5168         SIVAL(state->data,4,wire_flags);
5169         SIVAL(state->data,8,unix_perms_to_wire(mode));
5170         SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
5171         SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
5172
5173         subreq = cli_trans_send(state,                  /* mem ctx. */
5174                                 ev,                     /* event ctx. */
5175                                 cli,                    /* cli_state. */
5176                                 0,                      /* additional_flags2 */
5177                                 SMBtrans2,              /* cmd. */
5178                                 NULL,                   /* pipe name. */
5179                                 -1,                     /* fid. */
5180                                 0,                      /* function. */
5181                                 0,                      /* flags. */
5182                                 &state->setup,          /* setup. */
5183                                 1,                      /* num setup uint16_t words. */
5184                                 0,                      /* max returned setup. */
5185                                 state->param,           /* param. */
5186                                 talloc_get_size(state->param),/* num param. */
5187                                 2,                      /* max returned param. */
5188                                 state->data,            /* data. */
5189                                 18,                     /* num data. */
5190                                 12);                    /* max returned data. */
5191
5192         if (tevent_req_nomem(subreq, req)) {
5193                 return tevent_req_post(req, ev);
5194         }
5195         tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
5196         return req;
5197 }
5198
5199 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
5200                                         struct tevent_context *ev,
5201                                         struct cli_state *cli,
5202                                         const char *fname,
5203                                         int flags,
5204                                         mode_t mode)
5205 {
5206         return cli_posix_open_internal_send(mem_ctx, ev,
5207                                 cli, fname, flags, mode, false);
5208 }
5209
5210 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
5211 {
5212         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
5213         NTSTATUS status;
5214
5215         if (tevent_req_is_nterror(req, &status)) {
5216                 return status;
5217         }
5218         *pfnum = state->fnum;
5219         return NT_STATUS_OK;
5220 }
5221
5222 /****************************************************************************
5223  Open - POSIX semantics. Doesn't request oplock.
5224 ****************************************************************************/
5225
5226 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
5227                         int flags, mode_t mode, uint16_t *pfnum)
5228 {
5229
5230         TALLOC_CTX *frame = talloc_stackframe();
5231         struct tevent_context *ev = NULL;
5232         struct tevent_req *req = NULL;
5233         NTSTATUS status = NT_STATUS_OK;
5234
5235         if (smbXcli_conn_has_async_calls(cli->conn)) {
5236                 /*
5237                  * Can't use sync call while an async call is in flight
5238                  */
5239                 status = NT_STATUS_INVALID_PARAMETER;
5240                 goto fail;
5241         }
5242
5243         ev = samba_tevent_context_init(frame);
5244         if (ev == NULL) {
5245                 status = NT_STATUS_NO_MEMORY;
5246                 goto fail;
5247         }
5248
5249         req = cli_posix_open_send(frame,
5250                                 ev,
5251                                 cli,
5252                                 fname,
5253                                 flags,
5254                                 mode);
5255         if (req == NULL) {
5256                 status = NT_STATUS_NO_MEMORY;
5257                 goto fail;
5258         }
5259
5260         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5261                 goto fail;
5262         }
5263
5264         status = cli_posix_open_recv(req, pfnum);
5265
5266  fail:
5267         TALLOC_FREE(frame);
5268         return status;
5269 }
5270
5271 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
5272                                         struct tevent_context *ev,
5273                                         struct cli_state *cli,
5274                                         const char *fname,
5275                                         mode_t mode)
5276 {
5277         return cli_posix_open_internal_send(mem_ctx, ev,
5278                                 cli, fname, O_CREAT, mode, true);
5279 }
5280
5281 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
5282 {
5283         return tevent_req_simple_recv_ntstatus(req);
5284 }
5285
5286 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
5287 {
5288         TALLOC_CTX *frame = talloc_stackframe();
5289         struct tevent_context *ev = NULL;
5290         struct tevent_req *req = NULL;
5291         NTSTATUS status = NT_STATUS_OK;
5292
5293         if (smbXcli_conn_has_async_calls(cli->conn)) {
5294                 /*
5295                  * Can't use sync call while an async call is in flight
5296                  */
5297                 status = NT_STATUS_INVALID_PARAMETER;
5298                 goto fail;
5299         }
5300
5301         ev = samba_tevent_context_init(frame);
5302         if (ev == NULL) {
5303                 status = NT_STATUS_NO_MEMORY;
5304                 goto fail;
5305         }
5306
5307         req = cli_posix_mkdir_send(frame,
5308                                 ev,
5309                                 cli,
5310                                 fname,
5311                                 mode);
5312         if (req == NULL) {
5313                 status = NT_STATUS_NO_MEMORY;
5314                 goto fail;
5315         }
5316
5317         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5318                 goto fail;
5319         }
5320
5321         status = cli_posix_mkdir_recv(req);
5322
5323  fail:
5324         TALLOC_FREE(frame);
5325         return status;
5326 }
5327
5328 /****************************************************************************
5329  unlink or rmdir - POSIX semantics.
5330 ****************************************************************************/
5331
5332 struct cli_posix_unlink_internal_state {
5333         uint8_t data[2];
5334 };
5335
5336 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
5337
5338 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
5339                                         struct tevent_context *ev,
5340                                         struct cli_state *cli,
5341                                         const char *fname,
5342                                         uint16_t level)
5343 {
5344         struct tevent_req *req = NULL, *subreq = NULL;
5345         struct cli_posix_unlink_internal_state *state = NULL;
5346
5347         req = tevent_req_create(mem_ctx, &state,
5348                                 struct cli_posix_unlink_internal_state);
5349         if (req == NULL) {
5350                 return NULL;
5351         }
5352
5353         /* Setup data word. */
5354         SSVAL(state->data, 0, level);
5355
5356         subreq = cli_setpathinfo_send(state, ev, cli,
5357                                       SMB_POSIX_PATH_UNLINK,
5358                                       fname,
5359                                       state->data, sizeof(state->data));
5360         if (tevent_req_nomem(subreq, req)) {
5361                 return tevent_req_post(req, ev);
5362         }
5363         tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
5364         return req;
5365 }
5366
5367 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
5368 {
5369         NTSTATUS status = cli_setpathinfo_recv(subreq);
5370         tevent_req_simple_finish_ntstatus(subreq, status);
5371 }
5372
5373 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
5374                                         struct tevent_context *ev,
5375                                         struct cli_state *cli,
5376                                         const char *fname)
5377 {
5378         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
5379                                               SMB_POSIX_UNLINK_FILE_TARGET);
5380 }
5381
5382 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
5383 {
5384         return tevent_req_simple_recv_ntstatus(req);
5385 }
5386
5387 /****************************************************************************
5388  unlink - POSIX semantics.
5389 ****************************************************************************/
5390
5391 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
5392 {
5393         TALLOC_CTX *frame = talloc_stackframe();
5394         struct tevent_context *ev = NULL;
5395         struct tevent_req *req = NULL;
5396         NTSTATUS status = NT_STATUS_OK;
5397
5398         if (smbXcli_conn_has_async_calls(cli->conn)) {
5399                 /*
5400                  * Can't use sync call while an async call is in flight
5401                  */
5402                 status = NT_STATUS_INVALID_PARAMETER;
5403                 goto fail;
5404         }
5405
5406         ev = samba_tevent_context_init(frame);
5407         if (ev == NULL) {
5408                 status = NT_STATUS_NO_MEMORY;
5409                 goto fail;
5410         }
5411
5412         req = cli_posix_unlink_send(frame,
5413                                 ev,
5414                                 cli,
5415                                 fname);
5416         if (req == NULL) {
5417                 status = NT_STATUS_NO_MEMORY;
5418                 goto fail;
5419         }
5420
5421         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5422                 goto fail;
5423         }
5424
5425         status = cli_posix_unlink_recv(req);
5426
5427  fail:
5428         TALLOC_FREE(frame);
5429         return status;
5430 }
5431
5432 /****************************************************************************
5433  rmdir - POSIX semantics.
5434 ****************************************************************************/
5435
5436 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
5437                                         struct tevent_context *ev,
5438                                         struct cli_state *cli,
5439                                         const char *fname)
5440 {
5441         return cli_posix_unlink_internal_send(
5442                 mem_ctx, ev, cli, fname,
5443                 SMB_POSIX_UNLINK_DIRECTORY_TARGET);
5444 }
5445
5446 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
5447 {
5448         return tevent_req_simple_recv_ntstatus(req);
5449 }
5450
5451 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
5452 {
5453         TALLOC_CTX *frame = talloc_stackframe();
5454         struct tevent_context *ev = NULL;
5455         struct tevent_req *req = NULL;
5456         NTSTATUS status = NT_STATUS_OK;
5457
5458         if (smbXcli_conn_has_async_calls(cli->conn)) {
5459                 /*
5460                  * Can't use sync call while an async call is in flight
5461                  */
5462                 status = NT_STATUS_INVALID_PARAMETER;
5463                 goto fail;
5464         }
5465
5466         ev = samba_tevent_context_init(frame);
5467         if (ev == NULL) {
5468                 status = NT_STATUS_NO_MEMORY;
5469                 goto fail;
5470         }
5471
5472         req = cli_posix_rmdir_send(frame,
5473                                 ev,
5474                                 cli,
5475                                 fname);
5476         if (req == NULL) {
5477                 status = NT_STATUS_NO_MEMORY;
5478                 goto fail;
5479         }
5480
5481         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5482                 goto fail;
5483         }
5484
5485         status = cli_posix_rmdir_recv(req, frame);
5486
5487  fail:
5488         TALLOC_FREE(frame);
5489         return status;
5490 }
5491
5492 /****************************************************************************
5493  filechangenotify
5494 ****************************************************************************/
5495
5496 struct cli_notify_state {
5497         struct tevent_req *subreq;
5498         uint8_t setup[8];
5499         uint32_t num_changes;
5500         struct notify_change *changes;
5501 };
5502
5503 static void cli_notify_done(struct tevent_req *subreq);
5504 static void cli_notify_done_smb2(struct tevent_req *subreq);
5505 static bool cli_notify_cancel(struct tevent_req *req);
5506
5507 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
5508                                    struct tevent_context *ev,
5509                                    struct cli_state *cli, uint16_t fnum,
5510                                    uint32_t buffer_size,
5511                                    uint32_t completion_filter, bool recursive)
5512 {
5513         struct tevent_req *req;
5514         struct cli_notify_state *state;
5515         unsigned old_timeout;
5516
5517         req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
5518         if (req == NULL) {
5519                 return NULL;
5520         }
5521
5522         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5523                 /*
5524                  * Notifies should not time out
5525                  */
5526                 old_timeout = cli_set_timeout(cli, 0);
5527
5528                 state->subreq = cli_smb2_notify_send(
5529                         state,
5530                         ev,
5531                         cli,
5532                         fnum,
5533                         buffer_size,
5534                         completion_filter,
5535                         recursive);
5536
5537                 cli_set_timeout(cli, old_timeout);
5538
5539                 if (tevent_req_nomem(state->subreq, req)) {
5540                         return tevent_req_post(req, ev);
5541                 }
5542                 tevent_req_set_callback(
5543                         state->subreq, cli_notify_done_smb2, req);
5544                 goto done;
5545         }
5546
5547         SIVAL(state->setup, 0, completion_filter);
5548         SSVAL(state->setup, 4, fnum);
5549         SSVAL(state->setup, 6, recursive);
5550
5551         /*
5552          * Notifies should not time out
5553          */
5554         old_timeout = cli_set_timeout(cli, 0);
5555
5556         state->subreq = cli_trans_send(
5557                 state,                  /* mem ctx. */
5558                 ev,                     /* event ctx. */
5559                 cli,                    /* cli_state. */
5560                 0,                      /* additional_flags2 */
5561                 SMBnttrans,             /* cmd. */
5562                 NULL,                   /* pipe name. */
5563                 -1,                     /* fid. */
5564                 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
5565                 0,                      /* flags. */
5566                 (uint16_t *)state->setup, /* setup. */
5567                 4,                      /* num setup uint16_t words. */
5568                 0,                      /* max returned setup. */
5569                 NULL,                   /* param. */
5570                 0,                      /* num param. */
5571                 buffer_size,            /* max returned param. */
5572                 NULL,                   /* data. */
5573                 0,                      /* num data. */
5574                 0);                     /* max returned data. */
5575
5576         cli_set_timeout(cli, old_timeout);
5577
5578         if (tevent_req_nomem(state->subreq, req)) {
5579                 return tevent_req_post(req, ev);
5580         }
5581         tevent_req_set_callback(state->subreq, cli_notify_done, req);
5582 done:
5583         tevent_req_set_cancel_fn(req, cli_notify_cancel);
5584         return req;
5585 }
5586
5587 static bool cli_notify_cancel(struct tevent_req *req)
5588 {
5589         struct cli_notify_state *state = tevent_req_data(
5590                 req, struct cli_notify_state);
5591         bool ok;
5592
5593         ok = tevent_req_cancel(state->subreq);
5594         return ok;
5595 }
5596
5597 static void cli_notify_done(struct tevent_req *subreq)
5598 {
5599         struct tevent_req *req = tevent_req_callback_data(
5600                 subreq, struct tevent_req);
5601         struct cli_notify_state *state = tevent_req_data(
5602                 req, struct cli_notify_state);
5603         NTSTATUS status;
5604         uint8_t *params;
5605         uint32_t i, ofs, num_params;
5606         uint16_t flags2;
5607
5608         status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
5609                                 &params, 0, &num_params, NULL, 0, NULL);
5610         TALLOC_FREE(subreq);
5611         state->subreq = NULL;
5612         if (tevent_req_nterror(req, status)) {
5613                 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
5614                 return;
5615         }
5616
5617         state->num_changes = 0;
5618         ofs = 0;
5619
5620         while (num_params - ofs > 12) {
5621                 uint32_t next = IVAL(params, ofs);
5622                 state->num_changes += 1;
5623
5624                 if ((next == 0) || (ofs+next >= num_params)) {
5625                         break;
5626                 }
5627                 ofs += next;
5628         }
5629
5630         state->changes = talloc_array(state, struct notify_change,
5631                                       state->num_changes);
5632         if (tevent_req_nomem(state->changes, req)) {
5633                 TALLOC_FREE(params);
5634                 return;
5635         }
5636
5637         ofs = 0;
5638
5639         for (i=0; i<state->num_changes; i++) {
5640                 uint32_t next = IVAL(params, ofs);
5641                 uint32_t len = IVAL(params, ofs+8);
5642                 ssize_t ret;
5643                 char *name;
5644
5645                 if (trans_oob(num_params, ofs + 12, len)) {
5646                         TALLOC_FREE(params);
5647                         tevent_req_nterror(
5648                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5649                         return;
5650                 }
5651
5652                 state->changes[i].action = IVAL(params, ofs+4);
5653                 ret = clistr_pull_talloc(state->changes, (char *)params, flags2,
5654                                          &name, params+ofs+12, len,
5655                                          STR_TERMINATE|STR_UNICODE);
5656                 if (ret == -1) {
5657                         TALLOC_FREE(params);
5658                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5659                         return;
5660                 }
5661                 state->changes[i].name = name;
5662                 ofs += next;
5663         }
5664
5665         TALLOC_FREE(params);
5666         tevent_req_done(req);
5667 }
5668
5669 static void cli_notify_done_smb2(struct tevent_req *subreq)
5670 {
5671         struct tevent_req *req = tevent_req_callback_data(
5672                 subreq, struct tevent_req);
5673         struct cli_notify_state *state = tevent_req_data(
5674                 req, struct cli_notify_state);
5675         NTSTATUS status;
5676
5677         status = cli_smb2_notify_recv(
5678                 subreq,
5679                 state,
5680                 &state->changes,
5681                 &state->num_changes);
5682         TALLOC_FREE(subreq);
5683         if (tevent_req_nterror(req, status)) {
5684                 return;
5685         }
5686         tevent_req_done(req);
5687 }
5688
5689 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5690                          uint32_t *pnum_changes,
5691                          struct notify_change **pchanges)
5692 {
5693         struct cli_notify_state *state = tevent_req_data(
5694                 req, struct cli_notify_state);
5695         NTSTATUS status;
5696
5697         if (tevent_req_is_nterror(req, &status)) {
5698                 return status;
5699         }
5700
5701         *pnum_changes = state->num_changes;
5702         *pchanges = talloc_move(mem_ctx, &state->changes);
5703         return NT_STATUS_OK;
5704 }
5705
5706 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
5707                     uint32_t completion_filter, bool recursive,
5708                     TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
5709                     struct notify_change **pchanges)
5710 {
5711         TALLOC_CTX *frame;
5712         struct tevent_context *ev;
5713         struct tevent_req *req;
5714         NTSTATUS status = NT_STATUS_NO_MEMORY;
5715
5716         frame = talloc_stackframe();
5717
5718         if (smbXcli_conn_has_async_calls(cli->conn)) {
5719                 /*
5720                  * Can't use sync call while an async call is in flight
5721                  */
5722                 status = NT_STATUS_INVALID_PARAMETER;
5723                 goto fail;
5724         }
5725         ev = samba_tevent_context_init(frame);
5726         if (ev == NULL) {
5727                 goto fail;
5728         }
5729         req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
5730                               completion_filter, recursive);
5731         if (req == NULL) {
5732                 goto fail;
5733         }
5734         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5735                 goto fail;
5736         }
5737         status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
5738  fail:
5739         TALLOC_FREE(frame);
5740         return status;
5741 }
5742
5743 struct cli_qpathinfo_state {
5744         uint8_t *param;
5745         uint8_t *data;
5746         uint16_t setup[1];
5747         uint32_t min_rdata;
5748         uint8_t *rdata;
5749         uint32_t num_rdata;
5750 };
5751
5752 static void cli_qpathinfo_done(struct tevent_req *subreq);
5753
5754 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
5755                                       struct tevent_context *ev,
5756                                       struct cli_state *cli, const char *fname,
5757                                       uint16_t level, uint32_t min_rdata,
5758                                       uint32_t max_rdata)
5759 {
5760         struct tevent_req *req, *subreq;
5761         struct cli_qpathinfo_state *state;
5762         uint16_t additional_flags2 = 0;
5763
5764         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
5765         if (req == NULL) {
5766                 return NULL;
5767         }
5768         state->min_rdata = min_rdata;
5769         SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
5770
5771         state->param = talloc_zero_array(state, uint8_t, 6);
5772         if (tevent_req_nomem(state->param, req)) {
5773                 return tevent_req_post(req, ev);
5774         }
5775         SSVAL(state->param, 0, level);
5776         state->param = trans2_bytes_push_str(
5777                 state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
5778         if (tevent_req_nomem(state->param, req)) {
5779                 return tevent_req_post(req, ev);
5780         }
5781
5782         if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
5783                         !INFO_LEVEL_IS_UNIX(level)) {
5784                 additional_flags2 = FLAGS2_REPARSE_PATH;
5785         }
5786
5787         subreq = cli_trans_send(
5788                 state,                  /* mem ctx. */
5789                 ev,                     /* event ctx. */
5790                 cli,                    /* cli_state. */
5791                 additional_flags2,      /* additional_flags2 */
5792                 SMBtrans2,              /* cmd. */
5793                 NULL,                   /* pipe name. */
5794                 -1,                     /* fid. */
5795                 0,                      /* function. */
5796                 0,                      /* flags. */
5797                 state->setup,           /* setup. */
5798                 1,                      /* num setup uint16_t words. */
5799                 0,                      /* max returned setup. */
5800                 state->param,           /* param. */
5801                 talloc_get_size(state->param),  /* num param. */
5802                 2,                      /* max returned param. */
5803                 NULL,                   /* data. */
5804                 0,                      /* num data. */
5805                 max_rdata);             /* max returned data. */
5806
5807         if (tevent_req_nomem(subreq, req)) {
5808                 return tevent_req_post(req, ev);
5809         }
5810         tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5811         return req;
5812 }
5813
5814 static void cli_qpathinfo_done(struct tevent_req *subreq)
5815 {
5816         struct tevent_req *req = tevent_req_callback_data(
5817                 subreq, struct tevent_req);
5818         struct cli_qpathinfo_state *state = tevent_req_data(
5819                 req, struct cli_qpathinfo_state);
5820         NTSTATUS status;
5821
5822         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5823                                 NULL, 0, NULL,
5824                                 &state->rdata, state->min_rdata,
5825                                 &state->num_rdata);
5826         if (tevent_req_nterror(req, status)) {
5827                 return;
5828         }
5829         tevent_req_done(req);
5830 }
5831
5832 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5833                             uint8_t **rdata, uint32_t *num_rdata)
5834 {
5835         struct cli_qpathinfo_state *state = tevent_req_data(
5836                 req, struct cli_qpathinfo_state);
5837         NTSTATUS status;
5838
5839         if (tevent_req_is_nterror(req, &status)) {
5840                 return status;
5841         }
5842         if (rdata != NULL) {
5843                 *rdata = talloc_move(mem_ctx, &state->rdata);
5844         } else {
5845                 TALLOC_FREE(state->rdata);
5846         }
5847         if (num_rdata != NULL) {
5848                 *num_rdata = state->num_rdata;
5849         }
5850         return NT_STATUS_OK;
5851 }
5852
5853 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5854                        const char *fname, uint16_t level, uint32_t min_rdata,
5855                        uint32_t max_rdata,
5856                        uint8_t **rdata, uint32_t *num_rdata)
5857 {
5858         TALLOC_CTX *frame = talloc_stackframe();
5859         struct tevent_context *ev;
5860         struct tevent_req *req;
5861         NTSTATUS status = NT_STATUS_NO_MEMORY;
5862
5863         if (smbXcli_conn_has_async_calls(cli->conn)) {
5864                 /*
5865                  * Can't use sync call while an async call is in flight
5866                  */
5867                 status = NT_STATUS_INVALID_PARAMETER;
5868                 goto fail;
5869         }
5870         ev = samba_tevent_context_init(frame);
5871         if (ev == NULL) {
5872                 goto fail;
5873         }
5874         req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5875                                  max_rdata);
5876         if (req == NULL) {
5877                 goto fail;
5878         }
5879         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5880                 goto fail;
5881         }
5882         status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5883  fail:
5884         TALLOC_FREE(frame);
5885         return status;
5886 }
5887
5888 struct cli_qfileinfo_state {
5889         uint16_t setup[1];
5890         uint8_t param[4];
5891         uint8_t *data;
5892         uint16_t recv_flags2;
5893         uint32_t min_rdata;
5894         uint8_t *rdata;
5895         uint32_t num_rdata;
5896 };
5897
5898 static void cli_qfileinfo_done(struct tevent_req *subreq);
5899
5900 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
5901                                       struct tevent_context *ev,
5902                                       struct cli_state *cli, uint16_t fnum,
5903                                       uint16_t level, uint32_t min_rdata,
5904                                       uint32_t max_rdata)
5905 {
5906         struct tevent_req *req, *subreq;
5907         struct cli_qfileinfo_state *state;
5908
5909         req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
5910         if (req == NULL) {
5911                 return NULL;
5912         }
5913         state->min_rdata = min_rdata;
5914         SSVAL(state->param, 0, fnum);
5915         SSVAL(state->param, 2, level);
5916         SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
5917
5918         subreq = cli_trans_send(
5919                 state,                  /* mem ctx. */
5920                 ev,                     /* event ctx. */
5921                 cli,                    /* cli_state. */
5922                 0,                      /* additional_flags2 */
5923                 SMBtrans2,              /* cmd. */
5924                 NULL,                   /* pipe name. */
5925                 -1,                     /* fid. */
5926                 0,                      /* function. */
5927                 0,                      /* flags. */
5928                 state->setup,           /* setup. */
5929                 1,                      /* num setup uint16_t words. */
5930                 0,                      /* max returned setup. */
5931                 state->param,           /* param. */
5932                 sizeof(state->param),   /* num param. */
5933                 2,                      /* max returned param. */
5934                 NULL,                   /* data. */
5935                 0,                      /* num data. */
5936                 max_rdata);             /* max returned data. */
5937
5938         if (tevent_req_nomem(subreq, req)) {
5939                 return tevent_req_post(req, ev);
5940         }
5941         tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
5942         return req;
5943 }
5944
5945 static void cli_qfileinfo_done(struct tevent_req *subreq)
5946 {
5947         struct tevent_req *req = tevent_req_callback_data(
5948                 subreq, struct tevent_req);
5949         struct cli_qfileinfo_state *state = tevent_req_data(
5950                 req, struct cli_qfileinfo_state);
5951         NTSTATUS status;
5952
5953         status = cli_trans_recv(subreq, state,
5954                                 &state->recv_flags2,
5955                                 NULL, 0, NULL,
5956                                 NULL, 0, NULL,
5957                                 &state->rdata, state->min_rdata,
5958                                 &state->num_rdata);
5959         if (tevent_req_nterror(req, status)) {
5960                 return;
5961         }
5962         tevent_req_done(req);
5963 }
5964
5965 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5966                             uint16_t *recv_flags2,
5967                             uint8_t **rdata, uint32_t *num_rdata)
5968 {
5969         struct cli_qfileinfo_state *state = tevent_req_data(
5970                 req, struct cli_qfileinfo_state);
5971         NTSTATUS status;
5972
5973         if (tevent_req_is_nterror(req, &status)) {
5974                 return status;
5975         }
5976
5977         if (recv_flags2 != NULL) {
5978                 *recv_flags2 = state->recv_flags2;
5979         }
5980         if (rdata != NULL) {
5981                 *rdata = talloc_move(mem_ctx, &state->rdata);
5982         } else {
5983                 TALLOC_FREE(state->rdata);
5984         }
5985         if (num_rdata != NULL) {
5986                 *num_rdata = state->num_rdata;
5987         }
5988         return NT_STATUS_OK;
5989 }
5990
5991 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5992                        uint16_t fnum, uint16_t level, uint32_t min_rdata,
5993                        uint32_t max_rdata, uint16_t *recv_flags2,
5994                        uint8_t **rdata, uint32_t *num_rdata)
5995 {
5996         TALLOC_CTX *frame = talloc_stackframe();
5997         struct tevent_context *ev;
5998         struct tevent_req *req;
5999         NTSTATUS status = NT_STATUS_NO_MEMORY;
6000
6001         if (smbXcli_conn_has_async_calls(cli->conn)) {
6002                 /*
6003                  * Can't use sync call while an async call is in flight
6004                  */
6005                 status = NT_STATUS_INVALID_PARAMETER;
6006                 goto fail;
6007         }
6008         ev = samba_tevent_context_init(frame);
6009         if (ev == NULL) {
6010                 goto fail;
6011         }
6012         req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
6013                                  max_rdata);
6014         if (req == NULL) {
6015                 goto fail;
6016         }
6017         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6018                 goto fail;
6019         }
6020         status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
6021  fail:
6022         TALLOC_FREE(frame);
6023         return status;
6024 }
6025
6026 struct cli_flush_state {
6027         uint16_t vwv[1];
6028 };
6029
6030 static void cli_flush_done(struct tevent_req *subreq);
6031
6032 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
6033                                   struct tevent_context *ev,
6034                                   struct cli_state *cli,
6035                                   uint16_t fnum)
6036 {
6037         struct tevent_req *req, *subreq;
6038         struct cli_flush_state *state;
6039
6040         req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
6041         if (req == NULL) {
6042                 return NULL;
6043         }
6044         SSVAL(state->vwv + 0, 0, fnum);
6045
6046         subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
6047                               0, NULL);
6048         if (tevent_req_nomem(subreq, req)) {
6049                 return tevent_req_post(req, ev);
6050         }
6051         tevent_req_set_callback(subreq, cli_flush_done, req);
6052         return req;
6053 }
6054
6055 static void cli_flush_done(struct tevent_req *subreq)
6056 {
6057         struct tevent_req *req = tevent_req_callback_data(
6058                 subreq, struct tevent_req);
6059         NTSTATUS status;
6060
6061         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
6062         TALLOC_FREE(subreq);
6063         if (tevent_req_nterror(req, status)) {
6064                 return;
6065         }
6066         tevent_req_done(req);
6067 }
6068
6069 NTSTATUS cli_flush_recv(struct tevent_req *req)
6070 {
6071         return tevent_req_simple_recv_ntstatus(req);
6072 }
6073
6074 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
6075 {
6076         TALLOC_CTX *frame = talloc_stackframe();
6077         struct tevent_context *ev;
6078         struct tevent_req *req;
6079         NTSTATUS status = NT_STATUS_NO_MEMORY;
6080
6081         if (smbXcli_conn_has_async_calls(cli->conn)) {
6082                 /*
6083                  * Can't use sync call while an async call is in flight
6084                  */
6085                 status = NT_STATUS_INVALID_PARAMETER;
6086                 goto fail;
6087         }
6088         ev = samba_tevent_context_init(frame);
6089         if (ev == NULL) {
6090                 goto fail;
6091         }
6092         req = cli_flush_send(frame, ev, cli, fnum);
6093         if (req == NULL) {
6094                 goto fail;
6095         }
6096         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6097                 goto fail;
6098         }
6099         status = cli_flush_recv(req);
6100  fail:
6101         TALLOC_FREE(frame);
6102         return status;
6103 }
6104
6105 struct cli_shadow_copy_data_state {
6106         uint16_t setup[4];
6107         uint8_t *data;
6108         uint32_t num_data;
6109         bool get_names;
6110 };
6111
6112 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
6113
6114 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
6115                                              struct tevent_context *ev,
6116                                              struct cli_state *cli,
6117                                              uint16_t fnum,
6118                                              bool get_names)
6119 {
6120         struct tevent_req *req, *subreq;
6121         struct cli_shadow_copy_data_state *state;
6122         uint32_t ret_size;
6123
6124         req = tevent_req_create(mem_ctx, &state,
6125                                 struct cli_shadow_copy_data_state);
6126         if (req == NULL) {
6127                 return NULL;
6128         }
6129         state->get_names = get_names;
6130         ret_size = get_names ? CLI_BUFFER_SIZE : 16;
6131
6132         SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
6133         SSVAL(state->setup + 2, 0, fnum);
6134         SCVAL(state->setup + 3, 0, 1); /* isFsctl */
6135         SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
6136
6137         subreq = cli_trans_send(
6138                 state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
6139                 state->setup, ARRAY_SIZE(state->setup),
6140                 ARRAY_SIZE(state->setup),
6141                 NULL, 0, 0,
6142                 NULL, 0, ret_size);
6143         if (tevent_req_nomem(subreq, req)) {
6144                 return tevent_req_post(req, ev);
6145         }
6146         tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
6147         return req;
6148 }
6149
6150 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
6151 {
6152         struct tevent_req *req = tevent_req_callback_data(
6153                 subreq, struct tevent_req);
6154         struct cli_shadow_copy_data_state *state = tevent_req_data(
6155                 req, struct cli_shadow_copy_data_state);
6156         NTSTATUS status;
6157
6158         status = cli_trans_recv(subreq, state, NULL,
6159                                 NULL, 0, NULL, /* setup */
6160                                 NULL, 0, NULL, /* param */
6161                                 &state->data, 12, &state->num_data);
6162         TALLOC_FREE(subreq);
6163         if (tevent_req_nterror(req, status)) {
6164                 return;
6165         }
6166         tevent_req_done(req);
6167 }
6168
6169 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6170                                    char ***pnames, int *pnum_names)
6171 {
6172         struct cli_shadow_copy_data_state *state = tevent_req_data(
6173                 req, struct cli_shadow_copy_data_state);
6174         char **names = NULL;
6175         uint32_t i, num_names;
6176         uint32_t dlength;
6177         uint8_t *endp = NULL;
6178         NTSTATUS status;
6179
6180         if (tevent_req_is_nterror(req, &status)) {
6181                 return status;
6182         }
6183
6184         if (state->num_data < 16) {
6185                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6186         }
6187
6188         num_names = IVAL(state->data, 4);
6189         dlength = IVAL(state->data, 8);
6190
6191         if (num_names > 0x7FFFFFFF) {
6192                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6193         }
6194
6195         if (!state->get_names) {
6196                 *pnum_names = (int)num_names;
6197                 return NT_STATUS_OK;
6198         }
6199
6200         if (dlength + 12 < 12) {
6201                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6202         }
6203         if (dlength + 12 > state->num_data) {
6204                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6205         }
6206         if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
6207                         state->num_data) {
6208                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
6209         }
6210
6211         names = talloc_array(mem_ctx, char *, num_names);
6212         if (names == NULL) {
6213                 return NT_STATUS_NO_MEMORY;
6214         }
6215
6216         endp = state->data + state->num_data;
6217
6218         for (i=0; i<num_names; i++) {
6219                 bool ret;
6220                 uint8_t *src;
6221                 size_t converted_size;
6222
6223                 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
6224
6225                 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
6226                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
6227                 }
6228
6229                 ret = convert_string_talloc(
6230                         names, CH_UTF16LE, CH_UNIX,
6231                         src, 2 * sizeof(SHADOW_COPY_LABEL),
6232                         &names[i], &converted_size);
6233                 if (!ret) {
6234                         TALLOC_FREE(names);
6235                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
6236                 }
6237         }
6238         *pnum_names = (int)num_names;
6239         *pnames = names;
6240         return NT_STATUS_OK;
6241 }
6242
6243 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
6244                               uint16_t fnum, bool get_names,
6245                               char ***pnames, int *pnum_names)
6246 {
6247         TALLOC_CTX *frame = NULL;
6248         struct tevent_context *ev;
6249         struct tevent_req *req;
6250         NTSTATUS status = NT_STATUS_NO_MEMORY;
6251
6252         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6253                 return cli_smb2_shadow_copy_data(mem_ctx,
6254                                         cli,
6255                                         fnum,
6256                                         get_names,
6257                                         pnames,
6258                                         pnum_names);
6259         }
6260
6261         frame = talloc_stackframe();
6262
6263         if (smbXcli_conn_has_async_calls(cli->conn)) {
6264                 /*
6265                  * Can't use sync call while an async call is in flight
6266                  */
6267                 status = NT_STATUS_INVALID_PARAMETER;
6268                 goto fail;
6269         }
6270         ev = samba_tevent_context_init(frame);
6271         if (ev == NULL) {
6272                 goto fail;
6273         }
6274         req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
6275         if (req == NULL) {
6276                 goto fail;
6277         }
6278         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6279                 goto fail;
6280         }
6281         status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
6282  fail:
6283         TALLOC_FREE(frame);
6284         return status;
6285 }