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