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