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